vda: cosmetic.
[ffmpeg.git] / libavcodec / vda.c
1 /*
2  * VDA 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 <pthread.h>
24 #include <CoreFoundation/CFDictionary.h>
25 #include <CoreFoundation/CFNumber.h>
26 #include <CoreFoundation/CFData.h>
27 #include <CoreFoundation/CFString.h>
28
29 #include "avcodec.h"
30 #include "vda_internal.h"
31
32 /**
33  * \addtogroup VDA_Decoding
34  *
35  * @{
36  */
37
38 /* Mutex manager callback. */
39 static int vda_lock_operation(void **mtx, enum AVLockOp op)
40 {
41     switch(op)
42     {
43         case AV_LOCK_CREATE:
44             *mtx = av_malloc(sizeof(pthread_mutex_t));
45             if(!*mtx)
46                 return 1;
47             return !!pthread_mutex_init(*mtx, NULL);
48         case AV_LOCK_OBTAIN:
49             return !!pthread_mutex_lock(*mtx);
50         case AV_LOCK_RELEASE:
51             return !!pthread_mutex_unlock(*mtx);
52         case AV_LOCK_DESTROY:
53             pthread_mutex_destroy(*mtx);
54             av_freep(mtx);
55             return 0;
56     }
57     return 1;
58 }
59
60 /* Helper to create a dictionary according to the given pts. */
61 static CFDictionaryRef vda_dictionary_with_pts(int64_t i_pts)
62 {
63     CFStringRef key = CFSTR("FF_VDA_DECODER_PTS_KEY");
64     CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &i_pts);
65     CFDictionaryRef user_info = CFDictionaryCreate( kCFAllocatorDefault,
66                                                     (const void **)&key,
67                                                     (const void **)&value,
68                                                     1,
69                                                     &kCFTypeDictionaryKeyCallBacks,
70                                                     &kCFTypeDictionaryValueCallBacks);
71     CFRelease(value);
72     return user_info;
73 }
74
75 /* Helper to retrieve the pts from the given dictionary. */
76 static int64_t vda_pts_from_dictionary(CFDictionaryRef user_info)
77 {
78     CFNumberRef pts;
79     int64_t outValue = 0;
80
81     if (!user_info)
82         return 0;
83
84     pts = CFDictionaryGetValue(user_info, CFSTR("FF_VDA_DECODER_PTS_KEY"));
85
86     if (pts)
87         CFNumberGetValue(pts, kCFNumberSInt64Type, &outValue);
88
89     return outValue;
90 }
91
92 /* Removes and releases all frames from the queue. */
93 static void vda_clear_queue(struct vda_context *vda_ctx)
94 {
95     vda_frame *top_frame;
96
97     vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_OBTAIN);
98
99     while (vda_ctx->queue)
100     {
101         top_frame = vda_ctx->queue;
102         vda_ctx->queue = top_frame->next_frame;
103         ff_vda_release_vda_frame(top_frame);
104     }
105
106     vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_RELEASE);
107 }
108
109
110 /* Decoder callback that adds the vda frame to the queue in display order. */
111 static void vda_decoder_callback (void *vda_hw_ctx,
112                                   CFDictionaryRef user_info,
113                                   OSStatus status,
114                                   uint32_t infoFlags,
115                                   CVImageBufferRef image_buffer)
116 {
117     struct vda_context *vda_ctx = (struct vda_context*)vda_hw_ctx;
118     vda_frame *new_frame;
119     vda_frame *queue_walker;
120
121     if (!image_buffer)
122         return;
123
124     if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer))
125         return;
126
127     new_frame = (vda_frame *)av_mallocz(sizeof(vda_frame));
128     new_frame->next_frame = NULL;
129     new_frame->cv_buffer = CVPixelBufferRetain(image_buffer);
130     new_frame->pts = vda_pts_from_dictionary(user_info);
131
132     vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_OBTAIN);
133
134     queue_walker = vda_ctx->queue;
135
136     if (!queue_walker || (new_frame->pts < queue_walker->pts))
137     {
138         /* we have an empty queue, or this frame earlier than the current queue head */
139         new_frame->next_frame = queue_walker;
140         vda_ctx->queue = new_frame;
141     }
142     else
143     {
144         /* walk the queue and insert this frame where it belongs in display order */
145         vda_frame *next_frame;
146
147         while (1)
148         {
149             next_frame = queue_walker->next_frame;
150
151             if (!next_frame || (new_frame->pts < next_frame->pts))
152             {
153                 new_frame->next_frame = next_frame;
154                 queue_walker->next_frame = new_frame;
155                 break;
156             }
157             queue_walker = next_frame;
158         }
159     }
160
161     vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_RELEASE);
162 }
163
164 int ff_vda_create_decoder(struct vda_context *vda_ctx,
165                           uint8_t *extradata,
166                           int extradata_size)
167 {
168     OSStatus status = kVDADecoderNoErr;
169     CFNumberRef height;
170     CFNumberRef width;
171     CFNumberRef format;
172     CFDataRef avc_data;
173     CFMutableDictionaryRef config_info;
174     CFMutableDictionaryRef buffer_attributes;
175     CFMutableDictionaryRef io_surface_properties;
176     CFNumberRef cv_pix_fmt;
177
178     vda_ctx->bitstream = NULL;
179     vda_ctx->ref_size = 0;
180
181     if (av_lockmgr_register(vda_lock_operation))
182         return -1;
183
184     vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_CREATE);
185
186     config_info = CFDictionaryCreateMutable(kCFAllocatorDefault,
187                                             4,
188                                             &kCFTypeDictionaryKeyCallBacks,
189                                             &kCFTypeDictionaryValueCallBacks);
190
191     height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height);
192     width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width);
193     format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format);
194     avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size);
195
196     CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height);
197     CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width);
198     CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format);
199     CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data);
200
201     buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
202                                                   2,
203                                                   &kCFTypeDictionaryKeyCallBacks,
204                                                   &kCFTypeDictionaryValueCallBacks);
205     io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault,
206                                                       0,
207                                                       &kCFTypeDictionaryKeyCallBacks,
208                                                       &kCFTypeDictionaryValueCallBacks);
209     cv_pix_fmt  = CFNumberCreate(kCFAllocatorDefault,
210                                  kCFNumberSInt32Type,
211                                  &vda_ctx->cv_pix_fmt_type);
212     CFDictionarySetValue(buffer_attributes,
213                          kCVPixelBufferPixelFormatTypeKey,
214                          cv_pix_fmt);
215     CFDictionarySetValue(buffer_attributes,
216                          kCVPixelBufferIOSurfacePropertiesKey,
217                          io_surface_properties);
218
219     status = VDADecoderCreate( config_info,
220                                buffer_attributes,
221                                (VDADecoderOutputCallback *)vda_decoder_callback,
222                                (void *)vda_ctx,
223                                &vda_ctx->decoder );
224
225     CFRelease(height);
226     CFRelease(width);
227     CFRelease(format);
228     CFRelease(avc_data);
229     CFRelease(config_info);
230     CFRelease(io_surface_properties);
231     CFRelease(cv_pix_fmt);
232     CFRelease(buffer_attributes);
233
234     if (kVDADecoderNoErr != status)
235         return status;
236
237     return 0;
238 }
239
240 int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
241 {
242     OSStatus status = kVDADecoderNoErr;
243
244     if (vda_ctx->decoder)
245         status = VDADecoderDestroy(vda_ctx->decoder);
246
247     vda_clear_queue(vda_ctx);
248
249     if (vda_ctx->queue_mutex)
250         vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_DESTROY);
251
252     if (vda_ctx->bitstream)
253         av_freep(&vda_ctx->bitstream);
254
255     if (kVDADecoderNoErr != status)
256         return status;
257
258     return 0;
259 }
260
261 vda_frame *ff_vda_queue_pop(struct vda_context *vda_ctx)
262 {
263     vda_frame *top_frame;
264
265     if (!vda_ctx->queue)
266         return NULL;
267
268     vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_OBTAIN);
269     top_frame = vda_ctx->queue;
270     vda_ctx->queue = top_frame->next_frame;
271     vda_lock_operation(&vda_ctx->queue_mutex, AV_LOCK_RELEASE);
272
273     return top_frame;
274 }
275
276 void ff_vda_release_vda_frame(vda_frame *frame)
277 {
278     if (frame)
279     {
280         CVPixelBufferRelease(frame->cv_buffer);
281         av_freep(&frame);
282     }
283 }
284
285 int ff_vda_decoder_decode(struct vda_context *vda_ctx,
286                           uint8_t *bitstream,
287                           int bitstream_size,
288                           int64_t frame_pts)
289 {
290     OSStatus status = kVDADecoderNoErr;
291     CFDictionaryRef user_info;
292     CFDataRef coded_frame;
293
294     coded_frame = CFDataCreate(kCFAllocatorDefault, bitstream, bitstream_size);
295     user_info = vda_dictionary_with_pts(frame_pts);
296
297     status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, user_info);
298
299     CFRelease(user_info);
300     CFRelease(coded_frame);
301
302     if (kVDADecoderNoErr != status)
303         return status;
304
305     return 0;
306 }
307
308 /* @} */