libvlc 快退_libVLC 播放控制

c911b25dbee0b492a1a5ed13bd194133.gif

虽然之前介绍了 libVLC 的工作流程,但只能实现简单的播放。与真正的媒体播放器相比,还相差甚远,因为它连一些基本的控制都没有,像播放/暂停、停止、跳播、快进/快退、音量调节、静音等。

为了让我们的播放器更加专业一些,现在是时候加上这些功能了!

1

包装器

为了和 UI 分离,需要单独定义一个 Player 类,作为 libVLC 的一个包装器,它的主要作用是提供基本的媒体播放控制功能!

将上述所描述的接口添加进来,同时,再定义一些对应的信号,当有事件发生时,进行通知:

class Player : public QObject
{
    Q_OBJECT

public:
    // 播放状态
    typedef enum State {
        Idle,
        Opening,
        Buffering,
        Playing,
        Paused,
        Stopped,
        Ended,
        Error
    } State;

    explicit Player(QObject *parent = nullptr);
    ~Player();
    // 设置视频输出窗口
    void setVideoWindow(QWidget *window);
    // 获取当前状态
    Player::State state();

Q_SIGNALS:
    // 总时长发生变化
    void durationChanged(qint64 dur);
    // 当前时间发生变化
    void timeChanged(qint64 time);
    // 播放位置发生变化
    void positionChanged(float pos);
    // 状态发生变化
    void stateChanged(Player::State state);

public Q_SLOTS:
    // 打开文件
    void openFile(const QString &file);
    // 设置音量
    void setVolume(int vol);
    // 跳播
    void seek(int pos);
    // 播放
    void play();
    // 暂停
    void pause();
    // 停止
    void stop();

private:
    // 订阅事件
    void attachEvents();

private:
    libvlc_instance_t *m_instance          {nullptr};
    libvlc_media_player_t *m_player        {nullptr};
    libvlc_media_t *m_media                {nullptr};
    libvlc_event_manager_t *m_eventManager {nullptr};

    QWidget *m_videoWindow           {nullptr};
};

接口较多,挑一些核心的介绍一下。

2

订阅事件

这一步很关键,因为要实时获取媒体信息的话,必须订阅相关事件。比如,播放时间发生变化时,需要更新 UI 上的当前时间,这时就需要监听 libvlc_MediaPlayerTimeChanged 事件。

有关播放状态、音量、是否静音、媒体时长等相关的事件为以下几个:

void Player::attachEvents()
{
    // 事件列表
    QList events;
    events <           <           <           <           <           <           <           <           <           <           <           <// 订阅事件
    foreach (const libvlc_event_e &e, events) {
        libvlc_event_attach(m_eventManager, e, handleEvents, this);
    }
}

紧接着,需要在回调函数中对这些事件进行处理,可以将这些信息保存起来,也可以通过信号的形式发射出去:

// 回调函数,用于事件处理
static void handleEvents(const libvlc_event_t *event, void *userData){
    Player *player = static_cast(userData);switch (event->type) {// 播放状态改变case libvlc_MediaPlayerOpening:case libvlc_MediaPlayerBuffering:break;case libvlc_MediaPlayerPlaying: {
        emit player->stateChanged(Player::Playing);break;
    }case libvlc_MediaPlayerPaused: {
        emit player->stateChanged(Player::Paused);break;
    }case libvlc_MediaPlayerStopped: {
        emit player->stateChanged(Player::Stopped);break;
    }case libvlc_MediaPlayerEncounteredError: {
        emit player->stateChanged(Player::Error);break;
    }// 时长改变case libvlc_MediaPlayerLengthChanged: {
        qint64 dur = event->u.media_player_length_changed.new_length;
        emit player->durationChanged(dur);break;
    }// 播放时间改变case libvlc_MediaPlayerTimeChanged: {
        qint64 time = event->u.media_player_time_changed.new_time;
        emit player->timeChanged(time);break;
    }// 播放位置改变case libvlc_MediaPlayerPositionChanged: {float pos = event->u.media_player_position_changed.new_position;
        emit player->positionChanged(pos);break;
    }default:break;
    }
}

3

播放控制

当然了,最主要的是控制入口,这是外部调用的主要方式。

播放

对于播放来说,需要判断一下当前的状态;如果当前处于暂停状态,则恢复播放;否则,直接进行播放:

void Player::play()
{
    WId curWId = 0;
    if (nullptr != m_videoWindow)
        curWId = m_videoWindow->winId();

    // 指定输出窗口
#if defined (Q_OS_WIN)
    libvlc_media_player_set_hwnd(m_player, (void*)curWId);
#elif defined(Q_OS_MAC)
    libvlc_media_player_set_nsobject(m_player, (void *)curWId);
#else
    libvlc_media_player_set_xwindow(m_player, curWId);
#endif

    // 恢复或者播放
    if (state() == Player::Paused) {
        libvlc_media_player_set_pause(m_player, false);
    } else {
        libvlc_media_player_play(m_player);
    }
}

暂停

和上面的恢复播放一样,暂停也使用的是 libvlc_media_player_set_pause() 接口,只不过第二个参数为 true:

void Player::pause()
{
    if (libvlc_media_player_can_pause(m_player))
        libvlc_media_player_set_pause(m_player, true);
}

停止

如果想停止播放,直接使用 libvlc_media_player_stop() 即可,比较简单:

void Player::stop()
{
    libvlc_media_player_stop(m_player);
}

音量调节

在设置音量时,需要注意一下, libvlc_audio_set_volume() 的第二个参数是指音量的百分比。如果为 0,则表示静音;如果是 100,则是 0dB:

void Player::setVolume(int vol)
{
    libvlc_audio_set_volume(m_player, vol);
}

跳播

跳播相对来说复杂一些,因为需要将位置和时长对应起来。跳播的实现方式有两种,任选一种都可以:

  • 跳播到指定时间:使用 libvlc_media_player_set_time()

  • 跳播到指定位置:使用 libvlc_media_player_set_position()

以方式一为例,假设我们的播放滑块取值范围是 0 - 100,那么 float(pos)/100 就是 pos 所在位置占总范围的百分比。将这个结果乘以总时长 float(duration),算出的就是 pos 位置对应的时间。有了这个时间,就可以使用 libvlc_media_player_set_time() 进行跳播了:

void Player::seek(int pos)
{
    libvlc_media_t *curMedia = libvlc_media_player_get_media(m_player);
    if (nullptr == curMedia)
        return;

    libvlc_time_t duration = libvlc_media_get_duration(curMedia);
    float ms = float(pos)/100 * float(duration);
    libvlc_media_player_set_time(m_player, libvlc_time_t(ms));
}

大概的功能先介绍到这里,后面的更精彩,敬请期待吧!

·END·

2dbbc046c908442d32c2a515a22ecd0c.gif

作者:一去、二三里 爱学习,爱编程,爱生活。 欢迎来撩,一起畅谈程序人生!

点个在看,么么哒!

8a075f983b922d66bbff534d74d6e51a.gif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值