MetaDataWorker.cpp 9.19 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"
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
31

32 33 34
#include <QThreadPool>
#include <QRunnable>

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

44
MetaDataWorker::~MetaDataWorker()
45
{
46 47
    if ( m_audioBuffer )
        delete m_audioBuffer;
48 49
}

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

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

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

76 77
void
MetaDataWorker::computeImageMetaData()
78
{
79 80
    m_media->addVolatileParam( ":access=fake", ":access=''" );
    m_media->addVolatileParam( ":fake-duration=10000", ":fake-duration=''" );
81 82
    //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;
83 84
}

85 86
void
MetaDataWorker::prepareAudioSpectrumComputing()
87 88 89 90 91 92
{
    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 ) );
93
    m_media->getVLCMedia()->addOption( ":sout-transcode-acodec=fl32" );
94
    m_media->getVLCMedia()->addOption( ":no-sout-smem-time-sync" );
95
    m_media->getVLCMedia()->addOption( ":no-sout-keep" );
96
    connect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( generateAudioSpectrum() ), Qt::QueuedConnection );
97 98
}

99 100
void
MetaDataWorker::metaDataAvailable()
101
{
102
    m_mediaIsPlaying = false;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
103
    m_lengthHasChanged = false;
104

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

117 118
        m_media->setWidth( m_mediaPlayer->getWidth() );
        m_media->setHeight( m_mediaPlayer->getHeight() );
119 120 121 122 123 124
        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 );
        }
125
    }
126 127 128 129 130 131
    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() );
    }
132 133
    m_media->setLength( m_mediaPlayer->getLength() );

134 135
    m_media->setNbAudioTrack( m_mediaPlayer->getNbAudioTrack() );
    m_media->setNbVideoTrack( m_mediaPlayer->getNbVideoTrack() );
136
    m_media->setNbFrames( (m_media->getLengthMS() / 1000) * m_media->getFps() );
137 138

    m_media->emitMetaDataComputed();
139 140 141 142 143 144
    //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 );
145
    }
146 147
    else
        finalize();
148
}
149

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

160 161
    connect( m_mediaPlayer, SIGNAL( snapshotTaken( const char* ) ),
             this, SLOT( setSnapshot( const char* ) ), Qt::QueuedConnection );
162 163

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

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

180 181
    disconnect( m_mediaPlayer, SIGNAL( snapshotTaken(const char*) ),
                this, SLOT( setSnapshot( const char* ) ) );
182 183 184

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

187 188 189
    m_media->emitSnapshotComputed();
    finalize();
}
190

191 192
void
MetaDataWorker::finalize()
193 194 195
{
    m_media->disconnect( this );
    emit    computed();
196 197 198
    delete this;
}

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

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

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

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

    int bytePerChannelPerSample = bits_per_sample / 8;

    int leftAverage = 0;
    int rightAverage = 0;
239

240
    int it = 0;
241
    for ( unsigned int i = 0; i < nb_samples; i++)
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    {
        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 );
260 261
}

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

274 275
void
MetaDataWorker::addAudioValue( int value )
276
{
277
    m_media->getAudioValues()->append( value );
278
}