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 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *****************************************************************************
 * Copyright (C) 2008-2009 the VLMC team
 *
 * 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
void    MetaDataWorker::compute()
51
{
52 53 54
    if ( m_media->getFileType() == Media::Video ||
         m_media->getFileType() == Media::Audio )
        computeDynamicFileMetaData();
55
    else if ( m_media->getFileType() == Media::Image )
56
        computeImageMetaData();
57

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

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

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

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

95
void    MetaDataWorker::metaDataAvailable()
96
{
97
    m_mediaIsPlaying = false;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
98
    m_lengthHasChanged = false;
99

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

112 113
        m_media->setWidth( m_mediaPlayer->getWidth() );
        m_media->setHeight( m_mediaPlayer->getHeight() );
114 115 116 117 118 119
        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 );
        }
120
    }
121 122 123 124 125 126
    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() );
    }
127
    m_media->setLength( m_mediaPlayer->getLength() );
128
    m_media->emitMetaDataComputed();
129

130 131 132
    m_media->setTracksAvailable( m_mediaPlayer->hasVideoTrack(),
                                 m_mediaPlayer->hasAudioTrack() );

133 134 135 136 137 138 139
    m_media->setNbFrames( (m_media->getLengthMS() / 1000) * m_media->getFps() );
    //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 );
140
    }
141 142
    else
        finalize();
143
}
144

145
void    MetaDataWorker::renderSnapshot()
146
{
147 148
    if ( m_media->getFileType() == Media::Video ||
         m_media->getFileType() == Media::Audio )
149
        disconnect( m_mediaPlayer, SIGNAL( positionChanged( float ) ), this, SLOT( renderSnapshot() ) );
150 151 152
    QTemporaryFile tmp;
    tmp.setAutoRemove( false );
    tmp.open();
153
    m_tmpSnapshotFilename = tmp.fileName();
154

155
    connect( m_mediaPlayer, SIGNAL( snapshotTaken() ), this, SLOT( setSnapshot() ), Qt::QueuedConnection );
156 157

    //The slot should be triggered in this methode
158
    m_mediaPlayer->takeSnapshot( m_tmpSnapshotFilename.toStdString().c_str(), 0, 0 );
159 160 161
    //Snapshot slot should has been called (but maybe not in next version...)
}

162
void    MetaDataWorker::setSnapshot()
163
{
164 165 166 167
    QPixmap* pixmap = new QPixmap( m_tmpSnapshotFilename );
    if ( pixmap->isNull() )
        delete pixmap;
    else
168
        m_media->setSnapshot( pixmap );
169 170 171 172
    //TODO : we shouldn't have to do this... patch vlc to get a memory snapshot.
    QFile   tmp( m_tmpSnapshotFilename );
    tmp.remove();

173 174 175 176
    disconnect( m_mediaPlayer, SIGNAL( snapshotTaken() ), this, SLOT( setSnapshot() ) );

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

179 180 181
    m_media->emitSnapshotComputed();
    finalize();
}
182

183 184 185 186
void    MetaDataWorker::finalize()
{
    m_media->disconnect( this );
    emit    computed();
187 188 189
    delete this;
}

190
void    MetaDataWorker::entrypointLengthChanged()
191
{
192 193 194
    disconnect( m_mediaPlayer, SIGNAL( lengthChanged() ), this, SLOT( entrypointLengthChanged() ) );
    m_lengthHasChanged = true;
    if ( m_mediaIsPlaying == true )
195
        metaDataAvailable();
196 197
}

198
void    MetaDataWorker::entrypointPlaying()
199
{
200 201 202
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( entrypointPlaying() ) );
    m_mediaIsPlaying = true;
    if ( m_lengthHasChanged == true )
203
        metaDataAvailable();
204 205
}

206
void        MetaDataWorker::lock( MetaDataWorker* metaDataWorker, uint8_t** pcm_buffer , unsigned int size )
207
{
208 209 210
    if ( metaDataWorker->m_audioBuffer == NULL )
        metaDataWorker->m_audioBuffer = new unsigned char[size];
    *pcm_buffer = metaDataWorker->m_audioBuffer;
211 212
}

213 214 215 216
void        MetaDataWorker::unlock( MetaDataWorker* metaDataWorker, uint8_t* pcm_buffer,
                                      unsigned int channels, unsigned int rate,
                                      unsigned int nb_samples, unsigned int bits_per_sample,
                                      unsigned int size, int pts )
217
{
218 219 220 221 222 223 224 225
    Q_UNUSED( rate );
    Q_UNUSED( size );
    Q_UNUSED( pts );

    int bytePerChannelPerSample = bits_per_sample / 8;

    int leftAverage = 0;
    int rightAverage = 0;
226

227
    int it = 0;
228
    for ( unsigned int i = 0; i < nb_samples; i++)
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
    {
        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 );
247 248
}

249
void    MetaDataWorker::generateAudioSpectrum()
250
{
251 252
    disconnect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( generateAudioSpectrum() ) );
    m_mediaPlayer->stop();
253 254 255 256
//    AudioSpectrumHelper* audioSpectrum = new AudioSpectrumHelper( m_media->getAudioValues() );
//    audioSpectrum->setAutoDelete( true );
//    QThreadPool::globalInstance()->start( audioSpectrum );
    m_media->emitAudioSpectrumComuted();
257
    delete this;
258
}
259

260
void    MetaDataWorker::addAudioValue( int value )
261
{
262
    m_media->getAudioValues()->append( value );
263
}