Blender V2.61 - r43446

AUD_FFMPEGReader.cpp

Go to the documentation of this file.
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 }