Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Usage: glsl-shader="~~/SSimSuperRes.glsl"
// SSimSuperRes by Shiandow
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library.
//!HOOK POSTKERNEL
//!BIND HOOKED
//!SAVE LOWRES
//!HEIGHT NATIVE_CROPPED.h
//!WHEN NATIVE_CROPPED.h OUTPUT.h <
//!COMPONENTS 4
//!DESC SSSR Downscaling I
#define axis 1
#define offset vec2(0,0)
#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C))
#define Kernel(x) MN(0.334, 0.333, abs(x))
#define taps 2.0
#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722))
vec4 hook() {
float low = ceil((HOOKED_pos - taps/input_size) * HOOKED_size - offset - 0.5)[axis];
float high = floor((HOOKED_pos + taps/input_size) * HOOKED_size - offset - 0.5)[axis];
float W = 0.0;
vec4 avg = vec4(0);
vec2 pos = HOOKED_pos;
vec4 tex;
for (float k = low; k <= high; k++) {
pos[axis] = HOOKED_pt[axis] * (k - offset[axis] + 0.5);
float rel = (pos[axis] - HOOKED_pos[axis])*input_size[axis];
float w = Kernel(rel);
tex.rgb = textureLod(HOOKED_raw, pos, 0.0).rgb * HOOKED_mul;
tex.a = Luma(tex.rgb);
avg += w * tex;
W += w;
}
avg /= W;
return vec4(avg.rgb, max(abs(avg.a - Luma(avg.rgb)), 5e-7));
}
//!HOOK POSTKERNEL
//!BIND LOWRES
//!SAVE LOWRES
//!WIDTH NATIVE_CROPPED.w
//!HEIGHT NATIVE_CROPPED.h
//!WHEN NATIVE_CROPPED.w OUTPUT.w <
//!COMPONENTS 4
//!DESC SSSR Downscaling II
#define axis 0
#define offset vec2(0,0)
#define MN(B,C,x) (x < 1.0 ? ((2.-1.5*B-(C))*x + (-3.+2.*B+C))*x*x + (1.-(B)/3.) : (((-(B)/6.-(C))*x + (B+5.*C))*x + (-2.*B-8.*C))*x+((4./3.)*B+4.*C))
#define Kernel(x) MN(0.334, 0.333, abs(x))
#define taps 2.0
#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722))
vec4 hook() {
float low = ceil((LOWRES_pos - taps/input_size) * LOWRES_size - offset - 0.5)[axis];
float high = floor((LOWRES_pos + taps/input_size) * LOWRES_size - offset - 0.5)[axis];
float W = 0.0;
vec4 avg = vec4(0);
vec2 pos = LOWRES_pos;
vec4 tex;
for (float k = low; k <= high; k++) {
pos[axis] = LOWRES_pt[axis] * (k - offset[axis] + 0.5);
float rel = (pos[axis] - LOWRES_pos[axis])*input_size[axis];
float w = Kernel(rel);
tex.rgb = textureLod(LOWRES_raw, pos, 0.0).rgb * LOWRES_mul;
tex.a = Luma(tex.rgb);
avg += w * tex;
W += w;
}
avg /= W;
return vec4(avg.rgb, max(abs(avg.a - Luma(avg.rgb)), 5e-7) + LOWRES_texOff(0).a);
}
//!HOOK POSTKERNEL
//!BIND PREKERNEL
//!BIND LOWRES
//!SAVE var
//!WIDTH NATIVE_CROPPED.w
//!HEIGHT NATIVE_CROPPED.h
//!WHEN NATIVE_CROPPED.h OUTPUT.h <
//!COMPONENTS 2
//!DESC SSSR var
#define spread 1.0 / 4.0
#define GetL(x,y) PREKERNEL_tex(PREKERNEL_pt * (PREKERNEL_pos * input_size + tex_offset + vec2(x,y))).rgb
#define GetH(x,y) LOWRES_texOff(vec2(x,y)).rgb
#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722))
#define diff(x,y) vec2(Luma((GetL(x,y) - meanL)), Luma((GetH(x,y) - meanH)))
vec4 hook() {
vec3 meanL = GetL(0,0);
vec3 meanH = GetH(0,0);
for (int X=-1; X<=1; X+=2) {
meanL += GetL(X,0) * spread;
meanH += GetH(X,0) * spread;
}
for (int Y=-1; Y<=1; Y+=2) {
meanL += GetL(0,Y) * spread;
meanH += GetH(0,Y) * spread;
}
meanL /= (1.0 + 4.0*spread);
meanH /= (1.0 + 4.0*spread);
vec2 var = diff(0,0);
for (int X=-1; X<=1; X+=2)
var += diff(X,0) * spread;
for (int Y=-1; Y<=1; Y+=2)
var += diff(0,Y) * spread;
return vec4(max(var / (1.0 + 4.0*spread), vec2(1e-6)), 0, 0);
}
//!HOOK POSTKERNEL
//!BIND HOOKED
//!BIND PREKERNEL
//!BIND LOWRES
//!BIND var
//!WHEN NATIVE_CROPPED.h OUTPUT.h <
//!DESC SSSR final pass
#define oversharp 0.4
// -- Window Size --
#define taps 3.0
#define even (taps - 2.0 * floor(taps / 2.0) == 0.0)
#define minX int(1.0-ceil(taps/2.0))
#define maxX int(floor(taps/2.0))
#define Kernel(x) cos(acos(-1.0)*(x)/taps) // Hann kernel
// -- Input processing --
#define var(x,y) var_tex(var_pt * (pos + vec2(x,y) + 0.5)).rg
#define GetL(x,y) PREKERNEL_tex(PREKERNEL_pt * (pos + tex_offset + vec2(x,y) + 0.5)).rgb
#define GetH(x,y) LOWRES_tex(LOWRES_pt * (pos + vec2(x,y) + 0.5))
#define Luma(rgb) dot(rgb*rgb, vec3(0.2126, 0.7152, 0.0722))
vec4 hook() {
vec4 c0 = HOOKED_texOff(0);
vec2 pos = HOOKED_pos * LOWRES_size - vec2(0.5);
vec2 offset = pos - (even ? floor(pos) : round(pos));
pos -= offset;
vec2 mVar = vec2(0.0);
for (int X=-1; X<=1; X++)
for (int Y=-1; Y<=1; Y++) {
vec2 w = clamp(1.5 - abs(vec2(X,Y)), 0.0, 1.0);
mVar += w.r * w.g * vec2(GetH(X,Y).a, 1.0);
}
mVar.r /= mVar.g;
// Calculate faithfulness force
float weightSum = 0.0;
vec3 diff = vec3(0);
for (int X = minX; X <= maxX; X++)
for (int Y = minX; Y <= maxX; Y++)
{
float R = (-1.0 - oversharp) * sqrt(var(X,Y).r / (var(X,Y).g + mVar.r));
vec2 krnl = Kernel(vec2(X,Y) - offset);
float weight = krnl.r * krnl.g / (Luma((c0.rgb - GetH(X,Y).rgb)) + GetH(X,Y).a);
diff += weight * (GetL(X,Y) + GetH(X,Y).rgb * R + (-1.0 - R) * (c0.rgb));
weightSum += weight;
}
diff /= weightSum;
c0.rgb = ((c0.rgb) + diff);
return c0;
}
@Tsubajashi
Copy link

