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>
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
*);
44 static int Open_CVPX_to_CVPX(vlc_object_t
*);
45 static void Close_CVPX_to_CVPX(vlc_object_t
*);
49 set_description("Conversions from/to CoreVideo buffers")
50 set_capability("video converter", 10)
51 set_callbacks(Open
, Close
)
58 filter_t
*p_sw_filter
;
59 CVPixelBufferPoolRef pool
;
64 set_description("Conversions between CoreVideo buffers")
65 set_callbacks(Open_CVPX_to_CVPX
, Close_CVPX_to_CVPX
)
74 filter_t
*p_sw_filter
;
75 CVPixelBufferPoolRef pool
;
78 VTPixelTransferSessionRef vttransfer
;
83 /********************************
84 * CVPX to/from I420 conversion *
85 ********************************/
87 static picture_t
*CVPX_TO_SW_Filter(filter_t
*p_filter
, picture_t
*src
)
90 cvpxpic_create_mapped(&p_filter
->fmt_out
.video
, cvpxpic_get_ref(src
),
97 picture_CopyProperties(src_sw
, src
);
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
);
109 picture_Release(src
);
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);
119 picture_Release(src
);
123 /* Allocate a CVPX picture without any context */
124 picture_t
*dst
= picture_NewFromFormat(&p_filter
->fmt_out
.video
);
127 picture_Release(src
);
128 picture_Release(mapped_dst
);
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
);
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
;
155 cvpxpic_create_mapped(&p_sw_filter
->fmt_in
.video
, cvpxpic_get_ref(src
),
160 picture_Release(src
);
163 picture_CopyProperties(src_sw
, src
);
164 picture_Release(src
);
166 dst
= p_sw_filter
->pf_video_filter(p_sw_filter
, src_sw
);
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
);
186 cvpxpic_create_mapped(&p_sw_filter
->fmt_out
.video
, cvpx
, false);
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
);
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
);
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
)
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; \
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; \
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
)
259 CASE_CVPX_INPUT(UYVY
)
261 CASE_CVPX_INPUT(I420
)
263 CASE_CVPX_INPUT(BGRA
)
266 switch (p_filter
->fmt_out
.video
.i_chroma
)
268 CASE_CVPX_OUTPUT(NV12
)
270 CASE_CVPX_OUTPUT(UYVY
)
272 CASE_CVPX_OUTPUT(I420
)
274 CASE_CVPX_OUTPUT(BGRA
)
281 filter_sys_t
*p_sys
= p_filter
->p_sys
= malloc(sizeof(filter_sys_t
));
283 if (unlikely(!p_sys
))
286 p_sys
->p_sw_filter
= NULL
;
290 && (p_sys
->pool
= cvpxpool_create(&p_filter
->fmt_out
.video
, 3)) == NULL
)
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
))
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",
309 if (p_sw_filter
->p_module
== NULL
)
311 vlc_object_release(p_sw_filter
);
314 p_sys
->p_sw_filter
= p_sw_filter
;
322 #undef CASE_CVPX_INPUT
323 #undef CASE_CVPX_OUTPUT
326 /***************************
327 * CVPX to CVPX conversion *
328 ***************************/
330 #if !TARGET_OS_IPHONE
333 Filter(filter_t
*filter
, picture_t
*src
)
335 CVPixelBufferRef src_cvpx
= cvpxpic_get_ref(src
);
338 picture_t
*dst
= filter_NewPicture(filter
);
341 picture_Release(src
);
345 CVPixelBufferRef dst_cvpx
= cvpxpic_get_ref(dst
);
348 if (VTPixelTransferSessionTransferImage(filter
->p_sys
->vttransfer
,
349 src_cvpx
, dst_cvpx
) != noErr
)
351 picture_Release(dst
);
352 picture_Release(src
);
356 picture_CopyProperties(dst
, src
);
357 picture_Release(src
);
361 static vlc_fourcc_t
const supported_chromas
[] = { VLC_CODEC_CVPX_BGRA
,
364 VLC_CODEC_CVPX_UYVY
};
367 Open_CVPX_to_CVPX(vlc_object_t
*obj
)
369 filter_t
*filter
= (filter_t
*)obj
;
372 #define CHECK_CHROMA(fourcc) \
374 while (i < ARRAY_SIZE(supported_chromas) && \
375 fourcc != supported_chromas[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
)
384 filter
->p_sys
= calloc(1, sizeof(filter_sys_t
));
388 if (VTPixelTransferSessionCreate(NULL
, &filter
->p_sys
->vttransfer
)
395 filter
->pf_video_filter
= Filter
;
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
);