1、依赖下载
1.1 首先下载VLC依赖动态库和静态库,官网下载(VLC-3.0.4,64位),如需下载32位去 win32 目录下载即可。
VLC官网下载http://download.videolan.org/pub/videolan/vlc/3.0.4/win64/
另外我上传到了csdn:方便大家下载:
https://download.csdn.net/download/u012534831/10776378
1.2 下载完成后解压,拷贝出其中的 plugins 文件夹,libvlc.dll 文件,libvlccore.dll 文件,和sdk文件夹下的 include 和 lib 文件夹,总共5项。
image1.3 然后将 plugins 文件夹和 libvlc.dll 和 libvlccore.dll 文件拷贝到exe的同级目录,同时将 include 和 lib 文件夹拷贝到 cpp 代码的同级目录。
image2、链接配置
2.1 打开VS2015,右键项目,打开属性页,选择C/C++ 标签,选择常规, 附加包含目录,添加一项 .\include 。
include附加包含目录配置2.2 切换到链接器标签,选择常规,附加库目录,添加一项 .\lib 。
lib附加库目录配置3、代码展示
渲染思路: 将回调的每一帧转为 QImage,然后将 QImage 放入 list 末尾,然后使用槽函数通知 paintEvent 从 list 的头部取出一帧图像,使用 drawPixmap 方法进行绘制,绘制完成后从list头部移除渲染过的 image 图像。
// 头文件
#pragma once
#include <QtWidgets/QWidget>
#include <QPaintEvent>
class Vedio : public QWidget
{
Q_OBJECT
public:
Vedio(QWidget *parent = Q_NULLPTR);
void updatePicture(const QImage &image);
static Vedio *pThis; //声明 pThis 对象方便我们在静态函数中调用成员函数
protected:
virtual void paintEvent(QPaintEvent *event);
signals:
void showImage();
private:
std::list<QImage> lists;
};
正常情况下我们播放 VLC 视频只需要调用 libvlc_media_player_set_hwnd(mp, (void *)this->winId()); 传入窗口句柄即可播放视频,但是当需要获取每一帧自己去渲染的时候,此方法就失效了,需要通过 libvlc_video_set_callbacks(mp, lock, unlock, display, ctx); 方法在 VLC 提供的三个回调方法中处理数据,手动去渲染每一帧,这三个回调方法为 lock,unlock 和 display 方法。
// cpp文件
#include "vedio.h"
#include <include/vlc/vlc.h>
#pragma comment(lib, "libvlc.lib")
#pragma comment(lib, "libvlccore.lib")
#include <QPixmap>
#include <QImage>
#include <QPainter>
#include <QMutex>
using namespace std;
// 定义输出视频的分辨率
#define VIDEO_WIDTH 1920
#define VIDEO_HEIGHT 1280
struct context {
QMutex mutex;
uchar *pixels;
};
static void *lock(void *opaque, void **planes)
{
struct context *ctx = (context *)opaque;
ctx->mutex.lock();
*planes = ctx->pixels;
return NULL;
}
static void unlock(void *opaque, void *picture, void *const *planes)
{
struct context *ctx = (context *)opaque;
unsigned char *data = (unsigned char *)*planes; // planes即为帧数据
QImage image(data, VIDEO_WIDTH, VIDEO_HEIGHT, QImage::Format_RGBA8888);// 指定生成的图片格式为 RGBA 4通道
Vedio::pThis->updatePicture(image); //
ctx->mutex.unlock();
}
static void display(void *opaque, void *picture)
{
(void)opaque;
}
Vedio* Vedio::pThis = nullptr;
Vedio::Vedio(QWidget *parent)
: QWidget(parent)
{
pThis = this;
//
connect(this, SIGNAL(showImage()), this, SLOT(update()));
libvlc_instance_t * inst;
libvlc_media_player_t *mp;
libvlc_media_t *m;
context *ctx = new context;
ctx->pixels = new uchar[VIDEO_WIDTH * VIDEO_HEIGHT * 4]; // 申请大小也为4通道的像素
memset(ctx->pixels, 0, VIDEO_WIDTH * VIDEO_HEIGHT * 4);
libvlc_time_t length;
int width;
int height;
inst = libvlc_new(0, NULL);
m = libvlc_media_new_path(inst, u8"C:\\Users\\HiWin10\\Desktop\\4K.mp4");
mp = libvlc_media_player_new_from_media(m);
//libvlc_media_player_set_hwnd(mp, (void *)this->winId());
libvlc_video_set_callbacks(mp, lock, unlock, display, ctx);
libvlc_video_set_format(mp, "RGBA", VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_WIDTH * 4);
libvlc_media_release(m);
libvlc_media_player_play(mp);
}
void Vedio::updatePicture(const QImage &image)
{
lists.push_back(image);
emit showImage();
}
void Vedio::paintEvent(QPaintEvent *event)
{
if (lists.empty())
{
return;
}
QPainter painter(this);
painter.drawPixmap(this->rect(), QPixmap::fromImage(lists.front()));
lists.pop_front();
}
经过上面的步骤我们已经完成了整个视频的渲染,由于 paintEvent 方法使用的是cpu计算,且我们不停的生成的是 QImage 对象,因此对 CPU 负荷较高。
其实在绘制这块我们可以使用 Opencv 或者 openGL 去绘制,利用 GPU 减轻 CPU 计算负荷。
网友评论