srt2rtmp流程:接收srt data,然后decode,转封装为rtmp推送给rtmp server。
流程的关键是一个decode func。
int ts_demux::decode(SRT_DATA_MSG_PTR data_ptr, TS_DATA_CALLBACK_PTR callback)
{
int ret = -1;
std::string path;
if (!data_ptr || (data_ptr->data_len() < 188) || (data_ptr->data_len()%188 != 0))
{
return -1;
}
unsigned int count = data_ptr->data_len()/188;
path = data_ptr->get_path();
for (unsigned int index = 0; index < count; index++)
{
unsigned char* data = data_ptr->get_data() + 188*index;
if (data[0] != 0x47) {
continue;
}
ret = decode_unit(data, path, callback);
if (ret < 0)
{
break;
}
}
return ret;
}
SRT_DATA_MSG_PTR data_ptr,这个送进来的数据指针取自队列。
SRT_DATA_MSG_PTR srt2rtmp::get_data_message() {
std::unique_lock<std::mutex> locker(_mutex);
SRT_DATA_MSG_PTR msg_ptr;
if (_msg_queue.empty())
{
return msg_ptr;
}
//while (_msg_queue.empty()) {
// _notify_cond.wait(locker);
//}
msg_ptr = _msg_queue.front();
_msg_queue.pop();
return msg_ptr;
}
队列名称:
std::queue<SRT_DATA_MSG_PTR> _msg_queue;
核心转发函数:
void srt_handle::handle_push_data(SRT_SOCKSTATUS status, const std::string& subpath, SRTSOCKET conn_fd) {
ret = srt_conn_ptr->read(data, DEF_DATA_SIZE); //从srt连接上读数据。
srt_conn_ptr->update_timestamp(srt_now_ms); //timestamp是rtmp推流时需要的。
srt2rtmp::get_instance()->insert_data_message(data, ret, subpath); //把数据发到_msg_queue
}
srt_conn_ptr->read函数:
int srt_conn::read(unsigned char* data, int len) {
int ret = 0;
ret = srt_recv(_conn_fd, (char*)data, len);
if (ret <= 0) {
srs_error("srt read error:%d, socket fd:%d", ret, _conn_fd);
return ret;
}
return ret;
}
sls用的是这个srt_recvmsg(m_sc.fd, buf, size);
看起来没什么区别。注释说:srt_recvmsg is actually an alias to srt_recv
收下来的data,是mpegts格式。要重装包装为rtmp格式。
协议转换有一个核心函数:int ts_demux::decode_unit(unsigned char* data_p, std::string key_path, TS_DATA_CALLBACK_PTR callback)
这个函数很复杂,就不分析了。看起来是work的,没有问题。
新建一个srt2rtmp线程来进行转发,我感觉比当前的coroutine模型要简单许多!
线程主流程:
while(True){
int n = m_srt->libsrt_read(szData, TS_UDP_LEN);
if (n>0){
int ts_demux::decode(szData, TS_DATA_CALLBACK_PTR callback);
}
msleep(20);
}