2 * VDA H264 HW acceleration.
4 * copyright (c) 2011 Sebastien Zwickert
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <CoreFoundation/CFDictionary.h>
24 #include <CoreFoundation/CFNumber.h>
25 #include <CoreFoundation/CFData.h>
28 #include "libavutil/avutil.h"
32 CVPixelBufferRef cv_buffer;
35 #include "vda_vt_internal.h"
37 /* Decoder callback that adds the vda frame to the queue in display order. */
38 static void vda_decoder_callback(void *vda_hw_ctx,
39 CFDictionaryRef user_info,
42 CVImageBufferRef image_buffer)
44 struct vda_context *vda_ctx = vda_hw_ctx;
46 if (infoFlags & kVDADecodeInfo_FrameDropped)
47 vda_ctx->cv_buffer = NULL;
52 if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer))
55 vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer);
58 static int vda_sync_decode(VTContext *ctx, struct vda_context *vda_ctx)
61 CFDataRef coded_frame;
62 uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames
64 coded_frame = CFDataCreate(kCFAllocatorDefault,
68 status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL);
70 if (kVDADecoderNoErr == status)
71 status = VDADecoderFlush(vda_ctx->decoder, flush_flags);
73 CFRelease(coded_frame);
79 static int vda_old_h264_start_frame(AVCodecContext *avctx,
80 av_unused const uint8_t *buffer,
81 av_unused uint32_t size)
83 VTContext *vda = avctx->internal->hwaccel_priv_data;
84 struct vda_context *vda_ctx = avctx->hwaccel_context;
86 if (!vda_ctx->decoder)
89 vda->bitstream_size = 0;
94 static int vda_old_h264_decode_slice(AVCodecContext *avctx,
95 const uint8_t *buffer,
98 VTContext *vda = avctx->internal->hwaccel_priv_data;
99 struct vda_context *vda_ctx = avctx->hwaccel_context;
102 if (!vda_ctx->decoder)
105 tmp = av_fast_realloc(vda->bitstream,
106 &vda->allocated_size,
107 vda->bitstream_size + size + 4);
109 return AVERROR(ENOMEM);
111 vda->bitstream = tmp;
113 AV_WB32(vda->bitstream + vda->bitstream_size, size);
114 memcpy(vda->bitstream + vda->bitstream_size + 4, buffer, size);
116 vda->bitstream_size += size + 4;
121 static void vda_h264_release_buffer(void *opaque, uint8_t *data)
123 struct vda_buffer *context = opaque;
124 CVPixelBufferRelease(context->cv_buffer);
128 static int vda_old_h264_end_frame(AVCodecContext *avctx)
130 H264Context *h = avctx->priv_data;
131 VTContext *vda = avctx->internal->hwaccel_priv_data;
132 struct vda_context *vda_ctx = avctx->hwaccel_context;
133 AVFrame *frame = h->cur_pic_ptr->f;
134 struct vda_buffer *context;
138 if (!vda_ctx->decoder || !vda->bitstream)
141 status = vda_sync_decode(vda, vda_ctx);
142 frame->data[3] = (void*)vda_ctx->cv_buffer;
145 av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
147 if (!vda_ctx->use_ref_buffer || status)
150 context = av_mallocz(sizeof(*context));
151 buffer = av_buffer_create(NULL, 0, vda_h264_release_buffer, context, 0);
152 if (!context || !buffer) {
153 CVPixelBufferRelease(vda_ctx->cv_buffer);
158 context->cv_buffer = vda_ctx->cv_buffer;
159 frame->buf[3] = buffer;
164 int ff_vda_create_decoder(struct vda_context *vda_ctx,
173 CFMutableDictionaryRef config_info;
174 CFMutableDictionaryRef buffer_attributes;
175 CFMutableDictionaryRef io_surface_properties;
176 CFNumberRef cv_pix_fmt;
178 vda_ctx->priv_bitstream = NULL;
179 vda_ctx->priv_allocated_size = 0;
181 /* Each VCL NAL in the bitstream sent to the decoder
182 * is preceded by a 4 bytes length header.
183 * Change the avcC atom header if needed, to signal headers of 4 bytes. */
184 if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) {
185 uint8_t *rw_extradata;
187 if (!(rw_extradata = av_malloc(extradata_size)))
188 return AVERROR(ENOMEM);
190 memcpy(rw_extradata, extradata, extradata_size);
192 rw_extradata[4] |= 0x03;
194 avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size);
196 av_freep(&rw_extradata);
198 avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size);
201 config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
203 &kCFTypeDictionaryKeyCallBacks,
204 &kCFTypeDictionaryValueCallBacks);
206 height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height);
207 width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width);
208 format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format);
210 CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height);
211 CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width);
212 CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format);
213 CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data);
215 buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
217 &kCFTypeDictionaryKeyCallBacks,
218 &kCFTypeDictionaryValueCallBacks);
219 io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
221 &kCFTypeDictionaryKeyCallBacks,
222 &kCFTypeDictionaryValueCallBacks);
223 cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault,
225 &vda_ctx->cv_pix_fmt_type);
226 CFDictionarySetValue(buffer_attributes,
227 kCVPixelBufferPixelFormatTypeKey,
229 CFDictionarySetValue(buffer_attributes,
230 kCVPixelBufferIOSurfacePropertiesKey,
231 io_surface_properties);
233 status = VDADecoderCreate(config_info,
235 (VDADecoderOutputCallback *)vda_decoder_callback,
243 CFRelease(config_info);
244 CFRelease(io_surface_properties);
245 CFRelease(cv_pix_fmt);
246 CFRelease(buffer_attributes);
251 int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
253 OSStatus status = kVDADecoderNoErr;
255 if (vda_ctx->decoder)
256 status = VDADecoderDestroy(vda_ctx->decoder);
261 AVHWAccel ff_h264_vda_old_hwaccel = {
263 .type = AVMEDIA_TYPE_VIDEO,
264 .id = AV_CODEC_ID_H264,
265 .pix_fmt = AV_PIX_FMT_VDA_VLD,
266 .start_frame = vda_old_h264_start_frame,
267 .decode_slice = vda_old_h264_decode_slice,
268 .end_frame = vda_old_h264_end_frame,
269 .uninit = ff_videotoolbox_uninit,
270 .priv_data_size = sizeof(VTContext),
273 void ff_vda_output_callback(void *opaque,
274 CFDictionaryRef user_info,
277 CVImageBufferRef image_buffer)
279 AVCodecContext *ctx = opaque;
280 VTContext *vda = ctx->internal->hwaccel_priv_data;
284 CVPixelBufferRelease(vda->frame);
291 vda->frame = CVPixelBufferRetain(image_buffer);
294 static int vda_h264_end_frame(AVCodecContext *avctx)
296 H264Context *h = avctx->priv_data;
297 VTContext *vda = avctx->internal->hwaccel_priv_data;
298 AVVDAContext *vda_ctx = avctx->hwaccel_context;
299 AVFrame *frame = h->cur_pic_ptr->f;
300 uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames
301 CFDataRef coded_frame;
304 if (!vda->bitstream_size)
305 return AVERROR_INVALIDDATA;
308 coded_frame = CFDataCreate(kCFAllocatorDefault,
310 vda->bitstream_size);
312 status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL);
314 if (status == kVDADecoderNoErr)
315 status = VDADecoderFlush(vda_ctx->decoder, flush_flags);
317 CFRelease(coded_frame);
320 return AVERROR_UNKNOWN;
322 if (status != kVDADecoderNoErr) {
323 av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
324 return AVERROR_UNKNOWN;
327 return ff_videotoolbox_buffer_create(vda, frame);
330 int ff_vda_default_init(AVCodecContext *avctx)
332 AVVDAContext *vda_ctx = avctx->hwaccel_context;
333 OSStatus status = kVDADecoderNoErr;
338 CFMutableDictionaryRef config_info;
339 CFMutableDictionaryRef buffer_attributes;
340 CFMutableDictionaryRef io_surface_properties;
341 CFNumberRef cv_pix_fmt;
342 int32_t fmt = 'avc1', pix_fmt = vda_ctx->cv_pix_fmt_type;
344 // kCVPixelFormatType_420YpCbCr8Planar;
346 avc_data = ff_videotoolbox_avcc_extradata_create(avctx);
348 config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
350 &kCFTypeDictionaryKeyCallBacks,
351 &kCFTypeDictionaryValueCallBacks);
353 height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->height);
354 width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->width);
355 format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &fmt);
356 CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height);
357 CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width);
358 CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data);
359 CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format);
361 buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
363 &kCFTypeDictionaryKeyCallBacks,
364 &kCFTypeDictionaryValueCallBacks);
365 io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
367 &kCFTypeDictionaryKeyCallBacks,
368 &kCFTypeDictionaryValueCallBacks);
369 cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault,
373 CFDictionarySetValue(buffer_attributes,
374 kCVPixelBufferPixelFormatTypeKey,
376 CFDictionarySetValue(buffer_attributes,
377 kCVPixelBufferIOSurfacePropertiesKey,
378 io_surface_properties);
380 status = VDADecoderCreate(config_info,
382 (VDADecoderOutputCallback *)ff_vda_output_callback,
390 CFRelease(config_info);
391 CFRelease(cv_pix_fmt);
392 CFRelease(io_surface_properties);
393 CFRelease(buffer_attributes);
395 if (status != kVDADecoderNoErr) {
396 av_log(avctx, AV_LOG_ERROR, "Cannot initialize VDA %d\n", status);
400 case kVDADecoderHardwareNotSupportedErr:
401 case kVDADecoderFormatNotSupportedErr:
402 return AVERROR(ENOSYS);
403 case kVDADecoderConfigurationError:
404 return AVERROR(EINVAL);
405 case kVDADecoderDecoderFailedErr:
406 return AVERROR_INVALIDDATA;
407 case kVDADecoderNoErr:
410 return AVERROR_UNKNOWN;
414 AVHWAccel ff_h264_vda_hwaccel = {
416 .type = AVMEDIA_TYPE_VIDEO,
417 .id = AV_CODEC_ID_H264,
418 .pix_fmt = AV_PIX_FMT_VDA,
419 .alloc_frame = ff_videotoolbox_alloc_frame,
420 .start_frame = ff_videotoolbox_h264_start_frame,
421 .decode_slice = ff_videotoolbox_h264_decode_slice,
422 .end_frame = vda_h264_end_frame,
423 .uninit = ff_videotoolbox_uninit,
424 .priv_data_size = sizeof(VTContext),