Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F7159114
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
22 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/deps/pjsip/pjmedia/src/pjmedia/vid_codec_util.c b/deps/pjsip/pjmedia/src/pjmedia/vid_codec_util.c
index af2907bc..b8b4fb26 100644
--- a/deps/pjsip/pjmedia/src/pjmedia/vid_codec_util.c
+++ b/deps/pjsip/pjmedia/src/pjmedia/vid_codec_util.c
@@ -1,762 +1,756 @@
/* $Id: vid_codec_util.c 4362 2013-02-21 14:51:56Z nanang $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjmedia/vid_codec_util.h>
#include <pjmedia/errno.h>
#include <pjmedia/stream_common.h>
#include <pjlib-util/base64.h>
#include <pj/ctype.h>
#include <pj/math.h>
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
#define THIS_FILE "vid_codec_util.c"
/* If this is set to non-zero, H.264 custom negotiation will require
* "profile-level-id" and "packetization-mode" to be exact match to
* get a successful negotiation. Note that flexible answer (updating
* SDP answer to match remote offer) is always active regardless the
* value of this macro.
*/
#define H264_STRICT_SDP_NEGO 0
/* Default frame rate, if not specified */
#define DEFAULT_H264_FPS_NUM 15
#define DEFAULT_H264_FPS_DENUM 1
/* Default aspect ratio, if not specified */
#define DEFAULT_H264_RATIO_NUM 16
#define DEFAULT_H264_RATIO_DENUM 9
/* ITU resolution definition */
struct mpi_resolution_t
{
pj_str_t name;
pjmedia_rect_size size;
}
mpi_resolutions [] =
{
{{"CIF",3}, {352,288}},
{{"QCIF",4}, {176,144}},
{{"SQCIF",5}, {88,72}},
{{"CIF4",4}, {704,576}},
{{"CIF16",5}, {1408,1142}},
};
#define CALC_H264_MB_NUM(size) (((size.w+15)/16)*((size.h+15)/16))
#define CALC_H264_MBPS(size,fps) CALC_H264_MB_NUM(size)*fps.num/fps.denum
/* Parse fmtp value for custom resolution, e.g: "CUSTOM=800,600,2" */
static pj_status_t parse_custom_res_fmtp(const pj_str_t *fmtp_val,
pjmedia_rect_size *size,
unsigned *mpi)
{
const char *p, *p_end;
pj_str_t token;
unsigned long val[3] = {0};
unsigned i = 0;
p = token.ptr = fmtp_val->ptr;
p_end = p + fmtp_val->slen;
while (p<=p_end && i<PJ_ARRAY_SIZE(val)) {
if (*p==',' || p==p_end) {
token.slen = (char*)p - token.ptr;
val[i++] = pj_strtoul(&token);
token.ptr = (char*)p+1;
}
++p;
}
if (!val[0] || !val[1])
return PJ_ETOOSMALL;
if (val[2]<1 || val[2]>32)
return PJ_EINVAL;
size->w = val[0];
size->h = val[1];
*mpi = val[2];
return PJ_SUCCESS;
}
/* H263 fmtp parser */
PJ_DEF(pj_status_t) pjmedia_vid_codec_parse_h263_fmtp(
const pjmedia_codec_fmtp *fmtp,
pjmedia_vid_codec_h263_fmtp *h263_fmtp)
{
const pj_str_t CUSTOM = {"CUSTOM", 6};
unsigned i;
pj_bzero(h263_fmtp, sizeof(*h263_fmtp));
for (i=0; i<fmtp->cnt; ++i) {
unsigned j;
pj_bool_t parsed = PJ_FALSE;
if (h263_fmtp->mpi_cnt >= PJ_ARRAY_SIZE(h263_fmtp->mpi)) {
pj_assert(!"Too small MPI array in H263 fmtp");
continue;
}
/* Standard size MPIs */
for (j=0; j<PJ_ARRAY_SIZE(mpi_resolutions) && !parsed; ++j) {
if (pj_stricmp(&fmtp->param[i].name, &mpi_resolutions[j].name)==0)
{
unsigned mpi;
mpi = pj_strtoul(&fmtp->param[i].val);
if (mpi<1 || mpi>32)
return PJMEDIA_SDP_EINFMTP;
h263_fmtp->mpi[h263_fmtp->mpi_cnt].size =
mpi_resolutions[j].size;
h263_fmtp->mpi[h263_fmtp->mpi_cnt].val = mpi;
++h263_fmtp->mpi_cnt;
parsed = PJ_TRUE;
}
}
if (parsed)
continue;
/* Custom size MPIs */
if (pj_stricmp(&fmtp->param[i].name, &CUSTOM)==0) {
pjmedia_rect_size size;
unsigned mpi;
pj_status_t status;
status = parse_custom_res_fmtp(&fmtp->param[i].val, &size, &mpi);
if (status != PJ_SUCCESS)
return PJMEDIA_SDP_EINFMTP;
h263_fmtp->mpi[h263_fmtp->mpi_cnt].size = size;
h263_fmtp->mpi[h263_fmtp->mpi_cnt].val = mpi;
++h263_fmtp->mpi_cnt;
}
}
return PJ_SUCCESS;
}
static unsigned fps_to_mpi(const pjmedia_ratio *fps)
{
unsigned mpi;
/* Original formula = (fps->denum * 30000) / (fps->num * 1001) */
mpi = (fps->denum*30000 + fps->num*1001/2) / (fps->num*1001);
/* Normalize, should be in the range of 1-32 */
if (mpi > 32) mpi = 32;
if (mpi < 1) mpi = 1;
return mpi;
};
PJ_DEF(pj_status_t) pjmedia_vid_codec_h263_apply_fmtp(
pjmedia_vid_codec_param *param)
{
if (param->dir & PJMEDIA_DIR_ENCODING) {
pjmedia_vid_codec_h263_fmtp fmtp_loc, fmtp_rem;
pjmedia_rect_size size = {0};
unsigned mpi = 0;
pjmedia_video_format_detail *vfd;
pj_status_t status;
vfd = pjmedia_format_get_video_format_detail(¶m->enc_fmt,
PJ_TRUE);
/* Get local param */
// Local param should be fetched from "param->enc_fmt" instead of
// "param->dec_fmtp".
//status = pjmedia_vid_codec_parse_h263_fmtp(¶m->dec_fmtp,
// &fmtp_loc);
//if (status != PJ_SUCCESS)
// return status;
fmtp_loc.mpi_cnt = 1;
fmtp_loc.mpi[0].size = vfd->size;
fmtp_loc.mpi[0].val = fps_to_mpi(&vfd->fps);
/* Get remote param */
status = pjmedia_vid_codec_parse_h263_fmtp(¶m->enc_fmtp,
&fmtp_rem);
if (status != PJ_SUCCESS)
return status;
/* Negotiate size & MPI setting */
if (fmtp_rem.mpi_cnt == 0) {
/* Remote doesn't specify MPI setting, send QCIF=1 */
size.w = 176;
size.h = 144;
mpi = 1;
//} else if (fmtp_loc.mpi_cnt == 0) {
// /* Local MPI setting not set, just use remote preference. */
// size = fmtp_rem.mpi[0].size;
// mpi = fmtp_rem.mpi[0].val;
} else {
/* Both have preferences, let's try to match them */
unsigned i, j;
pj_bool_t matched = PJ_FALSE;
pj_uint32_t min_diff = 0xFFFFFFFF;
pj_uint32_t loc_sq, rem_sq, diff;
/* Find the exact size match or the closest size, then choose
* the highest MPI among the match/closest pair.
*/
for (i = 0; i < fmtp_rem.mpi_cnt && !matched; ++i) {
rem_sq = fmtp_rem.mpi[i].size.w * fmtp_rem.mpi[i].size.h;
for (j = 0; j < fmtp_loc.mpi_cnt; ++j) {
/* See if we got exact match */
if (fmtp_rem.mpi[i].size.w == fmtp_loc.mpi[j].size.w &&
fmtp_rem.mpi[i].size.h == fmtp_loc.mpi[j].size.h)
{
size = fmtp_rem.mpi[i].size;
mpi = PJ_MAX(fmtp_rem.mpi[i].val,
fmtp_loc.mpi[j].val);
matched = PJ_TRUE;
break;
}
/* Otherwise keep looking for the closest match */
loc_sq = fmtp_loc.mpi[j].size.w * fmtp_loc.mpi[j].size.h;
diff = loc_sq>rem_sq? (loc_sq-rem_sq):(rem_sq-loc_sq);
if (diff < min_diff) {
size = rem_sq<loc_sq? fmtp_rem.mpi[i].size :
fmtp_loc.mpi[j].size;
mpi = PJ_MAX(fmtp_rem.mpi[i].val,
fmtp_loc.mpi[j].val);
}
}
}
}
/* Apply the negotiation result */
vfd->size = size;
vfd->fps.num = 30000;
vfd->fps.denum = 1001 * mpi;
}
if (param->dir & PJMEDIA_DIR_DECODING) {
/* Here we just want to find the highest resolution and the lowest MPI
* we support and set it as the decoder param.
*/
pjmedia_vid_codec_h263_fmtp fmtp;
pjmedia_video_format_detail *vfd;
pj_status_t status;
status = pjmedia_vid_codec_parse_h263_fmtp(¶m->dec_fmtp,
&fmtp);
if (status != PJ_SUCCESS)
return status;
vfd = pjmedia_format_get_video_format_detail(¶m->dec_fmt,
PJ_TRUE);
if (fmtp.mpi_cnt == 0) {
/* No resolution specified, lets just assume 4CIF=1! */
vfd->size.w = 704;
vfd->size.h = 576;
vfd->fps.num = 30000;
vfd->fps.denum = 1001;
} else {
unsigned i, max_size = 0, max_size_idx = 0, min_mpi = 32;
/* Get the largest size and the lowest MPI */
for (i = 0; i < fmtp.mpi_cnt; ++i) {
if (fmtp.mpi[i].size.w * fmtp.mpi[i].size.h > max_size) {
max_size = fmtp.mpi[i].size.w * fmtp.mpi[i].size.h;
max_size_idx = i;
}
if (fmtp.mpi[i].val < min_mpi)
min_mpi = fmtp.mpi[i].val;
}
vfd->size = fmtp.mpi[max_size_idx].size;
vfd->fps.num = 30000;
vfd->fps.denum = 1001 * min_mpi;
}
}
return PJ_SUCCESS;
}
/* Declaration of H.264 level info */
typedef struct h264_level_info_t
{
unsigned id; /* Level id. */
unsigned max_mbps; /* Max macroblocks per second. */
unsigned max_mb; /* Max macroblocks. */
unsigned max_br; /* Max bitrate (kbps). */
} h264_level_info_t;
/* Init H264 parameters based on profile-level-id */
static pj_status_t init_h264_profile(const pj_str_t *profile,
pjmedia_vid_codec_h264_fmtp *fmtp)
{
const h264_level_info_t level_info[] =
{
{ 10, 1485, 99, 64 },
{ 9, 1485, 99, 128 }, /*< level 1b */
{ 11, 3000, 396, 192 },
{ 12, 6000, 396, 384 },
{ 13, 11880, 396, 768 },
{ 20, 11880, 396, 2000 },
{ 21, 19800, 792, 4000 },
{ 22, 20250, 1620, 4000 },
{ 30, 40500, 1620, 10000 },
{ 31, 108000, 3600, 14000 },
{ 32, 216000, 5120, 20000 },
{ 40, 245760, 8192, 20000 },
{ 41, 245760, 8192, 50000 },
{ 42, 522240, 8704, 50000 },
{ 50, 589824, 22080, 135000 },
{ 51, 983040, 36864, 240000 },
};
unsigned i, tmp;
pj_str_t endst;
const h264_level_info_t *li = NULL;
if (profile->slen != 6)
return PJMEDIA_SDP_EINFMTP;
tmp = pj_strtoul2(profile, &endst, 16);
if (endst.slen)
return PJMEDIA_SDP_EINFMTP;
fmtp->profile_idc = (pj_uint8_t)((tmp >> 16) & 0xFF);
fmtp->profile_iop = (pj_uint8_t)((tmp >> 8) & 0xFF);
fmtp->level = (pj_uint8_t)(tmp & 0xFF);
for (i = 0; i < PJ_ARRAY_SIZE(level_info); ++i) {
if (level_info[i].id == fmtp->level) {
li = &level_info[i];
break;
}
}
if (li == NULL)
return PJMEDIA_SDP_EINFMTP;
/* Init profile level spec */
if (fmtp->max_br == 0)
fmtp->max_br = li->max_br;
if (fmtp->max_mbps == 0)
fmtp->max_mbps = li->max_mbps;
if (fmtp->max_fs == 0)
fmtp->max_fs = li->max_mb;
return PJ_SUCCESS;
}
/* H264 fmtp parser */
PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp(
const pjmedia_codec_fmtp *fmtp,
pjmedia_vid_codec_h264_fmtp *h264_fmtp)
{
const pj_str_t PROFILE_LEVEL_ID = {"profile-level-id", 16};
const pj_str_t MAX_MBPS = {"max-mbps", 8};
const pj_str_t MAX_FS = {"max-fs", 6};
const pj_str_t MAX_CPB = {"max-cpb", 7};
const pj_str_t MAX_DPB = {"max-dpb", 7};
const pj_str_t MAX_BR = {"max-br", 6};
const pj_str_t PACKETIZATION_MODE = {"packetization-mode", 18};
const pj_str_t SPROP_PARAMETER_SETS = {"sprop-parameter-sets", 20};
unsigned i;
pj_status_t status;
pj_bzero(h264_fmtp, sizeof(*h264_fmtp));
for (i=0; i<fmtp->cnt; ++i) {
unsigned tmp;
if (pj_stricmp(&fmtp->param[i].name, &PROFILE_LEVEL_ID)==0) {
/* Init H264 parameters based on level, if not set yet */
status = init_h264_profile(&fmtp->param[i].val, h264_fmtp);
if (status != PJ_SUCCESS)
return status;
} else if (pj_stricmp(&fmtp->param[i].name, &PACKETIZATION_MODE)==0) {
tmp = pj_strtoul(&fmtp->param[i].val);
if (tmp >= 0 && tmp <= 2)
h264_fmtp->packetization_mode = (pj_uint8_t)tmp;
else
return PJMEDIA_SDP_EINFMTP;
} else if (pj_stricmp(&fmtp->param[i].name, &MAX_MBPS)==0) {
tmp = pj_strtoul(&fmtp->param[i].val);
h264_fmtp->max_mbps = PJ_MAX(tmp, h264_fmtp->max_mbps);
} else if (pj_stricmp(&fmtp->param[i].name, &MAX_FS)==0) {
tmp = pj_strtoul(&fmtp->param[i].val);
h264_fmtp->max_fs = PJ_MAX(tmp, h264_fmtp->max_fs);
} else if (pj_stricmp(&fmtp->param[i].name, &MAX_CPB)==0) {
tmp = pj_strtoul(&fmtp->param[i].val);
h264_fmtp->max_cpb = PJ_MAX(tmp, h264_fmtp->max_cpb);
} else if (pj_stricmp(&fmtp->param[i].name, &MAX_DPB)==0) {
tmp = pj_strtoul(&fmtp->param[i].val);
h264_fmtp->max_dpb = PJ_MAX(tmp, h264_fmtp->max_dpb);
} else if (pj_stricmp(&fmtp->param[i].name, &MAX_BR)==0) {
tmp = pj_strtoul(&fmtp->param[i].val);
h264_fmtp->max_br = PJ_MAX(tmp, h264_fmtp->max_br);
} else if (pj_stricmp(&fmtp->param[i].name, &SPROP_PARAMETER_SETS)==0)
{
pj_str_t sps_st;
sps_st = fmtp->param[i].val;
while (sps_st.slen) {
pj_str_t tmp_st;
int tmp_len;
const pj_uint8_t start_code[3] = {0, 0, 1};
char *p;
pj_uint8_t *nal;
pj_status_t status;
/* Find field separator ',' */
tmp_st = sps_st;
p = pj_strchr(&sps_st, ',');
if (p) {
tmp_st.slen = p - sps_st.ptr;
sps_st.ptr = p+1;
sps_st.slen -= (tmp_st.slen+1);
} else {
sps_st.slen = 0;
}
/* Decode field and build NAL unit for this param */
nal = &h264_fmtp->sprop_param_sets[
h264_fmtp->sprop_param_sets_len];
tmp_len = PJ_ARRAY_SIZE(h264_fmtp->sprop_param_sets) -
(int)h264_fmtp->sprop_param_sets_len -
PJ_ARRAY_SIZE(start_code);
status = pj_base64_decode(&tmp_st,
nal + PJ_ARRAY_SIZE(start_code),
&tmp_len);
if (status != PJ_SUCCESS)
return PJMEDIA_SDP_EINFMTP;
tmp_len += PJ_ARRAY_SIZE(start_code);
pj_memcpy(nal, start_code, PJ_ARRAY_SIZE(start_code));
h264_fmtp->sprop_param_sets_len += tmp_len;
}
}
}
/* When profile-level-id is not specified, use default value "42000A" */
if (h264_fmtp->profile_idc == 0) {
const pj_str_t DEF_PROFILE = {"42000A", 6};
status = init_h264_profile(&DEF_PROFILE, h264_fmtp);
if (status != PJ_SUCCESS)
return status;
}
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_match_sdp(pj_pool_t *pool,
pjmedia_sdp_media *offer,
unsigned o_fmt_idx,
pjmedia_sdp_media *answer,
unsigned a_fmt_idx,
unsigned option)
{
const pj_str_t PROFILE_LEVEL_ID = {"profile-level-id", 16};
const pj_str_t PACKETIZATION_MODE = {"packetization-mode", 18};
pjmedia_codec_fmtp o_fmtp_raw, a_fmtp_raw;
pjmedia_vid_codec_h264_fmtp o_fmtp, a_fmtp;
pj_status_t status;
PJ_UNUSED_ARG(pool);
/* Parse offer */
status = pjmedia_stream_info_parse_fmtp(
NULL, offer,
pj_strtoul(&offer->desc.fmt[o_fmt_idx]),
&o_fmtp_raw);
if (status != PJ_SUCCESS)
return status;
status = pjmedia_vid_codec_h264_parse_fmtp(&o_fmtp_raw, &o_fmtp);
if (status != PJ_SUCCESS)
return status;
/* Parse answer */
status = pjmedia_stream_info_parse_fmtp(
NULL, answer,
pj_strtoul(&answer->desc.fmt[a_fmt_idx]),
&a_fmtp_raw);
if (status != PJ_SUCCESS)
return status;
status = pjmedia_vid_codec_h264_parse_fmtp(&a_fmtp_raw, &a_fmtp);
if (status != PJ_SUCCESS)
return status;
if (option & PJMEDIA_SDP_NEG_FMT_MATCH_ALLOW_MODIFY_ANSWER) {
unsigned i;
- /* Flexible negotiation, if the answer has higher capability than
- * the offer, adjust the answer capability to be match to the offer.
+ /* Flexible negotiation, adjust our answer to the offer.
+ * Apply Postel's Principle (TM) in it's full glory.
*/
- if (a_fmtp.profile_idc >= o_fmtp.profile_idc)
+ if (a_fmtp.profile_idc != o_fmtp.profile_idc)
a_fmtp.profile_idc = o_fmtp.profile_idc;
if (a_fmtp.profile_iop != o_fmtp.profile_iop)
a_fmtp.profile_iop = o_fmtp.profile_iop;
- if (a_fmtp.level >= o_fmtp.level)
- a_fmtp.level = o_fmtp.level;
if (a_fmtp.packetization_mode >= o_fmtp.packetization_mode)
a_fmtp.packetization_mode = o_fmtp.packetization_mode;
/* Match them now */
#if H264_STRICT_SDP_NEGO
if (a_fmtp.profile_idc != o_fmtp.profile_idc ||
a_fmtp.profile_iop != o_fmtp.profile_iop ||
- a_fmtp.level != o_fmtp.level ||
a_fmtp.packetization_mode != o_fmtp.packetization_mode)
{
return PJMEDIA_SDP_EFORMATNOTEQUAL;
}
#else
if (a_fmtp.profile_idc != o_fmtp.profile_idc)
{
return PJMEDIA_SDP_EFORMATNOTEQUAL;
}
#endif
/* Update the answer */
for (i = 0; i < a_fmtp_raw.cnt; ++i) {
if (pj_stricmp(&a_fmtp_raw.param[i].name, &PROFILE_LEVEL_ID) == 0)
{
char *p = a_fmtp_raw.param[i].val.ptr;
pj_val_to_hex_digit(a_fmtp.profile_idc, p);
p += 2;
pj_val_to_hex_digit(a_fmtp.profile_iop, p);
- p += 2;
- pj_val_to_hex_digit(a_fmtp.level, p);
}
else if (pj_stricmp(&a_fmtp_raw.param[i].name, &PACKETIZATION_MODE) == 0)
{
char *p = a_fmtp_raw.param[i].val.ptr;
*p = '0' + a_fmtp.packetization_mode;
}
}
} else {
#if H264_STRICT_SDP_NEGO
/* Strict negotiation */
if (a_fmtp.profile_idc != o_fmtp.profile_idc ||
a_fmtp.profile_iop != o_fmtp.profile_iop ||
- a_fmtp.level != o_fmtp.level ||
a_fmtp.packetization_mode != o_fmtp.packetization_mode)
{
return PJMEDIA_SDP_EFORMATNOTEQUAL;
}
#else
/* Permissive negotiation */
if (a_fmtp.profile_idc != o_fmtp.profile_idc)
{
return PJMEDIA_SDP_EFORMATNOTEQUAL;
}
#endif
}
return PJ_SUCCESS;
}
/* Find greatest common divisor (GCD) */
static unsigned gcd (unsigned a, unsigned b) {
unsigned c;
while (b) {
c = a % b;
a = b;
b = c;
}
return a;
}
/* Find highest resolution possible for the specified H264 fmtp and
* aspect ratio.
*/
static pj_status_t find_highest_res(pjmedia_vid_codec_h264_fmtp *fmtp,
const pjmedia_ratio *fps,
const pjmedia_ratio *ratio,
pjmedia_rect_size *size,
pj_bool_t is_decoding)
{
pjmedia_ratio def_ratio = { DEFAULT_H264_RATIO_NUM,
DEFAULT_H264_RATIO_DENUM };
pjmedia_ratio def_fps = { DEFAULT_H264_FPS_NUM,
DEFAULT_H264_FPS_DENUM };
pjmedia_ratio asp_ratio, the_fps;
unsigned max_fs, g, scale;
pj_assert(size);
/* Get the ratio, or just use default if not provided. */
if (ratio && ratio->num && ratio->denum) {
asp_ratio = *ratio;
} else {
asp_ratio = def_ratio;
}
/* Normalize the aspect ratio */
g = gcd(asp_ratio.num, asp_ratio.denum);
asp_ratio.num /= g;
asp_ratio.denum /= g;
/* Get the frame rate, or just use default if not provided. */
if (fps && fps->num && fps->denum) {
the_fps = *fps;
} else {
the_fps = def_fps;
}
/* Calculate maximum size (in macroblocks) */
max_fs = fmtp->max_mbps * the_fps.denum / the_fps.num;
max_fs = PJ_MIN(max_fs, fmtp->max_fs);
/* Check if the specified ratio is using big numbers
* (not normalizable), override it with default ratio!
*/
if ((int)max_fs < asp_ratio.num * asp_ratio.denum)
asp_ratio = def_ratio;
/* Calculate the scale factor for size */
scale = pj_isqrt(max_fs / asp_ratio.denum / asp_ratio.num);
/* Calculate the size, note that the frame size is in macroblock units */
size->w = asp_ratio.num * scale * 16;
size->h = asp_ratio.denum * scale * 16;
/* #1769: for decoding, size is usually used for allocating buffer,
* so we need to make sure that frame size is not less than max_fs.
*/
if (is_decoding && ((size->w * size->h) >> 8) < max_fs) {
/* Size is less than max_fs, recalculate using ratio 1:1 and
* round up the scale.
*/
scale = pj_isqrt(max_fs) + 1;
size->w = size->h = scale * 16;
}
return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_apply_fmtp(
pjmedia_vid_codec_param *param)
{
if (param->dir & PJMEDIA_DIR_ENCODING) {
pjmedia_vid_codec_h264_fmtp fmtp;
pjmedia_video_format_detail *vfd;
pj_status_t status;
/* Get remote param */
status = pjmedia_vid_codec_h264_parse_fmtp(¶m->enc_fmtp,
&fmtp);
if (status != PJ_SUCCESS)
return status;
/* Adjust fps, size, and bitrate to conform to H.264 level
* specified by remote SDP fmtp.
*/
vfd = pjmedia_format_get_video_format_detail(¶m->enc_fmt,
PJ_TRUE);
if (vfd->fps.num == 0 || vfd->fps.denum == 0) {
vfd->fps.num = DEFAULT_H264_FPS_NUM;
vfd->fps.denum = DEFAULT_H264_FPS_DENUM;
}
if (vfd->size.w && vfd->size.h) {
unsigned mb, mbps;
/* Scale down the resolution if it exceeds profile spec */
mb = CALC_H264_MB_NUM(vfd->size);
mbps = CALC_H264_MBPS(vfd->size, vfd->fps);
if (mb > fmtp.max_fs || mbps > fmtp.max_mbps) {
pjmedia_ratio r;
r.num = vfd->size.w;
r.denum = vfd->size.h;
find_highest_res(&fmtp, &vfd->fps, &r, &vfd->size, PJ_FALSE);
}
} else {
/* When not specified, just use the highest res possible*/
pjmedia_ratio r;
r.num = vfd->size.w;
r.denum = vfd->size.h;
find_highest_res(&fmtp, &vfd->fps, &r, &vfd->size, PJ_FALSE);
}
/* Encoding bitrate must not be higher than H264 level spec */
if (vfd->avg_bps > fmtp.max_br * 1000)
vfd->avg_bps = fmtp.max_br * 1000;
if (vfd->max_bps > fmtp.max_br * 1000)
vfd->max_bps = fmtp.max_br * 1000;
}
if (param->dir & PJMEDIA_DIR_DECODING) {
/* Here we just want to find the highest resolution possible from the
* fmtp and set it as the decoder param.
*/
pjmedia_vid_codec_h264_fmtp fmtp;
pjmedia_video_format_detail *vfd;
pjmedia_ratio r;
pjmedia_rect_size highest_size;
pj_status_t status;
status = pjmedia_vid_codec_h264_parse_fmtp(¶m->dec_fmtp,
&fmtp);
if (status != PJ_SUCCESS)
return status;
vfd = pjmedia_format_get_video_format_detail(¶m->dec_fmt,
PJ_TRUE);
if (vfd->fps.num == 0 || vfd->fps.denum == 0) {
vfd->fps.num = DEFAULT_H264_FPS_NUM;
vfd->fps.denum = DEFAULT_H264_FPS_DENUM;
}
/* Normalize decoding resolution, i.e: it must not be lower than
* the H264 profile level setting used, as this may be used by
* app to allocate buffer.
*/
r.num = vfd->size.w;
r.denum = vfd->size.h;
find_highest_res(&fmtp, &vfd->fps, &r, &highest_size, PJ_TRUE);
if (vfd->size.w * vfd->size.h < highest_size.w * highest_size.h)
vfd->size = highest_size;
/* Normalize decoding bitrate based on H264 level spec */
if (vfd->avg_bps < fmtp.max_br * 1000)
vfd->avg_bps = fmtp.max_br * 1000;
if (vfd->max_bps < fmtp.max_br * 1000)
vfd->max_bps = fmtp.max_br * 1000;
}
return PJ_SUCCESS;
}
#endif /* PJMEDIA_HAS_VIDEO */
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 2:29 AM (13 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3408602
Default Alt Text
(22 KB)
Attached To
Mode
rPYNSIPSIMPLE python3-sipsimple
Attached
Detach File
Event Timeline
Log In to Comment