MetaDataWorker.cpp 9.24 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 30
#include "Library.h"

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

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

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

49
void    MetaDataWorker::compute()
50
{
51
    if ( m_media->getFileType() == Media::Video )
52
    {
53
        if ( m_type == Audio )
54 55 56
            computeAudioMetaData();
        else
            computeVideoMetaData();
57
    }
58
    else if ( m_media->getFileType() == Media::Image )
59 60 61
    {
        computeImageMetaData();
    }
62

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

71
void    MetaDataWorker::computeVideoMetaData()
72 73
{
    //Disabling audio for this specific use of the media
74
    m_media->addVolatileParam( ":no-audio", ":audio" );
75
    connect( m_mediaPlayer, SIGNAL( lengthChanged() ), this, SLOT( entrypointLengthChanged() ), Qt::QueuedConnection );
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 88 89 90 91 92 93 94
void    MetaDataWorker::computeAudioMetaData()
{
    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" );
95 96
    m_media->getVLCMedia()->addOption( ":no-sout-keep" );
    connect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( generateAudioSpectrum() ), Qt::QueuedConnection );
97 98
}

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

104
    //In order to wait for the VOUT to be ready:
105 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.
    LibVLCpp::Exception::setErrorCallback( LibVLCpp::Exception::silentExceptionHandler );
108
    while ( m_mediaPlayer->hasVout() == false )
109
    {
110
        SleepMS( 1 ); //Ugly isn't it :)
111
    }
112 113
    LibVLCpp::Exception::setErrorCallback( NULL );

114
    if ( m_type == MetaData )
115
    {
116 117 118 119 120 121 122
        m_media->setLength( m_mediaPlayer->getLength() );
        m_media->setWidth( m_mediaPlayer->getWidth() );
        m_media->setHeight( m_mediaPlayer->getHeight() );
        m_media->setFps( m_mediaPlayer->getFps() );
        if ( m_media->getFps() == .0f )
        {
            qWarning() << "Invalid FPS for media:" << m_media->getFileInfo()->absoluteFilePath();
123
            m_media->setFps( Clip::DefaultFPS );
124 125
        }
        m_media->setNbFrames( (m_media->getLengthMS() / 1000) * m_media->getFps() );
126 127
        if ( m_mediaPlayer->isPlaying() )
            m_mediaPlayer->stop();
128
        emit mediaPlayerIdle( m_mediaPlayer );
129
        m_media->emitMetaDataComputed( true );
130 131
        delete this;
        return;
132
    }
133
    else if ( m_type == Snapshot )
134
    {
135 136 137
        //Setting time for snapshot :
        if ( m_media->getFileType() == Media::Video )
        {
138
            connect( m_mediaPlayer, SIGNAL( positionChanged( float ) ), this, SLOT( renderSnapshot() ) );
139 140 141 142
            m_mediaPlayer->setTime( m_mediaPlayer->getLength() / 3 );
        }
        else
            connect( this, SIGNAL( snapshotRequested() ), this, SLOT( renderSnapshot() ) );
143
    }
144
}
145

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

157
    connect( m_mediaPlayer, SIGNAL( snapshotTaken() ), this, SLOT( setSnapshot() ), Qt::QueuedConnection );
158 159

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

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

175 176 177 178
    disconnect( m_mediaPlayer, SIGNAL( snapshotTaken() ), this, SLOT( setSnapshot() ) );

    //CHECKME:
    //This is synchrone, but it may become asynchrone in the future...
179
//    connect( m_mediaPlayer, SIGNAL( stopped () ), this, SLOT( mediaPlayerStopped() ), Qt::QueuedConnection );
180 181
    if ( m_mediaIsPlaying )
        m_mediaPlayer->stop();
182
    emit mediaPlayerIdle( m_mediaPlayer );
183

184 185 186 187
    if ( m_type == Snapshot )
        m_media->emitSnapshotComputed();
    else
        m_media->emitMetaDataComputed( true );
188

189 190 191
    delete this;
}

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

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

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

215 216 217 218
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 )
219
{
220 221 222 223 224 225 226 227
    Q_UNUSED( rate );
    Q_UNUSED( size );
    Q_UNUSED( pts );

    int bytePerChannelPerSample = bits_per_sample / 8;

    int leftAverage = 0;
    int rightAverage = 0;
228

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

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

263
void    MetaDataWorker::addAudioValue( int value )
264
{
265
    m_media->getAudioValues()->append( value );
266
}