~saiarcot895/ubuntu/trusty/openscenegraph/armhf-support

« back to all changes in this revision

Viewing changes to OpenSceneGraph/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alberto Luaces
  • Date: 2010-05-03 21:42:01 UTC
  • mfrom: (1.1.9 upstream) (2.1.11 sid)
  • Revision ID: james.westby@ubuntu.com-20100503214201-iy060qxb94vsfv87
Tags: 2.8.3-3
* Added README.source. Thanks Manuel Montecelo.
* Removed FindGDAL.cmake file supplied by upstream since it does not
  detect current libgdal1-1.6.0. The script provided by CMake works
  fine.
* Removed openthreads-doc since OpenThreads documentation is shared with
  OpenSceneGraph's, hence this package was empty.
* Now ccache handling is being done automatically by CMake.
* Drop conflict dependencies with previous versions to let them coexist
  with current ones (Closes: #580079 #580081).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
#include "FFmpegDecoder.hpp"
 
3
 
 
4
#include <osg/Notify>
 
5
#include <osgDB/FileNameUtils>
 
6
 
 
7
#include <cassert>
 
8
#include <limits>
 
9
#include <stdexcept>
 
10
#include <string.h>
 
11
#include <iostream>
 
12
 
 
13
 
 
14
namespace osgFFmpeg {
 
15
 
 
16
 
 
17
 
 
18
FFmpegDecoder::FFmpegDecoder() :
 
19
    m_audio_stream(0),
 
20
    m_video_stream(0),
 
21
    m_audio_queue(100),
 
22
    m_video_queue(100),
 
23
    m_audio_decoder(m_audio_queue, m_clocks),
 
24
    m_video_decoder(m_video_queue, m_clocks),
 
25
    m_state(NORMAL),
 
26
    m_loop(false)
 
27
{
 
28
 
 
29
}
 
30
 
 
31
 
 
32
 
 
33
FFmpegDecoder::~FFmpegDecoder()
 
34
{
 
35
    close(true);
 
36
}
 
37
 
 
38
 
 
39
bool FFmpegDecoder::open(const std::string & filename)
 
40
{
 
41
    try
 
42
    {
 
43
        // Open video file
 
44
        AVFormatContext * p_format_context = 0;
 
45
 
 
46
        if (filename.compare(0, 5, "/dev/")==0)
 
47
        {
 
48
            avdevice_register_all();
 
49
        
 
50
            osg::notify(osg::NOTICE)<<"Attempting to stream "<<filename<<std::endl;
 
51
 
 
52
            AVFormatParameters formatParams;
 
53
            memset(&formatParams, 0, sizeof(AVFormatParameters));
 
54
            AVInputFormat *iformat;
 
55
 
 
56
            formatParams.channel = 0;
 
57
            formatParams.standard = 0;
 
58
#if 1
 
59
            formatParams.width = 320;
 
60
            formatParams.height = 240;
 
61
#else
 
62
            formatParams.width = 640;
 
63
            formatParams.height = 480;
 
64
#endif            
 
65
            formatParams.time_base.num = 1;
 
66
            formatParams.time_base.den = 30;
 
67
 
 
68
            std::string format = "video4linux2";
 
69
            iformat = av_find_input_format(format.c_str());
 
70
            
 
71
            if (iformat)
 
72
            {
 
73
                osg::notify(osg::NOTICE)<<"Found input format: "<<format<<std::endl;
 
74
            }
 
75
            else
 
76
            {
 
77
                osg::notify(osg::NOTICE)<<"Failed to find input format: "<<format<<std::endl;
 
78
            }
 
79
 
 
80
            int error = av_open_input_file(&p_format_context, filename.c_str(), iformat, 0, &formatParams);
 
81
            if (error != 0)
 
82
            {
 
83
                std::string error_str;
 
84
                switch (error)
 
85
                {
 
86
                    //case AVERROR_UNKNOWN: error_str = "AVERROR_UNKNOWN"; break;   // same value as AVERROR_INVALIDDATA
 
87
                    case AVERROR_IO: error_str = "AVERROR_IO"; break;
 
88
                    case AVERROR_NUMEXPECTED: error_str = "AVERROR_NUMEXPECTED"; break;
 
89
                    case AVERROR_INVALIDDATA: error_str = "AVERROR_INVALIDDATA"; break;
 
90
                    case AVERROR_NOMEM: error_str = "AVERROR_NOMEM"; break;
 
91
                    case AVERROR_NOFMT: error_str = "AVERROR_NOFMT"; break;
 
92
                    case AVERROR_NOTSUPP: error_str = "AVERROR_NOTSUPP"; break;
 
93
                    case AVERROR_NOENT: error_str = "AVERROR_NOENT"; break;
 
94
                    case AVERROR_PATCHWELCOME: error_str = "AVERROR_PATCHWELCOME"; break;
 
95
                    default: error_str = "Unknown error"; break;
 
96
                }
 
97
 
 
98
                throw std::runtime_error("av_open_input_file() failed : " + error_str);
 
99
            }
 
100
        }
 
101
        else
 
102
        {
 
103
            if (av_open_input_file(&p_format_context, filename.c_str(), 0, 0, 0) !=0 )
 
104
                throw std::runtime_error("av_open_input_file() failed");
 
105
        }
 
106
        
 
107
        m_format_context.reset(p_format_context);
 
108
 
 
109
        // Retrieve stream info
 
110
        if (av_find_stream_info(p_format_context) < 0)
 
111
            throw std::runtime_error("av_find_stream_info() failed");
 
112
 
 
113
        m_duration = double(m_format_context->duration) / AV_TIME_BASE;
 
114
        m_start = double(m_format_context->start_time) / AV_TIME_BASE;
 
115
 
 
116
        // TODO move this elsewhere
 
117
        m_clocks.reset(m_start);
 
118
 
 
119
        // Dump info to stderr
 
120
        dump_format(p_format_context, 0, filename.c_str(), false);
 
121
 
 
122
        // Find and open the first video and audio streams (note that audio stream is optional and only opened if possible)
 
123
 
 
124
        findVideoStream();
 
125
        findAudioStream();
 
126
 
 
127
        m_video_decoder.open(m_video_stream);
 
128
 
 
129
        try
 
130
        {
 
131
            m_audio_decoder.open(m_audio_stream);
 
132
        }
 
133
 
 
134
        catch (const std::runtime_error & error)
 
135
        {
 
136
            osg::notify(osg::WARN) << "FFmpegImageStream::open audio failed, audio stream will be disabled: " << error.what() << std::endl;
 
137
        }
 
138
    }
 
139
 
 
140
    catch (const std::runtime_error & error)
 
141
    {
 
142
        osg::notify(osg::WARN) << "FFmpegImageStream::open : " << error.what() << std::endl;
 
143
        return false;
 
144
    }
 
145
    
 
146
    return true;
 
147
}
 
148
 
 
149
 
 
150
 
 
151
void FFmpegDecoder::close(bool waitForThreadToExit)
 
152
{
 
153
    flushAudioQueue();
 
154
    flushVideoQueue();
 
155
    
 
156
    m_audio_decoder.close(waitForThreadToExit);
 
157
    m_video_decoder.close(waitForThreadToExit);
 
158
}
 
159
 
 
160
 
 
161
 
 
162
bool FFmpegDecoder::readNextPacket()
 
163
{
 
164
    switch (m_state)
 
165
    {
 
166
    case NORMAL:
 
167
        return readNextPacketNormal();
 
168
 
 
169
    case PAUSE:
 
170
        return false;
 
171
 
 
172
    case END_OF_STREAM:
 
173
        return readNextPacketEndOfStream();
 
174
 
 
175
    case REWINDING:
 
176
        return readNextPacketRewinding();
 
177
 
 
178
    case SEEKING:
 
179
        return readNextPacketSeeking();
 
180
 
 
181
    default:
 
182
        assert(false);
 
183
        return false;
 
184
    }
 
185
}
 
186
 
 
187
 
 
188
 
 
189
void FFmpegDecoder::rewind()
 
190
{
 
191
    m_pending_packet.clear();
 
192
 
 
193
    flushAudioQueue();
 
194
    flushVideoQueue();
 
195
    rewindButDontFlushQueues();
 
196
}
 
197
 
 
198
void FFmpegDecoder::seek(double time) 
 
199
{
 
200
    m_pending_packet.clear();
 
201
 
 
202
    flushAudioQueue();
 
203
    flushVideoQueue();
 
204
    seekButDontFlushQueues(time);
 
205
}
 
206
 
 
207
void FFmpegDecoder::pause() 
 
208
{
 
209
    m_pending_packet.clear();
 
210
 
 
211
    flushAudioQueue();
 
212
    flushVideoQueue();
 
213
    m_state = PAUSE;
 
214
}
 
215
 
 
216
void FFmpegDecoder::findAudioStream()
 
217
{
 
218
    for (unsigned int i = 0; i < m_format_context->nb_streams; ++i)
 
219
    {
 
220
        if (m_format_context->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
 
221
        {
 
222
            m_audio_stream = m_format_context->streams[i];
 
223
            m_audio_index = i;
 
224
            return;
 
225
        }
 
226
    }
 
227
 
 
228
    m_audio_stream = 0;
 
229
    m_audio_index = std::numeric_limits<unsigned int>::max();
 
230
}
 
231
 
 
232
 
 
233
 
 
234
void FFmpegDecoder::findVideoStream()
 
235
{
 
236
    for (unsigned int i = 0; i < m_format_context->nb_streams; ++i)
 
237
    {
 
238
        if (m_format_context->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
 
239
        {
 
240
            m_video_stream = m_format_context->streams[i];
 
241
            m_video_index = i;
 
242
            return;
 
243
        }
 
244
    }
 
245
 
 
246
    throw std::runtime_error("could not find a video stream");
 
247
}
 
248
 
 
249
 
 
250
 
 
251
inline void FFmpegDecoder::flushAudioQueue()
 
252
{
 
253
    FFmpegPacketClear pc;
 
254
    m_audio_queue.flush(pc);
 
255
}
 
256
 
 
257
 
 
258
 
 
259
inline void FFmpegDecoder::flushVideoQueue()
 
260
{
 
261
    FFmpegPacketClear pc;
 
262
    m_video_queue.flush(pc);
 
263
}
 
264
 
 
265
 
 
266
 
 
267
bool FFmpegDecoder::readNextPacketNormal()
 
268
{
 
269
    AVPacket packet;
 
270
 
 
271
    if (! m_pending_packet)
 
272
    {
 
273
        bool end_of_stream = false;
 
274
 
 
275
        // Read the next frame packet
 
276
        if (av_read_frame(m_format_context.get(), &packet) < 0)
 
277
        {
 
278
            if (url_ferror(m_format_context->pb) == 0)
 
279
                end_of_stream = true;
 
280
            else
 
281
                throw std::runtime_error("av_read_frame() failed");
 
282
        }
 
283
 
 
284
        if (end_of_stream)
 
285
        {
 
286
            // If we reach the end of the stream, change the decoder state
 
287
            if (loop())
 
288
            {
 
289
                m_clocks.reset(m_start);
 
290
                rewindButDontFlushQueues();
 
291
            }
 
292
            else
 
293
                m_state = END_OF_STREAM;
 
294
 
 
295
            return false;
 
296
        }
 
297
        else
 
298
        {
 
299
            // Make the packet data available beyond av_read_frame() logical scope.
 
300
            if (av_dup_packet(&packet) < 0)
 
301
                throw std::runtime_error("av_dup_packet() failed");
 
302
 
 
303
            m_pending_packet = FFmpegPacket(packet);            
 
304
        }
 
305
    }
 
306
 
 
307
    // Send data packet
 
308
    if (m_pending_packet.type == FFmpegPacket::PACKET_DATA)
 
309
    {
 
310
        if (m_pending_packet.packet.stream_index == m_audio_index)
 
311
        {
 
312
            if (m_audio_queue.timedPush(m_pending_packet, 10)) {
 
313
                m_pending_packet.release();
 
314
                return true;
 
315
            }
 
316
        }
 
317
        else if (m_pending_packet.packet.stream_index == m_video_index)
 
318
        {
 
319
            if (m_video_queue.timedPush(m_pending_packet, 10)) {
 
320
                m_pending_packet.release();
 
321
                return true;
 
322
            }
 
323
        }
 
324
        else
 
325
        {
 
326
            m_pending_packet.clear();
 
327
            return true;
 
328
        }
 
329
    }
 
330
 
 
331
    return false;
 
332
}
 
333
 
 
334
 
 
335
 
 
336
bool FFmpegDecoder::readNextPacketEndOfStream()
 
337
{
 
338
    const FFmpegPacket packet(FFmpegPacket::PACKET_END_OF_STREAM);
 
339
 
 
340
    m_audio_queue.timedPush(packet, 10);
 
341
    m_video_queue.timedPush(packet, 10);
 
342
 
 
343
    return false;
 
344
}
 
345
    
 
346
 
 
347
 
 
348
bool FFmpegDecoder::readNextPacketRewinding()
 
349
{
 
350
    const FFmpegPacket packet(FFmpegPacket::PACKET_FLUSH);
 
351
 
 
352
    if (m_audio_queue.timedPush(packet, 10) && m_video_queue.timedPush(packet, 10))
 
353
        m_state = NORMAL;
 
354
 
 
355
    return false;
 
356
}
 
357
 
 
358
 
 
359
 
 
360
void FFmpegDecoder::rewindButDontFlushQueues()
 
361
{
 
362
    const AVRational AvTimeBaseQ = { 1, AV_TIME_BASE }; // = AV_TIME_BASE_Q
 
363
 
 
364
    const int64_t pos = int64_t(m_clocks.getStartTime() * double(AV_TIME_BASE));
 
365
    const int64_t seek_target = av_rescale_q(pos, AvTimeBaseQ, m_video_stream->time_base);
 
366
 
 
367
    if (av_seek_frame(m_format_context.get(), m_video_index, seek_target, 0/*AVSEEK_FLAG_BYTE |*/ /*AVSEEK_FLAG_BACKWARD*/) < 0)
 
368
        throw std::runtime_error("av_seek_frame failed()");
 
369
 
 
370
    m_clocks.rewind();
 
371
    m_state = REWINDING;
 
372
}
 
373
 
 
374
bool FFmpegDecoder::readNextPacketSeeking() 
 
375
{
 
376
    const FFmpegPacket packet(FFmpegPacket::PACKET_FLUSH);
 
377
 
 
378
    if (m_audio_queue.timedPush(packet, 10) && m_video_queue.timedPush(packet, 10))
 
379
        m_state = NORMAL;
 
380
 
 
381
    return false;    
 
382
}
 
383
 
 
384
void FFmpegDecoder::seekButDontFlushQueues(double time)
 
385
{
 
386
    const AVRational AvTimeBaseQ = { 1, AV_TIME_BASE }; // = AV_TIME_BASE_Q
 
387
 
 
388
    const int64_t pos = int64_t(m_clocks.getStartTime()+time * double(AV_TIME_BASE));
 
389
    const int64_t seek_target = av_rescale_q(pos, AvTimeBaseQ, m_video_stream->time_base);
 
390
 
 
391
    m_clocks.setSeekTime(time);
 
392
 
 
393
    if (av_seek_frame(m_format_context.get(), m_video_index, seek_target, 0/*AVSEEK_FLAG_BYTE |*/ /*AVSEEK_FLAG_BACKWARD*/) < 0)
 
394
        throw std::runtime_error("av_seek_frame failed()");
 
395
 
 
396
    m_clocks.seek(time);
 
397
    m_state = SEEKING;    
 
398
}
 
399
 
 
400
 
 
401
 
 
402
} // namespace osgFFmpeg