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 *****************************************************************************/
25 #include <vlc_atomic.h>
29 CFMutableDictionaryRef
30 cfdict_create(CFIndex capacity
)
32 return CFDictionaryCreateMutable(kCFAllocatorDefault
, capacity
,
33 &kCFTypeDictionaryKeyCallBacks
,
34 &kCFTypeDictionaryValueCallBacks
);
38 cfdict_set_int32(CFMutableDictionaryRef dict
, CFStringRef key
, int value
)
40 CFNumberRef number
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &value
);
41 CFDictionarySetValue(dict
, key
, number
);
48 CVPixelBufferRef cvpx
;
52 void (*on_released_cb
)(CVPixelBufferRef
, void *, unsigned);
53 void *on_released_data
;
57 cvpxpic_destroy_cb(picture_context_t
*opaque
)
59 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
61 if (vlc_atomic_rc_dec(&ctx
->rc
))
64 if (ctx
->on_released_cb
)
65 ctx
->on_released_cb(ctx
->cvpx
, ctx
->on_released_data
, ctx
->nb_fields
);
70 static picture_context_t
*
71 cvpxpic_copy_cb(struct picture_context_t
*opaque
)
73 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
74 vlc_atomic_rc_inc(&ctx
->rc
);
79 cvpxpic_attach_common(picture_t
*p_pic
, CVPixelBufferRef cvpx
,
80 void (*pf_destroy
)(picture_context_t
*),
81 void (*on_released_cb
)(CVPixelBufferRef
, void *, unsigned),
82 void *on_released_data
)
84 struct cvpxpic_ctx
*ctx
= malloc(sizeof(struct cvpxpic_ctx
));
87 picture_Release(p_pic
);
90 ctx
->s
.destroy
= pf_destroy
;
91 ctx
->s
.copy
= cvpxpic_copy_cb
;
92 ctx
->cvpx
= CVPixelBufferRetain(cvpx
);
93 ctx
->nb_fields
= p_pic
->i_nb_fields
;
94 vlc_atomic_rc_init(&ctx
->rc
);
96 ctx
->on_released_cb
= on_released_cb
;
97 ctx
->on_released_data
= on_released_data
;
99 p_pic
->context
= &ctx
->s
;
105 cvpxpic_attach(picture_t
*p_pic
, CVPixelBufferRef cvpx
)
107 return cvpxpic_attach_common(p_pic
, cvpx
, cvpxpic_destroy_cb
, NULL
, NULL
);
110 int cvpxpic_attach_with_cb(picture_t
*p_pic
, CVPixelBufferRef cvpx
,
111 void (*on_released_cb
)(CVPixelBufferRef
, void *, unsigned),
112 void *on_released_data
)
114 return cvpxpic_attach_common(p_pic
, cvpx
, cvpxpic_destroy_cb
, on_released_cb
,
119 cvpxpic_get_ref(picture_t
*pic
)
121 assert(pic
->context
!= NULL
);
122 return ((struct cvpxpic_ctx
*)pic
->context
)->cvpx
;
126 cvpxpic_destroy_mapped_ro_cb(picture_context_t
*opaque
)
128 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
130 CVPixelBufferUnlockBaseAddress(ctx
->cvpx
, kCVPixelBufferLock_ReadOnly
);
131 cvpxpic_destroy_cb(opaque
);
135 cvpxpic_destroy_mapped_rw_cb(picture_context_t
*opaque
)
137 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
139 CVPixelBufferUnlockBaseAddress(ctx
->cvpx
, 0);
140 cvpxpic_destroy_cb(opaque
);
144 cvpxpic_create_mapped(const video_format_t
*fmt
, CVPixelBufferRef cvpx
,
147 unsigned planes_count
;
148 switch (fmt
->i_chroma
)
151 case VLC_CODEC_UYVY
: planes_count
= 0; break;
153 case VLC_CODEC_P010
: planes_count
= 2; break;
154 case VLC_CODEC_I420
: planes_count
= 3; break;
155 default: return NULL
;
158 CVPixelBufferLockFlags lock
= readonly
? kCVPixelBufferLock_ReadOnly
: 0;
159 CVPixelBufferLockBaseAddress(cvpx
, lock
);
160 picture_resource_t rsc
= { };
163 assert(CVPixelBufferGetPlaneCount(cvpx
) == planes_count
);
166 if (planes_count
== 0)
168 rsc
.p
[0].p_pixels
= CVPixelBufferGetBaseAddress(cvpx
);
169 rsc
.p
[0].i_lines
= CVPixelBufferGetHeight(cvpx
);
170 rsc
.p
[0].i_pitch
= CVPixelBufferGetBytesPerRow(cvpx
);
174 for (unsigned i
= 0; i
< planes_count
; ++i
)
176 rsc
.p
[i
].p_pixels
= CVPixelBufferGetBaseAddressOfPlane(cvpx
, i
);
177 rsc
.p
[i
].i_lines
= CVPixelBufferGetHeightOfPlane(cvpx
, i
);
178 rsc
.p
[i
].i_pitch
= CVPixelBufferGetBytesPerRowOfPlane(cvpx
, i
);
182 void (*pf_destroy
)(picture_context_t
*) = readonly
?
183 cvpxpic_destroy_mapped_ro_cb
: cvpxpic_destroy_mapped_rw_cb
;
185 picture_t
*pic
= picture_NewFromResource(fmt
, &rsc
);
187 || cvpxpic_attach_common(pic
, cvpx
, pf_destroy
, NULL
, NULL
) != VLC_SUCCESS
)
189 CVPixelBufferUnlockBaseAddress(cvpx
, lock
);
196 cvpxpic_unmap(picture_t
*mapped_pic
)
198 video_format_t fmt
= mapped_pic
->format
;
199 switch (fmt
.i_chroma
)
201 case VLC_CODEC_UYVY
: fmt
.i_chroma
= VLC_CODEC_CVPX_UYVY
; break;
202 case VLC_CODEC_NV12
: fmt
.i_chroma
= VLC_CODEC_CVPX_NV12
; break;
203 case VLC_CODEC_P010
: fmt
.i_chroma
= VLC_CODEC_CVPX_P010
; break;
204 case VLC_CODEC_I420
: fmt
.i_chroma
= VLC_CODEC_CVPX_I420
; break;
205 case VLC_CODEC_BGRA
: fmt
.i_chroma
= VLC_CODEC_CVPX_BGRA
; break;
207 assert(!"invalid mapped_pic fmt");
208 picture_Release(mapped_pic
);
211 assert(mapped_pic
->context
!= NULL
);
213 picture_t
*hw_pic
= picture_NewFromFormat(&fmt
);
216 picture_Release(mapped_pic
);
220 cvpxpic_attach(hw_pic
, cvpxpic_get_ref(mapped_pic
));
221 picture_CopyProperties(hw_pic
, mapped_pic
);
222 picture_Release(mapped_pic
);
227 cvpxpool_create(const video_format_t
*fmt
, unsigned count
)
230 switch (fmt
->i_chroma
)
232 case VLC_CODEC_CVPX_UYVY
:
233 cvpx_format
= kCVPixelFormatType_422YpCbCr8
;
235 case VLC_CODEC_CVPX_NV12
:
236 cvpx_format
= kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
;
238 case VLC_CODEC_CVPX_I420
:
239 cvpx_format
= kCVPixelFormatType_420YpCbCr8Planar
;
241 case VLC_CODEC_CVPX_BGRA
:
242 cvpx_format
= kCVPixelFormatType_32BGRA
;
244 case VLC_CODEC_CVPX_P010
:
245 cvpx_format
= 'x420'; /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
251 /* destination pixel buffer attributes */
252 CFMutableDictionaryRef cvpx_attrs_dict
= cfdict_create(5);
253 if (unlikely(cvpx_attrs_dict
== NULL
))
255 CFMutableDictionaryRef pool_dict
= cfdict_create(2);
256 if (unlikely(pool_dict
== NULL
))
258 CFRelease(cvpx_attrs_dict
);
262 CFMutableDictionaryRef io_dict
= cfdict_create(0);
263 if (unlikely(io_dict
== NULL
))
265 CFRelease(cvpx_attrs_dict
);
266 CFRelease(pool_dict
);
269 CFDictionarySetValue(cvpx_attrs_dict
,
270 kCVPixelBufferIOSurfacePropertiesKey
, io_dict
);
273 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferPixelFormatTypeKey
,
275 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferWidthKey
, fmt
->i_visible_width
);
276 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferHeightKey
, fmt
->i_visible_height
);
277 /* Required by CIFilter to render IOSurface */
278 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferBytesPerRowAlignmentKey
, 16);
280 cfdict_set_int32(pool_dict
, kCVPixelBufferPoolMinimumBufferCountKey
, count
);
281 cfdict_set_int32(pool_dict
, kCVPixelBufferPoolMaximumBufferAgeKey
, 0);
283 CVPixelBufferPoolRef pool
;
285 CVPixelBufferPoolCreate(NULL
, pool_dict
, cvpx_attrs_dict
, &pool
);
286 CFRelease(pool_dict
);
287 CFRelease(cvpx_attrs_dict
);
288 if (err
!= kCVReturnSuccess
)
291 CVPixelBufferRef cvpxs
[count
];
292 for (unsigned i
= 0; i
< count
; ++i
)
294 err
= CVPixelBufferPoolCreatePixelBuffer(NULL
, pool
, &cvpxs
[i
]);
295 if (err
!= kCVReturnSuccess
)
297 CVPixelBufferPoolRelease(pool
);
303 for (unsigned i
= 0; i
< count
; ++i
)
310 cvpxpool_new_cvpx(CVPixelBufferPoolRef pool
)
312 CVPixelBufferRef cvpx
;
313 CVReturn err
= CVPixelBufferPoolCreatePixelBuffer(NULL
, pool
, &cvpx
);
315 if (err
!= kCVReturnSuccess
)