跨平台低延迟RTSP转RTMP推送技术方案探讨

简介: 实现RTSP摄像头数据转RTMP推送到服务器,可以用第三方库或者工具实现,总体设计架构如下:

实现RTSP摄像头数据转RTMP推送到服务器,可以用第三方库或者工具实现,总体设计架构如下:

cf21cae503594363b34d82dcbbd67c03.png

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


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服务器。


下面分别介绍下两种技术方案:

FFmpeg技术方案

  1. 安装FFmpeg:首先,您需要安装FFmpeg。FFmpeg是一个开源的跨平台视频和音频处理工具,它支持将RTSP流转换为RTMP流。您可以从FFmpeg官方网站下载适用于Windows的二进制安装程序,并按照说明进行安装。
  2. 配置FFmpeg:安装完FFmpeg后,您需要配置其命令行参数,以便将RTSP流转换为RTMP流,并将其推送到目标服务器。您可以使用以下命令行参数:
 ffmpeg -i rtsp://[摄像头地址]/[流媒体地址] -f flv rtmp://[服务器地址]/[直播频道]

其中,rtsp://[摄像头地址]/[流媒体地址]是摄像头的RTSP流地址,rtmp://[服务器地址]/[直播频道]是目标服务器的RTMP流地址。您可以根据实际情况修改这些参数。


1.运行FFmpeg:配置完FFmpeg后,您可以使用命令行或脚本文件来运行FFmpeg。您可以在命令行中直接运行上述命令,或者将命令写入脚本文件(例如bat文件),然后运行脚本文件。需要注意的是,上述方案中的摄像头地址、流媒体地址、服务器地址和直播频道都需要替换为实际的地址和信息。此外,您还需要确保摄像头的RTSP流可公开访问,并且目标服务器的RTMP流地址已经配置正确。


2.集成到应用程序中:如果您需要在应用程序中实现实时视频流推送,您可以将FFmpeg集成到应用程序中。您可以使用FFmpeg的API或命令行接口,通过编程方式调用FFmpeg的功能,并将摄像头的RTSP流转换为RTMP流,并将其推送到目标服务器。

SDK技术方案

以大牛直播SDK的Windows平台RTSP转RTMP推送C++的demo为例:


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;
  }
  if ( NT_ERC_OK != push_api_->StartPublisher(push_handle, NULL) )
  {
    if ( !is_started_rtsp_stream_ )
    {
      push_api_->Close(push_handle);
      SetPushHandle(nullptr);
    }
    return false;
  }
  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_);
  if ( !is_started_rtsp_stream_ )
  {
    push_api_->Close(push_handle_);
    push_handle_ = nullptr;
  }
}

总结

无论您选择哪种方案,需要确保以下几点:


  1. 选择一个稳定可靠的第三方库或服务,以确保转换的质量和可靠性;
  2. 了解和掌握相关的技术和协议,例如RTSP和RTMP,以及如何使用相关的库和工具进行转换和处理;
  3. 考虑性能和资源的问题,特别是在处理大量视频流或高并发的场景下。需要确保系统具有足够的处理能力和带宽,以避免延迟或丢帧等问题。


Windows平台上的RTSP转RTMP推送需要一些技术准备和规划,以及对相关协议和工具的理解和使用经验,做个基础的demo,用FFmpeg就可以,但是如果产品话,需要考虑的点实在太多了。

