ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Qt使用ffmpeg获取视频文件封面图

2026/9/25 1:53:47 拓冰建站 浏览量
Qt使用ffmpeg获取视频文件封面图

Qt使用ffmpeg获取视频文件封面图

#ifndef __THUM_HELPER_H_
#define __THUM_HELPER_H_extern "C" {
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
}
#include <QObject>
#include <QImage>
namespace Media {class ThumHelper :public QObject{Q_OBJECTpublic:ThumHelper();~ThumHelper();void initGlobal();QImage thumnail(const QString& videoPath);};
}#endif  //__THUM_HELPER_H_
#include "ThumHelper.h"Media::ThumHelper::ThumHelper()
{initGlobal();
}void Media::ThumHelper::initGlobal()
{av_register_all();
}QImage Media::ThumHelper::thumnail(const QString& videoPath)
{QImage image;AVFormatContext * fmtContext = nullptr;if (avformat_open_input(&fmtContext, videoPath.toStdString().c_str(), nullptr, nullptr) < 0) {return image;}if (avformat_find_stream_info(fmtContext, nullptr) < 0) {avformat_close_input(&fmtContext);return image;}int nStreamIndex = -1;AVCodecParameters *codecParameters = nullptr;for (int i = 0; i < fmtContext->nb_streams; i++) {if (fmtContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {nStreamIndex = i;codecParameters = fmtContext->streams[i]->codecpar;break;}}if (nStreamIndex == -1) {avformat_close_input(&fmtContext);return image;}AVCodec* codec = avcodec_find_decoder(codecParameters->codec_id);if (!codec) {avformat_close_input(&fmtContext);return image;}AVCodecContext* codecContext = avcodec_alloc_context3(codec);if (!codecContext) {// 分配解码器上下文失败avformat_close_input(&fmtContext);return image;}if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) {// 复制解码器参数到解码器上下文失败avcodec_free_context(&codecContext);avformat_close_input(&fmtContext);return image;}if (avcodec_open2(codecContext, codec, nullptr) < 0) {// 打开解码器失败avcodec_free_context(&codecContext);avformat_close_input(&fmtContext);return image;}AVPacket packet;av_init_packet(&packet);packet.data = nullptr;packet.size = 0;while (av_read_frame(fmtContext, &packet) >= 0) {if (packet.stream_index == nStreamIndex) {AVFrame* frame = av_frame_alloc();if (frame) {int ret = avcodec_send_packet(codecContext, &packet);if (ret >= 0) {ret = avcodec_receive_frame(codecContext, frame);if (ret >= 0) {// 将第一帧保存为封面图像if (frame->key_frame) {AVFrame* rgbFrame = av_frame_alloc();if (rgbFrame) {rgbFrame->format = AV_PIX_FMT_RGB24;rgbFrame->width = frame->width;rgbFrame->height = frame->height;int bufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB24, frame->width, frame->height, 1);uint8_t* buffer = new uint8_t[bufferSize];av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, buffer, AV_PIX_FMT_RGB24, frame->width, frame->height, 1);SwsContext* swsContext = sws_getContext(frame->width, frame->height, codecContext->pix_fmt,frame->width, frame->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, nullptr, nullptr, nullptr);if (swsContext) {sws_scale(swsContext, frame->data, frame->linesize, 0, frame->height, rgbFrame->data, rgbFrame->linesize);sws_freeContext(swsContext);// 保存封面图像到文件int outputBufferSize = rgbFrame->width * rgbFrame->height * 3;uchar* outputBuffer = new uchar[outputBufferSize];for (int i = 0; i < rgbFrame->height; i++) {memcpy(outputBuffer + i * rgbFrame->width * 3, rgbFrame->data[0] + i * rgbFrame->linesize[0], rgbFrame->width * 3);}image = QImage(outputBuffer, rgbFrame->width, rgbFrame->height, QImage::Format_RGB888).copy();if (outputBuffer) {delete [] outputBuffer;outputBuffer = nullptr;}}if (buffer) {delete[] buffer;buffer = nullptr;}av_frame_free(&rgbFrame);}}}}av_frame_free(&frame);}break;}av_packet_unref(&packet);}avcodec_free_context(&codecContext);avformat_close_input(&fmtContext);return image;}Media::ThumHelper::~ThumHelper()
{}

调用demo

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QPushButton>
#include <QListWidget>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = 0);~Widget();private:QPushButton* m_loadVideo = nullptr;QListWidget *m_imageList;
};#endif // WIDGET_H
#include "widget.h"
#include "ThumHelper.h"
#include <QVBoxLayout>
#include <QFileDialog>
#include <QPixmap>
#include <QLabel>
#include <QDebug>
#include <QDateTime>
Widget::Widget(QWidget *parent): QWidget(parent)
{QVBoxLayout  *layout = new QVBoxLayout;m_loadVideo = new QPushButton(this);m_loadVideo->setText("Load Image");m_imageList = new QListWidget;layout->addWidget(m_loadVideo);layout->addWidget(m_imageList);this->setLayout(layout);connect(m_loadVideo, &QPushButton::clicked, [&]() {QStringList paths = QFileDialog::getOpenFileNames(nullptr, QString("Open File"), "",tr("Videos(*.mp4 *.irgd)"));Media::ThumHelper  helper;QDateTime dateTime = QDateTime::currentDateTime();qDebug() << "Begin Load:" << QDateTime::currentDateTime().toString("yyyy-mm-DD-hh-MM-ss");for (int i = 0; i < paths.count(); i++) {QString videoPath = paths.at(i);QListWidgetItem*  item = new QListWidgetItem(m_imageList);QImage image = helper.thumnail(videoPath);item->setSizeHint(QSize(image.width() / 4, image.height() / 4));QLabel* label = new QLabel(m_imageList);label->setPixmap(QPixmap::fromImage(image).scaled(image.width()/4, image.height()/4));m_imageList->addItem(item);m_imageList->setItemWidget(item, label);}qDebug() << "finish Load:" << QDateTime::currentDateTime().toString("yyyy-mm-DD-hh-MM-ss");});
}Widget::~Widget()
{}
#-------------------------------------------------
#
# Project created by QtCreator 2023-12-21T13:13:56
#
#-------------------------------------------------QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = Media
TEMPLATE = app# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += main.cpp\widget.cppHEADERS  += widget.hINCLUDEPATH +=$$PWD/ffmpeg/4.2.1/includemessage($$PWD/ffmpeg/4.2.1/include)win32{CONFIG(debug,debug|release){LIBS+= -L$$PWD/ffmpeg/4.2.1/x64/libmessage($$PWD/ffmpeg/4.2.1/x64/lib)}
}LIBS+= -lavcodec \-lavfilter \-lavformat \-lswresample \-lswscale \-lpostproc \-lavutil \-lavdevice