- "Smart" resize instead of relying on ffmpeg for the logic. This fixes the bug with anamorphic video getting messed up aspect ratios.
- Normalize resolution will always normalize anamorphic videos, even if they have the same dimensions. - When transcoding and normalize resolution being off, padding will not be added. But there's a special case for odd dimensions, where it needs to add 1 pixel. - Changed scaling algorithm to 'billinear_fast'. It has 'fast' in the name, so hopefully it's faster?
This commit is contained in:
parent
ee08b3a601
commit
461dfea071
@ -215,17 +215,58 @@ class FFMPEG extends events.EventEmitter {
|
||||
|
||||
// Resolution fix: Add scale filter, current stream becomes [siz]
|
||||
let beforeSizeChange = currentVideo;
|
||||
if (this.ensureResolution && (iW != this.wantedW || iH != this.wantedH) ) {
|
||||
//Maybe the scaling algorithm could be configurable. bicubic seems good though
|
||||
videoComplex += `;${currentVideo}scale=${this.wantedW}:${this.wantedH}:flags=bicubic:force_original_aspect_ratio=decrease,pad=${this.wantedW}:${this.wantedH}:(ow-iw)/2:(oh-ih)/2[siz]`
|
||||
currentVideo = "[siz]";
|
||||
iW = this.wantedW;
|
||||
iH = this.wantedH;
|
||||
} else if ( isLargerResolution(iW, iH, this.wantedW, this.wantedH) ) {
|
||||
videoComplex += `;${currentVideo}scale=${this.wantedW}:${this.wantedH}:flags=bicubic:force_original_aspect_ratio=decrease,pad=${this.wantedW}:${this.wantedH}:(ow-iw)/2:(oh-ih)/2[minsiz]`
|
||||
currentVideo = "[minsiz]";
|
||||
iW = this.wantedW;
|
||||
iH = this.wantedH;
|
||||
let algo = "fast_bilinear";
|
||||
let resizeMsg = "";
|
||||
if (
|
||||
(this.ensureResolution && ( streamStats.anamorphic || (iW != this.wantedW || iH != this.wantedH) ) )
|
||||
||
|
||||
isLargerResolution(iW, iH, this.wantedW, this.wantedH)
|
||||
) {
|
||||
//scaler stuff, need to change the size of the video and also add bars
|
||||
// calculate wanted aspect ratio
|
||||
let p = iW * streamStats.pixelP ;
|
||||
let q = iH * streamStats.pixelQ;
|
||||
let g = gcd(q,p); // and people kept telling me programming contests knowledge had no use real programming!
|
||||
p = Math.floor(p / g);
|
||||
q = Math.floor(q / g);
|
||||
let hypotheticalW1 = this.wantedW;
|
||||
let hypotheticalH1 = Math.floor(hypotheticalW1*q / p);
|
||||
let hypotheticalH2 = this.wantedH;
|
||||
let hypotheticalW2 = Math.floor( (this.wantedH * p) / q );
|
||||
let cw, ch;
|
||||
if (hypotheticalH1 <= this.wantedH) {
|
||||
cw = hypotheticalW1;
|
||||
ch = hypotheticalH1;
|
||||
} else {
|
||||
cw = hypotheticalW2;
|
||||
ch = hypotheticalH2;
|
||||
}
|
||||
videoComplex += `;${currentVideo}scale=${cw}:${ch}:flags=${algo}[scaled]`;
|
||||
currentVideo = "scaled";
|
||||
resizeMsg = `Stretch to ${cw} x ${ch}. To fit target resolution of ${this.wantedW} x ${this.wantedH}.`;
|
||||
if (this.ensureResolution) {
|
||||
console.log(`First stretch to ${cw} x ${ch}. Then add padding to make it ${this.wantedW} x ${this.wantedH} `);
|
||||
} else if (cw % 2 == 1 || ch % 2 ==1) {
|
||||
//we need to add padding so that the video dimensions are even
|
||||
let xw = cw + cw % 2;
|
||||
let xh = ch + ch % 2;
|
||||
resizeMsg = `Stretch to ${cw} x ${ch}. To fit target resolution of ${this.wantedW} x ${this.wantedH}. Then add 1 pixel of padding so that dimensions are not odd numbers, because they are frowned upon. The final resolution will be ${xw} x ${xh}`;
|
||||
this.wantedW = xw;
|
||||
this.wantedH = xh;
|
||||
} else {
|
||||
resizeMsg = `Stretch to ${cw} x ${ch}. To fit target resolution of ${this.wantedW} x ${this.wantedH}.`;
|
||||
}
|
||||
if ( (this.wantedW != cw) || (this.wantedH != ch) ) {
|
||||
// also add black bars, because in this case it HAS to be this resolution
|
||||
videoComplex += `;[${currentVideo}]pad=${this.wantedW}:${this.wantedH}:(ow-iw)/2:(oh-ih)/2[blackpadded]`;
|
||||
currentVideo = "blackpadded";
|
||||
}
|
||||
let name = "siz";
|
||||
if (! this.ensureResolution) {
|
||||
name = "minsiz";
|
||||
}
|
||||
videoComplex += `;[${currentVideo}]setsar=1[${name}]`;
|
||||
currentVideo = `[${name}]`;
|
||||
}
|
||||
|
||||
// Channel overlay:
|
||||
@ -265,6 +306,8 @@ class FFMPEG extends events.EventEmitter {
|
||||
//do not change resolution if no other transcoding will be done
|
||||
// and resolution normalization is off
|
||||
currentVideo = beforeSizeChange;
|
||||
} else {
|
||||
console.log(resizeMsg)
|
||||
}
|
||||
if (currentVideo != '[video]') {
|
||||
transcodeVideo = true; //this is useful so that it adds some lines below
|
||||
@ -411,8 +454,8 @@ function isDifferentAudioCodec(codec, encoder) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function isLargerResolution(w1,h1, w2,h2) {
|
||||
return (w1 > w2) || (h1 > h2);
|
||||
function isLargerResolution( w1,h1, w2,h2) {
|
||||
return (w1 > w2) || (h1 > h2) || (w1 % 2 ==1) || (h1 % 2 == 1);
|
||||
}
|
||||
|
||||
function parseResolutionString(s) {
|
||||
@ -429,4 +472,15 @@ function parseResolutionString(s) {
|
||||
}
|
||||
}
|
||||
|
||||
function gcd(a, b) {
|
||||
|
||||
while (b != 0) {
|
||||
console.log(a,b);
|
||||
let c = b;
|
||||
b = a % b;
|
||||
a = c;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
module.exports = FFMPEG
|
||||
|
||||
@ -208,6 +208,18 @@ lang=en`
|
||||
streams.forEach(function (stream) {
|
||||
// Video
|
||||
if (stream["streamType"] == "1") {
|
||||
ret.anamorphic = (stream.anamorphic === "1");
|
||||
if (ret.anamorphic) {
|
||||
let parsed = parsePixelAspectRatio(stream.pixelAspectRatio);
|
||||
if (isNaN(parsed.p) || isNaN(parsed.q) ) {
|
||||
throw Error("isNaN");
|
||||
}
|
||||
ret.pixelP = parsed.p;
|
||||
ret.pixelQ = parsed.q;
|
||||
} else {
|
||||
ret.pixelP= 1;
|
||||
ret.pixelQ = 1;
|
||||
}
|
||||
ret.videoCodec = stream.codec;
|
||||
ret.videoWidth = stream.width;
|
||||
ret.videoHeight = stream.height;
|
||||
@ -342,4 +354,12 @@ X-Plex-Token=${this.server.accessToken}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function parsePixelAspectRatio(s) {
|
||||
let x = s.split(":");
|
||||
return {
|
||||
p: parseInt(x[0], 10),
|
||||
q: parseInt(x[1], 10),
|
||||
}
|
||||
}
|
||||
module.exports = PlexTranscoder
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user