ClipWorkflow.cpp 10.5 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 31
                m_clip( clip ),
                m_buffer( NULL ),
32
                //m_usingBackBuffer( false ),
33
                m_mediaPlayer(NULL),
34 35
                m_state( ClipWorkflow::Stopped ),
                m_requiredState( ClipWorkflow::None )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
36
{
37
    m_buffer = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 4];
38
//    m_backBuffer = new unsigned char[VIDEOHEIGHT * VIDEOWIDTH * 4];
39 40
    m_stateLock = new QReadWriteLock;
    m_requiredStateLock = new QMutex;
41 42
    m_waitCond = new QWaitCondition;
    m_condMutex = new QMutex;
43
    m_initWaitCond = new WaitCondition;
44 45
    m_renderWaitCond = new WaitCondition;
    m_pausingStateWaitCond = new WaitCondition;
46
//    m_backBufferLock = new QReadWriteLock;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
47 48 49 50
}

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

62
unsigned char*    ClipWorkflow::getOutput()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
63
{
64 65
//    QReadLocker     lock( m_backBufferLock );
//    if ( m_usingBackBuffer == true )
66
        return m_buffer;
67
//    return m_backBuffer;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
68 69
}

70 71 72
void    ClipWorkflow::checkStateChange()
{
    QMutexLocker    lock( m_requiredStateLock );
73
    QWriteLocker    lock2( m_stateLock );
74 75
    if ( m_requiredState != ClipWorkflow::None )
    {
76
        qDebug() << "Changed state from" << m_state << "to state" << m_requiredState;
77 78
        m_state = m_requiredState;
        m_requiredState = ClipWorkflow::None;
79
        checkSynchronisation( m_state );
80
    }
81 82
    else
        qDebug() << "No state required";
83 84
}

85
void    ClipWorkflow::lock( ClipWorkflow* cw, void** pp_ret )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
86
{
87
//    QReadLocker lock( cw->m_backBufferLock );
88

89 90 91 92 93 94
//    if ( cw->m_usingBackBuffer )
//    {
//        *pp_ret = cw->m_backBuffer;
//    }
//    else
//    {
95
        *pp_ret = cw->m_buffer;
96
        qDebug() << "Clip workflow locking <<<<<<<<<<<<<<<<<<<<<<<<<<";
97
//    }
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
98 99
}

100
void    ClipWorkflow::unlock( ClipWorkflow* cw )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
101
{
102
    cw->m_stateLock->lockForWrite();
103

104 105 106 107 108 109 110 111 112
//    if ( cw->m_oneFrameOnly )
//    {
//        qDebug() << "One frame only mode is ON :)";
//        //Forcing pause after rendering a frame
//        cw->m_oneFrameOnly = 0;
//        cw->m_state = Paused;
//    }
//    else
//        qDebug() << "One frame only mode is OFF :(";
113
    if ( cw->m_state == Rendering )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
114
    {
115 116
        QMutexLocker    lock( cw->m_condMutex );

117
        qDebug() << "Setting state to Sleeping";
118 119
        cw->m_state = Sleeping;
        cw->m_stateLock->unlock();
120
        //Signal that render has been completed.
121
        cw->m_renderWaitCond->wake();
122

123
        qDebug() << "Entering condwait";
124
        cw->m_waitCond->wait( cw->m_condMutex );
125
        qDebug() << "Leaved condwait";
126 127
        cw->m_stateLock->lockForWrite();
        cw->m_state = Rendering;
128 129 130 131
//        {
//            QWriteLocker    lock2( cw->m_backBufferLock );
//            cw->m_usingBackBuffer = !cw->m_usingBackBuffer;
//        }
132 133 134 135
        cw->m_stateLock->unlock();
    }
    else if ( cw->m_state == Paused )
    {
136
        qDebug() << "Forcing pause inside of unlock";
137
        cw->m_stateLock->unlock();
138
        cw->m_waitCond->wait( cw->m_condMutex );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
139
    }
140 141
    else
        cw->m_stateLock->unlock();
142
    cw->checkStateChange();
143 144
}

145
void    ClipWorkflow::setVmem()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
146 147 148
{
    char        buffer[32];

149 150 151 152 153 154
    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
155

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

159
    sprintf( buffer, ":vmem-height=%i", VIDEOHEIGHT );
160
    m_vlcMedia->addOption( buffer );
161 162

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

166
void    ClipWorkflow::initialize()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
167
{
168
    setState( Initializing );
169
    m_vlcMedia = new LibVLCpp::Media( m_clip->getParent()->getFileInfo()->absoluteFilePath() );
170
    setVmem();
171 172
    m_mediaPlayer = Pool<LibVLCpp::MediaPlayer>::getInstance()->get();
    m_mediaPlayer->setMedia( m_vlcMedia );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
173

174
    connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( setPositionAfterPlayback() ), Qt::DirectConnection );
175
    connect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( clipEndReached() ), Qt::DirectConnection );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
176 177 178
    m_mediaPlayer->play();
}

