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