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