hwcontext: Make it easier to work with device types
[libav.git] / libavutil / hwcontext.c
index 83f733e..2c6d51e 100644 (file)
@@ -28,7 +28,7 @@
 #include "pixdesc.h"
 #include "pixfmt.h"
 
-static const HWContextType *hw_table[] = {
+static const HWContextType * const hw_table[] = {
 #if CONFIG_CUDA
     &ff_hwcontext_type_cuda,
 #endif
@@ -47,6 +47,47 @@ static const HWContextType *hw_table[] = {
     NULL,
 };
 
+const char *hw_type_names[] = {
+    [AV_HWDEVICE_TYPE_CUDA]   = "cuda",
+    [AV_HWDEVICE_TYPE_DXVA2]  = "dxva2",
+    [AV_HWDEVICE_TYPE_QSV]    = "qsv",
+    [AV_HWDEVICE_TYPE_VAAPI]  = "vaapi",
+    [AV_HWDEVICE_TYPE_VDPAU]  = "vdpau",
+};
+
+enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name)
+{
+    int type;
+    for (type = 0; type < FF_ARRAY_ELEMS(hw_type_names); type++) {
+        if (hw_type_names[type] && !strcmp(hw_type_names[type], name))
+            return type;
+    }
+    return AV_HWDEVICE_TYPE_NONE;
+}
+
+const char *av_hwdevice_get_type_name(enum AVHWDeviceType type)
+{
+    if (type >= 0 && type < FF_ARRAY_ELEMS(hw_type_names))
+        return hw_type_names[type];
+    else
+        return NULL;
+}
+
+enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev)
+{
+    enum AVHWDeviceType next;
+    int i, set = 0;
+    for (i = 0; hw_table[i]; i++) {
+        if (prev != AV_HWDEVICE_TYPE_NONE && hw_table[i]->type <= prev)
+            continue;
+        if (!set || hw_table[i]->type < next) {
+            next = hw_table[i]->type;
+            set = 1;
+        }
+    }
+    return set ? next : AV_HWDEVICE_TYPE_NONE;
+}
+
 static const AVClass hwdevice_ctx_class = {
     .class_name = "AVHWDeviceContext",
     .item_name  = av_default_item_name,
@@ -65,6 +106,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);
@@ -535,6 +578,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;