From a1806d3a332c44def79e28a25b411104a13b19a9 Mon Sep 17 00:00:00 2001 From: mean Date: Tue, 26 Jul 2016 18:33:01 +0200 Subject: [PATCH] [editor] Try to not drop bframes that will be used later as reference (h264/h265 in copy mode). Experimental, that can cause problems --- .../common/ADM_editor/include/ADM_edit.hxx | 7 +- .../common/ADM_editor/include/ADM_segment.h | 9 +- .../common/ADM_editor/src/ADM_edRender.cpp | 2 +- .../common/ADM_editor/src/ADM_edSearch.cpp | 12 +-- .../common/ADM_editor/src/ADM_edVideoCopy.cpp | 95 +++++++++++++++++-- .../ADM_muxerGate/src/ADM_videoCopy.cpp | 19 +++- 6 files changed, 121 insertions(+), 23 deletions(-) diff --git a/avidemux/common/ADM_editor/include/ADM_edit.hxx b/avidemux/common/ADM_editor/include/ADM_edit.hxx index 10a6f02181..c94d4fe3ad 100644 --- a/avidemux/common/ADM_editor/include/ADM_edit.hxx +++ b/avidemux/common/ADM_editor/include/ADM_edit.hxx @@ -222,9 +222,9 @@ public: public: uint64_t getLastKeyFramePts(void); uint64_t getCurrentFramePts(void); - bool setCurrentFramePts(uint64_t pts); + bool setCurrentFramePts(uint64_t pts); bool goToTimeVideo(uint64_t time); - void getCurrentFrameFlags(uint32_t *flags, uint32_t *quantiser); + void getCurrentFrameFlags(uint32_t *flags, uint32_t *quantiser); bool goToIntraTimeVideo(uint64_t time); bool nextPicture(ADMImage *image,bool dontcross=false); bool samePicture(ADMImage *image); @@ -239,6 +239,7 @@ public: public: uint8_t updateVideoInfo(aviInfo *info); uint32_t getSpecificMpeg4Info( void ); + bool getNonClosedGopDelay(uint64_t time,uint32_t *delay); /************************************ /audioStream ******************************/ bool getAudioStreamsInfo(uint64_t xtime,uint32_t *nbStreams, audioInfo **infos); bool changeAudioStream(uint64_t xtime,uint32_t newstream); @@ -267,7 +268,7 @@ public: bool getPKFramePTS(uint64_t *frameTime); bool getDtsFromPts(uint64_t *time); /// Returns pts-dts for given frame - bool getPtsDtsDelta(uint64_t *frameTime); + bool getPtsDtsDelta(uint64_t frametime, uint64_t *delta); /******************************* Post Processing ************************************/ uint8_t setPostProc( uint32_t type, uint32_t strength, bool swapuv); uint8_t getPostProc( uint32_t *type, uint32_t *strength,bool *swapuv); diff --git a/avidemux/common/ADM_editor/include/ADM_segment.h b/avidemux/common/ADM_editor/include/ADM_segment.h index ad8d59743a..c724a47f3f 100644 --- a/avidemux/common/ADM_editor/include/ADM_segment.h +++ b/avidemux/common/ADM_editor/include/ADM_segment.h @@ -100,6 +100,11 @@ class _VIDEOS \brief The video is a collection of segment. Each segment refers to its source (the reference) and the part of the source the segment is made of. */ + +#define ADM_NO_DROP 0 +#define ADM_DROPPING 2 +#define ADM_DROP_MAYBE_AFER_SWITCH 1 + class _SEGMENT { public: @@ -107,7 +112,7 @@ class _SEGMENT uint64_t _refStartTimeUs; /// Starting time in reference uint64_t _startTimeUs; /// Start time in current (=sum(_duration of previous seg)) uint64_t _durationUs; /// - uint32_t _dropBframes; + uint32_t _dropBframes; /// Internal state machine to know is we should drop bframe that are orphean uint64_t _refStartDts; void clear(void) { @@ -115,7 +120,7 @@ class _SEGMENT _refStartTimeUs=0; _startTimeUs=0; _durationUs=0; - _dropBframes=0; + _dropBframes=ADM_NO_DROP; _refStartDts=0; } _SEGMENT() {clear();} diff --git a/avidemux/common/ADM_editor/src/ADM_edRender.cpp b/avidemux/common/ADM_editor/src/ADM_edRender.cpp index 080528194d..cf42bb2f58 100644 --- a/avidemux/common/ADM_editor/src/ADM_edRender.cpp +++ b/avidemux/common/ADM_editor/src/ADM_edRender.cpp @@ -129,7 +129,7 @@ bool ADM_Composer::GoToIntraTime_noDecoding(uint64_t time,uint32_t *tofra dts=time; _nextFrameDts=dts; - seg->_dropBframes=1; + seg->_dropBframes=ADM_DROP_MAYBE_AFER_SWITCH; return true; } /** diff --git a/avidemux/common/ADM_editor/src/ADM_edSearch.cpp b/avidemux/common/ADM_editor/src/ADM_edSearch.cpp index e4161fc607..93a653d0eb 100644 --- a/avidemux/common/ADM_editor/src/ADM_edSearch.cpp +++ b/avidemux/common/ADM_editor/src/ADM_edSearch.cpp @@ -149,21 +149,21 @@ bool r; \fn getPtsDtsDelta */ -bool ADM_Composer::getPtsDtsDelta(uint64_t *frameTime) +bool ADM_Composer::getPtsDtsDelta(uint64_t frameTime, uint64_t *outDelta) { uint64_t refTime,nkTime,segTime; int lastSeg=_segments.getNbSegments(); uint32_t seg; bool r; // 1- Convert frameTime to segments - if(false== _segments.convertLinearTimeToSeg( *frameTime, &seg, &segTime)) + if(false== _segments.convertLinearTimeToSeg( frameTime, &seg, &segTime)) { - ADM_warning(" Cannot find seg for time %" PRId64"\n",*frameTime); + ADM_warning(" Cannot find seg for time %" PRId64"\n",frameTime); return false; } // _SEGMENT *s=_segments.getSegment(seg); - int64_t delta=*frameTime-s->_startTimeUs; // Delta compared to the beginning of this seg + int64_t delta=(int64_t)frameTime-(int64_t)s->_startTimeUs; // Delta compared to the beginning of this seg delta+=s->_refStartTimeUs; if(delta<0) @@ -178,11 +178,11 @@ bool r; if(false==_segments.dtsFromPts(ref,refTime,&dts)) { ADM_error("Cannot get dtsFromDts for time %" PRIu64"\n",refTime); - *frameTime=0; + *outDelta=0; return false; } // Ok we have PTS and DTS, returns difference - *frameTime=refTime-dts; + *outDelta=refTime-dts; return true; } /** diff --git a/avidemux/common/ADM_editor/src/ADM_edVideoCopy.cpp b/avidemux/common/ADM_editor/src/ADM_edVideoCopy.cpp index 289f42a12f..3949e5fb61 100644 --- a/avidemux/common/ADM_editor/src/ADM_edVideoCopy.cpp +++ b/avidemux/common/ADM_editor/src/ADM_edVideoCopy.cpp @@ -95,9 +95,87 @@ bool ADM_Composer::checkCutsAreOnIntra(void) */ static bool bFrameDroppable(uint32_t fcc) { - if(isH264Compatible(fcc)) return false; + if(isH264Compatible(fcc)) + return false; + if(isH265Compatible(fcc)) + return false; return true; } +/** + * + * @param time + * @param delay + * @return + */ +bool ADM_Composer::getNonClosedGopDelay(uint64_t time,uint32_t *delay) +{ + aviInfo info; + uint32_t segNo; + uint64_t segTime; + *delay=0; + if(!_segments.convertLinearTimeToSeg(time,&segNo,&segTime)) + { + ADM_warning("Cannot navigate to get nonclosedgop\n"); + return false; + } + _SEGMENT *seg=_segments.getSegment(segNo); + ADM_assert(seg); + _VIDEOS *vid=_segments.getRefVideo(seg->_reference); + uint64_t pts,dts; + + vid->_aviheader->getVideoInfo (&info); + // + if(bFrameDroppable(info.fcc)) + { + return true; // no need to add extra delay + } + // Look ahead to see if we have some late bframe in the past + int nb=vid->_aviheader->getMainHeader ()->dwTotalFrames; + int found=-1; + if(!segTime) + { + found=0; + vid->_aviheader->getPtsDts(0,&pts,&dts); + } + else + for(int i=0;i_aviheader->getPtsDts (i,&pts,&dts); + if(pts==segTime) + { + found=i; + break; + } + } + if(found==-1) + { + ADM_warning("Cannot find the frame\n"); + return false; + } + for(int i=found+1;i_aviheader->getFlags(i,&flags); + if(!(flags & AVI_B_FRAME)) + { + ADM_info("Not a bframe, stopping (%d)\n",i-found); + break; + } + vid->_aviheader->getPtsDts(i,&pts,&dts); + if(pts*delay) *delay=delta; + }else + { + ADM_info("Pts delta = %d\n",(int)(pts-segTime)); + } + } + ADM_info("Found maximum non closed gop delay = %d\n",*delay); + return true; +} + /** \fn getCompressedPicture \brief bypass decoder and directly get the source image @@ -143,7 +221,7 @@ bool ADM_Composer::getCompressedPicture(uint64_t videoDelay,ADMCompressed { if(img->flags & AVI_B_FRAME) { - if(seg->_dropBframes==2) + if(seg->_dropBframes==ADM_DROPPING) { ADM_warning("%" PRIu32" Dropping bframes\n",fn); goto againGet; @@ -152,8 +230,9 @@ bool ADM_Composer::getCompressedPicture(uint64_t videoDelay,ADMCompressed { // not a bframe switch(seg->_dropBframes) { - case 2: seg->_dropBframes=0;break; - case 1: seg->_dropBframes=2;break; + case ADM_NO_DROP : break; + case ADM_DROPPING : seg->_dropBframes=ADM_NO_DROP;break; + case ADM_DROP_MAYBE_AFER_SWITCH : seg->_dropBframes=ADM_DROPPING;break; default: break; } } @@ -174,7 +253,7 @@ bool ADM_Composer::getCompressedPicture(uint64_t videoDelay,ADMCompressed } // Seeking is not accurate when cutting on non intra // we might have some frames that are clearly too early , even in seg0 - if(img->demuxerPts!=ADM_NO_PTS) + if(img->demuxerPts!=ADM_NO_PTS && bFrameDroppable(info.fcc)) { if(img->demuxerPts+seg->_startTimeUs_refStartTimeUs) { @@ -232,8 +311,8 @@ bool ADM_Composer::getCompressedPicture(uint64_t videoDelay,ADMCompressed // border case due to rounding we can have pts slighly above dts if(signedPts!=ADM_NO_PTS && _nextFrameDts!=ADM_NO_PTS) { - signedDts=_nextFrameDts; - if(signedPts != ADM_NO_PTS && signedDts>signedPts) + signedDts=_nextFrameDts; + if(signedPts != ADM_NO_PTS && signedDts>signedPts) { // not sure it is correct. We may want to do it the other way around, i.e. bumping pts ADM_warning("Compensating for rounding error with PTS=%" PRId64"ms DTS=%" PRId64"ms \n",signedPts,signedDts); @@ -305,7 +384,7 @@ bool ADM_Composer::getCompressedPicture(uint64_t videoDelay,ADMCompressed } // Mark it as drop b frames... _SEGMENT *thisseg=_segments.getSegment(_currentSegment); - thisseg->_dropBframes=1; + thisseg->_dropBframes=ADM_DROP_MAYBE_AFER_SWITCH; ADM_info("Retrying for next segment\n"); return getCompressedPicture(videoDelay,img); diff --git a/avidemux/common/ADM_muxerGate/src/ADM_videoCopy.cpp b/avidemux/common/ADM_muxerGate/src/ADM_videoCopy.cpp index 4ea2db70e7..adfcaaf66c 100644 --- a/avidemux/common/ADM_muxerGate/src/ADM_videoCopy.cpp +++ b/avidemux/common/ADM_muxerGate/src/ADM_videoCopy.cpp @@ -50,14 +50,25 @@ ADM_videoStreamCopy::ADM_videoStreamCopy(uint64_t startTime,uint64_t endTime) ptsStart=dtsStart=startTime; }else { - uint64_t delta=ptsStart; - video_body->getPtsDtsDelta(&delta); + // Do we have non droppable b frame ? + uint32_t bframeDelay; + if(true==video_body->getNonClosedGopDelay(ptsStart,&bframeDelay)) + { + ADM_info("Some B frames are non droppable, increasing delat by %d us\n",bframeDelay); + videoDelay+=bframeDelay; + }else + { + videoDelay=0; + } + + uint64_t delta=0; + video_body->getPtsDtsDelta(ptsStart,&delta); ADM_info("PTS/DTS delta=%" PRIu64" us\n",delta); //videoDelay if(delta>ptsStart) { - videoDelay=delta-ptsStart; + videoDelay+=delta-ptsStart; dtsStart=0; ADM_info("Dts is too early, delaying everything by %" PRIu64" ms\n",videoDelay/1000); }else @@ -68,6 +79,8 @@ ADM_videoStreamCopy::ADM_videoStreamCopy(uint64_t startTime,uint64_t endTime) } eofMet=false; + + this->startTimeDts=dtsStart; this->startTimePts=ptsStart; this->endTimePts=endTime;