---
This is several patches squashed together to invite thoughts.

The idea here is that we add a new array of possible hardware configurations to 
codec definitions, expressed as a hardware device type and the matching pixel 
format.  We can then use that to set up hwaccels without any additional 
knowledge at all, creating the appropriate device at startup and then matching 
the format in get_format in order to use it.

This is implemented here in lavc with the H.264 decoder and then used in 
avconv.  There is quite a bit of churn in avconv hardware setup as the choice 
of device all moves around, but it is hopefully a bit clearer now (and less 
likely to try to give devices to things not needing them).  "-hwaccel auto" is 
reimplemented completely as using the first device from the codec config list 
which can be instantiated.


 avtools/avconv.c     |  57 +++++++++----
 avtools/avconv.h     |   9 +-
 avtools/avconv_hw.c  | 233 ++++++++++++++++++++++++++++++++++-----------------
 avtools/avconv_opt.c |  41 ++++-----
 libavcodec/avcodec.h |  23 +++++
 libavcodec/h264dec.c |  18 ++++
 6 files changed, 254 insertions(+), 127 deletions(-)

diff --git a/avtools/avconv.c b/avtools/avconv.c
index 4e3ffecde..c5b440e08 100644
--- a/avtools/avconv.c
+++ b/avtools/avconv.c
@@ -1631,15 +1631,6 @@ static void print_sdp(void)
     av_freep(&avc);
 }
 
