/************************************************************* * mpgtx an mpeg toolbox * * by Laurent Alacoque * * (c) 2001 * * You may copy, modify and redistribute this * * source file under the terms of the GNU Public License * ************************************************************/ #include "mpeg.hh" #include //philipp #include extern bool desperate_mode; extern bool preserve_header; extern bool print_progress; int mpeg2found = 0; // #define _DEBUG_ int mpeg_bitrate_index [2][3][16] = { // MPEG 1 { // layer 1 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, // layer 2 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, // layer 3 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0} }, // MPEG 2 or 2.5 { // layer 1 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, // layer 2 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0}, // layer 3 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} } }; int mpeg_sampling_index [3][4] = { {44100,48000,32000,0}, //mpeg 1 {22050,24000,16000,0}, //mpeg 2 {11025,12000, 8000,0} //mpeg 2.5 }; double mpeg_frame_rate_index [9] = { 0., 24000./1001., 24., 25., 30000./1001., 30., 50., 60000./1001., 60. }; // ripped from id3ed V1.10.2 (Thx to Matt Mueller) // HEY you didn't want me to type *that* ! const char *genre[MAX_ID3_GENRE]={ "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap","Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop" }; float mpeg::Duration(){ BTRACK; if (Audio) return float(Audio->duration); if (Video) return float(Video->duration); return 0; } bool mpeg::Match(mpeg* peer){ BTRACK; if (MpegType != peer->MpegType) { fprintf(stderr, "mpeg files are not the same type!\n"); return false; } if (MpegType == mpeg_AUDIO || MpegType == mpeg_SYSTEM) { if (Audio->bitrate != peer->Audio->bitrate) { fprintf (stderr, "Incompatible audio bitrates %s (%d bps) %s (%d bps)\n", FileName, Audio->bitrate, peer->FileName, peer->Audio->bitrate); return false; } if (Audio->mpeg_ver != peer->Audio->mpeg_ver) { fprintf (stderr, "Incompatible mpeg audio versions " "%s is mpeg %d %s is mpeg %d\n", FileName,Audio->mpeg_ver, peer->FileName, peer->Audio->mpeg_ver); return false; } if (Audio->layer != peer->Audio->layer) { fprintf (stderr, "Incompatible audio layers %s is layer %d %s is layer %d", FileName, Audio->layer, peer->FileName, peer->Audio->layer); return false; } if (Audio->sampling_rate != peer->Audio->sampling_rate){ fprintf (stderr,"Incompatible sampling rates %s (%d Hz) %s (%d Hz)\n", FileName, Audio->sampling_rate, peer->FileName, peer->Audio->sampling_rate); return false; } return true; } if (MpegType == mpeg_VIDEO || MpegType == mpeg_SYSTEM){ if ( (Video->hsize != peer->Video->hsize) || (Video->vsize != peer->Video->vsize)) { fprintf(stderr,"Incompatible size %s [%ldx%ld] %s [%ldx%ld]\n", FileName, Video->hsize,Video->vsize, peer->FileName, peer->Video->hsize, peer->Video->vsize); return false; } if (Video->bitrate != peer->Video->bitrate) { fprintf(stderr,"incompatible video bitrate %s (%ld bps) %s (%ld bps)\n", FileName, Video->bitrate, peer->FileName, peer->Video->bitrate); return false; } if (Video->frame_rate != peer->Video->frame_rate) { fprintf(stderr, "incompatible video frame rate %s (%f fps) %s (%f fps)\n", FileName, Video->frame_rate, peer->FileName, peer->Video->frame_rate); return false; } return true; } // no known file return false; } mpeg::mpeg(const char* filename,int verbosity) : MpegFile(0), Verboseness(verbosity), HasAudio(false), HasVideo(false), composite(false), editable(false), MpegType(mpeg_UNKNOWN), Audio(0), n_audio(0), Video(0), n_video(0), System(0), Transport(0), start_with_id3(false), mpeg_version(1), buffstart(0),buffend(0),buffer(0) { BTRACK; UData=0; SExt=0; DExt=0; // keep track of filename (usefull for debugging) // TODO : only on mpeg_VERBOSE ? FileName = new char[strlen(filename) + 1]; strcpy(FileName , filename); // open infile read-only, binary type (for compatibility with other than POSIX/GNU) MpegFile = fopen(filename, "rb"); #ifdef _DEBUG_ Verboseness = mpeg_VERBOSE; #endif // case unable to open if (MpegFile == 0) { if (Verboseness!=mpeg_SILENT) { printf("Unable to open %s\n",filename); if(Verboseness == mpeg_VERBOSE) perror(filename); } //nothing more to do... return; } // Allocate buffer buffer = new byte[BUFFERSIZE]; // Seek to end of file if (FSEEK(MpegFile, 0, SEEK_END)) { if (Verboseness != mpeg_SILENT) { printf("Unable to seek in file %s\n", filename); if (Verboseness == mpeg_VERBOSE) perror(filename); } //give up.. return; } // File size off_t off_eof = FTELL(MpegFile); if (off_eof == -1) { if (Verboseness != mpeg_SILENT) { printf("Seeking to end of input file %s failed.\n", filename); if (Verboseness == mpeg_VERBOSE) perror(filename); } //give up.. return; } else FileSize = off_eof; // if (Verboseness==mpeg_VERBOSE){ #ifdef _DEBUG_ printf("%s has size " _OFF_d "\n", FileName, FileSize); #endif // } // nothing to do on an empty file if (!FileSize) { if (Verboseness != mpeg_SILENT) { printf("File %s is empty.\n", filename); if (Verboseness == mpeg_VERBOSE) perror(filename); } //give up.. return; } // first determine the file type between audio/video/system if (ParseAudio(0)) { // this is an Audio only mpeg file MpegType = mpeg_AUDIO; composite = false; editable = true; } else if (ParseVideo(0)) { // this is a Video only mpeg file MpegType = mpeg_VIDEO; composite = false; editable = true; } else if (ParseSystem()) { // this is an Audio and Video mpeg file MpegType = mpeg_SYSTEM; } else if (ParseID3()) { //this is an audio file with an ID3 v2 MpegType = mpeg_AUDIO; editable = true; composite = false; } else if (ParseRIFF()) { // this is either a Wave file or a divx or something else editable = false; composite = false; } else if (ParseTransportStream(0)) { // this is a MPEG 2 transport stream MpegType = mpeg_TRANSPORT; editable = false; composite = true; } else { // can not handle this mpeg file if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s is not a valid MPEG file (can't handle it)\n", FileName); } } // mpeg class destructor mpeg::~mpeg() { BTRACK; if (buffer) delete[] buffer; if (MpegFile) fclose(MpegFile); if (Audio) { if (Audio->tag) delete Audio->tag; delete Audio; } if (Video) { if (Video->video_header) delete[] Video->video_header; delete Video; } if (System) { if(System->audio_system_header) delete[] System->audio_system_header; if(System->video_system_header) delete[] System->video_system_header; delete System; } if (SExt) delete SExt; if (DExt) delete DExt; if (UData) { if (UData->ud) delete[] UData->ud; delete UData; } if (Transport) delete Transport; } // map a buffer onto file for efficiency byte mpeg::GetByte(off_t offset) { BTRACK; START_CLOCK; size_t nread; if ((offset >= buffend) || (offset < buffstart)) { // new buffer need (forward) if (FSEEK(MpegFile, offset, SEEK_SET)) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "could not get seek to offset (" _OFF_d ") in file %s (size:" _OFF_d ")\n", offset, FileName, FileSize); RTRACK; ATRACK("GetByte Invalid offset"); fprintf(stderr,"mpgtx: AT EOF - please stop me!\n"); return 0x11; } nread = fread(buffer, 1, BUFFERSIZE, MpegFile); buffstart = offset; buffend = offset + nread; if ((offset >= buffend) || (offset < buffstart)) { // weird if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "could not get offset " _OFF_d " in file %s [" _OFF_x "]\n", offset, FileName, FileSize); RTRACK; ATRACK("GetByte Invalid offset"); fprintf(stderr,"mpgtx: AT EOF - please stop me!\n"); return 0x11; } } STOP_CLOCK(GETBYTE); RTRACK; return buffer[offset - buffstart]; } byte mpeg::Byte(off_t offset){ return GetByte(offset); // because GetByte is inline } // same as above but improved for backward search byte mpeg::bdGetByte(off_t offset){ BTRACK; size_t nread; if ((offset >= buffend) || (offset < buffstart)){ // new buffer needed (backward) off_t start = offset-BUFFERSIZE+1 ; start = start >= 0?start:0; FSEEK(MpegFile, start, SEEK_SET); nread = fread(buffer, 1, BUFFERSIZE, MpegFile); buffstart = start; buffend = start + nread; if ((offset >= buffend) || (offset < buffstart)) { // weird if (Verboseness == mpeg_VERBOSE) fprintf(stderr,"could not get offset " _OFF_x " in file %s [" _OFF_x "]\n", offset, FileName, FileSize); RTRACK; ATRACK("bdGetByte Invalid offset"); return 0x11; } } RTRACK; return buffer[offset - buffstart]; } // make sure the sequence 0x00 00 01 mark // bool mpeg::EnsureMPEG(off_t offset, marker mark){ BTRACK; if (( GetByte(offset) == 0x00 ) && ( GetByte(offset+1) == 0x00 ) && ( GetByte(offset+2) == 0x01 ) && ( GetByte(offset+3) == mark )) return true; else return false; } // get a two byte size (word) // unsigned short int mpeg::GetSize(off_t offset ) { BTRACK; return GetByte(offset)*256 + GetByte(offset+1); } // print ID3v2 tag to stdout // bool mpeg::PrintID3() { BTRACK; // Byte 0-2: ID3v2/file identifier "ID3" if ( (GetByte(0)!='I') || (GetByte(1)!='D') || (GetByte(2)!='3')) return false; // Byte 3-4: ID3v2 version printf(" ID3 v2.%d.%d tag (more info on http://www.id3.org/)\n", GetByte(3), GetByte(4)); printf(" ----------------\n"); // Byte 5: ID3v2 flags (%abcd0000) // Byte 6-9: ID3v2 tag size (4 * %0xxxxxxx) size_t framesize; off_t tagsize; size_t i; tagsize = GetByte(6)<<21; tagsize |= GetByte(7)<<14; tagsize |= GetByte(8)<<7; tagsize |= GetByte(9); #ifdef _DEBUG_ printf("Tag size : " _OFF_d "\n", tagsize); #endif bool handled; off_t offset = 10; while (offset < tagsize+10) { if ((GetByte(offset)<'0') || (GetByte(offset)>'Z')) break; handled = false; framesize = (GetByte(offset+4)<<24) | (GetByte(offset+5)<<16) | (GetByte(offset+6)<<8) | (GetByte(offset+7)); // print tag printf(" %c%c%c%c : ", GetByte(offset), GetByte(offset+1), GetByte(offset+2), GetByte(offset+3)); // T... - all text tags if (GetByte(offset) == 'T') { if (!GetByte(offset+10)) //if text encoding = standard encoding for (i = 1; i < framesize; i++) { printf("%c", GetByte(offset + i + 10)); handled = true; } if (!handled) { printf("(empty)"); handled=true; } } // COMM - Comments tag if ( (GetByte(offset) =='C') && (GetByte(offset+1)=='O') && (GetByte(offset+2)=='M') && (GetByte(offset+3)=='M')) { printf("(lang: %c%c%c) : ", GetByte(offset+11), GetByte(offset+12), GetByte(offset+13)); for (i = 5; i < framesize; i++) { printf("%c", GetByte(offset + i + 10)); handled = true; } if (!handled) { printf("(empty)"); handled=true; } } if (!handled) printf("(skipped)"); printf("\n"); offset += 10 + framesize; } printf(" ----------------\n"); return true; } // check if ID3v2 tag is present and audio follows // bool mpeg::ParseID3(){ BTRACK; if ( (GetByte(0)!='I') || (GetByte(1)!='D') || (GetByte(2)!='3')) return false; start_with_id3 = true; // get tag size size_t tagsize=0; tagsize = GetByte(6)<<21; tagsize |= GetByte(7)<<14; tagsize |= GetByte(8)<<7; tagsize |= GetByte(9); return ParseAudio(tagsize + 10); } // Parses Audio header returns false on not audio // bool mpeg::ParseAudio(off_t myoffset) { BTRACK; HasAudio = false; bool mpeg2_5 = false; int i; // ensure that two first bytes are FFFx // TODO: give it a chance and search for a valid start after the beginning // even if most audio players will refuse to play such a file if ((GetByte(myoffset+0)!=0xFF)||((GetByte(myoffset+1) & 0xF0)!=0xF0)) { // doesn't start with 12 bits set if ((GetByte(myoffset+0)!=0xFF)||((GetByte(myoffset+1) & 0xE0)!=0xE0)) { // doesn't start with 11 bits set return false; } else { // start with 11 bits set mpeg2_5 = true; } } // seems to be audio, let's allocate the struct Audio=new mpgtx_audio; Audio->tag=0; Audio->first_frame_offset=myoffset; // Find mpeg version 1.0 or 2.0 if(GetByte(myoffset + 1) & 0x08) { if (!mpeg2_5) Audio->mpeg_ver = 1; else return false; // invalid 01 encountered } else { if (!mpeg2_5) Audio->mpeg_ver = 2; else Audio->mpeg_ver = 3; //for mpeg 2.5 } // Find Layer Audio->layer = (GetByte(myoffset + 1) & 0x06)>>1; switch(Audio->layer) { case 0: Audio->layer=-1; return false; case 1: Audio->layer=3; break; case 2: Audio->layer=2; break; case 3: Audio->layer=1; break; } // Protection Bit Audio->protect = GetByte(myoffset + 1) & 0x01; if (Audio->protect) Audio->protect = 0; else Audio->protect = 1; // Bitrate index and sampling index to pass through the array int bitrate_index = GetByte(myoffset+2)>>4; int sampling_index = (GetByte(myoffset+2)&0x0f)>>2; if (sampling_index >= 3) return false; if (bitrate_index == 15) return false; Audio->bitrate = mpeg_bitrate_index[Audio->mpeg_ver-1][Audio->layer-1][bitrate_index]; Audio->byte_rate = (float)((Audio->bitrate*1000)/8.0); Audio->sampling_rate = mpeg_sampling_index[Audio->mpeg_ver-1][sampling_index]; // Padding bit if (GetByte(myoffset+2)&0x02) Audio->padding = 1; else Audio->padding = 0; // Audio mode Audio->mode=GetByte(myoffset+3)>>6; if (Audio->mode==1) Audio->modext=(GetByte(myoffset+3)>>4)&0x03; else Audio->modext=-1; // Copyright bit if(GetByte(myoffset+3)&0x08) Audio->copyright=true; else Audio->copyright=false; // Original/Copy bit if(GetByte(myoffset+3)&0x04) Audio->original=true; else Audio->original=false; // emphasis index Audio->emphasis_index=GetByte(myoffset+3)&0x03; // Frame Length if (Audio->mpeg_ver == 1) { if (Audio->layer == 1) Audio->frame_length = int((48000.0*Audio->bitrate)/Audio->sampling_rate) + 4*Audio->padding; else Audio->frame_length = int((144000.0*Audio->bitrate)/Audio->sampling_rate) + Audio->padding; } else if (Audio->mpeg_ver == 2) { if (Audio->layer == 1) Audio->frame_length = int((24000.0*Audio->bitrate)/Audio->sampling_rate) +4*Audio->padding; else Audio->frame_length = int((72000.0*Audio->bitrate)/Audio->sampling_rate) +Audio->padding; } else { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Audio mpeg file layer invalid : " "%d (should be 1 or 2)\n", FileName,Audio->mpeg_ver); return false; } // size of CRC if (Audio->protect) Audio->frame_length += 2; //Audio->frame_length += 4; // size of standard header // let's get the id3 tag if present. if ( GetByte(FileSize-128) == 'T' && GetByte(FileSize-127) == 'A' && GetByte(FileSize-126) == 'G') { FSEEK(MpegFile, FileSize-125, SEEK_SET); Audio->tag = new id3; fread(Audio->tag, 1, sizeof(id3), MpegFile); FileSize -= 128; //empty unused fields bool keep_it=false; for ( i=0; i<30;i++) { if (Audio->tag->name[i] != ' ') { if (Audio->tag->name[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->name[0] = 0; keep_it = false; for ( i=0; i<30;i++){ if (Audio->tag->artist[i] != ' ') { if (Audio->tag->artist[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->artist[0] = 0; keep_it = false; for ( i=0; i<30;i++) { if (Audio->tag->album[i] != ' ') { if (Audio->tag->album[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->album[0] = 0; keep_it = false; for ( i=0; i<4;i++){ if (Audio->tag->year[i] != ' ') { if (Audio->tag->year[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->year[0] = 0; keep_it = false; for ( i=0; i<30;i++) { if (Audio->tag->comment[i] != ' '){ if (Audio->tag->comment[i] != '\0') keep_it = true; break; } } if (!keep_it) Audio->tag->comment[0] = 0; } Audio->duration = ((FileSize*1.0)/Audio->bitrate)*0.008; HasAudio = true; // fprintf(stderr, "found audio.\n"); return true; } //Parses Video header returns false on not video bool mpeg::ParseVideo(off_t myoffset){ BTRACK; // the MPEG video file should start with // the video start sequence, if not exit. // TODO: give it a chance and seek a video start elsewhere if(!EnsureMPEG(myoffset, 0xB3)) return false; off_t header_start=myoffset; // seems to be video okay, let's allocate the struct Video = new mpgtx_video; Video->video_header = 0; // Get vertical and horizontal picture sizes myoffset += 4; // after video sequence code Video->hsize = GetSize(myoffset) >> 4; Video->vsize = GetSize(myoffset+1) & 0x0FFF; // Get picture rate myoffset += 3; // after picture sizes int frame_rate_index = GetByte(myoffset) & 0x0F; if (frame_rate_index > 8) { // invalid frame rate index if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "Invalid frame rate index in file %s : %d\n", FileName, frame_rate_index); Video->frame_rate = 0.0; } else Video->frame_rate = mpeg_frame_rate_index[frame_rate_index]; Video->aspect_ratio = (GetByte(myoffset) & 0xF0) >>4; if (!Video->aspect_ratio) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "Invalid aspect ratio in file %s : %d\n", FileName, Video->aspect_ratio); } //Get Bitrate for duration estimation myoffset += 1; // after picture rate // 18 following bytes are the bitrate /400 //read first 16 bytes Video->bitrate = GetSize(myoffset); // scale Video->bitrate <<= 2; byte lasttwo = GetByte(myoffset + 2); lasttwo >>= 6; Video->bitrate |= lasttwo; //Given bitrate and FileSize, compute an estimation of the duration. Video->duration = (FileSize*8.0) / (Video->bitrate*400); //////////// Begin changes marker mymark; while (true) { myoffset = FindNextMarker(myoffset, &mymark); if (mymark == 0xB8) break; switch (GetByte(myoffset + 3)) { case 0xB5 : ParseExtension(myoffset); break; case 0xB2 : #ifdef _DEBUG_ printf("user data start code found\n"); #endif ParseUserData(myoffset); break; } myoffset++; } ///////////// end changes //Okay let's save the video sequence header somewhere // find first GOP after video sequence header off_t header_end = FindNextMarker(myoffset, 0xB8); Video->first_gop_offset = header_end; // did we find header end or are we lost in cyberspace? if (header_end < 0){ //could not find first GOP if(Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: could not find first GOP after Video Sequence start [" _OFF_x " (decimal)]\n", FileName, header_start); return false; } // okay we have header boundaries, let's fill the appropriate // field. Video->video_header_size = header_end - header_start; Video->video_header = new byte[Video->video_header_size]; // fprintf(stderr,"philipp found header: 0x%qx 0x%qx\n", header_end, header_start); FSEEK(MpegFile, header_start, SEEK_SET); if(fread(Video->video_header, Video->video_header_size, 1, MpegFile) != 1) { // couldn't read video header if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Found video header but couldn't read it [" _OFF_x "-" _OFF_x "]\n", FileName, header_start, header_end); return false; } HasVideo = true; return true; } //Parses System header returns false on not system bool mpeg::ParseSystem() { BTRACK; off_t offset = 0; off_t PACKlength = 0; unsigned short packetsize; byte packettype; int found = 0; // the MPEG system file should start with // the video start sequence, if not exit. // TODO: give it a chance and seek a PACK elsewhere // try to skip any zeros at mpeg start (some begin with a BUNCH of zeros while(GetByte(offset)== 0x00) offset ++; //here we're on the first non null byte let's get back to leave two zeros (packet start code) offset -=2; if (offset != 0) { // we actually skipped some zeroes fprintf(stderr,"Skipped " _OFF_d " zeroes at start of file\n",offset); } if (!EnsureMPEG(offset, 0xBA)){ //this file does not begin with a pack! fprintf(stderr,"mmm, this file does not start with a pack, offset: " _OFF_d " \n",offset); fprintf(stderr,"use the desperate_mode switch as the first option -X to search for a header in the whole file!\n"); fprintf(stderr,"if you want to force the operation. May yield to an endless loop if no valid header is found!\n"); if (GetByte(offset+2) != 0x01) { fprintf(stderr,"Does not even begin with a 00 00 01 xx sequence!\n"); // does not even begin with a 00 00 01 xx sequence ! if (desperate_mode) { // philipp tries here to search further .... offset +=3; while (found == 0) { if (print_progress) { fprintf(stderr,"Searching for a mpeg signature:\n"); fprintf(stderr,"Searching for 0x00 at offset: "); } while (GetByte(offset) != 0x00) { if (print_progress) fprintf (stderr,"\b\b\b\b\b\b\b\b\b\b%10qd", offset); offset++; } if (print_progress) fprintf(stderr,"\nSearching for != 0x00 at offset: "); while (GetByte(offset) == 0x00) { offset++; if (print_progress) fprintf (stderr,"\b\b\b\b\b\b\b\b\b\b%10qd", offset); } // now from the beginning .. offset -=2; if (!EnsureMPEG(offset, 0xBA)){ if (print_progress) fprintf(stderr,"\nno success......\n"); offset += 3; } else { fprintf(stderr,"\nsuccess! at " _OFF_d " \n",offset); found = 1; fprintf(stderr,"I dont know which kind of crazy header you have put into this file!\n"); if (!preserve_header) { fprintf(stderr,"But I will assume this is ok. If you split or join this file, it will be discarded\n"); } else { fprintf(stderr,"But I will assume this is ok. And if you split this file, it will be inserted\n"); } fprintf(stderr,"Before any segment. This movie maybe wil not play with quicktime, use Videolan instead\n"); fprintf(stderr,"If you dont want this, please correct the file, so its start with a valid Pack!\n"); } } } if (found == 0) { fprintf(stderr,"\nNo success at all.\n"); return false; } } } // allocate necessary space System = new mpgtx_system; System->audio_system_header = 0; System->video_system_header = 0; System->first_video_packet = 0; // tries to find the two system packets and store them bool keep_going = true; marker mark = 0; // fprintf(stderr, "Philipp: Searching for system packets (audio, video).\n"); while (keep_going) { // fprintf(stderr,"philipp: offset4 ?: 0x%qx\n",offset); offset = FindNextMarker(offset, &mark); // fprintf(stderr,"philipp: offset5 ?: 0x%qx\n",offset); // if error exit if (offset == -1) { fprintf(stderr, "offset error (-1)\n"); break; } // if this is a Video or Audio packet we're done with system if ((mark == VideoPkt) || (mark == AudioPkt)) break; // if this is a padding packet if (mark == PaddingPkt) { offset += GetSize(offset + 4); continue; } // if this is a PACK if (mark==0xBA) { System->muxrate = ReadPACKMuxRate(offset + 4); //standard pack length offset += 12; continue; } //Hey no more guess... if (mark != SystemPkt) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Unhandled packet encountered (%x @" _OFF_x ") while seeking system headers\n", FileName, mark, offset); offset += 4; continue; } // it has to be a system packet // March 27 changed because of variable length PACK in mpeg 2 // are we lost? // fprintf(stderr,"philipp: offset3 ?: 0x%qx\n",offset); off_t startofpack = bdFindNextMarker(offset, 0xBA); // fprintf(stderr,"philipp: offset2 ?: 0x%qx\n",offset); if (startofpack !=-1){ //found a PACK before system packet, compute its size (mpeg1 != mpeg2) if ((GetByte(startofpack + 4) & 0xF0) == 0x20) { // standard mpeg1 pack PACKlength=12; } else { if ((GetByte(startofpack + 4) & 0xC0) == 0x40){ // new mpeg2 pack : 14 bytes + stuffing PACKlength = 14 + (GetByte(startofpack + 13) & 0x07); } else{ // wazup? fprintf(stderr, "Weird PACK encountered\n"); PACKlength = 12; } } } if ((startofpack == -1) || (startofpack + PACKlength != offset)) { // we're probably lost fprintf(stderr, "%s: System Packet not preceded by a PACK [" _OFF_x "] start of pack : " _OFF_x " PACKlength : " _OFF_x " I'll probably crash but I love risk\n", FileName, offset,startofpack,PACKlength); startofpack=offset; // keep going anyway return false; } // end of modif. ParseSystemPacket(offset,startofpack); packetsize = GetSize(offset + 4); // to size field packettype = GetByte(offset + 12); // to ccode field if (GetByte(offset + 15) == AudioPkt || GetByte(offset + 15) == VideoPkt) { // system packet with both audio and vid infos packettype = VideoPkt; // since video is mandatory } if (packettype == AudioPkt){ if (System->audio_system_header != 0){ if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Warning two or more audio sys header encountered [" _OFF_x "]\n", FileName, offset); delete[] System->audio_system_header; } System->audio_system_header_length = PACKlength + 4 + 2 + packetsize; System->audio_system_header = new byte [System->audio_system_header_length]; FSEEK(MpegFile, offset-PACKlength, SEEK_SET); fread( System->audio_system_header, System->audio_system_header_length, 1, MpegFile); } else if (packettype == VideoPkt) { if (System->video_system_header != 0) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: Warning two or more video sys header encountered [" _OFF_x "]\n", FileName, offset); delete[] System->video_system_header; } // does this video packet begin System->video_system_header_length = PACKlength + 4 + 2 + packetsize; System->video_system_header = new byte [System->video_system_header_length]; // keep track of the initial timestamp if (PACKlength == 12) { #ifdef _DEBUG_ fprintf(stderr,"Now read mpeg initial_TS at [" _OFF_x "] \n",offset - PACKlength); fprintf(stderr,"Should all TS be printed? [n/y]:"); if (getchar() == 'y') print_all_ts(0xba); while(getchar() != '\n') ; #endif System->initial_TS = ReadTS(offset - PACKlength); mpeg2found = 0; } else { // off_t firstmpeg2gop = FindNextMarker(1, 0xB8); #ifdef _DEBUG_ fprintf(stderr,"Now read mpeg2 initial_TS at [" _OFF_x "] \n",offset - PACKlength); fprintf(stderr,"Should all TS be printed? [n/y]:"); if (getchar() == 'y') print_all_ts(0xba); while(getchar() != '\n') ; #endif mpeg2found = 1; // System->initial_TS = ReadTSMpeg2(firstmpeg2gop + 4); System->initial_TS = ReadTSMpeg2(offset - PACKlength); } FSEEK(MpegFile, (offset - PACKlength), SEEK_SET); fread( System->video_system_header, System->video_system_header_length, 1, MpegFile); } else { if (Verboseness==mpeg_VERBOSE) fprintf(stderr, "%s: Unknown system packet %x [" _OFF_x "]\n", FileName, packettype, offset); } offset += 4; } //okay this is a miracle but we have what we wanted here. // hey wait! are we really okay? if (!System->video_system_header) { //GOSH! we don't have video here! if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: didn't find any video system header in this mpeg system file\n", FileName); // return false; fprintf(stderr, "warning: couldn't find any valid system header. I'm continuing anyway\n"); } // let's go on and find audio and video infos // Video! offset = FindNextMarker(0, 0xB3); // fprintf(stderr,"philipp: offset1 ?: 0x%qx\n",offset); if (offset == -1) { //couldn't find any valid video if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: didn't find any video sequence header in this mpeg system file\n", FileName); return false; } // mkay, we have the video sequence header if (!ParseVideo(offset)) { return false; } off_t xB3_offset = offset; // now get the pack and the packet header just before the video sequence offset = bdFindNextMarker(offset, 0xBA); if (offset == -1) { //couldn't find any PACK before... if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: didn't find any PACK before video sequence\n", FileName); return false; } // May 2, PACK don't necessarily precede video sequence! off_t start_of_vid_packet = bdFindNextMarker(xB3_offset, 0xE0); // start of packet off_t offset2 = bdFindNextMarker(start_of_vid_packet-1, &mark); if (offset != offset2) { // the packet that precedes video sequence is not a PACK offset = start_of_vid_packet; } else { // end May 2 // March 27 compute pack length if ((GetByte(offset + 4) & 0xF0) == 0x20) { //standard mpeg1 pack PACKlength = 12; } else { if ((GetByte(offset + 4) & 0xC0) == 0x40) { //new mpeg2 pack : 14 bytes + stuffing PACKlength = 14 + (GetByte(offset + 13) & 0x07); } else { //wazup? fprintf(stderr,"Weird PACK encountered\n"); PACKlength = 12; } } // end March 27 // May 2 } //end May 2 // okay let's save this... System->first_video_packet = new byte[xB3_offset-offset]; System->first_video_packet_length = xB3_offset-offset; readHeader(MpegFile,offset,1); // save this if needed for later FSEEK(MpegFile,offset,SEEK_SET); fread(System->first_video_packet, 1, xB3_offset-offset, MpegFile); // Now look for an audio packet if necessary HasAudio = false; offset = FindNextMarker(0, AudioPkt); if ((offset == -1) || (offset > FileSize - 15)) { if (Verboseness == mpeg_VERBOSE) fprintf(stderr, "%s: didn't find any audio packet in this mpeg system file\n",FileName); } else { // we assume that we are on the first audio packet... offset = SkipPacketHeader(offset); if (!ParseAudio(offset)) { //mmm audio packet doesn't begin with FFF while ((offsetinitial_TS; if (HasVideo) Video->duration = duration; if (HasAudio) Audio->duration = duration; //okay okay this is redundant return true; } // print mpeg infos on stdout void mpeg::PrintInfos() { BTRACK; char HMS[30]; if (MpegType == mpeg_AUDIO){ SecsToHMS(HMS, Audio->duration); printf("%s\n", FileName); if (Audio->mpeg_ver != 3) printf(" Audio : Mpeg %d layer %d\n", Audio->mpeg_ver,Audio->layer); else printf(" Audio : Mpeg 2.5 (rare) layer %d\n", Audio->layer); printf(" Estimated Duration: %s\n", HMS); if (Audio->bitrate) { printf(" %d kbps %d Hz\n", Audio->bitrate,Audio->sampling_rate); printf(" Frame size: %d bytes\n", Audio->frame_length); } else { printf(" free bitrate %d Hz (this file is currently unsplitable)\n",Audio->sampling_rate); } switch (Audio->mode) { case 0: printf(" Stereo,"); break; case 1: printf(" Joint Stereo: "); if (Audio->layer==1 || Audio->layer==2) { switch (Audio->modext) { case 0: printf("(Intensity stereo on bands 4-31/32)\n"); break; case 1: printf("(Intensity stereo on bands 8-31/32)\n"); break; case 2: printf("(Intensity stereo on bands 12-31/32)\n"); break; case 3: printf("(Intensity stereo on bands 16-31/32)\n"); break; } } else { // mp3 switch (Audio->modext){ case 0: printf("(Intensity stereo off, M/S stereo off)\n"); break; case 1: printf("(Intensity stereo on, M/S stereo off)\n"); break; case 2: printf("(Intensity stereo off, M/S stereo on)\n"); break; case 3: printf("(Intensity stereo on, M/S stereo on)\n"); break; } } break; case 2: printf(" Dual Channel,"); break; case 3: printf(" Mono,"); break; } switch (Audio->emphasis_index){ case 0: printf(" No emphasis,"); break; case 1: printf(" Emphasis: 50/15 microsecs,"); break; case 2: printf(" Emphasis Unknown,"); break; case 3: printf(" Emphasis CCITT J 17,"); break; } if (Audio->copyright) printf(" (c),"); if (Audio->original) printf(" original\n"); else printf(" copy\n"); if (Audio->tag) { //print id3v1 tag---------------- if (Audio->tag->comment[28] == 0) printf (" ID3 v1.1 tag\n ----------------\n"); else printf(" ID3 v1.0 tag\n ----------------\n"); if (Audio->tag->name[0]) printf(" title : %.30s\n", Audio->tag->name); if (Audio->tag->artist[0]) printf(" artist : %.30s\n", Audio->tag->artist); if (Audio->tag->album[0]) { printf(" album : %.30s\n", Audio->tag->album); if(Audio->tag->comment[28]==0) printf(" track : %d\n", Audio->tag->comment[29]); } if (Audio->tag->year[0]) printf(" year : %.4s\n", Audio->tag->year); if (Audio->tag->comment[0]) printf(" comment : %.30s\n", Audio->tag->comment); if (Audio->tag->genre < MAX_ID3_GENRE) printf(" genre : %s\n", genre[Audio->tag->genre]); printf(" ----------------\n"); } if (start_with_id3) PrintID3(); printf("\n"); return; } if (MpegType == mpeg_VIDEO) { SecsToHMS(HMS, Video->duration); printf("%s\n", FileName); printf(" Mpeg %d Video File\n Estimated Duration: %s\n", mpeg_version, HMS); switch(Video->aspect_ratio) { case 0: printf(" Invalid aspect ratio (forbidden)\n"); break; case 1: printf(" Aspect ratio 1/1 (VGA)\n"); break; case 2: printf(" Aspect ratio 4/3 (TV)\n"); break; case 3: printf(" Aspect ratio 16/9 (large TV)\n"); break; case 4: printf(" Aspect ratio 2.21/1 (Cinema)\n"); break; #ifdef _DEBUG_ default: printf(" Invalid Aspect ratio (reserved)\n"); #endif } if (SExt) { if (SExt->progressive) printf(" Not interlaced, chroma format: "); else printf(" Interlaced, chroma format: "); switch (SExt->chroma_format) { case 1 : printf ("4:2:0\n"); break; case 2 : printf ("4:2:2\n"); break; case 3 : printf ("4:4:4\n"); break; } } if (DExt){ switch (DExt->video_format) { case 0 : printf (" Video Format: Component\n"); break; case 1 : printf (" Video Format: PAL\n"); break; case 2 : printf (" Video Format: NTSC\n"); break; case 3 : printf (" Video Format: SECAM\n"); break; case 4 : printf (" Video Format: MAC\n"); break; case 5 : printf (" Video Format: Unspecified\n"); break; } if ( (DExt->h_display_size != Video->hsize) || (DExt->v_display_size != Video->vsize)) printf(" Display Size [%ld x %ld]\n", DExt->h_display_size, DExt->v_display_size); } printf(" Size [%ld x %ld] %0.2f fps %.2f Mbps\n", Video->hsize,Video->vsize, Video->frame_rate, Video->bitrate/2500.0); if (UData) printf("\nUser Data:\n------------\n%s------------\n\n",UData->ud); return; } if (MpegType == mpeg_SYSTEM ) { if (composite) { printf(" Mpeg System File [%d Video/ %d Audio]\n", n_video,n_audio); } else { if (HasVideo) { SecsToHMS(HMS, Video->duration); printf("%s\n", FileName); if (mpeg_version == 1) { printf(" Mpeg 1 System File [Video"); } else { // TODO: [es] What is this if-clause for? if (mpeg_version!=2); printf(" Mpeg 2 Program Stream File [Video"); } if (HasAudio) printf("/Audio]\n"); else printf("]\n"); printf(" Muxrate : %.2f Mbps\n", (System->muxrate * 8.0) / 1000000); printf(" Estimated Duration: %s\n", HMS); if (print_progress) { // do time stamps continuing increase? int tlbreaks = 0; printf(" Checking all time stamps (This may take a while.) ...\n"); if ( (tlbreaks = CheckTimeline(0xBA)) ) { printf(" Time line is interupted at %d times.\n",tlbreaks); printf(" That means at these points the time stamp is earlier than the previous one.\n"); printf(" You may have problems in joining and splitting this file, sorry.\n"); } else printf(" Time line seems to be ok.\n"); } switch (Video->aspect_ratio) { case 0: printf(" Invalid aspect ratio (forbidden)\n"); break; case 1: printf(" Aspect ratio 1/1 (VGA)\n"); break; case 2: printf(" Aspect ratio 4/3 (TV)\n"); break; case 3: printf(" Aspect ratio 16/9 (large TV)\n"); break; case 4: printf(" Aspect ratio 2.21/1 (Cinema)\n"); break; #ifdef _DEBUG_ default: printf(" Invalid Aspect ratio (reserved)\n"); #endif } if (SExt){ if (SExt->progressive) printf(" Not interlaced, chroma format: "); else printf(" Interlaced, chroma format: "); switch (SExt->chroma_format){ case 1 : printf ("4:2:0\n");break; case 2 : printf ("4:2:2\n");break; case 3 : printf ("4:4:4\n");break; } } if (DExt){ switch(DExt->video_format){ case 0 : printf (" Video Format: Component\n");break; case 1 : printf (" Video Format: PAL\n");break; case 2 : printf (" Video Format: NTSC\n");break; case 3 : printf (" Video Format: SECAM\n");break; case 4 : printf (" Video Format: MAC\n");break; case 5 : printf (" Video Format: Unspecified\n");break; } if ((DExt->h_display_size != Video->hsize)|| (DExt->v_display_size != Video->vsize)) printf(" Display Size [%ld x %ld]\n", DExt->h_display_size,DExt->v_display_size); } printf(" Size [%ld x %ld] %0.2f fps %.2f Mbps\n", Video->hsize,Video->vsize, Video->frame_rate, (Video->bitrate/2500.0)); } if(UData) printf("\nUser Data:\n------------\n%s------------\n\n",UData->ud); if (HasAudio){ if (Audio->mpeg_ver !=3) printf(" Audio : Mpeg %d layer %d\n",Audio->mpeg_ver,Audio->layer); else printf(" Audio : Mpeg 2.5 (rare) layer %d\n",Audio->layer); if (Audio->bitrate) printf(" %d kbps %d Hz\n",Audio->bitrate,Audio->sampling_rate); else printf(" free bitrate %d Hz\n",Audio->sampling_rate); switch (Audio->mode){ case 0: printf(" Stereo,"); break; case 1: printf(" Joint Stereo: "); if (Audio->layer==1 || Audio->layer==2){ switch (Audio->modext){ case 0: printf("(Intensity stereo on bands 4-31/32)\n"); break; case 1: printf("(Intensity stereo on bands 8-31/32)\n"); break; case 2: printf("(Intensity stereo on bands 12-31/32)\n"); break; case 3: printf("(Intensity stereo on bands 16-31/32)\n"); break; } } else { //mp3 switch (Audio->modext){ case 0: printf("(Intensity stereo off, M/S stereo off)\n"); break; case 1: printf("(Intensity stereo on, M/S stereo off)\n"); break; case 2: printf("(Intensity stereo off, M/S stereo on)\n"); break; case 3: printf("(Intensity stereo on, M/S stereo on)\n"); break; } } break; case 2: printf(" Dual Channel,"); break; case 3: printf(" Mono,"); break; } switch (Audio->emphasis_index){ case 0: printf(" No emphasis\n"); break; case 1: printf(" Emphasis: 50/15 microsecs\n"); break; case 2: printf(" Emphasis Unknown\n"); break; case 3: printf(" Emphasis CCITT J 17\n"); break; } } } return; } if (MpegType== mpeg_TRANSPORT){ printf("%s\n",FileName); if (!Transport) { fprintf(stdout," Invalid MPEG 2 Transport Stream\n"); return; } Transport->PrintInfos(); return; } printf("%s can not be handled by this program\n",FileName); return; } //PrintInfos // convert a time in second to HH:mm:ss notation // void mpeg::SecsToHMS(char* HMS, float duration){ BTRACK; byte hours = (byte)(duration / 3600); byte mins = (byte)((duration / 60) - (hours * 60)); float secs = duration - 60 * mins - 3600 * hours; if (hours != 0) { sprintf (HMS,"%02d:%02d:%05.2fs",hours,mins,secs); return; } if (mins != 0) { sprintf(HMS,"%02d:%05.2fs",mins,secs); return; } sprintf(HMS,"%05.2fs",secs); } // find next 0x 00 00 01 xx sequence, returns offset or -1 on err // off_t mpeg::FindNextMarker(off_t from){ BTRACK; off_t offset; for (offset = from; offset < (FileSize - 4); offset++) { if ( (GetByte(offset + 0) == 0x00) && (GetByte(offset + 1) == 0x00) && (GetByte(offset + 2) == 0x01)) { RTRACK; return offset; } } RTRACK; return -1; } // find next 0x 00 00 01 xx sequence, returns offset or -1 on err and // change mark to xx // off_t mpeg::FindNextMarker(off_t from, marker* mark){ BTRACK; off_t offset = FindNextMarker(from); if (offset >= 0) { *mark = GetByte(offset + 3); RTRACK; return offset; } else { RTRACK; return -1; } } // find next 0X00 00 01 mark // off_t mpeg::FindNextMarker(off_t from, marker mark){ BTRACK; off_t offset = from; while(offset >= 0){ offset = FindNextMarker(offset); if (offset == -1) { RTRACK; return -1; } if (EnsureMPEG(offset, mark)) { RTRACK; return offset; } else offset++; } //shouldn't be here RTRACK; return -1; } // same as above but optimized for backward search // off_t mpeg::bdFindNextMarker(off_t from, marker mark) { BTRACK; off_t offset; for( offset = from; offset >= 0; offset--) { if( (bdGetByte(offset) == 0x00) && (bdGetByte(offset+1) == 0x00) && (bdGetByte(offset+2) == 0x01) && (bdGetByte(offset+3) == mark)) { RTRACK; return offset; } } RTRACK; return -1; } off_t mpeg::bdFindNextMarker(off_t from, marker* mark) { BTRACK; off_t offset; for (offset = from; offset >= 0; offset--) { if ( (bdGetByte(offset) ==0x00) && (bdGetByte(offset+1)==0x00) && (bdGetByte(offset+2)==0x01)) { *mark=bdGetByte(offset+3); RTRACK; return offset; } } RTRACK; return -1; } // read Time Stamp at given offset // NOTE: The guys at MPEG are really mad. // look at what we have to do to get a timestamp :/ double mpeg::ReadTS(off_t offset) { BTRACK; byte highbit; unsigned long low4Bytes; double TS; #ifdef _DEBUG_ // fprintf(stderr,"Offset: [" _OFF_x "] The bytes...: %2x %2x %2x %2x %2x\n",offset,GetByte(offset + 0),GetByte(offset + 1),GetByte(offset + 2),GetByte(offset + 3),GetByte(offset + 4) ); #endif highbit = (GetByte(offset) >> 3) & 0x01; low4Bytes = ((GetByte(offset) >> 1) & 0x03) << 30; low4Bytes |= GetByte(offset + 1) << 22; low4Bytes |= (GetByte(offset + 2) >> 1) << 15; low4Bytes |= GetByte(offset + 3) << 7; low4Bytes |= GetByte(offset + 4) >> 1; #define FLOAT_0x10000 (double)((unsigned long)1 << 16) #define STD_SYSTEM_CLOCK_FREQ (unsigned long)90000 TS = (double)(highbit * FLOAT_0x10000 * FLOAT_0x10000); TS += (double)(low4Bytes); TS /= (double)(STD_SYSTEM_CLOCK_FREQ); #ifdef _DEBUG_ // printf("read TS : %lf, base : 0x%d,%032lx\n",TS,highbit,low4Bytes); #endif return TS; } double mpeg::ReadTSMpeg2(off_t offset){ BTRACK; byte highbit; unsigned long low4Bytes; unsigned long sys_clock_ref; double TS; #ifdef _DEBUG_ // fprintf(stderr,"Offset: [" _OFF_x "] The bytes...: %2x %2x %2x %2x %2x %2x",offset,GetByte(offset + 0),GetByte(offset + 1),GetByte(offset + 2),GetByte(offset + 3),GetByte(offset + 4),GetByte(offset + 5) ); #endif highbit = (GetByte(offset)&0x20)>>5; low4Bytes = ((GetByte(offset) & 0x18) >> 3) << 30; low4Bytes |= (GetByte(offset) & 0x03) << 28; low4Bytes |= GetByte(offset + 1 ) << 20; low4Bytes |= (GetByte(offset + 2 ) & 0xF8) << 12; low4Bytes |= (GetByte(offset + 2 ) & 0x03) << 13; low4Bytes |= GetByte(offset + 3 ) << 5; low4Bytes |= (GetByte(offset + 4 )) >> 3; sys_clock_ref=(GetByte(offset + 4) & 0x3) << 7; sys_clock_ref|=(GetByte(offset + 5) >> 1); TS = (double)(highbit * FLOAT_0x10000 * FLOAT_0x10000); TS += (double)(low4Bytes); if (sys_clock_ref ==0) TS /= (double)(STD_SYSTEM_CLOCK_FREQ); else { // this is what I understood... CHECK // if not zero, then we have a 27 MHz accuracy with a max of 27 MHz // so clockfreq might well be 27MHz / sys_clock_ref // nonsense: TS /= (double)(27000000 / sys_clock_ref); TS /= (double)(STD_SYSTEM_CLOCK_FREQ); } //debug #ifdef _DEBUG_ // printf("read TS2 : %lf, base : 0x%d,%032lx ref : %016lx\n",TS,highbit,low4Bytes,sys_clock_ref); #endif return TS; } off_t mpeg::SkipPacketHeader(off_t myoffset){ BTRACK; byte mybyte; if (mpeg_version == 1) { // skip startcode and packet size myoffset += 6; //remove stuffing bytes mybyte = GetByte(myoffset); while (mybyte & 0x80) mybyte = GetByte(++myoffset); if ((mybyte & 0xC0) == 0x40) // next two bits are 01 myoffset += 2; mybyte=GetByte(myoffset); if ((mybyte & 0xF0) == 0x20) myoffset += 5; else if ((mybyte & 0xF0) == 0x30) myoffset += 10; else myoffset++; return myoffset; } else if (mpeg_version==2) { // this is a PES, easyer // offset + 9 is the header length (-9) return (myoffset + 9 +GetByte(myoffset + 8)); } else return (myoffset + 10); } bool mpeg::ParseSystemPacket(off_t startofpacket, off_t startofpack){ BTRACK; int size = Read2Bytes(startofpacket + 4); int i; byte code; size -= 6; //TODO check if there's already a system packet if ((size%3) != 0) return false; #ifdef _DEBUG_ else printf("%d streams found\n", size/3); #endif for (i=0; i < size/3; i++) { code = GetByte(startofpacket + 12 + i * 3); #ifdef _DEBUG_ printf("%02x ",code); #endif if ((code&0xF0)==0xC0) n_audio++; else if ((code&0xF0)==0xE0 || (code & 0xF0)==0xD0) n_video++; } if (n_audio) { HasAudio = true; if (n_audio > 1) { composite = true; editable = false; } } if (n_video) { HasVideo = true; if (n_video > 1){ composite = true; editable = false; } } #ifdef _DEBUG_ printf("\n audio %d video %d \n",n_audio,n_video); #endif return true; } void mpeg::ParseFramesInGOP(off_t offset){ BTRACK; int pict_ref; int pict_type; char type; marker mark; off_t off = offset + 1; off = FindNextMarker(off , &mark); while (off > 0) { switch (mark) { case 0xB8 : printf("GOP ends at [" _OFF_x "]\n",off); return; case 0x00 : //picture pict_ref=(GetByte(off+4)<<2); pict_ref |= ((GetByte(off+5)&0xC0)>>6); pict_type = ((GetByte(off+5)&0x38)>>3); switch (pict_type){ case 1: type ='I';break; case 2: type ='P';break; case 3: type ='B';break; default:type ='U';break; } printf("\n\n%c (%.2d) [" _OFF_x "]\n", type, pict_ref, off); break; case 0xba: printf(" PACK [" _OFF_x "]\n", off); break; case VideoPkt: printf(" Video [" _OFF_x "]\n", off); break; case AudioPkt: printf(" Audio [" _OFF_x "]\n", off); break; case PaddingPkt: printf(" Padding [" _OFF_x "]\n", off); break; } off++; off=FindNextMarker(off,&mark); } } bool mpeg::ParseExtension(off_t myoffset) { BTRACK; myoffset+=4; switch (GetByte(myoffset) >> 4) { case 1: return ParseSequenceExt(myoffset); case 2: return ParseSequenceDisplayExt(myoffset); } return false; } bool mpeg::ParseUserData(off_t myoffset) { BTRACK; off_t end = FindNextMarker(myoffset + 1); off_t i; bool allprintable=true; byte car; off_t mysize = end - myoffset - 4; if (mysize <= 0) return false; for (i = myoffset+4 ; i < end; i++) { car=GetByte(i); if ((car < 0x20) && (car != 0x0A) && (car != 0x0D)) { allprintable = false; break; } } if (allprintable) { if (!UData) { UData = new user_data; UData->ud = new char[1]; UData->ud[0] = 0; UData->ud_length = 1; } char* temp = new char[mysize+UData->ud_length+1]; //1 is for \n //copy all until \0 for ( i=0; i < UData->ud_length-1; i++){ temp[i] = UData->ud[i]; } //okay now copy the new string for ( i=0; i < mysize; i++){ temp[i + UData->ud_length -1] = GetByte(myoffset + 4 + i); } temp[UData->ud_length- 1 + mysize] = '\n'; temp[UData->ud_length + mysize] = '\0'; UData->ud_length += mysize + 1; delete[] UData->ud; UData->ud = temp; } return true; } bool mpeg::ParseSequenceExt(off_t myoffset) { BTRACK; unsigned long hsize; unsigned long vsize; unsigned long bitrate; // We are an mpeg 2 file mpeg_version=2; if (!SExt) SExt = new sequence_ext; //13TH if (GetByte(myoffset + 1) & 0x08) SExt->progressive = true; SExt->chroma_format = (GetByte(myoffset + 1) & 0x06) >> 1; hsize = (GetByte(myoffset + 1) & 0x01) << 1; hsize |= (GetByte(myoffset + 2) & 80) >> 7; hsize <<= 12; if (!Video) return false; Video->hsize |= hsize; vsize = (GetByte(myoffset+2)&0x60) << 7; Video->vsize |= vsize; bitrate = (GetByte(myoffset + 2) & 0x1F) << 7; bitrate |= (GetByte(myoffset+3)&0xFE) >> 1; bitrate <<= 18; Video->bitrate |= bitrate; if (GetByte(myoffset + 5) & 0x80) SExt->low_delay = true; else SExt->low_delay = false; byte frate_n = (GetByte(myoffset + 5) & 0x60) >> 5; byte frate_d = (GetByte(myoffset + 5) & 0x1F); frate_n++; frate_d++; Video->frame_rate = (Video->frame_rate * frate_n) / frate_d; return true; } bool mpeg::ParseSequenceDisplayExt(off_t myoffset){ BTRACK; if (!DExt) DExt = new display_ext; DExt->video_format = (GetByte(myoffset) & 0x0E) >> 1; if (GetByte(myoffset) & 0x01) { // three bytes to read DExt->colour_prim = GetByte(myoffset + 1); DExt->transfer_char = GetByte(myoffset + 2); DExt->matrix_coef = GetByte(myoffset + 3); myoffset += 3; } else { DExt->colour_prim = 0; DExt->transfer_char = 0; DExt->matrix_coef = 0; } DExt->h_display_size = GetByte(myoffset + 1) << 6; DExt->h_display_size |= (GetByte(myoffset + 2) & 0xFC) >> 2; DExt->v_display_size = (GetByte(myoffset + 2) & 0x01) << 13; DExt->v_display_size |= GetByte(myoffset + 3) << 5; DExt->v_display_size |= (GetByte(myoffset + 4) & 0xF8) >> 3; return true; } bool mpeg::ParseRIFF(){ BTRACK; // RIFF if ( GetByte(0) != 'R' || GetByte(1) != 'I' || GetByte(2) != 'F' || GetByte(3) != 'F') return false; // 23 march 2001 != changed to == in the following // Thank to Volker Moell // WAVE if ( GetByte(8) == 'W' || GetByte(9) == 'A' || GetByte(10) == 'V' || GetByte(11) =='E') { fprintf(stderr,"%s is a Wave file\n", FileName); return false; } // 'AVI ' if ( GetByte(8)=='A' || GetByte(9)=='V' || GetByte(10) == 'I' || GetByte(11) ==' ') { fprintf(stderr,"%s is an AVI file\n",FileName); } return false; } off_t mpeg::FindMatchingAudio(off_t myoffset){ BTRACK; for( ; myoffset < FileSize - 5; myoffset++) { if (GetByte(myoffset) == 0xFF) // maybe an audio sync if (MatchAudio(myoffset)) return myoffset; } if (myoffset >= FileSize) return FileSize; return -1; } off_t mpeg::bdFindMatchingAudio(off_t myoffset){ BTRACK; for( ; myoffset >= Audio->first_frame_offset; myoffset--) { if (bdGetByte(myoffset) == 0xFF) if (MatchAudio(myoffset)) return myoffset; } return -1; } bool mpeg::MatchAudio(off_t myoffset){ BTRACK; // do we have audio anyway? if (!Audio) return false; //does this start as an mpeg audio frame? if (GetByte(myoffset) != 0xFF || (GetByte(myoffset + 1) & 0xE0) != 0xE0) return false; // are version compatibles? int version = ((GetByte(myoffset + 1)) & 0x18) >> 3; switch (Audio->mpeg_ver){ case 1: if (version != 3) return false; break; case 2: if (version != 2) return false; break; case 3: if (version != 0) return false; break; default: return false; break; } //are layers compatible? int layer = (GetByte(myoffset+1)&0x06)>>1; switch (Audio->layer) { case 1: if (layer != 3) return false; break; case 2: if (layer != 2) return false; break; case 3: if (layer != 1) return false; break; default: return false; break; } //are mode compatibles? int mode = (GetByte(myoffset + 3) & 0xC0) >> 6; if (mode != Audio->mode) return false; return true; } long mpeg::ReadPACKMuxRate(off_t offset) { BTRACK; // at start of a PACK long muxrate = 0; if ((GetByte(offset) & 0xC0) == 0x40) { // mpeg2 muxrate = GetByte(offset + 6) << 14; muxrate |= GetByte(offset + 7) << 6; muxrate |= GetByte(offset + 8) >> 2; } else { //maybe mpeg1 if ((GetByte(offset)&0xF0)!=0x20) fprintf(stderr, "weird pack header while parsing muxrate (offset " _OFF_x ")\n", offset); muxrate = (GetByte(offset + 5) & 0x7F) << 15; muxrate |= (GetByte(offset + 6) << 7); muxrate |= (GetByte(offset + 7) >> 1); } muxrate *= 50; return muxrate; } void mpeg::ParsePAT(off_t offset){ BTRACK; // offset++; //skip the first byte int pnum,ppid,i; int n_progs; if (GetByte(offset + 1) != 0x00) { #ifdef _DEBUG_ printf("wrong table_id in PAT\n"); #endif return; } // next 4 bits are 10XX int length = Read12bitLength(offset + 2); #ifdef _DEBUG_ printf("PAT: %d programs in %d bytes described\n",(length-9)/4,length-9); #endif if ( ( (length - 9)%4) != 0) { #ifdef _DEBUG_ printf("malformed PAT \n"); #endif return; } n_progs=(length-9)/4; if (Transport->PMT_PIDs) delete [] Transport->PMT_PIDs; Transport->PMT_PIDs = new PID [n_progs]; Transport->n_progs = n_progs; Transport->delete_programs(); Transport->programs = new program[n_progs]; for ( i=0; i < n_progs; i++){ Transport->programs[i].prog_num = -1; Transport->programs[i].nstreams = -1; Transport->programs[i].TStreams = 0; } for ( i=0; i< n_progs; i++){ pnum = Read2Bytes(offset + 9 + (i*4)); ppid = ReadPID(offset + 11 + (i*4)); if (pnum == 0) { Transport->network_PID = ppid; Transport->n_progs--; } else { Transport->PMT_PIDs[Transport->n_PMT_PIDs++] = ppid; } } } long mpeg::Read12bitLength(off_t offset){ BTRACK; // length must be xxxxAAAA AAAAAAAA return (((GetByte(offset) & 0x0F) << 8) | GetByte(offset + 1)); } long mpeg::Read2Bytes(off_t offset){ BTRACK; return((GetByte(offset) << 8) | GetByte(offset + 1)); } long mpeg::ReadPID(off_t offset){ BTRACK; // PID must be xxxAAAAA AAAAAAAA return (((GetByte(offset) & 0x1F) << 8) | GetByte(offset + 1)); } void mpeg::ParseCAT(off_t offset){ BTRACK; // conditional access table if(GetByte(offset + 1) != 0x01) { fprintf(stderr,"malformed CAT\n"); return; } // int length=Read12bitLength(offset+2); // long desc_offset=ParseDescriptor(offset+9); // while (desc_offset < offset+length+4-4){ // desc_offset=ParseDescriptor(desc_offset); // } } void mpeg::ParsePMT(off_t offset){ BTRACK; off_t i, desc_offset; int prog_index=0; if (GetByte(offset + 1) != 0x02) { #ifdef _DEBUG_ printf("malformed PMT\n"); #endif return; } // next 4 bits are 10XX int length = Read12bitLength(offset + 2); #ifdef _DEBUG_ printf("PMT length : %d\n",length); #endif int pnum = Read2Bytes(offset + 4); #ifdef _DEBUG_ printf("This PMT describes Program N° %d\n",pnum); #endif // check if the program is already here for (i = 0; i < Transport->n_progs; i++) { if (Transport->programs[i].prog_num == pnum) { // already have info on this! fprintf(stderr, "Warning, prog num %d redefined ! \n", pnum); if (Transport->programs[i].TStreams != 0) Transport->delete_ES(Transport->programs[i].TStreams); Transport->programs[i].TStreams = 0; } } // fetch the first empty index for (i = 0; i < Transport->n_progs; i++){ if (Transport->programs[i].prog_num == -1) { prog_index = i; } } if (prog_index >= Transport->n_progs) { fprintf(stderr,"Error : no room for program %d\n", pnum); return; } program* temp = &(Transport->programs[prog_index]); temp->prog_num = pnum; temp->nstreams = 0; // temp->next=Transport->programs; // Transport->programs=temp; // Transport->n_progs++; // temp->prog_num=pnum; #ifdef _DEBUG_ int pcrpid = ReadPID(offset + 9); if (pcrpid != 0x1FFF) printf("PCR of this program is in PID %d\n", pcrpid); #endif int infolen = Read12bitLength(offset + 11); #ifdef _DEBUG_ printf("info length : %d\n", infolen); #endif //parsing descriptors if (infolen > 0) { desc_offset = ParseDescriptor(offset + 12, &(temp->descs)); while (desc_offset < (offset + 12 + infolen)){ desc_offset = ParseDescriptor(desc_offset, &(temp->descs)); } } desc_offset = (offset + 13 + infolen); off_t max_offset = offset + 4 + length - 4; //-4 is for CRC size_t desc_size; int ES_type; int ES_pid; int ES_infolen; for ( i = desc_offset;instreams++; EStream* tempES = new EStream; tempES->next = temp->TStreams; temp->TStreams = tempES; tempES->pid = ES_pid; tempES->type = ES_type; tempES->demuxFile = 0; tempES->demuxFileOk = true; /* switch(ES_type){ case 0 : printf("reserved"); break; case 1: printf("MPEG 1 video");break; case 2: printf("MPEG 2 video");break; case 3: printf("MPEG 1 audio");break; case 4: printf("MPEG 2 audio");break; case 5: printf("MPEG 2 private section");break; case 6: printf("MPEG 2 PES with private data");break; case 7: printf("MHEG");break; case 8: printf("DSM_CC");break; case 9: printf("Private data");break; default: if (ES_type <0x80) printf("MPEG 2 reserved"); else printf("User Private data"); break; } */ /* printf(" info@%4lx (%d bytes) PID [%d]\n",i+5,ES_infolen,ES_pid);*/ if (ES_infolen > 0) { desc_offset = ParseDescriptor(i + 5, &tempES->descs); while (desc_offset < (i + 5 + ES_infolen)) desc_offset = ParseDescriptor(desc_offset, &tempES->descs); } } } off_t mpeg::ParseDescriptor(off_t offset,mpeg_descriptors* target){ BTRACK; int tag = GetByte(offset); int length = GetByte(offset+1); #ifdef _DEBUG_ printf("Descriptor %d length %d\n",tag,length); #endif bool handled = false; switch (tag) { case 0: case 1: //printf("reserved descriptor\n"); break; case 2: //printf("video stream descriptor : video version %d\n",GetByte(offset+2)); target->video_coding_version = GetByte(offset + 2); handled = true; break; case 3: //printf("audio stream descriptor : audio version %d\n",GetByte(offset+2)); target->audio_coding_version = GetByte(offset + 2); handled = true; break; case 4: //printf("hierarchy descriptor\n"); break; case 5: //printf("registration descriptor\n"); break; case 6: //printf("data stream alignment descriptor\n"); break; case 7: //printf("target background grid descriptor\n"); break; case 8: //printf("video window descriptor\n"); break; case 9: DescCA(offset, target); handled = true; break; case 10:DescLang(offset, target); handled = true; break; case 11: //printf("System clock descriptor\n"); break; case 12: //printf("multiplex buffer utilization descriptor\n"); break; case 13: //printf("copyright descriptor\n"); target->copyright = true; break; default : #ifdef _DEBUG_ if (tag < 63) printf("MPEG 2 reserved descriptor\n"); else printf("User Private descriptor\n"); #endif break; } if (!handled) { /* for (int i=0;in_unhandled_desc++; } #ifdef _DEBUG_ printf("\n"); #endif return (offset + length + 2); } void mpeg::DescCA(off_t offset, mpeg_descriptors* target){ BTRACK; #ifdef _DEBUG_ printf("Conditional Access descriptor\n"); #endif // int length=GetByte(offset+1); int CAsysID = Read2Bytes(offset + 2); PID CA_PID = ReadPID(offset + 4); target->CA = CAsysID; target->CA_PID = CA_PID; /* printf("Conditional access ID : %d related PID is %d\n",CAsysID,CA_PID); if (length>4){ printf("private data:\n"); byte thebyte; for (long i=offset+6;i=0x20) printf("%02x ",thebyte); else printf("%02x ",thebyte); } printf("\n"); for (long i=offset+6;i=0x20) printf(" %c ",thebyte); else printf(" "); } printf("\n"); } */ } void mpeg::DescLang(off_t offset, mpeg_descriptors* target){ BTRACK; int i; #ifdef _DEBUG_ printf("Language descriptor (untested)\n"); #endif int length = GetByte(offset + 1); int audio_type = GetByte(offset + 1 + length); target->lang_audio_type=audio_type; if (length > 1) { // there are languages inside length--; //without the trailing audio_type if (length%3 != 0) { fprintf(stderr,"invalid language in descriptor encountered\n"); return; } target->languages = new char[length + 1]; for (i=0; i < length; i++) { target->languages[i] = GetByte(offset + 2 + i); } target->languages[length] = '\0'; // length /=3; #ifdef _DEBUG_ printf("languages(s) : "); #endif /* for (i=0; i < length; i++){ printf("%c%c%c ", GetByte(offset+2+(i*3)), GetByte(offset+3+(i*3)), GetByte(offset+4+(i*3))); } printf("\n"); */ } } bool mpeg::ParseTransportStream(off_t offset){ BTRACK; if (GetByte(offset) != 0x47) return false; // int packetnum=0; // int pmt; Transport = new transport; int pid, scramble, adaptation; int i; off_t payload_offset; // well this is a mpeg 2? transport stream mpeg_version = 2; #define MPEG2_TR_PKT_LENGTH 188 #define TRANSPORT_PAT 0 #define TRANSPORT_CAT 1 #define PAT_SID 0 #define CAT_SID 1 #define PMT_SID 2 for (; offset < FileSize-1; offset += MPEG2_TR_PKT_LENGTH) { if (GetByte(offset) != 0x47) { fprintf(stderr,"Bad Packet start code %#0x should be 0x47\n",GetByte(offset)); return false; } pid = ReadPID(offset + 1); scramble = GetByte(offset + 3) >> 6; adaptation = (GetByte(offset + 3) & 0x30) >> 4; if (adaptation == 0) { // this is reserved, skip! continue; } //compute the payload offset payload_offset = offset + 4; if (adaptation & 0x02){ //adaptation fiel is present. // skip it // first byte of adaptation field is adaptation field length payload_offset += GetByte(offset + 4) + 1; } // if this is a Program association table parse it if (pid == 0x00) { ParsePAT(payload_offset); } // if this is a Program Map Table parse it for (i = 0; i < Transport->n_PMT_PIDs; i++) { if (Transport->PMT_PIDs[i] == pid) { ParsePMT(payload_offset); Transport->read_pmts++; #ifdef _DEBUG_ printf("PMT at [" _OFF_x "]\n", payload_offset); #endif break; } } if (Transport->n_PMT_PIDs !=0 && Transport->n_PMT_PIDs == Transport->read_pmts) { // we read all program map table... // Transport->PrintInfos(); HasAudio=HasVideo = true; return true; } /* switch(GetByte(payload_offset+1)){ case PAT_SID : ParsePAT(payload_offset); break; case CAT_SID : ParseCAT(payload_offset); break; case PMT_SID : ParsePMT(payload_offset); break; default : continue; break; } printf ("\n\n"); */ } #ifdef _DEBUG_ fprintf(stderr,"Sorry MPEG-2 Transport Stream is currently not handled\n"); #endif fprintf(stderr,"Warning didn't find the promised Program Map Tables\n"); return false; } PID mpeg::NextTrPacket(off_t* offset,off_t* payload_start, off_t* payload_end){ BTRACK; PID pid; byte adaptation; off_t payload_offset; *payload_start = 0; *payload_end = 0; // *offset = *offset + MPEG2_TR_PKT_LENGTH; // *offset = *offset + 188; pid = ReadPID(*offset + 1); adaptation = (GetByte(*offset + 3) & 0x30) >> 4; if (adaptation == 0){ // this is reserved, skip! *offset += MPEG2_TR_PKT_LENGTH; return pid; } if (pid == 0x1FFF) { //null packet *payload_start = 0; *payload_end = 0; *offset += MPEG2_TR_PKT_LENGTH; return pid; } //compute the payload offset payload_offset = *offset + 4; if (adaptation & 0x02) { //adaptation fiel is present. // skip it // first byte of adaptation field is adaptation field length payload_offset += GetByte(*offset + 4) + 1; } *payload_start = payload_offset; *offset += MPEG2_TR_PKT_LENGTH; *payload_end = *offset; if (*offset >= FileSize) *payload_start = *payload_end=-1; return pid; } transport::transport() :programs(0), n_progs(0), n_audio_streams(0), n_video_streams(0), n_other_streams(0), network_PID(-1), PMT_PIDs(0), n_PMT_PIDs(0), read_pmts(0) {} transport::~transport() { BTRACK; if (n_progs >0) { delete [] programs; } } void transport::delete_programs(){ BTRACK; if (!programs) return; for (int i = 0; i < n_progs; i++){ if (programs[i].TStreams != 0) delete_ES(programs[i].TStreams); } delete[] programs; programs=0; } void transport::delete_ES(EStream* stream) { BTRACK; if (stream == 0) return; if (stream->next == 0) delete stream; else delete_ES(stream->next); } void transport::PrintInfos(){ BTRACK; EStream* current; if (n_progs == 1) printf(" Mpeg 2 Transport Stream [1 program]\n"); else printf(" Mpeg 2 Transport Stream [%d programs]\n",n_progs); for(int i = 0; i < n_progs; i++) { printf(" Program N° %d contains %d Elementary Streams:\n",programs[i].prog_num, programs[i].nstreams); programs[i].descs.PrintInfos(" "); current=programs[i].TStreams; int stream_count = 1; while (current != 0) { printf(" Stream %d: ", stream_count++); switch (current->type) { case 0: printf("reserved"); break; case 1: printf("MPEG 1 video");break; case 2: printf("MPEG 2 video");break; case 3: printf("MPEG 1 audio");break; case 4: printf("MPEG 2 audio");break; case 5: printf("MPEG 2 private section");break; case 6: printf("MPEG 2 PES with private data");break; case 7: printf("MHEG");break; case 8: printf("DSM_CC");break; case 9: printf("Private data");break; default: if (current->type <0x80) printf("MPEG 2 reserved"); else printf("User Private data"); break; } printf(" [pid: %d]\n", current->pid); current->descs.PrintInfos(" "); current=current->next; } } } void mpeg_descriptors::PrintInfos(char* prefix){ BTRACK; unsigned int i; if (prefix==0) prefix = ""; char* description = new char[300]; char temp[100]; description[0] = '\0'; if (video_coding_version != -1) { sprintf(temp, "%svideo version %d\n", prefix, video_coding_version); strcat(description,temp); } if (audio_coding_version != -1) { sprintf(temp,"%saudio version %d\n",prefix, audio_coding_version); strcat(description, temp); } if (CA != -1) { sprintf(temp,"%smaybe scrambled (CA ID %d)\n",prefix,CA); strcat(description, temp); } if (languages) { sprintf(temp,"%sstream language: ", prefix); for (i = 0; i < strlen(languages)/3; i++) { sprintf(temp,"%c%c%c ",languages[i*3], languages[i*3+1], languages[i*3+2]); strcat(description,temp); } strcat(description,"\n"); } if (lang_audio_type >= 1 && lang_audio_type <= 3) { switch (lang_audio_type) { case 1: sprintf(temp,"%sClean effects : not a language\n",prefix);break; case 2: sprintf(temp,"%sStream is prepared for hearing impaired\n",prefix);break; case 3: sprintf(temp,"%sStream is prepared for commentaries for visually impaired viewers\n",prefix); } strcat(description,temp); } if (copyright) { sprintf(temp,"%sThis stream has copyright limitations\n",prefix); strcat(description,temp); } if (n_unhandled_desc>0) { if (n_unhandled_desc==1) sprintf(temp,"%s1 additional descriptor was not handled\n",prefix); else sprintf(temp,"%s%d additional descriptors were not handled\n",prefix, n_unhandled_desc); strcat(description,temp); } printf("%s", description); delete[] description; } header_buf *readHeader(FILE *myMpegfile, off_t offset, int rw) { static byte *nix; static off_t size; static header_buf *p; if (rw == 1) { p = new header_buf; size = offset; nix = new byte[size]; if (!nix) { fprintf(stderr,"unable to alloc buffer for header\n"); exit(1); } FSEEK(myMpegfile,0L,SEEK_SET); fread(nix,size,1L,myMpegfile); p->size = size; p->buf = nix; if (preserve_header) fprintf(stderr,"Size of Fix: 0x%qx\n",size); return(NULL); } if (rw == 2) return(p); fprintf(stderr,"unable to understand command\n"); exit(1); } /// prints all time stamps on stdout void mpeg::print_all_ts(byte kind){ off_t p = 0; byte *nix; double tsx; // FIXME [es] What is "nix" for? nix = &kind; while( (p = FindNextMarker(p,kind)) != -1) { if (mpeg_version == 2) tsx = ReadTSMpeg2(p+4); else tsx = ReadTS(p+4); fprintf (stderr,"offset: " _OFF_x " TS: %lf\n",p,tsx); p+=4; } } /// Checks time line of increasing time stamps and return amount of breaks int mpeg::CheckTimeline(byte kind){ off_t p = 0; double tsx = 0, tsx_prev = 0; int ret = 0; while( (p = FindNextMarker(p,kind)) != -1) { if (mpeg_version == 2) tsx = ReadTSMpeg2(p+4); else tsx = ReadTS(p+4); if ( !(tsx >= tsx_prev) ){ ++ret; //#ifdef _DEBUG_ printf("\tTime stamps jumped from %lf to %lf at position " _OFF_x "\n",tsx_prev,tsx,p); //#endif } tsx_prev = tsx; p+=4; } return ret; }