ClipWorkflow.cpp 7.47 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 26

#include "ClipWorkflow.h"

27 28 29
int     g_debugId = 0;

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 43 44 45
    m_condMutex = new QMutex;
    m_waitCond = new QWaitCondition;
    m_backBufferLock = new QReadWriteLock;

    this->debugId = g_debugId++;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
46 47 48 49
}

ClipWorkflow::~ClipWorkflow()
{
50
    delete[] m_buffer;
51
    delete[] m_backBuffer;
52
    delete m_stateLock;
53
    delete m_requiredStateLock;
54
    delete m_backBufferLock;
55
}
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
56

57
unsigned char*    ClipWorkflow::getOutput()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
58
{
59 60 61 62
    QReadLocker     lock( m_backBufferLock );
    if ( m_usingBackBuffer == true )
        return m_buffer;
    return m_backBuffer;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
63 64
}

65 66 67
void    ClipWorkflow::checkStateChange()
{
    QMutexLocker    lock( m_requiredStateLock );
68
    QWriteLocker    lock2( m_stateLock );
69 70
    if ( m_requiredState != ClipWorkflow::None )
    {
71
        qDebug() << "Setting required state : " << m_requiredState;
72 73 74 75 76
        m_state = m_requiredState;
        m_requiredState = ClipWorkflow::None;
    }
}

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
77 78
void    ClipWorkflow::lock( ClipWorkflow* clipWorkflow, void** pp_ret )
{
79
//    qDebug() << "Locking in ClipWorkflow::lock";
80 81 82 83 84 85
    QReadLocker     lock( clipWorkflow->m_backBufferLock );

    if ( clipWorkflow->m_usingBackBuffer )
        *pp_ret = clipWorkflow->m_backBuffer;
    else
        *pp_ret = clipWorkflow->m_buffer;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
86 87
}

88
void    ClipWorkflow::unlock( ClipWorkflow* cw )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
89
{
90
    cw->m_stateLock->lockForWrite();
91

92
    if ( cw->m_state == Rendering )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
93
    {
94 95 96 97 98 99 100 101 102 103 104 105 106
        cw->m_state = Sleeping;
        cw->m_stateLock->unlock();

        QMutexLocker    lock( cw->m_condMutex );
        cw->m_waitCond->wait( cw->m_condMutex );

        {
            QWriteLocker    lock2( cw->m_backBufferLock );
            cw->m_usingBackBuffer = !cw->m_usingBackBuffer;
        }

        cw->m_stateLock->lockForWrite();
        cw->m_state = Rendering;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
107
    }
108 109 110
    cw->m_stateLock->unlock();
    cw->checkStateChange();

111
//    qDebug() << "UnLocking in ClipWorkflow::unlock";
112 113
}

114
void    ClipWorkflow::setVmem()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
115 116 117 118 119 120 121 122
{
    char        buffer[32];

    //TODO: it would be good if we somehow backup the old media parameters to restore it later.
    m_clip->getParent()->getVLCMedia()->addOption( ":vout=vmem" );
    m_clip->getParent()->getVLCMedia()->setDataCtx( this );
    m_clip->getParent()->getVLCMedia()->setLockCallback( reinterpret_cast<LibVLCpp::Media::lockCallback>( &ClipWorkflow::lock ) );
    m_clip->getParent()->getVLCMedia()->setUnlockCallback( reinterpret_cast<LibVLCpp::Media::unlockCallback>( &ClipWorkflow::unlock ) );
123
    m_clip->getParent()->getVLCMedia()->addOption( ":vmem-chroma=RV24" );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
124

125
    sprintf( buffer, ":vmem-width=%i", VIDEOWIDTH );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
126 127
    m_clip->getParent()->getVLCMedia()->addOption( buffer );

128 129 130 131
    sprintf( buffer, ":vmem-height=%i", VIDEOHEIGHT );
    m_clip->getParent()->getVLCMedia()->addOption( buffer );

    sprintf( buffer, "vmem-pitch=%i", VIDEOWIDTH * 3 );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
132 133 134
    m_clip->getParent()->getVLCMedia()->addOption( buffer );
}

135
void    ClipWorkflow::initialize( LibVLCpp::MediaPlayer* mediaPlayer )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
136
{
137
    setState( Initializing );
138
    setVmem();
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
139 140 141
    m_mediaPlayer = mediaPlayer;
    m_mediaPlayer->setMedia( m_clip->getParent()->getVLCMedia() );

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

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
    m_mediaPlayer->setPosition( m_clip->getBegin() );
}

154
void    ClipWorkflow::pauseAfterPlaybackStarted()
155
{
156 157
    disconnect( m_mediaPlayer, SIGNAL( positionChanged() ), this, SLOT( pauseAfterPlaybackStarted() ) );
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( pauseAfterPlaybackStarted() ) );
158

159 160 161 162 163 164 165 166
    connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( pausedMediaPlayer() ), Qt::DirectConnection );
    m_mediaPlayer->pause();

}

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

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

bool    ClipWorkflow::isEndReached() const
{
178 179 180 181 182 183 184 185 186 187 188 189 190
    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;
191
}
192 193 194

void    ClipWorkflow::startRender()
{
195 196
    while ( isReady() == false )
        usleep( 50 );
197
    m_mediaPlayer->play();
198
    setState( Rendering );
199
}
200 201 202

void    ClipWorkflow::endReached()
{
203
    setState( EndReached );
204
}
205

206
const Clip*     ClipWorkflow::getClip() const
207 208 209
{
    return m_clip;
}
210 211 212

void            ClipWorkflow::stop()
{
213
    Q_ASSERT( m_mediaPlayer != NULL );
214
    m_mediaPlayer->stop();
215
    m_mediaPlayer = NULL;
216
    setState( Stopped );
217 218
    QMutexLocker    lock( m_requiredStateLock );
    m_requiredState = ClipWorkflow::None;
219 220 221 222 223 224
}

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

226
bool            ClipWorkflow::isRendering() const
227
{
228 229
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Rendering;
230
}
231

232
void            ClipWorkflow::setState( State state )
233
{
234 235
    QWriteLocker    lock( m_stateLock );
    m_state = state;
236
}
237 238 239 240 241 242

void            ClipWorkflow::queryStateChange( State newState )
{
    QMutexLocker    lock( m_requiredStateLock );
    m_requiredState = newState;
}
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

void            ClipWorkflow::wake()
{
    m_waitCond->wakeAll();
}

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

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