root/OpenSceneGraph/trunk/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp @ 10892

Revision 10892, 9.9 kB (checked in by robert, 5 years ago)

From Julen Garcia, "So here is the code with a proper audio sync (at least in my computer)"

RevLine 
[9816]1
2#include "FFmpegDecoder.hpp"
3
4#include <osg/Notify>
[10030]5#include <osgDB/FileNameUtils>
[9816]6
7#include <cassert>
8#include <limits>
9#include <stdexcept>
10#include <string.h>
[10030]11#include <iostream>
[9816]12
13
14namespace osgFFmpeg {
15
16
17
18FFmpegDecoder::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
33FFmpegDecoder::~FFmpegDecoder()
34{
[9869]35    close(true);
[9816]36}
37
38
39bool FFmpegDecoder::open(const std::string & filename)
40{
41    try
42    {
43        // Open video file
44        AVFormatContext * p_format_context = 0;
45
[9865]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;
[9816]51
[9865]52            AVFormatParameters formatParams;
53            memset(&formatParams, 0, sizeof(AVFormatParameters));
54            AVInputFormat *iformat;
55
56            formatParams.channel = 0;
57            formatParams.standard = 0;
[9969]58#if 1
[9990]59            formatParams.width = 320;
60            formatParams.height = 240;
[9969]61#else
62            formatParams.width = 640;
63            formatParams.height = 480;
64#endif           
[9865]65            formatParams.time_base.num = 1;
[9990]66            formatParams.time_base.den = 30;
[9865]67
[10030]68            std::string format = "video4linux2";
69            iformat = av_find_input_format(format.c_str());
[9865]70           
71            if (iformat)
72            {
[10030]73                osg::notify(osg::NOTICE)<<"Found input format: "<<format<<std::endl;
[9865]74            }
75            else
76            {
[10030]77                osg::notify(osg::NOTICE)<<"Failed to find input format: "<<format<<std::endl;
[9865]78            }
79
[10030]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            }
[9865]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       
[9826]107        m_format_context.reset(p_format_context);
[9816]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
[9869]151void FFmpegDecoder::close(bool waitForThreadToExit)
[9816]152{
153    flushAudioQueue();
154    flushVideoQueue();
[9869]155   
156    m_audio_decoder.close(waitForThreadToExit);
157    m_video_decoder.close(waitForThreadToExit);
[9816]158}
159
160
161
162bool FFmpegDecoder::readNextPacket()
163{
164    switch (m_state)
165    {
166    case NORMAL:
167        return readNextPacketNormal();
168
[10809]169    case PAUSE:
170        return false;
171
[9816]172    case END_OF_STREAM:
173        return readNextPacketEndOfStream();
174
175    case REWINDING:
176        return readNextPacketRewinding();
177
[10809]178    case SEEKING:
179        return readNextPacketSeeking();
180
[9816]181    default:
182        assert(false);
183        return false;
184    }
185}
186
187
188
189void FFmpegDecoder::rewind()
190{
191    m_pending_packet.clear();
192
193    flushAudioQueue();
194    flushVideoQueue();
195    rewindButDontFlushQueues();
196}
197
[10809]198void FFmpegDecoder::seek(double time)
199{
200    m_pending_packet.clear();
[9816]201
[10809]202    flushAudioQueue();
203    flushVideoQueue();
204    seekButDontFlushQueues(time);
205}
[9816]206
[10809]207void FFmpegDecoder::pause()
208{
209    m_pending_packet.clear();
[9816]210
[10809]211    flushAudioQueue();
212    flushVideoQueue();
213    m_state = PAUSE;
214}
215
[9816]216void 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
234void 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
251inline void FFmpegDecoder::flushAudioQueue()
252{
253    FFmpegPacketClear pc;
254    m_audio_queue.flush(pc);
255}
256
257
258
259inline void FFmpegDecoder::flushVideoQueue()
260{
261    FFmpegPacketClear pc;
262    m_video_queue.flush(pc);
263}
264
265
266
267bool 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())
[10851]288            {
289                m_clocks.reset(m_start);
[9816]290                rewindButDontFlushQueues();
[10851]291            }
[9816]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
336bool 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
348bool 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
360void FFmpegDecoder::rewindButDontFlushQueues()
361{
362    const AVRational AvTimeBaseQ = { 1, AV_TIME_BASE }; // = AV_TIME_BASE_Q
363
[10422]364    const int64_t pos = int64_t(m_clocks.getStartTime() * double(AV_TIME_BASE));
[9816]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
[10892]370    m_clocks.rewind();
[9816]371    m_state = REWINDING;
372}
373
[10809]374bool FFmpegDecoder::readNextPacketSeeking()
375{
376    const FFmpegPacket packet(FFmpegPacket::PACKET_FLUSH);
[9816]377
[10809]378    if (m_audio_queue.timedPush(packet, 10) && m_video_queue.timedPush(packet, 10))
379        m_state = NORMAL;
[9816]380
[10809]381    return false;   
382}
383
384void 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
[10851]391    m_clocks.setSeekTime(time);
392
[10809]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
[10892]396    m_clocks.seek(time);
[10809]397    m_state = SEEKING;   
398}
399
400
401
[9816]402} // namespace osgFFmpeg
Note: See TracBrowser for help on using the browser.