ffmpeg 同步

本文详细介绍了音视频同步的三种方式,包括以音频为基准同步视频、设置播放速度同步以及使用AudioQueue和AVPlayer控制播放速率。同时讨论了帧时间戳(pts)在音频和视频流中的应用,以及FrameQueue在同步过程中的作用。
摘要由CSDN通过智能技术生成

音视频同步有三种方式

  1. 同步音频到视频
  2. 同步到外部时钟
  3. 同步视频到音频

同步视频到音频

  • 以audio为基准同步video,只要设置好了 ao 的参数,如sample rate, channels, sample size等, audio驱动就能以正确的速度播放,所以只要程序里write不出大问题的话,这种同步是非常有效的。
  • 设置以声音为基准进行同步,声频播放是只管自己播放,视频每渲染一张图片取到的avframe中对应的时间戳和音频适中的时间戳进行对比,调整视频的渲染速度。
  • 设置声音为2倍速度进行播放,让视频同步音频,测试可以完美支持。
  • 音频去同步视频设置多倍速度播放,无法有简单的方式指定视频严格的按照两倍的速度进行播放。
  • 三个clock,一个音频的,一个视频,一个中立的。
  • 以视频为准,AudioQueue每读取一音频帧,读取当前帧中的时间戳,并通过到中立的clock中。
  • 播放视频的时候,每渲染一个视频帧都需要拿videoclock和中立的clock进行对比,来决定是否要进行渲染。

二倍速度播放音频

  • AVPlayer 修改视频的播放速度

属性:

/* indicates the current rate of playback; 0.0 means "stopped", 1.0 means "play at the natural rate of the current item" */
@property (nonatomic) float rate;

实例代码:

-(void)setPlaybackRate:(float)playbackRate
{
   _playbackRate = playbackRate;
   if (_player != nil && !isFloatZero(_player.rate)) {
       _player.rate = _playbackRate;
   }
}
  • AudioQueue修改视频的播放速度
    实例代码:
-  (void)setPlaybackRate:(float)playbackRate
{
    if (fabsf(playbackRate - 1.0f) <= 0.000001) {
        UInt32 propValue = 1;
        AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue));
        AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_PlayRate, 1.0f);
    } else {
        UInt32 propValue = 0;
        AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue));
        AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_PlayRate, playbackRate);
    }
}

pts

视频读取pts

  • 函数实例:
 ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
                    ffp->stat.vdps = SDL_SpeedSamplerAdd(&ffp->vdps_sampler, FFP_SHOW_VDPS_AVCODEC, "vdps[avcodec]");
                    if (ffp->decoder_reorder_pts == -1) {
                        frame->pts = av_frame_get_best_effort_timestamp(frame);
                    } else if (ffp->decoder_reorder_pts) {
                        frame->pts = frame->pkt_pts;
                    } else {
                        frame->pts = frame->pkt_dts;
                    }
                }
  • 视频获取时间戳

int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame);

音频读取pts

函数实例:

 ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
                    AVRational tb = (AVRational){1, frame->sample_rate};
                    if (frame->pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(frame->pts, d->avctx->time_base, tb);
                    else if (frame->pkt_pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(frame->pkt_pts, av_codec_get_pkt_timebase(d->avctx), tb);
                    else if (d->next_pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
                    
                    if (frame->pts != AV_NOPTS_VALUE) {
                        d->next_pts = frame->pts + frame->nb_samples;
                        d->next_pts_tb = tb;
                    }
                }

音频一个AVPacket中只解析一个AVFrame, pkt_pts 可以当做真实的pts

流的时间基准

从某个音频或者视频流的时间基准中得到时间戳的 AVRational

AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx);

FrameQueue

typedef struct FrameQueue {
    Frame queue[FRAME_QUEUE_SIZE];
    int rindex;         // read index
    int windex;     // write index 
    int size;           // 大小
    int max_size;
    int keep_last;
    int rindex_shown; // read shown 已经读取的个数 
    SDL_mutex *mutex;
    SDL_cond *cond;
    PacketQueue *pktq;
} FrameQueue;

几个重要的函数

  1. synchronize_audio 音频clock校准函数
  2. video_refresh 视频的渲染调用
  3. compute_target_delay 计算音频和视频的delay
  4. update_video_pts 同步视频的时间戳
  5. audio_decode_frame 读取音频数据后同步音频时钟
  6. video_refresh_thread remaining_time决定每次休眠时间

粉丝福利, 免费领取C++音视频学习资料包+学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值