ClipWorkflow.cpp 7.17 KB
Newer Older
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
1
2
3
/*****************************************************************************
 * ClipWorkflow.cpp : Clip workflow. Will extract a single frame from a VLCMedia
 *****************************************************************************
Ludovic Fauvet's avatar
Ludovic Fauvet committed
4
 * Copyright (C) 2008-2010 VideoLAN
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * 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 "vlmc.h"
24
#include "Clip.h"
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
25
#include "ClipWorkflow.h"
26
#include "LightVideoFrame.h"
27
28
#include "Media.h"
#include "MemoryPool.hpp"
29
#include "WaitCondition.hpp"
30
#include "VLCMedia.h"
31
#include "VLCMediaPlayer.h"
32

33
#include <QReadWriteLock>
34
35
#include <QWaitCondition>
#include <QtDebug>
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
36

37
ClipWorkflow::ClipWorkflow( Clip::Clip* clip ) :
38
                m_mediaPlayer(NULL),
39
                m_clip( clip ),
40
                m_state( ClipWorkflow::Stopped )
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
41
{
42
    m_stateLock = new QReadWriteLock;
43
    m_initWaitCond = new WaitCondition;
44
    m_pausingStateWaitCond = new WaitCondition;
45
    m_renderLock = new QMutex;
46
    m_renderWaitCond = new QWaitCondition;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
47
48
49
50
}

ClipWorkflow::~ClipWorkflow()
{
51
    delete m_renderWaitCond;
52
    delete m_renderLock;
53
    delete m_pausingStateWaitCond;
54
    delete m_initWaitCond;
55
    delete m_stateLock;
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
56
57
}

58
void    ClipWorkflow::initialize()
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
59
{
60
61
    setState( ClipWorkflow::Initializing );

Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
62
    m_vlcMedia = new LibVLCpp::Media( m_clip->getMedia()->mrl() );
63
64
65
    m_currentPts = -1;
    m_previousPts = -1;
    m_pauseDuration = -1;
66
    initVlcOutput();
67
    m_mediaPlayer = MemoryPool<LibVLCpp::MediaPlayer>::getInstance()->get();
68
    m_mediaPlayer->setMedia( m_vlcMedia );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
69

70
    connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( loadingComplete() ), Qt::DirectConnection );
71
    connect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( clipEndReached() ), Qt::DirectConnection );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
72
73
74
    m_mediaPlayer->play();
}

75
76
void    ClipWorkflow::loadingComplete()
{
77
    adjustBegin();
78
    disconnect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( loadingComplete() ) );
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
79
80
    connect( m_mediaPlayer, SIGNAL( playing() ), this, SLOT( mediaPlayerUnpaused() ), Qt::DirectConnection );
    connect( m_mediaPlayer, SIGNAL( paused() ), this, SLOT( mediaPlayerPaused() ), Qt::DirectConnection );
81
82
83
    QMutexLocker    lock( m_initWaitCond->getMutex() );
    setState( Rendering );
    m_initWaitCond->wake();
84
85
}

86
87
void    ClipWorkflow::adjustBegin()
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
88
89
    if ( m_clip->getMedia()->fileType() == Media::Video ||
         m_clip->getMedia()->fileType() == Media::Audio )
90
    {
91
        m_mediaPlayer->setTime( m_clip->begin() /
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
92
                                m_clip->getMedia()->fps() * 1000 );
93
    }
94
95
}

96
97
bool    ClipWorkflow::isEndReached() const
{
98
99
100
101
102
103
104
105
106
107
108
109
110
    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;
111
}
112

113
void    ClipWorkflow::clipEndReached()
114
{
115
    setState( EndReached );
116
}
117

118
119
void            ClipWorkflow::stop()
{
120
121
122
123
    if ( m_mediaPlayer )
    {
        m_mediaPlayer->stop();
        disconnect( m_mediaPlayer, SIGNAL( endReached() ), this, SLOT( clipEndReached() ) );
124
        MemoryPool<LibVLCpp::MediaPlayer>::getInstance()->release( m_mediaPlayer );
125
126
        m_mediaPlayer = NULL;
        setState( Stopped );
127
        delete m_vlcMedia;
128
        flushComputedBuffers();
129
        releasePrealocated();
130
    }
131
132
}

133
134
void
ClipWorkflow::setTime( qint64 time )
135
{
136
    m_mediaPlayer->setTime( time );
137
    resyncClipWorkflow();
138
139
140
141
    QWriteLocker    lock( m_stateLock );
    if ( m_state == ClipWorkflow::Paused )
    {
        m_mediaPlayer->pause();
142
        m_state = ClipWorkflow::UnpauseRequired;
143
    }
144
}
145

146
bool            ClipWorkflow::isRendering() const
147
{
148
149
    QReadLocker lock( m_stateLock );
    return m_state == ClipWorkflow::Rendering;
150
}
151

152
void            ClipWorkflow::setState( State state )
153
{
154
155
    QWriteLocker    lock( m_stateLock );
    m_state = state;
156
}
157

158
159
160
161
162
QReadWriteLock* ClipWorkflow::getStateLock()
{
    return m_stateLock;
}

163
164
void        ClipWorkflow::waitForCompleteInit()
{
165
    if ( isRendering() == false )
166
167
168
169
    {
        QMutexLocker    lock( m_initWaitCond->getMutex() );
        m_initWaitCond->waitLocked();
    }
170
171
}

172
173
174
175
LibVLCpp::MediaPlayer*       ClipWorkflow::getMediaPlayer()
{
    return m_mediaPlayer;
}
176

177
bool        ClipWorkflow::preGetOutput()
178
{
Hugo Beauzee-Luyssen's avatar
Hugo Beauzee-Luyssen committed
179
    //Computed buffer mutex is already locked by underlying clipworkflow getoutput method
180
    if ( getNbComputedBuffers() == 0 )
181
182
        return false;
    return true;
183
184
}

185
void        ClipWorkflow::postGetOutput()
186
{
187
    //If we're running out of computed buffers, refill our stack.
188
    if ( getNbComputedBuffers() < getMaxComputedBuffers() / 3 )
189
    {
190
191
        QWriteLocker        lock( m_stateLock );
        if ( m_state == ClipWorkflow::Paused )
192
        {
193
            m_state = ClipWorkflow::UnpauseRequired;
194
//            This will act like an "unpause";
195
196
            m_mediaPlayer->pause();
        }
197
    }
198
199
}

200
201
void        ClipWorkflow::commonUnlock()
{
202
203
    //Don't test using availableBuffer, as it may evolve if a buffer is required while
    //no one is available : we would spawn a new buffer, thus modifying the number of available buffers
204
    if ( getNbComputedBuffers() >= getMaxComputedBuffers() )
205
    {
206
        setState( ClipWorkflow::PauseRequired );
207
        m_mediaPlayer->pause();
208
    }
209
}
210
211
212
213
214
215
216

void    ClipWorkflow::computePtsDiff( qint64 pts )
{
    if ( m_previousPts == -1 )
        m_previousPts = pts;
    if ( m_currentPts == -1 )
        m_currentPts = pts;
217
218
219
220
221
222
223
    if ( m_pauseDuration != -1 )
    {
        m_previousPts = m_currentPts + m_pauseDuration;
        m_pauseDuration = -1;
    }
    else
        m_previousPts = m_currentPts;
224
225
    m_currentPts = qMax( pts, m_previousPts );
}
226
227
228
229

void    ClipWorkflow::mediaPlayerPaused()
{
    setState( ClipWorkflow::Paused );
230
    m_beginPausePts = mdate();
231
232
233
234
235
}

void    ClipWorkflow::mediaPlayerUnpaused()
{
    setState( ClipWorkflow::Rendering );
236
    m_pauseDuration = mdate() - m_beginPausePts;
237
}
238
239
240
241
242
243
244

void    ClipWorkflow::resyncClipWorkflow()
{
    flushComputedBuffers();
    m_previousPts = -1;
    m_currentPts = -1;
}
245
246
247
248
249
250

void
ClipWorkflow::setFullSpeedRender( bool val )
{
    m_fullSpeedRender = val;
}
251
252
253
254
255
256
257
258
259
260
261
262
263

void
ClipWorkflow::mute()
{
    stop();
    setState( Muted );
}

void
ClipWorkflow::unmute()
{
    setState( Stopped );
}
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

void
ClipWorkflow::requireResync()
{
    m_resyncRequired = 1;
}

bool
ClipWorkflow::isResyncRequired()
{
    if ( m_resyncRequired == 1 )
    {
        m_resyncRequired = 0;
        return true;
    }
    return false;
}