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