FFMPEG之编码实现RTMP循环推流(附带av_interleaved_write_frame返回-22处理)04

FFMPEG之编码实现RTMP循环推流(附带av_interleaved_write_frame返回-22处理)

前言

本篇是参考雷神的推流进行二次处理的,可以参考雷神这篇博客。[最简单的基于FFmpeg的推流器(以推送RTMP为例)](https://blog.csdn.net/leixiaohua1020/article/details/39803457)。

为了防止遗忘,在此记录下来当时做题的过程。我当时实现这个功能的时候,确实非常困难,参考的博客不多,而且还被许多博客带偏了。。。前天开始弄,连续两晚通宵达旦,难受。 1)本篇思路是非常简单的,就是每次播放完毕利用av_seek_frame()就将ifmt_ctx往回移即可;然后重新播放。 以下是我遇到的问题 Q1:第一次读完毕后,av_read_frame返回-11,然后再读的时候结果发现pts、dts为很大的负数,无法继续执行; Q2:于是我往着时间戳的方面入手,结果打印pts,dts一看,前一帧的pts=80(假设数据),后一帧的pts=40,这样的话av_write_frame在写帧时就会报错,返回-22;于是我又找,发现雷神调用这两个函数在舍弃小数时会舍弃掉几十秒,造成pts前后帧不是顺序排序,解决就是换成我下面代码的那个函数,两个实际是一样的,只不过我的不会舍弃小数。 解决上面的后,运行结果还是不对,于是我以为是av_seek_frame()的问题,百度搜。。。但是也没有太好的答案,然后随便用一个,去打印了第一次循环播放的前一帧和第二次循环播放的第一帧,结果发现是一样的数据,所以排除了av_seek_frame()的可能,并且这里打印也解决了另一个问题,下面的。 Q3: av_read_frame()读完之后pkt还会留有部分帧数据吗?结果是没有的,因为第二次再读的时候与第一次的第一帧一模一样且帧的总数与用h264分析软件一样。注:读出来的pkt可能是h264的单元NALU或者是AAC的单元ADTS,并且发现av_read_frame自己会在每个NALU前封装四个字节的头。 Q4: 然后重点来了,经过上面一分析,最后就剩下雷神的计算时间方法了,他是先用自增frame_index来控制pts,然后再转为对应的时基,最后用AV_TIME_BASE=100万作单位,这样计算是没什么问题的;但是第二次转换时基的时候,由于100万太大了,所以int型的pts越界了,只有21亿多,而转换时基是大概好像是80多亿我当时测试的时候;所以我就确定是运算出错。所以我不用AV_TIME_BASE作单位,就以本数据段的时基作单位,例如flv的时基为1000,这样就不会导致越界。

Q5:(这个非常重要)
接着上面,然后可是雷神的代码只是针对I帧的,我就查看B帧是如何处理的,很多博客说在av_wrie_frame写帧时dts需要<=pts,结果我被这个误导了好久(也有可能是我做循环不一样的回事吧。。。),因为他确实返回了-22;但实际上是由于上一帧的pts比下一帧的pts大,导致返回-22的;所以我就用这种思想进行编码,一运行结果还是不行。。。别灰心,于是又断点到第二次循环的ptk查看pts和dts,发现原来它每一次读出来都会保留第一次循环本身的pts,s所以就需要每次都用下面的语句确保下一次的时间戳比上一次的大。 总结这个问题:就是要实现循环推流播放,下一次的帧的pts必须大于上一帧的pts,否则写帧时返回-22。

pkt.pts = ptsCon;//确保下一次的显示为上一次的末尾时间戳(可以自己设置循环多少次,防止int时间戳范围越界)
			pkt.dts = dtsCon;
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

`

代码实现

int Circly_Player_Video1() {
   

	//用于指定支持输出的格式
	AVOutputFormat *ofmt = NULL;
	//输入对应一个AVFormatContext,输出对应一个AVFormatContext
	AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
	AVPacket pkt;
	int ret, i;
	int frame_index = 0;

	const char *in_filename, *out_filename;//输入输出文件
										   //in_filename = "testvideo/cuc_ieschool.flv";//输入URL(Input file URL)
	in_filename = "testvideo/中国合伙人.flv";

	//out_filename = "rtp://233.233.233.233:6666";//输出 URL(Output URL)[UDP]
	//out_filename = "rtmp://localhost/vod/mp4:sample1_500kbps.f4v";
	out_filename = "rtmp://192.168.1.202/live/livestream";//输出 URL(Output URL)[RTMP]

	av_register_all();

	//Network
	avformat_network_init();

	//2 读视频
	if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
   
		printf("Could not open input file.");
		goto end;
	}

	//3 获取视频信息
	if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
   
		printf("Failed to retrieve input stream information");
		goto end;
	}
	//printf("tb=%ld\n", ifmt_ctx->streams[0]->time_base); //ifmt_ctx已经初始化, flv时基time_base.den=1000!!!1)

	int videoindex = -1;
	for (i = 0; i<
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值