root/OpenSceneGraph/trunk/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp @ 10851

Revision 10851, 6.6 kB (checked in by robert, 5 years ago)

From Julen Garcia,"I've been lately working also with the ffmpeg plugin and I implemented pause(), seek() and getReferenceTime(). I think that I have solved the internal clock issues (maybe not in the most elegant way :?"

RevLine 
[9816]1
2#include "FFmpegImageStream.hpp"
[9847]3#include "FFmpegAudioStream.hpp"
[9816]4
5#include <OpenThreads/ScopedLock>
6#include <osg/Notify>
7
8#include <memory>
9
10
11
12namespace osgFFmpeg {
13
14
15
16FFmpegImageStream::FFmpegImageStream() :
17    m_decoder(0),
18    m_commands(0),
19    m_frame_published_flag(false)
20{
[9910]21    setOrigin(osg::Image::TOP_LEFT);
[9816]22
23    std::auto_ptr<FFmpegDecoder> decoder(new FFmpegDecoder);
24    std::auto_ptr<CommandQueue> commands(new CommandQueue);
25
26    m_decoder = decoder.release();
27    m_commands = commands.release();
28}
29
30
31
32FFmpegImageStream::FFmpegImageStream(const FFmpegImageStream & image, const osg::CopyOp & copyop) :
33    osg::ImageStream(image, copyop)
34{
35    // TODO: probably incorrect or incomplete
36}
37
38
39
40FFmpegImageStream::~FFmpegImageStream()
41{
[9912]42    osg::notify(osg::INFO)<<"Destructing FFmpegImageStream..."<<std::endl;
[9861]43
[9816]44    quit(true);
[9869]45   
[9912]46    osg::notify(osg::INFO)<<"Have done quit"<<std::endl;
[9816]47
[9869]48    // release athe audio streams to make sure that the decoder doesn't retain any external
49    // refences.
50    getAudioStreams().clear();
51
[9861]52    // destroy the decoder and associated threads
53    m_decoder = 0;
54
55
[9816]56    delete m_commands;
[9861]57
[9912]58    osg::notify(osg::INFO)<<"Destructed FFMpegImageStream."<<std::endl;
[9816]59}
60
61
62
63bool FFmpegImageStream::open(const std::string & filename)
64{
65    setFileName(filename);
66
67    if (! m_decoder->open(filename))
68        return false;
69
70    setImage(
71        m_decoder->video_decoder().width(), m_decoder->video_decoder().height(), 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE,
72        const_cast<unsigned char *>(m_decoder->video_decoder().image()), NO_DELETE
73    );
74
[10538]75
[9910]76    setPixelAspectRatio(m_decoder->video_decoder().pixelAspectRatio());
[10538]77
78    osg::notify(osg::NOTICE)<<"ffmpeg::open("<<filename<<") size("<<s()<<", "<<t()<<") aspect ratio "<<m_decoder->video_decoder().pixelAspectRatio()<<std::endl;
79
80#if 1
81    // swscale is reported errors and then crashing when rescaling video of size less than 10 by 10.
82    if (s()<=10 || t()<=10) return false;
83#endif
84
[9816]85    m_decoder->video_decoder().setUserData(this);
86    m_decoder->video_decoder().setPublishCallback(publishNewFrame);
[10538]87
[9847]88    if (m_decoder->audio_decoder().validContext())
89    {
90        osg::notify(osg::NOTICE)<<"Attaching FFmpegAudioStream"<<std::endl;
[10538]91
[9847]92        getAudioStreams().push_back(new FFmpegAudioStream(m_decoder.get()));
93    }
[9816]94
95    _status = PAUSED;
96    applyLoopingMode();
97
98    start(); // start thread
99
100    return true;
101}
102
103
104
105void FFmpegImageStream::play()
106{
107    m_commands->push(CMD_PLAY);
108
109#if 0
110    // Wait for at least one frame to be published before returning the call
111    OpenThreads::ScopedLock<Mutex> lock(m_mutex);
112
113    while (duration() > 0 && ! m_frame_published_flag)
114        m_frame_published_cond.wait(&m_mutex);
115
116#endif
117}
118
119
120
121void FFmpegImageStream::pause()
122{
123    m_commands->push(CMD_PAUSE);
124}
125
126
127
128void FFmpegImageStream::rewind()
129{
130    m_commands->push(CMD_REWIND);
131}
132
[10809]133void FFmpegImageStream::seek(double time) {
134    m_seek_time = time;
135    m_commands->push(CMD_SEEK);
136}
[9816]137
138
[10809]139
[9816]140void FFmpegImageStream::quit(bool waitForThreadToExit)
141{
142    // Stop the packet producer thread
143    if (isRunning())
144    {
145        m_commands->push(CMD_STOP);
146
147        if (waitForThreadToExit)
148            join();
149    }
150
151    // Close the decoder (i.e. flush the decoder packet queues)
[9869]152    m_decoder->close(waitForThreadToExit);
[9816]153}
154
155
[9910]156double FFmpegImageStream::getLength() const
[9816]157{
158    return m_decoder->duration();
159}
160
161
[10851]162double FFmpegImageStream::getReferenceTime () const
163{
164    return m_decoder->reference();
165}
[9816]166
[10851]167
168
[9910]169double FFmpegImageStream::getFrameRate() const
[9816]170{
[9910]171    return m_decoder->video_decoder().frameRate();
[9816]172}
173
174
175
[9910]176bool FFmpegImageStream::isImageTranslucent() const 
[9816]177{
[9910]178    return m_decoder->video_decoder().alphaChannel();
[9816]179}
180
181
182
183void FFmpegImageStream::run()
184{
185    try
186    {
187        bool done = false;
188
189        while (! done)
190        {
191            if (_status == PLAYING)
192            {
193                bool no_cmd;
194                const Command cmd = m_commands->timedPop(no_cmd, 1);
195
196                if (no_cmd)
197                {
198                    m_decoder->readNextPacket();
199                }
200                else
201                    done = ! handleCommand(cmd);
202            }
203            else
204            {
205                done = ! handleCommand(m_commands->pop());
206            }
207        }
208    }
209
210    catch (const std::exception & error)
211    {
212        osg::notify(osg::WARN) << "FFmpegImageStream::run : " << error.what() << std::endl;
213    }
214
215    catch (...)
216    {
217        osg::notify(osg::WARN) << "FFmpegImageStream::run : unhandled exception" << std::endl;
218    }
[9869]219   
220    osg::notify(osg::NOTICE)<<"Finished FFmpegImageStream::run()"<<std::endl;
[9816]221}
222
223
224
225void FFmpegImageStream::applyLoopingMode()
226{
227    m_decoder->loop(getLoopingMode() == LOOPING);
228}
229
230
231
232bool FFmpegImageStream::handleCommand(const Command cmd)
233{
234    switch (cmd)
235    {
236    case CMD_PLAY:
237        cmdPlay();
238        return true;
239
240    case CMD_PAUSE:
241        cmdPause();
242        return true;
243
244    case CMD_REWIND:
245        cmdRewind();
246        return true;
247
[10809]248    case CMD_SEEK:
249        cmdSeek(m_seek_time);
250        return true;
251
[9816]252    case CMD_STOP:
253        return false;
254
255    default:
256        assert(false);
257        return false;
258    }
259}
260
261
262
263void FFmpegImageStream::cmdPlay()
264{
265    if (_status == PAUSED)
266    {
267        if (! m_decoder->audio_decoder().isRunning())
268            m_decoder->audio_decoder().start();
269
270        if (! m_decoder->video_decoder().isRunning())
271            m_decoder->video_decoder().start();
[10809]272
[10851]273        m_decoder->video_decoder().pause(false);
274        m_decoder->audio_decoder().pause(false);
[9816]275    }
276
277    _status = PLAYING;
278}
279
280
281
282void FFmpegImageStream::cmdPause()
283{
284    if (_status == PLAYING)
285    {
[10851]286        m_decoder->video_decoder().pause(true);
287        m_decoder->audio_decoder().pause(true);
[9816]288    }
289
290    _status = PAUSED;
291}
292
293
294
295void FFmpegImageStream::cmdRewind()
296{
297    m_decoder->rewind();
298}
299
[10809]300void FFmpegImageStream::cmdSeek(double time)
301{
302    m_decoder->seek(time);
303}
[9816]304
305
306void FFmpegImageStream::publishNewFrame(const FFmpegDecoderVideo &, void * user_data)
307{
308    FFmpegImageStream * const this_ = reinterpret_cast<FFmpegImageStream*>(user_data);
309
[9860]310#if 1
311    this_->setImage(
312        this_->m_decoder->video_decoder().width(), this_->m_decoder->video_decoder().height(), 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE,
313        const_cast<unsigned char *>(this_->m_decoder->video_decoder().image()), NO_DELETE
314    );
315#else
[9816]316    /** \bug If viewer.realize() hasn't been already called, this doesn't work? */
317    this_->dirty();
[9860]318#endif
[9816]319
320    OpenThreads::ScopedLock<Mutex> lock(this_->m_mutex);
321
322    if (! this_->m_frame_published_flag)
323    {
324        this_->m_frame_published_flag = true;
325        this_->m_frame_published_cond.signal();
326    }
327}
328
329
330
331} // namespace osgFFmpeg
Note: See TracBrowser for help on using the browser.