其他分享
首页 > 其他分享> > live555作为客户端接受H264视频流实现步骤

live555作为客户端接受H264视频流实现步骤

作者:互联网

1.    // Begin by setting up our usage environment:
    TaskScheduler * task_scheduler_ptr = BasicTaskScheduler::createNew();
2.  UsageEnvironment * usage_environment_ptr = BasicUsageEnvironment::createNew(*task_scheduler_ptr);
    创建RTSPClient对象同时传入流地址
3. 调用RTSPClient的sendDescribeCommand同时传入自己的回调函数RtspClient_OnResponse_DESCRIBE

4 实现RtspClient_OnResponse_DESCRIBE

RtspClient_OnResponse_DESCRIBE(RTSPClient * rtspClient, int resultCode, char * resultString)
   a.UsageEnvironment &env = RTSPClient的envir();
   b.    const char * sdpDescription = resultString;
   c.// Create a media session object from this SDP description:
    //根据sdp创建会话
        m_session = MediaSession::createNew(env, sdpDescription);
   d. delete[] sdpDescription;
   e.    // Then, create and set up our data source objects for the session.  We do this by iterating over the session's 'subsessions',
        // calling "MediaSubsession::initiate()", and then sending a RTSP "SETUP" command, on each one.
        // (Each 'subsession' will have its own data source.)
        m_mss_iter = new MediaSubsessionIterator(m_session);
        
    f.设置subsession,setup_next_subsession()
    
    m_subsession = m_mss_iter->next();
        
    if (NULL != m_subsession)
    {
        if (!m_subsession->initiate())
        {
            // give up on this subsession; go to the next one
            重新执行6,
        }
        else
        {
            // Continue setting up this subsession, by sending a RTSP "SETUP" command.
            // By default, we request that the server stream its data using RTP/UDP.
            // If, instead, you want to request that the server stream via RTP-over-TCP, change the following to True:
            const Boolean request_streaming_over_tcp = True;
            sendSetupCommand(*m_subsession, RtspClient_OnResponse_SETUP, False, request_streaming_over_tcp);
        }

        return;
    }
    // We've finished setting up all of the subsessions. Now, send a RTSP "PLAY" command to start the streaming:
    if (NULL != m_session->absStartTime())
    {
        // Special case: The stream is indexed by 'absolute' time, so send an appropriate "PLAY" command:
        sendPlayCommand(*m_session, RtspClient_OnResponse_PLAY, m_session->absStartTime(), m_session->absEndTime());
    }
    else
    {
        m_duration = m_session->playEndTime() - m_session->playStartTime();
        sendPlayCommand(*m_session, RtspClient_OnResponse_PLAY);
    }
