VideoClipWorkflow.cpp 6.05 KB
Newer Older
1 2 3
/*****************************************************************************
 * VideoClipWorkflow.cpp : Clip workflow. Will extract a single frame from a VLCMedia
 *****************************************************************************
4
 * Copyright (C) 2008-2014 VideoLAN
5
 *
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
6
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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 24
#include "Media/Clip.h"
#include "EffectsEngine/EffectInstance.h"
25
#include "Project/Project.h"
26
#include "MainWorkflow.h"
27 28 29
#include "Media/Media.h"
#include "Backend/ISource.h"
#include "Backend/ISourceRenderer.h"
30
#include "Settings/Settings.h"
31
#include "VideoClipWorkflow.h"
32
#include "VLCMedia.h"
33
#include "Tools/VlmcDebug.h"
34
#include "Workflow/Types.h"
35

36
#include <QMutexLocker>
37
#include <QReadWriteLock>
38
#include <QStringBuilder>
39 40
#include <QWaitCondition>

41 42
VideoClipWorkflow::VideoClipWorkflow( ClipHelper *ch ) :
        ClipWorkflow( ch ),
43
        m_lastReturnedBuffer( NULL )
44
{
45
    m_effectsLock = new QReadWriteLock();
46 47 48
}

VideoClipWorkflow::~VideoClipWorkflow()
49
{
50
    stop();
51 52 53 54
}

void
VideoClipWorkflow::releasePrealocated()
55
{
56
    while ( m_availableBuffers.isEmpty() == false )
57
        delete m_availableBuffers.dequeue();
58
    while ( m_computedBuffers.isEmpty() == false )
59
        delete m_computedBuffers.dequeue();
60 61
}

62 63 64
void
VideoClipWorkflow::preallocate()
{
65 66
    quint32     newWidth = Project::getInstance()->workflow()->getWidth();
    quint32     newHeight = Project::getInstance()->workflow()->getHeight();
67
    if ( newWidth != m_width || newHeight != m_height )
68
    {
69 70 71 72 73 74
        m_width = newWidth;
        m_height = newHeight;
        while ( m_availableBuffers.isEmpty() == false )
            delete m_availableBuffers.dequeue();
        for ( unsigned int i = 0; i < VideoClipWorkflow::nbBuffers; ++i )
        {
75
            m_availableBuffers.enqueue( new Workflow::Frame( newWidth, newHeight ) );
76
        }
77 78 79
    }
}

80
void
81
VideoClipWorkflow::initializeInternals()
82
{
83
    initFilters();
84
    m_renderer->setName( qPrintable( QString("VideoClipWorkflow " % m_clipHelper->uuid().toString() ) ) );
85 86 87 88 89
    m_renderer->enableVideoOutputToMemory( this, &lock, &unlock, m_fullSpeedRender );
    m_renderer->setOutputWidth( m_width );
    m_renderer->setOutputHeight( m_height );
    m_renderer->setOutputFps( (float)VLMC_PROJECT_GET_DOUBLE( "video/VLMCOutputFPS" ) );
    m_renderer->setOutputVideoCodec( "RV32" );
90 91
}

92
Workflow::OutputBuffer*
93
VideoClipWorkflow::getOutput( ClipWorkflow::GetMode mode, qint64 currentFrame )
94
{
95
    QMutexLocker    lock( m_renderLock );
96

97 98 99 100 101
    if ( m_lastReturnedBuffer != NULL )
    {
        m_availableBuffers.enqueue( m_lastReturnedBuffer );
        m_lastReturnedBuffer = NULL;
    }
102
    if ( shouldRender() == false )
103
        return NULL;
104
    if ( getNbComputedBuffers() == 0 )
105
    {
106 107 108 109 110 111
        if ( m_renderWaitCond->wait( m_renderLock, 50 ) == false )
        {
            vlmcWarning() << "Clip workflow" << m_clipHelper->uuid() << "Timed out while waiting for a frame";
            errorEncountered();
            return NULL;
        }
112
        if ( shouldRender() == false )
113 114
            return NULL;
    }
115
    Workflow::Frame         *buff = NULL;
116
    if ( mode == ClipWorkflow::Pop )
117 118 119 120
    {
        buff = m_computedBuffers.dequeue();
        m_lastReturnedBuffer = buff;
    }
121
    else
122
        buff = m_computedBuffers.head();
123 124

    quint32     *newFrame = applyFilters( buff, currentFrame,
125
                                 currentFrame * 1000.0 / clip()->getMedia()->source()->fps() );
126 127 128
    if ( newFrame != NULL )
        buff->setBuffer( newFrame );

129
    postGetOutput();
130
    return buff;
131 132
}

133
void
134
VideoClipWorkflow::lock( void *data, uint8_t** p_buffer, size_t size )
135
{
136 137
    VideoClipWorkflow* cw = reinterpret_cast<VideoClipWorkflow*>( data );

138
    //Mind the fact that frame size in bytes might not be width * height * bpp
139
    Workflow::Frame*    frame = NULL;
140

141
    cw->m_renderLock->lock();
142
    if ( cw->m_availableBuffers.isEmpty() == true )
143 144 145 146 147 148
    {
        if ( Workflow::Frame::Size( cw->m_width, cw->m_height ) == size )
            frame = new Workflow::Frame( cw->m_width, cw->m_height );
        else
            frame = new Workflow::Frame( cw->m_width, cw->m_height, size );
    }
149
    else
150
    {
151
        frame = cw->m_availableBuffers.dequeue();
152 153 154
        if ( frame->size() != size )
            frame->resize( size );
    }
155
    cw->m_computedBuffers.enqueue( frame );
156
    *p_buffer = (uint8_t*)frame->buffer();
157 158
}

159
void
160 161
VideoClipWorkflow::unlock( void *data, uint8_t *buffer, int width,
                           int height, int bpp, size_t size, int64_t pts )
162 163 164 165 166 167
{
    Q_UNUSED( buffer );
    Q_UNUSED( width );
    Q_UNUSED( height );
    Q_UNUSED( bpp );
    Q_UNUSED( size );
168

169 170
    VideoClipWorkflow* cw = reinterpret_cast<VideoClipWorkflow*>( data );

171
    cw->computePtsDiff( pts );
172 173
    Workflow::Frame     *frame = cw->m_computedBuffers.last();
    frame->ptsDiff = cw->m_currentPts - cw->m_previousPts;
174
    cw->commonUnlock();
175
    cw->m_renderWaitCond->wakeAll();
176
    cw->m_renderLock->unlock();
177 178
}

179
quint32
180
VideoClipWorkflow::getNbComputedBuffers() const
181 182 183
{
    return m_computedBuffers.count();
}
184

185
quint32
186
VideoClipWorkflow::getMaxComputedBuffers() const
187 188 189
{
    return VideoClipWorkflow::nbBuffers;
}
190

191 192
void
VideoClipWorkflow::flushComputedBuffers()
193
{
194
    QMutexLocker    lock( m_renderLock );
195 196 197 198

    while ( m_computedBuffers.isEmpty() == false )
        m_availableBuffers.enqueue( m_computedBuffers.dequeue() );
}