Tsubajashi commented Apr 29, 2019

which params would be for "Robidoux"?
i enjoy a tiny bit sharper videos than default SSSR.

@igv
Copy link
Author

igv commented Apr 29, 2019

0.3782, 0.3109

@deus0ww
Copy link

deus0ww commented Apr 30, 2019

Params:

RobidouxSoft
B = (9-3*sqrt(2))/7 = 0.67962275898295921
C = 0.1601886205085204

Robidoux
B = 12/(19+9sqrt(2)) = 0.37821575509399866
C = 113/(58+216
sqrt(2)) = 0.31089212245300067

Mitchell
B = 1/3
C = 1/3

RobidouxSharp
B = 6/(13+7sqrt(2)) = 0.2620145123990142
C = 7/(2+12
sqrt(2)) = 0.3689927438004929

Catrom
B = 0.0
C = 0.5

Sources:
https://www.imagemagick.org/Usage/filter/#mitchell
https://www.imagemagick.org/discourse-server/viewtopic.php?f=22&t=19823

@dixie-flatliner
Copy link

dixie-flatliner commented Apr 22, 2020

Does SSIMSuperRes require use of an upscaling filter which matches the one in the shader, as SSIMDownscaler does?

@igv
Copy link
Author

igv commented Apr 23, 2020

