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