FFmpegfs Fuse Multi Media Filesystem 2.19
Loading...
Searching...
No Matches
ffmpeg_transcoder.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017-2026 Norbert Schlia (nschlia@oblivion-software.de)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * On Debian systems, the complete text of the GNU General Public License
19 * Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
20 */
21
32#ifdef __cplusplus
33extern "C" {
34#endif
35// Disable annoying warnings outside our code
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wconversion"
38#pragma GCC diagnostic ignored "-Wsign-conversion"
39#include <libswscale/swscale.h>
40#include <libavutil/imgutils.h>
41#include <libavutil/opt.h>
42#include <libavutil/audio_fifo.h>
43#include <libavfilter/avfilter.h>
44#include <libavfilter/buffersink.h>
45#include <libavfilter/buffersrc.h>
46#include <libavcodec/avcodec.h>
47#include <libavformat/avformat.h>
48#include <libavformat/avio.h>
49#include <libavutil/file.h>
50#include <libswresample/swresample.h>
51#pragma GCC diagnostic pop
52#ifdef __cplusplus
53}
54#endif
55
56#include "ffmpeg_transcoder.h"
57#include "ffmpeg_dictionary.h"
58#include "buffer.h"
59#include "wave.h"
60#include "aiff.h"
61#include "logging.h"
62#include "ffmpegfs.h"
63
64#include <unistd.h>
65#include <filesystem>
66#include <thread>
67
68#define FRAME_SEEK_THRESHOLD 25
70const std::vector<FFmpeg_Transcoder::PRORES_BITRATE> FFmpeg_Transcoder::m_prores_bitrate =
71{
72 // SD
73 { 720, 486, { { 24, false } }, { 10, 23, 34, 50, 75, 113 } },
74 { 720, 486, { { 60, true }, { 30, false } }, { 12, 29, 42, 63, 94, 141 } },
75
76 { 720, 576, { { 50, true }, { 25, false } }, { 12, 28, 41, 61, 92, 138 } },
77
78 { 960, 720, { { 24, false } }, { 15, 35, 50, 75, 113, 170 } },
79 { 960, 720, { { 25, false } }, { 16, 36, 52, 79, 118, 177 } },
80 { 960, 720, { { 30, false } }, { 19, 44, 63, 94, 141, 212 } },
81 { 960, 720, { { 50, false } }, { 32, 73, 105, 157, 236, 354 } },
82 { 960, 720, { { 60, false } }, { 38, 87, 126, 189, 283, 424 } },
83 // HD
84 { 1280, 720, { { 24, false } }, { 18, 41, 59, 88, 132, 198 } },
85 { 1280, 720, { { 25, false } }, { 19, 42, 61, 92, 138, 206 } },
86 { 1280, 720, { { 30, false } }, { 23, 51, 73, 110, 165, 247 } },
87 { 1280, 720, { { 50, false } }, { 38, 84, 122, 184, 275, 413 } },
88 { 1280, 720, { { 60, false } }, { 45, 101, 147, 220, 330, 495 } },
89
90 { 1280, 1080, { { 24, false } }, { 31, 70, 101, 151, 226, 339 } },
91 { 1280, 1080, { { 60, true }, { 30, false } }, { 38, 87, 126, 189, 283, 424 } },
92
93 { 1440, 1080, { { 24, false } }, { 31, 70, 101, 151, 226, 339 } },
94 { 1440, 1080, { { 50, true }, { 25, false } }, { 32, 73, 105, 157, 236, 354 } },
95 { 1440, 1080, { { 60, true }, { 30, false } }, { 38, 87, 126, 189, 283, 424 } },
96 // Full HD
97 { 1920, 1080, { { 24, false } }, { 36, 82, 117, 176, 264, 396 } },
98 { 1920, 1080, { { 50, true }, { 25, false } }, { 38, 85, 122, 184, 275, 413 } },
99 { 1920, 1080, { { 60, true }, { 30, false } }, { 45, 102, 147, 220, 330, 495 } },
100 { 1920, 1080, { { 50, false } }, { 76, 170, 245, 367, 551, 826 } },
101 { 1920, 1080, { { 60, false } }, { 91, 204, 293, 440, 660, 990 } },
102 // 2K
103 { 2048, 1080, { { 24, false } }, { 41, 93, 134, 201, 302, 453 } },
104 { 2048, 1080, { { 25, false } }, { 43, 97, 140, 210, 315, 472 } },
105 { 2048, 1080, { { 30, false } }, { 52, 116, 168, 251, 377, 566 } },
106 { 2048, 1080, { { 50, false } }, { 86, 194, 280, 419, 629, 944 } },
107 { 2048, 1080, { { 60, false } }, { 103, 232, 335, 503, 754, 1131 } },
108 // 2K
109 { 2048, 1556, { { 24, false } }, { 56, 126, 181, 272, 407, 611 } },
110 { 2048, 1556, { { 25, false } }, { 58, 131, 189, 283, 425, 637 } },
111 { 2048, 1556, { { 30, false } }, { 70, 157, 226, 340, 509, 764 } },
112 { 2048, 1556, { { 50, false } }, { 117, 262, 377, 567, 850, 1275 } },
113 { 2048, 1556, { { 60, false } }, { 140, 314, 452, 679, 1019, 1528 } },
114 // QFHD
115 { 3840, 2160, { { 24, false } }, { 145, 328, 471, 707, 1061, 1591 } },
116 { 3840, 2160, { { 25, false } }, { 151, 342, 492, 737, 1106, 1659 } },
117 { 3840, 2160, { { 30, false } }, { 182, 410, 589, 884, 1326, 1989 } },
118 { 3840, 2160, { { 50, false } }, { 303, 684, 983, 1475, 2212, 3318 } },
119 { 3840, 2160, { { 60, false } }, { 363, 821, 1178, 1768, 2652, 3977 } },
120 // 4K
121 { 4096, 2160, { { 24, false } }, { 155, 350, 503, 754, 1131, 1697 } },
122 { 4096, 2160, { { 25, false } }, { 162, 365, 524, 786, 1180, 1769 } },
123 { 4096, 2160, { { 30, false } }, { 194, 437, 629, 943, 1414, 2121 } },
124 { 4096, 2160, { { 50, false } }, { 323, 730, 1049, 1573, 2359, 3539 } },
125 { 4096, 2160, { { 60, false } }, { 388, 875, 1257, 1886, 2828, 4242 } },
126 // 5K
127 { 5120, 2700, { { 24, false } }, { 243, 547, 786, 1178, 1768, 2652 } },
128 { 5120, 2700, { { 25, false } }, { 253, 570, 819, 1229, 1843, 2765 } },
129 { 5120, 2700, { { 30, false } }, { 304, 684, 982, 1473, 2210, 3314 } },
130 { 5120, 2700, { { 50, false } }, { 507, 1140, 1638, 2458, 3686, 5530 } },
131 { 5120, 2700, { { 60, false } }, { 608, 1367, 1964, 2946, 4419, 6629 } },
132 // 6K
133 { 6144, 3240, { { 24, false } }, { 350, 788, 1131, 1697, 2545, 3818 } },
134 { 6144, 3240, { { 25, false } }, { 365, 821, 1180, 1769, 2654, 3981 } },
135 { 6144, 3240, { { 30, false } }, { 437, 985, 1414, 2121, 3182, 4772 } },
136 { 6144, 3240, { { 50, false } }, { 730, 1643, 2359, 3539, 5308, 7962 } },
137 { 6144, 3240, { { 60, false } }, { 875, 1969, 2828, 4242, 6364, 9545 } },
138 // 8K
139 { 8192, 4320, { { 24, false } }, { 622, 1400, 2011, 3017, 4525, 6788 } },
140 { 8192, 4320, { { 25, false } }, { 649, 1460, 2097, 3146, 4719, 7078 } },
141 { 8192, 4320, { { 30, false } }, { 778, 1750, 2514, 3771, 5657, 8485 } },
142 { 8192, 4320, { { 50, false } }, { 1298, 2920, 4194, 6291, 9437, 14156 } },
143 { 8192, 4320, { { 60, false } }, { 1556, 3500, 5028, 7542, 11313, 16970 } }
144};
145
147{
148 { AV_HWDEVICE_TYPE_VAAPI, AV_PIX_FMT_NV12 },
149 #if 0
150 { AV_HWDEVICE_TYPE_CUDA, AV_PIX_FMT_CUDA },
151 { AV_HWDEVICE_TYPE_VDPAU, AV_PIX_FMT_YUV420P },
152 { AV_HWDEVICE_TYPE_QSV, AV_PIX_FMT_QSV },
153 { AV_HWDEVICE_TYPE_OPENCL, AV_PIX_FMT_OPENCL },
154 #if HAVE_VULKAN_HWACCEL
155 { AV_HWDEVICE_TYPE_VULKAN, AV_PIX_FMT_VULKAN },
156 #endif // HAVE_VULKAN_HWACCEL
157 #if __APPLE__
158 { AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },
159 #endif // __APPLE__
160 #if __ANDROID__
161 { AV_HWDEVICE_TYPE_MEDIACODEC, AV_PIX_FMT_MEDIACODEC },
162 #endif // __ANDROID__
163 #if _WIN32
164 { AV_HWDEVICE_TYPE_DRM, AV_PIX_FMT_DRM_PRIME },
165 { AV_HWDEVICE_TYPE_DXVA2, AV_PIX_FMT_DXVA2_VLD },
166 { AV_HWDEVICE_TYPE_D3D11VA, AV_PIX_FMT_D3D11VA_VLD },
167 #endif // _WIN32
168 #endif
169};
170
171FFmpeg_Transcoder::StreamRef::StreamRef() :
172 m_codec_ctx(nullptr),
173 m_stream(nullptr),
174 m_stream_idx(INVALID_STREAM),
175 m_start_time(0)
176{
177
178}
179FFmpeg_Transcoder::StreamRef::~StreamRef()
180{
181 reset();
182}
183
184template< typename T >
186{
191 void operator ()( T * p) const
192 {
193 avcodec_free_context(&p);
194 }
195};
196
197void FFmpeg_Transcoder::StreamRef::set_codec_ctx(AVCodecContext *codec_ctx)
198{
199 if (codec_ctx != nullptr)
200 {
201 std::shared_ptr<AVCodecContext> sp(codec_ctx, av_context_deleter<AVCodecContext>());
202
203 m_codec_ctx = sp;
204 }
205 else
206 {
207 m_codec_ctx.reset();
208 }
209}
210
212{
213 m_codec_ctx.reset();
214}
215
216#pragma GCC diagnostic push
217#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
219 : m_fileio(nullptr)
221 , m_have_seeked(false)
222 , m_skip_next_frame(false)
223 , m_is_video(false)
224 , m_cur_sample_fmt(AV_SAMPLE_FMT_NONE)
226 , m_buffer_sink_context(nullptr)
227 , m_buffer_source_context(nullptr)
228 , m_filter_graph(nullptr)
229 , m_pts(AV_NOPTS_VALUE)
230 , m_pos(AV_NOPTS_VALUE)
232 , m_insert_keyframe(true)
233 , m_copy_audio(false)
234 , m_copy_video(false)
235 , m_cur_audio_ts(0)
236 , m_cur_video_ts(0)
237 , m_current_format(nullptr)
238 , m_buffer(nullptr)
239 , m_reset_pts(0)
240 , m_fake_frame_no(0)
245 , m_hwaccel_enc_device_ctx(nullptr)
246 , m_hwaccel_dec_device_ctx(nullptr)
247 , m_enc_hw_pix_fmt(AV_PIX_FMT_NONE)
248 , m_dec_hw_pix_fmt(AV_PIX_FMT_NONE)
251{
252#pragma GCC diagnostic pop
253 Logging::trace(nullptr, "The FFmpeg trancoder is ready to initialise.");
254
255 std::memset(&m_mtime, 0, sizeof(m_mtime));
256
257#if LAVU_DEP_OLD_CHANNEL_LAYOUT
258 av_channel_layout_default(&m_cur_ch_layout, params.m_audiochannels);
259#else // !LAVU_DEP_OLD_CHANNEL_LAYOUT
260 m_cur_channel_layout = static_cast<uint64_t>(av_get_default_channel_layout(params.m_audiochannels));
261#endif // !LAVU_DEP_OLD_CHANNEL_LAYOUT
262
263 // Initialise ID3v1.1 tag structure
265}
266
268{
269 // Close files and resample context
270 closeio();
271
272 Logging::trace(nullptr, "The FFmpeg transcoder object was destroyed.");
273}
274
276{
277 bool is_video = false;
278
279 if (m_in.m_video.m_codec_ctx != nullptr && m_in.m_video.m_stream != nullptr)
280 {
281 is_video = !is_album_art(m_in.m_video.m_codec_ctx->codec_id, &m_in.m_video.m_stream->r_frame_rate);
282 }
283
284 return is_video;
285}
286
288{
289 return (m_in.m_format_ctx != nullptr);
290}
291
292int FFmpeg_Transcoder::open_input_file(LPVIRTUALFILE virtualfile, std::shared_ptr<FileIO> fio)
293{
295 int ret;
296
297 if (virtualfile == nullptr)
298 {
299 Logging::error(filename(), "INTERNAL ERROR: FFmpeg_Transcoder::open_input_file()! virtualfile is NULL.");
300 return AVERROR(EINVAL);
301 }
302
303 m_virtualfile = virtualfile;
304
305 m_mtime = m_virtualfile->m_st.st_mtime;
307
308 if (is_open())
309 {
310 Logging::warning(filename(), "The file is already open.");
311 return 0;
312 }
313
314 // This allows selecting if the demuxer should consider all streams to be
315 // found after the first PMT and add further streams during decoding or if it rather
316 // should scan all that are within the analyze-duration and other limits
317 ret = dict_set_with_check(opt.address(), "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
318 if (ret < 0)
319 {
320 return ret;
321 }
322
323 // avioflags direct: Reduce buffering.
324 //ret = dict_set_with_check(opt.address(), "avioflags", "direct", AV_DICT_DONT_OVERWRITE);
325 //if (ret < 0)
326 //{
327 // return ret;
328 //}
329
330 // analyzeduration: Defaults to 5,000,000 microseconds = 5 seconds.
331 ret = dict_set_with_check(opt.address(), "analyzeduration", "15000000", 0); // <<== honored: 15 seconds
332 if (ret < 0)
333 {
334 return ret;
335 }
336
337 // probesize: 5000000 by default.
338 ret = dict_set_with_check(opt.address(), "probesize", "15000000", 0); // <<== honoured: ~15 MB
339 if (ret < 0)
340 {
341 return ret;
342 }
343
344 // using own I/O
345 if (fio == nullptr)
346 {
347 // Open new file io
349 }
350 else
351 {
352 // Use already open file io
353 m_fileio = fio;
354 }
355
356 if (m_fileio == nullptr)
357 {
358 int orgerrno = errno;
359 Logging::error(filename(), "Error opening file: (%1) %2", errno, strerror(errno));
360 return AVERROR(orgerrno);
361 }
362
363 ret = m_fileio->openio(m_virtualfile);
364 if (ret)
365 {
366 return AVERROR(ret);
367 }
368
370 if (ret < 0)
371 {
372 Logging::error(filename(), "Out of memory opening file: format context could not be allocated.");
373 return ret;
374 }
375
376 unsigned char *iobuffer = static_cast<unsigned char *>(av_malloc(m_fileio->bufsize() + FF_INPUT_BUFFER_PADDING_SIZE));
377 if (iobuffer == nullptr)
378 {
379 Logging::error(filename(), "Out of memory opening file: I/O buffer could not be allocated.");
381 return AVERROR(ENOMEM);
382 }
383
384 AVIOContext * pb = avio_alloc_context(
385 iobuffer,
386 static_cast<int>(m_fileio->bufsize()),
387 0,
388 static_cast<void *>(m_fileio.get()),
390 nullptr, // input_write
391 seek); // input_seek
392 if (pb == nullptr)
393 {
394 Logging::error(filename(), "Out of memory opening file: I/O context could not be allocated.");
395 av_freep(&iobuffer);
397 return AVERROR(ENOMEM);
398 }
399 m_in.m_format_ctx->pb = pb;
401
402#if IF_DECLARED_CONST
403 const AVInputFormat * infmt = nullptr;
404#else // !IF_DECLARED_CONST
405 AVInputFormat * infmt = nullptr;
406#endif // !IF_DECLARED_CONST
407
408#ifdef USE_LIBVCD
410 {
411 Logging::debug(filename(), "To avoid misdetection, forcing MPEG format for VCD source.");
412 infmt = av_find_input_format("mpeg");
413 }
414#endif // USE_LIBVCD
415#ifdef USE_LIBDVD
417 {
418 Logging::debug(filename(), "To avoid misdetection, forcing MPEG format for DVD source.");
419 infmt = av_find_input_format("mpeg");
420 }
421#endif // USE_LIBDVD
422#ifdef USE_LIBBLURAY
424 {
425 Logging::debug(filename(), "To avoid misdetection, forcing MPEGTS format for Blu-ray source.");
426 infmt = av_find_input_format("mpegts");
427 }
428#endif // USE_LIBBLURAY
429
452 // Open the input file to read from it.
453 ret = avformat_open_input(m_in.m_format_ctx.address(), filename(), infmt, opt.address());
454 if (ret < 0)
455 {
456 Logging::error(filename(), "Could not open input file (error '%1').", ffmpeg_geterror(ret).c_str());
457 return ret;
458 }
459
461
462#if HAVE_AV_FORMAT_INJECT_GLOBAL_SIDE_DATA
463 av_format_inject_global_side_data(m_in.m_format_ctx);
464#endif
465
466 // Get information on the input file (number of streams etc.).
467 ret = avformat_find_stream_info(m_in.m_format_ctx, nullptr);
468 if (ret < 0)
469 {
470 Logging::error(filename(), "Could not find stream info (error '%1').", ffmpeg_geterror(ret).c_str());
471 return ret;
472 }
473
474#ifdef USE_LIBDVD
476 {
477 // FFmpeg API calculates a wrong duration, so use value from IFO
478 m_in.m_format_ctx->duration = m_fileio->duration();
479 }
480#endif // USE_LIBDVD
481#ifdef USE_LIBBLURAY
483 {
484 // FFmpeg API calculates a wrong duration, so use value from Blu-ray directory
485 m_in.m_format_ctx->duration = m_fileio->duration();
486 }
487#endif // USE_LIBBLURAY
488
490
491 ret = open_bestmatch_video();
492 if (ret < 0)
493 {
494 // Already logged
495 return ret;
496 }
497
498#ifdef USE_LIBDVD
500 {
501 // FFmpeg API sometimes cannot detect video size or frame rate, so use value from IFO
502 if (!m_in.m_video.m_codec_ctx->width || !m_in.m_video.m_stream->codecpar->height)
503 {
504 m_in.m_video.m_codec_ctx->width = m_in.m_video.m_stream->codecpar->width = m_virtualfile->m_width;
505 m_in.m_video.m_codec_ctx->height = m_in.m_video.m_stream->codecpar->height = m_virtualfile->m_height;
506 }
507 if (!m_in.m_video.m_stream->avg_frame_rate.den)
508 {
509 m_in.m_video.m_stream->avg_frame_rate = m_virtualfile->m_framerate;
510 }
511 }
512#endif // USE_LIBDVD
513#ifdef USE_LIBBLURAY
515 {
516 // FFmpeg API sometimes cannot detect video size or frame rate, so use value from Blu-ray directory
517 if (!m_in.m_video.m_codec_ctx->width || !m_in.m_video.m_stream->codecpar->height)
518 {
519 m_in.m_video.m_codec_ctx->width = m_in.m_video.m_stream->codecpar->width = m_virtualfile->m_width;
520 m_in.m_video.m_codec_ctx->height = m_in.m_video.m_stream->codecpar->height = m_virtualfile->m_height;
521 }
522 if (!m_in.m_video.m_stream->avg_frame_rate.den)
523 {
524 m_in.m_video.m_stream->avg_frame_rate = m_virtualfile->m_framerate;
525 }
526 }
527#endif // USE_LIBBLURAY
528
529 ret = open_bestmatch_audio();
530 if (ret < 0)
531 {
532 // Already logged
533 return ret;
534 }
535
537 {
538 Logging::error(filename(), "The file contains neither a video nor an audio stream.");
539 return AVERROR(EINVAL);
540 }
541
543 {
544 ret = open_subtitles();
545 if (ret < 0)
546 {
547 // Already logged
548 return ret;
549 }
550 }
551
552 // Predict size of transcoded file as exact as possible
554
555 // Calculate number or video frames in file based on duration and frame rate
556 if (m_in.m_video.m_stream != nullptr && m_in.m_video.m_stream->avg_frame_rate.den)
557 {
558 // Number of frames: should be quite accurate
559 m_virtualfile->m_video_frame_count = static_cast<uint32_t>(ffmpeg_rescale_q(m_in.m_video.m_stream->duration, m_in.m_video.m_stream->time_base, av_inv_q(m_in.m_video.m_stream->avg_frame_rate)));
560 }
561
562 ret = open_albumarts();
563 if (ret < 0)
564 {
565 // Already logged
566 return ret;
567 }
568
570 {
571 // Position to start of cue sheet track
572 ret = av_seek_frame(m_in.m_format_ctx, -1, m_virtualfile->m_cuesheet_track.m_start, 0);
573 if (ret < 0)
574 {
575 Logging::error(filename(), "The track start was nout found (error '%1').", ffmpeg_geterror(ret).c_str());
576 return ret;
577 }
578 }
579
580 return 0;
581}
582
584{
585 // Issue #80: Open input video codec, but only if target supports video.
586 // Saves resources: no need to decode video frames if not used.
587 if (m_current_format->video_codec() != AV_CODEC_ID_NONE)
588 {
589 int ret;
590
591 // Open best match video codec
592 AVCodecContext * codec_ctx = nullptr;
593 ret = open_bestmatch_decoder(m_in.m_format_ctx, &codec_ctx, &m_in.m_video.m_stream_idx, AVMEDIA_TYPE_VIDEO);
594 if (ret < 0 && ret != AVERROR_STREAM_NOT_FOUND) // AVERROR_STREAM_NOT_FOUND is not an error
595 {
596 Logging::error(filename(), "The video codec could not be opened (error '%1').", ffmpeg_geterror(ret).c_str());
597 return ret;
598 }
599 m_in.m_video.set_codec_ctx(codec_ctx);
600
602 {
603 // We have a video stream
604 // Check to see if encoder hardware acceleration is both requested and supported by codec.
605 std::string hw_encoder_codec_name;
606 if (!get_hw_encoder_name(m_current_format->video_codec(), &hw_encoder_codec_name))
607 {
608 // API supports hardware frame buffers
610 }
611
613 {
614 // Hardware buffers available, enabling encoder hardware accceleration.
615 Logging::trace(virtname(), "Hardware encoder frame buffering %1 is enabled.", get_hwaccel_API_text(params.m_hwaccel_enc_API).c_str());
617 if (ret < 0)
618 {
619 Logging::error(virtname(), "Failed to create a %1 device for encoding (error %2).", get_hwaccel_API_text(params.m_hwaccel_enc_API).c_str(), ffmpeg_geterror(ret).c_str());
620 return ret;
621 }
622 Logging::info(virtname(), "Hardware encoder acceleration and frame buffering are active using codec '%1'.", hw_encoder_codec_name.c_str());
623 }
624 else if (params.m_hwaccel_enc_device_type != AV_HWDEVICE_TYPE_NONE)
625 {
626 // No hardware acceleration, fallback to software,
627 Logging::debug(virtname(), "Hardware encoder frame buffering %1 is not supported by codec '%2'. Falling back to software.", get_hwaccel_API_text(params.m_hwaccel_enc_API).c_str(), get_codec_name(m_in.m_video.m_codec_ctx->codec_id, true));
628 }
629 else if (!hw_encoder_codec_name.empty())
630 {
631 // No frame buffering (e.g. OpenMAX or MMAL), but hardware acceleration possible.
632 Logging::info(virtname(), "Hardware encoder acceleration is active using codec '%1'.", hw_encoder_codec_name.c_str());
633 }
634
636
637#ifdef USE_LIBDVD
639 {
640 // FFmpeg API calculates a wrong duration, so use value from IFO
641 m_in.m_video.m_stream->duration = ffmpeg_rescale_q(m_in.m_format_ctx->duration, av_get_time_base_q(), m_in.m_video.m_stream->time_base);
642 }
643#endif // USE_LIBDVD
644#ifdef USE_LIBBLURAY
646 {
647 // FFmpeg API calculates a wrong duration, so use value from Blu-ray
648 m_in.m_video.m_stream->duration = ffmpeg_rescale_q(m_in.m_format_ctx->duration, av_get_time_base_q(), m_in.m_video.m_stream->time_base);
649 }
650#endif // USE_LIBBLURAY
651
653
655
656#if !LAVC_DEP_FLAG_TRUNCATED
657#ifdef AV_CODEC_CAP_TRUNCATED
658 if (m_in.m_video.m_codec_ctx->codec->capabilities & AV_CODEC_CAP_TRUNCATED)
659 {
660 m_in.m_video.m_codec_ctx->flags|= AV_CODEC_FLAG_TRUNCATED; // we do not send complete frames
661 }
662#else
663#warning "Your FFMPEG distribution is missing AV_CODEC_CAP_TRUNCATED flag. Probably requires fixing!"
664#endif
665#endif // !LAVC_DEP_FLAG_TRUNCATED
666 }
667 }
668 return 0;
669}
670
672{
673 int ret;
674
675 // Open best match audio codec
676 AVCodecContext * codec_ctx = nullptr;
677 ret = open_bestmatch_decoder(m_in.m_format_ctx, &codec_ctx, &m_in.m_audio.m_stream_idx, AVMEDIA_TYPE_AUDIO);
678 if (ret < 0 && ret != AVERROR_STREAM_NOT_FOUND) // AVERROR_STREAM_NOT_FOUND is not an error
679 {
680 Logging::error(filename(), "The audio codec could not be opened (error '%1').", ffmpeg_geterror(ret).c_str());
681 return ret;
682 }
683 m_in.m_audio.set_codec_ctx(codec_ctx);
684
686 {
687 // We have an audio stream
689
690#ifdef USE_LIBDVD
692 {
693 // FFmpeg API calculates a wrong duration, so use value from IFO
694 m_in.m_audio.m_stream->duration = ffmpeg_rescale_q(m_in.m_format_ctx->duration, av_get_time_base_q(), m_in.m_audio.m_stream->time_base);
695 }
696#endif // USE_LIBDVD
697#ifdef USE_LIBBLURAY
699 {
700 // FFmpeg API calculates a wrong duration, so use value from Blu-ray directory
701 m_in.m_audio.m_stream->duration = ffmpeg_rescale_q(m_in.m_format_ctx->duration, av_get_time_base_q(), m_in.m_audio.m_stream->time_base);
702 }
703#endif // USE_LIBBLURAY
704
706 }
707 return 0;
708}
709
711{
712 // If target supports subtitles, check to transcode subtitles
713 for (int stream_idx = 0; stream_idx < static_cast<int>(m_in.m_format_ctx->nb_streams); stream_idx++)
714 {
715 AVStream * stream = m_in.m_format_ctx->streams[stream_idx];
716
717 if (avcodec_get_type(stream->codecpar->codec_id) != AVMEDIA_TYPE_SUBTITLE)
718 {
719 continue;
720 }
721
722 if (m_current_format->subtitle_codec(stream->codecpar->codec_id) == AV_CODEC_ID_NONE)
723 {
724 // No match, no support for this type of subtitle
725 continue;
726 }
727
728 AVCodecContext * codec_ctx = nullptr;
729 int ret;
730
731 ret = open_decoder(m_in.m_format_ctx, &codec_ctx, stream_idx, nullptr, AVMEDIA_TYPE_SUBTITLE);
732 if (ret < 0)
733 {
734 Logging::error(filename(), "The subtitle codec could not be opened (error '%1').", ffmpeg_geterror(ret).c_str());
735 return ret;
736 }
737
738 codec_ctx->pkt_timebase = codec_ctx->time_base = stream->time_base;
739
740 StreamRef input_streamref;
741
742 // We have a subtitle stream
743 input_streamref.set_codec_ctx(codec_ctx);
744 input_streamref.m_stream = stream;
745 input_streamref.m_stream_idx = stream_idx;
746
747 m_in.m_subtitle.emplace(input_streamref.m_stream_idx, input_streamref);
748
749 subtitle_info(false, m_in.m_format_ctx, input_streamref.m_stream);
750 }
751 return 0;
752}
753
755{
756 // Open album art streams if present and supported by both source and target
757 if (!params.m_noalbumarts && m_in.m_audio.m_stream != nullptr)
758 {
759 for (int stream_idx = 0; stream_idx < static_cast<int>(m_in.m_format_ctx->nb_streams); stream_idx++)
760 {
761 AVStream *input_stream = m_in.m_format_ctx->streams[stream_idx];
762
763 if (is_album_art(input_stream->codecpar->codec_id, &input_stream->r_frame_rate))
764 {
765 StreamRef streamref;
766 AVCodecContext * input_codec_ctx;
767 int ret;
768
769 Logging::trace(filename(), "Found album art.");
770
771 ret = open_decoder(m_in.m_format_ctx, &input_codec_ctx, stream_idx, nullptr, AVMEDIA_TYPE_VIDEO);
772 if (ret < 0)
773 {
774 Logging::error(filename(), "The album art codec could not be opened (error '%1').", ffmpeg_geterror(ret).c_str());
775 return ret;
776 }
777
778 streamref.set_codec_ctx(input_codec_ctx);
779 streamref.m_stream = input_stream;
780 streamref.m_stream_idx = input_stream->index;
781
782 m_in.m_album_art.push_back(streamref);
783 }
784 }
785 }
786 return 0;
787}
788
789bool FFmpeg_Transcoder::can_copy_stream(const AVStream *stream) const
790{
792 {
793 // Auto copy disabled
794 return false;
795 }
796
797 if (stream == nullptr)
798 {
799 // Should normally not happen: Input stream stream unknown, no way to check - no auto copy
800 return false;
801 }
802
803 AVMediaType codec_type = stream->codecpar->codec_type;
804 AVCodecID codec_in = stream->codecpar->codec_id;
805 std::string codec_type_str;
806 AVCodecID codec_out;
807 int64_t bitrate_out;
808 if (codec_type == AVMEDIA_TYPE_VIDEO)
809 {
810 codec_type_str = "video";
811 codec_out = m_current_format->video_codec();
812 bitrate_out = params.m_videobitrate;
813 }
814 else if (codec_type == AVMEDIA_TYPE_AUDIO)
815 {
816 codec_type_str = "audio";
817 codec_out = m_current_format->audio_codec();
818 bitrate_out = params.m_audiobitrate;
819 }
820 else
821 {
822 // Codec is not video or audio
823 return false;
824 }
825
827 {
828 // Any codec supported by output format OK
829 const AVOutputFormat* oformat = av_guess_format(nullptr, virtname(), nullptr);
830 if (oformat->codec_tag == nullptr || av_codec_get_tag(oformat->codec_tag, stream->codecpar->codec_id) <= 0)
831 {
832 // Codec not supported - no auto copy
833 return false;
834 }
835 }
837 {
838 // Output codec must strictly match
839 Logging::debug(virtname(), "Check autocopy strict: %1: %2 -> %3", codec_type_str.c_str(), avcodec_get_name(codec_in), avcodec_get_name(codec_out));
840 if (codec_in != codec_out)
841 {
842 // Different codecs - no auto copy
843 return false;
844 }
845 }
846
848 {
849 BITRATE orig_bit_rate = (stream->codecpar->bit_rate != 0) ? stream->codecpar->bit_rate : m_in.m_format_ctx->bit_rate;
850 if (get_output_bit_rate(orig_bit_rate, bitrate_out))
851 {
852 // Bit rate changed, no auto copy
853 Logging::info(virtname(), "Because the bit rate has changed, no auto copy is possible.");
854 return false;
855 }
856 }
857
858 return true;
859}
860
862{
863 if (buffer == nullptr)
864 {
865 Logging::error(virtname(), "INTERNAL ERROR: FFmpeg_Transcoder::open_output_file()! buffer == nullptr in open_output_file()");
866 return AVERROR(EINVAL);
867 }
868
870
871 Logging::debug(virtname(), "Opening the output file.");
872
873 if (!stream_exists(m_in.m_audio.m_stream_idx) && m_current_format->video_codec() == AV_CODEC_ID_NONE)
874 {
875 Logging::error(virtname(), "Unable to transcode. The source contains no audio stream, but the target just supports audio.");
876 m_virtualfile->m_flags |= VIRTUALFLAG_HIDDEN; // Hide file from now on
877 return AVERROR(ENOENT); // Report file not found
878 }
879
880 if (!is_frameset())
881 {
882 // Not a frame set, open regular buffer
883 return open_output(buffer);
884 }
885 else
886 {
887 Logging::debug(virtname(), "Opening frame set type '%1'.", m_current_format->desttype().c_str());
888
889 // Open frame set buffer
890 return open_output_frame_set(buffer);
891 }
892}
893
894int FFmpeg_Transcoder::open_bestmatch_decoder(AVFormatContext *format_ctx, AVCodecContext **codec_ctx, int *stream_idx, AVMediaType type)
895{
896#if IF_DECLARED_CONST
897 const AVCodec *input_codec = nullptr;
898#else // !IF_DECLARED_CONST
899 AVCodec *input_codec = nullptr;
900#endif // !IF_DECLARED_CONST
901 int ret;
902
903 *codec_ctx = nullptr;
904 *stream_idx = INVALID_STREAM;
905
906 ret = av_find_best_stream(format_ctx, type, INVALID_STREAM, INVALID_STREAM, &input_codec, 0);
907 if (ret < 0)
908 {
909 if (ret != AVERROR_STREAM_NOT_FOUND) // Not an error
910 {
911 Logging::error(filename(), "Could not find a %1 stream in the input file (error '%2').", get_media_type_string(type), ffmpeg_geterror(ret).c_str());
912 }
913 return ret;
914 }
915
916 *stream_idx = ret;
917
918 return open_decoder(format_ctx, codec_ctx, *stream_idx, input_codec, type);
919}
920
921#if IF_DECLARED_CONST
922AVPixelFormat FFmpeg_Transcoder::get_hw_pix_fmt(const AVCodec *codec, AVHWDeviceType dev_type, bool use_device_ctx) const
923#else // !IF_DECLARED_CONST
924AVPixelFormat FFmpeg_Transcoder::get_hw_pix_fmt(AVCodec *codec, AVHWDeviceType dev_type, bool use_device_ctx) const
925#endif // !IF_DECLARED_CONST
926{
927 AVPixelFormat hw_pix_fmt = AV_PIX_FMT_NONE;
928
929 if (codec != nullptr && dev_type != AV_HWDEVICE_TYPE_NONE)
930 {
931 int method = use_device_ctx ? AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX : AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX;
932
933 for (int i = 0;; i++)
934 {
935 const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i);
936 if (!config)
937 {
938 Logging::error(av_codec_is_decoder(codec) ? filename() : virtname(), "%1 '%2' does not support device type %3.\n", av_codec_is_encoder(codec) ? "Encoder" : "Decoder", codec->name, hwdevice_get_type_name(dev_type));
939 break;
940 }
941
942 if ((config->methods & method) && (config->device_type == dev_type))
943 {
944 hw_pix_fmt = config->pix_fmt;
945 Logging::debug(av_codec_is_decoder(codec) ? filename() : virtname(), "%1 '%2' requests %3 for device type %4.\n", av_codec_is_encoder(codec) ? "Encoder" : "Decoder", codec->name, av_get_pix_fmt_name(hw_pix_fmt), hwdevice_get_type_name(dev_type));
946 break;
947 }
948 }
949 }
950
951 return hw_pix_fmt;
952}
953
954#if IF_DECLARED_CONST
955int FFmpeg_Transcoder::open_decoder(AVFormatContext *format_ctx, AVCodecContext **codec_ctx, int stream_idx, const AVCodec *input_codec, AVMediaType mediatype)
956#else // !IF_DECLARED_CONST
957int FFmpeg_Transcoder::open_decoder(AVFormatContext *format_ctx, AVCodecContext **codec_ctx, int stream_idx, AVCodec *input_codec, AVMediaType mediatype)
958#endif // !IF_DECLARED_CONST
959{
960 while (true)
961 {
962 AVCodecContext *input_codec_ctx = nullptr;
963 AVStream * input_stream = nullptr;
965 AVCodecID codec_id = AV_CODEC_ID_NONE;
966 int ret;
967
968 input_stream = format_ctx->streams[stream_idx];
969
970 // Init the decoders, with or without reference counting
971 // av_dict_set_with_check(opt.address(), "refcounted_frames", refcount ? "1" : "0", 0);
972
973 // allocate a new decoding context
974 input_codec_ctx = avcodec_alloc_context3(nullptr);
975 if (input_codec_ctx == nullptr)
976 {
977 Logging::error(filename(), "Decoding context could not be allocated.");
978 return AVERROR(ENOMEM);
979 }
980
981 // initialise the stream parameters with demuxer information
982 ret = avcodec_parameters_to_context(input_codec_ctx, input_stream->codecpar);
983 if (ret < 0)
984 {
985 return ret;
986 }
987
988 codec_id = input_stream->codecpar->codec_id;
989
990 if (params.m_hwaccel_dec_API != HWACCELAPI::NONE)
991 {
992 if (mediatype == AVMEDIA_TYPE_VIDEO)
993 {
994 if (check_hwaccel_dec_blocked(input_stream->codecpar->codec_id, input_stream->codecpar->profile))
995 {
996 const char *profile = ::avcodec_profile_name(codec_id, input_stream->codecpar->profile);
997 Logging::info(filename(), "Codec '%1' profile '%2' is blocked from hardware decoding. Reverting to software decoder.", ::get_codec_name(codec_id), profile != nullptr ? profile : "unknown");
998 m_hwaccel_dec_mode = HWACCELMODE::FALLBACK;
999 }
1000 }
1001
1002 if (mediatype == AVMEDIA_TYPE_VIDEO && m_hwaccel_dec_mode != HWACCELMODE::FALLBACK)
1003 {
1004 // Decide whether to use a hardware decoder
1005 // Check to see if decoder hardware acceleration is both requested and supported by codec.
1006 std::string hw_decoder_codec_name;
1007 if (!get_hw_decoder_name(input_codec_ctx->codec_id, &hw_decoder_codec_name))
1008 {
1009 m_dec_hw_pix_fmt = get_hw_pix_fmt(input_codec, params.m_hwaccel_dec_device_type, true);
1010
1011 m_hwaccel_enable_dec_buffering = (params.m_hwaccel_dec_device_type != AV_HWDEVICE_TYPE_NONE && m_dec_hw_pix_fmt != AV_PIX_FMT_NONE);
1012 //{
1013 // std::string fourcc2str;
1014 // fourcc_make_string(&fourcc2str, input_codec_ctx->codec_tag);
1015 // fprintf(stderr, "fourcc2str %s\n", fourcc2str.c_str());
1016 //}
1017 }
1018
1019 if (m_hwaccel_enable_dec_buffering)
1020 {
1021 // Hardware buffers available, enabling decoder hardware acceleration.
1022 Logging::trace(filename(), "Hardware decoder frame buffering %1 is enabled.", get_hwaccel_API_text(params.m_hwaccel_dec_API).c_str());
1023 ret = hwdevice_ctx_create(&m_hwaccel_dec_device_ctx, params.m_hwaccel_dec_device_type, params.m_hwaccel_dec_device);
1024 if (ret < 0)
1025 {
1026 Logging::error(filename(), "Failed to create a %1 device for decoding (error %2).", get_hwaccel_API_text(params.m_hwaccel_dec_API).c_str(), ffmpeg_geterror(ret).c_str());
1027 return ret;
1028 }
1029
1030 Logging::info(filename(), "Hardware decoder acceleration and frame buffering are active using codec '%1'.", (input_codec != nullptr) ? input_codec->name : "unknown");
1031
1032 m_hwaccel_dec_mode = HWACCELMODE::ENABLED; // Hardware acceleration active
1033 }
1034 else if (params.m_hwaccel_dec_device_type != AV_HWDEVICE_TYPE_NONE)
1035 {
1036 // No hardware acceleration, fallback to software,
1037 Logging::debug(filename(), "Hardware decoder frame buffering %1 not supported by codec '%2'. Falling back to software.", get_hwaccel_API_text(params.m_hwaccel_dec_API).c_str(), get_codec_name(input_codec_ctx->codec_id, true));
1038 }
1039 else if (!hw_decoder_codec_name.empty())
1040 {
1041 // No frame buffering (e.g. OpenMAX or MMAL), but hardware acceleration possible.
1042 // Open hw_decoder_codec_name codec here
1043 input_codec = avcodec_find_decoder_by_name(hw_decoder_codec_name.c_str());
1044
1045 if (input_codec == nullptr)
1046 {
1047 Logging::error(filename(), "Decoder '%1' could not be found.", hw_decoder_codec_name.c_str());
1048 return AVERROR(EINVAL);
1049 }
1050
1051 Logging::info(filename(), "Hardware decoder acceleration is active using codec '%1'.", input_codec->name);
1052
1053 m_hwaccel_dec_mode = HWACCELMODE::ENABLED; // Hardware acceleration active
1054 }
1055
1056 if (m_hwaccel_enable_dec_buffering)
1057 {
1058 ret = hwdevice_ctx_add_ref(input_codec_ctx);
1059 if (ret < 0)
1060 {
1061 return ret;
1062 }
1063 }
1064 }
1065 }
1066
1067 if (input_codec == nullptr)
1068 {
1069 // Find a decoder for the stream.
1070 input_codec = avcodec_find_decoder(codec_id);
1071
1072 if (input_codec == nullptr)
1073 {
1074 Logging::error(filename(), "Failed to find %1 input codec '%2'.", get_media_type_string(mediatype), avcodec_get_name(codec_id));
1075 return AVERROR(EINVAL);
1076 }
1077 }
1078
1079 input_codec_ctx->codec_id = input_codec->id;
1080
1081 //input_codec_ctx->time_base = input_stream->time_base;
1082
1083 ret = avcodec_open2(input_codec_ctx, input_codec, opt.address());
1084
1085 if (ret < 0)
1086 {
1087 if (m_hwaccel_dec_mode == HWACCELMODE::ENABLED)
1088 {
1089 Logging::info(filename(), "Unable to use %1 input codec '%2' with hardware acceleration. Falling back to software.", get_media_type_string(mediatype), avcodec_get_name(codec_id));
1090
1091 m_hwaccel_dec_mode = HWACCELMODE::FALLBACK;
1092 m_hwaccel_enable_dec_buffering = false;
1093 m_dec_hw_pix_fmt = AV_PIX_FMT_NONE;
1094
1095 // Free hardware device contexts if open
1096 hwdevice_ctx_free(&m_hwaccel_dec_device_ctx);
1097
1098 m_in.m_video.reset();
1099
1100 // Try again with a software decoder
1101 continue;
1102 }
1103
1104 Logging::error(filename(), "Failed to open %1 input codec for stream #%1 (error '%2').", get_media_type_string(mediatype), input_stream->index, ffmpeg_geterror(ret).c_str());
1105 return ret;
1106 }
1107
1108 Logging::debug(filename(), "Opened input codec for stream #%1: %2", input_stream->index, get_codec_name(codec_id, true));
1109
1110 *codec_ctx = input_codec_ctx;
1111
1112 return 0;
1113 };
1114}
1115
1117{
1118 const AVCodec * output_codec = nullptr;
1119 AVCodecContext *output_codec_ctx = nullptr;
1121 int ret = 0;
1122
1123 m_buffer = buffer;
1124 {
1125 std::lock_guard<std::recursive_mutex> lock_seek_to_fifo_mutex(m_seek_to_fifo_mutex);
1126 while (m_seek_to_fifo.size())
1127 {
1128 m_seek_to_fifo.pop();
1129 }
1130 }
1131 m_have_seeked = false;
1132
1133 output_codec = avcodec_find_encoder(m_current_format->video_codec());
1134 if (output_codec == nullptr)
1135 {
1136 Logging::error(virtname(), "Codec not found.");
1137 return AVERROR(EINVAL);
1138 }
1139
1140 output_codec_ctx = avcodec_alloc_context3(output_codec);
1141 if (output_codec_ctx == nullptr)
1142 {
1143 Logging::error(virtname(), "The video codec context could not be allocated.");
1144 return AVERROR(ENOMEM);
1145 }
1146
1147 output_codec_ctx->bit_rate = 400000;
1148 output_codec_ctx->width = m_in.m_video.m_codec_ctx->width;
1149 output_codec_ctx->height = m_in.m_video.m_codec_ctx->height;
1150 output_codec_ctx->time_base = {1, 25};
1151
1152 const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(m_in.m_video.m_codec_ctx->pix_fmt);
1153 int loss = 0;
1154
1155#if LAVC_USE_SUPPORTED_CFG
1156 {
1157 const enum AVPixelFormat *pix_list = nullptr;
1158 int npix = 0;
1159 int ret_cfg = avcodec_get_supported_config(output_codec_ctx, output_codec,
1160 AV_CODEC_CONFIG_PIX_FORMAT,
1161 0, (const void**)&pix_list, &npix);
1162 if (ret_cfg >= 0 && pix_list && npix > 0)
1163 {
1164 output_codec_ctx->pix_fmt = avcodec_find_best_pix_fmt_of_list(pix_list, m_in.m_video.m_codec_ctx->pix_fmt, (dst_desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? 1 : 0, &loss);
1165 }
1166 else
1167 {
1168 output_codec_ctx->pix_fmt = m_in.m_video.m_codec_ctx->pix_fmt;
1169 }
1170 }
1171#else
1172 output_codec_ctx->pix_fmt = avcodec_find_best_pix_fmt_of_list(output_codec->pix_fmts, m_in.m_video.m_codec_ctx->pix_fmt, (dst_desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? 1 : 0, &loss);
1173#endif
1174
1175 if (output_codec_ctx->pix_fmt == AV_PIX_FMT_NONE)
1176 {
1177 // No best match found, use default
1178 switch (m_current_format->video_codec())
1179 {
1180 case AV_CODEC_ID_MJPEG:
1181 {
1182 output_codec_ctx->pix_fmt = AV_PIX_FMT_YUVJ444P;
1183 break;
1184 }
1185 case AV_CODEC_ID_PNG:
1186 {
1187 output_codec_ctx->pix_fmt = AV_PIX_FMT_RGB24;
1188 break;
1189 }
1190 case AV_CODEC_ID_BMP:
1191 {
1192 output_codec_ctx->pix_fmt = AV_PIX_FMT_BGR24;
1193 break;
1194 }
1195 default:
1196 {
1197 break;
1198 }
1199 }
1200 Logging::debug(virtname(), "There was no best match output pixel format found, so we used the default: %1", get_pix_fmt_name(output_codec_ctx->pix_fmt).c_str());
1201 }
1202 else
1203 {
1204 Logging::debug(virtname(), "Output pixel format: %1", get_pix_fmt_name(output_codec_ctx->pix_fmt).c_str());
1205 }
1206
1207
1208 switch (m_current_format->video_codec())
1209 {
1210 case AV_CODEC_ID_MJPEG:
1211 {
1212 // set -strict -1 for JPG
1213 dict_set_with_check(opt.address(), "strict", "-1", 0);
1214
1215 // Allow the use of unoffical extensions
1216 output_codec_ctx->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
1217 break;
1218 }
1219 case AV_CODEC_ID_PNG:
1220 {
1221 output_codec_ctx->pix_fmt = AV_PIX_FMT_RGB24;
1222 break;
1223 }
1224 case AV_CODEC_ID_BMP:
1225 {
1226 output_codec_ctx->pix_fmt = AV_PIX_FMT_BGR24;
1227 break;
1228 }
1229 default:
1230 {
1231 break;
1232 }
1233 }
1234
1235 //codec_ctx->sample_aspect_ratio = frame->sample_aspect_ratio;
1236 //codec_ctx->sample_aspect_ratio = m_in.m_video.m_codec_ctx->sample_aspect_ratio;
1237
1238 ret = avcodec_open2(output_codec_ctx, output_codec, opt.address());
1239 if (ret < 0)
1240 {
1241 Logging::error(virtname(), "The image codec could not be opened.");
1242 return ret;
1243 }
1244
1245 // Initialise pixel format conversion and rescaling if necessary
1246 get_pix_formats(&m_in.m_pix_fmt, &m_out.m_pix_fmt, output_codec_ctx);
1247
1248 ret = init_rescaler(m_in.m_pix_fmt, m_in.m_video.m_stream->codecpar->width, m_in.m_video.m_stream->codecpar->height, m_out.m_pix_fmt, output_codec_ctx->width, output_codec_ctx->height);
1249 if (ret < 0)
1250 {
1251 return ret;
1252 }
1253
1255 {
1256 ret = init_deinterlace_filters(output_codec_ctx, m_in.m_pix_fmt, m_in.m_video.m_stream->avg_frame_rate, m_in.m_video.m_stream->time_base);
1257 if (ret < 0)
1258 {
1259 return ret;
1260 }
1261 }
1262
1263 m_out.m_video.set_codec_ctx(output_codec_ctx);
1265 m_out.m_video.m_stream = nullptr;
1266
1267 // No audio
1268 m_out.m_audio.set_codec_ctx(nullptr);
1270 m_out.m_audio.m_stream = nullptr;
1271
1272 // Open for read/write
1273 // Pre-allocate the predicted file size to reduce memory reallocations
1274 size_t buffsize = predicted_filesize() * video_frame_count();
1275
1276 if (!buffer->open_file(0, CACHE_FLAG_RW, buffsize))
1277 {
1278 return AVERROR(EPERM);
1279 }
1280
1281 return 0;
1282}
1283
1285{
1286 int ret = 0;
1287
1288 m_buffer = buffer;
1289 m_insert_keyframe = false;
1290
1291 if (!m_out.m_video_pts && is_hls())
1292 {
1293 const bool hls_segment_preselected = m_current_segment > 1;
1294
1295 if (!hls_segment_preselected)
1296 {
1298
1299 // The first output open is special: start_new_segment() has not run yet,
1300 // so a seek stacked before opening the output would otherwise not be
1301 // consumed until after segment 1 had already been opened and encoded.
1302 // Consume an initial HLS seek here and position the input before any
1303 // output segment is opened.
1304 uint32_t initial_seek_segment = 0;
1305 {
1306 std::lock_guard<std::recursive_mutex> lock_seek_to_fifo_mutex(m_seek_to_fifo_mutex);
1307 while (!m_seek_to_fifo.empty())
1308 {
1309 const uint32_t segment_no = m_seek_to_fifo.front();
1310 m_seek_to_fifo.pop();
1311
1312 if (segment_no > 1)
1313 {
1314 initial_seek_segment = segment_no;
1315 break;
1316 }
1317 }
1318 }
1319
1320 if (initial_seek_segment)
1321 {
1322 int ret = 0;
1323 const int64_t pos = (initial_seek_segment - 1) * params.m_segment_duration;
1324
1326 m_have_seeked = true;
1327
1328 Logging::info(virtname(), "Performing seek request to HLS segment no. %1.", initial_seek_segment);
1329
1331 {
1332 int64_t vstream_pts = ffmpeg_rescale_q(pos, av_get_time_base_q(), m_in.m_video.m_stream->time_base);
1333
1334 if (m_in.m_video.m_stream->start_time != AV_NOPTS_VALUE)
1335 {
1336 vstream_pts += m_in.m_video.m_stream->start_time;
1337 }
1338
1339 ret = av_seek_frame(m_in.m_format_ctx, m_in.m_video.m_stream_idx, vstream_pts, AVSEEK_FLAG_BACKWARD);
1340 }
1341 else if (stream_exists(m_in.m_audio.m_stream_idx) && m_in.m_audio.m_stream != nullptr)
1342 {
1343 int64_t astream_pts = ffmpeg_rescale_q(pos, av_get_time_base_q(), m_in.m_audio.m_stream->time_base);
1344
1345 if (m_in.m_audio.m_stream->start_time != AV_NOPTS_VALUE)
1346 {
1347 astream_pts += m_in.m_audio.m_stream->start_time;
1348 }
1349
1350 ret = av_seek_frame(m_in.m_format_ctx, m_in.m_audio.m_stream_idx, astream_pts, AVSEEK_FLAG_BACKWARD);
1351 }
1352
1353 if (ret < 0)
1354 {
1355 Logging::error(virtname(), "Seek failed on input file (error '%1').", ffmpeg_geterror(ret).c_str());
1356 return ret;
1357 }
1358
1359 flush_buffers();
1361
1362 m_current_segment = initial_seek_segment;
1363 }
1364 }
1365
1366 Logging::info(virtname(), "Starting HLS segment no. %1 of %2.", m_current_segment, m_virtualfile->get_segment_count());
1367
1368 // HLS uses one physical cache file per segment. Select the cache file
1369 // for the current segment before opening the output format and before
1370 // avformat_write_header()/process_output() can emit any data. This is
1371 // especially important for repair runs after a seek, where the first
1372 // segment written may be segment 2 or later rather than segment 1.
1373 const uint32_t segment_count = m_virtualfile != nullptr ? m_virtualfile->get_segment_count() : 0;
1375 {
1376 return AVERROR(EINVAL);
1377 }
1378
1379 size_t segment_buffsize = m_virtualfile->m_predicted_size / segment_count;
1380 if (!segment_buffsize)
1381 {
1382 segment_buffsize = static_cast<size_t>(sysconf(_SC_PAGESIZE));
1383 }
1384
1385 if (!buffer->set_segment(m_current_segment, segment_buffsize))
1386 {
1387 return AVERROR(errno);
1388 }
1389 }
1390
1391 while (true)
1392 {
1393 // Open the output file for writing. If buffer == nullptr continue using existing buffer.
1394 ret = open_output_filestreams(buffer);
1395 if (ret)
1396 {
1398 {
1399 Logging::info(virtname(), "Unable to use output codec '%1' with hardware acceleration. Falling back to software.", avcodec_get_name(m_current_format->video_codec()));
1400
1403 m_enc_hw_pix_fmt = AV_PIX_FMT_NONE;
1404
1405 // Free hardware device contexts if open
1407
1409
1410 // Try again with a software decoder
1411 continue;
1412 }
1413 return ret;
1414 }
1415 break;
1416 }
1417
1419 {
1421
1422 if (m_out.m_audio.m_codec_ctx != nullptr)
1423 {
1424 // If not just copying the stream, initialise the audio FIFO buffer to store audio samples to be encoded.
1425 ret = init_audio_fifo();
1426 if (ret)
1427 {
1428 return ret;
1429 }
1430 }
1431 }
1432
1434 {
1436 }
1437
1438 for (const auto & [key, value] : m_out.m_subtitle)
1439 {
1440 subtitle_info(true, m_out.m_format_ctx, value.m_stream);
1441 }
1442
1443 if (!is_hls())
1444 {
1445 // Open regular output files for read/write.
1446 // HLS output uses one cache file per segment; the active segment was
1447 // already selected above with Buffer::set_segment(). Opening segment
1448 // 0 here would switch the active cache file back to the first segment
1449 // and make repair/seek runs append the following output to 000001.ts.
1450 size_t buffsize = predicted_filesize();
1451 if (!buffer->open_file(0, CACHE_FLAG_RW, buffsize))
1452 {
1453 return AVERROR(EPERM);
1454 }
1455 }
1456
1457 ret = process_output();
1458 if (ret)
1459 {
1460 return ret;
1461 }
1462
1463 // process_output() calls avformat_write_header which feels free to change the stream time bases sometimes.
1464 // This means we have to do the following calculations here to use the correct values, otherwise this can cause
1465 // a lot of havoc.
1466
1467 if (m_in.m_audio.m_stream != nullptr && m_out.m_audio.m_stream != nullptr && m_in.m_audio.m_stream->start_time != AV_NOPTS_VALUE)
1468 {
1472 }
1473 else
1474 {
1478 {
1479 m_out.m_audio.m_stream->start_time = AV_NOPTS_VALUE;
1480 }
1481 }
1482
1483 if (m_in.m_video.m_stream != nullptr && m_out.m_video.m_stream != nullptr && m_in.m_video.m_stream->start_time != AV_NOPTS_VALUE)
1484 {
1488 }
1489 else
1490 {
1494 {
1495 m_out.m_video.m_stream->start_time = AV_NOPTS_VALUE;
1496 }
1497 }
1498
1499 for (auto & [key, value] : m_out.m_subtitle)
1500 {
1502 if (out_streamref != nullptr)
1503 {
1504 value.m_start_time = value.m_stream->start_time;
1505 out_streamref->m_start_time = ffmpeg_rescale_q_rnd(value.m_stream->start_time, value.m_stream->time_base, out_streamref->m_stream->time_base);
1506 out_streamref->m_stream->start_time = out_streamref->m_start_time;
1507 }
1508 }
1509
1512 m_out.m_last_mux_dts = AV_NOPTS_VALUE;
1513
1514 return 0;
1515}
1516
1518{
1519 // Process metadata. The decoder will call the encoder to set appropriate
1520 // tag values for the output file.
1521 int ret = process_metadata();
1522 if (ret)
1523 {
1524 return ret;
1525 }
1526
1527 // Write the header of the output file container.
1529 if (ret)
1530 {
1531 return ret;
1532 }
1533
1534 // Process album arts: copy all from source file to target.
1535 return process_albumarts();
1536}
1537
1538bool FFmpeg_Transcoder::get_output_sample_rate(int input_sample_rate, int max_sample_rate, int *output_sample_rate /*= nullptr*/)
1539{
1540 if (input_sample_rate > max_sample_rate)
1541 {
1542 if (output_sample_rate != nullptr)
1543 {
1544 *output_sample_rate = max_sample_rate;
1545 }
1546 return true;
1547 }
1548 else
1549 {
1550 if (output_sample_rate != nullptr)
1551 {
1552 *output_sample_rate = input_sample_rate;
1553 }
1554 return false;
1555 }
1556}
1557
1558bool FFmpeg_Transcoder::get_output_bit_rate(BITRATE input_bit_rate, BITRATE max_bit_rate, BITRATE * output_bit_rate /*= nullptr*/)
1559{
1560 if (!input_bit_rate || input_bit_rate > max_bit_rate)
1561 {
1562 if (output_bit_rate != nullptr)
1563 {
1564 *output_bit_rate = max_bit_rate;
1565 }
1566 return true;
1567 }
1568 else
1569 {
1570 if (output_bit_rate != nullptr)
1571 {
1572 *output_bit_rate = input_bit_rate;
1573 }
1574 return false;
1575 }
1576}
1577
1578bool FFmpeg_Transcoder::get_aspect_ratio(int width, int height, const AVRational & sar, AVRational *ar) const
1579{
1580 // Try to determine display aspect ratio
1581 AVRational dar;
1582
1583 ::av_reduce(&dar.num, &dar.den,
1584 static_cast<int64_t>(width) * sar.num,
1585 static_cast<int64_t>(height) * sar.den,
1586 1024 * 1024);
1587
1588 ar->num = ar->den = 0;
1589
1590 if (dar.num && dar.den)
1591 {
1592 *ar = dar;
1593 }
1594
1595 // If that fails, try sample aspect ratio instead
1596 if (!ar->den && sar.num != 0 && sar.den != 0)
1597 {
1598 *ar = sar;
1599 }
1600
1601 // If even that fails, try to use video size
1602 if (!ar->den && height)
1603 {
1604 ar->num = width;
1605 ar->den = height;
1606 }
1607
1608 if (!ar->den)
1609 {
1610 // Return false if all above failed
1611 return false;
1612 }
1613
1614 ::av_reduce(&ar->num, &ar->den,
1615 ar->num,
1616 ar->den,
1617 1024 * 1024);
1618
1619 return true;
1620}
1621
1622bool FFmpeg_Transcoder::get_video_size(int *output_width, int *output_height) const
1623{
1625 {
1626 // No options, leave as is
1627 return false;
1628 }
1629
1630 int input_width = m_in.m_video.m_stream->codecpar->width;
1631 int input_height = m_in.m_video.m_stream->codecpar->height;
1632 AVRational sar = m_in.m_video.m_stream->codecpar->sample_aspect_ratio;
1633
1635 {
1636 // Both width/source set. May look strange, but this is an order...
1637 *output_width = params.m_videowidth;
1638 *output_height = params.m_videoheight;
1639 }
1640 else if (params.m_videowidth)
1641 {
1642 // Only video width
1643 AVRational ar;
1644
1645 *output_width = params.m_videowidth;
1646
1647 if (!get_aspect_ratio(input_width, input_height, sar, &ar))
1648 {
1649 *output_height = input_height;
1650 }
1651 else
1652 {
1653 *output_height = static_cast<int>(params.m_videowidth / av_q2d(ar));
1654 *output_height &= ~(static_cast<int>(0x1)); // height must be multiple of 2
1655 }
1656 }
1657 else //if (params.m_videoheight)
1658 {
1659 // Only video height
1660 AVRational ar;
1661
1662 if (!get_aspect_ratio(input_width, input_height, sar, &ar))
1663 {
1664 *output_width = input_width;
1665 }
1666 else
1667 {
1668 *output_width = static_cast<int>(params.m_videoheight / av_q2d(ar));
1669 *output_width &= ~(static_cast<int>(0x1)); // width must be multiple of 2
1670 }
1671 *output_height = params.m_videoheight;
1672 }
1673
1674 return (input_width > *output_width || input_height > *output_height);
1675}
1676
1677int FFmpeg_Transcoder::update_codec(void *opt, const PROFILE_OPTION_VEC& profile_option_vec) const
1678{
1679 int ret = 0;
1680
1681 for (const PROFILE_OPTION & profile_option : profile_option_vec)
1682 {
1683 if ((m_hwaccel_enable_enc_buffering && profile_option.m_options & OPT_SW_ONLY) || (!m_hwaccel_enable_enc_buffering && profile_option.m_options & OPT_HW_ONLY))
1684 {
1685 continue;
1686 }
1687
1688 Logging::trace(virtname(), "Profile codec option -%1%2%3.", profile_option.m_key, *profile_option.m_value ? " " : "", profile_option.m_value);
1689
1690 ret = opt_set_with_check(opt, profile_option.m_key, profile_option.m_value, profile_option.m_flags, virtname());
1691 if (ret < 0)
1692 {
1693 break;
1694 }
1695 }
1696 return ret;
1697}
1698
1699int FFmpeg_Transcoder::prepare_codec(void *opt, FILETYPE filetype) const
1700{
1701 int ret = 0;
1702
1703 for (const PROFILE_LIST & profile : m_profile)
1704 {
1705 if (profile.m_filetype == filetype)
1706 {
1707 ret = AVERROR_OPTION_NOT_FOUND; // Once we found the file type, we also need to find the profile. Otherwise we have an invalid command line option.
1708 if (profile.m_profile == params.m_profile)
1709 {
1710 ret = update_codec(opt, profile.m_option_codec);
1711 break;
1712 }
1713 }
1714 }
1715
1716 return ret;
1717}
1718
1719int FFmpeg_Transcoder::init_rescaler(AVPixelFormat in_pix_fmt, int in_width, int in_height, AVPixelFormat out_pix_fmt, int out_width, int out_height)
1720{
1721 if (in_pix_fmt != out_pix_fmt || in_width != out_width || in_height != out_height)
1722 {
1723 // Rescale image if required
1724 if (in_pix_fmt != out_pix_fmt)
1725 {
1726 Logging::trace(virtname(), "Initialising pixel format conversion from %1 to %2.", get_pix_fmt_name(in_pix_fmt).c_str(), get_pix_fmt_name(out_pix_fmt).c_str());
1727 }
1728
1729 if (in_width != out_width || in_height != out_height)
1730 {
1731 Logging::debug(virtname(), "Rescaling video size from %1:%2 to %3:%4.",
1732 in_width, in_height,
1733 out_width, out_height);
1734 }
1735
1736 m_sws_ctx.reset(sws_getContext(
1737 // Source settings
1738 in_width, // width
1739 in_height, // height
1740 in_pix_fmt, // format
1741 // Target settings
1742 out_width, // width
1743 out_height, // height
1744 out_pix_fmt, // format
1745 SWS_FAST_BILINEAR, nullptr, nullptr, nullptr)); // Maybe SWS_LANCZOS | SWS_ACCURATE_RND
1746 if (m_sws_ctx == nullptr)
1747 {
1748 Logging::error(virtname(), "Could not allocate a scaling/conversion context.");
1749 return AVERROR(ENOMEM);
1750 }
1751 }
1752
1753 return 0;
1754}
1755
1756int FFmpeg_Transcoder::add_stream(AVCodecID codec_id)
1757{
1758 AVCodecContext *output_codec_ctx = nullptr;
1759 AVStream * output_stream = nullptr;
1760#if IF_DECLARED_CONST
1761 const AVCodec * output_codec = nullptr;
1762#else // !IF_DECLARED_CONST
1763 AVCodec * output_codec = nullptr;
1764#endif // !IF_DECLARED_CONST
1766 int ret;
1767
1768 std::string codec_name;
1769
1770 if (get_hw_encoder_name(codec_id, &codec_name) || m_hwaccel_enc_mode == HWACCELMODE::FALLBACK)
1771 {
1772 // find the encoder
1773 output_codec = avcodec_find_encoder(codec_id);
1774
1775 if (output_codec == nullptr)
1776 {
1777 Logging::error(virtname(), "Could not find encoder '%1'.", avcodec_get_name(codec_id));
1778 return AVERROR(EINVAL);
1779 }
1780 }
1781 else
1782 {
1783 output_codec = avcodec_find_encoder_by_name(codec_name.c_str());
1784
1785 if (output_codec == nullptr)
1786 {
1787 Logging::error(virtname(), "Could not find encoder '%1'.", codec_name.c_str());
1788 return AVERROR(EINVAL);
1789 }
1790
1791 //Logging::info(virtname(), "Hardware encoder acceleration active with codec '%1'.", output_codec->name);
1792
1794 }
1795
1796 output_stream = avformat_new_stream(m_out.m_format_ctx, output_codec);
1797 if (output_stream == nullptr)
1798 {
1799 Logging::error(virtname(), "Could not allocate stream for encoder '%1'.", avcodec_get_name(codec_id));
1800 return AVERROR(ENOMEM);
1801 }
1802 output_stream->id = static_cast<int>(m_out.m_format_ctx->nb_streams - 1);
1803
1804 output_codec_ctx = avcodec_alloc_context3(output_codec);
1805 if (output_codec_ctx == nullptr)
1806 {
1807 Logging::error(virtname(), "Could not allocate an encoding context.");
1808 return AVERROR(ENOMEM);
1809 }
1810
1811 switch (output_codec->type)
1812 {
1813 case AVMEDIA_TYPE_AUDIO:
1814 {
1815 BITRATE orig_bit_rate;
1816 int orig_sample_rate;
1817
1818 // Set the basic encoder parameters
1819 orig_bit_rate = (m_in.m_audio.m_stream->codecpar->bit_rate != 0) ? m_in.m_audio.m_stream->codecpar->bit_rate : m_in.m_format_ctx->bit_rate;
1820 if (get_output_bit_rate(orig_bit_rate, params.m_audiobitrate, &output_codec_ctx->bit_rate))
1821 {
1822 // Limit bit rate
1823 Logging::trace(virtname(), "Limiting audio bit rate from %1 to %2.",
1824 format_bitrate(orig_bit_rate).c_str(),
1825 format_bitrate(output_codec_ctx->bit_rate).c_str());
1826 }
1827
1829 {
1830 Logging::trace(virtname(), "Limiting audio channels from %1 to %2.",
1833 set_channels(output_codec_ctx, params.m_audiochannels);
1834 }
1835 else
1836 {
1837 set_channels(output_codec_ctx, m_in.m_audio.m_codec_ctx.get());
1838 }
1839
1840#if LAVU_DEP_OLD_CHANNEL_LAYOUT
1841 av_channel_layout_default(&output_codec_ctx->ch_layout, output_codec_ctx->ch_layout.nb_channels);
1842#else // !LAVU_DEP_OLD_CHANNEL_LAYOUT
1843 output_codec_ctx->channel_layout = static_cast<uint64_t>(av_get_default_channel_layout(output_codec_ctx->channels));
1844#endif // !LAVU_DEP_OLD_CHANNEL_LAYOUT
1845
1846 output_codec_ctx->sample_rate = m_in.m_audio.m_codec_ctx->sample_rate;
1847 orig_sample_rate = m_in.m_audio.m_codec_ctx->sample_rate;
1848 if (get_output_sample_rate(m_in.m_audio.m_stream->codecpar->sample_rate, params.m_audiosamplerate, &output_codec_ctx->sample_rate))
1849 {
1850 // Limit sample rate
1851 Logging::trace(virtname(), "Limiting audio sample rate from %1 to %2.",
1852 format_samplerate(orig_sample_rate).c_str(),
1853 format_samplerate(output_codec_ctx->sample_rate).c_str());
1854 orig_sample_rate = output_codec_ctx->sample_rate;
1855 }
1856
1857#if LAVC_USE_SUPPORTED_CFG
1858 {
1859 const int *supported_samplerates = nullptr;
1860 int num_samplerates = 0;
1861 int ret_cfg = avcodec_get_supported_config(output_codec_ctx, output_codec,
1862 AV_CODEC_CONFIG_SAMPLE_RATE,
1863 0, (const void**)&supported_samplerates,
1864 &num_samplerates);
1865 if (ret_cfg >= 0 && supported_samplerates && num_samplerates > 0)
1866 {
1867 bool exact_match = false;
1868 for (int n = 0; n < num_samplerates; n++)
1869 {
1870 if (supported_samplerates[n] == output_codec_ctx->sample_rate)
1871 {
1872 exact_match = true;
1873 break;
1874 }
1875 }
1876 if (!exact_match)
1877 {
1878 int min_samplerate = 0, max_samplerate = INT_MAX;
1879 for (int n = 0; n < num_samplerates; n++)
1880 {
1881 int s = supported_samplerates[n];
1882 if (min_samplerate <= s && output_codec_ctx->sample_rate >= s)
1883 min_samplerate = s;
1884 }
1885
1886 for (int n = 0; n < num_samplerates; n++)
1887 {
1888 int s = supported_samplerates[n];
1889 if (max_samplerate >= s && output_codec_ctx->sample_rate <= s)
1890 max_samplerate = s;
1891 }
1892
1893 if (min_samplerate != 0 && max_samplerate != INT_MAX)
1894 {
1895 if (output_codec_ctx->sample_rate - min_samplerate < max_samplerate - output_codec_ctx->sample_rate)
1896 output_codec_ctx->sample_rate = min_samplerate;
1897 else
1898 output_codec_ctx->sample_rate = max_samplerate;
1899 }
1900 else if (min_samplerate != 0)
1901 {
1902 output_codec_ctx->sample_rate = min_samplerate;
1903 }
1904 else if (max_samplerate != INT_MAX)
1905 {
1906 output_codec_ctx->sample_rate = max_samplerate;
1907 }
1908 else
1909 {
1910 for (int n = 0; n < num_samplerates; n++)
1911 if (supported_samplerates[n] == 48000)
1912 {
1913 output_codec_ctx->sample_rate = 48000;
1914 break;
1915 }
1916
1917 if (output_codec_ctx->sample_rate <= 0)
1918 output_codec_ctx->sample_rate = supported_samplerates[0];
1919 }
1920 }
1921 }
1922 }
1923#else
1924 if (output_codec->supported_samplerates != nullptr)
1925 {
1926 // Go through supported sample rates and adjust if necessary
1927 bool supported = false;
1928
1929 for (int n = 0; output_codec->supported_samplerates[n] != 0; n++)
1930 {
1931 if (output_codec->supported_samplerates[n] == output_codec_ctx->sample_rate)
1932 {
1933 // Is supported
1934 supported = true;
1935 break;
1936 }
1937 }
1938
1939 if (!supported)
1940 {
1941 int min_samplerate = 0;
1942 int max_samplerate = INT_MAX;
1943
1944 // Find next lower sample rate in probably unsorted list
1945 for (int n = 0; output_codec->supported_samplerates[n] != 0; n++)
1946 {
1947 if (min_samplerate <= output_codec->supported_samplerates[n] && output_codec_ctx->sample_rate >= output_codec->supported_samplerates[n])
1948 {
1949 min_samplerate = output_codec->supported_samplerates[n];
1950 }
1951 }
1952
1953 // Find next higher sample rate in probably unsorted list
1954 for (int n = 0; output_codec->supported_samplerates[n] != 0; n++)
1955 {
1956 if (max_samplerate >= output_codec->supported_samplerates[n] && output_codec_ctx->sample_rate <= output_codec->supported_samplerates[n])
1957 {
1958 max_samplerate = output_codec->supported_samplerates[n];
1959 }
1960 }
1961
1962 if (min_samplerate != 0 && max_samplerate != INT_MAX)
1963 {
1964 // set to nearest value
1965 if (output_codec_ctx->sample_rate - min_samplerate < max_samplerate - output_codec_ctx->sample_rate)
1966 {
1967 output_codec_ctx->sample_rate = min_samplerate;
1968 }
1969 else
1970 {
1971 output_codec_ctx->sample_rate = max_samplerate;
1972 }
1973 }
1974 else if (min_samplerate != 0)
1975 {
1976 // No higher sample rate, use next lower
1977 output_codec_ctx->sample_rate = min_samplerate;
1978 }
1979 else if (max_samplerate != INT_MAX)
1980 {
1981 // No lower sample rate, use higher lower
1982 output_codec_ctx->sample_rate = max_samplerate;
1983 }
1984 else
1985 {
1986 // Should never happen... There must at least be one.
1987 Logging::error(virtname(), "The codec does not support an audio sample rate of %1.", format_samplerate(output_codec_ctx->sample_rate).c_str());
1988 return AVERROR(EINVAL);
1989 }
1990
1991 Logging::debug(virtname(), "Because the requested value is not supported by codec, the audio sample rate was changed from %1 to %2.",
1992 format_samplerate(orig_sample_rate).c_str(),
1993 format_samplerate(output_codec_ctx->sample_rate).c_str());
1994 }
1995 }
1996#endif
1997
1998 // If sample format not pre-defined (not AV_SAMPLE_FMT_NONE), use input file setting.
1999 AVSampleFormat in_sample_format = (m_current_format->sample_format() == AV_SAMPLE_FMT_NONE) ? m_in.m_audio.m_codec_ctx->sample_fmt : m_current_format->sample_format();
2000#if LAVC_USE_SUPPORTED_CFG
2001 {
2002 // Query supported sample formats via the new API
2003 const enum AVSampleFormat *sample_fmts = nullptr;
2004 int num_fmts = 0;
2005 int ret_cfg = avcodec_get_supported_config(output_codec_ctx, output_codec,
2006 AV_CODEC_CONFIG_SAMPLE_FORMAT,
2007 0, (const void**)&sample_fmts,
2008 &num_fmts);
2009 if (ret_cfg >= 0 && sample_fmts && num_fmts > 0)
2010 {
2011 AVSampleFormat input_fmt_planar = av_get_planar_sample_fmt(in_sample_format);
2012 for (int i = 0; i < num_fmts; i++)
2013 {
2014 AVSampleFormat output_fmt_planar = av_get_planar_sample_fmt(sample_fmts[i]);
2015 if (sample_fmts[i] == in_sample_format ||
2016 (input_fmt_planar != AV_SAMPLE_FMT_NONE && input_fmt_planar == output_fmt_planar))
2017 {
2018 output_codec_ctx->sample_fmt = sample_fmts[i];
2019 break;
2020 }
2021 }
2022 if (output_codec_ctx->sample_fmt == AV_SAMPLE_FMT_NONE)
2023 {
2024 // Fallback: first supported format
2025 output_codec_ctx->sample_fmt = sample_fmts[0];
2026 }
2027 }
2028 else
2029 {
2030 // If supported sample formats are unknown simply take input format
2031 output_codec_ctx->sample_fmt = in_sample_format;
2032 }
2033 }
2034#else
2035 if (output_codec->sample_fmts != nullptr)
2036 {
2037 // Check if input sample format is supported and if so, use it (avoiding resampling)
2038 AVSampleFormat input_fmt_planar = av_get_planar_sample_fmt(in_sample_format);
2039
2040 output_codec_ctx->sample_fmt = AV_SAMPLE_FMT_NONE;
2041
2042 for (const AVSampleFormat *sample_fmt = output_codec->sample_fmts; *sample_fmt != -1; sample_fmt++)
2043 {
2044 AVSampleFormat output_fmt_planar = av_get_planar_sample_fmt(*sample_fmt);
2045
2046 if (*sample_fmt == in_sample_format ||
2047 (input_fmt_planar != AV_SAMPLE_FMT_NONE &&
2048 input_fmt_planar == output_fmt_planar))
2049 {
2050 output_codec_ctx->sample_fmt = *sample_fmt;
2051 break;
2052 }
2053 }
2054
2055 // If none of the supported formats match use the first supported
2056 if (output_codec_ctx->sample_fmt == AV_SAMPLE_FMT_NONE)
2057 {
2058 output_codec_ctx->sample_fmt = output_codec->sample_fmts[0];
2059 }
2060 }
2061 else
2062 {
2063 // If supported sample formats are unknown simply take input format and cross our fingers it'll work...
2064 output_codec_ctx->sample_fmt = in_sample_format;
2065 }
2066#endif
2067 // Set the sample rate for the container.
2068 output_stream->time_base.den = output_codec_ctx->sample_rate;
2069 output_stream->time_base.num = 1;
2070 output_codec_ctx->time_base = output_stream->time_base;
2071
2072 // set -strict -2 for aac (required for FFmpeg 2)
2073 dict_set_with_check(opt.address(), "strict", "-2", 0);
2074
2075 // Allow the use of the experimental AAC encoder
2076 output_codec_ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
2077
2078 // Set duration as hint for muxer
2079 if (m_in.m_audio.m_stream->duration != AV_NOPTS_VALUE)
2080 {
2081 output_stream->duration = ffmpeg_rescale_q(m_in.m_audio.m_stream->duration, m_in.m_audio.m_stream->time_base, output_stream->time_base);
2082 }
2083 else if (m_in.m_format_ctx->duration != AV_NOPTS_VALUE)
2084 {
2085 output_stream->duration = ffmpeg_rescale_q(m_in.m_format_ctx->duration, av_get_time_base_q(), output_stream->time_base);
2086 }
2087
2088 //av_dict_set_int(&output_stream->metadata, "DURATION", output_stream->duration, AV_DICT_IGNORE_SUFFIX);
2089
2090 // Save the encoder context for easier access later.
2091 m_out.m_audio.set_codec_ctx(output_codec_ctx);
2092 // Save the stream index
2093 m_out.m_audio.m_stream_idx = output_stream->index;
2094 // Save output audio stream for faster reference
2095 m_out.m_audio.m_stream = output_stream;
2096
2097 // Update input to output stream map, this is rather boring because currently we only have a single audio stream
2099 break;
2100 }
2101 case AVMEDIA_TYPE_VIDEO:
2102 {
2103 BITRATE orig_bit_rate;
2104
2106 {
2107 Logging::debug(virtname(), "Hardware encoder init: Creating a new hardware frame context for the encoder.", get_hwaccel_API_text(params.m_hwaccel_enc_API).c_str());
2108
2110
2111 ret = hwframe_ctx_set(output_codec_ctx, m_in.m_video.m_codec_ctx.get(), m_hwaccel_enc_device_ctx);
2112 if (ret < 0)
2113 {
2114 return ret;
2115 }
2116 }
2117
2118 output_codec_ctx->codec_id = codec_id;
2119
2120 // Set the basic encoder parameters
2121 orig_bit_rate = (m_in.m_video.m_stream->codecpar->bit_rate != 0) ? m_in.m_video.m_stream->codecpar->bit_rate : m_in.m_format_ctx->bit_rate;
2122 if (get_output_bit_rate(orig_bit_rate, params.m_videobitrate, &output_codec_ctx->bit_rate))
2123 {
2124 // Limit sample rate
2125 Logging::trace(virtname(), "Limiting video bit rate from %1 to %2.",
2126 format_bitrate(orig_bit_rate).c_str(),
2127 format_bitrate(output_codec_ctx->bit_rate).c_str());
2128 }
2129
2130 // output_codec_ctx->rc_min_rate = output_codec_ctx->bit_rate * 75 / 100;
2131 // output_codec_ctx->rc_max_rate = output_codec_ctx->bit_rate * 125 / 100;
2132
2133 // output_codec_ctx->qmin = 1;
2134 // output_codec_ctx->qmax = 31;
2135
2136 int width = 0;
2137 int height = 0;
2138 if (get_video_size(&width, &height))
2139 {
2140 Logging::trace(virtname(), "Changing video size from %1/%2 to %3/%4.", output_codec_ctx->width, output_codec_ctx->height, width, height);
2141 output_codec_ctx->width = width;
2142 output_codec_ctx->height = height;
2143 }
2144 else
2145 {
2146 output_codec_ctx->width = m_in.m_video.m_stream->codecpar->width;
2147 output_codec_ctx->height = m_in.m_video.m_stream->codecpar->height;
2148 }
2149
2150 video_stream_setup(output_codec_ctx, output_stream, m_in.m_video.m_codec_ctx.get(), m_in.m_video.m_stream->avg_frame_rate, m_enc_hw_pix_fmt);
2151
2152 if (!m_hwaccel_enable_enc_buffering && output_codec_ctx->codec_id == AV_CODEC_ID_H264 && m_out.m_filetype == FILETYPE::HLS && output_codec_ctx->pix_fmt != AV_PIX_FMT_YUV420P)
2153 {
2154 Logging::info(virtname(), "Forcing HLS/H.264 output pixel format from %1 to yuv420p for browser-compatible 8-bit output.", get_pix_fmt_name(output_codec_ctx->pix_fmt).c_str());
2155 output_codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
2156 }
2157
2158 AVRational sample_aspect_ratio = m_in.m_video.m_stream->codecpar->sample_aspect_ratio;
2159
2160 if (output_codec_ctx->codec_id != AV_CODEC_ID_VP9 && m_out.m_filetype != FILETYPE::MKV)
2161 {
2162 output_codec_ctx->sample_aspect_ratio = sample_aspect_ratio;
2163 output_stream->codecpar->sample_aspect_ratio = sample_aspect_ratio;
2164 }
2165
2166 else
2167 {
2168 // WebM and MKV do not respect the aspect ratio and always use 1:1 so we need to rescale "manually".
2175 output_codec_ctx->sample_aspect_ratio = { 1, 1 };
2176 output_stream->codecpar->sample_aspect_ratio = { 1, 1 };
2177
2178 // Make sure we do not zero width
2179 if (sample_aspect_ratio.num && sample_aspect_ratio.den)
2180 {
2181 output_codec_ctx->width = output_codec_ctx->width * sample_aspect_ratio.num / sample_aspect_ratio.den;
2182 }
2183 //output_codec_ctx->height *= sample_aspect_ratio.den;
2184 }
2185
2186 // Set up optimisations
2187 switch (output_codec_ctx->codec_id)
2188 {
2189 case AV_CODEC_ID_H264:
2190 {
2191 ret = prepare_codec(output_codec_ctx->priv_data, m_out.m_filetype);
2192 if (ret < 0)
2193 {
2194 Logging::error(virtname(), "Could not set profile for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2195 return ret;
2196 }
2197
2199 {
2200 // For hardware encoding only
2201
2202 // Defaults to 20. Set to 40 to create slightly smaller results (the bigger, the smaller the files).
2203 // Values seem to range between 1 and 51.
2204 // Must be non-zero, otherwise hardware encoding my fail with:
2205 // "Driver does not support any RC mode compatible with selected options (supported modes: CQP)."
2206 output_codec_ctx->global_quality = 40;
2207 }
2208
2209 //#define EXPERIMENTAL
2210#ifdef EXPERIMENTAL
2212 {
2213 // For hardware encoding only
2214#if 0
2215 // From libavcodec/vaapi_encode.c:
2216 //
2217 // Rate control mode selection:
2218 // * If the user has set a mode explicitly with the rc_mode option,
2219 // use it and fail if it is not available.
2220 // * If an explicit QP option has been set, use CQP.
2221 // * If the codec is CQ-only, use CQP.
2222 // * If the QSCALE avcodec option is set, use CQP.
2223 // * If bitrate and quality are both set, try QVBR.
2224 // * If quality is set, try ICQ, then CQP.
2225 // * If bitrate and maxrate are set and have the same value, try CBR.
2226 // * If a bitrate is set, try AVBR, then VBR, then CBR.
2227 // * If no bitrate is set, try ICQ, then CQP.
2228 ret = av_opt_set(output_codec_ctx->priv_data, "rc_mode", "CQP", AV_OPT_SEARCH_CHILDREN);
2229 if (ret < 0)
2230 {
2231 Logging::error(virtname(), "Could not set 'rc_mode=CQP' for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2232 return ret;
2233 }
2234
2235 // The range of the CRF scale is 0–51, where 0 is lossless (for 8 bit only, for 10 bit use -qp 0),
2236 // 23 is the default, and 51 is worst quality possible. A lower value generally leads to higher
2237 // quality, and a subjectively sane range is 17–28. Consider 17 or 18 to be visually lossless or
2238 // nearly so; it should look the same or nearly the same as the input but it isn't technically lossless.
2239 // See https://trac.ffmpeg.org/wiki/Encode/H.264
2240 ret = av_opt_set(output_codec_ctx->priv_data, "qp", "30", AV_OPT_SEARCH_CHILDREN);
2241 if (ret < 0)
2242 {
2243 Logging::error(virtname(), "Could not set 'qp' for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2244 return ret;
2245 }
2246#endif
2247 }
2248 else
2249 {
2250 // Software encoding
2251#if 0
2252 // Affects hard- and software encoding
2253 //
2254 // The range of the CRF scale is 0–51, where 0 is lossless (for 8 bit only, for 10 bit use -qp 0),
2255 // 23 is the default, and 51 is worst quality possible. A lower value generally leads to higher
2256 // quality, and a subjectively sane range is 17–28. Consider 17 or 18 to be visually lossless or
2257 // nearly so; it should look the same or nearly the same as the input but it isn't technically lossless.
2258 // See https://trac.ffmpeg.org/wiki/Encode/H.264
2259 ret = av_opt_set(output_codec_ctx->priv_data, "qp", "30", AV_OPT_SEARCH_CHILDREN);
2260 if (ret < 0)
2261 {
2262 Logging::error(virtname(), "Could not set 'qp' for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2263 return ret;
2264 }
2265#endif
2266
2267#if 0
2268 // Set constant rate factor to avoid getting huge result files
2269 // The default is 23, but values between 30..40 create properly sized results.
2270 // Possible values are 0 (lossless) to 51 (very small but ugly results).
2271 ret = av_opt_set(output_codec_ctx->priv_data, "crf", "30", AV_OPT_SEARCH_CHILDREN);
2272 if (ret < 0)
2273 {
2274 Logging::error(virtname(), "Could not set 'crf' for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2275 return ret;
2276 }
2277#endif
2278 }
2279#endif // EXPERIMENTAL
2280
2281 // Avoid mismatches for H264 and profile
2282 uint8_t *out_val;
2283 ret = av_opt_get(output_codec_ctx->priv_data, "profile", 0, &out_val);
2284 if (!ret)
2285 {
2286 if (!strcasecmp(reinterpret_cast<const char *>(out_val), "high"))
2287 {
2288 switch (output_codec_ctx->pix_fmt)
2289 {
2290 case AV_PIX_FMT_YUV420P9BE:
2291 case AV_PIX_FMT_YUV420P9LE:
2292 case AV_PIX_FMT_YUV420P10BE:
2293 case AV_PIX_FMT_YUV420P10LE:
2294 {
2295 ret = av_opt_set(output_codec_ctx->priv_data, "profile", "high10", 0);
2296 if (ret < 0)
2297 {
2298 Logging::error(virtname(), "Could not set profile=high10 for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2299 return ret;
2300 }
2301 break;
2302 }
2303 case AV_PIX_FMT_YUYV422:
2304 case AV_PIX_FMT_YUV422P:
2305 case AV_PIX_FMT_YUVJ422P:
2306 case AV_PIX_FMT_UYVY422:
2307 case AV_PIX_FMT_YUV422P16LE:
2308 case AV_PIX_FMT_YUV422P16BE:
2309 case AV_PIX_FMT_YUV422P10BE:
2310 case AV_PIX_FMT_YUV422P10LE:
2311 case AV_PIX_FMT_YUV422P9BE:
2312 case AV_PIX_FMT_YUV422P9LE:
2313 case AV_PIX_FMT_YUVA422P9BE:
2314 case AV_PIX_FMT_YUVA422P9LE:
2315 case AV_PIX_FMT_YUVA422P10BE:
2316 case AV_PIX_FMT_YUVA422P10LE:
2317 case AV_PIX_FMT_YUVA422P16BE:
2318 case AV_PIX_FMT_YUVA422P16LE:
2319 case AV_PIX_FMT_NV16:
2320 case AV_PIX_FMT_NV20LE:
2321 case AV_PIX_FMT_NV20BE:
2322 case AV_PIX_FMT_YVYU422:
2323 case AV_PIX_FMT_YUVA422P:
2324 case AV_PIX_FMT_YUV422P12BE:
2325 case AV_PIX_FMT_YUV422P12LE:
2326 case AV_PIX_FMT_YUV422P14BE:
2327 case AV_PIX_FMT_YUV422P14LE:
2328 {
2329 ret = av_opt_set(output_codec_ctx->priv_data, "profile", "high422", 0);
2330 if (ret < 0)
2331 {
2332 Logging::error(virtname(), "Could not set profile=high422 for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2333 return ret;
2334 }
2335 break;
2336 }
2337 case AV_PIX_FMT_YUV444P:
2338 case AV_PIX_FMT_YUVJ444P:
2339 case AV_PIX_FMT_YUV444P16LE:
2340 case AV_PIX_FMT_YUV444P16BE:
2341 case AV_PIX_FMT_RGB444LE:
2342 case AV_PIX_FMT_RGB444BE:
2343 case AV_PIX_FMT_BGR444LE:
2344 case AV_PIX_FMT_BGR444BE:
2345 case AV_PIX_FMT_YUV444P9BE:
2346 case AV_PIX_FMT_YUV444P9LE:
2347 case AV_PIX_FMT_YUV444P10BE:
2348 case AV_PIX_FMT_YUV444P10LE:
2349 case AV_PIX_FMT_GBRP:
2350 case AV_PIX_FMT_GBRP9BE:
2351 case AV_PIX_FMT_GBRP9LE:
2352 case AV_PIX_FMT_GBRP10BE:
2353 case AV_PIX_FMT_GBRP10LE:
2354 case AV_PIX_FMT_GBRP16BE:
2355 case AV_PIX_FMT_GBRP16LE:
2356 case AV_PIX_FMT_YUVA444P9BE:
2357 case AV_PIX_FMT_YUVA444P9LE:
2358 case AV_PIX_FMT_YUVA444P10BE:
2359 case AV_PIX_FMT_YUVA444P10LE:
2360 case AV_PIX_FMT_YUVA444P16BE:
2361 case AV_PIX_FMT_YUVA444P16LE:
2362 case AV_PIX_FMT_XYZ12LE:
2363 case AV_PIX_FMT_XYZ12BE:
2364 case AV_PIX_FMT_YUVA444P:
2365 case AV_PIX_FMT_GBRAP:
2366 case AV_PIX_FMT_GBRAP16BE:
2367 case AV_PIX_FMT_GBRAP16LE:
2368 case AV_PIX_FMT_YUV444P12BE:
2369 case AV_PIX_FMT_YUV444P12LE:
2370 case AV_PIX_FMT_YUV444P14BE:
2371 case AV_PIX_FMT_YUV444P14LE:
2372 case AV_PIX_FMT_GBRP12BE:
2373 case AV_PIX_FMT_GBRP12LE:
2374 case AV_PIX_FMT_GBRP14BE:
2375 case AV_PIX_FMT_GBRP14LE:
2376 case AV_PIX_FMT_AYUV64LE:
2377 case AV_PIX_FMT_AYUV64BE:
2378 {
2379 ret = av_opt_set(output_codec_ctx->priv_data, "profile", "high444", 0);
2380 if (ret < 0)
2381 {
2382 Logging::error(virtname(), "Could not set profile=high444 for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2383 return ret;
2384 }
2385 break;
2386 }
2387 default:
2388 {
2389 break;
2390 }
2391 }
2392 }
2393 av_free(out_val);
2394 }
2395 break;
2396 }
2397 case AV_CODEC_ID_VP9:
2398 {
2399 ret = prepare_codec(output_codec_ctx->priv_data, FILETYPE::WEBM);
2400 if (ret < 0)
2401 {
2402 Logging::error(virtname(), "Could not set profile for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2403 return ret;
2404 }
2405 break;
2406 }
2407 case AV_CODEC_ID_PRORES:
2408 {
2409 ret = prepare_codec(output_codec_ctx->priv_data, FILETYPE::PRORES);
2410 if (ret < 0)
2411 {
2412 Logging::error(virtname(), "Could not set profile for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2413 return ret;
2414 }
2415
2416 // 0 = ‘proxy’,
2417 // 1 = ‘lt’,
2418 // 2 = ‘standard’,
2419 // 3 = ‘hq’
2420 output_codec_ctx->profile = static_cast<int>(params.m_level);
2421 break;
2422 }
2423 case AV_CODEC_ID_ALAC:
2424 {
2425 ret = prepare_codec(output_codec_ctx->priv_data, FILETYPE::ALAC);
2426 if (ret < 0)
2427 {
2428 Logging::error(virtname(), "Could not set profile for %1 output codec %2 (error '%3').", get_media_type_string(output_codec->type), get_codec_name(codec_id), ffmpeg_geterror(ret).c_str());
2429 return ret;
2430 }
2431 break;
2432 }
2433 default:
2434 {
2435 break;
2436 }
2437 }
2438
2439 // Initialise pixel format conversion and rescaling if necessary
2440 get_pix_formats(&m_in.m_pix_fmt, &m_out.m_pix_fmt, output_codec_ctx);
2441
2442 ret = init_rescaler(m_in.m_pix_fmt, m_in.m_video.m_stream->codecpar->width, m_in.m_video.m_stream->codecpar->height, m_out.m_pix_fmt, output_codec_ctx->width, output_codec_ctx->height);
2443 if (ret < 0)
2444 {
2445 return ret;
2446 }
2447
2448 // set -strict -2 for aac (required for FFmpeg 2)
2449 dict_set_with_check(opt.address(), "strict", "-2", 0);
2450
2451 // Allow the use of the experimental AAC encoder
2452 output_codec_ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
2453
2454#ifdef _DEBUG
2455 print_stream_info(output_stream);
2456#endif // _DEBUG
2457
2458 // Set duration as hint for muxer
2459 if (m_in.m_video.m_stream->duration != AV_NOPTS_VALUE)
2460 {
2461 output_stream->duration = ffmpeg_rescale_q(m_in.m_video.m_stream->duration, m_in.m_video.m_stream->time_base, output_stream->time_base);
2462 }
2463 else if (m_in.m_format_ctx->duration != AV_NOPTS_VALUE)
2464 {
2465 output_stream->duration = ffmpeg_rescale_q(m_in.m_format_ctx->duration, av_get_time_base_q(), output_stream->time_base);
2466 }
2467
2468 //av_dict_set_int(&output_stream->metadata, "DURATION", output_stream->duration, AV_DICT_IGNORE_SUFFIX);
2469
2470 // Save the encoder context for easier access later.
2471 m_out.m_video.set_codec_ctx(output_codec_ctx);
2472 // Save the stream index
2473 m_out.m_video.m_stream_idx = output_stream->index;
2474 // Save output video stream for faster reference
2475 m_out.m_video.m_stream = output_stream;
2476
2477 // Update input to output stream map, this is rather boring because currently we only have a single video stream
2479 break;
2480 }
2481 default:
2482 break;
2483 }
2484
2485 // Although docs state this is "Demuxing only", this is actually used by encoders like Matroska/WebM, so we need to set this here.
2486 m_out.m_format_ctx->duration = m_in.m_format_ctx->duration;
2488 {
2489 av_dict_set_int(&m_out.m_format_ctx->metadata, "DURATION", m_virtualfile->m_cuesheet_track.m_duration, AV_DICT_IGNORE_SUFFIX);
2490 }
2491 else
2492 {
2493 av_dict_set_int(&m_out.m_format_ctx->metadata, "DURATION", m_out.m_format_ctx->duration, AV_DICT_IGNORE_SUFFIX);
2494 }
2495
2496 // Some formats want stream headers to be separate.
2497 if (m_out.m_format_ctx->oformat->flags & AVFMT_GLOBALHEADER)
2498 {
2499 output_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
2500 }
2501
2502 if (!av_dict_get(opt, "threads", nullptr, 0))
2503 {
2504 Logging::trace(virtname(), "Setting threads to auto for codec %1.", get_codec_name(output_codec_ctx->codec_id));
2505 dict_set_with_check(opt.address(), "threads", "auto", 0, virtname());
2506 }
2507
2508 // Open the encoder for the stream to use it later.
2509 ret = avcodec_open2(output_codec_ctx, output_codec, opt.address());
2510 if (ret < 0)
2511 {
2512 Logging::error(virtname(), "Could not open %1 output codec %2 for stream #%3 (error '%4').", get_media_type_string(output_codec->type), get_codec_name(codec_id), output_stream->index, ffmpeg_geterror(ret).c_str());
2513 return ret;
2514 }
2515
2516 Logging::debug(virtname(), "Opened %1 output codec %2 for stream #%3.", get_media_type_string(output_codec->type), get_codec_name(codec_id, true), output_stream->index);
2517
2518 ret = avcodec_parameters_from_context(output_stream->codecpar, output_codec_ctx);
2519 if (ret < 0)
2520 {
2521 Logging::error(virtname(), "Could not initialise stream parameters (error '%1').", ffmpeg_geterror(ret).c_str());
2522 return ret;
2523 }
2524
2525 return (output_stream->index);
2526}
2527
2528int FFmpeg_Transcoder::add_subtitle_stream(AVCodecID codec_id, StreamRef & input_streamref, const std::optional<std::string> & language)
2529{
2530 AVCodecContext *output_codec_ctx = nullptr;
2531 AVStream * output_stream = nullptr;
2532#if IF_DECLARED_CONST
2533 const AVCodec * output_codec = nullptr;
2534#else // !IF_DECLARED_CONST
2535 AVCodec * output_codec = nullptr;
2536#endif // !IF_DECLARED_CONST
2538 int ret;
2539
2540 // find the encoder
2541 output_codec = avcodec_find_encoder(codec_id);
2542
2543 if (output_codec == nullptr)
2544 {
2545 Logging::error(virtname(), "'%1' encoder could not be found.", avcodec_get_name(codec_id));
2546 return AVERROR(EINVAL);
2547 }
2548
2549 output_stream = avformat_new_stream(m_out.m_format_ctx, output_codec);
2550 if (output_stream == nullptr)
2551 {
2552 Logging::error(virtname(), "Could not allocate stream for encoder '%1'.", avcodec_get_name(codec_id));
2553 return AVERROR(ENOMEM);
2554 }
2555 output_stream->id = static_cast<int>(m_out.m_format_ctx->nb_streams - 1);
2556
2557 output_codec_ctx = avcodec_alloc_context3(output_codec);
2558 if (output_codec_ctx == nullptr)
2559 {
2560 Logging::error(virtname(), "Could not allocate an encoding context for encoder '%1'.", avcodec_get_name(codec_id));
2561 return AVERROR(ENOMEM);
2562 }
2563
2564 output_stream->time_base = input_streamref.m_stream->time_base;
2565 output_codec_ctx->time_base = output_stream->time_base;
2566
2567 // set -strict -2 for aac (required for FFmpeg 2)
2568 dict_set_with_check(opt.address(), "strict", "-2", 0);
2569
2570 // Allow the use of the experimental AAC encoder
2571 output_codec_ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
2572
2573 // Set duration as hint for muxer
2574 if (m_in.m_video.m_stream != nullptr && m_in.m_video.m_stream->duration != AV_NOPTS_VALUE)
2575 {
2576 output_stream->duration = ffmpeg_rescale_q(m_in.m_video.m_stream->duration, m_in.m_video.m_stream->time_base, output_stream->time_base);
2577 }
2578 if (m_in.m_audio.m_stream != nullptr && m_in.m_audio.m_stream->duration != AV_NOPTS_VALUE)
2579 {
2580 output_stream->duration = ffmpeg_rescale_q(m_in.m_audio.m_stream->duration, m_in.m_audio.m_stream->time_base, output_stream->time_base);
2581 }
2582 else if (m_in.m_format_ctx != nullptr && m_in.m_format_ctx->duration != AV_NOPTS_VALUE)
2583 {
2584 output_stream->duration = ffmpeg_rescale_q(m_in.m_format_ctx->duration, av_get_time_base_q(), output_stream->time_base);
2585 }
2586
2587 AVCodecContext * input_codec_ctx = input_streamref.m_codec_ctx.get();
2588
2589 if (input_codec_ctx != nullptr && input_codec_ctx->subtitle_header != nullptr)
2590 {
2591 // ASS code assumes this buffer is null terminated so add extra byte.
2592 output_codec_ctx->subtitle_header = static_cast<uint8_t *>(av_mallocz(static_cast<size_t>(input_codec_ctx->subtitle_header_size) + 1));
2593 if (output_codec_ctx->subtitle_header == nullptr)
2594 {
2595 return AVERROR(ENOMEM);
2596 }
2597 std::memcpy(output_codec_ctx->subtitle_header, input_codec_ctx->subtitle_header, static_cast<size_t>(input_codec_ctx->subtitle_header_size));
2598 output_codec_ctx->subtitle_header_size = input_codec_ctx->subtitle_header_size;
2599 }
2600 else if (output_codec_ctx->codec_id == AV_CODEC_ID_WEBVTT || output_codec_ctx->codec_id == AV_CODEC_ID_SUBRIP)
2601 {
2602 // If source had no header, we create a default one
2603 ret = get_script_info(output_codec_ctx,
2609
2610 if (ret)
2611 {
2612 Logging::error(virtname(), "Could not create ASS script info for encoder '%1'.", avcodec_get_name(codec_id));
2613 return ret;
2614 }
2615 }
2616
2617 // Open the encoder for the stream to use it later.
2618 ret = avcodec_open2(output_codec_ctx, output_codec, opt.address());
2619 if (ret < 0)
2620 {
2621 Logging::error(virtname(), "Could not open %1 output codec %2 for stream #%3 (error '%4').", get_media_type_string(output_codec->type), get_codec_name(codec_id), output_stream->index, ffmpeg_geterror(ret).c_str());
2622 return ret;
2623 }
2624
2625 Logging::debug(virtname(), "Opened %1 output codec %2 for stream #%3.", get_media_type_string(output_codec->type), get_codec_name(codec_id, true), output_stream->index);
2626
2627 ret = avcodec_parameters_from_context(output_stream->codecpar, output_codec_ctx);
2628 if (ret < 0)
2629 {
2630 Logging::error(virtname(), "Could not initialise stream parameters (error '%1').", ffmpeg_geterror(ret).c_str());
2631 return ret;
2632 }
2633
2634 if (!language)
2635 {
2636 // Copy language
2637 AVDictionaryEntry *tag = nullptr;
2638
2639 tag = av_dict_get(input_streamref.m_stream->metadata, "language", nullptr, AV_DICT_IGNORE_SUFFIX);
2640 if (tag != nullptr)
2641 {
2642 av_dict_set(&output_stream->metadata, "language", tag->value, AV_DICT_IGNORE_SUFFIX);
2643 }
2644 }
2645 else
2646 {
2647 // Use predefined value
2648 av_dict_set(&output_stream->metadata, "language", language->c_str(), AV_DICT_IGNORE_SUFFIX);
2649 }
2650
2651 // Save the encoder context for easier access later.
2652 StreamRef output_streamref;
2653
2654 output_streamref.set_codec_ctx(output_codec_ctx);
2655 // Save the stream index
2656 output_streamref.m_stream_idx = output_stream->index;
2657 // Save output audio stream for faster reference
2658 output_streamref.m_stream = output_stream;
2659
2660 m_out.m_subtitle.emplace(output_streamref.m_stream_idx, output_streamref);
2661
2662 // Update input to output stream map
2663 add_stream_map(input_streamref.m_stream_idx, output_streamref.m_stream_idx);
2664
2665 return output_streamref.m_stream_idx;
2666}
2667
2668int FFmpeg_Transcoder::add_stream_copy(AVCodecID codec_id, AVMediaType codec_type)
2669{
2670 AVStream * output_stream = nullptr;
2671 int ret;
2672
2673 output_stream = avformat_new_stream(m_out.m_format_ctx, nullptr);
2674 if (output_stream == nullptr)
2675 {
2676 Logging::error(virtname(), "Could not allocate stream for encoder '%1'.", avcodec_get_name(codec_id));
2677 return AVERROR(ENOMEM);
2678 }
2679 output_stream->id = static_cast<int>(m_out.m_format_ctx->nb_streams - 1);
2680
2681 switch (codec_type)
2682 {
2683 case AVMEDIA_TYPE_AUDIO:
2684 {
2685 ret = avcodec_parameters_copy(output_stream->codecpar, m_in.m_audio.m_stream->codecpar);
2686 if (ret < 0)
2687 {
2688 Logging::error(virtname(), "Could not allocate an encoding context (error '%2').", ffmpeg_geterror(ret).c_str());
2689 return ret;
2690 }
2691
2692 // Set the sample rate for the container.
2693 output_stream->time_base = m_in.m_audio.m_stream->time_base;
2694
2695 // Set duration as hint for muxer
2696 output_stream->duration = ffmpeg_rescale_q(m_in.m_audio.m_stream->duration, m_in.m_audio.m_stream->time_base, output_stream->time_base);
2697
2698 // Save the encoder context for easier access later.
2699 m_out.m_audio.set_codec_ctx(nullptr);
2700 // Save the stream index
2701 m_out.m_audio.m_stream_idx = output_stream->index;
2702 // Save output audio stream for faster reference
2703 m_out.m_audio.m_stream = output_stream;
2704
2705 // Update input to output stream map, this is rather boring because currently we only have a single audio stream
2707 break;
2708 }
2709 case AVMEDIA_TYPE_VIDEO:
2710 {
2711 ret = avcodec_parameters_copy(output_stream->codecpar, m_in.m_video.m_stream->codecpar);
2712 if (ret < 0)
2713 {
2714 Logging::error(virtname(), "Could not allocate an encoding context (error '%2').", ffmpeg_geterror(ret).c_str());
2715 return ret;
2716 }
2717
2718 output_stream->time_base = m_in.m_video.m_stream->time_base;
2719
2720#ifdef _DEBUG
2721 print_stream_info(output_stream);
2722#endif // _DEBUG
2723
2724 // Set duration as hint for muxer
2725 output_stream->duration = ffmpeg_rescale_q(m_in.m_video.m_stream->duration, m_in.m_video.m_stream->time_base, output_stream->time_base);
2726
2727 // Save the encoder context for easier access later.
2728 m_out.m_video.set_codec_ctx(nullptr);
2729 // Save the stream index
2730 m_out.m_video.m_stream_idx = output_stream->index;
2731 // Save output video stream for faster reference
2732 m_out.m_video.m_stream = output_stream;
2733
2734 // Update input to output stream map, this is rather boring because currently we only have a single video stream
2736 break;
2737 }
2738 default:
2739 break;
2740 }
2741
2742 output_stream->codecpar->codec_tag = 0;
2743
2744 return 0;
2745}
2746
2747int FFmpeg_Transcoder::add_albumart_stream(const AVCodecContext * input_codec_ctx)
2748{
2749 AVCodecContext * output_codec_ctx = nullptr;
2750 AVStream * output_stream = nullptr;
2751 const AVCodec * input_codec = input_codec_ctx->codec;
2752 const AVCodec * output_codec = nullptr;
2754 int ret;
2755
2756 // find the encoder
2757 output_codec = avcodec_find_encoder(input_codec->id);
2758 if (output_codec == nullptr)
2759 {
2760 Logging::error(virtname(), "'%1' encoder could not be found.", avcodec_get_name(input_codec->id));
2761 return AVERROR(EINVAL);
2762 }
2763
2764 // Must be a video codec
2765 if (output_codec->type != AVMEDIA_TYPE_VIDEO)
2766 {
2767 Logging::error(virtname(), "INTERNAL TROUBLE! Encoder '%1' is not a video codec.", avcodec_get_name(input_codec->id));
2768 return AVERROR(EINVAL);
2769 }
2770
2771 output_stream = avformat_new_stream(m_out.m_format_ctx, output_codec);
2772 if (output_stream == nullptr)
2773 {
2774 Logging::error(virtname(), "Could not allocate stream for encoder '%1'.", avcodec_get_name(input_codec->id));
2775 return AVERROR(ENOMEM);
2776 }
2777 output_stream->id = static_cast<int>(m_out.m_format_ctx->nb_streams - 1);
2778
2779 output_codec_ctx = avcodec_alloc_context3(output_codec);
2780 if (output_codec_ctx == nullptr)
2781 {
2782 Logging::error(virtname(), "Could not allocate an encoding context.");
2783 return AVERROR(ENOMEM);
2784 }
2785
2786 // Ignore missing width/height when adding album arts
2787#if !IF_DECLARED_CONST
2788 m_out.m_format_ctx->oformat->flags |= AVFMT_NODIMENSIONS;
2789#endif // !IF_DECLARED_CONST
2790 // This is required for some reason (let encoder decide?)
2791 // If not set, write header will fail!
2792 //output_codec_ctx->codec_tag = 0; //av_codec_get_tag(of->codec_tag, codec->codec_id);
2793
2794 //output_stream->codec->framerate = { 1, 0 };
2795
2797 // mp4 album arts do not work with ipod profile. Set mp4.
2798 //if (m_out.m_format_ctx->oformat->mime_type != nullptr && (!strcmp(m_out.m_format_ctx->oformat->mime_type, "application/mp4") || !strcmp(m_out.m_format_ctx->oformat->mime_type, "video/mp4")))
2799 //{
2800 // m_out.m_format_ctx->oformat->name = "mp4";
2801 // m_out.m_format_ctx->oformat->mime_type = "application/mp4";
2802 //}
2803
2804 // copy disposition
2805 // output_stream->disposition = input_stream->disposition;
2806 output_stream->disposition = AV_DISPOSITION_ATTACHED_PIC;
2807
2808 // copy estimated duration as a hint to the muxer
2809 if (output_stream->duration <= 0 && m_in.m_audio.m_stream->duration > 0)
2810 {
2811 output_stream->duration = ffmpeg_rescale_q(m_in.m_audio.m_stream->duration, m_in.m_audio.m_stream->time_base, output_stream->time_base);
2812 }
2813
2814 output_codec_ctx->time_base = { 1, 90000 };
2815 output_stream->time_base = { 1, 90000 };
2816
2817 output_codec_ctx->pix_fmt = input_codec_ctx->pix_fmt;
2818 output_codec_ctx->width = input_codec_ctx->width;
2819 output_codec_ctx->height = input_codec_ctx->height;
2820
2821 // Some formats want stream headers to be separate.
2822 if (m_out.m_format_ctx->oformat->flags & AVFMT_GLOBALHEADER)
2823 {
2824 output_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
2825 }
2826
2827 // Open the encoder for the stream to use it later.
2828 ret = avcodec_open2(output_codec_ctx, output_codec, opt.address());
2829 if (ret < 0)
2830 {
2831 Logging::error(virtname(), "Could not open %1 output codec %2 for stream #%3 (error '%4').", get_media_type_string(output_codec->type), get_codec_name(input_codec->id), output_stream->index, ffmpeg_geterror(ret).c_str());
2832 return ret;
2833 }
2834
2835 Logging::debug(virtname(), "Opened album art output codec %1 for stream #%2 (dimensions %3x%4).", get_codec_name(input_codec->id, true), output_stream->index, output_codec_ctx->width, output_codec_ctx->height);
2836
2837 ret = avcodec_parameters_from_context(output_stream->codecpar, output_codec_ctx);
2838 if (ret < 0)
2839 {
2840 Logging::error(virtname(), "Could not initialise stream parameters stream #%1 (error '%2').", output_stream->index, ffmpeg_geterror(ret).c_str());
2841 return ret;
2842 }
2843
2844 StreamRef streamref;
2845
2846 streamref.set_codec_ctx(output_codec_ctx);
2847 streamref.m_stream = output_stream;
2848 streamref.m_stream_idx = output_stream->index;
2849
2850 m_out.m_album_art.push_back(streamref);
2851
2852 return 0;
2853}
2854
2855int FFmpeg_Transcoder::add_albumart_frame(AVStream *output_stream, AVPacket *pkt_in)
2856{
2857 FFmpeg_Packet tmp_pkt(pkt_in);
2858 int ret = tmp_pkt.res();
2859
2860 if (ret < 0)
2861 {
2862 Logging::error(virtname(), "Could not write album art packet (error '%1').", ffmpeg_geterror(ret).c_str());
2863 return ret;
2864 }
2865
2866 Logging::trace(virtname(), "Adding album art stream #%1.", output_stream->index);
2867
2868 tmp_pkt->stream_index = output_stream->index;
2869 tmp_pkt->flags |= AV_PKT_FLAG_KEY; // Contains a single frame, make sure it's a key frame
2870 tmp_pkt->pos = 0;
2871 tmp_pkt->dts = 0;
2872
2873 return store_packet(tmp_pkt, AVMEDIA_TYPE_ATTACHMENT);
2874}
2875
2877{
2879
2880 Logging::debug(virtname(), "Opening output format '%1'.", m_current_format->desttype().c_str());
2881
2882 // Reset active streams
2885
2886 // Check if we can copy audio or video.
2889
2890 // Create a new format context for the output container format.
2891 int ret = 0;
2892 if (m_current_format->format_name() != "m4a")
2893 {
2895 }
2896 else
2897 {
2898 ret = m_out.m_format_ctx.alloc_output_context(nullptr, ".m4a");
2899 }
2900
2901 if (ret < 0 || m_out.m_format_ctx == nullptr)
2902 {
2903 Logging::error(virtname(), "Could not allocate an output format context.");
2904 return (ret < 0) ? ret : AVERROR(ENOMEM);
2905 }
2906
2907 if (!m_is_video)
2908 {
2910 }
2911
2912 //video_codec = m_out.m_format_ctx->oformat->video_codec;
2913
2914 // Open video streams
2915 if (stream_exists(m_in.m_video.m_stream_idx) && m_current_format->video_codec() != AV_CODEC_ID_NONE)
2916 {
2918
2919 if (!m_copy_video)
2920 {
2921 int ret;
2922
2924 if (ret < 0)
2925 {
2926 return ret;
2927 }
2928
2930 {
2931 // Init deinterlace filters
2933 if (ret < 0)
2934 {
2935 return ret;
2936 }
2937 }
2938 }
2939 else
2940 {
2941 int ret;
2942
2943 Logging::info(virtname(), "Copying video stream.");
2944
2945 ret = add_stream_copy(m_current_format->video_codec(), AVMEDIA_TYPE_VIDEO);
2946 if (ret < 0)
2947 {
2948 return ret;
2949 }
2950 }
2951 }
2952
2953 // Open audio streams
2954 if (stream_exists(m_in.m_audio.m_stream_idx) && m_current_format->audio_codec() != AV_CODEC_ID_NONE)
2955 {
2957
2958 if (!m_copy_audio)
2959 {
2960 int ret;
2961
2963 if (ret < 0)
2964 {
2965 return ret;
2966 }
2967 }
2968 else
2969 {
2970 int ret;
2971
2972 Logging::info(virtname(), "Copying audio stream.");
2973
2974 ret = add_stream_copy(m_current_format->audio_codec(), AVMEDIA_TYPE_AUDIO);
2975 if (ret < 0)
2976 {
2977 return ret;
2978 }
2979 }
2980 }
2981
2982 if (stream_exists(m_in.m_video.m_stream_idx) && m_current_format->video_codec() != AV_CODEC_ID_NONE)
2983 {
2984 int ret;
2985
2986 // Open subtitle streams
2987 if (m_in.m_subtitle.size())
2988 {
2989 // No copy option, not worth it for a few frames
2990 // Create as many subtitle streams as required
2991 ret = add_subtitle_streams();
2992 if (ret < 0)
2993 {
2994 return ret;
2995 }
2996 }
2997
2998 // Open streams for external subtitle files
3000 if (ret < 0)
3001 {
3002 return ret;
3003 }
3004 }
3005
3007 {
3008 for (StreamRef & album_art : m_in.m_album_art)
3009 {
3010 int ret;
3011
3012 ret = add_albumart_stream(album_art.m_codec_ctx.get());
3013 if (ret < 0)
3014 {
3015 return ret;
3016 }
3017 }
3018 }
3019
3020 const int buf_size = 5*1024*1024;
3021 unsigned char *iobuffer = static_cast<unsigned char *>(av_malloc(buf_size + FF_INPUT_BUFFER_PADDING_SIZE));
3022 if (iobuffer == nullptr)
3023 {
3024 Logging::error(virtname(), "Out of memory opening output file: Unable to allocate I/O buffer.");
3025 return AVERROR(ENOMEM);
3026 }
3027
3028 // open the output file
3029 m_out.m_format_ctx->pb = avio_alloc_context(
3030 iobuffer,
3031 buf_size,
3032 1,
3033 static_cast<void *>(buffer),
3034 nullptr, // read not required
3035 output_write, // write
3036 (m_current_format->audio_codec() != AV_CODEC_ID_OPUS) ? seek : nullptr); // seek
3037
3038 if (m_out.m_format_ctx->pb == nullptr)
3039 {
3040 Logging::error(virtname(), "Out of memory opening output file: Unable to allocate format context.");
3041 av_freep(&iobuffer);
3042 return AVERROR(ENOMEM);
3043 }
3045
3046 return 0;
3047}
3048
3050{
3051 for (auto & [key, value] : m_in.m_subtitle)
3052 {
3053 AVCodecID codec_id = m_current_format->subtitle_codec(value.m_stream->codecpar->codec_id); // Get matching output codec
3054
3055 if (codec_id == AV_CODEC_ID_NONE)
3056 {
3057 // No matching output codec
3058 continue;
3059 }
3060
3061 if (map_in_to_out_stream(value.m_stream_idx) != INVALID_STREAM)
3062 {
3063 // Already existing
3064 continue;
3065 }
3066
3067 //m_active_stream_msk |= FFMPEGFS_SUBTITLE;
3068
3069 int ret;
3070
3071 ret = add_subtitle_stream(codec_id, value);
3072 if (ret < 0)
3073 {
3074 return ret;
3075 }
3076 }
3077 return 0;
3078}
3079
3081{
3082 // Fail save: if channel layout not known assume mono or stereo
3083#if LAVU_DEP_OLD_CHANNEL_LAYOUT
3084 if (!m_in.m_audio.m_codec_ctx->ch_layout.nb_channels)
3085 {
3086 av_channel_layout_default(&m_in.m_audio.m_codec_ctx->ch_layout, 2);
3087 }
3088#else // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3089 if (!m_in.m_audio.m_codec_ctx->channel_layout)
3090 {
3091 m_in.m_audio.m_codec_ctx->channel_layout = static_cast<uint64_t>(av_get_default_channel_layout(m_in.m_audio.m_codec_ctx->channels));
3092 }
3093 if (!m_in.m_audio.m_codec_ctx->channel_layout)
3094 {
3095 m_in.m_audio.m_codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
3096 }
3097#endif // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3098
3099 // Only initialise the resampler if it is necessary, i.e.,
3100 // if and only if the sample formats differ.
3101#if LAVU_DEP_OLD_CHANNEL_LAYOUT
3102 if (m_in.m_audio.m_codec_ctx->sample_fmt == m_out.m_audio.m_codec_ctx->sample_fmt &&
3103 m_in.m_audio.m_codec_ctx->sample_rate == m_out.m_audio.m_codec_ctx->sample_rate &&
3104 !av_channel_layout_compare(&m_in.m_audio.m_codec_ctx->ch_layout, &m_out.m_audio.m_codec_ctx->ch_layout))
3105#else // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3106 if (m_in.m_audio.m_codec_ctx->sample_fmt == m_out.m_audio.m_codec_ctx->sample_fmt &&
3107 m_in.m_audio.m_codec_ctx->sample_rate == m_out.m_audio.m_codec_ctx->sample_rate &&
3108 m_in.m_audio.m_codec_ctx->channel_layout == m_out.m_audio.m_codec_ctx->channel_layout)
3109#endif // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3110 {
3111 // Formats are same
3113 return 0;
3114 }
3115
3116 if ((m_audio_resample_ctx == nullptr) ||
3117 (m_cur_sample_fmt != m_in.m_audio.m_codec_ctx->sample_fmt) ||
3118 (m_cur_sample_rate != m_in.m_audio.m_codec_ctx->sample_rate) ||
3120 av_channel_layout_compare(&m_cur_ch_layout, &m_in.m_audio.m_codec_ctx->ch_layout))
3121#else // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3122 (m_cur_channel_layout != m_in.m_audio.m_codec_ctx->channel_layout))
3123#endif // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3124 {
3125 int ret;
3126
3127#if LAVU_DEP_OLD_CHANNEL_LAYOUT
3128 Logging::debug(virtname(), "Creating audio resampler: %1 -> %2 / %3 -> %4 / %5 -> %6.",
3129 get_sample_fmt_name(m_in.m_audio.m_codec_ctx->sample_fmt).c_str(),
3130 get_sample_fmt_name(m_out.m_audio.m_codec_ctx->sample_fmt).c_str(),
3131 format_samplerate(m_in.m_audio.m_codec_ctx->sample_rate).c_str(),
3132 format_samplerate(m_out.m_audio.m_codec_ctx->sample_rate).c_str(),
3133 get_channel_layout_name(&m_in.m_audio.m_codec_ctx->ch_layout).c_str(),
3134 get_channel_layout_name(&m_out.m_audio.m_codec_ctx->ch_layout).c_str());
3135#else // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3136 Logging::debug(virtname(), "Creating audio resampler: %1 -> %2 / %3 -> %4 / %5 -> %6.",
3137 get_sample_fmt_name(m_in.m_audio.m_codec_ctx->sample_fmt).c_str(),
3138 get_sample_fmt_name(m_out.m_audio.m_codec_ctx->sample_fmt).c_str(),
3139 format_samplerate(m_in.m_audio.m_codec_ctx->sample_rate).c_str(),
3140 format_samplerate(m_out.m_audio.m_codec_ctx->sample_rate).c_str(),
3141 get_channel_layout_name(m_in.m_audio.m_codec_ctx->channels, m_in.m_audio.m_codec_ctx->channel_layout).c_str(),
3142 get_channel_layout_name(m_out.m_audio.m_codec_ctx->channels, m_out.m_audio.m_codec_ctx->channel_layout).c_str());
3143#endif // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3144
3146
3149#if LAVU_DEP_OLD_CHANNEL_LAYOUT
3150 av_channel_layout_copy(&m_cur_ch_layout, &m_in.m_audio.m_codec_ctx->ch_layout);
3151#else // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3152 m_cur_channel_layout = m_in.m_audio.m_codec_ctx->channel_layout;
3153#endif // !LAVU_DEP_OLD_CHANNEL_LAYOUT
3154
3155 // Create a resampler context for the conversion.
3156 // Set the conversion parameters.
3157#if SWR_DEP_ALLOC_SET_OPTS
3158 ret = swr_alloc_set_opts2(m_audio_resample_ctx.address(),
3159 &m_out.m_audio.m_codec_ctx->ch_layout,
3160 m_out.m_audio.m_codec_ctx->sample_fmt,
3161 m_out.m_audio.m_codec_ctx->sample_rate,
3162 &m_in.m_audio.m_codec_ctx->ch_layout,
3163 m_in.m_audio.m_codec_ctx->sample_fmt,
3164 m_in.m_audio.m_codec_ctx->sample_rate,
3165 0, nullptr);
3166 if (ret < 0)
3167 {
3168 Logging::error(virtname(), "Could not allocate resample context (error '%1').", ffmpeg_geterror(ret).c_str());
3169 return ret;
3170 }
3171#else
3172 m_audio_resample_ctx.reset(swr_alloc_set_opts(nullptr,
3173 static_cast<int64_t>(m_out.m_audio.m_codec_ctx->channel_layout),
3174 m_out.m_audio.m_codec_ctx->sample_fmt,
3175 m_out.m_audio.m_codec_ctx->sample_rate,
3176 static_cast<int64_t>(m_in.m_audio.m_codec_ctx->channel_layout),
3177 m_in.m_audio.m_codec_ctx->sample_fmt,
3178 m_in.m_audio.m_codec_ctx->sample_rate,
3179 0, nullptr));
3180 if (m_audio_resample_ctx == nullptr)
3181 {
3182 Logging::error(virtname(), "Could not allocate a resample context.");
3183 return AVERROR(ENOMEM);
3184 }
3185#endif
3186
3187 // Open the resampler with the specified parameters.
3188 ret = swr_init(m_audio_resample_ctx);
3189 if (ret < 0)
3190 {
3191 Logging::error(virtname(), "Could not open resampler context (error '%1').", ffmpeg_geterror(ret).c_str());
3193 return ret;
3194 }
3195 }
3196 return 0;
3197}
3198
3200{
3201 // Create the audio FIFO buffer based on the specified output sample format.
3203 if (ret < 0)
3204 {
3205 Logging::error(virtname(), "Could not allocate an audio FIFO.");
3206 return ret;
3207 }
3208 return 0;
3209}
3210
3211int FFmpeg_Transcoder::update_format(AVDictionary** dict, const PROFILE_OPTION_VEC &option_vec) const
3212{
3213 int ret = 0;
3214
3215 for (const PROFILE_OPTION & option : option_vec)
3216 {
3217 if ((option.m_options & OPT_AUDIO) && stream_exists(m_out.m_video.m_stream_idx))
3218 {
3219 // Option for audio only, but file contains video stream
3220 continue;
3221 }
3222
3223 if ((option.m_options & OPT_VIDEO) && !stream_exists(m_out.m_video.m_stream_idx))
3224 {
3225 // Option for video, but file contains no video stream
3226 continue;
3227 }
3228
3229 Logging::trace(virtname(), "Profile format option -%1%2%3.", option.m_key, *option.m_value ? " " : "", option.m_value);
3230
3231 ret = dict_set_with_check(dict, option.m_key, option.m_value, option.m_flags, virtname());
3232 if (ret < 0)
3233 {
3234 break;
3235 }
3236 }
3237 return ret;
3238}
3239
3240int FFmpeg_Transcoder::prepare_format(AVDictionary** dict, FILETYPE filetype) const
3241{
3242 int ret = 0;
3243
3244 for (const PROFILE_LIST & profile : m_profile)
3245 {
3246 if (profile.m_filetype == filetype)
3247 {
3248 ret = AVERROR_OPTION_NOT_FOUND; // Once we found the file type, we also need to find the profile. Otherwise we have an invalid command line option.
3249 if (profile.m_profile == params.m_profile)
3250 {
3251 ret = update_format(dict, profile.m_option_format);
3252 break;
3253 }
3254 }
3255 }
3256
3257 if (filetype == FILETYPE::MP4 || filetype == FILETYPE::PRORES || filetype == FILETYPE::TS || filetype == FILETYPE::HLS)
3258 {
3259 // All
3260 dict_set_with_check(dict, "flags:a", "+global_header", 0, virtname());
3261 dict_set_with_check(dict, "flags:v", "+global_header", 0, virtname());
3262 }
3263
3264 return ret;
3265}
3266
3268{
3269 // Insert fake WAV header (fill in size fields with estimated values instead of setting to -1)
3270 AVIOContext * output_io_context = static_cast<AVIOContext *>(m_out.m_format_ctx->pb);
3271 Buffer *buffer = static_cast<Buffer *>(output_io_context->opaque);
3272 size_t current_offset = buffer->tell();
3273 size_t read_offset = 0;
3274 WAV_HEADER wav_header;
3275 WAV_LIST_HEADER list_header;
3276 WAV_DATA_HEADER data_header;
3277
3278 buffer->copy(reinterpret_cast<uint8_t*>(&wav_header), 0, sizeof(WAV_HEADER));
3279 read_offset = sizeof(WAV_HEADER);
3280
3281 if (wav_header.m_audio_format == 0xfffe)
3282 {
3283 //WAV_HEADER_EX wav_header_ex;
3284 WAV_FACT wav_fact;
3285
3286 //buffer->copy(reinterpret_cast<uint8_t*>(&wav_header_ex), read_offset, sizeof(WAV_HEADER_EX));
3287 read_offset += sizeof(WAV_HEADER_EX); // Need to skip extension header
3288
3289 // Check for presence of "fact" chunk
3290 buffer->copy(reinterpret_cast<uint8_t*>(&wav_fact), read_offset, sizeof(WAV_FACT));
3291 if (!memcmp(&wav_fact.m_chunk_id, "fact", sizeof(wav_fact.m_chunk_id)))
3292 {
3293 read_offset += sizeof(WAV_FACT); // Also skip fact header
3294 }
3295 }
3296
3297 // Read list header
3298 buffer->copy(reinterpret_cast<uint8_t*>(&list_header), read_offset, sizeof(WAV_LIST_HEADER));
3299 read_offset += sizeof(WAV_LIST_HEADER) + list_header.m_data_bytes - 4;
3300 // Read data header
3301 buffer->copy(reinterpret_cast<uint8_t*>(&data_header), read_offset, sizeof(WAV_DATA_HEADER));
3302
3303 // Fill in size fields with predicted size
3304 wav_header.m_wav_size = static_cast<unsigned int>(predicted_filesize() - 8);
3305 data_header.m_data_bytes = static_cast<unsigned int>(predicted_filesize() - (read_offset + sizeof(WAV_DATA_HEADER)));
3306#if __BYTE_ORDER == __BIG_ENDIAN
3307 wav_header.m_wav_size = __builtin_bswap32(wav_header.m_wav_size);
3308 data_header.m_data_bytes = __builtin_bswap32(data_header.m_data_bytes);
3309#endif
3310
3311 // Write updated wav header
3312 buffer->seek(0, SEEK_SET);
3313 buffer->writeio(reinterpret_cast<uint8_t*>(&wav_header), sizeof(WAV_HEADER));
3314
3315 // Write updated data header
3316 buffer->seek(static_cast<long>(read_offset), SEEK_SET);
3317 buffer->writeio(reinterpret_cast<uint8_t*>(&data_header), sizeof(WAV_DATA_HEADER));
3318
3319 // Restore write position
3320 buffer->seek(static_cast<long>(current_offset), SEEK_SET);
3321
3322 return 0;
3323}
3324
3325int FFmpeg_Transcoder::read_aiff_chunk(Buffer *buffer, size_t *buffoffset, const char *ID, uint8_t *chunk, size_t *size) const
3326{
3327 AIFF_CHUNK *p = reinterpret_cast<AIFF_CHUNK*>(chunk);
3328 size_t buffsize = *size;
3329
3330 for (;;)
3331 {
3332 if (!buffer->copy(chunk, *buffoffset, buffsize))
3333 {
3334 return -1;
3335 }
3336
3337 if (buffer->eof())
3338 {
3339 errno = 0;
3340 return -1;
3341 }
3342
3343 if (!memcmp(&p->m_ckID, AIFF_FORMID, sizeof(p->m_ckID)))
3344 {
3345 // Special case: FormChunk has a fixed size
3346 *size = sizeof(AIFF_FORMCHUNK);
3347 }
3348 else
3349 {
3350#if __BYTE_ORDER == __BIG_ENDIAN
3351 *size = p->m_ckSize + 8;
3352#else
3353 *size = __builtin_bswap32(p->m_ckSize) + 8;
3354#endif
3355 }
3356
3357 if (!memcmp(&p->m_ckID, ID, sizeof(p->m_ckID)))
3358 {
3359 // Found
3360 break;
3361 }
3362
3363 // Advance to next potential position
3364 *buffoffset += *size;
3365 }
3366
3367 return 0;
3368}
3369
3371{
3372 // Insert fake WAV header (fill in size fields with estimated values instead of setting to -1)
3373 AVIOContext * output_io_context = static_cast<AVIOContext *>(m_out.m_format_ctx->pb);
3374 Buffer *buffer = static_cast<Buffer *>(output_io_context->opaque);
3375 size_t current_offset = buffer->tell();
3376 size_t read_offset = 0;
3377 size_t size;
3378 AIFF_FORMCHUNK form_chunk;
3379 AIFF_COMMONCHUNK common_chunk;
3380
3381 size = sizeof(form_chunk);
3382 if (read_aiff_chunk(buffer, &read_offset, AIFF_FORMID, reinterpret_cast<uint8_t*>(&form_chunk), &size))
3383 {
3384 return -1;
3385 }
3386
3387 read_offset += size;
3388
3389 form_chunk.m_ckSize = static_cast<uint32_t>(predicted_filesize() - 8);
3390#if __BYTE_ORDER != __BIG_ENDIAN
3391 form_chunk.m_ckSize = __builtin_bswap32(form_chunk.m_ckSize);
3392#endif
3393
3394 size = sizeof(common_chunk);
3395 if (read_aiff_chunk(buffer, &read_offset, AIFF_COMMONID, reinterpret_cast<uint8_t*>(&common_chunk), &size))
3396 {
3397 return -1;
3398 }
3399
3400 read_offset += size;
3401
3402 AIFF_SOUNDDATACHUNK sounddata_chunk;
3403
3404 size = sizeof(sounddata_chunk);
3405 if (read_aiff_chunk(buffer, &read_offset, AIFF_SOUNDATAID, reinterpret_cast<uint8_t*>(&sounddata_chunk), &size))
3406 {
3407 return -1;
3408 }
3409
3410 sounddata_chunk.m_ckSize = static_cast<uint32_t>(predicted_filesize() - read_offset);
3411#if __BYTE_ORDER != __BIG_ENDIAN
3412 sounddata_chunk.m_ckSize = __builtin_bswap32(sounddata_chunk.m_ckSize);
3413#endif
3414
3415 // Write updated AIFF header
3416 buffer->seek(0, SEEK_SET);
3417 buffer->writeio(reinterpret_cast<uint8_t*>(&form_chunk), sizeof(form_chunk));
3418
3419 // Write updated data header
3420 buffer->seek(static_cast<long>(read_offset), SEEK_SET);
3421 buffer->writeio(reinterpret_cast<uint8_t*>(&sounddata_chunk), sizeof(sounddata_chunk));
3422
3423 // Restore write position
3424 buffer->seek(static_cast<long>(current_offset), SEEK_SET);
3425
3426 return 0;
3427}
3428
3430{
3431 FFmpeg_Dictionary dict;
3432 int ret;
3433
3434 ret = prepare_format(dict.address(), m_out.m_filetype);
3435 if (ret < 0)
3436 {
3437 return ret;
3438 }
3439
3440 ret = avformat_write_header(m_out.m_format_ctx, dict.address());
3441 if (ret < 0)
3442 {
3443 Logging::error(virtname(), "Could not write output file header (error '%1').", ffmpeg_geterror(ret).c_str());
3444 return ret;
3445 }
3446
3447 switch (m_current_format->filetype())
3448 {
3449 case FILETYPE::WAV:
3450 {
3451 ret = create_fake_wav_header();
3452 break;
3453 }
3454 case FILETYPE::AIFF:
3455 {
3457 break;
3458 }
3459 default:
3460 {
3461 break;
3462 }
3463 }
3464
3465 return ret;
3466}
3467
3468int FFmpeg_Transcoder::alloc_picture(AVFrame *frame, AVPixelFormat pix_fmt, int width, int height) const
3469{
3470 int ret;
3471
3472 frame->format = pix_fmt;
3473 frame->width = width;
3474 frame->height = height;
3475
3476 // allocate the buffers for the frame data
3477 ret = av_frame_get_buffer(frame, 32);
3478 if (ret < 0)
3479 {
3480 Logging::error(virtname(), "Could not allocate frame data (error '%1').", ffmpeg_geterror(ret).c_str());
3481 return ret;
3482 }
3483
3484 return 0;
3485}
3486
3487int FFmpeg_Transcoder::decode(AVCodecContext *codec_ctx, AVFrame *frame, int *got_frame, const AVPacket *pkt) const
3488{
3489 int ret;
3490
3491 *got_frame = 0;
3492
3493 if (pkt != nullptr)
3494 {
3495 ret = avcodec_send_packet(codec_ctx, pkt);
3496 if (ret < 0 && ret != AVERROR_EOF)
3497 {
3498 // In particular, we don't expect AVERROR(EAGAIN), because we read all
3499 // decoded frames with avcodec_receive_frame() until done, so this should be handled
3500 // as an error.
3501 if (ret == AVERROR(EAGAIN))
3502 {
3503 ret = AVERROR_EXTERNAL;
3504 }
3505
3506 if (is_audio_stream(pkt->stream_index) && stream_exists(m_out.m_audio.m_stream_idx))
3507 {
3508 Logging::error(filename(), "Could not send audio packet at PTS=%1 to decoder (error '%2').", ffmpeg_rescale_q(pkt->pts, m_in.m_audio.m_stream->time_base), ffmpeg_geterror(ret).c_str());
3509 }
3510 else if (is_video_stream(pkt->stream_index) && stream_exists(m_out.m_video.m_stream_idx))
3511 {
3512 Logging::error(filename(), "Could not send video packet at PTS=%1 to decoder (error '%2').", ffmpeg_rescale_q(pkt->pts, m_in.m_video.m_stream->time_base), ffmpeg_geterror(ret).c_str());
3513 }
3514 else
3515 {
3516 // Should never come here, but what the heck...
3517 Logging::error(filename(), "Could not send packet at PTS=%1 to decoder (error '%2').", pkt->pts, ffmpeg_geterror(ret).c_str());
3518 }
3519 return ret;
3520 }
3521 }
3522
3523 ret = avcodec_receive_frame(codec_ctx, frame);
3524 if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
3525 {
3526 Logging::error(filename(), "Could not receive packet from decoder (error '%1').", ffmpeg_geterror(ret).c_str());
3527 }
3528
3536 *got_frame = (ret >= 0) ? 1 : 0;
3537
3538 return ret;
3539}
3540
3541int FFmpeg_Transcoder::decode_audio_frame(AVPacket *pkt, int *decoded)
3542{
3543 int data_present = 0;
3544 int ret = 0;
3545
3546 *decoded = 0;
3547
3548 // Decode the audio frame stored in the temporary packet.
3549 // The input audio stream decoder is used to do this.
3550 // If we are at the end of the file, pass an empty packet to the decoder
3551 // to flush it.
3552
3553 // Since FFMpeg version >= 3.2 this is deprecated
3554 bool again = false;
3555
3556 data_present = 0;
3557
3558 // read all the output frames (in general there may be any number of them)
3559 while (ret >= 0)
3560 {
3562
3563 ret = frame.res();
3564 if (ret < 0)
3565 {
3566 Logging::error(filename(), "Could not decode audio frame (error '%1').", ffmpeg_geterror(ret).c_str());
3567 break;
3568 }
3569
3570 ret = decode(m_in.m_audio.m_codec_ctx.get(), frame, &data_present, again ? nullptr : pkt);
3571 if (!data_present)
3572 {
3573 break;
3574 }
3575
3576 if (ret < 0)
3577 {
3578 // Anything else is an error, report it!
3579 Logging::error(filename(), "Could not decode audio frame (error '%1').", ffmpeg_geterror(ret).c_str());
3580 break;
3581 }
3582
3583 again = true;
3584
3585 *decoded += pkt->size;
3586
3587 // If there is decoded data, convert and store it
3588 if (frame->nb_samples)
3589 {
3590 // Temporary storage for the converted input samples.
3591 uint8_t **converted_input_samples = nullptr;
3592 try
3593 {
3594 int nb_output_samples;
3595
3596 // Initialise the resampler to be able to convert audio sample formats.
3597 ret = init_resampler();
3598 if (ret)
3599 {
3600 throw ret;
3601 }
3602
3603 nb_output_samples = (m_audio_resample_ctx != nullptr) ? swr_get_out_samples(m_audio_resample_ctx, frame->nb_samples) : frame->nb_samples;
3604
3605 // Store audio frame
3606 // Initialise the temporary storage for the converted input samples.
3607 ret = init_converted_samples(&converted_input_samples, nb_output_samples);
3608 if (ret < 0)
3609 {
3610 throw ret;
3611 }
3612
3613 // Convert the input samples to the desired output sample format.
3614 // This requires a temporary storage provided by converted_input_samples.
3615 ret = convert_samples(frame->extended_data, frame->nb_samples, converted_input_samples, &nb_output_samples);
3616 if (ret < 0)
3617 {
3618 throw ret;
3619 }
3620
3621 // Add the converted input samples to the audio FIFO buffer for later processing.
3622 ret = add_samples_to_fifo(converted_input_samples, nb_output_samples);
3623 if (ret < 0)
3624 {
3625 throw ret;
3626 }
3627 ret = 0;
3628 }
3629 catch (int _ret)
3630 {
3631 ret = _ret;
3632 }
3633
3634 if (converted_input_samples != nullptr)
3635 {
3636 av_freep(&converted_input_samples[0]);
3637 av_free(converted_input_samples);
3638 }
3639 }
3640 }
3641 return ret;
3642}
3643
3644int FFmpeg_Transcoder::decode_video_frame(AVPacket *pkt, int *decoded)
3645{
3646 int data_present;
3647 int ret = 0;
3648
3649 *decoded = 0;
3650
3651 // NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
3652 // and this is the only method to use them because you cannot
3653 // know the compressed data size before analysing it.
3654
3655 // BUT some other codecs (msmpeg4, mpeg4) are inherently frame
3656 // based, so you must call them with all the data for one
3657 // frame exactly. You must also initialise 'width' and
3658 // 'height' before initialising them.
3659
3660 // NOTE2: some codecs allow the raw parameters (frame size,
3661 // sample rate) to be changed at any frame. We handle this, so
3662 // you should also take care of it
3663
3664 // Since FFMpeg version >= 3.2 this is deprecated
3665 bool again = false;
3666
3667 data_present = 0;
3668
3669 // read all the output frames (in general there may be any number of them)
3670 while (ret >= 0)
3671 {
3673
3674 ret = frame.res();
3675 if (ret < 0)
3676 {
3677 Logging::error(filename(), "Could not decode video frame (error '%1').", ffmpeg_geterror(ret).c_str());
3678 break;
3679 }
3680
3681 ret = decode(m_in.m_video.m_codec_ctx.get(), frame, &data_present, again ? nullptr : pkt);
3682 if (!data_present)
3683 {
3684 // No data available
3685 break;
3686 }
3687
3688 if (ret < 0)
3689 {
3690 // Anything else is an error, report it!
3691 Logging::error(filename(), "Could not decode video frame (error '%1').", ffmpeg_geterror(ret).c_str());
3692 break;
3693 }
3694
3695 if (m_hwaccel_enable_dec_buffering && frame != nullptr)
3696 {
3698
3699 ret = sw_frame.res();
3700 if (ret < 0)
3701 {
3702 Logging::error(filename(), "Could not decode video frame (error '%1').", ffmpeg_geterror(ret).c_str());
3703 break;
3704 }
3705
3706 // If decoding is done in hardware, the resulting frame data needs to be copied to software memory
3707 //ret = hwframe_copy_from_hw(m_in.m_video.m_codec_ctx.get(), &sw_frame, frame);
3708
3709 // retrieve data from GPU to CPU
3710 ret = av_hwframe_transfer_data(sw_frame, frame, 0); // hwframe_copy_from_hw
3711 if (ret < 0)
3712 {
3713 Logging::error(filename(), "Error transferring the data to system memory (error '%1').", ffmpeg_geterror(ret).c_str());
3714 break;
3715 }
3716 frame = sw_frame;
3717 }
3718
3719 again = true;
3720 *decoded += pkt->size;
3721
3722 // Sometimes only a few packets contain valid dts/pts/pos data, so we keep it
3723 if (pkt->dts != AV_NOPTS_VALUE)
3724 {
3725 int64_t pkt_dts = pkt->dts;
3726 if (pkt_dts > m_pts)
3727 {
3728 m_pts = pkt_dts;
3729 }
3730 }
3731 else if (pkt->pts != AV_NOPTS_VALUE)
3732 {
3733 int64_t pkt_pts = pkt->pts;
3734 if (pkt_pts > m_pts)
3735 {
3736 m_pts = pkt_pts;
3737 }
3738 }
3739
3740 if (pkt->pos > -1)
3741 {
3742 m_pos = pkt->pos;
3743 }
3744
3745 if (frame != nullptr)
3746 {
3747 if (!(frame->flags & AV_FRAME_FLAG_CORRUPT || frame->flags & AV_FRAME_FLAG_DISCARD))
3748 {
3749 ret = send_filters(&frame, ret);
3750 if (ret)
3751 {
3752 break;
3753 }
3754
3755 if (m_sws_ctx != nullptr)
3756 {
3758
3759 ret = tmp_frame.res();
3760 if (ret < 0)
3761 {
3762 Logging::error(filename(), "Could not decode video frame (error '%1').", ffmpeg_geterror(ret).c_str());
3763 break;
3764 }
3765
3766 AVCodecContext *output_codec_ctx = m_out.m_video.m_codec_ctx.get();
3767
3768 ret = alloc_picture(tmp_frame, m_out.m_pix_fmt, output_codec_ctx->width, output_codec_ctx->height);
3769 if (ret < 0)
3770 {
3771 break;
3772 }
3773
3774 sws_scale(m_sws_ctx,
3775 static_cast<const uint8_t * const *>(frame->data), frame->linesize,
3776 0, frame->height,
3777 tmp_frame->data, tmp_frame->linesize);
3778
3779 tmp_frame->pts = frame->pts;
3780 tmp_frame->best_effort_timestamp = frame->best_effort_timestamp;
3781
3782 frame = tmp_frame;
3783 }
3784
3785 int64_t best_effort_timestamp = frame->best_effort_timestamp;
3786
3787 if (best_effort_timestamp != AV_NOPTS_VALUE)
3788 {
3789 frame->pts = best_effort_timestamp;
3790 }
3791
3792 if (frame->pts == AV_NOPTS_VALUE)
3793 {
3794 frame->pts = m_pts;
3795 }
3796
3797 int64_t video_start_time = m_out.m_video.m_start_time;
3798
3799 if (m_out.m_video.m_stream != nullptr && frame->pts != AV_NOPTS_VALUE)
3800 {
3801 if (m_in.m_video.m_stream->time_base.den != m_out.m_video.m_stream->time_base.den || m_in.m_video.m_stream->time_base.num != m_out.m_video.m_stream->time_base.num)
3802 {
3803 frame->pts = ffmpeg_rescale_q_rnd(frame->pts, m_in.m_video.m_stream->time_base, m_out.m_video.m_stream->time_base);
3804 video_start_time = ffmpeg_rescale_q_rnd(video_start_time, m_in.m_video.m_stream->time_base, m_out.m_video.m_stream->time_base);
3805 }
3806
3807 // Fix for issue #46: bitrate too high.
3808 // Solution found here https://stackoverflow.com/questions/11466184/setting-video-bit-rate-through-ffmpeg-api-is-ignored-for-libx264-codec
3809 // This is permanently used in the current ffmpeg.c code (see commit: e3fb9af6f1353f30855eaa1cbd5befaf06e303b8 Date:Wed Jan 22 15:52:10 2020 +0100)
3810 frame->pts = ffmpeg_rescale_q_rnd(frame->pts, m_out.m_video.m_stream->time_base, m_out.m_video.m_codec_ctx->time_base);
3811 video_start_time = ffmpeg_rescale_q_rnd(video_start_time, m_out.m_video.m_stream->time_base, m_out.m_video.m_codec_ctx->time_base);
3812 }
3813
3814 frame->quality = m_out.m_video.m_codec_ctx->global_quality;
3815#if !LAVU_ADD_NEW_FRAME_FLAGS
3816 frame->key_frame = 0; // Leave that decision to encoder
3817#endif
3818 frame->pict_type = AV_PICTURE_TYPE_NONE; // other than AV_PICTURE_TYPE_NONE causes warnings
3819
3820 if (frame->pts != AV_NOPTS_VALUE)
3821 {
3822 int64_t tmp_pts = frame->pts - video_start_time;
3823 int64_t pos = ffmpeg_rescale_q_rnd(tmp_pts, m_out.m_video.m_codec_ctx->time_base);
3824 if (pos < 0)
3825 {
3826 pos = 0;
3827 }
3828
3829 if (is_hls())
3830 {
3831 // Issue #90: Insert key frame at start of each subsequent HLS segment
3832 uint32_t next_segment = get_next_segment(pos);
3833
3834 if (goto_next_segment(next_segment) && !m_insert_keyframe)
3835 {
3836 Logging::debug(virtname(), "Force key frame for next segment no. %1 at PTS=%2 (%3).", next_segment, tmp_pts, format_duration(pos).c_str());
3837
3838#if LAVU_ADD_NEW_FRAME_FLAGS
3839 frame->flags |= AV_FRAME_FLAG_KEY; // This is required to reset the GOP counter (insert the next key frame after gop_size frames)
3840#else // !LAVU_ADD_NEW_FRAME_FLAGS
3841 frame->key_frame = 1; // This is required to reset the GOP counter (insert the next key frame after gop_size frames)
3842#endif // !LAVU_ADD_NEW_FRAME_FLAGS
3843 frame->pict_type = AV_PICTURE_TYPE_I;
3844 m_insert_keyframe = true;
3845 }
3846 }
3847
3848 m_frame_map.emplace(pos, frame);
3849 }
3850 else
3851 {
3852 m_frame_map.emplace(0, frame);
3853 }
3854 }
3855 }
3856 }
3857
3858 return ret;
3859}
3860
3861int FFmpeg_Transcoder::decode_subtitle(AVPacket *pkt, int *decoded)
3862{
3863 StreamRef_map::const_iterator it = m_in.m_subtitle.find(pkt->stream_index);
3864
3865 *decoded = 0;
3866
3867 if (it == m_in.m_subtitle.cend())
3868 {
3869 // Should never happen, this should never be called with anything else than subtitle packets.
3870 int ret = AVERROR_STREAM_NOT_FOUND;
3871 Logging::error(filename(), "INTERNAL ERROR: FFmpeg_Transcoder::decode_subtitle()! Subtitle stream #%1 not found (error '%2').", ffmpeg_geterror(ret).c_str());
3872 return ret;
3873 }
3874
3875 // Decode the audio frame stored in the temporary packet.
3876 // The input audio stream decoder is used to do this.
3877 // If we are at the end of the file, pass an empty packet to the decoder
3878 // to flush it.
3879
3880 // Temporary storage of the input samples of the frame read from the file.
3881
3882 int out_stream_idx = map_in_to_out_stream(it->first);
3883
3884 if (out_stream_idx == INVALID_STREAM)
3885 {
3886 Logging::error(virtname(), "INTERNAL ERROR: FFmpeg_Transcoder::decode_subtitle()! Unable to map input subtitle stream #%1 to output stream.", it->first);
3887 throw AVERROR(EINVAL);
3888 }
3889
3890 return decode_subtitle(it->second.m_codec_ctx.get(), pkt, decoded, out_stream_idx);
3891}
3892
3893int FFmpeg_Transcoder::decode_subtitle(AVCodecContext *codec_ctx, AVPacket *pkt, int *decoded, int out_stream_idx)
3894{
3895 FFmpeg_Subtitle subtitle(out_stream_idx);
3896 int data_present = 0;
3897 int ret = 0;
3898
3899 *decoded = 0;
3900
3901 ret = subtitle.res();
3902 if (ret < 0)
3903 {
3904 Logging::error(filename(), "Could not decode subtitle (error '%1').", ffmpeg_geterror(ret).c_str());
3905 return ret;
3906 }
3907
3908 ret = avcodec_decode_subtitle2(codec_ctx, subtitle, &data_present, pkt);
3909
3910 if (ret < 0 && ret != AVERROR(EINVAL))
3911 {
3912 Logging::error(filename(), "Could not decode subtitle frame (error '%1').", ffmpeg_geterror(ret).c_str());
3913 data_present = 0;
3914 }
3915 else
3916 {
3917 *decoded = ret;
3918 ret = 0;
3919 }
3920
3921 if (data_present)
3922 {
3923 // If there is decoded data, store it
3924 // sub->pts is already in AV_TIME_BASE
3925 m_frame_map.emplace(subtitle->pts, subtitle);
3926 }
3927
3928 return ret;
3929}
3930
3931int FFmpeg_Transcoder::store_packet(AVPacket *pkt, AVMediaType mediatype)
3932{
3933 int ret;
3934 if (is_hls() && pkt->pts != AV_NOPTS_VALUE)
3935 {
3936 switch (mediatype)
3937 {
3938 case AVMEDIA_TYPE_AUDIO:
3939 {
3940 int64_t pos = ffmpeg_rescale_q_rnd(pkt->pts - m_out.m_audio.m_start_time, m_out.m_audio.m_stream->time_base);
3941 if (pos < 0)
3942 {
3943 pos = 0;
3944 }
3945 uint32_t next_segment = get_next_segment(pos);
3946
3947 if (goto_next_segment(next_segment))
3948 {
3950 {
3952
3953 Logging::trace(virtname(), "Buffering audio packets until the next segment no. %1 from position %2 (%3).", next_segment, pos, format_duration(pos).c_str());
3954 }
3955
3956 FFmpeg_Packet fifo_pkt(pkt);
3957 ret = fifo_pkt.res();
3958 if (ret < 0)
3959 {
3960 return ret;
3961 }
3962 m_hls_packet_fifo.push(std::move(fifo_pkt));
3963 return 0;
3964 }
3965 break;
3966 }
3967 case AVMEDIA_TYPE_VIDEO:
3968 {
3969 int64_t pos = ffmpeg_rescale_q_rnd(pkt->pts - m_out.m_video.m_start_time, m_out.m_video.m_stream->time_base);
3970 if (pos < 0)
3971 {
3972 pos = 0;
3973 }
3974 uint32_t next_segment = get_next_segment(pos);
3975
3976 if (goto_next_segment(next_segment))
3977 {
3979 {
3981
3982 Logging::trace(virtname(), "Buffering video packets until the next segment no. %1 from position %2 (%3).", next_segment, pos, format_duration(pos).c_str());
3983 }
3984
3985 FFmpeg_Packet fifo_pkt(pkt);
3986 ret = fifo_pkt.res();
3987 if (ret < 0)
3988 {
3989 return ret;
3990 }
3991 m_hls_packet_fifo.push(std::move(fifo_pkt));
3992 return 0;
3993 }
3994 break;
3995 }
3996 case AVMEDIA_TYPE_SUBTITLE:
3997 {
3998 StreamRef * subtitle = get_out_subtitle_stream(pkt->stream_index);
3999
4000 if (subtitle != nullptr && subtitle->m_stream != nullptr)
4001 {
4002 int64_t pos = ffmpeg_rescale_q_rnd(pkt->pts - subtitle->m_start_time, subtitle->m_stream->time_base);
4003 if (pos < 0)
4004 {
4005 pos = 0;
4006 }
4007 uint32_t next_segment = get_next_segment(pos);
4008
4009 if (goto_next_segment(next_segment))
4010 {
4011 FFmpeg_Packet fifo_pkt(pkt);
4012 ret = fifo_pkt.res();
4013 if (ret < 0)
4014 {
4015 return ret;
4016 }
4017 m_hls_packet_fifo.push(std::move(fifo_pkt));
4018 return 0;
4019 }
4020 }
4021 break;
4022 }
4023 default:
4024 {
4025 break;
4026 }
4027 }
4028 }
4029
4030 ret = av_write_frame(m_out.m_format_ctx, pkt);
4031
4032 if (ret < 0)
4033 {
4034 const char *type;
4035
4036 if (mediatype != AVMEDIA_TYPE_ATTACHMENT)
4037 {
4038 type = av_get_media_type_string(mediatype);
4039
4040 if (type == nullptr)
4041 {
4042 type = "unknown";
4043 }
4044 }
4045 else
4046 {
4047 type = "album art";
4048 }
4049
4050 Logging::error(virtname(), "Could not write %1 frame (error '%2').", type, ffmpeg_geterror(ret).c_str());
4051 }
4052
4053 return ret;
4054}
4055
4056void FFmpeg_Transcoder::make_pts(AVPacket *pkt, int64_t *cur_ts) const
4057{
4058 if (pkt->pts != AV_NOPTS_VALUE)
4059 {
4060 *cur_ts = pkt->pts + pkt->duration;
4061 }
4062 else if (pkt->dts != AV_NOPTS_VALUE)
4063 {
4064 *cur_ts = pkt->dts;
4065 }
4066
4067 if (pkt->duration)
4068 {
4069 if (pkt->pts == AV_NOPTS_VALUE)
4070 {
4071 pkt->pts = *cur_ts;
4072 }
4073
4074 *cur_ts += pkt->duration;
4075
4076 if (pkt->dts == AV_NOPTS_VALUE)
4077 {
4078 pkt->dts = *cur_ts;
4079 }
4080 }
4081}
4082
4084{
4085 int ret = 0;
4086
4087 if (m_in.m_audio.m_stream != nullptr && is_audio_stream(pkt->stream_index) && stream_exists(m_out.m_audio.m_stream_idx))
4088 {
4089 if (m_reset_pts & FFMPEGFS_AUDIO && pkt->pts != AV_NOPTS_VALUE)
4090 {
4091 m_reset_pts &= ~FFMPEGFS_AUDIO; // Clear reset bit
4092
4093 int64_t pkt_pts = ffmpeg_rescale_q(pkt->pts, m_in.m_audio.m_stream->time_base);
4094
4095 m_out.m_audio_pts = ffmpeg_rescale_q(pkt_pts, av_get_time_base_q(), m_out.m_audio.m_stream->time_base);
4096
4097 Logging::debug(virtname(), "Reset the PTS from the audio packet to %1.", format_duration(pkt_pts).c_str());
4098 }
4099
4100 if (!m_copy_audio)
4101 {
4102 int decoded = 0;
4103 ret = decode_audio_frame(pkt, &decoded);
4104 }
4105 else
4106 {
4107 // Simply copy packet without recoding
4108 pkt->stream_index = m_out.m_audio.m_stream_idx;
4109
4110 // Rescale packet
4111 av_packet_rescale_ts(pkt, m_in.m_audio.m_stream->time_base, m_out.m_audio.m_stream->time_base);
4112
4113 // Make PTS/DTS if missing
4114 make_pts(pkt, &m_cur_audio_ts);
4115
4116 pkt->pos = -1;
4117
4118 ret = store_packet(pkt, AVMEDIA_TYPE_AUDIO);
4119 }
4120 }
4121 else if (m_in.m_video.m_stream != nullptr && is_video_stream(pkt->stream_index) && (stream_exists(m_out.m_video.m_stream_idx) || is_frameset()))
4122 {
4123 if (m_reset_pts & FFMPEGFS_VIDEO && pkt->pts != AV_NOPTS_VALUE)
4124 {
4125 m_reset_pts &= ~FFMPEGFS_VIDEO; // Clear reset bit
4126
4127 int64_t pkt_pts = ffmpeg_rescale_q(pkt->pts, m_in.m_video.m_stream->time_base);
4128
4129 m_out.m_video_pts = ffmpeg_rescale_q(pkt_pts, av_get_time_base_q(), m_out.m_video.m_stream->time_base);
4130
4131 Logging::debug(virtname(), "Reset PTS from the video packet to %1.", format_duration(pkt_pts).c_str());
4132 }
4133
4134 if (!m_copy_video)
4135 {
4136 int decoded = 0;
4147#ifndef USE_LIBDVD
4148 ret = decode_video_frame(pkt, &decoded);
4149#else //USE_LIBDVD
4151 {
4152 ret = decode_video_frame(pkt, &decoded);
4153 }
4154 else
4155 {
4156 int lastret = 0;
4157
4158 do
4159 {
4160 // Decode one frame.
4161 ret = decode_video_frame(pkt, &decoded);
4162
4163 if ((ret == AVERROR(EAGAIN) && ret == lastret) || ret == AVERROR_EOF)
4164 {
4165 // If EAGAIN reported twice or stream at EOF
4166 // quit loop, but this is not an error
4167 // (must process all streams).
4168 break;
4169 }
4170
4171 if (ret < 0 && ret != AVERROR(EAGAIN))
4172 {
4173 Logging::error(filename(), "Could not decode video frame (error '%1').", ffmpeg_geterror(ret).c_str());
4174 return ret;
4175 }
4176
4177 lastret = ret;
4178
4179 pkt->data += decoded;
4180 pkt->size -= decoded;
4181 }
4182 while (pkt->size > 0 && (ret == 0 || ret == AVERROR(EAGAIN)));
4183
4184 ret = 0;
4185 }
4186#endif // USE_LIBDVD
4187 }
4188 else
4189 {
4190 // Simply copy packet without recoding
4191 pkt->stream_index = m_out.m_video.m_stream_idx;
4192
4193 // Rescale packet
4194 av_packet_rescale_ts(pkt, m_in.m_video.m_stream->time_base, m_out.m_video.m_stream->time_base);
4195
4196 // Make PTS/DTS if missing
4197 make_pts(pkt, &m_cur_video_ts);
4198
4199 pkt->pos = -1;
4200
4201 ret = store_packet(pkt, AVMEDIA_TYPE_VIDEO);
4202 }
4203 }
4204 else if (is_subtitle_stream(pkt->stream_index))
4205 {
4206 // Decode subtitle. No copy option available.
4207 int decoded = 0;
4208 ret = decode_subtitle(pkt, &decoded);
4209 }
4210 else
4211 {
4212 // Finally process album arts
4213 switch (m_in.m_format_ctx->streams[pkt->stream_index]->codecpar->codec_type)
4214 {
4215 case AVMEDIA_TYPE_VIDEO:
4216 {
4217 for (size_t n = 0; n < m_in.m_album_art.size() && n < m_out.m_album_art.size(); n++)
4218 {
4219 AVStream *input_stream = m_in.m_album_art.at(n).m_stream;
4220
4221 // AV_DISPOSITION_ATTACHED_PIC streams already processed in process_albumarts()
4222 if (pkt->stream_index == input_stream->index && !(input_stream->disposition & AV_DISPOSITION_ATTACHED_PIC))
4223 {
4224 AVStream *output_stream = m_out.m_album_art.at(n).m_stream;
4225
4226 ret = add_albumart_frame(output_stream, pkt);
4227 break;
4228 }
4229 }
4230 break;
4231 }
4232 default:
4233 {
4234 break;
4235 }
4236 }
4237 }
4238
4239 // If decoding errors should be ignored by command line, reset return code.
4240 // Exemptions that need to be passed on anyway:
4241 // * EAGAIN tells the caller to retry, this is not an error
4242 // * AVERROR_EXTERNAL is an unrecoverable error and should be handled
4243 if (!params.m_decoding_errors && ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EXTERNAL)
4244 {
4245 // Ignore error, go on with transcoding
4246 ret = 0;
4247 }
4248
4249 return ret;
4250}
4251
4252int FFmpeg_Transcoder::init_converted_samples(uint8_t ***converted_input_samples, int frame_size)
4253{
4254 int ret;
4255
4256 // Allocate as many pointers as there are audio channels.
4257 // Each pointer will later point to the audio samples of the corresponding
4258 // channels (although it may be nullptr for interleaved formats).
4259
4260 *converted_input_samples = static_cast<uint8_t **>(av_calloc(static_cast<size_t>(get_channels(m_out.m_audio.m_codec_ctx.get())), sizeof(**converted_input_samples)));
4261
4262 if (*converted_input_samples == nullptr)
4263 {
4264 Logging::error(virtname(), "Could not allocate converted input sample pointers.");
4265 return AVERROR(ENOMEM);
4266 }
4267
4268 // Allocate memory for the samples of all channels in one consecutive
4269 // block for convenience.
4270 ret = av_samples_alloc(*converted_input_samples, nullptr,
4272 frame_size,
4273 m_out.m_audio.m_codec_ctx->sample_fmt, 0);
4274 if (ret < 0)
4275 {
4276 Logging::error(virtname(), "Could not allocate converted input samples (error '%1').", ffmpeg_geterror(ret).c_str());
4277 av_freep(&(*converted_input_samples)[0]);
4278 av_free(*converted_input_samples);
4279 return ret;
4280 }
4281 return 0;
4282}
4283
4284int FFmpeg_Transcoder::convert_samples(uint8_t **input_data, int in_samples, uint8_t **converted_data, int *out_samples)
4285{
4286 if (m_audio_resample_ctx != nullptr)
4287 {
4288 int ret;
4289
4290 // Convert the samples using the resampler.
4291 ret = swr_convert(m_audio_resample_ctx, converted_data, *out_samples, const_cast<const uint8_t **>(input_data), in_samples);
4292 if (ret < 0)
4293 {
4294 Logging::error(virtname(), "Could not convert input samples (error '%1').", ffmpeg_geterror(ret).c_str());
4295 return ret;
4296 }
4297
4298 *out_samples = ret;
4299 }
4300 else
4301 {
4302 *out_samples = in_samples;
4303
4304 // No resampling, just copy samples
4305 if (!av_sample_fmt_is_planar(m_out.m_audio.m_codec_ctx->sample_fmt))
4306 {
4307 // Interleaved format
4308 int samples = in_samples * av_get_bytes_per_sample(m_out.m_audio.m_codec_ctx->sample_fmt) * get_channels(m_in.m_audio.m_codec_ctx.get());
4309 std::memcpy(converted_data[0], input_data[0], static_cast<size_t>(samples));
4310 }
4311 else
4312 {
4313 // Planar format
4314 int samples = in_samples * av_get_bytes_per_sample(m_out.m_audio.m_codec_ctx->sample_fmt);
4315 for (int n = 0; n < get_channels(m_out.m_audio.m_codec_ctx.get()); n++)
4316 {
4317 std::memcpy(converted_data[n], input_data[n], static_cast<size_t>(samples));
4318 }
4319 }
4320 }
4321 return 0;
4322}
4323
4324int FFmpeg_Transcoder::add_samples_to_fifo(uint8_t **converted_input_samples, int frame_size)
4325{
4326 int ret;
4327
4328 // Make the audio FIFO as large as it needs to be to hold both,
4329 // the old and the new samples.
4330
4331 ret = m_audio_fifo.realloc(m_audio_fifo.size() + frame_size);
4332 if (ret < 0)
4333 {
4334 Logging::error(virtname(), "Could not reallocate the audio FIFO.");
4335 return ret;
4336 }
4337
4338 // Store the new samples in the audio FIFO buffer.
4339 ret = m_audio_fifo.write(reinterpret_cast<void **>(converted_input_samples), frame_size);
4340 if (ret < frame_size)
4341 {
4342 if (ret < 0)
4343 {
4344 Logging::error(virtname(), "Could not write data to audio FIFO (error '%1').", ffmpeg_geterror(ret).c_str());
4345 }
4346 else
4347 {
4348 Logging::error(virtname(), "Could not write data to audio FIFO.");
4349 }
4350 return AVERROR_EXIT;
4351 }
4352
4353 return 0;
4354}
4355
4356int FFmpeg_Transcoder::flush_frames_all(bool use_flush_packet)
4357{
4358 int ret = 0;
4359
4360 if (m_in.m_audio.m_codec_ctx != nullptr)
4361 {
4362 int ret2 = flush_frames_single(m_in.m_audio.m_stream_idx, use_flush_packet);
4363 if (ret2 < 0)
4364 {
4365 ret = ret2;
4366 }
4367 }
4368
4369 if (m_in.m_video.m_codec_ctx != nullptr)
4370 {
4371 int ret2 = flush_frames_single(m_in.m_video.m_stream_idx, use_flush_packet);
4372 if (ret2 < 0)
4373 {
4374 ret = ret2;
4375 }
4376 }
4377
4378 return ret;
4379}
4380
4381int FFmpeg_Transcoder::flush_frames_single(int stream_idx, bool use_flush_packet)
4382{
4383 int ret = 0;
4384
4385 if (stream_exists(stream_idx))
4386 {
4387 int (FFmpeg_Transcoder::*decode_frame_ptr)(AVPacket *pkt, int *decoded) = nullptr;
4388
4390 {
4391 decode_frame_ptr = &FFmpeg_Transcoder::decode_audio_frame;
4392 }
4394 {
4395 decode_frame_ptr = &FFmpeg_Transcoder::decode_video_frame;
4396 }
4397
4398 if (decode_frame_ptr != nullptr)
4399 {
4400 FFmpeg_Packet flush_packet(stream_idx);
4401 AVPacket *flush_packet_ptr = nullptr;
4402
4403 if (flush_packet.res() < 0)
4404 {
4405 return flush_packet.res();
4406 }
4407
4408 if (use_flush_packet)
4409 {
4410 flush_packet->data = nullptr;
4411 flush_packet->size = 0;
4412 flush_packet->stream_index = stream_idx;
4413 flush_packet_ptr = flush_packet;
4414 }
4415
4416 // cppcheck-suppress knownConditionTrueFalse
4417 for (int decoded = 1; decoded;)
4418 {
4419 ret = (this->*decode_frame_ptr)(flush_packet_ptr, &decoded);
4420 if (ret < 0 && ret != AVERROR(EAGAIN))
4421 {
4422 break;
4423 }
4424 }
4425 }
4426 }
4427
4428 return ret;
4429}
4430
4432{
4433 // Packet used for temporary storage.
4434 FFmpeg_Packet pkt;
4435 int ret = pkt.res();
4436
4437 if (ret < 0)
4438 {
4439 return ret;
4440 }
4441
4442 try
4443 {
4444 // Read one frame from the input file into a temporary packet.
4445 ret = av_read_frame(m_in.m_format_ctx, pkt);
4446 if (ret < 0)
4447 {
4448 if (ret == AVERROR_EOF)
4449 {
4450 // If we are the the end of the file, flush the decoder below.
4451 *finished = 1;
4452 Logging::trace(virtname(), "Read input file to EOF.");
4453 }
4454 else
4455 {
4456 Logging::error(virtname(), "Could not read frame (error '%1').", ffmpeg_geterror(ret).c_str());
4457 throw ret;
4458 }
4459 }
4460
4462 {
4463 // Check for end of cue sheet track
4465 if (is_audio_stream(pkt->stream_index))
4466 {
4467 int64_t pkt_pts = ffmpeg_rescale_q(pkt->pts, m_in.m_audio.m_stream->time_base);
4469 {
4470 Logging::trace(virtname(), "Read to end of track.");
4471 *finished = 1;
4472 ret = AVERROR_EOF;
4473 }
4474 }
4475 }
4476
4477 if (!*finished)
4478 {
4479 // Decode one packet, at least with the old API (!LAV_NEW_PACKET_INTERFACE)
4480 // it seems a packet can contain more than one frame so loop around it
4481 // if necessary...
4482 ret = decode_frame(pkt);
4483
4484 if (ret < 0 && ret != AVERROR(EAGAIN))
4485 {
4486 throw ret;
4487 }
4488 }
4489 else
4490 {
4491 // Flush cached frames, ignoring any errors
4492 flush_frames_all(true);
4493 }
4494
4495 ret = 0; // Errors will be reported by exception
4496 }
4497 catch (int _ret)
4498 {
4499 ret = _ret;
4500 }
4501
4502 return ret;
4503}
4504
4505int FFmpeg_Transcoder::init_audio_output_frame(AVFrame *frame, int frame_size) const
4506{
4507 int ret;
4508
4509 //
4510 // Set the frame's parameters, especially its size and format.
4511 // av_frame_get_buffer needs this to allocate memory for the
4512 // audio samples of the frame.
4513 // Default channel layouts based on the number of channels
4514 // are assumed for simplicity.
4515
4516 frame->nb_samples = frame_size;
4517#if LAVU_DEP_OLD_CHANNEL_LAYOUT
4518 ret = av_channel_layout_copy(&frame->ch_layout, &m_out.m_audio.m_codec_ctx->ch_layout);
4519 if (ret < 0)
4520 {
4521 Logging::error(virtname(), "Unable to copy channel layout (error '%1').", ffmpeg_geterror(ret).c_str());
4522 return ret;
4523 }
4524#else // !LAVU_DEP_OLD_CHANNEL_LAYOUT
4525 frame->channel_layout = m_out.m_audio.m_codec_ctx->channel_layout;
4526#endif // !LAVU_DEP_OLD_CHANNEL_LAYOUT
4527 frame->format = m_out.m_audio.m_codec_ctx->sample_fmt;
4528 frame->sample_rate = m_out.m_audio.m_codec_ctx->sample_rate;
4529
4530 // Allocate the samples of the created frame. This call will make
4531 // sure that the audio frame can hold as many samples as specified.
4532 // 29.05.2021: Let API decide about alignment. Should be properly set for the current CPU.
4533
4534 ret = av_frame_get_buffer(frame, 0);
4535 if (ret < 0)
4536 {
4537 Logging::error(virtname(), "Could allocate output frame samples (error '%1').", ffmpeg_geterror(ret).c_str());
4538 return ret;
4539 }
4540
4541 return 0;
4542}
4543
4545{
4546 if (pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
4547 {
4548 // Normally we have already added the PTS to the frame when it was created. Just in case
4549 // this failed, and there are no valid PTS/DTS values, we add it here.
4550 int64_t pkt_duration;
4551
4552 // Some encoders to not produce dts/pts.
4553 // So we make some up.
4554 if (pkt->duration)
4555 {
4556 pkt_duration = pkt->duration;
4557
4558#if !LAVC_DEP_TICKSPERFRAME
4559 // This has probably long since been fixed in FFmpeg, so we remove this completly
4560 // instead of replacing it with updated code.
4561 if (m_out.m_audio.m_codec_ctx->codec_id == AV_CODEC_ID_OPUS || m_current_format->filetype() == FILETYPE::TS || m_current_format->filetype() == FILETYPE::HLS)
4562 {
4569 if (pkt_duration > 0 && m_out.m_audio.m_stream->codecpar->sample_rate > 0)
4570 {
4571 pkt->duration = pkt_duration = static_cast<int>(av_rescale(pkt_duration, static_cast<int64_t>(m_out.m_audio.m_stream->time_base.den) * m_out.m_audio.m_codec_ctx->ticks_per_frame, m_out.m_audio.m_stream->codecpar->sample_rate * static_cast<int64_t>(m_out.m_audio.m_stream->time_base.num)));
4572 }
4573 }
4574#endif
4575 }
4576 else
4577 {
4578 pkt_duration = 1;
4579 }
4580
4581 pkt->dts = m_out.m_audio_pts - 1;
4582 pkt->pts = m_out.m_audio_pts;
4583
4584 m_out.m_audio_pts += pkt_duration;
4585 }
4586}
4587
4588int FFmpeg_Transcoder::encode_audio_frame(const AVFrame *frame, int *data_present)
4589{
4590 // Packet used for temporary storage.
4591 FFmpeg_Packet pkt;
4592 int ret = pkt.res();
4593
4594 if (ret < 0)
4595 {
4596 return ret;
4597 }
4598
4599 try
4600 {
4601 // Encode the audio frame and store it in the temporary packet.
4602 // The output audio stream encoder is used to do this.
4603
4604 *data_present = 0;
4605
4606 // send the frame for encoding
4607 ret = avcodec_send_frame(m_out.m_audio.m_codec_ctx.get(), frame);
4608 if (ret < 0 && ret != AVERROR_EOF)
4609 {
4610 Logging::error(virtname(), "Could not encode audio frame (error %1').", ffmpeg_geterror(ret).c_str());
4611 throw ret;
4612 }
4613
4614 // read all the available output packets (in general there may be any number of them)
4615 while (ret >= 0)
4616 {
4617 *data_present = 0;
4618
4619 ret = avcodec_receive_packet(m_out.m_audio.m_codec_ctx.get(), pkt);
4620 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
4621 {
4622 throw ret;
4623 }
4624 else if (ret < 0)
4625 {
4626 Logging::error(virtname(), "Could not encode audio frame (error '%1').", ffmpeg_geterror(ret).c_str());
4627 throw ret;
4628 }
4629
4630 *data_present = 1;
4631
4632 // Write one audio frame from the temporary packet to the output buffer.
4633 {
4634 pkt->stream_index = m_out.m_audio.m_stream_idx;
4635
4636 const bool packet_has_timestamps =
4637 pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE;
4638
4639 produce_audio_dts(pkt);
4640
4641 /*
4642 * AVFrame::pts passed to the encoder is in codec time base.
4643 * Therefore packet timestamps returned by the encoder are in
4644 * codec time base as well and must be converted to the output
4645 * stream time base before muxing/storing.
4646 *
4647 * If produce_audio_dts() had to invent timestamps, it used the
4648 * existing m_out.m_audio_pts fallback in output stream time base;
4649 * do not rescale those invented values a second time.
4650 */
4651 if (packet_has_timestamps)
4652 {
4653 av_packet_rescale_ts(pkt,
4654 m_out.m_audio.m_codec_ctx->time_base,
4655 m_out.m_audio.m_stream->time_base);
4656 }
4657
4658 ret = store_packet(pkt, AVMEDIA_TYPE_AUDIO);
4659 if (ret < 0)
4660 {
4661 throw ret;
4662 }
4663 }
4664 }
4665
4666 pkt.unref();
4667 }
4668 catch (int _ret)
4669 {
4670 pkt.unref();
4671 ret = _ret;
4672 }
4673
4674 return ret;
4675}
4676
4677int FFmpeg_Transcoder::encode_image_frame(const AVFrame *frame, int *data_present)
4678{
4679 *data_present = 0;
4680
4681 if (frame == nullptr || m_skip_next_frame)
4682 {
4683 // This called internally to flush frames. We do not have a cache to flush, so simply ignore that.
4684 // After seek oprations we need to skip the first frame.
4685 m_skip_next_frame = false;
4686 return 0;
4687 }
4688
4689 if (m_current_format == nullptr)
4690 {
4691 Logging::error(virtname(), "INTERNAL ERROR: FFmpeg_Transcoder::encode_image_frame()! Missing format.");
4692 return AVERROR(EINVAL);
4693 }
4694
4695 if (m_buffer == nullptr)
4696 {
4697 Logging::error(virtname(), "INTERNAL ERROR: FFmpeg_Transcoder::encode_image_frame()! Cache not open.");
4698 return AVERROR(EINVAL);
4699 }
4700
4701 FFmpeg_Packet pkt;
4702 int ret = pkt.res();
4703
4704 if (ret < 0)
4705 {
4706 return ret;
4707 }
4708
4709 try
4710 {
4711 FFmpeg_Frame cloned_frame(frame); // Clone frame. Does not copy data but references it, only the properties are copied. Not a big memory impact.
4712
4713 ret = cloned_frame.res();
4714 if (ret < 0)
4715 {
4716 Logging::error(virtname(), "Could not encode image frame (error '%1').", ffmpeg_geterror(ret).c_str());
4717 throw ret;
4718 }
4719
4720 uint32_t frame_no = pts_to_frame(m_in.m_video.m_stream, frame->pts);
4721
4722 if (m_current_format->video_codec() == AV_CODEC_ID_MJPEG)
4723 {
4724 // The MJEPG codec requires monotonically growing PTS values so we fake some to avoid them going backwards after seeks
4725 cloned_frame->pts = frame_to_pts(m_in.m_video.m_stream, ++m_fake_frame_no);
4726 }
4727
4728 *data_present = 0;
4729
4730 // send the frame for encoding
4731 ret = avcodec_send_frame(m_out.m_video.m_codec_ctx.get(), cloned_frame);
4732 if (ret < 0 && ret != AVERROR_EOF)
4733 {
4734 Logging::error(virtname(), "Could not encode image frame (error '%1').", ffmpeg_geterror(ret).c_str());
4735 throw ret;
4736 }
4737
4738 // read all the available output packets (in general there may be any number of them
4739 while (ret >= 0)
4740 {
4741 *data_present = 0;
4742
4743 ret = avcodec_receive_packet(m_out.m_video.m_codec_ctx.get(), pkt);
4744 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
4745 {
4746 pkt.unref();
4747 break;
4748 }
4749 else if (ret < 0)
4750 {
4751 Logging::error(virtname(), "Could not encode image frame (error '%1').", ffmpeg_geterror(ret).c_str());
4752 throw ret;
4753 }
4754
4755 *data_present = 1;
4756
4757 // Write one video frame from the temporary packet to the output buffer.
4758 {
4759 // Store current video PTS
4760 if (pkt->pts != AV_NOPTS_VALUE)
4761 {
4762 m_out.m_video_pts = pkt->pts;
4763 }
4764
4765 m_buffer->write_frame(pkt->data, static_cast<size_t>(pkt->size), frame_no);
4766
4767 if (m_last_seek_frame_no == frame_no) // Skip frames until seek pos
4768 {
4770 }
4771 }
4772
4773 pkt.unref();
4774 }
4775 }
4776 catch (int _ret)
4777 {
4778 pkt.unref();
4779 ret = _ret;
4780 }
4781
4782 return ret;
4783}
4784
4785int FFmpeg_Transcoder::encode_video_frame(const AVFrame *frame, int *data_present)
4786{
4787 if (m_out.m_video.m_stream == nullptr)
4788 {
4789 return 0; // ignore, avoid crash
4790 }
4791
4792 // Packet used for temporary storage.
4793 if (frame != nullptr)
4794 {
4795#if LAVU_ADD_NEW_FRAME_FLAGS
4796 if (frame->flags & AV_FRAME_FLAG_INTERLACED)
4797 {
4798 if (m_out.m_video.m_codec_ctx->codec->id == AV_CODEC_ID_MJPEG)
4799 {
4800 m_out.m_video.m_stream->codecpar->field_order = (frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? AV_FIELD_TT : AV_FIELD_BB;
4801 }
4802 else
4803 {
4804 m_out.m_video.m_stream->codecpar->field_order = (frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? AV_FIELD_TB : AV_FIELD_BT;
4805 }
4806 }
4807#else // !LAVU_ADD_NEW_FRAME_FLAGS
4808 if (frame->interlaced_frame)
4809 {
4810 if (m_out.m_video.m_codec_ctx->codec->id == AV_CODEC_ID_MJPEG)
4811 {
4812 m_out.m_video.m_stream->codecpar->field_order = frame->top_field_first ? AV_FIELD_TT : AV_FIELD_BB;
4813 }
4814 else
4815 {
4816 m_out.m_video.m_stream->codecpar->field_order = frame->top_field_first ? AV_FIELD_TB : AV_FIELD_BT;
4817 }
4818 }
4819#endif // !LAVU_ADD_NEW_FRAME_FLAGS
4820 else
4821 {
4822 m_out.m_video.m_stream->codecpar->field_order = AV_FIELD_PROGRESSIVE;
4823 }
4824 }
4825 FFmpeg_Frame *hw_frame = nullptr;
4826 FFmpeg_Packet pkt;
4827 int ret = pkt.res();
4828
4829 if (ret < 0)
4830 {
4831 return ret;
4832 }
4833
4834 try
4835 {
4836 if (m_hwaccel_enable_enc_buffering && frame != nullptr)
4837 {
4838 hw_frame = new (std::nothrow) FFmpeg_Frame(m_out.m_video.m_stream_idx);
4839 if (hw_frame == nullptr)
4840 {
4841 ret = AVERROR(ENOMEM);
4842 Logging::error(virtname(), "Could not encode video frame at PTS=%1 (error %2').", ffmpeg_rescale_q(frame->pts, m_in.m_video.m_stream->time_base), ffmpeg_geterror(ret).c_str());
4843 throw ret;
4844 }
4845
4846 ret = hw_frame->res();
4847 if (ret < 0)
4848 {
4849 Logging::error(virtname(), "Could not encode video frame at PTS=%1 (error %2').", ffmpeg_rescale_q(frame->pts, m_in.m_video.m_stream->time_base), ffmpeg_geterror(ret).c_str());
4850 throw ret;
4851 }
4852
4853 // If encoding is done in hardware, the resulting frame data needs to be copied to hardware
4854 ret = hwframe_copy_to_hw(m_out.m_video.m_codec_ctx.get(), hw_frame, frame);
4855 if (ret < 0)
4856 {
4857 throw ret;
4858 }
4859 frame = *hw_frame; // Copy, not clone!
4860 }
4861
4862 // Encode the video frame and store it in the temporary packet.
4863 // The output video stream encoder is used to do this.
4864
4865 *data_present = 0;
4866
4867 // send the frame for encoding
4868 ret = avcodec_send_frame(m_out.m_video.m_codec_ctx.get(), frame);
4869 if (ret < 0 && ret != AVERROR_EOF)
4870 {
4871 Logging::error(virtname(), "Could not encode video frame (error %1').", ffmpeg_geterror(ret).c_str());
4872 throw ret;
4873 }
4874
4875 // read all the available output packets (in general there may be any number of them
4876 while (ret >= 0)
4877 {
4878 *data_present = 0;
4879
4880 ret = avcodec_receive_packet(m_out.m_video.m_codec_ctx.get(), pkt);
4881 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
4882 {
4883 pkt.unref();
4884 break;
4885 }
4886 else if (ret < 0)
4887 {
4888 Logging::error(virtname(), "Could not encode video frame (error '%1').", ffmpeg_geterror(ret).c_str());
4889 throw ret;
4890 }
4891
4892 *data_present = 1;
4893
4894 // Write one video frame from the temporary packet to the output buffer.
4895 {
4896 // Fix for issue #46: bitrate too high.
4897 av_packet_rescale_ts(pkt, m_out.m_video.m_codec_ctx->time_base, m_out.m_video.m_stream->time_base);
4898
4899 if (!(m_out.m_format_ctx->oformat->flags & AVFMT_NOTIMESTAMPS))
4900 {
4901 if (pkt->dts != AV_NOPTS_VALUE &&
4902 pkt->pts != AV_NOPTS_VALUE &&
4903 pkt->dts > pkt->pts &&
4904 m_out.m_last_mux_dts != AV_NOPTS_VALUE)
4905 {
4906
4907 Logging::warning(virtname(), "Invalid DTS=%1 PTS=%2 in video output, replacing by guess.", pkt->dts, pkt->pts);
4908
4909 pkt->pts =
4910 pkt->dts = pkt->pts + pkt->dts + m_out.m_last_mux_dts + 1
4911 - FFMIN3(pkt->pts, pkt->dts, m_out.m_last_mux_dts + 1)
4912 - FFMAX3(pkt->pts, pkt->dts, m_out.m_last_mux_dts + 1);
4913 }
4914
4915 if (pkt->dts != AV_NOPTS_VALUE && m_out.m_last_mux_dts != AV_NOPTS_VALUE)
4916 {
4917 int64_t max = m_out.m_last_mux_dts + !(m_out.m_format_ctx->oformat->flags & AVFMT_TS_NONSTRICT);
4918 // AVRational avg_frame_rate = { m_out.m_video.m_stream->avg_frame_rate.den, m_out.m_video.m_stream->avg_frame_rate.num };
4919 // int64_t max = m_out.m_last_mux_dts + ffmpeg_rescale_q(1, avg_frame_rate, m_out.m_video.m_stream->time_base);
4920
4921 if (pkt->dts < max)
4922 {
4923 Logging::trace(virtname(), "Non-monotonous DTS in video output stream; previous: %1, current: %2; changing to %3. This may result in incorrect timestamps in the output.", m_out.m_last_mux_dts, pkt->dts, max);
4924
4925 if (pkt->pts >= pkt->dts)
4926 {
4927 pkt->pts = FFMAX(pkt->pts, max);
4928 }
4929 pkt->dts = max;
4930 }
4931 }
4932 }
4933
4934 if (frame != nullptr && !pkt->duration)
4935 {
4936#if !LAVU_DEP_PKT_DURATION
4937 pkt->duration = frame->pkt_duration;
4938#else
4939 pkt->duration = frame->duration;
4940#endif
4941 }
4942
4943 if (pkt->pts != AV_NOPTS_VALUE)
4944 {
4945 m_out.m_video_pts = pkt->pts;
4946 m_out.m_last_mux_dts = (pkt->dts != AV_NOPTS_VALUE) ? pkt->dts : (pkt->pts - pkt->duration);
4947 }
4948
4949 // Write packet to buffer
4950 ret = store_packet(pkt, AVMEDIA_TYPE_VIDEO);
4951 if (ret < 0)
4952 {
4953 throw ret;
4954 }
4955 }
4956
4957 pkt.unref();
4958 }
4959 }
4960 catch (int _ret)
4961 {
4962 pkt.unref();
4963 ret = _ret;
4964 }
4965
4966 delete hw_frame;
4967
4968 return ret;
4969}
4970
4971int FFmpeg_Transcoder::encode_subtitle(const AVSubtitle *sub, int out_stream_idx, int *data_present)
4972{
4973 StreamRef * out_streamref = get_out_subtitle_stream(out_stream_idx);
4974
4975 *data_present = 0;
4976
4977 if (out_streamref == nullptr)
4978 {
4979 Logging::error(virtname(), "INTERNAL ERROR: FFmpeg_Transcoder::encode_subtitle()! Invalid stream index #%1.", out_stream_idx);
4980 return AVERROR(EINVAL);
4981 }
4982
4983 // Packet used for temporary storage.
4984 FFmpeg_Packet pkt;
4985 int ret = pkt.res();
4986
4987 if (ret < 0)
4988 {
4989 return ret;
4990 }
4991
4992 AVSubtitle subtmp;
4993
4994 // Make a local copy, we have to modify it
4995 std::memcpy(&subtmp, sub, sizeof(AVSubtitle));
4996
4997 try
4998 {
4999 int nb;
5000 int64_t sub_pts;
5001
5002 if (subtmp.pts == AV_NOPTS_VALUE)
5003 {
5004 Logging::error(virtname(), "Subtitle packets must have a PTS (stream index #%1).", out_streamref->m_stream_idx);
5005 throw AVERROR(EINVAL);
5006 }
5007
5008 // Allocate a packet with 1KB buffer, hope that's sufficient
5009 ret = av_new_packet(pkt, 1024 * 1024);
5010 if (ret < 0)
5011 {
5012 Logging::error(virtname(), "Failed to allocate new packet (error '%1').", ffmpeg_geterror(ret).c_str());
5013 throw ret;
5014 }
5015
5016 // Note: DVB subtitles need one packet to draw them and one other packet to clear them
5017 if (out_streamref->m_codec_ctx->codec_id == AV_CODEC_ID_DVB_SUBTITLE)
5018 {
5019 nb = 2;
5020 }
5021 else
5022 {
5023 nb = 1;
5024 }
5025
5026 // shift timestamp
5027 sub_pts = subtmp.pts;
5028
5029 //if (out_streamref->m_stream->start_time != AV_NOPTS_VALUE)
5030 //{
5031 // pts -= ffmpeg_rescale_q(out_streamref->m_stream->start_time, out_streamref->m_stream->time_base);
5032 //}
5033
5034 for (int i = 0; i < nb; i++)
5035 {
5036 unsigned save_num_rects = subtmp.num_rects;
5037 subtmp.pts = sub_pts;
5038 // Some decoders may return end_display_time as UINT32_MAX, this causes strange results.
5039 if (subtmp.end_display_time == UINT32_MAX)
5040 {
5041 subtmp.end_display_time = 0;
5042 }
5043
5044 // start_display_time is required to be 0
5045 subtmp.pts += ffmpeg_rescale_q(subtmp.start_display_time, AVRational({ 1, 1000 }));
5046 subtmp.end_display_time -= subtmp.start_display_time;
5047 subtmp.start_display_time = 0;
5048 if (i == 1)
5049 {
5050 subtmp.num_rects = 0;
5051 }
5052
5053 // The avcodec_encode_subtitle seems to be not completely ready
5054 ret = avcodec_encode_subtitle(out_streamref->m_codec_ctx.get(), pkt->data, pkt->size, &subtmp);
5055 if (i == 1)
5056 {
5057 subtmp.num_rects = save_num_rects;
5058 }
5059
5060 if (ret < 0)
5061 {
5062 Logging::error(virtname(), "Could not encode subtitle frame (error '%1').", ffmpeg_geterror(ret).c_str());
5063 throw ret;
5064 }
5065
5066 pkt->size = ret;
5067 pkt->pts = ffmpeg_rescale_q(subtmp.pts, av_get_time_base_q(), out_streamref->m_stream->time_base);
5068 pkt->duration = ffmpeg_rescale_q(subtmp.end_display_time, AVRational({ 1, 1000 }), out_streamref->m_stream->time_base);
5069 pkt->stream_index = out_streamref->m_stream_idx;
5070
5071 if (out_streamref->m_codec_ctx->codec_id == AV_CODEC_ID_DVB_SUBTITLE)
5072 {
5073 // the pts correction is handled here. Maybe handling it in the codec would be better
5074 if (i)
5075 {
5076 pkt->pts += ffmpeg_rescale_q(subtmp.end_display_time, AVRational({ 1, 1000 }), out_streamref->m_stream->time_base);
5077 }
5078 }
5079 pkt->dts = pkt->pts;
5080
5081 ret = store_packet(pkt, AVMEDIA_TYPE_SUBTITLE);
5082 if (ret < 0)
5083 {
5084 throw ret;
5085 }
5086
5087 *data_present = 1;
5088 }
5089 pkt.unref();
5090 }
5091 catch (int _ret)
5092 {
5093 pkt.unref();
5094 ret = _ret;
5095 }
5096
5097 return ret;
5098}
5099
5101{
5102 // Temporary storage of the output samples of the frame written to the file.
5103 FFmpeg_Frame output_frame(m_out.m_audio.m_stream_idx);
5104 int ret = 0;
5105
5106 ret = output_frame.res();
5107 if (ret < 0)
5108 {
5109 Logging::error(virtname(), "Could not read data from the audio FIFO (error '%1').", ffmpeg_geterror(ret).c_str());
5110 return ret;
5111 }
5112
5113 // Use the maximum number of possible samples per frame.
5114 // If there is less than the maximum possible frame size in the audio FIFO
5115 // buffer use this number. Otherwise, use the maximum possible frame size
5116
5117 frame_size = FFMIN(m_audio_fifo.size(), frame_size);
5118
5119 // Initialise temporary storage for one output frame.
5120 ret = init_audio_output_frame(output_frame, frame_size);
5121 if (ret < 0)
5122 {
5123 return ret;
5124 }
5125
5126 // Read as many samples from the FIFO buffer as required to fill the frame.
5127 // The samples are stored in the frame temporarily.
5128
5129 ret = m_audio_fifo.read(reinterpret_cast<void **>(output_frame->data), frame_size);
5130 if (ret < frame_size)
5131 {
5132 if (ret < 0)
5133 {
5134 Logging::error(virtname(), "Could not read data from the audio FIFO (error '%1').", ffmpeg_geterror(ret).c_str());
5135 }
5136 else
5137 {
5138 Logging::error(virtname(), "Could not read data from the audio FIFO.");
5139 ret = AVERROR_EXIT;
5140 }
5141 return ret;
5142 }
5143
5144 /*
5145 * Build the output frame PTS.
5146 *
5147 * Keep m_out.m_audio_pts in the output stream time base because that is
5148 * what the cache/frame map and muxing side use. However, AVFrame::pts
5149 * handed to avcodec_send_frame() must use the encoder codec time base.
5150 *
5151 * This mirrors the video path: frames are passed to the encoder in codec
5152 * time base, and encoded packets are converted back to stream time base
5153 * before they are stored.
5154 */
5155 const int64_t stream_pts = m_out.m_audio_pts;
5156
5157 if (output_frame->sample_rate)
5158 {
5159 // Not used for encoding, but keep it meaningful for diagnostics.
5160 output_frame->best_effort_timestamp = ffmpeg_rescale_q(stream_pts,
5161 m_out.m_audio.m_stream->time_base,
5162 m_in.m_audio.m_stream->time_base);
5163
5164 output_frame->pts = ffmpeg_rescale_q(stream_pts,
5165 m_out.m_audio.m_stream->time_base,
5166 m_out.m_audio.m_codec_ctx->time_base);
5167
5168 // duration = `a * b / c` = AV_TIME_BASE * output_frame->nb_samples / output_frame->sample_rate;
5169 int64_t sample_duration = av_rescale(AV_TIME_BASE, output_frame->nb_samples, output_frame->sample_rate);
5170
5171 sample_duration = ffmpeg_rescale_q(sample_duration, av_get_time_base_q(), m_out.m_audio.m_stream->time_base);
5172
5173 m_out.m_audio_pts += sample_duration;
5174 }
5175
5176 int64_t pos = ffmpeg_rescale_q_rnd(stream_pts - m_out.m_audio.m_start_time, m_out.m_audio.m_stream->time_base);
5177
5178 m_frame_map.emplace(pos, output_frame);
5179
5180 return ret;
5181}
5182
5184{
5185 int ret;
5186
5187 ret = av_write_trailer(m_out.m_format_ctx);
5188 if (ret < 0)
5189 {
5190 Logging::error(virtname(), "Could not write output file trailer (error '%1').", ffmpeg_geterror(ret).c_str());
5191 return ret;
5192 }
5193
5194 return 0;
5195}
5196
5198{
5199 return m_mtime;
5200}
5201
5202template <size_t size>
5203const char * FFmpeg_Transcoder::tagcpy(char (&out) [ size ], const std::string & in) const // NOLINT(modernize-avoid-c-arrays)
5204{
5205 std::memset(out, ' ', size);
5206 std::memcpy(out, in.c_str(), std::min(size, in.size()));
5207 return out;
5208}
5209
5210template <class T>
5211const T & FFmpeg_Transcoder::tagcpy(T & out, const std::string & in) const
5212{
5213 out.fill(' ');
5214 std::memcpy(out.data(), in.c_str(), std::min(out.size(), in.size()));
5215 // std::memset(out, ' ', size);
5216 // std::memcpy(out, in.c_str(), std::min(size, in.size()));
5217 return out;
5218}
5219
5220
5221void FFmpeg_Transcoder::copy_metadata(AVDictionary **metadata_out, const AVDictionary *metadata_in, bool contentstream)
5222{
5223 AVDictionaryEntry *tag = nullptr;
5224
5225 while ((tag = av_dict_get(metadata_in, "", tag, AV_DICT_IGNORE_SUFFIX)) != nullptr)
5226 {
5227 std::string value(tag->value);
5228
5229 if (contentstream && m_virtualfile != nullptr && m_virtualfile->m_flags & VIRTUALFLAG_CUESHEET)
5230 {
5231 // Replace tags with cue sheet values
5232 if (!strcasecmp(tag->key, "ARTIST"))
5233 {
5235 }
5236 else if (!strcasecmp(tag->key, "TITLE"))
5237 {
5239 }
5240 else if (!strcasecmp(tag->key, "TRACK"))
5241 {
5243 }
5244 }
5245
5246 dict_set_with_check(metadata_out, tag->key, value.c_str(), 0, virtname());
5247
5248 if (contentstream && m_out.m_filetype == FILETYPE::MP3)
5249 {
5250 // For MP3 fill in ID3v1 structure
5251 if (!strcasecmp(tag->key, "ARTIST"))
5252 {
5253 tagcpy(m_out.m_id3v1.m_artist, value);
5254 }
5255 else if (!strcasecmp(tag->key, "TITLE"))
5256 {
5257 tagcpy(m_out.m_id3v1.m_title, value);
5258 }
5259 else if (!strcasecmp(tag->key, "ALBUM"))
5260 {
5261 tagcpy(m_out.m_id3v1.m_album, value);
5262 }
5263 else if (!strcasecmp(tag->key, "COMMENT"))
5264 {
5265 tagcpy(m_out.m_id3v1.m_comment, value);
5266 }
5267 else if (!strcasecmp(tag->key, "YEAR") || !strcasecmp(tag->key, "DATE"))
5268 {
5269 tagcpy(m_out.m_id3v1.m_year, value);
5270 }
5271 else if (!strcasecmp(tag->key, "TRACK"))
5272 {
5273 m_out.m_id3v1.m_title_no = static_cast<char>(std::stoi(value));
5274 }
5275 }
5276 }
5277}
5278
5280{
5281 Logging::trace(virtname(), "Processing metadata.");
5282
5283 if (m_in.m_audio.m_stream != nullptr && m_in.m_audio.m_stream->codecpar->codec_id == AV_CODEC_ID_VORBIS)
5284 {
5285 // For some formats (namely ogg) FFmpeg returns the tags, odd enough, with streams...
5286 copy_metadata(&m_out.m_format_ctx->metadata, m_in.m_audio.m_stream->metadata);
5287 }
5288
5289 copy_metadata(&m_out.m_format_ctx->metadata, m_in.m_format_ctx->metadata);
5290
5291 if (m_out.m_audio.m_stream != nullptr && m_in.m_audio.m_stream != nullptr)
5292 {
5293 // Copy audio stream meta data
5294 copy_metadata(&m_out.m_audio.m_stream->metadata, m_in.m_audio.m_stream->metadata);
5295 }
5296
5297 if (m_out.m_video.m_stream != nullptr && m_in.m_video.m_stream != nullptr)
5298 {
5299 // Copy video stream meta data
5300 copy_metadata(&m_out.m_video.m_stream->metadata, m_in.m_video.m_stream->metadata);
5301 }
5302
5303 // Also copy album art meta tags
5304 for (size_t n = 0; n < m_in.m_album_art.size() && n < m_out.m_album_art.size(); n++)
5305 {
5306 AVStream *input_stream = m_in.m_album_art.at(n).m_stream;
5307 AVStream *output_stream = m_out.m_album_art.at(n).m_stream;
5308
5309 copy_metadata(&output_stream->metadata, input_stream->metadata, is_audio_stream(input_stream->index) || is_video_stream(input_stream->index));
5310 }
5311
5313 {
5316 dict_set_with_check(&m_out.m_format_ctx->metadata, "ARTIST", m_virtualfile->m_cuesheet_track.m_artist.c_str(), 0, virtname(), true);
5317 if (av_dict_get(m_out.m_format_ctx->metadata, "ALBUM_ARTIST", nullptr, 0) == nullptr)
5318 {
5319 // Issue #78: duplicate ARTIST tag to ALBUM_ARTIST, if target is empty.
5320 dict_set_with_check(&m_out.m_format_ctx->metadata, "ALBUM_ARTIST", m_virtualfile->m_cuesheet_track.m_artist.c_str(), 0, virtname(), true);
5321 }
5322 dict_set_with_check(&m_out.m_format_ctx->metadata, "TITLE", m_virtualfile->m_cuesheet_track.m_title.c_str(), 0, virtname(), true);
5323 dict_set_with_check(&m_out.m_format_ctx->metadata, "ALBUM", m_virtualfile->m_cuesheet_track.m_album.c_str(), 0, virtname(), true);
5324 dict_set_with_check(&m_out.m_format_ctx->metadata, "GENRE", m_virtualfile->m_cuesheet_track.m_genre.c_str(), 0, virtname(), true);
5325 dict_set_with_check(&m_out.m_format_ctx->metadata, "DATE", m_virtualfile->m_cuesheet_track.m_date.c_str(), 0, virtname(), true);
5326 }
5327
5328 return 0;
5329}
5330
5332{
5333 int ret = 0;
5334
5335 for (size_t n = 0; n < m_in.m_album_art.size() && n < m_out.m_album_art.size(); n++)
5336 {
5337 AVStream *input_stream = m_in.m_album_art.at(n).m_stream;
5338
5339 if (input_stream->disposition & AV_DISPOSITION_ATTACHED_PIC)
5340 {
5341 AVStream *output_stream = m_out.m_album_art.at(n).m_stream;
5342
5343 ret = add_albumart_frame(output_stream, &input_stream->attached_pic);
5344 if (ret < 0)
5345 {
5346 break;
5347 }
5348 }
5349 }
5350
5351 return ret;
5352}
5353
5355{
5356 if (m_in.m_audio.m_codec_ctx != nullptr)
5357 {
5358 avcodec_flush_buffers(m_in.m_audio.m_codec_ctx.get());
5359 }
5360 if (m_in.m_video.m_codec_ctx != nullptr)
5361 {
5362 avcodec_flush_buffers(m_in.m_video.m_codec_ctx.get());
5363 }
5364}
5365
5367{
5368 m_have_seeked = true; // Note that we have seeked, thus skipped frames. We need to start transcoding over to fill any gaps.
5369
5370 //m_skip_next_frame = true; /**< @todo Take deinterlace into account. If deinterlace is on the frame number is decreased by one. */
5371
5373 {
5374 --frame_no;
5375 }
5376
5377 int64_t vstream_pts = frame_to_pts(m_in.m_video.m_stream, frame_no);
5378
5379 if (m_in.m_video.m_stream->start_time != AV_NOPTS_VALUE)
5380 {
5381 vstream_pts += m_in.m_video.m_stream->start_time;
5382 }
5383
5384 return av_seek_frame(m_in.m_format_ctx, m_in.m_video.m_stream_idx, vstream_pts, AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME);
5385}
5386
5387int FFmpeg_Transcoder::skip_decoded_frames(uint32_t frame_no, bool forced_seek)
5388{
5389 int ret = 0;
5390 uint32_t next_frame_no = frame_no;
5391
5392 // Seek next undecoded frame
5393 for (; m_buffer->have_frame(next_frame_no); next_frame_no++)
5394 {
5395 std::this_thread::yield();
5396 }
5397
5398 if (next_frame_no > m_virtualfile->m_video_frame_count)
5399 {
5400 // Reached end of file
5401 // Set PTS to end of file
5403 if (m_in.m_video.m_stream->start_time != AV_NOPTS_VALUE)
5404 {
5405 m_out.m_video_pts += m_in.m_video.m_stream->start_time;
5406 }
5407 // Seek to end of file to force AVERROR_EOF from next av_read_frame() call. Ignore errrors.
5408 av_seek_frame(m_in.m_format_ctx, m_in.m_video.m_stream_idx, m_out.m_video_pts, AVSEEK_FLAG_ANY);
5409 return 0;
5410 }
5411
5412 uint32_t last_frame_no = pts_to_frame(m_in.m_video.m_stream, m_out.m_video_pts);
5413
5414 // Ignore seek if target is within the next FRAME_SEEK_THRESHOLD frames
5415 if (next_frame_no >= last_frame_no /*+ 1*/ && next_frame_no <= last_frame_no + FRAME_SEEK_THRESHOLD)
5416 {
5417 return 0;
5418 }
5419
5420 if (forced_seek || (frame_no != next_frame_no && next_frame_no > 1))
5421 {
5422 // If frame changed, skip to it
5423 ret = do_seek_frame(next_frame_no);
5424
5425 if (ret < 0)
5426 {
5427 Logging::error(virtname(), "Could not encode audio frame: Seek to frame #%1 failed (error '%2').", next_frame_no, ffmpeg_geterror(ret).c_str());
5428 }
5429 }
5430
5431 return ret;
5432}
5433
5435{
5436 int ret = 0;
5437
5438 if (m_out.m_audio.m_codec_ctx != nullptr)
5439 {
5440 // Flush the encoder as it may have delayed frames.
5441 int data_written = 0;
5442 do
5443 {
5444 ret = encode_audio_frame(nullptr, &data_written);
5445
5446 if (ret == AVERROR_EOF)
5447 {
5448 // Not an error
5449 break;
5450 }
5451
5452 if (ret < 0 && ret != AVERROR(EAGAIN))
5453 {
5454 Logging::error(virtname(), "Could not encode audio frame (error '%1').", ffmpeg_geterror(ret).c_str());
5455 break;
5456 }
5457 }
5458 while (data_written);
5459 }
5460
5461 return ret;
5462}
5463
5465{
5466 int ret = 0;
5467
5468 if (m_out.m_video.m_codec_ctx != nullptr)
5469 {
5470 // Flush the encoder as it may have delayed frames.
5471 int data_written = 0;
5472 do
5473 {
5474 if (!is_frameset())
5475 {
5476 // Encode regular frame
5477 ret = encode_video_frame(nullptr, &data_written);
5478 }
5479 else
5480 {
5481 // Encode seperate image frame
5482 ret = encode_image_frame(nullptr, &data_written);
5483 }
5484
5485 if (ret == AVERROR_EOF)
5486 {
5487 // Not an error
5488 break;
5489 }
5490 if (ret < 0 && ret != AVERROR(EAGAIN))
5491 {
5492 Logging::error(virtname(), "Could not encode video frame (error '%1').", ffmpeg_geterror(ret).c_str());
5493 break;
5494 }
5495 }
5496 while (data_written);
5497 }
5498
5499 return ret;
5500}
5501
5503{
5504 return 0;
5505}
5506
5508{
5509 int output_frame_size;
5510
5511 if (m_out.m_audio.m_codec_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
5512 {
5513 // Encode supports variable frame size, use an arbitrary value
5514 output_frame_size = 10000;
5515 }
5516 else
5517 {
5518 // Use the encoder's desired frame size for processing.
5519 output_frame_size = m_out.m_audio.m_codec_ctx->frame_size;
5520 }
5521
5522 // Make sure that there is one frame worth of samples in the audio FIFO
5523 // buffer so that the encoder can do its work.
5524 // Since the decoder's and the encoder's frame size may differ, we
5525 // need to FIFO buffer to store as many frames worth of input samples
5526 // that they make up at least one frame worth of output samples.
5527
5528 while (m_audio_fifo.size() < output_frame_size)
5529 {
5530 int ret = 0;
5531
5532 // Decode one frame worth of audio samples, convert it to the
5533 // output sample format and put it into the audio FIFO buffer.
5534
5535 ret = read_decode_convert_and_store(finished);
5536 if (ret < 0)
5537 {
5538 return ret;
5539 }
5540
5541 // If we are at the end of the input file, we continue
5542 // encoding the remaining audio samples to the output file.
5543
5544 if (*finished)
5545 {
5546 break;
5547 }
5548 }
5549
5550 // If we have enough samples for the encoder, we encode them.
5551 // At the end of the file, we pass the remaining samples to
5552 // the encoder.
5553
5554 while (m_audio_fifo.size() >= output_frame_size || (*finished && m_audio_fifo.size() > 0))
5555 {
5556 int ret = 0;
5557
5558 // Take one frame worth of audio samples from the audio FIFO buffer,
5559 // create a frame and store in audio frame buffer.
5560
5561 ret = create_audio_frame(output_frame_size);
5562 if (ret < 0)
5563 {
5564 return ret;
5565 }
5566 }
5567
5568 return 0;
5569}
5570
5572{
5573 int finished = 0;
5574
5576
5577 try
5578 {
5579 if (m_in.m_video.m_stream != nullptr && is_frameset())
5580 {
5581 int ret = 0;
5582
5583 // Direct access handling for frame sets: seek to frame if requested.
5584 ret = seek_frame();
5585 if (ret == AVERROR_EOF)
5586 {
5587 *status = DECODER_STATUS::DEC_EOF; // Report EOF, but return no error
5588 throw 0;
5589 }
5590
5591 if (ret < 0)
5592 {
5593 throw ret;
5594 }
5595 }
5596
5598 {
5599 int ret = 0;
5600
5601 // Copy audio FIFO into frame buffer
5602 ret = copy_audio_to_frame_buffer(&finished);
5603 if (ret < 0)
5604 {
5605 throw ret;
5606 }
5607 }
5608 else
5609 {
5610 int ret = 0;
5611
5612 // If we have no audio stream, we'll only get video data
5613 // or we simply copy audio and/or video frames into the packet queue
5614 ret = read_decode_convert_and_store(&finished);
5615 if (ret < 0)
5616 {
5617 throw ret;
5618 }
5619
5620 if (finished)
5621 {
5622 *status = DECODER_STATUS::DEC_EOF; // Report EOF
5623 }
5624 }
5625
5626 do
5627 {
5628 if (!is_frameset())
5629 {
5630 int64_t delay;
5631
5632 // The following values are arbitrarily chosen and seem to work.
5633 if (is_hls())
5634 {
5635 delay = params.m_segment_duration * 75 / 100; // 75% of the segment duration
5636 }
5637 else
5638 {
5639 delay = 6 * AV_TIME_BASE; // 6 seconds
5640 }
5641
5642 if (!finished && (!m_frame_map.empty() && m_frame_map.cbegin()->first + delay > m_frame_map.crbegin()->first))
5643 {
5644 return 0;
5645 }
5646
5647 while (!m_frame_map.empty())
5648 {
5649 // Take first entry in map
5650 MULTIFRAME_MAP::const_iterator it = m_frame_map.cbegin();
5651
5652 if (is_hls())
5653 {
5654 uint32_t next_segment = get_next_segment(it->first);
5655
5656 if (goto_next_segment(next_segment))
5657 {
5658 // Reached next segment, end current now, and force new.
5660 break;
5661 }
5662 }
5663
5664 // Get multiframe from map
5665 MULTIFRAME multiframe = it->second;
5666
5667 // Drop key from map, we've got a clone in multiframe now.
5668 m_frame_map.erase(it);
5669
5670 if (std::holds_alternative<FFmpeg_Frame>(multiframe))
5671 {
5672 // Object is an audio/video frame
5673 const FFmpeg_Frame & frame = std::get<FFmpeg_Frame>(multiframe);
5674
5675 int stream_idx = frame.m_stream_idx;
5676
5677 if (!stream_exists(stream_idx))
5678 {
5679 Logging::error(virtname(), "INTERNAL ERROR: FFmpeg_Transcoder::process_single_fr()! Invalid stream index in audio/video buffer skipped.");
5680 continue;
5681 }
5682
5683 if (stream_idx == m_out.m_audio.m_stream_idx)
5684 {
5685 // Encode audio
5686 int ret = 0;
5687 int data_written;
5688
5689 // Encode one frame worth of audio samples.
5690 ret = encode_audio_frame(frame, &data_written);
5691
5692 if (ret < 0 && ret != AVERROR(EAGAIN))
5693 {
5694 throw ret;
5695 }
5696 }
5697 else if (stream_idx == m_out.m_video.m_stream_idx)
5698 {
5699 // Encode video
5700 int ret = 0;
5701 int data_written = 0;
5702 ret = encode_video_frame(frame, &data_written);
5703
5704 if (ret < 0 && ret != AVERROR(EAGAIN))
5705 {
5706 throw ret;
5707 }
5708 }
5709 }
5710 else if (std::holds_alternative<FFmpeg_Subtitle>(multiframe))
5711 {
5712 // Object is a subtitle
5713 const FFmpeg_Subtitle & subtitle = std::get<FFmpeg_Subtitle>(multiframe);
5714
5715 int stream_idx = subtitle.m_stream_idx;
5716
5717 if (!stream_exists(stream_idx))
5718 {
5719 Logging::error(virtname(), "INTERNAL ERROR: FFmpeg_Transcoder::process_single_fr()! Invalid stream index in subtitle buffer skipped.");
5720 continue;
5721 }
5722
5723 // Encode subtitles
5724
5725 int ret = 0;
5726 int data_written = 0;
5727
5728 ret = encode_subtitle(subtitle, stream_idx, &data_written);
5729
5730 if (ret < 0 && ret != AVERROR(EAGAIN))
5731 {
5732 throw ret;
5733 }
5734 }
5735 }
5736 }
5737 else
5738 {
5739 // Frame sets: no audio, no subtitles, no output stream (index)
5740 while (!m_frame_map.empty())
5741 {
5742 // Although I abhore "auto", it seems that nodes are declared slightly different throughout
5743 // several std::map implementations. To avoid #ifdef orgies, I resign: Using "auto" here
5744 // is much more coherent.
5745 auto nh = m_frame_map.extract(m_frame_map.cbegin());
5746 const MULTIFRAME & multiframe = nh.mapped();
5747 int ret = 0;
5748 int data_written = 0;
5749
5750 // Encode video
5751 ret = encode_image_frame(std::get<FFmpeg_Frame>(multiframe), &data_written);
5752
5753 if (ret < 0 && ret != AVERROR(EAGAIN))
5754 {
5755 throw ret;
5756 }
5757 }
5758 }
5759
5761 {
5762 // Start new HLS segment
5763 int ret = 0;
5764
5765 ret = start_new_segment();
5766 if (ret < 0)
5767 {
5768 throw ret;
5769 }
5770 }
5771 } while (finished && !m_frame_map.empty()); // Ensure we've processed all frames in our buffer
5772
5773 // If we are at the end of the input file and have encoded
5774 // all remaining samples, we can exit this loop and finish.
5775
5776 if (finished && m_frame_map.empty())
5777 {
5781
5782 *status = DECODER_STATUS::DEC_EOF; // Report EOF
5783 }
5784 }
5785 catch (int _ret)
5786 {
5787 *status = (_ret != AVERROR_EOF ? DECODER_STATUS::DEC_ERROR : DECODER_STATUS::DEC_EOF); // If _ret == AVERROR_EOF, simply signal EOF
5788 return _ret;
5789 }
5790
5791 return 0;
5792}
5793
5795{
5797 {
5798 // No current seek frame, check if new seek frame was stacked.
5799 {
5800 std::lock_guard<std::recursive_mutex> lock_seek_to_fifo_mutex(m_seek_to_fifo_mutex);
5801
5802 while (!m_seek_to_fifo.empty())
5803 {
5804 uint32_t frame_no = m_seek_to_fifo.front();
5805 m_seek_to_fifo.pop();
5806
5807 if (!m_buffer->have_frame(frame_no))
5808 {
5809 // Frame not yet decoded, so skip to it.
5810 m_last_seek_frame_no = frame_no;
5811 break;
5812 }
5813 }
5814 }
5815
5817 {
5818 int ret = 0;
5819
5820 // The first frame that FFmpeg API returns after av_seek_frame is wrong (the last frame before seek).
5821 // We are unable to detect that because the pts seems correct (the one that we requested).
5822 // So we position before the frame requested, and simply throw the first away.
5823
5824 //#define PRESCAN_FRAMES 3
5825 uint32_t seek_frame_no = m_last_seek_frame_no.exchange(0);
5826#ifdef PRESCAN_FRAMES
5827 if (seek_frame_no > PRESCAN_FRAMES)
5828 {
5829 seek_frame_no -= PRESCAN_FRAMES;
5830 //m_skip_next_frame = true; /**< @todo Take deinterlace into account */
5831 }
5832 else
5833 {
5834 seek_frame_no = 1;
5835 }
5836
5837#endif
5838 ret = skip_decoded_frames(seek_frame_no, true);
5839 if (ret < 0)
5840 {
5841 return ret;
5842 }
5843 }
5844 }
5845 return 0;
5846}
5847
5849{
5850 bool opened = false;
5851
5852 encode_finish();
5853
5854 // Go to next requested segment...
5855 uint32_t next_segment = m_current_segment + 1;
5856
5857 // ...or process any stacked seek requests.
5858 while (!m_seek_to_fifo.empty())
5859 {
5860 uint32_t segment_no = m_seek_to_fifo.front();
5861 m_seek_to_fifo.pop();
5862
5863 // No check if m_segment_duration == 0, values <= 0 not accepted
5864 // Cast is OK here, the result will always be small enough for an int32.
5865 uint32_t min_seek_segments = static_cast<uint32_t>(params.m_min_seek_time_diff / params.m_segment_duration);
5866
5867 if (min_seek_segments && segment_no >= next_segment && segment_no <= next_segment + min_seek_segments)
5868 {
5869 Logging::info(virtname(), "Discarding seek request to HLS segment no. %1, less than %2 seconds (%3 segments) away.", segment_no, params.m_min_seek_time_diff / AV_TIME_BASE, min_seek_segments);
5870 continue;
5871 }
5872
5873 if (!m_buffer->segment_exists(segment_no) || !m_buffer->tell(segment_no)) // NOT EXIST or NO DATA YET
5874 {
5875 int ret = 0;
5876
5877 m_reset_pts = FFMPEGFS_AUDIO | FFMPEGFS_VIDEO; // Note that we have to reset audio/video pts to the new position
5878 m_have_seeked = true; // Note that we have seeked, thus skipped frames. We need to start transcoding over to fill any gaps.
5879
5880 Logging::info(virtname(), "Performing seek request to HLS segment no. %1.", segment_no);
5881
5882 int64_t pos = (segment_no - 1) * params.m_segment_duration;
5883
5885 {
5886 int64_t vstream_pts = ffmpeg_rescale_q(pos, av_get_time_base_q(), m_in.m_video.m_stream->time_base);
5887
5888 if (m_in.m_video.m_stream->start_time != AV_NOPTS_VALUE)
5889 {
5890 vstream_pts += m_in.m_video.m_stream->start_time;
5891 }
5892
5893 ret = av_seek_frame(m_in.m_format_ctx, m_in.m_video.m_stream_idx, vstream_pts, AVSEEK_FLAG_BACKWARD);
5894 }
5896 {
5897 int64_t astream_pts = ffmpeg_rescale_q(pos, av_get_time_base_q(), m_in.m_audio.m_stream->time_base);
5898
5899 if (m_in.m_audio.m_stream->start_time != AV_NOPTS_VALUE)
5900 {
5901 astream_pts += m_in.m_audio.m_stream->start_time;
5902 }
5903
5904 ret = av_seek_frame(m_in.m_format_ctx, m_in.m_audio.m_stream_idx, astream_pts, AVSEEK_FLAG_BACKWARD);
5905 }
5906
5907 if (ret < 0)
5908 {
5909 Logging::error(virtname(), "Seek failed on input file (error '%1').", ffmpeg_geterror(ret).c_str());
5910 return ret;
5911 }
5912
5913 flush_buffers();
5914
5916
5917 purge_hls_fifo(); // We do not need the packets for the next frame, we start a new one at another position!
5918
5919 // open_output() selects the active HLS cache file before
5920 // process_output()/avformat_write_header() can emit data. Make
5921 // the requested seek segment visible before reopening the output,
5922 // otherwise a mid-stream repair can reopen the previous segment.
5923 m_current_segment = segment_no;
5924
5925 ret = open_output(m_buffer);
5926 if (ret < 0)
5927 {
5928 return ret;
5929 }
5930
5931 next_segment = segment_no;
5932
5933 opened = true;
5934
5935 break;
5936 }
5937
5938 Logging::info(virtname(), "Discarded seek request to HLS segment no. %1.", segment_no);
5939 }
5940
5941 // Set current segment
5942 m_current_segment = next_segment;
5944 m_insert_keyframe = false;
5945
5946 Logging::info(virtname(), "Starting HLS segment no. %1 of %2.", m_current_segment, m_virtualfile->get_segment_count());
5947
5949 {
5950 return AVERROR(errno);
5951 }
5952
5953 if (!opened)
5954 {
5955 int ret = 0;
5956
5957 // Process output file, already done by open_output() if file has been newly opened.
5958 ret = process_output();
5959 if (ret)
5960 {
5961 return ret;
5962 }
5963 }
5964
5965 // Flush delayed packets to disk, if any
5966 while (!m_hls_packet_fifo.empty())
5967 {
5968 int ret = 0;
5969 FFmpeg_Packet pkt(std::move(m_hls_packet_fifo.front()));
5970 m_hls_packet_fifo.pop();
5971
5972 ret = av_write_frame(m_out.m_format_ctx, pkt);
5973
5974 if (ret < 0)
5975 {
5976 Logging::error(virtname(), "Could not write frame (error '%1').", ffmpeg_geterror(ret).c_str());
5977 return ret;
5978 }
5979
5980 }
5981 return 0;
5982}
5983
5984BITRATE FFmpeg_Transcoder::get_prores_bitrate(int width, int height, const AVRational &framerate, bool interleaved, PRORESLEVEL profile)
5985{
5986 unsigned int mindist;
5987 size_t match = UINT_MAX;
5988
5989 // Find best match resolution
5990 mindist = UINT_MAX;
5991 for (size_t i = 0; i < m_prores_bitrate.size(); i++)
5992 {
5993 unsigned int x = static_cast<unsigned int>(width - m_prores_bitrate[i].m_width);
5994 unsigned int y = static_cast<unsigned int>(height - m_prores_bitrate[i].m_height);
5995 unsigned int dist = (x * x) + (y * y);
5996
5997 if (dist < mindist)
5998 {
5999 mindist = dist;
6000 match = i;
6001 }
6002
6003 if (!dist)
6004 {
6005 // Exact match, won't find a better one.
6006 break;
6007 }
6008 }
6009
6010 if (match == UINT_MAX)
6011 {
6012 return 0;
6013 }
6014
6015 width = m_prores_bitrate[match].m_width;
6016 height = m_prores_bitrate[match].m_height;
6017
6018 // Find best match framerate
6019 double framerateX = av_q2d(framerate);
6020 mindist = UINT_MAX;
6021 for (size_t i = match; width == m_prores_bitrate[i].m_width && height == m_prores_bitrate[i].m_height; i++)
6022 {
6023 unsigned int dist = UINT_MAX;
6024 for (size_t j = 0; j < MAX_PRORES_FRAMERATE && m_prores_bitrate[i].m_framerate[j].m_framerate; j++)
6025 {
6026 unsigned int x = static_cast<unsigned int>(framerateX - m_prores_bitrate[i].m_framerate[j].m_framerate);
6027 unsigned int y = static_cast<unsigned int>(interleaved - m_prores_bitrate[i].m_framerate[j].m_interleaved);
6028
6029 dist = (x * x) + (y * y);
6030
6031 if (dist < mindist)
6032 {
6033 mindist = dist;
6034 match = i;
6035 }
6036
6037 if (!dist)
6038 {
6039 // Exact match, won't find a better one.
6040 break;
6041 }
6042 }
6043
6044 if (!dist)
6045 {
6046 // Exact match, won't find a better one.
6047 break;
6048 }
6049 }
6050
6051 if (match == UINT_MAX)
6052 {
6053 return 0;
6054 }
6055
6056 return m_prores_bitrate[match].m_bitrate[static_cast<size_t>(profile)] * (1000 * 1000);
6057}
6058
6059bool FFmpeg_Transcoder::audio_size(size_t *filesize, AVCodecID codec_id, BITRATE bit_rate, int64_t duration, int channels, int sample_rate, AVSampleFormat sample_format)
6060{
6061 BITRATE output_audio_bit_rate;
6062 int output_sample_rate;
6063 bool success = true;
6064
6065 get_output_bit_rate(bit_rate, params.m_audiobitrate, &output_audio_bit_rate);
6066 get_output_sample_rate(sample_rate, params.m_audiosamplerate, &output_sample_rate);
6067
6068 switch (codec_id)
6069 {
6070 case AV_CODEC_ID_AAC:
6071 {
6072 // Try to predict the size of the AAC stream (this is fairly accurate, sometimes a bit larger, sometimes a bit too small
6073 *filesize += static_cast<size_t>(duration * output_audio_bit_rate / (8LL * AV_TIME_BASE));
6074 *filesize = static_cast<size_t>(1025 * (*filesize) / 1000); // add overhead (empirically determined value)
6075 break;
6076 }
6077 case AV_CODEC_ID_MP3:
6078 {
6079 // Kbps = bits per second / 8 = Bytes per second x 60 seconds = Bytes per minute x 60 minutes = Bytes per hour
6080 // This is the sum of the size of
6081 // ID3v2, ID3v1, and raw MP3 data. This is theoretically only approximate
6082 // but in practice gives excellent answers, usually exactly correct.
6083 // Cast to 64-bit int to avoid overflow.
6084
6085 *filesize += static_cast<size_t>(duration * output_audio_bit_rate / (8LL * AV_TIME_BASE)) + ID3V1_TAG_LENGTH;
6086 break;
6087 }
6088 case AV_CODEC_ID_PCM_U8:
6089 case AV_CODEC_ID_PCM_S8:
6090 {
6091 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_U8); // Unsigned/signed 8 have the same width
6092
6093 // File size:
6094 // file duration * sample rate (HZ) * channels * bytes per sample
6095 // + WAV_HEADER + DATA_HEADER + (with FFMpeg always) LIST_HEADER
6096 // The real size of the list header is unkown as we don't know the contents (meta tags)
6097 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6098 break;
6099 }
6100 case AV_CODEC_ID_PCM_S8_PLANAR:
6101 {
6102 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_U8P);
6103
6104 // File size:
6105 // file duration * sample rate (HZ) * channels * bytes per sample
6106 // + WAV_HEADER + DATA_HEADER + (with FFMpeg always) LIST_HEADER
6107 // The real size of the list header is unkown as we don't know the contents (meta tags)
6108 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6109 break;
6110 }
6111 case AV_CODEC_ID_PCM_U16LE:
6112 case AV_CODEC_ID_PCM_U16BE:
6113 case AV_CODEC_ID_PCM_S16LE:
6114 case AV_CODEC_ID_PCM_S16BE:
6115 {
6116 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); // Unsigned/signed 16 have the same width
6117
6118 // File size:
6119 // file duration * sample rate (HZ) * channels * bytes per sample
6120 // + WAV_HEADER + DATA_HEADER + (with FFMpeg always) LIST_HEADER
6121 // The real size of the list header is unkown as we don't know the contents (meta tags)
6122 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6123 break;
6124 }
6125 case AV_CODEC_ID_PCM_S16LE_PLANAR:
6126 case AV_CODEC_ID_PCM_S16BE_PLANAR:
6127 {
6128 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16P); // Unsigned/signed 16 have the same width
6129
6130 // File size:
6131 // file duration * sample rate (HZ) * channels * bytes per sample
6132 // + WAV_HEADER + DATA_HEADER + (with FFMpeg always) LIST_HEADER
6133 // The real size of the list header is unkown as we don't know the contents (meta tags)
6134 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6135 break;
6136 }
6137 case AV_CODEC_ID_PCM_U24LE: // U/S24 uses U/S32 storage
6138 case AV_CODEC_ID_PCM_U24BE:
6139 case AV_CODEC_ID_PCM_S24LE:
6140 case AV_CODEC_ID_PCM_S24BE:
6141 case AV_CODEC_ID_PCM_U32LE:
6142 case AV_CODEC_ID_PCM_U32BE:
6143 case AV_CODEC_ID_PCM_S32LE:
6144 case AV_CODEC_ID_PCM_S32BE:
6145 {
6146 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S32); // Unsigned/signed 32 have the same width
6147
6148 // File size:
6149 // file duration * sample rate (HZ) * channels * bytes per sample
6150 // + WAV_HEADER + DATA_HEADER + (with FFMpeg always) LIST_HEADER
6151 // The real size of the list header is unkown as we don't know the contents (meta tags)
6152 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6153 break;
6154 }
6155 case AV_CODEC_ID_PCM_S24LE_PLANAR: // S24 uses S32 storage
6156 case AV_CODEC_ID_PCM_S32LE_PLANAR:
6157 {
6158 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S32P);
6159
6160 // File size:
6161 // file duration * sample rate (HZ) * channels * bytes per sample
6162 // + WAV_HEADER + DATA_HEADER + (with FFMpeg always) LIST_HEADER
6163 // The real size of the list header is unkown as we don't know the contents (meta tags)
6164 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6165 break;
6166 }
6167 case AV_CODEC_ID_PCM_S64LE:
6168 case AV_CODEC_ID_PCM_S64BE:
6169 {
6170 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S64);
6171
6172 // File size:
6173 // file duration * sample rate (HZ) * channels * bytes per sample
6174 // + WAV_HEADER + DATA_HEADER + (with FFMpeg always) LIST_HEADER
6175 // The real size of the list header is unkown as we don't know the contents (meta tags)
6176 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6177 break;
6178 }
6179 case AV_CODEC_ID_PCM_F16LE:
6180 case AV_CODEC_ID_PCM_F24LE:
6181 case AV_CODEC_ID_PCM_F32BE:
6182 case AV_CODEC_ID_PCM_F32LE:
6183 case AV_CODEC_ID_PCM_F64BE:
6184 case AV_CODEC_ID_PCM_F64LE:
6185 {
6186 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT);
6187
6188 // File size:
6189 // file duration * sample rate (HZ) * channels * bytes per sample
6190 // + WAV_HEADER + DATA_HEADER + (with FFMpeg always) LIST_HEADER
6191 // The real size of the list header is unkown as we don't know the contents (meta tags)
6192 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6193 break;
6194 }
6195 case AV_CODEC_ID_VORBIS:
6196 {
6197 // Kbps = bits per second / 8 = Bytes per second x 60 seconds = Bytes per minute x 60 minutes = Bytes per hour
6198 *filesize += static_cast<size_t>(duration * output_audio_bit_rate / (8LL * AV_TIME_BASE));
6199 *filesize = static_cast<size_t>(900 * (*filesize) / 1000); // OGG files seem to be rather smaller than expected (empirically determined value)
6200 break;
6201 }
6202 case AV_CODEC_ID_OPUS:
6203 {
6204 // Kbps = bits per second / 8 = Bytes per second x 60 seconds = Bytes per minute x 60 minutes = Bytes per hour
6205 *filesize += static_cast<size_t>(duration * output_audio_bit_rate / (8LL * AV_TIME_BASE));
6206 *filesize = static_cast<size_t>(1020 * (*filesize) / 1000); // add overhead (empirically determined value)
6207 break;
6208 }
6209 case AV_CODEC_ID_ALAC:
6210 {
6211 int bytes_per_sample = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
6212
6213 // File size:
6214 // Apple Lossless Audio Coding promises a compression rate of 60-70%. The actual result ranges
6215 // between 30 and over 50%, heavily depending on the input.
6216 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6217 *filesize = static_cast<size_t>(620 * (*filesize) / 1000); // Estimate 38% compression rate (empirically determined value)
6218 break;
6219 }
6220 case AV_CODEC_ID_AC3:
6221 {
6222 // Kbps = bits per second / 8 = Bytes per second x 60 seconds = Bytes per minute x 60 minutes = Bytes per hour
6223 *filesize += static_cast<size_t>(duration * output_audio_bit_rate / (8LL * AV_TIME_BASE));
6224 *filesize = static_cast<size_t>(1025 * (*filesize) / 1000); // add overhead (empirically determined value)
6225 break;
6226 }
6227 case AV_CODEC_ID_FLAC:
6228 {
6229 int bytes_per_sample = av_get_bytes_per_sample(sample_format != AV_SAMPLE_FMT_NONE ? sample_format : AV_SAMPLE_FMT_S16);
6230
6231 // File size:
6232 // file duration * sample rate (HZ) * channels * bytes per sample
6233 // We do not add the overhead for headers, as this is an estimation and not exact anyways.
6234 *filesize += static_cast<size_t>(duration * sample_rate * (channels >= 2 ? 2 : 1) * bytes_per_sample / AV_TIME_BASE);
6235 *filesize = static_cast<size_t>(600 * (*filesize) / 1000); // Estimate 40% compression rate (empirically determined value)
6236 break;
6237 }
6238 case AV_CODEC_ID_NONE:
6239 {
6240 break;
6241 }
6242 default:
6243 {
6244 success = false;
6245 break;
6246 }
6247 }
6248 return success;
6249}
6250
6251bool FFmpeg_Transcoder::video_size(size_t *filesize, AVCodecID codec_id, BITRATE bit_rate, int64_t duration, int width, int height, bool interleaved, const AVRational &framerate)
6252{
6253 BITRATE out_video_bit_rate;
6254 bool success = true;
6255
6256 get_output_bit_rate(bit_rate, params.m_videobitrate, &out_video_bit_rate);
6257
6258 switch (codec_id)
6259 {
6260 case AV_CODEC_ID_MPEG1VIDEO:
6261 {
6262 *filesize += static_cast<size_t>(duration * out_video_bit_rate / (8LL * AV_TIME_BASE));
6263 *filesize = static_cast<size_t>(1020 * (*filesize) / 1000); // add overhead
6264 break;
6265 }
6266 case AV_CODEC_ID_MPEG2VIDEO:
6267 {
6268 *filesize += static_cast<size_t>(duration * out_video_bit_rate / (8LL * AV_TIME_BASE));
6269 *filesize = static_cast<size_t>(1020 * (*filesize) / 1000); // add overhead
6270 break;
6271 }
6272 case AV_CODEC_ID_H264:
6273 {
6274 *filesize += static_cast<size_t>(duration * out_video_bit_rate / (8LL * AV_TIME_BASE));
6275 *filesize = static_cast<size_t>(1050 * (*filesize) / 1000); // add overhead
6276 break;
6277 }
6278 case AV_CODEC_ID_H265:
6279 {
6280 *filesize += static_cast<size_t>(duration * out_video_bit_rate / (8LL * AV_TIME_BASE));
6281 *filesize = static_cast<size_t>(1250 * (*filesize) / 1000); // add overhead
6282 break;
6283 }
6284 case AV_CODEC_ID_THEORA:
6285 {
6286 *filesize += static_cast<size_t>(duration * out_video_bit_rate / (8LL * AV_TIME_BASE));
6287 *filesize = static_cast<size_t>(1025 * (*filesize) / 1000); // add overhead
6288 break;
6289 }
6290 case AV_CODEC_ID_VP8:
6291 {
6292 *filesize += static_cast<size_t>(duration * out_video_bit_rate / (8LL * AV_TIME_BASE));
6293 *filesize = static_cast<size_t>(1020 * (*filesize) / 1000); // add overhead
6294 break;
6295 }
6296 case AV_CODEC_ID_VP9:
6297 {
6298 *filesize += static_cast<size_t>(duration * out_video_bit_rate / (8LL * AV_TIME_BASE));
6299 *filesize = static_cast<size_t>(1450 * (*filesize) / 1000); // add overhead
6300 break;
6301 }
6302 case AV_CODEC_ID_AV1:
6303 {
6304 *filesize += static_cast<size_t>(duration * out_video_bit_rate / (8LL * AV_TIME_BASE));
6305 //*filesize = static_cast<size_t>(1150 * (*filesize) / 1000); // add overhead
6306 break;
6307 }
6308 case AV_CODEC_ID_PRORES:
6309 {
6310 *filesize += static_cast<size_t>(duration * get_prores_bitrate(width, height, framerate, interleaved, params.m_level) / (8LL * AV_TIME_BASE));
6311 break;
6312 }
6313 case AV_CODEC_ID_PNG:
6314 case AV_CODEC_ID_BMP:
6315 case AV_CODEC_ID_MJPEG:
6316 {
6317 // Max. file size = (pixel dimensions x bit depth) / 8 for an uncompressed BMP,
6318 // more than sufficient for JPG/PNG as they should never get this large.
6319 *filesize += static_cast<size_t>(width * height * 24 / 8); // Get the max. size
6320 break;
6321 }
6322 case AV_CODEC_ID_NONE:
6323 {
6324 break;
6325 }
6326 default:
6327 {
6328 success = false;
6329 break;
6330 }
6331 }
6332 return success;
6333}
6334
6335bool FFmpeg_Transcoder::total_overhead(size_t *filesize, FILETYPE filetype)
6336{
6337 bool success = true;
6338
6339 switch (filetype)
6340 {
6341 //
6342 // Audio only
6343 //
6344 case FILETYPE::MP3:
6345 {
6346 // The FFmpeg API always adds an IDv2 header, size of which is unknown and
6347 // really hard to determine. So we simply add something reasonable (empirically determined value).
6348 *filesize += 250000;
6349 break;
6350 }
6351 case FILETYPE::WAV:
6352 {
6353 // This could actually precise, but yet the FFmpeg API always adds an IDv2 header,
6354 // size of which is unknown and really hard to determine. The header is small, ~30 bytes,
6355 // so we ignore that deliberatly.
6356 *filesize += sizeof(WAV_HEADER) + sizeof(WAV_LIST_HEADER) + sizeof(WAV_DATA_HEADER);
6357 break;
6358 }
6359 case FILETYPE::AIFF:
6360 {
6361 // These two "chunks" will always be there, others may be there, may be not. Their
6362 // size is hard to precalculate and small (~100 bytes), so we disregard the rest.
6363 *filesize += sizeof(AIFF_FORMCHUNK) + sizeof(AIFF_COMMONCHUNK);
6364 break;
6365 }
6366 case FILETYPE::OPUS:
6367 case FILETYPE::ALAC:
6368 case FILETYPE::FLAC:
6369 {
6370 break;
6371 }
6372 //
6373 // Video
6374 //
6375 case FILETYPE::TS:
6376 case FILETYPE::HLS:
6377 {
6378 *filesize += 1600000; // empirically determined value
6379 break;
6380 }
6381 case FILETYPE::MP4:
6382 case FILETYPE::OGG:
6383 case FILETYPE::WEBM:
6384 case FILETYPE::MOV:
6385 case FILETYPE::PRORES:
6386 case FILETYPE::MKV:
6387 {
6388 break;
6389 }
6390 //
6391 // Stills
6392 //
6393 case FILETYPE::PNG:
6394 case FILETYPE::JPG:
6395 case FILETYPE::BMP:
6396 {
6397 break;
6398 }
6399 //
6400 // Invalid
6401 //
6402 case FILETYPE::UNKNOWN:
6403 {
6404 success = false;
6405 break;
6406 }
6407 }
6408
6409 return success;
6410}
6411
6413{
6414 if (m_in.m_format_ctx == nullptr)
6415 {
6416 return 0;
6417 }
6418
6419 if (m_current_format == nullptr)
6420 {
6421 // Should ever happen, but better check this to avoid crashes.
6422 return 0;
6423 }
6424
6425 size_t filesize = 0;
6426
6427 int64_t file_duration = m_in.m_format_ctx->duration != AV_NOPTS_VALUE ? m_in.m_format_ctx->duration : 0;
6428 BITRATE input_audio_bit_rate = 0;
6429 int input_sample_rate = 0;
6430 BITRATE input_video_bit_rate = 0;
6431
6432 if (m_fileio->duration() != AV_NOPTS_VALUE)
6433 {
6434 file_duration = m_fileio->duration();
6435 }
6436
6438 {
6439 input_sample_rate = m_in.m_audio.m_stream->codecpar->sample_rate;
6440 input_audio_bit_rate = (m_in.m_audio.m_stream->codecpar->bit_rate != 0) ? m_in.m_audio.m_stream->codecpar->bit_rate : m_in.m_format_ctx->bit_rate;
6441 }
6442
6444 {
6445 input_video_bit_rate = (m_in.m_video.m_stream->codecpar->bit_rate != 0) ? m_in.m_video.m_stream->codecpar->bit_rate : m_in.m_format_ctx->bit_rate;
6446 }
6447
6448 if (input_audio_bit_rate)
6449 {
6450 int channels = get_channels(m_in.m_audio.m_codec_ctx.get());
6451
6452 if (!audio_size(&filesize, m_current_format->audio_codec(), input_audio_bit_rate, file_duration, channels, input_sample_rate, m_cur_sample_fmt))
6453 {
6454 Logging::warning(filename(), "Unsupported audio codec '%1' for format %2.", get_codec_name(m_current_format->audio_codec()), m_current_format->desttype().c_str());
6455 }
6456 }
6457
6458 if (input_video_bit_rate)
6459 {
6460 if (m_is_video)
6461 {
6462 int width = m_in.m_video.m_stream->codecpar->width;
6463 int height = m_in.m_video.m_stream->codecpar->height;
6464 bool interleaved = params.m_deinterlace ? false : (m_in.m_video.m_stream->codecpar->field_order != AV_FIELD_PROGRESSIVE); // Deinterlace only if source is interlaced
6465 AVRational framerate = m_in.m_video.m_stream->avg_frame_rate;
6466
6467 if (!video_size(&filesize, m_current_format->video_codec(), input_video_bit_rate, file_duration, width, height, interleaved, framerate))
6468 {
6469 Logging::warning(filename(), "Unsupported video codec '%1' for format %2.", get_codec_name(m_current_format->video_codec()), m_current_format->desttype().c_str());
6470 }
6471 }
6472 // else /** @todo Feature #2260: Add picture size */
6473 // {
6474 // }
6475 }
6476
6477 // Support #2654: Test Code
6478 // add total overhead
6480
6481 return filesize;
6482}
6483
6485{
6486 return SAFE_VALUE(m_virtualfile, m_duration, 0);
6487}
6488
6490{
6491 return SAFE_VALUE(m_virtualfile, m_predicted_size, 0);
6492}
6493
6495{
6496 return SAFE_VALUE(m_virtualfile, m_video_frame_count, 0);
6497}
6498
6500{
6501 return SAFE_VALUE(m_virtualfile, get_segment_count(), 0);
6502}
6503
6505{
6506 int ret = 0;
6507
6508 if (!is_frameset())
6509 {
6510 // If not a frame set, write trailer
6511
6512 // Write the trailer of the output file container.
6514 }
6515
6516 if (is_hls())
6517 {
6519
6520 // Get segment VIRTUALFILE object
6522 LPVIRTUALFILE virtualfile = find_file(seg_filename);
6523
6524 if (virtualfile != nullptr)
6525 {
6527
6528 stat_set_size(&virtualfile->m_st, virtualfile->m_predicted_size);
6529 }
6530 }
6531 else //if (m_virtualfile->m_flags & VIRTUALFLAG_CUESHEET)
6532 {
6533 // Save actual result size of the file
6535 }
6536
6537 return ret;
6538}
6539
6541{
6542 return &m_out.m_id3v1;
6543}
6544
6545int FFmpeg_Transcoder::input_read(void * opaque, unsigned char * data, int size)
6546{
6547 FileIO * io = static_cast<FileIO *>(opaque);
6548
6549 if (io == nullptr)
6550 {
6551 Logging::error(nullptr, "input_read(): Internal error: FileIO is NULL!");
6552 return AVERROR(EINVAL);
6553 }
6554
6555 if (io->eof())
6556 {
6557 // At EOF
6558 return AVERROR_EOF;
6559 }
6560
6561 int read = static_cast<int>(io->readio(reinterpret_cast<char *>(data), static_cast<size_t>(size)));
6562
6563 if (read != size && io->error())
6564 {
6565 // Read failed
6566 return AVERROR(io->error());
6567 }
6568
6569 return read;
6570}
6571
6572#if LAVF_WRITEPACKET_CONST
6573int FFmpeg_Transcoder::output_write(void * opaque, const uint8_t * data, int size)
6574#else
6575int FFmpeg_Transcoder::output_write(void * opaque, unsigned char * data, int size)
6576#endif
6577{
6578 Buffer * buffer = static_cast<Buffer *>(opaque);
6579
6580 if (buffer == nullptr)
6581 {
6582 Logging::error(nullptr, "input_write(): Internal error: FileIO is NULL!");
6583 return AVERROR(EINVAL);
6584 }
6585
6586#if LAVF_WRITEPACKET_CONST
6587 int written = static_cast<int>(buffer->writeio(data, static_cast<size_t>(size)));
6588#else
6589 int written = static_cast<int>(buffer->writeio(static_cast<const uint8_t*>(data), static_cast<size_t>(size)));
6590#endif
6591 if (written != size)
6592 {
6593 // Write error
6594 return (AVERROR(errno));
6595 }
6596 return written;
6597}
6598
6599int64_t FFmpeg_Transcoder::seek(void * opaque, int64_t offset, int whence)
6600{
6601 FileIO * io = static_cast<FileIO *>(opaque);
6602 int64_t res_offset = 0;
6603
6604 if (io == nullptr)
6605 {
6606 Logging::error(nullptr, "seek(): Internal error: FileIO is NULL!");
6607 return AVERROR(EINVAL);
6608 }
6609
6610 if (whence & AVSEEK_SIZE)
6611 {
6612 // Return file size
6613 res_offset = static_cast<int64_t>(io->size());
6614 }
6615 else
6616 {
6617 whence &= ~(AVSEEK_SIZE | AVSEEK_FORCE);
6618
6619 if (!io->seek(offset, whence))
6620 {
6621 // OK: Return position
6622 res_offset = offset;
6623 }
6624 else
6625 {
6626 // Error
6627 res_offset = AVERROR(errno);
6628 }
6629 }
6630
6631 return res_offset;
6632}
6633
6638
6640{
6641 int audio_samples_left = 0;
6642
6643 if (!m_audio_fifo.empty())
6644 {
6645 audio_samples_left = m_audio_fifo.size();
6647 }
6648
6649 return audio_samples_left;
6650}
6651
6653{
6654 size_t frames_left = m_frame_map.size();
6655
6656 m_frame_map.clear();
6657
6658 return frames_left;
6659}
6660
6662{
6663 size_t hls_packets_left = m_hls_packet_fifo.size();
6664
6665 while (!m_hls_packet_fifo.empty())
6666 {
6667 m_hls_packet_fifo.pop();
6668 }
6669
6670 return hls_packets_left;
6671}
6672
6674{
6675 std::string outfile;
6676 int audio_samples_left = purge_audio_fifo();
6677 size_t frames_left = purge_multiframe_map();
6678 size_t hls_packets_left = purge_hls_fifo();
6679
6680 if (m_out.m_format_ctx != nullptr && m_out.m_format_ctx->url != nullptr)
6681 {
6682 outfile = m_out.m_format_ctx->url;
6683 }
6684 else if (m_virtualfile != nullptr)
6685 {
6686 outfile = m_virtualfile->m_virtfile;
6687 }
6688
6689 const char *p = outfile.empty() ? nullptr : outfile.c_str();
6690 if (audio_samples_left)
6691 {
6692 Logging::warning(p, "%1 audio samples left in buffer and not written to target file!", audio_samples_left);
6693 }
6694
6695 if (frames_left)
6696 {
6697 Logging::warning(p, "%1 frames left in buffer and not written to target file!", frames_left);
6698 }
6699
6700 if (hls_packets_left)
6701 {
6702 Logging::warning(p, "%1 HLS packets left in buffer and not written to target file!", hls_packets_left);
6703 }
6704}
6705
6707{
6708 bool closed = false;
6709
6710 purge();
6711
6713
6714 // The deinterlace filter graph belongs to the current output/transcoding
6715 // pipeline. HLS seeks and output reopens can rebuild that pipeline without
6716 // closing the input file, so do not leave an old AVFilterGraph attached
6717 // until close_input_file().
6718 free_filters();
6719
6720 m_sws_ctx.reset();
6721
6722 // Close output file
6725
6726 m_out.m_album_art.clear();
6727 m_out.m_subtitle.clear();
6728
6729 closed = m_out.m_format_ctx.reset();
6730
6731 return closed;
6732}
6733
6735{
6736 bool closed = false;
6737
6738 m_in.m_audio.reset();
6739 m_in.m_video.reset();
6740
6741 m_in.m_album_art.clear();
6742 m_in.m_subtitle.clear();
6743
6744 if (m_in.m_format_ctx != nullptr)
6745 {
6746 if (m_fileio.use_count() <= 1 && m_fileio != nullptr)
6747 {
6748 m_fileio->closeio();
6749 }
6750 m_fileio.reset();
6751
6752 closed = m_in.m_format_ctx.reset();
6753 }
6754
6755 free_filters();
6756
6757 return closed;
6758}
6759
6761{
6762 bool closed = false;
6763
6764 // Close input file
6765 closed |= close_input_file();
6766
6767 // Close output file
6768 closed |= close_output_file();
6769
6770 // Free hardware device contexts if open
6773
6774 // Closed anything (anything had been open to be closed in the first place)...
6775 if (closed)
6776 {
6777 Logging::trace(nullptr, "FFmpeg transcoder closed.");
6778 }
6779}
6780
6782{
6783 return (m_virtualfile != nullptr ? m_virtualfile->m_origfile.c_str() : "");
6784}
6785
6787{
6788 return (m_virtualfile != nullptr ? m_virtualfile->m_destfile.c_str() : "");
6789}
6790
6792{
6793 return (m_virtualfile != nullptr ? m_virtualfile->m_virtfile.c_str() : "");
6794}
6795
6796// create
6797int FFmpeg_Transcoder::init_deinterlace_filters(AVCodecContext *codec_ctx, AVPixelFormat pix_fmt, const AVRational & avg_frame_rate, const AVRational & time_base)
6798{
6799 // Defensive cleanup: this function may be called again when the output
6800 // pipeline is rebuilt, for example after an HLS seek. Do not overwrite the
6801 // old filter pointers with nullptr before the old AVFilterGraph has been
6802 // freed, otherwise the graph and its internal buffers become unreachable.
6803 free_filters();
6804
6805 const AVFilter * buffer_src = avfilter_get_by_name("buffer");
6806 const AVFilter * buffer_sink = avfilter_get_by_name("buffersink");
6807 AVFilterInOut * outputs = avfilter_inout_alloc();
6808 AVFilterInOut * inputs = avfilter_inout_alloc();
6809 int ret = 0;
6810
6811 try
6812 {
6813 if (!avg_frame_rate.den && !avg_frame_rate.num)
6814 {
6815 // No framerate, so this video "stream" has only one picture
6816 throw static_cast<int>(AVERROR(EINVAL)); // Einzelbild-"Stream"
6817 }
6818
6819 m_filter_graph = avfilter_graph_alloc();
6820
6821 if (outputs == nullptr || inputs == nullptr || m_filter_graph == nullptr)
6822 {
6823 throw static_cast<int>(AVERROR(ENOMEM));
6824 }
6825
6826 // --- buffersrc (Quelle) direkt mit Args erstellen ---
6827 std::string args;
6828 strsprintf(&args,
6829 "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
6830 codec_ctx->width, codec_ctx->height, pix_fmt,
6831 time_base.num, time_base.den,
6832 codec_ctx->sample_aspect_ratio.num,
6833 FFMAX(codec_ctx->sample_aspect_ratio.den, 1));
6834
6835 ret = avfilter_graph_create_filter(&m_buffer_source_context, buffer_src, "in", args.c_str(), nullptr, m_filter_graph);
6836 if (ret < 0)
6837 {
6838 Logging::error(virtname(), "Cannot create buffer source (error '%1').", ffmpeg_geterror(ret).c_str());
6839 throw ret;
6840 }
6841
6842 // --- buffersink (Senke) mit Pre-Init-Optionen ---
6843#if LIBAVFILTER_VERSION_INT >= AV_VERSION_INT(10, 6, 100) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(59, 36, 100)
6844 // Neuer Weg: Array-Optionen (pixel_formats) + av_opt_set_array()
6845 m_buffer_sink_context = avfilter_graph_alloc_filter(m_filter_graph, buffer_sink, "out");
6847 {
6848 throw static_cast<int>(AVERROR(ENOMEM));
6849 }
6850
6851 // Nicht-Runtime-Optionen vor dem Init setzen
6852 {
6853 const enum AVPixelFormat pf = pix_fmt;
6854 // Wir ersetzen (ab Index 0) 1 Element in "pixel_formats"
6855 ret = av_opt_set_array(m_buffer_sink_context,
6856 "pixel_formats",
6857 AV_OPT_SEARCH_CHILDREN | AV_OPT_ARRAY_REPLACE,
6858 0, /* start_elem */
6859 1, /* nb_elems */
6860 AV_OPT_TYPE_PIXEL_FMT,
6861 &pf);
6862 if (ret < 0)
6863 {
6864 Logging::error(virtname(), "Cannot set buffersink pixel_formats (error '%1').", ffmpeg_geterror(ret).c_str());
6865 throw ret;
6866 }
6867 }
6868
6869 ret = avfilter_init_str(m_buffer_sink_context, nullptr);
6870 if (ret < 0)
6871 {
6872 Logging::error(virtname(), "Cannot init buffer sink (error '%1').", ffmpeg_geterror(ret).c_str());
6873 throw ret;
6874 }
6875#else
6876 // Alter Weg: int-list-Option (pix_fmts) vor Init setzen
6877 m_buffer_sink_context = avfilter_graph_alloc_filter(m_filter_graph, buffer_sink, "out");
6879 {
6880 throw static_cast<int>(AVERROR(ENOMEM));
6881 }
6882
6883 // Liste inkl. Terminator, wie in älteren Beispielen
6884 enum AVPixelFormat pixel_fmts[] = { pix_fmt, AV_PIX_FMT_NONE };
6885
6886#pragma GCC diagnostic push
6887#pragma GCC diagnostic ignored "-Wconversion"
6888#pragma GCC diagnostic ignored "-Wsign-conversion"
6889 ret = av_opt_set_int_list(m_buffer_sink_context, "pix_fmts", pixel_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
6890#pragma GCC diagnostic pop
6891
6892 if (ret < 0)
6893 {
6894 Logging::error(virtname(), "Cannot set output pixel format (error '%1').", ffmpeg_geterror(ret).c_str());
6895 throw ret;
6896 }
6897
6898 ret = avfilter_init_str(m_buffer_sink_context, nullptr);
6899 if (ret < 0)
6900 {
6901 Logging::error(virtname(), "Cannot init buffer sink (error '%1').", ffmpeg_geterror(ret).c_str());
6902 throw ret;
6903 }
6904#endif
6905
6906 // Endpunkte für Graph
6907 outputs->name = av_strdup("in");
6908 outputs->filter_ctx = m_buffer_source_context;
6909 outputs->pad_idx = 0;
6910 outputs->next = nullptr;
6911
6912 inputs->name = av_strdup("out");
6913 inputs->filter_ctx = m_buffer_sink_context;
6914 inputs->pad_idx = 0;
6915 inputs->next = nullptr;
6916
6917 // args "null" passthrough (dummy) filter for video
6918 // args "null" passthrough (dummy) filter for audio
6919
6920 // --- Deinterlace-Filterkette
6921 const char * filters;
6922 //filters = "yadif=mode=send_frame:parity=auto:deint=interlaced";
6923 filters = "yadif=mode=send_frame:parity=auto:deint=all";
6924 //filters = "yadif=0:-1:0";
6925 //filters = "bwdif=mode=send_frame:parity=auto:deint=all";
6926 //filters = "kerndeint=thresh=10:map=0:order=0:sharp=1:twoway=1";
6927 //filters = "zoompan=z='min(max(zoom,pzoom)+0.0015,1.5)':d=1:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)'";
6928
6929 // vaapi_deinterlace=rate=field
6930 // format=nv12,hwupload,deinterlace_vaapi,hwdownload,format=nv12
6931 // deinterlace_vaapi,scale_vaapi=w=1280:h=720,hwdownload,format=nv12
6932
6933 ret = avfilter_graph_parse_ptr(m_filter_graph, filters, &inputs, &outputs, nullptr);
6934 if (ret < 0)
6935 {
6936 Logging::error(virtname(), "avfilter_graph_parse_ptr failed (error '%1').", ffmpeg_geterror(ret).c_str());
6937 throw ret;
6938 }
6939
6940 ret = avfilter_graph_config(m_filter_graph, nullptr);
6941 if (ret < 0)
6942 {
6943 Logging::error(virtname(), "avfilter_graph_config failed (error '%1').", ffmpeg_geterror(ret).c_str());
6944 throw ret;
6945 }
6946
6947 Logging::debug(virtname(), "Deinterlacing initialised with filters '%1'.", filters);
6948 }
6949 catch (int _ret)
6950 {
6951 ret = _ret;
6952
6953 // If graph creation/configuration failed halfway through, release the
6954 // partial graph immediately. Otherwise the next retry/seek would start
6955 // with stale filter pointers and retained filter buffers.
6956 free_filters();
6957 }
6958
6959 if (inputs != nullptr)
6960 {
6961 avfilter_inout_free(&inputs);
6962 }
6963 if (outputs != nullptr)
6964 {
6965 avfilter_inout_free(&outputs);
6966 }
6967
6968 return ret;
6969}
6970
6971
6972// Aug 26 21:41:22 plattenlurch ffmpegfs[1999231]: WARNING: FILTER [out @ 0x7f99a4193bc0] The "pix_fmts" option is deprecated: set the supported pixel formats
6973// Aug 26 21:41:22 plattenlurch ffmpegfs[1999231]: WARNING: FILTER [in @ 0x7f99a40f8700] Changing video frame properties on the fly is not supported by all filters.
6974// Aug 26 21:41:22 plattenlurch ffmpegfs[1999231]: WARNING: FILTER [in @ 0x7f99a40f8700] filter context - w: 720 h: 480 fmt: 0 csp: unknown range: unknown, incoming frame - w: 720 h: 480 fmt: 0 csp: unknown range: tv pts_time: 1117.2298
6975// Aug 26 21:41:22 plattenlurch ffmpegfs[1999231]: WARNING: ENCODER [libx264 @ 0x7f99a40c9080] non-strictly-monotonic PTS
6976
6977
6979{
6980 ret = 0;
6981
6982 if (m_buffer_source_context != nullptr)
6983 {
6984 try
6985 {
6986 FFmpeg_Frame filterframe(srcframe->m_stream_idx);
6987
6988 ret = filterframe.res();
6989 if (ret < 0)
6990 {
6991 Logging::error(virtname(), "Unable to allocate filter frame (error '%1').", ffmpeg_geterror(ret).c_str());
6992 throw ret;
6993 }
6994
6995 // push the decoded frame into the filtergraph
6996 ret = av_buffersrc_add_frame_flags(m_buffer_source_context, *srcframe, AV_BUFFERSRC_FLAG_KEEP_REF);
6997 if (ret < 0)
6998 {
6999 Logging::warning(virtname(), "Error while feeding the frame to filtergraph (error '%1').", ffmpeg_geterror(ret).c_str());
7000 throw ret;
7001 }
7002
7003 // pull filtered frames from the filtergraph
7004 ret = av_buffersink_get_frame(m_buffer_sink_context, filterframe);
7005 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
7006 {
7007 // Not an error, go on
7008 ret = 0;
7009 }
7010 else if (ret < 0)
7011 {
7012 Logging::error(virtname(), "Error while getting frame from filtergraph (error '%1').", ffmpeg_geterror(ret).c_str());
7013 throw ret;
7014 }
7015 else
7016 {
7017 // All OK; copy filtered frame and unref original
7018 filterframe->pts = (*srcframe)->pts;
7019 filterframe->best_effort_timestamp = (*srcframe)->best_effort_timestamp;
7020
7021 *srcframe = filterframe;
7022 }
7023 }
7024 catch (int _ret)
7025 {
7026 ret = _ret;
7027 }
7028 }
7029
7030 return ret;
7031}
7032
7033// free
7034
7036{
7037 // Filter contexts are owned by the graph once they have been attached to it.
7038 // Freeing the AVFilterGraph releases the source/sink contexts and all
7039 // buffers owned by the filter pipeline in one place. The member pointers
7040 // must be reset afterwards because they become dangling pointers.
7041 if (m_filter_graph != nullptr)
7042 {
7043 avfilter_graph_free(&m_filter_graph);
7044 }
7045
7046 m_buffer_source_context = nullptr;
7047 m_buffer_sink_context = nullptr;
7048 m_filter_graph = nullptr;
7049}
7050
7052{
7053 if (frame_no > 0 && frame_no <= video_frame_count())
7054 {
7055 std::lock_guard<std::recursive_mutex> lock_seek_to_fifo_mutex(m_seek_to_fifo_mutex);
7056 m_seek_to_fifo.push(frame_no); // Seek to this frame next decoding operation
7057 return 0;
7058 }
7059 else
7060 {
7061 errno = EINVAL;
7062 Logging::error(virtname(), "stack_seek_frame() failed: Frame %1 was requested, but is out of range (1...%2)", frame_no, video_frame_count() + 1);
7063 return AVERROR(EINVAL);
7064 }
7065}
7066
7068{
7069 if (segment_no > 0 && segment_no <= segment_count())
7070 {
7071 std::lock_guard<std::recursive_mutex> lock_seek_to_fifo_mutex(m_seek_to_fifo_mutex);
7072 m_seek_to_fifo.push(segment_no); // Seek to this segment next decoding operation
7073 return 0;
7074 }
7075 else
7076 {
7077 errno = EINVAL;
7078 Logging::error(virtname(), "stack_seek() failed: Segment no. %1 was requested, but is out of range (1...%2)", segment_no, video_frame_count() + 1);
7079 return AVERROR(EINVAL);
7080 }
7081}
7082
7084{
7085 if (m_current_format == nullptr)
7086 {
7087 return false;
7088 }
7089 else
7090 {
7092 }
7093}
7094
7095
7097{
7098 if (m_current_format == nullptr)
7099 {
7100 return false;
7101 }
7102 else
7103 {
7104 return m_current_format->is_frameset();
7105 }
7106}
7107
7109{
7110 if (m_current_format == nullptr)
7111 {
7112 return false;
7113 }
7114 else
7115 {
7116 return m_current_format->is_hls();
7117 }
7118}
7119
7121{
7122 return m_have_seeked;
7123}
7124
7125enum AVPixelFormat FFmpeg_Transcoder::get_format_static(AVCodecContext *input_codec_ctx, const enum AVPixelFormat *pix_fmts)
7126{
7127 FFmpeg_Transcoder * pThis = static_cast<FFmpeg_Transcoder *>(input_codec_ctx->opaque);
7128 return pThis->get_format(input_codec_ctx, pix_fmts);
7129}
7130
7131enum AVPixelFormat FFmpeg_Transcoder::get_format(__attribute__((unused)) AVCodecContext *input_codec_ctx, const enum AVPixelFormat *pix_fmts) const
7132{
7133 if (params.m_hwaccel_dec_device_type == AV_HWDEVICE_TYPE_NONE)
7134 {
7135 // We should never happen to end up here...
7136 Logging::error(filename(), "Unable to decode this file using hardware acceleration: Internal error! No hardware device type set.");
7137 return AV_PIX_FMT_NONE;
7138 }
7139
7140 AVPixelFormat pix_fmt_expected = m_dec_hw_pix_fmt;
7141
7142 for (const AVPixelFormat *p = pix_fmts; *p != AV_PIX_FMT_NONE; p++)
7143 {
7144 if (*p == pix_fmt_expected)
7145 {
7146 return pix_fmt_expected;
7147 }
7148 }
7149
7150 Logging::error(filename(), "Unable to decode this file using hardware acceleration. Expected format '%1' not supported.", get_pix_fmt_name(pix_fmt_expected).c_str());
7151
7152 return AV_PIX_FMT_NONE;
7153}
7154
7155int FFmpeg_Transcoder::hwdevice_ctx_create(AVBufferRef ** hwaccel_enc_device_ctx, AVHWDeviceType dev_type, const std::string & device) const
7156{
7157 std::string active_device(device);
7158 int ret;
7159
7160 if (active_device == "AUTO" && dev_type == AV_HWDEVICE_TYPE_VAAPI)
7161 {
7162 active_device = "/dev/dri/renderD128"; //** @todo HWACCEL - Try to autodetect rendering device
7163 }
7164
7165 ret = av_hwdevice_ctx_create(hwaccel_enc_device_ctx, dev_type, !active_device.empty() ? active_device.c_str() : nullptr, nullptr, 0);
7166 if (ret < 0)
7167 {
7168 Logging::error(virtname(), "Failed to create a %1 device (error '%2').", hwdevice_get_type_name(dev_type), ffmpeg_geterror(ret).c_str());
7169 return ret;
7170 }
7171 return 0;
7172}
7173
7174int FFmpeg_Transcoder::hwdevice_ctx_add_ref(AVCodecContext *input_codec_ctx)
7175{
7176 if (m_hwaccel_dec_device_ctx == nullptr)
7177 {
7178 int ret = AVERROR(EINVAL);
7179 Logging::error(virtname(), "INTERNAL ERROR: FFmpeg_Transcoder::hwdevice_ctx_add_ref()! HW decoder device context is NULL (error '%1').", ffmpeg_geterror(ret).c_str());
7180 return ret;
7181 }
7182
7183 input_codec_ctx->hw_device_ctx = av_buffer_ref(m_hwaccel_dec_device_ctx);
7184 if (input_codec_ctx->hw_device_ctx == nullptr)
7185 {
7186 int ret = AVERROR(ENOMEM);
7187 Logging::error(virtname(), "A hardware device reference create failed (error '%1').", ffmpeg_geterror(ret).c_str());
7188 return ret;
7189 }
7190
7191 input_codec_ctx->opaque = static_cast<void*>(this);
7192 input_codec_ctx->get_format = &FFmpeg_Transcoder::get_format_static;
7193
7194 return 0;
7195}
7196
7197void FFmpeg_Transcoder::hwdevice_ctx_free(AVBufferRef **hwaccel_device_ctx)
7198{
7199 if (*hwaccel_device_ctx != nullptr)
7200 {
7201 av_buffer_unref(hwaccel_device_ctx);
7202 *hwaccel_device_ctx = nullptr;
7203 }
7204}
7205
7206int FFmpeg_Transcoder::hwframe_ctx_set(AVCodecContext *output_codec_ctx, AVCodecContext *input_codec_ctx, AVBufferRef *hw_device_ctx) const
7207{
7208 AVBufferRef *hw_new_frames_ref;
7209 AVHWFramesContext *frames_ctx = nullptr;
7210 int ret = 0;
7211
7212 hw_new_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx);
7213 if (hw_new_frames_ref == nullptr)
7214 {
7215 ret = AVERROR(ENOMEM);
7216 Logging::error(virtname(), "hwframe_ctx_set(): Failed to create hwframe context (error '%1').", ffmpeg_geterror(ret).c_str());
7217 return ret;
7218 }
7219
7220 frames_ctx = reinterpret_cast<AVHWFramesContext *>(hw_new_frames_ref->data);
7221 frames_ctx->format = m_enc_hw_pix_fmt;
7222 frames_ctx->sw_format = /*input_codec_ctx->sw_pix_fmt; */find_sw_fmt_by_hw_type(params.m_hwaccel_enc_device_type);
7223 frames_ctx->width = input_codec_ctx->width;
7224 frames_ctx->height = input_codec_ctx->height;
7225
7226 frames_ctx->initial_pool_size = 20; // Driver default seems to be 17
7227
7228 ret = av_hwframe_ctx_init(hw_new_frames_ref);
7229 if (ret < 0)
7230 {
7231 Logging::error(virtname(), "hwframe_ctx_set(): Failed to initialise hwframe context (error '%1').", ffmpeg_geterror(ret).c_str());
7232 av_buffer_unref(&hw_new_frames_ref);
7233 return ret;
7234 }
7235
7236 output_codec_ctx->hw_frames_ctx = av_buffer_ref(hw_new_frames_ref);
7237 if (output_codec_ctx->hw_frames_ctx == nullptr)
7238 {
7239 ret = AVERROR(ENOMEM);
7240 Logging::error(virtname(), "hwframe_ctx_set(): A hardware frame reference create failed (error '%1').", ffmpeg_geterror(ret).c_str());
7241 }
7242
7243 av_buffer_unref(&hw_new_frames_ref);
7244
7245 return ret;
7246}
7247
7248//int FFmpeg_Transcoder::hwframe_ctx_set(AVCodecContext *output_codec_ctx, AVCodecContext *input_codec_ctx, AVBufferRef *hw_device_ctx)
7249//{
7250// // If the decoder runs in hardware, we should use the decoder's frames context. This will save us from
7251// // having to transfer frames from hardware to software and vice versa.
7252// // If the decoder runs in software, create a new frames context.
7253// if (input_codec_ctx->hw_frames_ctx != nullptr)
7254// {
7255// Logging::debug(virtname(), "Hardware encoder init: Hardware decoder active, using decoder hw_frames_ctx for encoder.");
7256
7257// /* we need to ref hw_frames_ctx of decoder to initialize encoder's codec.
7258// Only after we get a decoded frame, can we obtain its hw_frames_ctx */
7259// output_codec_ctx->hw_frames_ctx = av_buffer_ref(input_codec_ctx->hw_frames_ctx);
7260// if (!output_codec_ctx->hw_frames_ctx)
7261// {
7262// int ret = AVERROR(ENOMEM);
7263// Logging::error(virtname(), "A hardware frame reference create failed (error '%1').", ffmpeg_geterror(ret).c_str());
7264// return ret;
7265// }
7266
7267// m_hwaccel_dec = true; /* Doing decoding in hardware */
7268// }
7269// else {
7270// Logging::debug(virtname(), "Hardware encoder init: Software decoder active, creating new hw_frames_ctx for encoder.");
7271
7272// AVBufferRef *hw_new_frames_ref;
7273// AVHWFramesContext *frames_ctx = nullptr;
7274// int ret = 0;
7275
7276// if (!(hw_new_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx)))
7277// {
7278// ret = AVERROR(ENOMEM);
7279// Logging::error(virtname(), "Failed to create hwframe context (error '%1').", ffmpeg_geterror(ret).c_str());
7280// return ret;
7281// }
7282// frames_ctx = (AVHWFramesContext *)(hw_new_frames_ref->data);
7283// frames_ctx->format = m_hw_pix_fmt;
7284// frames_ctx->sw_format = find_sw_fmt_by_hw_type(params.m_hwaccel_enc_device_type);
7285// frames_ctx->width = input_codec_ctx->width;
7286// frames_ctx->height = input_codec_ctx->height;
7287
7288// frames_ctx->initial_pool_size = 20; // Driver default: 17
7289// if ((ret = av_hwframe_ctx_init(hw_new_frames_ref)) < 0)
7290// {
7291// Logging::error(virtname(), "Failed to initialise hwframe context (error '%1').", ffmpeg_geterror(ret).c_str());
7292// av_buffer_unref(&hw_new_frames_ref);
7293// return ret;
7294// }
7295
7296// output_codec_ctx->hw_frames_ctx = av_buffer_ref(hw_new_frames_ref);
7297// if (!output_codec_ctx->hw_frames_ctx)
7298// {
7299// Logging::error(virtname(), "A hardware frame reference create failed (error '%1').", ffmpeg_geterror(AVERROR(ENOMEM)));
7300// ret = AVERROR(ENOMEM);
7301// }
7302
7303// av_buffer_unref(&hw_new_frames_ref);
7304
7305// m_hwaccel_dec = false; /* Doing decoding in software */
7306// }
7307
7308// return 0;
7309//}
7310
7311int FFmpeg_Transcoder::hwframe_copy_from_hw(AVCodecContext * /*ctx*/, FFmpeg_Frame *sw_frame, const AVFrame * hw_frame) const
7312{
7313 int ret;
7314
7315 ret = av_frame_copy_props(*sw_frame, hw_frame);
7316 if (ret < 0)
7317 {
7318 Logging::error(filename(), "Failed to copy frame properties (error '%1').", ffmpeg_geterror(ret).c_str());
7319 return ret;
7320 }
7321
7322 ret = av_hwframe_transfer_data(*sw_frame, hw_frame, 0);
7323 if (ret < 0)
7324 {
7325 Logging::error(filename(), "Error while transferring frame data from surface (error '%1').", ffmpeg_geterror(ret).c_str());
7326 return ret;
7327 }
7328
7329 return 0;
7330}
7331
7332int FFmpeg_Transcoder::hwframe_copy_to_hw(AVCodecContext *output_codec_ctx, FFmpeg_Frame *hw_frame, const AVFrame * sw_frame) const
7333{
7334 int ret;
7335
7336 ret = av_frame_copy_props(*hw_frame, sw_frame);
7337 if (ret < 0)
7338 {
7339 Logging::error(virtname(), "Failed to copy frame properties (error '%1').", ffmpeg_geterror(ret).c_str());
7340 return ret;
7341 }
7342
7343 ret = av_hwframe_get_buffer(output_codec_ctx->hw_frames_ctx, *hw_frame, 0);
7344 if (ret < 0)
7345 {
7346 Logging::error(virtname(), "Failed to copy frame buffers to hardware memory (error '%1').", ffmpeg_geterror(ret).c_str());
7347 return ret;
7348 }
7349
7350 if ((*hw_frame)->hw_frames_ctx == nullptr)
7351 {
7352 ret = AVERROR(ENOMEM);
7353 Logging::error(virtname(), "Failed to copy frame buffers to hardware memory (error '%1').", ffmpeg_geterror(ret).c_str());
7354 return ret;
7355 }
7356
7357 ret = av_hwframe_transfer_data(*hw_frame, sw_frame, 0);
7358 if (ret < 0)
7359 {
7360 Logging::error(virtname(), "Error while transferring frame data to surface (error '%1').", ffmpeg_geterror(ret).c_str());
7361 return ret;
7362 }
7363
7364 return 0;
7365}
7366
7378int FFmpeg_Transcoder::get_hw_decoder_name(AVCodecID codec_id, std::string *codec_name) const
7379{
7380 std::string codec_name_buf;
7381 int ret = 0;
7382
7383 switch (params.m_hwaccel_dec_API)
7384 {
7385 case HWACCELAPI::VAAPI:
7386 {
7387 ret = get_hw_vaapi_codec_name(codec_id, &codec_name_buf);
7388 break;
7389 }
7390 case HWACCELAPI::MMAL:
7391 {
7392 ret = get_hw_mmal_decoder_name(codec_id, &codec_name_buf);
7393 break;
7394 }
7395 //case HWACCELAPI::V4L2M2M:
7396 //{
7397 // ret = get_hw_v4l2m2m_decoder_name(codec_id, &codec_name_buf);
7398 // break;
7399 //}
7400 case HWACCELAPI::NONE:
7401 default:
7402 {
7403 ret = AVERROR_DECODER_NOT_FOUND;
7404 break;
7405 }
7406 }
7407
7408 if (codec_name != nullptr)
7409 {
7410 if (!ret)
7411 {
7412 *codec_name = codec_name_buf;
7413 }
7414 else
7415 {
7416 codec_name->clear();
7417 }
7418 }
7419
7420 return ret;
7421}
7422
7423int FFmpeg_Transcoder::get_hw_encoder_name(AVCodecID codec_id, std::string *codec_name) const
7424{
7425 std::string codec_name_buf;
7426 int ret = 0;
7427
7428 switch (params.m_hwaccel_enc_API)
7429 {
7430 case HWACCELAPI::VAAPI:
7431 {
7432 ret = get_hw_vaapi_codec_name(codec_id, &codec_name_buf);
7433 break;
7434 }
7435 case HWACCELAPI::OMX:
7436 {
7437 ret = get_hw_omx_encoder_name(codec_id, &codec_name_buf);
7438 break;
7439 }
7440 //case HWACCELAPI::V4L2M2M:
7441 //{
7442 // ret = get_hw_v4l2m2m_encoder_name(codec_id, &codec_name_buf);
7443 // break;
7444 //}
7445 case HWACCELAPI::NONE:
7446 default:
7447 {
7448 ret = AVERROR_DECODER_NOT_FOUND;
7449 break;
7450 }
7451 }
7452
7453 if (codec_name != nullptr)
7454 {
7455 if (!ret)
7456 {
7457 *codec_name = codec_name_buf;
7458 }
7459 else
7460 {
7461 codec_name->clear();
7462 }
7463 }
7464
7465 return ret;
7466}
7467
7468int FFmpeg_Transcoder::get_hw_vaapi_codec_name(AVCodecID codec_id, std::string *codec_name) const
7469{
7470 int ret = 0;
7483 switch (codec_id)
7484 {
7485 case AV_CODEC_ID_H264:
7486 {
7487 *codec_name = "h264_vaapi";
7488 break;
7489 }
7516 //case AV_CODEC_ID_MJPEG:
7517 //{
7518 // *codec_name = "mjpeg_vaapi";
7519 // break;
7520 //}
7521 case AV_CODEC_ID_MPEG2VIDEO:
7522 {
7523 *codec_name = "mpeg2_vaapi";
7524 break;
7525 }
7526 case AV_CODEC_ID_HEVC:
7527 {
7528 *codec_name = "hevc_vaapi";
7529 break;
7530 }
7531 case AV_CODEC_ID_VC1:
7532 {
7533 *codec_name = "vc1_vaapi";
7534 break;
7535 }
7536 case AV_CODEC_ID_VP8:
7537 {
7538 *codec_name = "vp9_vaapi";
7539 break;
7540 }
7541 case AV_CODEC_ID_VP9:
7542 {
7543 *codec_name = "vp9_vaapi";
7544 break;
7545 }
7546 default:
7547 {
7548 ret = AVERROR_DECODER_NOT_FOUND;
7549 break;
7550 }
7551 }
7552
7553 return ret;
7554}
7555
7556int FFmpeg_Transcoder::get_hw_mmal_decoder_name(AVCodecID codec_id, std::string *codec_name) const
7557{
7558 int ret = 0;
7568 switch (codec_id)
7569 {
7570 case AV_CODEC_ID_H264:
7571 {
7572 *codec_name = "h264_mmal";
7573 break;
7574 }
7592 case AV_CODEC_ID_MPEG2VIDEO:
7593 {
7594 *codec_name = "mpeg2_mmal";
7595 break;
7596 }
7597 case AV_CODEC_ID_MPEG4:
7598 {
7599 *codec_name = "mpeg4_mmal";
7600 break;
7601 }
7615 case AV_CODEC_ID_VC1:
7616 {
7617 *codec_name = "vc1_mmal";
7618 break;
7619 }
7620 default:
7621 {
7622 ret = AVERROR_DECODER_NOT_FOUND;
7623 break;
7624 }
7625 }
7626
7627 return ret;
7628}
7629
7630//int FFmpeg_Transcoder::get_hw_v4l2m2m_decoder_name(AVCodecID codec_id, std::string *codec_name) const
7631//{
7632// int ret = 0;
7633// /**
7634// * *** v4l2m2m (Video2linux) decoder ***
7635// *
7636// * h263_v4l2m2m V4L2 mem2mem H.263 decoder wrapper (codec h263)
7637// * h264_v4l2m2m V4L2 mem2mem H.264 decoder wrapper (codec h264)
7638// * hevc_v4l2m2m V4L2 mem2mem HEVC decoder wrapper (codec hevc)
7639// * mpeg1_v4l2m2m V4L2 mem2mem MPEG1 decoder wrapper (codec mpeg1video)
7640// * mpeg2_v4l2m2m V4L2 mem2mem MPEG2 decoder wrapper (codec mpeg2video)
7641// * mpeg4_v4l2m2m V4L2 mem2mem MPEG4 decoder wrapper (codec mpeg4)
7642// * vc1_v4l2m2m V4L2 mem2mem VC1 decoder wrapper (codec vc1)
7643// * vp8_v4l2m2m V4L2 mem2mem VP8 decoder wrapper (codec vp8)
7644// * vp9_v4l2m2m V4L2 mem2mem VP9 decoder wrapper (codec vp9)
7645// */
7646// switch (codec_id)
7647// {
7648// case AV_CODEC_ID_H263:
7649// {
7650// *codec_name = "h263_v4l2m2m";
7651// break;
7652// }
7653// case AV_CODEC_ID_H264:
7654// {
7655// *codec_name = "h264_v4l2m2m";
7656// break;
7657// }
7658// case AV_CODEC_ID_H265:
7659// {
7660// *codec_name = "hevc_v4l2m2m";
7661// break;
7662// }
7663// case AV_CODEC_ID_MPEG1VIDEO:
7664// {
7665// *codec_name = "mpeg1_v4l2m2m";
7666// break;
7667// }
7668// case AV_CODEC_ID_MPEG2VIDEO:
7669// {
7670// *codec_name = "mpeg2_v4l2m2m";
7671// break;
7672// }
7673// case AV_CODEC_ID_MPEG4:
7674// {
7675// *codec_name = "mpeg4_v4l2m2m";
7676// break;
7677// }
7678// //case AV_CODEC_ID_VC1: /** @todo WMV is currently not supported */
7679// //{
7680// // *codec_name = "vc1_v4l2m2m";
7681// // break;
7682// //}
7683// case AV_CODEC_ID_VP8:
7684// {
7685// *codec_name = "vp8_v4l2m2m";
7686// break;
7687// }
7688// case AV_CODEC_ID_VP9:
7689// {
7690// *codec_name = "vp9_v4l2m2m";
7691// break;
7692// }
7693// default:
7694// {
7695// ret = AVERROR_DECODER_NOT_FOUND;
7696// break;
7697// }
7698// }
7699
7700// return ret;
7701//}
7702
7703int FFmpeg_Transcoder::get_hw_omx_encoder_name(AVCodecID codec_id, std::string *codec_name) const
7704{
7705 int ret = 0;
7711 switch (codec_id)
7712 {
7713 case AV_CODEC_ID_H264:
7714 {
7715 *codec_name = "h264_omx";
7716 break;
7717 }
7718 default:
7719 {
7720 ret = AVERROR_DECODER_NOT_FOUND;
7721 break;
7722 }
7723 }
7724
7725 return ret;
7726}
7727
7728int FFmpeg_Transcoder::get_hw_v4l2m2m_encoder_name(AVCodecID codec_id, std::string *codec_name) const
7729{
7730 int ret = 0;
7740 switch (codec_id)
7741 {
7742 case AV_CODEC_ID_H263:
7743 {
7744 *codec_name = "h263_v4l2m2m";
7745 break;
7746 }
7747 case AV_CODEC_ID_H264:
7748 {
7749 *codec_name = "h264_v4l2m2m";
7750 break;
7751 }
7752 case AV_CODEC_ID_H265:
7753 {
7754 *codec_name = "hevc_v4l2m2m";
7755 break;
7756 }
7757 case AV_CODEC_ID_MPEG4:
7758 {
7759 *codec_name = "mpeg4_v4l2m2m";
7760 break;
7761 }
7762 case AV_CODEC_ID_VP8:
7763 {
7764 *codec_name = "vp8_v4l2m2m";
7765 break;
7766 }
7767 default:
7768 {
7769 ret = AVERROR_DECODER_NOT_FOUND;
7770 break;
7771 }
7772 }
7773
7774 return ret;
7775}
7776
7777AVPixelFormat FFmpeg_Transcoder::find_sw_fmt_by_hw_type(AVHWDeviceType type)
7778{
7779 DEVICETYPE_MAP::const_iterator it = m_devicetype_map.find(type);
7780
7781 if (it == m_devicetype_map.cend())
7782 {
7783 return AV_PIX_FMT_NONE;
7784 }
7785
7786 return it->second;
7787}
7788
7789void FFmpeg_Transcoder::get_pix_formats(AVPixelFormat *in_pix_fmt, AVPixelFormat *out_pix_fmt, AVCodecContext* output_codec_ctx) const
7790{
7791 *in_pix_fmt = static_cast<AVPixelFormat>(m_in.m_video.m_stream->codecpar->format);
7792
7794 {
7796 }
7797
7798 if (output_codec_ctx == nullptr)
7799 {
7800 output_codec_ctx = m_out.m_video.m_codec_ctx.get();
7801 }
7802
7803 // Fail safe: If output_codec_ctx is NULL, set to something common (AV_PIX_FMT_YUV420P is widely used)
7804 *out_pix_fmt = (output_codec_ctx != nullptr) ? output_codec_ctx->pix_fmt : AV_PIX_FMT_YUV420P;
7805
7806 if (*in_pix_fmt == AV_PIX_FMT_NONE)
7807 {
7808 // If input's stream pixel format is unknown, use same as output (may not work but at least will not crash FFmpeg)
7809 *in_pix_fmt = *out_pix_fmt;
7810 }
7811
7812 // If hardware acceleration is enabled, e.g., output_codec_ctx->pix_fmt is AV_PIX_FMT_VAAPI
7813 // but the format actually is AV_PIX_FMT_NV12 so we use the correct value from sw_format in
7814 // the hardware frames context.
7816 output_codec_ctx != nullptr &&
7817 output_codec_ctx->hw_frames_ctx != nullptr &&
7818 output_codec_ctx->hw_frames_ctx->data != nullptr)
7819 {
7820 *out_pix_fmt = reinterpret_cast<AVHWFramesContext*>(output_codec_ctx->hw_frames_ctx->data)->sw_format;
7821 }
7822}
7823
7824uint32_t FFmpeg_Transcoder::get_next_segment(int64_t pos) const
7825{
7826 return (static_cast<uint32_t>(pos / params.m_segment_duration + 1));
7827}
7828
7829bool FFmpeg_Transcoder::goto_next_segment(uint32_t next_segment) const
7830{
7831 return (next_segment == m_current_segment + 1 && next_segment <= m_virtualfile->get_segment_count());
7832}
7833
7834bool FFmpeg_Transcoder::is_audio_stream(int stream_idx) const
7835{
7836 return (stream_exists(stream_idx) && stream_idx == m_in.m_audio.m_stream_idx);
7837}
7838
7839bool FFmpeg_Transcoder::is_video_stream(int stream_idx) const
7840{
7841 return (stream_exists(stream_idx) && stream_idx == m_in.m_video.m_stream_idx);
7842}
7843
7845{
7846 StreamRef_map::const_iterator it = m_in.m_subtitle.find(stream_idx);
7847
7848 return (it != m_in.m_subtitle.cend());
7849}
7850
7852{
7853 StreamRef_map::iterator it = m_out.m_subtitle.find(stream_idx);
7854
7855 if (it == m_out.m_subtitle.end())
7856 {
7857 return nullptr;
7858 }
7859
7860 return &it->second;
7861}
7862
7863bool FFmpeg_Transcoder::stream_exists(int stream_idx) const
7864{
7865 return (stream_idx != INVALID_STREAM);
7866}
7867
7868void FFmpeg_Transcoder::add_stream_map(int in_stream_idx, int out_stream_idx)
7869{
7870 if (in_stream_idx != INVALID_STREAM)
7871 {
7872 m_stream_map.emplace(in_stream_idx, out_stream_idx);
7873 }
7874}
7875
7877{
7878 STREAM_MAP::const_iterator it = m_stream_map.find(in_stream_idx);
7879
7880 if (it == m_stream_map.cend())
7881 {
7882 return INVALID_STREAM;
7883 }
7884
7885 return (it->second);
7886}
7887
7888inline int FFmpeg_Transcoder::foreach_subtitle_file(const std::string& search_path, const std::regex& regex, int depth, const std::function<int (const std::string &, const std::optional<std::string> &)> &f)
7889{
7890 int ret = 0;
7891
7892 try
7893 {
7894 const std::filesystem::directory_iterator end;
7895 for (std::filesystem::directory_iterator iter{ search_path }; iter != end && ret == 0; iter++)
7896 {
7897 const std::string subtitle_filename(iter->path().filename().string());
7898 if (std::filesystem::is_regular_file(*iter))
7899 {
7900 if (std::regex_match(subtitle_filename, regex))
7901 {
7902 std::smatch res;
7903 if (std::regex_search(subtitle_filename.cbegin(), subtitle_filename.cend(), res, regex))
7904 {
7905 if (res[2].length())
7906 {
7907 ret = f(iter->path().string(), res[2]);
7908 }
7909 else
7910 {
7911 ret = f(iter->path().string(), std::nullopt);
7912 }
7913 }
7914 }
7915 }
7916 else if (std::filesystem::is_directory(*iter) && depth > 0)
7917 {
7918 ret = foreach_subtitle_file(iter->path().string(), regex, depth - 1, f);
7919 }
7920 }
7921 }
7922 catch (std::filesystem::filesystem_error& e)
7923 {
7924 ret = AVERROR(e.code().value());
7925 Logging::error(filename(), "Could not open directory '%1' (error '%2').", search_path.c_str(), ffmpeg_geterror(ret).c_str());
7926 }
7927 catch (std::bad_alloc & e)
7928 {
7929 ret = AVERROR(ENOMEM);
7930 Logging::error(filename(), "Could not open directory '%1' (error '%2').", search_path.c_str(), ffmpeg_geterror(ret).c_str());
7931 }
7932
7933 return ret;
7934}
7935
7936int FFmpeg_Transcoder::read_packet(void *opaque, uint8_t *buf, int buf_size)
7937{
7938 BUFFER_DATA *bd = static_cast<BUFFER_DATA *>(opaque);
7939 buf_size = FFMIN(buf_size, static_cast<int>(bd->size));
7940
7941 if (!buf_size)
7942 {
7943 return AVERROR_EOF;
7944 }
7945
7946 /* copy internal buffer data to buf */
7947 std::memcpy(buf, bd->ptr, static_cast<size_t>(buf_size));
7948 bd->ptr += buf_size;
7949 bd->size -= static_cast<size_t>(buf_size);
7950
7951 return buf_size;
7952}
7953
7954int FFmpeg_Transcoder::add_external_subtitle_stream(const std::string & subtitle_file, const std::optional<std::string> & language)
7955{
7956 AVFormatContext *format_ctx = nullptr;
7957 AVIOContext *avio_ctx = nullptr;
7958 uint8_t *buffer = nullptr;
7959 size_t buffer_size;
7960 int ret = 0;
7961
7962 if (language)
7963 {
7964 Logging::debug(filename(), "Adding external subtitle stream: %1 [%2]", subtitle_file.c_str(), language->c_str());
7965 }
7966 else
7967 {
7968 Logging::debug(filename(), "Adding external subtitle stream: %1", subtitle_file.c_str());
7969 }
7970
7971 try
7972 {
7973 uint8_t *avio_ctx_buffer = nullptr;
7974 int avio_ctx_buffer_size = 4096;
7975 BUFFER_DATA bd = { nullptr, 0 };
7976
7977 // slurp file content into buffer
7978 ret = av_file_map(subtitle_file.c_str(), &buffer, &buffer_size, 0, nullptr);
7979 if (ret < 0)
7980 {
7981 throw ret;
7982 }
7983
7984 // fill opaque structure used by the AVIOContext read callback
7985 bd.ptr = buffer;
7986 bd.size = buffer_size;
7987
7988 format_ctx = avformat_alloc_context();
7989 if (format_ctx == nullptr)
7990 {
7991 throw AVERROR(ENOMEM);
7992 }
7993
7994 avio_ctx_buffer = reinterpret_cast<uint8_t *>(av_malloc(static_cast<size_t>(avio_ctx_buffer_size)));
7995 if (avio_ctx_buffer == nullptr)
7996 {
7997 throw AVERROR(ENOMEM);
7998 }
7999
8000 avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, 0, &bd, &read_packet, nullptr, nullptr);
8001 if (avio_ctx == nullptr)
8002 {
8003 throw AVERROR(ENOMEM);
8004 }
8005 format_ctx->pb = avio_ctx;
8006
8007 ret = avformat_open_input(&format_ctx, nullptr, nullptr, nullptr);
8008 if (ret < 0)
8009 {
8010 Logging::error(filename(), "Could not open input file (error '%1').", ffmpeg_geterror(ret).c_str());
8011 throw ret;
8012 }
8013
8014 ret = avformat_find_stream_info(format_ctx, nullptr);
8015 if (ret < 0)
8016 {
8017 Logging::error(filename(), "Could not find stream info (error '%1').", ffmpeg_geterror(ret).c_str());
8018 throw ret;
8019 }
8020
8021 //av_dump_format(format_ctx, 0, subtitle_file.c_str(), 0);
8022
8023 AVCodecContext * codec_ctx = nullptr;
8024 int stream_idx = INVALID_STREAM;
8025
8026 ret = open_bestmatch_decoder(format_ctx, &codec_ctx, &stream_idx, AVMEDIA_TYPE_SUBTITLE);
8027 if (ret < 0 && ret != AVERROR_STREAM_NOT_FOUND) // AVERROR_STREAM_NOT_FOUND is not an error
8028 {
8029 Logging::error(filename(), "Failed to open video codec (error '%1').", ffmpeg_geterror(ret).c_str());
8030 throw ret;
8031 }
8032
8033 if (ret != AVERROR_STREAM_NOT_FOUND)
8034 {
8035 AVCodecID codec_id = m_current_format->subtitle_codec(codec_ctx->codec_id); // Get matching output codec
8036
8037 if (codec_id != AV_CODEC_ID_NONE)
8038 {
8039 StreamRef input_streamref;
8040
8041 codec_ctx->pkt_timebase = codec_ctx->time_base = format_ctx->streams[0]->time_base;
8042
8043 // We have a subtitle stream
8044 input_streamref.set_codec_ctx(codec_ctx);
8045 input_streamref.m_stream = format_ctx->streams[0];
8046 input_streamref.m_stream_idx = INVALID_STREAM;
8047
8048 //m_active_stream_msk |= FFMPEGFS_SUBTITLE;
8049
8050 ret = add_subtitle_stream(codec_id, input_streamref, language);
8051 if (ret < 0)
8052 {
8053 throw ret;
8054 }
8055
8056 int output_stream_index = ret;
8057 FFmpeg_Packet pkt;
8058 ret = pkt.res();
8059 if (ret < 0)
8060 {
8061 throw ret;
8062 }
8063
8064 // Read one frame from the input file into a temporary packet.
8065 while ((ret = av_read_frame(format_ctx, pkt)) == 0)
8066 {
8067 int decoded;
8068 ret = decode_subtitle(codec_ctx, pkt, &decoded, output_stream_index);
8069 if (ret < 0)
8070 {
8071 throw ret;
8072 }
8073 }
8074 }
8075 }
8076
8077 if (ret == AVERROR_EOF)
8078 {
8079 ret = 0;
8080 }
8081 }
8082 catch (int _ret)
8083 {
8084 ret = _ret;
8085 }
8086
8087 avformat_close_input(&format_ctx);
8088
8089 // note: the internal buffer could have changed, and be != avio_ctx_buffer
8090 if (avio_ctx != nullptr)
8091 {
8092 av_freep(&avio_ctx->buffer);
8093 }
8094
8095 avio_context_free(&avio_ctx);
8096
8097 av_file_unmap(buffer, buffer_size);
8098
8099 return ret;
8100}
8101
8103{
8104 int ret;
8105
8106 try
8107 {
8108 std::filesystem::path file(filename());
8109 std::string stem(file.stem().string());
8110
8111 // Escape characters that are meaningful to regexp.
8112 regex_escape(&stem);
8113
8114 std::string regex_string("^(" + stem + "[.])(.*)([.]srt|[.]vtt)|^(" + stem + ")([.]srt|[.]vtt)"); // filename.srt/vtt or filename.lang.srt/vtt
8115 std::regex regex(regex_string, std::regex::ECMAScript);
8116
8117 //ret = foreach_subtitle_file(
8118 // file.parent_path(),
8119 // regex,
8120 // 0,
8121 // std::bind(&FFmpeg_Transcoder::add_external_subtitle_stream, this, std::placeholders::_1, std::placeholders::_2));
8122
8123 // clang-tidy now recommends a lambda
8125 file.parent_path().string(),
8126 regex,
8127 0,
8128 [this](const std::string & subtitle_file, const std::optional<std::string> & language)
8129 {
8130 add_external_subtitle_stream(std::forward<decltype(subtitle_file)>(subtitle_file), std::forward<decltype(language)>(language));
8131 return 0;
8132 });
8133
8134 // Ugly, but a lambda would also be possible
8135 //ret = foreach_subtitle_file(
8136 // file.parent_path(),
8137 // regex,
8138 // 0,
8139 // [this](const std::string & subtitle_file, const std::optional<std::string> & language)
8140 //{
8141 // if (language)
8142 // {
8143 // Logging::error(filename(), "[%1] %2", language->c_str(), subtitle_file.c_str());
8144 // }
8145 // else
8146 // {
8147 // Logging::error(filename(), "%1", subtitle_file.c_str());
8148 // }
8149 // return 0;
8150 //});
8151 }
8152 catch (std::regex_error & e)
8153 {
8154 ret = 0; // Ignore error
8155 Logging::error(filename(), "INTERNAL ERROR: FFmpeg_Transcoder::add_external_subtitle_streams()! Unable to create reg exp: %1", e.what());
8156 }
8157
8158 return ret;
8159}
8160
8162{
8163 MULTIFRAME_MAP::const_reverse_iterator it = m_frame_map.crbegin();
8164
8165 if (it != m_frame_map.crend())
8166 {
8167 return it->first;
8168 }
8169 else
8170 {
8171 return 0;
8172 }
8173}
8174
8176{
8177 return m_last_seek_frame_no;
8178}
AIFF file structures http://paulbourke.net/dataformats/audio/.
#define AIFF_SOUNDATAID
ckID for Sound Data Chunk
Definition aiff.h:81
#define AIFF_COMMONID
ckID for Common Chunk
Definition aiff.h:67
#define AIFF_FORMID
ckID for Form Chunk
Definition aiff.h:45
Buffer class.
#define CACHE_FLAG_RW
Mark cache file writeable, implies read permissions.
Definition buffer.h:50
The Buffer class.
Definition buffer.h:56
virtual bool eof() const override
Check if at end of file.
Definition buffer.cc:1146
bool segment_exists(uint32_t segment_no)
Check if segment exists.
Definition buffer.cc:347
void finished_segment()
Complete the segment decoding.
Definition buffer.cc:1195
virtual int seek(int64_t offset, int whence) override
Seek to position in file.
Definition buffer.cc:869
size_t writeio(const uint8_t *data, size_t length)
Write data to the current position in the buffer. The position pointer will be updated.
Definition buffer.cc:766
size_t write_frame(const uint8_t *data, size_t length, uint32_t frame_no)
Write image data for the frame number into the buffer.
Definition buffer.cc:793
bool have_frame(uint32_t frame_no)
Check if we have the requested frame number. Works only when processing a frame set.
Definition buffer.cc:1161
bool copy(std::vector< uint8_t > *out_data, size_t offset, uint32_t segment_no=0)
Copy buffered data into output buffer.
Definition buffer.cc:980
virtual size_t tell() const override
Get the value of the internal read position pointer.
Definition buffer.cc:926
bool set_segment(uint32_t segment_no, size_t size)
Set the current segment.
Definition buffer.cc:303
bool open_file(uint32_t segment_no, uint32_t flags, size_t defaultsize=0)
Open the cache file if not already open.
Definition buffer.cc:77
size_t buffer_watermark(uint32_t segment_no=0) const
Return the current watermark of the file while transcoding.
Definition buffer.cc:967
int write(void **data, int nb_samples)
Write audio samples into the FIFO.
void reset()
Free the owned FIFO and reset the wrapper to empty.
int read(void **data, int nb_samples)
Read audio samples from the FIFO.
bool empty() const
Check whether the wrapper currently owns a FIFO.
int size() const
Return the number of samples currently stored in the FIFO.
int realloc(int nb_samples)
Resize the FIFO allocation.
int alloc(AVSampleFormat sample_fmt, int channels, int nb_samples=1)
Allocate a new audio FIFO, replacing any existing one.
static std::string get_sample_fmt_name(AVSampleFormat sample_fmt)
Calls av_get_sample_fmt_name and returns a std::string with the format name.
int get_channels(const AVCodecParameters *codecpar) const
Get the number of channels from AVCodecParameters.
int opt_set_with_check(void *obj, const char *key, const char *value, int flags, const char *filename=nullptr) const
Call av_opt_set and check result code. Displays an error message if appropriate.
int get_script_info(AVCodecContext *codec_ctx, int play_res_x, int play_res_y, const char *font, int font_size, int primary_color, int secondary_color, int outline_color, int back_color, int bold, int italic, int underline, int border_style, int alignment) const
Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS. Nicked from the FFmpeg API funct...
void audio_info(bool out_file, const AVFormatContext *format_ctx, const AVStream *stream) const
Print data from the audio stream to log.
int64_t frame_to_pts(AVStream *stream, uint32_t frame_no) const
Convert frame number to PTS value.
uint32_t pts_to_frame(AVStream *stream, int64_t pts) const
Convert PTS value to frame number.
void video_info(bool out_file, const AVFormatContext *format_ctx, const AVStream *stream) const
Print data from the video stream to a log.
void subtitle_info(bool out_file, const AVFormatContext *format_ctx, const AVStream *stream) const
Print data from the subtitle stream to log.
VIRTUALFILE * m_virtualfile
Underlying virtual file object.
void video_stream_setup(AVCodecContext *output_codec_ctx, AVStream *output_stream, AVCodecContext *input_codec_ctx, AVRational framerate, AVPixelFormat enc_hw_pix_fmt) const
Set up a video stream.
static std::string get_channel_layout_name(const AVChannelLayout *ch_layout)
Calls av_channel_layout_describe and returns a std::string with the channel layout.
static std::string get_pix_fmt_name(AVPixelFormat pix_fmt)
Calls av_get_pix_fmt_name and returns a std::string with the pix format name.
int dict_set_with_check(AVDictionary **pm, const char *key, const char *value, int flags, const char *filename=nullptr, bool nodelete=false) const
Call av_dict_set and check the result code. It displays an error message if appropriate.
void set_channels(AVCodecParameters *codecpar_out, const AVCodecParameters *codecpar_in) const
Set the number of channels from AVCodecParameters.
RAII wrapper for AVDictionary.
AVDictionary ** address()
Get a writable pointer-to-pointer for FFmpeg APIs.
int alloc_input_context()
Allocate a new input format context.
bool reset()
Free the owned format context and reset the wrapper to empty.
AVFormatContext ** address()
Get a writable pointer-to-pointer for FFmpeg APIs.
void set_custom_io(bool custom_io=true)
Mark whether the context owns a custom AVIOContext.
int alloc_output_context(const char *format_name, const char *filename=nullptr)
Allocate a new output format context.
The FFmpeg_Frame class.
int m_stream_idx
Stream index frame belongs to, or -1 (INVALID_STREAM)
int res() const
Get result of last operation.
RAII wrapper for AVPacket.
void unref()
Unreference packet payload, keep the AVPacket object allocated.
int res() const
Get result of last operation.
static const PROFILE_LIST_VEC m_profile
List of profile options.
std::vector< PROFILE_OPTION > PROFILE_OPTION_VEC
PROFILE_OPTION array.
The FFmpeg_Subtitle class.
int m_stream_idx
Stream index frame belongs to, or -1 (INVALID_STREAM)
int res() const
Get result of last operation.
bool reset(SwrContext *ctx=nullptr)
Replace the owned context.
SwrContext ** address()
Get a writable pointer-to-pointer for FFmpeg allocation APIs.
bool reset(SwsContext *ctx=nullptr)
Replace the owned context.
In/output stream reference data.
int m_stream_idx
Stream index in AVFormatContext.
int64_t m_start_time
Start time of the stream in stream time base units, may be 0.
AVStream * m_stream
AVStream for this encoder stream.
void reset()
Close (reset) AVCodecContext pointer.
void set_codec_ctx(AVCodecContext *codec_ctx)
Set the AVCodecContext pointer. Will be shared and deleted after the last consumer freed it.
std::shared_ptr< AVCodecContext > m_codec_ctx
AVCodecContext for this encoder stream.
The FFmpeg_Transcoder class.
int add_samples_to_fifo(uint8_t **converted_input_samples, int frame_size)
Add converted input audio samples to the FIFO buffer for later processing.
uint32_t m_current_segment
HLS only: Segment file number currently being encoded.
static bool video_size(size_t *filesize, AVCodecID codec_id, BITRATE bit_rate, int64_t duration, int width, int height, bool interleaved, const AVRational &framerate)
Predict video file size. This may (better will surely) be inaccurate.
int add_subtitle_stream(AVCodecID codec_id, StreamRef &input_streamref, const std::optional< std::string > &language=std::nullopt)
Add new subtitle stream to output file.
HWACCELMODE
Currently active hardware acceleration mode.
@ NONE
Hardware acceleration not active.
@ ENABLED
Hardware acceleration is active.
@ FALLBACK
Hardware acceleration selected, but fell back to software.
bool m_hwaccel_enable_enc_buffering
Enable hardware acceleration frame buffers for encoder.
int open_albumarts()
open_albumarts
static const DEVICETYPE_MAP m_devicetype_map
List of AVPixelFormats mapped to hardware acceleration types.
int open_output(Buffer *buffer)
Open output file. Data will actually be written to buffer and copied by FUSE when accessed.
int flush_frames_all(bool use_flush_packet)
Flush the remaining frames for all streams.
int stack_seek_frame(uint32_t frame_no)
Seek to a specific frame. Does not actually perform the seek, this is done asynchronously by the tran...
int get_hw_vaapi_codec_name(AVCodecID codec_id, std::string *codec_name) const
Determine VAAPI codec name.
int purge_audio_fifo()
Purge all samples in audio FIFO.
int open_bestmatch_audio()
Open the best match audio stream.
virtual const char * filename() const override
Return source filename.
int get_hw_omx_encoder_name(AVCodecID codec_id, std::string *codec_name) const
Determine OMX encoder codec name.
int process_single_fr(DECODER_STATUS *status)
bool can_copy_stream(const AVStream *stream) const
Check if stream can be copied from input to output (AUTOCOPY option).
static int input_read(void *opaque, unsigned char *data, int size)
Custom read function for FFmpeg.
size_t purge_multiframe_map()
Purge all frames in buffer.
int get_hw_mmal_decoder_name(AVCodecID codec_id, std::string *codec_name) const
Determine MMAL decoder codec name.
bool m_hwaccel_enable_dec_buffering
Enable hardware acceleration frame buffers for decoder.
AVSampleFormat m_cur_sample_fmt
Currently selected audio sample format.
int store_packet(AVPacket *pkt, AVMediaType mediatype)
Store packet in output stream.
void purge()
Purge FIFO and map buffers and report lost packets/frames/samples.
int add_stream_copy(AVCodecID codec_id, AVMediaType codec_type)
Add new stream copy to output file.
std::queue< FFmpeg_Packet > m_hls_packet_fifo
HLS packet FIFO.
const FFmpegfs_Format * m_current_format
Currently used output format(s)
int map_in_to_out_stream(int in_stream_idx) const
Map input stream index to output stream index.
static bool audio_size(size_t *filesize, AVCodecID codec_id, BITRATE bit_rate, int64_t duration, int channels, int sample_rate, AVSampleFormat sample_format)
Predict audio file size. This may (better will surely) be inaccurate.
bool have_seeked() const
Check if we made a seek operation.
int add_external_subtitle_streams()
Scan for external subtitle files.
int init_deinterlace_filters(AVCodecContext *codec_ctx, AVPixelFormat pix_fmt, const AVRational &avg_frame_rate, const AVRational &time_base)
Initialise video filters.
int prepare_format(AVDictionary **dict, FILETYPE filetype) const
Prepare format optimisations.
StreamRef * get_out_subtitle_stream(int stream_idx)
Get subtitle stream for the stream index.
INPUTFILE m_in
Input file information.
FFmpeg_SwrContext m_audio_resample_ctx
SwResample context for audio resampling.
int decode_video_frame(AVPacket *pkt, int *decoded)
Decode one video frame.
int decode_subtitle(AVPacket *pkt, int *decoded)
Decode one subtitle.
bool m_copy_video
If true, copy video stream from source to target (just remux, no recode).
uint32_t m_inhibit_stream_msk
HLS: Currently inhibited streams bit mask. Packets temporarly go to m_hls_packet_fifo and will be pre...
std::queue< uint32_t > m_seek_to_fifo
Stack of seek requests. Will be processed FIFO.
uint32_t get_next_segment(int64_t pos) const
Calculate next HLS segment from position.
int open_subtitles()
Open all subtitles streams, if present in input file and if supported by output file....
int open_bestmatch_video()
Open the best match video stream, if present in input file.
static AVPixelFormat find_sw_fmt_by_hw_type(AVHWDeviceType type)
Get the software pixel format for the given hardware acceleration.
int send_filters(FFmpeg_Frame *srcframe, int &ret)
Send video frame to the filters.
bool m_insert_keyframe
HLS only: Allow insertion of 1 keyframe.
FFmpeg_AudioFifo m_audio_fifo
Audio sample FIFO.
int init_converted_samples(uint8_t ***converted_input_samples, int frame_size)
Initialise a temporary storage for the specified number of audio samples. The conversion requires tem...
static int output_write(void *opaque, const uint8_t *data, int size)
Custom write function for FFmpeg.
static bool get_output_sample_rate(int input_sample_rate, int max_sample_rate, int *output_sample_rate=nullptr)
Calculate output sample rate based on user option.
bool close_input_file()
Closes the input file if open. Can safely be called again after the file was already closed or if the...
void copy_metadata(AVDictionary **metadata_out, const AVDictionary *metadata_in, bool contentstream=true)
Process the metadata in the FFmpeg file. This should be called at the beginning, before reading audio...
int update_codec(void *opt, const PROFILE_OPTION_VEC &profile_option_vec) const
Prepare codec options.
void flush_buffers()
Flush FFmpeg's input buffers.
int add_external_subtitle_stream(const std::string &subtitle_file, const std::optional< std::string > &language)
add_external_subtitle_stream
AVFilterGraph * m_filter_graph
Video filter graph.
bool get_aspect_ratio(int width, int height, const AVRational &sar, AVRational *ar) const
Calculate aspect ratio for width/height and sample aspect ratio (sar).
enum AVPixelFormat get_format(AVCodecContext *input_codec_ctx, const enum AVPixelFormat *pix_fmts) const
uint32_t m_reset_pts
We have to reset audio/video pts to the new position.
AVBufferRef * m_hwaccel_dec_device_ctx
Hardware acceleration device context for decoder.
int init_resampler()
Initialize the audio resampler based on the input and output codec settings. If the input and output ...
Buffer * m_buffer
Pointer to cache buffer object.
int encode_video_frame(const AVFrame *frame, int *data_present)
Encode one frame worth of video to the output file.
std::shared_ptr< FileIO > m_fileio
FileIO object of input file.
bool m_skip_next_frame
After seek, skip next video frame.
void closeio()
Close transcoder, free all ressources.
int read_decode_convert_and_store(int *finished)
Read frame from source file, decode and store in FIFO.
int add_albumart_frame(AVStream *output_stream, AVPacket *pkt_in)
Add album art to stream.
int get_hw_encoder_name(AVCodecID codec_id, std::string *codec_name=nullptr) const
Get the hardware codec name as string. This is required, because e.g. the name for the software codec...
uint32_t video_frame_count() const
Get the number of video frames in file.
bool is_hls() const
Check for HLS format.
int copy_audio_to_frame_buffer(int *finished)
Copy data from audio FIFO to frame buffer. Divides WAV data into proper chunks to be fed into the enc...
FFmpeg_SwsContext m_sws_ctx
Context for video filtering.
int create_fake_aiff_header() const
Create a fake AIFF header Create a fake AIFF header. Inserts predicted file sizes to allow playback t...
int read_aiff_chunk(Buffer *buffer, size_t *buffoffset, const char *ID, uint8_t *chunk, size_t *size) const
Read AIFF chunk.
bool is_audio_stream(int stream_idx) const
Check for audio stream.
MULTIFRAME_MAP m_frame_map
Audio/video/subtitle frame map.
bool goto_next_segment(uint32_t next_segment) const
Check if segment number is next designated segment.
size_t predicted_filesize() const
Try to predict the recoded file size. This may (better will surely) be inaccurate.
bool is_video_stream(int stream_idx) const
Check for video stream.
static bool total_overhead(size_t *filesize, FILETYPE filetype)
Predict overhead in file size. This may (better will surely) be inaccurate.
bool is_subtitle_stream(int stream_idx) const
Check for subtitle stream.
int add_albumart_stream(const AVCodecContext *input_codec_ctx)
Add a stream for an album art.
int64_t m_pos
Generated position.
bool m_have_seeked
After seek operations this is set to make sure the trancoding result is marked RESULTCODE_INCOMPLETE ...
AVPixelFormat get_hw_pix_fmt(const AVCodec *codec, AVHWDeviceType dev_type, bool use_device_ctx) const
Determine the hardware pixel format for the codec, if applicable.
int flush_delayed_audio()
Flush delayed audio packets, if there are any.
int do_seek_frame(uint32_t frame_no)
Actually perform seek for frame. This function ensures that it is positioned at a key frame,...
int decode(AVCodecContext *codec_ctx, AVFrame *frame, int *got_frame, const AVPacket *pkt) const
const ID3v1 * id3v1tag() const
Assemble an ID3v1 file tag.
size_t calculate_predicted_filesize() const
Try to predict final file size.
int init_audio_output_frame(AVFrame *frame, int frame_size) const
Initialise one input frame for writing to the output file. The frame will be exactly frame_size sampl...
int encode_image_frame(const AVFrame *frame, int *data_present)
Encode frame to image.
static BITRATE get_prores_bitrate(int width, int height, const AVRational &framerate, bool interleaved, PRORESLEVEL profile)
Calculate the appropriate bitrate for a ProRes file given several parameters.
static int64_t seek(void *opaque, int64_t offset, int whence)
Custom seek function for FFmpeg.
uint32_t segment_count() const
Get the number of HLS segments of file.
int get_hw_v4l2m2m_encoder_name(AVCodecID codec_id, std::string *codec_name) const
Determine video for linux encoder codec name.
bool m_is_video
true if input is a video file
int alloc_picture(AVFrame *frame, AVPixelFormat pix_fmt, int width, int height) const
Allocate memory for one picture.
AVBufferRef * m_hwaccel_enc_device_ctx
Hardware acceleration device context for encoder.
static const std::vector< PRORES_BITRATE > m_prores_bitrate
ProRes bitrate table. Used for file size prediction.
int prepare_codec(void *opt, FILETYPE filetype) const
Prepare codec options for a file type.
void add_stream_map(int in_stream_idx, int out_stream_idx)
Add entry to input stream to output stream map.
int decode_frame(AVPacket *pkt)
Decode one frame.
int add_subtitle_streams()
Add all subtitle streams. Already existing streams are not added again.
int open_output_filestreams(Buffer *buffer)
Open an output file and the required encoder. Also set some basic encoder parameters....
int64_t m_cur_video_ts
If the video stream is copied and the time stamps are absent from the input stream,...
bool stream_exists(int stream_idx) const
Check if stream exists.
std::variant< FFmpeg_Frame, FFmpeg_Subtitle > MULTIFRAME
Combined audio/videoframe and subtitle.
bool is_multiformat() const
Check for an export frame format.
HWACCELMODE m_hwaccel_dec_mode
Current hardware acceleration mode for decoder.
int skip_decoded_frames(uint32_t frame_no, bool forced_seek)
Skip decoded frames or force seek to frame_no.
STREAM_MAP m_stream_map
Input stream to output stream map.
int create_audio_frame(int frame_size)
Load one audio frame from the FIFO buffer and store in frame buffer.
int write_output_file_header()
Write the header of the output file container.
int hwdevice_ctx_create(AVBufferRef **hwaccel_enc_device_ctx, AVHWDeviceType dev_type, const std::string &device) const
virtual const char * virtname() const override
Return virtual filename. Same as destination filename, but with virtual (mount) path....
void free_filters()
Free filter sinks.
virtual const char * destname() const override
Return destination filename.
uint32_t m_fake_frame_no
The MJEPG codec requires monotonically growing PTS values so we fake some to avoid them going backwar...
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
FFmpeg_Transcoder::read_packet.
int flush_frames_single(int stream_idx, bool use_flush_packet)
Flush the remaining frames.
AVFilterContext * m_buffer_sink_context
Video filter sink context.
int open_decoder(AVFormatContext *format_ctx, AVCodecContext **codec_ctx, int stream_idx, const AVCodec *input_codec, AVMediaType mediatype)
Open codec context for stream_idx.
int open_output_frame_set(Buffer *buffer)
Open output frame set. Data will actually be written to buffer and copied by FUSE when accessed.
int write_output_file_trailer()
Write the trailer of the output file container.
int create_fake_wav_header() const
Create a fake WAV header Create a fake WAV header. Inserts predicted file sizes to allow playback to ...
bool close_resample()
Close and free the resampler context.
int process_albumarts()
Copy all album arts from source to target.
int get_hw_decoder_name(AVCodecID codec_id, std::string *codec_name=nullptr) const
Get the hardware codec name as string. This is required, because e.g. the name for the software codec...
int64_t m_pts
Generated PTS.
int decode_audio_frame(AVPacket *pkt, int *decoded)
Decode one audio frame.
AVPixelFormat m_enc_hw_pix_fmt
Requested encoder hardware pixel format.
OUTPUTFILE m_out
Output file information.
int64_t m_cur_audio_ts
If the audio stream is copied and the time stamps are absent from the input stream,...
std::atomic_uint32_t m_last_seek_frame_no
If not 0, this is the last frame that we seeked to. Video sources only.
AVPixelFormat m_dec_hw_pix_fmt
Requested decoder hardware pixel format.
uint32_t last_seek_frame_no() const
Current seek frame if available.
int flush_delayed_subtitles()
Flush delayed subtitle packets, if there are any.
AVChannelLayout m_cur_ch_layout
Currently selected audio channel layout.
int process_metadata()
Copy metadata from source to target.
int init_rescaler(AVPixelFormat in_pix_fmt, int in_width, int in_height, AVPixelFormat out_pix_fmt, int out_width, int out_height)
Init image size rescaler and pixel format converter.
const char * tagcpy(char(&out)[size], const std::string &in) const
Safely copy a tag to a target buffer. If the input buffer size is larger than output the data will be...
int hwframe_copy_to_hw(AVCodecContext *output_codec_ctx, FFmpeg_Frame *hw_frame, const AVFrame *sw_frame) const
int hwframe_ctx_set(AVCodecContext *output_codec_ctx, AVCodecContext *input_codec_ctx, AVBufferRef *hw_device_ctx) const
Adds a reference to an existing decoder hardware frame context or allocates a new AVHWFramesContext t...
int open_output_file(Buffer *buffer)
Open output file. Data will actually be written to buffer and copied by FUSE when accessed.
int open_bestmatch_decoder(AVFormatContext *format_ctx, AVCodecContext **codec_ctx, int *stream_idx, AVMediaType type)
Find best match stream and open codec context for it.
time_t mtime() const
Get last modification time of file.
bool close_output_file()
Closes the output file if open and reports lost packets. Can safely be called again after the file wa...
static enum AVPixelFormat get_format_static(AVCodecContext *input_codec_ctx, const enum AVPixelFormat *pix_fmts)
std::map< AVHWDeviceType, AVPixelFormat > DEVICETYPE_MAP
Map device types to pixel formats.
int64_t duration() const
Get the file duration.
size_t purge_hls_fifo()
Purge all packets in HLS FIFO buffer.
int init_audio_fifo()
Initialise a FIFO buffer for the audio samples to be encoded.
bool is_frameset() const
Check for an export frame format.
int process_output()
Process headers of output file Write file header, process meta data and add album arts.
int start_new_segment()
HLS only: start a new HLS segment.
AVFilterContext * m_buffer_source_context
Video filter source context.
int convert_samples(uint8_t **input_data, int in_samples, uint8_t **converted_data, int *out_samples)
Convert the input audio samples into the output sample format. The conversion happens on a per-frame ...
int64_t pts() const
Get PTS (presentation time stamp) of decoded audio/video so far.
std::recursive_mutex m_seek_to_fifo_mutex
Access mutex for seek FIFO.
int flush_delayed_video()
Flush delayed video packets, if there are any.
int hwdevice_ctx_add_ref(AVCodecContext *input_codec_ctx)
Add reference to hardware device context.
int m_cur_sample_rate
Currently selected audio sample rate.
int update_format(AVDictionary **dict, const PROFILE_OPTION_VEC &option_vec) const
Update format options.
bool m_copy_audio
If true, copy audio stream from source to target (just remux, no recode).
int open_input_file(LPVIRTUALFILE virtualfile, std::shared_ptr< FileIO > fio=nullptr)
void make_pts(AVPacket *pkt, int64_t *cur_ts) const
Create PTS/DTS and update the packet. If the update packet lacks time stamps, create a fictitious PTS...
int stack_seek_segment(uint32_t segment_no)
Seek to a specific HLS segment. Does not actually perform the seek, this is done asynchronously by th...
time_t m_mtime
Modified time of input file.
void produce_audio_dts(AVPacket *pkt)
Produce audio dts/pts. This is required because the target codec usually has a different frame size t...
int hwframe_copy_from_hw(AVCodecContext *output_codec_ctx, FFmpeg_Frame *sw_frame, const AVFrame *hw_frame) const
int foreach_subtitle_file(const std::string &search_path, const std::regex &regex, int depth, const std::function< int(const std::string &, const std::optional< std::string > &)> &f)
foreach_subititle_file
uint32_t m_active_stream_msk
HLS: Currently active streams bit mask. Set FFMPEGFS_AUDIO and/or FFMPEGFS_VIDEO.
static bool get_output_bit_rate(BITRATE input_bit_rate, BITRATE max_bit_rate, BITRATE *output_bit_rate=nullptr)
Calculate output bit rate based on user option.
void get_pix_formats(AVPixelFormat *in_pix_fmt, AVPixelFormat *out_pix_fmt, AVCodecContext *output_codec_ctx=nullptr) const
Get correct input and output pixel format.
int seek_frame()
Frame sets only: perform seek to a certain frame.
HWACCELMODE m_hwaccel_enc_mode
Current hardware acceleration mode for encoder.
void hwdevice_ctx_free(AVBufferRef **hwaccel_device_ctx)
Free (remove reference) to hardware device context.
bool get_video_size(int *output_width, int *output_height) const
Get the size of the output video based on user selection and apsect ratio.
int add_stream(AVCodecID codec_id)
Add new stream to output file.
int encode_subtitle(const AVSubtitle *sub, int out_stream_idx, int *data_present)
Encode one subtitle frame to the output file.
int encode_audio_frame(const AVFrame *frame, int *data_present)
Create one frame worth of audio to the output file.
const std::string & desttype() const
Get destination type.
AVCodecID subtitle_codec(AVCodecID codec_id) const
Get subtitle codec_id.
bool albumart_supported() const
Check if album arts are supported.
bool is_hls() const
Check for HLS format.
AVSampleFormat sample_format() const
Get sample format (bit width)
FILETYPE filetype() const
Get selected filetype.
bool is_frameset() const
Check for an export frame format.
bool is_multiformat() const
Check if this is some sort of multi file format (any of the following: is_frameset() or is_hls()).
AVCodecID video_codec() const
Get video codec_id.
const std::string & fileext() const
Get file extension.
const std::string & format_name() const
Convert destination type to "real" type, i.e., the file extension to be used.
AVCodecID audio_codec() const
Get audio codec_id.
Base class for I/O.
Definition fileio.h:260
virtual int seek(int64_t offset, int whence)=0
Seek to position in file.
virtual size_t size() const =0
Get the file size.
LPVIRTUALFILE virtualfile()
Get virtual file object.
Definition fileio.cc:113
virtual size_t readio(void *data, size_t size)=0
Read data from a file.
virtual int error() const =0
Get last error.
static std::shared_ptr< FileIO > alloc(VIRTUALTYPE type)
Allocate the correct object for type().
Definition fileio.cc:63
virtual bool eof() const =0
Check if at end of file.
static void warning(const T filename, const std::string &format_string, Args &&...args)
Write warning level log entry.
Definition logging.h:220
static void debug(const T filename, const std::string &format_string, Args &&...args)
Write debug level log entry.
Definition logging.h:182
static void trace(const T filename, const std::string &format_string, Args &&...args)
Write trace level log entry.
Definition logging.h:163
static void info(const T filename, const std::string &format_string, Args &&...args)
Write info level log entry.
Definition logging.h:201
static void error(const T filename, const std::string &format_string, Args &&...args)
Write error level log entry.
Definition logging.h:239
#define ASS_DEFAULT_PLAYRESY
Default Y resolution.
#define ASS_DEFAULT_ALIGNMENT
Default alignment: bottom centre Alignment values are based on the numeric keypad....
#define ASS_DEFAULT_PLAYRESX
Default X resolution.
#define ASS_DEFAULT_COLOUR
Default foreground colour: white.
#define ASS_DEFAULT_BACK_COLOUR
Default background colour.
#define ASS_DEFAULT_FONT_SIZE
Default font size.
#define ASS_DEFAULT_BORDERSTYLE
Default border style: outline with shadow 1 - Outline with shadow, 3 - Rendered with an opaque box.
#define ASS_DEFAULT_FONT
Default font name.
#define ASS_DEFAULT_BOLD
Default no bold font.
#define ASS_DEFAULT_UNDERLINE
Default no underline.
#define ASS_DEFAULT_ITALIC
Default no italics.
#define LAVU_DEP_OLD_CHANNEL_LAYOUT
FFmpeg AVDictionary RAII wrapper.
#define OPT_VIDEO
For videos (not audio only)
#define OPT_HW_ONLY
Use this option for hardware encoding only.
#define OPT_AUDIO
For audio only files.
#define OPT_SW_ONLY
Use this option for software encoding only.
#define FRAME_SEEK_THRESHOLD
Ignore seek if target is within the next n frames.
FFmpeg transcoder.
#define MAX_PRORES_FRAMERATE
Number of selectable fram rates.
#define FFMPEGFS_AUDIO
Denote an audio stream.
#define FFMPEGFS_VIDEO
Denote a video stream.
DECODER_STATUS
Decoder status codes. Can be error, success or end of file.
@ DEC_ERROR
Decoder error, see return code.
@ DEC_EOF
Read to end of file.
@ DEC_SUCCESS
Frame decoded successfully.
const char * get_codec_name(AVCodecID codec_id, bool long_name)
Safe way to get the codec name. Function never fails, will return "unknown" on error.
std::string format_duration(int64_t value, uint32_t fracs)
Format a time in format HH:MM:SS.fract.
int strcasecmp(const std::string &s1, const std::string &s2)
strcasecmp() equivalent for std::string.
bool is_album_art(AVCodecID codec_id, const AVRational *frame_rate)
Minimal check if codec is an album art. Requires frame_rate to decide whether this is a video stream ...
const char * get_media_type_string(enum AVMediaType media_type)
av_get_media_type_string is missing, so we provide our own.
const std::string & regex_escape(std::string *str)
Escape characters that are meaningful to regexp.
const char * hwdevice_get_type_name(AVHWDeviceType dev_type)
int64_t ffmpeg_rescale_q_rnd(int64_t ts, const AVRational &timebase_in, const AVRational &timebase_out)
Convert a FFmpeg time from in timebase to out timebase with rounding.
std::string format_samplerate(int value)
Format a samplerate.
std::string make_filename(uint32_t file_no, const std::string &fileext)
Make a file name from file number and file extension.
std::string format_bitrate(BITRATE value)
Format a bit rate.
int print_stream_info(const AVStream *stream)
Print info about an AVStream.
void stat_set_size(struct stat *st, size_t size)
Properly fill in all size related members in stat struct.
void init_id3v1(ID3v1 *id3v1)
Initialise ID3v1 tag.
FILETYPE get_filetype_from_list(const std::string &desttypelist)
Get the FFmpegfs filetype, desttypelist must be a comma separated list of FFmpeg's "official" short n...
int64_t ffmpeg_rescale_q(int64_t ts, const AVRational &timebase_in, const AVRational &timebase_out)
Convert a FFmpeg time from in timebase to outtime base.
std::string ffmpeg_geterror(int errnum)
Get FFmpeg error string for errnum. Internally calls av_strerror().
PRORESLEVEL
#define BITRATE
For FFmpeg bit rate is an int.
#define AV_CODEC_CAP_VARIABLE_FRAME_SIZE
AV_CODEC_CAP_VARIABLE_FRAME_SIZE is missing in older FFmpeg versions.
#define FF_INPUT_BUFFER_PADDING_SIZE
FF_INPUT_BUFFER_PADDING_SIZE is missing in newer FFmpeg versions.
#define AV_CODEC_FLAG_GLOBAL_HEADER
AV_CODEC_FLAG_GLOBAL_HEADER is missing in older FFmpeg versions.
@ STRICT
Copy stream if codec matches desired target, transcode otherwise.
@ MATCH
Copy stream if target supports codec.
@ MATCHLIMIT
Same as MATCH, only copy if target not larger transcode otherwise.
@ OFF
Never copy streams, transcode always.
@ STRICTLIMIT
Same as STRICT, only copy if target not larger, transcode otherwise.
const std::string & strsprintf(std::string *str, const std::string &format, Args ... args)
Format a std::string sprintf-like.
FILETYPE
#define INVALID_STREAM
Denote an invalid stream.
#define SAFE_VALUE(p, v, d)
Access struct/class pointer safely, return default if nullptr.
FFMPEGFS_PARAMS params
FFmpegfs command line parameters.
Definition ffmpegfs.cc:81
bool check_hwaccel_dec_blocked(AVCodecID codec_id, int profile)
Check if codec_id and the optional profile are in the block list.
Definition ffmpegfs.cc:1596
std::string get_hwaccel_API_text(HWACCELAPI hwaccel_API)
Get the selected hardware acceleration as text.
Definition ffmpegfs.cc:1614
Main include for FFmpegfs project.
LPVIRTUALFILE find_file(const std::string &virtfile)
Find file in cache.
Definition fuseops.cc:1748
@ DVD
DVD file.
@ BLURAY
Blu-ray disk file.
@ VCD
Video CD file.
#define VIRTUALFLAG_CUESHEET
File is part of a set of cue sheet tracks or the directory.
Definition fileio.h:117
#define VIRTUALFLAG_HIDDEN
File is not transcodable or should otherwise show in listings.
Definition fileio.h:118
#define ID3V1_TAG_LENGTH
Fixed 128 bytes.
Definition id3v1tag.h:58
Provide various log facilities to stderr, disk or syslog.
uint32_t m_ckSize
Size of this chunk - 8.
Definition aiff.h:63
AIFF_ID m_ckID
Chunk ID.
Definition aiff.h:62
uint32_t m_ckSize
Total file size - 8.
Definition aiff.h:52
uint32_t m_ckSize
Total size of sound data chunk - 8.
Definition aiff.h:88
std::string m_hwaccel_enc_device
Encoder device. May be AUTO to auto detect or empty.
Definition ffmpegfs.h:218
AVHWDeviceType m_hwaccel_dec_device_type
Enable hardware acceleration buffering for decoder.
Definition ffmpegfs.h:220
int m_deinterlace
1: deinterlace video, 0: no deinterlace
Definition ffmpegfs.h:211
int m_decoding_errors
Break transcoding on decoding error.
Definition ffmpegfs.h:252
AVHWDeviceType m_hwaccel_enc_device_type
Enable hardware acceleration buffering for encoder.
Definition ffmpegfs.h:217
int m_no_subtitles
0: allow subtitles, 1: do no transcode subtitles
Definition ffmpegfs.h:224
std::string m_hwaccel_dec_device
Decoder device. May be AUTO to auto detect or empty.
Definition ffmpegfs.h:221
const FFmpegfs_Format * current_format(LPCVIRTUALFILE virtualfile) const
Get FFmpegfs_Format for a virtual file.
Definition ffmpegfs.cc:242
int m_audiochannels
Max. number of audio channels.
Definition ffmpegfs.h:205
int64_t m_min_seek_time_diff
Minimum time diff from current to next requested segment to perform a seek, in AV_TIME_BASE fractiona...
Definition ffmpegfs.h:214
int m_videowidth
Output video width.
Definition ffmpegfs.h:209
BITRATE m_videobitrate
Output video bit rate (bits per second)
Definition ffmpegfs.h:208
HWACCELAPI m_hwaccel_dec_API
Decoder API.
Definition ffmpegfs.h:219
int m_videoheight
Output video height.
Definition ffmpegfs.h:210
int64_t m_segment_duration
Duration of one HLS segment file, in AV_TIME_BASE fractional seconds.
Definition ffmpegfs.h:213
BITRATE m_audiobitrate
Output audio bit rate (bits per second)
Definition ffmpegfs.h:203
PROFILE m_profile
Target profile: Firefox, MS Edge/IE or other.
Definition ffmpegfs.h:200
int m_audiosamplerate
Output audio sample rate (in Hz)
Definition ffmpegfs.h:204
PRORESLEVEL m_level
Level, currently proxy/hq/lt/HQ (ProRes only)
Definition ffmpegfs.h:201
int m_noalbumarts
Skip album arts.
Definition ffmpegfs.h:226
HWACCELAPI m_hwaccel_enc_API
Encoder API.
Definition ffmpegfs.h:216
AUTOCOPY m_autocopy
Copy streams if codec matches.
Definition ffmpegfs.h:198
Buffer structure, used in FFmpeg_Transcoder::read_packet.
size_t size
Size left in the buffer.
uint8_t * ptr
Pointer to buffer.
StreamRef_map m_subtitle
Subtitle stream information.
AVPixelFormat m_pix_fmt
Video stream pixel format.
std::vector< StreamRef > m_album_art
Album art stream.
StreamRef m_audio
Audio stream information.
FFmpeg_FormatContext m_format_ctx
Format context.
StreamRef m_video
Video stream information.
FILETYPE m_filetype
File type, MP3, MP4, OPUS etc.
int64_t m_video_pts
Global timestamp for the video frames in output video stream time base units
ID3v1 m_id3v1
mp3 only, can be referenced at any time
int64_t m_audio_pts
Global timestamp for the audio frames in output audio stream time base units
int64_t m_last_mux_dts
Last muxed DTS.
ID3 version 1 tag
Definition id3v1tag.h:42
std::array< char, 30 > m_title
Title of sound track.
Definition id3v1tag.h:44
std::array< char, 30 > m_artist
Artist name.
Definition id3v1tag.h:45
std::array< char, 30 > m_album
Album name.
Definition id3v1tag.h:46
char m_title_no
Title number.
Definition id3v1tag.h:50
std::array< char, 4 > m_year
Year of publishing.
Definition id3v1tag.h:47
std::array< char, 28 > m_comment
Any user comments.
Definition id3v1tag.h:48
std::string m_artist
Track artist.
Definition fileio.h:232
int64_t m_duration
Track/chapter duration, in AV_TIME_BASE fractional seconds.
Definition fileio.h:239
std::string m_album
Album title.
Definition fileio.h:234
std::string m_title
Track title.
Definition fileio.h:233
int64_t m_start
Track start time, in AV_TIME_BASE fractional seconds.
Definition fileio.h:238
int m_trackno
Track number.
Definition fileio.h:231
int m_tracktotal
Total number of tracks in cue sheet.
Definition fileio.h:230
std::string m_genre
Album genre.
Definition fileio.h:235
std::string m_date
Publishing date.
Definition fileio.h:236
Virtual file definition.
Definition fileio.h:123
std::string m_destfile
Name and path of destination file.
Definition fileio.h:150
size_t m_predicted_size
Use this as the size instead of computing it over and over.
Definition fileio.h:157
VIRTUALTYPE m_type
Type of this virtual file.
Definition fileio.h:146
std::string m_origfile
Sanitised name and path of original file.
Definition fileio.h:152
int m_flags
One of the VIRTUALFLAG_* flags.
Definition fileio.h:147
int m_width
Video width - Filled in for the DVD/Blu-ray directory.
Definition fileio.h:249
int m_height
Video height - Filled in for the DVD/Blu-ray directory.
Definition fileio.h:250
std::string m_virtfile
Name and path of virtual file.
Definition fileio.h:151
AVRational m_framerate
Video frame rate - Filled in for the DVD/Blu-ray directory.
Definition fileio.h:251
struct stat m_st
stat structure with size etc.
Definition fileio.h:153
struct VIRTUALFILE::CUESHEET_TRACK m_cuesheet_track
Cue sheet data for track.
uint32_t get_segment_count() const
Number of HLS segments in set.
Definition fileio.cc:45
uint32_t m_video_frame_count
Number of frames in video or 0 if not a video.
Definition fileio.h:158
int64_t m_duration
Track/chapter duration, in AV_TIME_BASE fractional seconds.
Definition fileio.h:156
WAVE data header structure.
Definition wave.h:129
uint32_t m_data_bytes
Number of bytes in data. Number of samples * num_channels * bit_depth / 8.
Definition wave.h:131
WAVE "fact" header structure.
Definition wave.h:102
std::array< uint8_t, 4 > m_chunk_id
Chunk ID 4 0x66 0x61 0x63 0x74 (i.e. "fact")
Definition wave.h:103
WAVE extended header structure.
Definition wave.h:87
WAVE header structure.
Definition wave.h:50
uint32_t m_wav_size
Definition wave.h:63
uint16_t m_audio_format
Should be 1 for PCM. 3 for IEEE Float.
Definition wave.h:70
WAVE list header structure.
Definition wave.h:116
uint32_t m_data_bytes
Number of bytes in list.
Definition wave.h:118
Delete helper struct for std::shared_ptr<AVCodecContext>
WAVE file structures https://wavefilegem.com/how_wave_files_work.html.