当前位置: 首页 > news >正文

音视频同步知识

时间基和时间戳

实际时间(秒) = 时间戳 × 时间基值

下面详细解释这两个概念及其关系:
1. 时间基(Time Base)
时间基是一个分数({num, den}),表示时间戳的单位。它定义了每个时间戳单位对应的实际时间。
示例:
{1, 1000} 表示每个时间戳单位为 1/1000 秒(毫秒)。
{1, 90000} 表示每个时间戳单位为 1/90000 秒(常用于视频流,如 MPEG-2)。
{1, 44100} 表示每个时间戳单位为 1/44100 秒(常用于 44.1kHz 音频采样)。
作用:不同的媒体流(视频、音频)可能使用不同的时间基,通过转换到统一的时间基,可以实现时间同步。
2. 时间戳(Timestamp)
时间戳是一个整数,指示媒体数据(如帧、包)的播放或解码时间点。常见的时间戳类型:

PTS(Presentation Time Stamp):指示帧应该何时被显示。
DTS(Decoding Time Stamp):指示帧应该何时被解码(对 B 帧编码的视频特别重要)。
示例:
若时间基为 {1, 1000},时间戳 5000 表示 5000 × (1/1000) = 5 秒。
若时间基为 {1, 90000},时间戳 450000 表示 450000 × (1/90000) = 5 秒。

常见时间基

(1)编解码器时间基(Codec Time Base)
用途:编码器或解码器内部使用的时间基。
获取方式:AVCodecContext.time_base
示例:
视频编码器可能使用 {1, 25} 表示 25fps(每帧 40ms)。
音频编码器可能使用 {1, 44100} 与采样率匹配。
(2)流时间基(Stream Time Base)
用途:输出文件中每个流的时间基。
获取方式:AVStream.time_base
示例:
MP4 容器的视频流可能使用 {1, 90000}。
音频流可能使用 {1, 48000}。

编码的时间基操作


step 1 计算帧的时间戳增量

double audio_frame_duration = 1.0 *audio_encoder.GetFrameSize()/pcm_sample_rate*audio_time_base;
double video_frame_duration = 1.0/yuv_fps * video_time_base;

step2 转化时间基

pts = av_rescale_q(pts, AVRational{1, (int)time_base}, codec_ctx_->time_base);
frame_->pts = pts;

将我自己的时间基转化为了编码时间基,实现了pts同步


流时间基操作


