专栏首页用户1692782的专栏协议转换之rtsp转rtmp推流

协议转换之rtsp转rtmp推流

近些年,每一年的风口,几乎都离不开音视频。2020年了,音视频依然很火,只不过是火的领域有所不同,从年初受疫情而爆发的视频会议,到后来为了大力发展网络经济的直播带货!不过呢,本篇我们暂时不讨论这个,咱们聊技术,说到直播,rtmp协议依然是主流!不过呢,音视频中,流媒体协议rtsp也占有很大份额!日常生活呢,我们也会遇到一些不同流媒体协议转换的问题!本篇记录实现一个rtsp转rtmp直播流的程序!闲言少叙,接下来置入主题。

需求

有一个摄像头,比如海康的监控摄像头,可以通过rtsp流的方式访问其视频画面!需要将其画面转换为rtmp协议,并实现直播!

实现思路

我们的程序,称之为rtsp2rtmp,使用该程序实现拉取摄像头rtsp视频流,并将rtmp视频流转换为rtmp视频流,然后推送到直播服务器,直播服务器采用nginx+rtmp_module的方式实现,环境搭建的步骤可以参考之前的文章:搭一个简单的直播平台,嗨起来

rtsp2rtmp,使用FFmpeg API来实现!

准备工作

  • visual studio(笔者使用vs2019)
  • FFmpeg sdk: 下载下载地址:
https://ffmpeg.zeranoe.com/builds/

