ClipWorkflow.cpp 9.72 KB
Newer Older
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*****************************************************************************
 * ClipWorkflow.cpp : Clip workflow. Will extract a single frame from a VLCMedia
 *****************************************************************************
 * 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.
 *****************************************************************************/

23
#include <QtDebug>
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
24

25
#include "vlmc.h"
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
26
#include "ClipWorkflow.h"
27
#include "Pool.hpp"
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
28

29
ClipWorkflow::ClipWorkflow( Clip::Clip* clip ) :
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
30
                m_clip( clip ),
31
                m_mediaPlayer(NULL),
32
                m_state( ClipWorkflow::Stopped ),
33 34 35
                m_requiredState( ClipWorkflow::None ),
                m_rendering( false ),
                m_initFlag( false )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
36
{
37 38
    m_stateLock = new QReadWriteLock;
    m_requiredStateLock = new QMutex;
39 40
    m_waitCond = new QWaitCondition;
    m_condMutex = new QMutex;
41
    m_initWaitCond = new WaitCondition;
42 43
    m_renderWaitCond = new WaitCondition;
    m_pausingStateWaitCond = new WaitCondition;
44 45
    m_renderLock = new QMutex;
    m_buffer = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 4];
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
46 47 48 49
}

ClipWorkflow::~ClipWorkflow()
{
50
    delete m_renderLock;
51
    delete m_pausingStateWaitCond;
52
    delete m_initWaitCond;
53
    delete m_condMutex;
54 55 56 57
    delete m_waitCond;
    delete m_requiredStateLock;
    delete m_stateLock;
    delete[] m_buffer;
58
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
59

60
unsigned char*    ClipWorkflow::getOutput()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
61
{
62
    QMutexLocker    lock( m_renderLock );
63

64
    return m_buffer;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
65 66
}

67 68 69
void    ClipWorkflow::checkStateChange()
{
    QMutexLocker    lock( m_requiredStateLock );
70
    QWriteLocker    lock2( m_stateLock );
71 72 73 74
    if ( m_requiredState != ClipWorkflow::None )
    {
        m_state = m_requiredState;
        m_requiredState = ClipWorkflow::None;
75
        checkSynchronisation( m_state );
76 77 78
    }
}

79
void    ClipWorkflow::lock( ClipWorkflow* cw, void** pp_ret )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
80
{
81 82
    cw->m_renderLock->lock();
    *pp_ret = cw->m_buffer;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
83 84
}

85
void    ClipWorkflow::unlock( ClipWorkflow* cw )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
86
{
87
    cw->m_renderLock->unlock();
88
    cw->m_stateLock->lockForWrite();
89

90
    if ( cw->m_state == Rendering )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
91
    {
92 93
        QMutexLocker    lock( cw->m_condMutex );

94 95
        cw->m_state = Sleeping;
        cw->m_stateLock->unlock();
96

97
        cw->m_renderWaitCond->wake();
98
        cw->emit renderComplete( cw );
99

100
//        qDebug() << ">>>Entering condwait";
101
        cw->m_waitCond->wait( cw->m_condMutex );
102
//        qDebug() << "<<<Leaving condwait";
103 104
        cw->m_stateLock->lockForWrite();
        cw->m_state = Rendering;
105
        cw->m_stateLock->unlock();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
106
    }
107 108
    else
        cw->m_stateLock->unlock();
109
    cw->checkStateChange();
110 111
}

112
void    ClipWorkflow::setVmem()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
113 114 115
{
    char        buffer[32];

116 117 118 119 120 121
    m_vlcMedia->addOption( ":no-audio" );
    m_vlcMedia->addOption( ":vout=vmem" );
    m_vlcMedia->setDataCtx( this );
    m_vlcMedia->setLockCallback( reinterpret_cast<LibVLCpp::Media::lockCallback>( &ClipWorkflow::lock ) );
    m_vlcMedia->setUnlockCallback( reinterpret_cast<LibVLCpp::Media::unlockCallback>( &ClipWorkflow::unlock ) );
    m_vlcMedia->addOption( ":vmem-chroma=RV24" );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
122

123
    sprintf( buffer, ":vmem-width=%i", VIDEOWIDTH );
124
    m_vlcMedia->addOption( buffer );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
125

126
    sprintf( buffer, ":vmem-height=%i", VIDEOHEIGHT );
127
    m_vlcMedia->addOption( buffer );
128 129

    sprintf( buffer, "vmem-pitch=%i", VIDEOWIDTH * 3 );
130
    m_vlcMedia->addOption( buffer );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
131 132
}

133
void    ClipWorkflow::initialize()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
134
{
135
    setState( Initializing );
136
    m_vlcMedia = new LibVLCpp::Media( "file://" + m_clip->getParent()->getFileInfo()->absoluteFilePath() );
137
    setVmem();
138 139
    m_mediaPlayer = Pool<LibVLCpp::MediaPlayer>::getInstance()->get();
    m_mediaPlayer->setMedia( m_vlcMedia );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
140

141
    connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( setPositionAfterPlayback() ), Qt::DirectConnection );
142
    connect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( clipEndReached() ), Qt::DirectConnection );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
143 144 145
    m_mediaPlayer->play();
}

146
//FIXME: this step is probably useless, due to modification in the TrackWorkflow
147
void    ClipWorkflow::setPositionAfterPlayback()
148
{
149
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( setPositionAfterPlayback() ) );
150
    connect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ), Qt::DirectConnection );
151

152 153 154
    m_mediaPlayer->setPosition( m_clip->getBegin() );
}