5.实现    回调函数RtspClient_OnResponse_SETUP
    RtspClient_OnResponse_SETUP(RTSPClient * rtspClient, int resultCode, char * resultString)
    
    // Having successfully setup the subsession, create a data sink for it, and call "startPlaying()" on it.
    // (This will prepare the data sink to receive data; the actual flow of data from the client won't start happening until later,
    // after we've sent a RTSP "PLAY" command.)

    vxMediaSink * sink_ptr = vxMediaSink::create(env, obj_ptr->m_subsession, vxMediaSink::ECV_DEF_RECVBUF_SIZE);
    // a hack to let subsession handle functions get the "RTSPClient" from the subsession
    设置接受数据的回调函数后面需要自己实现
    sink_ptr->set_recved_realframe_cbk(Stream_OnEvent_RecvedRealFrame, obj_ptr);
    m_subsession->sink = sink_ptr;
    设置关闭subsession的回调函数,后面需自己实现
    m_subsession->sink->startPlaying(*(obj_ptr->m_subsession->readSource()),
                                    Subsession_OnEvent_Playing, obj_ptr->m_subsession);
                                    
    // Get SPS and PPS data for decode H264 video stream.
    unsigned int nSPropRecords = 0;
    SPropRecord * pSPropRecord = parseSPropParameterSets(m_subsession->fmtp_spropparametersets(), nSPropRecords);
    通过自己的函数把SPS,PPS传出去进行处理,这是原始数据,具体怎么操作则由外面实现
    if ((nSPropRecords > 0))
    {
        for (unsigned int i = 0; i < nSPropRecords; ++i)
        {
            //SPropRecord * sps_ptr = &pSPropRecord[i];
            m_func_recved( pSPropRecord[i].sPropBytes, pSPropRecord[i].sPropLength, RTSP_FRAMETYPE_RCDPARAM);
        }
        delete[] pSPropRecord;
    }
    
    // Also set a handler to be called if a RTCP "BYE" arrives for this subsession:
    Subsession_OnEvent_ByeHandler需要自己实现回调函数
    if (NULL != m_subsession->rtcpInstance())
    {
        m_subsession->rtcpInstance()->setByeHandler(Subsession_OnEvent_ByeHandler, m_subsession);
    }
    delete[] resultString;

    // Set up the next subsession, if any:
    setup_next_subsession();
    
    
    
    a.Stream_OnEvent_RecvedRealFrame(void * pv_handle, void * frame_buf, unsigned int frame_size, void * pv_user)
        vxMediaSink     * sink_ptr = (vxMediaSink *)pv_handle;
        MediaSubsession * subsession_ptr = sink_ptr->subsession();
        const char * sz_media_name = subsession_ptr->mediumName();
        const char * sz_codec_name = subsession_ptr->codecName();
        if ((0 == strcmp(sz_media_name, "video")) && (0 == strcmp(sz_codec_name, "H264")))
        {
            调用外面写好的处理函数,处理收到的原始真数据
            m_func_recved( frame_buf, frame_size, RTSP_FRAMETYPE_REALH264)
        }
        
        
    b.Subsession_OnEvent_Playing(void * clientData)
        MediaSubsession *subsession = (MediaSubsession *)clientData;
        // Begin by closing this subsession's stream:
        Medium::close(subsession->sink);
        subsession->sink = NULL;
        
        // Next, check whether *all* subsessions' streams have now been closed:
        MediaSession &session = subsession->parentSession();
        MediaSubsessionIterator iter(session);
        while (NULL != (subsession = iter.next()))
        {
            // this subsession is still active
            if (subsession->sink != NULL)
                return;
        }

     // All subsessions' streams have now been closed, so shutdown the client:
     shutdown_stream();一会写这个写,在其他地方实现的
        
        
        
    c.Subsession_OnEvent_ByeHandler(void * clientData)
        MediaSubsession * subsession = (MediaSubsession *)clientData;
        // Now act as if the subsession had closed:
        vxRtspCliHandle::Subsession_OnEvent_Playing(subsession);
    
6.实现回调函数    RtspClient_OnResponse_PLAY
    RtspClient_OnResponse_PLAY(RTSPClient *rtspClient, int resultCode, char *resultString);
    这个我还没搞懂,应该是设置一个定时时间做一些事情
    
    
    
7这就是刚才楼下的那个关闭流操作shutdown_stream(void)
{
    UsageEnvironment &env = envir();

    // First, check whether any subsessions have still to be closed:
    if (NULL != m_session)
    {
        bool someSubsessionsWereActive = false;

        MediaSubsessionIterator iter(*m_session);
        MediaSubsession * subsession_ptr;
        while (NULL != (subsession_ptr = iter.next()))
        {
            if (NULL != subsession_ptr->sink)
            {
                Medium::close(subsession_ptr->sink);
                subsession_ptr->sink = NULL;

                if (subsession_ptr->rtcpInstance() != NULL)
                {
                    // in case the server sends a RTCP "BYE" while handling "TEARDOWN"
                    subsession_ptr->rtcpInstance()->setByeHandler(NULL, NULL);
                }

                someSubsessionsWereActive = true;
            }
        }

        if (someSubsessionsWereActive)
        {
            // Send a RTSP "TEARDOWN" command, to tell the server to shutdown the stream.
            // Don't bother handling the response to the "TEARDOWN".
            sendTeardownCommand(*m_session, NULL);
        }

        env.taskScheduler().unscheduleDelayedTask(m_stream_timer_task);
        Medium::close(m_session);
        m_session = NULL;
    }

    if (NULL != m_mss_iter)
    {
        delete m_mss_iter;
        m_mss_iter = NULL;
    }

    env << url() << "Closing the stream.\n";

}

结束

Eraser的橡皮擦 发布了21 篇原创文章 · 获赞 1 · 访问量 1615 私信 关注

标签:live555,H264,视频流,subsession,session,sink,NULL,RtspClient,ptr
来源: https://blog.csdn.net/m0_38012470/article/details/104555810