This is the 24th day of my participation in the August Text Challenge.More challenges in August
QT + VS2015, get every frame of VLC and render it to Qwidget
1. Rely on downloads
VLC depends on dynamic library and static library, download the official website (VLC-3.0.4, 64 bits), if you need to download 32 bits to win32 directory download.
Download.videolan.org/pub/videola…
In addition, I uploaded it to CSDN: for everyone to download:
Download.csdn.net/download/u0…
1.2 Decompress the files and copy the plugins folder, libvlc. DLL file, libvlccore. DLL file, and include and lib folders in the SDK folder.
1.3 Then copy the plugins folder and the libvlc. DLL and libvlccore. DLL files to the same directory as exe, and copy the include and lib folders to the same directory as CPP code.
2. Link configuration
2.1 Open VS2015, right-click the project, open the properties page, select the C/C++ TAB, select General, Attach the include directory, and add a.\include item.
2.2 Switch to the linker TAB, select General, attach the library directory, and add a.\lib.
3. Code presentation
Rendering idea: Convert each frame of the callback into a QImage, and then place the QImage at the end of the list. Then use the slot function to tell paintEvent to pull a frame from the top of the list and draw it using the drawPixmap method. Remove the rendered image from the list header after drawing.
#include <QtWidgets/QWidget> #include <QPaintEvent> class Vedio: QWidget {Q_OBJECT public: Vedio(QWidget *parent = Q_NULLPTR); void updatePicture(const QImage &image); static Vedio *pThis; Protected: virtual void paintEvent(QPaintEvent *event); signals: void showImage(); private: std::list<QImage> lists; };Copy the code
Libvlc_media_player_set_hwnd (mp, (void *)this->winId()); Pass in the window handle to play the video, but when you need to get each frame to render yourself, this method will not work, you need to use libvlc_video_set_callbacks(mp, lock, unlock, display, CTX); Method processes the data in the three VLC callbacks that render each frame manually: Lock, unlock, and display.
// CPP file #include "vedio.h" #include <include/ VLC /vlc.h> #pragma comment(lib, "libvlc.lib") #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; QImage image(data, VIDEO_WIDTH, VIDEO_HEIGHT, QImage::Format_RGBA8888); PThis -> updateTure (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]; // Apply pixels memset(CTX -> Pixels, 0, VIDEO_WIDTH * VIDEO_HEIGHT * 4); // Apply pixels 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(); }Copy the code
After the above steps, we have completed the rendering of the entire video. Since paintEvent method uses CPU calculation, and we constantly generate QImage objects, it has a high CPU load.
In fact, we can use Opencv or openGL to draw this piece, using GPU to reduce the CPU calculation load.