Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * Copyright 2009-2011 Jörg Hermann Müller 00005 * 00006 * This file is part of AudaSpace. 00007 * 00008 * Audaspace is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * AudaSpace is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with Audaspace; if not, write to the Free Software Foundation, 00020 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00021 * 00022 * ***** END GPL LICENSE BLOCK ***** 00023 */ 00024 00030 // needed for INT64_C 00031 #ifndef __STDC_CONSTANT_MACROS 00032 #define __STDC_CONSTANT_MACROS 00033 #endif 00034 00035 #include "AUD_FFMPEGReader.h" 00036 00037 extern "C" { 00038 #include <libavcodec/avcodec.h> 00039 #include <libavformat/avformat.h> 00040 #include <libavformat/avio.h> 00041 #include "ffmpeg_compat.h" 00042 } 00043 00044 int AUD_FFMPEGReader::decode(AVPacket* packet, AUD_Buffer& buffer) 00045 { 00046 // save packet parameters 00047 uint8_t *audio_pkg_data = packet->data; 00048 int audio_pkg_size = packet->size; 00049 00050 int buf_size = buffer.getSize(); 00051 int buf_pos = 0; 00052 00053 int read_length, data_size; 00054 00055 AVPacket tmp_pkt; 00056 00057 av_init_packet(&tmp_pkt); 00058 00059 // as long as there is still data in the package 00060 while(audio_pkg_size > 0) 00061 { 00062 // resize buffer if needed 00063 if(buf_size - buf_pos < AVCODEC_MAX_AUDIO_FRAME_SIZE) 00064 { 00065 buffer.resize(buf_size + AVCODEC_MAX_AUDIO_FRAME_SIZE, true); 00066 buf_size += AVCODEC_MAX_AUDIO_FRAME_SIZE; 00067 } 00068 00069 // read samples from the packet 00070 data_size = buf_size - buf_pos; 00071 00072 tmp_pkt.data = audio_pkg_data; 00073 tmp_pkt.size = audio_pkg_size; 00074 00075 read_length = avcodec_decode_audio3( 00076 m_codecCtx, 00077 (int16_t*)(((data_t*)buffer.getBuffer()) + buf_pos), 00078 &data_size, &tmp_pkt); 00079 00080 // read error, next packet! 00081 if(read_length < 0) 00082 break; 00083 00084 buf_pos += data_size; 00085 00086 // move packet parameters 00087 audio_pkg_data += read_length; 00088 audio_pkg_size -= read_length; 00089 } 00090 00091 return buf_pos; 00092 } 00093 00094 static const char* streaminfo_error = "AUD_FFMPEGReader: Stream info couldn't " 00095 "be found."; 00096 static const char* noaudio_error = "AUD_FFMPEGReader: File doesn't include an " 00097 "audio stream."; 00098 static const char* nodecoder_error = "AUD_FFMPEGReader: No decoder found for " 00099 "the audio stream."; 00100 static const char* codecopen_error = "AUD_FFMPEGReader: Codec couldn't be " 00101 "opened."; 00102 static const char* format_error = "AUD_FFMPEGReader: Unsupported sample " 00103 "format."; 00104 00105 void AUD_FFMPEGReader::init() 00106 { 00107 m_position = 0; 00108 m_pkgbuf_left = 0; 00109 00110 if(av_find_stream_info(m_formatCtx)<0) 00111 AUD_THROW(AUD_ERROR_FFMPEG, streaminfo_error); 00112 00113 // find audio stream and codec 00114 m_stream = -1; 00115 00116 for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++) 00117 { 00118 if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) 00119 && (m_stream < 0)) 00120 { 00121 m_stream=i; 00122 break; 00123 } 00124 } 00125 00126 if(m_stream == -1) 00127 AUD_THROW(AUD_ERROR_FFMPEG, noaudio_error); 00128 00129 m_codecCtx = m_formatCtx->streams[m_stream]->codec; 00130 00131 // get a decoder and open it 00132 AVCodec *aCodec = avcodec_find_decoder(m_codecCtx->codec_id); 00133 if(!aCodec) 00134 AUD_THROW(AUD_ERROR_FFMPEG, nodecoder_error); 00135 00136 if(avcodec_open(m_codecCtx, aCodec)<0) 00137 AUD_THROW(AUD_ERROR_FFMPEG, codecopen_error); 00138 00139 // XXX this prints file information to stdout: 00140 //dump_format(m_formatCtx, 0, NULL, 0); 00141 00142 m_specs.channels = (AUD_Channels) m_codecCtx->channels; 00143 00144 switch(m_codecCtx->sample_fmt) 00145 { 00146 case SAMPLE_FMT_U8: 00147 m_convert = AUD_convert_u8_float; 00148 m_specs.format = AUD_FORMAT_U8; 00149 break; 00150 case SAMPLE_FMT_S16: 00151 m_convert = AUD_convert_s16_float; 00152 m_specs.format = AUD_FORMAT_S16; 00153 break; 00154 case SAMPLE_FMT_S32: 00155 m_convert = AUD_convert_s32_float; 00156 m_specs.format = AUD_FORMAT_S32; 00157 break; 00158 case SAMPLE_FMT_FLT: 00159 m_convert = AUD_convert_copy<float>; 00160 m_specs.format = AUD_FORMAT_FLOAT32; 00161 break; 00162 case SAMPLE_FMT_DBL: 00163 m_convert = AUD_convert_double_float; 00164 m_specs.format = AUD_FORMAT_FLOAT64; 00165 break; 00166 default: 00167 AUD_THROW(AUD_ERROR_FFMPEG, format_error); 00168 } 00169 00170 m_specs.rate = (AUD_SampleRate) m_codecCtx->sample_rate; 00171 } 00172 00173 static const char* fileopen_error = "AUD_FFMPEGReader: File couldn't be " 00174 "opened."; 00175 00176 AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) : 00177 m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), 00178 m_formatCtx(NULL), 00179 m_aviocontext(NULL), 00180 m_membuf(NULL) 00181 { 00182 // open file 00183 if(avformat_open_input(&m_formatCtx, filename.c_str(), NULL, NULL)!=0) 00184 AUD_THROW(AUD_ERROR_FILE, fileopen_error); 00185 00186 try 00187 { 00188 init(); 00189 } 00190 catch(AUD_Exception&) 00191 { 00192 av_close_input_file(m_formatCtx); 00193 throw; 00194 } 00195 } 00196 00197 static const char* streamopen_error = "AUD_FFMPEGReader: Stream couldn't be " 00198 "opened."; 00199 00200 AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer) : 00201 m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1), 00202 m_membuffer(buffer), 00203 m_membufferpos(0) 00204 { 00205 m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE)); 00206 00207 m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this, 00208 read_packet, NULL, seek_packet); 00209 00210 if(!m_aviocontext) 00211 { 00212 av_free(m_aviocontext); 00213 AUD_THROW(AUD_ERROR_FILE, fileopen_error); 00214 } 00215 00216 m_formatCtx = avformat_alloc_context(); 00217 m_formatCtx->pb = m_aviocontext; 00218 if(avformat_open_input(&m_formatCtx, "", NULL, NULL)!=0) 00219 { 00220 av_free(m_aviocontext); 00221 AUD_THROW(AUD_ERROR_FILE, streamopen_error); 00222 } 00223 00224 try 00225 { 00226 init(); 00227 } 00228 catch(AUD_Exception&) 00229 { 00230 av_close_input_stream(m_formatCtx); 00231 av_free(m_aviocontext); 00232 throw; 00233 } 00234 } 00235 00236 AUD_FFMPEGReader::~AUD_FFMPEGReader() 00237 { 00238 avcodec_close(m_codecCtx); 00239 00240 if(m_aviocontext) 00241 { 00242 av_close_input_stream(m_formatCtx); 00243 av_free(m_aviocontext); 00244 } 00245 else 00246 av_close_input_file(m_formatCtx); 00247 } 00248 00249 int AUD_FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size) 00250 { 00251 AUD_FFMPEGReader* reader = reinterpret_cast<AUD_FFMPEGReader*>(opaque); 00252 00253 int size = AUD_MIN(buf_size, reader->m_membuffer->getSize() - reader->m_membufferpos); 00254 00255 if(size < 0) 00256 return -1; 00257 00258 memcpy(buf, ((data_t*)reader->m_membuffer->getBuffer()) + reader->m_membufferpos, size); 00259 reader->m_membufferpos += size; 00260 00261 return size; 00262 } 00263 00264 int64_t AUD_FFMPEGReader::seek_packet(void* opaque, int64_t offset, int whence) 00265 { 00266 AUD_FFMPEGReader* reader = reinterpret_cast<AUD_FFMPEGReader*>(opaque); 00267 00268 switch(whence) 00269 { 00270 case SEEK_SET: 00271 reader->m_membufferpos = 0; 00272 break; 00273 case SEEK_END: 00274 reader->m_membufferpos = reader->m_membuffer->getSize(); 00275 break; 00276 case AVSEEK_SIZE: 00277 return reader->m_membuffer->getSize(); 00278 } 00279 00280 return (reader->m_membufferpos += offset); 00281 } 00282 00283 bool AUD_FFMPEGReader::isSeekable() const 00284 { 00285 return true; 00286 } 00287 00288 void AUD_FFMPEGReader::seek(int position) 00289 { 00290 if(position >= 0) 00291 { 00292 uint64_t st_time = m_formatCtx->start_time; 00293 uint64_t seek_pos = ((uint64_t)position) * ((uint64_t)AV_TIME_BASE) / ((uint64_t)m_specs.rate); 00294 00295 if (seek_pos < 0) { 00296 seek_pos = 0; 00297 } 00298 00299 if (st_time != AV_NOPTS_VALUE) { 00300 seek_pos += st_time; 00301 } 00302 00303 double pts_time_base = 00304 av_q2d(m_formatCtx->streams[m_stream]->time_base); 00305 uint64_t pts_st_time = 00306 ((st_time != AV_NOPTS_VALUE) ? st_time : 0) 00307 / pts_time_base / (uint64_t) AV_TIME_BASE; 00308 00309 // a value < 0 tells us that seeking failed 00310 if(av_seek_frame(m_formatCtx, -1, seek_pos, 00311 AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0) 00312 { 00313 avcodec_flush_buffers(m_codecCtx); 00314 m_position = position; 00315 00316 AVPacket packet; 00317 bool search = true; 00318 00319 while(search && av_read_frame(m_formatCtx, &packet) >= 0) 00320 { 00321 // is it a frame from the audio stream? 00322 if(packet.stream_index == m_stream) 00323 { 00324 // decode the package 00325 m_pkgbuf_left = decode(&packet, m_pkgbuf); 00326 search = false; 00327 00328 // check position 00329 if(packet.pts != AV_NOPTS_VALUE) 00330 { 00331 // calculate real position, and read to frame! 00332 m_position = (packet.pts - 00333 pts_st_time) * pts_time_base * m_specs.rate; 00334 00335 if(m_position < position) 00336 { 00337 // read until we're at the right position 00338 int length = AUD_DEFAULT_BUFFER_SIZE; 00339 AUD_Buffer buffer(length * AUD_SAMPLE_SIZE(m_specs)); 00340 bool eos; 00341 for(int len = position - m_position; 00342 length == AUD_DEFAULT_BUFFER_SIZE; 00343 len -= AUD_DEFAULT_BUFFER_SIZE) 00344 { 00345 if(len < AUD_DEFAULT_BUFFER_SIZE) 00346 length = len; 00347 read(length, eos, buffer.getBuffer()); 00348 } 00349 } 00350 } 00351 } 00352 av_free_packet(&packet); 00353 } 00354 } 00355 else 00356 { 00357 fprintf(stderr, "seeking failed!\n"); 00358 // Seeking failed, do nothing. 00359 } 00360 } 00361 } 00362 00363 int AUD_FFMPEGReader::getLength() const 00364 { 00365 // return approximated remaning size 00366 return (int)((m_formatCtx->duration * m_codecCtx->sample_rate) 00367 / AV_TIME_BASE)-m_position; 00368 } 00369 00370 int AUD_FFMPEGReader::getPosition() const 00371 { 00372 return m_position; 00373 } 00374 00375 AUD_Specs AUD_FFMPEGReader::getSpecs() const 00376 { 00377 return m_specs.specs; 00378 } 00379 00380 void AUD_FFMPEGReader::read(int& length, bool& eos, sample_t* buffer) 00381 { 00382 // read packages and decode them 00383 AVPacket packet; 00384 int data_size = 0; 00385 int pkgbuf_pos; 00386 int left = length; 00387 int sample_size = AUD_DEVICE_SAMPLE_SIZE(m_specs); 00388 00389 sample_t* buf = buffer; 00390 pkgbuf_pos = m_pkgbuf_left; 00391 m_pkgbuf_left = 0; 00392 00393 // there may still be data in the buffer from the last call 00394 if(pkgbuf_pos > 0) 00395 { 00396 data_size = AUD_MIN(pkgbuf_pos, left * sample_size); 00397 m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), 00398 data_size / AUD_FORMAT_SIZE(m_specs.format)); 00399 buf += data_size / AUD_FORMAT_SIZE(m_specs.format); 00400 left -= data_size/sample_size; 00401 } 00402 00403 // for each frame read as long as there isn't enough data already 00404 while((left > 0) && (av_read_frame(m_formatCtx, &packet) >= 0)) 00405 { 00406 // is it a frame from the audio stream? 00407 if(packet.stream_index == m_stream) 00408 { 00409 // decode the package 00410 pkgbuf_pos = decode(&packet, m_pkgbuf); 00411 00412 // copy to output buffer 00413 data_size = AUD_MIN(pkgbuf_pos, left * sample_size); 00414 m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), 00415 data_size / AUD_FORMAT_SIZE(m_specs.format)); 00416 buf += data_size / AUD_FORMAT_SIZE(m_specs.format); 00417 left -= data_size/sample_size; 00418 } 00419 av_free_packet(&packet); 00420 } 00421 // read more data than necessary? 00422 if(pkgbuf_pos > data_size) 00423 { 00424 m_pkgbuf_left = pkgbuf_pos-data_size; 00425 memmove(m_pkgbuf.getBuffer(), 00426 ((data_t*)m_pkgbuf.getBuffer())+data_size, 00427 pkgbuf_pos-data_size); 00428 } 00429 00430 if((eos = (left > 0))) 00431 length -= left; 00432 00433 m_position += length; 00434 }