00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00027 #include <string.h>
00028 #include <CoreFoundation/CoreFoundation.h>
00029
00030 #include "vda.h"
00031 #include "h264.h"
00032 #include "avcodec.h"
00033
00034 #ifndef kCFCoreFoundationVersionNumber10_7
00035 #define kCFCoreFoundationVersionNumber10_7 635.00
00036 #endif
00037
00038 extern AVCodec ff_h264_decoder, ff_h264_vda_decoder;
00039
00040 static const enum PixelFormat vda_pixfmts_prior_10_7[] = {
00041 PIX_FMT_UYVY422,
00042 PIX_FMT_YUV420P,
00043 PIX_FMT_NONE
00044 };
00045
00046 static const enum PixelFormat vda_pixfmts[] = {
00047 PIX_FMT_UYVY422,
00048 PIX_FMT_YUYV422,
00049 PIX_FMT_NV12,
00050 PIX_FMT_YUV420P,
00051 PIX_FMT_NONE
00052 };
00053
00054 typedef struct {
00055 H264Context h264ctx;
00056 int h264_initialized;
00057 struct vda_context vda_ctx;
00058 enum PixelFormat pix_fmt;
00059 } VDADecoderContext;
00060
00061 static enum PixelFormat get_format(struct AVCodecContext *avctx,
00062 const enum PixelFormat *fmt)
00063 {
00064 return PIX_FMT_VDA_VLD;
00065 }
00066
00067 static int get_buffer(AVCodecContext *avctx, AVFrame *pic)
00068 {
00069 pic->type = FF_BUFFER_TYPE_USER;
00070 pic->data[0] = (void *)1;
00071 return 0;
00072 }
00073
00074 static void release_buffer(AVCodecContext *avctx, AVFrame *pic)
00075 {
00076 int i;
00077
00078 CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
00079 CVPixelBufferUnlockBaseAddress(cv_buffer, 0);
00080 CVPixelBufferRelease(cv_buffer);
00081
00082 for (i = 0; i < 4; i++)
00083 pic->data[i] = NULL;
00084 }
00085
00086 static int vdadec_decode(AVCodecContext *avctx,
00087 void *data, int *data_size, AVPacket *avpkt)
00088 {
00089 VDADecoderContext *ctx = avctx->priv_data;
00090 AVFrame *pic = data;
00091 int ret;
00092
00093 ret = ff_h264_decoder.decode(avctx, data, data_size, avpkt);
00094 if (*data_size) {
00095 CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
00096 CVPixelBufferLockBaseAddress(cv_buffer, 0);
00097 pic->format = ctx->pix_fmt;
00098 if (CVPixelBufferIsPlanar(cv_buffer)) {
00099 int i, count = CVPixelBufferGetPlaneCount(cv_buffer);
00100 av_assert0(count < 4);
00101 for (i = 0; i < count; i++) {
00102 pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i);
00103 pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i);
00104 }
00105 } else {
00106 pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer);
00107 pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer);
00108 }
00109 }
00110 avctx->pix_fmt = ctx->pix_fmt;
00111
00112 return ret;
00113 }
00114
00115 static av_cold int vdadec_close(AVCodecContext *avctx)
00116 {
00117 VDADecoderContext *ctx = avctx->priv_data;
00118
00119 ff_vda_destroy_decoder(&ctx->vda_ctx);
00120
00121 if (ctx->h264_initialized)
00122 ff_h264_decoder.close(avctx);
00123 return 0;
00124 }
00125
00126 static av_cold int check_format(AVCodecContext *avctx)
00127 {
00128 AVCodecParserContext *parser;
00129 uint8_t *pout;
00130 int psize;
00131 int index;
00132 H264Context *h;
00133 int ret = -1;
00134
00135
00136 parser = av_parser_init(avctx->codec->id);
00137 if (!parser) {
00138 av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 parser.\n");
00139 goto final;
00140 }
00141 parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
00142 index = av_parser_parse2(parser, avctx, &pout, &psize, NULL, 0, 0, 0, 0);
00143 if (index < 0) {
00144 av_log(avctx, AV_LOG_ERROR, "Failed to parse this file.\n");
00145 goto release_parser;
00146 }
00147
00148
00149 h = parser->priv_data;
00150 switch (h->sps.bit_depth_luma) {
00151 case 8:
00152 if (!CHROMA444 && !CHROMA422) {
00153
00154 ret = 0;
00155 break;
00156 }
00157 default:
00158 av_log(avctx, AV_LOG_ERROR, "Unsupported file.\n");
00159 }
00160
00161 release_parser:
00162 av_parser_close(parser);
00163
00164 final:
00165 return ret;
00166 }
00167
00168 static av_cold int vdadec_init(AVCodecContext *avctx)
00169 {
00170 VDADecoderContext *ctx = avctx->priv_data;
00171 struct vda_context *vda_ctx = &ctx->vda_ctx;
00172 OSStatus status;
00173 int ret;
00174
00175 ctx->h264_initialized = 0;
00176
00177
00178 if (!ff_h264_vda_decoder.pix_fmts) {
00179 if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7)
00180 ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7;
00181 else
00182 ff_h264_vda_decoder.pix_fmts = vda_pixfmts;
00183 }
00184
00185
00186 if (check_format(avctx) < 0)
00187 goto failed;
00188
00189
00190 memset(vda_ctx, 0, sizeof(struct vda_context));
00191 vda_ctx->width = avctx->width;
00192 vda_ctx->height = avctx->height;
00193 vda_ctx->format = 'avc1';
00194 vda_ctx->use_sync_decoding = 1;
00195 ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
00196 switch (ctx->pix_fmt) {
00197 case PIX_FMT_UYVY422:
00198 vda_ctx->cv_pix_fmt_type = '2vuy';
00199 break;
00200 case PIX_FMT_YUYV422:
00201 vda_ctx->cv_pix_fmt_type = 'yuvs';
00202 break;
00203 case PIX_FMT_NV12:
00204 vda_ctx->cv_pix_fmt_type = '420v';
00205 break;
00206 case PIX_FMT_YUV420P:
00207 vda_ctx->cv_pix_fmt_type = 'y420';
00208 break;
00209 default:
00210 av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt);
00211 goto failed;
00212 }
00213 status = ff_vda_create_decoder(vda_ctx,
00214 avctx->extradata, avctx->extradata_size);
00215 if (status != kVDADecoderNoErr) {
00216 av_log(avctx, AV_LOG_ERROR,
00217 "Failed to init VDA decoder: %d.\n", status);
00218 goto failed;
00219 }
00220 avctx->hwaccel_context = vda_ctx;
00221
00222
00223 avctx->get_format = get_format;
00224 avctx->get_buffer = get_buffer;
00225 avctx->release_buffer = release_buffer;
00226
00227
00228 ret = ff_h264_decoder.init(avctx);
00229 if (ret < 0) {
00230 av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
00231 goto failed;
00232 }
00233 ctx->h264_initialized = 1;
00234
00235 return 0;
00236
00237 failed:
00238 vdadec_close(avctx);
00239 return -1;
00240 }
00241
00242 static void vdadec_flush(AVCodecContext *avctx)
00243 {
00244 return ff_h264_decoder.flush(avctx);
00245 }
00246
00247 AVCodec ff_h264_vda_decoder = {
00248 .name = "h264_vda",
00249 .type = AVMEDIA_TYPE_VIDEO,
00250 .id = AV_CODEC_ID_H264,
00251 .priv_data_size = sizeof(VDADecoderContext),
00252 .init = vdadec_init,
00253 .close = vdadec_close,
00254 .decode = vdadec_decode,
00255 .capabilities = CODEC_CAP_DELAY,
00256 .flush = vdadec_flush,
00257 .long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"),
00258 };