相关文章
|
4月前
|
网络协议 Linux
音视频学习之rtsp推拉流学习2(流媒体服务器ZLMediaKit)
音视频学习之rtsp推拉流学习2(流媒体服务器ZLMediaKit)
209 0
|
7月前
|
Web App开发 数据采集 物联网
Android平台基于RTMP或RTSP的一对一音视频互动技术方案探讨
随着智能门禁等物联网产品的普及,越来越多的开发者对音视频互动体验提出了更高的要求。目前市面上大多一对一互动都是基于WebRTC,优点不再赘述,我们这里先说说可能需要面临的问题:WebRTC的服务器部署非常复杂,可以私有部署,但是非常复杂。传输基于UDP,很难保证传输质量,由于UDP是不可靠的传输协议,在复杂的公网网络环境下,各种突发流量、偶尔的传输错误、网络抖动、超时等等都会引起丢包异常,都会在一定程度上影响音视频通信的质量,难以应对复杂的互联网环境,如跨区跨运营商、低带宽、高丢包等场景,行话说的好:从demo到实用,中间还差1万个WebRTC。
|
3月前
|
数据采集 编解码 图形学
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
108 0
|
7月前
|
编解码 网络协议 开发工具
跨平台低延迟的RTMP/RTSP直播播放器设计实现
2015年,当我们试图在市面上找一款专供直播播放使用的低延迟播放器,来配合测试我们的RTMP推送模块使用时,居然发现没有一款好用的,市面上的,如VLC或Vitamio,说白了都是基于FFMPEG,在点播这块支持格式很多,也非常优异,但是直播这块,特别是RTMP,延迟要几秒钟,对如纯音频、纯视频播放,快速启播、网络异常状态处理、集成复杂度等各方面,支持非常差,而且因为功能强大,bug很多,除了行业内资深的开发者能驾驭,好多开发者甚至连编译整体环境,都要耗费很大的精力。
258 0
|
7月前
|
图形学 开发者 Windows
Unity平台如何实现RTSP转RTMP推送?
Unity平台下,RTSP、RTMP播放和RTMP推送,甚至包括轻量级RTSP服务这块都不再赘述,今天探讨的一位开发者提到的问题,如果在Unity下,实现RTSP播放的同时,随时转RTMP推送出去?
|
7月前
|
编解码 开发工具 图形学
Unity环境下RTMP推流+RTMP播放低延迟解决方案
在本文之前,我们发布了Unity环境下的RTMP推流(Windows平台+Android平台)和RTMP|RTSP拉流(Windows平台+Android平台+iOS平台)低延迟的解决方案,今天做个整体汇总,权当抛砖引玉。
446 0
|
7月前
|
Linux 图形学 Android开发
Unity3D下如何实现跨平台低延迟的RTMP、RTSP播放
好多开发者,希望我们能探讨下Unity平台RTMP或RTSP直播流数据播放和录制相关的模块,实际上,这块流程我们已经聊过多次,无非就是通过原生的RTMP或者RTSP模块,先从协议层拉取到数据,并解包解码,回调YUV或RGB数据,然后,在Unity创建响应的shader,获取图像数据填充纹理即可,说起来流程很简单,但是每个环节,如果做到极致体验,都非常难。简单来说,多一次拷贝,都会增大性能瓶颈或延迟。
|
7月前
|
存储 开发工具 Android开发
如何实现Android端获取RTSP|RTMP流转推RTMP
技术背景 最近不少开发者找到我们,他们在做智能家居等传统行业时,希望实现在Android板件拉取本地的RTSP或RTMP流,然后对外推送RTMP出去,亦或内部启个轻量级RTSP服务,提供个对外对接的媒介URL,简单来说,设计架构图如下:
443 0
|
7月前
|
Web App开发 开发工具 Android开发
利用RTMP或RTSP实现跨平台一对一互动功能
目前市面上大多一对一互动都是基于WebRTC,缺点如下: 1. 服务器部署非常复杂,不利于私有部署,在一些私密性高的场景下,无法使用,如公安、市政等体系; 2. 传输基于UDP,很难保证传输质量,由于UDP是不可靠的传输协议,在复杂的公网网络环境下,各种突发流量、偶尔的传输错误、网络抖动、超时等等都会引起丢包异常,都会在一定程度上影响音视频通信的质量; 3. 难以应对复杂的互联网环境,如跨区跨运营商、低带宽、高丢包等场景; 4. 整个框架体系不够灵活,代码复杂度高,行话说的好:从demo到实用,中间还差1万个WebRTC。
|
7月前
|
开发工具 图形学 Android开发
如何在Unity3d平台下低延迟播放RTMP或RTSP流
随着VR类、工业仿真、智慧城市等场景的快速发展,开发者对Unity3d低延迟的直播需求量越来越大,前两年,大牛直播SDK发布了Windows平台、Android平台和iOS平台的Unity3d RTMP和RTSP的播放,好多公司用起来体验都非常好,以下介绍大概实现流程。
111 0

热门文章

最新文章