root/OpenSceneGraph/trunk/src/osgPlugins/ffmpeg/FFmpegDecoderAudio.cpp @ 11177

Revision 11177, 9.0 kB (checked in by robert, 5 years ago)

Added extra ffmpeg version check

RevLine 
[9816]1#include "FFmpegDecoderAudio.hpp"
2
3#include <osg/Notify>
4
5#include <stdexcept>
6#include <string.h>
7
8//DEBUG
9//#include <iostream>
10
11
12
13namespace osgFFmpeg {
14
[11165]15static int decode_audio(AVCodecContext *avctx, int16_t *samples,
16                         int *frame_size_ptr,
17                         const uint8_t *buf, int buf_size)
18{
[11177]19#if LIBAVCODEC_VERSION_MAJOR >= 53 || (LIBAVCODEC_VERSION_MAJOR==52 && LIBAVCODEC_VERSION_MINOR>=32)
[9816]20
[11165]21    // following code segment copied from ffmpeg's avcodec_decode_audio2()
22    // implementation to avoid warnings about deprecated function usage.
23    AVPacket avpkt;
24    av_init_packet(&avpkt);
25    avpkt.data = const_cast<uint8_t *>(buf);
26    avpkt.size = buf_size;
[9816]27
[11165]28    return avcodec_decode_audio3(avctx, samples, frame_size_ptr, &avpkt);
29#else
30    // fallback for older versions of ffmpeg that don't have avcodec_decode_audio3.
31    return avcodec_decode_audio2(avctx, samples, frame_size_ptr, buf, buf_size);
32#endif
33}
34
35
[9816]36FFmpegDecoderAudio::FFmpegDecoderAudio(PacketQueue & packets, FFmpegClocks & clocks) :
37    m_packets(packets),
38    m_clocks(clocks),
39    m_stream(0),
40    m_context(0),
41    m_packet_data(0),
42    m_bytes_remaining(0),
43    m_audio_buffer((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2),
44    m_audio_buf_size(0),
45    m_audio_buf_index(0),
46    m_end_of_stream(false),
[10851]47    m_paused(true),
[9816]48    m_exit(false)
49{
50
51}
52
53
54
55FFmpegDecoderAudio::~FFmpegDecoderAudio()
56{
57    if (isRunning())
58    {
59        m_exit = true;
[9869]60#if 0       
61        while(isRunning()) { OpenThreads::YieldCurrentThread(); }
62#else       
[9816]63        join();
[9869]64#endif
[9816]65    }
66}
67
68
69
70void FFmpegDecoderAudio::open(AVStream * const stream)
71{
72    try
73    {
74        // Sound can be optional (i.e. no audio stream is present)
75        if (stream == 0)
76            return;
77
78        m_stream = stream;
79        m_context = stream->codec;
80
81        m_frequency = m_context->sample_rate;
82        m_nb_channels = m_context->channels;
[9827]83        m_sample_format = osg::AudioStream::SampleFormat(m_context->sample_fmt);
[9816]84
85        // Check stream sanity
86        if (m_context->codec_id == CODEC_ID_NONE)
87            throw std::runtime_error("invalid audio codec");;
88
89        // Find the decoder for the audio stream
90        AVCodec * const p_codec = avcodec_find_decoder(m_context->codec_id);
91
92        if (p_codec == 0)
93            throw std::runtime_error("avcodec_find_decoder() failed");
94
95        // Inform the codec that we can handle truncated bitstreams
96        //if (p_codec->capabilities & CODEC_CAP_TRUNCATED)
97        //    m_context->flags |= CODEC_FLAG_TRUNCATED;
98
99        // Open codec
100        if (avcodec_open(m_context, p_codec) < 0)
101            throw std::runtime_error("avcodec_open() failed");
102    }
103
104    catch (...)
105    {
106        m_context = 0;
107        throw;
108    }
109}
110
[10851]111void FFmpegDecoderAudio::pause(bool pause)
112{
[10925]113    if (pause != m_paused)
114    {
115        m_paused = pause;
116        if (m_audio_sink.valid())
117        {
118            if (m_paused) m_audio_sink->pause();
119            else m_audio_sink->play();
120        }
121    }
[10851]122}
[9816]123
[9869]124void FFmpegDecoderAudio::close(bool waitForThreadToExit)
125{
126    m_exit = true;
127   
128    if (isRunning() && waitForThreadToExit)
129    {
130        while(isRunning()) { OpenThreads::Thread::YieldCurrentThread(); }
131    }
132}
[9816]133
[10961]134void FFmpegDecoderAudio::setVolume(float volume)
135{
136    if (m_audio_sink.valid())
137    {
138        m_audio_sink->setVolume(volume);
139    }
140}
[9869]141
[10961]142float FFmpegDecoderAudio::getVolume() const
143{
144    if (m_audio_sink.valid())
145    {
146        return m_audio_sink->getVolume();
147    }
148    return 0.0f;
149}
150
[9816]151void FFmpegDecoderAudio::run()
152{
153    try
154    {
155        decodeLoop();
156    }
157
158    catch (const std::exception & error)
159    {
160        osg::notify(osg::WARN) << "FFmpegDecoderAudio::run : " << error.what() << std::endl;
161    }
162
163    catch (...)
164    {
165        osg::notify(osg::WARN) << "FFmpegDecoderAudio::run : unhandled exception" << std::endl;
166    }
167}
168
169
[9847]170void FFmpegDecoderAudio::setAudioSink(osg::ref_ptr<osg::AudioSink> audio_sink)
[9816]171{
172    // The FFmpegDecoderAudio object takes the responsability of destroying the audio_sink.
[9847]173    osg::notify(osg::NOTICE)<<"Assigning "<<audio_sink<<std::endl;
[9816]174    m_audio_sink = audio_sink;
175}
176
177
178
179void FFmpegDecoderAudio::fillBuffer(void * const buffer, size_t size)
180{
181    uint8_t * dst_buffer = reinterpret_cast<uint8_t*>(buffer);
182
183    while (size != 0)
184    {
185        if (m_audio_buf_index == m_audio_buf_size)
186        {
187            m_audio_buf_index = 0;
188
189            // Pre-fetch audio buffer is empty, refill it.
190            const size_t bytes_decoded = decodeFrame(&m_audio_buffer[0], m_audio_buffer.size());
191
192            // If nothing could be decoded (e.g. error or no packet available), output a bit of silence
193            if (bytes_decoded == 0)
194            {
195                m_audio_buf_size = std::min(Buffer::size_type(1024), m_audio_buffer.size());
196                memset(&m_audio_buffer[0], 0, m_audio_buf_size);
197            }
198            else
199            {
200                m_audio_buf_size = bytes_decoded;
201            }
202        }
203
204        const size_t fill_size = std::min(m_audio_buf_size - m_audio_buf_index, size);
205
206        memcpy(dst_buffer, &m_audio_buffer[m_audio_buf_index], fill_size);
207
208        size -= fill_size;
209        dst_buffer += fill_size;
210
211        m_audio_buf_index += fill_size;
212
213        adjustBufferEndTps(fill_size);
214    }
215}
216
217
218
219void FFmpegDecoderAudio::decodeLoop()
220{
221    const bool skip_audio = ! validContext() || ! m_audio_sink.valid();
222   
223    if (! skip_audio && ! m_audio_sink->playing())
224    {
225        m_clocks.audioSetDelay(m_audio_sink->getDelay());
[10925]226        m_audio_sink->play();
[9816]227    }
228    else
229    {
230        m_clocks.audioDisable();
231    }
232
233    while (! m_exit)
234    {
[10851]235
236        if(m_paused)
237        {
238            m_clocks.pause(true);
239            m_pause_timer.setStartTick();
240
241            while(m_paused)
242            {
243                microSleep(10000);
244            }
245
246            m_clocks.setPauseTime(m_pause_timer.time_s());
247            m_clocks.pause(false);
248        }
249
[9816]250        // If skipping audio, make sure the audio stream is still consumed.
251        if (skip_audio)
252        {
253            bool is_empty;
254            FFmpegPacket packet = m_packets.timedPop(is_empty, 10);
255
256            if (packet.valid())
257                packet.clear();
258        }
259        // Else, just idle in this thread.
260        // Note: If m_audio_sink has an audio callback, this thread will still be awaken
261        // from time to time to refill the audio buffer.
262        else
263        {
264            OpenThreads::Thread::microSleep(10000);
265        }
266    }
267}
268
269
270
271void FFmpegDecoderAudio::adjustBufferEndTps(const size_t buffer_size)
272{
273    int sample_size = nbChannels() * frequency();
274
275    switch (sampleFormat())
276    {
[9827]277    case osg::AudioStream::SAMPLE_FORMAT_U8:
[9816]278        sample_size *= 1;
279        break;
280
[9827]281    case osg::AudioStream::SAMPLE_FORMAT_S16:
[9816]282        sample_size *= 2;
283        break;
284
[9827]285    case osg::AudioStream::SAMPLE_FORMAT_S24:
[9816]286        sample_size *= 3;
287        break;
288
[9827]289    case osg::AudioStream::SAMPLE_FORMAT_S32:
[9816]290        sample_size *= 4;
291        break;
292
[9827]293    case osg::AudioStream::SAMPLE_FORMAT_F32:
[9816]294        sample_size *= 4;
295        break;
296
297    default:
298        throw std::runtime_error("unsupported audio sample format");
299    }
300
301    m_clocks.audioAdjustBufferEndPts(double(buffer_size) / double(sample_size));
302}
303
304
305
306size_t FFmpegDecoderAudio::decodeFrame(void * const buffer, const size_t size)
307{
308    for (;;)
309    {
310        // Decode current packet
311
312        while (m_bytes_remaining > 0)
313        {
314            int data_size = size;
315
[11165]316            const int bytes_decoded = decode_audio(m_context, reinterpret_cast<int16_t*>(buffer), &data_size, m_packet_data, m_bytes_remaining);
[9816]317
318            if (bytes_decoded < 0)
319            {
320                // if error, skip frame
321                m_bytes_remaining = 0;
322                break;
323            }
324
325            m_bytes_remaining -= bytes_decoded;
326            m_packet_data += bytes_decoded;
327
328            // If we have some data, return it and come back for more later.
329            if (data_size > 0)
330                return data_size;
331        }
332
333        // Get next packet
334
335        if (m_packet.valid())
336            m_packet.clear();
337
338        if (m_exit)
339            return 0;
340
341        bool is_empty = true;
342        m_packet = m_packets.tryPop(is_empty);
343
344        if (is_empty)
345            return 0;
346
347        if (m_packet.type == FFmpegPacket::PACKET_DATA)
348        {
[10414]349            if (m_packet.packet.pts != int64_t(AV_NOPTS_VALUE))
[9816]350            {
351                const double pts = av_q2d(m_stream->time_base) * m_packet.packet.pts;
352                m_clocks.audioSetBufferEndPts(pts);
353            }
354
355            m_bytes_remaining = m_packet.packet.size;
356            m_packet_data = m_packet.packet.data;
357        }
358        else if (m_packet.type == FFmpegPacket::PACKET_END_OF_STREAM)
359        {
360            m_end_of_stream = true;
361        }
362        else if (m_packet.type == FFmpegPacket::PACKET_FLUSH)
363        {
364            avcodec_flush_buffers(m_context);
365        }
366
367        // just output silence when we reached the end of stream
368        if (m_end_of_stream)
369        {
370            memset(buffer, 0, size);
371            return size;
372        }
373    }
374}
375
376
377
378} // namespace osgFFmpeg
Note: See TracBrowser for help on using the browser.