From 7f3dfd2010c6f92447e34ccbbb303b0fd18997ff Mon Sep 17 00:00:00 2001 From: Sebastien Zwickert Date: Sun, 12 Aug 2012 17:03:05 +0200 Subject: vda: support synchronous decoding. Note that the symbols used to run the hardware decoder in asynchronous mode has been marked as deprecated and will be dropped at a future version dump. Signed-off-by: Michael Niedermayer --- libavcodec/vda.c | 122 +++++++++++++++++++++++++++------------------- libavcodec/vda.h | 47 ++++++++++++++++-- libavcodec/vda_h264.c | 16 ++++-- libavcodec/vda_internal.h | 4 ++ libavcodec/version.h | 4 ++ 5 files changed, 135 insertions(+), 58 deletions(-) diff --git a/libavcodec/vda.c b/libavcodec/vda.c index d3ced6c..a4ec158 100644 --- a/libavcodec/vda.c +++ b/libavcodec/vda.c @@ -20,15 +20,16 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include #include -#include #include "libavutil/avutil.h" #include "vda_internal.h" +#if FF_API_VDA_ASYNC +#include + /* Helper to create a dictionary according to the given pts. */ static CFDictionaryRef vda_dictionary_with_pts(int64_t i_pts) { @@ -76,7 +77,7 @@ static void vda_clear_queue(struct vda_context *vda_ctx) pthread_mutex_unlock(&vda_ctx->queue_mutex); } - +#endif /* Decoder callback that adds the vda frame to the queue in display order. */ static void vda_decoder_callback (void *vda_hw_ctx, @@ -86,8 +87,6 @@ static void vda_decoder_callback (void *vda_hw_ctx, CVImageBufferRef image_buffer) { struct vda_context *vda_ctx = (struct vda_context*)vda_hw_ctx; - vda_frame *new_frame; - vda_frame *queue_walker; if (!image_buffer) return; @@ -95,46 +94,54 @@ static void vda_decoder_callback (void *vda_hw_ctx, if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer)) return; - new_frame = av_mallocz(sizeof(vda_frame)); - if (!new_frame) - return; - - new_frame->next_frame = NULL; - new_frame->cv_buffer = CVPixelBufferRetain(image_buffer); - new_frame->pts = vda_pts_from_dictionary(user_info); - - pthread_mutex_lock(&vda_ctx->queue_mutex); - - queue_walker = vda_ctx->queue; - - if (!queue_walker || (new_frame->pts < queue_walker->pts)) { - /* we have an empty queue, or this frame earlier than the current queue head */ - new_frame->next_frame = queue_walker; - vda_ctx->queue = new_frame; - } else { - /* walk the queue and insert this frame where it belongs in display order */ - vda_frame *next_frame; - - while (1) { - next_frame = queue_walker->next_frame; - - if (!next_frame || (new_frame->pts < next_frame->pts)) { - new_frame->next_frame = next_frame; - queue_walker->next_frame = new_frame; - break; + if (vda_ctx->use_sync_decoding) { + vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer); + } + else { + vda_frame *new_frame; + vda_frame *queue_walker; + + new_frame = av_mallocz(sizeof(vda_frame)); + if (!new_frame) + return; + + new_frame->next_frame = NULL; + new_frame->cv_buffer = CVPixelBufferRetain(image_buffer); + new_frame->pts = vda_pts_from_dictionary(user_info); + + pthread_mutex_lock(&vda_ctx->queue_mutex); + + queue_walker = vda_ctx->queue; + + if (!queue_walker || (new_frame->pts < queue_walker->pts)) { + /* we have an empty queue, or this frame earlier than the current queue head */ + new_frame->next_frame = queue_walker; + vda_ctx->queue = new_frame; + } else { + /* walk the queue and insert this frame where it belongs in display order */ + vda_frame *next_frame; + + while (1) { + next_frame = queue_walker->next_frame; + + if (!next_frame || (new_frame->pts < next_frame->pts)) { + new_frame->next_frame = next_frame; + queue_walker->next_frame = new_frame; + break; + } + queue_walker = next_frame; } - queue_walker = next_frame; } - } - pthread_mutex_unlock(&vda_ctx->queue_mutex); + pthread_mutex_unlock(&vda_ctx->queue_mutex); + } } int ff_vda_create_decoder(struct vda_context *vda_ctx, uint8_t *extradata, int extradata_size) { - OSStatus status = kVDADecoderNoErr; + OSStatus status; CFNumberRef height; CFNumberRef width; CFNumberRef format; @@ -147,7 +154,9 @@ int ff_vda_create_decoder(struct vda_context *vda_ctx, vda_ctx->bitstream = NULL; vda_ctx->ref_size = 0; +#if FF_API_VDA_ASYNC pthread_mutex_init(&vda_ctx->queue_mutex, NULL); +#endif /* Each VCL NAL in the bistream sent to the decoder * is preceded by a 4 bytes length header. @@ -216,10 +225,7 @@ int ff_vda_create_decoder(struct vda_context *vda_ctx, CFRelease(cv_pix_fmt); CFRelease(buffer_attributes); - if (kVDADecoderNoErr != status) - return status; - - return 0; + return status; } int ff_vda_destroy_decoder(struct vda_context *vda_ctx) @@ -229,19 +235,17 @@ int ff_vda_destroy_decoder(struct vda_context *vda_ctx) if (vda_ctx->decoder) status = VDADecoderDestroy(vda_ctx->decoder); +#if FF_API_VDA_ASYNC vda_clear_queue(vda_ctx); - pthread_mutex_destroy(&vda_ctx->queue_mutex); - +#endif if (vda_ctx->bitstream) av_freep(&vda_ctx->bitstream); - if (kVDADecoderNoErr != status) - return status; - - return 0; + return status; } +#if FF_API_VDA_ASYNC vda_frame *ff_vda_queue_pop(struct vda_context *vda_ctx) { vda_frame *top_frame; @@ -270,7 +274,7 @@ int ff_vda_decoder_decode(struct vda_context *vda_ctx, int bitstream_size, int64_t frame_pts) { - OSStatus status = kVDADecoderNoErr; + OSStatus status; CFDictionaryRef user_info; CFDataRef coded_frame; @@ -282,8 +286,26 @@ int ff_vda_decoder_decode(struct vda_context *vda_ctx, CFRelease(user_info); CFRelease(coded_frame); - if (kVDADecoderNoErr != status) - return status; + return status; +} +#endif + +int ff_vda_sync_decode(struct vda_context *vda_ctx) +{ + OSStatus status; + CFDataRef coded_frame; + uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames + + coded_frame = CFDataCreate(kCFAllocatorDefault, + vda_ctx->bitstream, + vda_ctx->bitstream_size); + + status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL); + + if (kVDADecoderNoErr == status) + status = VDADecoderFlush(vda_ctx->decoder, flush_flags); + + CFRelease(coded_frame); - return 0; + return status; } diff --git a/libavcodec/vda.h b/libavcodec/vda.h index 4ea0e9f..8c5ed66 100644 --- a/libavcodec/vda.h +++ b/libavcodec/vda.h @@ -29,7 +29,11 @@ * Public libavcodec VDA header. */ +#include "libavcodec/version.h" + +#if FF_API_VDA_ASYNC #include +#endif #include // emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes @@ -47,8 +51,12 @@ * @{ */ +#if FF_API_VDA_ASYNC /** - * This structure is used to store a decoded frame information and data. + * This structure is used to store a decoded frame information and data. + * + * @deprecated Use synchronous decoding mode. + * */ typedef struct { /** @@ -75,6 +83,7 @@ typedef struct { */ struct vda_frame *next_frame; } vda_frame; +#endif /** * This structure is used to provide the necessary configurations and data @@ -92,8 +101,27 @@ struct vda_context { VDADecoder decoder; /** + * The Core Video pixel buffer that contains the current image data. + * + * encoding: unused + * decoding: Set by libavcodec. Unset by user. + */ + CVPixelBufferRef cv_buffer; + + /** + * An integer value that indicates whether use the hardware decoder in synchronous mode. + * + * encoding: unused + * decoding: Set by user. + */ + int use_sync_decoding; + +#if FF_API_VDA_ASYNC + /** * VDA frames queue ordered by presentation timestamp. * + * @deprecated Use synchronous decoding mode. + * * - encoding: unused * - decoding: Set/Unset by libavcodec. */ @@ -102,10 +130,13 @@ struct vda_context { /** * Mutex for locking queue operations. * + * @deprecated Use synchronous decoding mode. + * * - encoding: unused * - decoding: Set/Unset by libavcodec. */ pthread_mutex_t queue_mutex; +#endif /** * The frame width. @@ -172,11 +203,21 @@ int ff_vda_create_decoder(struct vda_context *vda_ctx, /** Destroy the video decoder. */ int ff_vda_destroy_decoder(struct vda_context *vda_ctx); -/** Return the top frame of the queue. */ +#if FF_API_VDA_ASYNC +/** + * Return the top frame of the queue. + * + * @deprecated Use synchronous decoding mode. + */ vda_frame *ff_vda_queue_pop(struct vda_context *vda_ctx); -/** Release the given frame. */ +/** + * Release the given frame. + * + * @deprecated Use synchronous decoding mode. + */ void ff_vda_release_vda_frame(vda_frame *frame); +#endif /** * @} diff --git a/libavcodec/vda_h264.c b/libavcodec/vda_h264.c index a4a4c90..aaf9745 100644 --- a/libavcodec/vda_h264.c +++ b/libavcodec/vda_h264.c @@ -47,7 +47,9 @@ static int decode_slice(AVCodecContext *avctx, if (!vda_ctx->decoder) return -1; - tmp = av_fast_realloc(vda_ctx->bitstream, &vda_ctx->ref_size, vda_ctx->bitstream_size+size+4); + tmp = av_fast_realloc(vda_ctx->bitstream, + &vda_ctx->ref_size, + vda_ctx->bitstream_size+size+4); if (!tmp) return AVERROR(ENOMEM); @@ -71,9 +73,14 @@ static int end_frame(AVCodecContext *avctx) if (!vda_ctx->decoder || !vda_ctx->bitstream) return -1; - status = ff_vda_decoder_decode(vda_ctx, vda_ctx->bitstream, - vda_ctx->bitstream_size, - frame->reordered_opaque); + if (vda_ctx->use_sync_decoding) { + status = ff_vda_sync_decode(vda_ctx); + frame->data[3] = (void*)vda_ctx->cv_buffer; + } else { + status = ff_vda_decoder_decode(vda_ctx, vda_ctx->bitstream, + vda_ctx->bitstream_size, + frame->reordered_opaque); + } if (status) av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); @@ -89,5 +96,4 @@ AVHWAccel ff_h264_vda_hwaccel = { .start_frame = start_frame, .decode_slice = decode_slice, .end_frame = end_frame, - .priv_data_size = 0, }; diff --git a/libavcodec/vda_internal.h b/libavcodec/vda_internal.h index df7305b..55ef6e9 100644 --- a/libavcodec/vda_internal.h +++ b/libavcodec/vda_internal.h @@ -31,11 +31,15 @@ * @{ */ +#if FF_API_VDA_ASYNC /** Send frame data to the hardware decoder. */ int ff_vda_decoder_decode(struct vda_context *vda_ctx, uint8_t *bitstream, int bitstream_size, int64_t frame_pts); +#endif + +int ff_vda_sync_decode(struct vda_context *vda_ctx); /* @} */ diff --git a/libavcodec/version.h b/libavcodec/version.h index c877fe9..8fd2164 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -90,4 +90,8 @@ #define FF_API_CODEC_ID (LIBAVCODEC_VERSION_MAJOR < 55) #endif +#ifndef FF_API_VDA_ASYNC +#define FF_API_VDA_ASYNC (LIBAVCODEC_VERSION_MAJOR < 55) +#endif + #endif /* AVCODEC_VERSION_H */ -- cgit v1.1