summaryrefslogtreecommitdiff
path: root/libavutil/hwcontext.c
diff options
context:
space:
mode:
authorMark Thompson <sw@jkqxz.net>2017-03-04 23:57:28 +0000
committerMark Thompson <sw@jkqxz.net>2017-03-20 23:15:43 +0000
commitb266ad56fe0e4ce5bb70118ba2e2b1dabfaf76ce (patch)
tree9ffc32c7d86e1c40ea8c4c343a8339b7d6387b48 /libavutil/hwcontext.c
parentb864230c49089b087eef56988a3d6a784f6f9827 (diff)
hwcontext: Add device derivation
Creates a new device context from another of a different type which refers to the same underlying hardware.
Diffstat (limited to 'libavutil/hwcontext.c')
-rw-r--r--libavutil/hwcontext.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c
index 608da68727..252dd32e38 100644
--- a/libavutil/hwcontext.c
+++ b/libavutil/hwcontext.c
@@ -65,6 +65,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 +537,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;