FFmpeg音视频同步

FFmpeg音视频同步

音视频同步在音视频开发中是非常重要的知识点,所以在这里记录下音视频同步相关知识的理解。

音视频同步简介

从前面的学习可以知道,在一个视频文件中,音频和视频都是单独以一条流的形式存在,互不干扰。那么在播放时根据视频的帧率(Frame Rate)和音频的采样率(Sample Rate)通过简单的计算得到其在某一Frame(Sample)的播放时间分别播放,**理论**上应该是同步的。但是由于机器运行速度,解码效率等等因素影响,很有可能出现音频和视频不同步,例如出现视频中人在说话,却只能看到人物嘴动却没有声音,非常影响用户观看体验。

如何做到音视频同步?要知道音视频同步是一个动态的过程,同步是暂时的,不同步才是常态,需要一种随着时间会线性增长的量,视频和音频的播放速度都以该量为标准,播放快了就减慢播放速度;播放慢了就加快播放的速度,在你追我赶中达到同步的状态。目前主要有三种方式实现同步:

  • 将视频和音频同步外部的时钟上,选择一个外部时钟为基准,视频和音频的播放速度都以该时钟为标准。
  • 将音频同步到视频上,就是以视频的播放速度为基准来同步音频。
  • 将视频同步到音频上,就是以音频的播放速度为基准来同步视频。

比较主流的是第三种,将视频同步到音频上。至于为什么不使用前两种,因为一般来说,人对于声音的敏感度更高,如果频繁地去调整音频会产生杂音让人感觉到刺耳不舒服,而人对图像的敏感度就低很多了,所以一般都会采用第三种方式。

复习DTS、PTS和时间基

  • PTS: Presentation Time Stamp,显示渲染用的时间戳,告诉我们什么时候需要显示
  • DTS: Decode Time Stamp,视频解码时的时间戳,告诉我们什么时候需要解码

在音频中PTS和DTS一般相同。但是在视频中,由于B帧的存在,PTS和DTS可能会不同。

实际帧顺序:I B B P

存放帧顺序:I P B B

解码时间戳:1 4 2 3

展示时间戳:1 2 3 4

  • 时间基

