[FFmpeg-devel] [PATCH v2] ffmpeg: Add option to force a specific decode format

Mark Thompson sw at jkqxz.net
Wed Nov 14 01:43:31 EET 2018


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



More information about the ffmpeg-devel mailing list