用FFMPEG SDK进行视频转码压缩时解决音视频不同步问题的方法
用FFMPEG SDK进行视频转码压缩的时候,转码成功后去看视频的内容,发现音视频是不同步的。这个的确是一个恼火的事情。我在用FFMPEG SDK做h264格式的FLV文件编码Filter的时候就碰到了这个问题。
经过研究发现,FFMPEG SDK写入视频的时候有两个地方用来控制写入的时间戳,一个是AvPacket, 一个是AvFrame。 在调用avcodec_encode_video的时候需要传入AvFrame的对象指针,也就是传入一帧未压缩的视频进行压缩处理,AvFrame包含一个pts的参数,这个参数就是当前帧将来在还原播放的时候的时间戳。而AvPacket里面也有pts,还有dts。说起这个就必须要说明一下I,P,B三种视频压缩帧。I帧就是关键帧,不依赖于其他视频帧,P帧是向前预测的帧,只依赖于前面的视频帧,而B帧是双向预测视频帧,依赖于前后视频帧。由于B帧的存在,因为它是双向的,必须知道前面的视频帧和后面的视频帧的详细内容后,才能知道本B帧最终该呈现什么图像。而pts和dts两个参数就是用来控制视频帧的显示和解码的顺序。
pts就是帧显示的顺序。
dts就是帧被读取进行解码的顺序。
如果没有B帧存在,dts和pts是相同的。反之,则是不相同的。关于这个的详细介绍可以参考一下mpeg的原理。
再说说AvPacket中包含的pts和dts两个到底该设置什么值?
pts和dts需要设置的就是视频帧解码和显示的顺序。每增加一帧就加一,并不是播放视频的时间戳。
但是实践证明经过rmvb解码的视频有时候并不是固定帧率的,而是变帧率的,这样,如果每压缩一帧,pts和dts加一的方案为导致音视频不同步。
那怎么来解决音视频同步的问题呢?
请看如下代码段。
lTimeStamp 是通过directshow 获取的当前的视频帧的时间戳。
m_llframe_index为当前已经经过压缩处理的帧的数量。
首先av_rescale计算得到当前压缩处理已经需要处理什么时间戳的视频帧,如果该时间戳尚未到达directshow当前提供的视频帧的时间戳,则将该帧丢弃掉。
否则进行压缩操作。并设置AVPacket的pts和dts。这里假设B帧不存在。
因为在将来播放的时候视频以我们设定的固定播放帧率进行播放,所以需要根据设定的播放帧率计算得到的视频帧时间戳和directshow提供的当前视频帧的时间戳进行比较,设定是否需要进行实施延缓播放的策略。如果需要延缓播放,则将pts增加步长2,否则以普通速度播放,则设置为1.dts与之相同。
__int64 x = av_rescale(m_llframe_index,AV_TIME_BASE*(int64_t)c- time_base.num,c- time_base.den);if( x lTimeStamp )
{
return TRUE;
}
m_pVideoFrame2- pts = lTimeStamp;
m_pVideoFrame2- pict_type = 0;
int out_size = avcodec_encode_video( c, m_pvideo_outbuf, video_outbuf_size, m_pVideoFrame2 );
if (out_size 0)
{
AVPacket pkt;
av_init_packet( pkt);
if( x lTimeStamp )
{
pkt.pts = pkt.dts = m_llframe_index;
pkt.duration = 0;
}
else
{
pkt.duration = (lTimeStamp - x)*c- time_base.den/1000000 + 1;
pkt.pts = m_llframe_index;
pkt.dts = pkt.pts;
m_llframe_index += pkt.duration;
}
//pkt.pts = lTimeStamp * (__int64)frame_rate.den / 1000;
if( c- coded_frame c- coded_frame- key_frame )
{
pkt.flags |= PKT_FLAG_KEY;
}
pkt.stream_index= m_pVideoStream- index;
pkt.data= m_pvideo_outbuf;
pkt.size= out_size;
ret = av_interleaved_write_frame( m_pAvFormatContext, pkt );
}
else
{
ret = 0;
}
产品百科 | RTC Windows SDK 音视频设备测试说明 RTC SDK 为您提供音视频设备测试的方法,您可以在音视频通话前检查当前设备上的摄像头,麦克风以及扬声器等音视频设备是否正常工作,以保证音视频通话质量。通过阅读本文,您可以了解音视频设备测试的方法。
产品百科 | RTC Mac SDK 音视频设备测试说明 RTC SDK 为您提供音视频设备测试的方法,您可以在音视频通话前检查当前设备上的摄像头,麦克风以及扬声器等音视频设备是否正常工作,以保证音视频通话质量。通过阅读本文,您可以了解音视频设备测试的方法。
音视频通信 RTC - SDK V1.9发布 信息摘要: 优化音视频传输质量、弱网传输、通信稳定性和设备兼容性,全平台音视频通信体验大幅提升。适用客户: 适用于在线教育、互动娱乐、多媒体社交及音视频通信行业应用开发者版本/规格功能: 1. 视频质量优化,降低画面像素破损发生率
相关文章
- ESXI5.5设置主机的时间自动同步服务 NTP
- Java并发编程实战系列(15)-原子遍历与非阻塞同步机制
- 美柚与MaxCompute数据同步架构说明
- github fork 别人的项目源作者更新后如何同步更新
- 基于UDQ的并网单相逆变器控制【同步参考系下单相并网全桥正弦PWM逆变器闭环控制】(Simulink)
- Promise & Generator——幸福地用同步方法写异步JavaScript
- 通过触发器进行数据同步
- 让异步操作同步执行的方法详解
- Redis主从同步介绍
- linux线程间同步(1)读写锁
- Java 多线程同步的五种方法
- 同步(Synchronous)和异步(Asynchronous)方法的区别
- Rsync同步时删除多余文件 [附:删除大量文件方法的效率对比]
- [日常工作]vCenter下虚拟机设置与宿主机时间同步的方法
- 同步方法与同步代码块的区别
- MYSQL数据库间同步数据
- pull同步远程仓 笔记
- 同步机制
- 万一 Github不让用了,Gitee同步指南请收好
- Java 基础(同步方法解决线程安全问题)
- PostgreSQL 通过归档日志定期增量同步数据
- mysql 半同步 5.6及5.7
- Java多线程(五) 静态同步synchronized方法与synchronized(class)代码块
- POSIX线程库(二)线程同步轮询技术——一种笨笨方法
- 【并发编程十二】c++20线程同步——信号量(semaphore)
- Mysql主从不同步解决方法 binlog三种模式的区别
- 2019-9-2-C#同步方法转异步
- 2019-9-2-C#同步方法转异步
- C#同步方法转异步
- MySQL主从同步配置
- Java多线程-线程的同步(同步方法)
- 小凡的Linux主机与时间服务器同步记录
- rsync同步时报错