]> git.sesse.net Git - ffmpeg/blob - libavcodec/vda_h264.c
avcodec: Add av_cold attributes to init functions missing them
[ffmpeg] / 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 /* 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; ///< kVDADecoderFlush_emitFrames
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
70 static int vda_h264_start_frame(AVCodecContext *avctx,
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
84 static int vda_h264_decode_slice(AVCodecContext *avctx,
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
110 static int vda_h264_end_frame(AVCodecContext *avctx)
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,
197                               vda_decoder_callback,
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
213 int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
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
225 AVHWAccel ff_h264_vda_hwaccel = {
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 };