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