/** * \fn compute the minimum us delta = maximum fps * \brief average fps is not good enough, it might be too high * @return */ bool MP4Header::refineFps(void) { int n=VDEO.nbIndex; uint64_t minDelta=60*1000*1000; for(int i=0;i<n-1;i++) { MP4Index *dex=&(_tracks[0].index[i]); MP4Index *next=&(_tracks[0].index[i+1]); if(dex->dts==ADM_NO_PTS) continue; if(next->dts==ADM_NO_PTS) continue; uint64_t delta=next->dts-dex->dts; if(delta<minDelta) minDelta=delta; } if(minDelta>1000) { double f=1000000./(double)minDelta; f*=1000.; ADM_info("MinDelta=%d us\n",(int)minDelta); ADM_info("Computed fps1000=%d\n",(int)f); uint32_t fps1000=floor(f+0.49); if(fps1000> _videostream.dwRate) { ADM_info("Adjusting fps, the computed is higher than average, dropped frames ?\n"); _videostream.dwRate=fps1000; _mainaviheader.dwMicroSecPerFrame=ADM_UsecFromFps1000(_videostream.dwRate); } } }
/** \fn updateIncrement \brief FPS->TimeIncrement */ bool resampleFps::updateIncrement(void) { float f=configuration.newFpsNum*1000; f/=configuration.newFpsDen; info.frameIncrement=ADM_UsecFromFps1000((uint32_t)f); return true; }
/** \fn mx_mainHeaderFromVideoStream \brief Write MainAVIHeader from video */ void mx_mainHeaderFromVideoStream(MainAVIHeader *header,ADM_videoStream *video) { memset(header,0,sizeof(*header)); header->dwMicroSecPerFrame= ADM_UsecFromFps1000(video->getAvgFps1000()); //int32_t dwMicroSecPerFrame; // frame display rate (or 0L) header->dwMaxBytesPerSec=8*1000*1000; //int32_t dwMaxBytesPerSec; // max. transfer rate header->dwPaddingGranularity=0; //int32_t dwPaddingGranularity; // pad to multiples of this // size; normally 2K. header->dwFlags= AVIF_HASINDEX + AVIF_ISINTERLEAVED; // FIXME HAS INDEX //int32_t dwFlags; // the ever-present flags //header->dwTotalFrames=0; //int32_t dwTotalFrames; // # frames in file header->dwInitialFrames=0; //int32_t dwInitialFrames; // Must be set by caller header->dwStreams=int32_t dwStreams; header->dwSuggestedBufferSize=64*1024;// int32_t dwSuggestedBufferSize; header->dwWidth=video->getWidth();//int32_t dwWidth; header->dwHeight=video->getHeight();//int32_t dwHeight; }
/** \fn parseStbl \brief parse sample table. this is the most important function. */ uint8_t MP4Header::parseStbl(void *ztom,uint32_t trackType,uint32_t w,uint32_t h,uint32_t trackScale) { adm_atom *tom=(adm_atom *)ztom; ADMAtoms id; uint32_t container; MPsampleinfo info; memset(&info,0,sizeof(info)); printf("<<Parsing Stbl>>\n"); while(!tom->isDone()) { adm_atom son(tom); if(!ADM_mp4SearchAtomName(son.getFCC(), &id,&container)) { adm_printf(ADM_PRINT_DEBUG,"[STBL]Found atom %s unknown\n",fourCC::tostringBE(son.getFCC())); son.skipAtom(); continue; } switch(id) { case ADM_MP4_STSS: // Sync sample atom (i.e. keyframes) { son.read32(); info.nbSync=son.read32(); printf("Stss:%u\n",info.nbSync); if(info.nbSync) { info.Sync=new uint32_t[info.nbSync]; for(int i=0;i<info.nbSync;i++) { info.Sync[i]=son.read32(); } } break; } case ADM_MP4_STTS: { printf("stts:%lu\n",son.read32()); // version & flags info.nbStts=son.read32(); printf("Time stts atom found (%lu)\n",info.nbStts); printf("Using myscale %lu\n",trackScale); info.SttsN=new uint32_t[info.nbStts]; info.SttsC=new uint32_t[info.nbStts]; double dur; for(int i=0;i<info.nbStts;i++) { info.SttsN[i]=son.read32(); info.SttsC[i]=son.read32(); adm_printf(ADM_PRINT_VERY_VERBOSE,"stts: count:%u size:%u (unscaled)\n",info.SttsN[i],info.SttsC[i]); //dur*=1000.*1000.;; // us //dur/=myScale; } } break; case ADM_MP4_STSC: { son.read32(); info.nbSc=son.read32(); info.Sc=new uint32_t[info.nbSc]; info.Sn=new uint32_t[info.nbSc]; for(int j=0;j<info.nbSc;j++) { info.Sc[j]=son.read32(); info.Sn[j]=son.read32(); son.read32(); adm_printf(ADM_PRINT_VERY_VERBOSE,"\t sc %d : sc start:%u sc count: %u\n",j,info.Sc[j],info.Sn[j]); } } break; case ADM_MP4_STSZ: { uint32_t n; son.read32(); n=son.read32(); info.nbSz=son.read32(); info.SzIndentical=0; printf("%lu frames /%lu nbsz..\n",n,info.nbSz); if(n) { adm_printf(ADM_PRINT_VERY_VERBOSE,"\t\t%lu frames of the same size %lu , n=%lu\n", info.nbSz,info.SzIndentical,n); info.SzIndentical=n; info.Sz=NULL; } else { info.Sz=new uint32_t[info.nbSz]; for(int j=0;j<info.nbSz;j++) { info.Sz[j]=son.read32(); } } } break; case ADM_MP4_CTTS: // Composition time to sample { uint32_t n,i,j,k,v; printf("ctts:%lu\n",son.read32()); // version & flags n=son.read32(); if(n==1) // all the same , ignore { break; } uint32_t *values=new uint32_t [n]; uint32_t *count=new uint32_t [n]; for(i=0;i<n;i++) { count[i]=son.read32(); values[i]=son.read32(); } uint32_t sum=0; for(i=0;i<n;i++) { sum+=count[i]; } info.Ctts=new uint32_t[sum+1]; // keep a safe margin for(i=0;i<n;i++) { if(i<20) { adm_printf(ADM_PRINT_VERY_VERBOSE,"Ctts: nb: %u (%x) val:%u (%x)\n",count[i],count[i],values[i],values[i]); } for(k=0;k<count[i];k++) { info.Ctts[info.nbCtts++]=values[i]; } } delete [] values; delete [] count; if(!info.nbCtts) { delete [] info.Ctts; info.Ctts=NULL; printf("Destroying Ctts, seems invalid\n"); } ADM_assert(info.nbCtts<sum+1); printf("Found %u elements\n",info.nbCtts); } break; case ADM_MP4_STCO: { son.read32(); info.nbCo=son.read32(); printf("\t\tnbCo:%u\n",info.nbCo); info.Co=new uint32_t[info.nbCo]; for(int j=0;j< info.nbCo;j++) { info.Co[j]=son.read32(); adm_printf(ADM_PRINT_VERY_VERBOSE,"Chunk offset : %u / %u : %u\n", j,info.nbCo,info.Co[j]); } } break; case ADM_MP4_STCO64: { printf("Incomplete support for 64 bits quicktime!!\n"); son.read32(); info.nbCo=son.read32(); printf("\t\tnbCo:%u\n",info.nbCo); info.Co=new uint32_t[info.nbCo]; for(int j=0;j< info.nbCo;j++) { son.read32(); // Ignore MSB info.Co[j]=son.read32(); adm_printf(ADM_PRINT_VERY_VERBOSE,"Chunk offset : %u / %u : %lu\n", j,info.nbCo,info.Co[j]); } } break; case ADM_MP4_STSD: { son.read32(); // flags & version int nbEntries=son.read32(); int left; adm_printf(ADM_PRINT_DEBUG,"[STSD]Found %d entries\n",nbEntries); for(int i=0;i<nbEntries;i++) { int entrySize=son.read32(); int entryName=son.read32(); left=entrySize-8; if(i || (trackType==TRACK_VIDEO && _videoFound) || (trackType==TRACK_OTHER)) { son.skipBytes(left); printf("[STSD] ignoring %s, size %u\n",fourCC::tostringBE(entryName),entrySize); if(trackType==TRACK_OTHER) printf("[STSD] because track=other\n"); continue; } switch(trackType) { case TRACK_VIDEO: { uint32_t lw=0,lh=0; printf("[STSD] VIDEO %s, size %u\n",fourCC::tostringBE(entryName),entrySize); son.skipBytes(8); // reserved etc.. left-=8; son.read32(); // version/revision left-=4; printf("[STSD] vendor %s\n",fourCC::tostringBE(son.read32())); left-=4; son.skipBytes(8); // spatial qual etc.. left-=8; printf("[STSD] width :%u\n",lw=son.read16()); printf("[STSD] height :%u\n",lh=son.read16()); left-=4; son.skipBytes(8); // Resolution left-=8; printf("[STSD] datasize :%u\n",son.read32()); left-=4; printf("[STSD] FrameCount :%u\n",son.read16()); left-=4; // Codec name uint32_t u32=son.read(); if(u32>31) u32=31; printf("Codec string :%d <",u32); for(int i=0;i<u32;i++) printf("%c",son.read()); printf(">\n"); son.skipBytes(32-1-u32); left-=32; // son.read32(); left-=4; //Depth & color Id // printf("LEFT:%d\n",left); if(left>8) { // decodeVideoAtom(&son); } // #define commonPart(x) _videostream.fccHandler=_video_bih.biCompression=fourCC::get((uint8_t *)#x); _video_bih.biWidth=_mainaviheader.dwWidth=lw ; _video_bih.biHeight=_mainaviheader.dwHeight=lh; _video_bih.biCompression=_videostream.fccHandler; // switch(entryName) { case MKFCCR('m','j','p','b'): //mjpegb { commonPart(MJPB); left=0; } break; case MKFCCR('s','2','6','3'): //s263 d263 { commonPart(H263); adm_atom d263(&son); printf("Reading s253, got %s\n",fourCC::tostringBE(d263.getFCC())); left=0; } break; case MKFCCR('m','p','4','v'): //mp4v { commonPart(DIVX); adm_atom esds(&son); printf("Reading esds, got %s\n",fourCC::tostringBE(esds.getFCC())); if(esds.getFCC()==MKFCCR('e','s','d','s')) decodeEsds(&esds,TRACK_VIDEO); left=0; } break; case MKFCCR('S','V','Q','3'): {//'SVQ3': // For SVQ3, the codec needs it to begin by SVQ3 // We go back by 4 bytes to get the 4CC printf("SVQ3 atom found\n"); VDEO.extraDataSize=left+4; VDEO.extraData=new uint8_t[ VDEO.extraDataSize ]; if(!son.readPayload(VDEO.extraData+4,VDEO.extraDataSize-4 )) { GUI_Error_HIG(QT_TR_NOOP("Problem reading SVQ3 headers"), NULL); } VDEO.extraData[0]='S'; VDEO.extraData[1]='V'; VDEO.extraData[2]='Q'; VDEO.extraData[3]='3'; printf("SVQ3 Header size : %lu",_videoExtraLen); commonPart(SVQ3); left=0; } break; case MKFCCR('d','v','c',' ') : //'dvc ': case MKFCCR('d','v','c','p'): //'dvcp': commonPart(DVDS); break; case MKFCCR('c','v','i','d'): //'cvid' commonPart(cvid); break; case MKFCCR('h','2','6','3'): //'dv': commonPart(H263); break; case MKFCCR('M','J','P','G'): //'jpeg': case MKFCCR('j','p','e','g'): //'jpeg': case MKFCCR('A','V','D','J'): //'jpeg': commonPart(MJPG); break; case MKFCCR('a','v','c','1'): // avc1 { commonPart(H264); // There is a avcC atom just after // configuration data for h264 adm_atom avcc(&son); printf("Reading avcC, got %s\n",fourCC::tostringBE(avcc.getFCC())); int len,offset; VDEO.extraDataSize=avcc.getRemainingSize(); VDEO.extraData=new uint8_t [VDEO.extraDataSize]; avcc.readPayload(VDEO.extraData,VDEO.extraDataSize); printf("avcC size:%d\n",VDEO.extraDataSize); // Dump some info #define MKD8(x) VDEO.extraData[x] #define MKD16(x) ((MKD8(x)<<8)+MKD8(x+1)) #define MKD32(x) ((MKD16(x)<<16)+MKD16(x+2)) printf("avcC Revision :%x\n", MKD8(0)); printf("avcC AVCProfileIndication :%x\n", MKD8(1)); printf("avcC profile_compatibility:%x\n", MKD8(2)); printf("avcC AVCLevelIndication :%x\n", MKD8(3)); printf("avcC lengthSizeMinusOne :%x\n", MKD8(4)); printf("avcC NumSeq :%x\n", MKD8(5)); len=MKD16(6); printf("avcC sequenceParSetLen :%x ",len ); offset=8; mixDump(VDEO.extraData+offset,len); offset=8+len; printf("\navcC numOfPictureParSets :%x\n", MKD8(offset++)); len=MKD16(offset++); printf("avcC Pic len :%x\n",len); mixDump(VDEO.extraData+offset,len); left=0; } break; default: if(left>10) { adm_atom avcc(&son); printf("Reading , got %s\n",fourCC::tostringBE(avcc.getFCC())); left=0; } break; } // Entry name } break; case TRACK_AUDIO: { uint32_t channels,bpp,encoding,fq,packSize; // Put some defaults ADIO.encoding=1234; ADIO.frequency=44100; ADIO.byterate=128000>>3; ADIO.channels=2; ADIO.bitspersample=16; printf("[STSD] AUDIO <%s>, 0x%08x, size %u\n",fourCC::tostringBE(entryName),entryName,entrySize); son.skipBytes(8); // reserved etc.. left-=8; int atomVersion=son.read16(); // version left-=2; printf("[STSD]Revision :%d\n",atomVersion); son.skipBytes(2); // revision left-=2; printf("[STSD]Vendor : %s\n",fourCC::tostringBE(son.read32())); left-=4; ADIO.channels=channels=son.read16(); // Channel left-=2; printf("[STSD]Channels :%d\n",ADIO.channels); ADIO.bitspersample=bpp=son.read16(); // version/revision left-=2; printf("[STSD]Bit per sample :%d\n",bpp); encoding=son.read16(); // version/revision left-=2; printf("[STSD]Encoding :%d\n",encoding); packSize=son.read16(); // Packet Size left-=2; printf("[STSD]Packet size :%d\n",encoding); fq=ADIO.frequency=son.read16(); printf("[STSD]Fq:%u\n",fq); if(ADIO.frequency<6000) ADIO.frequency=48000; printf("[STSD]Fq :%d\n",ADIO.frequency); // Bps son.skipBytes(2); // Fixed point left-=4; if(atomVersion) { info.samplePerPacket=son.read32(); info.bytePerPacket=son.read32(); info.bytePerFrame=son.read32(); printf("[STSD] Sample per packet %u\n",info.samplePerPacket); printf("[STSD] Bytes per packet %u\n",info.bytePerPacket); printf("[STSD] Bytes per frame %u\n",info.bytePerFrame); printf("[STSD] Bytes per sample %u\n",son.read32()); left-=16; }else { info.samplePerPacket=1; info.bytePerPacket=1; info.bytePerFrame=1; } switch(atomVersion) { case 0:break; case 1: break; case 2: ADIO.frequency=44100; // FIXME ADIO.channels=son.read32(); printf("Channels :%d\n",ADIO.channels); // Channels printf("Tak(7F000) :%x\n",son.read32()); // Channels printf("Bits per channel :%d\n",son.read32()); // Vendor printf("Format specific :%x\n",son.read32()); // Vendor printf("Byte per audio packe:%x\n",son.read32()); // Vendor printf("LPCM :%x\n",son.read32()); // Vendor left-=(5*4+4+16); break; } printf("[STSD] chan:%u bpp:%u encoding:%u fq:%u (left %u)\n",channels,bpp,encoding,fq,left); #define audioCodec(x) ADIO.encoding=WAV_##x; switch(entryName) { case MKFCCR('t','w','o','s'): audioCodec(LPCM); ADIO.byterate=ADIO.frequency*ADIO.bitspersample*ADIO.channels/8; break; case MKFCCR('u','l','a','w'): audioCodec(ULAW); ADIO.byterate=ADIO.frequency; break; case MKFCCR('s','o','w','t'): audioCodec(PCM); ADIO.byterate=ADIO.frequency*ADIO.bitspersample*ADIO.channels/8; break; case MKFCCR('.','m','p','3'): //.mp3 audioCodec(MP3); ADIO.byterate=128000>>3; break; case MKFCCR('r','a','w',' '): audioCodec(8BITS_UNSIGNED); ADIO.byterate=ADIO.frequency*ADIO.channels; break; case MKFCCR('s','a','m','r'): { audioCodec(AMRNB); ADIO.frequency=8000; ADIO.channels=1; ADIO.bitspersample=16; ADIO.byterate=12000/8; if(left>10) { adm_atom amr(&son); printf("Reading wave, got %s\n",fourCC::tostringBE(amr.getFCC())); left=0; } } break; case MKFCCR('Q','D','M','2'): { uint32_t sz; audioCodec(QDM2); sz=son.getRemainingSize(); _tracks[1+nbAudioTrack].extraDataSize=sz; _tracks[1+nbAudioTrack].extraData=new uint8_t[sz]; son.readPayload(_tracks[1+nbAudioTrack].extraData,sz); left=0; } break; case MKFCCR('m','s',0,0x55): // why 55 ??? case MKFCCR('m','p','4','a'): { audioCodec(AAC); if(left>10) { adm_atom wave(&son); printf("Reading wave, got %s\n",fourCC::tostringBE(wave.getFCC())); if(MKFCCR('w','a','v','e')==wave.getFCC()) { // mp4a // wave // frma // mp4a // esds while(!wave.isDone()) { adm_atom item(&wave); printf("parsing wave, got %s,0x%x\n",fourCC::tostringBE(item.getFCC()), item.getFCC()); switch(item.getFCC()) { case MKFCCR('f','r','m','a'): { uint32_t codecid=item.read32(); printf("frma Codec Id :%s\n",fourCC::tostringBE(codecid)); } break; case MKFCCR('m','s',0,0x55): { // We have a waveformat here printf("[STSD]Found MS audio header:\n"); ADIO.encoding=ADM_swap16(item.read16()); ADIO.channels=ADM_swap16(item.read16()); ADIO.frequency=ADM_swap32(item.read32()); ADIO.byterate=ADM_swap32(item.read32()); ADIO.blockalign=ADM_swap16(item.read16()); ADIO.bitspersample=ADM_swap16(item.read16()); printWavHeader(&(ADIO)); } break; case MKFCCR('m','p','4','a'): break; case MKFCCR('e','s','d','s'): { decodeEsds(&item,TRACK_AUDIO); goto foundit; // FIXME!!! } break; default: break; } item.skipAtom(); } // Wave iddone left=0; } // if ==wave else { if(wave.getFCC()==MKFCCR('e','s','d','s')) { decodeEsds(&wave,TRACK_AUDIO); goto foundit; // FIXME!!! } else { printf("UNHANDLED ATOM : %s\n",fourCC::tostringBE(wave.getFCC())); } } } // if left > 10 foundit: // HACK FIXME left=0; } break; // mp4a } } break; default: ADM_assert(0); } son.skipBytes(left); } } break; default: printf("[STBL]Skipping atom %s\n",fourCC::tostringBE(son.getFCC())); } son.skipAtom(); } uint8_t r=0; uint32_t nbo=0; switch(trackType) { case TRACK_VIDEO: { if(_tracks[0].index) { printf("Already got a video track\n"); return 1; } r=indexify(&(_tracks[0]),trackScale,&info,0,&nbo); _videostream.dwLength= _mainaviheader.dwTotalFrames=_tracks[0].nbIndex; // update fps float f=_videostream.dwLength; if(_movieDuration) f=1000000.*f/_movieDuration; else f=25000; _videostream.dwRate=(uint32_t)floor(f); _mainaviheader.dwMicroSecPerFrame=ADM_UsecFromFps1000(_videostream.dwRate); // if we have a sync atom ??? if(info.nbSync) { // Mark keyframes for(int i=0;i<info.nbSync;i++) { int sync=info.Sync[i]; if(sync) sync--; _tracks[0].index[sync].intra=AVI_KEY_FRAME; } } else { // All frames are kf for(int i=0;i<_tracks[0].nbIndex;i++) { _tracks[0].index[i].intra=AVI_KEY_FRAME; } } // Now do the CTTS thing if(info.Ctts) { updateCtts(&info); } VDEO.index[0].intra=AVI_KEY_FRAME; } break; case TRACK_AUDIO: printf("Cur audio track :%u\n",nbAudioTrack); if(info.SzIndentical ==1 && (ADIO.encoding==WAV_LPCM || ADIO.encoding==WAV_PCM )) { printf("Overriding size %lu -> %lu\n", info.SzIndentical,info.SzIndentical*2*ADIO.channels); info.SzIndentical=info.SzIndentical*2*ADIO.channels; } r=indexify(&(_tracks[1+nbAudioTrack]),trackScale,&info,1,&nbo); printf("Indexed audio, nb blocks:%u\n",nbo); if(r) { nbo=_tracks[1+nbAudioTrack].nbIndex; if(nbo) _tracks[1+nbAudioTrack].nbIndex=nbo; else _tracks[1+nbAudioTrack].nbIndex=info.nbSz; printf("Indexed audio, nb blocks:%u (final)\n",_tracks[1+nbAudioTrack].nbIndex); _tracks[1+nbAudioTrack].scale=trackScale; nbAudioTrack++; } break; case TRACK_OTHER: r=1; break; } return r; }
uint8_t flvHeader::open(char *name) { uint32_t prevLen, type, size, pts,pos=0; _isvideopresent=0; _isaudiopresent=0; audioTrack=NULL; videoTrack=NULL; _filename=ADM_strdup(name); _fd=fopen(name,"rb"); if(!_fd) { printf("[FLV] Cannot open %s\n",name); return 0; } // Get size uint32_t fileSize=0; fseeko(_fd,0,SEEK_END); fileSize=ftello(_fd); fseeko(_fd,0,SEEK_SET); printf("[FLV] file size :%u bytes\n",fileSize); // It must begin by F L V 01 uint8_t four[4]; read(4,four); if(four[0]!='F' || four[1]!='L' || four[2]!='V') { printf("[FLV] Not a flv file %s\n",name); return 0; } // Next one is flags uint32_t flags=read8(); if(flags & 1) // VIDEO { _isvideopresent=1; printf("[FLV] Video flag\n"); }else { GUI_Info_HIG(ADM_LOG_INFO,"Warning","This FLV file says it has no video.\nI will assume it has and try to continue"); _isvideopresent=1; } if(flags & 4) // Audio { _isaudiopresent=1; printf("[FLV] Audio flag\n"); } // Skip header uint32_t skip=read32(); fseeko(_fd,skip,SEEK_SET); printf("[FLV] Skipping %u header bytes\n",skip); pos=ftello(_fd);; printf("pos:%u/%u\n",pos,fileSize); // Create our video index videoTrack=new flvTrak(50); if(_isaudiopresent) audioTrack=new flvTrak(50); else audioTrack=NULL; // Loop while(pos<fileSize-14) { pos=ftello(_fd); prevLen=read32(); type=read8(); size=read24(); pts=read24(); read32(); // ??? uint32_t remaining=size; //printf("[FLV] At %08x found type %x size %u pts%u\n",pos,type,size,pts); switch(type) { case FLV_TAG_TYPE_AUDIO: { if(!_isaudiopresent) { audioTrack=new flvTrak(50); _isaudiopresent=1; /* Damn lying headers...*/ }; uint8_t flags=read8(); int of=1+4+3+3+1+4; remaining--; int format=flags>>4; int fq=(flags>>2)&3; int bps=(flags>>1) & 1; int channel=(flags) & 1; if(!audioTrack->_nbIndex) // first frame.. { setAudioHeader(format,fq,bps,channel); } insertAudio(pos+of,remaining,pts); } break; case FLV_TAG_TYPE_VIDEO: { int of=1+4+3+3+1+4; uint8_t flags=read8(); remaining--; int frameType=flags>>4; int codec=(flags)&0xf; if(codec==FLV_CODECID_VP6) { read8(); // 1 byte of extraData remaining--; of++; } int first=0; if(!videoTrack->_nbIndex) first=1; insertVideo(pos+of,remaining,frameType,pts); if(first) // first frame.. { if(!setVideoHeader(codec,&remaining)) return 0; } } break; default: printf("[FLV]At 0x%x, unhandled type %u\n",pos,type); } Skip(remaining); } // while // Udpate frame count etc.. printf("[FLV] Found %u frames\n",videoTrack->_nbIndex); _videostream.dwLength= _mainaviheader.dwTotalFrames=videoTrack->_nbIndex; // Compute average fps float f=_videostream.dwLength; uint32_t duration=videoTrack->_index[videoTrack->_nbIndex-1].timeCode; if(duration) f=1000.*1000.*f/duration; else f=25000; _videostream.dwRate=(uint32_t)floor(f); _videostream.dwScale=1000; _mainaviheader.dwMicroSecPerFrame=ADM_UsecFromFps1000(_videostream.dwRate); printf("[FLV] Duration %u ms\n",videoTrack->_index[videoTrack->_nbIndex-1].timeCode); // _videostream.fccType=fourCC::get((uint8_t *)"vids"); _video_bih.biBitCount=24; _videostream.dwInitialFrames= 0; _videostream.dwStart= 0; videoTrack->_index[0].flags=AVI_KEY_FRAME; // audio track _audioStream=new flvAudio(name,audioTrack,&wavHeader); printf("[FLV]FLV successfully read\n"); return 1; }
bool avs_start(FilterInfo *info, FilterInfo *avisynth_info, char *fname, AVS_PIPES *avs_pipes) { DEBUG_PRINTF("avsfilter : avs_start()\n"); DEBUG_PRINTF("avsfilter : %X %X %s %X\n", avs_pipes[PIPE_LOADER_WRITE].hpipe, avs_pipes[PIPE_FILTER_WRITE].hpipe, fname, info); DEBUG_PRINTF("avsfilter : avs_start info : frameIncrement %lu totalDuration %llu\n", info->frameIncrement, info->totalDuration); ADV_Info aii, aio; aii.width = info->width; aii.height = info->height; aii.nb_frames = info->totalDuration / info->frameIncrement; aii.encoding = 1; aii.codec = 0; aii.fps1000 = ADM_Fps1000FromUs(info->frameIncrement); aii.orgFrame = 0; DEBUG_PRINTF("avsfilter : send ADV_Info to avsloader [fps1000 = %d, nb_frames = %d]\n", aii.fps1000, aii.nb_frames); if (!send_cmd(avs_pipes[PIPE_LOADER_WRITE].hpipe, LOAD_AVS_SCRIPT, fname, strlen(fname) + sizeof("\0")) || !send_cmd(avs_pipes[PIPE_FILTER_WRITE].hpipe, SET_CLIP_PARAMETER, &aii, sizeof(aii))) { DEBUG_PRINTF_RED("avsfilter : cannot set script name or set clip parameters\n"); deinit_pipes(avs_pipes, CMD_PIPE_NUM); return false; } // get avisynth frame info PIPE_MSG_HEADER msg; if (!receive_cmd(avs_pipes[PIPE_LOADER_READ].hpipe, &msg) || msg.avs_cmd != SET_CLIP_PARAMETER || !receive_data(avs_pipes[PIPE_LOADER_READ].hpipe, &msg, &aio)) { DEBUG_PRINTF_RED("avsfilter : cannot receive avisynth clip parameters\n"); deinit_pipes(avs_pipes, CMD_PIPE_NUM); return false; } DEBUG_PRINTF("avsfilter : receive ADV_Info from avsloader [fps1000 = %d, nb_frames = %d]\n", aio.fps1000, aio.nb_frames); avisynth_info->width = aio.width; avisynth_info->height = aio.height; avisynth_info->frameIncrement = ADM_UsecFromFps1000(aio.fps1000); avisynth_info->totalDuration = aio.nb_frames * avisynth_info->frameIncrement; // correct avisynth_info for span of frames, calculate fps change metrics /* float k_fps; k_fps = float(avisynth_info->frameIncrement) / float(info->frameIncrement); DEBUG_PRINTF("avsfilter : FPS change metrics %f\n", k_fps); avisynth_info->nb_frames = int (info->nb_frames * k_fps); avisynth_info->orgFrame = int (info->orgFrame * k_fps); DEBUG_PRINTF("avsfilter : Calculate new span for avisynth script [%d - %d]\n", avisynth_info->orgFrame,avisynth_info->orgFrame + avisynth_info->nb_frames);*/ return true; }