第5课 使用FFmpeg将rtmp流再转推到rtmp服务器

本课对应源文件下载链接:

https://download.csdn.net/download/XiBuQiuChong/88801992

 通过前面的学习,我们已经可以正常播放网络rtmp流及本地mp4文件。这节课,我们将在前面的基础上实现一个常用的转推功能:读取rtmp流或mp4文件并转推到rtmp服务器上实现直播转发功能。

一、最终实现的效果

上面左图为播放的rtmp流并将该流转推到另一台rtmp服务器,右图为用vlc播放的另一台rtmp服务器上被转发的流。

二、使用FFmpeg将rtmp流转推到另一台rtmp服务器​的原理

使用FFmpeg API 转码推流的一般过程如下:

1.引入ffmpeg库:在代码中引入ffmpeg库,以便使用其提供的功能。

2.打开输入文件:使用avformat_open_input()函数打开输入文件,并获取输入文件的相关信息。

3.查找流信息:使用avformat_find_stream_info()函数查找输入文件中的流信息,并将其存储在AVFormatContext结构体中。

4.创建输出上下文:使用avformat_alloc_output_context2()函数创建输出上下文,并设置输出格式。

5.添加输出流:根据输入文件的流信息,使用avformat_new_stream()函数创建输出流,并将其添加到输出上下文中。

6.设置编码参数:为输出流设置编码参数,包括编码器、编码器参数等。

7.输出文件:使用avio_open()函数打开输出文件,并将输出文件的相关信息存储在输出上下文中。

8.写入文件头:使用avformat_write_header()函数写入输出文件的文件头。

9.转码推流:循环读取输入文件的数据包,使用av_read_frame()函数读取数据包,然后使用avcodec_send_frame()函数发送数据包给编码器进行编码,再使用avcodec_receive_packet()函数接收编码后的数据包,最后使用av_interleaved_write_frame()函数将编码后的数据包写入输出流。

10.写入文件尾:使用av_write_trailer()函数写入输出文件的文件尾。

11.释放资源:释放所有的上下文、流和其他资源,使用avformat_close_input()函数关闭输入文件。

三、转推功能的具体实现

与rtmp流或mp4文件播放功能相比,转推功能只是在原来的基础上又增加了编码功能和向rtmp服务器的推送功能。为了降低难度,这节课的转推功能不涉及编码部分,只实现将拉取来的rtmp流直接进行转推。

1.为了与上节课的播放功能区分,新建或直接复制fmlp(Flash Media Live Player)类为一个新的fmlt(Flash Media Live Transcoder)类,并修改主对话框相应代码使fmlt能正常工作并实现正常的播放功能。

修改如下:

//#include "fmlp.h"
#include "fmlt.h"
………………
//fmlp *myFmlp = new fmlp();
fmlt *myFmlt = new fmlt();

2.与mp4文件相比,rtmp流转推实现起来相对容易,因此,我们先在原来的基础上实现rtmp流的转推功能。

(1)直接拷贝原fmlp.cpp的代码到fmt.cpp中,并定义转推到另一台rtmp服务器的流地址等变量:

//转码输出初始化	
	const char *outFileName = "rtmp://192.168.0.101/hk/cctv";		
	AVOutputFormat *outFormat = NULL;
	AVFormatContext *outFormatCtx = NULL;
	//定义输出音视频流
	AVStream *videoStream = NULL;
	AVStream *audioStream = NULL;

(2)打开输出流:

avformat_alloc_output_context2(&outFormatCtx, NULL, "flv", outFileName);

………………

         videoStream = avformat_new_stream(outFormatCtx, vDecodec);

         videoStream->id = outFormatCtx->nb_streams - 1;

         videoStream->codecpar->codec_tag = 0;

         avcodec_parameters_from_context(videoStream->codecpar, vDecodeCtx);

         audioStream = avformat_new_stream(outFormatCtx, aDecodec);

         audioStream->codecpar->codec_tag = 0;

         audioStream->id = outFormatCtx->nb_streams - 1;

         avcodec_parameters_from_context(audioStream->codecpar, aDecodeCtx);

         av_dump_format(outFormatCtx, 0, outFileName, 1);

         ret = avio_open2(&outFormatCtx->pb, outFileName, AVIO_FLAG_READ_WRITE, nullptr, nullptr);

         if (ret < 0){

                  return -1;

         }

         ret = avformat_write_header(outFormatCtx, NULL);

         if (ret < 0){

                  TRACE("ret:%d\n", ret);

                  return -1;

         }

(3)获取到原rtmp流并正常播放音视频后,将音视频包直接写入输出流:

if (normalPkt.stream_index == videoIndex) {

                          //原视频播放代码

                          normalPkt.stream_index = videoStream->index;

                          normalPkt.pts = currentTime;

                          normalPkt.dts = currentTime;

                          normalPkt.duration = currentTime;

                          normalPkt.pos = -1;

                          //enVideoPacket.flags = AV_PKT_FLAG_KEY;

                          if (normalPkt.size > 0){

                                   ret = av_interleaved_write_frame(outFormatCtx, &normalPkt);

                          }

                          av_packet_unref(&normalPkt);

                  }

                  else if (normalPkt.stream_index == audioIndex)

                  {                       

                          //原音频播放代码

                          normalPkt.stream_index = audioStream->index;

                          normalPkt.pts = currentTime;

                          normalPkt.dts = currentTime;

                          normalPkt.duration = currentTime;

                          normalPkt.pos = -1;

                          //enVideoPacket.flags = AV_PKT_FLAG_KEY;

                          if (normalPkt.size > 0){

                                   ret = av_interleaved_write_frame(outFormatCtx, &normalPkt);

                          }

                          av_packet_unref(&normalPkt);

          }

这样,就实现了在播放音视频的同时又能将该流转推到另一台服务器的功能。

相关推荐

  1. FFMPEGRTMP服务器命令

    2024-02-02 16:04:03       41 阅读
  2. 通过ffmpeg实现rtsp rtmp rtmps

    2024-02-02 16:04:03       58 阅读
  3. ffmpegflvrtmp

    2024-02-02 16:04:03       30 阅读
  4. ffmpeg命令】RTMP

    2024-02-02 16:04:03       21 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-02 16:04:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-02 16:04:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-02-02 16:04:03       82 阅读
  4. Python语言-面向对象

    2024-02-02 16:04:03       91 阅读

热门阅读

  1. 寒假每日练习——搜索

    2024-02-02 16:04:03       47 阅读
  2. LeetCode解法汇总2670. 找出不同元素数目差数组

    2024-02-02 16:04:03       58 阅读
  3. 浅谈 Unix Timestamp 时间戳

    2024-02-02 16:04:03       45 阅读
  4. ORA-65096: 公用用户名或角色名无效

    2024-02-02 16:04:03       46 阅读
  5. Redis为什么快?

    2024-02-02 16:04:03       54 阅读
  6. MySQL中的约束(七)

    2024-02-02 16:04:03       47 阅读
  7. mysql innodb 之 buffer pool

    2024-02-02 16:04:03       44 阅读
  8. HttpSession

    2024-02-02 16:04:03       55 阅读
  9. 零信任安全架构发展趋势

    2024-02-02 16:04:03       50 阅读
  10. go语言-context的基本使用

    2024-02-02 16:04:03       52 阅读
  11. 民安智库开展空气污染治理满意度调研

    2024-02-02 16:04:03       54 阅读
  12. 如何提高Bito生成函数代码的准确度

    2024-02-02 16:04:03       48 阅读