[FFmpeg-devel] [PATCH v2] ffmpeg: Add option to force a specific decode format
Mark Thompson
sw at jkqxz.net
Wed Nov 14 03:10:53 EET 2018
On 14/11/18 00:50, Fu, Linjie wrote:
>> -----Original Message-----
>> From: ffmpeg-devel [mailto:ffmpeg-devel-bounces at ffmpeg.org] On Behalf
>> Of Mark Thompson
>> Sent: Wednesday, November 14, 2018 07:44
>> To: ffmpeg-devel at ffmpeg.org
>> Subject: [FFmpeg-devel] [PATCH v2] ffmpeg: Add option to force a specific
>> decode format
>>
>> Fixes #7519.
>> ---
>> doc/ffmpeg.texi | 13 ++++++++++++
>> fftools/ffmpeg.c | 10 ++++++++++
>> fftools/ffmpeg.h | 4 ++++
>> fftools/ffmpeg_opt.c | 47
>> ++++++++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 74 insertions(+)
>>
>> diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
>> index 3717f22d42..d127bc0f0d 100644
>> --- a/doc/ffmpeg.texi
>> +++ b/doc/ffmpeg.texi
>> @@ -920,6 +920,19 @@ would be more efficient.
>> When doing stream copy, copy also non-key frames found at the
>> beginning.
>>
>> + at item -decode_format[:@var{stream_specifier}]
>> @var{pixfmt}[, at var{pixfmt}...] (@emph{input,per-stream})
>> +Set the possible output formats to be used by the decoder for this stream.
>> +If the decoder does not natively support any format in the given list for
>> +the input stream then decoding will fail rather than continuing with a
>> +different format.
>> +
>> +In general this should not be set - the decoder will select an output
>> +format based on the input stream parameters and available components,
>> and
>> +that will be automatically converted to whatever the output requires. It
>> +may be useful to force a hardware decoder supporting output in multiple
>> +different memory types to pick a desired one, or to ensure that a hardware
>> +decoder is used when software fallback is also available.
>> +
>> @item -init_hw_device
>> @var{type}[=@var{name}][:@var{device}[, at var{key=value}...]]
>> Initialise a new hardware device of type @var{type} called @var{name},
>> using the
>> given device parameters.
>> diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
>> index 38c21e944a..c651c8d3a8 100644
>> --- a/fftools/ffmpeg.c
>> +++ b/fftools/ffmpeg.c
>> @@ -598,6 +598,7 @@ static void ffmpeg_cleanup(int ret)
>> avsubtitle_free(&ist->prev_sub.subtitle);
>> av_frame_free(&ist->sub2video.frame);
>> av_freep(&ist->filters);
>> + av_freep(&ist->decode_formats);
>> av_freep(&ist->hwaccel_device);
>> av_freep(&ist->dts_buffer);
>>
>> @@ -2800,6 +2801,15 @@ static enum AVPixelFormat
>> get_format(AVCodecContext *s, const enum AVPixelFormat
>> const AVCodecHWConfig *config = NULL;
>> int i;
>>
>> + if (ist->decode_formats) {
>> + for (i = 0; ist->decode_formats[i] != AV_PIX_FMT_NONE; i++) {
>> + if (ist->decode_formats[i] == *p)
>> + break;
>> + }
>> + if (ist->decode_formats[i] != *p)
>> + continue;
>> + }
>> +
>> if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
>> break;
>>
>> diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
>> index eb1eaf6363..b06fd18b1c 100644
>> --- a/fftools/ffmpeg.h
>> +++ b/fftools/ffmpeg.h
>> @@ -125,6 +125,8 @@ typedef struct OptionsContext {
>> int nb_ts_scale;
>> SpecifierOpt *dump_attachment;
>> int nb_dump_attachment;
>> + SpecifierOpt *decode_formats;
>> + int nb_decode_formats;
>> SpecifierOpt *hwaccels;
>> int nb_hwaccels;
>> SpecifierOpt *hwaccel_devices;
>> @@ -334,6 +336,8 @@ typedef struct InputStream {
>> int top_field_first;
>> int guess_layout_max;
>>
>> + enum AVPixelFormat *decode_formats;
>> +
>> int autorotate;
>>
>> int fix_sub_duration;
>> diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
>> index d4851a2cd8..63bb05053b 100644
>> --- a/fftools/ffmpeg_opt.c
>> +++ b/fftools/ffmpeg_opt.c
>> @@ -701,6 +701,7 @@ static void add_input_streams(OptionsContext *o,
>> AVFormatContext *ic)
>> AVStream *st = ic->streams[i];
>> AVCodecParameters *par = st->codecpar;
>> InputStream *ist = av_mallocz(sizeof(*ist));
>> + char *decode_formats = NULL;
>> char *framerate = NULL, *hwaccel_device = NULL;
>> const char *hwaccel = NULL;
>> char *hwaccel_output_format = NULL;
>> @@ -797,6 +798,49 @@ static void add_input_streams(OptionsContext *o,
>> AVFormatContext *ic)
>> ist->top_field_first = -1;
>> MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic,
>> st);
>>
>> + MATCH_PER_STREAM_OPT(decode_formats, str, decode_formats, ic,
>> st);
>> + if (decode_formats) {
>> + const char *p, *q;
>> + int i, nb_formats;
>> + char tmp[32];
>> +
>> + nb_formats = 0;
>> + for (p = decode_formats; p; p = strchr(p + 1, ','))
>> + ++nb_formats;
>> +
>> + ist->decode_formats =
>> + av_malloc_array(nb_formats + 1, sizeof(*ist->decode_formats));
>> + if (!ist->decode_formats)
>> + exit_program(1);
>> +
>> + p = decode_formats;
>> + for (i = 0; i < nb_formats; i++) {
>> + q = strchr(p, ',');
>> + if (!q) {
>> + ist->decode_formats[i] = av_get_pix_fmt(p);
>> + if (ist->decode_formats[i] == AV_PIX_FMT_NONE)
>> + break;
>> + continue;
>> + }
>> + if (q - p > sizeof(tmp) - 1)
>> + break;
>> + memcpy(tmp, p, q - p);
>> + tmp[q - p] = 0;
>> + ist->decode_formats[i] = av_get_pix_fmt(tmp);
>> + if (ist->decode_formats[i] == AV_PIX_FMT_NONE)
>> + break;
>> + p = q + 1;
>> + }
>> + if (i < nb_formats) {
>> + av_log(NULL, AV_LOG_FATAL,
>> + "Unrecognised decode format: %s.\n", p);
>> + exit_program(1);
>> + }
>> + ist->decode_formats[nb_formats] = AV_PIX_FMT_NONE;
>> + } else {
>> + ist->decode_formats = NULL;
>> + }
>> +
>> MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
>> if (hwaccel) {
>> // The NVDEC hwaccels use a CUDA device, so remap the name here.
>> @@ -3583,6 +3627,9 @@ const OptionDef options[] = {
>> "audio bitrate (please use -b:a)", "bitrate" },
>> { "b", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT,
>> { .func_arg = opt_bitrate },
>> "video bitrate (please use -b:v)", "bitrate" },
>> + { "decode_format", OPT_VIDEO | OPT_STRING | HAS_ARG |
>> OPT_EXPERT |
>> + OPT_SPEC | OPT_INPUT, { .off =
>> OFFSET(decode_formats) },
>> + "set output format(s) to be used by decoder, fail if none of these
>> formats are available", "format" },
>> { "hwaccel", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
>> OPT_SPEC | OPT_INPUT, { .off =
>> OFFSET(hwaccels) },
>> "use HW accelerated decoding", "hwaccel name" },
>> --
>> 2.19.1
>>
>
> Is there any other conditions which will cause the hwaccel failed and fallback to software path?
> Like profile was not supported by hardware?
If this option is set then get_format will never choose a format not on the list you provide, so it shouldn't be able to use software decode unless a software format is on the list.
> I applied the patch and tested some cases, like yuv422 VAAPI decoding (currently not supported), HEVC decoding with unsupported profile.
> It reports an error like "hwaccel initialization returned error", and continue to decode and produce less frames than expected. (which I thought fallback still happened).
Can you give an example? With -v debug there will be output saying exactly what happened in ff_get_format().
- Mark
More information about the ffmpeg-devel
mailing list