No.

@po5
Copy link

po5 commented Jul 3, 2020

This stretches and crops videos with a display aspect ratio when used together with FSRCNNX.

glsl-shaders="~~/shaders/FSRCNNX_x2_8-0-4-1.glsl"
glsl-shaders-append="~~/shaders/SSimSuperRes.glsl"

Sample video: https://0x0.st/iyNb.mkv generated with the following commands
wget http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_60fps_normal.mp4
ffmpeg -ss 1:10 -t 5 -r 25 -i bbb_sunflower_1080p_60fps_normal.mp4 -vf scale=720:576 bbb.mkv

MediaInfo:

General
Unique ID                                : 174675382607623785347252629000047310909 (0x83694147194CB82603DFF87EA3F4383D)
Complete name                            : bbb.mkv
Format                                   : Matroska
Format version                           : Version 4
File size                                : 404 KiB
Duration                                 : 5 s 3 ms
Overall bit rate mode                    : Variable
Overall bit rate                         : 662 kb/s
Movie name                               : Big Buck Bunny, Sunflower version
Writing application                      : Lavf58.29.100
Writing library                          : Lavf58.29.100
Comment                                  : Creative Commons Attribution 3.0 - http://bbb3d.renderfarming.net
ErrorDetectionType                       : Per level 1
ARTIST                                   : Blender Foundation 2008, Janus Bager Kristensen 2013
COMPOSER                                 : Sacha Goedegebure
GENRE                                    : Animation

Video
ID                                       : 1
Format                                   : AVC
Format/Info                              : Advanced Video Codec
Format profile                           : High@L3
Format settings                          : CABAC / 4 Ref Frames
Format settings, CABAC                   : Yes
Format settings, Reference frames        : 4 frames
Codec ID                                 : V_MPEG4/ISO/AVC
Duration                                 : 5 s 3 ms
Bit rate                                 : 373 kb/s
Width                                    : 720 pixels
Height                                   : 576 pixels
Display aspect ratio                     : 16:9
Frame rate mode                          : Constant
Frame rate                               : 25.000 FPS
Standard                                 : PAL
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Bits/(Pixel*Frame)                       : 0.036
Stream size                              : 228 KiB (56%)
Writing library                          : x264 core 159 r2999 296494a
Encoding settings                        : cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=7 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=12 / lookahead_threads=2 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=25 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=23.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00
Default                                  : Yes
Forced                                   : No

Audio
ID                                       : 2
Format                                   : Vorbis
Format settings, Floor                   : 1 / 16898
Codec ID                                 : A_VORBIS
Duration                                 : 5 s 3 ms
Bit rate mode                            : Variable
Bit rate                                 : 276 kb/s
Channel(s)                               : 6 channels
Sampling rate                            : 48.0 kHz
Compression mode                         : Lossy
Stream size                              : 169 KiB (42%)
Writing application                      : Lavc58.54.100
Writing library                          : libVorbis (Now 100% fewer shells) (20180316 (Now 100% fewer shells))
Default                                  : Yes
Forced                                   : No

Screenshots (in fullscreen, to trigger scaling):
FSRCNNX
FSRCNNX+SSimSuperRes

As you can see it's stretched vertically and part of the image is missing at the bottom.

This was caused by commit 44add43ba89236b107431c375e3c98a8841f0065. The previous commit (5431ce139c20a9dccd1d3eaa0aee1cb2a2647771) works fine.

