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
#include
namespace Media {
class ThumHelper :public QObject
{
Q_OBJECT
public:
ThumHelper();
~ThumHelper();
void initGlobal();
QImage thumnail(const QString& videoPath);
};
}
#endif
#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
#include
#include
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private:
QPushButton* m_loadVideo = nullptr;
QListWidget *m_imageList;
};
#endif
#include "widget.h"
#include "ThumHelper.h"
#include
#include
#include
#include
#include
#include
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()
{
}
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Media
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += main.cpp\
widget.cpp
HEADERS += widget.h
INCLUDEPATH +=$$PWD/ffmpeg/4.2.1/include
message($$PWD/ffmpeg/4.2.1/include)
win32{
CONFIG(debug,debug|release){
LIBS+= -L$$PWD/ffmpeg/4.2.1/x64/lib
message($$PWD/ffmpeg/4.2.1/x64/lib)
}
}
LIBS+= -lavcodec \
-lavfilter \
-lavformat \
-lswresample \
-lswscale \
-lpostproc \
-lavutil \
-lavdevice