Panda3D
|
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