Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjmedia / src / pjmedia / vid_codec_util.c
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_util.h>
21 #include <pjmedia/errno.h>
22 #include <pjmedia/stream_common.h>
23 #include <pjlib-util/base64.h>
24 #include <pj/ctype.h>
25 #include <pj/math.h>
26
27
28 #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
29
30
31 #define THIS_FILE   "vid_codec_util.c"
32
33 /* If this is set to non-zero, H.264 custom negotiation will require
34  * "profile-level-id" and "packetization-mode" to be exact match to
35  * get a successful negotiation. Note that flexible answer (updating
36  * SDP answer to match remote offer) is always active regardless the
37  * value of this macro.
38  */
39 #define H264_STRICT_SDP_NEGO        0
40
41
42 /* ITU resolution definition */
43 struct mpi_resolution_t
44 {
45     pj_str_t            name;    
46     pjmedia_rect_size   size;
47 }
48 mpi_resolutions [] =
49 {
50     {{"CIF",3},     {352,288}},
51     {{"QCIF",4},    {176,144}},
52     {{"SQCIF",5},   {88,72}},
53     {{"CIF4",4},    {704,576}},
54     {{"CIF16",5},   {1408,1142}},
55 };
56
57
58 /* Parse fmtp value for custom resolution, e.g: "CUSTOM=800,600,2" */
59 static pj_status_t parse_custom_res_fmtp(const pj_str_t *fmtp_val,
60                                          pjmedia_rect_size *size,
61                                          unsigned *mpi)
62 {
63     const char *p, *p_end;
64     pj_str_t token;
65     unsigned long val[3] = {0};
66     unsigned i = 0;
67
68     p = token.ptr = fmtp_val->ptr;
69     p_end = p + fmtp_val->slen;
70
71     while (p<=p_end && i<PJ_ARRAY_SIZE(val)) {
72         if (*p==',' || p==p_end) {
73             token.slen = (char*)p - token.ptr;
74             val[i++] = pj_strtoul(&token);
75             token.ptr = (char*)p+1;
76         }
77         ++p;
78     }
79
80     if (!val[0] || !val[1])
81         return PJ_ETOOSMALL;
82
83     if (val[2]<1 || val[2]>32)
84         return PJ_EINVAL;
85
86     size->w = val[0];
87     size->h = val[1];
88     *mpi = val[2];
89     return PJ_SUCCESS;
90 }
91
92
93 /* H263 fmtp parser */
94 PJ_DEF(pj_status_t) pjmedia_vid_codec_parse_h263_fmtp(
95                                     const pjmedia_codec_fmtp *fmtp,
96                                     pjmedia_vid_codec_h263_fmtp *h263_fmtp)
97 {
98     const pj_str_t CUSTOM = {"CUSTOM", 6};
99     unsigned i;
100
101     pj_bzero(h263_fmtp, sizeof(*h263_fmtp));
102
103     for (i=0; i<fmtp->cnt; ++i) {
104         unsigned j;
105         pj_bool_t parsed = PJ_FALSE;
106
107         if (h263_fmtp->mpi_cnt >= PJ_ARRAY_SIZE(h263_fmtp->mpi)) {
108             pj_assert(!"Too small MPI array in H263 fmtp");
109             continue;
110         }
111
112         /* Standard size MPIs */
113         for (j=0; j<PJ_ARRAY_SIZE(mpi_resolutions) && !parsed; ++j) {
114             if (pj_stricmp(&fmtp->param[i].name, &mpi_resolutions[j].name)==0)
115             {
116                 unsigned mpi;
117
118                 mpi = pj_strtoul(&fmtp->param[i].val);
119                 if (mpi<1 || mpi>32)
120                     return PJMEDIA_SDP_EINFMTP;
121
122                 h263_fmtp->mpi[h263_fmtp->mpi_cnt].size = 
123                                                     mpi_resolutions[j].size;
124                 h263_fmtp->mpi[h263_fmtp->mpi_cnt].val = mpi;
125                 ++h263_fmtp->mpi_cnt;
126                 parsed = PJ_TRUE;
127             }
128         }
129         if (parsed)
130             continue;
131
132         /* Custom size MPIs */
133         if (pj_stricmp(&fmtp->param[i].name, &CUSTOM)==0) {
134             pjmedia_rect_size size;
135             unsigned mpi;
136             pj_status_t status;
137
138             status = parse_custom_res_fmtp(&fmtp->param[i].val, &size, &mpi);
139             if (status != PJ_SUCCESS)
140                 return PJMEDIA_SDP_EINFMTP;
141
142             h263_fmtp->mpi[h263_fmtp->mpi_cnt].size = size;
143             h263_fmtp->mpi[h263_fmtp->mpi_cnt].val = mpi;
144             ++h263_fmtp->mpi_cnt;
145         }
146     }
147
148     return PJ_SUCCESS;
149 }
150
151
152 static unsigned fps_to_mpi(const pjmedia_ratio *fps) 
153 {
154     unsigned mpi;
155
156     /* Original formula = (fps->denum * 30000) / (fps->num * 1001) */
157     mpi = (fps->denum*30000 + fps->num*1001/2) / (fps->num*1001);
158     
159     /* Normalize, should be in the range of 1-32 */
160     if (mpi > 32) mpi = 32;
161     if (mpi < 1) mpi = 1;
162
163     return mpi;
164 };
165
166 PJ_DEF(pj_status_t) pjmedia_vid_codec_h263_apply_fmtp(
167                                 pjmedia_vid_codec_param *param)
168 {
169     if (param->dir & PJMEDIA_DIR_ENCODING) {
170         pjmedia_vid_codec_h263_fmtp fmtp_loc, fmtp_rem;
171         pjmedia_rect_size size = {0};
172         unsigned mpi = 0;
173         pjmedia_video_format_detail *vfd;
174         pj_status_t status;
175
176         vfd = pjmedia_format_get_video_format_detail(&param->enc_fmt,
177                                                      PJ_TRUE);
178
179         /* Get local param */
180         // Local param should be fetched from "param->enc_fmt" instead of
181         // "param->dec_fmtp".
182         //status = pjmedia_vid_codec_parse_h263_fmtp(&param->dec_fmtp,
183         //                                         &fmtp_loc);
184         //if (status != PJ_SUCCESS)
185         //    return status;
186         fmtp_loc.mpi_cnt = 1;
187         fmtp_loc.mpi[0].size = vfd->size;
188         fmtp_loc.mpi[0].val  = fps_to_mpi(&vfd->fps);
189
190         /* Get remote param */
191         status = pjmedia_vid_codec_parse_h263_fmtp(&param->enc_fmtp,
192                                                    &fmtp_rem);
193         if (status != PJ_SUCCESS)
194             return status;
195
196         /* Negotiate size & MPI setting */
197         if (fmtp_rem.mpi_cnt == 0) {
198             /* Remote doesn't specify MPI setting, send QCIF=1 */
199             size.w = 176;
200             size.h = 144;
201             mpi    = 1;
202         //} else if (fmtp_loc.mpi_cnt == 0) {
203         //    /* Local MPI setting not set, just use remote preference. */
204         //    size = fmtp_rem.mpi[0].size;
205         //    mpi  = fmtp_rem.mpi[0].val;
206         } else {
207             /* Both have preferences, let's try to match them */
208             unsigned i, j;
209             pj_bool_t matched = PJ_FALSE;
210             pj_uint32_t min_diff = 0xFFFFFFFF;
211             pj_uint32_t loc_sq, rem_sq, diff;
212
213             /* Find the exact size match or the closest size, then choose
214              * the highest MPI among the match/closest pair.
215              */
216             for (i = 0; i < fmtp_rem.mpi_cnt && !matched; ++i) {
217                 rem_sq = fmtp_rem.mpi[i].size.w * fmtp_rem.mpi[i].size.h;
218                 for (j = 0; j < fmtp_loc.mpi_cnt; ++j) {
219                     /* See if we got exact match */
220                     if (fmtp_rem.mpi[i].size.w == fmtp_loc.mpi[j].size.w &&
221                         fmtp_rem.mpi[i].size.h == fmtp_loc.mpi[j].size.h)
222                     {
223                         size = fmtp_rem.mpi[i].size;
224                         mpi  = PJ_MAX(fmtp_rem.mpi[i].val,
225                                       fmtp_loc.mpi[j].val);
226                         matched = PJ_TRUE;
227                         break;
228                     }
229
230                     /* Otherwise keep looking for the closest match */
231                     loc_sq = fmtp_loc.mpi[j].size.w * fmtp_loc.mpi[j].size.h;
232                     diff = loc_sq>rem_sq? (loc_sq-rem_sq):(rem_sq-loc_sq);
233                     if (diff < min_diff) {
234                         size = rem_sq<loc_sq? fmtp_rem.mpi[i].size :
235                                               fmtp_loc.mpi[j].size;
236                         mpi  = PJ_MAX(fmtp_rem.mpi[i].val,
237                                       fmtp_loc.mpi[j].val);
238                     }
239                 }
240             }
241         }
242
243         /* Apply the negotiation result */
244         vfd->size = size;
245         vfd->fps.num = 30000;
246         vfd->fps.denum = 1001 * mpi;
247     }
248
249     if (param->dir & PJMEDIA_DIR_DECODING) {
250         /* Here we just want to find the highest resolution and the lowest MPI
251          * we support and set it as the decoder param.
252          */
253         pjmedia_vid_codec_h263_fmtp fmtp;
254         pjmedia_video_format_detail *vfd;
255         pj_status_t status;
256         
257         status = pjmedia_vid_codec_parse_h263_fmtp(&param->dec_fmtp,
258                                                    &fmtp);
259         if (status != PJ_SUCCESS)
260             return status;
261
262         vfd = pjmedia_format_get_video_format_detail(&param->dec_fmt,
263                                                      PJ_TRUE);
264
265         if (fmtp.mpi_cnt == 0) {
266             /* No resolution specified, lets just assume 4CIF=1! */
267             vfd->size.w = 704;
268             vfd->size.h = 576;
269             vfd->fps.num = 30000;
270             vfd->fps.denum = 1001;
271         } else {
272             unsigned i, max_size = 0, max_size_idx = 0, min_mpi = 32;
273             
274             /* Get the largest size and the lowest MPI */
275             for (i = 0; i < fmtp.mpi_cnt; ++i) {
276                 if (fmtp.mpi[i].size.w * fmtp.mpi[i].size.h > max_size) {
277                     max_size = fmtp.mpi[i].size.w * fmtp.mpi[i].size.h;
278                     max_size_idx = i;
279                 }
280                 if (fmtp.mpi[i].val < min_mpi)
281                     min_mpi = fmtp.mpi[i].val;
282             }
283
284             vfd->size = fmtp.mpi[max_size_idx].size;
285             vfd->fps.num = 30000;
286             vfd->fps.denum = 1001 * min_mpi;
287         }
288     }
289
290     return PJ_SUCCESS;
291 }
292
293
294 /* H264 fmtp parser */
295 PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp(
296                                     const pjmedia_codec_fmtp *fmtp,
297                                     pjmedia_vid_codec_h264_fmtp *h264_fmtp)
298 {
299     const pj_str_t PROFILE_LEVEL_ID     = {"profile-level-id", 16};
300     const pj_str_t MAX_MBPS             = {"max-mbps", 8};
301     const pj_str_t MAX_FS               = {"max-fs", 6};
302     const pj_str_t MAX_CPB              = {"max-cpb", 7};
303     const pj_str_t MAX_DPB              = {"max-dpb", 7};
304     const pj_str_t MAX_BR               = {"max-br", 6};
305     const pj_str_t PACKETIZATION_MODE   = {"packetization-mode", 18};
306     const pj_str_t SPROP_PARAMETER_SETS = {"sprop-parameter-sets", 20};
307     unsigned i;
308
309     pj_bzero(h264_fmtp, sizeof(*h264_fmtp));
310
311     for (i=0; i<fmtp->cnt; ++i) {
312         unsigned tmp;
313         if (pj_stricmp(&fmtp->param[i].name, &PROFILE_LEVEL_ID)==0) {
314             pj_str_t endst;
315
316             if (fmtp->param[i].val.slen != 6)
317                 return PJMEDIA_SDP_EINFMTP;
318
319             tmp = pj_strtoul2(&fmtp->param[i].val, &endst, 16);
320             if (endst.slen)
321                 return PJMEDIA_SDP_EINFMTP;
322
323             h264_fmtp->profile_idc = (pj_uint8_t)((tmp >> 16) & 0xFF);
324             h264_fmtp->profile_iop = (pj_uint8_t)((tmp >> 8) & 0xFF);
325             h264_fmtp->level = (pj_uint8_t)(tmp & 0xFF);
326         } else if (pj_stricmp(&fmtp->param[i].name, &PACKETIZATION_MODE)==0) {
327             tmp = pj_strtoul(&fmtp->param[i].val);
328             if (tmp >= 0 && tmp <= 2) 
329                 h264_fmtp->packetization_mode = (pj_uint8_t)tmp;
330             else
331                 return PJMEDIA_SDP_EINFMTP;
332         } else if (pj_stricmp(&fmtp->param[i].name, &MAX_MBPS)==0) {
333             tmp = pj_strtoul(&fmtp->param[i].val);
334             h264_fmtp->max_mbps = tmp;
335         } else if (pj_stricmp(&fmtp->param[i].name, &MAX_FS)==0) {
336             tmp = pj_strtoul(&fmtp->param[i].val);
337             h264_fmtp->max_fs = tmp;
338         } else if (pj_stricmp(&fmtp->param[i].name, &MAX_CPB)==0) {
339             tmp = pj_strtoul(&fmtp->param[i].val);
340             h264_fmtp->max_cpb = tmp;
341         } else if (pj_stricmp(&fmtp->param[i].name, &MAX_DPB)==0) {
342             tmp = pj_strtoul(&fmtp->param[i].val);
343             h264_fmtp->max_dpb = tmp;
344         } else if (pj_stricmp(&fmtp->param[i].name, &MAX_BR)==0) {
345             tmp = pj_strtoul(&fmtp->param[i].val);
346             h264_fmtp->max_br = tmp;
347         } else if (pj_stricmp(&fmtp->param[i].name, &SPROP_PARAMETER_SETS)==0)
348         {
349             pj_str_t sps_st;
350
351             sps_st = fmtp->param[i].val;
352             while (sps_st.slen) {
353                 pj_str_t tmp_st;
354                 int tmp_len;
355                 const pj_uint8_t start_code[3] = {0, 0, 1};
356                 char *p;
357                 pj_uint8_t *nal;
358                 pj_status_t status;
359
360                 /* Find field separator ',' */
361                 tmp_st = sps_st;
362                 p = pj_strchr(&sps_st, ',');
363                 if (p) {
364                     tmp_st.slen = p - sps_st.ptr;
365                     sps_st.ptr  = p+1;
366                     sps_st.slen -= (tmp_st.slen+1);
367                 } else {
368                     sps_st.slen = 0;
369                 }
370
371                 /* Decode field and build NAL unit for this param */
372                 nal = &h264_fmtp->sprop_param_sets[
373                                           h264_fmtp->sprop_param_sets_len];
374                 tmp_len = PJ_ARRAY_SIZE(h264_fmtp->sprop_param_sets) -
375                           h264_fmtp->sprop_param_sets_len -
376                           PJ_ARRAY_SIZE(start_code);
377                 status = pj_base64_decode(&tmp_st,
378                                           nal + PJ_ARRAY_SIZE(start_code),
379                                           &tmp_len);
380                 if (status != PJ_SUCCESS)
381                     return PJMEDIA_SDP_EINFMTP;
382
383                 tmp_len += PJ_ARRAY_SIZE(start_code);
384                 pj_memcpy(nal, start_code, PJ_ARRAY_SIZE(start_code));
385                 h264_fmtp->sprop_param_sets_len += tmp_len;
386             }
387         }
388     }
389
390     /* When profile-level-id is not specified, use default value "42000A" */
391     if (h264_fmtp->profile_idc == 0) {
392         h264_fmtp->profile_idc = 0x42;
393         h264_fmtp->profile_iop = 0x00;
394         h264_fmtp->level = 0x0A;
395     }
396
397     return PJ_SUCCESS;
398 }
399
400 PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_match_sdp(pj_pool_t *pool,
401                                                      pjmedia_sdp_media *offer,
402                                                      unsigned o_fmt_idx,
403                                                      pjmedia_sdp_media *answer,
404                                                      unsigned a_fmt_idx,
405                                                      unsigned option)
406 {
407     const pj_str_t PROFILE_LEVEL_ID     = {"profile-level-id", 16};
408     const pj_str_t PACKETIZATION_MODE   = {"packetization-mode", 18};
409     pjmedia_codec_fmtp o_fmtp_raw, a_fmtp_raw;
410     pjmedia_vid_codec_h264_fmtp o_fmtp, a_fmtp;
411     pj_status_t status;
412
413     PJ_UNUSED_ARG(pool);
414
415     /* Parse offer */
416     status = pjmedia_stream_info_parse_fmtp(
417                                     NULL, offer, 
418                                     pj_strtoul(&offer->desc.fmt[o_fmt_idx]),
419                                     &o_fmtp_raw);
420     if (status != PJ_SUCCESS)
421         return status;
422
423     status = pjmedia_vid_codec_h264_parse_fmtp(&o_fmtp_raw, &o_fmtp);
424     if (status != PJ_SUCCESS)
425         return status;
426
427     /* Parse answer */
428     status = pjmedia_stream_info_parse_fmtp(
429                                     NULL, answer, 
430                                     pj_strtoul(&answer->desc.fmt[a_fmt_idx]),
431                                     &a_fmtp_raw);
432     if (status != PJ_SUCCESS)
433         return status;
434
435     status = pjmedia_vid_codec_h264_parse_fmtp(&a_fmtp_raw, &a_fmtp);
436     if (status != PJ_SUCCESS)
437         return status;
438
439     if (option & PJMEDIA_SDP_NEG_FMT_MATCH_ALLOW_MODIFY_ANSWER) {
440         unsigned i;
441
442         /* Flexible negotiation, if the answer has higher capability than
443          * the offer, adjust the answer capability to be match to the offer.
444          */
445         if (a_fmtp.profile_idc >= o_fmtp.profile_idc)
446             a_fmtp.profile_idc = o_fmtp.profile_idc;
447         if (a_fmtp.profile_iop != o_fmtp.profile_iop)
448             a_fmtp.profile_iop = o_fmtp.profile_iop;
449         if (a_fmtp.level >= o_fmtp.level)
450             a_fmtp.level = o_fmtp.level;
451         if (a_fmtp.packetization_mode >= o_fmtp.packetization_mode)
452             a_fmtp.packetization_mode = o_fmtp.packetization_mode;
453
454         /* Match them now */
455 #if H264_STRICT_SDP_NEGO
456         if (a_fmtp.profile_idc != o_fmtp.profile_idc ||
457             a_fmtp.profile_iop != o_fmtp.profile_iop ||
458             a_fmtp.level != o_fmtp.level ||
459             a_fmtp.packetization_mode != o_fmtp.packetization_mode)
460         {
461             return PJMEDIA_SDP_EFORMATNOTEQUAL;
462         }
463 #else
464         if (a_fmtp.profile_idc != o_fmtp.profile_idc)
465         {
466             return PJMEDIA_SDP_EFORMATNOTEQUAL;
467         }
468 #endif
469
470         /* Update the answer */
471         for (i = 0; i < a_fmtp_raw.cnt; ++i) {
472             if (pj_stricmp(&a_fmtp_raw.param[i].name, &PROFILE_LEVEL_ID) == 0)
473             {
474                 char *p = a_fmtp_raw.param[i].val.ptr;
475                 pj_val_to_hex_digit(a_fmtp.profile_idc, p);
476                 p += 2;
477                 pj_val_to_hex_digit(a_fmtp.profile_iop, p);
478                 p += 2;
479                 pj_val_to_hex_digit(a_fmtp.level, p);
480             }
481             else if (pj_stricmp(&a_fmtp_raw.param[i].name, &PACKETIZATION_MODE) == 0)
482             {
483                 char *p = a_fmtp_raw.param[i].val.ptr;
484                 *p = '0' + a_fmtp.packetization_mode;
485             }
486         }
487     } else {
488 #if H264_STRICT_SDP_NEGO
489         /* Strict negotiation */
490         if (a_fmtp.profile_idc != o_fmtp.profile_idc ||
491             a_fmtp.profile_iop != o_fmtp.profile_iop ||
492             a_fmtp.level != o_fmtp.level ||
493             a_fmtp.packetization_mode != o_fmtp.packetization_mode)
494         {
495             return PJMEDIA_SDP_EFORMATNOTEQUAL;
496         }
497 #else
498         /* Permissive negotiation */
499         if (a_fmtp.profile_idc != o_fmtp.profile_idc)
500         {
501             return PJMEDIA_SDP_EFORMATNOTEQUAL;
502         }
503 #endif
504     }
505
506     return PJ_SUCCESS;
507 }
508
509
510 /* Declaration of H.264 level info */
511 typedef struct h264_level_info_t
512 {
513     unsigned id;            /* Level id.                        */
514     unsigned max_mbps;      /* Max macroblocks per second.      */
515     unsigned max_mb;        /* Max macroblocks.                 */
516     unsigned bitrate;       /* Max bitrate (kbps).              */
517     unsigned def_w;         /* Default width.                   */
518     unsigned def_h;         /* Default height.                  */
519     unsigned def_fps;       /* Default fps.                     */
520 } h264_level_info_t;
521
522
523 /* Get H.264 level info from specified level ID */
524 static pj_status_t get_h264_level_info(unsigned id, h264_level_info_t *level)
525 {
526     unsigned i;
527     const h264_level_info_t level_info[] =
528     {
529         { 10,   1485,    99,     64,  176,  144, 15 },
530         { 9,    1485,    99,    128,  176,  144, 15 }, /*< level 1b */
531         { 11,   3000,   396,    192,  320,  240, 10 },
532         { 12,   6000,   396,    384,  352,  288, 15 },
533         { 13,  11880,   396,    768,  352,  288, 15 },
534         { 20,  11880,   396,   2000,  352,  288, 30 },
535         { 21,  19800,   792,   4000,  352,  288, 30 },
536         { 22,  20250,  1620,   4000,  352,  288, 30 },
537         { 30,  40500,  1620,  10000,  720,  480, 30 },
538         { 31, 108000,  3600,  14000, 1280,  720, 30 },
539         { 32, 216000,  5120,  20000, 1280,  720, 30 },
540         { 40, 245760,  8192,  20000, 1920, 1080, 30 },
541         { 41, 245760,  8192,  50000, 1920, 1080, 30 },
542         { 42, 522240,  8704,  50000, 1920, 1080, 30 },
543         { 50, 589824, 22080, 135000, 1920, 1080, 30 },
544         { 51, 983040, 36864, 240000, 1920, 1080, 30 },
545     };
546
547     for (i = 0; i < PJ_ARRAY_SIZE(level_info); ++i) {
548         if (level_info[i].id == id) {
549             *level = level_info[i];
550             return PJ_SUCCESS;
551         }
552     }
553     return PJ_ENOTFOUND;
554 }
555
556
557 #define CALC_H264_MB_NUM(size) (((size.w+15)/16)*((size.h+15)/16))
558 #define CALC_H264_MBPS(size,fps) CALC_H264_MB_NUM(size)*fps.num/fps.denum
559
560
561 PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_apply_fmtp(
562                                 pjmedia_vid_codec_param *param)
563 {
564     const unsigned default_fps = 30;
565
566     if (param->dir & PJMEDIA_DIR_ENCODING) {
567         pjmedia_vid_codec_h264_fmtp fmtp;
568         pjmedia_video_format_detail *vfd;
569         h264_level_info_t level_info;
570         pj_status_t status;
571
572         /* Get remote param */
573         status = pjmedia_vid_codec_h264_parse_fmtp(&param->enc_fmtp,
574                                                    &fmtp);
575         if (status != PJ_SUCCESS)
576             return status;
577
578         status = get_h264_level_info(fmtp.level, &level_info);
579         if (status != PJ_SUCCESS)
580             return status;
581
582         /* Size and fps for encoding direction must conform to H.264 level
583          * specified by remote SDP fmtp.
584          */
585         vfd = pjmedia_format_get_video_format_detail(&param->enc_fmt,
586                                                      PJ_TRUE);
587         if (vfd->size.w && vfd->size.h) {
588             unsigned mb, mbps;
589             
590             if (vfd->fps.num == 0 || vfd->fps.denum == 0) {
591                 vfd->fps.num = default_fps;
592                 vfd->fps.denum = 1;
593             }
594             mb = CALC_H264_MB_NUM(vfd->size);
595             mbps = CALC_H264_MBPS(vfd->size, vfd->fps);
596             if (mb > level_info.max_mb || mbps > level_info.max_mbps) {
597                 vfd->size.w = level_info.def_w;
598                 vfd->size.h = level_info.def_h;
599                 vfd->fps.num = level_info.def_fps;
600                 vfd->fps.denum = 1;
601             }
602         } else {
603             vfd->size.w = level_info.def_w;
604             vfd->size.h = level_info.def_h;
605             vfd->fps.num = level_info.def_fps;
606             vfd->fps.denum = 1;
607         }
608     }
609
610     if (param->dir & PJMEDIA_DIR_DECODING) {
611         /* Here we just want to find the highest resolution possible from the
612          * fmtp and set it as the decoder param.
613          */
614         pjmedia_vid_codec_h264_fmtp fmtp;
615         pjmedia_video_format_detail *vfd;
616         h264_level_info_t level_info;
617         pj_status_t status;
618         
619         status = pjmedia_vid_codec_h264_parse_fmtp(&param->dec_fmtp,
620                                                    &fmtp);
621         if (status != PJ_SUCCESS)
622             return status;
623
624         status = get_h264_level_info(fmtp.level, &level_info);
625         if (status != PJ_SUCCESS)
626             return status;
627
628         vfd = pjmedia_format_get_video_format_detail(&param->dec_fmt,
629                                                      PJ_TRUE);
630
631         if (vfd->size.w * vfd->size.h < level_info.def_w * level_info.def_h) {
632             vfd->size.w = level_info.def_w;
633             vfd->size.h = level_info.def_h;
634         }
635
636         if (vfd->fps.num == 0 || vfd->fps.denum == 0) {
637             vfd->fps.num = default_fps;
638             vfd->fps.denum = 1;
639         }
640     }
641
642     return PJ_SUCCESS;
643 }
644
645
646 #endif /* PJMEDIA_HAS_VIDEO */