Panda3D

ffmpegAudioCursor.cxx

00001 // Filename: ffmpegAudioCursor.cxx
00002 // Created by: jyelon (01Aug2007)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #ifdef HAVE_FFMPEG
00016 
00017 #include "ffmpegAudioCursor.h"
00018 extern "C" {
00019   #include "libavcodec/avcodec.h"
00020   #include "libavformat/avformat.h"
00021 }
00022 
00023 TypeHandle FfmpegAudioCursor::_type_handle;
00024 
00025 ////////////////////////////////////////////////////////////////////
00026 //     Function: FfmpegAudioCursor::Constructor
00027 //       Access: Protected
00028 //  Description: xxx
00029 ////////////////////////////////////////////////////////////////////
00030 FfmpegAudioCursor::
00031 FfmpegAudioCursor(FfmpegAudio *src) :
00032   MovieAudioCursor(src),
00033   _filename(src->_filename),
00034   _packet(0),
00035   _packet_data(0),
00036   _format_ctx(0),
00037   _audio_ctx(0),
00038   _buffer(0),
00039   _buffer_alloc(0)
00040 {
00041   string url = "pandavfs:";
00042   url += _filename;
00043   if (av_open_input_file(&_format_ctx, url.c_str(), NULL, 0, NULL)!=0) {
00044     cleanup();
00045     return;
00046   }
00047 
00048   if (av_find_stream_info(_format_ctx)<0) {
00049     cleanup();
00050     return;
00051   }
00052 
00053   // Find the audio stream
00054   for(int i=0; i<_format_ctx->nb_streams; i++) {
00055     if(_format_ctx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO) {
00056       _audio_index = i;
00057       _audio_ctx = _format_ctx->streams[i]->codec;
00058       _audio_timebase = av_q2d(_format_ctx->streams[i]->time_base);
00059       _audio_rate = _audio_ctx->sample_rate;
00060       _audio_channels = _audio_ctx->channels;
00061     }
00062   }
00063 
00064   if (_audio_ctx == 0) {
00065     cleanup();
00066     return;
00067   }
00068 
00069   AVCodec *pAudioCodec=avcodec_find_decoder(_audio_ctx->codec_id);
00070   if(pAudioCodec == 0) {
00071     cleanup();
00072     return;
00073   }
00074   if(avcodec_open(_audio_ctx, pAudioCodec)<0) {
00075     cleanup();
00076     return;
00077   }
00078 
00079   _length = (_format_ctx->duration * 1.0) / AV_TIME_BASE;
00080   _can_seek = true;
00081   _can_seek_fast = true;
00082 
00083   _packet = new AVPacket;
00084   _buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE / 2;
00085   _buffer_alloc = new PN_int16[_buffer_size + 128];
00086   if ((_packet == 0)||(_buffer_alloc == 0)) {
00087     cleanup();
00088     return;
00089   }
00090   memset(_packet, 0, sizeof(AVPacket));
00091 
00092   // Align the buffer to a 16-byte boundary
00093   // The ffmpeg codec likes this, because it uses SSE/SSE2.
00094   _buffer = _buffer_alloc;
00095   while (((size_t)_buffer) & 15) {
00096     _buffer += 1;
00097   }
00098 
00099   fetch_packet();
00100   _initial_dts = _packet->dts;
00101   _last_seek = 0;
00102   _samples_read = 0;
00103   _buffer_head = 0;
00104   _buffer_tail = 0;
00105 }
00106 
00107 ////////////////////////////////////////////////////////////////////
00108 //     Function: FfmpegAudioCursor::Destructor
00109 //       Access: Protected, Virtual
00110 //  Description: xxx
00111 ////////////////////////////////////////////////////////////////////
00112 FfmpegAudioCursor::
00113 ~FfmpegAudioCursor() {
00114   cleanup();
00115 }
00116 
00117 ////////////////////////////////////////////////////////////////////
00118 //     Function: FfmpegAudioCursor::cleanup
00119 //       Access: Public
00120 //  Description: Reset to a standard inactive state.
00121 ////////////////////////////////////////////////////////////////////
00122 void FfmpegAudioCursor::
00123 cleanup() {
00124   if (_packet) {
00125     if (_packet->data) {
00126       av_free_packet(_packet);
00127     }
00128     delete _packet;
00129     _packet = 0;
00130   }
00131   if (_buffer_alloc) {
00132     delete[] _buffer_alloc;
00133     _buffer_alloc = 0;
00134     _buffer = 0;
00135   }
00136   if ((_audio_ctx)&&(_audio_ctx->codec)) {
00137     avcodec_close(_audio_ctx);
00138   }
00139   _audio_ctx = 0;
00140   if (_format_ctx) {
00141     av_close_input_file(_format_ctx);
00142     _format_ctx = 0;
00143   }
00144   _audio_ctx = 0;
00145   _audio_index = -1;
00146 }
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: FfmpegAudioCursor::fetch_packet
00150 //       Access: Protected
00151 //  Description: Fetches an audio packet and stores it in the
00152 //               packet buffer.  Also sets packet_size and packet_data.
00153 ////////////////////////////////////////////////////////////////////
00154 void FfmpegAudioCursor::
00155 fetch_packet() {
00156   if (_packet->data) {
00157     av_free_packet(_packet);
00158   }
00159   while (av_read_frame(_format_ctx, _packet) >= 0) {
00160     if (_packet->stream_index == _audio_index) {
00161       _packet_size = _packet->size;
00162       _packet_data = _packet->data;
00163       return;
00164     }
00165     av_free_packet(_packet);
00166   }
00167   _packet->data = 0;
00168   _packet_size = 0;
00169   _packet_data = 0;
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: FfmpegAudioCursor::reload_buffer
00174 //       Access: Protected
00175 //  Description: Reloads the audio buffer by decoding audio packets
00176 //               until one of those audio packets finally yields
00177 //               some samples.  If we encounter the end of the
00178 //               stream, we synthesize silence.
00179 ////////////////////////////////////////////////////////////////////
00180 bool FfmpegAudioCursor::
00181 reload_buffer() {
00182 
00183 
00184   while (_buffer_head == _buffer_tail) {
00185     // If we're out of packets, generate silence.
00186     if (_packet->data == 0) {
00187       _buffer_head = 0;
00188       _buffer_tail = _buffer_size;
00189       memset(_buffer, 0, _buffer_size * 2);
00190       return true;
00191     } else if (_packet_size > 0) {
00192       int bufsize = _buffer_size * 2;
00193 #if LIBAVCODEC_VERSION_INT < 3414272
00194 #if LIBAVCODEC_VERSION_INT < 3349504
00195       int len = avcodec_decode_audio(_audio_ctx, _buffer, &bufsize,
00196                                     _packet_data, _packet_size);
00197       movies_debug("avcodec_decode_audio returned " << len);
00198 #else
00199       int len = avcodec_decode_audio2(_audio_ctx, _buffer, &bufsize,
00200                                       _packet_data, _packet_size);
00201       movies_debug("avcodec_decode_audio2 returned " << len);
00202 #endif
00203 #else
00204       AVPacket pkt; 
00205       av_init_packet(&pkt); 
00206       pkt.data = _packet_data;
00207       pkt.size = _packet_size;
00208       int len = avcodec_decode_audio3(_audio_ctx, _buffer, &bufsize, &pkt);
00209       movies_debug("avcodec_decode_audio3 returned " << len);
00210       av_free_packet(&pkt); // Not sure about this
00211 #endif
00212       if (len < 0) {
00213         return false;
00214       } else if (len == 0){
00215         return true;
00216       }
00217       _packet_data += len;
00218       _packet_size -= len;
00219       if (bufsize > 0) {
00220         _buffer_head = 0;
00221         _buffer_tail = (bufsize/2);
00222         return true;
00223       }
00224     } else {
00225       fetch_packet();
00226     }
00227   }
00228   return true;
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: FfmpegAudioCursor::seek
00233 //       Access: Protected
00234 //  Description: Seeks to a target location.  Afterward, the
00235 //               packet_time is guaranteed to be less than or
00236 //               equal to the specified time.
00237 ////////////////////////////////////////////////////////////////////
00238 void FfmpegAudioCursor::
00239 seek(double t) {
00240   PN_int64 target_ts = (PN_int64)(t / _audio_timebase);
00241   if (target_ts < (PN_int64)(_initial_dts)) {
00242     // Attempts to seek before the first packet will fail.
00243     target_ts = _initial_dts;
00244   }
00245   if (av_seek_frame(_format_ctx, _audio_index, target_ts, AVSEEK_FLAG_BACKWARD) < 0) {
00246     movies_cat.error() << "Seek failure. Shutting down movie.\n";
00247     cleanup();
00248     return;
00249   }
00250   avcodec_close(_audio_ctx);
00251   AVCodec *pAudioCodec=avcodec_find_decoder(_audio_ctx->codec_id);
00252   if(pAudioCodec == 0) {
00253     cleanup();
00254     return;
00255   }
00256   if(avcodec_open(_audio_ctx, pAudioCodec)<0) {
00257     cleanup();
00258     return;
00259   }
00260   _buffer_head = 0;
00261   _buffer_tail = 0;
00262   fetch_packet();
00263   double ts = _packet->dts * _audio_timebase;
00264   if (t > ts) {
00265     int skip = (int)((t-ts) * _audio_rate);
00266     read_samples(skip, 0);
00267   }
00268   _last_seek = t;
00269   _samples_read = 0;
00270 }
00271 
00272 ////////////////////////////////////////////////////////////////////
00273 //     Function: FfmpegAudioCursor::read_samples
00274 //       Access: Public, Virtual
00275 //  Description: Read audio samples from the stream.  N is the
00276 //               number of samples you wish to read.  Your buffer
00277 //               must be equal in size to N * channels.
00278 //               Multiple-channel audio will be interleaved.
00279 ////////////////////////////////////////////////////////////////////
00280 void FfmpegAudioCursor::
00281 read_samples(int n, PN_int16 *data) {
00282 
00283   //movies_debug("here!!! FfmpegAudioCursor n="<<n);
00284 
00285   int desired = n * _audio_channels;
00286 
00287   while (desired > 0) {
00288 
00289     if (_buffer_head == _buffer_tail) {
00290       if(!reload_buffer()){
00291         break;
00292       }
00293       movies_debug("read_samples() Desired samples: " << desired << " N:" << n);
00294     }
00295     int available = _buffer_tail - _buffer_head;
00296     int ncopy = (desired > available) ? available : desired;
00297     if (ncopy) {
00298       if (data != 0) {
00299         memcpy(data, _buffer + _buffer_head, ncopy * 2);
00300         data += ncopy;
00301       }
00302       desired -= ncopy;
00303       _buffer_head += ncopy;
00304     }
00305 
00306   }
00307   _samples_read += n;
00308 }
00309 
00310 ////////////////////////////////////////////////////////////////////
00311 
00312 #endif // HAVE_FFMPEG
 All Classes Functions Variables Enumerations