155
void    ClipWorkflow::pauseAfterPlaybackStarted()
156
{
157
    disconnect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ) );
158
    //FIXME: it seems that this signal is never connected :o
159
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( pauseAfterPlaybackStarted() ) );
160
    connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( initializedMediaPlayer() ), Qt::DirectConnection );
161

162
    m_mediaPlayer->pause();
163 164
}

165
void    ClipWorkflow::initializedMediaPlayer()
166
{
167
    disconnect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( initializedMediaPlayer() ) );
168
    setState( Ready );
169 170
}

171
bool    ClipWorkflow::isReady() const
172
{
173 174
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Ready;
175
}
176 177 178

bool    ClipWorkflow::isEndReached() const
{
179 180 181 182 183 184 185 186 187 188 189 190 191
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::EndReached;
}

bool    ClipWorkflow::isStopped() const
{
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Stopped;
}

ClipWorkflow::State     ClipWorkflow::getState() const
{
    return m_state;
192
}
193

194
void    ClipWorkflow::startRender( bool startInPausedMode )
195
{
196 197 198
    if ( isReady() == false )
        m_initWaitCond->wait();

199 200 201 202 203 204 205 206 207
    if ( startInPausedMode == false )
    {
        m_mediaPlayer->play();
        setState( Rendering );
    }
    else
    {
        setState( Paused );
    }
208
}
209

210
void    ClipWorkflow::clipEndReached()
211
{
212
    setState( EndReached );
213
}
214

215
Clip*     ClipWorkflow::getClip()
216 217 218
{
    return m_clip;
}
219 220 221

void            ClipWorkflow::stop()
{
222 223 224
    if ( m_mediaPlayer )
    {
        m_mediaPlayer->stop();
225
        Pool<LibVLCpp::MediaPlayer>::getInstance()->release( m_mediaPlayer );
226 227 228 229 230
        disconnect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( clipEndReached() ) );
        m_mediaPlayer = NULL;
        setState( Stopped );
        QMutexLocker    lock( m_requiredStateLock );
        m_requiredState = ClipWorkflow::None;
231
        delete m_vlcMedia;
232 233
        m_initFlag = false;
        m_rendering = false;
234 235 236
    }
    else
        qDebug() << "ClipWorkflow has already been stopped";
237 238 239 240 241 242
}

void            ClipWorkflow::setPosition( float pos )
{
    m_mediaPlayer->setPosition( pos );
}
243

244
bool            ClipWorkflow::isRendering() const
245
{
246 247
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Rendering;
248
}
249

250 251 252 253 254 255
bool            ClipWorkflow::isSleeping() const
{
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Sleeping;
}

256 257 258 259 260 261 262 263 264 265 266 267
void            ClipWorkflow::checkSynchronisation( State newState )
{
    switch ( newState )
    {
        case Ready:
            m_initWaitCond->wake();
            break ;
        default:
            break ;
    }
}

268
void            ClipWorkflow::setState( State state )
269
{
270 271
    {
        QWriteLocker    lock( m_stateLock );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
272
//        qDebug() << "Changing from state" << m_state << "to state" << state;
273 274 275
        m_state = state;
    }
    checkSynchronisation( state );
276
}
277 278 279

void            ClipWorkflow::queryStateChange( State newState )
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
280
//    qDebug() << "Querying state change to" << newState;
281 282 283
    QMutexLocker    lock( m_requiredStateLock );
    m_requiredState = newState;
}
284 285 286

void            ClipWorkflow::wake()
{
287
    m_waitCond->wakeAll();
288 289 290 291 292 293 294 295 296 297 298 299 300
}

QReadWriteLock* ClipWorkflow::getStateLock()
{
    return m_stateLock;
}

void            ClipWorkflow::reinitialize()
{
    QWriteLocker    lock( m_stateLock );
    m_state = Stopped;
    queryStateChange( None );
}
301 302 303

void            ClipWorkflow::pause()
{
304
    connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( pausedMediaPlayer() ), Qt::DirectConnection );
305
    setState( Pausing );
306
    m_mediaPlayer->pause();
307 308
    QMutexLocker    lock( m_requiredStateLock );
    m_requiredState = ClipWorkflow::None;
309

310 311 312 313
    {
        QMutexLocker    sync( m_condMutex );
        wake();
    }
314 315
}

316
void            ClipWorkflow::unpause()
317
{
318
    queryStateChange( ClipWorkflow::Rendering );
319
    connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( unpausedMediaPlayer() ), Qt::DirectConnection );
320
    m_mediaPlayer->pause();
321
}
322

323
void        ClipWorkflow::waitForCompleteRender( bool dontCheckRenderStarted /*= false*/ )
324
{
325
    if ( isRendering() == true || dontCheckRenderStarted == true )
326 327 328 329 330 331 332 333 334
        m_renderWaitCond->wait();
}

void        ClipWorkflow::waitForCompleteInit()
{
    if ( isReady() == false )
        m_initWaitCond->wait();
}

335 336 337 338
QMutex*     ClipWorkflow::getSleepMutex()
{
    return m_condMutex;
}
339 340 341 342 343

LibVLCpp::MediaPlayer*       ClipWorkflow::getMediaPlayer()
{
    return m_mediaPlayer;
}
344 345 346

void        ClipWorkflow::pausedMediaPlayer()
{
347
    disconnect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( pausedMediaPlayer() ) );
348
    setState( Paused );
349 350 351 352 353 354 355
    emit paused();
}

void        ClipWorkflow::unpausedMediaPlayer()
{
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( unpausedMediaPlayer() ) );
    emit unpaused();
356
}