hwcontext: Add device derivation
authorMark Thompson <sw@jkqxz.net>
Sat, 4 Mar 2017 23:57:28 +0000 (23:57 +0000)
committerMark Thompson <sw@jkqxz.net>
Wed, 14 Jun 2017 21:25:57 +0000 (22:25 +0100)
Creates a new device context from another of a different type which
refers to the same underlying hardware.

(cherry picked from commit b266ad56fe0e4ce5bb70118ba2e2b1dabfaf76ce)

doc/APIchanges
libavutil/hwcontext.c
libavutil/hwcontext.h
libavutil/hwcontext_internal.h
libavutil/version.h

index 67a6142..8d08999 100644 (file)
@@ -15,6 +15,9 @@ libavutil:     2015-08-28
 
 API changes, most recent first:
 
+2017-06-14 - xxxxxxx - lavu 55.64.100 - hwcontext.h
+  Add av_hwdevice_ctx_create_derived().
+
 2017-05-15 - xxxxxxxxxx - lavc 57.96.100 - avcodec.h
   VideoToolbox hardware-accelerated decoding now supports the new hwaccel API,
   which can create the decoder context and allocate hardware frames automatically.
index 8d50a32..86d290d 100644 (file)
@@ -68,6 +68,8 @@ static void hwdevice_ctx_free(void *opaque, uint8_t *data)
     if (ctx->free)
         ctx->free(ctx);
 
+    av_buffer_unref(&ctx->internal->source_device);
+
     av_freep(&ctx->hwctx);
     av_freep(&ctx->internal->priv);
     av_freep(&ctx->internal);
@@ -538,6 +540,69 @@ fail:
     return ret;
 }
 
+int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr,
+                                   enum AVHWDeviceType type,
+                                   AVBufferRef *src_ref, int flags)
+{
+    AVBufferRef *dst_ref = NULL, *tmp_ref;
+    AVHWDeviceContext *dst_ctx, *tmp_ctx;
+    int ret = 0;
+
+    tmp_ref = src_ref;
+    while (tmp_ref) {
+        tmp_ctx = (AVHWDeviceContext*)tmp_ref->data;
+        if (tmp_ctx->type == type) {
+            dst_ref = av_buffer_ref(tmp_ref);
+            if (!dst_ref) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+            goto done;
+        }
+        tmp_ref = tmp_ctx->internal->source_device;
+    }
+
+    dst_ref = av_hwdevice_ctx_alloc(type);
+    if (!dst_ref) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+    dst_ctx = (AVHWDeviceContext*)dst_ref->data;
+
+    tmp_ref = src_ref;
+    while (tmp_ref) {
+        tmp_ctx = (AVHWDeviceContext*)tmp_ref->data;
+        if (dst_ctx->internal->hw_type->device_derive) {
+            ret = dst_ctx->internal->hw_type->device_derive(dst_ctx,
+                                                            tmp_ctx,
+                                                            flags);
+            if (ret == 0) {
+                dst_ctx->internal->source_device = av_buffer_ref(src_ref);
+                if (!dst_ctx->internal->source_device) {
+                    ret = AVERROR(ENOMEM);
+                    goto fail;
+                }
+                goto done;
+            }
+            if (ret != AVERROR(ENOSYS))
+                goto fail;
+        }
+        tmp_ref = tmp_ctx->internal->source_device;
+    }
+
+    ret = AVERROR(ENOSYS);
+    goto fail;
+
+done:
+    *dst_ref_ptr = dst_ref;
+    return 0;
+
+fail:
+    av_buffer_unref(&dst_ref);
+    *dst_ref_ptr = NULL;
+    return ret;
+}
+
 static void ff_hwframe_unmap(void *opaque, uint8_t *data)
 {
     HWMapDescriptor *hwmap = (HWMapDescriptor*)data;
index cfc6ad0..782dbf2 100644 (file)
@@ -271,6 +271,32 @@ int av_hwdevice_ctx_create(AVBufferRef **device_ctx, enum AVHWDeviceType type,
                            const char *device, AVDictionary *opts, int flags);
 
 /**
+ * Create a new device of the specified type from an existing device.
+ *
+ * If the source device is a device of the target type or was originally
+ * derived from such a device (possibly through one or more intermediate
+ * devices of other types), then this will return a reference to the
+ * existing device of the same type as is requested.
+ *
+ * Otherwise, it will attempt to derive a new device from the given source
+ * device.  If direct derivation to the new type is not implemented, it will
+ * attempt the same derivation from each ancestor of the source device in
+ * turn looking for an implemented derivation method.
+ *
+ * @param dst_ctx On success, a reference to the newly-created
+ *                AVHWDeviceContext.
+ * @param type    The type of the new device to create.
+ * @param src_ctx A reference to an existing AVHWDeviceContext which will be
+ *                used to create the new device.
+ * @param flags   Currently unused; should be set to zero.
+ * @return        Zero on success, a negative AVERROR code on failure.
+ */
+int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ctx,
+                                   enum AVHWDeviceType type,
+                                   AVBufferRef *src_ctx, int flags);
+
+
+/**
  * Allocate an AVHWFramesContext tied to a given device context.
  *
  * @param device_ctx a reference to a AVHWDeviceContext. This function will make
index cf05323..6451c0e 100644 (file)
@@ -66,6 +66,8 @@ typedef struct HWContextType {
 
     int              (*device_create)(AVHWDeviceContext *ctx, const char *device,
                                       AVDictionary *opts, int flags);
+    int              (*device_derive)(AVHWDeviceContext *dst_ctx,
+                                      AVHWDeviceContext *src_ctx, int flags);
 
     int              (*device_init)(AVHWDeviceContext *ctx);
     void             (*device_uninit)(AVHWDeviceContext *ctx);
@@ -95,6 +97,12 @@ typedef struct HWContextType {
 struct AVHWDeviceInternal {
     const HWContextType *hw_type;
     void                *priv;
+
+    /**
+     * For a derived device, a reference to the original device
+     * context it was derived from.
+     */
+    AVBufferRef *source_device;
 };
 
 struct AVHWFramesInternal {
index fb61dcc..dd8d240 100644 (file)
@@ -80,7 +80,7 @@
 
 
 #define LIBAVUTIL_VERSION_MAJOR  55
-#define LIBAVUTIL_VERSION_MINOR  63
+#define LIBAVUTIL_VERSION_MINOR  64
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \