如何实现多路海康大华等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服务器。

系统设计架构图


20200201190619120.png

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<std::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<std::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<std::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推送的流程,感兴趣的开发者,可做设计参考。

相关文章
|
6月前
|
Web App开发 流计算 内存技术
安防领域常用的视频流协议介绍
安防领域常用的视频流协议介绍
339 0
|
Web App开发 数据采集 物联网
Android平台基于RTMP或RTSP的一对一音视频互动技术方案探讨
随着智能门禁等物联网产品的普及,越来越多的开发者对音视频互动体验提出了更高的要求。目前市面上大多一对一互动都是基于WebRTC,优点不再赘述,我们这里先说说可能需要面临的问题:WebRTC的服务器部署非常复杂,可以私有部署,但是非常复杂。传输基于UDP,很难保证传输质量,由于UDP是不可靠的传输协议,在复杂的公网网络环境下,各种突发流量、偶尔的传输错误、网络抖动、超时等等都会引起丢包异常,都会在一定程度上影响音视频通信的质量,难以应对复杂的互联网环境,如跨区跨运营商、低带宽、高丢包等场景,行话说的好:从demo到实用,中间还差1万个WebRTC。
150 0
|
编解码 网络协议 安全
一文看懂音视频流媒体协议及信令技术
音视频通信完整流程有如下几个环节:采集、编码、前后处理、传输、解码、缓冲、渲染等。 每一个细分环节,还有更细分的技术模块。比如,前后处理环节有美颜、滤镜、回声消除、噪声抑制等,采集有麦克风阵列等,编解码有H.263,H.264、H.265等,传输就涉及到了本文重点介绍的RTSP/RTMP/RTP/RTCP等流媒体协议以及相关的信令技术。
一文看懂音视频流媒体协议及信令技术
|
Linux 数据安全/隐私保护 Windows
音视频开发:大华摄像头配置RTSP与RTMP地址访问视频画面
音视频开发:大华摄像头配置RTSP与RTMP地址访问视频画面
3341 0
音视频开发:大华摄像头配置RTSP与RTMP地址访问视频画面
|
Web App开发 编解码 算法
发现一个非常好用的RTC(实时音视频通信)方案,做直播和视频通话都很牛
HaaS RTC是阿里云IoT联合视频云开发的IoT设备端上的实时通讯服务,主要面向直播,音视频通话等各种场景。
2216 0
发现一个非常好用的RTC(实时音视频通信)方案,做直播和视频通话都很牛
|
2月前
|
Web App开发 网络协议 Android开发
Android平台一对一音视频通话方案大比拼:WebRTC VS RTMP VS RTSP,谁才是王者?
【9月更文挑战第4天】本文详细对比了在Android平台上实现一对一音视频通话时常用的WebRTC、RTMP及RTSP三种技术方案。从技术原理、性能表现与开发难度等方面进行了深入分析,并提供了示例代码。WebRTC适合追求低延迟和高质量的场景,但开发成本较高;RTMP和RTSP则在简化开发流程的同时仍能保持较好的传输效果,适用于不同需求的应用场景。
155 1
|
2月前
|
XML 编解码 开发工具
多路RTSP转RTMP推送方案的两个选择
RTSP转RTMP模块设计,可以用ffmpeg直接命令行转发,也可以用方案二的非常成熟的转发设计,ffmpeg转发,需要有一定的代码基础,有问题的话,bug修复需要对底层逻辑非常了解才行,方案二,技术成熟,二次开发难度不大,很容易集成到自己现有系统
|
3月前
|
数据采集 编解码 开发工具
Android平台实现无纸化同屏并推送RTMP或轻量级RTSP服务(毫秒级延迟)
一个好的无纸化同屏系统,需要考虑的有整体组网、分辨率、码率、实时延迟、音视频同步和连续性等各个指标,做容易,做好难
|
3月前
|
编解码 开发工具 Android开发
Android平台RTMP直播推送模块技术接入说明
大牛直播SDK跨平台RTMP直播推送模块,始于2015年,支持Windows、Linux(x64_64架构|aarch64)、Android、iOS平台,支持采集推送摄像头、屏幕、麦克风、扬声器、编码前、编码后数据对接,功能强大,性能优异,配合大牛直播SDK的SmartPlayer播放器,轻松实现毫秒级的延迟体验,满足大多数行业的使用场景。RTMP直播推送模块数据源,支持编码前、编码后数据对接
|
6月前
|
编解码 移动开发 C++
RTMP协议深度解析:从原理到实践,掌握实时流媒体传输技术
RTMP协议深度解析:从原理到实践,掌握实时流媒体传输技术
1203 0
RTMP协议深度解析:从原理到实践,掌握实时流媒体传输技术