音视频BUG学习

找Bug流程

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

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

一、额外知识学习

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

二、解决过程

0 问题复现

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

0 简单分析

分析源文件
在这里插入图片描述

可能在本地转码过程(转码过程可能发生在本地也可能发生在服务器端)中 数据丢失,也可能是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

在这里插入图片描述

数据被置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 PTSAVRational timeBase1 = inStream->time_base;//Duration between 2 framesdouble 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 PTSAVRational timeBase1 = inStream->time_base;//printf("timeBase = %.15lf\n", (double)(av_q2d(timeBase1)));//Duration between 2 framesdouble 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/DTSpacket.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

在这里插入图片描述

(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

在这里插入图片描述

YUV 第69帧出现数据错误

在这里插入图片描述

三、解决方案

录像不存在丢帧,但在第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 不报错
在这里插入图片描述
软件分析原视频无问题
在这里插入图片描述

3 将h264解码为YUV

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

4 分析YUV

在这里插入图片描述

三、解决方案

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/2415.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android逆向解析加壳与脱壳技术

加壳 加壳是指在 APK 文件中插入额外的代码或数据&#xff0c;使得原始代码难以被分析和反编译。通常加壳是为了保护软件的知识产权或者防止逆向工程。下面是 Android 加壳的一般流程&#xff1a; 选择加壳工具&#xff1a;选择合适的加壳工具进行加壳&#xff0c;比如市面上…

[计算机入门]了解键盘

2.1 了解键盘 键盘一般可以根据按键的功能进行分区&#xff0c;一般分为&#xff1a;主键盘区、小键盘区、控制键区、功能键区、指示灯区。下面介绍键盘的各个分区按键及功能。 2.1.1 主键盘区 主键盘区又叫打字键盘区或字符键区&#xff0c;具有标准英文打字机键盘的格式。…

基于Dlib的疲劳检测系统

需要源码的朋友可以私信我 基于Dlib的疲劳检测系统 1、设计背景及要求2、系统分析3、系统设计3.1功能结构图3.2基于EAR、MAR和HPE算法的疲劳检测3.2.1基于EAR算法的眨眼检测3.2.2基于MAR算法的哈欠检测3.3.3基于HPE算法的点头检测 4、系统实现与调试4.1初步实现4.2具体实现过程…

用雪花 id 和 uuid 还是自增id做 MySQL 主键

MySQL中设计表的时候&#xff0c;MySQL官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一)&#xff0c;而是推荐连续自增的主键id&#xff0c;官方的推荐是auto_increment&#xff0c;那么为什么不建议采用uuid&#xff0c;使用uuid究竟有什么坏处&#xff1f; MySQ…

3.跑马灯

1.GPIO的输出模式&#xff1a; 推挽模式输出&#xff1a;因为LED0和LED1阳极都是3.3V&#xff0c;需要将阴极设置为低电平才可以点亮LED&#xff1b;操作io口时&#xff0c;必须引入源文件和头文件&#xff1b;关于时钟的文件存放在rcc中&#xff1b; 2.GPIO库函数介绍&#…

NodeJS NVM版本管理⑩⑧

文章目录 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持&#x1f618;前言NVM IntroduceNVM UseDownload And InstallNVM Project Use总结 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹…

使用VSCODE跑orbslam2踩的坑

我用的是ubuntu22.04&#xff0c;opencv是4.7&#xff0c;使用其他的库感觉就算版本不一样&#xff0c;也能跑。 一、运行build.sh能够产生可执行文件遇到的问题 1.由于opencv版本高带来的问题 这些问题怎么定位出现在哪些文件中&#xff0c;你通过命令行&#xff0c;运行下…

【K8SRockyLinux】基于开源操作系统搭建K8S高可用集群(详细版)

文章目录 一、实验节点规划表&#x1f447;二、实验版本说明&#x1f4c3;三、实验拓扑&#x1f4ca;四、实验详细操作步骤&#x1f579;️1. 安装Rocky Linux开源企业操作系统2. 所有主机系统初始化3. 所有master节点部署keepalived4. 所有master节点部署haproxy5. 所有节点配…

【SpringMVC 学习笔记】

SpringMVC 笔记记录 1. SpringMVC 简介2. 入门案例3. 基本配置3.1 xml形式配置3.2 注解形式配置 4. 请求4.1 请求参数4.1.1 普通类型传参4.1.2 实体类类型传参4.1.3 数组和集合类型传参 4.2 类型转换器4.3 请求映射 5. 响应 1. SpringMVC 简介 三层架构 2. 入门案例 3. 基本…

Java死锁

代码&#xff1a; package Test0629;public class BankTest {static Bank b1 null;static Bank b2 null;public static void main(String[] args) {Thread t1 new Thread(){public void run(){b1 Bank.getInstance();}};Thread t2 new Thread(){public void run(){b2 Ba…

fast admin报错:Unexpected token ‘<‘, “ (已解决)

报错信息&#xff1a; 在新加视图的时候的&#xff0c;点击编辑/添加忽然报这个错误&#xff0c;网上找了半天&#xff0c;js、视图、修修改改最后竟是一个小问题&#xff1b; 解决方法&#xff1a; 改为&#xff1a; 简单的说就是&#xff1a;btn-ajax ->btn-dialog

【MySQL】MySQL数据库,RDBMS 术语,使用说明和报错解决的详细讲解

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…