179
void    ClipWorkflow::setPositionAfterPlayback()
180
{
181
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( setPositionAfterPlayback() ) );
182
    connect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ), Qt::DirectConnection );
183 184 185
    m_mediaPlayer->setPosition( m_clip->getBegin() );
}

186
void    ClipWorkflow::pauseAfterPlaybackStarted()
187
{
188 189
    disconnect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ) );
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( pauseAfterPlaybackStarted() ) );
190

191
    connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( initializedMediaPlayer() ), Qt::DirectConnection );
192 193 194 195
    m_mediaPlayer->pause();

}

196
void    ClipWorkflow::initializedMediaPlayer()
197
{
198
    disconnect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( initializedMediaPlayer() ) );
199
    setState( Ready );
200 201
}

202
bool    ClipWorkflow::isReady() const
203
{
204 205
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Ready;
206
}
207

208 209 210 211 212 213
bool    ClipWorkflow::isPausing() const
{
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Pausing;
}

214 215
bool    ClipWorkflow::isEndReached() const
{
216 217 218 219 220 221 222 223 224 225 226 227 228
    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;
229
}
230 231 232

void    ClipWorkflow::startRender()
{
233 234 235
    if ( isReady() == false )
        m_initWaitCond->wait();

236
    m_mediaPlayer->play();
237
    setState( Rendering );
238
}
239

240
void    ClipWorkflow::clipEndReached()
241
{
242
    setState( EndReached );
243
}
244

245
Clip*     ClipWorkflow::getClip()
246 247 248
{
    return m_clip;
}
249 250 251

void            ClipWorkflow::stop()
{
252 253 254
    if ( m_mediaPlayer )
    {
        m_mediaPlayer->stop();
255
        Pool<LibVLCpp::MediaPlayer>::getInstance()->release( m_mediaPlayer );
256 257 258 259 260
        disconnect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( clipEndReached() ) );
        m_mediaPlayer = NULL;
        setState( Stopped );
        QMutexLocker    lock( m_requiredStateLock );
        m_requiredState = ClipWorkflow::None;
261
        delete m_vlcMedia;
262 263 264
    }
    else
        qDebug() << "ClipWorkflow has already been stopped";
265 266 267 268 269 270
}

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

272
bool            ClipWorkflow::isRendering() const
273
{
274 275
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Rendering;
276
}
277

278 279 280 281 282 283 284
void            ClipWorkflow::checkSynchronisation( State newState )
{
    switch ( newState )
    {
        case Ready:
            m_initWaitCond->wake();
            break ;
285
        case Pausing:
286
            qDebug() << "Waking m_pausingStateWaitCond";
287 288
            m_pausingStateWaitCond->wake();
            break ;
289 290 291 292 293
        default:
            break ;
    }
}

294
void            ClipWorkflow::setState( State state )
295
{
296 297 298 299 300
    {
        QWriteLocker    lock( m_stateLock );
        m_state = state;
    }
    checkSynchronisation( state );
301
}
302 303 304

void            ClipWorkflow::queryStateChange( State newState )
{
305
    qDebug() << "Querying state change to" << newState;
306 307 308
    QMutexLocker    lock( m_requiredStateLock );
    m_requiredState = newState;
}
309 310 311

void            ClipWorkflow::wake()
{
312
    m_waitCond->wakeAll();
313
    qDebug() << "Awaked thread";
314 315 316 317 318 319 320 321 322 323 324 325 326
}

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

void            ClipWorkflow::reinitialize()
{
    QWriteLocker    lock( m_stateLock );
    m_state = Stopped;
    queryStateChange( None );
}
327 328 329 330

void            ClipWorkflow::pause()
{
    setState( Paused );
331
    m_mediaPlayer->pause();
332
    QMutexLocker    lock( m_requiredStateLock );
333
    qDebug() << "ClipWorkflow::pause(); Reseting required state";
334
    m_requiredState = ClipWorkflow::None;
335 336
}

337
void            ClipWorkflow::unpause( bool wakeRenderThread /*= true*/ )
338 339 340
{
    //Since VLC will detect that the media player is paused and unpause it, we can do this safely
    setState( ClipWorkflow::Rendering );
341 342 343 344 345
    m_mediaPlayer->pause();
//    QMutexLocker    lock( m_requiredStateLock );
//    m_requiredState = ClipWorkflow::None;
    if ( wakeRenderThread == true )
        wake();
346
}
347 348 349 350 351 352

//void            ClipWorkflow::activateOneFrameOnly()
//{
//    qDebug() << "Activating one frame only";
//    m_oneFrameOnly = 1;
//}
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367

void        ClipWorkflow::waitForCompleteRender()
{
    if ( isRendering() == true )
        m_renderWaitCond->wait();
}

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

void        ClipWorkflow::waitForPausingState()
{
368
    if ( isPausing() == false )
369 370
        m_pausingStateWaitCond->wait();
}
371 372 373 374 375

QMutex*     ClipWorkflow::getSleepMutex()
{
    return m_condMutex;
}
376 377 378 379 380

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