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_I420_Filter(filter_t
*p_filter
, picture_t
*src
)
89 filter_sys_t
*p_sys
= p_filter
->p_sys
;
90 filter_t
*p_sw_filter
= p_sys
->p_sw_filter
;
91 assert(p_sw_filter
!= NULL
);
92 picture_t
*dst
= NULL
;
95 cvpxpic_create_mapped(&p_sw_filter
->fmt_in
.video
, cvpxpic_get_ref(src
),
100 picture_Release(src
);
103 picture_CopyProperties(src_sw
, src
);
104 picture_Release(src
);
106 dst
= p_sw_filter
->pf_video_filter(p_sw_filter
, src_sw
);
111 static picture_t
*CVPX_buffer_new(filter_t
*p_sw_filter
)
113 filter_t
*p_filter
= p_sw_filter
->owner
.sys
;
114 filter_sys_t
*p_sys
= p_filter
->p_sys
;
116 CVPixelBufferRef cvpx
= cvpxpool_get_cvpx(p_sys
->pool
);
121 cvpxpic_create_mapped(&p_sw_filter
->fmt_out
.video
, cvpx
, false);
126 static picture_t
*I420_TO_CVPX_Filter(filter_t
*p_filter
, picture_t
*src
)
128 filter_sys_t
*p_sys
= p_filter
->p_sys
;
129 filter_t
*p_sw_filter
= p_sys
->p_sw_filter
;
131 picture_t
*sw_dst
= p_sw_filter
->pf_video_filter(p_sw_filter
, src
);
135 return cvpxpic_unmap(sw_dst
);
138 static void Close(vlc_object_t
*obj
)
140 filter_t
*p_filter
= (filter_t
*)obj
;
141 filter_sys_t
*p_sys
= p_filter
->p_sys
;
143 if (p_sys
->p_sw_filter
!= NULL
)
145 module_unneed(p_sys
->p_sw_filter
, p_sys
->p_sw_filter
->p_module
);
146 vlc_object_release(p_sys
->p_sw_filter
);
149 if (p_sys
->pool
!= NULL
)
150 CVPixelBufferPoolRelease(p_sys
->pool
);
154 static int Open(vlc_object_t
*obj
)
156 filter_t
*p_filter
= (filter_t
*)obj
;
158 if (p_filter
->fmt_in
.video
.i_height
!= p_filter
->fmt_out
.video
.i_height
159 || p_filter
->fmt_in
.video
.i_width
!= p_filter
->fmt_out
.video
.i_width
)
162 #define CASE_CVPX_INPUT(x) \
163 case VLC_CODEC_CVPX_##x: \
164 if (p_filter->fmt_out.video.i_chroma != VLC_CODEC_I420) \
165 return VLC_EGENERIC; \
166 p_filter->pf_video_filter = CVPX_TO_I420_Filter; \
167 i_sw_filter_in_chroma = VLC_CODEC_##x; \
168 i_sw_filter_out_chroma = VLC_CODEC_I420; \
169 sw_filter_owner = p_filter->owner; \
172 #define CASE_CVPX_OUTPUT(x) \
173 case VLC_CODEC_CVPX_##x: \
174 if (p_filter->fmt_in.video.i_chroma != VLC_CODEC_I420) \
175 return VLC_EGENERIC; \
176 p_filter->pf_video_filter = I420_TO_CVPX_Filter; \
177 i_sw_filter_in_chroma = VLC_CODEC_I420; \
178 i_sw_filter_out_chroma = VLC_CODEC_##x; \
179 sw_filter_owner.sys = p_filter; \
180 sw_filter_owner.video.buffer_new = CVPX_buffer_new; \
184 vlc_fourcc_t i_sw_filter_in_chroma
= 0, i_sw_filter_out_chroma
= 0;
185 filter_owner_t sw_filter_owner
= {};
186 switch (p_filter
->fmt_in
.video
.i_chroma
)
188 CASE_CVPX_INPUT(NV12
)
190 CASE_CVPX_INPUT(UYVY
)
192 CASE_CVPX_INPUT(I420
)
195 switch (p_filter
->fmt_out
.video
.i_chroma
)
197 CASE_CVPX_OUTPUT(NV12
)
199 CASE_CVPX_OUTPUT(UYVY
)
201 CASE_CVPX_OUTPUT(I420
)
208 filter_sys_t
*p_sys
= p_filter
->p_sys
= malloc(sizeof(filter_sys_t
));
210 if (unlikely(!p_sys
))
213 p_sys
->p_sw_filter
= NULL
;
217 && (p_sys
->pool
= cvpxpool_create(&p_filter
->fmt_out
.video
, 3)) == NULL
)
220 filter_t
*p_sw_filter
= vlc_object_create(p_filter
, sizeof(filter_t
));
221 if (unlikely(p_sw_filter
== NULL
))
224 p_sw_filter
->fmt_in
= p_filter
->fmt_in
;
225 p_sw_filter
->fmt_out
= p_filter
->fmt_out
;
226 p_sw_filter
->fmt_in
.i_codec
= p_sw_filter
->fmt_in
.video
.i_chroma
227 = i_sw_filter_in_chroma
;
228 p_sw_filter
->fmt_out
.i_codec
= p_sw_filter
->fmt_out
.video
.i_chroma
229 = i_sw_filter_out_chroma
;
231 p_sw_filter
->owner
= sw_filter_owner
;
232 p_sw_filter
->p_module
= module_need(p_sw_filter
, "video converter",
234 if (p_sw_filter
->p_module
== NULL
)
236 vlc_object_release(p_sw_filter
);
239 p_sys
->p_sw_filter
= p_sw_filter
;
247 #undef CASE_CVPX_INPUT
248 #undef CASE_CVPX_OUTPUT
251 /***************************
252 * CVPX to CVPX conversion *
253 ***************************/
255 #if !TARGET_OS_IPHONE
258 Filter(filter_t
*filter
, picture_t
*src
)
260 CVPixelBufferRef src_cvpx
= cvpxpic_get_ref(src
);
263 picture_t
*dst
= filter_NewPicture(filter
);
266 picture_Release(src
);
270 CVPixelBufferRef dst_cvpx
= cvpxpic_get_ref(dst
);
273 if (VTPixelTransferSessionTransferImage(filter
->p_sys
->vttransfer
,
274 src_cvpx
, dst_cvpx
) != noErr
)
276 picture_Release(dst
);
277 picture_Release(src
);
281 picture_CopyProperties(dst
, src
);
282 picture_Release(src
);
286 static vlc_fourcc_t
const supported_chromas
[] = { VLC_CODEC_CVPX_BGRA
,
289 VLC_CODEC_CVPX_UYVY
};
292 Open_CVPX_to_CVPX(vlc_object_t
*obj
)
294 filter_t
*filter
= (filter_t
*)obj
;
297 #define CHECK_CHROMA(fourcc) \
299 while (i < ARRAY_SIZE(supported_chromas) && \
300 fourcc != supported_chromas[i]) \
302 if (i == ARRAY_SIZE(supported_chromas)) \
303 return VLC_EGENERIC; \
305 CHECK_CHROMA(filter->fmt_in.video.i_chroma)
306 CHECK_CHROMA(filter
->fmt_out
.video
.i_chroma
)
309 filter
->p_sys
= calloc(1, sizeof(filter_sys_t
));
313 if (VTPixelTransferSessionCreate(NULL
, &filter
->p_sys
->vttransfer
)
320 filter
->pf_video_filter
= Filter
;
326 Close_CVPX_to_CVPX(vlc_object_t
*obj
)
328 filter_t
*filter
= (filter_t
*)obj
;
330 VTPixelTransferSessionInvalidate(filter
->p_sys
->vttransfer
);
331 CFRelease(filter
->p_sys
->vttransfer
);