Creates a new device context from another of a different type which
refers to the same underlying hardware.
(cherry picked from commit b266ad56fe
)
tags/n3.4
@@ -15,6 +15,9 @@ libavutil: 2015-08-28 | |||||
API changes, most recent first: | 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 | 2017-05-15 - xxxxxxxxxx - lavc 57.96.100 - avcodec.h | ||||
VideoToolbox hardware-accelerated decoding now supports the new hwaccel API, | VideoToolbox hardware-accelerated decoding now supports the new hwaccel API, | ||||
which can create the decoder context and allocate hardware frames automatically. | which can create the decoder context and allocate hardware frames automatically. | ||||
@@ -68,6 +68,8 @@ static void hwdevice_ctx_free(void *opaque, uint8_t *data) | |||||
if (ctx->free) | if (ctx->free) | ||||
ctx->free(ctx); | ctx->free(ctx); | ||||
av_buffer_unref(&ctx->internal->source_device); | |||||
av_freep(&ctx->hwctx); | av_freep(&ctx->hwctx); | ||||
av_freep(&ctx->internal->priv); | av_freep(&ctx->internal->priv); | ||||
av_freep(&ctx->internal); | av_freep(&ctx->internal); | ||||
@@ -538,6 +540,69 @@ fail: | |||||
return ret; | 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) | static void ff_hwframe_unmap(void *opaque, uint8_t *data) | ||||
{ | { | ||||
HWMapDescriptor *hwmap = (HWMapDescriptor*)data; | HWMapDescriptor *hwmap = (HWMapDescriptor*)data; | ||||
@@ -270,6 +270,32 @@ int av_hwdevice_ctx_init(AVBufferRef *ref); | |||||
int av_hwdevice_ctx_create(AVBufferRef **device_ctx, enum AVHWDeviceType type, | int av_hwdevice_ctx_create(AVBufferRef **device_ctx, enum AVHWDeviceType type, | ||||
const char *device, AVDictionary *opts, int flags); | 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. | * Allocate an AVHWFramesContext tied to a given device context. | ||||
* | * | ||||
@@ -66,6 +66,8 @@ typedef struct HWContextType { | |||||
int (*device_create)(AVHWDeviceContext *ctx, const char *device, | int (*device_create)(AVHWDeviceContext *ctx, const char *device, | ||||
AVDictionary *opts, int flags); | AVDictionary *opts, int flags); | ||||
int (*device_derive)(AVHWDeviceContext *dst_ctx, | |||||
AVHWDeviceContext *src_ctx, int flags); | |||||
int (*device_init)(AVHWDeviceContext *ctx); | int (*device_init)(AVHWDeviceContext *ctx); | ||||
void (*device_uninit)(AVHWDeviceContext *ctx); | void (*device_uninit)(AVHWDeviceContext *ctx); | ||||
@@ -95,6 +97,12 @@ typedef struct HWContextType { | |||||
struct AVHWDeviceInternal { | struct AVHWDeviceInternal { | ||||
const HWContextType *hw_type; | const HWContextType *hw_type; | ||||
void *priv; | void *priv; | ||||
/** | |||||
* For a derived device, a reference to the original device | |||||
* context it was derived from. | |||||
*/ | |||||
AVBufferRef *source_device; | |||||
}; | }; | ||||
struct AVHWFramesInternal { | struct AVHWFramesInternal { | ||||
@@ -80,7 +80,7 @@ | |||||
#define LIBAVUTIL_VERSION_MAJOR 55 | #define LIBAVUTIL_VERSION_MAJOR 55 | ||||
#define LIBAVUTIL_VERSION_MINOR 63 | |||||
#define LIBAVUTIL_VERSION_MINOR 64 | |||||
#define LIBAVUTIL_VERSION_MICRO 100 | #define LIBAVUTIL_VERSION_MICRO 100 | ||||
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ | #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ | ||||