具体实现步骤

  • 打开输入流上下文
  //av_register_all();
  avformat_network_init();


  m_strRtspUrl = rtspUrl;
  m_strRtmpUrl = rtmpUrl;

  m_pRtspAVFormatContext = NULL;
  m_nRet = 0;

  m_nVideoIndex = -1;
  m_nAudioIndex = -1;
  
  memset(errBuf, 0, 1024);

  // 1. 申请输出流上下文
  m_pRtmpAVFormatContext = NULL;
  avformat_alloc_output_context2(&m_pRtmpAVFormatContext, NULL, "flv", m_strRtmpUrl.c_str());
  if (!m_pRtmpAVFormatContext)
  {
    std::cout << "avformat_alloc_output_contex2 failed!" << std::endl;
    return false;
  }
  std::cout << "[" << m_strRtmpUrl.c_str() << "] avformat_alloc_output_context2 success " << std::endl;

  //1.打开输入流
  m_nRet = avformat_open_input(&m_pRtspAVFormatContext, m_strRtspUrl.c_str(), 0, 0);
  if (m_nRet != 0)
  {
    std::cout << "open " << m_strRtspUrl.c_str() << "error!" << std::endl;
    return m_nRet;
  }
  std::cout << "open " << m_strRtspUrl.c_str() << "success !" << std::endl;

  // 2.获得流信息
  m_nRet = avformat_find_stream_info(m_pRtspAVFormatContext, 0);
  if (m_nRet < 0)
  {
    std::cout << "avformat_find_stream_info failed" << std::endl;
    return m_nRet;
  }

  std::cout << "avformat_find_stream_info success" << std::endl;
  av_dump_format(m_pRtspAVFormatContext, 0, m_strRtspUrl.c_str(),0);



  for (int i = 0; i < m_pRtspAVFormatContext->nb_streams; i++)
  {
    if (m_pRtspAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) 
    {
      m_nVideoIndex = i;
    }

    if (m_pRtspAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) 
    { 
      m_nAudioIndex = i;
    }
  }

  • 打开输出流上下文
  //3. 申请输出AVStream(rtmp)
  const AVCodec* outCodec = avcodec_find_decoder(m_pRtspAVFormatContext->streams[m_nVideoIndex]->codecpar->codec_id);
  m_pRtmpAVStream = avformat_new_stream(m_pRtmpAVFormatContext, outCodec);
  if (!m_pRtmpAVStream)
  {
    std::cout << "[rtmp] Failed allocating output stream!" << std::endl;
    return m_nRet;
  }

  std::cout << "[rtmp] avformat_new_stream success!" << std::endl;

  //4. stream信息复制
  AVCodecContext* rtmpOutCodec = avcodec_alloc_context3(outCodec);

  m_nRet = avcodec_parameters_to_context(rtmpOutCodec, m_pRtspAVFormatContext->streams[m_nVideoIndex]->codecpar);
  if (m_nRet < 0)
  {
    std::cout << "[rtmp] avcodec_paramertes_to_context failed " << std::endl;
    return m_nRet;
  }
  std::cout << "[rtmp] avcodec_paramertes_to_context success" << std::endl;

  m_nRet = avcodec_parameters_from_context(m_pRtmpAVStream->codecpar, rtmpOutCodec);
  if (m_nRet < 0)
  {
    std::cout << "[rtmp] avcodec_parameters_from_context failed";
    return m_nRet;
  }


  if (!(m_pRtmpAVFormatContext->flags & AVFMT_NOFILE)) {
    m_nRet = avio_open2(&m_pRtmpAVFormatContext->pb, m_strRtmpUrl.c_str(), AVIO_FLAG_WRITE, NULL, NULL);
    if (m_nRet < 0) {
      av_strerror(m_nRet, errBuf, 1024);
      //std::cout << "avio_open2 failed: " << errBuf << std::endl;
      printf("avio_open2 failed: %s\n", errBuf);
      return m_nRet;
    }
  }


  //5. 写rtmp头信息
  m_nRet = avformat_write_header(m_pRtmpAVFormatContext, NULL);
  if (m_nRet < 0)
  {
    std::cout << "[rtmp] avformat_write_header failed" << std::endl;

    av_strerror(m_nRet, errBuf, 1024);
    printf("errBuf: %s\n", errBuf);
    //std::cout << err << std::endl;
    return m_nRet;
  }

  std::cout << "[rtmp] avformat_write_header success!" << std::endl;
  • 读取输入流
    m_nRet = av_read_frame(m_pRtspAVFormatContext, &pkt);
    if (m_nRet < 0)
    {
      break;
    }
  • 写入输出流
    rtspStream = m_pRtspAVFormatContext->streams[pkt.stream_index];
    rtmpStream = m_pRtmpAVFormatContext->streams[pkt.stream_index];

    pkt.pts = av_rescale_q_rnd(pkt.pts, rtspStream->time_base, rtmpStream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
    pkt.dts = av_rescale_q_rnd(pkt.dts, rtspStream->time_base, rtmpStream->time_base, AVRounding(AV_ROUND_NEAR_INF |AV_ROUND_PASS_MINMAX));
    pkt.duration = av_rescale_q(pkt.duration, rtspStream->time_base, rtmpStream->time_base);

    pkt.pos = -1;
    m_nRet = av_interleaved_write_frame(m_pRtmpAVFormatContext, &pkt);
    if (m_nRet < 0)
    {
      break;
    }
    av_packet_unref(&pkt);

github传送门

https://github.com/mlfcjob/Rtsp2Rtmp.git

欢迎star,欢迎使用修改和提交!

本文分享自微信公众号 - 视界音你而不同(WorldOfVideoAndAudio),作者:马龙飞

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • RTSP协议转换RTMP直播协议

      RTSP协议也是广泛使用的直播/点播流媒体协议,以前的项目里实现了一个RTSP协议转换RTMP直播协议的程序,为的是可以接收远端设备或服务器的多路RTSP直...

    hbstream
  • 视频流媒体服务器RTSP拉流、RTMP推流方案之EasyNVR、EasyGBS、EasyDSS三者相似点及区别分析

    众所周知,EasyNVR可以将局域网/广域网上的海康/大华等网络摄像头由rtsp转换为rtmp、rtsp、hls、flv协议转换,并提供推流服务,可以将拉到的网...

    EasyNVR
  • 视沃科技-大牛直播SDK

    本文转载自https://github.com/daniulive/SmarterStreaming

    ccf19881030
  • 工具系列 | 视频监控RTSP转HLS解决方案

    由于公司业务,需要实现基于WEB访问监控摄像头实时流的预览,经过各种百度,补充了不少相关知识,了解到了很多大神的实现方法,也因为很多过时的帖子,而踩了不少的坑。

    Tinywan
  • EasyRTMP推流助力EasyNVR安防摄像机互联网化,实现核心的RTSP流转RTMP/HLS(m3u8)/HTTP-FLV流功能

    今天,我们着重讲解的是视频输出中的RTMP推流功能,这也是我们EasyNVR功能组件中,最为重要的一个组成部分! EasyRTMP是一套封装了基础的RTMP推...

    EasyNVR
  • 监控摄像头RTSP协议对接腾讯云直播

    传统监控高清摄像机ip camera(如: 海康,大华等)遵循监控行业标准,一般只支持rtsp传输协议,互联网直播通用标准为rtmp协议,将这些摄像机视频流引入...

    tylerliu
  • 如何使用流媒体接入网关实现拉RTSP流转推RTMP流到流媒体服务器?

    我们团队有一款完善的流媒体接入软件网关EasyRTMPLive,即软件编码器,可以实现将RTSP、RTMP、HTTP、HLS等各种各样的网络流媒体先拉取到本地,...

    EasyNVR
  • RTSP?不存在的 -> 前端实时流探索记

    传送门:https://segmentfault.com/a/1190000022994032

    ConardLi
  • RTMP推流网关如何实现摄像头微信幼儿园直播?

    网关(Gateway)又称网间连接器、协议转换器。网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互...

    EasyNVR

扫码关注云+社区

领取腾讯云代金券