File indexing completed on 2024-05-12 16:35:05
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2012 Gopalakrishna Bhat A <gopalakbhat@gmail.com> 0003 * Copyright (C) 2006-2009 Marco Gulino <marco.gulino@gmail.com> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "VideoThumbnailer.h" 0022 0023 #include "VideoData.h" 0024 #include "VideoDebug.h" 0025 0026 #include <phonon/experimental/videoframe2.h> 0027 #include <QTime> 0028 #include <QVBoxLayout> 0029 #include <QVarLengthArray> 0030 0031 0032 #define THRESHOLD_FRAME_VARIANCE 40.0 0033 0034 VideoThumbnailer::VideoThumbnailer() 0035 : QObject() 0036 { 0037 m_vdata.setRunning(true); 0038 Phonon::createPath(&m_media, &m_vdata); 0039 connect(&m_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, 0040 SLOT(stateChanged(Phonon::State,Phonon::State))); 0041 connect(this,SIGNAL(signalCreateThumbnail(VideoData*,QSize)), 0042 this, SLOT(slotCreateThumbnail(VideoData*,QSize)), Qt::QueuedConnection); 0043 } 0044 0045 VideoThumbnailer::~VideoThumbnailer() 0046 { 0047 } 0048 0049 void VideoThumbnailer::createThumbnail(VideoData *videoData, const QSize &size) 0050 { 0051 emit signalCreateThumbnail(videoData, size); 0052 } 0053 0054 void VideoThumbnailer::slotCreateThumbnail(VideoData *videoData, const QSize &size) 0055 { 0056 m_media.setCurrentSource(videoData->playableUrl()); 0057 m_media.play(); 0058 0059 m_thumbnailSize = size; 0060 0061 0062 int retcode = 0; 0063 for (int i = 0; i < 50; i++) { 0064 retcode = m_eventLoop.exec(); 0065 if (retcode == 0) { 0066 break; 0067 } 0068 debugVideo << "Seeking to " << (i * 3); 0069 m_media.seek(i * 3); 0070 } 0071 if (retcode) { 0072 warnVideo << "Unable to generate thumbnail for "; 0073 m_media.stop(); 0074 return; 0075 } 0076 m_media.stop(); 0077 0078 emit thumbnailReady(); 0079 } 0080 0081 void VideoThumbnailer::frameReady(const Phonon::Experimental::VideoFrame2 &frame) 0082 { 0083 QImage thumb = frame.qImage().scaled(m_thumbnailSize.width(), m_thumbnailSize.height(), Qt::KeepAspectRatio); 0084 if (isFrameInteresting(thumb)) { 0085 m_thumbnailImage = thumb; 0086 m_vdata.disconnect(SIGNAL(frameReadySignal(Phonon::Experimental::VideoFrame2)), 0087 this, SLOT(frameReady(Phonon::Experimental::VideoFrame2))); 0088 m_eventLoop.quit(); 0089 return; 0090 } 0091 m_eventLoop.exit(1); 0092 } 0093 0094 void VideoThumbnailer::stateChanged(Phonon::State newState, Phonon::State oldState) 0095 { 0096 Q_UNUSED(oldState); 0097 if (newState == Phonon::PlayingState) { 0098 connect(&m_vdata, SIGNAL(frameReadySignal(Phonon::Experimental::VideoFrame2)), 0099 this, SLOT(frameReady(Phonon::Experimental::VideoFrame2))); 0100 m_eventLoop.exit(1); 0101 } 0102 } 0103 0104 QImage VideoThumbnailer::thumbnail() 0105 { 0106 return m_thumbnailImage; 0107 } 0108 0109 bool VideoThumbnailer::isFrameInteresting(const QImage &frame) 0110 { 0111 float variance = 0; 0112 //taken from mplayerthumbs 0113 uint delta=0; 0114 uint avg=0; 0115 uint bytes=frame.numBytes(); 0116 uint STEPS=bytes/2; 0117 QVarLengthArray<uchar> pivot(STEPS); 0118 0119 const uchar *bits=frame.bits(); 0120 // First pass: get pivots and taking average 0121 for( uint i=0; i<STEPS ; i++ ){ 0122 pivot[i]=bits[i*(bytes/STEPS)]; 0123 avg+=pivot[i]; 0124 } 0125 avg=avg/STEPS; 0126 // Second Step: calculate delta (average?) 0127 for (uint i=0; i<STEPS; i++) 0128 { 0129 int curdelta=abs(int(avg-pivot[i])); 0130 delta+=curdelta; 0131 } 0132 variance= delta/STEPS; 0133 0134 return variance > THRESHOLD_FRAME_VARIANCE; 0135 } 0136 0137