From 483805f79570115ab95c69698792d238c1719b1b Mon Sep 17 00:00:00 2001 From: Jason Parker Date: Mon, 11 Mar 2013 15:09:56 -0500 Subject: Import pjproject-2.1 --- pjmedia/src/pjmedia/codec.c | 52 ++++-- pjmedia/src/pjmedia/conference.c | 6 +- pjmedia/src/pjmedia/converter.c | 4 +- pjmedia/src/pjmedia/endpoint.c | 10 +- pjmedia/src/pjmedia/g711.c | 7 +- pjmedia/src/pjmedia/jbuf.c | 9 +- pjmedia/src/pjmedia/rtcp.c | 5 +- pjmedia/src/pjmedia/rtp.c | 4 +- pjmedia/src/pjmedia/sdp.c | 14 +- pjmedia/src/pjmedia/sdp_neg.c | 4 +- pjmedia/src/pjmedia/stream.c | 104 +++++++++--- pjmedia/src/pjmedia/transport_ice.c | 8 +- pjmedia/src/pjmedia/transport_srtp.c | 69 +++++--- pjmedia/src/pjmedia/transport_udp.c | 8 +- pjmedia/src/pjmedia/types.c | 6 +- pjmedia/src/pjmedia/vid_codec_util.c | 290 +++++++++++++++++++++++----------- pjmedia/src/pjmedia/vid_port.c | 13 +- pjmedia/src/pjmedia/vid_stream.c | 21 ++- pjmedia/src/pjmedia/vid_stream_info.c | 5 +- 19 files changed, 447 insertions(+), 192 deletions(-) (limited to 'pjmedia/src/pjmedia') diff --git a/pjmedia/src/pjmedia/codec.c b/pjmedia/src/pjmedia/codec.c index db8cad2..5107c8c 100644 --- a/pjmedia/src/pjmedia/codec.c +++ b/pjmedia/src/pjmedia/codec.c @@ -1,4 +1,4 @@ -/* $Id: codec.c 3664 2011-07-19 03:42:28Z nanang $ */ +/* $Id: codec.c 4254 2012-09-14 04:06:29Z nanang $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -40,6 +40,39 @@ struct pjmedia_codec_default_param static void sort_codecs(pjmedia_codec_mgr *mgr); +/* + * Duplicate codec parameter. + */ +PJ_DEF(pjmedia_codec_param*) pjmedia_codec_param_clone( + pj_pool_t *pool, + const pjmedia_codec_param *src) +{ + pjmedia_codec_param *p; + unsigned i; + + PJ_ASSERT_RETURN(pool && src, NULL); + + p = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_param); + + /* Update codec param */ + pj_memcpy(p, src, sizeof(pjmedia_codec_param)); + for (i = 0; i < src->setting.dec_fmtp.cnt; ++i) { + pj_strdup(pool, &p->setting.dec_fmtp.param[i].name, + &src->setting.dec_fmtp.param[i].name); + pj_strdup(pool, &p->setting.dec_fmtp.param[i].val, + &src->setting.dec_fmtp.param[i].val); + } + for (i = 0; i < src->setting.enc_fmtp.cnt; ++i) { + pj_strdup(pool, &p->setting.enc_fmtp.param[i].name, + &src->setting.enc_fmtp.param[i].name); + pj_strdup(pool, &p->setting.enc_fmtp.param[i].val, + &src->setting.enc_fmtp.param[i].val); + } + + return p; +} + + /* * Initialize codec manager. */ @@ -600,22 +633,11 @@ PJ_DEF(pj_status_t) pjmedia_codec_mgr_set_default_param( codec_desc->param = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_default_param); p = codec_desc->param; p->pool = pool; - p->param = PJ_POOL_ZALLOC_T(pool, pjmedia_codec_param); /* Update codec param */ - pj_memcpy(p->param, param, sizeof(pjmedia_codec_param)); - for (i = 0; i < param->setting.dec_fmtp.cnt; ++i) { - pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].name, - ¶m->setting.dec_fmtp.param[i].name); - pj_strdup(pool, &p->param->setting.dec_fmtp.param[i].val, - ¶m->setting.dec_fmtp.param[i].val); - } - for (i = 0; i < param->setting.enc_fmtp.cnt; ++i) { - pj_strdup(pool, &p->param->setting.enc_fmtp.param[i].name, - ¶m->setting.enc_fmtp.param[i].name); - pj_strdup(pool, &p->param->setting.enc_fmtp.param[i].val, - ¶m->setting.enc_fmtp.param[i].val); - } + p->param = pjmedia_codec_param_clone(pool, param); + if (!p->param) + return PJ_EINVAL; pj_mutex_unlock(mgr->mutex); diff --git a/pjmedia/src/pjmedia/conference.c b/pjmedia/src/pjmedia/conference.c index a08e7b0..391e4e3 100644 --- a/pjmedia/src/pjmedia/conference.c +++ b/pjmedia/src/pjmedia/conference.c @@ -1,4 +1,4 @@ -/* $Id: conference.c 4162 2012-06-11 04:17:54Z nanang $ */ +/* $Id: conference.c 4198 2012-07-05 10:25:46Z nanang $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -1810,11 +1810,11 @@ static pj_status_t get_frame(pjmedia_port *this_port, /* Var "ci" is to count how many ports have been visited so far. */ ++ci; - /* Reset buffer (only necessary if more than one transmitter) and + /* Reset buffer (only necessary if the port has transmitter) and * reset auto adjustment level for mixed signal. */ conf_port->mix_adj = NORMAL_LEVEL; - if (conf_port->transmitter_cnt > 1) { + if (conf_port->transmitter_cnt) { pj_bzero(conf_port->mix_buf, conf->samples_per_frame*sizeof(conf_port->mix_buf[0])); } diff --git a/pjmedia/src/pjmedia/converter.c b/pjmedia/src/pjmedia/converter.c index 50fbcc8..19a8a8c 100644 --- a/pjmedia/src/pjmedia/converter.c +++ b/pjmedia/src/pjmedia/converter.c @@ -1,4 +1,4 @@ -/* $Id: converter.c 4087 2012-04-26 03:39:24Z ming $ */ +/* $Id: converter.c 4412 2013-03-05 03:12:32Z riza $ */ /* * Copyright (C) 2010-2011 Teluu Inc. (http://www.teluu.com) * @@ -39,7 +39,9 @@ PJ_DEF(pj_status_t) pjmedia_converter_mgr_create(pj_pool_t *pool, pjmedia_converter_mgr **p_mgr) { pjmedia_converter_mgr *mgr; +#if PJMEDIA_HAS_LIBSWSCALE && PJMEDIA_HAS_LIBAVUTIL pj_status_t status = PJ_SUCCESS; +#endif mgr = PJ_POOL_ALLOC_T(pool, pjmedia_converter_mgr); pj_list_init(&mgr->factory_list); diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c index e20a5a4..b61152e 100644 --- a/pjmedia/src/pjmedia/endpoint.c +++ b/pjmedia/src/pjmedia/endpoint.c @@ -1,4 +1,4 @@ -/* $Id: endpoint.c 3999 2012-03-30 07:10:13Z bennylp $ */ +/* $Id: endpoint.c 4240 2012-08-31 09:03:36Z ming $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -49,6 +49,10 @@ static const pj_str_t STR_SENDRECV = { "sendrecv", 8 }; pj_bool_t pjmedia_add_rtpmap_for_static_pt = PJMEDIA_ADD_RTPMAP_FOR_STATIC_PT; +/* Config to control use of RFC3890 TIAS */ +pj_bool_t pjmedia_add_bandwidth_tias_in_sdp = + PJMEDIA_ADD_BANDWIDTH_TIAS_IN_SDP; + /* Worker thread proc. */ @@ -551,7 +555,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt, /* Put bandwidth info in media level using bandwidth modifier "TIAS" * (RFC3890). */ - if (max_bitrate) { + if (max_bitrate && pjmedia_add_bandwidth_tias_in_sdp) { const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 }; pjmedia_sdp_bandw *b; @@ -715,7 +719,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt, /* Put bandwidth info in media level using bandwidth modifier "TIAS" * (RFC3890). */ - if (max_bitrate) { + if (max_bitrate && pjmedia_add_bandwidth_tias_in_sdp) { const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 }; pjmedia_sdp_bandw *b; diff --git a/pjmedia/src/pjmedia/g711.c b/pjmedia/src/pjmedia/g711.c index 0a61a47..2e3ec7b 100644 --- a/pjmedia/src/pjmedia/g711.c +++ b/pjmedia/src/pjmedia/g711.c @@ -1,4 +1,4 @@ -/* $Id: g711.c 3664 2011-07-19 03:42:28Z nanang $ */ +/* $Id: g711.c 4266 2012-09-26 05:55:18Z nanang $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -331,7 +331,8 @@ static pj_status_t g711_alloc_codec( pjmedia_codec_factory *factory, #if !PLC_DISABLED /* Create PLC, always with 10ms ptime */ - status = pjmedia_plc_create(g711_factory.pool, 8000, 80, + status = pjmedia_plc_create(g711_factory.pool, 8000, + SAMPLES_PER_FRAME, 0, &codec_priv->plc); if (status != PJ_SUCCESS) { pj_mutex_unlock(g711_factory.mutex); @@ -341,7 +342,7 @@ static pj_status_t g711_alloc_codec( pjmedia_codec_factory *factory, /* Create VAD */ status = pjmedia_silence_det_create(g711_factory.pool, - 8000, 80, + 8000, SAMPLES_PER_FRAME, &codec_priv->vad); if (status != PJ_SUCCESS) { pj_mutex_unlock(g711_factory.mutex); diff --git a/pjmedia/src/pjmedia/jbuf.c b/pjmedia/src/pjmedia/jbuf.c index 74f6469..8c54074 100644 --- a/pjmedia/src/pjmedia/jbuf.c +++ b/pjmedia/src/pjmedia/jbuf.c @@ -1,4 +1,4 @@ -/* $Id: jbuf.c 4100 2012-04-26 16:57:47Z nanang $ */ +/* $Id: jbuf.c 4369 2013-02-21 21:55:54Z bennylp $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -167,7 +167,7 @@ struct pjmedia_jbuf /* Enabling this would log the jitter buffer state about once per * second. */ -#if 1 +#if 0 # define TRACE__(args) PJ_LOG(5,args) #else # define TRACE__(args) @@ -599,6 +599,7 @@ PJ_DEF(pj_status_t) pjmedia_jbuf_set_fixed( pjmedia_jbuf *jb, jb->jb_min_prefetch = jb->jb_max_prefetch = jb->jb_prefetch = jb->jb_init_prefetch = prefetch; + pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_NONE); return PJ_SUCCESS; } @@ -724,6 +725,8 @@ static void jbuf_calculate_jitter(pjmedia_jbuf *jb) jb->jb_prefetch = jb->jb_eff_level; if (jb->jb_prefetch < jb->jb_min_prefetch) jb->jb_prefetch = jb->jb_min_prefetch; + if (jb->jb_prefetch > jb->jb_max_prefetch) + jb->jb_prefetch = jb->jb_max_prefetch; } /* Reset history */ @@ -747,6 +750,8 @@ static void jbuf_calculate_jitter(pjmedia_jbuf *jb) jb->jb_prefetch = jb->jb_eff_level; if (jb->jb_prefetch > jb->jb_max_prefetch) jb->jb_prefetch = jb->jb_max_prefetch; + if (jb->jb_prefetch < jb->jb_min_prefetch) + jb->jb_prefetch = jb->jb_min_prefetch; } jb->jb_stable_hist = 0; diff --git a/pjmedia/src/pjmedia/rtcp.c b/pjmedia/src/pjmedia/rtcp.c index f57797c..fbfae13 100644 --- a/pjmedia/src/pjmedia/rtcp.c +++ b/pjmedia/src/pjmedia/rtcp.c @@ -1,4 +1,4 @@ -/* $Id: rtcp.c 3999 2012-03-30 07:10:13Z bennylp $ */ +/* $Id: rtcp.c 4283 2012-10-12 06:19:32Z ming $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -752,7 +752,8 @@ static void parse_rtcp_bye(pjmedia_rtcp_session *sess, /* Check and get BYE reason */ if (size > 8) { - reason.slen = *((pj_uint8_t*)pkt+8); + reason.slen = PJ_MIN(sizeof(sess->stat.peer_sdes_buf_), + *((pj_uint8_t*)pkt+8)); pj_memcpy(sess->stat.peer_sdes_buf_, ((pj_uint8_t*)pkt+9), reason.slen); reason.ptr = sess->stat.peer_sdes_buf_; diff --git a/pjmedia/src/pjmedia/rtp.c b/pjmedia/src/pjmedia/rtp.c index 7fe6f89..c9ea53c 100644 --- a/pjmedia/src/pjmedia/rtp.c +++ b/pjmedia/src/pjmedia/rtp.c @@ -1,4 +1,4 @@ -/* $Id: rtp.c 3553 2011-05-05 06:14:19Z nanang $ */ +/* $Id: rtp.c 4235 2012-08-24 03:15:42Z ming $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -118,8 +118,6 @@ PJ_DEF(pj_status_t) pjmedia_rtp_encode_rtp( pjmedia_rtp_session *ses, int payload_len, int ts_len, const void **rtphdr, int *hdrlen ) { - PJ_UNUSED_ARG(payload_len); - /* Update timestamp */ ses->out_hdr.ts = pj_htonl(pj_ntohl(ses->out_hdr.ts)+ts_len); diff --git a/pjmedia/src/pjmedia/sdp.c b/pjmedia/src/pjmedia/sdp.c index e54bfcf..c0d43d8 100644 --- a/pjmedia/src/pjmedia/sdp.c +++ b/pjmedia/src/pjmedia/sdp.c @@ -1,4 +1,4 @@ -/* $Id: sdp.c 3945 2012-01-27 09:12:59Z nanang $ */ +/* $Id: sdp.c 4367 2013-02-21 20:49:19Z nanang $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -1422,6 +1422,14 @@ static pj_status_t validate_sdp_conn(const pjmedia_sdp_conn *c) /* Validate SDP session descriptor. */ PJ_DEF(pj_status_t) pjmedia_sdp_validate(const pjmedia_sdp_session *sdp) +{ + return pjmedia_sdp_validate2(sdp, PJ_TRUE); +} + + +/* Validate SDP session descriptor. */ +PJ_DEF(pj_status_t) pjmedia_sdp_validate2(const pjmedia_sdp_session *sdp, + pj_bool_t strict) { unsigned i; const pj_str_t STR_RTPMAP = { "rtpmap", 6 }; @@ -1471,7 +1479,8 @@ PJ_DEF(pj_status_t) pjmedia_sdp_validate(const pjmedia_sdp_session *sdp) */ if (m->conn == NULL) { if (sdp->conn == NULL) - return PJMEDIA_SDP_EMISSINGCONN; + if (strict || m->desc.port != 0) + return PJMEDIA_SDP_EMISSINGCONN; } /* Verify payload type. */ @@ -1505,6 +1514,7 @@ PJ_DEF(pj_status_t) pjmedia_sdp_validate(const pjmedia_sdp_session *sdp) return PJ_SUCCESS; } + PJ_DEF(pj_status_t) pjmedia_sdp_transport_cmp( const pj_str_t *t1, const pj_str_t *t2) { diff --git a/pjmedia/src/pjmedia/sdp_neg.c b/pjmedia/src/pjmedia/sdp_neg.c index bdce18d..61e6d93 100644 --- a/pjmedia/src/pjmedia/sdp_neg.c +++ b/pjmedia/src/pjmedia/sdp_neg.c @@ -1,4 +1,4 @@ -/* $Id: sdp_neg.c 3980 2012-03-20 09:23:20Z ming $ */ +/* $Id: sdp_neg.c 4367 2013-02-21 20:49:19Z nanang $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -138,7 +138,7 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_create_w_remote_offer(pj_pool_t *pool, *p_neg = NULL; /* Validate remote offer and initial answer */ - status = pjmedia_sdp_validate(remote); + status = pjmedia_sdp_validate2(remote, PJ_FALSE); if (status != PJ_SUCCESS) return status; diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index 5c7c873..840b06c 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -1,4 +1,4 @@ -/* $Id: stream.c 4120 2012-05-12 07:18:09Z ming $ */ +/* $Id: stream.c 4336 2013-01-29 08:15:02Z ming $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -73,6 +73,8 @@ # define PJMEDIA_STREAM_INC 1000 #endif +/* Number of DTMF E bit transmissions */ +#define DTMF_EBIT_RETRANSMIT_CNT 3 /** * Media channel. @@ -94,6 +96,7 @@ struct dtmf { int event; pj_uint32_t duration; + int ebit_cnt; /**< # of E bit transmissions */ }; /** @@ -876,7 +879,7 @@ static pj_status_t get_frame_ext( pjmedia_port *port, pjmedia_frame *frame) */ static void create_dtmf_payload(pjmedia_stream *stream, struct pjmedia_frame *frame_out, - int *first, int *last) + int forced_last, int *first, int *last) { pjmedia_rtp_dtmf_event *event; struct dtmf *digit = &stream->tx_dtmf_buf[0]; @@ -896,25 +899,33 @@ static void create_dtmf_payload(pjmedia_stream *stream, } digit->duration += PJMEDIA_PIA_SPF(&stream->port.info); + if (digit->duration >= PJMEDIA_DTMF_DURATION) + digit->duration = PJMEDIA_DTMF_DURATION; event->event = (pj_uint8_t)digit->event; event->e_vol = 10; event->duration = pj_htons((pj_uint16_t)digit->duration); + if (forced_last) { + digit->duration = PJMEDIA_DTMF_DURATION; + } if (digit->duration >= PJMEDIA_DTMF_DURATION) { event->e_vol |= 0x80; - *last = 1; - /* Prepare next digit. */ - pj_mutex_lock(stream->jb_mutex); + if (++digit->ebit_cnt >= DTMF_EBIT_RETRANSMIT_CNT) { + *last = 1; - pj_array_erase(stream->tx_dtmf_buf, sizeof(stream->tx_dtmf_buf[0]), - stream->tx_dtmf_count, 0); - --stream->tx_dtmf_count; + /* Prepare next digit. */ + pj_mutex_lock(stream->jb_mutex); - pj_mutex_unlock(stream->jb_mutex); + pj_array_erase(stream->tx_dtmf_buf, sizeof(stream->tx_dtmf_buf[0]), + stream->tx_dtmf_count, 0); + --stream->tx_dtmf_count; + + pj_mutex_unlock(stream->jb_mutex); + } } frame_out->size = 4; @@ -1217,7 +1228,7 @@ static pj_status_t put_frame_imp( pjmedia_port *port, if (stream->tx_dtmf_count) { int first=0, last=0; - create_dtmf_payload(stream, &frame_out, &first, &last); + create_dtmf_payload(stream, &frame_out, 0, &first, &last); /* Encapsulate into RTP packet. Note that: * - RTP marker should be set on the beginning of a new event @@ -1235,7 +1246,9 @@ static pj_status_t put_frame_imp( pjmedia_port *port, * Increment the RTP timestamp of the RTP session, for next * RTP packets. */ - inc_timestamp = PJMEDIA_DTMF_DURATION - rtp_ts_len; + inc_timestamp = PJMEDIA_DTMF_DURATION + + ((DTMF_EBIT_RETRANSMIT_CNT-1) * samples_per_frame) + - rtp_ts_len; } @@ -1765,7 +1778,11 @@ static void on_rx_rtp( void *data, peer_frm_ts_diff == (frm_ts_span>>1))) { if (peer_frm_ts_diff < stream->rtp_rx_ts_len_per_frame) + { stream->rtp_rx_ts_len_per_frame = peer_frm_ts_diff; + /* Done, stop the check immediately */ + stream->rtp_rx_check_cnt = 1; + } if (--stream->rtp_rx_check_cnt == 0) { PJ_LOG(4, (THIS_FILE, "G722 codec used, remote" @@ -1985,6 +2002,8 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM); stream->own_pool = own_pool; pj_memcpy(&stream->si, info, sizeof(*info)); + stream->si.param = pjmedia_codec_param_clone(pool, info->param); + pj_strdup(pool, &stream->si.fmt.encoding_name, &info->fmt.encoding_name); /* Init stream/port name */ name.ptr = (char*) pj_pool_alloc(pool, M); @@ -2159,12 +2178,16 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, } /* Get the frame size */ - stream->frame_size = stream->codec_param.info.max_bps * - stream->codec_param.info.frm_ptime / 8 / 1000; - if ((stream->codec_param.info.max_bps * stream->codec_param.info.frm_ptime) - % 8000 != 0) - { - ++stream->frame_size; + if (stream->codec_param.info.max_rx_frame_size > 0) { + stream->frame_size = stream->codec_param.info.max_rx_frame_size; + } else { + stream->frame_size = stream->codec_param.info.max_bps * + stream->codec_param.info.frm_ptime / 8 / 1000; + if ((stream->codec_param.info.max_bps * + stream->codec_param.info.frm_ptime) % 8000 != 0) + { + ++stream->frame_size; + } } /* How many consecutive PLC frames can be generated */ @@ -2172,7 +2195,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt, stream->codec_param.info.frm_ptime; #if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG!=0) - stream->rtp_rx_check_cnt = 5; + stream->rtp_rx_check_cnt = 50; stream->has_g722_mpeg_bug = PJ_FALSE; stream->rtp_rx_last_ts = 0; stream->rtp_rx_last_cnt = 0; @@ -2410,6 +2433,8 @@ err_cleanup: */ PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream ) { + pj_status_t status; + PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); /* Send RTCP BYE (also SDES & XR) */ @@ -2417,6 +2442,48 @@ PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream ) send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_TRUE); } + /* If we're in the middle of transmitting DTMF digit, send one last + * RFC 2833 RTP packet with 'End' flag set. + */ + if (stream->tx_dtmf_count && stream->tx_dtmf_buf[0].duration != 0) { + pjmedia_frame frame_out; + pjmedia_channel *channel = stream->enc; + int first=0, last=0; + void *rtphdr; + int rtphdrlen; + + pj_bzero(&frame_out, sizeof(frame_out)); + frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); + frame_out.size = 0; + + create_dtmf_payload(stream, &frame_out, 1, &first, &last); + + /* Encapsulate into RTP packet. Note that: + * - RTP marker should be set on the beginning of a new event + * - RTP timestamp is constant for the same packet. + */ + status = pjmedia_rtp_encode_rtp( &channel->rtp, + stream->tx_event_pt, first, + frame_out.size, 0, + (const void**)&rtphdr, + &rtphdrlen); + if (status == PJ_SUCCESS) { + /* Copy RTP header to the beginning of packet */ + pj_memcpy(channel->out_pkt, rtphdr, sizeof(pjmedia_rtp_hdr)); + + /* Send the RTP packet to the transport. */ + status = pjmedia_transport_send_rtp(stream->transport, + channel->out_pkt, + frame_out.size + + sizeof(pjmedia_rtp_hdr)); + } + + if (status != PJ_SUCCESS) { + PJ_PERROR(4,(stream->port.info.name.ptr, status, + "Error sending RTP/DTMF end packet")); + } + } + /* Detach from transport * MUST NOT hold stream mutex while detaching from transport, as * it may cause deadlock. See ticket #460 for the details. @@ -2692,6 +2759,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_dial_dtmf( pjmedia_stream *stream, stream->tx_dtmf_buf[stream->tx_dtmf_count+i].event = pt; stream->tx_dtmf_buf[stream->tx_dtmf_count+i].duration = 0; + stream->tx_dtmf_buf[stream->tx_dtmf_count+i].ebit_cnt = 0; } if (status != PJ_SUCCESS) diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c index 40bb71b..7c3deb2 100644 --- a/pjmedia/src/pjmedia/transport_ice.c +++ b/pjmedia/src/pjmedia/transport_ice.c @@ -1,4 +1,4 @@ -/* $Id: transport_ice.c 3999 2012-03-30 07:10:13Z bennylp $ */ +/* $Id: transport_ice.c 4350 2013-02-15 03:57:31Z nanang $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -285,7 +285,9 @@ static void set_no_ice(struct transport_ice *tp_ice, const char *reason, "Stopping ICE, reason=%s", reason)); } - pj_ice_strans_stop_ice(tp_ice->ice_st); + if (tp_ice->ice_st) { + pj_ice_strans_stop_ice(tp_ice->ice_st); + } tp_ice->use_ice = PJ_FALSE; } @@ -1541,6 +1543,8 @@ static pj_status_t transport_get_info(pjmedia_transport *tp, ii = (pjmedia_ice_transport_info*) tsi->buffer; pj_bzero(ii, sizeof(*ii)); + ii->active = tp_ice->use_ice; + if (pj_ice_strans_has_sess(tp_ice->ice_st)) ii->role = pj_ice_strans_get_role(tp_ice->ice_st); else diff --git a/pjmedia/src/pjmedia/transport_srtp.c b/pjmedia/src/pjmedia/transport_srtp.c index 1321e75..a661c37 100644 --- a/pjmedia/src/pjmedia/transport_srtp.c +++ b/pjmedia/src/pjmedia/transport_srtp.c @@ -1,4 +1,4 @@ -/* $Id: transport_srtp.c 3999 2012-03-30 07:10:13Z bennylp $ */ +/* $Id: transport_srtp.c 4366 2013-02-21 20:41:31Z ming $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -34,10 +34,12 @@ #define THIS_FILE "transport_srtp.c" -/* Maximum size of packet */ -#define MAX_RTP_BUFFER_LEN 1500 -#define MAX_RTCP_BUFFER_LEN 1500 -#define MAX_KEY_LEN 32 +/* Maximum size of outgoing packet */ +#define MAX_RTP_BUFFER_LEN PJMEDIA_MAX_MTU +#define MAX_RTCP_BUFFER_LEN PJMEDIA_MAX_MTU + +/* Maximum SRTP crypto key length */ +#define MAX_KEY_LEN 128 /* Initial value of probation counter. When probation counter > 0, * it means SRTP is in probation state, and it may restart when @@ -611,19 +613,47 @@ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start( /* Declare SRTP session initialized */ srtp->session_inited = PJ_TRUE; - PJ_LOG(5, (srtp->pool->obj_name, "TX: %s key=%s", srtp->tx_policy.name.ptr, - octet_string_hex_string(tx->key.ptr, tx->key.slen))); - if (srtp->tx_policy.flags) { - PJ_LOG(5,(srtp->pool->obj_name,"TX: disable%s%s", (cr_tx_idx?"":" enc"), - (au_tx_idx?"":" auth"))); - } + /* Logging stuffs */ +#if PJ_LOG_MAX_LEVEL >= 5 + { + char b64[PJ_BASE256_TO_BASE64_LEN(MAX_KEY_LEN)]; + int b64_len; + + /* TX crypto and key */ + b64_len = sizeof(b64); + status = pj_base64_encode((pj_uint8_t*)tx->key.ptr, tx->key.slen, + b64, &b64_len); + if (status != PJ_SUCCESS) + b64_len = pj_ansi_sprintf(b64, "--key too long--"); + else + b64[b64_len] = '\0'; + + PJ_LOG(5, (srtp->pool->obj_name, "TX: %s key=%s", + srtp->tx_policy.name.ptr, b64)); + if (srtp->tx_policy.flags) { + PJ_LOG(5,(srtp->pool->obj_name, "TX: disable%s%s", + (cr_tx_idx?"":" enc"), + (au_tx_idx?"":" auth"))); + } - PJ_LOG(5, (srtp->pool->obj_name, "RX: %s key=%s", srtp->rx_policy.name.ptr, - octet_string_hex_string(rx->key.ptr, rx->key.slen))); - if (srtp->rx_policy.flags) { - PJ_LOG(5,(srtp->pool->obj_name,"RX: disable%s%s", (cr_rx_idx?"":" enc"), - (au_rx_idx?"":" auth"))); + /* RX crypto and key */ + b64_len = sizeof(b64); + status = pj_base64_encode((pj_uint8_t*)rx->key.ptr, rx->key.slen, + b64, &b64_len); + if (status != PJ_SUCCESS) + b64_len = pj_ansi_sprintf(b64, "--key too long--"); + else + b64[b64_len] = '\0'; + + PJ_LOG(5, (srtp->pool->obj_name, "RX: %s key=%s", + srtp->rx_policy.name.ptr, b64)); + if (srtp->rx_policy.flags) { + PJ_LOG(5,(srtp->pool->obj_name,"RX: disable%s%s", + (cr_rx_idx?"":" enc"), + (au_rx_idx?"":" auth"))); + } } +#endif on_return: pj_lock_release(srtp->mutex); @@ -777,7 +807,7 @@ static pj_status_t transport_send_rtp( pjmedia_transport *tp, if (srtp->bypass_srtp) return pjmedia_transport_send_rtp(srtp->member_tp, pkt, size); - if (size > sizeof(srtp->rtp_tx_buffer)) + if (size > sizeof(srtp->rtp_tx_buffer) - 10) return PJ_ETOOBIG; pj_memcpy(srtp->rtp_tx_buffer, pkt, size); @@ -791,7 +821,8 @@ static pj_status_t transport_send_rtp( pjmedia_transport *tp, pj_lock_release(srtp->mutex); if (err == err_status_ok) { - status = pjmedia_transport_send_rtp(srtp->member_tp, srtp->rtp_tx_buffer, len); + status = pjmedia_transport_send_rtp(srtp->member_tp, + srtp->rtp_tx_buffer, len); } else { status = PJMEDIA_ERRNO_FROM_LIBSRTP(err); } @@ -822,7 +853,7 @@ static pj_status_t transport_send_rtcp2(pjmedia_transport *tp, pkt, size); } - if (size > sizeof(srtp->rtcp_tx_buffer)) + if (size > sizeof(srtp->rtcp_tx_buffer) - 10) return PJ_ETOOBIG; pj_memcpy(srtp->rtcp_tx_buffer, pkt, size); diff --git a/pjmedia/src/pjmedia/transport_udp.c b/pjmedia/src/pjmedia/transport_udp.c index 76f9bbb..458424d 100644 --- a/pjmedia/src/pjmedia/transport_udp.c +++ b/pjmedia/src/pjmedia/transport_udp.c @@ -1,4 +1,4 @@ -/* $Id: transport_udp.c 3841 2011-10-24 09:28:13Z ming $ */ +/* $Id: transport_udp.c 4197 2012-07-05 07:26:29Z nanang $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -29,7 +29,7 @@ /* Maximum size of incoming RTP packet */ -#define RTP_LEN PJMEDIA_MAX_MTU +#define RTP_LEN PJMEDIA_MAX_MRU /* Maximum size of incoming RTCP packet */ #define RTCP_LEN 600 @@ -42,7 +42,7 @@ static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 }; /* Pending write buffer */ typedef struct pending_write { - char buffer[RTP_LEN]; + char buffer[PJMEDIA_MAX_MTU]; pj_ioqueue_op_key_t op_key; } pending_write; @@ -752,7 +752,7 @@ static pj_status_t transport_send_rtp( pjmedia_transport *tp, PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP); /* Check that the size is supported */ - PJ_ASSERT_RETURN(size <= RTP_LEN, PJ_ETOOBIG); + PJ_ASSERT_RETURN(size <= PJMEDIA_MAX_MTU, PJ_ETOOBIG); /* Simulate packet lost on TX direction */ if (udp->tx_drop_pct) { diff --git a/pjmedia/src/pjmedia/types.c b/pjmedia/src/pjmedia/types.c index b280ea8..732f9b5 100644 --- a/pjmedia/src/pjmedia/types.c +++ b/pjmedia/src/pjmedia/types.c @@ -1,4 +1,4 @@ -/* $Id: types.c 3715 2011-08-19 09:35:25Z nanang $ */ +/* $Id: types.c 4411 2013-03-04 04:34:38Z nanang $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono @@ -37,10 +37,10 @@ PJ_DEF(const char*) pjmedia_type_name(pjmedia_type t) "unknown" }; - pj_assert(t < PJ_ARRAY_SIZE(type_names)); + pj_assert(t < (int)PJ_ARRAY_SIZE(type_names)); pj_assert(PJMEDIA_TYPE_UNKNOWN == 4); - if (t < PJ_ARRAY_SIZE(type_names)) + if (t < (int)PJ_ARRAY_SIZE(type_names)) return type_names[t]; else return "??"; diff --git a/pjmedia/src/pjmedia/vid_codec_util.c b/pjmedia/src/pjmedia/vid_codec_util.c index e51fff4..8cc241b 100644 --- a/pjmedia/src/pjmedia/vid_codec_util.c +++ b/pjmedia/src/pjmedia/vid_codec_util.c @@ -1,4 +1,4 @@ -/* $Id: vid_codec_util.c 3995 2012-03-29 10:54:01Z nanang $ */ +/* $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 @@ -38,6 +38,14 @@ */ #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 @@ -55,6 +63,10 @@ mpi_resolutions [] = }; +#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, @@ -291,6 +303,75 @@ PJ_DEF(pj_status_t) pjmedia_vid_codec_h263_apply_fmtp( } +/* 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, @@ -305,24 +386,17 @@ PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp( 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; icnt; ++i) { unsigned tmp; if (pj_stricmp(&fmtp->param[i].name, &PROFILE_LEVEL_ID)==0) { - pj_str_t endst; - - if (fmtp->param[i].val.slen != 6) - return PJMEDIA_SDP_EINFMTP; - - tmp = pj_strtoul2(&fmtp->param[i].val, &endst, 16); - if (endst.slen) - return PJMEDIA_SDP_EINFMTP; - - h264_fmtp->profile_idc = (pj_uint8_t)((tmp >> 16) & 0xFF); - h264_fmtp->profile_iop = (pj_uint8_t)((tmp >> 8) & 0xFF); - h264_fmtp->level = (pj_uint8_t)(tmp & 0xFF); + /* 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) @@ -331,19 +405,19 @@ PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp( 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 = tmp; + 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 = tmp; + 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 = tmp; + 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 = tmp; + 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 = tmp; + 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; @@ -507,66 +581,80 @@ PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_match_sdp(pj_pool_t *pool, } -/* 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 bitrate; /* Max bitrate (kbps). */ - unsigned def_w; /* Default width. */ - unsigned def_h; /* Default height. */ - unsigned def_fps; /* Default fps. */ -} h264_level_info_t; - +/* 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; +} -/* Get H.264 level info from specified level ID */ -static pj_status_t get_h264_level_info(unsigned id, h264_level_info_t *level) +/* 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) { - unsigned i; - const h264_level_info_t level_info[] = - { - { 10, 1485, 99, 64, 176, 144, 15 }, - { 9, 1485, 99, 128, 176, 144, 15 }, /*< level 1b */ - { 11, 3000, 396, 192, 320, 240, 10 }, - { 12, 6000, 396, 384, 352, 288, 15 }, - { 13, 11880, 396, 768, 352, 288, 15 }, - { 20, 11880, 396, 2000, 352, 288, 30 }, - { 21, 19800, 792, 4000, 352, 288, 30 }, - { 22, 20250, 1620, 4000, 352, 288, 30 }, - { 30, 40500, 1620, 10000, 720, 480, 30 }, - { 31, 108000, 3600, 14000, 1280, 720, 30 }, - { 32, 216000, 5120, 20000, 1280, 720, 30 }, - { 40, 245760, 8192, 20000, 1920, 1080, 30 }, - { 41, 245760, 8192, 50000, 1920, 1080, 30 }, - { 42, 522240, 8704, 50000, 1920, 1080, 30 }, - { 50, 589824, 22080, 135000, 1920, 1080, 30 }, - { 51, 983040, 36864, 240000, 1920, 1080, 30 }, - }; + 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; + } - for (i = 0; i < PJ_ARRAY_SIZE(level_info); ++i) { - if (level_info[i].id == id) { - *level = level_info[i]; - return PJ_SUCCESS; - } + /* 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; } - return PJ_ENOTFOUND; -} + /* Calculate maximum size (in macroblocks) */ + max_fs = fmtp->max_mbps * fps->denum / fps->num; + max_fs = PJ_MIN(max_fs, fmtp->max_fs); -#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 + /* 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; + + return PJ_SUCCESS; +} PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_apply_fmtp( pjmedia_vid_codec_param *param) { - const unsigned default_fps = 30; - if (param->dir & PJMEDIA_DIR_ENCODING) { pjmedia_vid_codec_h264_fmtp fmtp; pjmedia_video_format_detail *vfd; - h264_level_info_t level_info; pj_status_t status; /* Get remote param */ @@ -575,36 +663,42 @@ PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_apply_fmtp( if (status != PJ_SUCCESS) return status; - status = get_h264_level_info(fmtp.level, &level_info); - if (status != PJ_SUCCESS) - return status; - - /* Size and fps for encoding direction must conform to H.264 level + /* 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; - if (vfd->fps.num == 0 || vfd->fps.denum == 0) { - vfd->fps.num = default_fps; - vfd->fps.denum = 1; - } + /* 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 > level_info.max_mb || mbps > level_info.max_mbps) { - vfd->size.w = level_info.def_w; - vfd->size.h = level_info.def_h; - vfd->fps.num = level_info.def_fps; - vfd->fps.denum = 1; + 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); } } else { - vfd->size.w = level_info.def_w; - vfd->size.h = level_info.def_h; - vfd->fps.num = level_info.def_fps; - vfd->fps.denum = 1; + /* 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); } + + /* 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) { @@ -613,7 +707,8 @@ PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_apply_fmtp( */ pjmedia_vid_codec_h264_fmtp fmtp; pjmedia_video_format_detail *vfd; - h264_level_info_t level_info; + pjmedia_ratio r; + pjmedia_rect_size highest_size; pj_status_t status; status = pjmedia_vid_codec_h264_parse_fmtp(¶m->dec_fmtp, @@ -621,22 +716,29 @@ PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_apply_fmtp( if (status != PJ_SUCCESS) return status; - status = get_h264_level_info(fmtp.level, &level_info); - if (status != PJ_SUCCESS) - return status; - vfd = pjmedia_format_get_video_format_detail(¶m->dec_fmt, PJ_TRUE); - if (vfd->size.w * vfd->size.h < level_info.def_w * level_info.def_h) { - vfd->size.w = level_info.def_w; - vfd->size.h = level_info.def_h; - } - if (vfd->fps.num == 0 || vfd->fps.denum == 0) { - vfd->fps.num = default_fps; - vfd->fps.denum = 1; + 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); + 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; diff --git a/pjmedia/src/pjmedia/vid_port.c b/pjmedia/src/pjmedia/vid_port.c index 289e3e5..017e867 100644 --- a/pjmedia/src/pjmedia/vid_port.c +++ b/pjmedia/src/pjmedia/vid_port.c @@ -1,4 +1,4 @@ -/* $Id: vid_port.c 4168 2012-06-18 05:59:08Z ming $ */ +/* $Id: vid_port.c 4290 2012-11-01 03:06:33Z ming $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * @@ -332,9 +332,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_port_create( pj_pool_t *pool, PJMEDIA_SIG_VID_PORT, prm->vidparam.dir, &prm->vidparam.fmt); - if (vp->stream_role == ROLE_ACTIVE) { - need_frame_buf = PJ_TRUE; - } + need_frame_buf = PJ_TRUE; } if (need_frame_buf) { @@ -654,8 +652,10 @@ static pj_status_t convert_frame(pjmedia_vid_port *vp, pj_status_t status = PJ_SUCCESS; if (vp->conv.conv) { - dst_frame->buf = vp->conv.conv_buf; - dst_frame->size = vp->conv.conv_buf_size; + if (!dst_frame->buf || dst_frame->size < vp->conv.conv_buf_size) { + dst_frame->buf = vp->conv.conv_buf; + dst_frame->size = vp->conv.conv_buf_size; + } status = pjmedia_converter_convert(vp->conv.conv, src_frame, dst_frame); } @@ -922,6 +922,7 @@ static pj_status_t vid_pasv_port_put_frame(struct pjmedia_port *this_port, pj_status_t status; pjmedia_frame frame_; + pj_bzero(&frame_, sizeof(frame_)); status = convert_frame(vp, frame, &frame_); if (status != PJ_SUCCESS) return status; diff --git a/pjmedia/src/pjmedia/vid_stream.c b/pjmedia/src/pjmedia/vid_stream.c index d899408..e101d7b 100644 --- a/pjmedia/src/pjmedia/vid_stream.c +++ b/pjmedia/src/pjmedia/vid_stream.c @@ -1,4 +1,4 @@ -/* $Id: vid_stream.c 4123 2012-05-14 11:17:31Z ming $ */ +/* $Id: vid_stream.c 4197 2012-07-05 07:26:29Z nanang $ */ /* * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com) * @@ -68,6 +68,13 @@ # define PJMEDIA_VSTREAM_INC 1000 #endif +/* Due to network MTU limitation, a picture bitstream may be splitted into + * several chunks for RTP delivery. The chunk number may vary depend on the + * picture resolution and MTU. This constant specifies the minimum chunk + * number to be allocated to store a picture bitstream in decoding direction. + */ +#define MIN_CHUNKS_PER_FRM 30 + /* Video stream keep-alive feature is currently disabled. */ #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0 # undef PJMEDIA_STREAM_ENABLE_KA @@ -1357,7 +1364,6 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_create( int frm_ptime, chunks_per_frm; pjmedia_video_format_detail *vfd_enc, *vfd_dec; char *p; - unsigned dec_mtu; pj_status_t status; if (!pool) { @@ -1410,9 +1416,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_create( if (info->codec_param->enc_mtu > PJMEDIA_MAX_MTU) info->codec_param->enc_mtu = PJMEDIA_MAX_MTU; - /* MTU estimation for decoding direction */ - dec_mtu = PJMEDIA_MAX_MTU; - + /* Packet size estimation for decoding direction */ vfd_enc = pjmedia_format_get_video_format_detail( &info->codec_param->enc_fmt, PJ_TRUE); vfd_dec = pjmedia_format_get_video_format_detail( @@ -1528,8 +1532,9 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_create( /* Init jitter buffer parameters: */ frm_ptime = 1000 * vfd_enc->fps.denum / vfd_enc->fps.num; - chunks_per_frm = stream->frame_size / dec_mtu; - if (chunks_per_frm == 0) chunks_per_frm = 1; + chunks_per_frm = stream->frame_size / PJMEDIA_MAX_MRU; + if (chunks_per_frm < MIN_CHUNKS_PER_FRM) + chunks_per_frm = MIN_CHUNKS_PER_FRM; /* JB max count, default 500ms */ if (info->jb_max >= frm_ptime) @@ -1564,7 +1569,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_create( /* Create jitter buffer */ status = pjmedia_jbuf_create(pool, &stream->dec->port.info.name, - dec_mtu + PJMEDIA_STREAM_RESV_PAYLOAD_LEN, + PJMEDIA_MAX_MRU, 1000 * vfd_enc->fps.denum / vfd_enc->fps.num, jb_max, &stream->jb); if (status != PJ_SUCCESS) diff --git a/pjmedia/src/pjmedia/vid_stream_info.c b/pjmedia/src/pjmedia/vid_stream_info.c index 51b688f..37dae5b 100644 --- a/pjmedia/src/pjmedia/vid_stream_info.c +++ b/pjmedia/src/pjmedia/vid_stream_info.c @@ -1,4 +1,4 @@ -/* $Id: vid_stream_info.c 3982 2012-03-22 09:56:52Z bennylp $ */ +/* $Id: vid_stream_info.c 4257 2012-09-17 03:11:44Z ming $ */ /* * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com) * @@ -22,6 +22,7 @@ #include #include +#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) static const pj_str_t ID_VIDEO = { "video", 5}; static const pj_str_t ID_IN = { "IN", 2 }; @@ -382,4 +383,4 @@ PJ_DEF(pj_status_t) pjmedia_vid_stream_info_from_sdp( return status; } - +#endif /* PJMEDIA_HAS_VIDEO */ -- cgit v1.2.3