//________________________________________________ // Beginning of the write process // We fill-in the headers // 2- Write video headers //_______________________________________________ uint8_t aviWrite::writeVideoHeader( uint8_t *extra, uint32_t extraLen ) { assert (_out); _videostream.fccType = fourCC::get ((uint8_t *) "vids"); _bih.biSize=sizeof(_bih)+extraLen; #ifdef ADM_BIG_ENDIAN // in case of Little endian, do the usual swap crap AVIStreamHeader as; BITMAPINFOHEADER b; memcpy(&as,&_videostream,sizeof(as)); Endian_AviStreamHeader(&as); memcpy(&b,&_bih,sizeof(_bih)); Endian_BitMapInfo( &b ); setStreamInfo (_out, (uint8_t *) &as, (uint8_t *)&b,sizeof(BITMAPINFOHEADER), extra,extraLen, 0x1000); #else setStreamInfo (_out, (uint8_t *) &_videostream, (uint8_t *)&_bih,sizeof(BITMAPINFOHEADER), extra,extraLen, 0x1000); #endif return 1; }
//________________________________________________ // Beginning of the write process // We fill-in the headers // 2- Write video headers //_______________________________________________ uint8_t aviWrite::writeVideoHeader( uint8_t *extra, uint32_t extraLen ) { ADM_assert (_file); _videostream.fccType = fourCC::get ((uint8_t *) "vids"); _bih.biSize=sizeof(_bih)+extraLen; // MOD Feb 2005 by GMV: video super index length uint32_t odml_video_super_idx_size; if(doODML!=NORMAL) { odml_video_super_idx_size=24+odml_default_nbrof_index*16; }else { odml_video_super_idx_size=24+odml_indexes[0].odml_nbrof_index*16; } // END MOD Feb 2005 by GMV #ifdef ADM_BIG_ENDIAN // in case of Little endian, do the usual swap crap AVIStreamHeader as; BITMAPINFOHEADER b; memcpy(&as,&_videostream,sizeof(as)); Endian_AviStreamHeader(&as); memcpy(&b,&_bih,sizeof(_bih)); Endian_BitMapInfo( &b ); setStreamInfo (_file, (uint8_t *) &as, (uint8_t *)&b,sizeof(BITMAPINFOHEADER), // MOD Feb 2005 by GMV: ODML support odml_video_super_idx_size,0, // END MOD Feb 2005 by GMV extra,extraLen, 0x1000); #else setStreamInfo (_file, (uint8_t *) &_videostream, (uint8_t *)&_bih,sizeof(ADM_BITMAPINFOHEADER), // MOD Feb 2005 by GMV: ODML support odml_video_super_idx_size,0, // END MOD Feb 2005 by GMV extra,extraLen, 0x1000); #endif return 1; }
//______________________________________ // // Open and get the headears/index built // along way //______________________________________ uint8_t OpenDMLHeader::open(const char *name) { uint8_t badAvi=0; uint32_t rd; printf("** opening OpenDML files **"); _fd=fopen(name,"rb"); if(!_fd) { printf("\n cannot open %s \n",name); return 0; } myName=ADM_strdup(name); #define CLR(x) memset(& x,0,sizeof( x)); CLR( _videostream); CLR( _mainaviheader); _isvideopresent=1; _isaudiopresent=0; _nbTrack=0; riffParser *parser=new riffParser(name); if(MKFCC('R','I','F','F')!=(rd=parser->read32())) { printf("Not riff\n");badAvi=1; printf("%lx != %lx\n",rd,MKFCC('R','I','F','F')); } parser->read32(); if(MKFCC('A','V','I',' ')!=parser->read32()) { printf("Not Avi\n");badAvi=1; } if(!badAvi) { walk(parser); } delete parser; aprintf("Found %d tracks\n:-----------\n",_nbTrack); // check if it looks like a correct avi if(!_nbTrack) badAvi=1; // if we are up to here -> good avi :) if(badAvi) { printf("FAIL\n"); return 0; } // now read up each parts... //____________________________ #ifdef __WIN32 #define DUMP_TRACK(i) aprintf(" at %I64u (%I64x) size : %I64u (%I64x)\n", \ _Tracks[i].strh.offset,\ _Tracks[i].strh.offset,\ _Tracks[i].strh.size,\ _Tracks[i].strh.size); #else #define DUMP_TRACK(i) aprintf(" at %llu (%llx) size : %llu (%llx)\n", \ _Tracks[i].strh.offset,\ _Tracks[i].strh.offset,\ _Tracks[i].strh.size,\ _Tracks[i].strh.size); #endif for(uint32_t i=0;i<_nbTrack;i++) { DUMP_TRACK(i); } uint32_t vidTrack=0xff; // search wich track is the video one // and load it to _videoheader for(uint32_t i=0;i<_nbTrack;i++) { fseeko(_fd,_Tracks[i].strh.offset,SEEK_SET); if(_Tracks[i].strh.size!=sizeof(_videostream)) { printf("Mmm(1) we have a bogey here, size mismatch : %"LLU"\n",_Tracks[i].strh.size); printf("expected %d\n",sizeof(_videostream)); if(_Tracks[i].strh.size<sizeof(_videostream)-8) // RECT is not mandatory { GUI_Error_HIG(QT_TR_NOOP("Malformed header"), NULL); return 0; } printf("Trying to continue anyway\n"); } fread(&_videostream,sizeof(_videostream),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_AviStreamHeader(&_videostream); #endif if(_videostream.fccType==MKFCC('v','i','d','s')) { vidTrack=i; printf("Video track is %ld\n",i); break; } } if(0xff==vidTrack) { printf("Could not identify video track!"); return 0; } // STOP HERE -> Alex <- //return 0; // STOP HERE -> Alex <- // then bih stuff int32_t extra; // _fd=fopen(name,"rb"); fseeko(_fd,_Tracks[vidTrack].strf.offset,SEEK_SET); extra=_Tracks[vidTrack].strf.size-sizeof(_video_bih); if(extra<0) { printf("bih is not big enough (%lu/%lu)!\n",_Tracks[vidTrack].strf.size,sizeof(_video_bih)); return 0; } fread(&_video_bih,sizeof(_video_bih),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_BitMapInfo(&_video_bih); #endif if(extra>0) { _videoExtraLen=extra; _videoExtraData=new uint8_t [extra]; fread(_videoExtraData,extra,1,_fd); } _isvideopresent=1; //-------------------------------------------------- // Read audio trak info, select if there is // several //-------------------------------------------------- // and audio track if(_mainaviheader.dwStreams>=2) { // which one is the audio track, is there several ? if(!(_nbAudioTracks=countAudioTrack())) { printf("Weird, there is no audio track, but more than one stream...\n"); } else { uint32_t run=0,audio=0; odmlAudioTrack *track; _audioTracks=new odmlAudioTrack[_nbAudioTracks]; while(audio<_nbAudioTracks) { ADM_assert(run<_nbTrack); track=&(_audioTracks[audio]); fseeko(_fd,_Tracks[run].strh.offset,SEEK_SET); if(_Tracks[run].strh.size != sizeof(_audiostream)) { printf("Mmm(2) we have a bogey here, size mismatch : %"LLU"\n",_Tracks[run].strh.size); printf("expected %d\n",sizeof(_audiostream)); if(_Tracks[run].strh.size<sizeof(_audiostream)-8) { GUI_Error_HIG(QT_TR_NOOP("Malformed header"), NULL); return 0; } printf("Trying to continue anyway\n"); } fread(track->avistream,sizeof(_audiostream),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_AviStreamHeader(track->avistream); #endif if(track->avistream->fccType!=MKFCC('a','u','d','s')) { printf("Not an audio track!\n"); run++; continue; } // now read extra stuff fseeko(_fd,_Tracks[run].strf.offset,SEEK_SET); extra=_Tracks[run].strf.size-sizeof(WAVHeader); if(extra<0) { printf("WavHeader is not big enough (%lu/%lu)!\n", _Tracks[run].strf.size,sizeof(WAVHeader)); return 0; } fread(track->wavHeader,sizeof(WAVHeader),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_WavHeader(track->wavHeader); #endif if(extra>2) { fgetc(_fd);fgetc(_fd); extra-=2; track->extraDataLen=extra; track->extraData=new uint8_t [extra]; fread(track->extraData,extra,1,_fd); } track->trackNum=run; audio++; run++; } } } // now look at the index stuff // there could be 3 cases: // 1- It is a openDML index, meta index + several smaller index // 2- It is a legacy index (type 1 , most common) // 3- It is a broken index or no index at all // // If it is a openDML index we will find a "indx" field in the Tracks // Else we will find it in _regularIndex Track // Since openDML often also have a regular index we will try open DML first uint8_t ret=0; Dump(); // take the size of riff header and actual file size uint64_t riffSize; fseeko(_fd,0,SEEK_END); _fileSize=ftello(_fd); fseeko(_fd,0,SEEK_SET); read32(); riffSize=(uint64_t )read32(); // 1st case, we have an avi < 4 Gb // potentially avi type 1 #if 0 if((_fileSize<4*1024*1024*1024LL)&& // if riff size is ~ fileSize try regular index (abs(riffSize-_fileSize)<1024*1024)) #endif #define HAS(x) if(x) printf(#x" : yes\n"); else printf(#x" : no\n"); // If there is no openDML index HAS( _regularIndex.offset); HAS( _Tracks[vidTrack].indx.offset); if(!ret && _regularIndex.offset &&!_Tracks[vidTrack].indx.offset) // try regular avi if a idx1 field is there (avi index) ret=indexRegular(vidTrack); if (!ret && _Tracks[vidTrack].indx.offset) // Try openDML if a index field is there (openDML) ret=indexODML(vidTrack); if(!ret) { printf("Could not index it properly...\n"); return 0; } if(!_nbAudioTracks) { _isaudiopresent=0; } else { // build audio stream odmlAudioTrack *track; // Check it is not a weird DV file if(fourCC::check(_video_bih.biCompression,(uint8_t *)"dvsd")) { for(int i=0;i<_nbAudioTracks;i++) { track=&(_audioTracks[i]); WAVHeader *hdr= track->wavHeader; if(!hdr->frequency) { printf("Fixing audio track to be PCM\n"); hdr->frequency=48000; //hdr->channels=2; hdr->byterate=48000*hdr->channels*2; hdr->blockalign=2*hdr->channels; } } } for(int i=0;i<_nbAudioTracks;i++) { track=&(_audioTracks[i]); _audioTracks[i].track= new AVDMAviAudioStream(track->index, track->nbChunks, myName, track->wavHeader, 0, track->extraDataLen,track->extraData); } } if (!_video_bih.biCompression && fourCC::check(_videostream.fccHandler,(uint8_t*)"DIB ")) { // flip video uint8_t *extraData = new uint8_t[_videoExtraLen + 9]; memcpy(extraData, _videoExtraData, _videoExtraLen); memcpy(extraData + _videoExtraLen, "BottomUp", 9); delete [] _videoExtraData; _videoExtraLen += 9; _videoExtraData = extraData; _videostream.fccHandler = _video_bih.biCompression = fourCC::get((uint8_t*)"DIB "); } else _videostream.fccHandler=_video_bih.biCompression; printf("\nOpenDML file successfully read..\n"); return ret; }
uint8_t picHeader::open(char *inname) { uint32_t nnum; uint32_t *fcc; uint8_t fcc_tab[4]; FILE *fd; char *end; uint32_t w=0,h=0; // 1- identity the file type // fcc=(uint32_t *)fcc_tab; fd=fopen(inname,"rb"); if(!fd) { printf("\n Cannot open that file!\n"); return 0; } fread(fcc_tab,4,1,fd); fclose(fd); if(fourCC::check(*fcc,(uint8_t *)"RIFF")) { _type=PIC_BMP; printf("\n It looks like BMP (RIFF)...\n"); } else { if(fcc_tab[0]=='B' && fcc_tab[1]=='M') { _type=PIC_BMP2; printf("\n It looks like BMP (BM)...\n"); } else if(fcc_tab[0]==0xff && fcc_tab[1]==0xd8) { _type=PIC_JPEG; printf("\n It looks like Jpg...\n"); } else { printf("\n Cannot identify file (%x %x)\n",*fcc,*fcc&0xffff); return 0; } } // Then spit the name in name and extension char *name; char *extension; PathSplit(inname, &name, &extension); nnum=1; end=name+strlen(name)-1; while(( *end>='0') && (*end<='9')) { end--; nnum++; }; if(nnum==1) { printf("\n only one file!"); return 0; } nnum--; end++; _first=atoi(end); printf("\n First : %lu, num digit :%lu",_first,nnum); *(end)=0; printf("\n Path : %s\n",name); char realname[250]; char realstring[250]; sprintf(realstring,"%%s%%0%lud.%s",nnum,extension); printf("\n string : %s",realstring); _nb_file=0; for(uint32_t i=0;i<MAX_ACCEPTED_OPEN_FILE;i++) { sprintf(realname,realstring,name,i+_first); printf("\n %lu : %s",i,realname); fd=fopen(realname,"rb"); if(fd==NULL) break; fclose(fd); _nb_file++; } printf("\n found %lu images\n",_nb_file); _fd=(FILE **)ADM_alloc(_nb_file*sizeof(FILE*)); _imgSize=new uint32_t[_nb_file]; //_________________________________ // now open them and assign fd && imgSize //__________________________________ for(uint32_t i=0;i<_nb_file;i++) { sprintf(realname,realstring,name,i+_first); printf("\n %lu : %s",i,realname); _fd[i]=fopen(realname,"rb"); fseek(_fd[i],0,SEEK_END); _imgSize[i]=ftell( _fd[i] ); fseek(_fd[i],0,SEEK_SET); ADM_assert(_fd[i]!=NULL); } delete [] name; delete [] extension; // // Image is bmp type //________________________ switch(_type) { case PIC_BMP: { BITMAPHEADER bmph; fread(&s16,2,1, _fd[0]); if(s16!=0x4D42) { printf("\n incorrect bmp sig.\n"); return 0; } fread(&s32,4,1, _fd[0]); fread(&s32,4,1, _fd[0]); fread(&s32,4,1, _fd[0]); fread(&bmph, sizeof(bmph), 1, _fd[0]); if(bmph.compressionScheme!=0) { printf("\ncannot handle compressed bmp\n"); return 0; } _offset=bmph.size+14; w=bmph.width ; h=bmph.height ; } break; // Jpeg : Grab the size //____________________ case PIC_JPEG: { uint16_t tag=0,count=0,off; _offset=0; fseek(_fd[0],0,SEEK_SET); read16(_fd[0]); // skip jpeg ffd8 while(count<10 && tag!=0xFFC0) { tag=read16(_fd[0]); if( (tag >>8 ) !=0xff) { printf("invalid jpeg tag found (%x)\n",tag); } if(tag==0xFFC0) { read16(_fd[0]); // size read8(_fd[0]); // precision h=read16(_fd[0]); w=read16(_fd[0]); } else { off=read16(_fd[0]); if(off<2) { printf("Offset too short!\n"); return 0; } aprintf("Found tag : %x , jumping %d bytes\n",tag,off); fseek(_fd[0],off-2,SEEK_CUR); } count++; } if(tag!=0xffc0) { printf("Cannot fint start of frame\n"); return 0; } printf("\n %lu x %lu..\n",w,h); } break; case PIC_BMP2: { BITMAPINFOHEADER bmph; fseek(_fd[0],10,SEEK_SET); #define MK32() (fcc_tab[0]+(fcc_tab[1]<<8)+(fcc_tab[2]<<16)+ \ (fcc_tab[3]<<24)) fread(fcc_tab,4,1, _fd[0]); _offset=MK32(); // size, width height follow as int32 fread(&bmph, sizeof(bmph), 1, _fd[0]); #ifdef ADM_BIG_ENDIAN Endian_BitMapInfo(&bmph); #endif if(bmph.biCompression!=0) { printf("\ncannot handle compressed bmp\n"); return 0; } w=bmph.biWidth ; h=bmph.biHeight ; printf("W: %d H: %d offset : %d\n",w,h,_offset); } break; default: ADM_assert(0); } //_______________________________________ // Now build header info //_______________________________________ _isaudiopresent=0; // Remove audio ATM _isvideopresent=1; // Remove audio ATM #define CLR(x) memset(& x,0,sizeof( x)); CLR( _videostream); CLR( _mainaviheader); _videostream.dwScale=1; _videostream.dwRate=25; _mainaviheader.dwMicroSecPerFrame=40000;; // 25 fps hard coded _videostream.fccType=fourCC::get((uint8_t *)"vids"); _video_bih.biBitCount=24; _videostream.dwLength= _mainaviheader.dwTotalFrames=_nb_file; _videostream.dwInitialFrames= 0; _videostream.dwStart= 0; // //_video_bih.biCompression= 24; // _video_bih.biWidth=_mainaviheader.dwWidth =w ; _video_bih.biHeight=_mainaviheader.dwHeight =h; //_video_bih.biPlanes= 24; if(PIC_JPEG==_type) { _video_bih.biCompression=_videostream.fccHandler=fourCC::get((uint8_t *)"MJPG");; } else { _video_bih.biCompression=_videostream.fccHandler=0; } printf("Offset : %lu\n",_offset); return 1; }
//______________________________________ // // Open and get the headears/index built // along way //______________________________________ uint8_t OpenDMLHeader::open(char *name) { uint8_t badAvi=0; uint32_t rd; printf("** opening OpenDML files **"); _fd=fopen(name,"rb"); if(!_fd) { printf("\n cannot open %s \n",name); return 0; } #define CLR(x) memset(& x,0,sizeof( x)); CLR( _videostream); CLR( _mainaviheader); _isvideopresent=1; _isaudiopresent=0; _nbTrack=0; riffParser *parser=new riffParser(name); if(MKFCC('R','I','F','F')!=(rd=parser->read32())) { printf("Not riff\n");badAvi=1; printf("%lx != %lx\n",rd,MKFCC('R','I','F','F')); } parser->read32(); if(MKFCC('A','V','I',' ')!=parser->read32()) { printf("Not Avi\n");badAvi=1; } if(!badAvi) { walk(parser); } delete parser; aprintf("Found %d tracks\n:-----------\n",_nbTrack); // check if it looks like a correct avi if(!_nbTrack) badAvi=1; // if we are up to here -> good avi :) if(badAvi) { printf("FAIL\n"); return 0; } // now read up each parts... //____________________________ #define DUMP_TRACK(i) aprintf(" at %llu (%llx) size : %llu (%llx)\n", \ _Tracks[i].strh.offset,\ _Tracks[i].strh.offset,\ _Tracks[i].strh.size,\ _Tracks[i].strh.size); for(uint32_t i=0;i<_nbTrack;i++) { DUMP_TRACK(i); } uint32_t vidTrack=0xff; // search wich track is the video one // and load it to _videoheader for(uint32_t i=0;i<_nbTrack;i++) { fseeko(_fd,_Tracks[i].strh.offset,SEEK_SET); if(_Tracks[i].strh.size!=sizeof(_videostream)) { printf("Mmm(1) we have a bogey here, size mismatch : %lu \n",_Tracks[i].strh.size); printf("expected %d\n",sizeof(_videostream)); if(_Tracks[i].strh.size<sizeof(_videostream)-8) // RECT is not mandatory { GUI_Alert("Maformed header!"); return 0; } printf("Trying to continue anyway\n"); } fread(&_videostream,sizeof(_videostream),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_AviStreamHeader(&_videostream); #endif if(_videostream.fccType==MKFCC('v','i','d','s')) { vidTrack=i; printf("Video track is %ld\n",i); break; } } if(0xff==vidTrack) { printf("Could not identify video track!"); return 0; } // STOP HERE -> Alex <- //return 0; // STOP HERE -> Alex <- // then bih stuff int32_t extra; _fd=fopen(name,"rb"); fseeko(_fd,_Tracks[vidTrack].strf.offset,SEEK_SET); extra=_Tracks[vidTrack].strf.size-sizeof(_video_bih); if(extra<0) { printf("bih is not big enough (%lu/%lu)!\n",_Tracks[vidTrack].strf.size,sizeof(_video_bih)); return 0; } fread(&_video_bih,sizeof(_video_bih),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_BitMapInfo(&_video_bih); #endif if(extra>0) { _videoExtraLen=extra; _videoExtraData=new uint8_t [extra]; fread(_videoExtraData,extra,1,_fd); } _isvideopresent=1; //-------------------------------------------------- // Read audio trak info, select if there is // several //-------------------------------------------------- // and audio track uint32_t audioTrack=0xff; uint32_t audioTrackNumber=0; if(_mainaviheader.dwStreams>=2) { // which one is the audio track, is there several ? switch(countAudioTrack()) { case 0: printf("No audio track found.\n"); break; case 1: printf("One audio track found\n"); audioTrack=searchAudioTrack(0); audioTrackNumber=0; break; default: printf("Several audio tracks found\n"); uint32_t t; t=GUI_Question("Take second audio track ?"); audioTrackNumber=t; audioTrack=searchAudioTrack(t); } if(audioTrack!=0xff) // one is marked { // Read information printf("Taking audio track : %lu %lu\n",audioTrackNumber,audioTrack); _isaudiopresent=1; fseeko(_fd,_Tracks[audioTrack].strh.offset,SEEK_SET); if(_Tracks[audioTrack].strh.size!=sizeof(_audiostream)); { printf("Mmm(2) we have a bogey here, size mismatch : %lu \n" ,_Tracks[audioTrack].strh.size); printf("expected %d\n",sizeof(_audiostream)); if(_Tracks[audioTrack].strh.size<sizeof(_audiostream)-8) { GUI_Alert("Maformed header!"); return 0; } printf("Trying to continue anyway\n"); } fread(&_audiostream,sizeof(_audiostream),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_AviStreamHeader(&_audiostream); #endif if(_audiostream.fccType!=MKFCC('a','u','d','s')) { printf("Not an audio track!\n"); return 0; } // now read extra stuff fseeko(_fd,_Tracks[audioTrack].strf.offset,SEEK_SET); extra=_Tracks[audioTrack].strf.size-sizeof(_wavHeader); if(extra<0) { printf("WavHeader is not big enough (%lu/%lu)!\n", _Tracks[audioTrack].strf.size,sizeof(WAVHeader)); return 0; } fread(&_wavHeader,sizeof(WAVHeader),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_WavHeader(&_wavHeader); #endif if(extra>2) { fgetc(_fd);fgetc(_fd); extra-=2; _audioExtraLen=extra; _audioExtraData=new uint8_t [extra]; fread(_audioExtraData,extra,1,_fd); } } } // now look at the index stuff // there could be 3 cases: // 1- It is a openDML index, meta index + several smaller index // 2- It is a legacy index (type 1 , most common) // 3- It is a broken index or no index at all // // If it is a openDML index we will find a "indx" field in the Tracks // Else we will find it in _regularIndex Track // Since openDML often also have a regular index we will try open DML first uint8_t ret=0; Dump(); // take the size of riff header and actual file size uint64_t riffSize; fseeko(_fd,0,SEEK_END); _fileSize=ftello(_fd); fseeko(_fd,0,SEEK_SET); read32(); riffSize=(uint64_t )read32(); // 1st case, we have an avi < 4 Gb // potentially avi type 1 if((_fileSize<4*1024*1024*1024LL)&& // if riff size is ~ fileSize try regular index (abs(riffSize-_fileSize)<1024*1024)) { printf("Size looks good, maybe type 1 avi\n"); if(!ret && !_Tracks[vidTrack].indx.offset) // try regular avi ret=indexRegular(vidTrack,audioTrack,audioTrackNumber); if (!ret && _Tracks[vidTrack].indx.offset) ret=indexODML(vidTrack,audioTrack,audioTrackNumber); if(!ret) // re-index! ret=indexReindex(vidTrack,audioTrack,audioTrackNumber); } // else try openDML/reindexing else { printf("Size mismatch, not type 1 avi\n"); if (!ret && _Tracks[vidTrack].indx.offset) ret=indexODML(vidTrack,audioTrack,audioTrackNumber); if(!ret) // re-index! ret=indexReindex(vidTrack,audioTrack,audioTrackNumber); } if(!ret) { printf("Cound not index it properly...\n"); return 0; } if(!_audioIdx) _isaudiopresent=0; else { // build audio stream _audioTrack = new AVDMAviAudioStream(_audioIdx, _nbAudioChunk, _fd, &_wavHeader, 0, _audioExtraLen,_audioExtraData); } _videostream.fccHandler=_video_bih.biCompression; printf("\nOpenDML file successfully read..\n"); return ret; }
/** \fn saveAsBmp \brief save current image into filename, into bmp format */ uint8_t ADMImage::saveAsBmp(const char *filename) { BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmph; FILE *fd; uint32_t sz; uint16_t s16; uint32_t s32; sz = _width* _height * 3; bmfh.bfReserved1 = bmfh.bfReserved2 = 0; bmfh.bfOffBits = sizeof (bmfh) + sizeof (bmph); //_________________________________________ bmph.biSize = sizeof (bmph); bmph.biWidth = _width; bmph.biHeight = _height; bmph.biPlanes = 1; bmph.biBitCount = 24; bmph.biCompression = 0; // COMPRESSION NONE bmph.biSizeImage = sz; bmph.biXPelsPerMeter = 0; bmph.biYPelsPerMeter = 0; bmph.biClrUsed = 0; bmph.biClrImportant = 0; /* bmph.resolutionUnits=0; bmph.origin=0; bmph.colorEncoding=0; */ ADMImage image(_width,_height); printf ("\n %u x %u=%u\n", bmph.biWidth, bmph.biHeight, sz); uint8_t *out; out=(uint8_t *)ADM_alloc(sz); if(!out) { GUI_Error_HIG(QT_TR_NOOP("Memory error"), NULL); // ADM_dealloc(out); return 0; } if(!COL_yv12rgbBMP(bmph.biWidth, bmph.biHeight,data, out)) { GUI_Error_HIG(QT_TR_NOOP("Error converting to BMP"), NULL); ADM_dealloc(out); return 0; } fd = fopen (filename, "wb"); if (!fd) { GUI_Error_HIG (QT_TR_NOOP("Something bad happened"), NULL); ADM_dealloc(out); return 0; } // Bitmpap file header, not using tructure due to gcc padding it #ifdef ADM_BIG_ENDIAN s16 = 0x424D; #else s16 = 0x4D42; #endif s32 = 14 + sizeof (bmph) + sz; #ifdef ADM_BIG_ENDIAN #define SWAP32(x) x=R32(x) #else #define SWAP32(x) ; #endif SWAP32(s32); fwrite (&s16, 2, 1, fd); fwrite (&s32, 4, 1, fd); s32 = 0; fwrite (&s32, 4, 1, fd); s32 = 14 + sizeof (bmph); SWAP32(s32); fwrite (&s32, 4, 1, fd); #ifdef ADM_BIG_ENDIAN Endian_BitMapInfo(&bmph); #endif fwrite (&bmph, sizeof (bmph), 1, fd); fwrite (out, sz, 1, fd); fclose(fd); ADM_dealloc(out); return 1; }
/** \fn saveAsBmp \brief save current image into filename, into bmp format */ bool ADMImage::saveAsBmp(const char *filename) { ADM_BITMAPFILEHEADER bmfh; ADM_BITMAPINFOHEADER bmph; FILE *fd; uint32_t sz; uint16_t s16; uint32_t s32; sz = _width* _height * 3; bmfh.bfReserved1 = bmfh.bfReserved2 = 0; bmfh.bfOffBits = sizeof (bmfh) + sizeof (bmph); //_________________________________________ bmph.biSize = sizeof (bmph); bmph.biWidth = _width; bmph.biHeight = _height; bmph.biPlanes = 1; bmph.biBitCount = 24; bmph.biCompression = 0; // COMPRESSION NONE bmph.biSizeImage = sz; bmph.biXPelsPerMeter = 0; bmph.biYPelsPerMeter = 0; bmph.biClrUsed = 0; bmph.biClrImportant = 0; /* bmph.resolutionUnits=0; bmph.origin=0; bmph.colorEncoding=0; */ ADMImageDefault image(_width,_height); printf ("\n %u x %u=%u\n", bmph.biWidth, bmph.biHeight, sz); uint8_t *out; out=(uint8_t *)ADM_alloc(sz); if(!out) { GUI_Error_HIG(QT_TR_NOOP("Memory error"), NULL); // ADM_dealloc(out); return 0; } ADMColorScalerSimple converter(bmph.biWidth, bmph.biHeight, ADM_COLOR_YV12,ADM_COLOR_RGB24); converter.convertImage(this,out); uint32_t ww=bmph.biWidth; uint32_t hh=bmph.biHeight; uint8_t *swap = new uint8_t[ww*3]; uint8_t *up=out; uint8_t *down=out+(hh-1)*ww*3; for(int y=0;y<hh>>1;y++) { SwapMe(swap,up,ww); SwapMe(up,down,ww); memcpy( down,swap,ww*3); down-=3*ww; up+=3*ww; } delete [] swap; fd = ADM_fopen (filename, "wb"); if (!fd) { GUI_Error_HIG (QT_TR_NOOP("Something bad happened"), NULL); ADM_dealloc(out); return 0; } // Bitmpap file header, not using tructure due to gcc padding it #ifdef ADM_BIG_ENDIAN s16 = 0x424D; #else s16 = 0x4D42; #endif s32 = 14 + sizeof (bmph) + sz; #ifdef ADM_BIG_ENDIAN #define SWAP32(x) x=R32(x) #else #define SWAP32(x) ; #endif SWAP32(s32); fwrite (&s16, 2, 1, fd); fwrite (&s32, 4, 1, fd); s32 = 0; fwrite (&s32, 4, 1, fd); s32 = 14 + sizeof (bmph); SWAP32(s32); fwrite (&s32, 4, 1, fd); #ifdef ADM_BIG_ENDIAN Endian_BitMapInfo(&bmph); #endif fwrite (&bmph, sizeof (bmph), 1, fd); fwrite (out, sz, 1, fd); fclose(fd); ADM_dealloc(out); return 1; }
uint8_t asfHeader::loadVideo(asfChunk *s) { uint32_t w,h,x; printf("--\n"); w=s->read32(); h=s->read32(); s->read8(); x=s->read16(); _isvideopresent=1; memset(&_mainaviheader,0,sizeof(_mainaviheader)); _mainaviheader.dwWidth=w; _mainaviheader.dwHeight=h; _video_bih.biWidth=w; _video_bih.biHeight=h; printf("Pic Width %04d\n",w); printf("Pic Height %04d\n",h); printf(" BMP size %04d (%04d)\n",x,(int)sizeof(ADM_BITMAPINFOHEADER)); s->read((uint8_t *)&_video_bih,sizeof(ADM_BITMAPINFOHEADER)); #ifdef ADM_BIG_ENDIAN Endian_BitMapInfo(&_video_bih); #endif _videostream.fccHandler=_video_bih.biCompression; printf("Codec : <%s> (%04x)\n", fourCC::tostring(_video_bih.biCompression),_video_bih.biCompression); if(fourCC::check(_video_bih.biCompression,(uint8_t *)"DVR ")) { // It is MS DVR, fail so that the mpeg2 indexer can take it from here _videostream.fccHandler=_video_bih.biCompression=fourCC::get((uint8_t *)"MPEG"); printf("This is MSDVR, not ASF\n"); return 0; } printBih(&_video_bih); #if 1 if(_video_bih.biSize>sizeof(ADM_BITMAPINFOHEADER)) { x=_video_bih.biSize; #else if(x>sizeof(ADM_BITMAPINFOHEADER)) { #endif _videoExtraLen=x-sizeof(ADM_BITMAPINFOHEADER); _videoExtraData=new uint8_t[_videoExtraLen]; s->read(_videoExtraData,_videoExtraLen); ADM_info("We have %d bytes of extra data for video.\n",(int)_videoExtraLen); }else { ADM_info("No extra data for video\n"); } uint64_t l=ftello(_fd); printf("Bytes left : %d\n",(int)(s->endPos()-l)); return 1; } /** \fn buildIndex \brief Scan the file to build an index Header Chunk Chunk Chunk Chunk Data chunk Chunk Chunk We skip the 1st one, and just read the header of the 2nd one */ uint8_t asfHeader::buildIndex(void) { uint32_t fSize; const chunky *id; uint32_t chunkFound; uint32_t r=5; uint32_t len; fseeko(_fd,0,SEEK_END); fSize=ftello(_fd); fseeko(_fd,0,SEEK_SET); asfChunk h(_fd); printf("[ASF] ********** Building index **********\n"); printf("[ASF] Searching data\n"); while(r--) { h.nextChunk(); // Skip headers id=h.chunkId(); h.dump(); if(id->id==ADM_CHUNK_DATA_CHUNK) break; h.skipChunk(); } if(id->id!=ADM_CHUNK_DATA_CHUNK) return 0; // Remove leftover from DATA_chunk // Unknown GUID 16 // Number of packets UINT64 8 // Unknown UINT8 1 // Unknown UINT8 1 // h.read32(); h.read32(); h.read32(); h.read32(); _nbPackets=(uint32_t) h.read64(); h.read16(); len=h.chunkLen-16-8-2-24; printf("[ASF] nbPacket : %u\n",_nbPackets); printf("[ASF] len to go : %u\n",len); printf("[ASF] scanning data\n"); _dataStartOffset=ftello(_fd); // Here we go asfPacket *aPacket=new asfPacket(_fd,_nbPackets,_packetSize, &readQueue,&storageQueue,_dataStartOffset); uint32_t packet=0; #define MAXIMAGE (_nbPackets) uint32_t sequence=0; uint32_t ceilImage=MAXIMAGE; nbImage=0; len=0; asfIndex indexEntry; memset(&indexEntry,0,sizeof(indexEntry)); bool first=true; DIA_workingBase *progressBar=createWorking("Indexing"); uint32_t fileSizeMB=(uint32_t)(fSize>>10); uint64_t lastDts[ASF_MAX_AUDIO_TRACK]; for(int i=0;i<ASF_MAX_AUDIO_TRACK;i++) { lastDts[i]=0; } while(packet<_nbPackets) { while(readQueue.size()) { asfBit *bit=NULL; // update UI uint32_t curPos=(uint32_t)(ftello(_fd)>>10); progressBar->update(curPos,fileSizeMB); bit=readQueue.front(); readQueue.pop_front(); // -- uint64_t dts=bit->dts; uint64_t pts=bit->pts; aprintf("** DTS=%s\n",ADM_us2plain(dts)); aprintf("** PDTS=%s\n",ADM_us2plain(pts)); if(bit->stream==_videoStreamId) { aprintf(">found video packet of size=%d off=%d seq %d, while curseq =%d, dts=%s", bit->len,bit->offset, bit->sequence,curSeq, ADM_us2plain(dts)); aprintf(" pts=%s\n",ADM_us2plain(pts)); if(bit->sequence!=sequence || first==true) { if(first==false) { indexEntry.frameLen=len; aprintf("Pushing video frame index=%d seq=%d pts=%s \n", _index.size(), indexEntry.segNb,ADM_us2plain(indexEntry.pts)); aprintf("dts=%s\n",ADM_us2plain(indexEntry.dts)); _index.append(indexEntry); } aprintf("New sequence\n"); if( ((sequence+1)&0xff)!=(bit->sequence&0xff)) { ADM_warning("!!!!!!!!!!!! non continuous sequence %u %u\n",sequence,bit->sequence); } indexEntry.frameLen=0; indexEntry.segNb=bit->sequence; indexEntry.packetNb=bit->packet; indexEntry.flags=bit->flags; indexEntry.dts=dts; indexEntry.pts=pts; if(first==false) { sequence=bit->sequence; readQueue.push_front(bit); // reuse it next time len=0; continue; }else { sequence=bit->sequence; first=false; // first packet } } len+=bit->len; } // End of video stream Id else // Audio ? { int found=0; for(int i=0;i<_nbAudioTrack && !found;i++) { if(bit->stream == _allAudioTracks[i].streamIndex) { if(bit->pts!=ADM_NO_PTS) { if(!lastDts[i] || (bit->pts>lastDts[i]+500000L)) // seek point every 500 ms { asfAudioSeekPoint seek; seek.pts=bit->pts; seek.packetNb=bit->packet; (audioSeekPoints[i]).append(seek); #if 1 if(!lastDts[i]) printf("Adding seek point for track %d at %s (packet=%d)\n", i,ADM_us2plain(bit->pts),(int)seek.packetNb); #endif lastDts[i]=bit->pts; aprintf("Adding seek point for track %d at %s (packet=%d)\n", i,ADM_us2plain(bit->pts),(int)seek.packetNb); } } found=1; } } if(!found) { printf("Unmapped stream %u\n",bit->stream); } } delete [] bit->data; bit->data=NULL; storageQueue.push_back(bit); } //working->update(packet,_nbPackets); packet++; aPacket->nextPacket(0xff); // All packets aPacket->skipPacket(); } delete progressBar; delete aPacket; //delete working; /* Compact index */ fseeko(_fd,_dataStartOffset,SEEK_SET); printf("[ASF] %u images found\n",nbImage); printf("[ASF] ******** End of buildindex *******\n"); nbImage=_index.size();; if(!nbImage) return 0; uint64_t shift=60*1000*1000; bool canShift=false; uint64_t tPts; tPts=_index[0].pts; ADM_info("First image pts: %s, dts: %s\n",ADM_us2plain(tPts), ADM_us2plain(_index[0].dts)); if(tPts != ADM_NO_PTS) { shift=tPts; ADM_info("Video shift = %s\n",ADM_us2plain(tPts)); canShift=true; }else canShift=false; for(int i=0;i<_nbAudioTrack;i++) { if(!audioSeekPoints[i].size()) { ADM_info("audio track : %d, no seek\n",i); canShift=false; continue; } tPts=audioSeekPoints[i][0].pts; ADM_info("audio track : %d, %s\n",i,ADM_us2plain(tPts)); if(tPts<shift) shift=tPts; } if(canShift) { ADM_info("Shifting a/v raw=%s\n",ADM_us2plain(shift)); }else { ADM_info("Can t shift\n"); shift=0; } _videostream.dwLength=_mainaviheader.dwTotalFrames=nbImage; _index[0].flags=AVI_KEY_FRAME; if(_index[0].pts==ADM_NO_PTS) _index[0].pts=_index[0].dts; // Update fps // In fact it is an average fps // _videostream.dwScale=1000; // check if we have a duration per frame for video... int n=frameDurationMapping.size(); int dex=-1; for(int i=0;i<n;i++) { if(frameDurationMapping[i].streamNb==_videoStreamId) dex=i; } if(dex!=-1) { ADM_info("Average fps provided\n"); setFps(frameDurationMapping[dex].usPerFrame); } else { ADM_info("Fps not provided, guessing it from nbFrame and duration\n"); uint32_t avgFps; if(_index[nbImage-1].pts!=ADM_NO_PTS && _index[0].pts!=ADM_NO_PTS) { float f=(_index[nbImage-1].pts-_index[0].pts); f/=nbImage; // average duration of 1 image in us setFps((uint64_t) f); }else { printf("[Asf] No pts, setting 30 fps hardcoded\n"); _videostream.dwRate=(uint32_t)30000;; } } if(shift) { double frames3=_videostream.dwScale; frames3/=_videostream.dwRate; frames3*=3*1000*1000; // ADM_info("3 frames time = %s\n",ADM_us2plain((uint64_t)frames3)); uint64_t frame64=(uint64_t)frames3; if(frame64<shift) shift=shift-frame64; else shift=0; shiftAudioVideoBy(shift); } return 1; }