音视频BUG学习

这篇具有很好参考价值的文章主要介绍了音视频BUG学习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

找Bug流程

1、首先看出现概率是偶现还是必现
2、如果是必现,则复现整个bug过程,看Bug是否出现
如果是偶现,则分析问题视频

问题一 【欧立】【远程抓拍】安卓-远程抓拍的视频,下载到手机本地相册,声音慢放

一、额外知识学习

在复现问题过程中,刚开始没下载到本地,直接点击播放发生慢放,因为流量网速较低,15s,40Mb 平均网速要超过2.7Mb/s,因此误以为复现了bug

二、解决过程

0 问题复现

找设备抓拍,下载,发现视频没有问题,Bug无法复现

0 简单分析

分析源文件
音视频BUG学习

可能在本地转码过程(转码过程可能发生在本地也可能发生在服务器端)中 数据丢失,也可能是ADTS头部,通道数自动转换

1 mp4文件提取出h264/h265

播放没问题

ffmpeg -i test.mp4 -map 0:v:1 -c:v copy video.h264
ffmpeg -i test.mp4 -map 0:v:0 -c:v copy video.h265

-i test.mp4: 指定输入文件为 test.mp4。-i 是指定输入文件的选项,后面跟着输入文件的路径。
-map 0:v:0: 使用 -map 选项选择输入文件中的第一个视频流。0 表示第一个输入文件,v 表示视频流,0 表示第一个视频流。
-c:v copy: 使用 -c:v 选项指定视频流的编码方式为 “copy”,表示直接复制视频流而不进行重新编码。这意味着输出文件将与输入文件的视频流完全相同,不会更改编码格式或参数。

2 mp4文件中提取aac

ffmpeg -i test1.mp4 -vn -acodec copy test1.aac

3 aac转码为pcm

ffmpeg -i BadAAC.aac -acodec pcm_s16le -ar 32000 -f s16le Bad.pcm

4 分析pcm

音视频BUG学习

数据被置0,正常应该是较为连续的
因为是必现,估计是pcm数据拷贝,长度计算不对,只拷贝了一半数据,剩下的一半是内存中初始化的0值

三、解决方案

无法复现Bug,Bug已不存在

问题二 【欧立】【本地录像】本地视频偶现轻微花屏

一、额外知识学习

花屏出现可能原因

(1)丢帧会报错

模拟过程,在aac和h264复用为mp4的过程中,故意丢没100帧丢一帧,用ffplay播放出现报错

复用代码
#include <stdio.h>
#include <iostream>
extern "C"
{
#include "libavformat/avformat.h"
};

