- Timestamp:
- Apr 6, 2011 1:55:01 PM (14 years ago)
- Location:
- pjproject/branches/projects/2.0-dev
- Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia-codec/types.h
r3461 r3500 108 108 PJMEDIA_RTP_PT_H263P, 109 109 PJMEDIA_RTP_PT_H264, 110 PJMEDIA_RTP_PT_H264_RSV1, 111 PJMEDIA_RTP_PT_H264_RSV2, 112 PJMEDIA_RTP_PT_H264_RSV3, 113 PJMEDIA_RTP_PT_H264_RSV4, 110 114 111 115 /* Caution! -
pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/config.h
r3498 r3500 603 603 604 604 /** 605 * This specifies the maximum number of the customized SDP format 606 * negotiation callbacks. 607 */ 608 #ifndef PJMEDIA_SDP_NEG_MAX_CUSTOM_FMT_NEG_CB 609 # define PJMEDIA_SDP_NEG_MAX_CUSTOM_FMT_NEG_CB 8 610 #endif 611 612 613 /** 605 614 * Support for sending and decoding RTCP port in SDP (RFC 3605). 606 615 * Default is equal to PJMEDIA_ADVERTISE_RTCP setting. -
pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/sdp_neg.h
r3217 r3500 664 664 665 665 666 /** 667 * Enumeration of customized SDP format matching option flags. See 668 * #pjmedia_sdp_neg_register_fmt_match_cb() for more info. 669 */ 670 typedef enum pjmedia_sdp_neg_fmt_match_flag 671 { 672 /** 673 * In generating answer, the SDP fmtp in the answer candidate may need 674 * to be modified by the customized SDP format matching callback to 675 * achieve flexible SDP negotiation, e.g: AMR fmtp 'octet-align' field 676 * can be adjusted with the offer when the codec implementation support 677 * both packetization modes octet-aligned and bandwidth-efficient. 678 */ 679 PJMEDIA_SDP_NEG_FMT_MATCH_ALLOW_MODIFY_ANSWER = 1, 680 681 } pjmedia_sdp_neg_fmt_match_flag; 682 683 684 /** 685 * The declaration of customized SDP format matching callback. See 686 * #pjmedia_sdp_neg_register_fmt_match_cb() for more info. 687 * 688 * @param pool The memory pool. 689 * @param offer The SDP media offer. 690 * @param o_fmt_idx Index of the format in the SDP media offer. 691 * @param answer The SDP media answer. 692 * @param a_fmt_idx Index of the format in the SDP media answer. 693 * @param option The format matching option, see 694 * #pjmedia_sdp_neg_fmt_match_flag. 695 * 696 * @return PJ_SUCCESS when the formats in offer and answer match. 697 */ 698 typedef pj_status_t (*pjmedia_sdp_neg_fmt_match_cb)(pj_pool_t *pool, 699 pjmedia_sdp_media *offer, 700 unsigned o_fmt_idx, 701 pjmedia_sdp_media *answer, 702 unsigned a_fmt_idx, 703 unsigned option); 704 705 706 /** 707 * Register customized SDP format matching callback function for the specified 708 * format. The customized SDP format matching is needed when the format 709 * identification in a media stream session cannot be simply determined by 710 * encoding name and clock rate, but also involves one or more format specific 711 * parameters, which are specified in SDP fmtp attribute. For example, 712 * an H.264 video stream is also identified by profile, level, and 713 * packetization-mode parameters. As those parameters are format specifics, 714 * the negotiation must be done by the format or codec implementation. 715 * 716 * To unregister the callback of specific format, just call this function with 717 * parameter #cb set to NULL. 718 * 719 * @param fmt_name The format name, e.g: "H.264", "AMR", "G7221". Note 720 * that the string buffer must remain valid until the 721 * callback is unregistered. 722 * @param cb The customized SDP format negotiation callback or 723 * NULL to unregister the specified format callback. 724 * 725 * @return PJ_SUCCESS on success. 726 */ 727 PJ_DECL(pj_status_t) pjmedia_sdp_neg_register_fmt_match_cb( 728 const pj_str_t *fmt_name, 729 pjmedia_sdp_neg_fmt_match_cb cb); 730 731 732 /** 733 * Match format in the SDP media offer and answer. The matching mechanism 734 * will be done by comparing the encoding name and clock rate, and if the 735 * custom format matching callback for the specified format is registered, 736 * see #pjmedia_sdp_neg_register_fmt_match_cb(), it will be called for more 737 * detail verification, e.g: format parameters specified in SDP fmtp. 738 * 739 * @param pool The memory pool. 740 * @param offer The SDP media offer. 741 * @param o_fmt_idx Index of the format in the SDP media offer. 742 * @param answer The SDP media answer. 743 * @param a_fmt_idx Index of the format in the SDP media answer. 744 * @param option The format matching option, see 745 * #pjmedia_sdp_neg_fmt_match_flag. 746 * 747 * @return PJ_SUCCESS when the formats in offer and answer match. 748 */ 749 PJ_DECL(pj_status_t) pjmedia_sdp_neg_fmt_match( pj_pool_t *pool, 750 pjmedia_sdp_media *offer, 751 unsigned o_fmt_idx, 752 pjmedia_sdp_media *answer, 753 unsigned a_fmt_idx, 754 unsigned option); 666 755 667 756 -
pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/stream_common.h
r3419 r3500 33 33 34 34 /** 35 * This is internal function for parsing SDP format parameter of specific format36 * or payload type, used by stream in generating stream info from SDP.35 * This is internal function for parsing SDP format parameter of specific 36 * format or payload type, used by stream in generating stream info from SDP. 37 37 * 38 * @param pool Pool to allocate memory. 38 * @param pool Pool to allocate memory, if pool is NULL, the fmtp 39 * string pointers will point to the original string in 40 * the SDP media descriptor. 39 41 * @param m The SDP media containing the format parameter to 40 42 * be parsed. -
pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/vid_codec.h
r3493 r3500 45 45 { 46 46 pjmedia_format_id fmt_id; /**< Encoded format ID */ 47 unsigned pt; /**< Payload type */ 47 48 pj_str_t encoding_name; /**< Encoding name */ 48 unsigned pt; /**< Payload type (may be 255 for 49 dynamic payload type) */ 49 pj_str_t encoding_desc; /**< Encoding desc */ 50 50 unsigned clock_rate; /**< Clock rate */ 51 51 pjmedia_dir dir; /**< Direction */ … … 535 535 536 536 /** 537 * Get codec info for the specified static payload type. 538 * 539 * @param mgr The codec manager instance. If NULL, the default codec 540 * manager instance will be used. 541 * @param pt Static payload type/number. 537 * Get codec info for the specified payload type. The payload type must be 538 * static or locally defined in #pjmedia_video_pt. 539 * 540 * @param mgr The codec manager instance. If NULL, the default codec 541 * manager instance will be used. 542 * @param pt The payload type/number. 542 543 * @param info Pointer to receive codec info. 543 544 * -
pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/vid_codec_util.h
r3493 r3500 28 28 29 29 #include <pjmedia/vid_codec.h> 30 30 #include <pjmedia/sdp_neg.h> 31 31 32 32 PJ_BEGIN_DECL … … 108 108 * @return PJ_SUCCESS on success. 109 109 */ 110 PJ_DECL(pj_status_t) pjmedia_vid_codec_ parse_h264_fmtp(110 PJ_DECL(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp( 111 111 const pjmedia_codec_fmtp *fmtp, 112 112 pjmedia_vid_codec_h264_fmtp *h264_fmtp); 113 113 114 114 115 /** 116 * Match H.264 format in the SDP media offer and answer. This will compare 117 * H.264 identifier parameters in SDP fmtp, i.e: "profile-level-id" and 118 * "packetization-mode" fields. For better interoperability, when the option 119 * #PJMEDIA_SDP_NEG_FMT_MATCH_ALLOW_MODIFY_ANSWER is set, this function 120 * may update the answer so the parameters in the answer match to ones 121 * in the offer. 122 * 123 * @param pool The memory pool. 124 * @param offer The SDP media offer. 125 * @param o_fmt_idx Index of the H.264 format in the SDP media offer. 126 * @param answer The SDP media answer. 127 * @param a_fmt_idx Index of the H.264 format in the SDP media answer. 128 * @param option The format matching option, see 129 * #pjmedia_sdp_neg_fmt_match_flag. 130 * 131 * @return PJ_SUCCESS when the formats in offer and answer match. 132 */ 133 PJ_DECL(pj_status_t) pjmedia_vid_codec_h264_match_sdp( 134 pj_pool_t *pool, 135 pjmedia_sdp_media *offer, 136 unsigned o_fmt_idx, 137 pjmedia_sdp_media *answer, 138 unsigned a_fmt_idx, 139 unsigned option); 115 140 116 141 -
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c
r3496 r3500 176 176 pj_size_t bits_len, unsigned *bits_pos) 177 177 178 #define FUNC_FMT_MATCH(name) \ 179 pj_status_t(name)(pj_pool_t *pool, \ 180 pjmedia_sdp_media *offer, unsigned o_fmt_idx, \ 181 pjmedia_sdp_media *answer, unsigned a_fmt_idx, \ 182 unsigned option) 183 184 185 /* Type definition of codec specific functions */ 178 186 typedef FUNC_PACKETIZE(*func_packetize); 179 187 typedef FUNC_UNPACKETIZE(*func_unpacketize); 180 188 typedef pj_status_t (*func_preopen) (ffmpeg_private *ff); 181 189 typedef pj_status_t (*func_postopen) (ffmpeg_private *ff); 190 typedef FUNC_FMT_MATCH(*func_sdp_fmt_match); 182 191 183 192 … … 187 196 /* Predefined info */ 188 197 pjmedia_vid_codec_info info; 189 pjmedia_format_id base_fmt_id; 198 pjmedia_format_id base_fmt_id; /**< Some codecs may be exactly 199 same or compatible with 200 another codec, base format 201 will tell the initializer 202 to copy this codec desc 203 from its base format */ 190 204 pj_uint32_t avg_bps; 191 205 pj_uint32_t max_bps; … … 194 208 func_preopen preopen; 195 209 func_preopen postopen; 210 func_sdp_fmt_match sdp_fmt_match; 196 211 pjmedia_codec_fmtp dec_fmtp; 197 212 … … 217 232 { 218 233 { 219 {PJMEDIA_FORMAT_H264, {"H264",4}, PJMEDIA_RTP_PT_H264}, 220 0, 500000, 1000000, 234 {PJMEDIA_FORMAT_H264, PJMEDIA_RTP_PT_H264, {"H264",4}, 235 {"Constrained Baseline (level=30, pack=1)", 39}}, 236 0, 128000, 1000000, 221 237 &h264_packetize, &h264_unpacketize, &h264_preopen, &h264_postopen, 238 &pjmedia_vid_codec_h264_match_sdp, 222 239 /* Leading space for better compatibility (strange indeed!) */ 223 {2, { {{" profile-level-id",17}, {"42e01e",6}},240 {2, { {{"profile-level-id",16}, {"42e01e",6}}, 224 241 {{" packetization-mode",19}, {"1",1}}, } }, 225 242 }, 226 243 { 227 {PJMEDIA_FORMAT_H263P, {"H263-1998",9}, PJMEDIA_RTP_PT_H263P}, 244 {PJMEDIA_FORMAT_H264, PJMEDIA_RTP_PT_H264_RSV1, {"H264",4}, 245 {"Baseline (level=30, pack=1)", 27}}, 246 PJMEDIA_FORMAT_H264, 128000, 1000000, 247 &h264_packetize, &h264_unpacketize, &h264_preopen, &h264_postopen, 248 &pjmedia_vid_codec_h264_match_sdp, 249 {2, { {{"profile-level-id",16}, {"42001e",6}}, 250 {{" packetization-mode",19}, {"1",1}}, } }, 251 }, 252 { 253 {PJMEDIA_FORMAT_H263P, PJMEDIA_RTP_PT_H263P, {"H263-1998",9}}, 228 254 PJMEDIA_FORMAT_H263, 1000000, 2000000, 229 &h263_packetize, &h263_unpacketize, &h263_preopen, NULL, 255 &h263_packetize, &h263_unpacketize, &h263_preopen, NULL, NULL, 230 256 {2, { {{"CIF",3}, {"1",1}}, 231 257 {{"QCIF",4}, {"1",1}}, } }, 232 258 }, 233 259 { 234 {PJMEDIA_FORMAT_H263, {"H263",4}, PJMEDIA_RTP_PT_H263},260 {PJMEDIA_FORMAT_H263, PJMEDIA_RTP_PT_H263, {"H263",4}}, 235 261 }, 236 262 { 237 {PJMEDIA_FORMAT_H261, {"H261",4}, PJMEDIA_RTP_PT_H261},263 {PJMEDIA_FORMAT_H261, PJMEDIA_RTP_PT_H261, {"H261",4}}, 238 264 }, 239 265 { 240 {PJMEDIA_FORMAT_MJPEG, {"JPEG",4}, PJMEDIA_RTP_PT_JPEG},266 {PJMEDIA_FORMAT_MJPEG, PJMEDIA_RTP_PT_JPEG, {"JPEG",4}}, 241 267 }, 242 268 { 243 {PJMEDIA_FORMAT_MPEG4, {"MP4V",4}},269 {PJMEDIA_FORMAT_MPEG4, 0, {"MP4V",4}}, 244 270 }, 245 271 { 246 {PJMEDIA_FORMAT_XVID, {"XVID",4}},272 {PJMEDIA_FORMAT_XVID, 0, {"XVID",4}}, 247 273 PJMEDIA_FORMAT_MPEG4, 248 274 }, … … 266 292 ff->data = data; 267 293 294 /* Parse remote fmtp */ 295 status = pjmedia_vid_codec_h264_parse_fmtp(&ff->param.enc_fmtp, 296 &data->fmtp); 297 if (status != PJ_SUCCESS) 298 return status; 299 268 300 /* Create packetizer */ 269 301 pktz_cfg.mtu = ff->param.enc_mtu; 270 pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED; 302 if (data->fmtp.packetization_mode == 0) 303 pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL; 304 else if (data->fmtp.packetization_mode == 1) 305 pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED; 306 else 307 return PJ_ENOTSUP; 308 271 309 status = pjmedia_h264_packetizer_create(ff->pool, &pktz_cfg, &data->pktz); 272 310 if (status != PJ_SUCCESS) … … 276 314 AVCodecContext *ctx = ff->enc_ctx; 277 315 278 status = pjmedia_vid_codec_parse_h264_fmtp(&ff->param.enc_fmtp, 279 &data->fmtp); 280 if (status != PJ_SUCCESS) 281 return status; 282 316 /* Apply profile. Note that, for x264 backend, ffmpeg doesn't seem to 317 * use this profile param field, so let's try to apply it "manually". 318 */ 283 319 ctx->profile = data->fmtp.profile_idc; 320 if (ctx->profile == FF_PROFILE_H264_BASELINE) { 321 /* Baseline profile settings (the most used profile in 322 * conversational/real-time communications). 323 */ 324 ctx->coder_type = FF_CODER_TYPE_VLC; 325 ctx->max_b_frames = 0; 326 ctx->flags2 &= ~(CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT); 327 ctx->weighted_p_pred = 0; 328 } else if (ctx->profile == FF_PROFILE_H264_MAIN) { 329 ctx->flags2 &= ~CODEC_FLAG2_8X8DCT; 330 } 331 332 /* Apply profile constraint bits. */ 333 // The x264 doesn't seem to support non-constrained (baseline) profile 334 // so this shouldn't be a problem (for now). 335 //PJ_TODO(set_h264_constraint_bits_properly_in_ffmpeg); 284 336 if (data->fmtp.profile_iop) { 285 337 #if defined(FF_PROFILE_H264_CONSTRAINED) … … 287 339 #endif 288 340 } 341 342 /* Apply profile level. */ 343 PJ_TODO(apply_h264_profile_level_in_pjmedia_vid_codec_param); 289 344 ctx->level = data->fmtp.level; 290 PJ_TODO(set_h264_constrain_bits_properly_in_ffmpeg);291 345 292 346 /* Libx264 rejects the "broken" ffmpeg defaults, so just change some */ … … 383 437 (desc->info.fmt_id == info->fmt_id) && 384 438 ((desc->info.dir & info->dir) == info->dir) && 385 pj_stricmp(&desc->info.encoding_name, &info->encoding_name)==0)439 (desc->info.pt == info->pt)) 386 440 { 387 441 return desc; … … 566 620 } 567 621 568 /* Init unassigned encoder/decoder description from base codec */ 622 /* Review all codecs for applying base format, registering format match for 623 * SDP negotiation, etc. 624 */ 569 625 for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) { 570 626 ffmpeg_codec_desc *desc = &codec_desc[i]; 571 627 628 /* Init encoder/decoder description from base format */ 572 629 if (desc->base_fmt_id && (!desc->dec || !desc->enc)) { 573 630 ffmpeg_codec_desc *base_desc = NULL; … … 606 663 desc->info.dir |= copied_dir; 607 664 desc->enabled = (desc->info.dir != PJMEDIA_DIR_NONE); 665 desc->info.has_rtp_pack = (desc->packetize != NULL) && 666 (desc->unpacketize != NULL); 608 667 609 668 if (copied_dir != PJMEDIA_DIR_NONE) { … … 617 676 } 618 677 } 678 679 /* Registering format match for SDP negotiation */ 680 if (desc->sdp_fmt_match) { 681 status = pjmedia_sdp_neg_register_fmt_match_cb( 682 &desc->info.encoding_name, 683 desc->sdp_fmt_match); 684 pj_assert(status == PJ_SUCCESS); 685 } 619 686 } 620 687 -
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/sdp_neg.c
r3493 r3500 71 71 72 72 73 /* Definition of customized SDP format negotiation callback */ 74 struct fmt_match_cb_t 75 { 76 pj_str_t fmt_name; 77 pjmedia_sdp_neg_fmt_match_cb cb; 78 }; 79 80 /* Number of registered customized SDP format negotiation callbacks */ 81 static unsigned fmt_match_cb_cnt; 82 83 /* The registered customized SDP format negotiation callbacks */ 84 static struct fmt_match_cb_t 85 fmt_match_cb[PJMEDIA_SDP_NEG_MAX_CUSTOM_FMT_NEG_CB]; 86 87 /* Redefining a very long identifier name, just for convenience */ 88 #define ALLOW_MODIFY_ANSWER PJMEDIA_SDP_NEG_FMT_MATCH_ALLOW_MODIFY_ANSWER 89 90 static pj_status_t custom_fmt_match( pj_pool_t *pool, 91 const pj_str_t *fmt_name, 92 pjmedia_sdp_media *offer, 93 unsigned o_fmt_idx, 94 pjmedia_sdp_media *answer, 95 unsigned a_fmt_idx, 96 unsigned option); 97 98 73 99 /* 74 100 * Get string representation of negotiator state. … … 683 709 684 710 685 /* Matching H.264 between offer and answer. */686 static pj_bool_t match_h264( const pjmedia_sdp_media *offer,687 unsigned o_fmt_idx,688 const pjmedia_sdp_media *answer,689 unsigned a_fmt_idx)690 {691 const pjmedia_sdp_attr *attr_ans;692 const pjmedia_sdp_attr *attr_ofr;693 pjmedia_sdp_fmtp fmtp;694 pj_uint32_t profile1, profile2;695 unsigned pack_mode1, pack_mode2;696 const pj_str_t STR_PROFILE = {"profile-level-id=", 17};697 const pj_str_t STR_PACK_MODE = {"packetization-mode=", 19};698 699 /* Parse offer */700 attr_ofr = pjmedia_sdp_media_find_attr2(offer, "fmtp",701 &offer->desc.fmt[o_fmt_idx]);702 if (!attr_ofr)703 return PJ_FALSE;704 705 if (pjmedia_sdp_attr_get_fmtp(attr_ofr, &fmtp) != PJ_SUCCESS)706 return PJ_FALSE;707 708 GET_FMTP_IVAL_BASE(profile1, 16, fmtp, STR_PROFILE, 0x42000A);709 GET_FMTP_IVAL(pack_mode1, fmtp, STR_PACK_MODE, 0);710 711 /* Parse answer */712 attr_ans = pjmedia_sdp_media_find_attr2(answer, "fmtp",713 &answer->desc.fmt[a_fmt_idx]);714 if (!attr_ans)715 return PJ_FALSE;716 717 if (pjmedia_sdp_attr_get_fmtp(attr_ans, &fmtp) != PJ_SUCCESS)718 return PJ_FALSE;719 720 GET_FMTP_IVAL_BASE(profile2, 16, fmtp, STR_PROFILE, 0x42000A);721 GET_FMTP_IVAL(pack_mode2, fmtp, STR_PACK_MODE, 0);722 723 /* Compare bitrate in answer and offer. */724 return ((profile1 == profile2) && (pack_mode1 == pack_mode2));725 }726 727 728 711 /* Toggle AMR octet-align setting in the fmtp. 729 712 */ … … 929 912 break; 930 913 } else 914 931 915 /* Further check for AMR, negotiate fmtp. */ 932 916 if (pj_stricmp2(&or_.enc_name, "AMR") == 0 || … … 937 921 break; 938 922 } else 939 /* Further check for H264, negotiate fmtp. */ 940 if (pj_stricmp2(&or_.enc_name, "H264") == 0) 923 924 /* Call custom format matching callbacks */ 925 if (custom_fmt_match(pool, &or_.enc_name, 926 offer, i, answer, j, 0) == 927 PJ_SUCCESS) 941 928 { 942 if (match_h264(offer, i, answer, j))943 break;944 } else {945 929 /* Match! */ 946 930 break; … … 1236 1220 /* Match! */ 1237 1221 if (is_codec) { 1222 pjmedia_sdp_media *o, *a; 1223 unsigned o_fmt_idx, a_fmt_idx; 1224 1225 o = (pjmedia_sdp_media*)offer; 1226 a = (pjmedia_sdp_media*)preanswer; 1227 o_fmt_idx = prefer_remote_codec_order? i:j; 1228 a_fmt_idx = prefer_remote_codec_order? j:i; 1229 1230 /* Call custom format matching callbacks */ 1231 if (custom_fmt_match(pool, &or_.enc_name, 1232 o, o_fmt_idx, 1233 a, a_fmt_idx, 1234 ALLOW_MODIFY_ANSWER) != 1235 PJ_SUCCESS) 1236 { 1237 continue; 1238 } else 1239 1238 1240 /* Further check for G7221, negotiate bitrate */ 1239 1241 if (pj_stricmp2(&or_.enc_name, "G7221") == 0 && … … 1241 1243 { 1242 1244 continue; 1243 } else 1245 } else 1246 1244 1247 /* Further check for AMR, negotiate fmtp */ 1245 1248 if (pj_stricmp2(&or_.enc_name, "AMR")==0 || … … 1254 1257 PJ_TRUE, &pt_amr_need_adapt)) 1255 1258 continue; 1256 } else1257 if (pj_stricmp2(&or_.enc_name, "H264") == 0 &&1258 !match_h264(master, i, slave, j))1259 {1260 continue;1261 1259 } 1260 1262 1261 found_matching_codec = 1; 1263 1262 } else { … … 1533 1532 } 1534 1533 1534 1535 static pj_status_t custom_fmt_match(pj_pool_t *pool, 1536 const pj_str_t *fmt_name, 1537 pjmedia_sdp_media *offer, 1538 unsigned o_fmt_idx, 1539 pjmedia_sdp_media *answer, 1540 unsigned a_fmt_idx, 1541 unsigned option) 1542 { 1543 unsigned i; 1544 1545 for (i = 0; i < fmt_match_cb_cnt; ++i) { 1546 if (pj_stricmp(fmt_name, &fmt_match_cb[i].fmt_name) == 0) { 1547 pj_assert(fmt_match_cb[i].cb); 1548 return (*fmt_match_cb[i].cb)(pool, offer, o_fmt_idx, 1549 answer, a_fmt_idx, 1550 option); 1551 } 1552 } 1553 1554 /* Not customized format matching found, should be matched */ 1555 return PJ_SUCCESS; 1556 } 1557 1558 /* Register customized SDP format negotiation callback function. */ 1559 PJ_DECL(pj_status_t) pjmedia_sdp_neg_register_fmt_match_cb( 1560 const pj_str_t *fmt_name, 1561 pjmedia_sdp_neg_fmt_match_cb cb) 1562 { 1563 struct fmt_match_cb_t *f = NULL; 1564 unsigned i; 1565 1566 PJ_ASSERT_RETURN(fmt_name, PJ_EINVAL); 1567 1568 /* Check if the callback for the format name has been registered */ 1569 for (i = 0; i < fmt_match_cb_cnt; ++i) { 1570 if (pj_stricmp(fmt_name, &fmt_match_cb[i].fmt_name) == 0) 1571 break; 1572 } 1573 1574 /* Unregistration */ 1575 1576 if (cb == NULL) { 1577 if (i == fmt_match_cb_cnt) 1578 return PJ_ENOTFOUND; 1579 1580 pj_array_erase(fmt_match_cb, sizeof(fmt_match_cb[0]), 1581 fmt_match_cb_cnt, i); 1582 fmt_match_cb_cnt--; 1583 1584 return PJ_SUCCESS; 1585 } 1586 1587 /* Registration */ 1588 1589 if (i < fmt_match_cb_cnt) { 1590 /* The same format name has been registered before */ 1591 if (cb != fmt_match_cb[i].cb) 1592 return PJ_EEXISTS; 1593 else 1594 return PJ_SUCCESS; 1595 } 1596 1597 if (fmt_match_cb_cnt >= PJ_ARRAY_SIZE(fmt_match_cb)) 1598 return PJ_ETOOMANY; 1599 1600 f = &fmt_match_cb[fmt_match_cb_cnt++]; 1601 f->fmt_name = *fmt_name; 1602 f->cb = cb; 1603 1604 return PJ_SUCCESS; 1605 } 1606 1607 1608 /* Match format in the SDP media offer and answer. */ 1609 PJ_DEF(pj_bool_t) pjmedia_sdp_neg_fmt_match( pj_pool_t *pool, 1610 pjmedia_sdp_media *offer, 1611 unsigned o_fmt_idx, 1612 pjmedia_sdp_media *answer, 1613 unsigned a_fmt_idx, 1614 unsigned option) 1615 { 1616 const pjmedia_sdp_attr *attr; 1617 pjmedia_sdp_rtpmap o_rtpmap, a_rtpmap; 1618 1619 /* Get the format rtpmap from the offer. */ 1620 attr = pjmedia_sdp_media_find_attr2(offer, "rtpmap", 1621 &offer->desc.fmt[o_fmt_idx]); 1622 if (!attr) { 1623 pj_assert(!"Bug! Offer haven't been validated"); 1624 return PJ_EBUG; 1625 } 1626 pjmedia_sdp_attr_get_rtpmap(attr, &o_rtpmap); 1627 1628 /* Get the format rtpmap from the answer. */ 1629 attr = pjmedia_sdp_media_find_attr2(answer, "rtpmap", 1630 &answer->desc.fmt[a_fmt_idx]); 1631 if (!attr) { 1632 pj_assert(!"Bug! Answer haven't been validated"); 1633 return PJ_EBUG; 1634 } 1635 pjmedia_sdp_attr_get_rtpmap(attr, &a_rtpmap); 1636 1637 if (pj_stricmp(&o_rtpmap.enc_name, &a_rtpmap.enc_name) != 0 || 1638 o_rtpmap.clock_rate != a_rtpmap.clock_rate) 1639 { 1640 return PJMEDIA_SDP_EFORMATNOTEQUAL; 1641 } 1642 1643 /* Further check for G7221, negotiate bitrate. */ 1644 if (pj_stricmp2(&o_rtpmap.enc_name, "G7221") == 0) { 1645 if (match_g7221(offer, o_fmt_idx, answer, a_fmt_idx)) 1646 return PJ_SUCCESS; 1647 else 1648 return PJMEDIA_SDP_EFORMATNOTEQUAL; 1649 } else 1650 /* Further check for AMR, negotiate fmtp. */ 1651 if (pj_stricmp2(&o_rtpmap.enc_name, "AMR") == 0 || 1652 pj_stricmp2(&o_rtpmap.enc_name, "AMR-WB") == 0) 1653 { 1654 if (match_amr(offer, o_fmt_idx, answer, a_fmt_idx, PJ_FALSE, NULL)) 1655 return PJ_SUCCESS; 1656 else 1657 return PJMEDIA_SDP_EFORMATNOTEQUAL; 1658 } 1659 PJ_TODO(replace_hardcoded_fmt_match_in_sdp_neg_with_custom_fmt_match_cb); 1660 1661 return custom_fmt_match(pool, &o_rtpmap.enc_name, 1662 offer, o_fmt_idx, answer, a_fmt_idx, option); 1663 } 1664 -
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/stream.c
r3446 r3500 2948 2948 2949 2949 /* Get local fmtp for our decoder. */ 2950 pjmedia_stream_info_parse_fmtp(pool, local_m, si->fmt.pt, 2950 pjmedia_stream_info_parse_fmtp(pool, local_m, si->fmt.pt, 2951 2951 &si->param->setting.dec_fmtp); 2952 2952 -
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/stream_common.c
r3498 r3500 87 87 /* Store token */ 88 88 if (end > start) { 89 token = (char*)pj_pool_alloc(pool, end - start); 90 pj_ansi_strncpy(token, start, end - start); 89 if (pool) { 90 token = (char*)pj_pool_alloc(pool, end - start); 91 pj_ansi_strncpy(token, start, end - start); 92 } else { 93 token = start; 94 } 91 95 if (*p == '=') 92 96 /* Got param name */ -
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/vid_codec.c
r3425 r3500 307 307 308 308 /* 309 * Get codec info for staticpayload type.309 * Get codec info for the specified payload type. 310 310 */ 311 311 PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_get_codec_info( … … 316 316 unsigned i; 317 317 318 PJ_ASSERT_RETURN(p_info && pt>=0 && pt < 96, PJ_EINVAL);318 PJ_ASSERT_RETURN(p_info, PJ_EINVAL); 319 319 320 320 if (!mgr) mgr = def_vid_codec_mgr; … … 369 369 /* 370 370 * Convert codec info struct into a unique codec identifier. 371 * A codec identifier looks something like " L16/44100/2".371 * A codec identifier looks something like "H263/34". 372 372 */ 373 373 PJ_DEF(char*) pjmedia_vid_codec_info_to_id( … … 382 382 (int)info->encoding_name.slen, 383 383 info->encoding_name.ptr, 384 info-> clock_rate);384 info->pt); 385 385 386 386 if (len < 1 || len >= (int)max_len) { -
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/vid_codec_util.c
r3493 r3500 20 20 #include <pjmedia/vid_codec_util.h> 21 21 #include <pjmedia/errno.h> 22 #include <pjmedia/stream_common.h> 22 23 #include <pjlib-util/base64.h> 24 #include <pj/ctype.h> 23 25 #include <pj/math.h> 24 26 … … 259 261 260 262 /* H264 fmtp parser */ 261 PJ_DEF(pj_status_t) pjmedia_vid_codec_ parse_h264_fmtp(263 PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp( 262 264 const pjmedia_codec_fmtp *fmtp, 263 265 pjmedia_vid_codec_h264_fmtp *h264_fmtp) … … 289 291 h264_fmtp->profile_idc = (pj_uint8_t)((tmp >> 16) & 0xFF); 290 292 h264_fmtp->profile_iop = (pj_uint8_t)((tmp >> 8) & 0xFF); 291 h264_fmtp-> profile_idc= (pj_uint8_t)(tmp & 0xFF);293 h264_fmtp->level = (pj_uint8_t)(tmp & 0xFF); 292 294 } else if (pj_stricmp(&fmtp->param[i].name, &PACKETIZATION_MODE)==0) { 293 295 tmp = pj_strtoul(&fmtp->param[i].val); 294 if (tmp) h264_fmtp->max_br = tmp; 296 if (tmp >= 0 && tmp <= 2) 297 h264_fmtp->packetization_mode = (pj_uint8_t)tmp; 298 else 299 return PJMEDIA_SDP_EINFMTP; 295 300 } else if (pj_stricmp(&fmtp->param[i].name, &MAX_MBPS)==0) { 296 301 tmp = pj_strtoul(&fmtp->param[i].val); 297 if (tmp)h264_fmtp->max_mbps = tmp;302 h264_fmtp->max_mbps = tmp; 298 303 } else if (pj_stricmp(&fmtp->param[i].name, &MAX_FS)==0) { 299 304 tmp = pj_strtoul(&fmtp->param[i].val); 300 if (tmp)h264_fmtp->max_fs = tmp;305 h264_fmtp->max_fs = tmp; 301 306 } else if (pj_stricmp(&fmtp->param[i].name, &MAX_CPB)==0) { 302 307 tmp = pj_strtoul(&fmtp->param[i].val); 303 if (tmp)h264_fmtp->max_cpb = tmp;308 h264_fmtp->max_cpb = tmp; 304 309 } else if (pj_stricmp(&fmtp->param[i].name, &MAX_DPB)==0) { 305 310 tmp = pj_strtoul(&fmtp->param[i].val); 306 if (tmp)h264_fmtp->max_dpb = tmp;311 h264_fmtp->max_dpb = tmp; 307 312 } else if (pj_stricmp(&fmtp->param[i].name, &MAX_BR)==0) { 308 313 tmp = pj_strtoul(&fmtp->param[i].val); 309 if (tmp)h264_fmtp->max_br = tmp;314 h264_fmtp->max_br = tmp; 310 315 } else if (pj_stricmp(&fmtp->param[i].name, &SPROP_PARAMETER_SETS)==0) 311 316 { … … 351 356 } 352 357 358 /* When profile-level-id is not specified, use default value "42000A" */ 359 if (h264_fmtp->profile_idc == 0) { 360 h264_fmtp->profile_idc = 0x42; 361 h264_fmtp->profile_iop = 0x00; 362 h264_fmtp->level = 0x0A; 363 } 364 353 365 return PJ_SUCCESS; 354 366 } 367 368 PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_match_sdp(pj_pool_t *pool, 369 pjmedia_sdp_media *offer, 370 unsigned o_fmt_idx, 371 pjmedia_sdp_media *answer, 372 unsigned a_fmt_idx, 373 unsigned option) 374 { 375 const pj_str_t PROFILE_LEVEL_ID = {"profile-level-id", 16}; 376 const pj_str_t PACKETIZATION_MODE = {"packetization-mode", 18}; 377 pjmedia_codec_fmtp o_fmtp_raw, a_fmtp_raw; 378 pjmedia_vid_codec_h264_fmtp o_fmtp, a_fmtp; 379 pj_status_t status; 380 381 PJ_UNUSED_ARG(pool); 382 383 /* Parse offer */ 384 status = pjmedia_stream_info_parse_fmtp( 385 NULL, offer, 386 pj_strtoul(&offer->desc.fmt[o_fmt_idx]), 387 &o_fmtp_raw); 388 if (status != PJ_SUCCESS) 389 return status; 390 391 status = pjmedia_vid_codec_h264_parse_fmtp(&o_fmtp_raw, &o_fmtp); 392 if (status != PJ_SUCCESS) 393 return status; 394 395 /* Parse answer */ 396 status = pjmedia_stream_info_parse_fmtp( 397 NULL, answer, 398 pj_strtoul(&answer->desc.fmt[a_fmt_idx]), 399 &a_fmtp_raw); 400 if (status != PJ_SUCCESS) 401 return status; 402 403 status = pjmedia_vid_codec_h264_parse_fmtp(&a_fmtp_raw, &a_fmtp); 404 if (status != PJ_SUCCESS) 405 return status; 406 407 if (option & PJMEDIA_SDP_NEG_FMT_MATCH_ALLOW_MODIFY_ANSWER) { 408 unsigned i; 409 410 /* Flexible negotiation, if the answer has higher capability than 411 * the offer, adjust the answer capability to be match to the offer. 412 */ 413 if (a_fmtp.profile_idc >= o_fmtp.profile_idc) 414 a_fmtp.profile_idc = o_fmtp.profile_idc; 415 if (a_fmtp.profile_iop != o_fmtp.profile_iop) 416 a_fmtp.profile_iop = o_fmtp.profile_iop; 417 if (a_fmtp.level >= o_fmtp.level) 418 a_fmtp.level = o_fmtp.level; 419 if (a_fmtp.packetization_mode >= o_fmtp.packetization_mode) 420 a_fmtp.packetization_mode = o_fmtp.packetization_mode; 421 422 /* Match them now */ 423 if (a_fmtp.profile_idc != o_fmtp.profile_idc || 424 a_fmtp.profile_iop != o_fmtp.profile_iop || 425 a_fmtp.level != o_fmtp.level || 426 a_fmtp.packetization_mode != o_fmtp.packetization_mode) 427 { 428 return PJMEDIA_SDP_EFORMATNOTEQUAL; 429 } 430 431 /* Update the answer */ 432 for (i = 0; i < a_fmtp_raw.cnt; ++i) { 433 if (pj_stricmp(&a_fmtp_raw.param[i].name, &PROFILE_LEVEL_ID) == 0) 434 { 435 char *p = a_fmtp_raw.param[i].val.ptr; 436 pj_val_to_hex_digit(a_fmtp.profile_idc, p); 437 p += 2; 438 pj_val_to_hex_digit(a_fmtp.profile_iop, p); 439 p += 2; 440 pj_val_to_hex_digit(a_fmtp.level, p); 441 } 442 else if (pj_stricmp(&a_fmtp_raw.param[i].name, &PACKETIZATION_MODE) == 0) 443 { 444 char *p = a_fmtp_raw.param[i].val.ptr; 445 *p = '0' + a_fmtp.packetization_mode; 446 } 447 } 448 } else { 449 /* Strict negotiation */ 450 if (a_fmtp.profile_idc != o_fmtp.profile_idc || 451 a_fmtp.profile_iop != o_fmtp.profile_iop || 452 a_fmtp.level != o_fmtp.level || 453 a_fmtp.packetization_mode != o_fmtp.packetization_mode) 454 { 455 return PJMEDIA_SDP_EFORMATNOTEQUAL; 456 } 457 } 458 459 return PJ_SUCCESS; 460 } -
pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/vid_stream.c
r3497 r3500 22 22 #include <pjmedia/rtcp.h> 23 23 #include <pjmedia/jbuf.h> 24 #include <pjmedia/sdp_neg.h> 24 25 #include <pjmedia/stream_common.h> 25 26 #include <pj/array.h> … … 1722 1723 const pjmedia_sdp_media *rem_m) 1723 1724 { 1724 const pjmedia_sdp_attr *attr; 1725 pjmedia_sdp_rtpmap *rtpmap; 1726 unsigned i, pt = 0; 1725 unsigned pt = 0; 1726 const pjmedia_vid_codec_info *p_info; 1727 1727 pj_status_t status; 1728 1728 1729 /* Get codec info.1730 * For static payload types, get the info from codec manager.1731 * For dynamic payload types, MUST get the rtpmap.1732 */1733 1729 pt = pj_strtoul(&local_m->desc.fmt[0]); 1730 1731 /* Get codec info. */ 1732 status = pjmedia_vid_codec_mgr_get_codec_info(mgr, pt, &p_info); 1733 if (status != PJ_SUCCESS) 1734 return status; 1735 1736 si->codec_info = *p_info; 1737 1738 /* Get payload type for receiving direction */ 1734 1739 si->rx_pt = pt; 1740 1741 /* Get payload type for transmitting direction */ 1735 1742 if (pt < 96) { 1736 const pjmedia_vid_codec_info *p_info;1737 1738 status = pjmedia_vid_codec_mgr_get_codec_info(mgr, pt, &p_info);1739 if (status != PJ_SUCCESS)1740 return status;1741 1742 si->codec_info = *p_info;1743 1744 1743 /* For static payload type, pt's are symetric */ 1745 1744 si->tx_pt = pt; 1746 1745 1747 1746 } else { 1748 unsigned info_cnt = 1; 1749 const pjmedia_vid_codec_info *p_info; 1750 1751 attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 1752 &local_m->desc.fmt[0]); 1753 if (attr == NULL) 1754 return PJMEDIA_EMISSINGRTPMAP; 1755 1756 status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap); 1757 if (status != PJ_SUCCESS) 1758 return status; 1759 1760 /* Get codec info from codec id */ 1761 status = pjmedia_vid_codec_mgr_find_codecs_by_id( 1762 mgr, &rtpmap->enc_name, 1763 &info_cnt, &p_info, NULL); 1764 if (status != PJ_SUCCESS) 1765 return status; 1766 1767 si->codec_info = *p_info; 1747 unsigned i; 1768 1748 1769 1749 /* Determine payload type for outgoing channel, by finding … … 1772 1752 si->tx_pt = 0xFFFF; 1773 1753 for (i=0; i<rem_m->desc.fmt_count; ++i) { 1774 unsigned rpt; 1775 pjmedia_sdp_attr *r_attr; 1776 pjmedia_sdp_rtpmap r_rtpmap; 1777 1778 rpt = pj_strtoul(&rem_m->desc.fmt[i]); 1779 if (rpt < 96) 1780 continue; 1781 1782 r_attr = pjmedia_sdp_media_find_attr(rem_m, &ID_RTPMAP, 1783 &rem_m->desc.fmt[i]); 1784 if (!r_attr) 1785 continue; 1786 1787 if (pjmedia_sdp_attr_get_rtpmap(r_attr, &r_rtpmap) != PJ_SUCCESS) 1788 continue; 1789 1790 if (!pj_stricmp(&rtpmap->enc_name, &r_rtpmap.enc_name) && 1791 rtpmap->clock_rate == r_rtpmap.clock_rate) 1754 if (pjmedia_sdp_neg_fmt_match(NULL, 1755 (pjmedia_sdp_media*)local_m, 0, 1756 (pjmedia_sdp_media*)rem_m, i, 0) == 1757 PJ_SUCCESS) 1792 1758 { 1793 1759 /* Found matched codec. */ 1794 si->tx_pt = rpt; 1795 1760 si->tx_pt = pj_strtoul(&rem_m->desc.fmt[i]); 1796 1761 break; 1797 1762 } -
pjproject/branches/projects/2.0-dev/pjsip-apps/src/pjsua/pjsua_app.c
r3477 r3500 3543 3543 pjsua_vid_enum_codecs(c, &count); 3544 3544 for (i=0; i<count; ++i) { 3545 printf(" %d\t%.*s\n", c[i].priority, (int)c[i].codec_id.slen, 3546 c[i].codec_id.ptr); 3545 printf(" %d\t%.*s%s%.*s\n", c[i].priority, 3546 (int)c[i].codec_id.slen, 3547 c[i].codec_id.ptr, 3548 c[i].desc.slen? " - ":"", 3549 (int)c[i].desc.slen, 3550 c[i].desc.ptr); 3547 3551 } 3548 3552 #endif -
pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h
r3471 r3500 4380 4380 4381 4381 /** 4382 * Codec description. 4383 */ 4384 pj_str_t desc; 4385 4386 /** 4382 4387 * Internal buffer. 4383 4388 */ 4384 char buf_[ 32];4389 char buf_[64]; 4385 4390 4386 4391 } pjsua_codec_info; -
pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c
r3487 r3500 3758 3758 3759 3759 for (i=0; i<count; ++i) { 3760 pj_bzero(&id[i], sizeof(pjsua_codec_info)); 3761 3760 3762 pjmedia_codec_info_to_id(&info[i], id[i].buf_, sizeof(id[i].buf_)); 3761 3763 id[i].codec_id = pj_str(id[i].buf_); … … 3875 3877 for (i=0, j=0; i<count && j<*p_count; ++i) { 3876 3878 if (info[i].has_rtp_pack) { 3879 pj_bzero(&id[j], sizeof(pjsua_codec_info)); 3880 3877 3881 pjmedia_vid_codec_info_to_id(&info[i], id[j].buf_, sizeof(id[j].buf_)); 3878 3882 id[j].codec_id = pj_str(id[j].buf_); 3879 3883 id[j].priority = (pj_uint8_t) prio[i]; 3884 3885 if (id[j].codec_id.slen < sizeof(id[j].buf_)) { 3886 id[j].desc.ptr = id[j].codec_id.ptr + id[j].codec_id.slen + 1; 3887 pj_strncpy(&id[j].desc, &info[i].encoding_desc, 3888 sizeof(id[j].buf_) - id[j].codec_id.slen - 1); 3889 } 3890 3880 3891 ++j; 3881 3892 }
Note: See TracChangeset
for help on using the changeset viewer.