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

Revision 9847, 5.0 kB (checked in by robert, 6 years ago)

Introduce FFmpegAudioStream implementation

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