Skip to content

Commit

Permalink
[videoCodec][editor] Drain decoder to retrieve last decoded video fra…
Browse files Browse the repository at this point in the history
…mes + move to the new lavc API
  • Loading branch information
eumagga0x2a committed Jan 4, 2018
1 parent 1244d98 commit ade4b26
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 80 deletions.
1 change: 1 addition & 0 deletions avidemux/common/ADM_editor/include/ADM_edit.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ protected:
int64_t _nextFrameDts; // COPYMODE Used in copy mode to fill the missing timestamp
// Warning, it is actually the DTS of the NEXT frame to fetch
uint8_t compBuffer[MAXIMUM_SIZE * MAXIMUM_SIZE * 3]; // Buffer used for decoding
bool endOfStream; // The decoder has been flushed and no more compressed images from demuxer
//****************************** Audio **********************************
// _audiooffset points to the offset / the total segment
// not the used part !
Expand Down
92 changes: 63 additions & 29 deletions avidemux/common/ADM_editor/src/ADM_edRenderInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,20 @@ bool ADM_Composer::seektoTime(uint32_t ref,uint64_t timeToSeek,bool dontdecode)
EditorCache *cache =vid->_videoCache;
ADM_assert(cache);
bool found=false;
ADMImage *image=cache->getByPts(timeToSeek);
if(image)
{
vid->lastReadPts=timeToSeek;
ADM_info("Image found in cache, pts=%" PRIu64" ms\n",timeToSeek/1000);
endOfStream=false;
return true;
}
// Search the previous keyframe for segment....
uint64_t seekTime;
if(_segments.isKeyFrameByTime(ref,timeToSeek))
{
seekTime=timeToSeek;
ADM_info("First frame of the new segment is a keyframe at %" PRIu32"ms\n",seekTime/1000);
ADM_info("Seeking to a keyframe at %" PRIu64" ms\n",seekTime/1000);
found=true;
}else
{
Expand All @@ -58,6 +66,7 @@ bool ADM_Composer::seektoTime(uint32_t ref,uint64_t timeToSeek,bool dontdecode)
}
}
uint32_t frame=_segments.intraTimeToFrame(ref,seekTime);
ADM_info("Seeking to frame %" PRIu32" at %" PRIu64" ms\n",frame,seekTime/1000);
if(dontdecode==true)
{
vid->lastSentFrame=frame;
Expand All @@ -68,7 +77,7 @@ bool ADM_Composer::seektoTime(uint32_t ref,uint64_t timeToSeek,bool dontdecode)

if(false==DecodePictureUpToIntra(ref,frame))
{
ADM_warning("Cannot decode up to intra %" PRIu64" at %" PRIu64" ms\n",frame,seekTime/1000);
ADM_warning("Cannot decode up to intra %" PRIu32" at %" PRIu64" ms\n",frame,seekTime/1000);
return false;
}
if(found==true) return true;
Expand Down Expand Up @@ -142,6 +151,11 @@ bool ADM_Composer::nextPictureInternal(uint32_t ref,ADMImage *out,uint64_t time)
// Try decoding loop rames ahead, if not we can consider it fails
while(loop--)
{
if(endOfStream)
{
ADM_warning("End of stream, skipping decoding the next picture\n");
return false;
}
// first decode a picture, cannot hurt...
if(DecodeNextPicture(ref)==false)
{
Expand Down Expand Up @@ -194,12 +208,16 @@ bool ADM_Composer::DecodeNextPicture(uint32_t ref)
{
EditorCache *cache;
ADMImage *result;
bool drain=false;
uint32_t flags;
ADMCompressedImage img;
_VIDEOS *vid=_segments.getRefVideo(ref);
vidHeader *demuxer=vid->_aviheader;
cache=vid->_videoCache;
ADM_assert(vid->decoder);
if(vid->decoder->endOfStreamReached())
return false;
cache=vid->_videoCache;
// PlaceHolder...
ADMCompressedImage img;
img.data=compBuffer;
img.cleanup(vid->lastSentFrame+1);

Expand All @@ -210,31 +228,42 @@ bool ADM_Composer::DecodeNextPicture(uint32_t ref)
aprintf("[EditorRender] DecodeNext %u ref:%u\n",frame,ref);
// Fetch frame
aprintf("[Editor] Decoding frame %u\n",frame);
if (!demuxer->getFrame (frame,&img))
{
drain=vid->decoder->getDrainingState();
if(!drain)
{
if(!demuxer->getFrame(frame,&img))
{
ADM_warning("getFrame failed for frame %" PRIu32"\n",vid->lastSentFrame);
return false;
}

// Now uncompress it...
result=cache->getFreeImage();
if(!result)
{
ADM_warning(" Cache full for frame %" PRIu32"\n",vid->lastSentFrame);
return false;
}
drain=true;
vid->decoder->setDrainingState(true);
}else
{
endOfStream=false;
}
}
// Now uncompress it...
result=cache->getFreeImage();
if(!result)
{
ADM_warning(" Cache full for frame %" PRIu32"\n",vid->lastSentFrame);
return false;
}
if(!drain)
{
aprintf("Demuxed frame %" PRIu32" with pts=%" PRId64" us, %" PRId64" ms\n",
frame,
img.demuxerPts,
img.demuxerPts/1000);

if(!decompressImage(result,&img,ref))
{
ADM_info("Decoding error for frame %" PRIu32", not necessarily a problem\n",vid->lastSentFrame);
stats.nbNoImage++;
cache->invalidate(result);
}
if(!decompressImage(result,&img,ref))
{
ADM_info("Decoding error for frame %" PRIu32", not necessarily a problem\n",vid->lastSentFrame);
stats.nbNoImage++;
cache->invalidate(result);
if(drain)
endOfStream=true;
return true; // Not an error in itself
}
}
aprintf("Got image with PTS=%s\n",ADM_us2plain(result->Pts));
uint64_t pts=result->Pts;
uint64_t old=vid->lastDecodedPts;
Expand Down Expand Up @@ -389,7 +418,6 @@ bool ADM_Composer::decompressImage(ADMImage *out,ADMCompressedImage *in,uint32_t
*/
bool ADM_Composer::DecodePictureUpToIntra(uint32_t ref,uint32_t frame)
{
uint8_t ret = 0;
EditorCache *cache;
ADMImage *result;
uint32_t flags,flagsNext=0;
Expand All @@ -399,11 +427,11 @@ bool ADM_Composer::DecodePictureUpToIntra(uint32_t ref,uint32_t frame)
img.data=compBuffer;
img.cleanup(frame);

ADM_info(" DecodeUpToInta %u ref:%u\n",frame,ref);
_VIDEOS *vid=_segments.getRefVideo(ref);
ADM_info("Decoding up to intra frame %u, ref: %u\n",frame,ref);
_VIDEOS *vid=_segments.getRefVideo(ref);
vidHeader *demuxer=vid->_aviheader;
cache=vid->_videoCache;
ADM_assert(cache);
cache=vid->_videoCache;
ADM_assert(cache);
// Make sure frame is an intra, or the next field is intra
demuxer->getFlags(frame,&flags);
demuxer->getFlags(frame+1,&flagsNext);
Expand All @@ -419,12 +447,18 @@ bool ADM_Composer::DecodePictureUpToIntra(uint32_t ref,uint32_t frame)
aprintf("[EditorRender] DecodeUpToIntra flushing cache & codec\n");
cache->flush();
vid->decoder->flush();
vid->decoder->setEndOfStream(false);
// The PTS associated with our frame is the one we are looking for
uint64_t wantedPts=demuxer->estimatePts(frame);
uint32_t tries=15+7; // Max Ref frames for H264 + MaxRecovery , let's say 7 is ok for recovery
bool syncFound=false;
while(found==false && tries--)
{
if(vid->decoder->endOfStreamReached())
{
ADM_warning("End of stream reached\n");
break;
}
// Last frame ? if so repeat
if(vid->lastSentFrame>=nbFrames-1) vid->lastSentFrame=nbFrames-1;
// Fetch frame
Expand All @@ -434,7 +468,7 @@ bool ADM_Composer::DecodePictureUpToIntra(uint32_t ref,uint32_t frame)
{
ADM_warning(" getFrame failed for frame %" PRIu32"\n",vid->lastSentFrame);
//cache->flush();
return false;
vid->decoder->setDrainingState(true);
}
// Now uncompress it...
result=cache->getFreeImage();
Expand Down
1 change: 1 addition & 0 deletions avidemux/common/ADM_editor/src/ADM_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ bool ADM_Composer::addFile (const char *name)
ADM_info("Halving Fps...\n");
_segments.halfFps();
}
endOfStream=false;
return 1;
}
#if 0
Expand Down
35 changes: 17 additions & 18 deletions avidemux/common/ADM_videoCodec/src/ADM_ffmpeg_dxva2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,16 +441,6 @@ bool decoderFFDXVA2::uncompress (ADMCompressedImage * in, ADMImage * out)
out->refType=ADM_HW_NONE;
}

if (!in->dataLength ) // Null frame, silently skipped
{
out->_noPicture = 1;
out->Pts=ADM_COMPRESSED_NO_PTS;
out->refType=ADM_HW_NONE;
ADM_info("[LibVa] Nothing to decode -> no Picture\n");
return false;
}


if (!in->dataLength ) // Null frame, silently skipped
{
out->_noPicture = 1;
Expand All @@ -475,16 +465,25 @@ bool decoderFFDXVA2::uncompress (ADMCompressedImage * in, ADMImage * out)

AVFrame *frame=_parent->getFramePointer();
ADM_assert(frame);
int ret = avcodec_decode_video2 (_context, frame, &got_picture, &pkt);

if(ret<0)
if(_parent->getDrainingState())
{
char er[2048]={0};
av_make_error_string(er, sizeof(er)-1, ret);
ADM_warning("DXVA: Error %d in lavcodec (%s)\n",ret,er);
out->refType=ADM_HW_NONE;
return false;
if(_parent->getDrainingInitiated()==false)
{
avcodec_send_packet(_context, NULL);
_parent->setDrainingInitiated(true);
}
}else
{
avcodec_send_packet(_context, &pkt);
}

int ret = avcodec_receive_frame(_context, frame);

if(!ret)
_parent->setEndOfStream(false);
if(!_parent->decodeErrorHandler(ret))
return false;

if(frame->pict_type==AV_PICTURE_TYPE_NONE)
{
out->_noPicture=true;
Expand Down
25 changes: 17 additions & 8 deletions avidemux/common/ADM_videoCodec/src/ADM_ffmpeg_libva.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,16 +496,25 @@ bool decoderFFLIBVA::uncompress (ADMCompressedImage * in, ADMImage * out)

AVFrame *frame=_parent->getFramePointer();
ADM_assert(frame);
int ret = avcodec_decode_video2 (_context, frame, &got_picture, &pkt);

if(ret<0)
if(_parent->getDrainingState())
{
char er[2048]={0};
av_make_error_string(er, sizeof(er)-1, ret);
ADM_warning("Error %d in lavcodec (%s)\n",ret,er);
out->refType=ADM_HW_NONE;
return false;
if(_parent->getDrainingInitiated()==false)
{
avcodec_send_packet(_context, NULL);
_parent->setDrainingInitiated(true);
}
}else
{
avcodec_send_packet(_context, &pkt);
}

int ret = avcodec_receive_frame(_context, frame);

if(!ret)
_parent->setEndOfStream(false);
if(!_parent->decodeErrorHandler(ret))
return false;

if(frame->pict_type==AV_PICTURE_TYPE_NONE)
{
out->_noPicture=true;
Expand Down
24 changes: 17 additions & 7 deletions avidemux/common/ADM_videoCodec/src/ADM_ffmpeg_vdpau.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,15 +383,25 @@ bool decoderFFVDPAU::uncompress (ADMCompressedImage * in, ADMImage * out)

AVFrame *frame=_parent->getFramePointer();
ADM_assert(frame);
int ret = avcodec_decode_video2 (_context, frame, &got_picture, &pkt);

if(ret<0)
if(_parent->getDrainingState())
{
char er[2048]={0};
av_make_error_string(er, sizeof(er)-1, ret);
ADM_warning("Error %d in lavcodec (%s)\n",ret,er);
return false;
if(_parent->getDrainingInitiated()==false)
{
avcodec_send_packet(_context, NULL);
_parent->setDrainingInitiated(true);
}
}else
{
avcodec_send_packet(_context, &pkt);
}

int ret = avcodec_receive_frame(_context, frame);

if(!ret)
_parent->setEndOfStream(false);
if(!_parent->decodeErrorHandler(ret))
return false;

if(frame->pict_type==AV_PICTURE_TYPE_NONE)
{
out->_noPicture=true;
Expand Down
10 changes: 10 additions & 0 deletions avidemux_core/ADM_coreVideoCodec/include/ADM_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ class decoders
{
return false;
}
virtual bool endOfStreamReached(void)
{
return false;
}
virtual void setEndOfStream(bool reached) { };
virtual bool getDrainingState(void)
{
return 0;
}
virtual void setDrainingState(bool drain) { };
virtual bool flush(void)
{
return true;
Expand Down
15 changes: 11 additions & 4 deletions avidemux_core/ADM_coreVideoCodec/include/ADM_ffmp43.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ friend class ADM_acceleratedDecoderFF;

uint8_t _allowNull;
bool hurryUp;
bool _drain;
bool _done;
bool _endOfStream;
bool _setBpp;
bool _setFcc;
int codecId;
Expand All @@ -72,15 +75,12 @@ friend class ADM_acceleratedDecoderFF;
uint32_t _threads;
ADM_acceleratedDecoderFF *hwDecoder;
decoderFF_param_t decoderFF_params;


protected:
uint32_t frameType (void);
uint8_t clonePic (AVFrame * src, ADMImage * out);
void decoderMultiThread ();
uint32_t admFrameTypeFromLav (AVFrame *pic);



public:
decoderFF (uint32_t w, uint32_t h,uint32_t fcc, uint32_t extraDataLen, uint8_t *extraData,uint32_t bpp);
Expand All @@ -107,7 +107,14 @@ friend class ADM_acceleratedDecoderFF;
// virtual uint32_t getSpecificMpeg4Info (void);
virtual uint8_t getPARWidth (void);
virtual uint8_t getPARHeight (void);
virtual bool flush(void);
virtual bool decodeErrorHandler(int code, bool headerOnly=false);
virtual bool endOfStreamReached(void) { return _endOfStream; }
virtual void setEndOfStream(bool reached) { _endOfStream=reached; }
virtual bool getDrainingState(void) { return _drain; }
virtual void setDrainingState(bool OnOff) { _drain=OnOff; }
virtual bool getDrainingInitiated(void) { return _done; }
virtual void setDrainingInitiated(bool initiated) { _done=initiated; }
virtual bool flush(void);
virtual const char *getDecoderName(void)
{
if(hwDecoder)
Expand Down
4 changes: 3 additions & 1 deletion avidemux_core/ADM_coreVideoCodec/src/ADM_ffVp9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ bool decoderFFVP9::uncompress (ADMCompressedImage * in, ADMImage * out)
xlog("Parse %d\n",in->dataLength);
while(offset<in->dataLength)
{
int bufSize=in->dataLength-offset;
if(_drain) bufSize=0;
int r=av_parser_parse2( _parserContext, _context,
&parsedPointer, &parsedLen,
in->data+offset, in->dataLength-offset,
in->data+offset, bufSize,
in->demuxerPts, in->demuxerDts, -1);
if(r<=0 || !parsedPointer)
break;
Expand Down
Loading

0 comments on commit ade4b26

Please sign in to comment.