input: add an input_item_t arg to input_CreateFilename()
[vlc.git] / modules / codec / vt_utils.c
blob88224c4e5fd92024bfbdbd9e2ef93d99a9bfabce
1 /*****************************************************************************
2 * vt_utils.c: videotoolbox/cvpx utility functions
3 *****************************************************************************
4 * Copyright (C) 2017 VLC authors, VideoLAN and VideoLabs
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <vlc_atomic.h>
27 #include "vt_utils.h"
29 CFMutableDictionaryRef
30 cfdict_create(CFIndex capacity)
32 return CFDictionaryCreateMutable(kCFAllocatorDefault, capacity,
33 &kCFTypeDictionaryKeyCallBacks,
34 &kCFTypeDictionaryValueCallBacks);
37 void
38 cfdict_set_int32(CFMutableDictionaryRef dict, CFStringRef key, int value)
40 CFNumberRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
41 CFDictionarySetValue(dict, key, number);
42 CFRelease(number);
45 struct cvpxpic_ctx
47 picture_context_t s;
48 CVPixelBufferRef cvpx;
49 unsigned nb_fields;
51 vlc_atomic_rc_t rc;
52 void (*on_released_cb)(CVPixelBufferRef, void *, unsigned);
53 void *on_released_data;
56 static void
57 cvpxpic_destroy_cb(picture_context_t *opaque)
59 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
61 if (vlc_atomic_rc_dec(&ctx->rc))
63 CFRelease(ctx->cvpx);
64 if (ctx->on_released_cb)
65 ctx->on_released_cb(ctx->cvpx, ctx->on_released_data, ctx->nb_fields);
66 free(opaque);
70 static picture_context_t *
71 cvpxpic_copy_cb(struct picture_context_t *opaque)
73 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
74 vlc_atomic_rc_inc(&ctx->rc);
75 return opaque;
78 static int
79 cvpxpic_attach_common(picture_t *p_pic, CVPixelBufferRef cvpx,
80 void (*pf_destroy)(picture_context_t *),
81 void (*on_released_cb)(CVPixelBufferRef, void *, unsigned),
82 void *on_released_data)
84 struct cvpxpic_ctx *ctx = malloc(sizeof(struct cvpxpic_ctx));
85 if (ctx == NULL)
87 picture_Release(p_pic);
88 return VLC_ENOMEM;
90 ctx->s.destroy = pf_destroy;
91 ctx->s.copy = cvpxpic_copy_cb;
92 ctx->cvpx = CVPixelBufferRetain(cvpx);
93 ctx->nb_fields = p_pic->i_nb_fields;
94 vlc_atomic_rc_init(&ctx->rc);
96 ctx->on_released_cb = on_released_cb;
97 ctx->on_released_data = on_released_data;
99 p_pic->context = &ctx->s;
101 return VLC_SUCCESS;
105 cvpxpic_attach(picture_t *p_pic, CVPixelBufferRef cvpx)
107 return cvpxpic_attach_common(p_pic, cvpx, cvpxpic_destroy_cb, NULL, NULL);
110 int cvpxpic_attach_with_cb(picture_t *p_pic, CVPixelBufferRef cvpx,
111 void (*on_released_cb)(CVPixelBufferRef, void *, unsigned),
112 void *on_released_data)
114 return cvpxpic_attach_common(p_pic, cvpx, cvpxpic_destroy_cb, on_released_cb,
115 on_released_data);
118 CVPixelBufferRef
119 cvpxpic_get_ref(picture_t *pic)
121 assert(pic->context != NULL);
122 return ((struct cvpxpic_ctx *)pic->context)->cvpx;
125 static void
126 cvpxpic_destroy_mapped_ro_cb(picture_context_t *opaque)
128 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
130 CVPixelBufferUnlockBaseAddress(ctx->cvpx, kCVPixelBufferLock_ReadOnly);
131 cvpxpic_destroy_cb(opaque);
134 static void
135 cvpxpic_destroy_mapped_rw_cb(picture_context_t *opaque)
137 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
139 CVPixelBufferUnlockBaseAddress(ctx->cvpx, 0);
140 cvpxpic_destroy_cb(opaque);
143 picture_t *
144 cvpxpic_create_mapped(const video_format_t *fmt, CVPixelBufferRef cvpx,
145 bool readonly)
147 unsigned planes_count;
148 switch (fmt->i_chroma)
150 case VLC_CODEC_BGRA:
151 case VLC_CODEC_UYVY: planes_count = 0; break;
152 case VLC_CODEC_NV12:
153 case VLC_CODEC_P010: planes_count = 2; break;
154 case VLC_CODEC_I420: planes_count = 3; break;
155 default: return NULL;
158 CVPixelBufferLockFlags lock = readonly ? kCVPixelBufferLock_ReadOnly : 0;
159 CVPixelBufferLockBaseAddress(cvpx, lock);
160 picture_resource_t rsc = { };
162 #ifndef NDEBUG
163 assert(CVPixelBufferGetPlaneCount(cvpx) == planes_count);
164 #endif
166 if (planes_count == 0)
168 rsc.p[0].p_pixels = CVPixelBufferGetBaseAddress(cvpx);
169 rsc.p[0].i_lines = CVPixelBufferGetHeight(cvpx);
170 rsc.p[0].i_pitch = CVPixelBufferGetBytesPerRow(cvpx);
172 else
174 for (unsigned i = 0; i < planes_count; ++i)
176 rsc.p[i].p_pixels = CVPixelBufferGetBaseAddressOfPlane(cvpx, i);
177 rsc.p[i].i_lines = CVPixelBufferGetHeightOfPlane(cvpx, i);
178 rsc.p[i].i_pitch = CVPixelBufferGetBytesPerRowOfPlane(cvpx, i);
182 void (*pf_destroy)(picture_context_t *) = readonly ?
183 cvpxpic_destroy_mapped_ro_cb : cvpxpic_destroy_mapped_rw_cb;
185 picture_t *pic = picture_NewFromResource(fmt, &rsc);
186 if (pic == NULL
187 || cvpxpic_attach_common(pic, cvpx, pf_destroy, NULL, NULL) != VLC_SUCCESS)
189 CVPixelBufferUnlockBaseAddress(cvpx, lock);
190 return NULL;
192 return pic;
195 picture_t *
196 cvpxpic_unmap(picture_t *mapped_pic)
198 video_format_t fmt = mapped_pic->format;
199 switch (fmt.i_chroma)
201 case VLC_CODEC_UYVY: fmt.i_chroma = VLC_CODEC_CVPX_UYVY; break;
202 case VLC_CODEC_NV12: fmt.i_chroma = VLC_CODEC_CVPX_NV12; break;
203 case VLC_CODEC_P010: fmt.i_chroma = VLC_CODEC_CVPX_P010; break;
204 case VLC_CODEC_I420: fmt.i_chroma = VLC_CODEC_CVPX_I420; break;
205 case VLC_CODEC_BGRA: fmt.i_chroma = VLC_CODEC_CVPX_BGRA; break;
206 default:
207 assert(!"invalid mapped_pic fmt");
208 picture_Release(mapped_pic);
209 return NULL;
211 assert(mapped_pic->context != NULL);
213 picture_t *hw_pic = picture_NewFromFormat(&fmt);
214 if (hw_pic == NULL)
216 picture_Release(mapped_pic);
217 return NULL;
220 cvpxpic_attach(hw_pic, cvpxpic_get_ref(mapped_pic));
221 picture_CopyProperties(hw_pic, mapped_pic);
222 picture_Release(mapped_pic);
223 return hw_pic;
226 CVPixelBufferPoolRef
227 cvpxpool_create(const video_format_t *fmt, unsigned count)
229 int cvpx_format;
230 switch (fmt->i_chroma)
232 case VLC_CODEC_CVPX_UYVY:
233 cvpx_format = kCVPixelFormatType_422YpCbCr8;
234 break;
235 case VLC_CODEC_CVPX_NV12:
236 cvpx_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
237 break;
238 case VLC_CODEC_CVPX_I420:
239 cvpx_format = kCVPixelFormatType_420YpCbCr8Planar;
240 break;
241 case VLC_CODEC_CVPX_BGRA:
242 cvpx_format = kCVPixelFormatType_32BGRA;
243 break;
244 case VLC_CODEC_CVPX_P010:
245 cvpx_format = 'x420'; /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
246 break;
247 default:
248 return NULL;
251 /* destination pixel buffer attributes */
252 CFMutableDictionaryRef cvpx_attrs_dict = cfdict_create(5);
253 if (unlikely(cvpx_attrs_dict == NULL))
254 return NULL;
255 CFMutableDictionaryRef pool_dict = cfdict_create(2);
256 if (unlikely(pool_dict == NULL))
258 CFRelease(cvpx_attrs_dict);
259 return NULL;
262 CFMutableDictionaryRef io_dict = cfdict_create(0);
263 if (unlikely(io_dict == NULL))
265 CFRelease(cvpx_attrs_dict);
266 CFRelease(pool_dict);
267 return NULL;
269 CFDictionarySetValue(cvpx_attrs_dict,
270 kCVPixelBufferIOSurfacePropertiesKey, io_dict);
271 CFRelease(io_dict);
273 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferPixelFormatTypeKey,
274 cvpx_format);
275 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferWidthKey, fmt->i_visible_width);
276 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferHeightKey, fmt->i_visible_height);
277 /* Required by CIFilter to render IOSurface */
278 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferBytesPerRowAlignmentKey, 16);
280 cfdict_set_int32(pool_dict, kCVPixelBufferPoolMinimumBufferCountKey, count);
281 cfdict_set_int32(pool_dict, kCVPixelBufferPoolMaximumBufferAgeKey, 0);
283 CVPixelBufferPoolRef pool;
284 CVReturn err =
285 CVPixelBufferPoolCreate(NULL, pool_dict, cvpx_attrs_dict, &pool);
286 CFRelease(pool_dict);
287 CFRelease(cvpx_attrs_dict);
288 if (err != kCVReturnSuccess)
289 return NULL;
291 CVPixelBufferRef cvpxs[count];
292 for (unsigned i = 0; i < count; ++i)
294 err = CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &cvpxs[i]);
295 if (err != kCVReturnSuccess)
297 CVPixelBufferPoolRelease(pool);
298 pool = NULL;
299 count = i;
300 break;
303 for (unsigned i = 0; i < count; ++i)
304 CFRelease(cvpxs[i]);
306 return pool;
309 CVPixelBufferRef
310 cvpxpool_new_cvpx(CVPixelBufferPoolRef pool)
312 CVPixelBufferRef cvpx;
313 CVReturn err = CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &cvpx);
315 if (err != kCVReturnSuccess)
316 return NULL;
318 return cvpx;