annotate ffmpeg/libavcodec/vda_h264_dec.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents 6840f77b83aa
children
rev   line source
yading@10 1 /*
yading@10 2 * Copyright (c) 2012, Xidorn Quan
yading@10 3 *
yading@10 4 * This file is part of FFmpeg.
yading@10 5 *
yading@10 6 * FFmpeg is free software; you can redistribute it and/or
yading@10 7 * modify it under the terms of the GNU Lesser General Public
yading@10 8 * License as published by the Free Software Foundation; either
yading@10 9 * version 2.1 of the License, or (at your option) any later version.
yading@10 10 *
yading@10 11 * FFmpeg is distributed in the hope that it will be useful,
yading@10 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@10 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@10 14 * Lesser General Public License for more details.
yading@10 15 *
yading@10 16 * You should have received a copy of the GNU Lesser General Public
yading@10 17 * License along with FFmpeg; if not, write to the Free Software
yading@10 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@10 19 */
yading@10 20
yading@10 21 /**
yading@10 22 * @file
yading@10 23 * H.264 decoder via VDA
yading@10 24 * @author Xidorn Quan <quanxunzhen@gmail.com>
yading@10 25 */
yading@10 26
yading@10 27 #include <string.h>
yading@10 28 #include <CoreFoundation/CoreFoundation.h>
yading@10 29
yading@10 30 #include "vda.h"
yading@10 31 #include "h264.h"
yading@10 32 #include "avcodec.h"
yading@10 33
yading@10 34 #ifndef kCFCoreFoundationVersionNumber10_7
yading@10 35 #define kCFCoreFoundationVersionNumber10_7 635.00
yading@10 36 #endif
yading@10 37
yading@10 38 extern AVCodec ff_h264_decoder, ff_h264_vda_decoder;
yading@10 39
yading@10 40 static const enum AVPixelFormat vda_pixfmts_prior_10_7[] = {
yading@10 41 AV_PIX_FMT_UYVY422,
yading@10 42 AV_PIX_FMT_YUV420P,
yading@10 43 AV_PIX_FMT_NONE
yading@10 44 };
yading@10 45
yading@10 46 static const enum AVPixelFormat vda_pixfmts[] = {
yading@10 47 AV_PIX_FMT_UYVY422,
yading@10 48 AV_PIX_FMT_YUYV422,
yading@10 49 AV_PIX_FMT_NV12,
yading@10 50 AV_PIX_FMT_YUV420P,
yading@10 51 AV_PIX_FMT_NONE
yading@10 52 };
yading@10 53
yading@10 54 typedef struct {
yading@10 55 H264Context h264ctx;
yading@10 56 int h264_initialized;
yading@10 57 struct vda_context vda_ctx;
yading@10 58 enum AVPixelFormat pix_fmt;
yading@10 59 } VDADecoderContext;
yading@10 60
yading@10 61 static enum AVPixelFormat get_format(struct AVCodecContext *avctx,
yading@10 62 const enum AVPixelFormat *fmt)
yading@10 63 {
yading@10 64 return AV_PIX_FMT_VDA_VLD;
yading@10 65 }
yading@10 66
yading@10 67 typedef struct {
yading@10 68 CVPixelBufferRef cv_buffer;
yading@10 69 } VDABufferContext;
yading@10 70
yading@10 71 static void release_buffer(void *opaque, uint8_t *data)
yading@10 72 {
yading@10 73 VDABufferContext *context = opaque;
yading@10 74 CVPixelBufferUnlockBaseAddress(context->cv_buffer, 0);
yading@10 75 CVPixelBufferRelease(context->cv_buffer);
yading@10 76 av_free(context);
yading@10 77 }
yading@10 78
yading@10 79 static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flag)
yading@10 80 {
yading@10 81 VDABufferContext *context = av_mallocz(sizeof(VDABufferContext));
yading@10 82 AVBufferRef *buffer = av_buffer_create(NULL, 0, release_buffer, context, 0);
yading@10 83 if (!context || !buffer) {
yading@10 84 av_free(context);
yading@10 85 return AVERROR(ENOMEM);
yading@10 86 }
yading@10 87
yading@10 88 pic->buf[0] = buffer;
yading@10 89 pic->data[0] = (void *)1;
yading@10 90 return 0;
yading@10 91 }
yading@10 92
yading@10 93 static int vdadec_decode(AVCodecContext *avctx,
yading@10 94 void *data, int *got_frame, AVPacket *avpkt)
yading@10 95 {
yading@10 96 VDADecoderContext *ctx = avctx->priv_data;
yading@10 97 AVFrame *pic = data;
yading@10 98 int ret;
yading@10 99
yading@10 100 ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt);
yading@10 101 if (*got_frame) {
yading@10 102 AVBufferRef *buffer = pic->buf[0];
yading@10 103 VDABufferContext *context = av_buffer_get_opaque(buffer);
yading@10 104 CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
yading@10 105 CVPixelBufferLockBaseAddress(cv_buffer, 0);
yading@10 106 context->cv_buffer = cv_buffer;
yading@10 107 pic->format = ctx->pix_fmt;
yading@10 108 if (CVPixelBufferIsPlanar(cv_buffer)) {
yading@10 109 int i, count = CVPixelBufferGetPlaneCount(cv_buffer);
yading@10 110 av_assert0(count < 4);
yading@10 111 for (i = 0; i < count; i++) {
yading@10 112 pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i);
yading@10 113 pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i);
yading@10 114 }
yading@10 115 } else {
yading@10 116 pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer);
yading@10 117 pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer);
yading@10 118 }
yading@10 119 }
yading@10 120 avctx->pix_fmt = ctx->pix_fmt;
yading@10 121
yading@10 122 return ret;
yading@10 123 }
yading@10 124
yading@10 125 static av_cold int vdadec_close(AVCodecContext *avctx)
yading@10 126 {
yading@10 127 VDADecoderContext *ctx = avctx->priv_data;
yading@10 128 /* release buffers and decoder */
yading@10 129 ff_vda_destroy_decoder(&ctx->vda_ctx);
yading@10 130 /* close H.264 decoder */
yading@10 131 if (ctx->h264_initialized)
yading@10 132 ff_h264_decoder.close(avctx);
yading@10 133 return 0;
yading@10 134 }
yading@10 135
yading@10 136 static av_cold int check_format(AVCodecContext *avctx)
yading@10 137 {
yading@10 138 AVCodecParserContext *parser;
yading@10 139 uint8_t *pout;
yading@10 140 int psize;
yading@10 141 int index;
yading@10 142 H264Context *h;
yading@10 143 int ret = -1;
yading@10 144
yading@10 145 /* init parser & parse file */
yading@10 146 parser = av_parser_init(avctx->codec->id);
yading@10 147 if (!parser) {
yading@10 148 av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 parser.\n");
yading@10 149 goto final;
yading@10 150 }
yading@10 151 parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
yading@10 152 index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0, 0, 0, 0);
yading@10 153 if (index < 0) {
yading@10 154 av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");
yading@10 155 goto release_parser;
yading@10 156 }
yading@10 157
yading@10 158 /* check if support */
yading@10 159 h = parser->priv_data;
yading@10 160 switch (h->sps.bit_depth_luma) {
yading@10 161 case 8:
yading@10 162 if (!CHROMA444(h) && !CHROMA422(h)) {
yading@10 163 // only this will H.264 decoder switch to hwaccel
yading@10 164 ret = 0;
yading@10 165 break;
yading@10 166 }
yading@10 167 default:
yading@10 168 av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
yading@10 169 }
yading@10 170
yading@10 171 release_parser:
yading@10 172 av_parser_close(parser);
yading@10 173
yading@10 174 final:
yading@10 175 return ret;
yading@10 176 }
yading@10 177
yading@10 178 static av_cold int vdadec_init(AVCodecContext *avctx)
yading@10 179 {
yading@10 180 VDADecoderContext *ctx = avctx->priv_data;
yading@10 181 struct vda_context *vda_ctx = &ctx->vda_ctx;
yading@10 182 OSStatus status;
yading@10 183 int ret;
yading@10 184
yading@10 185 ctx->h264_initialized = 0;
yading@10 186
yading@10 187 /* init pix_fmts of codec */
yading@10 188 if (!ff_h264_vda_decoder.pix_fmts) {
yading@10 189 if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7)
yading@10 190 ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7;
yading@10 191 else
yading@10 192 ff_h264_vda_decoder.pix_fmts = vda_pixfmts;
yading@10 193 }
yading@10 194
yading@10 195 /* check if VDA supports this file */
yading@10 196 if (check_format(avctx) < 0)
yading@10 197 goto failed;
yading@10 198
yading@10 199 /* init vda */
yading@10 200 memset(vda_ctx, 0, sizeof(struct vda_context));
yading@10 201 vda_ctx->width = avctx->width;
yading@10 202 vda_ctx->height = avctx->height;
yading@10 203 vda_ctx->format = 'avc1';
yading@10 204 vda_ctx->use_sync_decoding = 1;
yading@10 205 ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
yading@10 206 switch (ctx->pix_fmt) {
yading@10 207 case AV_PIX_FMT_UYVY422:
yading@10 208 vda_ctx->cv_pix_fmt_type = '2vuy';
yading@10 209 break;
yading@10 210 case AV_PIX_FMT_YUYV422:
yading@10 211 vda_ctx->cv_pix_fmt_type = 'yuvs';
yading@10 212 break;
yading@10 213 case AV_PIX_FMT_NV12:
yading@10 214 vda_ctx->cv_pix_fmt_type = '420v';
yading@10 215 break;
yading@10 216 case AV_PIX_FMT_YUV420P:
yading@10 217 vda_ctx->cv_pix_fmt_type = 'y420';
yading@10 218 break;
yading@10 219 default:
yading@10 220 av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt);
yading@10 221 goto failed;
yading@10 222 }
yading@10 223 status = ff_vda_create_decoder(vda_ctx,
yading@10 224 avctx->extradata, avctx->extradata_size);
yading@10 225 if (status != kVDADecoderNoErr) {
yading@10 226 av_log(avctx, AV_LOG_ERROR,
yading@10 227 "Failed to init VDA decoder: %d.\n", status);
yading@10 228 goto failed;
yading@10 229 }
yading@10 230 avctx->hwaccel_context = vda_ctx;
yading@10 231
yading@10 232 /* changes callback functions */
yading@10 233 avctx->get_format = get_format;
yading@10 234 avctx->get_buffer2 = get_buffer2;
yading@10 235 #if FF_API_GET_BUFFER
yading@10 236 // force the old get_buffer to be empty
yading@10 237 avctx->get_buffer = NULL;
yading@10 238 #endif
yading@10 239
yading@10 240 /* init H.264 decoder */
yading@10 241 ret = ff_h264_decoder.init(avctx);
yading@10 242 if (ret < 0) {
yading@10 243 av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
yading@10 244 goto failed;
yading@10 245 }
yading@10 246 ctx->h264_initialized = 1;
yading@10 247
yading@10 248 return 0;
yading@10 249
yading@10 250 failed:
yading@10 251 vdadec_close(avctx);
yading@10 252 return -1;
yading@10 253 }
yading@10 254
yading@10 255 static void vdadec_flush(AVCodecContext *avctx)
yading@10 256 {
yading@10 257 return ff_h264_decoder.flush(avctx);
yading@10 258 }
yading@10 259
yading@10 260 AVCodec ff_h264_vda_decoder = {
yading@10 261 .name = "h264_vda",
yading@10 262 .type = AVMEDIA_TYPE_VIDEO,
yading@10 263 .id = AV_CODEC_ID_H264,
yading@10 264 .priv_data_size = sizeof(VDADecoderContext),
yading@10 265 .init = vdadec_init,
yading@10 266 .close = vdadec_close,
yading@10 267 .decode = vdadec_decode,
yading@10 268 .capabilities = CODEC_CAP_DELAY,
yading@10 269 .flush = vdadec_flush,
yading@10 270 .long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"),
yading@10 271 };