vlc 调用live555的源码分析--vlc v2.1.1版本

VLC调用Live555源码解析

 以前在看live555的源码和例子的时,发现live555的例子都是回调,这样我们根本无法判断命令是否发送成功,也无法判断发送是否超时;网上搜索,也没有看到有用的资料;于是就分析了VLC的live555.cpp文件,对该问题恍然大悟,于是记下vlc live555的Rtsp连接建立过程,供大家参考,我们可以从vlc怎么调用live555.cpp中看到vlc 是如何结合live555的,这样对我们调用live555写客户端等等有很大的帮助!

 

源码见:

http://blog.csdn.net/smilestone_322/article/details/17504909

1)  连接RTSP服务器

/*****************************************************************************

 * Connect: connects to the RTSP server to setup the session DESCRIBE

 *****************************************************************************/

static int Connect( demux_t *p_demux )

{

    demux_sys_t *p_sys = p_demux->p_sys;

    Authenticator authenticator;

    char *psz_user    = NULL;

    char *psz_pwd     = NULL;

    char *psz_url     = NULL;

    int  i_http_port  = 0;

int  i_ret        = VLC_SUCCESS;

 

//获取超时的时间

    const int i_timeout = var_InheritInteger( p_demux, "ipv4-timeout" );

 

/* Get the user name and password */

//获取RTSP的URL的用户名和密码;

    if( p_sys->url.psz_username || p_sys->url.psz_password )

    {

        /* Create the URL by stripping away the username/password part */

        if( p_sys->url.i_port == 0 )

            p_sys->url.i_port = 554;

        if( asprintf( &psz_url, "rtsp://%s:%d%s",

                      strempty( p_sys->url.psz_host ),

                      p_sys->url.i_port,

                      strempty( p_sys->url.psz_path ) ) == -1 )

            return VLC_ENOMEM;

 

        psz_user = strdup( strempty( p_sys->url.psz_username ) );

        psz_pwd  = strdup( strempty( p_sys->url.psz_password ) );

    }

    else

    {

        if( asprintf( &psz_url, "rtsp://%s", p_sys->psz_path ) == -1 )

            return VLC_ENOMEM;

 

        psz_user = var_InheritString( p_demux, "rtsp-user" );

        psz_pwd  = var_InheritString( p_demux, "rtsp-pwd" );

    }

 

createnew:

    if( !vlc_object_alive (p_demux) )

    {

        i_ret = VLC_EGENERIC;

        goto bailout;

    }

       //判断是否走http隧道

    if( var_CreateGetBool( p_demux, "rtsp-http" ) )

        i_http_port = var_InheritInteger( p_demux, "rtsp-http-port" );

 

//创建一个RTSPClient客户端, RTSPClientVlc继承自live555的RTSPClient

    p_sys->rtsp = new RTSPClientVlc( *p_sys->env, psz_url,

                                     var_InheritInteger( p_demux, "verbose" ) > 1 ? 1 : 0,

                                     "LibVLC/"VERSION, i_http_port, p_sys );

    if( !p_sys->rtsp )

    {

        msg_Err( p_demux, "RTSPClient::createNew failed (%s)",

                 p_sys->env->getResultMsg() );

        i_ret = VLC_EGENERIC;

        goto bailout;

    }

 

    /* Kasenna enables KeepAlive by analysing the User-Agent string.

     * Appending _KA to the string should be enough to enable this feature,

     * however, there is a bug where the _KA doesn't get parsed from the

     * default User-Agent as created by VLC/Live555 code. This is probably due

     * to spaces in the string or the string being too long. Here we override

     * the default string with a more compact version.

     */

    if( var_InheritBool( p_demux, "rtsp-kasenna" ))

    {

        p_sys->rtsp->setUserAgentString( "VLC_MEDIA_PLAYER_KA" );

    }

 

describe:

    authenticator.setUsernameAndPassword( psz_user, psz_pwd );

      

       //往服务器发送sendOptionsCommand请求,continueAfterOPTIONS和live555的例子一样,是一个回调,在发送完sendOptionsCommand请求,收到它的应答后调用该回调函数,在continueAfterOPTIONS函数中发送Describe请求;

    p_sys->rtsp->sendOptionsCommand( &continueAfterOPTIONS, &authenticator );

      

       // wait_Live555_response 用来判断发送命令是否超时,相当重要,Live555给的例子中都没有这个,这样我们是不好判断我们发送的命令是否失败,比如发送命令超时了,程序就没有响应了,都不能给个提示,VLC使用该函数解决了Live555的这个问题;

    if( !wait_Live555_response( p_demux, i_timeout ) )

    {

        int i_code = p_sys->i_live555_ret;

        if( i_code == 401 )

        {

            msg_Dbg( p_demux, "authentication failed" );

 

            free( psz_user );

            free( psz_pwd );

            dialog_Login( p_demux, &psz_user, &psz_pwd,

                          _("RTSP authentication"), "%s",

                        _("Please enter a valid login name and a password.") );

            if( psz_user != NULL && psz_pwd != NULL )

            {

                            //鉴权失败,转到describe再次发送Opinion请求

                msg_Dbg( p_demux, "retrying with user=%s", psz_user );

                goto describe;

            }

        }

        else if( i_code > 0 && i_code != 404 && !var_GetBool( p_demux, "rtsp-http" ) )

        {

            /* Perhaps a firewall is being annoying. Try HTTP tunneling mode */

                     //失败,转http 隧道模式

            msg_Dbg( p_demux, "we will now try HTTP tunneling mode" );

            var_SetBool( p_demux, "rtsp-http", true );

            if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );

            p_sys->rtsp = NULL;

            goto createnew;

        }

        else

        {

                     // i_code=0表示连接超时

            if( i_code == 0 )

                msg_Dbg( p_demux, "connection timeout" );

            else

            {

                            //连接失败

                msg_Dbg( p_demux, "connection error %d", i_code );

                if( i_code == 403 )

                    dialog_Fatal( p_demux, _("RTSP connection failed"),

                                  _("Access to the stream is denied by the server configuration.") );

            }

            if( p_sys->rtsp ) RTSPClient::close( p_sys->rtsp );

            p_sys->rtsp = NULL;

        }

        i_ret = VLC_EGENERIC;

    }

 