This display aspect ratio stuff is common in PAL regions, please fix.

@igv
Copy link
Author

igv commented Jul 3, 2020

Fixed.

@crazysword1
Copy link

crazysword1 commented Feb 6, 2021

Hi igv,

I am currently using all your shaders. My current config is:

scale=lanczos
dscale=mitchell
cscale=lanczos

For scale and cscale , does it matter what I use at all? I am already using FSRCNNX + SSSR and for chroma, I am already using Krig.
I know dscale should be Mitchell because I am using the ssimdownscaler.

Thanks

@igv
Copy link
Author

igv commented Feb 6, 2021

For small upscaling ratios (when FSRCNNX doesn't kick in) scale=ewa_hanning or similar might be sometimes slightly better than lanczos.
cscale doesn't matter.

@crazysword1
Copy link

crazysword1 commented Feb 6, 2021

Thanks for the quick response. So SSimSuperRes does not replace scale, but it's a supplement/tweak to it? I always thought SSimSuperRes would kick in for small upscaling ratios ( <1.4 for FSRCNNX ) and it was to replace the MPV's built-in scale. Is SSimSuperRes also a 2x prescaler like FSRCNNX?

@igv
Copy link
Author

igv commented Feb 7, 2021

It's a supplement/tweak to scale.

@yeezylife
Copy link

yeezylife commented Aug 27, 2021

Hello igv.
I'm wondering in oder to get the best quality possible,which built in scaler should we choose to use with SSR?
I'm currently using scale=ewa_lanczossharp by the way.

@igv
Copy link
Author

igv commented Aug 27, 2021

ewa_lanczossharp probably.

@igv
Copy link
Author

igv commented Aug 27, 2021

Btw, I'm using VIFp (preferred) and SSIM (with weights = [0.2,0.8]) for measuring "quality".

@yeezylife
Copy link

yeezylife commented Oct 12, 2021

I watch anime mostly,and I find out that SSSR tend to bloate up the lines(as in dark line) in anime content.
With ravu or fsrcnnx the lines are thin,like the original lines.

@igv
Copy link
Author

igv commented Oct 12, 2021

If you talking about dark lines, then that's because your anime was downscaled in gamma light. SSSR doesn't account for that, ravu and fsrcnnx do.

@RafeeDaBoy
Copy link

RafeeDaBoy commented Jan 24, 2022

@crazysword1 Could you post your config? I'm trying to make one and I'm a little lost on how to use shaders and scalers. Thanks!

@RafeeDaBoy
Copy link

RafeeDaBoy commented Jan 25, 2022

@igv Is there a way to know if the shaders are working? When playing back 4K HDR content on a 1440p screen, CPU (Ryzen 5 3600) usage is high and GPU (RTX 3070) usage is low. From what I've seen on various posts, shaders are supposed to be GPU intensive

My config:

vo=gpu 
deband=no
gpu-api=vulkan
fbo-format=rgba16hf
linear-downscaling=no
keep-open=yes
save-position-on-quit=yes
autofit=30%
screenshot-format=png
screenshot-high-bit-depth=yes
screenshot-png-compression=0
screenshot-png-filter=0
screenshot-directory='~~desktop/'


#### OSD/OSC
osc=no                           #Allows for custom OSC to be used  https://github.com/cyl0/mpv-osc-morden-x
border=no


#### Subtitles
demuxer-mkv-subtitle-preroll=yes
sub-ass-vsfilter-blur-compat=no
slang=en,eng


#### Dither
dither-depth=auto


#### Resizer & Shader ####
glsl-shader="C:\Users\Rafee\Documents\Programs\mpv\mpv\shaders\FSRCNNX_x2_16-0-4-1.glsl"
glsl-shader="C:\Users\Rafee\Documents\Programs\mpv\mpv\shaders\SSimSuperRes.glsl"
glsl-shader="C:\Users\Rafee\Documents\Programs\mpv\mpv\shaders\SSimDownscaler.glsl"
glsl-shader="C:\Users\Rafee\Documents\Programs\mpv\mpv\shaders\KrigBilateral.glsl"
no-scaler-resizes-only           #fixing the pixel shift

scale=ewa_lanczossharp
dscale=lanczos 
cscale=lanczos

image

@yeezylife
Copy link

yeezylife commented Jan 25, 2022

"shift+i" then press "2" .Also you can find most stuff you need to know here by the way.

@RafeeDaBoy
Copy link

RafeeDaBoy commented Jan 26, 2022

When do I know SSR or FSRCNNX is in use and when scale=ewa_lanczossharp is in use? (Native res: 1920x1080p, Scaled res: 2560x1440p)

Config:

glsl-shader="C:\Users\Rafee\Documents\Programs\mpv\mpv\shaders\FSRCNNX_x2_16-0-4-1.glsl"
glsl-shader="C:\Users\Rafee\Documents\Programs\mpv\mpv\shaders\SSimSuperRes.glsl"
glsl-shader="C:\Users\Rafee\Documents\Programs\mpv\mpv\shaders\SSimDownscaler.glsl"
glsl-shader="C:\Users\Rafee\Documents\Programs\mpv\mpv\shaders\KrigBilateral.glsl"
no-scaler-resizes-only

scale=ewa_lanczossharp
dscale=lanczos 
cscale=lanczos

@igv
Copy link
Author

igv commented Jan 26, 2022

For scaling factors >1 ... <=1.3 - only SSimSuperRes (together with ewa_lanczossharp) is in use.
>1.3 ... <2 - FSRCNNX + SSimDownscaler.
>2 - FSRCNNX + SSimSuperRes (together with ewa_lanczossharp)

@yeezylife
Copy link

yeezylife commented Jun 4, 2022

In artoriuz's tests Mathematically Evaluating mpv's Upscaling Algorithms,lanczos seems to have higher scores in every upscale tests.Does this mean we should just use scale=lanczos with SSR since it has higher test scores and use less resources?

@igv
Copy link
Author

igv commented Jun 4, 2022

yes.

@lextra2
Copy link

lextra2 commented Jul 20, 2022

@igv Would you be interested in adding this as a shader for mpv? I'm mostly interested in debilinear & debicubic. Would be useful for bluray sources from older animes.

@yeezylife
Copy link

yeezylife commented Jul 20, 2022

It's a "VapourSynth plugin to undo upscaling"

Maybe not suitable for normal downscaling?

@lextra2
Copy link

lextra2 commented Jul 20, 2022

It's a "VapourSynth plugin to undo upscaling"

Maybe not suitable for normal downscaling?

Yeah. Not suitable for normal downscaling. But I don't see a reason why you couldn't do a chain like "scale down with debilinear shader > scale up with spline36 from mpv".

Undoing the bilinear/bicubic upscaling companies did for the bluray release and using a better upscaling filter would result in a sharper image.

@po5
Copy link

po5 commented Jul 20, 2022

Sadly almost no production has all elements at the same resolution, and a lot of them have to be descaled per-scene if a descale is even possible.
Descaling without masking isn't a great idea, and that's where you lose enough performance that your filtering may not be realtime viable anymore.
You can use mpv's vapoursynth filtering feature btw.

@yeezylife
Copy link

yeezylife commented Jul 20, 2022

your filtering may not be realtime viable anymore.

That's why this kind of process(if it was needed at all) was usually done by a BDrip release group. For example "GA-REI -zero" by VCB-Studio.

@lextra2
Copy link

lextra2 commented Jul 20, 2022

Sadly almost no production has all elements at the same resolution, and a lot of them have to be descaled per-scene if a descale is even possible. Descaling without masking isn't a great idea, and that's where you lose enough performance that your filtering may not be realtime viable anymore. You can use mpv's vapoursynth filtering feature btw.

True. If you'd want perfection you'd add masking. But undoing bilinear/bicubic is enough for my needs.

And yeah, I guess I'll see if I can make the vapoursynth plugin work. But a shader would be more flexible.

@igv
Copy link
Author

igv commented Jul 21, 2022

@lextra2 No, not interested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment