This also adds a new field to AVHWAccel to set supported hardware device
types, so that we can query the right hwaccel.
---
Not entirely sure that the AVCodecContext should be the first argument of 
probe_hw() - AVCodecParameters might be nicer, but we are likely to end up 
needing an AVCodecContext anyway.  (More generally, please bikeshed freely over 
naming and structures used.)

The probe_hw() function on the D*VA hwaccel would be where the extra alignment 
gets set (when AVCodecContext.hw_device_ctx is not used).


 doc/APIchanges        |  3 +++
 libavcodec/avcodec.h  | 51 +++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/decode.c   | 53 ++++++++++++++++++++++++++++++++++++++++++++-------
 libavcodec/encode.c   | 13 +++++++++++++
 libavcodec/internal.h | 10 ++++++++++
 libavcodec/utils.c    | 15 +++++++++++++++
 6 files changed, 138 insertions(+), 7 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 5da821c90..649d35a08 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -13,6 +13,9 @@ libavutil:     2017-03-23
 
 API changes, most recent first:
 
+2017-04-xx - xxxxxxx - lavc 58.x+1.0 - avcodec.h
+  Add AVHWAccel.device_type and avcodec_probe_hw().
+
 2017-04-xx - xxxxxxx - lavc 58.x.y+1 - avcodec.h
   Add AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH.
 
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 2aa70ca4f..8f7293d02 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"
@@ -2857,6 +2858,15 @@ typedef struct AVCodec {
      * packets before decoding.
      */
     const char *bsfs;
+
+    /**
+     * Test support for the given encode/decode parameters, and if possible
+     * set the fields in the frames context to a set of usable values.
+     *
+     * If a hwaccel is used with a decoder and it also has a probe_hw()
+     * function, that will be called instead of this.
+     */
+    int (*probe_hw)(AVCodecContext *avctx, AVHWFramesContext *hw_frames);
 } AVCodec;
 
 /**
@@ -2898,6 +2908,11 @@ typedef struct AVHWAccel {
      */
     int capabilities;
 
+    /**
+     * Hardware device type which this hwaccel can use.
+     */
+    enum AVHWDeviceType device_type;
+
     /*****************************************************************
      * No fields below this line are part of the public API. They
      * may not be used outside of libavcodec and can be changed and
@@ -2988,6 +3003,11 @@ typedef struct AVHWAccel {
      * Internal hwaccel capabilities.
      */
     int caps_internal;
+
+    /**
+     * Probe hardware for support and parameters.
+     */
+    int (*probe_hw)(AVCodecContext *avctx, AVHWFramesContext *hw_frames);
 } AVHWAccel;
 
 /**
@@ -4927,6 +4947,37 @@ const AVCodecDescriptor 
*avcodec_descriptor_get_by_name(const char *name);
 AVCPBProperties *av_cpb_properties_alloc(size_t *size);
 
 /**
+ * Probe hardware support for the given codec parameters.
+ *
+ * For decoders, it tests whether a stream with the given parameters can be
+ * decoded on the given device.  For encoders, it tests whether encoding with
+ * the given parameters is possible on the device.
+ *
+ * On successful return, the fields of hw_frames_ref are set such that, once
+ * initialised, it will be usable as AVCodecContext.hw_frames_ctx.  If the
+ * user has additional requirements to apply to the frames context (for
+ * example, for a larger pool size or for frames created with some system-
+ * specific attribute) then they should be applied after this call but before
+ * calling av_hwframe_ctx_init().
+ *
+ * The device to use is provided as the allocating context of hw_frames_ref.
+ * (Even if set, the hw_frames_ctx and hw_device_ctx fields of avctx are
+ * ignored.)
+ *
+ * @param avctx Codec context with relevant fields set.  It need not have been
+ *              opened.
+ * @param hw_frames_ref A reference to a newly-allocated AVHWFramesContext,
+ *                      which will be used to return the result.
+ * @return 0 on success, otherwise negative error code:
+ *     AVERROR(ENOSYS): This function is not implemented (hardware support
+ *                      may or may not be available).
+ *     AVERROR(ENODEV): The device is not usable.
+ *     AVERROR(EINVAL): The codec parameters are not supported.
+ *     Other errors:    Probing failed for some other reason.
+ */
+int avcodec_probe_hw(AVCodecContext *avctx, AVBufferRef *hw_frames_ref);
+
+/**
  * @}
  */
 
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index e4f6a0d72..4029683e6 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -701,13 +701,6 @@ static int is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt)
     return desc->flags & AV_PIX_FMT_FLAG_HWACCEL;
 }
 
-enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const 
enum AVPixelFormat *fmt)
-{
-    while (*fmt != AV_PIX_FMT_NONE && is_hwaccel_pix_fmt(*fmt))
-        ++fmt;
-    return fmt[0];
-}
-
 static AVHWAccel *find_hwaccel(enum AVCodecID codec_id,
                                enum AVPixelFormat pix_fmt)
 {
@@ -753,6 +746,28 @@ static int setup_hwaccel(AVCodecContext *avctx,
     return 0;
 }
 
+enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const 
enum AVPixelFormat *fmt)
+{
+    if (s->hw_device_ctx) {
+        const AVHWDeviceContext *device = (const 
AVHWDeviceContext*)s->hw_device_ctx->data;
+        const AVHWAccel *hwaccel;
+        int i;
+        for (i = 0; fmt[i] != AV_PIX_FMT_NONE; i++) {
+            if (!is_hwaccel_pix_fmt(fmt[i]))
+                continue;
+            hwaccel = find_hwaccel(s->codec_id, fmt[i]);
+            if (!hwaccel)
+                continue;
+            if (hwaccel->device_type == device->type)
+                return fmt[i];
+        }
+    }
+
+    while (*fmt != AV_PIX_FMT_NONE && is_hwaccel_pix_fmt(*fmt))
+        ++fmt;
+    return fmt[0];
+}
+
 int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
 {
     const AVPixFmtDescriptor *desc;
@@ -1210,3 +1225,27 @@ void ff_decode_bsfs_uninit(AVCodecContext *avctx)
     av_freep(&s->bsfs);
     s->nb_bsfs = 0;
 }
+
+int ff_decode_probe_hw(AVCodecContext *avctx, AVHWFramesContext *hw_frames)
+{
+    const AVCodec *codec = avctx->codec;
+    const AVHWAccel *hwaccel = NULL;
+
+    if (!codec)
+        return AVERROR(EINVAL);
+
+    if (!hw_frames->device_ctx)
+        return AVERROR(ENODEV);
+
+    while ((hwaccel = av_hwaccel_next(hwaccel))) {
+        if (hwaccel->id == avctx->codec_id &&
+            hwaccel->device_type == hw_frames->device_ctx->type)
+            break;
+    }
+    if (hwaccel && hwaccel->probe_hw)
+        return hwaccel->probe_hw(avctx, hw_frames);
+    else if (codec->probe_hw)
+        return codec->probe_hw(avctx, hw_frames);
+    else
+        return AVERROR(ENOSYS);
+}
diff --git a/libavcodec/encode.c b/libavcodec/encode.c
index 9bb7ae5bd..d4914d7da 100644
--- a/libavcodec/encode.c
+++ b/libavcodec/encode.c
@@ -354,3 +354,16 @@ int attribute_align_arg 
avcodec_receive_packet(AVCodecContext *avctx, AVPacket *
     avctx->internal->buffer_pkt_valid = 0;
     return 0;
 }
+
+int ff_encode_probe_hw(AVCodecContext *avctx, AVHWFramesContext *hw_frames)
+{
+    const AVCodec *codec = avctx->codec;
+
+    if (!codec)
+        return AVERROR(EINVAL);
+
+    if (codec->probe_hw)
+        return codec->probe_hw(avctx, hw_frames);
+    else
+        return AVERROR(ENOSYS);
+}
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 403fb4a09..930b32fd6 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -285,4 +285,14 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame 
*frame);
  */
 AVCPBProperties *ff_add_cpb_side_data(AVCodecContext *avctx);
 
+/**
+ * Probe decoder/hwaccel hardware support.
+ */
+int ff_decode_probe_hw(AVCodecContext *avctx, AVHWFramesContext *hw_frames);
+
+/**
+ * Probe encoder hardware support.
+ */
+int ff_encode_probe_hw(AVCodecContext *avctx, AVHWFramesContext *hw_frames);
+
 #endif /* AVCODEC_INTERNAL_H */
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index bc421f67f..2a73098ec 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -1685,3 +1685,18 @@ int avcodec_parameters_to_context(AVCodecContext *codec,
 
     return 0;
 }
+
+int avcodec_probe_hw(AVCodecContext *avctx, AVBufferRef *hw_frames_ref)
+{
+    AVHWFramesContext *hw_frames = (AVHWFramesContext*)hw_frames_ref->data;
+
+    switch (avctx->codec_type) {
+    case AVMEDIA_TYPE_VIDEO:
+        if (av_codec_is_encoder(avctx->codec))
+            return ff_encode_probe_hw(avctx, hw_frames);
+        else
+            return ff_decode_probe_hw(avctx, hw_frames);
+    default:
+        return AVERROR(ENOSYS);
+    }
+}
-- 
2.11.0
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to