~ubuntu-branches/debian/experimental/openscenegraph/experimental

« back to all changes in this revision

Viewing changes to .pc/osg_libav9.patch/OpenSceneGraph/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp

  • Committer: Package Import Robot
  • Author(s): Alberto Luaces Fernández
  • Date: 2014-08-01 20:41:55 UTC
  • mfrom: (1.4.4) (24.1.14 sid)
  • Revision ID: package-import@ubuntu.com-20140801204155-ykq00e43h6eg0ms3
Tags: 3.2.1-1
* Acknowledge NMU.
* New upstream version.
* Removal of old patches.
* Confirmation that (LP: #1339264) is already closed.
* Removed obsolete conflict rules.

Show diffs side-by-side

added added

removed removed

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