[FFmpeg-devel] [PATCH] avcodec/allcodecs: add FFMPEG_PREFER_* env vars

Martin Dørum martid0311 at gmail.com
Thu Apr 19 13:15:07 EEST 2018


When a program uses FFmpeg to decode or encode media, and uses
`avcodec_find_decoder` or `avcodec_find_encoder`, I interpret that as
the program not caring a whole lot what AVCodec is used; it just wants
something which can encode or decode the desired format. I think it
makes sense for the user to be able to specify what codec should be the
default in that case, because the user might know that they're on a
system with a fast hardware encoder or decoder. Currently, the only way
to convince FFmpeg to default to a different codec is to recompile it
without support for other codecs than the desired one, which feels
unnecessary.

An argument against this patch could be that it's the application's
responsibility to add an -encoder or -decoder option like the ffmpeg
CLI utilities do. If that's the "official" stance of FFmpeg, I'm fine
with that, even though I don't necessarily agree.

Anotehr point is that some applications make assumptions about the
pix_fmt the decoder they get from `avcodec_find_decoder` uses. Chromium
does this. I believe this is a problem with those applications
(and I submitted an issue to the Chromium project:
https://bugs.chromium.org/p/webrtc/issues/detail?id=9137#c2), but it
should be considered.

(I also haven't submitted a patch to FFmpeg before, or any open-source
project which doesn't use GitHub pull requests, so I apologize if I
have followed the process incorrectly.)

This patch makes it possible to choose what codec avcodec_find_encoder
and avcodec_find_decoder returns with environment variables.
FFMPEG_PREFER_CODEC is an environment variable with a comma-separated
list of codec names, and if it contains the name of an applicable
codec, that codec will be returned instead of whatever av_codec_iterate
happens to return first.

There's also FFMPEG_PREFER_ENCODER and FFMPEG_PREFER_DECODER, which
specifically apply to avcodec_find_encoder and avcodec_find_decoder
respectively. These are prioritized above FFMPEG_PREFER_CODEC.

Signed-off-by: Martin Dørum <martid0311 at gmail.com>
---
  libavcodec/allcodecs.c | 59 ++++++++++++++++++++++++++++++++++++++----
  1 file changed, 54 insertions(+), 5 deletions(-)

diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 4d4ef530e4..3c85908969 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -833,25 +833,74 @@ static enum AVCodecID remap_deprecated_codec_id(enum AVCodecID id)
      }
  }
  
+static int codec_matches_preferred(const AVCodec *p, const char *str)
+{
+    int pi = 0, stri = 0;
+    int match = 1;
+
+    if (str == NULL)
+        return 0;
+
+    while (1) {
+        if (str[stri] == '\0' || str[stri] == ',') {
+            if (match && p->name[pi] == '\0') {
+                return 1;
+            } else if (str[stri] == '\0') {
+                return 0;
+            } else {
+                match = 1;
+                pi = 0;
+            }
+        } else if (p->name[pi] == '\0') {
+            match = 0;
+        } else {
+            if (match && p->name[pi] != str[stri])
+                match = 0;
+            pi += 1;
+        }
+
+        stri += 1;
+    }
+}
+
  static AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *))
  {
-    const AVCodec *p, *experimental = NULL;
+    const AVCodec *p, *experimental = NULL, *fallback = NULL, *preferred = NULL;
      void *i = 0;
  
+    char *preferred_codec = getenv("FFMPEG_PREFER_CODEC");
+    char *preferred_encdec = NULL;
+    if (x == av_codec_is_encoder)
+        preferred_encdec = getenv("FFMPEG_PREFER_ENCODER");
+    else if (x == av_codec_is_decoder)
+        preferred_encdec = getenv("FFMPEG_PREFER_DECODER");
+
      id = remap_deprecated_codec_id(id);
  
      while ((p = av_codec_iterate(&i))) {
          if (!x(p))
              continue;
          if (p->id == id) {
-            if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {
-                experimental = p;
-            } else
+            if (codec_matches_preferred(p, preferred_encdec)) {
                  return (AVCodec*)p;
+            } else if (codec_matches_preferred(p, preferred_codec) && !preferred) {
+                preferred = p;
+            } else if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) {
+                experimental = p;
+            } else if (!fallback) {
+                fallback = p;
+            }
          }
      }
  
-    return (AVCodec*)experimental;
+    if (preferred)
+        return (AVCodec*)preferred;
+    else if (fallback)
+        return (AVCodec*)fallback;
+    else if (experimental)
+        return (AVCodec*)experimental;
+    else
+        return NULL;
  }
  
  AVCodec *avcodec_find_encoder(enum AVCodecID id)
-- 
2.17.0


More information about the ffmpeg-devel mailing list