vda: support synchronous decoding.
[ffmpeg.git] / libavcodec / vda.c
index d3ced6c..a4ec158 100644 (file)
  * 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;
 }