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

Revision 9869, 5.8 kB (checked in by robert, 5 years ago)

Fixed thread exit problems

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{
21    setOrigin(osg::Image::BOTTOM_LEFT);
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{
[9861]42    osg::notify(osg::NOTICE)<<"Destructing FFMpegImageStream..."<<std::endl;
43
[9816]44    quit(true);
[9869]45   
46    osg::notify(osg::NOTICE)<<"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
58    osg::notify(osg::NOTICE)<<"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    );
[9860]74   
75    setOrigin(osg::Image::TOP_LEFT);
[9816]76
77    m_decoder->video_decoder().setUserData(this);
78    m_decoder->video_decoder().setPublishCallback(publishNewFrame);
[9847]79   
80    if (m_decoder->audio_decoder().validContext())
81    {
82        osg::notify(osg::NOTICE)<<"Attaching FFmpegAudioStream"<<std::endl;
83   
84        getAudioStreams().push_back(new FFmpegAudioStream(m_decoder.get()));
85    }
[9816]86
87    _status = PAUSED;
88    applyLoopingMode();
89
90    start(); // start thread
91
92    return true;
93}
94
95
96
97void FFmpegImageStream::play()
98{
99    m_commands->push(CMD_PLAY);
100
101#if 0
102    // Wait for at least one frame to be published before returning the call
103    OpenThreads::ScopedLock<Mutex> lock(m_mutex);
104
105    while (duration() > 0 && ! m_frame_published_flag)
106        m_frame_published_cond.wait(&m_mutex);
107
108#endif
109}
110
111
112
113void FFmpegImageStream::pause()
114{
115    m_commands->push(CMD_PAUSE);
116}
117
118
119
120void FFmpegImageStream::rewind()
121{
122    m_commands->push(CMD_REWIND);
123}
124
125
126
127void FFmpegImageStream::quit(bool waitForThreadToExit)
128{
129    // Stop the packet producer thread
130    if (isRunning())
131    {
132        m_commands->push(CMD_STOP);
133
134        if (waitForThreadToExit)
135            join();
136    }
137
138    // Close the decoder (i.e. flush the decoder packet queues)
[9869]139    m_decoder->close(waitForThreadToExit);
[9816]140}
141
142
143double FFmpegImageStream::duration() const
144{
145    return m_decoder->duration();
146}
147
148
149
150bool FFmpegImageStream::videoAlphaChannel() const 
151{
152    return m_decoder->video_decoder().alphaChannel();
153}
154
155
156
157double FFmpegImageStream::videoAspectRatio() const
158{
159    return m_decoder->video_decoder().aspectRatio();
160}
161
162
163
164double FFmpegImageStream::videoFrameRate() const
165{
166    return m_decoder->video_decoder().frameRate();
167}
168
169
170void FFmpegImageStream::run()
171{
172    try
173    {
174        bool done = false;
175
176        while (! done)
177        {
178            if (_status == PLAYING)
179            {
180                bool no_cmd;
181                const Command cmd = m_commands->timedPop(no_cmd, 1);
182
183                if (no_cmd)
184                {
185                    m_decoder->readNextPacket();
186                }
187                else
188                    done = ! handleCommand(cmd);
189            }
190            else
191            {
192                done = ! handleCommand(m_commands->pop());
193            }
194        }
195    }
196
197    catch (const std::exception & error)
198    {
199        osg::notify(osg::WARN) << "FFmpegImageStream::run : " << error.what() << std::endl;
200    }
201
202    catch (...)
203    {
204        osg::notify(osg::WARN) << "FFmpegImageStream::run : unhandled exception" << std::endl;
205    }
[9869]206   
207    osg::notify(osg::NOTICE)<<"Finished FFmpegImageStream::run()"<<std::endl;
[9816]208}
209
210
211
212void FFmpegImageStream::applyLoopingMode()
213{
214    m_decoder->loop(getLoopingMode() == LOOPING);
215}
216
217
218
219bool FFmpegImageStream::handleCommand(const Command cmd)
220{
221    switch (cmd)
222    {
223    case CMD_PLAY:
224        cmdPlay();
225        return true;
226
227    case CMD_PAUSE:
228        cmdPause();
229        return true;
230
231    case CMD_REWIND:
232        cmdRewind();
233        return true;
234
235    case CMD_STOP:
236        return false;
237
238    default:
239        assert(false);
240        return false;
241    }
242}
243
244
245
246void FFmpegImageStream::cmdPlay()
247{
248    if (_status == PAUSED)
249    {
250        if (! m_decoder->audio_decoder().isRunning())
251            m_decoder->audio_decoder().start();
252
253        if (! m_decoder->video_decoder().isRunning())
254            m_decoder->video_decoder().start();
255    }
256
257    _status = PLAYING;
258}
259
260
261
262void FFmpegImageStream::cmdPause()
263{
264    if (_status == PLAYING)
265    {
266
267    }
268
269    _status = PAUSED;
270}
271
272
273
274void FFmpegImageStream::cmdRewind()
275{
276    m_decoder->rewind();
277}
278
279
280
281void FFmpegImageStream::publishNewFrame(const FFmpegDecoderVideo &, void * user_data)
282{
283    FFmpegImageStream * const this_ = reinterpret_cast<FFmpegImageStream*>(user_data);
284
[9860]285#if 1
286    this_->setImage(
287        this_->m_decoder->video_decoder().width(), this_->m_decoder->video_decoder().height(), 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE,
288        const_cast<unsigned char *>(this_->m_decoder->video_decoder().image()), NO_DELETE
289    );
290#else
[9816]291    /** \bug If viewer.realize() hasn't been already called, this doesn't work? */
292    this_->dirty();
[9860]293#endif
[9816]294
295    OpenThreads::ScopedLock<Mutex> lock(this_->m_mutex);
296
297    if (! this_->m_frame_published_flag)
298    {
299        this_->m_frame_published_flag = true;
300        this_->m_frame_published_cond.signal();
301    }
302}
303
304
305
306} // namespace osgFFmpeg
Note: See TracBrowser for help on using the browser.