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

Revision 9816, 5.6 kB (checked in by robert, 6 years ago)

From Tanguy Fautre (Aris Technologies), ffmpeg plugin

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