input: add input_SetProgramId
[vlc.git] / modules / codec / vt_utils.c
blob75191117fe7df4b04f040e886cdf0b0cc6a870f9
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)(vlc_video_context *vctx, unsigned);
55 static void
56 cvpxpic_destroy_cb(picture_context_t *opaque)
58 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
60 if (vlc_atomic_rc_dec(&ctx->rc))
62 CFRelease(ctx->cvpx);
63 if (ctx->on_released_cb)
64 ctx->on_released_cb(opaque->vctx, ctx->nb_fields);
65 free(opaque);
69 static picture_context_t *
70 cvpxpic_copy_cb(struct picture_context_t *opaque)
72 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
73 vlc_atomic_rc_inc(&ctx->rc);
74 vlc_video_context_Hold(opaque->vctx);
75 return opaque;
78 static int
79 cvpxpic_attach_common(picture_t *p_pic, CVPixelBufferRef cvpx,
80 void (*pf_destroy)(picture_context_t *),
81 vlc_video_context *vctx,
82 void (*on_released_cb)(vlc_video_context *vctx, unsigned))
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 = (picture_context_t) {
91 pf_destroy, cvpxpic_copy_cb, vctx,
93 ctx->cvpx = CVPixelBufferRetain(cvpx);
94 ctx->nb_fields = p_pic->i_nb_fields;
95 vlc_atomic_rc_init(&ctx->rc);
97 assert(vctx);
98 vlc_video_context_Hold(vctx);
99 ctx->on_released_cb = on_released_cb;
101 p_pic->context = &ctx->s;
103 return VLC_SUCCESS;
107 cvpxpic_attach(picture_t *p_pic, CVPixelBufferRef cvpx, vlc_video_context *vctx,
108 void (*on_released_cb)(vlc_video_context *vctx, unsigned))
110 return cvpxpic_attach_common(p_pic, cvpx, cvpxpic_destroy_cb, vctx, on_released_cb);
113 CVPixelBufferRef
114 cvpxpic_get_ref(picture_t *pic)
116 assert(pic->context != NULL);
117 return ((struct cvpxpic_ctx *)pic->context)->cvpx;
120 static void
121 cvpxpic_destroy_mapped_ro_cb(picture_context_t *opaque)
123 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
125 CVPixelBufferUnlockBaseAddress(ctx->cvpx, kCVPixelBufferLock_ReadOnly);
126 cvpxpic_destroy_cb(opaque);
129 static void
130 cvpxpic_destroy_mapped_rw_cb(picture_context_t *opaque)
132 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
134 CVPixelBufferUnlockBaseAddress(ctx->cvpx, 0);
135 cvpxpic_destroy_cb(opaque);
138 picture_t *
139 cvpxpic_create_mapped(const video_format_t *fmt, CVPixelBufferRef cvpx,
140 vlc_video_context *vctx, bool readonly)
143 unsigned planes_count;
144 switch (fmt->i_chroma)
146 case VLC_CODEC_BGRA:
147 case VLC_CODEC_UYVY: planes_count = 0; break;
148 case VLC_CODEC_NV12:
149 case VLC_CODEC_P010: planes_count = 2; break;
150 case VLC_CODEC_I420: planes_count = 3; break;
151 default: return NULL;
154 CVPixelBufferLockFlags lock = readonly ? kCVPixelBufferLock_ReadOnly : 0;
155 CVPixelBufferLockBaseAddress(cvpx, lock);
156 picture_resource_t rsc = { };
158 #ifndef NDEBUG
159 assert(CVPixelBufferGetPlaneCount(cvpx) == planes_count);
160 #endif
162 void (*pf_destroy)(picture_context_t *) = readonly ?
163 cvpxpic_destroy_mapped_ro_cb : cvpxpic_destroy_mapped_rw_cb;
165 picture_t *pic = picture_NewFromResource(fmt, &rsc);
166 if (pic == NULL
167 || cvpxpic_attach_common(pic, cvpx, pf_destroy, vctx, NULL) != VLC_SUCCESS)
169 CVPixelBufferUnlockBaseAddress(cvpx, lock);
170 return NULL;
173 if (planes_count == 0)
175 pic->p[0].p_pixels = CVPixelBufferGetBaseAddress(cvpx);
176 pic->p[0].i_lines = CVPixelBufferGetHeight(cvpx);
177 pic->p[0].i_pitch = CVPixelBufferGetBytesPerRow(cvpx);
179 else
181 for (unsigned i = 0; i < planes_count; ++i)
183 pic->p[i].p_pixels = CVPixelBufferGetBaseAddressOfPlane(cvpx, i);
184 pic->p[i].i_lines = CVPixelBufferGetHeightOfPlane(cvpx, i);
185 pic->p[i].i_pitch = CVPixelBufferGetBytesPerRowOfPlane(cvpx, i);
189 return pic;
192 picture_t *
193 cvpxpic_unmap(picture_t *mapped_pic)
195 video_format_t fmt = mapped_pic->format;
196 switch (fmt.i_chroma)
198 case VLC_CODEC_UYVY: fmt.i_chroma = VLC_CODEC_CVPX_UYVY; break;
199 case VLC_CODEC_NV12: fmt.i_chroma = VLC_CODEC_CVPX_NV12; break;
200 case VLC_CODEC_P010: fmt.i_chroma = VLC_CODEC_CVPX_P010; break;
201 case VLC_CODEC_I420: fmt.i_chroma = VLC_CODEC_CVPX_I420; break;
202 case VLC_CODEC_BGRA: fmt.i_chroma = VLC_CODEC_CVPX_BGRA; break;
203 default:
204 assert(!"invalid mapped_pic fmt");
205 picture_Release(mapped_pic);
206 return NULL;
208 assert(mapped_pic->context != NULL);
210 picture_t *hw_pic = picture_NewFromFormat(&fmt);
211 if (hw_pic == NULL)
213 picture_Release(mapped_pic);
214 return NULL;
217 cvpxpic_attach(hw_pic, cvpxpic_get_ref(mapped_pic), NULL, NULL);
218 picture_CopyProperties(hw_pic, mapped_pic);
219 picture_Release(mapped_pic);
220 return hw_pic;
223 CVPixelBufferPoolRef
224 cvpxpool_create(const video_format_t *fmt, unsigned count)
226 int cvpx_format;
227 switch (fmt->i_chroma)
229 case VLC_CODEC_CVPX_UYVY:
230 cvpx_format = kCVPixelFormatType_422YpCbCr8;
231 break;
232 case VLC_CODEC_CVPX_NV12:
233 cvpx_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
234 break;
235 case VLC_CODEC_CVPX_I420:
236 cvpx_format = kCVPixelFormatType_420YpCbCr8Planar;
237 break;
238 case VLC_CODEC_CVPX_BGRA:
239 cvpx_format = kCVPixelFormatType_32BGRA;
240 break;
241 case VLC_CODEC_CVPX_P010:
242 cvpx_format = 'x420'; /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
243 break;
244 default:
245 return NULL;
248 /* destination pixel buffer attributes */
249 CFMutableDictionaryRef cvpx_attrs_dict = cfdict_create(5);
250 if (unlikely(cvpx_attrs_dict == NULL))
251 return NULL;
252 CFMutableDictionaryRef pool_dict = cfdict_create(2);
253 if (unlikely(pool_dict == NULL))
255 CFRelease(cvpx_attrs_dict);
256 return NULL;
259 CFMutableDictionaryRef io_dict = cfdict_create(0);
260 if (unlikely(io_dict == NULL))
262 CFRelease(cvpx_attrs_dict);
263 CFRelease(pool_dict);
264 return NULL;
266 CFDictionarySetValue(cvpx_attrs_dict,
267 kCVPixelBufferIOSurfacePropertiesKey, io_dict);
268 CFRelease(io_dict);
270 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferPixelFormatTypeKey,
271 cvpx_format);
272 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferWidthKey, fmt->i_visible_width);
273 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferHeightKey, fmt->i_visible_height);
274 /* Required by CIFilter to render IOSurface */
275 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferBytesPerRowAlignmentKey, 16);
277 cfdict_set_int32(pool_dict, kCVPixelBufferPoolMinimumBufferCountKey, count);
278 cfdict_set_int32(pool_dict, kCVPixelBufferPoolMaximumBufferAgeKey, 0);
280 CVPixelBufferPoolRef pool;
281 CVReturn err =
282 CVPixelBufferPoolCreate(NULL, pool_dict, cvpx_attrs_dict, &pool);
283 CFRelease(pool_dict);
284 CFRelease(cvpx_attrs_dict);
285 if (err != kCVReturnSuccess)
286 return NULL;
288 CVPixelBufferRef cvpxs[count];
289 for (unsigned i = 0; i < count; ++i)
291 err = CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &cvpxs[i]);
292 if (err != kCVReturnSuccess)
294 CVPixelBufferPoolRelease(pool);
295 pool = NULL;
296 count = i;
297 break;
300 for (unsigned i = 0; i < count; ++i)
301 CFRelease(cvpxs[i]);
303 return pool;
306 CVPixelBufferRef
307 cvpxpool_new_cvpx(CVPixelBufferPoolRef pool)
309 CVPixelBufferRef cvpx;
310 CVReturn err = CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &cvpx);
312 if (err != kCVReturnSuccess)
313 return NULL;
315 return cvpx;
318 struct cvpx_video_context
320 const struct vlc_video_context_operations *ops;
321 enum cvpx_video_context_type type;
322 uint8_t private[];
325 static void
326 cvpx_video_context_Destroy(void *priv)
328 struct cvpx_video_context *cvpx_vctx = priv;
329 if (cvpx_vctx->ops->destroy)
330 cvpx_vctx->ops->destroy(&cvpx_vctx->private);
333 vlc_video_context *
334 vlc_video_context_CreateCVPX(vlc_decoder_device *device,
335 enum cvpx_video_context_type type, size_t type_size,
336 const struct vlc_video_context_operations *ops)
338 static const struct vlc_video_context_operations vctx_ops =
340 cvpx_video_context_Destroy,
342 vlc_video_context *vctx =
343 vlc_video_context_Create(device, VLC_VIDEO_CONTEXT_CVPX,
344 sizeof(struct cvpx_video_context) + type_size,
345 &vctx_ops);
346 if (!vctx)
347 return NULL;
348 struct cvpx_video_context *cvpx_vctx =
349 vlc_video_context_GetPrivate(vctx, VLC_VIDEO_CONTEXT_CVPX);
350 assert(cvpx_vctx != NULL);
351 cvpx_vctx->type = type;
352 cvpx_vctx->ops = ops;
354 return vctx;
357 void *
358 vlc_video_context_GetCVPXPrivate(vlc_video_context *vctx,
359 enum cvpx_video_context_type type)
361 struct cvpx_video_context *cvpx_vctx =
362 vlc_video_context_GetPrivate(vctx, VLC_VIDEO_CONTEXT_CVPX);
364 if (cvpx_vctx && cvpx_vctx->type == type)
365 return &cvpx_vctx->private;
366 return NULL;