MKIO.cpp

00001 #ifdef ENABLE_MKV 00002 00003 /*********************************************************************** 00004 * * 00005 * ViTooKi * 00006 * * 00007 * title: MKIO.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 "io/MKIO.hpp" 00047 #include "CompressedVideoFrame.hpp" 00048 #include "CompressedAudioFrame.hpp" 00049 #include "Frame.hpp" 00050 #include "VideoESInfo.hpp" 00051 #include "AudioESInfo.hpp" 00052 00053 00054 #ifdef _MSC_VER 00055 #include <windows.h> // for min/max 00056 #endif // _MSC_VER 00057 00058 #include <iostream> 00059 00060 00061 00062 using namespace LIBMATROSKA_NAMESPACE; 00063 using namespace std; 00064 00065 00066 unsigned int BIN_FILE_SIZE = 15000; 00067 unsigned int TXT_FILE_SIZE = 3000; 00068 const unsigned int BIN_FRAME_SIZE = 1500; 00069 const unsigned int TXT_FRAME_SIZE = 200; 00070 const u64 TIMECODE_SCALE = 1000000; 00071 00072 const bool bWriteDefaultValues = false; 00073 /* 00074 #define CACHESIZE 65536 00075 struct StdIoStream { 00076 struct InputStream base; 00077 FILE *fp; 00078 int error; 00079 }; 00080 00081 00082 00083 typedef struct StdIoStream StdIoStream; 00084 */ 00085 /* StdIoStream methods */ 00086 00087 /* read count bytes into buffer starting at file position pos 00088 * return the number of bytes read, -1 on error or 0 on EOF 00089 */ 00090 int StdIoRead(StdIoStream *st, ulonglong pos, void *buffer, int count) { 00091 size_t rd; 00092 if (fseek(st->fp, pos, SEEK_SET)) { 00093 st->error = errno; 00094 return -1; 00095 } 00096 rd = fread(buffer, 1, count, st->fp); 00097 if (rd == 0) { 00098 if (feof(st->fp)) 00099 return 0; 00100 st->error = errno; 00101 return -1; 00102 } 00103 return rd; 00104 } 00105 00106 /* scan for a signature sig(big-endian) starting at file position pos 00107 * return position of the first byte of signature or -1 if error/not found 00108 */ 00109 longlong StdIoScan(StdIoStream *st, ulonglong start, unsigned signature) { 00110 int c; 00111 unsigned cmp = 0; 00112 FILE *fp = st->fp; 00113 00114 if (fseek(fp, start, SEEK_SET)) 00115 return -1; 00116 00117 while ((c = getc(fp)) != EOF) { 00118 cmp = ((cmp << 8) | c) & 0xffffffff; 00119 if (cmp == signature) 00120 return ftell(fp) - 4; 00121 } 00122 00123 return -1; 00124 } 00125 00126 /* return cache size, this is used to limit readahead */ 00127 unsigned StdIoGetCacheSize(StdIoStream *st) { 00128 return CACHESIZE; 00129 } 00130 00131 /* return last error message */ 00132 const char *StdIoGetLastError(StdIoStream *st) { 00133 return strerror(st->error); 00134 } 00135 00136 /* memory allocation, this is done via stdlib */ 00137 void *StdIoMalloc(StdIoStream *st, size_t size) { 00138 return malloc(size); 00139 } 00140 00141 void *StdIoRealloc(StdIoStream *st, void *mem, size_t size) { 00142 return realloc(mem,size); 00143 } 00144 00145 void StdIoFree(StdIoStream *st, void *mem) { 00146 free(mem); 00147 } 00148 00149 /* progress report handler for lengthy operations 00150 * returns 0 to abort operation, nonzero to continue 00151 */ 00152 int StdIoProgress(StdIoStream *st, ulonglong cur, ulonglong max) { 00153 return 1; 00154 } 00155 00156 StdIoStream st; 00157 MatroskaFile *mf; 00158 00159 //KaxSegment FileSegment; 00160 00161 00162 /***************************************************************/ 00163 MKIO::MKIO(ESInfo *esi, const char *mkvFile, bool write) { 00164 00165 es = esi; 00166 state = CLOSED; 00167 input = new char[strlen(mkvFile) + 1]; 00168 strcpy(input, mkvFile); 00169 writeOnly = write; 00170 DTS = 0; 00171 // file_iformat = NULL; 00172 currentFrameNumber = 0; 00173 endFrameNumber = 0; 00174 priofp = NULL; 00175 // ic=NULL; 00176 // file_iformat=NULL; 00177 headerWritten = false; 00178 00179 char err_msg[256]; 00180 00181 // ap = &ap1; 00182 if (es->isVisualStream()) { //set up timely distribution priority table 00183 tableSize = (int)ceil(((VideoESInfo*)es)->getFPS()); 00184 int maxdepth=(int)((log((double)tableSize)/log(2.0)) + 1); 00185 00186 dprintf_full("MKIO: timelyDistTable: calculating maxdepth %i for patSize %i (=fps)\n", maxdepth,tableSize); 00187 int actpos=tableSize; //pseudo-global helper var 00188 for (int i=0; i<maxdepth; i++){ 00189 patSplit(prioTable,tableSize,i,&actpos); 00190 } 00191 00192 #ifdef VITOOKI_DEBUG 00193 dprintf_full("MKIO: timelyDistTable: "); 00194 printPat(prioTable,tableSize); 00195 #endif 00196 } 00197 00198 if(!write) { 00199 /* fill in I/O object */ 00200 memset(&st,0,sizeof(st)); 00201 st.base.read = reinterpret_cast<int(*)(InputStream*, long long unsigned int,void*,int)>(StdIoRead); 00202 st.base.scan = reinterpret_cast<long long(*)(InputStream*,long long unsigned int, unsigned int)>(StdIoScan); 00203 st.base.getcachesize = reinterpret_cast<unsigned int(*)(InputStream*)>(StdIoGetCacheSize); 00204 st.base.geterror = reinterpret_cast<const char*(*)(InputStream*)>(StdIoGetLastError); 00205 st.base.memalloc = reinterpret_cast<void*(*)(InputStream*,unsigned int)>(StdIoMalloc); 00206 st.base.memrealloc = reinterpret_cast<void*(*)(InputStream*,void*,unsigned int)>(StdIoRealloc); 00207 st.base.memfree = reinterpret_cast<void(*)(InputStream*,void*)>(StdIoFree); 00208 st.base.progress = reinterpret_cast<int(*)(InputStream*,long long unsigned int,long long unsigned int)>(StdIoProgress); 00209 00210 /* open source file */ 00211 st.fp = fopen(input,"rb"); 00212 if (st.fp == NULL) { 00213 fprintf(stderr,"Can't open '%s': %s\n",input,strerror(errno)); 00214 00215 } 00216 setvbuf(st.fp, NULL, _IOFBF, CACHESIZE); 00217 00218 /* initialize matroska parser */ 00219 mf = mkv_OpenEx(&st.base, /* pointer to I/O object */ 00220 0, /* starting position in the file */ 00221 0, /* flags, you can set MKVF_AVOID_SEEKS if this is a non-seekable stream */ 00222 err_msg, sizeof(err_msg)); /* error message is returned here */ 00223 00224 if (mf == NULL) { 00225 fclose(st.fp); 00226 fprintf(stderr,"Can't parse Matroska file: %s\n", err_msg); 00227 00228 } 00229 dprintf_full("Matroska parser initialized!\n"); 00230 } 00231 00232 00233 } 00234 00235 00236 /***************************************************************/ 00237 MKIO::~MKIO() { 00238 delete[] input; 00239 close(); 00240 // dfclose(fp); 00241 if(priofp) 00242 fclose(priofp); 00243 00244 if (out_file) 00245 delete out_file; 00246 } 00247 00248 00249 00250 00251 /***************************************************************/ 00252 Frame *MKIO::getFrame() { 00253 00254 if (state != OPEN || writeOnly) { // FIXME: change this when adding buffering 00255 return NULL; 00256 } 00257 00258 if( (this->currentFrameNumber > this->endFrameNumber) && (endFrameNumber != 0)) { 00259 close(true); 00260 state=STREAMEOF; 00261 return NULL; 00262 } 00263 00264 Frame *frm = NULL; 00265 Frame::FrameType type = Frame::NN_VOP; 00266 AU *au = new AU(); 00267 00268 //AVPacket pkt1, *pkt = &pkt1; //necessary? 00269 //int err; 00270 00271 00272 //unsigned i; 00273 int track; 00274 //FILE *out = stdout; 00275 00276 00277 00278 00279 // list available tracks 00280 /*for (i = 0; i < mkv_GetNumTracks(mf); ++i) { 00281 TrackInfo *ti = mkv_GetTrackInfo(mf, i); 00282 printf("Track %u: %s\n", i, ti->CodecID); 00283 }*/ 00284 00285 dprintf("\n--->READING FRAME<---\n"); 00286 00287 00288 00289 00290 00291 ulonglong StartTime, EndTime, FilePos; 00292 unsigned rt, FrameSize, FrameFlags; 00293 unsigned fb = 0; 00294 void *frame = NULL; 00295 CompressedStream *cs = NULL; 00296 00297 // find out, what the track number of the current track is 00298 //for (i = 0; i < mkv_GetNumTracks(mf); ++i) { 00299 // TrackInfo *ti = mkv_GetTrackInfo(mf, i); 00300 // dprintf("\n--->Track %s<---\n",ti->CodecID); 00301 // // let's look if the IDs match, then we get the track number 00302 // if(es->getStreamId()==ti->UID) { 00303 // track = ti->Number - 1; //stupid mkv starts with zero... 00304 // dprintf("\n--->Track %d<---\n",track); 00305 // } 00306 //} 00307 00308 track = es->getStreamId(); 00309 00310 if(es->isVisualStream()) { 00311 dprintf("\n--->Visual stream detected<---\n"); 00312 00313 au->prio = IO_NETWORK_HIGHEST_PRIORITY; 00314 au->duration = es->getVOPTimeIncrement(); 00315 au->cts = currentFrameNumber * es->getVOPTimeIncrement(); 00316 au->dts = currentFrameNumber * es->getVOPTimeIncrement(); 00317 au->sampleFlags = 0; 00318 00319 DTS += es->getVOPTimeIncrement(); 00320 00321 dprintf("MATROSKA: TRACK %d selected!",track); 00322 dprintf("\n--->Tracks parsed<---\n"); 00323 00324 /* mask other tracks because we don't need them */ 00325 mkv_SetTrackMask(mf, ~(1 << track)); 00326 00327 /* init zlib decompressor if needed */ 00328 if (mkv_GetTrackInfo(mf,track)->CompEnabled) { 00329 cs = cs_Create(mf, track, err_msg, sizeof(err_msg)); 00330 if (cs == NULL) { 00331 fprintf(stderr,"Can't create decompressor: %s\n",err_msg); 00332 return NULL; 00333 } 00334 } 00335 00336 if(mkv_ReadFrame(mf, 0, &rt, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0) { 00337 00338 if(cs) { 00339 dprintf("MATROSKA: compressed frame\n"); 00340 /* CODE TO HANDLE COMPRESSED FRAME */ 00341 } 00342 else { 00343 dprintf("MATROSKA: uncompressed frame\n"); 00344 size_t rd; 00345 00346 if (fseek(st.fp, FilePos, SEEK_SET)) { 00347 dprintf("fseek(): %s\n", strerror(errno)); 00348 //return NULL; 00349 } 00350 00351 dprintf("MATROSKA: Allocating memory\n"); 00352 /* allocate memory for frame/payload */ 00353 if (fb < FrameSize) { 00354 dprintf("MATROSKA: fb < FrameSize\n"); 00355 fb = FrameSize; 00356 frame = realloc(frame, fb); 00357 if (frame == NULL) { 00358 dprintf("Out of memory\n"); 00359 //return NULL; 00360 } 00361 } 00362 dprintf("MATROSKA: memory (%u) for frame %d allocated\n",FrameSize, currentFrameNumber); 00363 00364 dprintf("MATROSKA: reading frame\n"); 00365 rd = fread(frame,1,FrameSize,st.fp); 00366 dprintf("MATROSKA: read frame %d from file, rd = %d\n",currentFrameNumber, rd); 00367 00368 if (rd != FrameSize) { 00369 dprintf("MATROSKA: rd!= FrameSize\n"); 00370 if (rd == 0) { 00371 if (feof(st.fp)){ 00372 dprintf("Unexpected EOF while reading frame\n");} 00373 else 00374 dprintf("Error reading frame: %s\n",strerror(errno)); 00375 } else 00376 dprintf("Short read while reading frame\n"); 00377 //return NULL; 00378 } 00379 dprintf("MATROSKA: preparing to copy payload ...\n"); 00380 //fwrite(frame,1,FrameSize,out); 00381 // has to do deep-copy, otherwise collision with MP4lib mem handler 00382 00383 au->size = FrameSize; 00384 au->payload = new u8[au->size]; 00385 dprintf("MATROSKA: initializing payload-memory (deep-copy) ...\n"); 00386 memcpy(au->payload,frame,FrameSize); 00387 dprintf("MATROSKA: payload copied!\n"); 00388 } 00389 }//readframe 00390 else{ 00391 00392 state = STREAMEOF; 00393 return NULL; 00394 00395 } 00396 00397 00398 00399 00400 // dprintf("MATROSKA: Writing Frame %d, size=%u\n",currentFrameNumberFrameSize); 00401 00402 } 00403 else if(es->isAudioStream()) { 00404 dprintf("\n--->Audio stream detected<---\n"); 00405 au->prio = IO_NETWORK_HIGHEST_PRIORITY; 00406 //au->duration = es->getVOPTimeIncrement(); 00407 au->cts = DTS; 00408 au->dts = DTS; 00409 au->duration = 0; 00410 au->sampleFlags = 0; 00411 au->err = SA_OK; 00412 00413 DTS += es->getVOPTimeIncrement(); 00414 00415 00416 dprintf("MATROSKA: TRACK %d selected!",track); 00417 dprintf("\n--->Tracks parsed<---\n"); 00418 00419 /* mask other tracks because we don't need them */ 00420 mkv_SetTrackMask(mf, ~(1 << track)); 00421 00422 /* init zlib decompressor if needed */ 00423 if (mkv_GetTrackInfo(mf,track)->CompEnabled) { 00424 cs = cs_Create(mf, track, err_msg, sizeof(err_msg)); 00425 if (cs == NULL) { 00426 fprintf(stderr,"Can't create decompressor: %s\n",err_msg); 00427 return NULL; 00428 } 00429 } 00430 00431 if(mkv_ReadFrame(mf, 0, &rt, &StartTime, &EndTime, &FilePos, &FrameSize, &FrameFlags) == 0){ 00432 00433 if(cs) { 00434 dprintf("MATROSKA: compressed frame\n"); 00435 /* CODE TO HANDLE COMPRESSED FRAME */ 00436 } 00437 else { 00438 dprintf("MATROSKA: uncompressed frame\n"); 00439 size_t rd; 00440 00441 if (fseek(st.fp, FilePos, SEEK_SET)) { 00442 dprintf("fseek(): %s\n", strerror(errno)); 00443 //return NULL; 00444 } 00445 00446 dprintf("MATROSKA: Allocating memory\n"); 00447 /* allocate memory for frame/payload */ 00448 if (fb < FrameSize) { 00449 dprintf("MATROSKA: fb < FrameSize\n"); 00450 fb = FrameSize; 00451 frame = realloc(frame, fb); 00452 if (frame == NULL) { 00453 dprintf("Out of memory\n"); 00454 //return NULL; 00455 } 00456 } 00457 dprintf("MATROSKA: memory (%u)for frame %d allocated\n",FrameSize, currentFrameNumber); 00458 dprintf("MATROSKA: reading frame\n"); 00459 rd = fread(frame,1,FrameSize,st.fp); 00460 dprintf("MATROSKA: read frame %d from file, rd = %d\n",currentFrameNumber, rd); 00461 00462 if (rd != FrameSize) { 00463 dprintf("MATROSKA: rd!= FrameSize\n"); 00464 if (rd == 0) { 00465 if (feof(st.fp)){ 00466 dprintf("Unexpected EOF while reading frame\n");} 00467 else 00468 dprintf("Error reading frame: %s\n",strerror(errno)); 00469 } else 00470 dprintf("Short read while reading frame\n"); 00471 //return NULL; 00472 } 00473 dprintf("MATROSKA: preparing to copy payload ...\n"); 00474 //fwrite(frame,1,FrameSize,out); 00475 // has to do deep-copy, otherwise collision with MP4lib mem handler 00476 00477 au->size = FrameSize; 00478 au->payload = new u8[au->size]; 00479 dprintf("MATROSKA: initializing payload-memory (deep-copy) ...\n"); 00480 memcpy(au->payload,frame,FrameSize); 00481 dprintf("MATROSKA: payload copied!\n"); 00482 00483 00484 00485 } 00486 }//readframe 00487 else{ 00488 00489 state = STREAMEOF; 00490 return NULL; 00491 00492 } 00493 00494 00495 } 00496 else{ 00497 dprintf("\n--->Other stream detected<---\n"); 00498 } 00499 00500 // frame types will be detected in frm->setAU()! 00501 if(es->isVisualStream()) 00502 frm = new CompressedVideoFrame(type, ((VideoESInfo*)es)->getWidth(), ((VideoESInfo*)es)->getHeight()); 00503 else 00504 frm = new CompressedVideoFrame(type, 0, 0); 00505 00506 frm->setAU(au); 00507 frm->setMediaTimeScale(es->getMediaTimeScale()); 00508 framesSeen++; 00509 currentFrameNumber++; 00510 #ifdef _POSIX_PRIORITY_SCHEDULING 00511 sched_yield(); 00512 #else 00513 // for windows pthread lib! 00514 #ifdef WIN32 00515 #ifndef WINCE 00516 sched_yield(); 00517 #else 00518 Sleep(1); 00519 #endif 00520 #endif 00521 #endif 00522 00523 return frm; 00524 } 00525 00526 00527 /***************************************************************/ 00528 bool MKIO::open() { 00529 dprintf_full("MKIO::open()\r\n"); 00530 if(!writeOnly) 00531 return openForReading(); 00532 else 00533 return openForWriting(); 00534 } 00535 00536 00537 /***************************************************************/ 00538 IO::State MKIO::play(double prefetchTime) { 00539 dprintf_full("MKIO::play prefetch %f (old state %i)\n",prefetchTime,state); 00540 00541 if (state==CLOSED) { 00542 open(); 00543 return state; 00544 } else 00545 if ( (state==PAUSED) || (state==MUTED) ) 00546 setState(OPEN); 00547 else { 00548 dprintf_err("MKIO::play tried to OPEN from state %i\n",state); 00549 return state; 00550 } 00551 return state; 00552 00553 } 00554 00555 00556 /***************************************************************/ 00557 bool MKIO::openForReading() { 00558 state = OPENING; 00559 //int err; 00560 /* 00561 dprintf_full("MKIO::openForReading : input is %s\n", input); 00562 if (strlen(input)==0) 00563 { 00564 00565 memset(ap, 0, sizeof(*ap)); 00566 if (es->isVisualStream()) 00567 { 00568 dprintf_full("MKIO::openForReading : using video4linux as input: VIDEO\n"); 00569 ap->frame_rate = 25; 00570 ap->width = 720; 00571 ap->height = 576; 00572 00573 file_iformat = av_find_input_format("video4linux"); 00574 ap->device = NULL; 00575 ap->channel = 0; 00576 ap->standard = "ntsc"; 00577 } 00578 else if (es->isAudioStream()) 00579 { 00580 dprintf_full("MKIO::openForReading : using audio grabbing as input: AUDIO\n"); 00581 ap->sample_rate = 44100; 00582 ap->channels = 2; 00583 file_iformat = av_find_input_format("audio_device"); 00584 } 00585 else 00586 dprintf_err("MKIO::openForReading : Video 4 Linux: Unknown stream type!\n"); 00587 } 00588 00589 err = av_open_input_file(&ic, input, file_iformat, 0, ap); 00590 if(err < 0) { 00591 dprintf_full("MKIO::openForReading : Error in opening file!! ffmpeg error %i\n",err); 00592 state = CLOSED; 00593 return false; 00594 } 00595 dprintf_full("MKIO::openForReading : av_open_input_file is ok\r\n"); 00596 00597 //If not enough info to get the stream parameters, we decode the 00598 //first frames to get it. (used in cases when file has no headers eg. mpeg1) 00599 #ifndef WIN32 //This gives error on windows in case of audio 00600 err = av_find_stream_info(ic); 00601 if (err < 0) { 00602 fprintf(stderr, "%s: could not find codec parameters\n", input); 00603 state = CLOSED; 00604 return false; 00605 } 00606 #endif 00607 00608 00609 streamID = es->getStreamId(); 00610 char *tmp = new char[MAX_STR_LEN]; 00611 strncpy(tmp,input,MAX_STR_LEN); 00612 if (es->isVisualStream()) 00613 strcat(tmp,".video"); 00614 else if (es->isAudioStream()) 00615 strcat(tmp,".audio"); 00616 else { 00617 dprintf_err("ffMP4IO::openForReading requesting streamID neither video nor audio!\n"); 00618 delete [] tmp; 00619 return false; 00620 } 00621 sprintf(tmp,"%s.%i.prio",tmp,streamID); 00622 00623 if ((priofp=fopen(tmp,"r")) != NULL) { 00624 dprintf_full("ffMP4IO::openForReading: successfully opened prio-File %s\n",tmp); 00625 } else { 00626 dprintf_full("ffMP4IO::openForReading: prio-File %s not found. using timely distribution!\n",tmp); 00627 } 00628 */ 00629 state = OPEN; 00630 dprintf_full("MKIO::openForReading : State is open\n"); 00631 // delete [] tmp; 00632 return true; 00633 } 00634 00635 00636 /***************************************************************/ 00637 bool MKIO::openForWriting() { 00638 00639 state = OPEN; 00640 dprintf_full("MKIO::openForWriting : State is open\n"); 00641 00642 00643 00644 return true; 00645 } 00646 00647 00648 /***************************************************************/ 00649 bool MKIO::close(bool immediate) { 00650 00651 dprintf_full("MKIO::close: closing MKIO\n"); 00652 00653 if (priofp) 00654 fclose(priofp); 00655 priofp = NULL; 00656 if (state == CLOSED) 00657 return true; 00658 00659 state = CLOSED; 00660 int err; 00661 /* 00662 if (ic) 00663 { 00664 av_close_input_file(ic); 00665 ic = NULL; 00666 00667 } 00668 */ 00669 00670 err = 0; //ASSUMING no error has occured because 00671 //av_close_.... does not return anything; ISONoErr = 0 00672 00673 //out_file.close(); 00674 // send a NULL-frame to announce the end of the file 00675 00676 #ifdef ENABLE_MKV_WRITE 00677 MKIO::writeFrame(NULL); 00678 00679 assert(out_file); 00680 00681 out_file->close(); 00682 #endif 00683 00684 return err; 00685 } 00686 00687 00688 /***************************************************************/ 00689 int MKIO::writeFrame(Frame * frm, ESInfo *out_es) { 00690 #ifdef _POSIX_PRIORITY_SCHEDULING 00691 sched_yield(); //this is necessary to give parallel getFrames a chance 00692 #endif 00693 00694 #ifdef ENABLE_MKV_WRITE 00695 dprintf_full("MKIO::writeFrame: writing frame (%i bytes) to input %s\n", frm->getAU()->size, input); 00696 00697 if (!headerWritten) { 00698 // write the head of the file (with everything already configured) 00699 out_file = new StdIOCallback (input, MODE_CREATE); 00700 00702 EbmlHead FileHead; 00703 00704 EDocType & MyDocType = GetChild<EDocType>(FileHead); 00705 *static_cast<EbmlString *>(&MyDocType) = "matroska"; 00706 00707 EDocTypeVersion & MyDocTypeVer = GetChild<EDocTypeVersion>(FileHead); 00708 *(static_cast<EbmlUInteger *>(&MyDocTypeVer)) = MATROSKA_VERSION; 00709 00710 EDocTypeReadVersion & MyDocTypeReadVer = GetChild<EDocTypeReadVersion>(FileHead); 00711 *(static_cast<EbmlUInteger *>(&MyDocTypeReadVer)) = 1; 00712 00713 FileHead.Render(*out_file, bWriteDefaultValues); 00714 /* EBML Header rendered to file */ 00715 00716 //KaxSegment FileSegment; 00717 00718 // size is unknown and will always be, we can render it right away 00719 uint64 SegmentSize = FileSegment.WriteHead(*out_file, 5, bWriteDefaultValues); 00720 /* Segment Header rendered to file */ 00721 00722 00723 KaxTracks & MyTracks = GetChild<KaxTracks>(FileSegment); 00724 00725 // reserve some space for the Meta Seek writen at the end 00726 EbmlVoid Dummy; 00727 Dummy.SetSize(300); // 300 octets 00728 Dummy.Render(*out_file, bWriteDefaultValues); 00729 /* Dummy Header rendered to file */ 00730 00731 //KaxSeekHead MetaSeek; 00732 00733 // fill the mandatory Info section 00734 KaxInfo & MyInfos = GetChild<KaxInfo>(FileSegment); 00735 KaxTimecodeScale & TimeScale = GetChild<KaxTimecodeScale>(MyInfos); 00736 *(static_cast<EbmlUInteger *>(&TimeScale)) = TIMECODE_SCALE; 00737 00738 KaxDuration & SegDuration = GetChild<KaxDuration>(MyInfos); 00739 *(static_cast<EbmlFloat *>(&SegDuration)) = es->getDuration(); 00740 00741 *((EbmlUnicodeString *)&GetChild<KaxMuxingApp>(MyInfos)) = L"ViTooKi MKV Muxer"; 00742 *((EbmlUnicodeString *)&GetChild<KaxWritingApp>(MyInfos)) = L"ViTooKi MKV MKIO"; 00743 GetChild<KaxWritingApp>(MyInfos).SetDefaultSize(25); 00744 00745 uint32 InfoSize = MyInfos.Render(*out_file); 00746 MetaSeek.IndexThis(MyInfos, FileSegment); 00747 00748 00749 if (es->isVisualStream()) { 00750 00751 00752 } 00753 else if (es->isAudioStream()) { 00754 00755 00756 } 00757 00758 // fill track 1 params 00759 KaxTrackEntry & MyTrack1 = GetChild<KaxTrackEntry>(MyTracks); 00760 MyTrack1.SetGlobalTimecodeScale(TIMECODE_SCALE); 00761 00762 /* fill in tracknumber from ESInfo */ 00763 KaxTrackNumber & MyTrack1Number = GetChild<KaxTrackNumber>(MyTrack1); 00764 *(static_cast<EbmlUInteger *>(&MyTrack1Number)) = 1; 00765 00766 /* fill in UID, can/should be equal Tracknumber*/ 00767 KaxTrackUID & MyTrack1UID = GetChild<KaxTrackUID>(MyTrack1); 00768 *(static_cast<EbmlUInteger *>(&MyTrack1UID)) = 7; 00769 00770 /* set track to audio or video, according to ES track type */ 00771 /* if ES->isvisual */ 00772 *(static_cast<EbmlUInteger *>(&GetChild<KaxTrackType>(MyTrack1))) = track_audio; 00773 00774 /* Set CODEC in MATROSKA-ID-Style, read from ES in FFMPEG-style */ 00775 KaxCodecID & MyTrack1CodecID = GetChild<KaxCodecID>(MyTrack1); 00776 *static_cast<EbmlString *>(&MyTrack1CodecID) = "Dummy Audio Codec"; 00777 00778 MyTrack1.EnableLacing(true); 00779 00780 // Test the new ContentEncoding elements 00781 KaxContentEncodings &cencodings = GetChild<KaxContentEncodings>(MyTrack1); 00782 KaxContentEncoding &cencoding = GetChild<KaxContentEncoding>(cencodings); 00783 *(static_cast<EbmlUInteger *>(&GetChild<KaxContentEncodingOrder>(cencoding))) = 10; 00784 *(static_cast<EbmlUInteger *>(&GetChild<KaxContentEncodingScope>(cencoding))) = 11; 00785 *(static_cast<EbmlUInteger *>(&GetChild<KaxContentEncodingType>(cencoding))) = 12; 00786 00787 KaxContentCompression &ccompression = GetChild<KaxContentCompression>(cencoding); 00788 *(static_cast<EbmlUInteger *>(&GetChild<KaxContentCompAlgo>(ccompression))) = 13; 00789 GetChild<KaxContentCompSettings>(ccompression).CopyBuffer((const binary *)"hello1", 6); 00790 00791 KaxContentEncryption &cencryption = GetChild<KaxContentEncryption>(cencoding); 00792 *(static_cast<EbmlUInteger *>(&GetChild<KaxContentEncAlgo>(cencryption))) = 14; 00793 GetChild<KaxContentEncKeyID>(cencryption).CopyBuffer((const binary *)"hello2", 6); 00794 *(static_cast<EbmlUInteger *>(&GetChild<KaxContentSigAlgo>(cencryption))) = 15; 00795 *(static_cast<EbmlUInteger *>(&GetChild<KaxContentSigHashAlgo>(cencryption))) = 16; 00796 GetChild<KaxContentSigKeyID>(cencryption).CopyBuffer((const binary *)"hello3", 6); 00797 GetChild<KaxContentSignature>(cencryption).CopyBuffer((const binary *)"hello4", 6); 00798 /* if audio */ 00799 // audio specific params 00800 KaxTrackAudio & MyTrack1Audio = GetChild<KaxTrackAudio>(MyTrack1); 00801 00802 KaxAudioSamplingFreq & MyTrack1Freq = GetChild<KaxAudioSamplingFreq>(MyTrack1Audio); 00803 *(static_cast<EbmlFloat *>(&MyTrack1Freq)) = 44100.0; 00804 MyTrack1Freq.ValidateSize(); 00805 00806 #if MATROSKA_VERSION >= 2 00807 KaxAudioPosition & MyTrack1Pos = GetChild<KaxAudioPosition>(MyTrack1Audio); 00808 binary *_Pos = new binary[5]; 00809 _Pos[0] = '0'; 00810 _Pos[1] = '1'; 00811 _Pos[2] = '2'; 00812 _Pos[3] = '3'; 00813 _Pos[4] = '\0'; 00814 MyTrack1Pos.SetBuffer(_Pos, 5); 00815 #endif // MATROSKA_VERSION 00816 00817 KaxAudioChannels & MyTrack1Channels = GetChild<KaxAudioChannels>(MyTrack1Audio); 00818 *(static_cast<EbmlUInteger *>(&MyTrack1Channels)) = 2; 00819 00820 // fill track 2 params 00821 KaxTrackEntry & MyTrack2 = GetNextChild<KaxTrackEntry>(MyTracks, MyTrack1); 00822 MyTrack2.SetGlobalTimecodeScale(TIMECODE_SCALE); 00823 00824 KaxTrackNumber & MyTrack2Number = GetChild<KaxTrackNumber>(MyTrack2); 00825 *(static_cast<EbmlUInteger *>(&MyTrack2Number)) = 200; 00826 00827 KaxTrackUID & MyTrack2UID = GetChild<KaxTrackUID>(MyTrack2); 00828 *(static_cast<EbmlUInteger *>(&MyTrack2UID)) = 13; 00829 00830 *(static_cast<EbmlUInteger *>(&GetChild<KaxTrackType>(MyTrack2))) = track_video; 00831 00832 KaxCodecID & MyTrack2CodecID = GetChild<KaxCodecID>(MyTrack2); 00833 *static_cast<EbmlString *>(&MyTrack2CodecID) = "Dummy Video Codec"; 00834 00835 KaxTrackDefaultDuration & MyTrack2DefaultDuration = GetChild<KaxTrackDefaultDuration>(MyTrack2); 00836 //*(static_cast<EbmlUInteger *>(&MyTrack2DefaultDuration)) = 40000000; 00837 *(static_cast<EbmlUInteger *>(&MyTrack2DefaultDuration)) = es->getDuration(); 00838 00839 /* if video */ 00840 MyTrack2.EnableLacing(false); 00841 00842 // video specific params 00843 00844 VideoESInfo *esVideo = (VideoESInfo *) es; 00845 00846 KaxTrackVideo & MyTrack2Video = GetChild<KaxTrackVideo>(MyTrack2); 00847 00848 KaxVideoPixelHeight & MyTrack2PHeight = GetChild<KaxVideoPixelHeight>(MyTrack2Video); 00849 *(static_cast<EbmlUInteger *>(&MyTrack2PHeight)) = esVideo->getHeight(); 00850 00851 KaxVideoPixelWidth & MyTrack2PWidth = GetChild<KaxVideoPixelWidth>(MyTrack2Video); 00852 *(static_cast<EbmlUInteger *>(&MyTrack2PWidth)) = esVideo->getWidth(); 00853 00854 00855 uint64 TrackSize = MyTracks.Render(*out_file, bWriteDefaultValues); 00856 00857 KaxTracks * pMyTracks2 = static_cast<KaxTracks *>(MyTracks.Clone()); 00858 00859 MetaSeek.IndexThis(MyTracks, FileSegment); 00860 00861 /* first header stops here 00862 * the passing of the payload takes place here*/ 00863 00864 // "manual" filling of a cluster" 00865 00866 KaxCues AllCues; 00867 AllCues.SetGlobalTimecodeScale(TIMECODE_SCALE); 00868 00869 KaxCluster Clust1; 00870 Clust1.SetParent(FileSegment); // mandatory to store references in this Cluster 00871 Clust1.SetPreviousTimecode(0, TIMECODE_SCALE); // the first timecode here 00872 Clust1.EnableChecksum(); 00873 00874 // automatic filling of a Cluster 00875 // simple frame 00876 // the payload of vitooki frame objects can be used here for writing to file -> DataBuffer 00877 KaxBlockGroup *MyNewBlock, *MyLastBlockTrk1 = NULL, *MyLastBlockTrk2 = NULL, *MyNewBlock2; 00878 00879 DataBuffer *data7 = new DataBuffer((binary *)"tototototo", countof("tototototo")); 00880 Clust1.AddFrame(MyTrack1, 250 * TIMECODE_SCALE, *data7, MyNewBlock, LACING_EBML); 00881 if (MyNewBlock != NULL) 00882 MyLastBlockTrk1 = MyNewBlock; 00883 00884 /* #### */ 00885 00886 DataBuffer *data0 = new DataBuffer((binary *)"TOTOTOTO", countof("TOTOTOTO")); 00887 Clust1.AddFrame(MyTrack1, 260 * TIMECODE_SCALE, *data0, MyNewBlock); // to test EBML lacing 00888 if (MyNewBlock != NULL) 00889 MyLastBlockTrk1 = MyNewBlock; 00890 00891 DataBuffer *data6 = new DataBuffer((binary *)"tototototo", countof("tototototo")); 00892 Clust1.AddFrame(MyTrack1, 270 * TIMECODE_SCALE, *data6, MyNewBlock); // to test lacing 00893 if (MyNewBlock != NULL) { 00894 MyLastBlockTrk1 = MyNewBlock; 00895 } else { 00896 MyLastBlockTrk1->SetBlockDuration(50 * TIMECODE_SCALE); 00897 } 00898 00899 DataBuffer *data5 = new DataBuffer((binary *)"tototototo", countof("tototototo")); 00900 Clust1.AddFrame(MyTrack2, 23 * TIMECODE_SCALE, *data5, MyNewBlock); // to test with another track 00901 00902 // add the "real" block to the cue entries 00903 AllCues.AddBlockGroup(*MyLastBlockTrk1); 00904 00905 // frame for Track 2 00906 DataBuffer *data8 = new DataBuffer((binary *)"tttyyy", countof("tttyyy")); 00907 Clust1.AddFrame(MyTrack2, 107 * TIMECODE_SCALE, *data8, MyNewBlock, *MyLastBlockTrk2); 00908 00909 AllCues.AddBlockGroup(*MyNewBlock); 00910 00911 // frame with a past reference 00912 DataBuffer *data4 = new DataBuffer((binary *)"tttyyy", countof("tttyyy")); 00913 Clust1.AddFrame(MyTrack1, 300 * TIMECODE_SCALE, *data4, MyNewBlock, *MyLastBlockTrk1); 00914 00915 // frame with a past & future reference 00916 if (MyNewBlock != NULL) { 00917 DataBuffer *data3 = new DataBuffer((binary *)"tttyyy", countof("tttyyy")); 00918 if (Clust1.AddFrame(MyTrack1, 280 * TIMECODE_SCALE, *data3, MyNewBlock2, *MyLastBlockTrk1, *MyNewBlock)) { 00919 MyNewBlock2->SetBlockDuration(20 * TIMECODE_SCALE); 00920 MyLastBlockTrk1 = MyNewBlock2; 00921 } else { 00922 printf("Error adding a frame !!!"); 00923 } 00924 } 00925 00926 AllCues.AddBlockGroup(*MyLastBlockTrk1); 00927 //AllCues.UpdateSize(); 00928 00929 // simulate the writing of the stream : 00930 // - write an empty element with enough size for the cue entry 00931 // - write the cluster(s) 00932 // - seek back in the file and write the cue entry over the empty element 00933 00934 uint64 ClusterSize = Clust1.Render(*out_file, AllCues, bWriteDefaultValues); 00935 Clust1.ReleaseFrames(); 00936 MetaSeek.IndexThis(Clust1, FileSegment); 00937 00938 KaxCluster Clust2; 00939 Clust2.SetParent(FileSegment); // mandatory to store references in this Cluster 00940 Clust2.SetPreviousTimecode(300 * TIMECODE_SCALE, TIMECODE_SCALE); // the first timecode here 00941 Clust2.EnableChecksum(); 00942 00943 DataBuffer *data2 = new DataBuffer((binary *)"tttyyy", countof("tttyyy")); 00944 Clust2.AddFrame(MyTrack1, 350 * TIMECODE_SCALE, *data2, MyNewBlock, *MyLastBlockTrk1); 00945 00946 AllCues.AddBlockGroup(*MyNewBlock); 00947 00948 ClusterSize += Clust2.Render(*out_file, AllCues, bWriteDefaultValues); 00949 Clust2.ReleaseFrames(); 00950 00951 00952 uint32 CueSize = AllCues.Render(*out_file, bWriteDefaultValues); 00953 MetaSeek.IndexThis(AllCues, FileSegment); 00954 00955 // Chapters 00956 KaxChapters Chapters; 00957 Chapters.EnableChecksum(); 00958 KaxEditionEntry & aEdition = GetChild<KaxEditionEntry>(Chapters); 00959 KaxChapterAtom & aAtom = GetChild<KaxChapterAtom>(aEdition); 00960 KaxChapterUID & aUID = GetChild<KaxChapterUID>(aAtom); 00961 *static_cast<EbmlUInteger *>(&aUID) = 0x67890; 00962 00963 KaxChapterTimeStart & aChapStart = GetChild<KaxChapterTimeStart>(aAtom); 00964 *static_cast<EbmlUInteger *>(&aChapStart) = 0; 00965 00966 KaxChapterTimeEnd & aChapEnd = GetChild<KaxChapterTimeEnd>(aAtom); 00967 *static_cast<EbmlUInteger *>(&aChapEnd) = 300 * TIMECODE_SCALE; 00968 00969 KaxChapterDisplay & aDisplay = GetChild<KaxChapterDisplay>(aAtom); 00970 KaxChapterString & aChapString = GetChild<KaxChapterString>(aDisplay); 00971 *static_cast<EbmlUnicodeString *>(&aChapString) = L"der film in einem kapitel"; 00972 00973 KaxChapterLanguage & aChapLang = GetChild<KaxChapterLanguage>(aDisplay); 00974 *static_cast<EbmlString *>(&aChapLang) = "de"; 00975 00976 KaxChapterDisplay & aDisplay2 = GetNextChild<KaxChapterDisplay>(aAtom, aDisplay); 00977 KaxChapterString & aChapString2 = GetChild<KaxChapterString>(aDisplay2); 00978 *static_cast<EbmlUnicodeString *>(&aChapString2) = L"The movie in one chapter"; 00979 00980 KaxChapterLanguage & aChapLang2 = GetChild<KaxChapterLanguage>(aDisplay2); 00981 *static_cast<EbmlString *>(&aChapLang2) = "eng"; 00982 00983 uint32 ChapterSize = Chapters.Render(*out_file, bWriteDefaultValues); 00984 MetaSeek.IndexThis(Chapters, FileSegment); 00985 00986 // Write some tags 00987 KaxTags AllTags; 00988 AllTags.EnableChecksum(); 00989 KaxTag & aTag = GetChild<KaxTag>(AllTags); 00990 KaxTagTargets & Targets = GetChild<KaxTagTargets>(aTag); 00991 KaxTagGeneral & TagGeneral = GetChild<KaxTagGeneral>(aTag); 00992 00993 KaxTagTrackUID & TrackUID = GetChild<KaxTagTrackUID>(Targets); 00994 *static_cast<EbmlUInteger *>(&TrackUID) = 0x12345; 00995 00996 KaxTagChapterUID & ChapterUID = GetChild<KaxTagChapterUID>(Targets); 00997 *static_cast<EbmlUInteger *>(&ChapterUID) = 0x67890; 00998 00999 KaxTagSubject & Subject = GetChild<KaxTagSubject>(TagGeneral); 01000 *static_cast<EbmlUnicodeString *>(&Subject) = L"Test123"; 01001 01002 KaxTagBibliography & Biblio = GetChild<KaxTagBibliography>(TagGeneral); 01003 *static_cast<EbmlUnicodeString *>(&Biblio) = L"Biblio"; 01004 01005 KaxTagFile & File = GetChild<KaxTagFile>(TagGeneral); 01006 *static_cast<EbmlUnicodeString *>(&File) = L"general tag"; 01007 01008 KaxTagLanguage & Lang = GetChild<KaxTagLanguage>(TagGeneral); 01009 *static_cast<EbmlString *>(&Lang) = "de"; 01010 01011 uint32 TagsSize = AllTags.Render(*out_file, bWriteDefaultValues); 01012 MetaSeek.IndexThis(AllTags, FileSegment); 01013 01014 TrackSize += pMyTracks2->Render(*out_file, bWriteDefaultValues); 01015 MetaSeek.IndexThis(*pMyTracks2, FileSegment); 01016 01017 uint32 MetaSeekSize = Dummy.ReplaceWith(MetaSeek, *out_file, bWriteDefaultValues); 01018 01019 01020 // let's assume we know the size of the Segment element 01021 // the size of the FileSegment is also computed because mandatory elements exist 01022 if (FileSegment.ForceSize(SegmentSize - FileSegment.HeadSize() + MetaSeekSize 01023 + TrackSize + ClusterSize + CueSize + InfoSize + TagsSize + ChapterSize)) { 01024 FileSegment.OverwriteHead(*out_file, true); 01025 01026 headerWritten = true; 01027 } 01028 } 01029 01030 //write normal frame to mkv container here 01031 01032 #endif 01033 01034 return 1; 01035 } 01036 01037 01038 /***************************************************************/ 01041 int MKIO::getBufferFillLevel() const { 01042 if (state == OPEN) 01043 return 50; 01044 else if (state == STREAMEOF) 01045 return -1; 01046 else 01047 return 0; 01048 } 01049 01050 01051 /***************************************************************/ 01052 bool MKIO::destroy() { 01053 close(); 01054 return remove(input) == 0; 01055 } 01056 01057 01061 bool MKIO::setToFrameNumber(u32 frameNumber) { 01062 01063 return false; 01064 } 01065 01066 /***************************************************************/ 01067 int MKIO::patSplitRec(int *pat, int len, int actdepth, int maxdepth, int gowhere, int *actpos) { 01068 int half=len/2; 01069 int *middle = &pat[half]; 01070 int ret; 01071 01072 // printf("depth %i (of %i) pos %i len %i left %i right %i --> ",actdepth,maxdepth,*actpos,len,half,len-half); 01073 //printPat(pat,len,-1,0); 01074 01075 if (actdepth < maxdepth) { 01076 if (gowhere) { 01077 ret = patSplitRec(pat, half, actdepth+1, maxdepth, gowhere,actpos); 01078 if (ret == 0) 01079 ret = patSplitRec(pat+half,len-half, actdepth+1, maxdepth, gowhere,actpos); 01080 return ret; 01081 } else { 01082 ret = patSplitRec(pat+half,len-half, actdepth+1, maxdepth, gowhere,actpos); 01083 if (ret == 0) 01084 ret = patSplitRec(pat, half, actdepth+1, maxdepth, gowhere,actpos); 01085 return ret; 01086 } 01087 } else { 01088 if (*middle == -1) { 01089 *middle = (*actpos)--; 01090 return 1; 01091 } else { 01092 // printf("FULL\n"); 01093 return 0; 01094 } 01095 } 01096 01097 } 01098 01099 01100 /***************************************************************/ 01101 void MKIO::patSplit(int *pat, int len, int maxdepth, int *actpos) { 01102 int i=1, j=1; 01103 01104 if (*actpos == len) { //init 01105 for (int k=0; k<len;k++) 01106 pat[k]=-1; 01107 patSplitRec(pat, len, 0, 0, 0, actpos); 01108 } 01109 01110 while ((i!=0) || (j!=0)) { 01111 // printf(">>>next node RIGHT\n"); 01112 //printPat(pat,len); 01113 i = patSplitRec(pat, len, 0, maxdepth, 1, actpos); 01114 // printf(">>>next node LEFT \n"); 01115 //printPat(pat,len); 01116 j = patSplitRec(pat, len, 0, maxdepth, 0, actpos); 01117 } 01118 } 01119 01120 01121 /***************************************************************/ 01122 void MKIO::printPat(int *pat, int len) { 01123 int i; 01124 for (i=0; i<len; i++) { 01125 if (pat[i] > -1) 01126 printf("%2i-", pat[i]); 01127 else 01128 printf("..-"); 01129 } 01130 printf("\n"); 01131 } 01132 01133 #endif