![]() |
Mixxx
|
00001 /* -*- mode:C++; indent-tabs-mode:t; tab-width:8; c-basic-offset:4; -*- */ 00002 /*************************************************************************** 00003 soundsourceffmpeg.cpp - ffmpeg decoder 00004 ------------------- 00005 copyright : (C) 2007 by Cedric GESTES 00006 email : ctaf42@gmail.com 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "trackinfoobject.h" 00019 #include "soundsourceffmpeg.h" 00020 //#ifdef __WINDOWS__ 00021 //#include <io.h> 00022 //#include <fcntl.h> 00023 //#endif 00024 00025 // GED's notes - 2007-09-09 00026 // sudo aptitude install libavcodec-dev libavformat-dev liba52-dev libdts-dev 00027 // add '#include <QDebug> to fix qDebug' << "stuff" syntax. 00028 #include <QDebug> 00029 00030 static QMutex ffmpegmutex; 00031 static bool ffmpeginit = false; 00032 00033 /* TODO 00034 * - seek doesnt work correctly (seek is not precise for mp3) 00035 * - remove lock except for av_open/av_close 00036 * - do something like in soundbuffermp3 (keep a list of all frame for seeking) 00037 * - make ffmpeginit a singleton 00038 * DTS is not always updated, (maybe only after an av_seek_frame) 00039 * - remove qdebug (it slow down mixxx a lot) 00040 */ 00041 00042 static void FFmpegInit() 00043 { 00044 if (!ffmpeginit) { 00045 qDebug() << "Initialising avcodec/avformat"; 00046 av_register_all(); 00047 ffmpeginit = true; 00048 } 00049 } 00050 00051 //TODO: handle error 00052 SoundSourceFFmpeg::SoundSourceFFmpeg(QString qFilename) : SoundSource(qFilename) 00053 { 00054 AVFormatParameters param; 00055 int i; 00056 QByteArray fname; 00057 00058 packet.data = NULL; 00059 bufferOffset = 0; 00060 bufferSize = 0; 00061 memset(buffer, 0, AVCODEC_MAX_AUDIO_FRAME_SIZE); 00062 fname = qFilename.toLatin1(); 00063 FFmpegInit(); 00064 00065 qDebug() << "New SoundSourceFFmpeg :" << fname; 00066 00067 /* initialize param to something so av_open_input_file works for raw */ 00068 memset(¶m, 0, sizeof(AVFormatParameters)); 00069 param.channels = 2; 00070 param.sample_rate = 44100; 00071 00072 iformat = av_find_input_format(fname.constData()); 00073 // Open audio file 00074 if(av_open_input_file(&pFormatCtx, fname.constData(), iformat, 0, ¶m)!=0) { 00075 qDebug() << "av_open_input_file: cannot open" << fname; 00076 return; 00077 } 00078 00079 // Retrieve stream information 00080 if(av_find_stream_info(pFormatCtx)<0) { 00081 qDebug() << "av_find_stream_info: cannot open" << fname; 00082 return; 00083 } 00084 //debug only 00085 dump_format(pFormatCtx, 0, fname.constData(), false); 00086 00087 qDebug() << "ffmpeg: using the first audio stream available"; 00088 // Find the first video stream 00089 audioStream=-1; 00090 for(i=0; i<pFormatCtx->nb_streams; i++) 00091 if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO) { 00092 audioStream=i; 00093 break; 00094 } 00095 if(audioStream==-1) { 00096 qDebug() << "cannot find an audio stream: cannot open" << fname; 00097 return; 00098 } 00099 00100 // Get a pointer to the codec context for the video stream 00101 pCodecCtx=pFormatCtx->streams[audioStream]->codec; 00102 00103 // Find the decoder for the audio stream 00104 if(!(pCodec=avcodec_find_decoder(pCodecCtx->codec_id))) { 00105 qDebug() << "cannot find a decoder for" << fname; 00106 return; 00107 } 00108 00109 qDebug() << "ffmpeg: opening the audio codec"; 00110 //avcodec_open is not thread safe 00111 lock(); 00112 if(avcodec_open(pCodecCtx, pCodec)<0) { 00113 qDebug() << "avcodec: cannot open" << fname; 00114 return; 00115 } 00116 unlock(); 00117 00118 pFrame=avcodec_alloc_frame(); 00119 channels = pCodecCtx->channels; 00120 SRATE = pCodecCtx->sample_rate; 00121 00122 qDebug() << "Samplerate: " << SRATE << ", Channels: " << channels << "\n"; 00123 if(channels > 2){ 00124 qDebug() << "ffmpeg: No support for more than 2 channels!"; 00125 return; 00126 } 00127 filelength = (long int) ((double)pFormatCtx->duration * 2 / AV_TIME_BASE * SRATE); 00128 00129 qDebug() << "ffmpeg: filelength: " << filelength << "d -|- duration: " << pFormatCtx->duration << "ld -- starttime: " << pFormatCtx->streams[audioStream]->start_time << "ld -- " << AV_TIME_BASE << " " << pFormatCtx->streams[audioStream]->codec_info_duration << "ld"; 00130 } 00131 00132 SoundSourceFFmpeg::~SoundSourceFFmpeg() 00133 { 00134 av_free(pFrame); 00135 // Close the codec 00136 lock(); 00137 avcodec_close(pCodecCtx); 00138 unlock(); 00139 // Close the video file 00140 av_close_input_file(pFormatCtx); 00141 }; 00142 00143 void SoundSourceFFmpeg::lock() 00144 { 00145 // qDebug() << "ffmpeg: Before lock"; 00146 ffmpegmutex.lock(); 00147 //qDebug() << "ffmpeg: After lock"; 00148 } 00149 00150 void SoundSourceFFmpeg::unlock() 00151 { 00152 //qDebug() << "ffmpeg: Before unlock"; 00153 ffmpegmutex.unlock(); 00154 //qDebug() << "ffmpeg: After unlock"; 00155 } 00156 00157 long SoundSourceFFmpeg::ffmpeg2mixxx(long pos, const AVRational &time_base) { 00158 return (long)((double)pos / (double)time_base.den * (double)SRATE * (double)2.); 00159 } 00160 00161 long SoundSourceFFmpeg::mixxx2ffmpeg(long pos, const AVRational &time_base) { 00162 return (long)((double)pos / (double)SRATE / (double)2. * (double)time_base.den); 00163 } 00164 00165 00166 /* PLAYGROUND */ 00167 /* 00168 REAL: 00169 speedfreak 00170 Debug: file length 28263168 00171 nofreestyle 00172 Debug: file length 23904000 00173 00174 00175 speedfreak 00176 ratio 1,014428253 00177 Debug: ffmpeg: filelength: 28427212 -|- duration: 322304000 -- starttime: 0 -- 1000000 00178 Debug: ffmpeg: Seek ERRORRRRRRRRr ret(-1) filepos(28837367). 00179 Debug: file length 28427212 00180 //audiostream=-1 00181 Debug: ffmpeg: filelength: 28427212 -|- duration: 322304000 -- starttime: 0 -- 1000000 00182 time base is 1/90000 00183 Debug: ffmpeg: Seek ERRORRRRRRRRr ret(-1) filepos(320415184). 00184 -- 00185 Debug: ffmpeg: filelength: 10342873 -|- duration: 117266144 -- starttime: 0 -- 1000000 00186 Debug: ffmpeg: Seek ERRORRRRRRRRr ret(-1) filepos(10551289). 00187 Debug: file length 10342873 00188 seek to <filepos> 00189 00190 no free style 00191 Debug: ffmpeg: filelength: 53174016 -|- duration: 602880000 -- starttime: 0 -- 1000000 00192 time base is 1/90000 00193 Debug: ffmpeg: Seek ERRORRRRRRRRr ret(-1) filepos(24389275). 00194 //audistream = -1: 00195 Debug: ffmpeg: filelength: 53174016 -|- duration: 602880000 -- starttime: 0 -- 1000000 00196 time base is 1/90000 00197 Debug: ffmpeg: Seek ERRORRRRRRRRr ret(-1) filepos(270991939). 00198 */ 00199 /* 00200 int avcodec_decode_audio (AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, uint8_t *buf, int buf_size) 00201 int av_seek_frame (AVFormatContext *s, int stream_index, int64_t timestamp, int flags) 00202 Seek to the key frame at timestamp. 00203 Decode an audio frame. 00204 int av_seek_frame_binary (AVFormatContext *s, int stream_index, int64_t target_ts, int flags) 00205 Does a binary search using av_index_search_timestamp() and AVCodec.read_timestamp(). */ 00206 00207 // secs = filepos / SRATE / 2; 00208 // mins = secs / 60; 00209 // secs %= 60; 00210 // hours = mins / 60; 00211 // mins %= 60; 00212 /*for (fspos = 0; fspos < 602890000; fspos++){ 00213 ret = av_seek_frame(pFormatCtx, -1, fspos, 0); 00214 if (ret){ 00215 qDebug() << "ffmpeg: Seek ERRORRRRRRRRr ret(" << ret << ") filepos(" << fspos << "d)."; 00216 fspos--; 00217 ret = av_seek_frame(pFormatCtx, audioStream, fspos, 0); 00218 readInput(); 00219 qDebug() << "ffmpeg: seek2EROR " << bufferOffset << " " << bufferSize << " " << packet.pos << "ld"; 00220 return 0; 00221 } 00222 }*/ 00223 // std::cout<< "time base is " << time_base.num << "/" << time_base.den << "\n"; 00224 // fspos = (long)((double)filepos / SRATE / 2 * AV_TIME_BASE); 00225 00226 // fspos2 = (long)((double)filepos / SRATE / 2 * time_base.den); 00227 00228 long SoundSourceFFmpeg::seek(long filepos) 00229 { 00230 int ret = 0; 00231 int hours, mins, secs; 00232 long fspos, diff; 00233 AVRational time_base = pFormatCtx->streams[audioStream]->time_base; 00234 00235 lock(); 00236 00237 fspos = mixxx2ffmpeg(filepos, time_base); 00238 // qDebug() << "ffmpeg: seek0.5 " << packet.pos << "ld -- " << packet.duration << " -- " << pFormatCtx->streams[audioStream]->cur_dts << "ld"; 00239 qDebug() << "ffmpeg: seek (ffpos " << fspos << "d) (mixxxpos " << filepos << "d)"; 00240 00241 ret = av_seek_frame(pFormatCtx, audioStream, fspos, AVSEEK_FLAG_BACKWARD /*AVSEEK_FLAG_ANY*/); 00242 00243 if (ret){ 00244 qDebug() << "ffmpeg: Seek ERROR ret(" << ret << ") filepos(" << filepos << "d)."; 00245 unlock(); 00246 return 0; 00247 } 00248 00249 readInput(); 00250 diff = ffmpeg2mixxx(fspos - pFormatCtx->streams[audioStream]->cur_dts, time_base); 00251 qDebug() << "ffmpeg: seeked (dts " << pFormatCtx->streams[audioStream]->cur_dts << ") (diff " << diff << ") (diff " << fspos - pFormatCtx->streams[audioStream]->cur_dts << ")"; 00252 00253 bufferOffset = 0; //diff; 00254 if (bufferOffset > bufferSize) { 00255 qDebug() << "ffmpeg: ERROR BAD OFFFFFFSET, buffsize: " << bufferSize << " offset: " << bufferOffset; 00256 bufferOffset = 0; 00257 } 00258 unlock(); 00259 return filepos; 00260 } 00261 00262 /* 00263 * internal function to only read one paquet 00264 */ 00265 bool SoundSourceFFmpeg::readInput(){ 00266 char * dst; 00267 unsigned char * src; 00268 int ret = 0; 00269 int readsize = 0; 00270 int inputsize = 0; 00271 int tries = 0; 00272 //DEBUG 00273 bufferSize = 0; 00274 bufferOffset = 0; 00275 memset(buffer, 0, AVCODEC_MAX_AUDIO_FRAME_SIZE); 00276 while (av_read_packet(pFormatCtx, &packet)>0) { 00277 if (packet.stream_index==audioStream){ 00278 dst = (char *)buffer; 00279 src = packet.data; 00280 inputsize = 0; 00281 readsize = 0; 00282 //qDebug() << "ffmpeg: before avcodec_decode_audio packet.size(" << packet.size << ")"; 00283 tries = 0; 00284 do { 00285 ret = avcodec_decode_audio(pCodecCtx, (int16_t *)dst, &readsize, src, packet.size - inputsize); 00286 if (readsize == 0) 00287 { 00288 tries++; 00289 //qDebug() << "ffmpeg: skip frame, decoded readsize = 0"; 00290 break; 00291 } 00292 if (ret <= 0) 00293 { 00294 tries++; 00295 //qDebug() << "ffmpeg: skip frame, decoded ret = 0"; 00296 if (tries > 3) break; 00297 continue; 00298 } 00299 dst += readsize; 00300 bufferSize += readsize; 00301 src += ret; 00302 inputsize += ret; 00303 //qDebug() << "ffmpeg: loop buffersize(" << bufferSize << "), readsize(" << readsize << ") ret(" << ret << ") psize(" << packet.size << ")"; 00304 } while (inputsize < packet.size); 00305 //qDebug() << "ffmpeg: after avcodec_decode_audio outsize(" << bufferSize << ") - ret(" << ret << ")"; 00306 if (bufferSize != 0) 00307 return true; 00308 00309 } 00310 //debug 00311 av_free_packet(&packet); 00312 } 00313 return false; 00314 } 00315 00316 /* 00317 read <size> samples into <destination>, and return the number of 00318 samples actually read. 00319 */ 00320 unsigned SoundSourceFFmpeg::read(unsigned long size, const SAMPLE * destination) 00321 { 00322 00323 qDebug() << "This code has a bug! It needs fixing before you use it."; 00324 char * dest = (char *) destination; 00325 char * src = NULL; 00326 int index = 0; 00327 int outsize = 0; 00328 00329 // rryan 2/2009 This is wrong! read()'s semantics are that 00330 // destination has only 'size' free items. 00331 int needed = size*2; //*channels; 00332 00333 lock(); 00334 qDebug() << "ffmpeg: read, requested:(" << needed / 2 << ") dts:" << pFormatCtx->streams[audioStream]->cur_dts << "ld buffoffset:" << bufferOffset << " buffsize: " << bufferSize << "\n"; 00335 //copy previous buffer 00336 src = (char *)buffer; 00337 src += bufferOffset; 00338 while (needed > 0) { 00339 if (bufferOffset < bufferSize) { 00340 index = bufferSize - bufferOffset > needed ? needed : bufferSize - bufferOffset; 00341 //qDebug() << "ffmpeg: copy(" << index << ") needed(" << needed << ")"; 00342 memcpy((char *)dest, (char *)(src), index); 00343 src += index; 00344 dest += index; //(SAMPLE *)((char *)(dest) + index); 00345 needed -= index; 00346 bufferOffset += index; 00347 outsize += index; 00348 } 00349 if (needed > 0 && (bufferSize - bufferOffset <= 0)) { 00350 bufferOffset = 0; 00351 readInput(); 00352 src = (char *)buffer; 00353 src += bufferOffset; 00354 } 00355 } 00356 // convert into stereo if file is mono 00357 /*if (channels == 1) { 00358 for(int i=index;i>0;i--) { 00359 dest[i*2] = dest[i]; 00360 dest[(i*2)+1] = dest[i]; 00361 } 00362 }*/ 00363 // return the number of samples in buffer 00364 unlock(); 00365 return (outsize/2); 00366 } 00367 00368 /* 00369 Parse the the file to get metadata 00370 */ 00371 00372 int SoundSourceFFmpeg::ParseHeader( TrackInfoObject * Track ) 00373 { 00374 QString location = Track->getLocation(); 00375 AVFormatContext * FmtCtx; 00376 AVCodecContext * CodecCtx; 00377 int i, audioStream = -1; 00378 QByteArray fname; 00379 00380 fname = location.toAscii(); 00381 FFmpegInit(); 00382 qDebug() << "ffmpeg: pqrsing file:" << fname; 00383 if(av_open_input_file(&FmtCtx, fname.constData(), NULL, 0, NULL)!=0) 00384 { 00385 qDebug() << "av_open_input_file: cannot open" << fname; 00386 return ERR; 00387 } 00388 // Retrieve stream information 00389 if(av_find_stream_info(FmtCtx)<0) 00390 { 00391 qDebug() << "av_find_stream_info: cannot open" << fname; 00392 return ERR; 00393 } 00394 for(i=0; i<FmtCtx->nb_streams; i++) 00395 if(FmtCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO) 00396 { 00397 audioStream=i; 00398 break; 00399 } 00400 if(audioStream==-1) 00401 { 00402 qDebug() << "cannot find an audio stream: cannot open" << location; 00403 return ERR; 00404 } 00405 // Get a pointer to the codec context for the video stream 00406 CodecCtx=FmtCtx->streams[audioStream]->codec; 00407 Track->setType(location.section(".",-1).toLower()); 00408 Track->setDuration(FmtCtx->duration / AV_TIME_BASE); 00409 Track->setBitrate((int)(CodecCtx->bit_rate / 1000)); 00410 Track->setSampleRate(CodecCtx->sample_rate); 00411 Track->setChannels(CodecCtx->channels); 00412 av_close_input_file(FmtCtx); 00413 return OK; 00414 } 00415 00416 /* 00417 Return the length of the file in samples. 00418 */ 00419 inline long unsigned SoundSourceFFmpeg::length() 00420 { 00421 return filelength; 00422 }