bailout:

    /* malloc-ated copy */

    free( psz_url );

    free( psz_user );

    free( psz_pwd );

 

    return i_ret;

}

 

其中:

static void continueAfterOPTIONS( RTSPClient* client, int result_code,

                                  char* result_string )

{

    RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> (client);

    demux_sys_t *p_sys = client_vlc->p_sys;

    p_sys->b_get_param =

      // If OPTIONS fails, assume GET_PARAMETER is not supported but

      // still continue on with the stream.  Some servers (foscam)

      // return 501/not implemented for OPTIONS.

      result_code == 0

      && result_string != NULL

      && strstr( result_string, "GET_PARAMETER" ) != NULL;

    client->sendDescribeCommand( continueAfterDESCRIBE );

    delete[] result_string;

}

 

在continueAfterOPTIONS函数中,调用sendDescribeCommand函数发送Describe命令;continueAfterDESCRIBE为sendDescribeCommand命令发送后调用的回调函数;

 

continueAfterDESCRIBE函数如下:

static void continueAfterDESCRIBE( RTSPClient* client, int result_code,

                                   char* result_string )

{

    RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> ( client );

    demux_sys_t *p_sys = client_vlc->p_sys;

    p_sys->i_live555_ret = result_code;

    if ( result_code == 0 )

    {

        char* sdpDescription = result_string;

        free( p_sys->p_sdp );

        p_sys->p_sdp = NULL;

        if( sdpDescription )

        {

            p_sys->p_sdp = strdup( sdpDescription );

            p_sys->b_error = false;

        }

    }

    else

        p_sys->b_error = true;

    delete[] result_string;

    p_sys->event_rtsp = 1;

}

 

回调函数中的result_code和result_string还是挺重要的,可以从其中判断发送的命令是否错误;

 

判断超时的函数如下:

/* return true if the RTSP command succeeded */

static bool wait_Live555_response( demux_t *p_demux, int i_timeout = 0 /* ms */ )

