2 * VDA H.264 hardware acceleration
4 * copyright (c) 2011 Sebastien Zwickert
6 * This file is part of Libav.
8 * Libav 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 * Libav 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 Libav; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <CoreFoundation/CFNumber.h>
24 #include <CoreFoundation/CFData.h>
25 #include <CoreFoundation/CFString.h>
27 #include "libavutil/avutil.h"
31 #include "vda_internal.h"
33 typedef struct VDAContext
{
34 // The current bitstream buffer.
37 // The current size of the bitstream.
40 // The reference size used for fast reallocation.
43 CVImageBufferRef frame
;
46 /* Decoder callback that adds the VDA frame to the queue in display order. */
47 static void vda_decoder_callback(void *vda_hw_ctx
,
48 CFDictionaryRef user_info
,
51 CVImageBufferRef image_buffer
)
53 struct vda_context
*vda_ctx
= vda_hw_ctx
;
58 if (vda_ctx
->cv_pix_fmt_type
!= CVPixelBufferGetPixelFormatType(image_buffer
))
61 vda_ctx
->cv_buffer
= CVPixelBufferRetain(image_buffer
);
64 static int vda_sync_decode(VDAContext
*ctx
, struct vda_context
*vda_ctx
)
67 CFDataRef coded_frame
;
68 uint32_t flush_flags
= 1 << 0; ///< kVDADecoderFlush_emitFrames
70 coded_frame
= CFDataCreate(kCFAllocatorDefault
,
74 status
= VDADecoderDecode(vda_ctx
->decoder
, 0, coded_frame
, NULL
);
76 if (kVDADecoderNoErr
== status
)
77 status
= VDADecoderFlush(vda_ctx
->decoder
, flush_flags
);
79 CFRelease(coded_frame
);
85 static int vda_old_h264_start_frame(AVCodecContext
*avctx
,
86 av_unused
const uint8_t *buffer
,
87 av_unused
uint32_t size
)
89 VDAContext
*vda
= avctx
->internal
->hwaccel_priv_data
;
90 struct vda_context
*vda_ctx
= avctx
->hwaccel_context
;
92 if (!vda_ctx
->decoder
)
95 vda
->bitstream_size
= 0;
100 static int vda_old_h264_decode_slice(AVCodecContext
*avctx
,
101 const uint8_t *buffer
,
104 VDAContext
*vda
= avctx
->internal
->hwaccel_priv_data
;
105 struct vda_context
*vda_ctx
= avctx
->hwaccel_context
;
108 if (!vda_ctx
->decoder
)
111 tmp
= av_fast_realloc(vda
->bitstream
,
112 &vda
->allocated_size
,
113 vda
->bitstream_size
+ size
+ 4);
115 return AVERROR(ENOMEM
);
117 vda
->bitstream
= tmp
;
119 AV_WB32(vda
->bitstream
+ vda
->bitstream_size
, size
);
120 memcpy(vda
->bitstream
+ vda
->bitstream_size
+ 4, buffer
, size
);
122 vda
->bitstream_size
+= size
+ 4;
127 static int vda_old_h264_end_frame(AVCodecContext
*avctx
)
129 H264Context
*h
= avctx
->priv_data
;
130 VDAContext
*vda
= avctx
->internal
->hwaccel_priv_data
;
131 struct vda_context
*vda_ctx
= avctx
->hwaccel_context
;
132 AVFrame
*frame
= h
->cur_pic_ptr
->f
;
135 if (!vda_ctx
->decoder
|| !vda
->bitstream
)
138 status
= vda_sync_decode(vda
, vda_ctx
);
139 frame
->data
[3] = (void*)vda_ctx
->cv_buffer
;
142 av_log(avctx
, AV_LOG_ERROR
, "Failed to decode frame (%d)\n", status
);
147 int ff_vda_create_decoder(struct vda_context
*vda_ctx
,
151 OSStatus status
= kVDADecoderNoErr
;
156 CFMutableDictionaryRef config_info
;
157 CFMutableDictionaryRef buffer_attributes
;
158 CFMutableDictionaryRef io_surface_properties
;
159 CFNumberRef cv_pix_fmt
;
161 /* Each VCL NAL in the bitstream sent to the decoder
162 * is preceded by a 4 bytes length header.
163 * Change the avcC atom header if needed, to signal headers of 4 bytes. */
164 if (extradata_size
>= 4 && (extradata
[4] & 0x03) != 0x03) {
165 uint8_t *rw_extradata
;
167 if (!(rw_extradata
= av_malloc(extradata_size
)))
168 return AVERROR(ENOMEM
);
170 memcpy(rw_extradata
, extradata
, extradata_size
);
172 rw_extradata
[4] |= 0x03;
174 avc_data
= CFDataCreate(kCFAllocatorDefault
, rw_extradata
, extradata_size
);
176 av_freep(&rw_extradata
);
178 avc_data
= CFDataCreate(kCFAllocatorDefault
, extradata
, extradata_size
);
181 config_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
183 &kCFTypeDictionaryKeyCallBacks
,
184 &kCFTypeDictionaryValueCallBacks
);
186 height
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &vda_ctx
->height
);
187 width
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &vda_ctx
->width
);
188 format
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &vda_ctx
->format
);
190 CFDictionarySetValue(config_info
, kVDADecoderConfiguration_Height
, height
);
191 CFDictionarySetValue(config_info
, kVDADecoderConfiguration_Width
, width
);
192 CFDictionarySetValue(config_info
, kVDADecoderConfiguration_SourceFormat
, format
);
193 CFDictionarySetValue(config_info
, kVDADecoderConfiguration_avcCData
, avc_data
);
195 buffer_attributes
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
197 &kCFTypeDictionaryKeyCallBacks
,
198 &kCFTypeDictionaryValueCallBacks
);
199 io_surface_properties
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
201 &kCFTypeDictionaryKeyCallBacks
,
202 &kCFTypeDictionaryValueCallBacks
);
203 cv_pix_fmt
= CFNumberCreate(kCFAllocatorDefault
,
205 &vda_ctx
->cv_pix_fmt_type
);
206 CFDictionarySetValue(buffer_attributes
,
207 kCVPixelBufferPixelFormatTypeKey
,
209 CFDictionarySetValue(buffer_attributes
,
210 kCVPixelBufferIOSurfacePropertiesKey
,
211 io_surface_properties
);
213 status
= VDADecoderCreate(config_info
,
215 (VDADecoderOutputCallback
*)vda_decoder_callback
,
223 CFRelease(config_info
);
224 CFRelease(io_surface_properties
);
225 CFRelease(cv_pix_fmt
);
226 CFRelease(buffer_attributes
);
231 int ff_vda_destroy_decoder(struct vda_context
*vda_ctx
)
233 OSStatus status
= kVDADecoderNoErr
;
235 if (vda_ctx
->decoder
)
236 status
= VDADecoderDestroy(vda_ctx
->decoder
);
241 static int vda_h264_uninit(AVCodecContext
*avctx
)
243 VDAContext
*vda
= avctx
->internal
->hwaccel_priv_data
;
244 av_freep(&vda
->bitstream
);
246 CVPixelBufferRelease(vda
->frame
);
250 const AVHWAccel ff_h264_vda_old_hwaccel
= {
252 .type
= AVMEDIA_TYPE_VIDEO
,
253 .id
= AV_CODEC_ID_H264
,
254 .pix_fmt
= AV_PIX_FMT_VDA_VLD
,
255 .start_frame
= vda_old_h264_start_frame
,
256 .decode_slice
= vda_old_h264_decode_slice
,
257 .end_frame
= vda_old_h264_end_frame
,
258 .uninit
= vda_h264_uninit
,
259 .priv_data_size
= sizeof(VDAContext
),
262 void ff_vda_output_callback(void *opaque
,
263 CFDictionaryRef user_info
,
266 CVImageBufferRef image_buffer
)
268 AVCodecContext
*ctx
= opaque
;
269 VDAContext
*vda
= ctx
->internal
->hwaccel_priv_data
;
273 CVPixelBufferRelease(vda
->frame
);
280 vda
->frame
= CVPixelBufferRetain(image_buffer
);
283 static int vda_h264_start_frame(AVCodecContext
*avctx
,
284 const uint8_t *buffer
,
287 VDAContext
*vda
= avctx
->internal
->hwaccel_priv_data
;
289 vda
->bitstream_size
= 0;
294 static int vda_h264_decode_slice(AVCodecContext
*avctx
,
295 const uint8_t *buffer
,
298 VDAContext
*vda
= avctx
->internal
->hwaccel_priv_data
;
301 tmp
= av_fast_realloc(vda
->bitstream
,
302 &vda
->allocated_size
,
303 vda
->bitstream_size
+ size
+ 4);
305 return AVERROR(ENOMEM
);
307 vda
->bitstream
= tmp
;
309 AV_WB32(vda
->bitstream
+ vda
->bitstream_size
, size
);
310 memcpy(vda
->bitstream
+ vda
->bitstream_size
+ 4, buffer
, size
);
312 vda
->bitstream_size
+= size
+ 4;
317 static void release_buffer(void *opaque
, uint8_t *data
)
319 CVImageBufferRef frame
= (CVImageBufferRef
)data
;
320 CVPixelBufferRelease(frame
);
323 static int vda_h264_end_frame(AVCodecContext
*avctx
)
325 H264Context
*h
= avctx
->priv_data
;
326 VDAContext
*vda
= avctx
->internal
->hwaccel_priv_data
;
327 AVVDAContext
*vda_ctx
= avctx
->hwaccel_context
;
328 AVFrame
*frame
= h
->cur_pic_ptr
->f
;
329 uint32_t flush_flags
= 1 << 0; ///< kVDADecoderFlush_emitFrames
330 CFDataRef coded_frame
;
333 if (!vda
->bitstream_size
)
334 return AVERROR_INVALIDDATA
;
337 coded_frame
= CFDataCreate(kCFAllocatorDefault
,
339 vda
->bitstream_size
);
341 status
= VDADecoderDecode(vda_ctx
->decoder
, 0, coded_frame
, NULL
);
343 if (status
== kVDADecoderNoErr
)
344 status
= VDADecoderFlush(vda_ctx
->decoder
, flush_flags
);
346 CFRelease(coded_frame
);
349 return AVERROR_UNKNOWN
;
351 if (status
!= kVDADecoderNoErr
) {
352 av_log(avctx
, AV_LOG_ERROR
, "Failed to decode frame (%d)\n", status
);
353 return AVERROR_UNKNOWN
;
356 av_buffer_unref(&frame
->buf
[0]);
358 frame
->buf
[0] = av_buffer_create((uint8_t*)vda
->frame
,
360 release_buffer
, NULL
,
361 AV_BUFFER_FLAG_READONLY
);
363 return AVERROR(ENOMEM
);
365 frame
->data
[3] = (uint8_t*)vda
->frame
;
371 int ff_vda_default_init(AVCodecContext
*avctx
)
373 AVVDAContext
*vda_ctx
= avctx
->hwaccel_context
;
374 OSStatus status
= kVDADecoderNoErr
;
379 CFMutableDictionaryRef config_info
;
380 CFMutableDictionaryRef buffer_attributes
;
381 CFMutableDictionaryRef io_surface_properties
;
382 CFNumberRef cv_pix_fmt
;
383 int32_t fmt
= 'avc1', pix_fmt
= vda_ctx
->cv_pix_fmt_type
;
385 // kCVPixelFormatType_420YpCbCr8Planar;
387 /* Each VCL NAL in the bitstream sent to the decoder
388 * is preceded by a 4 bytes length header.
389 * Change the avcC atom header if needed, to signal headers of 4 bytes. */
390 if (avctx
->extradata_size
>= 4 && (avctx
->extradata
[4] & 0x03) != 0x03) {
391 uint8_t *rw_extradata
;
393 if (!(rw_extradata
= av_malloc(avctx
->extradata_size
)))
394 return AVERROR(ENOMEM
);
396 memcpy(rw_extradata
, avctx
->extradata
, avctx
->extradata_size
);
398 rw_extradata
[4] |= 0x03;
400 avc_data
= CFDataCreate(kCFAllocatorDefault
, rw_extradata
, avctx
->extradata_size
);
402 av_freep(&rw_extradata
);
404 avc_data
= CFDataCreate(kCFAllocatorDefault
,
405 avctx
->extradata
, avctx
->extradata_size
);
408 config_info
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
410 &kCFTypeDictionaryKeyCallBacks
,
411 &kCFTypeDictionaryValueCallBacks
);
413 height
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &avctx
->height
);
414 width
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &avctx
->width
);
415 format
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberSInt32Type
, &fmt
);
416 CFDictionarySetValue(config_info
, kVDADecoderConfiguration_Height
, height
);
417 CFDictionarySetValue(config_info
, kVDADecoderConfiguration_Width
, width
);
418 CFDictionarySetValue(config_info
, kVDADecoderConfiguration_avcCData
, avc_data
);
419 CFDictionarySetValue(config_info
, kVDADecoderConfiguration_SourceFormat
, format
);
421 buffer_attributes
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
423 &kCFTypeDictionaryKeyCallBacks
,
424 &kCFTypeDictionaryValueCallBacks
);
425 io_surface_properties
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
427 &kCFTypeDictionaryKeyCallBacks
,
428 &kCFTypeDictionaryValueCallBacks
);
429 cv_pix_fmt
= CFNumberCreate(kCFAllocatorDefault
,
433 CFDictionarySetValue(buffer_attributes
,
434 kCVPixelBufferPixelFormatTypeKey
,
436 CFDictionarySetValue(buffer_attributes
,
437 kCVPixelBufferIOSurfacePropertiesKey
,
438 io_surface_properties
);
440 status
= VDADecoderCreate(config_info
,
442 (VDADecoderOutputCallback
*)ff_vda_output_callback
,
450 CFRelease(config_info
);
451 CFRelease(cv_pix_fmt
);
452 CFRelease(io_surface_properties
);
453 CFRelease(buffer_attributes
);
455 if (status
!= kVDADecoderNoErr
) {
456 av_log(avctx
, AV_LOG_ERROR
, "Cannot initialize VDA %d\n", status
);
460 case kVDADecoderHardwareNotSupportedErr
:
461 case kVDADecoderFormatNotSupportedErr
:
462 return AVERROR(ENOSYS
);
463 case kVDADecoderConfigurationError
:
464 return AVERROR(EINVAL
);
465 case kVDADecoderDecoderFailedErr
:
466 return AVERROR_INVALIDDATA
;
467 case kVDADecoderNoErr
:
470 return AVERROR_UNKNOWN
;
474 static int vda_h264_alloc_frame(AVCodecContext
*avctx
, AVFrame
*frame
)
476 frame
->width
= avctx
->width
;
477 frame
->height
= avctx
->height
;
478 frame
->format
= avctx
->pix_fmt
;
479 frame
->buf
[0] = av_buffer_alloc(1);
482 return AVERROR(ENOMEM
);
486 const AVHWAccel ff_h264_vda_hwaccel
= {
488 .type
= AVMEDIA_TYPE_VIDEO
,
489 .id
= AV_CODEC_ID_H264
,
490 .pix_fmt
= AV_PIX_FMT_VDA
,
491 .alloc_frame
= vda_h264_alloc_frame
,
492 .start_frame
= vda_h264_start_frame
,
493 .decode_slice
= vda_h264_decode_slice
,
494 .end_frame
= vda_h264_end_frame
,
495 .uninit
= vda_h264_uninit
,
496 .priv_data_size
= sizeof(VDAContext
),