00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <CoreFoundation/CFDictionary.h>
00024 #include <CoreFoundation/CFNumber.h>
00025 #include <CoreFoundation/CFData.h>
00026
00027 #include "vda.h"
00028 #include "libavutil/avutil.h"
00029 #include "h264.h"
00030
00031 #if FF_API_VDA_ASYNC
00032 #include <CoreFoundation/CFString.h>
00033
00034
00035 static CFDictionaryRef vda_dictionary_with_pts(int64_t i_pts)
00036 {
00037 CFStringRef key = CFSTR("FF_VDA_DECODER_PTS_KEY");
00038 CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &i_pts);
00039 CFDictionaryRef user_info = CFDictionaryCreate(kCFAllocatorDefault,
00040 (const void **)&key,
00041 (const void **)&value,
00042 1,
00043 &kCFTypeDictionaryKeyCallBacks,
00044 &kCFTypeDictionaryValueCallBacks);
00045 CFRelease(value);
00046 return user_info;
00047 }
00048
00049
00050 static int64_t vda_pts_from_dictionary(CFDictionaryRef user_info)
00051 {
00052 CFNumberRef pts;
00053 int64_t outValue = 0;
00054
00055 if (!user_info)
00056 return 0;
00057
00058 pts = CFDictionaryGetValue(user_info, CFSTR("FF_VDA_DECODER_PTS_KEY"));
00059
00060 if (pts)
00061 CFNumberGetValue(pts, kCFNumberSInt64Type, &outValue);
00062
00063 return outValue;
00064 }
00065
00066
00067 static void vda_clear_queue(struct vda_context *vda_ctx)
00068 {
00069 vda_frame *top_frame;
00070
00071 pthread_mutex_lock(&vda_ctx->queue_mutex);
00072
00073 while (vda_ctx->queue) {
00074 top_frame = vda_ctx->queue;
00075 vda_ctx->queue = top_frame->next_frame;
00076 ff_vda_release_vda_frame(top_frame);
00077 }
00078
00079 pthread_mutex_unlock(&vda_ctx->queue_mutex);
00080 }
00081
00082 static int vda_decoder_decode(struct vda_context *vda_ctx,
00083 uint8_t *bitstream,
00084 int bitstream_size,
00085 int64_t frame_pts)
00086 {
00087 OSStatus status;
00088 CFDictionaryRef user_info;
00089 CFDataRef coded_frame;
00090
00091 coded_frame = CFDataCreate(kCFAllocatorDefault, bitstream, bitstream_size);
00092 user_info = vda_dictionary_with_pts(frame_pts);
00093
00094 status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, user_info);
00095
00096 CFRelease(user_info);
00097 CFRelease(coded_frame);
00098
00099 return status;
00100 }
00101
00102 vda_frame *ff_vda_queue_pop(struct vda_context *vda_ctx)
00103 {
00104 vda_frame *top_frame;
00105
00106 if (!vda_ctx->queue)
00107 return NULL;
00108
00109 pthread_mutex_lock(&vda_ctx->queue_mutex);
00110 top_frame = vda_ctx->queue;
00111 vda_ctx->queue = top_frame->next_frame;
00112 pthread_mutex_unlock(&vda_ctx->queue_mutex);
00113
00114 return top_frame;
00115 }
00116
00117 void ff_vda_release_vda_frame(vda_frame *frame)
00118 {
00119 if (frame) {
00120 CVPixelBufferRelease(frame->cv_buffer);
00121 av_freep(&frame);
00122 }
00123 }
00124 #endif
00125
00126
00127 static void vda_decoder_callback (void *vda_hw_ctx,
00128 CFDictionaryRef user_info,
00129 OSStatus status,
00130 uint32_t infoFlags,
00131 CVImageBufferRef image_buffer)
00132 {
00133 struct vda_context *vda_ctx = vda_hw_ctx;
00134
00135 if (!image_buffer)
00136 return;
00137
00138 if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer))
00139 return;
00140
00141 if (vda_ctx->use_sync_decoding) {
00142 vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer);
00143 } else {
00144 vda_frame *new_frame;
00145 vda_frame *queue_walker;
00146
00147 if (!(new_frame = av_mallocz(sizeof(*new_frame))))
00148 return;
00149
00150 new_frame->next_frame = NULL;
00151 new_frame->cv_buffer = CVPixelBufferRetain(image_buffer);
00152 new_frame->pts = vda_pts_from_dictionary(user_info);
00153
00154 pthread_mutex_lock(&vda_ctx->queue_mutex);
00155
00156 queue_walker = vda_ctx->queue;
00157
00158 if (!queue_walker || (new_frame->pts < queue_walker->pts)) {
00159
00160 new_frame->next_frame = queue_walker;
00161 vda_ctx->queue = new_frame;
00162 } else {
00163
00164 vda_frame *next_frame;
00165
00166 while (1) {
00167 next_frame = queue_walker->next_frame;
00168
00169 if (!next_frame || (new_frame->pts < next_frame->pts)) {
00170 new_frame->next_frame = next_frame;
00171 queue_walker->next_frame = new_frame;
00172 break;
00173 }
00174 queue_walker = next_frame;
00175 }
00176 }
00177
00178 pthread_mutex_unlock(&vda_ctx->queue_mutex);
00179 }
00180 }
00181
00182 static int vda_sync_decode(struct vda_context *vda_ctx)
00183 {
00184 OSStatus status;
00185 CFDataRef coded_frame;
00186 uint32_t flush_flags = 1 << 0;
00187
00188 coded_frame = CFDataCreate(kCFAllocatorDefault,
00189 vda_ctx->priv_bitstream,
00190 vda_ctx->priv_bitstream_size);
00191
00192 status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL);
00193
00194 if (kVDADecoderNoErr == status)
00195 status = VDADecoderFlush(vda_ctx->decoder, flush_flags);
00196
00197 CFRelease(coded_frame);
00198
00199 return status;
00200 }
00201
00202 static int start_frame(AVCodecContext *avctx,
00203 av_unused const uint8_t *buffer,
00204 av_unused uint32_t size)
00205 {
00206 struct vda_context *vda_ctx = avctx->hwaccel_context;
00207
00208 if (!vda_ctx->decoder)
00209 return -1;
00210
00211 vda_ctx->priv_bitstream_size = 0;
00212
00213 return 0;
00214 }
00215
00216 static int decode_slice(AVCodecContext *avctx,
00217 const uint8_t *buffer,
00218 uint32_t size)
00219 {
00220 struct vda_context *vda_ctx = avctx->hwaccel_context;
00221 void *tmp;
00222
00223 if (!vda_ctx->decoder)
00224 return -1;
00225
00226 tmp = av_fast_realloc(vda_ctx->priv_bitstream,
00227 &vda_ctx->priv_allocated_size,
00228 vda_ctx->priv_bitstream_size + size + 4);
00229 if (!tmp)
00230 return AVERROR(ENOMEM);
00231
00232 vda_ctx->priv_bitstream = tmp;
00233
00234 AV_WB32(vda_ctx->priv_bitstream + vda_ctx->priv_bitstream_size, size);
00235 memcpy(vda_ctx->priv_bitstream + vda_ctx->priv_bitstream_size + 4, buffer, size);
00236
00237 vda_ctx->priv_bitstream_size += size + 4;
00238
00239 return 0;
00240 }
00241
00242 static int end_frame(AVCodecContext *avctx)
00243 {
00244 H264Context *h = avctx->priv_data;
00245 struct vda_context *vda_ctx = avctx->hwaccel_context;
00246 AVFrame *frame = &h->s.current_picture_ptr->f;
00247 int status;
00248
00249 if (!vda_ctx->decoder || !vda_ctx->priv_bitstream)
00250 return -1;
00251
00252 if (vda_ctx->use_sync_decoding) {
00253 status = vda_sync_decode(vda_ctx);
00254 frame->data[3] = (void*)vda_ctx->cv_buffer;
00255 } else {
00256 status = vda_decoder_decode(vda_ctx, vda_ctx->priv_bitstream,
00257 vda_ctx->priv_bitstream_size,
00258 frame->reordered_opaque);
00259 }
00260
00261 if (status)
00262 av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
00263
00264 return status;
00265 }
00266
00267 int ff_vda_create_decoder(struct vda_context *vda_ctx,
00268 uint8_t *extradata,
00269 int extradata_size)
00270 {
00271 OSStatus status;
00272 CFNumberRef height;
00273 CFNumberRef width;
00274 CFNumberRef format;
00275 CFDataRef avc_data;
00276 CFMutableDictionaryRef config_info;
00277 CFMutableDictionaryRef buffer_attributes;
00278 CFMutableDictionaryRef io_surface_properties;
00279 CFNumberRef cv_pix_fmt;
00280
00281 vda_ctx->priv_bitstream = NULL;
00282 vda_ctx->priv_allocated_size = 0;
00283
00284 #if FF_API_VDA_ASYNC
00285 pthread_mutex_init(&vda_ctx->queue_mutex, NULL);
00286 #endif
00287
00288
00289
00290
00291 if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) {
00292 uint8_t *rw_extradata;
00293
00294 if (!(rw_extradata = av_malloc(extradata_size)))
00295 return AVERROR(ENOMEM);
00296
00297 memcpy(rw_extradata, extradata, extradata_size);
00298
00299 rw_extradata[4] |= 0x03;
00300
00301 avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size);
00302
00303 av_freep(&rw_extradata);
00304 } else {
00305 avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size);
00306 }
00307
00308 config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
00309 4,
00310 &kCFTypeDictionaryKeyCallBacks,
00311 &kCFTypeDictionaryValueCallBacks);
00312
00313 height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height);
00314 width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width);
00315 format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format);
00316
00317 CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height);
00318 CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width);
00319 CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format);
00320 CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data);
00321
00322 buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
00323 2,
00324 &kCFTypeDictionaryKeyCallBacks,
00325 &kCFTypeDictionaryValueCallBacks);
00326 io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
00327 0,
00328 &kCFTypeDictionaryKeyCallBacks,
00329 &kCFTypeDictionaryValueCallBacks);
00330 cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault,
00331 kCFNumberSInt32Type,
00332 &vda_ctx->cv_pix_fmt_type);
00333 CFDictionarySetValue(buffer_attributes,
00334 kCVPixelBufferPixelFormatTypeKey,
00335 cv_pix_fmt);
00336 CFDictionarySetValue(buffer_attributes,
00337 kCVPixelBufferIOSurfacePropertiesKey,
00338 io_surface_properties);
00339
00340 status = VDADecoderCreate(config_info,
00341 buffer_attributes,
00342 vda_decoder_callback,
00343 vda_ctx,
00344 &vda_ctx->decoder);
00345
00346 CFRelease(height);
00347 CFRelease(width);
00348 CFRelease(format);
00349 CFRelease(avc_data);
00350 CFRelease(config_info);
00351 CFRelease(io_surface_properties);
00352 CFRelease(cv_pix_fmt);
00353 CFRelease(buffer_attributes);
00354
00355 return status;
00356 }
00357
00358 int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
00359 {
00360 OSStatus status = kVDADecoderNoErr;
00361
00362 if (vda_ctx->decoder)
00363 status = VDADecoderDestroy(vda_ctx->decoder);
00364
00365 #if FF_API_VDA_ASYNC
00366 vda_clear_queue(vda_ctx);
00367 pthread_mutex_destroy(&vda_ctx->queue_mutex);
00368 #endif
00369 av_freep(&vda_ctx->priv_bitstream);
00370
00371 return status;
00372 }
00373
00374 AVHWAccel ff_h264_vda_hwaccel = {
00375 .name = "h264_vda",
00376 .type = AVMEDIA_TYPE_VIDEO,
00377 .id = AV_CODEC_ID_H264,
00378 .pix_fmt = PIX_FMT_VDA_VLD,
00379 .start_frame = start_frame,
00380 .decode_slice = decode_slice,
00381 .end_frame = end_frame,
00382 };