demux: mp4: avoid audio cuts on seek
[vlc.git] / modules / video_chroma / cvpx.c
bloba111468328081cd3f1c0343f7a697d4dc8435534
1 /*****************************************************************************
2 * cvpx.c: core video buffer to picture converter
3 *****************************************************************************
4 * Copyright (C) 2015-2017 VLC authors, VideoLAN and VideoLabs
6 * Authors: Felix Paul Kühne <fkuehne at videolan dot org>
7 * Thomas Guillem <thomas@gllm.fr>
8 * Victorien Le Couviour--Tuffet <victorien.lecouiour.tuffet@gmail.com>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #include <QuartzCore/QuartzCore.h>
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <TargetConditionals.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
36 #include <vlc_picture.h>
37 #include <vlc_modules.h>
38 #include "../codec/vt_utils.h"
40 static int Open(vlc_object_t *);
41 static void Close(vlc_object_t *);
43 #if !TARGET_OS_IPHONE
44 static int Open_CVPX_to_CVPX(vlc_object_t *);
45 static void Close_CVPX_to_CVPX(vlc_object_t *);
46 #endif
48 vlc_module_begin ()
49 set_description("Conversions from/to CoreVideo buffers")
50 set_capability("video converter", 10)
51 set_callbacks(Open, Close)
53 #if TARGET_OS_IPHONE
54 vlc_module_end ()
56 struct filter_sys_t
58 filter_t *p_sw_filter;
59 CVPixelBufferPoolRef pool;
62 #else
63 add_submodule()
64 set_description("Conversions between CoreVideo buffers")
65 set_callbacks(Open_CVPX_to_CVPX, Close_CVPX_to_CVPX)
66 vlc_module_end ()
68 struct filter_sys_t
70 union
72 struct
74 filter_t *p_sw_filter;
75 CVPixelBufferPoolRef pool;
78 VTPixelTransferSessionRef vttransfer;
81 #endif
83 /********************************
84 * CVPX to/from I420 conversion *
85 ********************************/
87 static picture_t *CVPX_TO_SW_Filter(filter_t *p_filter, picture_t *src)
89 picture_t *src_sw =
90 cvpxpic_create_mapped(&p_filter->fmt_out.video, cvpxpic_get_ref(src),
91 true);
92 if (!src_sw)
94 picture_Release(src);
95 return NULL;
97 picture_CopyProperties(src_sw, src);
98 picture_Release(src);
99 return src_sw;
102 static picture_t *SW_TO_CVPX_Filter(filter_t *p_filter, picture_t *src)
104 filter_sys_t *p_sys = p_filter->p_sys;
106 CVPixelBufferRef cvpx = cvpxpool_new_cvpx(p_sys->pool);
107 if (cvpx == NULL)
109 picture_Release(src);
110 return NULL;
113 /* Allocate a CPVX backed picture mapped for read/write */
114 picture_t *mapped_dst =
115 cvpxpic_create_mapped(&p_filter->fmt_in.video, cvpx, false);
116 CFRelease(cvpx);
117 if (!mapped_dst)
119 picture_Release(src);
120 return NULL;
123 /* Allocate a CVPX picture without any context */
124 picture_t *dst = picture_NewFromFormat(&p_filter->fmt_out.video);
125 if (!dst)
127 picture_Release(src);
128 picture_Release(mapped_dst);
129 return NULL;
132 /* Copy pixels to the CVPX backed picture */
133 picture_CopyPixels(mapped_dst, src);
135 /* Attach the CVPX to a new opaque picture */
136 cvpxpic_attach(dst, (void *)mapped_dst->p_sys);
138 /* Unlock and unmap the dst picture */
139 picture_Release(mapped_dst);
141 picture_CopyProperties(dst, src);
142 picture_Release(src);
143 return dst;
147 static picture_t *CVPX_TO_I420_Filter(filter_t *p_filter, picture_t *src)
149 filter_sys_t *p_sys = p_filter->p_sys;
150 filter_t *p_sw_filter = p_sys->p_sw_filter;
151 assert(p_sw_filter != NULL);
152 picture_t *dst = NULL;
154 picture_t *src_sw =
155 cvpxpic_create_mapped(&p_sw_filter->fmt_in.video, cvpxpic_get_ref(src),
156 true);
158 if (!src_sw)
160 picture_Release(src);
161 return NULL;
163 picture_CopyProperties(src_sw, src);
164 picture_Release(src);
166 dst = p_sw_filter->pf_video_filter(p_sw_filter, src_sw);
168 return dst;
171 static picture_t *SW_buffer_new(filter_t *p_filter)
173 return picture_NewFromFormat( &p_filter->fmt_out.video );
176 static picture_t *CVPX_buffer_new(filter_t *p_sw_filter)
178 filter_t *p_filter = p_sw_filter->owner.sys;
179 filter_sys_t *p_sys = p_filter->p_sys;
181 CVPixelBufferRef cvpx = cvpxpool_new_cvpx(p_sys->pool);
182 if (cvpx == NULL)
183 return NULL;
185 picture_t *pic =
186 cvpxpic_create_mapped(&p_sw_filter->fmt_out.video, cvpx, false);
187 CFRelease(cvpx);
188 return pic;
191 static picture_t *I420_TO_CVPX_Filter(filter_t *p_filter, picture_t *src)
193 filter_sys_t *p_sys = p_filter->p_sys;
194 filter_t *p_sw_filter = p_sys->p_sw_filter;
196 picture_t *sw_dst = p_sw_filter->pf_video_filter(p_sw_filter, src);
197 if (sw_dst == NULL)
198 return NULL;
200 return cvpxpic_unmap(sw_dst);
203 static void Close(vlc_object_t *obj)
205 filter_t *p_filter = (filter_t *)obj;
206 filter_sys_t *p_sys = p_filter->p_sys;
208 if (p_sys->p_sw_filter != NULL)
210 module_unneed(p_sys->p_sw_filter, p_sys->p_sw_filter->p_module);
211 vlc_object_release(p_sys->p_sw_filter);
214 if (p_sys->pool != NULL)
215 CVPixelBufferPoolRelease(p_sys->pool);
216 free(p_sys);
219 static int Open(vlc_object_t *obj)
221 filter_t *p_filter = (filter_t *)obj;
223 if (p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height
224 || p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width)
225 return VLC_EGENERIC;
227 #define CASE_CVPX_INPUT(x) \
228 case VLC_CODEC_CVPX_##x: \
229 if (p_filter->fmt_out.video.i_chroma == VLC_CODEC_##x) { \
230 p_filter->pf_video_filter = CVPX_TO_SW_Filter; \
231 } else if (p_filter->fmt_out.video.i_chroma == VLC_CODEC_I420) {\
232 p_filter->pf_video_filter = CVPX_TO_I420_Filter; \
233 i_sw_filter_in_chroma = VLC_CODEC_##x; \
234 i_sw_filter_out_chroma = VLC_CODEC_I420; \
235 sw_filter_owner.video.buffer_new = SW_buffer_new; \
236 } else return VLC_EGENERIC; \
237 b_need_pool = false;
239 #define CASE_CVPX_OUTPUT(x) \
240 case VLC_CODEC_CVPX_##x: \
241 if (p_filter->fmt_in.video.i_chroma == VLC_CODEC_##x) { \
242 p_filter->pf_video_filter = SW_TO_CVPX_Filter; \
243 } else if (p_filter->fmt_in.video.i_chroma == VLC_CODEC_I420) {\
244 p_filter->pf_video_filter = I420_TO_CVPX_Filter; \
245 i_sw_filter_in_chroma = VLC_CODEC_I420; \
246 i_sw_filter_out_chroma = VLC_CODEC_##x; \
247 sw_filter_owner.sys = p_filter; \
248 sw_filter_owner.video.buffer_new = CVPX_buffer_new; \
249 } else return VLC_EGENERIC; \
250 b_need_pool = true;
252 bool b_need_pool;
253 vlc_fourcc_t i_sw_filter_in_chroma = 0, i_sw_filter_out_chroma = 0;
254 filter_owner_t sw_filter_owner = {};
255 switch (p_filter->fmt_in.video.i_chroma)
257 CASE_CVPX_INPUT(NV12)
258 break;
259 CASE_CVPX_INPUT(UYVY)
260 break;
261 CASE_CVPX_INPUT(I420)
262 break;
263 CASE_CVPX_INPUT(BGRA)
264 break;
265 default:
266 switch (p_filter->fmt_out.video.i_chroma)
268 CASE_CVPX_OUTPUT(NV12)
269 break;
270 CASE_CVPX_OUTPUT(UYVY)
271 break;
272 CASE_CVPX_OUTPUT(I420)
273 break;
274 CASE_CVPX_OUTPUT(BGRA)
275 break;
276 default:
277 return VLC_EGENERIC;
281 filter_sys_t *p_sys = p_filter->p_sys = malloc(sizeof(filter_sys_t));
283 if (unlikely(!p_sys))
284 return VLC_ENOMEM;
286 p_sys->p_sw_filter = NULL;
287 p_sys->pool = NULL;
289 if (b_need_pool
290 && (p_sys->pool = cvpxpool_create(&p_filter->fmt_out.video, 3)) == NULL)
291 goto error;
293 if (i_sw_filter_in_chroma != 0)
295 filter_t *p_sw_filter = vlc_object_create(p_filter, sizeof(filter_t));
296 if (unlikely(p_sw_filter == NULL))
297 goto error;
299 p_sw_filter->fmt_in = p_filter->fmt_in;
300 p_sw_filter->fmt_out = p_filter->fmt_out;
301 p_sw_filter->fmt_in.i_codec = p_sw_filter->fmt_in.video.i_chroma
302 = i_sw_filter_in_chroma;
303 p_sw_filter->fmt_out.i_codec = p_sw_filter->fmt_out.video.i_chroma
304 = i_sw_filter_out_chroma;
306 p_sw_filter->owner = sw_filter_owner;
307 p_sw_filter->p_module = module_need(p_sw_filter, "video converter",
308 NULL, false);
309 if (p_sw_filter->p_module == NULL)
311 vlc_object_release(p_sw_filter);
312 goto error;
314 p_sys->p_sw_filter = p_sw_filter;
317 return VLC_SUCCESS;
319 error:
320 Close(obj);
321 return VLC_EGENERIC;
322 #undef CASE_CVPX_INPUT
323 #undef CASE_CVPX_OUTPUT
326 /***************************
327 * CVPX to CVPX conversion *
328 ***************************/
330 #if !TARGET_OS_IPHONE
332 static picture_t *
333 Filter(filter_t *filter, picture_t *src)
335 CVPixelBufferRef src_cvpx = cvpxpic_get_ref(src);
336 assert(src_cvpx);
338 picture_t *dst = filter_NewPicture(filter);
339 if (!dst)
341 picture_Release(src);
342 return NULL;
345 CVPixelBufferRef dst_cvpx = cvpxpic_get_ref(dst);
346 assert(dst_cvpx);
348 if (VTPixelTransferSessionTransferImage(filter->p_sys->vttransfer,
349 src_cvpx, dst_cvpx) != noErr)
351 picture_Release(dst);
352 picture_Release(src);
353 return NULL;
356 picture_CopyProperties(dst, src);
357 picture_Release(src);
358 return dst;
361 static vlc_fourcc_t const supported_chromas[] = { VLC_CODEC_CVPX_BGRA,
362 VLC_CODEC_CVPX_I420,
363 VLC_CODEC_CVPX_NV12,
364 VLC_CODEC_CVPX_UYVY };
366 static int
367 Open_CVPX_to_CVPX(vlc_object_t *obj)
369 filter_t *filter = (filter_t *)obj;
371 unsigned int i;
372 #define CHECK_CHROMA(fourcc) \
373 i = 0; \
374 while (i < ARRAY_SIZE(supported_chromas) && \
375 fourcc != supported_chromas[i]) \
376 ++i; \
377 if (i == ARRAY_SIZE(supported_chromas)) \
378 return VLC_EGENERIC; \
380 CHECK_CHROMA(filter->fmt_in.video.i_chroma)
381 CHECK_CHROMA(filter->fmt_out.video.i_chroma)
382 #undef CHECK_CHROMA
384 filter->p_sys = calloc(1, sizeof(filter_sys_t));
385 if (!filter->p_sys)
386 return VLC_ENOMEM;
388 if (VTPixelTransferSessionCreate(NULL, &filter->p_sys->vttransfer)
389 != noErr)
391 free(filter->p_sys);
392 return VLC_EGENERIC;
395 filter->pf_video_filter = Filter;
397 return VLC_SUCCESS;
400 static void
401 Close_CVPX_to_CVPX(vlc_object_t *obj)
403 filter_t *filter = (filter_t *)obj;
405 VTPixelTransferSessionInvalidate(filter->p_sys->vttransfer);
406 CFRelease(filter->p_sys->vttransfer);
407 free(filter->p_sys);
410 #endif