rdp rmtp 转_如何实现多路海康大华等RTSP数据转RTMP推送

一个好的转发模块,首先要低延迟!其次足够稳定、灵活、有状态反馈机制、资源占用低,跨平台,最好以接口形式提供,便于第三方系统集成。

以Windows平台为例,我们的考虑的点如下

1. 拉流:通过RTSP直播播放SDK的数据回调接口,拿到音视频数据;

2. 转推:通过RTMP直播推送SDK的编码后数据输入接口,把回调上来的数据,传给RTMP直播推送模块,实现RTSP数据流到RTMP服务器的转发;

3. 录像:如果需要录像,借助RTSP直播播放SDK,拉到音视频数据后,直接存储MP4文件即可;

4. 快照:如果需要实时快照,拉流后,解码调用播放端快照接口,生成快照,因为快照涉及到video数据解码,如无必要,可不必开启,不然会额外消耗性能。

5. 拉流预览:如需预览拉流数据,只要调用播放端的播放接口,即可实现拉流数据预览;

6. 数据转AAC后转发:考虑到好多监控设备出来的音频可能是PCMA/PCMU的,如需要更通用的音频格式,可以转AAC后,在通过RTMP推送;

7. 转推RTMP实时静音:只需要在传audio数据的地方,加个判断即可;

8. 拉流速度反馈:通过RTSP播放端的实时码率反馈event,拿到实时带宽占用即可;

9. 整体网络状态反馈:考虑到有些摄像头可能会临时或异常关闭,RTMP服务器亦是,可以通过推拉流的event回调状态,查看那整体网络情况,如此界定:是拉不到流,还是推不到RTMP服务器。

系统设计架构图

​Windows转发demo分析

大牛直播SDK的转发demo,Windows平台,对应C++ demo工程:WIN-RelaySDK-CPP-Demo,如需下载demo源码,参看 Github

1. 拉流:拉流和播放有些类似,但不需要播放(也就是说不要解码,资源消耗非常低),在做过基础的参数配置之后(对应demo里面OpenPullHandle()),设置音视频数据回调,然后调用StartPullStream()即可:

1.1 基础参数设置:

bool nt_stream_relay_wrapper::OpenPullHandle(const std::string& url, bool is_rtsp_tcp_mode, bool is_mute)

{

if ( pull_handle_ != NULL )

return true;

if ( url.empty() )

return false;

duration_ = 0;

NT_HANDLE pull_handle = NULL;

ASSERT( pull_api_ != NULL );

if (NT_ERC_OK != pull_api_->Open(&pull_handle, render_wnd_, 0, NULL))

{

return false;

}

ASSERT(pull_handle != NULL);

pull_api_->SetEventCallBack(pull_handle, this, &NT_Pull_SDKEventHandle);

pull_api_->SetBuffer(pull_handle, 0);

pull_api_->SetFastStartup(pull_handle, 1);

pull_api_->SetRTSPTcpMode(pull_handle, is_rtsp_tcp_mode ? 1 : 0);

pull_api_->SetMute(pull_handle, is_mute ? 1 : 0);

if ( NT_ERC_OK != pull_api_->SetURL(pull_handle, url.c_str()) )

{

pull_api_->Close(pull_handle);

pull_handle = NULL;

return false;

}

if ( setting_pos_ >= 0ll )

{

pull_api_->SetPos(pull_handle, setting_pos_);

}

pull_handle_ = pull_handle;

return true;

}

1.2 设置音视频数据回调:

pull_api_->SetPullStreamVideoDataCallBack(pull_handle_, this, &SP_SDKPullStreamVideoDataHandle);

pull_api_->SetPullStreamAudioDataCallBack(pull_handle_, this, &SP_SDKPullStreamAudioDataHandle);

1.3 开始拉流:

auto ret = pull_api_->StartPullStream(pull_handle_);

if ( NT_ERC_OK != ret )

{

if ( !is_playing_ )

{

pull_api_->Close(pull_handle_);

pull_handle_ = NULL;

}

return false;

}

拉流整体代码如下:

bool nt_stream_relay_wrapper::StartPull(const std::string& url, bool is_rtsp_tcp_mode, bool is_transcode_aac)

{

if ( is_pulling_ )

return false;

if ( !OpenPullHandle(url, is_rtsp_tcp_mode) )

return false;

pull_api_->SetPullStreamVideoDataCallBack(pull_handle_, this, &SP_SDKPullStreamVideoDataHandle);

pull_api_->SetPullStreamAudioDataCallBack(pull_handle_, this, &SP_SDKPullStreamAudioDataHandle);

pull_api_->SetPullStreamAudioTranscodeAAC(pull_handle_, is_transcode_aac? 1: 0);

auto ret = pull_api_->StartPullStream(pull_handle_);

if ( NT_ERC_OK != ret )

{

if ( !is_playing_ )

{

pull_api_->Close(pull_handle_);

pull_handle_ = NULL;

}

return false;

}

is_pulling_ = true;

return true;

}

2. 停止拉流:

停止拉流流程比较简单,先判断是否在拉流状态,如果拉流,调用StopPullStream() 即可,如没有预览画面,调用Close()接口关闭拉流实例。

void nt_stream_relay_wrapper::StopPull()

{

if ( !is_pulling_ )

return;

pull_api_->StopPullStream(pull_handle_);

if ( !is_playing_ )

{

pull_api_->Close(pull_handle_);

pull_handle_ = NULL;

}

is_pulling_ = false;

}

