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