ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-02-28 14:40:53  阅读:314  来源: 互联网

标签:live555 H264 视频流 subsession session sink NULL RtspClient ptr


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有