美文网首页
34_音视频播放器_音视频同步

34_音视频播放器_音视频同步

作者: 咸鱼Jay | 来源:发表于2022-11-16 20:16 被阅读0次

简介

音视频同步的实现可以有两种方式

  1. 视频同步到音频
  2. 音频同步到视频

我们这里选择第一种,因为音频播放的频率是SDL控制的,我们没法改变,所以使用视频同步到音频。

实现音视频同步

videoplayer.h先定义两个全局变量,用于记录音频时钟和视频时钟

/** 音频时钟,当前音频包对应的时间值 */
double _aTime = 0;
/** 视频时钟,当前视频包对应的时间值 */
double _vTime = 0;

在音频处理类videoplayer_audio.cpp里保存音频时钟

// 保存音频时钟
if (pkt.pts != AV_NOPTS_VALUE) {
    _aTime = av_q2d(_aStream->time_base) *pkt.pts;
}

videoplayer_video.cpp里的解码视频方法decodeVideo里记录视频时钟并进行音画同步

// 视频时钟
if (pkt.dts != AV_NOPTS_VALUE) {
    _vTime = av_q2d(_vStream->time_base) * pkt.dts;
}

// 如果视频包过早被解码出来,那就需要等待对应的音频时钟到达
while (_vTime > _aTime && _state == Playing) {
    SDL_Delay(5);
}

处理没有音频的播放

上面音视频同步是一个视频文件里有音频的情况下可以正常使用,但是如果一个视频文件没有音频是不能正常使用。

videoplayer.cppreadFile方法里的局部判断是否有音频和视频弄成成员变量:

// videoplayer.h
/** 是否有音频流 */
bool _hasAudio = false;
/** 是否有视频流 */
bool _hasVideo = false;

// videoplayer.cpp
// 初始化音频信息
_hasAudio = initAudioInfo() >= 0;
// 初始化视频信息
_hasVideo = initVideoInfo() >= 0;
if (!_hasAudio && !_hasVideo) {
   emit playFailed(this);
   free();
   return;
}

videoplayer_video.cpp中音画同步的地方添加是否有音频判断

if(_hasAudio){// 有音频
    // 如果视频包过早被解码出来,那就需要等待对应的音频时钟到达
    while (_vTime > _aTime && _state == Playing) {
        SDL_Delay(5);
    }
}

更新界面播放的进度条

因为我们音视频同步是根据音频为基准的,所以我们可以在音频获取音频时钟的地方,把音频时钟发送到界面里进行更新。

videoplayer.cpp中给外界提供获取当前的播放时刻的方法

/** 当前的播放时刻(单位是秒) */
int VideoPlayer::getTime(){
    return round(_aTime);// round四舍五入的意思
}

在提供一个信号量用于给外界发送消息

void timeChanged(VideoPlayer *player);

然后在videoplayer_audio.cpp里的获取音频当前时刻的地方,发送信号给外界

// 保存音频时钟
if (pkt.pts != AV_NOPTS_VALUE) {
    _aTime = av_q2d(_aStream->time_base) *pkt.pts;
    // 通知外界:播放时间点发生了改变
    emit timeChanged(this);
}

在界面类mainwindow.cpp里注册当前播放时刻的监听

connect(_player, &VideoPlayer::timeChanged,
            this, &MainWindow::onPlayerTimeChanged);
            
void MainWindow::onPlayerTimeChanged(VideoPlayer *player) {
    ui->currentSlider->setValue(player->getTime());
}

处理切换音视频时还保留上一个视频的最后一帧画面

我们在播放一个视频文件时,点击停止后在去播放另外一个视频文件,会出现上一个视频的最后一帧画面。

我们点击停止后,会发出停止的信号出来,而我们的VideoWidget类里也有出来状态改变的监听,那么还是会出现上一个视频的最后一帧画面呢?

// 状态改变的监听
void VideoWidget::onPlayerStateChanged(VideoPlayer *player) {
    if (player->getState() != VideoPlayer::Stopped) return;

    freeImage();
    update();
}

这是因为VideoWidget类里onPlayerFrameDecoded方法是在主线程,而发射它的信号(frameDecoded)是在子线程中,所以有多线程的情况,就会导致出现这种情况,现在我们需要在onPlayerFrameDecoded方法里添加判断

void VideoWidget::onPlayerFrameDecoded(VideoPlayer *player,
                                       uint8_t *data,
                                       VideoPlayer::VideoSwsSpec &spec) {
    if (player->getState() == VideoPlayer::Stopped) return;
    ......
}

源码链接

相关文章

  • 34_音视频播放器_音视频同步

    简介 音视频同步的实现可以有两种方式 视频同步到音频 音频同步到视频 我们这里选择第一种,因为音频播放的频率是SD...

  • 29_SDL 多线程与锁机制

    一、简介 为什么要用多线程?在音视频领域主要是实现音视频同步。实现了音视频同步,我们的播放器就基本上合格了。多线程...

  • Ffmpeg音视频常用命令

    播放器架构 同时还有音视频同步,这个是很重要的。 渲染流程 1、FFmpeg常用命令实战 FFmpeg音视频处理流...

  • ffmpeg中的时间戳与时间基

    前言 在开发多媒体播放器或直播系统时,音视频的同步是非常关键且复杂的点。要想把音视频同步搞明白,我们必须要了解一些...

  • FFmpeg中的时间戳与时间基

    简介 在开发多媒体播放器或直播系统时,音视频的同步是非常关键且复杂的点。要想把音视频同步搞明白,我们必须要了解一些...

  • FFmpeg 音视频同步

    音视频播放器的工作的具体流程如下图所示: 简单的来说包括:解协议,解封装,对音频和视频分别进行解码,音视频同步播放...

  • FFmpeg命令行工具ffplay

    插播下音画同步的知识: 其中的音频为基准进行音视频同步: ffplay设置音视频同步方式: 播放封装好的音视频: ...

  • FFmpeg 音视频同步

    FFmpeg简易播放器的实现5-音视频同步 写的很不错 : https://www.cnblogs.com/lei...

  • 图片资源音视频文件添加header防盗链Referer iOS

    flutter视频播放器 flutter图片资源 iOS 原生OC 音视频 iOS swift 音视频 iOS s...

  • ffplay.c源码阅读之音频、视频、字幕同步原理(四)

    前言 音视频同步 所谓音视频同步,是指视频画面和音频声音给用户的感觉是差不多的,一致的。对于已经压缩好的音视频流(...

网友评论

      本文标题:34_音视频播放器_音视频同步

      本文链接:https://www.haomeiwen.com/subject/uqjlxdtx.html