-static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt)
-{
-    int i;
-    for (i = 0; hwaccels[i].name; i++)
-        if (hwaccels[i].pix_fmt == pix_fmt)
-            return &hwaccels[i];
-    return NULL;
-}
-
 static enum AVPixelFormat get_format(AVCodecContext *s, const enum 
AVPixelFormat *pix_fmts)
 {
     InputStream *ist = s->opaque;
@@ -1647,17 +1638,50 @@ static enum AVPixelFormat get_format(AVCodecContext *s, 
const enum AVPixelFormat
     int ret;
 
     for (p = pix_fmts; *p != -1; p++) {
-        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
-        const HWAccel *hwaccel;
+        const AVPixFmtDescriptor *desc  = av_pix_fmt_desc_get(*p);
+        const HWAccel *hwaccel          = NULL;
+        const AVCodecHWConfig *hwconfig = NULL;
+        int i;
 
         if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
             break;
 
-        hwaccel = get_hwaccel(*p);
-        if (!hwaccel ||
-            (ist->active_hwaccel_id && ist->active_hwaccel_id != hwaccel->id) 
||
-            (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id != 
hwaccel->id))
-            continue;
+        if (ist->hwaccel_id == HWACCEL_GENERIC && s->codec->hw_configs) {
+            for (i = 0;; i++) {
+                if (s->codec->hw_configs[i].device_type == 
AV_HWDEVICE_TYPE_NONE)
+                    break;
+                if (s->codec->hw_configs[i].pix_fmt == *p) {
+                    hwconfig = &s->codec->hw_configs[i];
+                    break;
+                }
+            }
+        }
+        if (hwconfig) {
+            if (hwconfig->device_type != ist->hwaccel_device_type) {
+                // Different hwaccel offered, ignore.
+                continue;
+            }
+            hwaccel = &hwaccels[0];
+        }
+        if (!hwaccel) {
+            int i;
+            hwaccel = NULL;
+            for (i = 1; hwaccels[i].name; i++) {
+                if (hwaccels[i].pix_fmt == *p) {
+                    hwaccel = &hwaccels[i];
+                    break;
+                }
+            }
+            if (!hwaccel) {
+                // No hwaccel supporting this pixfmt.
+                continue;
+            }
+            if (hwaccel->id != ist->hwaccel_id &&
+                hwaccel->id != HWACCEL_AUTO) {
+                // Does not match requested hwaccel.
+                continue;
+            }
+        }
 
         ret = hwaccel->init(s);
         if (ret < 0) {
@@ -1677,7 +1701,6 @@ static enum AVPixelFormat get_format(AVCodecContext *s, 
const enum AVPixelFormat
                 return AV_PIX_FMT_NONE;
         }
 
-        ist->active_hwaccel_id = hwaccel->id;
         ist->hwaccel_pix_fmt   = *p;
         break;
     }
diff --git a/avtools/avconv.h b/avtools/avconv.h
index b5843fbc0..0d24c71a7 100644
--- a/avtools/avconv.h
+++ b/avtools/avconv.h
@@ -52,13 +52,9 @@
 enum HWAccelID {
     HWACCEL_NONE = 0,
     HWACCEL_AUTO,
-    HWACCEL_VDPAU,
-    HWACCEL_DXVA2,
+    HWACCEL_GENERIC,
     HWACCEL_VDA,
     HWACCEL_QSV,
-    HWACCEL_VAAPI,
-    HWACCEL_D3D11VA,
-    HWACCEL_CUVID,
 };
 
 typedef struct HWAccel {
@@ -66,7 +62,6 @@ typedef struct HWAccel {
     int (*init)(AVCodecContext *s);
     enum HWAccelID id;
     enum AVPixelFormat pix_fmt;
-    enum AVHWDeviceType device_type;
 } HWAccel;
 
 typedef struct HWDevice {
@@ -301,11 +296,11 @@ typedef struct InputStream {
 
     /* hwaccel options */
     enum HWAccelID hwaccel_id;
+    enum AVHWDeviceType hwaccel_device_type;
     char  *hwaccel_device;
     enum AVPixelFormat hwaccel_output_format;
 
     /* hwaccel context */
-    enum HWAccelID active_hwaccel_id;
     void  *hwaccel_ctx;
     void (*hwaccel_uninit)(AVCodecContext *s);
     int  (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
diff --git a/avtools/avconv_hw.c b/avtools/avconv_hw.c
index 36ef86692..a424e7055 100644
--- a/avtools/avconv_hw.c
+++ b/avtools/avconv_hw.c
@@ -62,6 +62,31 @@ static HWDevice *hw_device_add(void)
     return hw_devices[nb_hw_devices++];
 }
 
+static char *hw_device_default_name(enum AVHWDeviceType type)
+{
+    // Make an automatic name of the form "type%d".  We arbitrarily
+    // limit at 1000 anonymous devices of the same type - there is
+    // probably something else very wrong if you get to this limit.
+    const char *type_name = av_hwdevice_get_type_name(type);
+    char *name;
+    size_t index_pos;
+    int index, index_limit = 1000;
+    index_pos = strlen(type_name);
+    name = av_malloc(index_pos + 4);
+    if (!name)
+        return NULL;
+    for (index = 0; index < index_limit; index++) {
+        snprintf(name, index_pos + 4, "%s%d", type_name, index);
+        if (!hw_device_get_by_name(name))
+            break;
+    }
+    if (index >= index_limit) {
+        av_freep(&name);
+        return NULL;
+    }
+    return name;
+}
+
 int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
 {
     // "type=name:device,key=value,key2=value2"
@@ -109,27 +134,11 @@ int hw_device_init_from_string(const char *arg, HWDevice 
**dev_out)
 
         p += 1 + k;
     } else {
-        // Give the device an automatic name of the form "type%d".
-        // We arbitrarily limit at 1000 anonymous devices of the same
-        // type - there is probably something else very wrong if you
-        // get to this limit.
-        size_t index_pos;
-        int index, index_limit = 1000;
-        index_pos = strlen(type_name);
-        name = av_malloc(index_pos + 4);
+        name = hw_device_default_name(type);
         if (!name) {
             err = AVERROR(ENOMEM);
             goto fail;
         }
-        for (index = 0; index < index_limit; index++) {
-            snprintf(name, index_pos + 4, "%s%d", type_name, index);
-            if (!hw_device_get_by_name(name))
-                break;
-        }
-        if (index >= index_limit) {
-            errmsg = "too many devices";
-            goto invalid;
-        }
     }
 
     if (!*p) {
@@ -212,6 +221,49 @@ fail:
     goto done;
 }
 
+static int hw_device_init_from_type(enum AVHWDeviceType type,
+                                    const char *device,
+                                    HWDevice **dev_out)
+{
+    AVBufferRef *device_ref = NULL;
+    HWDevice *dev;
+    char *name;
+    int err;
+
+    name = hw_device_default_name(type);
+    if (!name) {
+        err = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
+    if (err < 0) {
+        av_log(NULL, AV_LOG_ERROR,
+               "Device creation failed: %d.\n", err);
+        goto fail;
+    }
+
+    dev = hw_device_add();
+    if (!dev) {
+        err = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    dev->name = name;
+    dev->type = type;
+    dev->device_ref = device_ref;
+
+    if (dev_out)
+        *dev_out = dev;
+
+    return 0;
+
+fail:
+    av_freep(&name);
+    av_buffer_unref(&device_ref);
+    return err;
+}
+
 void hw_device_free_all(void)
 {
     int i;
@@ -224,85 +276,116 @@ void hw_device_free_all(void)
     nb_hw_devices = 0;
 }
 
-static enum AVHWDeviceType hw_device_match_type_by_hwaccel(enum HWAccelID 
hwaccel_id)
+static HWDevice *hw_device_match_by_codec(const AVCodec *codec)
 {
+    enum AVHWDeviceType type;
+    HWDevice *dev = NULL;
     int i;
-    if (hwaccel_id == HWACCEL_NONE)
+    if (!codec->hw_configs)
         return AV_HWDEVICE_TYPE_NONE;
-    for (i = 0; hwaccels[i].name; i++) {
-        if (hwaccels[i].id == hwaccel_id)
-            return hwaccels[i].device_type;
+    for (i = 0;; i++) {
+        type = codec->hw_configs[i].device_type;
+        if (type == AV_HWDEVICE_TYPE_NONE)
+            break;
+        if ((dev = hw_device_get_by_type(type)))
+            break;
     }
-    return AV_HWDEVICE_TYPE_NONE;
-}
-
-static enum AVHWDeviceType hw_device_match_type_in_name(const char *codec_name)
-{
-    const char *type_name;
-    enum AVHWDeviceType type;
-    for (type = av_hwdevice_iterate_types(AV_HWDEVICE_TYPE_NONE);
-         type != AV_HWDEVICE_TYPE_NONE;
-         type = av_hwdevice_iterate_types(type)) {
-        type_name = av_hwdevice_get_type_name(type);
-        if (strstr(codec_name, type_name))
-            return type;
-    }
-    return AV_HWDEVICE_TYPE_NONE;
+    return dev;
 }
 
 int hw_device_setup_for_decode(InputStream *ist)
 {
     enum AVHWDeviceType type;
-    HWDevice *dev;
-    const char *type_name;
-    int err;
+    HWDevice *dev = NULL;
+    int err, auto_device = 0;
 
     if (ist->hwaccel_device) {
         dev = hw_device_get_by_name(ist->hwaccel_device);
         if (!dev) {
-            char *tmp;
-            size_t len;
-            type = hw_device_match_type_by_hwaccel(ist->hwaccel_id);
-            if (type == AV_HWDEVICE_TYPE_NONE) {
-                // No match - this isn't necessarily invalid, though,
-                // because an explicit device might not be needed or
-                // the hwaccel setup could be handled elsewhere.
+            if (ist->hwaccel_id == HWACCEL_AUTO) {
+                auto_device = 1;
+            } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
+                type = ist->hwaccel_device_type;
+                err = hw_device_init_from_type(type, ist->hwaccel_device,
+                                               &dev);
+            } else {
+                // This will be dealt with by API-specific initialisation
+                // (using hwaccel_device), so nothing further needed here.
                 return 0;
             }
-            type_name = av_hwdevice_get_type_name(type);
-            len = strlen(type_name) + 1 +
-                  strlen(ist->hwaccel_device) + 1;
-            tmp = av_malloc(len);
-            if (!tmp)
-                return AVERROR(ENOMEM);
-            snprintf(tmp, len, "%s:%s", type_name, ist->hwaccel_device);
-            err = hw_device_init_from_string(tmp, &dev);
-            av_free(tmp);
-            if (err < 0)
-                return err;
         }
     } else {
-        if (ist->hwaccel_id != HWACCEL_NONE)
-            type = hw_device_match_type_by_hwaccel(ist->hwaccel_id);
-        else
-            type = hw_device_match_type_in_name(ist->dec->name);
-        if (type != AV_HWDEVICE_TYPE_NONE) {
+        if (ist->hwaccel_id == HWACCEL_AUTO) {
+            auto_device = 1;
+        } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
+            type = ist->hwaccel_device_type;
             dev = hw_device_get_by_type(type);
+            if (!dev)
+                err = hw_device_init_from_type(type, NULL, &dev);
+        } else {
+            dev = hw_device_match_by_codec(ist->dec);
             if (!dev) {
-                hw_device_init_from_string(av_hwdevice_get_type_name(type),
+                // No device for this codec, but not using generic hwaccel
+                // and therefore may well not need one - ignore.
+                return 0;
+            }
+        }
+    }
+
+    if (auto_device) {
+        int i;
+        if (!ist->dec->hw_configs) {
+            // Decoder does not support any hardware devices.
+            return 0;
+        }
+        for (i = 0; !dev; i++) {
+            type = ist->dec->hw_configs[i].device_type;
+            if (type == AV_HWDEVICE_TYPE_NONE)
+                break;
+            if ((dev = hw_device_get_by_type(type))) {
+                av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
+                       "hwaccel type %s with existing device %s.\n",
+                       av_hwdevice_get_type_name(type), dev->name);
+            }
+        }
+        for (i = 0; !dev; i++) {
+            type = ist->dec->hw_configs[i].device_type;
+            if (type == AV_HWDEVICE_TYPE_NONE)
+                break;
+            // Try to make a new device of this type.
+            err = hw_device_init_from_type(type, ist->hwaccel_device,
                                            &dev);
+            if (err < 0) {
+                // Can't make a device of this type.
+                continue;
+            }
+            if (ist->hwaccel_device) {
+                av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
+                       "hwaccel type %s with new device created "
+                       "from %s.\n", av_hwdevice_get_type_name(type),
+                       ist->hwaccel_device);
+            } else {
+                av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
+                       "hwaccel type %s with new default device.\n",
+                       av_hwdevice_get_type_name(type));
             }
+        }
+        if (dev) {
+            ist->hwaccel_id = HWACCEL_GENERIC;
+            ist->hwaccel_device_type = type;
         } else {
-            // No device required.
+            av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel "
+                   "disabled: no device found.\n");
+            ist->hwaccel_id = HWACCEL_NONE;
             return 0;
         }
     }
 
     if (!dev) {
-        av_log(ist->dec_ctx, AV_LOG_WARNING, "No device available "
-               "for decoder (device type %s for codec %s).\n",
+        av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available "
+               "for decoder: device type %s needed for codec %s.\n",
                av_hwdevice_get_type_name(type), ist->dec->name);
-        return 0;
+        return err;
     }
 
     ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
@@ -314,24 +397,16 @@ int hw_device_setup_for_decode(InputStream *ist)
 
 int hw_device_setup_for_encode(OutputStream *ost)
 {
-    enum AVHWDeviceType type;
     HWDevice *dev;
 
-    type = hw_device_match_type_in_name(ost->enc->name);
-    if (type != AV_HWDEVICE_TYPE_NONE) {
-        dev = hw_device_get_by_type(type);
-        if (!dev) {
-            av_log(ost->enc_ctx, AV_LOG_WARNING, "No device available "
-                   "for encoder (device type %s for codec %s).\n",
-                   av_hwdevice_get_type_name(type), ost->enc->name);
-            return 0;
-        }
+    dev = hw_device_match_by_codec(ost->enc);
+    if (dev) {
         ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
         if (!ost->enc_ctx->hw_device_ctx)
             return AVERROR(ENOMEM);
         return 0;
     } else {
-        // No device required.
+        // No device required, or no device available.
         return 0;
     }
 }
diff --git a/avtools/avconv_opt.c b/avtools/avconv_opt.c
index df693360a..f523f1566 100644
--- a/avtools/avconv_opt.c
+++ b/avtools/avconv_opt.c
@@ -56,33 +56,13 @@
 }
 
 const HWAccel hwaccels[] = {
-#if HAVE_VDPAU_X11
-    { "vdpau", hwaccel_decode_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU,
-      AV_HWDEVICE_TYPE_VDPAU },
-#endif
-#if CONFIG_D3D11VA
-    { "d3d11va", hwaccel_decode_init, HWACCEL_D3D11VA, AV_PIX_FMT_D3D11,
-      AV_HWDEVICE_TYPE_D3D11VA },
-#endif
-#if CONFIG_DXVA2
-    { "dxva2", hwaccel_decode_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD,
-      AV_HWDEVICE_TYPE_DXVA2 },
-#endif
+    // Generic hwaccel must be first in this list.
+    { "generic", hwaccel_decode_init, HWACCEL_GENERIC },
 #if CONFIG_VDA
-    { "vda",   vda_init,   HWACCEL_VDA,   AV_PIX_FMT_VDA,
-      AV_HWDEVICE_TYPE_NONE },
+    { "vda",   vda_init,   HWACCEL_VDA,   AV_PIX_FMT_VDA },
 #endif
 #if CONFIG_LIBMFX
-    { "qsv",   qsv_init,   HWACCEL_QSV,   AV_PIX_FMT_QSV,
-      AV_HWDEVICE_TYPE_NONE },
-#endif
-#if CONFIG_VAAPI
-    { "vaapi", hwaccel_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI,
-      AV_HWDEVICE_TYPE_VAAPI },
-#endif
-#if CONFIG_CUVID
-    { "cuvid", hwaccel_decode_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA,
-       AV_HWDEVICE_TYPE_CUDA },
+    { "qsv",   qsv_init,   HWACCEL_QSV,   AV_PIX_FMT_QSV },
 #endif
     { 0 },
 };
@@ -201,9 +181,13 @@ static double parse_frame_aspect_ratio(const char *arg)
 
 static int show_hwaccels(void *optctx, const char *opt, const char *arg)
 {
+    enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
     int i;
 
     printf("Supported hardware acceleration:\n");
+    while ((type = av_hwdevice_iterate_types(type)) !=
+           AV_HWDEVICE_TYPE_NONE)
+        printf("%s\n", av_hwdevice_get_type_name(type));
     for (i = 0; hwaccels[i].name; i++) {
         printf("%s\n", hwaccels[i].name);
     }
@@ -623,6 +607,7 @@ static void add_input_streams(OptionsContext *o, 
AVFormatContext *ic)
                 else if (!strcmp(hwaccel, "auto"))
                     ist->hwaccel_id = HWACCEL_AUTO;
                 else {
+                    enum AVHWDeviceType type;
                     int i;
                     for (i = 0; hwaccels[i].name; i++) {
                         if (!strcmp(hwaccels[i].name, hwaccel)) {
@@ -632,6 +617,14 @@ static void add_input_streams(OptionsContext *o, 
AVFormatContext *ic)
                     }
 
                     if (!ist->hwaccel_id) {
+                        type = av_hwdevice_find_type_by_name(hwaccel);
+                        if (type != AV_HWDEVICE_TYPE_NONE) {
+                            ist->hwaccel_id = HWACCEL_GENERIC;
+                            ist->hwaccel_device_type = type;
+                        }
+                    }
+
+                    if (!ist->hwaccel_id) {
                         av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: 
%s.\n",
                                hwaccel);
                         av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: ");
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 847b7f139..0dafe05ec 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -35,6 +35,7 @@
 #include "libavutil/cpu.h"
 #include "libavutil/dict.h"
 #include "libavutil/frame.h"
+#include "libavutil/hwcontext.h"
 #include "libavutil/log.h"
 #include "libavutil/pixfmt.h"
 #include "libavutil/rational.h"
@@ -2771,6 +2772,19 @@ typedef struct AVProfile {
     const char *name; ///< short name for the profile
 } AVProfile;
 
+typedef struct AVCodecHWConfig {
+    /**
+     * A device type which can be supplied to the codec.
+     */
+    enum AVHWDeviceType device_type;
+    /**
+     * The matching hardware pixel format which the codec can produce.
+     *
+     * Set to AV_PIX_FMT_NONE if no hardware pixel format is available.
+     */
+    enum AVPixelFormat pix_fmt;
+} AVCodecHWConfig;
+
 typedef struct AVCodecDefault AVCodecDefault;
 
 struct AVSubtitle;
@@ -2806,6 +2820,15 @@ typedef struct AVCodec {
     const AVClass *priv_class;              ///< AVClass for the private 
context
     const AVProfile *profiles;              ///< array of recognized profiles, 
or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN}
 
+    /**
+     * Array of hardware configurations supported by the codec, or NULL
+     * if no hardware supported.
+     *
+     * The array is terminated by a configuration with a device_type of
+     * AV_HW_DEVICE_TYPE_NONE.
+     */
+    const AVCodecHWConfig *hw_configs;
+
     /*****************************************************************
      * No fields below this line are part of the public API. They
      * may not be used outside of libavcodec and can be changed and
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 7a8293efa..0d3d87a64 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -786,6 +786,24 @@ AVCodec ff_h264_decoder = {
     .capabilities          = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ 
AV_CODEC_CAP_DR1 |
                              AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS |
                              AV_CODEC_CAP_FRAME_THREADS,
+    .hw_configs            = (const AVCodecHWConfig[]) {
+#if CONFIG_H264_CUVID_HWACCEL
+                             { AV_HWDEVICE_TYPE_CUVID,   AV_PIX_FMT_CUVID },
+#endif
+#if CONFIG_H264_DXVA2_HWACCEL
+                             { AV_HWDEVICE_TYPE_DXVA2,   AV_PIX_FMT_DXVA2 },
+#endif
+#if CONFIG_H264_D3D11VA_HWACCEL
+                             { AV_HWDEVICE_TYPE_D3D11VA, AV_PIX_FMT_D3D11 },
+#endif
+#if CONFIG_H264_VAAPI_HWACCEL
+                             { AV_HWDEVICE_TYPE_VAAPI,   AV_PIX_FMT_VAAPI },
+#endif
+#if CONFIG_H264_VDPAU_HWACCEL
+                             { AV_HWDEVICE_TYPE_VDPAU,   AV_PIX_FMT_VDPAU },
+#endif
+                             { AV_HWDEVICE_TYPE_NONE },
+                           },
     .caps_internal         = FF_CODEC_CAP_INIT_THREADSAFE | 
FF_CODEC_CAP_EXPORTS_CROPPING,
     .flush                 = flush_dpb,
     .init_thread_copy      = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
-- 
2.11.0

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to