FFmpeg5.0.1 代码读取MP4视频推送RTMP流

当下代码在FfmpegTest类创建实例时调用

可根据实际情况在main()函数中调用videoPlay(pszFile, pszRTMPURL)。

源代码分享

#include "ffmpegtest.h"
#include <iostream>
#include <QDebug>

using namespace std;

extern "C" {
#include <libavcodec/avcodec.h>
#include "libavformat/avformat.h"
#include "libavutil/time.h"
}

#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")

void XError(int errNum)
{
	char buf[1024] = { 0 };
	av_strerror(errNum, buf, sizeof(buf));
	cout << buf << endl;
	getchar();
}
static double r2d(AVRational r)
{
	return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
}

FfmpegTest::FfmpegTest(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
    //主函数调用部分
	const char* pszFile = "D:/work/Ffmpeg/ffmpeg_code/guduyueqiu.mp4";
	const char* pszRTMPURL = "rtmp://192.168.3.10/live/livestream";
	videoPlay(pszFile, pszRTMPURL);
}
void FfmpegTest::videoPlay(const char* pszFile, const char* pszRTMPURL)
{
	int nVideoIndex = -1;
	avformat_network_init();

	AVFormatContext* pInputAVFormatContext = NULL;
	int nRet = avformat_open_input(&pInputAVFormatContext, pszFile, 0, NULL);
	if (nRet < 0)
	{
		XError(nRet);
	}
	nRet = avformat_find_stream_info(pInputAVFormatContext, 0);
	if (nRet != 0)
	{
		XError(nRet);
	}
	av_dump_format(pInputAVFormatContext, 0, pszFile, 0);
	AVFormatContext* pOutputAVFormatContext = NULL;
	nRet = avformat_alloc_output_context2(&pOutputAVFormatContext, NULL, "flv", pszRTMPURL);
	if (nRet < 0)
	{
		XError(nRet);
	}

	for (int i = 0; i < pInputAVFormatContext->nb_streams; i++)
	{
		AVStream* pInputAVStream = pInputAVFormatContext->streams[i];
		AVStream* pOutputAVStream = avformat_new_stream(pOutputAVFormatContext, 0);
		nRet = avcodec_parameters_copy(pOutputAVStream->codecpar, pInputAVStream->codecpar);
		if (nRet < 0)
		{
			XError(nRet);
		}
		pOutputAVStream->codecpar->codec_tag = 0;
	}
	for (int i = 0; i < pInputAVFormatContext->nb_streams; i++)
	{
		if (pInputAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			nVideoIndex = i;
			break;
		}
	}
	av_dump_format(pOutputAVFormatContext, 0, pszRTMPURL, 1);
	nRet = avio_open(&pOutputAVFormatContext->pb, pszRTMPURL, AVIO_FLAG_WRITE);
	if (nRet < 0)
	{
		XError(nRet);
	}
	nRet = avformat_write_header(pOutputAVFormatContext, 0);
	if (nRet < 0)
	{
		XError(nRet);
	}
	AVPacket pkt;
	std::int64_t llStartTime = av_gettime();
	std::int64_t llFrameIndex = 0;
	while (true)
	{
		AVStream* pInputStream = NULL;
		AVStream* pOutputStream = NULL;
		nRet = av_read_frame(pInputAVFormatContext, &pkt);
		if (nRet < 0)
		{
			break;
		}
		if (pkt.pts == AV_NOPTS_VALUE)
		{
			AVRational timeBase = pInputAVFormatContext->streams[nVideoIndex]->time_base;
			std::int64_t llCalcDuration = (double)AV_TIME_BASE / av_q2d(pInputAVFormatContext->streams[nVideoIndex]->r_frame_rate);
			pkt.pts = (double)(llFrameIndex * llCalcDuration) / (double(av_q2d(timeBase)*AV_TIME_BASE));
			pkt.dts = pkt.pts;
			pkt.duration = (double)llCalcDuration / (double)(av_q2d(timeBase)*AV_TIME_BASE);
		}
		if (pkt.stream_index == nVideoIndex)
		{
			AVRational timeBase = pInputAVFormatContext->streams[nVideoIndex]->time_base;
			AVRational timeBaseQ = { 1, AV_TIME_BASE };
			std::int64_t pts_time = av_rescale_q(pkt.dts, timeBase, timeBaseQ);
			std::int64_t now_time = av_gettime() - llStartTime;
			AVRational avr = pInputAVFormatContext->streams[nVideoIndex]->time_base;
			if (pts_time > now_time)
			{
				av_usleep((unsigned int)(pts_time - now_time));
			}
		}
		pInputStream = pInputAVFormatContext->streams[pkt.stream_index];
		pOutputStream = pOutputAVFormatContext->streams[pkt.stream_index];
		pkt.pts = av_rescale_q_rnd(pkt.pts, pInputStream->time_base, pOutputStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		pkt.dts = av_rescale_q_rnd(pkt.dts, pInputStream->time_base, pOutputStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		pkt.duration = (int)av_rescale_q(pkt.duration, pInputStream->time_base, pOutputStream->time_base);
		pkt.pos = -1;
		if (pkt.stream_index == nVideoIndex)
		{
			llFrameIndex++;
		}
		nRet = av_interleaved_write_frame(pOutputAVFormatContext, &pkt);
		if (nRet < 0) {
			std::cout << "发送数据包出错" << std::endl;
			break;
		}
		av_packet_unref(&pkt);
	}
	av_write_trailer(pOutputAVFormatContext);
	if (!(pOutputAVFormatContext->oformat->flags & AVFMT_NOFILE))
	{
		avio_close(pOutputAVFormatContext->pb);
	}
	avformat_free_context(pOutputAVFormatContext);
	avformat_close_input(&pInputAVFormatContext);
}

效果展示

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leonban

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值