diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-08-26 15:10:18 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-08-26 15:10:18 +0100 |
| commit | 150c9823e71a161e97003849cf8b2f55b21520bd (patch) | |
| tree | 3559c840cf403d1386708b2591d58f928c7b160d /ffmpeg1/libavcodec/vda_h264.c | |
| parent | b4b1e2630c95d5e6014463f7608d59dc2322a3b8 (diff) | |
adding ffmpeg specific version
Diffstat (limited to 'ffmpeg1/libavcodec/vda_h264.c')
| -rw-r--r-- | ffmpeg1/libavcodec/vda_h264.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/ffmpeg1/libavcodec/vda_h264.c b/ffmpeg1/libavcodec/vda_h264.c new file mode 100644 index 0000000..d0237c2 --- /dev/null +++ b/ffmpeg1/libavcodec/vda_h264.c @@ -0,0 +1,237 @@ +/* + * VDA H264 HW acceleration. + * + * copyright (c) 2011 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <CoreFoundation/CFDictionary.h> +#include <CoreFoundation/CFNumber.h> +#include <CoreFoundation/CFData.h> + +#include "vda.h" +#include "libavutil/avutil.h" +#include "h264.h" + + +/* Decoder callback that adds the vda frame to the queue in display order. */ +static void vda_decoder_callback (void *vda_hw_ctx, + CFDictionaryRef user_info, + OSStatus status, + uint32_t infoFlags, + CVImageBufferRef image_buffer) +{ + struct vda_context *vda_ctx = vda_hw_ctx; + + if (!image_buffer) + return; + + if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer)) + return; + + vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer); +} + +static int 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->priv_bitstream, + vda_ctx->priv_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 status; +} + + +static int vda_h264_start_frame(AVCodecContext *avctx, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + struct vda_context *vda_ctx = avctx->hwaccel_context; + + if (!vda_ctx->decoder) + return -1; + + vda_ctx->priv_bitstream_size = 0; + + return 0; +} + +static int vda_h264_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + struct vda_context *vda_ctx = avctx->hwaccel_context; + void *tmp; + + if (!vda_ctx->decoder) + return -1; + + tmp = av_fast_realloc(vda_ctx->priv_bitstream, + &vda_ctx->priv_allocated_size, + vda_ctx->priv_bitstream_size + size + 4); + if (!tmp) + return AVERROR(ENOMEM); + + vda_ctx->priv_bitstream = tmp; + + AV_WB32(vda_ctx->priv_bitstream + vda_ctx->priv_bitstream_size, size); + memcpy(vda_ctx->priv_bitstream + vda_ctx->priv_bitstream_size + 4, buffer, size); + + vda_ctx->priv_bitstream_size += size + 4; + + return 0; +} + +static int vda_h264_end_frame(AVCodecContext *avctx) +{ + H264Context *h = avctx->priv_data; + struct vda_context *vda_ctx = avctx->hwaccel_context; + AVFrame *frame = &h->cur_pic_ptr->f; + int status; + + if (!vda_ctx->decoder || !vda_ctx->priv_bitstream) + return -1; + + status = vda_sync_decode(vda_ctx); + frame->data[3] = (void*)vda_ctx->cv_buffer; + + if (status) + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); + + return status; +} + +int ff_vda_create_decoder(struct vda_context *vda_ctx, + uint8_t *extradata, + int extradata_size) +{ + OSStatus status; + CFNumberRef height; + CFNumberRef width; + CFNumberRef format; + CFDataRef avc_data; + CFMutableDictionaryRef config_info; + CFMutableDictionaryRef buffer_attributes; + CFMutableDictionaryRef io_surface_properties; + CFNumberRef cv_pix_fmt; + + vda_ctx->priv_bitstream = NULL; + vda_ctx->priv_allocated_size = 0; + + /* Each VCL NAL in the bitstream sent to the decoder + * is preceded by a 4 bytes length header. + * Change the avcC atom header if needed, to signal headers of 4 bytes. */ + if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) { + uint8_t *rw_extradata; + + if (!(rw_extradata = av_malloc(extradata_size))) + return AVERROR(ENOMEM); + + memcpy(rw_extradata, extradata, extradata_size); + + rw_extradata[4] |= 0x03; + + avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size); + + av_freep(&rw_extradata); + } else { + avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size); + } + + config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 4, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height); + width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width); + format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format); + + CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); + CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); + CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); + CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); + + buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, + 2, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt32Type, + &vda_ctx->cv_pix_fmt_type); + CFDictionarySetValue(buffer_attributes, + kCVPixelBufferPixelFormatTypeKey, + cv_pix_fmt); + CFDictionarySetValue(buffer_attributes, + kCVPixelBufferIOSurfacePropertiesKey, + io_surface_properties); + + status = VDADecoderCreate(config_info, + buffer_attributes, + vda_decoder_callback, + vda_ctx, + &vda_ctx->decoder); + + CFRelease(height); + CFRelease(width); + CFRelease(format); + CFRelease(avc_data); + CFRelease(config_info); + CFRelease(io_surface_properties); + CFRelease(cv_pix_fmt); + CFRelease(buffer_attributes); + + return status; +} + +int ff_vda_destroy_decoder(struct vda_context *vda_ctx) +{ + OSStatus status = kVDADecoderNoErr; + + if (vda_ctx->decoder) + status = VDADecoderDestroy(vda_ctx->decoder); + + av_freep(&vda_ctx->priv_bitstream); + + return status; +} + +AVHWAccel ff_h264_vda_hwaccel = { + .name = "h264_vda", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .pix_fmt = AV_PIX_FMT_VDA_VLD, + .start_frame = vda_h264_start_frame, + .decode_slice = vda_h264_decode_slice, + .end_frame = vda_h264_end_frame, +}; |
