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

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

Introduced osg::AudioStream? class to help manage audio streams coming in from movie reading plugins

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
[9826]124void FFmpegImageStream::setAudioSink(osg::AudioSinkInterface* audio_sink)
[9816]125{
126    m_decoder->audio_decoder().setAudioSink(audio_sink);
127}
128
129
[9827]130void FFmpegImageStream::consumeAudioBuffer(void * const buffer, const size_t size)
[9816]131{
132    m_decoder->audio_decoder().fillBuffer(buffer, size);
133}
134
135
136
137double FFmpegImageStream::duration() const
138{
139    return m_decoder->duration();
140}
141
142
143
144bool FFmpegImageStream::videoAlphaChannel() const 
145{
146    return m_decoder->video_decoder().alphaChannel();
147}
148
149
150
151double FFmpegImageStream::videoAspectRatio() const
152{
153    return m_decoder->video_decoder().aspectRatio();
154}
155
156
157
158double FFmpegImageStream::videoFrameRate() const
159{
160    return m_decoder->video_decoder().frameRate();
161}
162
163
164
165bool FFmpegImageStream::audioStream() const 
166{
167    return m_decoder->audio_decoder().validContext();
168}
169
170
171
172int FFmpegImageStream::audioFrequency() const 
173{
174    return m_decoder->audio_decoder().frequency();
175}
176
177
178
179int FFmpegImageStream::audioNbChannels() const 
180{
181    return m_decoder->audio_decoder().nbChannels();
182}
183
184
185
[9827]186osg::AudioStream::SampleFormat FFmpegImageStream::audioSampleFormat() const 
[9816]187{
188    return m_decoder->audio_decoder().sampleFormat();
189}
190
191
192
193void FFmpegImageStream::run()
194{
195    try
196    {
197        bool done = false;
198
199        while (! done)
200        {
201            if (_status == PLAYING)
202            {
203                bool no_cmd;
204                const Command cmd = m_commands->timedPop(no_cmd, 1);
205
206                if (no_cmd)
207                {
208                    m_decoder->readNextPacket();
209                }
210                else
211                    done = ! handleCommand(cmd);
212            }
213            else
214            {
215                done = ! handleCommand(m_commands->pop());
216            }
217        }
218    }
219
220    catch (const std::exception & error)
221    {
222        osg::notify(osg::WARN) << "FFmpegImageStream::run : " << error.what() << std::endl;
223    }
224
225    catch (...)
226    {
227        osg::notify(osg::WARN) << "FFmpegImageStream::run : unhandled exception" << std::endl;
228    }
229}
230
231
232
233void FFmpegImageStream::applyLoopingMode()
234{
235    m_decoder->loop(getLoopingMode() == LOOPING);
236}
237
238
239
240bool FFmpegImageStream::handleCommand(const Command cmd)
241{
242    switch (cmd)
243    {
244    case CMD_PLAY:
245        cmdPlay();
246        return true;
247
248    case CMD_PAUSE:
249        cmdPause();
250        return true;
251
252    case CMD_REWIND:
253        cmdRewind();
254        return true;
255
256    case CMD_STOP:
257        return false;
258
259    default:
260        assert(false);
261        return false;
262    }
263}
264
265
266
267void FFmpegImageStream::cmdPlay()
268{
269    if (_status == PAUSED)
270    {
271        if (! m_decoder->audio_decoder().isRunning())
272            m_decoder->audio_decoder().start();
273
274        if (! m_decoder->video_decoder().isRunning())
275            m_decoder->video_decoder().start();
276    }
277
278    _status = PLAYING;
279}
280
281
282
283void FFmpegImageStream::cmdPause()
284{
285    if (_status == PLAYING)
286    {
287
288    }
289
290    _status = PAUSED;
291}
292
293
294
295void FFmpegImageStream::cmdRewind()
296{
297    m_decoder->rewind();
298}
299
300
301
302void FFmpegImageStream::publishNewFrame(const FFmpegDecoderVideo &, void * user_data)
303{
304    FFmpegImageStream * const this_ = reinterpret_cast<FFmpegImageStream*>(user_data);
305
306    /** \bug If viewer.realize() hasn't been already called, this doesn't work? */
307    this_->dirty();
308
309    OpenThreads::ScopedLock<Mutex> lock(this_->m_mutex);
310
311    if (! this_->m_frame_published_flag)
312    {
313        this_->m_frame_published_flag = true;
314        this_->m_frame_published_cond.signal();
315    }
316}
317
318
319
320} // namespace osgFFmpeg
Note: See TracBrowser for help on using the browser.