{

    TaskToken task;

    demux_sys_t * p_sys = p_demux->p_sys;

    p_sys->event_rtsp = 0;

    if( i_timeout > 0 )

    {

        /* Create a task that will be called if we wait more than timeout ms */

        task = p_sys->scheduler->scheduleDelayedTask( i_timeout*1000,

                                                      TaskInterruptRTSP,

                                                      p_demux );

    }

    p_sys->event_rtsp = 0;

    p_sys->b_error = true;

p_sys->i_live555_ret = 0;

//

    p_sys->scheduler->doEventLoop( &p_sys->event_rtsp );

    //here, if b_error is true and i_live555_ret = 0 we didn't receive a response

    if( i_timeout > 0 )

    {

        /* remove the task */

        p_sys->scheduler->unscheduleDelayedTask( task );

    }

    return !p_sys->b_error;

}

 

如果超时:那么调用TaskInterruptRTSP函数;当超时时,在TaskInterruptRTSP将event_rtsp置为非0;这样doEventLoop里面的while循环会顺利退出;如果没有超时,在continueAfterDESCRIBE函数中也将event_rtsp置为非0;DoEventLoop的线程也会顺利退出,这样在根据p_sys->b_error;判断是否成功还是失败;

 

*****************************************************************************/

static void TaskInterruptRTSP( void *p_private )

{

    demux_t *p_demux = (demux_t*)p_private;

 

    /* Avoid lock */

    p_demux->p_sys->event_rtsp = 0xff;

}

 

2)  发送Setup建立会话;

 

/*****************************************************************************

 * SessionsSetup: prepares the subsessions and does the SETUP

 *****************************************************************************/

static int SessionsSetup( demux_t *p_demux )

