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
# 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
# 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 guigreaterThan( QT_MAJOR_VERSION, 4 ) : QT += widgetsTARGET = Media
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += 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