Ignore:
Timestamp:
Feb 24, 2011 7:47:55 AM (13 years ago)
Author:
nanang
Message:

Re #1182:

  • Added video stream interface in vid_stream.h, the video stream will be able to handle different video formats in encoding and decoding direction.
  • Renamed video device stream class identifiers from 'pjmedia_vid_stream*' to 'pjmedia_vid_dev_stream*' as 'pjmedia_vid_stream' is used by video stream interface.
  • Added ffmpeg video capability to be able to parse SDP format param for H263 and also decide video format for encoding direction based on remote preference and local format-capability setting.
  • Added some new APIs in jitter buffer for handling video stream: pjmedia_jbuf_put_frame3(), pjmedia_jbuf_get_frame3(), pjmedia_jbuf_peek_frame(), and pjmedia_jbuf_remove_frame().
  • Moved pjmedia_stream_info_from_sdp() from session to stream
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/2.0-dev/pjmedia/src/pjmedia/stream.c

    r3418 r3420  
    2323#include <pjmedia/rtcp.h> 
    2424#include <pjmedia/jbuf.h> 
     25#include <pjmedia/stream_common.h> 
    2526#include <pj/array.h> 
    2627#include <pj/assert.h> 
     
    27392740} 
    27402741 
     2742 
     2743static const pj_str_t ID_AUDIO = { "audio", 5}; 
     2744static const pj_str_t ID_VIDEO = { "video", 5}; 
     2745static const pj_str_t ID_APPLICATION = { "application", 11}; 
     2746static const pj_str_t ID_IN = { "IN", 2 }; 
     2747static const pj_str_t ID_IP4 = { "IP4", 3}; 
     2748static const pj_str_t ID_IP6 = { "IP6", 3}; 
     2749static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 }; 
     2750static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 }; 
     2751//static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 }; 
     2752static const pj_str_t ID_RTPMAP = { "rtpmap", 6 }; 
     2753static const pj_str_t ID_TELEPHONE_EVENT = { "telephone-event", 15 }; 
     2754 
     2755static const pj_str_t STR_INACTIVE = { "inactive", 8 }; 
     2756static const pj_str_t STR_SENDRECV = { "sendrecv", 8 }; 
     2757static const pj_str_t STR_SENDONLY = { "sendonly", 8 }; 
     2758static const pj_str_t STR_RECVONLY = { "recvonly", 8 }; 
     2759 
     2760 
     2761/* 
     2762 * Internal function for collecting codec info and param from the SDP media. 
     2763 */ 
     2764static pj_status_t get_audio_codec_info_param(pjmedia_stream_info *si, 
     2765                                              pj_pool_t *pool, 
     2766                                              pjmedia_codec_mgr *mgr, 
     2767                                              const pjmedia_sdp_media *local_m, 
     2768                                              const pjmedia_sdp_media *rem_m) 
     2769{ 
     2770    const pjmedia_sdp_attr *attr; 
     2771    pjmedia_sdp_rtpmap *rtpmap; 
     2772    unsigned i, fmti, pt = 0; 
     2773    pj_status_t status; 
     2774 
     2775    /* Find the first codec which is not telephone-event */ 
     2776    for ( fmti = 0; fmti < local_m->desc.fmt_count; ++fmti ) { 
     2777        if ( !pj_isdigit(*local_m->desc.fmt[fmti].ptr) ) 
     2778            return PJMEDIA_EINVALIDPT; 
     2779        pt = pj_strtoul(&local_m->desc.fmt[fmti]); 
     2780        if ( PJMEDIA_RTP_PT_TELEPHONE_EVENTS == 0 || 
     2781                pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS ) 
     2782                break; 
     2783    } 
     2784    if ( fmti >= local_m->desc.fmt_count ) 
     2785        return PJMEDIA_EINVALIDPT; 
     2786 
     2787    /* Get codec info. 
     2788     * For static payload types, get the info from codec manager. 
     2789     * For dynamic payload types, MUST get the rtpmap. 
     2790     */ 
     2791    if (pt < 96) { 
     2792        pj_bool_t has_rtpmap; 
     2793 
     2794        rtpmap = NULL; 
     2795        has_rtpmap = PJ_TRUE; 
     2796 
     2797        attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,  
     2798                                           &local_m->desc.fmt[fmti]); 
     2799        if (attr == NULL) { 
     2800            has_rtpmap = PJ_FALSE; 
     2801        } 
     2802        if (attr != NULL) { 
     2803            status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap); 
     2804            if (status != PJ_SUCCESS) 
     2805                has_rtpmap = PJ_FALSE; 
     2806        } 
     2807 
     2808        /* Build codec format info: */ 
     2809        if (has_rtpmap) { 
     2810            si->fmt.type = si->type; 
     2811            si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]); 
     2812            pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name); 
     2813            si->fmt.clock_rate = rtpmap->clock_rate; 
     2814             
     2815#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0) 
     2816            /* The session info should have the actual clock rate, because  
     2817             * this info is used for calculationg buffer size, etc in stream  
     2818             */ 
     2819            if (si->fmt.pt == PJMEDIA_RTP_PT_G722) 
     2820                si->fmt.clock_rate = 16000; 
     2821#endif 
     2822 
     2823            /* For audio codecs, rtpmap parameters denotes the number of 
     2824             * channels. 
     2825             */ 
     2826            if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) { 
     2827                si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param); 
     2828            } else { 
     2829                si->fmt.channel_cnt = 1; 
     2830            } 
     2831 
     2832        } else {             
     2833            const pjmedia_codec_info *p_info; 
     2834 
     2835            status = pjmedia_codec_mgr_get_codec_info( mgr, pt, &p_info); 
     2836            if (status != PJ_SUCCESS) 
     2837                return status; 
     2838 
     2839            pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info)); 
     2840        } 
     2841 
     2842        /* For static payload type, pt's are symetric */ 
     2843        si->tx_pt = pt; 
     2844 
     2845    } else { 
     2846 
     2847        attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP,  
     2848                                           &local_m->desc.fmt[fmti]); 
     2849        if (attr == NULL) 
     2850            return PJMEDIA_EMISSINGRTPMAP; 
     2851 
     2852        status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap); 
     2853        if (status != PJ_SUCCESS) 
     2854            return status; 
     2855 
     2856        /* Build codec format info: */ 
     2857 
     2858        si->fmt.type = si->type; 
     2859        si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]); 
     2860        pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name); 
     2861        si->fmt.clock_rate = rtpmap->clock_rate; 
     2862 
     2863        /* For audio codecs, rtpmap parameters denotes the number of 
     2864         * channels. 
     2865         */ 
     2866        if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) { 
     2867            si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param); 
     2868        } else { 
     2869            si->fmt.channel_cnt = 1; 
     2870        } 
     2871 
     2872        /* Determine payload type for outgoing channel, by finding 
     2873         * dynamic payload type in remote SDP that matches the answer. 
     2874         */ 
     2875        si->tx_pt = 0xFFFF; 
     2876        for (i=0; i<rem_m->desc.fmt_count; ++i) { 
     2877            unsigned rpt; 
     2878            pjmedia_sdp_attr *r_attr; 
     2879            pjmedia_sdp_rtpmap r_rtpmap; 
     2880 
     2881            rpt = pj_strtoul(&rem_m->desc.fmt[i]); 
     2882            if (rpt < 96) 
     2883                continue; 
     2884 
     2885            r_attr = pjmedia_sdp_media_find_attr(rem_m, &ID_RTPMAP, 
     2886                                                 &rem_m->desc.fmt[i]); 
     2887            if (!r_attr) 
     2888                continue; 
     2889 
     2890            if (pjmedia_sdp_attr_get_rtpmap(r_attr, &r_rtpmap) != PJ_SUCCESS) 
     2891                continue; 
     2892 
     2893            if (!pj_stricmp(&rtpmap->enc_name, &r_rtpmap.enc_name) && 
     2894                rtpmap->clock_rate == r_rtpmap.clock_rate) 
     2895            { 
     2896                /* Found matched codec. */ 
     2897                si->tx_pt = rpt; 
     2898 
     2899                break; 
     2900            } 
     2901        } 
     2902 
     2903        if (si->tx_pt == 0xFFFF) 
     2904            return PJMEDIA_EMISSINGRTPMAP; 
     2905    } 
     2906 
     2907   
     2908    /* Now that we have codec info, get the codec param. */ 
     2909    si->param = PJ_POOL_ALLOC_T(pool, pjmedia_codec_param); 
     2910    status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt, 
     2911                                                 si->param); 
     2912 
     2913    /* Get remote fmtp for our encoder. */ 
     2914    pjmedia_stream_info_parse_fmtp(pool, rem_m, si->tx_pt, 
     2915                                   &si->param->setting.enc_fmtp); 
     2916 
     2917    /* Get local fmtp for our decoder. */ 
     2918    pjmedia_stream_info_parse_fmtp(pool, local_m, si->fmt.pt,  
     2919                                   &si->param->setting.dec_fmtp); 
     2920 
     2921    /* Get the remote ptime for our encoder. */ 
     2922    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 
     2923                                  "ptime", NULL); 
     2924    if (attr) { 
     2925        pj_str_t tmp_val = attr->value; 
     2926        unsigned frm_per_pkt; 
     2927  
     2928        pj_strltrim(&tmp_val); 
     2929 
     2930        /* Round up ptime when the specified is not multiple of frm_ptime */ 
     2931        frm_per_pkt = (pj_strtoul(&tmp_val) +  
     2932                      si->param->info.frm_ptime/2) / 
     2933                      si->param->info.frm_ptime; 
     2934        if (frm_per_pkt != 0) { 
     2935            si->param->setting.frm_per_pkt = (pj_uint8_t)frm_per_pkt; 
     2936        } 
     2937    } 
     2938 
     2939    /* Get remote maxptime for our encoder. */ 
     2940    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 
     2941                                  "maxptime", NULL); 
     2942    if (attr) { 
     2943        pj_str_t tmp_val = attr->value; 
     2944 
     2945        pj_strltrim(&tmp_val); 
     2946        si->tx_maxptime = pj_strtoul(&tmp_val); 
     2947    } 
     2948 
     2949    /* When direction is NONE (it means SDP negotiation has failed) we don't 
     2950     * need to return a failure here, as returning failure will cause 
     2951     * the whole SDP to be rejected. See ticket #: 
     2952     *  http:// 
     2953     * 
     2954     * Thanks Alain Totouom  
     2955     */ 
     2956    if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE) 
     2957        return status; 
     2958 
     2959 
     2960    /* Get incomming payload type for telephone-events */ 
     2961    si->rx_event_pt = -1; 
     2962    for (i=0; i<local_m->attr_count; ++i) { 
     2963        pjmedia_sdp_rtpmap r; 
     2964 
     2965        attr = local_m->attr[i]; 
     2966        if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) 
     2967            continue; 
     2968        if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) 
     2969            continue; 
     2970        if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { 
     2971            si->rx_event_pt = pj_strtoul(&r.pt); 
     2972            break; 
     2973        } 
     2974    } 
     2975 
     2976    /* Get outgoing payload type for telephone-events */ 
     2977    si->tx_event_pt = -1; 
     2978    for (i=0; i<rem_m->attr_count; ++i) { 
     2979        pjmedia_sdp_rtpmap r; 
     2980 
     2981        attr = rem_m->attr[i]; 
     2982        if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) 
     2983            continue; 
     2984        if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) 
     2985            continue; 
     2986        if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { 
     2987            si->tx_event_pt = pj_strtoul(&r.pt); 
     2988            break; 
     2989        } 
     2990    } 
     2991 
     2992    return PJ_SUCCESS; 
     2993} 
     2994 
     2995 
     2996 
     2997/* 
     2998 * Create stream info from SDP media line. 
     2999 */ 
     3000PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp( 
     3001                                           pjmedia_stream_info *si, 
     3002                                           pj_pool_t *pool, 
     3003                                           pjmedia_endpt *endpt, 
     3004                                           const pjmedia_sdp_session *local, 
     3005                                           const pjmedia_sdp_session *remote, 
     3006                                           unsigned stream_idx) 
     3007{ 
     3008    pjmedia_codec_mgr *mgr; 
     3009    const pjmedia_sdp_attr *attr; 
     3010    const pjmedia_sdp_media *local_m; 
     3011    const pjmedia_sdp_media *rem_m; 
     3012    const pjmedia_sdp_conn *local_conn; 
     3013    const pjmedia_sdp_conn *rem_conn; 
     3014    int rem_af, local_af; 
     3015    pj_sockaddr local_addr; 
     3016    pj_status_t status; 
     3017 
     3018     
     3019    /* Validate arguments: */ 
     3020    PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL); 
     3021    PJ_ASSERT_RETURN(stream_idx < local->media_count, PJ_EINVAL); 
     3022    PJ_ASSERT_RETURN(stream_idx < remote->media_count, PJ_EINVAL); 
     3023 
     3024    /* Keep SDP shortcuts */ 
     3025    local_m = local->media[stream_idx]; 
     3026    rem_m = remote->media[stream_idx]; 
     3027 
     3028    local_conn = local_m->conn ? local_m->conn : local->conn; 
     3029    if (local_conn == NULL) 
     3030        return PJMEDIA_SDP_EMISSINGCONN; 
     3031 
     3032    rem_conn = rem_m->conn ? rem_m->conn : remote->conn; 
     3033    if (rem_conn == NULL) 
     3034        return PJMEDIA_SDP_EMISSINGCONN; 
     3035 
     3036    /* Media type must be audio */ 
     3037    if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) == 0) 
     3038        return PJMEDIA_EINVALIMEDIATYPE; 
     3039 
     3040    /* Get codec manager. */ 
     3041    mgr = pjmedia_endpt_get_codec_mgr(endpt); 
     3042 
     3043    /* Reset: */ 
     3044 
     3045    pj_bzero(si, sizeof(*si)); 
     3046 
     3047#if PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR 
     3048    /* Set default RTCP XR enabled/disabled */ 
     3049    si->rtcp_xr_enabled = PJ_TRUE; 
     3050#endif 
     3051 
     3052    /* Media type: */ 
     3053    si->type = PJMEDIA_TYPE_AUDIO; 
     3054 
     3055    /* Transport protocol */ 
     3056 
     3057    /* At this point, transport type must be compatible,  
     3058     * the transport instance will do more validation later. 
     3059     */ 
     3060    status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport,  
     3061                                       &local_m->desc.transport); 
     3062    if (status != PJ_SUCCESS) 
     3063        return PJMEDIA_SDPNEG_EINVANSTP; 
     3064 
     3065    if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) { 
     3066 
     3067        si->proto = PJMEDIA_TP_PROTO_RTP_AVP; 
     3068 
     3069    } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) { 
     3070 
     3071        si->proto = PJMEDIA_TP_PROTO_RTP_SAVP; 
     3072 
     3073    } else { 
     3074 
     3075        si->proto = PJMEDIA_TP_PROTO_UNKNOWN; 
     3076        return PJ_SUCCESS; 
     3077    } 
     3078 
     3079 
     3080    /* Check address family in remote SDP */ 
     3081    rem_af = pj_AF_UNSPEC(); 
     3082    if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) { 
     3083        if (pj_stricmp(&rem_conn->addr_type, &ID_IP4)==0) { 
     3084            rem_af = pj_AF_INET(); 
     3085        } else if (pj_stricmp(&rem_conn->addr_type, &ID_IP6)==0) { 
     3086            rem_af = pj_AF_INET6(); 
     3087        } 
     3088    } 
     3089 
     3090    if (rem_af==pj_AF_UNSPEC()) { 
     3091        /* Unsupported address family */ 
     3092        return PJ_EAFNOTSUP; 
     3093    } 
     3094 
     3095    /* Set remote address: */ 
     3096    status = pj_sockaddr_init(rem_af, &si->rem_addr, &rem_conn->addr,  
     3097                              rem_m->desc.port); 
     3098    if (status != PJ_SUCCESS) { 
     3099        /* Invalid IP address. */ 
     3100        return PJMEDIA_EINVALIDIP; 
     3101    } 
     3102 
     3103    /* Check address family of local info */ 
     3104    local_af = pj_AF_UNSPEC(); 
     3105    if (pj_stricmp(&local_conn->net_type, &ID_IN)==0) { 
     3106        if (pj_stricmp(&local_conn->addr_type, &ID_IP4)==0) { 
     3107            local_af = pj_AF_INET(); 
     3108        } else if (pj_stricmp(&local_conn->addr_type, &ID_IP6)==0) { 
     3109            local_af = pj_AF_INET6(); 
     3110        } 
     3111    } 
     3112 
     3113    if (local_af==pj_AF_UNSPEC()) { 
     3114        /* Unsupported address family */ 
     3115        return PJ_SUCCESS; 
     3116    } 
     3117 
     3118    /* Set remote address: */ 
     3119    status = pj_sockaddr_init(local_af, &local_addr, &local_conn->addr,  
     3120                              local_m->desc.port); 
     3121    if (status != PJ_SUCCESS) { 
     3122        /* Invalid IP address. */ 
     3123        return PJMEDIA_EINVALIDIP; 
     3124    } 
     3125 
     3126    /* Local and remote address family must match */ 
     3127    if (local_af != rem_af) 
     3128        return PJ_EAFNOTSUP; 
     3129 
     3130    /* Media direction: */ 
     3131 
     3132    if (local_m->desc.port == 0 ||  
     3133        pj_sockaddr_has_addr(&local_addr)==PJ_FALSE || 
     3134        pj_sockaddr_has_addr(&si->rem_addr)==PJ_FALSE || 
     3135        pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL) 
     3136    { 
     3137        /* Inactive stream. */ 
     3138 
     3139        si->dir = PJMEDIA_DIR_NONE; 
     3140 
     3141    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) { 
     3142 
     3143        /* Send only stream. */ 
     3144 
     3145        si->dir = PJMEDIA_DIR_ENCODING; 
     3146 
     3147    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) { 
     3148 
     3149        /* Recv only stream. */ 
     3150 
     3151        si->dir = PJMEDIA_DIR_DECODING; 
     3152 
     3153    } else { 
     3154 
     3155        /* Send and receive stream. */ 
     3156 
     3157        si->dir = PJMEDIA_DIR_ENCODING_DECODING; 
     3158 
     3159    } 
     3160 
     3161    /* No need to do anything else if stream is rejected */ 
     3162    if (local_m->desc.port == 0) { 
     3163        return PJ_SUCCESS; 
     3164    } 
     3165 
     3166    /* If "rtcp" attribute is present in the SDP, set the RTCP address 
     3167     * from that attribute. Otherwise, calculate from RTP address. 
     3168     */ 
     3169    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 
     3170                                  "rtcp", NULL); 
     3171    if (attr) { 
     3172        pjmedia_sdp_rtcp_attr rtcp; 
     3173        status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp); 
     3174        if (status == PJ_SUCCESS) { 
     3175            if (rtcp.addr.slen) { 
     3176                status = pj_sockaddr_init(rem_af, &si->rem_rtcp, &rtcp.addr, 
     3177                                          (pj_uint16_t)rtcp.port); 
     3178            } else { 
     3179                pj_sockaddr_init(rem_af, &si->rem_rtcp, NULL,  
     3180                                 (pj_uint16_t)rtcp.port); 
     3181                pj_memcpy(pj_sockaddr_get_addr(&si->rem_rtcp), 
     3182                          pj_sockaddr_get_addr(&si->rem_addr), 
     3183                          pj_sockaddr_get_addr_len(&si->rem_addr)); 
     3184            } 
     3185        } 
     3186    } 
     3187     
     3188    if (!pj_sockaddr_has_addr(&si->rem_rtcp)) { 
     3189        int rtcp_port; 
     3190 
     3191        pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr)); 
     3192        rtcp_port = pj_sockaddr_get_port(&si->rem_addr) + 1; 
     3193        pj_sockaddr_set_port(&si->rem_rtcp, (pj_uint16_t)rtcp_port); 
     3194    } 
     3195 
     3196 
     3197    /* Get the payload number for receive channel. */ 
     3198    /* 
     3199       Previously we used to rely on fmt[0] being the selected codec, 
     3200       but some UA sends telephone-event as fmt[0] and this would 
     3201       cause assert failure below. 
     3202 
     3203       Thanks Chris Hamilton <chamilton .at. cs.dal.ca> for this patch. 
     3204 
     3205    // And codec must be numeric! 
     3206    if (!pj_isdigit(*local_m->desc.fmt[0].ptr) ||  
     3207        !pj_isdigit(*rem_m->desc.fmt[0].ptr)) 
     3208    { 
     3209        return PJMEDIA_EINVALIDPT; 
     3210    } 
     3211 
     3212    pt = pj_strtoul(&local_m->desc.fmt[0]); 
     3213    pj_assert(PJMEDIA_RTP_PT_TELEPHONE_EVENTS==0 || 
     3214              pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS); 
     3215    */ 
     3216 
     3217    /* Get codec info and param */ 
     3218    status = get_audio_codec_info_param(si, pool, mgr, local_m, rem_m); 
     3219 
     3220    /* Leave SSRC to random. */ 
     3221    si->ssrc = pj_rand(); 
     3222 
     3223    /* Set default jitter buffer parameter. */ 
     3224    si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1; 
     3225 
     3226    return status; 
     3227} 
Note: See TracChangeset for help on using the changeset viewer.