modules: use plane_SwapUV()
[vlc.git] / modules / codec / vt_utils.c
blob0b428fabda1653f34c836caff29af6e744237743
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;
50 atomic_uint ref_count;
51 void (*on_released_cb)(void *);
52 void *on_released_data;
55 static void
56 cvpxpic_destroy_cb(picture_context_t *opaque)
58 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
60 if (atomic_fetch_sub(&ctx->ref_count, 1) == 1)
62 CFRelease(ctx->cvpx);
63 if (ctx->on_released_cb)
64 ctx->on_released_cb(ctx->on_released_data);
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 atomic_fetch_add(&ctx->ref_count, 1);
74 return opaque;
77 static int
78 cvpxpic_attach_common(picture_t *p_pic, CVPixelBufferRef cvpx,
79 void (*pf_destroy)(picture_context_t *),
80 void (*on_released_cb)(void *), void *on_released_data)
82 struct cvpxpic_ctx *ctx = malloc(sizeof(struct cvpxpic_ctx));
83 if (ctx == NULL)
85 picture_Release(p_pic);
86 return VLC_ENOMEM;
88 ctx->s.destroy = pf_destroy;
89 ctx->s.copy = cvpxpic_copy_cb;
90 ctx->cvpx = CVPixelBufferRetain(cvpx);
91 atomic_init(&ctx->ref_count, 1);
93 ctx->on_released_cb = on_released_cb;
94 ctx->on_released_data = on_released_data;
96 p_pic->context = &ctx->s;
98 return VLC_SUCCESS;
102 cvpxpic_attach(picture_t *p_pic, CVPixelBufferRef cvpx)
104 return cvpxpic_attach_common(p_pic, cvpx, cvpxpic_destroy_cb, NULL, NULL);
107 int cvpxpic_attach_with_cb(picture_t *p_pic, CVPixelBufferRef cvpx,
108 void (*on_released_cb)(void *),
109 void *on_released_data)
111 return cvpxpic_attach_common(p_pic, cvpx, cvpxpic_destroy_cb, on_released_cb,
112 on_released_data);
115 CVPixelBufferRef
116 cvpxpic_get_ref(picture_t *pic)
118 assert(pic->context != NULL);
119 return ((struct cvpxpic_ctx *)pic->context)->cvpx;
122 static void
123 cvpxpic_destroy_mapped_ro_cb(picture_context_t *opaque)
125 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
127 CVPixelBufferUnlockBaseAddress(ctx->cvpx, kCVPixelBufferLock_ReadOnly);
128 cvpxpic_destroy_cb(opaque);
131 static void
132 cvpxpic_destroy_mapped_rw_cb(picture_context_t *opaque)
134 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
136 CVPixelBufferUnlockBaseAddress(ctx->cvpx, 0);
137 cvpxpic_destroy_cb(opaque);
140 picture_t *
141 cvpxpic_create_mapped(const video_format_t *fmt, CVPixelBufferRef cvpx,
142 bool readonly)
144 unsigned planes_count;
145 switch (fmt->i_chroma)
147 case VLC_CODEC_BGRA:
148 case VLC_CODEC_UYVY: planes_count = 0; break;
149 case VLC_CODEC_NV12: 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 if (planes_count == 0)
164 rsc.p[0].p_pixels = CVPixelBufferGetBaseAddress(cvpx);
165 rsc.p[0].i_lines = CVPixelBufferGetHeight(cvpx);
166 rsc.p[0].i_pitch = CVPixelBufferGetBytesPerRow(cvpx);
168 else
170 for (unsigned i = 0; i < planes_count; ++i)
172 rsc.p[i].p_pixels = CVPixelBufferGetBaseAddressOfPlane(cvpx, i);
173 rsc.p[i].i_lines = CVPixelBufferGetHeightOfPlane(cvpx, i);
174 rsc.p[i].i_pitch = CVPixelBufferGetBytesPerRowOfPlane(cvpx, i);
178 void (*pf_destroy)(picture_context_t *) = readonly ?
179 cvpxpic_destroy_mapped_ro_cb : cvpxpic_destroy_mapped_rw_cb;
181 picture_t *pic = picture_NewFromResource(fmt, &rsc);
182 if (pic == NULL
183 || cvpxpic_attach_common(pic, cvpx, pf_destroy, NULL, NULL) != VLC_SUCCESS)
185 CVPixelBufferUnlockBaseAddress(cvpx, lock);
186 return NULL;
188 return pic;
191 picture_t *
192 cvpxpic_unmap(picture_t *mapped_pic)
194 video_format_t fmt = mapped_pic->format;
195 switch (fmt.i_chroma)
197 case VLC_CODEC_UYVY: fmt.i_chroma = VLC_CODEC_CVPX_UYVY; break;
198 case VLC_CODEC_NV12: fmt.i_chroma = VLC_CODEC_CVPX_NV12; break;
199 case VLC_CODEC_I420: fmt.i_chroma = VLC_CODEC_CVPX_I420; break;
200 case VLC_CODEC_BGRA: fmt.i_chroma = VLC_CODEC_CVPX_BGRA; break;
201 default:
202 assert(!"invalid mapped_pic fmt");
203 picture_Release(mapped_pic);
204 return NULL;
206 assert(mapped_pic->context != NULL);
208 picture_t *hw_pic = picture_NewFromFormat(&fmt);
209 if (hw_pic == NULL)
211 picture_Release(mapped_pic);
212 return NULL;
215 cvpxpic_attach(hw_pic, cvpxpic_get_ref(mapped_pic));
216 picture_CopyProperties(hw_pic, mapped_pic);
217 picture_Release(mapped_pic);
218 return hw_pic;
221 CVPixelBufferPoolRef
222 cvpxpool_create(const video_format_t *fmt, unsigned count)
224 int cvpx_format;
225 switch (fmt->i_chroma)
227 case VLC_CODEC_CVPX_UYVY:
228 cvpx_format = kCVPixelFormatType_422YpCbCr8;
229 break;
230 case VLC_CODEC_CVPX_NV12:
231 cvpx_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
232 break;
233 case VLC_CODEC_CVPX_I420:
234 cvpx_format = kCVPixelFormatType_420YpCbCr8Planar;
235 break;
236 case VLC_CODEC_CVPX_BGRA:
237 cvpx_format = kCVPixelFormatType_32BGRA;
238 break;
239 default:
240 return NULL;
243 /* destination pixel buffer attributes */
244 CFMutableDictionaryRef cvpx_attrs_dict = cfdict_create(5);
245 if (unlikely(cvpx_attrs_dict == NULL))
246 return NULL;
247 CFMutableDictionaryRef pool_dict = cfdict_create(2);
248 if (unlikely(pool_dict == NULL))
250 CFRelease(cvpx_attrs_dict);
251 return NULL;
254 CFMutableDictionaryRef io_dict = cfdict_create(0);
255 if (unlikely(io_dict == NULL))
257 CFRelease(cvpx_attrs_dict);
258 CFRelease(pool_dict);
259 return NULL;
261 CFDictionarySetValue(cvpx_attrs_dict,
262 kCVPixelBufferIOSurfacePropertiesKey, io_dict);
263 CFRelease(io_dict);
265 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferBytesPerRowAlignmentKey,
266 fmt->i_width);
267 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferPixelFormatTypeKey,
268 cvpx_format);
269 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferWidthKey, fmt->i_width);
270 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferHeightKey, fmt->i_height);
271 /* Required by CIFilter to render IOSurface */
272 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferBytesPerRowAlignmentKey, 16);
274 cfdict_set_int32(pool_dict, kCVPixelBufferPoolMinimumBufferCountKey, count);
275 cfdict_set_int32(pool_dict, kCVPixelBufferPoolMaximumBufferAgeKey, 0);
277 CVPixelBufferPoolRef pool;
278 CVReturn err =
279 CVPixelBufferPoolCreate(NULL, pool_dict, cvpx_attrs_dict, &pool);
280 CFRelease(pool_dict);
281 CFRelease(cvpx_attrs_dict);
282 if (err != kCVReturnSuccess)
283 return NULL;
285 CVPixelBufferRef cvpxs[count];
286 for (unsigned i = 0; i < count; ++i)
288 err = CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &cvpxs[i]);
289 if (err != kCVReturnSuccess)
291 CVPixelBufferPoolRelease(pool);
292 pool = NULL;
293 count = i;
294 break;
297 for (unsigned i = 0; i < count; ++i)
298 CFRelease(cvpxs[i]);
300 return pool;
303 CVPixelBufferRef
304 cvpxpool_new_cvpx(CVPixelBufferPoolRef pool)
306 CVPixelBufferRef cvpx;
307 CVReturn err = CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &cvpx);
309 if (err != kCVReturnSuccess)
310 return NULL;
312 return cvpx;