Search code examples
qtvideoqt5qt4thumbnails

Use QtAV for video thumbnailing


I'm using the wonderful [QtAV](https://github.com/wang-bin/QtAV/) package to perform video decoding. What I want to achieve is to obtain a thumbnail for a video. Here is what I have done so far.

bool saveThumb( QString videoFile ) {

    AVDemuxer *demux = new AVDemuxer();
    demux->setSeekUnit( SeekByFrame );
    demux->setSeekType( KeyFrameSeek );

    VideoDecoder *vdec = VideoDecoder::create( VideoDecoderId_FFmpeg );

    demux->setMedia( videoFile );

    qDebug() << "Loading file:" << demux->load();
    qDebug() << "Seeking to 50%" << demux->seek( 0.5 );
    qDebug() << "Reading frame:" << demux->readFrame();

    vdec->setCodecContext( demux->videoCodecContext() );
    vdec->open();

    Packet pkt = demux->packet();
    qDebug() << "Packet valid:" << pkt.isValid();
    qDebug() << "Decoding packet:" << vdec->decode( pkt );

    VideoFrame frame = vdec->frame();
    qDebug() << "Valid frame:" << frame.isValid();
    QImage img = frame.toImage();
    qDebug() << "Valid image:" << ( not img.isNull() );
    bool saved = img.save( videoFile + ".jpg" );

    return saved;
}

My problem is that frame.isValid() always returns false, no matter to where I seek, or which video I play. All the checks above return true.

I would like to add that if I use AVPlayer and play the video, the video renders properly, however there is no audio playing.

Also I am able to capture snapshots using AVPlayer::videoCapture()->capture()

For the record, I have tried this using both Qt4 and Qt5


Solution

  • For getting thumbnails of videos you can simply use QtAV VideoFrameExtractor class like:

    #include "QtAV/VideoFrameExtractor.h"
    ...
    
    bool saveThumb(const QString& videoFile) {
       auto extractor = new QtAV::VideoFrameExtractor;
       connect(
           extractor,
           &QtAV::VideoFrameExtractor::frameExtracted,
           extractor,
           [this, extractor, videoFile](const QtAV::VideoFrame& frame) {
               const auto& img = frame.toImage();
               auto saved = img.save(videoFile + ".jpg" );
               extractor->deleteLater();
           });
       connect(
           extractor,
           &QtAV::VideoFrameExtractor::error,
           extractor,
           [this, extractor](const QString& errorStr) {
               qDebug() << errorStr;
               extractor->deleteLater();
           });
    
       extractor->setAsync(true);
       extractor->setSource(videoFile);
       extractor->setPosition(1);
    }