/** \fn save */ bool muxerMp4v2::save(void) { bool result=true; int nbFrame=0; printf("[Mp4v2Muxer] Saving\n"); initUI("Saving MP4V2"); encoding->setContainer("MP4 (libmp4v2)"); uint64_t lastSentDts=0; while(loadNextVideoFrame((&(in[nextWrite])))) { bool kf=false; int other=!nextWrite; if(in[other].flags & AVI_KEY_FRAME) kf=true; ADM_assert(in[nextWrite].dts!=ADM_NO_PTS) ADM_assert(in[nextWrite].dts!=ADM_NO_PTS) if(in[other].pts==ADM_NO_PTS || in[other].pts==ADM_NO_PTS) { GUI_Error_HIG("Video","Video does not have enough timing information. Are you copying from AVI ?"); goto theEnd; } uint64_t nextDts=in[nextWrite].dts; // Delta between dts=duration of the frame (sort of) uint64_t myDts=in[other].dts; uint64_t myPts=in[other].pts; cprintf(">>next DTS=%"PRIu64", last DTS=%"PRIu64"delta=%"PRIu64"\n",nextDts,lastSentDts,nextDts-lastSentDts); encoding->pushVideoFrame(in[other].len,in[other].out_quantizer,myDts); uint64_t delta=myPts-lastSentDts; // composition time... delta=timeScale(delta); uint64_t duration=nextDts-lastSentDts; uint64_t scaled_duration=timeScale(duration); duration=inverseTimeScale(scaled_duration); // handle rounding error nbFrame++; cprintf("Sending frame duration=%"PRIu64", pts/dts=%"PRIu64"\n",lastSentDts,delta); if(false==MP4WriteSample(handle,videoTrackId,in[other].data,in[other].len, scaled_duration, // duration delta, // pts/dts offset kf // Sync Sample )) { ADM_error("Cannot write video sample\n"); result=false; goto theEnd; } // update lastSentDts lastSentDts+=duration; // beginning of next frame... // cprintf("lastSendDts=%"PRIu64", next Dts=%"PRIu64", skew=%"PRId64"\n",lastSentDts,nextDts, (int64_t)nextDts-(int64_t)lastSentDts); // fillAudio(lastSentDts); // toggle nextWrite=other; if(updateUI()==false) { result=false; break; } } // Write last frame nextWrite=!nextWrite; int scale; if(videoIncrement>5000) scale=(1000000.0/videoIncrement); else scale=100; // 10 ms MP4WriteSample(handle,videoTrackId,in[nextWrite].data,in[nextWrite].len, (MP4Duration)90000/scale, 0, // pts/dts offset 0 // Sync Sample ); theEnd: close(); if(muxerConfig.optimize && result==true) { encoding->setPhasis("Optimizing"); string tmpTargetFileName=targetFileName+string(".tmp"); if(!ADM_renameFile(targetFileName.c_str(),tmpTargetFileName.c_str())) { GUI_Error_HIG("","Cannot rename file (optimize)"); return false; } // Optimize ADM_info("Optimizing...\n"); MP4Optimize( tmpTargetFileName.c_str(), targetFileName.c_str() ); // delete unlink(tmpTargetFileName.c_str()); } closeUI(); return result; }
void TimeSpinBox::reportChange() { kDebug() << i18n( "Reporting new timestep value: " ) << timeScale(); emit scaleChanged( timeScale() ); }