int main(int argc, char* argv[])
{
	AVFormatContext* ifmtCtxVideo = NULL, * ifmtCtxAudio = NULL, * ofmtCtx = NULL;
	AVCodecContext* video_ctx = NULL;
	AVPacket packet;
	AVCodec* video_codec = NULL;
	//AVBSFContext* bsf_ctx = nullptr;
	const AVBitStreamFilter* pfilter = av_bsf_get_by_name("h264_mp4toannexb");
	AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
	//av_bsf_alloc(pfilter, &bsf_ctx);

	int inVideoIndex = -1, inAudioIndex = -1;
	int outVideoIndex = -1, outAudioIndex = -1;

	int audioindex = 0;
	int videoindex = 0;
	int idx = 0;
	
	int64_t curPstVideo = 0, curPstAudio = 0;

	int ret = 0;
	unsigned int i = 0;

	const char* inFilenameVideo = "Titanic.h264";
	const char* inFilenameAudio = "Titanic.aac";
	const char* outFilename = "MissFrame.mp4";

	//打开输入视频文件
	ret = avformat_open_input(&ifmtCtxVideo, inFilenameVideo, 0, 0);
	if (ret < 0)
	{
		printf("can't open input video file\n");
		goto end;
	}

	//查找输入流
	ret = avformat_find_stream_info(ifmtCtxVideo, 0);
	if (ret < 0)
	{
		printf("failed to retrieve input video stream information\n");
		goto end;
	}

	//打开输入音频文件
	ret = avformat_open_input(&ifmtCtxAudio, inFilenameAudio, 0, 0);
	if (ret < 0)
	{
		printf("can't open input audio file\n");
		goto end;
	}

	//查找输入流
	ret = avformat_find_stream_info(ifmtCtxAudio, 0);
	if (ret < 0)
	{
		printf("failed to retrieve input audio stream information\n");
		goto end;
	}

	printf("===========Input Information==========\n");
	av_dump_format(ifmtCtxVideo, 0, inFilenameVideo, 0);
	av_dump_format(ifmtCtxAudio, 0, inFilenameAudio, 0);
	printf("======================================\n");

	//新建输出上下文
	avformat_alloc_output_context2(&ofmtCtx, NULL, NULL, outFilename);
	if (!ofmtCtx)
	{
		printf("can't create output context\n");
		goto end;
	}

	//视频输入流
	for (i = 0; i < ifmtCtxVideo->nb_streams; ++i)
	{
		if (ifmtCtxVideo->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			AVStream* inStream = ifmtCtxVideo->streams[i];
			AVStream* outStream = avformat_new_stream(ofmtCtx, NULL);
			//av_dump_format(ofmtCtx, 0, outFilename, 1);
			inVideoIndex = i;

			if (!outStream)
			{
				printf("failed to allocate output stream\n");
				goto end;
			}

			outVideoIndex = outStream->index;

			if (avcodec_parameters_copy(outStream->codecpar, inStream->codecpar) < 0)
			{
				printf("faild to copy context from input to output stream");
				goto end;
			}

			outStream->codecpar->codec_tag = 0;
			//av_dump_format(ofmtCtx, 0, outFilename, 1);
			break;
		}
	}
	video_ctx = avcodec_alloc_context3(video_codec);
	video_codec = avcodec_find_decoder(ifmtCtxVideo->streams[0]->codecpar->codec_id);

	video_ctx = ifmtCtxVideo->streams[0]->codec;
	//音频输入流
	for (i = 0; i < ifmtCtxAudio->nb_streams; ++i)
	{
		if (ifmtCtxAudio->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			AVStream* inStream = ifmtCtxAudio->streams[i];
			AVStream* outStream = avformat_new_stream(ofmtCtx, NULL);
			inAudioIndex = i;

			if (!outStream)
			{
				printf("failed to allocate output stream\n");
				goto end;
			}

			if (avcodec_parameters_copy(outStream->codecpar, inStream->codecpar) < 0)
			{
				printf("faild to copy context from input to output stream");
				goto end;
			}
			outAudioIndex = outStream->index;

			break;
		}
	}

	printf("==========Output Information==========\n");
	av_dump_format(ofmtCtx, 0, outFilename, 1);
	printf("======================================\n");
	//打开输入文件
	if (!(ofmtCtx->oformat->flags & AVFMT_NOFILE))
	{
		if (avio_open(&ofmtCtx->pb, outFilename, AVIO_FLAG_WRITE) < 0)
		{
			printf("can't open out file\n");
			goto end;
		}
	}

	//写文件头
	if (avformat_write_header(ofmtCtx, NULL) < 0)
	{
		printf("Error occurred when opening output file\n");
		goto end;
	}

	while (1)
	{
		AVFormatContext* ifmtCtx = NULL;
		AVStream* inStream, * outStream;
		int streamIndex = 0;
		if (av_compare_ts(curPstVideo, ifmtCtxVideo->streams[inVideoIndex]->time_base, curPstAudio, ifmtCtxAudio->streams[inAudioIndex]->time_base) < 0)
		{
			ifmtCtx = ifmtCtxVideo;
			streamIndex = outVideoIndex;

			if (av_read_frame(ifmtCtx, &packet) >= 0)
			{
				//printf("Video start packet.pts = %d \n\n", packet.pts);
				inStream = ifmtCtx->streams[packet.stream_index];
				//printf("Video sample_rate = %\n", inStream->codecpar->sample_rate);
				outStream = ofmtCtx->streams[streamIndex];
				if (packet.stream_index == inVideoIndex)
				{
					av_bitstream_filter_filter(h264bsfc, ifmtCtxVideo->streams[0]->codec, NULL, &packet.data, &packet.size, packet.data, packet.size, 0);
					// Fix: No PTS(Example: Raw H.264
					// Simple Write PTS
					//printf("Video PTS: %ld\n", packet.pts);
					//printf("Video DTS: %ld\n", packet.dts);
					if (packet.pts == AV_NOPTS_VALUE)
					{
						//write PTS
						AVRational timeBase1 = inStream->time_base;
						//Duration between 2 frames
						double calcDuration = (double)1.0 / av_q2d(inStream->r_frame_rate);
						//Parameters 转化为
						//printf("Video calcDuration =  %lf\n", calcDuration);
						packet.pts = (double)(videoindex * calcDuration) / (double)(av_q2d(timeBase1));
						packet.dts = packet.pts;
						packet.duration = (double)calcDuration / (double)(av_q2d(timeBase1));
						videoindex++;
						//printf("Video PTS: %ld\n", packet.pts);
						//printf("Video DTS: %ld\n", packet.dts);
					}
					curPstVideo = packet.pts;
				}
			}
			else
			{
				break;
			}
		}
		else
		{
			ifmtCtx = ifmtCtxAudio;
			streamIndex = outAudioIndex;
			if (av_read_frame(ifmtCtx, &packet) >= 0)
			{
				//printf("Audio start packet.pts = %d \n\n", packet.pts);
				inStream = ifmtCtx->streams[packet.stream_index];
				outStream = ofmtCtx->streams[streamIndex];
				//printf("Audio PTS: %ld\n", packet.pts);
				//printf("Audio DTS: %ld\n", packet.dts);
				if (packet.stream_index == inAudioIndex)
				{
					//Fix: No PTS(Example: Raw H.264
					//Simple Write PTS
					AVRational timeBase1 = inStream->time_base;
					//printf("timeBase = %.15lf\n", (double)(av_q2d(timeBase1)));
					//Duration between 2 frames

					double calcDuration =  (double)1024.0 / inStream->codecpar->sample_rate;
					//printf("Audio calcDuration =  %lf\n", calcDuration);
					packet.pts = (double)(audioindex * calcDuration) / (double)(av_q2d(timeBase1));
					packet.dts = packet.pts;
					packet.duration = (double)calcDuration / (double)(av_q2d(timeBase1));
					audioindex ++;
					//printf("Audio PTS: %ld\n", packet.pts);
					//printf("Audio DTS: %ld\n", packet.dts);
					curPstAudio = packet.pts;
				}
			}
			else
			{
				break;
			}
		}
		//FIX:Bitstream Filter

		//Convert PTS/DTS
		packet.pts = av_rescale_q_rnd(packet.pts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		packet.dts = av_rescale_q_rnd(packet.dts, inStream->time_base, outStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
		packet.duration = av_rescale_q(packet.duration, inStream->time_base, outStream->time_base);
		packet.pos = -1;
		packet.stream_index = streamIndex;
		//write
		// printf("Audio sample_rate =  %d \n\n", inStream->codecpar->sample_rate);
		if (streamIndex == outVideoIndex)++idx;
		if(streamIndex == outVideoIndex && (idx % 100 == 0))  continue;

		if (av_interleaved_write_frame(ofmtCtx, &packet) < 0)
		{
			printf("error muxing packet");
			break;
		}
		av_packet_unref(&packet);
		
	}
	printf("idx = %d\n", idx);
	av_write_trailer(ofmtCtx);//写文件尾

end:
	avformat_close_input(&ifmtCtxVideo);
	avformat_close_input(&ifmtCtxAudio);
	if (ofmtCtx && !(ofmtCtx->oformat->flags & AVFMT_NOFILE))
		avio_close(ofmtCtx->pb);
	avformat_free_context(ofmtCtx);

	return 0;
}

结果
ffplay C:\Users\Administrator\Desktop\VideoDemo\MissFrame.mp4

音视频BUG学习

(2)无丢帧不会报错

据没有报错但是有花屏的情况,推断是动态画面采样时,码率没有上去造成数据采样不足出现马赛克。需要设备在编码动态画面时把码率动态(vbr码率,静态是cbr,均衡生abr)搞上去。

二、解决过程

0 简单查看视频信息

1 把MP4中的h265提取出来

ffmpeg -i test.mp4 -map 0:v:0 -c:v copy video.h265

2 把h265中的yuv提取出来

ffmpeg -i video.h265 -c:v rawvideo -pix_fmt yuv420p output.yuv

3 分析h265和YUV数据

h265

音视频BUG学习

YUV 第69帧出现数据错误

音视频BUG学习

三、解决方案

录像不存在丢帧,但在第69帧(视频中14:01:08:3处)数据出错

问题三 【欧立】【远程直播】远程直播晃动摄像头,马赛克严重

一、额外知识学习

0 参考文章

Elecard Stream Eye 学习链接
直播疑难杂症排查(6)— 马赛克严重
直播常见问题:马赛克严重
抖音直播画面出现马赛克怎么回事?

1 码率

码率(Bit Rate)是指在数字音视频中,每秒传输的比特数。它表示以每秒的速度传输的数据量,通常以比特每秒(bps)或千比特每秒(kbps)为单位。

在音视频中,码率是描述音频或视频数据传输速率和质量的关键参数。较高的码率通常意味着更高的数据传输速率和更好的音视频质量,而较低的码率可能导致较低的传输速率和较差的音视频质量。

对于音频,较高的码率通常表示更多的数据被分配给每秒钟的音频采样,从而提供更高的音频质量和更准确的声音还原。较低的码率可能导致音频失真、噪声或低质量的声音。

对于视频,较高的码率通常表示更多的数据被分配给每秒的视频帧,从而提供更高的图像质量、更多的细节和更平滑的动画。较低的码率可能导致视频图像模糊、马赛克、图像压缩伪影以及运动模糊。

选择适当的码率需要平衡带宽限制、储存空间限制和期望的音视频质量。较高的码率可以提供更好的质量,但会占用更多的带宽和存储空间。较低的码率可以节省带宽和存储空间,但可能牺牲音视频质量。

在音视频编码过程中,可以根据具体需求选择合适的码率。通常会根据目标应用或平台的要求,选择适当的码率以满足预期的音视频质量和资源限制。

二、解决过程

0 简单分析

分析源文件

可能在本地转码过程(转码过程可能发生在本地也可能发生在服务器端)中 数据丢失,也可能是ADTS头部,通道数自动转换

1 mp4文件提取出h264

播放没问题

ffmpeg -i test.mp4 -map 0:v:0 -c:v copy video.h264

2 分析h264

ffplay 不报错
音视频BUG学习
软件分析原视频无问题
音视频BUG学习

3 将h264解码为YUV

ffmpeg -i video.h264 -c:v rawvideo -pix_fmt yuv420p output.yuv

4 分析YUV

音视频BUG学习

三、解决方案

视频本身无丢帧,数据正常,可能运动过程中采集视频码率较低或者网速不稳定,建议方案商将码率调高
本视频码率为821kb/s 帧率27.49fps

问题四 【欧立】【wifi回看】安卓-wifi回看,播放历史视频很卡顿

一、额外知识学习

记路者版本过低会出现视频打不开现象,下载最新版即可

二、解决过程

0 简单分析

需要分析 下载视频,下载视频如果有问题证明是视频本身的问题
然后 复现问题 找问题所在位置

1 mp4文件提取出h264

播放没问题

ffmpeg -i test.mp4 -map 0:v:0 -c:v copy video.h264

2 分析h264

ffplay 不报错
软件分析,原视频无问题

3 mp4文件提取aac、aac解码为pcm

pcm无错误
音视频BUG学习

三、解决方案

下载同一段历史视频分析正常,应该是 设备端 数据传输速度不够
视频卡顿为偶现,在600k/s以上网速无发生卡顿现象
前四张网速高,播放正常,最后一张286k发生卡顿
音视频BUG学习文章来源地址https://www.toymoban.com/news/detail-510717.html

到了这里,关于音视频BUG学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 音视频学习—音视频理论基础(2)

      音频是一种模拟信号,它是由声波转化而来的电信号。声波是通过气体、液体或固体传播的机械波,代表了声音的震动。在录制过程中,声音被转换成电信号,然后被储存在数字格式中。   声音的三要素是频率、振幅和波形   频率是指声波的振动次数,通常使用赫

    2024年04月29日
    浏览(42)
  • C++/Qt音视频通话开发MetaRTC源码解读,dtls交互流程,dtls抓包分析

    本章内容解读MetaRTC开源代码,无任何二次开发,用于学习交流。 MetaRTC是国人开发的开源项目,适用各种场景音视频二次开发,可以去git阅读README,我们使用相对成熟的版本测试: Release v5.0-b4。 本章解读dtls交互流程,dtls抓包分析,dlts概念介绍。 DTLS (Datagram Transport Layer Se

    2023年04月09日
    浏览(48)
  • 学习笔记/音视频面试

    1.DTS/PTS 如果没有B帧,那么DTS一般与PTS相同 DTS(Decoding Time Stamp):即解码时间戳,这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。(解码I-P-B) PTS(Presentation Time Stamp):即显示时间戳,这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。 2.GOP 就是将

    2023年04月12日
    浏览(49)
  • 音视频入门知识学习

    1920x1080的屏幕,32位,30帧的fps。一秒钟需要1920x1080x32x30字节,所以需要压缩 压缩的核心思想就是去除冗余信息 空间冗余 空间冗余 == 相邻像素重复:图像内部相邻像素之间存在较强的相关性多造成的冗余 比如一张图片中间的一个位置大小20x20,它的表现肉眼看起来其实是一

    2024年02月12日
    浏览(50)
  • 从数字图像到音视频学习:我的学习之旅

    数字图像是一门广泛应用于计算机视觉、图像处理和计算机图形学等领域的学科,而音视频学习则涵盖了音频和视频的处理、分析和应用。 如果你最开始接触数字图像,可能会学习一些基本概念,例如像素、分辨率、色彩空间和图像处理算法等。这可能涉及到使用编程语言(

    2024年02月11日
    浏览(53)
  • 5G 时代来了;还不赶紧学习音视频?

    随着 5G 时代的到来 , 移动技术 的发展不仅带来 网速的提升 ,同时也推动 流量单位成本下降 , 企业通信方式 从 文本消息 到 富媒体消息 ,如今也逐渐向 实时高清音视频升级 ; 防护 工作的持续使得 视频会议、远程办公、线上教学 成为许多人工作中的**“常态” ;对于

    2023年04月14日
    浏览(53)
  • 音视频学习(二十)——rtsp收流(udp方式)

    本文主要介绍通过udp方式实现rtsp拉流。 流程说明: 相较于tcp方式“信令+数据”复用同一连接拉流,udp方式拉流“信令+数据”采用不同的连接,信令传输采用tcp,流数据传输采用udp; 客户端向服务端(设备等)发起tcp请求,用于后续信令交互; tcp连接成功后,开始rtsp信令

    2024年02月04日
    浏览(44)
  • ffmpeg系列学习——FFmpeg的音视频处理

    1.音视频的采样率、采样位深度和声道数 音频和视频的采样率、采样位深度和声道数是媒体文件中的重要参数,它们会直接影响到音视频的质量和文件大小。下面对它们进行详细解释: 采样率 采样率指音频每秒钟采样的次数,用赫兹(Hz)表示。采样率越高,音频的还原度越

    2024年02月04日
    浏览(64)
  • 音视频学习(二十一)——rtmp收流(tcp方式)

    本文主要介绍rtmp协议收流流程,在linux上搭建rtmp服务器,通过自研的rtmp收流库发起取流请求,使用ffmpeg+qt实现视频流的解码与播放。 关于rtmp协议基础介绍可查看:https://blog.csdn.net/www_dong/article/details/131026072 下载nginx 解压,将nginx-rtmp-module拷贝至nginx-1.24.0目录,如下所示:

    2024年02月03日
    浏览(51)
  • 如何找到更多音视频开发学习资料和资源?

    如果你对学习音视频开发感兴趣,以下是一些建议,可以帮助你获取更多相关的资料和资源: 在线学习平台:参考一些知名的在线学习平台,如Coursera、Udemy、edX等,搜索他们的课程目录,看是否有与音视频开发相关的课程。这些平台通常提供高质量的学习资源,包括视频教

    2024年02月12日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包