step1 判断大小

 if((video_finish != 1 && audio_pts > video_pts)   // audio和vidoe都还有数据,优先audio(audio_pts > video_pts)||  (video_finish != 1 && audio_finish == 1)) {read_len = fread(yuv_frame_buf, 1, yuv_frame_size, in_yuv_fd);if(read_len < yuv_frame_size) {video_finish = 1;printf("fread yuv_frame_buf finish\n");}

条件 1:audio_pts > video_pts时优先处理视频,避免视频落后太多。
条件 2:音频处理完毕但视频未完成时,继续处理视频帧。
核心逻辑:通过比较audio_pts和video_pts,确保音视频时间戳保持相近,实现同步输出。

等于1的时候 代表已经全部编码完成了


step2 转换流的时间基

   AVRational src_time_base;   // 编码后的包 时间基AVRational dst_time_base;   // mp4输出文件对应流的time_baseif(vid_stream_ && vid_codec_ctx_ && stream_index == video_index_) {src_time_base = vid_codec_ctx_->time_base;dst_time_base = vid_stream_->time_base;} else if(aud_stream_ && aud_codec_ctx_ && stream_index == audio_index_) {src_time_base = aud_codec_ctx_->time_base;dst_time_base = aud_stream_->time_base;}// 时间基转换 这确保了音视频时间戳在输出文件中具有统一的时间刻度。packet->pts = av_rescale_q(packet->pts, src_time_base, dst_time_base);packet->dts = av_rescale_q(packet->dts, src_time_base, dst_time_base);packet->duration = av_rescale_q(packet->duration, src_time_base, dst_time_base);

ret = av_interleaved_write_frame(fmt_ctx_, packet);

av_interleaved_write_frame() 是 FFmpeg 中用于将编码后的音视频数据包写入输出文件的核心函数,它在实现音视频同步和交错输出中起着关键作用。以下是对该函数的详细解析:

  1. 函数作用
    av_interleaved_write_frame() 用于将音视频数据包(AVPacket)按照正确的时间顺序写入输出媒体文件(如 MP4、MKV 等)。它主要完成以下工作:
    时间戳检查与修正:确保数据包的时间戳(PTS/DTS)单调递增且合法。
    缓存与排序:内部维护一个缓冲区,对音视频包进行排序,确保按时间顺序输出。
    交错输出:将不同流(音频、视频、字幕)的数据包按时间顺序交错写入文件,实现同步

总结

基于时间戳同步:这是最常见的方法。在播放过程中,系统会不断获取音频和视频帧的时间戳,并根据时间戳来调整播放进度。例如,如果发现视频帧的时间戳比音频帧的时间戳大,说明视频播放进度落后于音频,此时可以适当加快视频的播放速度,或者暂停音频的播放,直到两者的时间戳接近。

补充一 不同时间基

1. 核心处理原则

  • 统一时间轴:将不同流的时间戳转换到同一时间基下,才能进行同步比较。
  • 换方向:通常将所有流的时间戳转换为输出流的时间基(如 MP4 容器要求的{1, 90000})。
  • 使用 FFmpeg 工具:通过av_rescale_q()或av_packet_rescale_ts()函数完成转换,避免手动计算。
// 视频流信息
AVRational video_codec_time_base = video_codec_ctx->time_base;  // 编码器时间基
AVRational video_stream_time_base = video_stream->time_base;    // 输出流时间基// 音频流信息
AVRational audio_codec_time_base = audio_codec_ctx->time_base;  // 编码器时间基
AVRational audio_stream_time_base = audio_stream->time_base;    // 输出流时间基

(2)时间基转换
在将数据包写入输出文件前,必须将其时间戳从编码器时间基转换为输出流时间基:

// 对视频包进行时间基转换
av_packet_rescale_ts(packet, video_codec_time_base, video_stream_time_base);// 对音频包进行时间基转换
av_packet_rescale_ts(packet, audio_codec_time_base, audio_stream_time_base);

(3)写入交错帧
使用av_interleaved_write_frame()确保按时间戳排序输出:

ret = av_interleaved_write_frame(fmt_ctx, packet);

常见时间基

场景编码器时间基输出流时间基
MP4视频{1, 90000}{1, 90000}
MP4音频(48kHz){1, 48000}{1, 48000}
自定义帧率视频{1, fps}(如{1, 25}{1, 90000}
网络流{1, 1000}(毫秒级){1, 90000}

补充二 H.264 中 PTS≠DTS 时的音视频同步

1. 问题背景
H.264 特性:因 B 帧(双向预测帧)存在,解码顺序(DTS)与显示顺序(PTS)不同,导致DTS ≤ PTS(B 帧 DTS 可能小于前序 P 帧)。
同步核心:以音频为基准(人耳对音频延迟更敏感),通过时间戳转换和动态调整,确保视频显示与音频播放同步。
2. 关键处理步骤

  • (1)时间基统一与时间戳转换
    目标:将音视频时间戳转换为同一时间基(如输出流时间基)。
    操作:
    使用 FFmpeg 的 av_packet_rescale_ts() 或 av_rescale_q(),将编码器时间基(如 H.264 的{1, 90000})转换为输出流时间基。
    确保数据包的PTS/DTS在转换后保持单调递增,供后续排序和同步使用。
  • (2)以音频为基准的同步逻辑
    • 音频时钟:
      基于音频实际播放的样本数计算实时时钟(如 audio_clock = 已播放样本数 / 采样率),作为同步基准。
    • 视频帧处理:
      解码后按PTS(显示顺序)排序,而非DTS(解码顺序)。
      计算视频帧显示时间与音频时钟的差值 delay = 视频PTS - 音频时钟:
      delay > 0:视频超前,等待或降低播放速度。
      delay < -阈值:视频落后,丢弃非关键帧或加快播放。
  • (3)动态调整策略
    • 缓冲与排序:
      解码器输出的帧按PTS存入队列,确保显示顺序正确(处理 B 帧乱序问题)。
    • 丢帧与重复帧:
      严重落后时丢弃 B 帧 / P 帧(保留 I 帧),避免卡顿。
      严重超前时重复显示上一帧,避免音画脱节。
      播放速度微调:
      轻微差异时调整视频播放速度(±5% 范围内),平滑同步误差。
  • (4)FFmpeg 关键 API 支持
    时间基转换:av_packet_rescale_ts(pkt, 源时间基, 目标时间基),统一音视频时间戳单位。
    交错写入:av_interleaved_write_frame() 按PTS排序输出数据包,确保文件中音视频交错正确。
    精准跳转:avformat_seek_file() 基于音频时钟定位,处理快进 / 快退后的同步恢复。

3 总结
H.264 中 PTS 与 DTS 的差异通过以下步骤实现音视频同步:
统一时间基:转换音视频时间戳到相同单位,消除格式差异。
音频基准:以音频时钟为参考,动态调整视频显示时机(等待、调速、丢帧)。
FFmpeg 工具:利用 API 处理时间戳转换、帧排序和交错输出,简化同步逻辑。
鲁棒性策略:通过缓冲、丢帧等机制应对解码乱序和同步误差,确保播放流畅。

http://www.xdnf.cn/news/368155.html

相关文章:

  • 今日行情明日机会——20250509
  • Codeforces Round 1023 (Div. 2)
  • 反向沙箱介绍
  • 麒麟系统使用-个性化设置
  • 库室指静脉人脸门禁机 LK-BM-S10C/JR
  • CDGP|数据治理怎么带动企业高速发展?
  • 革新锅炉厂智能控制——Ethernet IP转CANopen协议网关的工业互联新方案
  • 【UltralyticsYolo11图像分类完整项目-04】代码重构
  • 出现在‘{‘的段错误
  • 【RAG官方大神笔记】检索增强生成 (RAG):Python AI 教程的详细介绍
  • 【Qwen3_ 4b lora xinli】
  • 深入理解大模型分片优化:Late Chunking 技术解析
  • A2A与MCP定义下,User,Agent,api(tool)间的交互流程图
  • Agent-S: 操作计算机的智能代理框架
  • LVGL源码学习之渲染、更新过程(3)---绘制和刷写
  • 华为欧拉(EulerOS)系统全栈软件部署指南:从 Redis 到 MySQL 实战详解
  • JAVA继承中变量和方法的存储和方法中访问变量的顺序
  • 视频流:大华及海康视频流本地测试预览
  • LeetCode 解题思路 47(最长回文子串、最长公共子序列)
  • SQL注入的绕过方式
  • 【人工智能学习之动作识别TSM训练与部署】
  • 通信阵列波导性能提升难?OAS 软件助力精准解决
  • 操纵杆支架加工工艺及钻3φ11孔夹具设计
  • TransPose: Keypoint Localization via Transformer(ICCV2021)
  • 【UEFN】用于可靠多模态情感分析的高效不确定性估计融合网络
  • ASCII码的快速记忆方法
  • 优雅草星云智控系统产品发布会前瞻:SNMP协议全设备开启指南-优雅草卓伊凡
  • 【传感器】代码——DHT11温湿度传感器
  • 企业如何选择靠谱的软件测试外包公司?
  • CSS实现图片垂直居中方法