FFMPEG音视频同步

2020-08-06  本文已影响0人  明日即是今朝

问题

在写ffmpeg音视频同步的时候,我是参考了动脑老师的方法,根据音频的时间来同步视频,写完以后发现播放mp4文件音视频同步,流畅度基本上是没有问题的,但是播放直播流就会有问题,有时候音频和视频的差距很大导致视频根本就出不来(因为视频比音频块了很多,这样会让他睡很久,所以没视频),那这里我自己又没有音视频的经验根本解决不了这个问题,这个时候只能去看下ffmpeg提供的ffplay的源码,看看他的音视频同步是怎么做的,这样来解决我自己音视频同步的问题。ffplay还是挺大的,希望自己花几天时间搞明白他,最起码搞明白他音视频同步的方案,他好像三种方案都写了,以视频为基准,以音频为基准和以外部时间为基准。下面我先贴出我当前有问题的音视频同步代码,如果有知道问题的麻烦能不吝赐教。

 //每个画面刷新的时间间隔
    double frameDelays = 1.0 / fps;
    while (isPlaying) {
        frames.pop(frame);
        sws_scale(swsContext, frame->data, frame->linesize, 0, codecContext->height, dst_data,
                  dst_linesize);
        //做音视频同步  获取当前视频的时间
        double clock = frame->best_effort_timestamp * av_q2d(time_base);
        //还有个额外的时间
        double extra_delay = frame->repeat_pict / (2 * fps);
        //真正的延时
        double delays=frameDelays+extra_delay;
        double audioClock = audioChannel->clock;
        double diff=clock-audioClock;
        LOGE("player diff %f audioClock %f  videoclock  %f",diff,audioChannel->clock,clock);
        if(!audioChannel){
//            //如果没有音频  就睡这么长时间
            av_usleep(delays*1000000);
        } else{
            if (clock==0){
                //刚刚开始
                av_usleep(delays*1000000);
            } else {
                //比较音频和视频
                double audioClock = audioChannel->clock;

                double diff=clock-audioClock;
                if(diff>0){
                    //视频比音频快
                    LOGE("player 视频快了");
                    av_usleep((delays+diff)*1000000);
                } else if (diff<0){
                    LOGE("player  音频快了");
                    //视频积压太多  就丢包
                    if(fabs(diff)>=0.05){
                        releaseAvFrame(&frame);
                        frames.sync();
                        continue;
                    } else{
                        //不要睡  赶紧去跟上
                    }
                }
            }
        }
 int datasize = 0;
    AVFrame *avFrame;
    int ret = frames.pop(avFrame);

    //对avframe 进行重采样
    //1、拿到积压的数据
    int64_t delays = swr_get_delay(swrContext, avFrame->sample_rate);

    //最大能返回多少个数据
    int max_samples = av_rescale_rnd(delays + avFrame->nb_samples, out_sample_rate,
                                     avFrame->sample_rate, AV_ROUND_UP);
    //返回每个声道的输出数据
    int samples = swr_convert(swrContext, &data, max_samples, (const uint8_t **) avFrame->data,
                              avFrame->nb_samples);
    datasize=samples*out_samplesize*out_channels;



    //当前音频的时间戳
    clock=avFrame->pts*av_q2d(time_base);

主要是通过音频的clock去同步视频的clock,不知道为什么直播流的播放页面会非常卡。

总结

这次主要是记录当前的问题,和我接下来要做的工作,分析ffplay源码,解决音视频同步问题。

上一篇 下一篇

猜你喜欢

热点阅读