]> git.sesse.net Git - ffmpeg/blob - libavcodec/vda_h264.c
Merge commit 'c209d0df657f172f42d9bafbcdfa02dfb14f6965'
[ffmpeg] / libavcodec / vda_h264.c
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
71 static int vda_h264_start_frame(AVCodecContext *avctx,
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
85 static int vda_h264_decode_slice(AVCodecContext *avctx,
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
111 static int vda_h264_end_frame(AVCodecContext *avctx)
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,
201                               vda_decoder_callback,
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
217 int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
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
229 AVHWAccel ff_h264_vda_hwaccel = {
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 };