PageRenderTime 36ms CodeModel.GetById 11ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/libavcodec/vda_h264.c

http://github.com/FFmpeg/FFmpeg
C | 425 lines | 318 code | 81 blank | 26 comment | 33 complexity | 6716502f9f992b504c69f8cf6f9b26d4 MD5 | raw file
  1/*
  2 * VDA H264 HW acceleration.
  3 *
  4 * copyright (c) 2011 Sebastien Zwickert
  5 *
  6 * This file is part of FFmpeg.
  7 *
  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.
 12 *
 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.
 17 *
 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
 21 */
 22
 23#include <CoreFoundation/CFDictionary.h>
 24#include <CoreFoundation/CFNumber.h>
 25#include <CoreFoundation/CFData.h>
 26
 27#include "vda.h"
 28#include "libavutil/avutil.h"
 29#include "h264dec.h"
 30
 31struct vda_buffer {
 32    CVPixelBufferRef cv_buffer;
 33};
 34#include "internal.h"
 35#include "vda_vt_internal.h"
 36
 37/* Decoder callback that adds the vda frame to the queue in display order. */
 38static void vda_decoder_callback(void *vda_hw_ctx,
 39                                 CFDictionaryRef user_info,
 40                                 OSStatus status,
 41                                 uint32_t infoFlags,
 42                                 CVImageBufferRef image_buffer)
 43{
 44    struct vda_context *vda_ctx = vda_hw_ctx;
 45
 46    if (infoFlags & kVDADecodeInfo_FrameDropped)
 47        vda_ctx->cv_buffer = NULL;
 48
 49    if (!image_buffer)
 50        return;
 51
 52    if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer))
 53        return;
 54
 55    vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer);
 56}
 57
 58static int vda_sync_decode(VTContext *ctx, struct vda_context *vda_ctx)
 59{
 60    OSStatus status;
 61    CFDataRef coded_frame;
 62    uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames
 63
 64    coded_frame = CFDataCreate(kCFAllocatorDefault,
 65                               ctx->bitstream,
 66                               ctx->bitstream_size);
 67
 68    status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL);
 69
 70    if (kVDADecoderNoErr == status)
 71        status = VDADecoderFlush(vda_ctx->decoder, flush_flags);
 72
 73    CFRelease(coded_frame);
 74
 75    return status;
 76}
 77
 78
 79static int vda_old_h264_start_frame(AVCodecContext *avctx,
 80                                av_unused const uint8_t *buffer,
 81                                av_unused uint32_t size)
 82{
 83    VTContext *vda = avctx->internal->hwaccel_priv_data;
 84    struct vda_context *vda_ctx = avctx->hwaccel_context;
 85
 86    if (!vda_ctx->decoder)
 87        return -1;
 88
 89    vda->bitstream_size = 0;
 90
 91    return 0;
 92}
 93
 94static int vda_old_h264_decode_slice(AVCodecContext *avctx,
 95                                 const uint8_t *buffer,
 96                                 uint32_t size)
 97{
 98    VTContext *vda              = avctx->internal->hwaccel_priv_data;
 99    struct vda_context *vda_ctx = avctx->hwaccel_context;
100    void *tmp;
101
102    if (!vda_ctx->decoder)
103        return -1;
104
105    tmp = av_fast_realloc(vda->bitstream,
106                          &vda->allocated_size,
107                          vda->bitstream_size + size + 4);
108    if (!tmp)
109        return AVERROR(ENOMEM);
110
111    vda->bitstream = tmp;
112
113    AV_WB32(vda->bitstream + vda->bitstream_size, size);
114    memcpy(vda->bitstream + vda->bitstream_size + 4, buffer, size);
115
116    vda->bitstream_size += size + 4;
117
118    return 0;
119}
120
121static void vda_h264_release_buffer(void *opaque, uint8_t *data)
122{
123    struct vda_buffer *context = opaque;
124    CVPixelBufferRelease(context->cv_buffer);
125    av_free(context);
126}
127
128static int vda_old_h264_end_frame(AVCodecContext *avctx)
129{
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;
135    AVBufferRef *buffer;
136    int status;
137
138    if (!vda_ctx->decoder || !vda->bitstream)
139        return -1;
140
141    status = vda_sync_decode(vda, vda_ctx);
142    frame->data[3] = (void*)vda_ctx->cv_buffer;
143
144    if (status)
145        av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
146
147    if (!vda_ctx->use_ref_buffer || status)
148        return status;
149
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);
154        av_free(context);
155        return -1;
156    }
157
158    context->cv_buffer = vda_ctx->cv_buffer;
159    frame->buf[3] = buffer;
160
161    return status;
162}
163
164int ff_vda_create_decoder(struct vda_context *vda_ctx,
165                          uint8_t *extradata,
166                          int extradata_size)
167{
168    OSStatus status;
169    CFNumberRef height;
170    CFNumberRef width;
171    CFNumberRef format;
172    CFDataRef avc_data;
173    CFMutableDictionaryRef config_info;
174    CFMutableDictionaryRef buffer_attributes;
175    CFMutableDictionaryRef io_surface_properties;
176    CFNumberRef cv_pix_fmt;
177
178    vda_ctx->priv_bitstream = NULL;
179    vda_ctx->priv_allocated_size = 0;
180
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;
186
187        if (!(rw_extradata = av_malloc(extradata_size)))
188            return AVERROR(ENOMEM);
189
190        memcpy(rw_extradata, extradata, extradata_size);
191
192        rw_extradata[4] |= 0x03;
193
194        avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size);
195
196        av_freep(&rw_extradata);
197    } else {
198        avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size);
199    }
200
201    config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
202                                            4,
203                                            &kCFTypeDictionaryKeyCallBacks,
204                                            &kCFTypeDictionaryValueCallBacks);
205
206    height   = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height);
207    width    = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width);
208    format   = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format);
209
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);
214
215    buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
216                                                  2,
217                                                  &kCFTypeDictionaryKeyCallBacks,
218                                                  &kCFTypeDictionaryValueCallBacks);
219    io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
220                                                      0,
221                                                      &kCFTypeDictionaryKeyCallBacks,
222                                                      &kCFTypeDictionaryValueCallBacks);
223    cv_pix_fmt  = CFNumberCreate(kCFAllocatorDefault,
224                                 kCFNumberSInt32Type,
225                                 &vda_ctx->cv_pix_fmt_type);
226    CFDictionarySetValue(buffer_attributes,
227                         kCVPixelBufferPixelFormatTypeKey,
228                         cv_pix_fmt);
229    CFDictionarySetValue(buffer_attributes,
230                         kCVPixelBufferIOSurfacePropertiesKey,
231                         io_surface_properties);
232
233    status = VDADecoderCreate(config_info,
234                              buffer_attributes,
235                              (VDADecoderOutputCallback *)vda_decoder_callback,
236                              vda_ctx,
237                              &vda_ctx->decoder);
238
239    CFRelease(height);
240    CFRelease(width);
241    CFRelease(format);
242    CFRelease(avc_data);
243    CFRelease(config_info);
244    CFRelease(io_surface_properties);
245    CFRelease(cv_pix_fmt);
246    CFRelease(buffer_attributes);
247
248    return status;
249}
250
251int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
252{
253    OSStatus status = kVDADecoderNoErr;
254
255    if (vda_ctx->decoder)
256        status = VDADecoderDestroy(vda_ctx->decoder);
257
258    return status;
259}
260
261AVHWAccel ff_h264_vda_old_hwaccel = {
262    .name           = "h264_vda",
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),
271};
272
273void ff_vda_output_callback(void *opaque,
274                            CFDictionaryRef user_info,
275                            OSStatus status,
276                            uint32_t infoFlags,
277                            CVImageBufferRef image_buffer)
278{
279    AVCodecContext *ctx = opaque;
280    VTContext *vda = ctx->internal->hwaccel_priv_data;
281
282
283    if (vda->frame) {
284        CVPixelBufferRelease(vda->frame);
285        vda->frame = NULL;
286    }
287
288    if (!image_buffer)
289        return;
290
291    vda->frame = CVPixelBufferRetain(image_buffer);
292}
293
294static int vda_h264_end_frame(AVCodecContext *avctx)
295{
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;
302    OSStatus status;
303
304    if (!vda->bitstream_size)
305        return AVERROR_INVALIDDATA;
306
307
308    coded_frame = CFDataCreate(kCFAllocatorDefault,
309                               vda->bitstream,
310                               vda->bitstream_size);
311
312    status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL);
313
314    if (status == kVDADecoderNoErr)
315        status = VDADecoderFlush(vda_ctx->decoder, flush_flags);
316
317    CFRelease(coded_frame);
318
319    if (!vda->frame)
320        return AVERROR_UNKNOWN;
321
322    if (status != kVDADecoderNoErr) {
323        av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
324        return AVERROR_UNKNOWN;
325    }
326
327    return ff_videotoolbox_buffer_create(vda, frame);
328}
329
330int ff_vda_default_init(AVCodecContext *avctx)
331{
332    AVVDAContext *vda_ctx = avctx->hwaccel_context;
333    OSStatus status = kVDADecoderNoErr;
334    CFNumberRef height;
335    CFNumberRef width;
336    CFNumberRef format;
337    CFDataRef avc_data;
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;
343
344    // kCVPixelFormatType_420YpCbCr8Planar;
345
346    avc_data = ff_videotoolbox_avcc_extradata_create(avctx);
347
348    config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
349                                            4,
350                                            &kCFTypeDictionaryKeyCallBacks,
351                                            &kCFTypeDictionaryValueCallBacks);
352
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);
360
361    buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
362                                                  2,
363                                                  &kCFTypeDictionaryKeyCallBacks,
364                                                  &kCFTypeDictionaryValueCallBacks);
365    io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
366                                                      0,
367                                                      &kCFTypeDictionaryKeyCallBacks,
368                                                      &kCFTypeDictionaryValueCallBacks);
369    cv_pix_fmt      = CFNumberCreate(kCFAllocatorDefault,
370                                     kCFNumberSInt32Type,
371                                     &pix_fmt);
372
373    CFDictionarySetValue(buffer_attributes,
374                         kCVPixelBufferPixelFormatTypeKey,
375                         cv_pix_fmt);
376    CFDictionarySetValue(buffer_attributes,
377                         kCVPixelBufferIOSurfacePropertiesKey,
378                         io_surface_properties);
379
380    status = VDADecoderCreate(config_info,
381                              buffer_attributes,
382                              (VDADecoderOutputCallback *)ff_vda_output_callback,
383                              avctx,
384                              &vda_ctx->decoder);
385
386    CFRelease(format);
387    CFRelease(height);
388    CFRelease(width);
389    CFRelease(avc_data);
390    CFRelease(config_info);
391    CFRelease(cv_pix_fmt);
392    CFRelease(io_surface_properties);
393    CFRelease(buffer_attributes);
394
395    if (status != kVDADecoderNoErr) {
396        av_log(avctx, AV_LOG_ERROR, "Cannot initialize VDA %d\n", status);
397    }
398
399    switch (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:
408        return 0;
409    default:
410        return AVERROR_UNKNOWN;
411    }
412}
413
414AVHWAccel ff_h264_vda_hwaccel = {
415    .name           = "h264_vda",
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),
425};