QT应用编程:基于VLC开发音视频播放器(回调方式)

简介: QT应用编程:基于VLC开发音视频播放器(回调方式)

一、环境介绍

操作系统: win10 64位


QT版本:  QT5.12.6


编译器:  MinGW 32


VLC版本: 3.0.12


完整项目代码下载地址:  https://download.csdn.net/download/xiaolong1126626497/16579867


上篇文章讲的是使用句柄方式,这篇文章使用回调的方式截取VLC输出的每帧数据,自己完成图像显示处理。

image.png

image.png

二、下载VLC的SDK文件

参考这里:  https://blog.csdn.net/xiaolong1126626497/article/details/115174182


三、创建QT工程,编写简单的播放器

参考这里:  https://blog.csdn.net/xiaolong1126626497/article/details/115174182


3.4  widget.cpp代码

#include "widget.h"
#include "ui_widget.h"
Widget* Widget::pThis = nullptr;
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    pThis=this;
    ui->setupUi(this);
    this->setWindowTitle("视频播放器");
    //VLC相关的初始化
    vlc_base=libvlc_new(0, nullptr); //创建并初始化libvlc实例
    if(!vlc_base)
    {
        qDebug()<<"libvlc_new 执行错误.";
    }
     ctx.pixels=nullptr;
    //播放速度设置
    ui->MediaSpeedBtn->setCheckable(true);
    m_TimeSpeedGrp = new QActionGroup(this);
    QStringList strSpeedItems;
      strSpeedItems << tr("0.03X") << tr("0.06X") << tr("0.1X") << tr("0.15X") << tr("0.2X") << tr("0.3X") << tr("0.4X") << tr("0.5X") << tr("0.6X") << tr("0.8X") << tr("1.0X") << tr("1.25X") << tr("1.5X") << tr("2.0X") << tr("4.0X") << tr("8.0X");
      float speeds[] = { 0.03, 0.06, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5,0.6,0.8,1.0,1.25,1.5,2.0,4.0,8.0};
    for (int i = 0; i < strSpeedItems.size(); i++)
    {
        QAction *pSpeedItem = m_SpeedMenu.addAction(strSpeedItems.at(i));
        pSpeedItem->setData(QVariant::fromValue(speeds[i]));
        pSpeedItem->setCheckable(true);
        m_TimeSpeedGrp->addAction(pSpeedItem);
        if (i == 10)
        {
            pSpeedItem->setChecked(true);
        }
    }
    connect(m_TimeSpeedGrp, SIGNAL(triggered(QAction *)), this, SLOT(slot_onSetTimeSpeed(QAction *)));
}
Widget::~Widget()
{
    delete ui;
    libvlc_release(vlc_base); //减少libvlc实例的引用计数,并销毁它
}
/*
工程: QtVLC_Player
日期: 2021-03-24
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 打开本地文件
*/
void Widget::on_pushButton_open_clicked()
{
    /*选择文件*/
    QString filename=QFileDialog::getOpenFileName(this,"选择打开的文件","D:/",tr("*.*"));
    /* 将 / 转为windows下的右斜杆 */
    std::replace(filename.begin(), filename.end(), QChar('/'), QChar('\\'));
    qDebug()<<"播放的媒体:"<<filename;
    //宽高清0
    video_width=0;
    video_height=0;
    /*为特定文件路径创建媒体*/
    if(vlc_media)libvlc_media_release(vlc_media);
    vlc_media=libvlc_media_new_path(vlc_base,filename.toUtf8().data());
    if(vlc_media==nullptr)
    {
        qDebug()<<"libvlc_media_new_path 执行错误.";
        return;
    }
    /*根据给定的媒体对象创建一个播放器对象*/
    if(vlc_mediaPlayer)libvlc_media_player_release(vlc_mediaPlayer);
    vlc_mediaPlayer=libvlc_media_player_new_from_media(vlc_media);
    // 设置回调,用于提取帧或者在界面上显示。
     libvlc_video_set_callbacks(vlc_mediaPlayer, vlc_lock, vlc_unlock, display, &ctx);
    /*解析媒体实例*/
    // libvlc_media_parse(vlc_media);
    /*获取媒体播放器事件管理器*/
    libvlc_event_manager_t *em = libvlc_media_player_event_manager(vlc_mediaPlayer);
    libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, vlcEvents, this);
    libvlc_event_attach(em, libvlc_MediaPlayerEndReached, vlcEvents, this);
    libvlc_event_attach(em, libvlc_MediaPlayerStopped, vlcEvents, this);
    libvlc_event_attach(em, libvlc_MediaPlayerPlaying, vlcEvents, this);
    libvlc_event_attach(em, libvlc_MediaPlayerPaused, vlcEvents, this);
    /*播放媒体文件*/
    if(vlc_mediaPlayer)libvlc_media_player_play(vlc_mediaPlayer);
    //等待VLC解析文件.否则下面的时间获取不成功
    QThread::msleep(100);
    //获取媒体文件总长度 ms
    libvlc_time_t length = libvlc_media_player_get_length(vlc_mediaPlayer);
    qDebug()<<"媒体文件总长度:"<<length;
    ui->label_t2->setText(QString("%1").arg(length));
    //获取当前媒体播放的位置
    libvlc_time_t current_movie_time=libvlc_media_player_get_time(vlc_mediaPlayer);
    qDebug()<<"获取当前媒体播放的位置:"<<current_movie_time;
    libvlc_video_get_size(vlc_mediaPlayer,0,&video_width,&video_height);
    qDebug()<<"视频尺寸:"<<"width:"<<video_width<<"height:"<<video_height;
    if(ctx.pixels)
    {
        delete ctx.pixels;
    }
    ctx.pixels = new uchar[video_width * video_height * 4];
    memset(ctx.pixels, 0, video_width * video_height * 4);
    /*设置给予媒体播放器媒体输出的win32/win64窗口句柄*/
    // libvlc_media_player_set_hwnd(vlc_mediaPlayer, (void *)ui->widget_VideoPlay->winId());
    //如果不使用句柄方式,VLC也支持回调方式处理图像,这种方式可以自己提取图像数据,自己渲染显示处理. libvlc_video_set_callbacks
    /*设置给予媒体播放器媒体输出的win32/win64窗口句柄*/
    // libvlc_media_player_set_hwnd(vlc_mediaPlayer, (void *)ui->widget_VideoPlay->winId());
     libvlc_video_set_format(vlc_mediaPlayer, "RV32", video_width, video_height, video_width * 4);
    /*获取媒体播放器使用的媒体。*/
    ui->label_video_name->setText(QString("%1:%2x%3").arg(filename).arg(video_width).arg(video_height));
    //暂停: 停留在第一帧画面
    if(vlc_mediaPlayer)libvlc_media_player_pause(vlc_mediaPlayer);
}
/*
工程: QtVLC_Player
日期: 2021-03-24
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: VLC的事件回调
*/
void Widget::vlcEvents(const libvlc_event_t *ev, void *param)
{
    switch (ev->type){
    case libvlc_MediaPlayerTimeChanged:
         qDebug() << "VLC媒体播放器时间已更改";
         //获取当前媒体播放的位置
         pThis->ui->label_t1->setText(QString("%1").arg(libvlc_media_player_get_time(pThis->vlc_mediaPlayer)));
         break;
    case libvlc_MediaPlayerEndReached:
         qDebug() << "VLC播放完毕.";
        break;
    case libvlc_MediaPlayerStopped:
        qDebug() << "VLC停止播放";
        break;
    case libvlc_MediaPlayerPlaying:
        qDebug() << "VLC开始播放";
        break;
    case libvlc_MediaPlayerPaused:
        qDebug() << "VLC暂停播放";
        break;
    }
}
void Widget::display(void *opaque, void *picture)
{
    (void)opaque;
}
void *Widget::vlc_lock(void *opaque, void **planes)
{
    struct Context *ctx = (struct Context *)opaque;
    ctx->mutex.lock();
    // 告诉 VLC 将解码的数据放到缓冲区中
    *planes = ctx->pixels;
    return nullptr;
}
//获取 argb 帧
void Widget::vlc_unlock(void *opaque, void *picture, void *const *planes)
{
    struct Context *ctx = (struct Context *)opaque;
    unsigned char *data = static_cast<unsigned char *>(*planes);
    if(pThis->video_width>0 && pThis->video_height>0 && data!=nullptr)
    {
        QImage image(data, pThis->video_width,pThis->video_height, QImage::Format_RGB32);
        if(!image.isNull())
        {
            qDebug()<<"采集到新图片:"<<image.width()<<"x"<<image.height();
            pThis->ui->widget_VideoPlay->slotGetOneFrame(image.copy());
        }
    }
    ctx->mutex.unlock();
}
/*
工程: QtVLC_Player
日期: 2021-03-24
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 暂停
*/
void Widget::on_pushButton_pause_clicked()
{
     if(vlc_mediaPlayer)libvlc_media_player_pause(vlc_mediaPlayer);
}
/*
工程: QtVLC_Player
日期: 2021-03-24
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 停止
*/
void Widget::on_pushButton_stop_clicked()
{
    if(vlc_mediaPlayer)libvlc_media_player_stop(vlc_mediaPlayer);
}
/*
工程: QtVLC_Player
日期: 2021-03-24
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 速率
*/
void Widget::slot_onSetTimeSpeed(QAction *action)
{
    action->setChecked(true);
    ui->MediaSpeedBtn->setToolTip(action->text());
    ui->MediaSpeedBtn->setText(action->text());
    /*设置播放速率*/
    if(vlc_mediaPlayer)libvlc_media_player_set_rate(vlc_mediaPlayer,float(action->data().toFloat()));
}
void Widget::on_MediaSpeedBtn_clicked()
{
    QPoint ptWgt = ui->MediaSpeedBtn->mapToGlobal(QPoint(0, 0));
    ptWgt -= QPoint(10, 180);
    QAction *pSelect = m_SpeedMenu.exec(ptWgt);
    if (pSelect == nullptr)
        return;
}
void Widget::on_pushButton_get_state_clicked()
{
    if(vlc_mediaPlayer)
    {
        //4表示暂停  3表示继续   5表示停止
        qDebug()<<"播放状态:"<<libvlc_media_player_get_state(vlc_mediaPlayer);
    }
}
/*
工程: QtVLC_Player
日期: 2021-03-24
作者: DS小龙哥
环境: win10 QT5.12.6 MinGW32
功能: 跳转视频帧
*/
void Widget::on_pushButton_seek_clicked()
{
    if(vlc_mediaPlayer)
    {
        if(!ui->lineEdit_seek->text().isEmpty())
        {
             libvlc_media_player_set_position(vlc_mediaPlayer,ui->lineEdit_seek->text().toFloat()/100);
//             //当前的播放位置
//             float currPos = libvlc_media_player_get_position(vlc_mediaPlayer);
//             libvlc_media_player_set_position (vlc_mediaPlayer, currPos+newPos);
        }
    }
}
void Widget::on_pushButton_reset_clicked()
{
    /*需要先停止才可以继续重头播放*/
    if(vlc_mediaPlayer)libvlc_media_player_stop(vlc_mediaPlayer);
    /*播放媒体文件*/
    if(vlc_mediaPlayer)libvlc_media_player_play(vlc_mediaPlayer);
}
目录
相关文章
|
1月前
|
存储 网络协议 C语言
【C/C++ 串口编程 】深入探讨C/C++与Qt串口编程中的粘包现象及其解决策略
【C/C++ 串口编程 】深入探讨C/C++与Qt串口编程中的粘包现象及其解决策略
79 0
|
1月前
|
安全 前端开发 C++
C++视角下的Qt按钮:从基础应用到高级定制(二)
C++视角下的Qt按钮:从基础应用到高级定制
45 2
|
15天前
|
图形学 Python 容器
【PyQt5桌面应用开发】3.Qt Designer快速入门(控件详解)
【PyQt5桌面应用开发】3.Qt Designer快速入门(控件详解)
35 0
|
23天前
qt开发使用camera类获取摄像头信息并拍照保存
qt开发使用camera类获取摄像头信息并拍照保存
|
29天前
|
测试技术 API UED
【Qt 应用开发 】初步理解 Qt窗口中的模态性应用
【Qt 应用开发 】初步理解 Qt窗口中的模态性应用
70 1
|
1月前
|
监控 C++
C++ Qt开发:QProcess进程管理模块
Qt是一个跨平台的C++图形库,简化了窗体应用开发,支持通过拖放组件提升效率。本章节关注`QProcess`组件,它用于控制和管理进程,例如执行命令、运行可执行文件及与外部进程通信。`QProcess`提供多种方法如`start`、`waitForStarted`和`waitForFinished`等,实现启动、监控和交互。示例展示了如何使用`QProcess`获取系统进程和信息,通过`tasklist`和`systeminfo`命令,并将结果展示在`QTreeWidget`中。
28 0
C++ Qt开发:QProcess进程管理模块
|
1月前
|
存储 算法 数据可视化
Qt与Excel:从底层原理到上层应用的全面探索
Qt与Excel:从底层原理到上层应用的全面探索
36 0
|
1月前
|
设计模式 安全 API
C++视角下的Qt按钮:从基础应用到高级定制(三)
C++视角下的Qt按钮:从基础应用到高级定制
52 0
|
1月前
|
网络协议 C++
C++ Qt开发:QTcpSocket网络通信组件
`QTcpSocket`和`QTcpServer`是Qt中用于实现基于TCP(Transmission Control Protocol)通信的两个关键类。TCP是一种面向连接的协议,它提供可靠的、双向的、面向字节流的通信。这两个类允许Qt应用程序在网络上建立客户端和服务器之间的连接。Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QTcpSocket`组件实现基于TCP的网络通信功能。
38 8
C++ Qt开发:QTcpSocket网络通信组件
|
1月前
|
存储 C++ 网络架构
C++ Qt开发:QUdpSocket实现组播通信
Qt教程:使用`QUdpSocket`实现UDP组播通信。通过设置套接字选项、绑定端口、加入和离开组播组,以及发送和接收数据报,简化跨平台窗体应用开发。关键函数包括`setSocketOption`设置多播TTL,`bind`绑定地址和端口,`joinMulticastGroup`加入组播,`leaveMulticastGroup`退出,`writeDatagram`发送,和`readDatagram`接收数据报。
23 1
C++ Qt开发:QUdpSocket实现组播通信

推荐镜像

更多