Skip to content

Commit

Permalink
[coreVideoEncoder] Go back to fake constant frame rate mode, derive F…
Browse files Browse the repository at this point in the history
…PS from time base when it matches a standard one

Some video encoders like HEVC NVENC don't handle time base not being equal
the inverse of frame rate well. This patch tries to fix in particular
an extremely low output bitrate with HEVC NVENC and fallback time base of
1/90000 which Avidemux chooses for most variable frame rate source videos.
  • Loading branch information
eumagga0x2a committed Dec 2, 2020
1 parent 85bc8a7 commit 388aa89
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ virtual uint64_t getEncoderDelay(void){return encoderDelay;}
uint64_t lastDts; //
};
ADM_COREVIDEOENCODER6_EXPORT bool usSecondsToFrac(uint64_t useconds, int *n, int *d, int maxclock=0xFFFF); // mpeg4 allows a maximum of 1<<16-1 as time base
ADM_COREVIDEOENCODER6_EXPORT bool isStdFrameRate(int &frameRateNum, int &frameRateDen);
ADM_COREVIDEOENCODER6_EXPORT bool ADM_pluginGetPath(const std::string& pluginName,int pluginVersion,std::string &rootPath);
ADM_COREVIDEOENCODER6_EXPORT bool ADM_pluginInstallSystem(const std::string& pluginName,const std::string& ext,int pluginVersion);
ADM_COREVIDEOENCODER6_EXPORT bool ADM_listFile(const std::string& path,const std::string& extension,vector <std::string > & list);
Expand Down
36 changes: 36 additions & 0 deletions avidemux_core/ADM_coreVideoEncoder/src/ADM_coreVideoEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,42 @@ bool usSecondsToFrac(uint64_t useconds, int *n, int *d, int limit)
return true;
}

/**
\fn stdFrameRate
\brief Check that given num/den pair matches a known standard frame rate
*/
bool isStdFrameRate(int &frameRateNum, int &frameRateDen)
{
if(frameRateNum < 1 || frameRateDen < 1)
return false;
int nn,dd;
#define MAX_CLOCK 180000
#define MAX_FPS 60
if(!av_reduce(&nn, &dd, frameRateNum, frameRateDen, MAX_CLOCK))
return false;
if(dd != 1 && dd != 1001)
return false;
if(nn/dd > MAX_FPS)
return false;
if(dd == 1)
{
dd*=1000;
nn*=1000;
}
int nb=sizeof(fpsTable)/sizeof(TimeIncrementType);
for(int i=0;i<nb;i++)
{
TimeIncrementType *t=fpsTable+i;
if(t->d == nn && t->n == dd)
{
frameRateNum = nn;
frameRateDen = dd;
return true;
}
}
return false;
}

/**
\fn getRealPtsFromInternal
\brief Lookup in the stored value to get the exact pts from the truncated one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ extern "C"
char *av_strdup(const char *s);
void *av_malloc(size_t size) ;
}
//#define TIME_TENTH_MILLISEC
#define USE_REAL_TIME_BASE
#if 1
#define aprintf(...) {}
#else
Expand Down Expand Up @@ -341,27 +339,41 @@ bool ADM_coreVideoEncoderFFmpeg::setupInternal(AVCodec *codec)
prolog(image);

FilterInfo *info=source->getInfo();
#if defined(TIME_TENTH_MILLISEC)
_context->time_base.num=1;
_context->time_base.den=10000LL;
#elif defined(USE_REAL_TIME_BASE)
int n = timeScalerNum = info->timeBaseNum & 0x7FFFFFFF;
int d = timeScalerDen = info->timeBaseDen & 0x7FFFFFFF;
ADM_assert(timeScalerNum);
ADM_assert(timeScalerDen);
if(codec->id == AV_CODEC_ID_MPEG4)
av_reduce(&n,&d,timeScalerNum,timeScalerDen,0xFFFF);
_context->time_base.num=n;
_context->time_base.den=d;
#else
int n,d;
usSecondsToFrac(info->frameIncrement,&n,&d);
_context->time_base.num=n;
_context->time_base.den=d;
#endif
int n = info->timeBaseNum & 0x7FFFFFFF;
int d = info->timeBaseDen & 0x7FFFFFFF;
ADM_assert(n);
ADM_assert(d);
if(isStdFrameRate(d,n))
{
_context->time_base.num = _context->framerate.den = n;
_context->time_base.den = _context->framerate.num = d;
}else
{
int maxClockFreq = 0x7FFFFFFF;
switch(codec->id)
{
case AV_CODEC_ID_MPEG4:
maxClockFreq = 0xFFFF;
break;
case AV_CODEC_ID_MPEG2VIDEO:
maxClockFreq = 90000;
break;
default:break;
}
usSecondsToFrac(info->frameIncrement,&n,&d,maxClockFreq);
_context->time_base.num = _context->framerate.den = n;
_context->time_base.den = _context->framerate.num = d;
if(codec->id == AV_CODEC_ID_MPEG2VIDEO && !isStdFrameRate(d,n))
{
ADM_error("Non-standard frame rate %d/%d is not supported for mpeg2video.\n",d,n);
return false;
}
}
timeScalerNum=_context->time_base.num;
timeScalerDen=_context->time_base.den;
printf("[ff] Time base %d/%d\n", _context->time_base.num,_context->time_base.den);
printf("[ff] Time base: %d/%d, frame rate: %d/%d\n",
_context->time_base.num, _context->time_base.den,
_context->framerate.num, _context->framerate.den);
if(_hasSettings && LAVS(MultiThreaded))
{
encoderMT();
Expand Down

0 comments on commit 388aa89

Please sign in to comment.