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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    int bytePerChannelPerSample = bits_per_sample / 8;

    int leftAverage = 0;
    int rightAverage = 0;
240

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

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

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