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

Revision 10961, 8.2 kB (checked in by robert, 4 years ago)

From Serge Lages, "Here is a patch to allow setting an audio volume with the AudioSink? interface, I've also modified the ffmpeg plugin code to implement the ImageStream?'s setVolume method with its AudioSink?."

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