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 *****************************************************************************/
27 CFMutableDictionaryRef
28 cfdict_create(CFIndex capacity
)
30 return CFDictionaryCreateMutable(kCFAllocatorDefault
, capacity
,
31 &kCFTypeDictionaryKeyCallBacks
,
32 &kCFTypeDictionaryValueCallBacks
);
36 cfdict_set_int32(CFMutableDictionaryRef dict
, CFStringRef key
, int value
)
38 CFNumberRef number
= CFNumberCreate(NULL
, kCFNumberSInt32Type
, &value
);
39 CFDictionarySetValue(dict
, key
, number
);
46 CVPixelBufferRef cvpx
;
50 cvpxpic_destroy_cb(picture_context_t
*opaque
)
52 struct cvpxpic_ctx
*ctx
= (struct cvpxpic_ctx
*)opaque
;
58 static picture_context_t
*
59 cvpxpic_copy_cb(struct picture_context_t
*opaque
)
61 struct cvpxpic_ctx
*src_ctx
= (struct cvpxpic_ctx
*)opaque
;
62 struct cvpxpic_ctx
*dst_ctx
= malloc(sizeof(struct cvpxpic_ctx
));
66 dst_ctx
->cvpx
= CVPixelBufferRetain(dst_ctx
->cvpx
);
71 cvpxpic_attach(picture_t
*p_pic
, CVPixelBufferRef cvpx
)
73 /* will be freed by the vout */
74 struct cvpxpic_ctx
*ctx
= malloc(sizeof(struct cvpxpic_ctx
));
77 picture_Release(p_pic
);
80 ctx
->s
.destroy
= cvpxpic_destroy_cb
;
81 ctx
->s
.copy
= cvpxpic_copy_cb
;
82 ctx
->cvpx
= CVPixelBufferRetain(cvpx
);
83 p_pic
->context
= &ctx
->s
;
89 cvpxpic_get_ref(picture_t
*pic
)
91 assert(pic
->context
!= NULL
);
92 return ((struct cvpxpic_ctx
*)pic
->context
)->cvpx
;
96 cvpxpic_destroy_mapped_ro_cb(picture_t
*pic
)
98 CVPixelBufferRef cvpx
= (void *) pic
->p_sys
;
99 CVPixelBufferUnlockBaseAddress(cvpx
, kCVPixelBufferLock_ReadOnly
);
105 cvpxpic_destroy_mapped_rw_cb(picture_t
*pic
)
107 CVPixelBufferRef cvpx
= (void *) pic
->p_sys
;
108 CVPixelBufferUnlockBaseAddress(cvpx
, 0);
114 cvpxpic_create_mapped(const video_format_t
*fmt
, CVPixelBufferRef cvpx
,
117 unsigned planes_count
;
118 switch (fmt
->i_chroma
)
121 case VLC_CODEC_UYVY
: planes_count
= 0; break;
122 case VLC_CODEC_NV12
: planes_count
= 2; break;
123 case VLC_CODEC_I420
: planes_count
= 3; break;
124 default: return NULL
;
127 CVPixelBufferLockFlags lock
= readonly
? kCVPixelBufferLock_ReadOnly
: 0;
128 CVPixelBufferLockBaseAddress(cvpx
, lock
);
129 picture_resource_t rsc
= {
130 .p_sys
= (void *)cvpx
,
131 .pf_destroy
= readonly
? cvpxpic_destroy_mapped_ro_cb
132 : cvpxpic_destroy_mapped_rw_cb
,
136 assert(CVPixelBufferGetPlaneCount(cvpx
) == planes_count
);
139 if (planes_count
== 0)
141 rsc
.p
[0].p_pixels
= CVPixelBufferGetBaseAddress(cvpx
);
142 rsc
.p
[0].i_lines
= CVPixelBufferGetHeight(cvpx
);
143 rsc
.p
[0].i_pitch
= CVPixelBufferGetBytesPerRow(cvpx
);
147 for (unsigned i
= 0; i
< planes_count
; ++i
)
149 rsc
.p
[i
].p_pixels
= CVPixelBufferGetBaseAddressOfPlane(cvpx
, i
);
150 rsc
.p
[i
].i_lines
= CVPixelBufferGetHeightOfPlane(cvpx
, i
);
151 rsc
.p
[i
].i_pitch
= CVPixelBufferGetBytesPerRowOfPlane(cvpx
, i
);
155 picture_t
*pic
= picture_NewFromResource(fmt
, &rsc
);
158 CVPixelBufferUnlockBaseAddress(cvpx
, lock
);
161 CVPixelBufferRetain(cvpx
);
166 cvpxpic_unmap(picture_t
*mapped_pic
)
168 video_format_t fmt
= mapped_pic
->format
;
169 switch (fmt
.i_chroma
)
171 case VLC_CODEC_UYVY
: fmt
.i_chroma
= VLC_CODEC_CVPX_UYVY
; break;
172 case VLC_CODEC_NV12
: fmt
.i_chroma
= VLC_CODEC_CVPX_NV12
; break;
173 case VLC_CODEC_I420
: fmt
.i_chroma
= VLC_CODEC_CVPX_I420
; break;
174 case VLC_CODEC_BGRA
: fmt
.i_chroma
= VLC_CODEC_CVPX_BGRA
; break;
176 assert(!"invalid mapped_pic fmt");
177 picture_Release(mapped_pic
);
180 assert(mapped_pic
->p_sys
!= NULL
);
182 picture_t
*hw_pic
= picture_NewFromFormat(&fmt
);
185 picture_Release(mapped_pic
);
189 cvpxpic_attach(hw_pic
, (void *)mapped_pic
->p_sys
);
190 picture_CopyProperties(hw_pic
, mapped_pic
);
191 picture_Release(mapped_pic
);
196 cvpxpool_create(const video_format_t
*fmt
, unsigned count
)
199 switch (fmt
->i_chroma
)
201 case VLC_CODEC_CVPX_UYVY
:
202 cvpx_format
= kCVPixelFormatType_422YpCbCr8
;
204 case VLC_CODEC_CVPX_NV12
:
205 cvpx_format
= kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
;
207 case VLC_CODEC_CVPX_I420
:
208 cvpx_format
= kCVPixelFormatType_420YpCbCr8Planar
;
210 case VLC_CODEC_CVPX_BGRA
:
211 cvpx_format
= kCVPixelFormatType_32BGRA
;
217 /* destination pixel buffer attributes */
218 CFMutableDictionaryRef cvpx_attrs_dict
= cfdict_create(5);
219 if (unlikely(cvpx_attrs_dict
== NULL
))
221 CFMutableDictionaryRef pool_dict
= cfdict_create(2);
222 if (unlikely(pool_dict
== NULL
))
224 CFRelease(cvpx_attrs_dict
);
228 CFMutableDictionaryRef io_dict
= cfdict_create(0);
229 if (unlikely(io_dict
== NULL
))
231 CFRelease(cvpx_attrs_dict
);
232 CFRelease(pool_dict
);
235 CFDictionarySetValue(cvpx_attrs_dict
,
236 kCVPixelBufferIOSurfacePropertiesKey
, io_dict
);
239 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferBytesPerRowAlignmentKey
,
241 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferPixelFormatTypeKey
,
243 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferWidthKey
, fmt
->i_width
);
244 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferHeightKey
, fmt
->i_height
);
245 /* Required by CIFilter to render IOSurface */
246 cfdict_set_int32(cvpx_attrs_dict
, kCVPixelBufferBytesPerRowAlignmentKey
, 16);
248 cfdict_set_int32(pool_dict
, kCVPixelBufferPoolMinimumBufferCountKey
, count
);
249 cfdict_set_int32(pool_dict
, kCVPixelBufferPoolMaximumBufferAgeKey
, 0);
251 CVPixelBufferPoolRef pool
;
253 CVPixelBufferPoolCreate(NULL
, pool_dict
, cvpx_attrs_dict
, &pool
);
254 CFRelease(pool_dict
);
255 CFRelease(cvpx_attrs_dict
);
256 if (err
!= kCVReturnSuccess
)
259 CVPixelBufferRef cvpxs
[count
];
260 for (unsigned i
= 0; i
< count
; ++i
)
262 err
= CVPixelBufferPoolCreatePixelBuffer(NULL
, pool
, &cvpxs
[i
]);
263 if (err
!= kCVReturnSuccess
)
265 CVPixelBufferPoolRelease(pool
);
271 for (unsigned i
= 0; i
< count
; ++i
)
278 cvpxpool_new_cvpx(CVPixelBufferPoolRef pool
)
280 CVPixelBufferRef cvpx
;
281 CVReturn err
= CVPixelBufferPoolCreatePixelBuffer(NULL
, pool
, &cvpx
);
283 if (err
!= kCVReturnSuccess
)