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
)(vlc_video_context
*vctx
, unsigned);
56 cvpxpic_destroy_cb(picture_context_t
*opaque
)
58 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
60 if (vlc_atomic_rc_dec(&ctx
->rc
))
63 if (ctx
->on_released_cb
)
64 ctx
->on_released_cb(opaque
->vctx
, ctx
->nb_fields
);
69 static picture_context_t
*
70 cvpxpic_copy_cb(struct picture_context_t
*opaque
)
72 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
73 vlc_atomic_rc_inc(&ctx
->rc
);
74 vlc_video_context_Hold(opaque
->vctx
);
79 cvpxpic_attach_common(picture_t
*p_pic
, CVPixelBufferRef cvpx
,
80 void (*pf_destroy
)(picture_context_t
*),
81 vlc_video_context
*vctx
,
82 void (*on_released_cb
)(vlc_video_context
*vctx
, unsigned))
84 struct cvpxpic_ctx
*ctx
= malloc(sizeof(struct cvpxpic_ctx
));
87 picture_Release(p_pic
);
90 ctx
->s
= (picture_context_t
) {
91 pf_destroy
, cvpxpic_copy_cb
, vctx
,
93 ctx
->cvpx
= CVPixelBufferRetain(cvpx
);
94 ctx
->nb_fields
= p_pic
->i_nb_fields
;
95 vlc_atomic_rc_init(&ctx
->rc
);
98 vlc_video_context_Hold(vctx
);
99 ctx
->on_released_cb
= on_released_cb
;
101 p_pic
->context
= &ctx
->s
;
107 cvpxpic_attach(picture_t
*p_pic
, CVPixelBufferRef cvpx
, vlc_video_context
*vctx
,
108 void (*on_released_cb
)(vlc_video_context
*vctx
, unsigned))
110 return cvpxpic_attach_common(p_pic
, cvpx
, cvpxpic_destroy_cb
, vctx
, on_released_cb
);
114 cvpxpic_get_ref(picture_t
*pic
)
116 assert(pic
->context
!= NULL
);
117 return ((struct cvpxpic_ctx
*)pic
->context
)->cvpx
;
121 cvpxpic_destroy_mapped_ro_cb(picture_context_t
*opaque
)
123 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
125 CVPixelBufferUnlockBaseAddress(ctx
->cvpx
, kCVPixelBufferLock_ReadOnly
);
126 cvpxpic_destroy_cb(opaque
);
130 cvpxpic_destroy_mapped_rw_cb(picture_context_t
*opaque
)
132 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
134 CVPixelBufferUnlockBaseAddress(ctx
->cvpx
, 0);
135 cvpxpic_destroy_cb(opaque
);
139 cvpxpic_create_mapped(const video_format_t
*fmt
, CVPixelBufferRef cvpx
,
140 vlc_video_context
*vctx
, bool readonly
)
143 unsigned planes_count
;
144 switch (fmt
->i_chroma
)
147 case VLC_CODEC_UYVY
: planes_count
= 0; break;
149 case VLC_CODEC_P010
: 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
= { };
159 assert(CVPixelBufferGetPlaneCount(cvpx
) == planes_count
);
162 void (*pf_destroy
)(picture_context_t
*) = readonly
?
163 cvpxpic_destroy_mapped_ro_cb
: cvpxpic_destroy_mapped_rw_cb
;
165 picture_t
*pic
= picture_NewFromResource(fmt
, &rsc
);
167 || cvpxpic_attach_common(pic
, cvpx
, pf_destroy
, vctx
, NULL
) != VLC_SUCCESS
)
169 CVPixelBufferUnlockBaseAddress(cvpx
, lock
);
173 if (planes_count
== 0)
175 pic
->p
[0].p_pixels
= CVPixelBufferGetBaseAddress(cvpx
);
176 pic
->p
[0].i_lines
= CVPixelBufferGetHeight(cvpx
);
177 pic
->p
[0].i_pitch
= CVPixelBufferGetBytesPerRow(cvpx
);
181 for (unsigned i
= 0; i
< planes_count
; ++i
)
183 pic
->p
[i
].p_pixels
= CVPixelBufferGetBaseAddressOfPlane(cvpx
, i
);
184 pic
->p
[i
].i_lines
= CVPixelBufferGetHeightOfPlane(cvpx
, i
);
185 pic
->p
[i
].i_pitch
= CVPixelBufferGetBytesPerRowOfPlane(cvpx
, i
);
193 cvpxpic_unmap(picture_t
*mapped_pic
)
195 video_format_t fmt
= mapped_pic
->format
;
196 switch (fmt
.i_chroma
)
198 case VLC_CODEC_UYVY
: fmt
.i_chroma
= VLC_CODEC_CVPX_UYVY
; break;
199 case VLC_CODEC_NV12
: fmt
.i_chroma
= VLC_CODEC_CVPX_NV12
; break;
200 case VLC_CODEC_P010
: fmt
.i_chroma
= VLC_CODEC_CVPX_P010
; break;
201 case VLC_CODEC_I420
: fmt
.i_chroma
= VLC_CODEC_CVPX_I420
; break;
202 case VLC_CODEC_BGRA
: fmt
.i_chroma
= VLC_CODEC_CVPX_BGRA
; break;
204 assert(!"invalid mapped_pic fmt");
205 picture_Release(mapped_pic
);
208 assert(mapped_pic
->context
!= NULL
);
210 picture_t
*hw_pic
= picture_NewFromFormat(&fmt
);
213 picture_Release(mapped_pic
);
217 cvpxpic_attach(hw_pic
, cvpxpic_get_ref(mapped_pic
), NULL
, NULL
);
218 picture_CopyProperties(hw_pic
, mapped_pic
);
219 picture_Release(mapped_pic
);
224 cvpxpool_create(const video_format_t
*fmt
, unsigned count
)
227 switch (fmt
->i_chroma
)
229 case VLC_CODEC_CVPX_UYVY
:
230 cvpx_format
= kCVPixelFormatType_422YpCbCr8
;
232 case VLC_CODEC_CVPX_NV12
:
233 cvpx_format
= kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
;
235 case VLC_CODEC_CVPX_I420
:
236 cvpx_format
= kCVPixelFormatType_420YpCbCr8Planar
;
238 case VLC_CODEC_CVPX_BGRA
:
239 cvpx_format
= kCVPixelFormatType_32BGRA
;
241 case VLC_CODEC_CVPX_P010
:
242 cvpx_format
= 'x420'; /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
248 /* destination pixel buffer attributes */
249 CFMutableDictionaryRef cvpx_attrs_dict
= cfdict_create(5);
250 if (unlikely(cvpx_attrs_dict
== NULL
))
252 CFMutableDictionaryRef pool_dict
= cfdict_create(2);
253 if (unlikely(pool_dict
== NULL
))
255 CFRelease(cvpx_attrs_dict
);
259 CFMutableDictionaryRef io_dict
= cfdict_create(0);
260 if (unlikely(io_dict
== NULL
))
262 CFRelease(cvpx_attrs_dict
);
263 CFRelease(pool_dict
);
266 CFDictionarySetValue(cvpx_attrs_dict
,
267 kCVPixelBufferIOSurfacePropertiesKey
, io_dict
);
270 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferPixelFormatTypeKey
,
272 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferWidthKey
, fmt
->i_visible_width
);
273 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferHeightKey
, fmt
->i_visible_height
);
274 /* Required by CIFilter to render IOSurface */
275 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferBytesPerRowAlignmentKey
, 16);
277 cfdict_set_int32(pool_dict
, kCVPixelBufferPoolMinimumBufferCountKey
, count
);
278 cfdict_set_int32(pool_dict
, kCVPixelBufferPoolMaximumBufferAgeKey
, 0);
280 CVPixelBufferPoolRef pool
;
282 CVPixelBufferPoolCreate(NULL
, pool_dict
, cvpx_attrs_dict
, &pool
);
283 CFRelease(pool_dict
);
284 CFRelease(cvpx_attrs_dict
);
285 if (err
!= kCVReturnSuccess
)
288 CVPixelBufferRef cvpxs
[count
];
289 for (unsigned i
= 0; i
< count
; ++i
)
291 err
= CVPixelBufferPoolCreatePixelBuffer(NULL
, pool
, &cvpxs
[i
]);
292 if (err
!= kCVReturnSuccess
)
294 CVPixelBufferPoolRelease(pool
);
300 for (unsigned i
= 0; i
< count
; ++i
)
307 cvpxpool_new_cvpx(CVPixelBufferPoolRef pool
)
309 CVPixelBufferRef cvpx
;
310 CVReturn err
= CVPixelBufferPoolCreatePixelBuffer(NULL
, pool
, &cvpx
);
312 if (err
!= kCVReturnSuccess
)
318 struct cvpx_video_context
320 const struct vlc_video_context_operations
*ops
;
321 enum cvpx_video_context_type type
;
326 cvpx_video_context_Destroy(void *priv
)
328 struct cvpx_video_context
*cvpx_vctx
= priv
;
329 if (cvpx_vctx
->ops
->destroy
)
330 cvpx_vctx
->ops
->destroy(&cvpx_vctx
->private);
334 vlc_video_context_CreateCVPX(vlc_decoder_device
*device
,
335 enum cvpx_video_context_type type
, size_t type_size
,
336 const struct vlc_video_context_operations
*ops
)
338 static const struct vlc_video_context_operations vctx_ops
=
340 cvpx_video_context_Destroy
,
342 vlc_video_context
*vctx
=
343 vlc_video_context_Create(device
, VLC_VIDEO_CONTEXT_CVPX
,
344 sizeof(struct cvpx_video_context
) + type_size
,
348 struct cvpx_video_context
*cvpx_vctx
=
349 vlc_video_context_GetPrivate(vctx
, VLC_VIDEO_CONTEXT_CVPX
);
350 assert(cvpx_vctx
!= NULL
);
351 cvpx_vctx
->type
= type
;
352 cvpx_vctx
->ops
= ops
;
358 vlc_video_context_GetCVPXPrivate(vlc_video_context
*vctx
,
359 enum cvpx_video_context_type type
)
361 struct cvpx_video_context
*cvpx_vctx
=
362 vlc_video_context_GetPrivate(vctx
, VLC_VIDEO_CONTEXT_CVPX
);
364 if (cvpx_vctx
&& cvpx_vctx
->type
== type
)
365 return &cvpx_vctx
->private;