最近因为耳机3.5mm接口的一些干扰问题,舍弃了之前的接入方式,需要重新实现网络音频流的接入,在这个过程中遇到了一些问题,特来记录一下~

一、网络音频流的接入

这个音频流来源各不相同,我这里是udp广播到10001端口上的,直接监听本机10001端口就可以看到音频信息。

需要提前知道的是这个网络音频流原本的采样率和位深是多少,这里我已经知道了61000hz的采样率和16的位深

这时候我们借助ffmpeg下的ffplay程序可以直接播放这个音频,命令如下

.\ffplay.exe -f s16le -ar 61000 -ac 2 udp://0.0.0.0:10001

二、音频流和视频流合并

通过ffmpeg对网络音频流进行读取,读取之后和rtsp视频流进行合并,

这一步简单讲一讲:

首先跟rtsp读取流的方式类似,ffmpeg对音频流的读取方式也是支持url直接读取的

如下所示:

if ((ret = ffmpeg.avformat_open_input(&formatContext, _audioUrl, _inputAudioFormat, &options)) < 0)
{
ffmpeg.av_dict_free(&options);
ffmpeg.avformat_close_input(&formatContext);
throw new Exception($"Could not open input path: {_audioUrl} (error '{FFmpegHelper.av_err2str(ret)}')");
}

需要注意的是,因为是网络音频流,这个音频流是不带位深和采样率信息的,需要我们自己提前指定

AVCodecParameters* codecpar = formatContext->streams[_audioIndex]->codecpar;

if (SampleRate > 0)
{
codecpar->sample_rate = 61000;
codecpar->channels = ffmpeg.av_get_channel_layout_nb_channels((ulong)_channelLayout);
}
_inputAudioFormat = ffmpeg.av_find_input_format("s16le");

由上面初始化开启探针读取网络音频流和视频流之后,剩下的处理就是合并了。

合并这里本质上就是合并读取出来的audioPacket和videoPacket,然后将packet转为frame,这时候转换为要输出的格式,再构建到packet中,最终将packet交错写入到同一个_formatContext进行保存。(很大白话了23333)

ffmpeg.av_interleaved_write_frame(_formatContext, outputPacket);

三、音画不同步的问题

上面的功能实现之后又发现保存后的视频存在音画不同步的问题

现象是:

①实时播放过程中,耳机反馈实时播放声音,实际动作比声音略晚,视频略早于声音

②播放视频过程中,声音比动作先出现了,也就是音频早于视频。

这里①很正常,因为本来音频通过wave过去并播放,肯定是需要时间的

但是②就不太对了,这是摆明了就是视频音画不同步。

而音画不同步的原因有以下几种可能:

①网络延迟:音频和视频数据在传输过程中可能会受到网络延迟的影响,导致数据到达接收端的时间不同步。这可能是由于网络拥塞、传输路径不稳定等原因引起的。

②编解码延迟:音频和视频的编解码过程可能会引入一定的延迟,导致数据的播放时间不同步。不同的编解码算法和参数设置可能会对延迟产生影响。

③媒体同步机制:RTP流中的音频和视频数据通常是分开传输的,接收端需要根据时间戳等信息将它们进行同步播放。如果同步机制实现不正确或者缺失,就会导致音频和视频不同步。

其实原因看起来很多,但归根到底都还是同步问题。

这里上面的现象让我直接推断是视频进入帧的时候比较晚,于是直接就怀疑了是视频读包要晚于音频的情况,想到这我们直接验证:

只需要在写入第一个视频帧和写入第一个音频帧的地方打印一个距流开启的时间就能观察到问题,这里我使用了_stopwatch进行准确的打印。

结果确实也验证了上面的想法——音频的偏移大概是35ms左右,可以忽略不计,而视频相较于音频大概延迟400-500ms。

那么我们这时候就可以进行音画同步了。

四、音画同步

首先说明:这里的同步是针对于探针时间偏差和编解码延迟导致的音画不同步问题设计的。

