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

Revision 10538, 6.1 kB (checked in by robert, 5 years ago)

Added check against a minimual video size of 10x10 to prevent problems with swscale reporting errors and crashing on small video dimensionsline, and those below, will be ignored--

M ffmpeg/FFmpegImageStream.cpp

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
133
134
135void FFmpegImageStream::quit(bool waitForThreadToExit)
136{
137    // Stop the packet producer thread
138    if (isRunning())
139    {
140        m_commands->push(CMD_STOP);
141
142        if (waitForThreadToExit)
143            join();
144    }
145
146    // Close the decoder (i.e. flush the decoder packet queues)
[9869]147    m_decoder->close(waitForThreadToExit);
[9816]148}
149
150
[9910]151double FFmpegImageStream::getLength() const
[9816]152{
153    return m_decoder->duration();
154}
155
156
157
[9910]158double FFmpegImageStream::getFrameRate() const
[9816]159{
[9910]160    return m_decoder->video_decoder().frameRate();
[9816]161}
162
163
164
[9910]165bool FFmpegImageStream::isImageTranslucent() const 
[9816]166{
[9910]167    return m_decoder->video_decoder().alphaChannel();
[9816]168}
169
170
171
172void FFmpegImageStream::run()
173{
174    try
175    {
176        bool done = false;
177
178        while (! done)
179        {
180            if (_status == PLAYING)
181            {
182                bool no_cmd;
183                const Command cmd = m_commands->timedPop(no_cmd, 1);
184
185                if (no_cmd)
186                {
187                    m_decoder->readNextPacket();
188                }
189                else
190                    done = ! handleCommand(cmd);
191            }
192            else
193            {
194                done = ! handleCommand(m_commands->pop());
195            }
196        }
197    }
198
199    catch (const std::exception & error)
200    {
201        osg::notify(osg::WARN) << "FFmpegImageStream::run : " << error.what() << std::endl;
202    }
203
204    catch (...)
205    {
206        osg::notify(osg::WARN) << "FFmpegImageStream::run : unhandled exception" << std::endl;
207    }
[9869]208   
209    osg::notify(osg::NOTICE)<<"Finished FFmpegImageStream::run()"<<std::endl;
[9816]210}
211
212
213
214void FFmpegImageStream::applyLoopingMode()
215{
216    m_decoder->loop(getLoopingMode() == LOOPING);
217}
218
219
220
221bool FFmpegImageStream::handleCommand(const Command cmd)
222{
223    switch (cmd)
224    {
225    case CMD_PLAY:
226        cmdPlay();
227        return true;
228
229    case CMD_PAUSE:
230        cmdPause();
231        return true;
232
233    case CMD_REWIND:
234        cmdRewind();
235        return true;
236
237    case CMD_STOP:
238        return false;
239
240    default:
241        assert(false);
242        return false;
243    }
244}
245
246
247
248void FFmpegImageStream::cmdPlay()
249{
250    if (_status == PAUSED)
251    {
252        if (! m_decoder->audio_decoder().isRunning())
253            m_decoder->audio_decoder().start();
254
255        if (! m_decoder->video_decoder().isRunning())
256            m_decoder->video_decoder().start();
257    }
258
259    _status = PLAYING;
260}
261
262
263
264void FFmpegImageStream::cmdPause()
265{
266    if (_status == PLAYING)
267    {
268
269    }
270
271    _status = PAUSED;
272}
273
274
275
276void FFmpegImageStream::cmdRewind()
277{
278    m_decoder->rewind();
279}
280
281
282
283void FFmpegImageStream::publishNewFrame(const FFmpegDecoderVideo &, void * user_data)
284{
285    FFmpegImageStream * const this_ = reinterpret_cast<FFmpegImageStream*>(user_data);
286
[9860]287#if 1
288    this_->setImage(
289        this_->m_decoder->video_decoder().width(), this_->m_decoder->video_decoder().height(), 1, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE,
290        const_cast<unsigned char *>(this_->m_decoder->video_decoder().image()), NO_DELETE
291    );
292#else
[9816]293    /** \bug If viewer.realize() hasn't been already called, this doesn't work? */
294    this_->dirty();
[9860]295#endif
[9816]296
297    OpenThreads::ScopedLock<Mutex> lock(this_->m_mutex);
298
299    if (! this_->m_frame_published_flag)
300    {
301        this_->m_frame_published_flag = true;
302        this_->m_frame_published_cond.signal();
303    }
304}
305
306
307
308} // namespace osgFFmpeg
Note: See TracBrowser for help on using the browser.