Changeset 3500 for pjproject


Ignore:
Timestamp:
Apr 6, 2011 1:55:01 PM (14 years ago)
Author:
nanang
Message:

Re #1186:

  • Added custom negotiation callback mechanism in SDP negotiator, mainly for specific formats that require SDP fmtp negotiation.
  • Modified video codec ID string to use encoding name+payload type (was encoding name+clock rate), also added encoding description in video codec info, so duplicated codecs (e.g: multiple H264 configurations) can be differentiated.
  • Few enhancements for H264 in ffmpeg wrapper (e.g: added proper profile-id & packetization-mode setup).
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  
    108108     PJMEDIA_RTP_PT_H263P, 
    109109     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, 
    110114 
    111115     /* Caution! 
  • pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/config.h

    r3498 r3500  
    603603 
    604604/** 
     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/** 
    605614 * Support for sending and decoding RTCP port in SDP (RFC 3605). 
    606615 * Default is equal to PJMEDIA_ADVERTISE_RTCP setting. 
  • pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/sdp_neg.h

    r3217 r3500  
    664664 
    665665 
     666/** 
     667 * Enumeration of customized SDP format matching option flags. See 
     668 * #pjmedia_sdp_neg_register_fmt_match_cb() for more info. 
     669 */ 
     670typedef 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 */ 
     698typedef 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 */ 
     727PJ_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 */ 
     749PJ_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); 
    666755 
    667756 
  • pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/stream_common.h

    r3419 r3500  
    3333 
    3434/** 
    35  * This is internal function for parsing SDP format parameter of specific format 
    36  * 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. 
    3737 * 
    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. 
    3941 * @param m             The SDP media containing the format parameter to 
    4042 *                      be parsed. 
  • pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/vid_codec.h

    r3493 r3500  
    4545{ 
    4646    pjmedia_format_id   fmt_id;         /**< Encoded format ID              */ 
     47    unsigned            pt;             /**< Payload type                   */ 
    4748    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                  */ 
    5050    unsigned            clock_rate;     /**< Clock rate                     */ 
    5151    pjmedia_dir         dir;            /**< Direction                      */ 
     
    535535 
    536536/** 
    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. 
    542543 * @param info      Pointer to receive codec info. 
    543544 * 
  • pjproject/branches/projects/2.0-dev/pjmedia/include/pjmedia/vid_codec_util.h

    r3493 r3500  
    2828 
    2929#include <pjmedia/vid_codec.h> 
    30  
     30#include <pjmedia/sdp_neg.h> 
    3131 
    3232PJ_BEGIN_DECL 
     
    108108 * @return              PJ_SUCCESS on success. 
    109109 */ 
    110 PJ_DECL(pj_status_t) pjmedia_vid_codec_parse_h264_fmtp( 
     110PJ_DECL(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp( 
    111111                                const pjmedia_codec_fmtp *fmtp, 
    112112                                pjmedia_vid_codec_h264_fmtp *h264_fmtp); 
    113113 
    114114 
     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 */ 
     133PJ_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); 
    115140 
    116141 
  • pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c

    r3496 r3500  
    176176                      pj_size_t bits_len, unsigned *bits_pos) 
    177177 
     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 */ 
    178186typedef FUNC_PACKETIZE(*func_packetize); 
    179187typedef FUNC_UNPACKETIZE(*func_unpacketize); 
    180188typedef pj_status_t (*func_preopen)     (ffmpeg_private *ff); 
    181189typedef pj_status_t (*func_postopen)    (ffmpeg_private *ff); 
     190typedef FUNC_FMT_MATCH(*func_sdp_fmt_match); 
    182191 
    183192 
     
    187196    /* Predefined info */ 
    188197    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   */ 
    190204    pj_uint32_t                  avg_bps; 
    191205    pj_uint32_t                  max_bps; 
     
    194208    func_preopen                 preopen; 
    195209    func_preopen                 postopen; 
     210    func_sdp_fmt_match           sdp_fmt_match; 
    196211    pjmedia_codec_fmtp           dec_fmtp; 
    197212 
     
    217232{ 
    218233    { 
    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, 
    221237        &h264_packetize, &h264_unpacketize, &h264_preopen, &h264_postopen, 
     238        &pjmedia_vid_codec_h264_match_sdp, 
    222239        /* Leading space for better compatibility (strange indeed!) */ 
    223         {2, { {{" profile-level-id",17},    {"42e01e",6}},  
     240        {2, { {{"profile-level-id",16},    {"42e01e",6}},  
    224241              {{" packetization-mode",19},  {"1",1}}, } }, 
    225242    }, 
    226243    { 
    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}}, 
    228254        PJMEDIA_FORMAT_H263,    1000000,    2000000, 
    229         &h263_packetize, &h263_unpacketize, &h263_preopen, NULL, 
     255        &h263_packetize, &h263_unpacketize, &h263_preopen, NULL, NULL, 
    230256        {2, { {{"CIF",3},   {"1",1}},  
    231257              {{"QCIF",4},  {"1",1}}, } }, 
    232258    }, 
    233259    { 
    234         {PJMEDIA_FORMAT_H263,   {"H263",4},         PJMEDIA_RTP_PT_H263}, 
     260        {PJMEDIA_FORMAT_H263,   PJMEDIA_RTP_PT_H263,    {"H263",4}}, 
    235261    }, 
    236262    { 
    237         {PJMEDIA_FORMAT_H261,   {"H261",4},         PJMEDIA_RTP_PT_H261}, 
     263        {PJMEDIA_FORMAT_H261,   PJMEDIA_RTP_PT_H261,    {"H261",4}}, 
    238264    }, 
    239265    { 
    240         {PJMEDIA_FORMAT_MJPEG,  {"JPEG",4},         PJMEDIA_RTP_PT_JPEG}, 
     266        {PJMEDIA_FORMAT_MJPEG,  PJMEDIA_RTP_PT_JPEG,    {"JPEG",4}}, 
    241267    }, 
    242268    { 
    243         {PJMEDIA_FORMAT_MPEG4,  {"MP4V",4}}, 
     269        {PJMEDIA_FORMAT_MPEG4,  0,                      {"MP4V",4}}, 
    244270    }, 
    245271    { 
    246         {PJMEDIA_FORMAT_XVID,   {"XVID",4}}, 
     272        {PJMEDIA_FORMAT_XVID,   0,                      {"XVID",4}}, 
    247273        PJMEDIA_FORMAT_MPEG4, 
    248274    }, 
     
    266292    ff->data = data; 
    267293 
     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 
    268300    /* Create packetizer */ 
    269301    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 
    271309    status = pjmedia_h264_packetizer_create(ff->pool, &pktz_cfg, &data->pktz); 
    272310    if (status != PJ_SUCCESS) 
     
    276314        AVCodecContext *ctx = ff->enc_ctx; 
    277315 
    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         */ 
    283319        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); 
    284336        if (data->fmtp.profile_iop) { 
    285337#if defined(FF_PROFILE_H264_CONSTRAINED) 
     
    287339#endif 
    288340        } 
     341 
     342        /* Apply profile level. */ 
     343        PJ_TODO(apply_h264_profile_level_in_pjmedia_vid_codec_param); 
    289344        ctx->level    = data->fmtp.level; 
    290         PJ_TODO(set_h264_constrain_bits_properly_in_ffmpeg); 
    291345 
    292346        /* Libx264 rejects the "broken" ffmpeg defaults, so just change some */ 
     
    383437            (desc->info.fmt_id == info->fmt_id) && 
    384438            ((desc->info.dir & info->dir) == info->dir) && 
    385             pj_stricmp(&desc->info.encoding_name, &info->encoding_name)==0) 
     439            (desc->info.pt == info->pt)) 
    386440        { 
    387441            return desc; 
     
    566620    } 
    567621 
    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     */ 
    569625    for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) { 
    570626        ffmpeg_codec_desc *desc = &codec_desc[i]; 
    571627 
     628        /* Init encoder/decoder description from base format */ 
    572629        if (desc->base_fmt_id && (!desc->dec || !desc->enc)) { 
    573630            ffmpeg_codec_desc *base_desc = NULL; 
     
    606663            desc->info.dir |= copied_dir; 
    607664            desc->enabled = (desc->info.dir != PJMEDIA_DIR_NONE); 
     665            desc->info.has_rtp_pack = (desc->packetize != NULL) && 
     666                                      (desc->unpacketize != NULL); 
    608667 
    609668            if (copied_dir != PJMEDIA_DIR_NONE) { 
     
    617676            } 
    618677        } 
     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        } 
    619686    } 
    620687 
  • pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/sdp_neg.c

    r3493 r3500  
    7171 
    7272 
     73/* Definition of customized SDP format negotiation callback */ 
     74struct 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 */ 
     81static unsigned fmt_match_cb_cnt; 
     82 
     83/* The registered customized SDP format negotiation callbacks */ 
     84static 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 
     90static 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 
    7399/* 
    74100 * Get string representation of negotiator state. 
     
    683709 
    684710 
    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  
    728711/* Toggle AMR octet-align setting in the fmtp. 
    729712 */ 
     
    929912                                    break; 
    930913                            } else 
     914 
    931915                            /* Further check for AMR, negotiate fmtp. */ 
    932916                            if (pj_stricmp2(&or_.enc_name, "AMR") == 0 || 
     
    937921                                    break; 
    938922                            } 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) 
    941928                            { 
    942                                 if (match_h264(offer, i, answer, j)) 
    943                                     break; 
    944                             } else { 
    945929                                /* Match! */ 
    946930                                break; 
     
    12361220                            /* Match! */ 
    12371221                            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 
    12381240                                /* Further check for G7221, negotiate bitrate */ 
    12391241                                if (pj_stricmp2(&or_.enc_name, "G7221") == 0 && 
     
    12411243                                { 
    12421244                                    continue; 
    1243                                 } else  
     1245                                } else 
     1246 
    12441247                                /* Further check for AMR, negotiate fmtp */ 
    12451248                                if (pj_stricmp2(&or_.enc_name, "AMR")==0 || 
     
    12541257                                                   PJ_TRUE, &pt_amr_need_adapt)) 
    12551258                                        continue; 
    1256                                 } else 
    1257                                 if (pj_stricmp2(&or_.enc_name, "H264") == 0 && 
    1258                                     !match_h264(master, i, slave, j)) 
    1259                                 { 
    1260                                     continue; 
    12611259                                } 
     1260 
    12621261                                found_matching_codec = 1; 
    12631262                            } else { 
     
    15331532} 
    15341533 
     1534 
     1535static 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. */ 
     1559PJ_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. */ 
     1609PJ_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  
    29482948 
    29492949    /* 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, 
    29512951                                   &si->param->setting.dec_fmtp); 
    29522952 
  • pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/stream_common.c

    r3498 r3500  
    8787        /* Store token */ 
    8888        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            } 
    9195            if (*p == '=') 
    9296                /* Got param name */ 
  • pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/vid_codec.c

    r3425 r3500  
    307307 
    308308/* 
    309  * Get codec info for static payload type. 
     309 * Get codec info for the specified payload type. 
    310310 */ 
    311311PJ_DEF(pj_status_t) pjmedia_vid_codec_mgr_get_codec_info( 
     
    316316    unsigned i; 
    317317 
    318     PJ_ASSERT_RETURN(p_info && pt>=0 && pt < 96, PJ_EINVAL); 
     318    PJ_ASSERT_RETURN(p_info, PJ_EINVAL); 
    319319 
    320320    if (!mgr) mgr = def_vid_codec_mgr; 
     
    369369/* 
    370370 * 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". 
    372372 */ 
    373373PJ_DEF(char*) pjmedia_vid_codec_info_to_id( 
     
    382382                           (int)info->encoding_name.slen, 
    383383                           info->encoding_name.ptr, 
    384                            info->clock_rate); 
     384                           info->pt); 
    385385 
    386386    if (len < 1 || len >= (int)max_len) { 
  • pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/vid_codec_util.c

    r3493 r3500  
    2020#include <pjmedia/vid_codec_util.h> 
    2121#include <pjmedia/errno.h> 
     22#include <pjmedia/stream_common.h> 
    2223#include <pjlib-util/base64.h> 
     24#include <pj/ctype.h> 
    2325#include <pj/math.h> 
    2426 
     
    259261 
    260262/* H264 fmtp parser */ 
    261 PJ_DEF(pj_status_t) pjmedia_vid_codec_parse_h264_fmtp( 
     263PJ_DEF(pj_status_t) pjmedia_vid_codec_h264_parse_fmtp( 
    262264                                    const pjmedia_codec_fmtp *fmtp, 
    263265                                    pjmedia_vid_codec_h264_fmtp *h264_fmtp) 
     
    289291            h264_fmtp->profile_idc = (pj_uint8_t)((tmp >> 16) & 0xFF); 
    290292            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); 
    292294        } else if (pj_stricmp(&fmtp->param[i].name, &PACKETIZATION_MODE)==0) { 
    293295            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; 
    295300        } else if (pj_stricmp(&fmtp->param[i].name, &MAX_MBPS)==0) { 
    296301            tmp = pj_strtoul(&fmtp->param[i].val); 
    297             if (tmp) h264_fmtp->max_mbps = tmp; 
     302            h264_fmtp->max_mbps = tmp; 
    298303        } else if (pj_stricmp(&fmtp->param[i].name, &MAX_FS)==0) { 
    299304            tmp = pj_strtoul(&fmtp->param[i].val); 
    300             if (tmp) h264_fmtp->max_fs = tmp; 
     305            h264_fmtp->max_fs = tmp; 
    301306        } else if (pj_stricmp(&fmtp->param[i].name, &MAX_CPB)==0) { 
    302307            tmp = pj_strtoul(&fmtp->param[i].val); 
    303             if (tmp) h264_fmtp->max_cpb = tmp; 
     308            h264_fmtp->max_cpb = tmp; 
    304309        } else if (pj_stricmp(&fmtp->param[i].name, &MAX_DPB)==0) { 
    305310            tmp = pj_strtoul(&fmtp->param[i].val); 
    306             if (tmp) h264_fmtp->max_dpb = tmp; 
     311            h264_fmtp->max_dpb = tmp; 
    307312        } else if (pj_stricmp(&fmtp->param[i].name, &MAX_BR)==0) { 
    308313            tmp = pj_strtoul(&fmtp->param[i].val); 
    309             if (tmp) h264_fmtp->max_br = tmp; 
     314            h264_fmtp->max_br = tmp; 
    310315        } else if (pj_stricmp(&fmtp->param[i].name, &SPROP_PARAMETER_SETS)==0) 
    311316        { 
     
    351356    } 
    352357 
     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 
    353365    return PJ_SUCCESS; 
    354366} 
     367 
     368PJ_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  
    2222#include <pjmedia/rtcp.h> 
    2323#include <pjmedia/jbuf.h> 
     24#include <pjmedia/sdp_neg.h> 
    2425#include <pjmedia/stream_common.h> 
    2526#include <pj/array.h> 
     
    17221723                                              const pjmedia_sdp_media *rem_m) 
    17231724{ 
    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; 
    17271727    pj_status_t status; 
    17281728 
    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      */ 
    17331729    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 */ 
    17341739    si->rx_pt = pt; 
     1740 
     1741    /* Get payload type for transmitting direction */ 
    17351742    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  
    17441743        /* For static payload type, pt's are symetric */ 
    17451744        si->tx_pt = pt; 
    17461745 
    17471746    } 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; 
    17681748 
    17691749        /* Determine payload type for outgoing channel, by finding 
     
    17721752        si->tx_pt = 0xFFFF; 
    17731753        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) 
    17921758            { 
    17931759                /* Found matched codec. */ 
    1794                 si->tx_pt = rpt; 
    1795  
     1760                si->tx_pt = pj_strtoul(&rem_m->desc.fmt[i]); 
    17961761                break; 
    17971762            } 
  • pjproject/branches/projects/2.0-dev/pjsip-apps/src/pjsua/pjsua_app.c

    r3477 r3500  
    35433543    pjsua_vid_enum_codecs(c, &count); 
    35443544    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); 
    35473551    } 
    35483552#endif 
  • pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h

    r3471 r3500  
    43804380 
    43814381    /** 
     4382     * Codec description. 
     4383     */ 
     4384    pj_str_t            desc; 
     4385 
     4386    /** 
    43824387     * Internal buffer. 
    43834388     */ 
    4384     char                buf_[32]; 
     4389    char                buf_[64]; 
    43854390 
    43864391} pjsua_codec_info; 
  • pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c

    r3487 r3500  
    37583758 
    37593759    for (i=0; i<count; ++i) { 
     3760        pj_bzero(&id[i], sizeof(pjsua_codec_info)); 
     3761 
    37603762        pjmedia_codec_info_to_id(&info[i], id[i].buf_, sizeof(id[i].buf_)); 
    37613763        id[i].codec_id = pj_str(id[i].buf_); 
     
    38753877    for (i=0, j=0; i<count && j<*p_count; ++i) { 
    38763878        if (info[i].has_rtp_pack) { 
     3879            pj_bzero(&id[j], sizeof(pjsua_codec_info)); 
     3880 
    38773881            pjmedia_vid_codec_info_to_id(&info[i], id[j].buf_, sizeof(id[j].buf_)); 
    38783882            id[j].codec_id = pj_str(id[j].buf_); 
    38793883            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 
    38803891            ++j; 
    38813892        } 
Note: See TracChangeset for help on using the changeset viewer.