root/OpenSceneGraph/trunk/src/osgPlugins/mpeg/MpegImageStream.cpp @ 3285

Revision 3285, 7.5 kB (checked in by robert, 10 years ago)

Cleaned up output level of debugging messages

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// -*-c++-*-
2
3/*
4 * Copyright (C) 2001 Ulrich Hertlein <u.hertlein@web.de>
5 *
6 * Uses libmpeg3 by Adam Williams
7 * See http://www.heroinewarrior.com
8 *
9 * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
10 * real-time rendering of large 3D photo-realistic models.
11 * The OSG homepage is http://www.openscenegraph.org/
12 *
13 * This software is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This software is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 */
27
28#include "MpegImageStream.h"
29#include <osg/Notify>
30#include <osg/Timer>
31
32#include <OpenThreads/ScopedLock>
33#include <OpenThreads/Mutex>
34
35
36#include <stdio.h>
37#include <unistd.h>
38#include <sys/time.h>
39
40#include "libmpeg3/libmpeg3.h"
41
42
43
44using namespace osg;
45
46#define IDLE_TIMEOUT 150000L
47
48
49// Constructor: setup and start thread
50MpegImageStream::MpegImageStream(const char* fileName) : ImageStream()
51{
52    _useMMX = false;
53    _fps = 0.0f;
54    _frames = 0;
55    _len = 0;
56    _mpg = 0;
57
58    _videoWriteData = 0;
59    _rows = 0;
60   
61    for (int i = 0; i < NUM_CMD_INDEX; i++)
62        _cmd[i] = THREAD_IDLE;
63    _wrIndex = _rdIndex = 0;
64
65    load(fileName);
66
67    if (fileName)
68        setFileName(fileName);
69}
70
71
72// Deconstructor: stop and terminate thread
73MpegImageStream::~MpegImageStream()
74{
75    if( isRunning() )
76    {
77        quit(true);
78    }
79
80    mpeg3_t* mpg = (mpeg3_t*)_mpg;
81    if (mpg) {
82        mpeg3_close(mpg);
83        mpg = NULL;
84    }
85    if (_rows) {
86        delete [] _rows;
87        _rows = NULL;
88    }
89   
90    if (_videoWriteData)
91    {
92        delete [] _videoWriteData;
93    }
94
95}
96
97// Set command
98void MpegImageStream::setCmd(ThreadCommand cmd)
99{
100    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
101    _cmd[_wrIndex] = cmd;
102    _wrIndex = (_wrIndex + 1) % NUM_CMD_INDEX;
103}
104
105
106// Get command
107MpegImageStream::ThreadCommand MpegImageStream::getCmd()
108{
109    ThreadCommand cmd = THREAD_IDLE;
110
111    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
112    if (_rdIndex != _wrIndex)
113    {
114        cmd = _cmd[_rdIndex];
115        _rdIndex = (_rdIndex + 1) % NUM_CMD_INDEX;
116    }
117
118    return cmd;
119}
120
121
122void MpegImageStream::load(const char* fileName)
123{
124    mpeg3_t* mpg = mpeg3_open((char*) fileName);
125    if (!mpg) {
126        osg::notify(WARN) << "Unable to open " << fileName << std::endl;
127        return;
128    }
129
130    if (!mpeg3_has_video(mpg))
131    {
132        osg::notify(WARN) << "No video streams in" << fileName << std::endl;
133        return;
134    }
135    if (mpeg3_has_audio(mpg))
136    {
137        osg::notify(INFO) << "Stream has audio" << std::endl;
138    }
139
140    _mpg = (void*)mpg;
141
142    mpeg3_set_cpus(mpg, 1);
143    mpeg3_set_mmx(mpg, _useMMX);
144
145    int str = 0; //mpeg3_total_vstreams(mpg) - 1;
146
147    _fps = mpeg3_frame_rate(mpg, str);
148    _frames = mpeg3_video_frames(mpg, str);
149    _len = (float) _frames / _fps;
150
151
152    int s = mpeg3_video_width(mpg, str);
153    int t = mpeg3_video_height(mpg, str);
154
155    // Calculate texture size
156    // these are also calculated and stored within osg::Texture but
157    // too late (on the first apply) to be of any use...
158    int texWidth = 1;
159    for (; texWidth < s; texWidth <<= 1)
160        ;
161    int texHeight = 1;
162    for (; texHeight < t; texHeight <<= 1)
163        ;
164
165
166    // Allocate image data
167    // maybe use BGR888 and save some conversion somewhere?
168    unsigned char* data = new unsigned char [s * t * 3];
169    _videoWriteData = new unsigned char [s * t * 3];
170
171    setImage(s, t, 0,
172             GL_RGB,
173             GL_RGB, GL_UNSIGNED_BYTE, data,
174             osg::Image::USE_NEW_DELETE);
175
176
177    // Allocate decoder rows
178    // documentation says we need add'l bytes at the end of each
179    // row for MMX but this is more efficient and works so far.
180    _rows = new unsigned char* [t];
181   
182    // set up the rows to the current view write data.
183    swapData();
184
185
186    osg::notify(INFO) << _frames << " @ " << _fps << " " << _len << "s" << std::endl;
187    osg::notify(INFO) << "img " << s << "x" << t << std::endl;
188    osg::notify(INFO) << "tex " << texWidth << "x" << texHeight << std::endl;
189}
190
191
192void MpegImageStream::swapData()
193{
194    std::swap(_videoWriteData,_data);
195    unsigned char* dp = _videoWriteData;
196    for (int i = 0; i < t(); i++)
197    {
198        _rows[t()-i-1] = dp;
199        dp += (s() * 3);
200    }
201}
202
203
204void MpegImageStream::quit(bool wiatForThreadToExit)
205{
206    osg::notify(osg::DEBUG_INFO)<<"Sending quit"<<std::endl;
207    setCmd(THREAD_QUIT);
208
209    if (wiatForThreadToExit)
210    {
211        while(isRunning())
212        {
213            osg::notify(osg::DEBUG_INFO)<<"Waiting for MpegImageStream to quit"<<std::endl;
214            OpenThreads::Thread::YieldCurrentThread();
215        }
216    }
217}
218
219
220void MpegImageStream::run()
221{
222    bool playing = false;
223    mpeg3_t* mpg = (mpeg3_t*)_mpg;
224    int str = 0;
225    float t0 = 0.0f;
226    unsigned long delay = (unsigned long) ((1.0f / _fps) * 1000.0f);
227
228    bool done = false;
229   
230    const osg::Timer* timer = osg::Timer::instance();
231    osg::Timer_t start_tick = timer->tick();
232    osg::Timer_t last_frame_tick = start_tick;
233    double timePerFrame = 1.0f/_fps;
234    double frameNumber = 0.0;
235   
236    while (!done)
237    {
238        // Handle commands
239        ThreadCommand cmd = getCmd();
240        if (cmd != THREAD_IDLE)
241        {
242            switch (cmd)
243            {
244            case THREAD_START: // Start or continue stream
245                playing = true;
246                break;
247            case THREAD_STOP: // XXX
248                playing = false;
249                break;
250            case THREAD_REWIND: // XXX
251                t0 = 0.0;
252                mpeg3_seek_percentage(mpg, 0.0);
253                start_tick = timer->tick();               
254                frameNumber = 0;
255                break;
256            case THREAD_CLOSE: // Stop and close
257                playing = false;
258                if (mpg)
259                {
260                    mpeg3_close(mpg);
261                    mpg = NULL;
262                }
263                break;
264            case THREAD_QUIT:
265                playing = false;
266                done = true;
267                break;
268            default:
269                osg::notify(osg::WARN) << "Unknown command " << cmd << std::endl;
270                break;
271            }
272        }
273
274        if (playing)
275        {
276            last_frame_tick = timer->tick();
277           
278            // XXX needs more work to be real-time
279            mpeg3_read_frame(mpg, _rows,
280                             0, 0, _s, _t,
281                             _s, _t,
282                             MPEG3_RGB888, str);
283
284            swapData();
285
286            dirty(); //Image();
287
288            ++frameNumber;
289           
290            if (frameNumber>=_frames)
291            {
292                rewind();
293                //stop();
294            }
295            else
296            {
297                while (timePerFrame*(frameNumber+1)>timer->delta_s(start_tick,timer->tick()))
298                {
299                    ::usleep(delay);
300                }
301            }
302        }
303        else if (!done)
304        {
305            //OpenThreads::Thread::YieldCurrentThread();
306            ::usleep(IDLE_TIMEOUT);
307        }
308    }
309}
Note: See TracBrowser for help on using the browser.