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

Revision 9847, 7.1 kB (checked in by robert, 6 years ago)

Introduce FFmpegAudioStream implementation

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