Qt使用ffmpeg获取视频文件封面图
2023-12-21 18:02:41
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_OBJECT
public:
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_OBJECT
public:
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 gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = 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.0
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
文章来源:https://blog.csdn.net/weixin_42252757/article/details/135134823
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!