|
|
|
@@ -20,15 +20,16 @@ |
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <pthread.h> |
|
|
|
#include <CoreFoundation/CFDictionary.h> |
|
|
|
#include <CoreFoundation/CFNumber.h> |
|
|
|
#include <CoreFoundation/CFData.h> |
|
|
|
#include <CoreFoundation/CFString.h> |
|
|
|
|
|
|
|
#include "libavutil/avutil.h" |
|
|
|
#include "vda_internal.h" |
|
|
|
|
|
|
|
#if FF_API_VDA_ASYNC |
|
|
|
#include <CoreFoundation/CFString.h> |
|
|
|
|
|
|
|
/* 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; |
|
|
|
} |