原理很简单:通过音频和视频写入第一帧的时间和流开启的时间的偏差,移动视频和音频的pts和dts进行对齐。

首先从上面的例子中就可以获取_stopwatch.ElapsedMilliseconds,分别是音频写入第一帧的时间和视频写入第一帧的时间与流开启的时间的偏差,这里分别是音频35ms,视频400ms。这时候我们统一对音频和视频pts和dts进行左移,将二者的首端都移到视频起始的位置。

这里需要注意的是,我们需要在时基转换之后的outpacket上进行操作,不然无法生效。

ffmpeg.av_packet_rescale_ts(outputPacket, _audioCodecContext->time_base, _audioStream->time_base);

在上面的时基转换后,我们以音频举例,这时获取了_sampleStartPts(音频的偏移),因为ElapsedMilliseconds是毫秒,所以我们需要除1000换算成秒,然后乘以时基,这时候我们就得到了pts实际的需要偏移的量。

_sampleStartPts = _stopwatch.ElapsedMilliseconds * _audioStream->time_base.den / 1000;

(特别提醒:这里的时基我默认分子为1,所以我直接用的分母,如果分子不同需要加入进行换算)

得到了ptsOffset(_sampleStartPts)之后呢,我们直接对所有输出的packet进行pts、dts移动就可以啦

outputPacket->pts -= _sampleStartPts;
outputPacket->dts -= _sampleStartPts;

这里因为是要去首端对齐,所以是减去偏移量~

最后再把上面的操作对应到视频流中执行一遍,出来的视频音画就同步了~

ps 文章原创于idealy233,转载请私信哦~

ffmpeg合并时音画不同步问题及音频软编码实现记录的更多相关文章

  1. (大概是最全的解决方法)使用bandicam录制视频导入pr后音画不同步问题

    遇到这个问题大部分都是使用了VBR来录制视频导致的, 搜集了各种能够找到的方法,并没有每个尝试过 一 Handbrake转码 Audio out of sync AFTER importing 解决方 ...

  2. 在FPS游戏中,玩家对音画同步感知的量化与评估

    前言 在游戏测试中,音画同步测试是个难点(所谓游戏音画同步:游戏中,音效与画面的同步程度),现在一般采用人工主观判断的方式测试,但这会带来2个问题: 无法准确量化,针对同一场景的多次测试结果可能会相反 ...

  3. QQ视频直播架构及原理 流畅与低延迟之间做平衡 音画如何做同步?

    QQ视频直播架构及原理 - tianyu的专栏 - CSDN博客 https://blog.csdn.net/wishfly/article/details/53035342 作者:王宇(腾讯音视频高 ...

  4. ffmpeg protocol concat 进行ts流合并视频的时间戳计算及其音画同步方式一点浅析

    ffmpeg protocol concat 进行ts流合并视频的时间戳计算及音画同步方式一点浅析 目录 ffmpeg protocol concat 进行ts流合并视频的时间戳计算及音画同步方式一点 ...

  5. 【FFMPEG】各种音视频编解码学习详解 h264 ,mpeg4 ,aac 等所有音视频格式

    目录(?)[-] 编解码学习笔记二codec类型 编解码学习笔记三Mpeg系列Mpeg 1和Mpeg 2 编解码学习笔记四Mpeg系列Mpeg 4 编解码学习笔记五Mpeg系列AAC音频 编解码学习笔 ...

  6. 音视频编解码流程与如何使用 FFMPEG 命令进行音视频处理

    一.前言 FFMPEG 是特别强大的专门用于处理音视频的开源库.你既可以使用它的 API 对音视频进行处理,也可以使用它提供的工具,如 ffmpeg, ffplay, ffprobe,来编辑你的音视频 ...

  7. FastAdmin 开发时如何与官方同步升级

    FastAdmin 开发时如何与官方同步升级 使用 FastAdmin 开发时为了与官方同步升级,推荐使用 git 管理代码. 官网上提供的完整包是为了方便第一次使用的人快速测试. 我一般是给官方的 ...

  8. rsync+inotify 实现资源服务器的同步目录下的文件变化时,备份服务器的同步目录更新,以资源服务器为准,去同步其他客户端

    测试环境: 资源服务器(主服务器):192.168.200.95 备份服务器(客户端):192.168.200.89 同步目录:/etc/test 同步时使用的用户名hadoop密码12345 实验目 ...

  9. 关于 Javascript 严格模式下多文件合并时注意

    Javascript 在第一行使用 "use strict" 声明严格模式. 但是在多个 js 文件合并时就需要注意了,可能你的是严格模式,但别的文件不是,就会造成错误. 为什么使 ...

  10. 使用ffmpeg合并视频文件的三种方法

    ffmpeg合并视频的方法有三种.国内大多数仅介绍了其中之一.于是觉得有必要翻译一下.其实在ffmpeg的 FAQ文档中有比较详细的说明. 使用concat协议进行视频文件的合并 这种方式的适用场景是 ...