/** * This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. * 这是表示帧时间戳的基本时间单位(以秒为单位)。**/typedef struct AVRational{ int num; ///< Numerator 分子 int den; ///< Denominator 分母} AVRational;

时间基是一个分数,以秒为单位,比如1/50秒,那它到底表示的是什么意思呢?以帧率为例,如果它的时间基是1/50秒,那么就表示每隔1/50秒显示一帧数据,也就是每1秒显示50帧,帧率为50FPS。

每一帧数据都有对应的PTS,在播放视频或音频的时候我们需要将PTS时间戳转化为以秒为单位的时间,用来最后的展示。那如何计算一桢在整个视频中的时间位置?

static inline double av_q2d(AVRational a){ return a.num / (double) a.den;}//计算一桢在整个视频中的时间位置timestamp(秒) = pts * av_q2d(st->time_base);

Audio_Clock

Audio_Clock,也就是Audio的播放时长,从开始到当前的时间。获取Audio_Clock:

if (pkt->pts != AV_NOPTS_VALUE) { state->audio_clock = av_q2d(state->audio_st->time_base) * pkt->pts;}

【免费分享】整理了一些学习资料、教学视频和学习路线图,资料包括《Andoird音视频开发必备手册+音视频学习视频+学习文档资料包+大厂面试真题+2022最新学习路线图》等

点击下方链接加卫星号获取,领取资料一定要备注来源:“007”,会优先通过

FFmpegWebRTCRTMPRTSPHLSRTP播放器-音视频流媒体高级开发

还没有结束,由于一个packet中可以包含多个Frame帧,packet中的PTS比真正的播放的PTS可能会早很多,可以根据Sample Rate 和 Sample Format来计算出该packet中的数据可以播放的时长,再次更新Audio_Clock。

// 每秒钟音频播放的字节数 采样率 * 通道数 * 采样位数 (一个sample占用的字节数)n = 2 * state->audio_ctx->channels;state->audio_clock += (double) data_size / (double) (n * state->audio_ctx->sample_rate);

最后还有一步,在我们获取这个Audio_Clock时,很有可能音频缓冲区还有没有播放结束的数据,也就是有一部分数据实际还没有播放,所以就要在Audio_Clock上减去这部分数据的播放时间,才是真正的Audio_Clock。

double get_audio_clock(VideoState *state) { double pts; int buf_size, bytes_per_sec; //上一步获取的PTS pts = state->audio_clock; // 音频缓冲区还没有播放的数据 buf_size = state->audio_buf_size – state->audio_buf_index; // 每秒钟音频播放的字节数 bytes_per_sec = state->audio_ctx->sample_rate * state->audio_ctx->channels * 2; pts -= (double) buf_size / bytes_per_sec; return pts;}

get_audio_clock中返回的才是我们最终需要的Audio_Clock,当前的音频的播放时长。

Video_Clock

Video_Clock,视频播放到当前帧时的已播放的时间长度。

avcodec_send_packet(state->video_ctx, packet);while (avcodec_receive_frame(state->video_ctx, pFrame) == 0) { if ((pts = pFrame->best_effort_timestamp) != AV_NOPTS_VALUE) { } else { pts = 0; } pts *= av_q2d(state->video_st->time_base); // 时间基换算,单位为秒 pts = synchronize_video(state, pFrame, pts); av_packet_unref(packet);}

旧版的FFmpeg使用av_frame_get_best_effort_timestamp函数获取视频的最合适PTS,新版本的则在解码时生成了best_effort_timestamp。但是依然可能会获取不到正确的PTS,所以在synchronize_video中进行处理。

double synchronize_video(VideoState *state, AVFrame *src_frame, double pts) { double frame_delay; if (pts != 0) { state->video_clock = pts; } else { pts = state->video_clock;// PTS错误,使用上一次的PTS值 } //根据时间基,计算每一帧的间隔时间 frame_delay = av_q2d(state->video_ctx->time_base); //解码后的帧要延时的时间 frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); state->video_clock += frame_delay;//得到video_clock,实际上也是预测的下一帧视频的时间 return pts;}

同步

上面两步获得了Audio_Clock和Video_Clock,这样我们就有了视频流中Frame的显示时间,并且得到了作为基准时间的音频播放时长Audio clock ,可以将视频同步到音频了。

  • 用当前帧的PTS – 上一播放帧的PTS得到一个延迟时间
  • 用当前帧的PTS和Audio_Clock进行比较,来判断视频的播放速度是快了还是慢了
  • 根据2的结果,设置播放下一帧的延迟时间
  • #define AV_SYNC_THRESHOLD 0.01 // 同步最小阈值#define AV_NOSYNC_THRESHOLD 10.0 // 不同步阈值double actual_delay, delay, sync_threshold, ref_clock, diff;// 当前Frame时间减去上一帧的时间,获取两帧间的延时delay = vp->pts – is->frame_last_pts;if (delay = 1.0) { // 延时小于0或大于1秒(太长)都是错误的,将延时时间设置为上一次的延时时间 delay = is->frame_last_delay;}// 获取音频Audio_Clockref_clock = get_audio_clock(is);// 得到当前PTS和Audio_Clock的差值diff = vp->pts – ref_clock;sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;// 调整播放下一帧的延迟时间,以实现同步if (fabs(diff) frame_timer += delay;// 最终真正要延时的时间actual_delay = is->frame_timer – (av_gettime() / 1000000.0);if (actual_delay < 0.010) { // 延时时间过小就设置个最小值 actual_delay = 0.010;}// 根据延时时间刷新视频schedule_refresh(is, (int) (actual_delay * 1000 + 0.5));

    最后

    将视频同步到音频上实现音视频同步基本完成,总体就是动态的过程快了就等待,慢了就加速,在一个你追我赶的状态下实现同步播放。

    后面的博客会持续更新真正实现一个音视频同步的播放器。

    分享一个非常好的音视频学习地址,可点击免费报名订阅学习,先关注不迷路。[给力]

    【免费】FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发-学习视频教程-腾讯课堂

    郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
    用户投稿
    上一篇 2022年6月20日 09:10
    下一篇 2022年6月20日 09:11

    相关推荐

    • 抖音只说了封禁没说时长(抖音封禁一般多长时间)

      最近是不是发现抖音监管和封号的力度大了很多,我常能看到,有同学吐槽,为什么又被封了,我也没有违规呀!! 那么今天,我就列出4大容易被封的原因,帮你避开90%的坑。学会了就点赞吧。 …

      2022年11月27日
    • 短视频策划内容的3个要点(短视频策划内容怎么做)

      短视频在制作时,内容框架非常重要。如果直奔主题,然后结束,聚卓告诉你,这样的短视频已经过时了。现在的短视频需要框架的,但不是任何框架,它需要一种易于理解和消化的框架。而且,现在大多…

      2022年11月27日
    • TES官宣knight断开连接!网友:左手就是下一个369

      2022LPL冬季转会期已经正式到来,如果说此次转会期热度最高的一支队伍,无疑就是在2022全球总决赛中拿到四强成绩的JDG了。因为据目前网上爆料人的消息来看,JDG很有可能会通过…

      2022年11月27日
    • 个人怎么做抖音带货(个人做抖音带货能赚钱吗)

      抖音如今是大家很熟悉的短视频平台,不过现在的抖音却不只是短视频那么简单,它的功能非常丰富,其中一个就是可以带货,相信很多小伙伴都有在抖音上买过东西,抖音如今的变现能力也是不容小觑的…

      2022年11月25日
    • 全民K歌升级新版本7.0之后,有哪些隐藏功能?

      作者:高百烈来源:知乎 这个功能,旧版并没有,要升级到全新的全民K歌7.0版本才能发现。 作为朋友圈当代K歌之王,我费了不少功夫才抢到内测版本。有一说一,全民K歌的路子真的很野,新…

      2022年11月25日
    • “濛翔”搭档展现不一样的世界杯 中国移动咪咕多档综艺上线

      2022国际足联卡塔尔世界杯如火如荼进行中,王濛、黄健翔冬奥之后再聚首,作为咪咕嘉宾天团的成员,不仅陪伴观众直击现场,畅聊世界杯赛场内外趣事,更携手于11月26日、11月30日在咪…

      2022年11月25日
    • 5+3疫情防控从哪天开始算(辽宁疫情防控最新政策)

      最近有关国内各地的疫情大家也都有在持续关注,目前国内各地疫情隔离时间也根据二十条防控措施有了新的调整。那么,5+3疫情防控从哪天开始算?对于密接的5+3隔离时间计算大家还是比较关心…

      2022年11月25日
    • 蓝码怎么变绿码需要几天(蓝码怎么变绿码需要几天)

      大家都知道健康码的颜色有红码、绿码、黄码,近日湖南健康码上线“蓝码”,不少小伙伴发现自己健康码变蓝了,都想赶紧恢复绿码,那么蓝码怎么变绿码需要几天?下面小编为大家带来蓝码变绿码需要…

      2022年11月25日
    • 拼多多百亿补贴预售一般多久发货(拼多多百亿补贴预售)

      拼多多里面有很多优惠活动,其中百亿补贴活动非常火爆,一些里面的东西价格比别的平台便宜,质量也有保障,还有预售的活动,那么拼多多百亿补贴预售一般多久发货?下面小编为大家带来拼多多百亿…

      2022年11月25日
    • 北京疫情多久能解除封控(北京疫情还要多久结束)

      最近一段时间北京疫情形势备受关注,马上就要到年底了,不少人想要去北京办事,。都非常关注当地疫情相关政策,那么 北京疫情多久能解除封控?北京疫情什么时候恢复正常生活?下面小编为大家带…

      2022年11月25日

    联系我们

    联系邮箱:admin#wlmqw.com
    工作时间:周一至周五,10:30-18:30,节假日休息