python api for ID property access by Joseph Eager, copied from blender 2.4x.
[blender.git] / intern / audaspace / ffmpeg / AUD_FFMPEGReader.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN LGPL LICENSE BLOCK *****
5  *
6  * Copyright 2009 Jörg Hermann Müller
7  *
8  * This file is part of AudaSpace.
9  *
10  * AudaSpace is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * AudaSpace is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * ***** END LGPL LICENSE BLOCK *****
24  */
25
26 // needed for INT64_C
27 #define __STDC_CONSTANT_MACROS
28
29 #include "AUD_FFMPEGReader.h"
30 #include "AUD_Buffer.h"
31
32 extern "C" {
33 #include <libavcodec/avcodec.h>
34 #include <libavformat/avformat.h>
35 }
36
37 // This function transforms a FFMPEG SampleFormat to our own sample format
38 static inline AUD_SampleFormat FFMPEG_TO_AUD(SampleFormat fmt)
39 {
40         switch(fmt)
41         {
42         case SAMPLE_FMT_U8:
43                 return AUD_FORMAT_U8;
44         case SAMPLE_FMT_S16:
45                 return AUD_FORMAT_S16;
46         case SAMPLE_FMT_S32:
47                 return AUD_FORMAT_S32;
48         case SAMPLE_FMT_FLT:
49                 return AUD_FORMAT_FLOAT32;
50         case SAMPLE_FMT_DBL:
51                 return AUD_FORMAT_FLOAT64;
52         default:
53                 return AUD_FORMAT_INVALID;
54         }
55 }
56
57 int AUD_FFMPEGReader::decode(AVPacket* packet, AUD_Buffer* buffer)
58 {
59         // save packet parameters
60         uint8_t *audio_pkg_data = packet->data;
61         int audio_pkg_size = packet->size;
62
63         int buf_size = buffer->getSize();
64         int buf_pos = 0;
65
66         int read_length, data_size;
67
68         // as long as there is still data in the package
69         while(audio_pkg_size > 0)
70         {
71                 // resize buffer if needed
72                 if(buf_size - buf_pos < AVCODEC_MAX_AUDIO_FRAME_SIZE)
73                 {
74                         buffer->resize(buf_size + AVCODEC_MAX_AUDIO_FRAME_SIZE, true);
75                         buf_size += AVCODEC_MAX_AUDIO_FRAME_SIZE;
76                 }
77
78                 // read samples from the packet
79                 data_size = buf_size - buf_pos;
80                 /*read_length = avcodec_decode_audio3(m_codecCtx,
81                         (int16_t*)(buffer->getBuffer()+buf_pos),
82                         &data_size,
83                         packet);*/
84                 read_length = avcodec_decode_audio2(m_codecCtx,
85                         (int16_t*)(buffer->getBuffer()+buf_pos),
86                         &data_size,
87                         audio_pkg_data,
88                         audio_pkg_size);
89
90                 buf_pos += data_size;
91
92                 // read error, next packet!
93                 if(read_length < 0)
94                         break;
95
96                 // move packet parameters
97                 audio_pkg_data += read_length;
98                 audio_pkg_size -= read_length;
99         }
100
101         return buf_pos;
102 }
103
104 AUD_FFMPEGReader::AUD_FFMPEGReader(const char* filename)
105 {
106         m_position = 0;
107         m_pkgbuf_left = 0;
108         m_byteiocontext = NULL;
109
110         // open file
111         if(av_open_input_file(&m_formatCtx, filename, NULL, 0, NULL)!=0)
112                 AUD_THROW(AUD_ERROR_FILE);
113
114         try
115         {
116                 if(av_find_stream_info(m_formatCtx)<0)
117                         AUD_THROW(AUD_ERROR_FFMPEG);
118
119                 // find audio stream and codec
120                 m_stream = -1;
121
122                 for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
123                         if((m_formatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
124                                 && (m_stream < 0))
125                         {
126                                 m_stream=i;
127                                 break;
128                         }
129                 if(m_stream == -1)
130                         AUD_THROW(AUD_ERROR_FFMPEG);
131
132                 m_codecCtx = m_formatCtx->streams[m_stream]->codec;
133
134                 // get a decoder and open it
135                 AVCodec *aCodec = avcodec_find_decoder(m_codecCtx->codec_id);
136                 if(!aCodec)
137                         AUD_THROW(AUD_ERROR_FFMPEG);
138
139                 if(avcodec_open(m_codecCtx, aCodec)<0)
140                         AUD_THROW(AUD_ERROR_FFMPEG);
141
142                 // XXX this prints file information to stdout:
143                 //dump_format(m_formatCtx, 0, filename, 0);
144
145                 m_specs.channels = (AUD_Channels) m_codecCtx->channels;
146                 m_specs.format = FFMPEG_TO_AUD(m_codecCtx->sample_fmt);
147                 m_specs.rate = (AUD_SampleRate) m_codecCtx->sample_rate;
148         }
149         catch(AUD_Exception)
150         {
151                 av_close_input_file(m_formatCtx);
152                 throw;
153         }
154
155         // last but not least if there hasn't been any error, create the buffers
156         m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
157         m_pkgbuf = new AUD_Buffer(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1);
158         AUD_NEW("buffer")
159 }
160
161 AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer)
162 {
163         m_position = 0;
164         m_pkgbuf_left = 0;
165         m_byteiocontext = (ByteIOContext*)av_mallocz(sizeof(ByteIOContext));
166         AUD_NEW("byteiocontext")
167         m_membuffer = buffer;
168
169         if(init_put_byte(m_byteiocontext, buffer.get()->getBuffer(), buffer.get()->getSize(), 0,
170                                          NULL, NULL, NULL, NULL) != 0)
171                 AUD_THROW(AUD_ERROR_FILE);
172
173         AVProbeData probe_data;
174         probe_data.filename = "";
175         probe_data.buf = buffer.get()->getBuffer();
176         probe_data.buf_size = buffer.get()->getSize();
177         AVInputFormat* fmt = av_probe_input_format(&probe_data, 1);
178
179         // open stream
180         if(av_open_input_stream(&m_formatCtx, m_byteiocontext, "", fmt, NULL)!=0)
181                 AUD_THROW(AUD_ERROR_FILE);
182
183         try
184         {
185                 if(av_find_stream_info(m_formatCtx)<0)
186                         AUD_THROW(AUD_ERROR_FFMPEG);
187
188                 // find audio stream and codec
189                 m_stream = -1;
190
191                 for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
192                         if((m_formatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
193                                 && (m_stream < 0))
194                         {
195                                 m_stream=i;
196                                 break;
197                         }
198                 if(m_stream == -1)
199                         AUD_THROW(AUD_ERROR_FFMPEG);
200
201                 m_codecCtx = m_formatCtx->streams[m_stream]->codec;
202
203                 // get a decoder and open it
204                 AVCodec *aCodec = avcodec_find_decoder(m_codecCtx->codec_id);
205                 if(!aCodec)
206                         AUD_THROW(AUD_ERROR_FFMPEG);
207
208                 if(avcodec_open(m_codecCtx, aCodec)<0)
209                         AUD_THROW(AUD_ERROR_FFMPEG);
210
211                 // XXX this prints stream information to stdout:
212                 //dump_format(m_formatCtx, 0, NULL, 0);
213
214                 m_specs.channels = (AUD_Channels) m_codecCtx->channels;
215                 m_specs.format = FFMPEG_TO_AUD(m_codecCtx->sample_fmt);
216                 m_specs.rate = (AUD_SampleRate) m_codecCtx->sample_rate;
217         }
218         catch(AUD_Exception)
219         {
220                 av_close_input_stream(m_formatCtx);
221                 av_free(m_byteiocontext); AUD_DELETE("byteiocontext")
222                 throw;
223         }
224
225         // last but not least if there hasn't been any error, create the buffers
226         m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
227         m_pkgbuf = new AUD_Buffer(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1);
228         AUD_NEW("buffer")
229 }
230
231 AUD_FFMPEGReader::~AUD_FFMPEGReader()
232 {
233         avcodec_close(m_codecCtx);
234
235         if(m_byteiocontext)
236         {
237                 av_close_input_stream(m_formatCtx);
238                 av_free(m_byteiocontext); AUD_DELETE("byteiocontext")
239         }
240         else
241                 av_close_input_file(m_formatCtx);
242
243         delete m_buffer; AUD_DELETE("buffer")
244         delete m_pkgbuf; AUD_DELETE("buffer")
245 }
246
247 bool AUD_FFMPEGReader::isSeekable()
248 {
249         return true;
250 }
251
252 void AUD_FFMPEGReader::seek(int position)
253 {
254         if(position >= 0)
255         {
256                 // a value < 0 tells us that seeking failed
257                 if(av_seek_frame(m_formatCtx,
258                                                  -1,
259                                                  (uint64_t)(((uint64_t)position *
260                                                                          (uint64_t)AV_TIME_BASE) /
261                                                                         (uint64_t)m_specs.rate),
262                                                  AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
263                 {
264                         avcodec_flush_buffers(m_codecCtx);
265                         m_position = position;
266
267                         AVPacket packet;
268                         bool search = true;
269
270                         while(search && av_read_frame(m_formatCtx, &packet) >= 0)
271                         {
272                                 // is it a frame from the audio stream?
273                                 if(packet.stream_index == m_stream)
274                                 {
275                                         // decode the package
276                                         m_pkgbuf_left = decode(&packet, m_pkgbuf);
277                                         search = false;
278
279                                         // check position
280                                         if(packet.pts != AV_NOPTS_VALUE)
281                                         {
282                                                 // calculate real position, and read to frame!
283                                                 m_position = packet.pts *
284                                                         av_q2d(m_formatCtx->streams[m_stream]->time_base) *
285                                                         m_specs.rate;
286
287                                                 if(m_position < position)
288                                                 {
289                                                         sample_t* buf;
290                                                         int length = position - m_position;
291                                                         read(length, buf);
292                                                 }
293                                         }
294                                 }
295                                 av_free_packet(&packet);
296                         }
297                 }
298                 else
299                 {
300                         // Seeking failed, do nothing.
301                 }
302         }
303 }
304
305 int AUD_FFMPEGReader::getLength()
306 {
307         // return approximated remaning size
308         return (int)((m_formatCtx->duration * m_codecCtx->sample_rate)
309                                  / AV_TIME_BASE)-m_position;
310 }
311
312 int AUD_FFMPEGReader::getPosition()
313 {
314         return m_position;
315 }
316
317 AUD_Specs AUD_FFMPEGReader::getSpecs()
318 {
319         return m_specs;
320 }
321
322 AUD_ReaderType AUD_FFMPEGReader::getType()
323 {
324         return AUD_TYPE_STREAM;
325 }
326
327 bool AUD_FFMPEGReader::notify(AUD_Message &message)
328 {
329         return false;
330 }
331
332 void AUD_FFMPEGReader::read(int & length, sample_t* & buffer)
333 {
334         // read packages and decode them
335         AVPacket packet;
336         int data_size = 0;
337         int pkgbuf_pos;
338         int left = length;
339         int sample_size = AUD_SAMPLE_SIZE(m_specs);
340
341         // resize output buffer if necessary
342         if(m_buffer->getSize() < length*sample_size)
343                 m_buffer->resize(length*sample_size);
344
345         buffer = m_buffer->getBuffer();
346         pkgbuf_pos = m_pkgbuf_left;
347         m_pkgbuf_left = 0;
348
349         // there may still be data in the buffer from the last call
350         if(pkgbuf_pos > 0)
351         {
352                 data_size = AUD_MIN(pkgbuf_pos, left * sample_size);
353                 memcpy(buffer, m_pkgbuf->getBuffer(), data_size);
354                 buffer += data_size;
355                 left -= data_size/sample_size;
356         }
357
358         // for each frame read as long as there isn't enough data already
359         while((left > 0) && (av_read_frame(m_formatCtx, &packet) >= 0))
360         {
361                 // is it a frame from the audio stream?
362                 if(packet.stream_index == m_stream)
363                 {
364                         // decode the package
365                         pkgbuf_pos = decode(&packet, m_pkgbuf);
366
367                         // copy to output buffer
368                         data_size = AUD_MIN(pkgbuf_pos, left * sample_size);
369                         memcpy(buffer, m_pkgbuf->getBuffer(), data_size);
370                         buffer += data_size;
371                         left -= data_size/sample_size;
372                 }
373                 av_free_packet(&packet);
374         }
375         // read more data than necessary?
376         if(pkgbuf_pos > data_size)
377         {
378                 m_pkgbuf_left = pkgbuf_pos-data_size;
379                 memmove(m_pkgbuf->getBuffer(), m_pkgbuf->getBuffer()+data_size,
380                                 pkgbuf_pos-data_size);
381         }
382
383         buffer = m_buffer->getBuffer();
384
385         if(left > 0)
386                 length -= left;
387         m_position += length;
388 }