随机推荐

  1. SpringBoot 集成Swagger后提通过http://localhost:8001/swagger-ui.html#/访问得不到页面

    SpringBoot 集成Swagger后提通过http://localhost:8001/swagger-ui.html#/访问得不到页面: spring boot  集成 swagger2步骤: ...

  2. CF1763C Another Array Problem

    人类智慧题.harmis_yz 不会. 题意 \(\tt{Link}\) 给定一个序列 \(\{a_n\}\),可以进行若干次操作,每次可以选择 \(i,j(1 \le i < j \le n) ...

  3. Circos软件学习

    circos 是一款perl 语言开发的画图软件,提供了染色体相关数据的一种可视化方式.其制作的图表精美,被科研工作者广泛使用.Circos可以对染色体相关数据进行可视化,以每条染色体为一个扇区,组成 ...

  4. 高通QCM6125平台TZ释放后使用GPIO导致死机问题

    问题的根本原因是TZ侧没有释放完整. 释放QUPV3_0_SE0从TZ到AP侧,QUPv3的固件也从SPI改成了UART 2线. 但是出现了一个很奇怪的问题,AP侧可以使用UART,但是一旦使用GPI ...

  5. 展锐SE8451E 开启硬件流控

    Dear Customer:  如电话沟通,若将uart0配置成3M波特率,需进行如下更改:  1.时钟源更改为96M/sprdroid10_trunk_19c_rls1/bsp/kernel/ker ...

  6. JVM实战—13.OOM的生产案例

    大纲 1.每秒仅上百请求的系统为何会OOM(RPC超时时间设置过长导致QPS翻几倍) 2.Jetty服务器的NIO机制如何导致堆外内存溢出(S区太小 + 禁NIO的显式GC) 3.一次微服务架构下的R ...

  7. 一点区块链资料-copy

    1. 场景描述 (1)今天找资料,无意中看到15年底-16年初弄的关于区块链的资料,当时写了个交流汇报区块链的ppt,感觉挺好的,共享下,希望能帮助朋友们理解区块链. (2)背景:15年底,老板从朋友 ...

  8. 使用badboy配合jmeter测试(详细)

    工具 badboy2.2.5  jmeter 5.4.1 两个工具都必须是最新版,否则jmeter打开脚本的时候会报错 1.首先打开badboy,首页如下图 2.进入后就开始自动录制脚本,可以输入要测 ...

  9. 一个登录功能也能玩出这么多花样?sa-token带你轻松搞定多地登录、单地登录、同端互斥登录

    需求场景 说起登录,你可能会不屑一顾,还有比这更简单的功能吗? 获取一下用户提交参数 username + password 和数据库中一比对,有记录返回[登录成功],无记录返回[用户名或密码错误] ...

  10. 将VSCode设置为中文(汉化)

    1.VSCode安装好后默认语言为英文,此汉化过程的VSCode版本为1.42.1,如下图所示: 2.下载安装完成后,打开VSCode,使用快捷键Ctrl+Shift+P,然后在出现的输入框中输入co ...