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/vid_codec.h>
21 #include <pjmedia/errno.h>
22 #include <pj/array.h>
23 #include <pj/assert.h>
24 #include <pj/log.h>
25 #include <pj/string.h>
26 
27 
28 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
29 
30 
31 #define THIS_FILE   "vid_codec.c"
32 
33 static pjmedia_vid_codec_mgr *def_vid_codec_mgr;
34 
35 
36 /* Definition of default codecs parameters */
37 typedef struct pjmedia_vid_codec_default_param
38 {
39     pj_pool_t			*pool;
40     pjmedia_vid_codec_param	*param;
41 } pjmedia_vid_codec_default_param;
42 
43 
44 /*
45  * Codec manager maintains array of these structs for each supported
46  * codec.
47  */
48 typedef struct pjmedia_vid_codec_desc
49 {
50     pjmedia_vid_codec_info	     info;	/**< Codec info.	    */
51     pjmedia_codec_id	             id;        /**< Fully qualified name   */
52     pjmedia_codec_priority           prio;      /**< Priority.		    */
53     pjmedia_vid_codec_factory       *factory;	/**< The factory.	    */
54     pjmedia_vid_codec_default_param *def_param; /**< Default codecs
55 					             parameters.	    */
56 } pjmedia_vid_codec_desc;
57 
58 
59 /* The declaration of video codec manager */
60 struct pjmedia_vid_codec_mgr
61 {
62     /** Pool factory instance. */
63     pj_pool_factory		*pf;
64 
65     /** Codec manager mutex. */
66     pj_mutex_t			*mutex;
67 
68     /** List of codec factories registered to codec manager. */
69     pjmedia_vid_codec_factory	 factory_list;
70 
71     /** Number of supported codecs. */
72     unsigned			 codec_cnt;
73 
74     /** Array of codec descriptor. */
75     pjmedia_vid_codec_desc	 codec_desc[PJMEDIA_CODEC_MGR_MAX_CODECS];
76 
77 };
78 
79 
80 
81 /* Sort codecs in codec manager based on priorities */
82 static void sort_codecs(pjmedia_vid_codec_mgr *mgr);
83 
84 
85 /*
86  * Duplicate video codec parameter.
87  */
pjmedia_vid_codec_param_clone(pj_pool_t * pool,const pjmedia_vid_codec_param * src)88 PJ_DEF(pjmedia_vid_codec_param*) pjmedia_vid_codec_param_clone(
89 					pj_pool_t *pool,
90 					const pjmedia_vid_codec_param *src)
91 {
92     pjmedia_vid_codec_param *p;
93     unsigned i;
94 
95     PJ_ASSERT_RETURN(pool && src, NULL);
96 
97     p = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec_param);
98 
99     /* Update codec param */
100     pj_memcpy(p, src, sizeof(pjmedia_vid_codec_param));
101     for (i = 0; i < src->dec_fmtp.cnt; ++i) {
102 	pj_strdup(pool, &p->dec_fmtp.param[i].name,
103 		  &src->dec_fmtp.param[i].name);
104 	pj_strdup(pool, &p->dec_fmtp.param[i].val,
105 		  &src->dec_fmtp.param[i].val);
106     }
107     for (i = 0; i < src->enc_fmtp.cnt; ++i) {
108 	pj_strdup(pool, &p->enc_fmtp.param[i].name,
109 		  &src->enc_fmtp.param[i].name);
110 	pj_strdup(pool, &p->enc_fmtp.param[i].val,
111 		  &src->enc_fmtp.param[i].val);
112     }
113 
114     return p;
115 }
116 
117 /*
118  * Initialize codec manager.
119  */
pjmedia_vid_codec_mgr_create(pj_pool_t * pool,pjmedia_vid_codec_mgr ** p_mgr)120 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_create(
121                                             pj_pool_t *pool,
122                                             pjmedia_vid_codec_mgr **p_mgr)
123 {
124     pjmedia_vid_codec_mgr *mgr;
125     pj_status_t status;
126 
127     PJ_ASSERT_RETURN(pool, PJ_EINVAL);
128 
129     mgr = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec_mgr);
130     mgr->pf = pool->factory;
131     pj_list_init (&mgr->factory_list);
132     mgr->codec_cnt = 0;
133 
134     /* Create mutex */
135     status = pj_mutex_create_recursive(pool, "vid-codec-mgr", &mgr->mutex);
136     if (status != PJ_SUCCESS)
137 	return status;
138 
139     if (!def_vid_codec_mgr)
140         def_vid_codec_mgr = mgr;
141 
142     if (p_mgr)
143         *p_mgr = mgr;
144 
145     return PJ_SUCCESS;
146 }
147 
148 /*
149  * Initialize codec manager.
150  */
pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr * mgr)151 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_destroy (pjmedia_vid_codec_mgr *mgr)
152 {
153     if (!mgr) mgr = def_vid_codec_mgr;
154     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
155 
156     /* Destroy mutex */
157     if (mgr->mutex)
158 	pj_mutex_destroy(mgr->mutex);
159 
160     /* Just for safety, set codec manager states to zero */
161     pj_bzero(mgr, sizeof(pjmedia_vid_codec_mgr));
162 
163     if (mgr == def_vid_codec_mgr)
164         def_vid_codec_mgr = NULL;
165 
166     return PJ_SUCCESS;
167 }
168 
169 
pjmedia_vid_codec_mgr_instance(void)170 PJ_DEF(pjmedia_vid_codec_mgr*) pjmedia_vid_codec_mgr_instance(void)
171 {
172     //pj_assert(def_vid_codec_mgr);
173     return def_vid_codec_mgr;
174 }
175 
pjmedia_vid_codec_mgr_set_instance(pjmedia_vid_codec_mgr * mgr)176 PJ_DEF(void) pjmedia_vid_codec_mgr_set_instance(pjmedia_vid_codec_mgr* mgr)
177 {
178     def_vid_codec_mgr = mgr;
179 }
180 
181 
182 /*
183  * Register a codec factory.
184  */
pjmedia_vid_codec_mgr_register_factory(pjmedia_vid_codec_mgr * mgr,pjmedia_vid_codec_factory * factory)185 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_register_factory(
186                                     pjmedia_vid_codec_mgr *mgr,
187 				    pjmedia_vid_codec_factory *factory)
188 {
189     pjmedia_vid_codec_info info[PJMEDIA_CODEC_MGR_MAX_CODECS];
190     unsigned i, count;
191     pj_status_t status;
192 
193     PJ_ASSERT_RETURN(factory, PJ_EINVAL);
194 
195     if (!mgr) mgr = def_vid_codec_mgr;
196     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
197 
198     /* Enum codecs */
199     count = PJ_ARRAY_SIZE(info);
200     status = factory->op->enum_info(factory, &count, info);
201     if (status != PJ_SUCCESS)
202 	return status;
203 
204     pj_mutex_lock(mgr->mutex);
205 
206     /* Check codec count */
207     if (count + mgr->codec_cnt > PJ_ARRAY_SIZE(mgr->codec_desc)) {
208 	pj_mutex_unlock(mgr->mutex);
209 	return PJ_ETOOMANY;
210     }
211 
212 
213     /* Save the codecs */
214     for (i=0; i<count; ++i) {
215 	pj_memcpy( &mgr->codec_desc[mgr->codec_cnt+i],
216 		   &info[i], sizeof(pjmedia_vid_codec_info));
217 	mgr->codec_desc[mgr->codec_cnt+i].prio = PJMEDIA_CODEC_PRIO_NORMAL;
218 	mgr->codec_desc[mgr->codec_cnt+i].factory = factory;
219 	pjmedia_vid_codec_info_to_id( &info[i],
220 				  mgr->codec_desc[mgr->codec_cnt+i].id,
221 				  sizeof(pjmedia_codec_id));
222     }
223 
224     /* Update count */
225     mgr->codec_cnt += count;
226 
227     /* Re-sort codec based on priorities */
228     sort_codecs(mgr);
229 
230     /* Add factory to the list */
231     pj_list_push_back(&mgr->factory_list, factory);
232 
233     pj_mutex_unlock(mgr->mutex);
234 
235     return PJ_SUCCESS;
236 }
237 
238 
239 /*
240  * Unregister a codec factory.
241  */
pjmedia_vid_codec_mgr_unregister_factory(pjmedia_vid_codec_mgr * mgr,pjmedia_vid_codec_factory * factory)242 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_unregister_factory(
243 				pjmedia_vid_codec_mgr *mgr,
244 				pjmedia_vid_codec_factory *factory)
245 {
246     unsigned i;
247     PJ_ASSERT_RETURN(factory, PJ_EINVAL);
248 
249     if (!mgr) mgr = def_vid_codec_mgr;
250     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
251 
252     pj_mutex_lock(mgr->mutex);
253 
254     /* Factory must be registered. */
255     if (pj_list_find_node(&mgr->factory_list, factory) != factory) {
256 	pj_mutex_unlock(mgr->mutex);
257 	return PJ_ENOTFOUND;
258     }
259 
260     /* Erase factory from the factory list */
261     pj_list_erase(factory);
262 
263 
264     /* Remove all supported codecs from the codec manager that were created
265      * by the specified factory.
266      */
267     for (i=0; i<mgr->codec_cnt; ) {
268 
269 	if (mgr->codec_desc[i].factory == factory) {
270 	    /* Remove the codec from array of codec descriptions */
271 	    pj_array_erase(mgr->codec_desc, sizeof(mgr->codec_desc[0]),
272 			   mgr->codec_cnt, i);
273 	    --mgr->codec_cnt;
274 
275 	} else {
276 	    ++i;
277 	}
278     }
279 
280     pj_mutex_unlock(mgr->mutex);
281 
282     return PJ_SUCCESS;
283 }
284 
285 
286 /*
287  * Enum all codecs.
288  */
pjmedia_vid_codec_mgr_enum_codecs(pjmedia_vid_codec_mgr * mgr,unsigned * count,pjmedia_vid_codec_info codecs[],unsigned * prio)289 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_enum_codecs(
290                                 pjmedia_vid_codec_mgr *mgr,
291 			        unsigned *count,
292 			        pjmedia_vid_codec_info codecs[],
293 			        unsigned *prio)
294 {
295     unsigned i;
296 
297     PJ_ASSERT_RETURN(count && codecs, PJ_EINVAL);
298 
299     if (!mgr) mgr = def_vid_codec_mgr;
300     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
301 
302     pj_mutex_lock(mgr->mutex);
303 
304     if (*count > mgr->codec_cnt)
305 	*count = mgr->codec_cnt;
306 
307     for (i=0; i<*count; ++i) {
308 	pj_memcpy(&codecs[i],
309 		  &mgr->codec_desc[i].info,
310 		  sizeof(pjmedia_vid_codec_info));
311     }
312 
313     if (prio) {
314 	for (i=0; i < *count; ++i)
315 	    prio[i] = mgr->codec_desc[i].prio;
316     }
317 
318     pj_mutex_unlock(mgr->mutex);
319 
320     return PJ_SUCCESS;
321 }
322 
323 
324 /*
325  * Get codec info for the specified payload type.
326  */
pjmedia_vid_codec_mgr_get_codec_info(pjmedia_vid_codec_mgr * mgr,unsigned pt,const pjmedia_vid_codec_info ** p_info)327 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_get_codec_info(
328                                     pjmedia_vid_codec_mgr *mgr,
329 				    unsigned pt,
330 				    const pjmedia_vid_codec_info **p_info)
331 {
332     unsigned i;
333 
334     PJ_ASSERT_RETURN(p_info, PJ_EINVAL);
335 
336     if (!mgr) mgr = def_vid_codec_mgr;
337     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
338 
339     pj_mutex_lock(mgr->mutex);
340 
341     for (i=0; i<mgr->codec_cnt; ++i) {
342 	if (mgr->codec_desc[i].info.pt == pt) {
343 	    *p_info = &mgr->codec_desc[i].info;
344 
345 	    pj_mutex_unlock(mgr->mutex);
346 	    return PJ_SUCCESS;
347 	}
348     }
349 
350     pj_mutex_unlock(mgr->mutex);
351 
352     return PJMEDIA_CODEC_EUNSUP;
353 }
354 
355 
pjmedia_vid_codec_mgr_get_codec_info2(pjmedia_vid_codec_mgr * mgr,pjmedia_format_id fmt_id,const pjmedia_vid_codec_info ** p_info)356 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_get_codec_info2(
357 				    pjmedia_vid_codec_mgr *mgr,
358 				    pjmedia_format_id fmt_id,
359 				    const pjmedia_vid_codec_info **p_info)
360 {
361     unsigned i;
362 
363     PJ_ASSERT_RETURN(p_info, PJ_EINVAL);
364 
365     if (!mgr) mgr = def_vid_codec_mgr;
366     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
367 
368     pj_mutex_lock(mgr->mutex);
369 
370     for (i=0; i<mgr->codec_cnt; ++i) {
371 	if (mgr->codec_desc[i].info.fmt_id == fmt_id) {
372 	    *p_info = &mgr->codec_desc[i].info;
373 
374 	    pj_mutex_unlock(mgr->mutex);
375 	    return PJ_SUCCESS;
376 	}
377     }
378 
379     pj_mutex_unlock(mgr->mutex);
380 
381     return PJMEDIA_CODEC_EUNSUP;
382 }
383 
384 
385 /*
386  * Convert codec info struct into a unique codec identifier.
387  * A codec identifier looks something like "H263/34".
388  */
pjmedia_vid_codec_info_to_id(const pjmedia_vid_codec_info * info,char * id,unsigned max_len)389 PJ_DEF(char*) pjmedia_vid_codec_info_to_id(
390                                         const pjmedia_vid_codec_info *info,
391 				        char *id, unsigned max_len )
392 {
393     int len;
394 
395     PJ_ASSERT_RETURN(info && id && max_len, NULL);
396 
397     len = pj_ansi_snprintf(id, max_len, "%.*s/%u",
398 			   (int)info->encoding_name.slen,
399 			   info->encoding_name.ptr,
400 			   info->pt);
401 
402     if (len < 1 || len >= (int)max_len) {
403 	id[0] = '\0';
404 	return NULL;
405     }
406 
407     return id;
408 }
409 
410 
411 /*
412  * Find codecs by the unique codec identifier.
413  */
pjmedia_vid_codec_mgr_find_codecs_by_id(pjmedia_vid_codec_mgr * mgr,const pj_str_t * codec_id,unsigned * count,const pjmedia_vid_codec_info * p_info[],unsigned prio[])414 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_find_codecs_by_id(
415                                      pjmedia_vid_codec_mgr *mgr,
416 				     const pj_str_t *codec_id,
417 				     unsigned *count,
418 				     const pjmedia_vid_codec_info *p_info[],
419 				     unsigned prio[])
420 {
421     unsigned i, found = 0;
422 
423     PJ_ASSERT_RETURN(codec_id && count && *count, PJ_EINVAL);
424 
425     if (!mgr) mgr = def_vid_codec_mgr;
426     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
427 
428     pj_mutex_lock(mgr->mutex);
429 
430     for (i=0; i<mgr->codec_cnt; ++i) {
431 
432 	if (codec_id->slen == 0 ||
433 	    pj_strnicmp2(codec_id, mgr->codec_desc[i].id,
434 			 codec_id->slen) == 0)
435 	{
436 
437 	    if (p_info)
438 		p_info[found] = &mgr->codec_desc[i].info;
439 	    if (prio)
440 		prio[found] = mgr->codec_desc[i].prio;
441 
442 	    ++found;
443 
444 	    if (found >= *count)
445 		break;
446 	}
447 
448     }
449 
450     pj_mutex_unlock(mgr->mutex);
451 
452     *count = found;
453 
454     return found ? PJ_SUCCESS : PJ_ENOTFOUND;
455 }
456 
457 
458 /* Swap two codecs positions in codec manager */
swap_codec(pjmedia_vid_codec_mgr * mgr,unsigned i,unsigned j)459 static void swap_codec(pjmedia_vid_codec_mgr *mgr, unsigned i, unsigned j)
460 {
461     pjmedia_vid_codec_desc tmp;
462 
463     pj_memcpy(&tmp, &mgr->codec_desc[i], sizeof(pjmedia_vid_codec_desc));
464 
465     pj_memcpy(&mgr->codec_desc[i], &mgr->codec_desc[j],
466 	       sizeof(pjmedia_vid_codec_desc));
467 
468     pj_memcpy(&mgr->codec_desc[j], &tmp, sizeof(pjmedia_vid_codec_desc));
469 }
470 
471 
472 /* Sort codecs in codec manager based on priorities */
sort_codecs(pjmedia_vid_codec_mgr * mgr)473 static void sort_codecs(pjmedia_vid_codec_mgr *mgr)
474 {
475     unsigned i;
476 
477    /* Re-sort */
478     for (i=0; i<mgr->codec_cnt; ++i) {
479 	unsigned j, max;
480 
481 	for (max=i, j=i+1; j<mgr->codec_cnt; ++j) {
482 	    if (mgr->codec_desc[j].prio > mgr->codec_desc[max].prio)
483 		max = j;
484 	}
485 
486 	if (max != i)
487 	    swap_codec(mgr, i, max);
488     }
489 
490     /* Change PJMEDIA_CODEC_PRIO_HIGHEST codecs to NEXT_HIGHER */
491     for (i=0; i<mgr->codec_cnt; ++i) {
492 	if (mgr->codec_desc[i].prio == PJMEDIA_CODEC_PRIO_HIGHEST)
493 	    mgr->codec_desc[i].prio = PJMEDIA_CODEC_PRIO_NEXT_HIGHER;
494 	else
495 	    break;
496     }
497 }
498 
499 
500 /**
501  * Set codec priority. The codec priority determines the order of
502  * the codec in the SDP created by the endpoint. If more than one codecs
503  * are found with the same codec_id prefix, then the function sets the
504  * priorities of all those codecs.
505  */
pjmedia_vid_codec_mgr_set_codec_priority(pjmedia_vid_codec_mgr * mgr,const pj_str_t * codec_id,pj_uint8_t prio)506 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_set_codec_priority(
507 				pjmedia_vid_codec_mgr *mgr,
508 				const pj_str_t *codec_id,
509 				pj_uint8_t prio)
510 {
511     unsigned i, found = 0;
512 
513     PJ_ASSERT_RETURN(codec_id, PJ_EINVAL);
514 
515     if (!mgr) mgr = def_vid_codec_mgr;
516     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
517 
518     pj_mutex_lock(mgr->mutex);
519 
520     /* Update the priorities of affected codecs */
521     for (i=0; i<mgr->codec_cnt; ++i)
522     {
523 	if (codec_id->slen == 0 ||
524 	    pj_strnicmp2(codec_id, mgr->codec_desc[i].id,
525 			 codec_id->slen) == 0)
526 	{
527 	    mgr->codec_desc[i].prio = (pjmedia_codec_priority) prio;
528 	    ++found;
529 	}
530     }
531 
532     if (!found) {
533 	pj_mutex_unlock(mgr->mutex);
534 	return PJ_ENOTFOUND;
535     }
536 
537     /* Re-sort codecs */
538     sort_codecs(mgr);
539 
540     pj_mutex_unlock(mgr->mutex);
541 
542     return PJ_SUCCESS;
543 }
544 
545 
546 /*
547  * Allocate one codec.
548  */
pjmedia_vid_codec_mgr_alloc_codec(pjmedia_vid_codec_mgr * mgr,const pjmedia_vid_codec_info * info,pjmedia_vid_codec ** p_codec)549 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_alloc_codec(
550                                         pjmedia_vid_codec_mgr *mgr,
551 					const pjmedia_vid_codec_info *info,
552 					pjmedia_vid_codec **p_codec)
553 {
554     pjmedia_vid_codec_factory *factory;
555     pj_status_t status;
556 
557     PJ_ASSERT_RETURN(info && p_codec, PJ_EINVAL);
558 
559     if (!mgr) mgr = def_vid_codec_mgr;
560     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
561 
562     *p_codec = NULL;
563 
564     pj_mutex_lock(mgr->mutex);
565 
566     factory = mgr->factory_list.next;
567     while (factory != &mgr->factory_list) {
568 
569 	if ( (*factory->op->test_alloc)(factory, info) == PJ_SUCCESS ) {
570 
571 	    status = (*factory->op->alloc_codec)(factory, info, p_codec);
572 	    if (status == PJ_SUCCESS) {
573 		pj_mutex_unlock(mgr->mutex);
574 		return PJ_SUCCESS;
575 	    }
576 
577 	}
578 
579 	factory = factory->next;
580     }
581 
582     pj_mutex_unlock(mgr->mutex);
583 
584     return PJMEDIA_CODEC_EUNSUP;
585 }
586 
587 
588 /*
589  * Get default codec parameter.
590  */
pjmedia_vid_codec_mgr_get_default_param(pjmedia_vid_codec_mgr * mgr,const pjmedia_vid_codec_info * info,pjmedia_vid_codec_param * param)591 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_get_default_param(
592                                         pjmedia_vid_codec_mgr *mgr,
593 					const pjmedia_vid_codec_info *info,
594 					pjmedia_vid_codec_param *param )
595 {
596     pjmedia_vid_codec_factory *factory;
597     pj_status_t status;
598     pjmedia_codec_id codec_id;
599     pjmedia_vid_codec_desc *codec_desc = NULL;
600     unsigned i;
601 
602     PJ_ASSERT_RETURN(info && param, PJ_EINVAL);
603 
604     if (!mgr) mgr = def_vid_codec_mgr;
605     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
606 
607     if (!pjmedia_vid_codec_info_to_id(info, (char*)&codec_id,
608                                       sizeof(codec_id)))
609 	return PJ_EINVAL;
610 
611     pj_mutex_lock(mgr->mutex);
612 
613     /* First, lookup default param in codec desc */
614     for (i=0; i < mgr->codec_cnt; ++i) {
615 	if (pj_ansi_stricmp(codec_id, mgr->codec_desc[i].id) == 0) {
616 	    codec_desc = &mgr->codec_desc[i];
617 	    break;
618 	}
619     }
620 
621     /* If we found the codec and its default param is set, return it */
622     if (codec_desc && codec_desc->def_param) {
623 	pj_memcpy(param, codec_desc->def_param->param,
624 		  sizeof(pjmedia_vid_codec_param));
625 
626 	pj_mutex_unlock(mgr->mutex);
627 	return PJ_SUCCESS;
628     }
629 
630     /* Otherwise query the default param from codec factory */
631     factory = mgr->factory_list.next;
632     while (factory != &mgr->factory_list) {
633 
634 	if ( (*factory->op->test_alloc)(factory, info) == PJ_SUCCESS ) {
635 
636 	    status = (*factory->op->default_attr)(factory, info, param);
637 	    if (status == PJ_SUCCESS) {
638 		/* Check for invalid max_bps. */
639 		//if (param->info.max_bps < param->info.avg_bps)
640 		//    param->info.max_bps = param->info.avg_bps;
641 
642 		pj_mutex_unlock(mgr->mutex);
643 		return PJ_SUCCESS;
644 	    }
645 
646 	}
647 
648 	factory = factory->next;
649     }
650 
651     pj_mutex_unlock(mgr->mutex);
652 
653 
654     return PJMEDIA_CODEC_EUNSUP;
655 }
656 
657 
658 /*
659  * Set default codec parameter.
660  */
pjmedia_vid_codec_mgr_set_default_param(pjmedia_vid_codec_mgr * mgr,const pjmedia_vid_codec_info * info,const pjmedia_vid_codec_param * param)661 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_set_default_param(
662 					    pjmedia_vid_codec_mgr *mgr,
663 					    const pjmedia_vid_codec_info *info,
664 					    const pjmedia_vid_codec_param *param )
665 {
666     unsigned i;
667     pjmedia_codec_id codec_id;
668     pjmedia_vid_codec_desc *codec_desc = NULL;
669     pj_pool_t *pool, *old_pool = NULL;
670     pjmedia_vid_codec_default_param *p;
671 
672     PJ_ASSERT_RETURN(info, PJ_EINVAL);
673 
674     if (!mgr) mgr = def_vid_codec_mgr;
675     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
676 
677     if (!pjmedia_vid_codec_info_to_id(info, (char*)&codec_id, sizeof(codec_id)))
678 	return PJ_EINVAL;
679 
680     pj_mutex_lock(mgr->mutex);
681 
682     /* Lookup codec desc */
683     for (i=0; i < mgr->codec_cnt; ++i) {
684 	if (pj_ansi_stricmp(codec_id, mgr->codec_desc[i].id) == 0) {
685 	    codec_desc = &mgr->codec_desc[i];
686 	    break;
687 	}
688     }
689 
690     /* Codec not found */
691     if (!codec_desc) {
692 	pj_mutex_unlock(mgr->mutex);
693 	return PJMEDIA_CODEC_EUNSUP;
694     }
695 
696     /* If codec param is previously set */
697     if (codec_desc->def_param) {
698 	pj_assert(codec_desc->def_param->pool);
699         old_pool = codec_desc->def_param->pool;
700 	codec_desc->def_param = NULL;
701     }
702 
703     /* When param is set to NULL, i.e: setting default codec param to library
704      * default setting, just return PJ_SUCCESS.
705      */
706     if (NULL == param) {
707 	pj_mutex_unlock(mgr->mutex);
708         if (old_pool)
709 	    pj_pool_release(old_pool);
710 	return PJ_SUCCESS;
711     }
712 
713     /* Create new default codec param instance */
714     pool = pj_pool_create(mgr->pf, (char*)codec_id, 256, 256, NULL);
715     codec_desc->def_param = PJ_POOL_ZALLOC_T(pool,
716 					     pjmedia_vid_codec_default_param);
717     p = codec_desc->def_param;
718     p->pool = pool;
719 
720     /* Update codec default param */
721     p->param = pjmedia_vid_codec_param_clone(pool, param);
722     if (!p->param) {
723 	pj_mutex_unlock(mgr->mutex);
724 	return PJ_EINVAL;
725     }
726 
727     codec_desc->def_param = p;
728 
729     pj_mutex_unlock(mgr->mutex);
730 
731     /* Release old pool at the very end, as application tends to apply changes
732      * to the existing/old codec param fetched using
733      * pjmedia_vid_codec_mgr_get_default_param() which doesn't do deep clone.
734      */
735     if (old_pool)
736 	pj_pool_release(old_pool);
737 
738     return PJ_SUCCESS;
739 }
740 
741 
742 /*
743  * Dealloc codec.
744  */
745 PJ_DEF(pj_status_t)
pjmedia_vid_codec_mgr_dealloc_codec(pjmedia_vid_codec_mgr * mgr,pjmedia_vid_codec * codec)746 pjmedia_vid_codec_mgr_dealloc_codec(pjmedia_vid_codec_mgr *mgr,
747 				    pjmedia_vid_codec *codec)
748 {
749     PJ_ASSERT_RETURN(codec, PJ_EINVAL);
750 
751     if (!mgr) mgr = def_vid_codec_mgr;
752     PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
753 
754     return (*codec->factory->op->dealloc_codec)(codec->factory, codec);
755 }
756 
757 
758 #endif /* PJMEDIA_HAS_VIDEO */
759