1 /* $Id$ */
2 /*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #include <pjmedia/format.h>
21 #include <pj/assert.h>
22 #include <pj/errno.h>
23 #include <pj/pool.h>
24 #include <pj/string.h>
25
26
27 PJ_DEF(pjmedia_audio_format_detail*)
pjmedia_format_get_audio_format_detail(const pjmedia_format * fmt,pj_bool_t assert_valid)28 pjmedia_format_get_audio_format_detail(const pjmedia_format *fmt,
29 pj_bool_t assert_valid)
30 {
31 if (fmt->detail_type==PJMEDIA_FORMAT_DETAIL_AUDIO) {
32 return (pjmedia_audio_format_detail*) &fmt->det.aud;
33 } else {
34 /* Get rid of unused var compiler warning if pj_assert()
35 * macro does not do anything
36 */
37 PJ_UNUSED_ARG(assert_valid);
38 pj_assert(!assert_valid || !"Invalid audio format detail");
39 return NULL;
40 }
41 }
42
43
pjmedia_format_copy(pjmedia_format * dst,const pjmedia_format * src)44 PJ_DEF(pjmedia_format*) pjmedia_format_copy(pjmedia_format *dst,
45 const pjmedia_format *src)
46 {
47 return (pjmedia_format*)pj_memcpy(dst, src, sizeof(*src));
48 }
49
50
51 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
52
53
54 static pj_status_t apply_packed_fmt(const pjmedia_video_format_info *fi,
55 pjmedia_video_apply_fmt_param *aparam);
56
57 static pj_status_t apply_planar_420(const pjmedia_video_format_info *fi,
58 pjmedia_video_apply_fmt_param *aparam);
59
60 static pj_status_t apply_planar_422(const pjmedia_video_format_info *fi,
61 pjmedia_video_apply_fmt_param *aparam);
62
63 static pj_status_t apply_planar_444(const pjmedia_video_format_info *fi,
64 pjmedia_video_apply_fmt_param *aparam);
65
66 static pj_status_t apply_biplanar_420(const pjmedia_video_format_info *fi,
67 pjmedia_video_apply_fmt_param *aparam);
68
69 struct pjmedia_video_format_mgr
70 {
71 unsigned max_info;
72 unsigned info_cnt;
73 pjmedia_video_format_info **infos;
74 };
75
76 static pjmedia_video_format_mgr *video_format_mgr_instance;
77 static pjmedia_video_format_info built_in_vid_fmt_info[] =
78 {
79 {PJMEDIA_FORMAT_RGB24, "RGB24", PJMEDIA_COLOR_MODEL_RGB, 24, 1, &apply_packed_fmt},
80 {PJMEDIA_FORMAT_RGBA, "RGBA", PJMEDIA_COLOR_MODEL_RGB, 32, 1, &apply_packed_fmt},
81 {PJMEDIA_FORMAT_BGRA, "BGRA", PJMEDIA_COLOR_MODEL_RGB, 32, 1, &apply_packed_fmt},
82 {PJMEDIA_FORMAT_DIB , "DIB ", PJMEDIA_COLOR_MODEL_RGB, 24, 1, &apply_packed_fmt},
83 {PJMEDIA_FORMAT_GBRP, "GBRP", PJMEDIA_COLOR_MODEL_RGB, 24, 3, &apply_planar_444},
84 {PJMEDIA_FORMAT_AYUV, "AYUV", PJMEDIA_COLOR_MODEL_YUV, 32, 1, &apply_packed_fmt},
85 {PJMEDIA_FORMAT_YUY2, "YUY2", PJMEDIA_COLOR_MODEL_YUV, 16, 1, &apply_packed_fmt},
86 {PJMEDIA_FORMAT_UYVY, "UYVY", PJMEDIA_COLOR_MODEL_YUV, 16, 1, &apply_packed_fmt},
87 {PJMEDIA_FORMAT_YVYU, "YVYU", PJMEDIA_COLOR_MODEL_YUV, 16, 1, &apply_packed_fmt},
88 {PJMEDIA_FORMAT_I420, "I420", PJMEDIA_COLOR_MODEL_YUV, 12, 3, &apply_planar_420},
89 {PJMEDIA_FORMAT_YV12, "YV12", PJMEDIA_COLOR_MODEL_YUV, 12, 3, &apply_planar_420},
90 {PJMEDIA_FORMAT_I422, "I422", PJMEDIA_COLOR_MODEL_YUV, 16, 3, &apply_planar_422},
91 {PJMEDIA_FORMAT_I420JPEG, "I420JPG", PJMEDIA_COLOR_MODEL_YUV, 12, 3, &apply_planar_420},
92 {PJMEDIA_FORMAT_I422JPEG, "I422JPG", PJMEDIA_COLOR_MODEL_YUV, 16, 3, &apply_planar_422},
93 {PJMEDIA_FORMAT_NV12, "NV12", PJMEDIA_COLOR_MODEL_YUV, 12, 2, &apply_biplanar_420},
94 {PJMEDIA_FORMAT_NV21, "NV21", PJMEDIA_COLOR_MODEL_YUV, 12, 2, &apply_biplanar_420},
95 };
96
pjmedia_format_init_video(pjmedia_format * fmt,pj_uint32_t fmt_id,unsigned width,unsigned height,unsigned fps_num,unsigned fps_denum)97 PJ_DEF(void) pjmedia_format_init_video( pjmedia_format *fmt,
98 pj_uint32_t fmt_id,
99 unsigned width,
100 unsigned height,
101 unsigned fps_num,
102 unsigned fps_denum)
103 {
104 pj_assert(fps_denum);
105 fmt->id = fmt_id;
106 fmt->type = PJMEDIA_TYPE_VIDEO;
107 fmt->detail_type = PJMEDIA_FORMAT_DETAIL_VIDEO;
108
109 fmt->det.vid.size.w = width;
110 fmt->det.vid.size.h = height;
111 fmt->det.vid.fps.num = fps_num;
112 fmt->det.vid.fps.denum = fps_denum;
113 fmt->det.vid.avg_bps = fmt->det.vid.max_bps = 0;
114
115 if (pjmedia_video_format_mgr_instance()) {
116 const pjmedia_video_format_info *vfi;
117 pjmedia_video_apply_fmt_param vafp;
118 pj_uint32_t bps;
119
120 vfi = pjmedia_get_video_format_info(NULL, fmt->id);
121 if (vfi) {
122 pj_bzero(&vafp, sizeof(vafp));
123 vafp.size = fmt->det.vid.size;
124 vfi->apply_fmt(vfi, &vafp);
125
126 bps = (pj_uint32_t)((pj_uint64_t)vafp.framebytes * fps_num * 8 / fps_denum);
127 fmt->det.vid.avg_bps = fmt->det.vid.max_bps = bps;
128 }
129 }
130 }
131
132 PJ_DEF(pjmedia_video_format_detail*)
pjmedia_format_get_video_format_detail(const pjmedia_format * fmt,pj_bool_t assert_valid)133 pjmedia_format_get_video_format_detail(const pjmedia_format *fmt,
134 pj_bool_t assert_valid)
135 {
136 if (fmt->detail_type==PJMEDIA_FORMAT_DETAIL_VIDEO) {
137 return (pjmedia_video_format_detail*)&fmt->det.vid;
138 } else {
139 pj_assert(!assert_valid || !"Invalid video format detail");
140 return NULL;
141 }
142 }
143
144
apply_packed_fmt(const pjmedia_video_format_info * fi,pjmedia_video_apply_fmt_param * aparam)145 static pj_status_t apply_packed_fmt(const pjmedia_video_format_info *fi,
146 pjmedia_video_apply_fmt_param *aparam)
147 {
148 unsigned i;
149 pj_size_t stride;
150
151 stride = (pj_size_t)((aparam->size.w*fi->bpp) >> 3);
152
153 /* Calculate memsize */
154 aparam->framebytes = stride * aparam->size.h;
155
156 /* Packed formats only use 1 plane */
157 aparam->planes[0] = aparam->buffer;
158 aparam->strides[0] = (int)stride;
159 aparam->plane_bytes[0] = aparam->framebytes;
160
161 /* Zero unused planes */
162 for (i=1; i<PJMEDIA_MAX_VIDEO_PLANES; ++i) {
163 aparam->strides[i] = 0;
164 aparam->planes[i] = NULL;
165 }
166
167 return PJ_SUCCESS;
168 }
169
apply_planar_420(const pjmedia_video_format_info * fi,pjmedia_video_apply_fmt_param * aparam)170 static pj_status_t apply_planar_420(const pjmedia_video_format_info *fi,
171 pjmedia_video_apply_fmt_param *aparam)
172 {
173 unsigned i;
174 pj_size_t Y_bytes;
175
176 PJ_UNUSED_ARG(fi);
177
178 /* Calculate memsize */
179 Y_bytes = (pj_size_t)(aparam->size.w * aparam->size.h);
180 aparam->framebytes = Y_bytes + (Y_bytes>>1);
181
182 /* Planar formats use 3 plane */
183 aparam->strides[0] = aparam->size.w;
184 aparam->strides[1] = aparam->strides[2] = (aparam->size.w>>1);
185
186 aparam->planes[0] = aparam->buffer;
187 aparam->planes[1] = aparam->planes[0] + Y_bytes;
188 aparam->planes[2] = aparam->planes[1] + (Y_bytes>>2);
189
190 aparam->plane_bytes[0] = Y_bytes;
191 aparam->plane_bytes[1] = aparam->plane_bytes[2] = (Y_bytes>>2);
192
193 /* Zero unused planes */
194 for (i=3; i<PJMEDIA_MAX_VIDEO_PLANES; ++i) {
195 aparam->strides[i] = 0;
196 aparam->planes[i] = NULL;
197 aparam->plane_bytes[i] = 0;
198 }
199
200 return PJ_SUCCESS;
201 }
202
apply_planar_422(const pjmedia_video_format_info * fi,pjmedia_video_apply_fmt_param * aparam)203 static pj_status_t apply_planar_422(const pjmedia_video_format_info *fi,
204 pjmedia_video_apply_fmt_param *aparam)
205 {
206 unsigned i;
207 pj_size_t Y_bytes;
208
209 PJ_UNUSED_ARG(fi);
210
211 /* Calculate memsize */
212 Y_bytes = (pj_size_t)(aparam->size.w * aparam->size.h);
213 aparam->framebytes = (Y_bytes << 1);
214
215 /* Planar formats use 3 plane */
216 aparam->strides[0] = aparam->size.w;
217 aparam->strides[1] = aparam->strides[2] = (aparam->size.w>>1);
218
219 aparam->planes[0] = aparam->buffer;
220 aparam->planes[1] = aparam->planes[0] + Y_bytes;
221 aparam->planes[2] = aparam->planes[1] + (Y_bytes>>1);
222
223 aparam->plane_bytes[0] = Y_bytes;
224 aparam->plane_bytes[1] = aparam->plane_bytes[2] = (Y_bytes>>1);
225
226 /* Zero unused planes */
227 for (i=3; i<PJMEDIA_MAX_VIDEO_PLANES; ++i) {
228 aparam->strides[i] = 0;
229 aparam->planes[i] = NULL;
230 aparam->plane_bytes[i] = 0;
231 }
232
233 return PJ_SUCCESS;
234 }
235
apply_planar_444(const pjmedia_video_format_info * fi,pjmedia_video_apply_fmt_param * aparam)236 static pj_status_t apply_planar_444(const pjmedia_video_format_info *fi,
237 pjmedia_video_apply_fmt_param *aparam)
238 {
239 unsigned i;
240 pj_size_t Y_bytes;
241
242 PJ_UNUSED_ARG(fi);
243
244 /* Calculate memsize */
245 Y_bytes = (pj_size_t)(aparam->size.w * aparam->size.h);
246 aparam->framebytes = (Y_bytes * 3);
247
248 /* Planar formats use 3 plane */
249 aparam->strides[0] = aparam->strides[1] =
250 aparam->strides[2] = aparam->size.w;
251
252 aparam->planes[0] = aparam->buffer;
253 aparam->planes[1] = aparam->planes[0] + Y_bytes;
254 aparam->planes[2] = aparam->planes[1] + Y_bytes;
255
256 aparam->plane_bytes[0] = aparam->plane_bytes[1] =
257 aparam->plane_bytes[2] = Y_bytes;
258
259 /* Zero unused planes */
260 for (i=3; i<PJMEDIA_MAX_VIDEO_PLANES; ++i) {
261 aparam->strides[i] = 0;
262 aparam->planes[i] = NULL;
263 aparam->plane_bytes[i] = 0;
264 }
265
266 return PJ_SUCCESS;
267 }
268
apply_biplanar_420(const pjmedia_video_format_info * fi,pjmedia_video_apply_fmt_param * aparam)269 static pj_status_t apply_biplanar_420(const pjmedia_video_format_info *fi,
270 pjmedia_video_apply_fmt_param *aparam)
271 {
272 unsigned i;
273 pj_size_t Y_bytes;
274
275 PJ_UNUSED_ARG(fi);
276
277 /* Calculate memsize */
278 Y_bytes = (pj_size_t)(aparam->size.w * aparam->size.h);
279 aparam->framebytes = Y_bytes + (Y_bytes>>1);
280
281 /* Planar formats use 2 plane */
282 aparam->strides[0] = aparam->size.w;
283 aparam->strides[1] = aparam->size.w;
284
285 aparam->planes[0] = aparam->buffer;
286 aparam->planes[1] = aparam->planes[0] + Y_bytes;
287
288 aparam->plane_bytes[0] = Y_bytes;
289 aparam->plane_bytes[1] = (Y_bytes>>1);
290
291 /* Zero unused planes */
292 for (i=2; i<PJMEDIA_MAX_VIDEO_PLANES; ++i) {
293 aparam->strides[i] = 0;
294 aparam->planes[i] = NULL;
295 aparam->plane_bytes[i] = 0;
296 }
297
298 return PJ_SUCCESS;
299 }
300
301
302 PJ_DEF(pj_status_t)
pjmedia_video_format_mgr_create(pj_pool_t * pool,unsigned max_fmt,unsigned options,pjmedia_video_format_mgr ** p_mgr)303 pjmedia_video_format_mgr_create(pj_pool_t *pool,
304 unsigned max_fmt,
305 unsigned options,
306 pjmedia_video_format_mgr **p_mgr)
307 {
308 pjmedia_video_format_mgr *mgr;
309 unsigned i;
310
311 PJ_ASSERT_RETURN(pool && options==0, PJ_EINVAL);
312
313 PJ_UNUSED_ARG(options);
314
315 mgr = PJ_POOL_ALLOC_T(pool, pjmedia_video_format_mgr);
316 mgr->max_info = max_fmt;
317 mgr->info_cnt = 0;
318 mgr->infos = pj_pool_calloc(pool, max_fmt, sizeof(pjmedia_video_format_info *));
319
320 if (video_format_mgr_instance == NULL)
321 video_format_mgr_instance = mgr;
322
323 for (i=0; i<PJ_ARRAY_SIZE(built_in_vid_fmt_info); ++i) {
324 pjmedia_register_video_format_info(mgr,
325 &built_in_vid_fmt_info[i]);
326 }
327
328 if (p_mgr)
329 *p_mgr = mgr;
330
331 return PJ_SUCCESS;
332 }
333
334
335 PJ_DEF(const pjmedia_video_format_info*)
pjmedia_get_video_format_info(pjmedia_video_format_mgr * mgr,pj_uint32_t id)336 pjmedia_get_video_format_info(pjmedia_video_format_mgr *mgr,
337 pj_uint32_t id)
338 {
339 pjmedia_video_format_info **first;
340 unsigned n;
341
342 if (!mgr)
343 mgr = pjmedia_video_format_mgr_instance();
344
345 PJ_ASSERT_RETURN(mgr != NULL, NULL);
346
347 /* Binary search for the appropriate format id */
348 first = &mgr->infos[0];
349 n = mgr->info_cnt;
350 for (; n > 0; ) {
351 unsigned half = n / 2;
352 pjmedia_video_format_info **mid = first + half;
353
354 if ((*mid)->id < id) {
355 first = ++mid;
356 n -= half + 1;
357 } else if ((*mid)->id==id) {
358 return *mid;
359 } else {
360 n = half;
361 }
362 }
363
364 return NULL;
365 }
366
367
368 PJ_DEF(pj_status_t)
pjmedia_register_video_format_info(pjmedia_video_format_mgr * mgr,pjmedia_video_format_info * info)369 pjmedia_register_video_format_info(pjmedia_video_format_mgr *mgr,
370 pjmedia_video_format_info *info)
371 {
372 unsigned i;
373
374 if (!mgr)
375 mgr = pjmedia_video_format_mgr_instance();
376
377 PJ_ASSERT_RETURN(mgr != NULL, PJ_EINVALIDOP);
378
379 if (mgr->info_cnt >= mgr->max_info)
380 return PJ_ETOOMANY;
381
382 /* Insert to the array, sorted */
383 for (i=0; i<mgr->info_cnt; ++i) {
384 if (mgr->infos[i]->id >= info->id)
385 break;
386 }
387
388 if (i < mgr->info_cnt) {
389 if (mgr->infos[i]->id == info->id) {
390 /* just overwrite */
391 mgr->infos[i] = info;
392 return PJ_SUCCESS;
393 }
394
395 pj_memmove(&mgr->infos[i+1], &mgr->infos[i],
396 (mgr->info_cnt - i) * sizeof(pjmedia_video_format_info*));
397 }
398
399 mgr->infos[i] = info;
400 mgr->info_cnt++;
401
402 return PJ_SUCCESS;
403 }
404
pjmedia_video_format_mgr_instance(void)405 PJ_DEF(pjmedia_video_format_mgr*) pjmedia_video_format_mgr_instance(void)
406 {
407 pj_assert(video_format_mgr_instance != NULL);
408 return video_format_mgr_instance;
409 }
410
411 PJ_DEF(void)
pjmedia_video_format_mgr_set_instance(pjmedia_video_format_mgr * mgr)412 pjmedia_video_format_mgr_set_instance(pjmedia_video_format_mgr *mgr)
413 {
414 video_format_mgr_instance = mgr;
415 }
416
417
pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr * mgr)418 PJ_DEF(void) pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr *mgr)
419 {
420 if (!mgr)
421 mgr = pjmedia_video_format_mgr_instance();
422
423 PJ_ASSERT_ON_FAIL(mgr != NULL, return);
424
425 mgr->info_cnt = 0;
426 if (video_format_mgr_instance == mgr)
427 video_format_mgr_instance = NULL;
428 }
429
430 #endif /* PJMEDIA_HAS_VIDEO */
431