3. 拉流端预览:

拉流端预览,说白了就是播放拉流数据,流程比较简单,demo调用如下,如不需要播放声音,调用SetMute(),实时打开/关闭即可:

bool nt_stream_relay_wrapper::StartPlay(const std::string& url, bool is_rtsp_tcp_mode, bool is_mute)

{

if ( is_playing_ )

return false;

if ( !OpenPullHandle(url, is_rtsp_tcp_mode, is_mute) )

return false;

pull_api_->SetMute(pull_handle_, is_mute ? 1 : 0);

auto ret = pull_api_->StartPlay(pull_handle_);

if ( NT_ERC_OK != ret )

{

if ( !is_pulling_ )

{

pull_api_->Close(pull_handle_);

pull_handle_ = NULL;

}

return false;

}

is_playing_ = true;

return true;

}

4. 拉流端关闭预览:

void nt_stream_relay_wrapper::StopPlay()

{

if ( !is_playing_ )

return;

pull_api_->StopPlay(pull_handle_);

if ( !is_pulling_ )

{

pull_api_->Close(pull_handle_);

pull_handle_ = NULL;

}

is_playing_ = false;

}

5. 开始推流到RTMP服务器:

推流的流程,如之前所述,调用RTMP推送模块,然后数据源传编码后的音视频数据即可,下图的demo源码,同时展示了,RTSP流获取到后,转推RTMP的时候,数据解密的处理:

bool nt_stream_relay_wrapper::StartPush(const std::string& url)

{

if ( is_pushing_ )

return false;

if ( url.empty() )

return false;

if ( !OpenPushHandle() )

return false;

auto push_handle = GetPushHandle();

ASSERT(push_handle != nullptr);

ASSERT(push_api_ != NULL);

if ( NT_ERC_OK != push_api_->SetURL(push_handle, url.c_str(), NULL) )

{

if ( !is_started_rtsp_stream_ )

{

push_api_->Close(push_handle);

SetPushHandle(nullptr);

}

return false;

}

// 加密测试 +++

// push_api_->SetRtmpEncryptionOption(push_handle, url.c_str(), 1, 1);

// NT_BYTE test_key[16] = {'1', '2', '3'};

// push_api_->SetRtmpEncryptionKey(push_handle, url.c_str(), test_key, 16);

// 加密测试 --

if ( NT_ERC_OK != push_api_->StartPublisher(push_handle, NULL) )

{

if ( !is_started_rtsp_stream_ )

{

push_api_->Close(push_handle);

SetPushHandle(nullptr);

}

return false;

}

// // test push rtsp ++

// push_api_->SetPushRtspTransportProtocol(push_handle, 1);

// // push_api_->SetPushRtspTransportProtocol(push_handle, 2);

// push_api_->SetPushRtspURL(push_handle, "rtsp://player.daniulive.com:554/liverelay111.sdp");

// push_api_->StartPushRtsp(push_handle, 0);

// // test push rtsp--

is_pushing_ = true;

return true;

}

6. 传递转推RTMP数据:

void nt_stream_relay_wrapper::OnVideoDataHandle(NT_HANDLE handle, NT_UINT32 video_codec_id,

NT_BYTE* data, NT_UINT32 size, NT_SP_PullStreamVideoDataInfo* info)

{

if (!is_pushing_ && !is_started_rtsp_stream_)

return;

if ( pull_handle_ != handle )

return;

if (data == NULL)

return;

if (size < 1)

return;

if (info == NULL)

return;

std::unique_lock<:recursive_mutex> lock(push_handle_mutex_);

if (!is_pushing_ && !is_started_rtsp_stream_)

return;

if (push_handle_ == NULL)

return;

push_api_->PostVideoEncodedDataV2(push_handle_, video_codec_id,

data, size, info->is_key_frame_, info->timestamp_, info->presentation_timestamp_);

}

void nt_stream_relay_wrapper::OnAudioDataHandle(NT_HANDLE handle, NT_UINT32 auido_codec_id,

NT_BYTE* data, NT_UINT32 size, NT_SP_PullStreamAuidoDataInfo* info)

{

if (!is_pushing_ && !is_started_rtsp_stream_)

return;

if (pull_handle_ != handle)

return;

if (data == NULL)

return;

if (size < 1)

return;

if (info == NULL)

return;

std::unique_lock<:recursive_mutex> lock(push_handle_mutex_);

if (!is_pushing_ && !is_started_rtsp_stream_)

return;

if (push_handle_ == NULL)

return;

push_api_->PostAudioEncodedData(push_handle_, auido_codec_id, data, size,

info->is_key_frame_, info->timestamp_,

info->parameter_info_, info->parameter_info_size_);

}

7. 关闭实时RTMP转推

void nt_stream_relay_wrapper::StopPush()

{

if ( !is_pushing_ )

return;

is_pushing_ = false;

std::unique_lock<:recursive_mutex> lock(push_handle_mutex_);

if ( nullptr == push_handle_ )

return;

push_api_->StopPublisher(push_handle_);

// // test push rtsp ++

// push_api_->StopPushRtsp(push_handle_);

// // test push rtsp--

if ( !is_started_rtsp_stream_ )

{

push_api_->Close(push_handle_);

push_handle_ = nullptr;

}

}

以上就是RTSP或RTMP流转RTMP推送的流程,感兴趣的开发者,可做设计参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值