{

    demux_sys_t             *p_sys  = p_demux->p_sys;

    MediaSubsessionIterator *iter   = NULL;

    MediaSubsession         *sub    = NULL;

 

    bool           b_rtsp_tcp;

    int            i_client_port;

    int            i_return = VLC_SUCCESS;

    unsigned int   i_receive_buffer = 0;

    int            i_frame_buffer = DEFAULT_FRAME_BUFFER_SIZE;

    unsigned const thresh = 200000; /* RTP reorder threshold .2 second (default .1) */

 

    b_rtsp_tcp    = var_CreateGetBool( p_demux, "rtsp-tcp" ) ||

                    var_GetBool( p_demux, "rtsp-http" );

    i_client_port = var_InheritInteger( p_demux, "rtp-client-port" );

 

 

    /* Create the session from the SDP */

    if( !( p_sys->ms = MediaSession::createNew( *p_sys->env, p_sys->p_sdp ) ) )

    {

        msg_Err( p_demux, "Could not create the RTSP Session: %s",

            p_sys->env->getResultMsg() );

        return VLC_EGENERIC;

    }

 

    /* Initialise each media subsession */

    iter = new MediaSubsessionIterator( *p_sys->ms );

    while( ( sub = iter->next() ) != NULL )

    {

        Boolean bInit;

        live_track_t *tk;

 

        if( !vlc_object_alive (p_demux) )

        {

            delete iter;

            return VLC_EGENERIC;

        }

 

        /* Value taken from mplayer */

        if( !strcmp( sub->mediumName(), "audio" ) )

            i_receive_buffer = 100000;

        else if( !strcmp( sub->mediumName(), "video" ) )

        {

            int i_var_buf_size = var_InheritInteger( p_demux, "rtsp-frame-buffer-size" );

            if( i_var_buf_size > 0 )

                i_frame_buffer = i_var_buf_size;

            i_receive_buffer = 2000000;

        }

        else if( !strcmp( sub->mediumName(), "text" ) )

            ;

        else continue;

 

        if( i_client_port != -1 )

        {

            sub->setClientPortNum( i_client_port );

            i_client_port += 2;

        }

 

        if( strcasestr( sub->codecName(), "REAL" ) )

        {

            msg_Info( p_demux, "real codec detected, using real-RTSP instead" );

            p_sys->b_real = true; /* This is a problem, we'll handle it later */

            continue;

        }

 

        if( !strcmp( sub->codecName(), "X-ASF-PF" ) )

            bInit = sub->initiate( 0 );

        else

            bInit = sub->initiate();

 

        if( !bInit )

        {

            msg_Warn( p_demux, "RTP subsession '%s/%s' failed (%s)",

                      sub->mediumName(), sub->codecName(),

                      p_sys->env->getResultMsg() );

        }

        else

        {

            if( sub->rtpSource() != NULL )

            {

                int fd = sub->rtpSource()->RTPgs()->socketNum();

 

                /* Increase the buffer size */

                if( i_receive_buffer > 0 )

                    increaseReceiveBufferTo( *p_sys->env, fd, i_receive_buffer );

 

                /* Increase the RTP reorder timebuffer just a bit */

                sub->rtpSource()->setPacketReorderingThresholdTime(thresh);

            }

            msg_Dbg( p_demux, "RTP subsession '%s/%s'", sub->mediumName(),

                     sub->codecName() );

 

            /* Issue the SETUP */

            if( p_sys->rtsp )

            {

       //发送Setup命令,建立会话;default_live555_callback为sendSetupCommand函数的回调函数;其主要作用是判断SetUp命令是否发送成功,置为DoEvent的线程标志,使得线程顺利退出,从而wait_Live555_response函数能够顺利退出;

                p_sys->rtsp->sendSetupCommand( *sub, default_live555_callback, False,

                                               toBool( b_rtsp_tcp ),

                                               toBool( p_sys->b_force_mcast && !b_rtsp_tcp ) );

//判断Setup命令是否发送成功

                if( !wait_Live555_response( p_demux ) )

                {

                    /* if we get an unsupported transport error, toggle TCP

                     * use and try again */

                    if( p_sys->i_live555_ret == 461 )

                        p_sys->rtsp->sendSetupCommand( *sub, default_live555_callback, False,

                                                       !toBool( b_rtsp_tcp ), False );

                    if( p_sys->i_live555_ret != 461 || !wait_Live555_response( p_demux ) )

                    {

                        msg_Err( p_demux, "SETUP of'%s/%s' failed %s",

                                 sub->mediumName(), sub->codecName(),

                                 p_sys->env->getResultMsg() );

                        continue;

                    }

                    else

                    {

                        var_SetBool( p_demux, "rtsp-tcp", true );

                        b_rtsp_tcp = true;

                    }

                }

            }

 

            /* Check if we will receive data from this subsession for

             * this track */

            if( sub->readSource() == NULL ) continue;

            if( !p_sys->b_multicast )

            {

                /* We need different rollover behaviour for multicast */

                p_sys->b_multicast = IsMulticastAddress( sub->connectionEndpointAddress() );

            }

 

            tk = (live_track_t*)malloc( sizeof( live_track_t ) );

            if( !tk )

            {

                delete iter;

                return VLC_ENOMEM;

            }

            tk->p_demux     = p_demux;

            tk->sub         = sub;

            tk->p_es        = NULL;

            tk->b_quicktime = false;

            tk->b_asf       = false;

            tk->p_asf_block = NULL;

            tk->b_muxed     = false;

            tk->b_discard_trunc = false;

            tk->p_out_muxed = NULL;

            tk->waiting     = 0;

            tk->b_rtcp_sync = false;

            tk->i_pts       = VLC_TS_INVALID;

            tk->f_npt       = 0.;

            tk->b_selected  = true;

            tk->i_buffer    = i_frame_buffer;

            tk->p_buffer    = (uint8_t *)malloc( i_frame_buffer );

 

            if( !tk->p_buffer )

            {

                free( tk );

                delete iter;

                return VLC_ENOMEM;

            }

 

            /* Value taken from mplayer */

            if( !strcmp( sub->mediumName(), "audio" ) )

            {

                es_format_Init( &tk->fmt, AUDIO_ES, VLC_FOURCC('u','n','d','f') );

                tk->fmt.audio.i_channels = sub->numChannels();

                tk->fmt.audio.i_rate = sub->rtpTimestampFrequency();

 

                if( !strcmp( sub->codecName(), "MPA" ) ||

                    !strcmp( sub->codecName(), "MPA-ROBUST" ) ||

                    !strcmp( sub->codecName(), "X-MP3-DRAFT-00" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_MPGA;

                    tk->fmt.audio.i_rate = 0;

                }

                else if( !strcmp( sub->codecName(), "AC3" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_A52;

                    tk->fmt.audio.i_rate = 0;

                }

                else if( !strcmp( sub->codecName(), "L16" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_S16B;

                    tk->fmt.audio.i_bitspersample = 16;

                }

                else if( !strcmp( sub->codecName(), "L20" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_S20B;

                    tk->fmt.audio.i_bitspersample = 20;

                }

                else if( !strcmp( sub->codecName(), "L24" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_S24B;

                    tk->fmt.audio.i_bitspersample = 24;

                }

                else if( !strcmp( sub->codecName(), "L8" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_U8;

                    tk->fmt.audio.i_bitspersample = 8;

                }

                else if( !strcmp( sub->codecName(), "DAT12" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_DAT12;

                    tk->fmt.audio.i_bitspersample = 12;

                }

                else if( !strcmp( sub->codecName(), "PCMU" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_MULAW;

                    tk->fmt.audio.i_bitspersample = 8;

                }

                else if( !strcmp( sub->codecName(), "PCMA" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_ALAW;

                    tk->fmt.audio.i_bitspersample = 8;

                }

                else if( !strncmp( sub->codecName(), "G726", 4 ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_ADPCM_G726;

                    tk->fmt.audio.i_rate = 8000;

                    tk->fmt.audio.i_channels = 1;

                    if( !strcmp( sub->codecName()+5, "40" ) )

                        tk->fmt.i_bitrate = 40000;

                    else if( !strcmp( sub->codecName()+5, "32" ) )

                        tk->fmt.i_bitrate = 32000;

                    else if( !strcmp( sub->codecName()+5, "24" ) )

                        tk->fmt.i_bitrate = 24000;

                    else if( !strcmp( sub->codecName()+5, "16" ) )

                        tk->fmt.i_bitrate = 16000;

                }

                else if( !strcmp( sub->codecName(), "AMR" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_AMR_NB;

                }

                else if( !strcmp( sub->codecName(), "AMR-WB" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_AMR_WB;

                }

                else if( !strcmp( sub->codecName(), "MP4A-LATM" ) )

                {

                    unsigned int i_extra;

                    uint8_t      *p_extra;

 

                    tk->fmt.i_codec = VLC_CODEC_MP4A;

 

                    if( ( p_extra = parseStreamMuxConfigStr( sub->fmtp_config(),

                                                             i_extra ) ) )

                    {

                        tk->fmt.i_extra = i_extra;

                        tk->fmt.p_extra = xmalloc( i_extra );

                        memcpy( tk->fmt.p_extra, p_extra, i_extra );

                        delete[] p_extra;

                    }

                    /* Because the "faad" decoder does not handle the LATM

                     * data length field at the start of each returned LATM

                     * frame, tell the RTP source to omit. */

                    ((MPEG4LATMAudioRTPSource*)sub->rtpSource())->omitLATMDataLengthField();

                }

                else if( !strcmp( sub->codecName(), "MPEG4-GENERIC" ) )

                {

                    unsigned int i_extra;

                    uint8_t      *p_extra;

 

                    tk->fmt.i_codec = VLC_CODEC_MP4A;

 

                    if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(),

                                                           i_extra ) ) )

                    {

                        tk->fmt.i_extra = i_extra;

                        tk->fmt.p_extra = xmalloc( i_extra );

                        memcpy( tk->fmt.p_extra, p_extra, i_extra );

                        delete[] p_extra;

                    }

                }

                else if( !strcmp( sub->codecName(), "X-ASF-PF" ) )

                {

                    tk->b_asf = true;

                    if( p_sys->p_out_asf == NULL )

                        p_sys->p_out_asf = stream_DemuxNew( p_demux, "asf",

                                                            p_demux->out );

                }

                else if( !strcmp( sub->codecName(), "X-QT" ) ||

                         !strcmp( sub->codecName(), "X-QUICKTIME" ) )

                {

                    tk->b_quicktime = true;

                }

                else if( !strcmp( sub->codecName(), "SPEEX" ) )

                {

                    tk->fmt.i_codec = VLC_FOURCC( 's', 'p', 'x', 'r' );

                    if ( tk->fmt.audio.i_rate == 0 )

                    {

                        msg_Warn( p_demux,"Using 8kHz as default sample rate." );

                        tk->fmt.audio.i_rate = 8000;

                    }

                }

                else if( !strcmp( sub->codecName(), "VORBIS" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_VORBIS;

                    unsigned int i_extra;

                    unsigned char *p_extra;

                    if( ( p_extra=parseVorbisConfigStr( sub->fmtp_config(),

                                                        i_extra ) ) )

                    {

                        tk->fmt.i_extra = i_extra;

                        tk->fmt.p_extra = p_extra;

                    }

                    else

                        msg_Warn( p_demux,"Missing or unsupported vorbis header." );

                }

            }

            else if( !strcmp( sub->mediumName(), "video" ) )

            {

                es_format_Init( &tk->fmt, VIDEO_ES, VLC_FOURCC('u','n','d','f') );

                if( !strcmp( sub->codecName(), "MPV" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_MPGV;

                    tk->fmt.b_packetized = false;

                }

                else if( !strcmp( sub->codecName(), "H263" ) ||

                         !strcmp( sub->codecName(), "H263-1998" ) ||

                         !strcmp( sub->codecName(), "H263-2000" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_H263;

                }

                else if( !strcmp( sub->codecName(), "H261" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_H261;

                }

                else if( !strcmp( sub->codecName(), "H264" ) )

                {

                    unsigned int i_extra = 0;

                    uint8_t      *p_extra = NULL;

 

                    tk->fmt.i_codec = VLC_CODEC_H264;

                    tk->fmt.b_packetized = false;

 

                    if((p_extra=parseH264ConfigStr( sub->fmtp_spropparametersets(),

                                                    i_extra ) ) )

                    {

                        tk->fmt.i_extra = i_extra;

                        tk->fmt.p_extra = xmalloc( i_extra );

                        memcpy( tk->fmt.p_extra, p_extra, i_extra );

 

                        delete[] p_extra;

                    }

                }

                else if( !strcmp( sub->codecName(), "JPEG" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_MJPG;

                }

                else if( !strcmp( sub->codecName(), "MP4V-ES" ) )

                {

                    unsigned int i_extra;

                    uint8_t      *p_extra;

 

                    tk->fmt.i_codec = VLC_CODEC_MP4V;

 

                    if( ( p_extra = parseGeneralConfigStr( sub->fmtp_config(),

                                                           i_extra ) ) )

                    {

                        tk->fmt.i_extra = i_extra;

                        tk->fmt.p_extra = xmalloc( i_extra );

                        memcpy( tk->fmt.p_extra, p_extra, i_extra );

                        delete[] p_extra;

                    }

                }

                else if( !strcmp( sub->codecName(), "X-QT" ) ||

                         !strcmp( sub->codecName(), "X-QUICKTIME" ) ||

                         !strcmp( sub->codecName(), "X-QDM" ) ||

                         !strcmp( sub->codecName(), "X-SV3V-ES" )  ||

                         !strcmp( sub->codecName(), "X-SORENSONVIDEO" ) )

                {

                    tk->b_quicktime = true;

                }

                else if( !strcmp( sub->codecName(), "MP2T" ) )

                {

                    tk->b_muxed = true;

                    tk->p_out_muxed = stream_DemuxNew( p_demux, "ts", p_demux->out );

                }

                else if( !strcmp( sub->codecName(), "MP2P" ) ||

                         !strcmp( sub->codecName(), "MP1S" ) )

                {

                    tk->b_muxed = true;

                    tk->p_out_muxed = stream_DemuxNew( p_demux, "ps",

                                                       p_demux->out );

                }

                else if( !strcmp( sub->codecName(), "X-ASF-PF" ) )

                {

                    tk->b_asf = true;

                    if( p_sys->p_out_asf == NULL )

                        p_sys->p_out_asf = stream_DemuxNew( p_demux, "asf",

                                                            p_demux->out );;

                }

                else if( !strcmp( sub->codecName(), "DV" ) )

                {

                    tk->b_muxed = true;

                    tk->b_discard_trunc = true;

                    tk->p_out_muxed = stream_DemuxNew( p_demux, "rawdv",

                                                       p_demux->out );

                }

                else if( !strcmp( sub->codecName(), "VP8" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_VP8;

                }

            }

            else if( !strcmp( sub->mediumName(), "text" ) )

            {

                es_format_Init( &tk->fmt, SPU_ES, VLC_FOURCC('u','n','d','f') );

 

                if( !strcmp( sub->codecName(), "T140" ) )

                {

                    tk->fmt.i_codec = VLC_CODEC_ITU_T140;

                }

            }

 

            if( !tk->b_quicktime && !tk->b_muxed && !tk->b_asf )

            {

                tk->p_es = es_out_Add( p_demux->out, &tk->fmt );

            }

 

            if( sub->rtcpInstance() != NULL )

            {

                sub->rtcpInstance()->setByeHandler( StreamClose, tk );

            }

 

            if( tk->p_es || tk->b_quicktime || ( tk->b_muxed && tk->p_out_muxed ) ||

                ( tk->b_asf && p_sys->p_out_asf ) )

            {

                TAB_APPEND_CAST( (live_track_t **), p_sys->i_track, p_sys->track, tk );

            }

            else

            {

                /* BUG ??? */

                msg_Err( p_demux, "unusable RTSP track. this should not happen" );

                es_format_Clean( &tk->fmt );

                free( tk );

            }

        }

    }

    delete iter;

    if( p_sys->i_track <= 0 ) i_return = VLC_EGENERIC;

 

    /* Retrieve the starttime if possible */

    p_sys->f_npt_start = p_sys->ms->playStartTime();

 

    /* Retrieve the duration if possible */

    p_sys->f_npt_length = p_sys->ms->playEndTime();

 

    /* */

    msg_Dbg( p_demux, "setup start: %f stop:%f", p_sys->f_npt_start, p_sys->f_npt_length );

 

    /* */

    p_sys->b_no_data = true;

    p_sys->i_no_data_ti = 0;

 

    return i_return;

}

 

其中default_live555_callback函数定义如下,该函数也是挺重要的:

 

static void default_live555_callback( RTSPClient* client, int result_code, char* result_string )

{

    RTSPClientVlc *client_vlc = static_cast<RTSPClientVlc *> ( client );

    demux_sys_t *p_sys = client_vlc->p_sys;

    delete []result_string;

    p_sys->i_live555_ret = result_code;

    p_sys->b_error = p_sys->i_live555_ret != 0;

    p_sys->event_rtsp = 1;

}

 

3)  发送Play请求;

 

static int Play( demux_t *p_demux )

{

    demux_sys_t *p_sys = p_demux->p_sys;

 

    if( p_sys->rtsp )

    {

        /* The PLAY */

              //发送sendPlayCommand命令,default_live555_callback为其回调函数

        p_sys->rtsp->sendPlayCommand( *p_sys->ms, default_live555_callback, p_sys->f_npt_start, -1, 1 );

 

              //判断Play命令是否发送超时

        if( !wait_Live555_response(p_demux) )

        {

            msg_Err( p_demux, "RTSP PLAY failed %s", p_sys->env->getResultMsg() );

            return VLC_EGENERIC;

        }

 

        /* Retrieve the timeout value and set up a timeout prevention thread */

        p_sys->i_timeout = p_sys->rtsp->sessionTimeoutParameter();

        if( p_sys->i_timeout <= 0 )

            p_sys->i_timeout = 60; /* default value from RFC2326 */

 

        /* start timeout-thread only if GET_PARAMETER is supported by the server */

        /* or start it if wmserver dialect, since they don't report that GET_PARAMETER is supported correctly */

        if( !p_sys->p_timeout && ( p_sys->b_get_param || var_InheritBool( p_demux, "rtsp-wmserver" ) ) )

        {

            msg_Dbg( p_demux, "We have a timeout of %d seconds",  p_sys->i_timeout );

            p_sys->p_timeout = (timeout_thread_t *)malloc( sizeof(timeout_thread_t) );

            if( p_sys->p_timeout )

            {

                memset( p_sys->p_timeout, 0, sizeof(timeout_thread_t) );

                p_sys->p_timeout->p_sys = p_demux->p_sys; /* lol, object recursion :D */

                if( vlc_clone( &p_sys->p_timeout->handle,  TimeoutPrevention,

                               p_sys->p_timeout, VLC_THREAD_PRIORITY_LOW ) )

                {

                    msg_Err( p_demux, "cannot spawn liveMedia timeout thread" );

                    free( p_sys->p_timeout );

                    p_sys->p_timeout = NULL;

                }

                else

                    msg_Dbg( p_demux, "spawned timeout thread" );

            }

            else

                msg_Err( p_demux, "cannot spawn liveMedia timeout thread" );

        }

    }

    p_sys->i_pcr = 0;

 

    /* Retrieve the starttime if possible */

    p_sys->f_npt_start = p_sys->ms->playStartTime();

    if( p_sys->ms->playEndTime() > 0 )

        p_sys->f_npt_length = p_sys->ms->playEndTime();

 

    msg_Dbg( p_demux, "play start: %f stop:%f", p_sys->f_npt_start, p_sys->f_npt_length );

    return VLC_SUCCESS;

}

 

 

 

你可能感兴趣的:(vlc 调用live555的源码分析--vlc v2.1.1版本)