demux: mp4: avoid audio cuts on seek
[vlc.git] / modules / codec / vt_utils.c
blob943f39945cc1e14ff1a1616b6b5a91d77adf3c68
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 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include "vt_utils.h"
27 CFMutableDictionaryRef
28 cfdict_create(CFIndex capacity)
30 return CFDictionaryCreateMutable(kCFAllocatorDefault, capacity,
31 &kCFTypeDictionaryKeyCallBacks,
32 &kCFTypeDictionaryValueCallBacks);
35 void
36 cfdict_set_int32(CFMutableDictionaryRef dict, CFStringRef key, int value)
38 CFNumberRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
39 CFDictionarySetValue(dict, key, number);
40 CFRelease(number);
43 struct cvpxpic_ctx
45 picture_context_t s;
46 CVPixelBufferRef cvpx;
49 static void
50 cvpxpic_destroy_cb(picture_context_t *opaque)
52 struct cvpxpic_ctx *ctx = (struct cvpxpic_ctx *)opaque;
54 CFRelease(ctx->cvpx);
55 free(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));
63 if (dst_ctx == NULL)
64 return NULL;
65 *dst_ctx = *src_ctx;
66 dst_ctx->cvpx = CVPixelBufferRetain(dst_ctx->cvpx);
67 return &dst_ctx->s;
70 int
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));
75 if (ctx == NULL)
77 picture_Release(p_pic);
78 return VLC_ENOMEM;
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;
85 return VLC_SUCCESS;
88 CVPixelBufferRef
89 cvpxpic_get_ref(picture_t *pic)
91 assert(pic->context != NULL);
92 return ((struct cvpxpic_ctx *)pic->context)->cvpx;
95 static void
96 cvpxpic_destroy_mapped_ro_cb(picture_t *pic)
98 CVPixelBufferRef cvpx = (void *) pic->p_sys;
99 CVPixelBufferUnlockBaseAddress(cvpx, kCVPixelBufferLock_ReadOnly);
100 CFRelease(cvpx);
101 free(pic);
104 static void
105 cvpxpic_destroy_mapped_rw_cb(picture_t *pic)
107 CVPixelBufferRef cvpx = (void *) pic->p_sys;
108 CVPixelBufferUnlockBaseAddress(cvpx, 0);
109 CFRelease(cvpx);
110 free(pic);
113 picture_t *
114 cvpxpic_create_mapped(const video_format_t *fmt, CVPixelBufferRef cvpx,
115 bool readonly)
117 unsigned planes_count;
118 switch (fmt->i_chroma)
120 case VLC_CODEC_BGRA:
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,
135 #ifndef NDEBUG
136 assert(CVPixelBufferGetPlaneCount(cvpx) == planes_count);
137 #endif
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);
145 else
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);
156 if (pic == NULL)
158 CVPixelBufferUnlockBaseAddress(cvpx, lock);
159 return NULL;
161 CVPixelBufferRetain(cvpx);
162 return pic;
165 picture_t *
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;
175 default:
176 assert(!"invalid mapped_pic fmt");
177 picture_Release(mapped_pic);
178 return NULL;
180 assert(mapped_pic->p_sys != NULL);
182 picture_t *hw_pic = picture_NewFromFormat(&fmt);
183 if (hw_pic == NULL)
185 picture_Release(mapped_pic);
186 return NULL;
189 cvpxpic_attach(hw_pic, (void *)mapped_pic->p_sys);
190 picture_CopyProperties(hw_pic, mapped_pic);
191 picture_Release(mapped_pic);
192 return hw_pic;
195 CVPixelBufferPoolRef
196 cvpxpool_create(const video_format_t *fmt, unsigned count)
198 int cvpx_format;
199 switch (fmt->i_chroma)
201 case VLC_CODEC_CVPX_UYVY:
202 cvpx_format = kCVPixelFormatType_422YpCbCr8;
203 break;
204 case VLC_CODEC_CVPX_NV12:
205 cvpx_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
206 break;
207 case VLC_CODEC_CVPX_I420:
208 cvpx_format = kCVPixelFormatType_420YpCbCr8Planar;
209 break;
210 case VLC_CODEC_CVPX_BGRA:
211 cvpx_format = kCVPixelFormatType_32BGRA;
212 break;
213 default:
214 return NULL;
217 /* destination pixel buffer attributes */
218 CFMutableDictionaryRef cvpx_attrs_dict = cfdict_create(5);
219 if (unlikely(cvpx_attrs_dict == NULL))
220 return NULL;
221 CFMutableDictionaryRef pool_dict = cfdict_create(2);
222 if (unlikely(pool_dict == NULL))
224 CFRelease(cvpx_attrs_dict);
225 return NULL;
228 CFMutableDictionaryRef io_dict = cfdict_create(0);
229 if (unlikely(io_dict == NULL))
231 CFRelease(cvpx_attrs_dict);
232 CFRelease(pool_dict);
233 return NULL;
235 CFDictionarySetValue(cvpx_attrs_dict,
236 kCVPixelBufferIOSurfacePropertiesKey, io_dict);
237 CFRelease(io_dict);
239 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferBytesPerRowAlignmentKey,
240 fmt->i_width);
241 cfdict_set_int32(cvpx_attrs_dict, kCVPixelBufferPixelFormatTypeKey,
242 cvpx_format);
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;
252 CVReturn err =
253 CVPixelBufferPoolCreate(NULL, pool_dict, cvpx_attrs_dict, &pool);
254 CFRelease(pool_dict);
255 CFRelease(cvpx_attrs_dict);
256 if (err != kCVReturnSuccess)
257 return NULL;
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);
266 pool = NULL;
267 count = i;
268 break;
271 for (unsigned i = 0; i < count; ++i)
272 CFRelease(cvpxs[i]);
274 return pool;
277 CVPixelBufferRef
278 cvpxpool_new_cvpx(CVPixelBufferPoolRef pool)
280 CVPixelBufferRef cvpx;
281 CVReturn err = CVPixelBufferPoolCreatePixelBuffer(NULL, pool, &cvpx);
283 if (err != kCVReturnSuccess)
284 return NULL;
286 return cvpx;