Ignore:
Timestamp:
Apr 6, 2011 1:55:01 PM (13 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).
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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 
Note: See TracChangeset for help on using the changeset viewer.