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
# 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
# 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 ( )
{
}
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