FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vda_h264.c
Go to the documentation of this 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 "h264.h"
30 
31 struct vda_buffer {
32  CVPixelBufferRef cv_buffer;
33 };
34 
35 /* Decoder callback that adds the vda frame to the queue in display order. */
36 static void vda_decoder_callback(void *vda_hw_ctx,
37  CFDictionaryRef user_info,
38  OSStatus status,
39  uint32_t infoFlags,
40  CVImageBufferRef image_buffer)
41 {
42  struct vda_context *vda_ctx = vda_hw_ctx;
43 
44  if (infoFlags & kVDADecodeInfo_FrameDropped)
45  vda_ctx->cv_buffer = NULL;
46 
47  if (!image_buffer)
48  return;
49 
50  if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer))
51  return;
52 
53  vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer);
54 }
55 
56 static int vda_sync_decode(struct vda_context *vda_ctx)
57 {
58  OSStatus status;
59  CFDataRef coded_frame;
60  uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames
61 
62  coded_frame = CFDataCreate(kCFAllocatorDefault,
63  vda_ctx->priv_bitstream,
64  vda_ctx->priv_bitstream_size);
65 
66  status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL);
67 
68  if (kVDADecoderNoErr == status)
69  status = VDADecoderFlush(vda_ctx->decoder, flush_flags);
70 
71  CFRelease(coded_frame);
72 
73  return status;
74 }
75 
76 
78  av_unused const uint8_t *buffer,
79  av_unused uint32_t size)
80 {
81  struct vda_context *vda_ctx = avctx->hwaccel_context;
82 
83  if (!vda_ctx->decoder)
84  return -1;
85 
86  vda_ctx->priv_bitstream_size = 0;
87 
88  return 0;
89 }
90 
92  const uint8_t *buffer,
93  uint32_t size)
94 {
95  struct vda_context *vda_ctx = avctx->hwaccel_context;
96  void *tmp;
97 
98  if (!vda_ctx->decoder)
99  return -1;
100 
101  tmp = av_fast_realloc(vda_ctx->priv_bitstream,
102  &vda_ctx->priv_allocated_size,
103  vda_ctx->priv_bitstream_size + size + 4);
104  if (!tmp)
105  return AVERROR(ENOMEM);
106 
107  vda_ctx->priv_bitstream = tmp;
108 
109  AV_WB32(vda_ctx->priv_bitstream + vda_ctx->priv_bitstream_size, size);
110  memcpy(vda_ctx->priv_bitstream + vda_ctx->priv_bitstream_size + 4, buffer, size);
111 
112  vda_ctx->priv_bitstream_size += size + 4;
113 
114  return 0;
115 }
116 
117 static void vda_h264_release_buffer(void *opaque, uint8_t *data)
118 {
119  struct vda_buffer *context = opaque;
120  CVPixelBufferRelease(context->cv_buffer);
121  av_free(context);
122 }
123 
125 {
126  H264Context *h = avctx->priv_data;
127  struct vda_context *vda_ctx = avctx->hwaccel_context;
128  AVFrame *frame = &h->cur_pic_ptr->f;
129  struct vda_buffer *context;
131  int status;
132 
133  if (!vda_ctx->decoder || !vda_ctx->priv_bitstream)
134  return -1;
135 
136  status = vda_sync_decode(vda_ctx);
137  frame->data[3] = (void*)vda_ctx->cv_buffer;
138 
139  if (status)
140  av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
141 
142  if (!vda_ctx->use_ref_buffer || status)
143  return status;
144 
145  context = av_mallocz(sizeof(*context));
146  buffer = av_buffer_create(NULL, 0, vda_h264_release_buffer, context, 0);
147  if (!context || !buffer) {
148  CVPixelBufferRelease(vda_ctx->cv_buffer);
149  av_free(context);
150  return -1;
151  }
152 
153  context->cv_buffer = vda_ctx->cv_buffer;
154  frame->buf[3] = buffer;
155 
156  return status;
157 }
158 
159 int ff_vda_create_decoder(struct vda_context *vda_ctx,
160  uint8_t *extradata,
161  int extradata_size)
162 {
163  OSStatus status;
164  CFNumberRef height;
165  CFNumberRef width;
166  CFNumberRef format;
167  CFDataRef avc_data;
168  CFMutableDictionaryRef config_info;
169  CFMutableDictionaryRef buffer_attributes;
170  CFMutableDictionaryRef io_surface_properties;
171  CFNumberRef cv_pix_fmt;
172 
173  vda_ctx->priv_bitstream = NULL;
174  vda_ctx->priv_allocated_size = 0;
175 
176  /* Each VCL NAL in the bitstream sent to the decoder
177  * is preceded by a 4 bytes length header.
178  * Change the avcC atom header if needed, to signal headers of 4 bytes. */
179  if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) {
180  uint8_t *rw_extradata;
181 
182  if (!(rw_extradata = av_malloc(extradata_size)))
183  return AVERROR(ENOMEM);
184 
185  memcpy(rw_extradata, extradata, extradata_size);
186 
187  rw_extradata[4] |= 0x03;
188 
189  avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size);
190 
191  av_freep(&rw_extradata);
192  } else {
193  avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size);
194  }
195 
196  config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
197  4,
198  &kCFTypeDictionaryKeyCallBacks,
199  &kCFTypeDictionaryValueCallBacks);
200 
201  height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height);
202  width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width);
203  format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format);
204 
205  CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height);
206  CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width);
207  CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format);
208  CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data);
209 
210  buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
211  2,
212  &kCFTypeDictionaryKeyCallBacks,
213  &kCFTypeDictionaryValueCallBacks);
214  io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
215  0,
216  &kCFTypeDictionaryKeyCallBacks,
217  &kCFTypeDictionaryValueCallBacks);
218  cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault,
219  kCFNumberSInt32Type,
220  &vda_ctx->cv_pix_fmt_type);
221  CFDictionarySetValue(buffer_attributes,
222  kCVPixelBufferPixelFormatTypeKey,
223  cv_pix_fmt);
224  CFDictionarySetValue(buffer_attributes,
225  kCVPixelBufferIOSurfacePropertiesKey,
226  io_surface_properties);
227 
228  status = VDADecoderCreate(config_info,
229  buffer_attributes,
231  vda_ctx,
232  &vda_ctx->decoder);
233 
234  CFRelease(height);
235  CFRelease(width);
236  CFRelease(format);
237  CFRelease(avc_data);
238  CFRelease(config_info);
239  CFRelease(io_surface_properties);
240  CFRelease(cv_pix_fmt);
241  CFRelease(buffer_attributes);
242 
243  return status;
244 }
245 
247 {
248  OSStatus status = kVDADecoderNoErr;
249 
250  if (vda_ctx->decoder)
251  status = VDADecoderDestroy(vda_ctx->decoder);
252 
253  av_freep(&vda_ctx->priv_bitstream);
254 
255  return status;
256 }
257 
259  .name = "h264_vda",
260  .type = AVMEDIA_TYPE_VIDEO,
261  .id = AV_CODEC_ID_H264,
262  .pix_fmt = AV_PIX_FMT_VDA_VLD,
263  .start_frame = vda_h264_start_frame,
264  .decode_slice = vda_h264_decode_slice,
265  .end_frame = vda_h264_end_frame,
266 };