MKContainerFile.cpp

00001 #ifndef WIN32 00002 00003 /*********************************************************************** 00004 * * 00005 * ViTooKi * 00006 * * 00007 * title: MKContainerFile.cpp * 00008 * * 00009 * * 00010 * * 00011 * ITEC institute of the University of Klagenfurt (Austria) * 00012 * http://www.itec.uni-klu.ac.at * 00013 * * 00014 * * 00015 * For more information visit the ViTooKi homepage: * 00016 * http://ViTooKi.sourceforge.net * 00017 * vitooki-user@lists.sourceforge.net * 00018 * vitooki-devel@lists.sourceforge.net * 00019 * * 00020 * This file is part of ViTooKi, a free video toolkit. * 00021 * ViTooKi is free software; you can redistribute it and/or * 00022 * modify it under the terms of the GNU General Public License * 00023 * as published by the Free Software Foundation; either version 2 * 00024 * of the License, or (at your option) any later version. * 00025 * * 00026 * This program is distributed in the hope that it will be useful, * 00027 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00029 * GNU General Public License for more details. * 00030 * * 00031 * You should have received a copy of the GNU General Public License * 00032 * along with this program; if not, write to the Free Software * 00033 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00034 * MA 02111-1307, USA. * 00035 * * 00036 ***********************************************************************/ 00037 00038 /*********************************************************************** 00039 * * 00040 * REVISION HISTORY: * 00041 * * 00042 * * 00043 * * 00044 ***********************************************************************/ 00045 00046 #include <string.h> 00047 #include <stdlib.h> 00048 #include <stdio.h> 00049 #include <errno.h> 00050 #include <string.h> 00051 #include <fcntl.h> 00052 00053 /* windows-specific */ 00054 #ifdef WIN32 00055 #include <io.h> 00056 #endif 00057 00058 #include "MatroskaParser.h" 00059 00060 #include "MKContainerFile.hpp" 00061 #include "ContainerInfo.hpp" 00062 #include "VideoESInfo.hpp" 00063 #include "AudioESInfo.hpp" 00064 #include "DataChannel.hpp" 00065 #include "DataSink.hpp" 00066 #include "Adaptor.hpp" 00067 #include "AdaptorChain.hpp" 00068 #include "MP3Parser.hpp" 00069 00070 #include "../adaptors/MP4Decoder.hpp" 00071 00072 #include "../io/DevNull.hpp" 00073 #include "../io/MPGStreamIO.hpp" 00074 00075 #include "../net/Url.hpp" 00076 #include "../net/SDP.hpp" 00077 00078 /* Matroska Codec definition*/ 00079 #define MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC "V_MS/VFW/FOURCC" 00080 #define MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED "V_UNCOMPRESSED" 00081 #define MATROSKA_CODEC_ID_VIDEO_MPEG4_SP "V_MPEG4/ISO/SP" 00082 #define MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP "V_MPEG4/ISO/ASP" 00083 #define MATROSKA_CODEC_ID_VIDEO_MPEG4_AP "V_MPEG4/ISO/AP" 00084 #define MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC "V_MPEG4/ISO/AVC" 00085 #define MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3 "V_MPEG4/MS/V3" 00086 #define MATROSKA_CODEC_ID_VIDEO_MPEG1 "V_MPEG1" 00087 #define MATROSKA_CODEC_ID_VIDEO_MPEG2 "V_MPEG2" 00088 #define MATROSKA_CODEC_ID_VIDEO_MJPEG "V_MJPEG" 00089 #define MATROSKA_CODEC_ID_VIDEO_THEORA "V_THEORA" 00090 /* TODO: Real/Quicktime */ 00091 00092 #define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" 00093 #define MATROSKA_CODEC_ID_AUDIO_MPEG1_L1 "A_MPEG/L1" 00094 #define MATROSKA_CODEC_ID_AUDIO_MPEG1_L2 "A_MPEG/L2" 00095 #define MATROSKA_CODEC_ID_AUDIO_MPEG1_L3 "A_MPEG/L3" 00096 #define MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE "A_PCM/INT/BIG" 00097 #define MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE "A_PCM/INT/LIT" 00098 #define MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT "A_PCM/FLOAT/IEEE" 00099 #define MATROSKA_CODEC_ID_AUDIO_AC3 "A_AC3" 00100 #define MATROSKA_CODEC_ID_AUDIO_DTS "A_DTS" 00101 #define MATROSKA_CODEC_ID_AUDIO_VORBIS "A_VORBIS" 00102 #define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM" 00103 #define MATROSKA_CODEC_ID_AUDIO_MPEG2 "A_AAC/MPEG2/" 00104 #define MATROSKA_CODEC_ID_AUDIO_MPEG4 "A_AAC/MPEG4/" 00105 /* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */ 00106 00107 /* first we need to create an I/O object that the parser will use to read the 00108 * source file 00109 */ 00110 struct StdIoStream { 00111 struct InputStream base; 00112 FILE *fp; 00113 int error; 00114 }; 00115 typedef struct StdIoStream StdIoStream; 00116 00117 #define CACHESIZE 65536 00118 00119 /* StdIoStream methods */ 00120 00121 /* read count bytes into buffer starting at file position pos 00122 * return the number of bytes read, -1 on error or 0 on EOF 00123 */ 00124 int StdIoRead(StdIoStream *st, ulonglong pos, void *buffer, int count) { 00125 size_t rd; 00126 if (fseek(st->fp, pos, SEEK_SET)) { 00127 st->error = errno; 00128 return -1; 00129 } 00130 rd = fread(buffer, 1, count, st->fp); 00131 if (rd == 0) { 00132 if (feof(st->fp)) 00133 return 0; 00134 st->error = errno; 00135 return -1; 00136 } 00137 return rd; 00138 } 00139 00140 /* scan for a signature sig(big-endian) starting at file position pos 00141 * return position of the first byte of signature or -1 if error/not found 00142 */ 00143 longlong StdIoScan(StdIoStream *st, ulonglong start, unsigned signature) { 00144 int c; 00145 unsigned cmp = 0; 00146 FILE *fp = st->fp; 00147 00148 if (fseek(fp, start, SEEK_SET)) 00149 return -1; 00150 00151 while ((c = getc(fp)) != EOF) { 00152 cmp = ((cmp << 8) | c) & 0xffffffff; 00153 if (cmp == signature) 00154 return ftell(fp) - 4; 00155 } 00156 00157 return -1; 00158 } 00159 00160 /* return cache size, this is used to limit readahead */ 00161 unsigned StdIoGetCacheSize(StdIoStream *st) { 00162 return CACHESIZE; 00163 } 00164 00165 /* return last error message */ 00166 const char *StdIoGetLastError(StdIoStream *st) { 00167 return strerror(st->error); 00168 } 00169 00170 /* memory allocation, this is done via stdlib */ 00171 void *StdIoMalloc(StdIoStream *st, size_t size) { 00172 return malloc(size); 00173 } 00174 00175 void *StdIoRealloc(StdIoStream *st, void *mem, size_t size) { 00176 return realloc(mem,size); 00177 } 00178 00179 void StdIoFree(StdIoStream *st, void *mem) { 00180 free(mem); 00181 } 00182 00183 /* progress report handler for lengthy operations 00184 * returns 0 to abort operation, nonzero to continue 00185 */ 00186 int StdIoProgress(StdIoStream *st, ulonglong cur, ulonglong max) { 00187 return 1; 00188 } 00189 00190 00191 ContainerInfo *MKContainerFile::loadContainerInfo(const char *fileName, const Url* uri) { 00192 00193 dprintf_full("MKContainerFile: :loadContainerInfo: Init...\n"); 00194 00195 StdIoStream st; 00196 MatroskaFile *mf; 00197 char err_msg[256]; 00198 unsigned i; 00199 //int track; 00200 int streamcnt; 00201 //FILE *out = stdout; 00202 00203 00204 /* fill in I/O object */ 00205 memset(&st,0,sizeof(st)); 00206 st.base.read = reinterpret_cast<int(*)(InputStream*, long long unsigned int,void*,int)>(StdIoRead); 00207 st.base.scan = reinterpret_cast<long long(*)(InputStream*,long long unsigned int, unsigned int)>(StdIoScan); 00208 st.base.getcachesize = reinterpret_cast<unsigned int(*)(InputStream*)>(StdIoGetCacheSize); 00209 st.base.geterror = reinterpret_cast<const char*(*)(InputStream*)>(StdIoGetLastError); 00210 st.base.memalloc = reinterpret_cast<void*(*)(InputStream*,unsigned int)>(StdIoMalloc); 00211 st.base.memrealloc = reinterpret_cast<void*(*)(InputStream*,void*,unsigned int)>(StdIoRealloc); 00212 st.base.memfree = reinterpret_cast<void(*)(InputStream*,void*)>(StdIoFree); 00213 st.base.progress = reinterpret_cast<int(*)(InputStream*,long long unsigned int,long long unsigned int)>(StdIoProgress); 00214 00215 dprintf_full("MKContainerFile::loadContainerInfo: Opening Video...\n"); 00216 /* open source file */ 00217 st.fp = fopen(fileName,"rb"); 00218 if (st.fp == NULL) { 00219 dprintf_full("MKContainerFile::loadContainerInfo: Can't open '%s'\n", fileName); 00220 exit(1); 00221 } 00222 setvbuf(st.fp, NULL, _IOFBF, CACHESIZE); 00223 00224 /* initialize matroska parser */ 00225 mf = mkv_OpenEx(&st.base, /* pointer to I/O object */ 00226 0, /* starting position in the file */ 00227 0, /* flags, you can set MKVF_AVOID_SEEKS if this is a non-seekable stream */ 00228 err_msg, sizeof(err_msg)); /* error message is returned here */ 00229 if (mf == NULL) { 00230 fclose(st.fp); 00231 dprintf_full("MKContainerFile::loadContainerInfo: Can't parse Matroska file: %s\n", err_msg); 00232 exit(1); 00233 } 00234 00235 dprintf_full("MKContainerFile::loadContainerInfo: Init Matroska-parser done!\n"); 00236 00237 const char* pUri=NULL; 00238 if(uri){ 00239 pUri=uri->toString(); 00240 } 00241 00242 ContainerInfo * result = new ContainerInfo(pUri,fileName, ContainerInfo::MATROSKA); 00243 00244 /* count streams, min. 1 stream required, optimally a video stream*/ 00245 streamcnt = mkv_GetNumTracks(mf); 00246 if(streamcnt < 0) { 00247 dprintf_full("MKContainerFile::loadContainerInfo: couldn't find any ElemStreams in container!\n"); 00248 return NULL; 00249 } 00250 00251 // get file-information 00252 SegmentInfo *si = mkv_GetFileInfo(mf); 00253 00254 //duration of video 00255 double duration = double(si->Duration)*(si->TimecodeScale/ 1000000.0)/ 1000000000.0; 00256 printf("MKContainerFile: %f\n",duration); 00257 double hours = duration / 3600; 00258 00259 int minutes = (int(duration) % 3600)/60; 00260 00261 00262 00263 dprintf_full("MKContainerFile::loadContainerInfo: (f): Duration: %.3fs (%dh:%dm:%ds)\n",duration, int(hours), minutes, int(duration)%60); 00264 dprintf_full("MKContainerFile::loadContainerInfo: (f): Muxingapp: %s\n", si->MuxingApp); 00265 dprintf_full("MKContainerFile::loadContainerInfo: (f): Muxingapp: %s\n", si->WritingApp); 00266 00267 /* list available streams, for debugging only? */ 00268 dprintf_full("\n\tMKContainerFile::loadContainerInfo:### stream-info ###\n"); 00269 for (i = 0; i < mkv_GetNumTracks(mf); ++i) { 00270 TrackInfo *ti = mkv_GetTrackInfo(mf, i); 00271 switch(ti->Type) { 00272 //Video with track# and codec 00273 case TT_VIDEO: dprintf_full("\nMKContainerFile::loadContainerInfo: Track %u(#%u): %s, type: video\n", i,ti->Number, ti->CodecID); 00274 dprintf_full("MKContainerFile::loadContainerInfo: (v):id: %u, Pixel width: %u, height: %u\n",int(ti->UID), ti->Video.PixelWidth, ti->Video.PixelHeight); 00275 break; 00276 case TT_AUDIO: dprintf_full("\nMKContainerFile::loadContainerInfo: Track %u(#%u): %s, type: audio\n", i,ti->Number, ti->CodecID); 00277 dprintf_full("MKContainerFile::loadContainerInfo: (a):id: %u, SampleRate: %d\n",int(ti->UID),ti->Audio.OutputSamplingFreq); 00278 break; 00279 // subtitle 00280 case TT_SUB: dprintf_full("\nMKContainerFile::loadContainerInfo: Track %u(#%u): %s, type: subtitle\n", i, ti->Number,ti->CodecID); 00281 break; 00282 default: dprintf_full("\nMKContainerFile::loadContainerInfo: Track %u(#%u): %s, type: unknown\n", i, ti->Number,ti->CodecID);break; 00283 } 00284 } 00285 dprintf_full("\n\tMKContainerFile::loadContainerInfo:####################\n\n"); 00286 00287 char *mkvFile = new char[strlen(fileName) + 1]; 00288 strcpy(mkvFile, fileName); 00289 00290 unsigned int size = 0; 00291 for (int streamIndex = 0; streamIndex < streamcnt; streamIndex++) 00292 { 00293 ESInfo *es = MKContainerFile::loadESInfo(result, streamIndex, mf); 00294 /*if (!es) { 00295 delete es; 00296 delete result; 00297 delete[] mkvFile; 00298 return NULL; 00299 }*/ 00300 00301 dprintf_full("MKContainerFile::loadContainerInfo: creating ES %i\r\n", streamIndex); 00302 00303 //es->setInput(mkvFile); 00304 result->addESInfo(es); 00305 //size += es->getOrigMediaSize(); 00306 } 00307 00308 QualityInfo *qi = result->getQualityInfo(); 00309 qi->steps[0]->size = size; 00310 00311 delete[] mkvFile; 00312 00313 00314 00315 00316 return result; 00317 00318 } 00319 00320 bool saveToContainerFile(const char *fileName, ContainerInfo *ci){ 00321 00322 00323 return false; 00324 } 00325 00326 ESInfo *MKContainerFile::loadESInfo(ContainerInfo *vob, int streamIndex, MatroskaFile *mf) 00327 { 00328 unsigned int streamId, handlerType, width, height, mediaTimeScale, totalSamples, mediaSize; 00329 unsigned int objectType=0, streamType=0, bufferSize=0, avgbit = 0, maxbit = 0; 00330 double duration = 0; 00331 float aspect_ratio = -1; 00332 float fps = 0.0; 00333 float quality = 1.0; 00334 unsigned int sampling_freq = 0; 00335 CodecID codec_video; 00336 CodecID codec_audio; 00337 unsigned int bps = 0; 00338 00339 00340 TrackInfo *ti = mkv_GetTrackInfo(mf, streamIndex); 00341 dprintf_full("MKContainerFile::loadContainerInfo: track #%u, codec: %s, type: %u\n",ti->Number, ti->CodecID, ti->Type); 00342 00343 dprintf_full("MKContainerFile::loadContainerInfo: checking if video or audio\n"); 00344 00345 mediaTimeScale = 90000; //FIXME: quickhack for divx 00346 //convert time base of duration from secs to 90000 timebase 00347 // get file-information 00348 SegmentInfo *si = mkv_GetFileInfo(mf); 00349 00350 //duration of video 00351 duration = double(si->Duration)/ 1000000000.0; 00352 //dprintf_full("MKContainerFile: duration: %.f\n", duration); 00353 duration = (int)ceil(duration*mediaTimeScale); 00354 //dprintf_full("MKContainerFile: duration: %.f\n", duration); 00355 00356 00357 switch(ti->Type){ 00358 //Video with track# and codec 00359 case TT_VIDEO: { 00360 dprintf_full("\nMKContainerFile::loadContainerInfo: type: video\n"); 00361 dprintf_full("MKContainerFile::loadContainerInfo: (v):id: %u, Pixel width: %u, height: %u\n",int(ti->UID), ti->Video.PixelWidth, ti->Video.PixelHeight); 00362 00363 //streamId = ti->UID; //Unique ID 00364 streamId = ti->Number -1; 00365 streamType = 0;//type of stream, video=0 audio=1 00366 fps = 1000000000.0 / ti->DefaultDuration; 00367 00368 totalSamples = fps * double(si->Duration)/ 1000000000.0; 00369 00370 avgbit = 0; 00371 00372 maxbit = 0; 00373 00374 mediaSize = 0; 00375 00376 width = ti->Video.PixelWidth; 00377 height = ti->Video.PixelHeight; 00378 00379 /* dummy value for ffmpeg */ 00380 //codec_video = CODEC_ID_MPEG4; 00381 00382 /* mapping from Matroska codec_ids to FFMPEG codec_ids */ 00383 if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_VIDEO_MPEG4_SP) || 00384 !strcmp(ti->CodecID,MATROSKA_CODEC_ID_VIDEO_MPEG4_ASP) || 00385 !strcmp(ti->CodecID,MATROSKA_CODEC_ID_VIDEO_MPEG4_AP)) 00386 { 00387 codec_video = CODEC_ID_MPEG4; 00388 } 00389 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_VIDEO_MPEG4_AVC)) 00390 { 00391 codec_video = CODEC_ID_H264; 00392 } 00393 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_VIDEO_MSMPEG4V3)) 00394 { 00395 codec_video = CODEC_ID_MSMPEG4V3; 00396 } 00397 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_VIDEO_THEORA)) 00398 { 00399 codec_video = CODEC_ID_THEORA; 00400 } 00401 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_VIDEO_MPEG1) || 00402 !strcmp(ti->CodecID,MATROSKA_CODEC_ID_VIDEO_MPEG2)) 00403 { 00404 codec_video = CODEC_ID_MPEG2VIDEO; 00405 } 00406 else 00407 codec_video = CODEC_ID_MPEG4; 00408 00409 00410 00411 aspect_ratio = (float)width/ (float)height; 00412 00413 dprintf_full("\nMKContainerFile::loadContainerInfo: (v): %.3f fps", fps); 00414 dprintf_full("\nMKContainerFile::loadContainerInfo: (v): %d samples\n\n", totalSamples); 00415 00416 return new VideoESInfo(streamId, streamType, vob, duration/totalSamples, NULL, objectType, bufferSize, avgbit, maxbit, mediaTimeScale, duration, 00417 mediaSize, width, height, true, true, codec_video, quality, aspect_ratio); 00418 00419 00420 break; 00421 } 00422 // Audio 00423 case TT_AUDIO: { 00424 dprintf_full("\nMKContainerFile::loadContainerInfo: type: audio\n"); 00425 dprintf_full("MKContainerFile::loadContainerInfo: (a):id: %u, SampleRate: %.2f\n",int(ti->UID),ti->Audio.OutputSamplingFreq); 00426 00427 int channels = int(ti->Audio.Channels); 00428 dprintf_full("MKContainerFile::loadContainerInfo: (a): %d Channels\n", channels); 00429 #ifdef BUILD_ARCH_ARM 00430 if (channels < 2) { 00431 dprintf_full("MKContainerFile::loadContainerInfo: iPAQ hack: simulating stereo audio!\n"); 00432 channels=2; //always set to stereo on ipaq... else --> mickey mouse 00433 } 00434 #endif 00435 00436 //streamId = ti->UID; //Unique ID 00437 streamId = ti->Number -1; 00438 streamType = 1;//type of stream, video=0 audio=1 00439 00440 fps = 1000000000.0 / ti->DefaultDuration; 00441 00442 totalSamples = fps * double(si->Duration)/ 1000000000.0; 00443 00444 avgbit = 0; 00445 00446 maxbit = 0; 00447 00448 mediaSize = 0; 00449 00450 sampling_freq = ti->Audio.OutputSamplingFreq; 00451 00452 /* dummy value for ffmpeg */ 00453 codec_audio = CODEC_ID_MP3; 00454 00455 /* mapping from Matroska codec_ids to FFMPEG codec_ids */ 00456 if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_MPEG1_L1) || 00457 !strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_MPEG1_L2) || 00458 !strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_MPEG1_L3)) 00459 { 00460 codec_audio = CODEC_ID_MP3; 00461 } 00462 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE)) 00463 { 00464 codec_audio = CODEC_ID_PCM_U16BE; 00465 } 00466 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE)) 00467 { 00468 codec_audio = CODEC_ID_PCM_U16LE; 00469 } 00470 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_AC3)) 00471 { 00472 codec_audio = CODEC_ID_AC3; 00473 } 00474 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_DTS)) 00475 { 00476 codec_audio = CODEC_ID_DTS; 00477 } 00478 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_VORBIS)) 00479 { 00480 codec_audio = CODEC_ID_VORBIS; 00481 } 00482 else if (!strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_MPEG2) || 00483 !strcmp(ti->CodecID,MATROSKA_CODEC_ID_AUDIO_MPEG4)) 00484 { 00485 codec_audio = CODEC_ID_AAC; 00486 } 00487 else 00488 codec_audio = CODEC_ID_MP3; 00489 00490 00491 00492 // FIXME: read BitsPerSecond from mkv file 00493 //bps = ti->Audio.BitDepth; 00494 bps = 128000; 00495 00496 00497 dprintf_full("\nMKContainerFile::loadContainerInfo: (a): %u bps freq\n\n", bps); 00498 00499 return new AudioESInfo(streamId, streamType, vob, 2351, NULL, objectType, bufferSize, avgbit, maxbit, mediaTimeScale, duration, mediaSize, sampling_freq, channels, true, codec_audio, quality, bps); 00500 00501 00502 break; 00503 } 00504 00505 // subtitle 00506 case TT_SUB: { 00507 dprintf_full("\nMKContainerFile::loadContainerInfo: type: subtitle\n"); 00508 break; 00509 } 00510 00511 // unknown stream type 00512 default: dprintf_full("\nMKContainerFile::loadContainerInfo: type: unknown\n");break; 00513 } 00514 00515 00516 return NULL; 00517 } 00518 00519 00520 #endif