MetaDataWorker.cpp 9.26 KB
Newer Older
Christophe Courtaut's avatar
Christophe Courtaut committed
1
/*****************************************************************************
2
 * MetaDataWorker.cpp: Implement the thread that will get the media informations
Christophe Courtaut's avatar
Christophe Courtaut committed
3
 *****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
4
 * Copyright (C) 2008-2010 VideoLAN
Christophe Courtaut's avatar
Christophe Courtaut committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 * Authors: Hugo Beauzee-Luyssen <hugo@vlmc.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
22

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
23
#include <QtDebug>
24 25 26
#include <QPainter>
#include <QLabel>
#include <QImage>
27
#include "vlmc.h"
28
#include "MetaDataWorker.h"
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
29
#include "Library.h"
30
#include "SettingsManager.h"
31
#include "VLCMediaPlayer.h"
32 33
#include "VLCMedia.h"
#include "Clip.h"
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
34

35 36 37
#include <QThreadPool>
#include <QRunnable>

38
MetaDataWorker::MetaDataWorker( LibVLCpp::MediaPlayer* mediaPlayer, Media* media ) :
39 40
        m_mediaPlayer( mediaPlayer ),
        m_media( media ),
41
        m_mediaIsPlaying( false),
42 43
        m_lengthHasChanged( false ),
        m_audioBuffer( NULL )
44 45 46
{
}

47
MetaDataWorker::~MetaDataWorker()
48
{
49 50
    if ( m_audioBuffer )
        delete m_audioBuffer;
51 52
}

53 54
void
MetaDataWorker::compute()
55
{
56 57 58
    if ( m_media->getFileType() == Media::Video ||
         m_media->getFileType() == Media::Audio )
        computeDynamicFileMetaData();
59
    else if ( m_media->getFileType() == Media::Image )
60
        computeImageMetaData();
61

62 63
    m_media->addConstantParam( ":vout=dummy" );
    m_mediaPlayer->setMedia( m_media->getVLCMedia() );
64 65
    connect( m_mediaPlayer, SIGNAL( playing() ),
             this, SLOT( entrypointPlaying() ), Qt::QueuedConnection );
66
    m_mediaPlayer->play();
67
    m_media->flushVolatileParameters();
68 69
}

70 71
void
MetaDataWorker::computeDynamicFileMetaData()
72 73
{
    //Disabling audio for this specific use of the media
74
    m_media->addVolatileParam( ":no-audio", ":audio" );
75 76
    connect( m_mediaPlayer, SIGNAL( lengthChanged() ),
             this, SLOT( entrypointLengthChanged() ), Qt::QueuedConnection );
77 78
}

79 80
void
MetaDataWorker::computeImageMetaData()
81
{
82 83
    m_media->addVolatileParam( ":access=fake", ":access=''" );
    m_media->addVolatileParam( ":fake-duration=10000", ":fake-duration=''" );
84 85
    //There can't be a length for an image file, so we don't have to wait for it to be updated.
    m_lengthHasChanged = true;
86 87
}

88 89
void
MetaDataWorker::prepareAudioSpectrumComputing()
90 91 92 93 94 95
{
    m_media->getVLCMedia()->addOption( ":no-sout-video" );
    m_media->getVLCMedia()->addOption( ":sout=#transcode{}:smem" );
    m_media->getVLCMedia()->setAudioDataCtx( this );
    m_media->getVLCMedia()->setAudioLockCallback( reinterpret_cast<void*>( lock ) );
    m_media->getVLCMedia()->setAudioUnlockCallback( reinterpret_cast<void*>( unlock ) );
96
    m_media->getVLCMedia()->addOption( ":sout-transcode-acodec=fl32" );
97
    m_media->getVLCMedia()->addOption( ":no-sout-smem-time-sync" );
98
    m_media->getVLCMedia()->addOption( ":no-sout-keep" );
99
    connect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( generateAudioSpectrum() ), Qt::QueuedConnection );
100 101
}

102 103
void
MetaDataWorker::metaDataAvailable()
104
{
105
    m_mediaIsPlaying = false;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
106
    m_lengthHasChanged = false;
107

108
    //In order to wait for the VOUT to be ready:
109 110
    //Until we have a way of knowing when it is, both getWidth and getHeight method
    //will trigger exception... so we shut it up.
111
    if ( m_media->getFileType() != Media::Audio )
112
    {
113 114 115 116 117 118
        LibVLCpp::Exception::setErrorCallback( LibVLCpp::Exception::silentExceptionHandler );
        while ( m_mediaPlayer->hasVout() == false )
        {
            SleepMS( 1 ); //Ugly isn't it :)
        }
        LibVLCpp::Exception::setErrorCallback( NULL );
119

120 121
        m_media->setWidth( m_mediaPlayer->getWidth() );
        m_media->setHeight( m_mediaPlayer->getHeight() );
122 123 124 125 126 127
        m_media->setFps( m_mediaPlayer->getFps() );
        if ( m_media->getFps() == .0f )
        {
            qWarning() << "Invalid FPS for media:" << m_media->getFileInfo()->absoluteFilePath();
            m_media->setFps( Clip::DefaultFPS );
        }
128
    }
129 130 131 132 133 134
    else
    {
        const SettingValue *val = SettingsManager::getInstance()->getValue( "project", "VideoProjectFPS" );
        Q_ASSERT_X( val != NULL, "MetaDataWorker", "Can't operate without a project FPS value ");
        m_media->setFps( val->get().toDouble() );
    }
135 136
    m_media->setLength( m_mediaPlayer->getLength() );

137 138
    m_media->setNbAudioTrack( m_mediaPlayer->getNbAudioTrack() );
    m_media->setNbVideoTrack( m_mediaPlayer->getNbVideoTrack() );
139
    m_media->setNbFrames( (m_media->getLengthMS() / 1000) * m_media->getFps() );
140 141

    m_media->emitMetaDataComputed();
142 143 144 145 146 147
    //Setting time for snapshot :
    if ( m_media->getFileType() == Media::Video ||
         m_media->getFileType() == Media::Image )
    {
        connect( m_mediaPlayer, SIGNAL( positionChanged( float ) ), this, SLOT( renderSnapshot() ) );
        m_mediaPlayer->setTime( m_mediaPlayer->getLength() / 3 );
148
    }
149 150
    else
        finalize();
151
}
152

153 154
void
MetaDataWorker::renderSnapshot()
155
{
156 157
    if ( m_media->getFileType() == Media::Video ||
         m_media->getFileType() == Media::Audio )
158
        disconnect( m_mediaPlayer, SIGNAL( positionChanged( float ) ), this, SLOT( renderSnapshot() ) );
159 160 161 162
    QTemporaryFile tmp;
    tmp.setAutoRemove( false );
    tmp.open();

163 164
    connect( m_mediaPlayer, SIGNAL( snapshotTaken( const char* ) ),
             this, SLOT( setSnapshot( const char* ) ), Qt::QueuedConnection );
165 166

    //The slot should be triggered in this methode
167
    m_mediaPlayer->takeSnapshot( tmp.fileName().toStdString().c_str(), 0, 0 );
168 169 170
    //Snapshot slot should has been called (but maybe not in next version...)
}

171 172
void
MetaDataWorker::setSnapshot( const char* filename )
173
{
174
    QPixmap* pixmap = new QPixmap( filename );
175 176 177
    if ( pixmap->isNull() )
        delete pixmap;
    else
178
        m_media->setSnapshot( pixmap );
179
    //TODO : we shouldn't have to do this... patch vlc to get a memory snapshot.
180
    QFile   tmp( filename );
181 182
    tmp.remove();

183 184
    disconnect( m_mediaPlayer, SIGNAL( snapshotTaken(const char*) ),
                this, SLOT( setSnapshot( const char* ) ) );
185 186 187

    //CHECKME:
    //This is synchrone, but it may become asynchrone in the future...
188
//    connect( m_mediaPlayer, SIGNAL( stopped () ), this, SLOT( mediaPlayerStopped() ), Qt::QueuedConnection );
189

190 191 192
    m_media->emitSnapshotComputed();
    finalize();
}
193

194 195
void
MetaDataWorker::finalize()
196 197 198
{
    m_media->disconnect( this );
    emit    computed();
199 200 201
    delete this;
}

202 203
void
MetaDataWorker::entrypointLengthChanged()
204
{
205 206 207
    disconnect( m_mediaPlayer, SIGNAL( lengthChanged() ), this, SLOT( entrypointLengthChanged() ) );
    m_lengthHasChanged = true;
    if ( m_mediaIsPlaying == true )
208
        metaDataAvailable();
209 210
}

211 212
void
MetaDataWorker::entrypointPlaying()
213
{
214 215 216
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( entrypointPlaying() ) );
    m_mediaIsPlaying = true;
    if ( m_lengthHasChanged == true )
217
        metaDataAvailable();
218 219
}

220 221
void
MetaDataWorker::lock( MetaDataWorker* metaDataWorker, uint8_t** pcm_buffer , unsigned int size )
222
{
223 224 225
    if ( metaDataWorker->m_audioBuffer == NULL )
        metaDataWorker->m_audioBuffer = new unsigned char[size];
    *pcm_buffer = metaDataWorker->m_audioBuffer;
226 227
}

228 229
void
MetaDataWorker::unlock( MetaDataWorker* metaDataWorker, uint8_t* pcm_buffer,
230 231 232
                                      unsigned int channels, unsigned int rate,
                                      unsigned int nb_samples, unsigned int bits_per_sample,
                                      unsigned int size, int pts )
233
{
234 235 236 237 238 239 240 241
    Q_UNUSED( rate );
    Q_UNUSED( size );
    Q_UNUSED( pts );

    int bytePerChannelPerSample = bits_per_sample / 8;

    int leftAverage = 0;
    int rightAverage = 0;
242

243
    int it = 0;
244
    for ( unsigned int i = 0; i < nb_samples; i++)
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
    {
        int left = 0;
        int right = 0;
        for ( int u = 0 ; u < bytePerChannelPerSample; u++, it++ )
        {
            int increment = 0;
            if ( channels == 2 )
                increment = bytePerChannelPerSample;
            left <<= 8;
            left += pcm_buffer[ it ];
            right <<= 8;
            right += pcm_buffer[ it + increment ];
        }
        leftAverage += left;
        rightAverage += right;
    }
    leftAverage /= nb_samples;
    metaDataWorker->addAudioValue( leftAverage );
263 264
}

265 266
void
MetaDataWorker::generateAudioSpectrum()
267
{
268 269
    disconnect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( generateAudioSpectrum() ) );
    m_mediaPlayer->stop();
270 271 272 273
//    AudioSpectrumHelper* audioSpectrum = new AudioSpectrumHelper( m_media->getAudioValues() );
//    audioSpectrum->setAutoDelete( true );
//    QThreadPool::globalInstance()->start( audioSpectrum );
    m_media->emitAudioSpectrumComuted();
274
    delete this;
275
}
276

277 278
void
MetaDataWorker::addAudioValue( int value )
279
{
280
    m_media->getAudioValues()->append( value );
281
}