ffMP4ContainerFile.cpp

00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: ffMP4ContainerFile.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 #include <string.h> 00045 00046 #include "ffMP4ContainerFile.hpp" 00047 #include "ContainerInfo.hpp" 00048 #include "VideoESInfo.hpp" 00049 #include "AudioESInfo.hpp" 00050 #include "DataChannel.hpp" 00051 #include "DataSink.hpp" 00052 #include "Adaptor.hpp" 00053 #include "AdaptorChain.hpp" 00054 #include "MP3Parser.hpp" 00055 00056 #include "../adaptors/MP4Decoder.hpp" 00057 00058 #include "../io/DevNull.hpp" 00059 #include "../io/MPGStreamIO.hpp" 00060 00061 #include "../net/Url.hpp" 00062 #include "../net/SDP.hpp" 00063 00064 /* This structure is there temporarily .... I know it looks ugly. 00065 will be removed when FFmpeg becomes consistent in providing 00066 all required parameters 00067 */ 00068 struct stInfo { 00069 CodecID codec_id; //eg. CODEC_ID_MPEG4==15, CODEC_ID_MPEG4AAC=0x15003 00070 float rate; //frame_rate for Video; sample_rate for audio 00071 long size; //size of Elementary Stream 00072 u32 packet_size; 00073 int totalSamples; //total samples in ES 00074 long avgBitRate; 00075 u32 bits_per_sample; //bits per sample of uncompressed wave frame (eg. 16) 00076 u32 channels; //audio only (eg. 2...stereo) 00077 u32 packetDuration; 00078 float duration; //duration of ES in ticks 00079 float test_duration; //used internally for calculation 00080 bool done; // -do- 00081 }; 00082 static stInfo strm[MAX_STREAMS]; 00083 00084 //Some default values need to be declared here; 00085 static int frame_width = 352; 00086 static int frame_height = 288; 00087 //static int frame_rate = 30; /*@ * FRAME_RATE_BASE;*/ 00088 //static int frame_rate_base = 1; 00089 static int audio_sample_rate = 44100; 00090 static int audio_channels = 2; 00091 00092 00093 /**********************************************************/ 00097 ContainerInfo *ffMP4ContainerFile::loadContainerInfo(const char *fileName, const Url* uri, const enum ParseType type) { 00098 int streamcnt = 0; 00099 const char* pUri=NULL; 00100 if(uri) 00101 pUri=uri->toString(); 00102 00103 ContainerInfo * result = new ContainerInfo(pUri,fileName, ContainerInfo::MP4); 00104 00105 enum ParseType parseType = type; 00106 if (strstr(fileName+strlen(fileName)-4,".m4v") || strstr(fileName+strlen(fileName)-4,".M4V") ) { 00107 //force run_through for single elem streams 00108 parseType = RUN_THROUGH; 00109 } 00110 00111 dprintf_full("ffMP4ContainerFile::loadContainerInfo %s START-MARK parseType %i\r\n",fileName,parseType); 00112 00113 switch(parseType) { 00114 case RUN_THROUGH: 00115 streamcnt = getStreamParameters_run_through(fileName); 00116 break; 00117 case ESTIMATE1: 00118 streamcnt = getStreamParameters_estimate1(fileName); 00119 break; 00120 case ESTIMATE2: 00121 streamcnt = getStreamParameters_estimate2(fileName); 00122 break; 00123 default: 00124 streamcnt = getStreamParameters_run_through(fileName); 00125 } 00126 00127 00128 if(streamcnt < 0) { 00129 dprintf_full("ffMP4ContainerFile::loadContainerInfo: Error in getting stream parameters\n"); 00130 delete result; 00131 return NULL; 00132 } 00133 00134 AVInputFormat *informat = NULL; 00135 AVFormatContext *ic=NULL; 00136 AVFormatParameters params, *ap = &params; 00137 00138 //AVOutputFormat *fmt; //this has been introduced to support multiple file formats. 00139 /* auto detect the output format from the name. default is mp4. */ 00140 /*fmt = guess_format(NULL, fileName, NULL); 00141 if (!fmt) { 00142 printf("Could not deduce output format from file extension: using mp4.\n"); 00143 fmt = guess_format("mp4", NULL, NULL); 00144 } 00145 if (!fmt) { 00146 fprintf(stderr, "Could not find suitable output format\n"); 00147 exit(1); 00148 }*/ 00149 00150 00151 00152 /* set some default parameters if required */ 00153 memset(ap, 0, sizeof(*ap)); 00154 ap->sample_rate = audio_sample_rate; 00155 ap->channels = audio_channels; 00156 // ap->frame_rate = frame_rate; 00157 ap->width = frame_width; 00158 ap->height = frame_height; 00159 00160 int ret; 00161 char *mp4File = new char[strlen(fileName) + 1]; 00162 strcpy(mp4File, fileName); 00163 00164 00165 //open the input file with the generic libavformat function(avformat.h) 00166 ret = av_open_input_file(&ic, fileName, informat, 0, ap); 00167 if(ret < 0) { 00168 //HACK FOR DVB-HTTP STREAM: assume&force mpeg 00169 informat = av_find_input_format("mpeg"); 00170 dprintf_full("informat is %p\n",informat); 00171 ret = av_open_input_file(&ic, fileName, informat, 0, ap); 00172 if(ret < 0) { 00173 //print_error(fileName, ret); 00174 dprintf_full("ffMP4ContainerFile::loadContainerInfo : Error in opening file!!\n"); 00175 delete result; 00176 delete[] mp4File; 00177 return NULL; 00178 } 00179 } 00180 dprintf_full("ffMP4ContainerFile::loadContainerInfo : av_open_input_file is ok\r\n"); 00181 00182 00183 //If not enough info to get the stream parameters, we decode the 00184 //first frames to get it. (used in cases when file has no headers eg. mpeg1) 00185 ret = av_find_stream_info(ic); 00186 if (ret < 0) { 00187 dprintf_full("ffMP4ContainerFile: %s - could not find codec parameters\n", fileName); 00188 exit(1); 00189 } 00190 00191 00192 // unsigned int timeScale = 0; 00193 // timeScale = ic->pts_den; 00194 00195 00196 /*FIXME DUMMY IOD passed 00197 iodhandle not set because ffmpeg-0.4.6 does not provide it 00198 set the iodhandle here when needed 00199 NOTE: IOD is not required by most of the players so it may not cause any problem 00200 However, the ISO/IEC Reference code player does expect the IOD 00201 */ 00202 u32 iodHandleSize = 30; //Arbit size 00203 u8 iod[] = "11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDD"; 00204 u8 *iodhandle = iod; 00205 result->setIODHandle(iodhandle, iodHandleSize); 00206 00207 00208 00209 streamcnt = 0; 00210 streamcnt = ic->nb_streams; 00211 00212 if (streamcnt == 0) { 00213 dprintf_err("ffMP4ContainerFile::loadFromffMP4ContainerFile couldn't find any ElemStreams in container!\n"); 00214 ::exit(1); 00215 } 00216 00217 unsigned int size = 0; 00218 for (int streamIndex = 0; streamIndex < streamcnt; streamIndex++) 00219 { 00220 ESInfo *es = ffMP4ContainerFile::loadESInfo(ic, result, streamIndex); 00221 if (!es) { 00222 delete es; 00223 delete result; 00224 av_close_input_file(ic); 00225 delete[] mp4File; 00226 return NULL; 00227 } 00228 00229 dprintf_full("ffMP4ContainerFile::loadFromffMP4ContainerFile creating ES %i\r\n", streamIndex); 00230 es->setInput(mp4File); 00231 result->addESInfo(es); 00232 size += es->getOrigMediaSize(); 00233 } 00234 00235 QualityInfo *qi = result->getQualityInfo(); 00236 qi->steps[0]->size = size; 00237 av_close_input_file(ic); 00238 delete[] mp4File; 00239 return result; 00240 }; 00241 00242 00243 /**********************************************************/ 00244 ESInfo *ffMP4ContainerFile::loadESInfo(AVFormatContext *ic, ContainerInfo *vob, int streamIndex) 00245 { 00246 //XXX currently some parameters for audio are set in MP4audioDecoder::initialize() 00247 //this is becaue ffmpeg fails to deliver the necessary information for audio. 00248 AVStream *st; 00249 st = ic->streams[streamIndex]; 00250 00251 unsigned int streamId, handlerType, width, height, mediaTimeScale, totalSamples, mediaSize; 00252 unsigned int objectType=0, streamType=0, bufferSize=0, avgbit = 0, maxbit = 0; 00253 u64 duration = 0; 00254 float aspect_ratio = -1; 00255 00256 streamId = st->id; 00257 width = st->codec->width; 00258 height = st->codec->height; 00259 streamType = st->codec->codec_type; 00260 00261 if(st->codec->sample_aspect_ratio.num == 0) 00262 aspect_ratio = (float)width / (float)height; 00263 else if (height != 0) 00264 aspect_ratio = av_q2d(st->codec->sample_aspect_ratio) * (float)width / (float)height; 00265 if (aspect_ratio <= 0) 00266 aspect_ratio = (float)width / (float)height; 00267 00268 handlerType = st->codec->codec_type; //video = 0; audio = 1; others = -1 00269 if(handlerType == 0) //FIXME set the #defines in global.hpp for ffmpeg and replace these lines 00270 handlerType = MP4VisualHandlerType; 00271 if(handlerType == 1) 00272 handlerType = MP4AudioHandlerType; 00273 00274 // mediaTimeScale = ic->pts_den; 00275 //some videos (divx?) come with 1000000, instead of 90000 00276 mediaTimeScale = 90000; //FIXME: quickhack for divx 00277 //convert time base of duration from secs to 90000 timebase 00278 duration = (int)ceil(strm[streamIndex].duration*mediaTimeScale); 00279 avgbit = strm[streamIndex].avgBitRate; 00280 maxbit = 0; 00281 mediaSize = strm[streamIndex].size; 00282 totalSamples = strm[streamIndex].totalSamples; 00283 if (strm[streamIndex].totalSamples < 0 || strm[streamIndex].totalSamples == 0x7FFFFFFF) { 00284 dprintf_err("FATAL: ffMP4ContainerFile::loadESInfo could not determine number of totalSamples (was %i)!\n",totalSamples); 00285 dprintf_err("so assuming arbitrary high values for live-streaming\n"); 00286 totalSamples = 999999; 00287 duration = totalSamples * (mediaTimeScale/25); //assume 25 fps 00288 mediaSize = duration/mediaTimeScale * avgbit; 00289 //::exit(1); 00290 00291 /* 00292 dprintf_err("so assuming VOPTimeIncrement of lame-friendly 2351!\n"); 00293 //FIXME: absolute hack alarm! 00294 // vopInc 2351 seems to be a "lame"-friendly value, this results in 39 packets, take 40, to be on the safe side 00295 totalSamples = 40 * (int)((float)(duration) / (float)(mediaTimeScale)); 00296 */ 00297 } 00298 00299 dprintf_full("ffMP4ContainerFile::loadESInfo Ticks/sec %i Duration: %6.2f secs (ticks %li, samples %u) \n", 00300 mediaTimeScale, 00301 (float) ((float)(duration) / (float)(mediaTimeScale)), 00302 (long)duration, totalSamples ); 00303 int dcsize = 0; 00304 u8 *dptr = NULL; 00305 dptr = getDecoderConfiguration(ic, dcsize, streamIndex); 00306 if(dptr == NULL) 00307 { 00308 dprintf_full("ffMP4ContainerFile : loadESInfo got NULL instead of DecoderConfiguration !! \n"); 00309 dprintf_full("ffMP4ContainerFile : unknown %s codec %i????\n",st->codec->codec_type==CODEC_TYPE_VIDEO?"VIDEO" 00310 :st->codec->codec_type==CODEC_TYPE_AUDIO?"AUDIO":"UNKNOWN_STREAM",st->codec->codec_id); 00311 exit(1); 00312 } 00313 u8 *encodedDecoderConfig = new u8[dcsize * 2 + 1]; 00314 SDP::encodeDecoderConfig(encodedDecoderConfig, dptr, dcsize); 00315 00316 //XXX some of these things are not set before passing 00317 if(handlerType == MP4VisualHandlerType) { 00318 dprintf_full("ffMP4ContainerFile::loadESInfo VideoESInfo CodecID %i, ticks: %u\n", 00319 st->codec->codec_id, (unsigned)(duration/totalSamples)); 00320 return new VideoESInfo(streamId, streamType, vob, duration/totalSamples, 00321 encodedDecoderConfig, 00322 objectType, bufferSize, 00323 avgbit, maxbit, mediaTimeScale, duration, 00324 mediaSize, width, height, 00325 true, true, strm[streamIndex].codec_id, st->quality, aspect_ratio); 00326 } 00327 else if(handlerType == MP4AudioHandlerType) { 00328 u32 channels = st->codec->channels; 00329 #ifdef BUILD_ARCH_ARM 00330 if (channels <2 ) { 00331 dprintf_err("ffMP4ContainerFile::loadESInfo iPAQ hack: simulating stereo audio!\n"); 00332 channels=2; //always set to stereo on ipaq... else --> mickey mouse 00333 } 00334 #endif 00335 dprintf_full("ffMP4ContainerFile::loadESInfo AudioESInfo CodecID %i, %i Hz Channels: %i, ticks: %u\n", 00336 st->codec->codec_id, st->codec->sample_rate, channels, (unsigned)(duration/totalSamples)); 00337 return new AudioESInfo(streamId, streamType, vob, duration/totalSamples, 00338 encodedDecoderConfig, 00339 objectType, bufferSize, 00340 avgbit, maxbit, mediaTimeScale, duration, mediaSize, 00341 st->codec->sample_rate, channels, true, 00342 st->codec->codec_id, st->quality, strm[streamIndex].bits_per_sample); 00343 } 00344 return NULL; 00345 } 00346 00347 00348 /**********************************************************/ 00349 int ffMP4ContainerFile::getStreamParameters_estimate1(const char *fileName) 00350 { 00351 AVInputFormat *informat = NULL; 00352 AVFormatContext *temp = NULL; 00353 AVFormatParameters params, *ap = &params; 00354 AVStream * st; 00355 structMPEGaudioHeader mp3header; 00356 MP3Parser mp3; 00357 int dcsize = 0; 00358 u8 *dptr = NULL; 00359 int ret, totalBitrate; 00360 00361 memset(ap, 0, sizeof(*ap)); 00362 ap->sample_rate = audio_sample_rate; 00363 ap->channels = audio_channels; 00364 // ap->frame_rate = frame_rate; 00365 // ap->frame_rate_base = frame_rate_base; 00366 ap->width = frame_width; 00367 ap->height = frame_height; 00368 00369 // if (!strstr(fileName,".")) //no suffix, assume mp3 00370 //informat = av_find_input_format("mp3"); 00371 00372 00373 00374 //open the input file with the generic libavformat function(avformat.h) 00375 ret = av_open_input_file(&temp, fileName, informat, 0, ap); 00376 if(ret < 0) { 00377 //HACK FOR DVB-HTTP STREAM: assume and force mpeg 00378 informat = av_find_input_format("mpeg"); 00379 dprintf_full("informat is %p\n",informat); 00380 00381 ret = av_open_input_file(&temp, fileName, informat, 0, ap); 00382 if(ret < 0) { 00383 dprintf_full("ffMP4ContainerFile::getStreamParameters_estimate1 Error %i in opening file!!\n",ret); 00384 return -1; 00385 } 00386 } 00387 00388 dprintf_full("ffMP4ContainerFile::getStreamParameters_estimate1 : av_open_input_file is ok\r\n"); 00389 00390 //If not enough info to get the stream parameters, we decode the 00391 //first frames to get it. (used in cases when file has no headers) 00392 ret = av_find_stream_info(temp); 00393 if (ret < 0) { 00394 dprintf_full("ffMP4ContainerFile %s: could not find codec parameters\n", fileName); 00395 exit(1); 00396 } 00397 00398 int noStreams = temp->nb_streams; 00399 dprintf_small("ffMP4ContainerFile::getStreamParameters_estimate1() streams %d \n", noStreams); 00400 int i=0, j; 00401 totalBitrate = temp->bit_rate; 00402 for(i = 0; i < noStreams; i++) { 00403 st = temp->streams[i]; 00404 strm[i].duration = st->duration / st->time_base.den; 00405 /* HACK (mt): replace duration by value of container 00406 * if stream duration is not plausible 00407 */ 00408 if (strm[i].duration < 1.0) { 00409 // strm[i].duration = temp->duration / 1000000.0; 00410 strm[i].duration = 99999999; 00411 dprintf_err("ffMP4ContainerFile::getStreamParameters_estimate1() " 00412 "stream %d contains suspicious duration %6.2f, corrected to %6.2f\n", 00413 i, st->duration/1000000.0, strm[i].duration); 00414 } 00415 00416 strm[i].codec_id = st->codec->codec_id; 00417 00418 if(st->codec->codec_type == CODEC_TYPE_AUDIO) { 00419 dptr = getDecoderConfiguration(temp, dcsize, i); 00420 if(dptr == NULL) { 00421 dprintf_full("ffMP4ContainerFile : getStreamParameters() got NULL instead of DecoderConfiguration !! \n"); 00422 dprintf_full("ffMP4ContainerFile : (the file is not an mp3, maybe raw PCM ?? ) \n"); 00423 //exit(1); 00424 } 00425 00426 strm[i].rate = (float)(st->codec->sample_rate); 00427 strm[i].channels = st->codec->channels; 00428 00429 switch (st->codec->codec_id) { 00430 case CODEC_ID_MP3: 00431 case CODEC_ID_AAC: 00432 case CODEC_ID_MPEG4AAC: 00433 if(dptr && dptr[0] == 0xFF && dptr[1]>>5 == 0x07) 00434 mp3header = mp3.parseMPEGaudioHeader(dptr, dcsize); 00435 else 00436 dprintf_err("ffMP4ContainerFile::getStreamParameters_estimate1: Valid mp3 header not found\n"); 00437 strm[i].avgBitRate = mp3header.bitrate*1000; 00438 strm[i].bits_per_sample = mp3header.bits_per_sample; 00439 strm[i].totalSamples = (int) ceil(strm[i].duration / 00440 ((mp3header.frame_duration / 90000.0) * 00441 (strm[i].packet_size/mp3header.frame_size_in_bytes))); 00442 break; 00443 case CODEC_ID_MP2: 00444 if(dptr && dptr[0] == 0xFF && dptr[1]>>5 == 0x07) 00445 mp3header = mp3.parseMPEGaudioHeader(dptr, dcsize); 00446 else 00447 dprintf_err("ffMP4ContainerFile::getStreamParameters_estimate1: Valid mp2 header not found\n"); 00448 strm[i].avgBitRate = mp3header.bitrate*1000; 00449 strm[i].bits_per_sample = mp3header.bits_per_sample; 00450 strm[i].totalSamples = (int) ceil(strm[i].duration / 00451 ((mp3header.frame_duration / 90000.0) * 00452 (strm[i].packet_size/mp3header.frame_size_in_bytes))); 00453 break; 00454 case CODEC_ID_PCM_S8: 00455 case CODEC_ID_PCM_U8: 00456 case CODEC_ID_PCM_S16LE: 00457 case CODEC_ID_PCM_S16BE: 00458 case CODEC_ID_PCM_U16LE: 00459 case CODEC_ID_PCM_U16BE: 00460 00461 if (st->codec->codec_id == CODEC_ID_PCM_S8 || st->codec->codec_id == CODEC_ID_PCM_U8) { 00462 strm[i].bits_per_sample = 8; 00463 dprintf_err("ffMP4ContainerFile::getStreamParameters_estimate1: PCM Audio with 8bits not yet supported, eg. in DSPaudioIO\n"); 00464 exit(1); 00465 } else 00466 strm[i].bits_per_sample = 16; 00467 //for pcm, get duration from AVFormatContext, not stream... 00468 strm[i].duration = temp->duration/1000000.0; 00469 strm[i].avgBitRate = (int)ceil(strm[i].rate) * strm[i].channels * strm[i].bits_per_sample; 00470 // strm[i].totalSamples = (int)ceil(strm[i].duration); // store 1 second of raw pcm in one frame... 00471 00472 //FIXME: ffmpeg reads 256 bytes for one PCM-raw frame with av_get_frame().... 00473 strm[i].totalSamples = strm[i].avgBitRate/8/256 * (int)ceil(strm[i].duration); 00474 break; 00475 default: 00476 dprintf_err("ffMP4ContainerFile: unknown audio stream codec ID %i!\n",st->codec->codec_id); 00477 exit(1); 00478 } 00479 } 00480 }//run thru all streams 00481 00482 for(i = 0; i < noStreams; i++) { 00483 st = temp->streams[i]; 00484 if(st->codec->codec_type == CODEC_TYPE_VIDEO) { 00485 if (st->r_frame_rate.den > 0) 00486 strm[i].rate = (float)(st->r_frame_rate.num/st->r_frame_rate.den); 00487 else //fails on .avi :( 00488 strm[i].rate = 25; 00489 00490 strm[i].totalSamples = (int)strm[i].duration * (int)strm[i].rate; 00491 strm[i].avgBitRate = totalBitrate; 00492 for (j = 0; j < noStreams; j++) { 00493 if(j != i) 00494 strm[i].avgBitRate -= strm[j].avgBitRate; 00495 } 00496 } 00497 strm[i].size = (int)(strm[i].avgBitRate*strm[i].duration/8.0); 00498 if (st->codec->codec_type == CODEC_TYPE_VIDEO) { 00499 dprintf_full("ffMP4ContainerFile::getStreamParameters_estimate1 VIDEO stream %i: codecID: %i fps %2.1f " 00500 "duration %6.2f size %li numFrms: %i avg BW is %ld bit/sec\n", 00501 i, strm[i].codec_id, strm[i].rate, strm[i].duration, strm[i].size,strm[i].totalSamples, 00502 strm[i].avgBitRate); 00503 } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) { 00504 dprintf_full("ffMP4ContainerFile::getStreamParameters_estimate1 AUDIO stream %i: codecID: %i " 00505 "rate %2.1f bits: %i " 00506 "channels: %i duration %6.2f size %li numFrms: %i avg BW is %ld bit/sec\n", 00507 i, strm[i].codec_id, strm[i].rate, strm[i].bits_per_sample, strm[i].channels, 00508 strm[i].duration, strm[i].size, 00509 strm[i].totalSamples, strm[i].avgBitRate); 00510 } else { 00511 dprintf_err("ffMP4ContainerFile::getStreamParameters_estimate1 stream %i is neither video nor audio (is: %i)!!!\n",i, st->codec->codec_type); 00512 exit(1); 00513 } 00514 } 00515 00516 av_close_input_file(temp); 00517 00518 return noStreams; 00519 } 00520 00521 00522 00523 /**********************************************************/ 00524 int ffMP4ContainerFile::getStreamParameters_estimate2(const char *fileName) 00525 { 00526 AVInputFormat *informat = NULL; 00527 AVFormatContext *temp; 00528 AVStream *st; 00529 AVFormatParameters params, *ap = &params; 00530 00531 structMPEGaudioHeader mp3header; MP3Parser mp3; 00532 int dcsize = 0; 00533 u8 *dptr = NULL; 00534 00535 memset(ap, 0, sizeof(*ap)); 00536 ap->sample_rate = audio_sample_rate; 00537 ap->channels = audio_channels; 00538 //ap->frame_rate = frame_rate; 00539 //ap->frame_rate_base = frame_rate_base; 00540 ap->width = frame_width; 00541 ap->height = frame_height; 00542 00543 int ret; 00544 00545 //open the input file with the generic libavformat function(avformat.h) 00546 ret = av_open_input_file(&temp, fileName, informat, 0, ap); 00547 if(ret < 0) 00548 { 00549 dprintf_full("ffMP4ContainerFile::getStreamParameters_estimate2 Error in opening file!!\n"); 00550 return -1; 00551 } 00552 00553 00554 dprintf_full("ffMP4ContainerFile::getStreamParameters : av_open_input_file is ok\r\n"); 00555 00556 //If not enough info to get the stream parameters, we decode the 00557 //first frames to get it. (used in cases when file has no headers) 00558 ret = av_find_stream_info(temp); 00559 if (ret < 0) { 00560 dprintf_full("ffMP4ContainerFile %s: could not find codec parameters\n", fileName); 00561 exit(1); 00562 } 00563 00564 AVPacket pkt1, *pkt = &pkt1; 00565 int stIndex=0, noStreams = temp->nb_streams, i=0, done = 0; 00566 u32 data = 0; 00567 int startOfHeader = 0; 00568 bool first = true; 00569 00570 for(i = 0; i < noStreams; i++) { 00571 st = temp->streams[i]; 00572 strm[i].size = 0; strm[i].totalSamples = 0; strm[i].avgBitRate = 0; 00573 strm[i].done = false; 00574 strm[i].test_duration = MAX_TEST_DURATION; 00575 //if(st->codec->codec_type == CODEC_TYPE_VIDEO) 00576 // strm[i].rate = st->r_frame_rate/st->r_frame_rate_base; /*@/FRAME_RATE_BASE;*/ 00577 00578 strm[i].duration = st->duration/1000000.0; //strm[i].totalSamples/strm[i].rate; //The divide by 1000000 is done to convert the 00579 //duration from TIME_BASE 1000000 to secs 00580 if(strm[i].duration < strm[i].test_duration) 00581 strm[i].test_duration = strm[i].duration; 00582 } 00583 //here we go ..... read packets(or frames) and perform calculations 00584 for(;;) { 00585 00586 ret = av_read_frame(temp, pkt); 00587 if(ret < 0) { 00588 dprintf_full("ffMP4ContainerFile : Error in retrieving packet or EOF reached\n"); 00589 break; 00590 } 00591 00592 if (!pkt->size) { 00593 dprintf_full("ffMP4ContainerFile : Seems the packet is empty!!\n"); 00594 } 00595 00596 stIndex = pkt->stream_index; 00597 00598 if(temp->streams[stIndex]->codec->codec_type == CODEC_TYPE_AUDIO && first) 00599 { 00600 data = 0; 00601 startOfHeader = 0; 00602 while((data>>21) != 0x000007FF && startOfHeader <= pkt->size) //this is the start code for the decConf info 00603 { 00604 data <<= 8; 00605 data += pkt->data[startOfHeader]; 00606 startOfHeader++; 00607 } 00608 if((data>>21) == 0x000007FF) 00609 { 00610 dcsize = 4; 00611 startOfHeader -= 4; 00612 dptr = pkt->data + startOfHeader; 00613 } 00614 mp3header = mp3.parseMPEGaudioHeader(dptr, dcsize); 00615 strm[stIndex].bits_per_sample = mp3header.bits_per_sample; 00616 strm[stIndex].rate = (90000/((float)mp3header.frame_duration*(float)(pkt->size/mp3header.frame_size_in_bytes))); 00617 if(strm[stIndex].rate <= 0.0) 00618 strm[stIndex].rate = 1.0; 00619 if(mp3header.frame_size_in_bytes/pkt->size < 0.9) 00620 strm[stIndex].packetDuration = mp3header.frame_duration*(pkt->size/mp3header.frame_size_in_bytes); 00621 else 00622 strm[stIndex].packetDuration = mp3header.frame_duration; 00623 00624 first = false; 00625 } 00626 if(strm[stIndex].totalSamples < (int)(strm[stIndex].rate*strm[stIndex].test_duration)) { 00627 strm[stIndex].size += pkt->size; 00628 strm[stIndex].totalSamples++; 00629 } 00630 else 00631 strm[stIndex].done = true; 00632 av_free_packet(pkt); 00633 done = 0; 00634 for(i = 0; i< noStreams; i++) { 00635 if(strm[i].done) 00636 done++; 00637 } 00638 if(done == noStreams) 00639 break; 00640 00641 } 00642 00643 for(i = 0; i < noStreams; i++) 00644 { 00645 strm[i].avgBitRate = (long int)((strm[i].size/strm[i].test_duration) * 8.0); 00646 strm[i].size = (int)((strm[i].avgBitRate*strm[i].duration)/8.0); 00647 strm[i].totalSamples = (int)((strm[i].totalSamples/strm[i].test_duration)*strm[i].duration); 00648 dprintf_full("ffMP4ContainerFile::getStreamParameters_estimate2 stream %i: duration %6.2f size %li numFrms: %i avg BW is %ld bit/sec\n",i,strm[i].duration,strm[i].size,strm[i].totalSamples, strm[i].avgBitRate); 00649 } 00650 00651 av_close_input_file(temp); 00652 00653 return noStreams; 00654 } 00655 00656 00657 /**********************************************************/ 00658 int ffMP4ContainerFile::getStreamParameters_run_through(const char *fileName) 00659 { 00660 AVInputFormat *informat = NULL; 00661 AVFormatContext *temp; 00662 AVFormatParameters params, *ap = &params; 00663 00664 memset(ap, 0, sizeof(*ap)); 00665 ap->sample_rate = audio_sample_rate; 00666 ap->channels = audio_channels; 00667 //ap->frame_rate = frame_rate; 00668 //ap->frame_rate_base = frame_rate_base; 00669 ap->width = frame_width; 00670 ap->height = frame_height; 00671 00672 int ret; 00673 00674 //open the input file with the generic libavformat function(avformat.h) 00675 ret = av_open_input_file(&temp, fileName, informat, 0, ap); 00676 if(ret < 0) 00677 { 00678 dprintf_full("ffMP4ContainerFile::getStreamParameters_run_through Error in opening file!!\n"); 00679 return -1; 00680 } 00681 00682 00683 dprintf_full("ffMP4ContainerFile::getStreamParameters_run_through : av_open_input_file is ok\r\n"); 00684 00685 //If not enough info to get the stream parameters, we decode the 00686 //first frames to get it. (used in cases when file has no headers) 00687 ret = av_find_stream_info(temp); 00688 if (ret < 0) { 00689 dprintf_full("ffMP4ContainerFile::getStreamParameters_run_through %s: could not find codec parameters\n", fileName); 00690 exit(1); 00691 } 00692 00693 AVPacket pkt1, *pkt = &pkt1; 00694 int stIndex=0, noStreams = temp->nb_streams; 00695 int i=0; 00696 00697 //initialize 00698 for(i = 0; i< noStreams; i++) { 00699 strm[i].size = 0; strm[i].totalSamples = 0; strm[i].avgBitRate = 0; 00700 00701 //FIXME : so far rate is correct for video only; arbit value set for audio 00702 //This part requires fixing when upgraded to newer version of ffmpeg. 00703 //For video: rate = frame rate audio: rate = sample rate. 00704 00705 /* 00706 if(temp->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) 00707 strm[i].rate = temp->streams[i]->r_frame_rate/temp->streams[i]->r_frame_rate_base; 00708 else if(temp->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) 00709 strm[i].rate = 50.0; 00710 */ 00711 } 00712 00713 //here we go ..... read packets(or frames) and perform calculations 00714 for(;;) { 00715 00716 ret = av_read_frame(temp, pkt); 00717 if(ret < 0) { 00718 dprintf_full("ffMP4ContainerFile : Error in retrieving packet or EOF reached\n"); 00719 break; 00720 } 00721 00722 if (!pkt->size) { 00723 dprintf_full("ffMP4ContainerFile : Seems the packet is empty!!\n"); 00724 } 00725 00726 stIndex = pkt->stream_index; 00727 strm[stIndex].size += pkt->size; 00728 strm[stIndex].totalSamples++; 00729 00730 av_free_packet(pkt); 00731 } 00732 00733 for(i = 0; i < noStreams; i++) 00734 { 00735 strm[i].duration = temp->streams[i]->duration/1000000; //strm[i].totalSamples/strm[i].rate; //The divide by 1000000 is done to convert the 00736 //duration from TIME_BASE 1000000 to secs 00737 /* Duration of raw mpeg files is not obtained from ffmpeg 00738 * .... so calculate it 00739 */ 00740 if(strstr(fileName, ".m4v") || strstr(fileName, ".M4V")) 00741 strm[i].duration = strm[i].totalSamples/strm[i].rate; 00742 00743 strm[i].avgBitRate = (long int)((strm[i].size/strm[i].duration) * 8.0); 00744 dprintf_full("ffMP4ContainerFile::getStreamParameters_run_through stream %i: duration %6.2f size %li numFrms: %i avg BW is %ld bit/sec\n",i,strm[i].duration,strm[i].size,strm[i].totalSamples, strm[i].avgBitRate); 00745 } 00746 00747 av_close_input_file(temp); 00748 00749 return noStreams; 00750 } 00751 00752 00753 /**********************************************************/ 00754 u8 *ffMP4ContainerFile::getDecoderConfiguration(AVFormatContext *ic, int& pktSize, int streamIndex) 00755 { 00756 AVPacket pkt; 00757 bool parseVideo = false; 00758 if(ic->streams[streamIndex]->codec->codec_type == CODEC_TYPE_VIDEO) { 00759 switch(ic->streams[streamIndex]->codec->codec_id) { 00760 case CODEC_ID_MPEG4 : 00761 case CODEC_ID_MSMPEG4V1 : 00762 case CODEC_ID_MSMPEG4V2 : 00763 case CODEC_ID_MSMPEG4V3 : 00764 pktSize = ic->streams[streamIndex]->codec->extradata_size; 00765 if(pktSize != 0 && (u8*)ic->streams[streamIndex]->codec->extradata != NULL) 00766 return (u8*)ic->streams[streamIndex]->codec->extradata; 00767 else { 00768 parseVideo = true; 00769 break; 00770 } 00771 break; 00772 case CODEC_ID_MPEG1VIDEO : 00773 case CODEC_ID_MPEG2VIDEO : 00774 pktSize = 20; 00775 return ((u8*)"dummyDecoderConfiguration"); //XXX Dummy header sent for MPEG1/2 00776 default : 00777 return NULL; 00778 } 00779 } 00780 00781 00782 for(;;) { //XXX Remove the infinite loop 00783 if (av_read_frame(ic, &pkt) < 0) { 00784 dprintf_full("ffMP4ContainerFile::getDecoderConfiguration - Error in retrieving packet or decConfig not found\n"); 00785 return NULL; 00786 } 00787 00788 if (!pkt.size) { 00789 dprintf_full("ffMP4ContainerFile : Seems the packet is empty!!\n"); 00790 } 00791 00792 /* NOT NEEDED AS INFO HAS BEEN FOUND ABOVE FOR MP4 VIDEO 00793 * BUT if you dont get it above than parse Video to get it 00794 */ 00795 if(parseVideo && ic->streams[pkt.stream_index]->codec->codec_type == CODEC_TYPE_VIDEO 00796 && ic->streams[streamIndex]->codec->codec_type == CODEC_TYPE_VIDEO) { 00797 pktSize = 0; 00798 int data = 0; 00799 while((data>>8) != 0x00000001 && pktSize <= pkt.size) { //this is the start code for the decConf info 00800 data <<= 8; 00801 data += pkt.data[pktSize]; 00802 pktSize++; 00803 } 00804 if((data>>8) == 0x00000001) { 00805 pktSize = 0; 00806 data = 0; 00807 while(data != 0x000001B6 && pktSize <= pkt.size) { //this is the start code for the VOP header 00808 //we need only the decoder configuration info 00809 data <<= 8; 00810 data += pkt.data[pktSize]; 00811 pktSize++; 00812 } 00813 pktSize--; //since last 32 bits are startcode for the VOP header 00814 return pkt.data; 00815 } 00816 } 00817 00818 //The code below id for decoder configuration for MP3 files ONLY 00819 if(ic->streams[pkt.stream_index]->codec->codec_type == CODEC_TYPE_AUDIO 00820 && ic->streams[streamIndex]->codec->codec_type == CODEC_TYPE_AUDIO) { 00821 pktSize = 0; 00822 u32 data = 0; 00823 int startOfHeader = 0; 00824 while((data>>21) != 0x000007FF && startOfHeader <= pkt.size) { //this is the start code for the decConf info 00825 data <<= 8; 00826 data += pkt.data[startOfHeader]; 00827 startOfHeader++; 00828 } 00829 if((data>>21) == 0x000007FF) { 00830 pktSize = 4; 00831 00832 startOfHeader -= 4; 00833 strm[streamIndex].packet_size = pkt.size; 00834 return (pkt.data + startOfHeader); 00835 } 00836 } 00837 } 00838 00839 return NULL; 00840 }