Forked from quietvoid/singlepass-scenecut-aware-qp.patch
Last active
July 24, 2023 00:18
-
-
Save al3xtjames/6c50b26615d12a6440441bdfd17c4bba to your computer and use it in GitHub Desktop.
Enables x265 --scenecut-aware-qp for single pass, fixes float precision in settings string and allows offset to be set to 0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/source/common/param.cpp b/source/common/param.cpp | |
index 1a4df4cdc..e1505b29e 100755 | |
--- a/source/common/param.cpp | |
+++ b/source/common/param.cpp | |
@@ -1832,10 +1832,10 @@ int x265_check_params(x265_param* param) | |
"Invalid SAO tune level. Value must be between 0 and 4 (inclusive)"); | |
if (param->bEnableSceneCutAwareQp) | |
{ | |
- if (!param->rc.bStatRead) | |
+ if (param->bEnableSceneCutAwareQp != FORWARD && !param->rc.bStatRead) | |
{ | |
param->bEnableSceneCutAwareQp = 0; | |
- x265_log(param, X265_LOG_WARNING, "Disabling Scenecut Aware Frame Quantizer Selection since it works only in pass 2\n"); | |
+ x265_log(param, X265_LOG_WARNING, "Disabling Scenecut Aware Frame Quantizer Selection since single pass only works with Forward masking\n"); | |
} | |
else | |
{ | |
@@ -2327,8 +2327,8 @@ char *x265_param2string(x265_param* p, int padx, int pady) | |
s += sprintf(s, " qp-adaptation-range=%.2f", p->rc.qpAdaptationRange); | |
s += sprintf(s, " scenecut-aware-qp=%d", p->bEnableSceneCutAwareQp); | |
if (p->bEnableSceneCutAwareQp) | |
- s += sprintf(s, " fwd-scenecut-window=%d fwd-ref-qp-delta=%f fwd-nonref-qp-delta=%f bwd-scenecut-window=%d bwd-ref-qp-delta=%f bwd-nonref-qp-delta=%f", p->fwdMaxScenecutWindow, p->fwdRefQpDelta[0], p->fwdNonRefQpDelta[0], p->bwdMaxScenecutWindow, p->bwdRefQpDelta[0], p->bwdNonRefQpDelta[0]); | |
- s += sprintf(s, "conformance-window-offsets right=%d bottom=%d", p->confWinRightOffset, p->confWinBottomOffset); | |
+ s += sprintf(s, " fwd-scenecut-window=%d fwd-ref-qp-delta=%.2f fwd-nonref-qp-delta=%.2f bwd-scenecut-window=%d bwd-ref-qp-delta=%.2f bwd-nonref-qp-delta=%.2f", p->fwdScenecutWindow, p->fwdRefQpDelta[0], p->fwdNonRefQpDelta[0], p->bwdScenecutWindow, p->bwdRefQpDelta[0], p->bwdNonRefQpDelta[0]); | |
+ s += sprintf(s, " conformance-window-offsets right=%d bottom=%d", p->confWinRightOffset, p->confWinBottomOffset); | |
s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate); | |
BOOL(p->bliveVBV2pass, "vbv-live-multi-pass"); | |
if (p->filmGrain) | |
@@ -2420,9 +2420,9 @@ bool parseMaskingStrength(x265_param* p, const char* value) | |
{ | |
if (window1[0] > 0) | |
p->fwdMaxScenecutWindow = window1[0]; | |
- if (refQpDelta1[0] > 0) | |
+ if (refQpDelta1[0] >= 0) | |
p->fwdRefQpDelta[0] = refQpDelta1[0]; | |
- if (nonRefQpDelta1[0] > 0) | |
+ if (nonRefQpDelta1[0] >= 0) | |
p->fwdNonRefQpDelta[0] = nonRefQpDelta1[0]; | |
p->fwdScenecutWindow[0] = p->fwdMaxScenecutWindow / 6; | |
@@ -2459,9 +2459,9 @@ bool parseMaskingStrength(x265_param* p, const char* value) | |
{ | |
if (window1[0] > 0) | |
p->bwdMaxScenecutWindow = window1[0]; | |
- if (refQpDelta1[0] > 0) | |
+ if (refQpDelta1[0] >= 0) | |
p->bwdRefQpDelta[0] = refQpDelta1[0]; | |
- if (nonRefQpDelta1[0] > 0) | |
+ if (nonRefQpDelta1[0] >= 0) | |
p->bwdNonRefQpDelta[0] = nonRefQpDelta1[0]; | |
p->bwdScenecutWindow[0] = p->bwdMaxScenecutWindow / 6; | |
@@ -2500,15 +2500,15 @@ bool parseMaskingStrength(x265_param* p, const char* value) | |
{ | |
if (window1[0] > 0) | |
p->fwdMaxScenecutWindow = window1[0]; | |
- if (refQpDelta1[0] > 0) | |
+ if (refQpDelta1[0] >= 0) | |
p->fwdRefQpDelta[0] = refQpDelta1[0]; | |
- if (nonRefQpDelta1[0] > 0) | |
+ if (nonRefQpDelta1[0] >= 0) | |
p->fwdNonRefQpDelta[0] = nonRefQpDelta1[0]; | |
if (window2[0] > 0) | |
p->bwdMaxScenecutWindow = window2[0]; | |
- if (refQpDelta2[0] > 0) | |
+ if (refQpDelta2[0] >= 0) | |
p->bwdRefQpDelta[0] = refQpDelta2[0]; | |
- if (nonRefQpDelta2[0] > 0) | |
+ if (nonRefQpDelta2[0] >= 0) | |
p->bwdNonRefQpDelta[0] = nonRefQpDelta2[0]; | |
p->fwdScenecutWindow[0] = p->fwdMaxScenecutWindow / 6; | |
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp | |
index c2dd6f4e8..9d9ce12fc 100644 | |
--- a/source/encoder/encoder.cpp | |
+++ b/source/encoder/encoder.cpp | |
@@ -2129,17 +2129,27 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) | |
frameEnc = m_lookahead->getDecidedPicture(); | |
if (frameEnc && !pass && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd))) | |
{ | |
- if ((m_param->bEnableSceneCutAwareQp & FORWARD) && m_param->rc.bStatRead) | |
+ if (m_param->bEnableSceneCutAwareQp & FORWARD) | |
{ | |
- RateControlEntry * rcEntry; | |
- rcEntry = &(m_rateControl->m_rce2Pass[frameEnc->m_poc]); | |
+ bool isSceneCut = frameEnc->m_lowres.bScenecut; | |
- if (rcEntry->scenecut) | |
+ // If multi pass, overwrite with stats file scenecut info | |
+ if (m_param->rc.bStatRead) | |
+ { | |
+ RateControlEntry * rcEntry; | |
+ rcEntry = &(m_rateControl->m_rce2Pass[frameEnc->m_poc]); | |
+ | |
+ isSceneCut = rcEntry->scenecut; | |
+ } | |
+ | |
+ if (isSceneCut) | |
{ | |
+ // No previous scenecut | |
if (m_rateControl->m_lastScenecut == -1) | |
m_rateControl->m_lastScenecut = frameEnc->m_poc; | |
else | |
{ | |
+ // Only set as scenecut if it's not within an existing scenecut forward window | |
int maxWindowSize = int((m_param->fwdMaxScenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5); | |
if (frameEnc->m_poc > (m_rateControl->m_lastScenecut + maxWindowSize)) | |
m_rateControl->m_lastScenecut = frameEnc->m_poc; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment