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