View Full Version : CRT emulation with scanline and phosphor effects


cretindesalpes
5th June 2014, 21:55
Download: crt_display v1.0 (https://ldesoras.fr/src/avs/crt-display-1.0.zip)

This function emulates a CRT display using aperture grille (Trinitron) or Cromaclear technologies. It is slow but gives interesting results. Could be nice to chain after a NTSC defect emulator like dotcrawlplus (http://forum.doom9.org/showthread.php?t=170433). It implements various features like:
Works at any (non-integer) upscaling factor
Various ways of adjusting the scanline thickness and beam shape
Low-pass filtering of the input signal
Specific gamma target
Beam glow
Optional colored phosphor effect and shadow mask
Colors shift caused by beam misalignment
Automatic contrast adjustment
Halation
Very large upscale is possible, showing the grid of phosphors.

Requirements: Dither 1.26.0 or above and its dependencies, Avisynth 2.6, RGB colorspace.

Detailed instructions in the .avsi file. Prototype:
Function crt_display (clip src, float sw, float sh, float "voff", float "ppp",
\ float "cutoff", float "scandist", float "sharpv", float "sharph",
\ float "blurh", float "glowgain", float "glowh", float "glowv",
\ float "glowsens", float "contrast", float "gamma", float "softclip",
\ float "mix", float "beamshape", bool "phosphor", bool "pgrid",
\ float "vcs", float "cromaclear", float "maskpp", float "gainb",
\ float "halgain", float "halrange", string "pixel_type")


Examples of real NTSC footage with aperture grille (left) and Cromaclear shadow mask (right):
https://s33.postimg.cc/5oqlfr0a3/koya-960-trinitron.png (https://postimg.cc/image/5oqlfr0a3/) https://s33.postimg.cc/tpsw3yaff/koya-1200-cromaclear.jpg (https://postimg.cc/image/tpsw3yaff/)
ar = 10.0 / 11.0
crt_display (2*ar, 2, ppp=1*ar, blurh=2.0) # Left
crt_display (2.5*ar, 2.5, ppp=1.25*ar, maskpp=1.25, cromaclear=1.0, voff=0.25) # right
Make sure to check the pictures at their original size.
Note that the scanline density (480) makes difficult to reproduce the Cromaclear effect in a limited resolution and exhibits unwanted pattern effects. We would need at least three lines per scanline to give it a better look.

But it works very well for upscaling 240p content, especially old-school videogame captures:

Sources, point-resized:
https://s33.postimg.cc/ejrfqhmkb/mana-point-02.png (https://postimg.cc/image/ejrfqhmkb/) https://s33.postimg.cc/6e9dsclgr/mana-point-04.png (https://postimg.cc/image/6e9dsclgr/) https://s33.postimg.cc/bpoad57kb/mana-point-06.png (https://postimg.cc/image/bpoad57kb/) https://s33.postimg.cc/5oqlg3niz/mana-point-07.png (https://postimg.cc/image/5oqlg3niz/)
I don’t know at which gamma these pictures should be viewed so I kept them untouched like if they were in standard sRGB.

Cromaclear display type:
https://s33.postimg.cc/k6j7a2uij/mana-cromaclear-02.png (https://postimg.cc/image/k6j7a2uij/) https://s33.postimg.cc/jv6cay0uj/mana-cromaclear-04.png (https://postimg.cc/image/jv6cay0uj/) https://s33.postimg.cc/a986hcn0b/mana-cromaclear-06.png (https://postimg.cc/image/a986hcn0b/) https://s33.postimg.cc/8vl4ziah7/mana-cromaclear-07.png (https://postimg.cc/image/8vl4ziah7/)
ar = 8.0 / 7.0
crt_display (5*ar, 5, ppp=2.5*ar, blurh=1.0, maskpp=2.5, cromaclear=1, scandist=1.5, cutoff=0.9, glowgain=0.125, halgain=0.03)

Aperture grille display type:
https://s33.postimg.cc/folhvwyrf/mana-trinitron-02.png (https://postimg.cc/image/folhvwyrf/) https://s33.postimg.cc/h3n2khf8b/mana-trinitron-04.png (https://postimg.cc/image/h3n2khf8b/) https://s33.postimg.cc/76c1rlfe3/mana-trinitron-06.png (https://postimg.cc/image/76c1rlfe3/) https://s33.postimg.cc/mrtdbnty3/mana-trinitron-07.png (https://postimg.cc/image/mrtdbnty3/)
crt_display (5*ar, 5, ppp=2.5*ar, blurh=0.75, scandist=1, cutoff=0.9, glowgain=0.125, halgain=0.03)
The scanline effect and variable-width beam could have been more pronounced just by adding sharpv=2, beamshape=2.

Simple scanlines without phosphor effect:
https://s33.postimg.cc/50hqwxrbf/mana-scanlines-02.png (https://postimg.cc/image/50hqwxrbf/) https://s33.postimg.cc/pw418j31n/mana-scanlines-04.png (https://postimg.cc/image/pw418j31n/) https://s33.postimg.cc/ttraxopsb/mana-scanlines-06.png (https://postimg.cc/image/ttraxopsb/) https://s33.postimg.cc/qzo5kal23/mana-scanlines-07.png (https://postimg.cc/image/qzo5kal23/)
crt_display (5*ar, 5, ppp=2.5*ar, blurh=1.0, maskpp=2.5, phosphor=false, scandist=3, cutoff=0.8, glowgain=1.0, glowh=6, glowv=0, halgain=0.03, sharpv=2)
This is just insane but gives an idea about how it could look with extreme settings.

More screenshots here (https://postimg.cc/gallery/1cqmuzc3g/). Default settings are generally OK, but tweaking the parameters can improve the results a lot.

My 15 kHz CRT is gone for a long time and I only have half-decent monitor photos for reference, so any advice based on real CRTs is welcome to improve the emulation.

Motenai Yoda
5th June 2014, 23:41
It's look very like my old Sony Triniton!!! :eek:

But Triniton have also a defect, there were some horizontal gray lines.
http://www.dansdata.com/images/sg400/sonydampersml.jpg
http://www.dansdata.com/sg400.htm

TheSkiller
6th June 2014, 00:07
Impressive! :eek:
Being a CRT expert and lover I definitely have to say this is the most authentic CRT simulation I've seen. Goes very nice especially with old games. I'll have some fun with this, even though I have plenty real CRTs right here. :p


Edit: One thing I noticed is the scanlines in your simulation are more pronounced with the Cromaclear setting compared to the Trinitron setting. Well, in my experience, and I have a Trinitron as well as a shadow mask CRT side by side here, the scanlines are generally more pronounced with Trinitrion masks and slightly less with shadow masks. This is also commonly known among retro gamer "CRT fetishists" on the internet. Trinitrons have slightly more pronounced scanlines compared to shadow masks.

cretindesalpes
6th June 2014, 00:24
TheSkiller:

Thanks. I agree with the Cromaclear/Trinitron mismatch. I just put different settings to show the versatility of the function, of course it’s possible to increase the scanline effect with the Trinitron.

Motenai Yoda:

Indeed, I haven’t included the “damping wire” effect. I’m not sure if it’s a wanted feature…

Reel.Deel
6th June 2014, 03:52
This is nice, it reminds me of much simpler times. :)
Kudos cretindesalpes.

Lyris
6th June 2014, 04:29
Outstanding attention to detail. That really puts the crummy "Old TV effect" in NLEs to shame.

creaothceann
6th June 2014, 07:17
Here (http://board.byuu.org/viewtopic.php?f=10&t=4719&p=108903#p108903)'s another thread about CRT simulation. :)

Btw. I get this (http://i.imgur.com/ovppcDZ.png) error (crt_display.avsi is in the plugins folder)... any idea what could be the cause? I have this (http://i.imgur.com/WSa7I2Z.png) version and the plugins.

Gavino
6th June 2014, 08:33
I get this (http://i.imgur.com/ovppcDZ.png) error (crt_display.avsi is in the plugins folder)... any idea what could be the cause? I have this (http://i.imgur.com/WSa7I2Z.png) version and the plugins.
You need an updated MaskTools fully compatible with 2.6a4 - see here.

creaothceann
6th June 2014, 17:55
Mmmh... (http://i.imgur.com/FKifd3J.png)

Motenai Yoda
6th June 2014, 21:14
Mmmh... (http://i.imgur.com/FKifd3J.png)

U must delete old mt dlls

osgZach
17th June 2014, 13:21
This is so awesome...

It would be sweet if someone could turn these particular effects into shaders (or provide SweetFX/etc. settings that can emulate them)

NightSprinter
22nd September 2014, 13:48
To the author of this script/OP of the thread, I know I asked this via e-mail, but is there any way to help with the speed for rendering a video with this? Rendering to an MP4 file on my machine takes sometimes upwards of a day for a five minute recording.

cretindesalpes
22nd September 2014, 22:03
Yes I saw your email but the previous week was quite intense for me IRL and I hadn’t the time to reply. Anyway I’m not sure about what is slow in the script, and if it can be optimized. I’ll try to benchmark it and narrow down the slowest parts in the next days but I cannot guarantee that I can come with significant speed improvement.

EDIT: I just found that vertical resizing/convolution in Dither_resize16 was not multi-threaded… Got a 75 % speed-up just by fixing it. More later.

cretindesalpes
23rd September 2014, 18:53
As stated in my previous edited post, updating Dither (http://forum.doom9.org/showthread.php?p=1386559#post1386559) to v1.26.5 will give a significant speed boost to crt_display. You can also maximize the CPU usage and double again the fps throughput by splitting the source video into 2 or 3 parts and encode them simultaneously.

These are probably the only large speed improvement left without altering the quality and accuracy of the emulation. I think implementing a native Dither_lut16 implementation (instead of a wrapper function around several mt_lutxy calls) could help a little too, as the function is heavily used.

Next, there’s a great amount of finetuning to do (like cutting the number of taps to the strict minimum for the gaussian blurs, or reducing the vertical oversampling of the beam), but this is a lot of work for little results.

NightSprinter
4th October 2014, 18:50
Thanks greatly for the reply. As I'm using AVISynth 2.6, what would you suggest further to improve? I've updated the dither plugins as suggested, and you've mentioned something about multi-threading. If it helps, here are my specs as well:

CPU: Intel Core i7-920 @2.8GHZ overclock
RAM: Corsair XMS3 DDR3-10666
GPU: PNY GeForce GTS-450
Motherboard: Gigabyte X58A-UD3Rv1
PSU: Corsair TX750
HDD: 3x500GB Seagate Barracuda 7200rpm
Capture Card 1: Startech PEXHDCAP (for anything above composite or s-video)
Capture Card 2: Pinnacle Dazzle DVC-101

[Edit] Here's an error that shows up all too often for me. I wonder what I'm doing wrong?

foxyshadis
7th October 2014, 00:32
[Edit] Here's an error that shows up all too often for me. I wonder what I'm doing wrong?

Use this version of Masktools (https://github.com/tp7/masktools/releases), which should help speed a bit as well.

NightSprinter
9th October 2014, 03:39
That seemed to work, though I guess even 6GB of memory may not even be enough to render the 240p deinterlaced image up to 1280x960 in VirtualDub. I had to use AVIDemux and its AVSProxy companion to render the video I had set up in my script.

cretindesalpes
9th October 2014, 08:58
With a regular Avisynth 2.6 version (32-bit single-threaded) you shouldn’t need such a huge RAM amount. Playing back a 224p to 1080p conversion in VirtualDub uses only 700 MB here. What is your script?

NightSprinter
9th October 2014, 12:59
My script looks like this (as I'm using the MT version of AVISynth, and did some deinterlacing of footage captured with a Dazzle at 640x480i)

SetMemoryMax(512)
SetMTMode(3)
SetMTMode(2)
Import("crt_display.avsi")
AviSource("converttorgb.avi")
SeparateFields(AssumeTFF)
#PointResize(640,480)
#Scanlines(STRENGTH=0)
ar = 1.0 / 1.0
crt_display (2*ar, 4, ppp=2.5*ar, blurh=1.0, maskpp=2.5, cromaclear=1, scandist=1.5, cutoff=0.9, glowgain=0.125, halgain=0.03)

The render takes an entire night's worth of time via the AVIDemux program setup I have in order to render the final MP4 video.

osgZach
27th April 2015, 02:34
Anyone got any idea what would cause this?

I'd really like to try this script on some DOSBox captures

http://i.imgur.com/sXwBAoa.png

Reel.Deel
27th April 2015, 02:42
Anyone got any idea what would cause this?

WeaveRows is only available in AviSynth 2.6.

osgZach
27th April 2015, 03:15
lol the fun never ends..

I updated my Avisynth build (I had 2.6) to a more recent one. Now I get a different error.

http://i.imgur.com/oSCVxxw.png

Line 322

g = (phosphor) ? g.insert_black_col16 (ssx, ssx / 3, ssx / 3 - g_thickness) : g




Line 420

msk = msk.mt_lutspa (mode="absolute", expr="x "+String(nbr)+" % "+String(ofs)+" >= x "+String(nbr)+" % "+String(ofs+w)+" < & 255 0 ?")


Changing the PAR to 1.0 / 1.0 changes the error to an access violation.

Relevant Line 322:

# Phosphor processing. Applies a mask to put each color component on
# its own phosphor column.
r = SelectEvery (3, 0)
g = SelectEvery (3, 1)
b = SelectEvery (3, 2)
r = (phosphor) ? r.insert_black_col16 (ssx, 0, ssx / 3 - g_thickness) : r
g = (phosphor) ? g.insert_black_col16 (ssx, ssx / 3, ssx / 3 - g_thickness) : g
b = (phosphor) ? b.insert_black_col16 (ssx, 2 * ssx / 3, ssx / 3 - g_thickness) : b
Interleave (r, g, b)



Relevant Line 430

Function insert_black_col16 (clip src, int nbr, int ofs, int w)
{
src
dw = Width ()
dh = Height () / 2

# Tiling the mt_lutspa speeds up a bit the filter initialisation.
# msk = last.mt_lutspa (mode="absolute", expr="x "+String(nbr)+" % "+String(ofs)+" >= x "+String(nbr)+" % "+String(ofs+w)+" < & 255 0 ?")

msk = last.Crop (0, 0, 0, 32)
msk = msk.mt_lutspa (mode="absolute", expr="x "+String(nbr)+" % "+String(ofs)+" >= x "+String(nbr)+" % "+String(ofs+w)+" < & 255 0 ?")
msk = msk.make_tile (dw, dh * 2)
# end tiling

mt_logic (last, msk, mode="and")
}



Just for reference.. very simple script I used copying example from the images showcase on the first page.

AviSource("whip_000.avi")

ar = 1.0 / 1.0
crt_display (5*ar, 5, ppp=2.5*ar, blurh=1.0, maskpp=2.5, cromaclear=1, scandist=1.5, cutoff=0.9,

glowgain=0.125, halgain=0.03)


Source Video

Video
ID : 0
Format : Zip
Codec ID : ZMBV
Codec ID/Info : Zip Motion Blocks Video
Duration : 7mn 55s
Bit rate : 12.8 Mbps
Width : 640 pixels
Height : 400 pixels
Display aspect ratio : 16:10
Frame rate : 69.755 fps
Bits/(Pixel*Frame) : 0.715
Stream size : 724 MiB (90%)

osgZach
27th April 2015, 03:30
maybe I should just nuke my plugins folder....

feisty2
27th April 2015, 03:36
Anyone got any idea what would cause this?

I'd really like to try this script on some DOSBox captures

http://i.imgur.com/sXwBAoa.png

Whatever version of avisynth you are using, it surly isn't the latest
Upgrade it

Edit: check your masktools version, is it for avs 2.5?

osgZach
27th April 2015, 04:05
I'm using the version linked here http://forum.doom9.org/showthread.php?p=1696036#post1696036

From earlier in this thread. Not using the 2.5.8 version

feisty2
27th April 2015, 04:15
I'm using the version linked here http://forum.doom9.org/showthread.php?p=1696036#post1696036

From earlier in this thread. Not using the 2.5.8 version

That page got 3 builds, 2.5 version, 2.6/avs+ x86 and avs+ x64
And you got which one in your plugins folder?

osgZach
27th April 2015, 09:41
2.6 x86

StainlessS
27th April 2015, 10:01
Weaverows introduced in Avisynth v2.6a4 http://forum.doom9.org/showthread.php?p=1610746&highlight=weaverows#post1610746
So you are using Alpha 3 or prior. Update to v2.6RC3.

EDIT: Here (AviSynth_150419.exe): http://sourceforge.net/projects/avisynth2/files/AviSynth_Alpha_Releases/AVS%202.6.0%20RC%203%20%5B150419%5D/

osgZach
27th April 2015, 14:14
Sorry I wasn't clear, I do have that version of 2.6 installed. The weaverows errors went away, then the new ones I posted above popped up. ( http://forum.doom9.org/showpost.php?p=1719327&postcount=22 )

I'm gonna try rebuilding my plugins folder I guess.

cretindesalpes
27th April 2015, 17:43
osgZach:

The resulting frames are large, 3200x2000. Make sure you don’t run out of memory (almost 1 GB taken just with BlankClip as source here). Your host application should be patched to accept 4 GB of memory.

Also, if you have a recent version of Avisynth 2.6, use the Masktools 2 version modified by tp7 (https://github.com/tp7/masktools/releases). Same with RemoveGrain (https://github.com/tp7/RgTools/releases).

osgZach
28th April 2015, 07:20
Hi, thank you so much, I got it working now.

I didn't have that newer Removegrain (RgTools.dll), but even then I still got weird errors... and I guess my plugins folder is really a mess. I've been spoiled by auto-load over the years as it makes script writing so much more convenient.
I gotta get a handle on this stuff and learn to source multiple directories or something.

Just curious. Why do return frames turn out so large? Is there any way to control that?

edit: spoke too soon.. Test clip worked, but the video made it run out of memory I guess..
I am using 32-bit AVS - I take it I need to use 64-bit or something? Can they co-exist on the same system? Kind of confused what you meant with patching to accept more than 4GB
(using Vdub x32 on Win7 x64)

StainlessS
28th April 2015, 13:27
osgZach, think this is what cretindesalpes was suggesting:
https://www.google.co.uk/?gws_rd=ssl#q=4gb+patch

osgZach
28th April 2015, 13:42
I actually tried that a few hours ago, and I'm not sure what I was supposed to do with it?

Avisynth doesn't have an executable, and I assumed by host he meant Virtualdub, so I applied it to that but that didn't seem to work either.

I keep getting out of memory errors on anything but the sample AVS clip =\
(16GB of RAM so that's not the issue)

Feeling really inept here...lol

edit:

Ok so some progress. I am able to load my video in MeGUI and play it using the preview function. So clearly the issue is with Vdub

osgZach
28th April 2015, 14:16
Oh boy people weren't kidding when they said it was slow! :D

So I had a (weird?) idea I was wondering about..

Is it possible to say, tweak it to get the look I want - knowing my intended output resolution ahead of time, etc. And then instead of rendering the video, render out an RGB image file with a transparent background layer, leaving the emulated CRT type effects in the image.. and then you could say, load that image back in to a different script (hopefully with transparency intact) and simple overlay it on top of every frame in the video?

Wondering if that's possible and how good it might look.

edit:
Or maybe someone can just recommend a good free CRT type filter for Vegas, etc. Or some such program, that is much faster.

cretindesalpes
28th April 2015, 18:03
Why do return frames turn out so large? Is there any way to control that?
The frames you get are large because you specified an enlargement factor of 5 (640x400 -> 3200x2000), which gave a decent size with my 240p sources. Try something lower like 2 or 2.5, and set ppp to half of it to minimize moire effects.

So clearly the issue is with Vdub
Try to close your script then open it again instead of pressing F2. With the latter, the previous script version is kept in memory until the new script renders its frame without error.

Is it possible to say, tweak it to get the look I want - knowing my intended output resolution ahead of time, etc. And then instead of rendering the video, render out an RGB image file with a transparent background layer, leaving the emulated CRT type effects in the image.. and then you could say, load that image back in to a different script (hopefully with transparency intact) and simple overlay it on top of every frame in the video?
Unfortunately this won’t work because of the beam size emulation, contrast compensation and other non-linear effects. Anyway you can get a decent approximation just by using an RGB grid mask, like many CRT shaders did, but you’ll lose a lot of contrast.

osgZach
28th April 2015, 19:01
I see.

Well it definitely looks nice, but I suppose what I am really after is that light scanline look. Something similar to what you can get done in most emulators these days. Not very thick lines, but still there enough that it has that "look".
Is there an easy, much faster way to accomplish that? Aside from just pasting some black 1px lines across the image I mean. I'm looking for something potentially halfway between nothing, and what your script does now. But taking much less render time.

I just can't sit around for 24 hours on a 7 minute video for instance. If it were an hour or two long maybe, but not for 7 minutes :p

raffriff42
28th April 2015, 21:04
what I am really after is that light scanline look... Is there an easy, much faster way to accomplish that?There's Scanlines (http://avisynth.nl/index.php/Scanlines). Very fast.

But the lines don't "twitter" as they should (IMHO) - so here's an alternative:
(EDIT better version here (http://forum.doom9.org/showpost.php?p=1719572&postcount=42)) LoadPlugin "mt_masktools-26.dll")
## version a48 required
## http://forum.doom9.org/showthread.php?t=98985

## Last == YV12
return scanlines2(size=0.5, stren=0.1)

function scanlines2(clip C, float "size", float "stren")
{
size=Min(Max(0.25, Default(size, 1.0)), 10.0)
stren=Min(Max(0.0, Default(stren, 0.2)), 1.0)

C ## Last==C
A=mt_lutspa(
\ mode="absolute",
\ expr=("""(((y/(2*$s))%2)>0) ? 255 : 0""")
\ .StrReplace("$s", String(size))
\ .mt_polish,
\ u=-128, v=-128
\ )

B=ScriptClip(A, """(current_frame % 2) > 0 ? Last : Last.FlipVertical""")

#return Overlay(B, opacity=stren)
return ConvertToYUY2
\ .Layer(B.ConvertToYUY2, level=Round(257.0*stren), use_chroma=false)
\ .ConvertToYV12
}

osgZach
28th April 2015, 21:58
Thanks I will try both of those out when I have some free time.

rcubed
28th April 2015, 23:24
It's look very like my old Sony Triniton!!! :eek:

But Triniton have also a defect, there were some horizontal gray lines.
http://www.dansdata.com/images/sg400/sonydampersml.jpg
http://www.dansdata.com/sg400.htm

If I remember correctly the horizontal lines are due to the design of the shadow mask. The line(s) is a connection between the vertical shadow mask slots to stiffen the overall shadow mask. Sony would probably call it a "design feature" :)

cheers,

rcubed

osgZach
29th April 2015, 00:37
haha I remember people complaining about that back in the day.. man I'm getting old

osgZach
29th April 2015, 04:29
raffriff42,

That's a pretty neat script (and fast). Although the screen flicker kind of bothers me.. Can it be reduced a little? Or maybe a version with it removed. Also I noticed when I resized and added bars on the sides to maintain aspect ratio, there is a green line on the left hand side of the picture edge. I Don't know if that's from Vdub for some reason or the script tho.

I did find another thread with some stuff too, if anyone finds it interesting.
http://forum.doom9.org/showthread.php?t=156658

raffriff42
29th April 2015, 05:44
Thanks, osgZach. Good points. Try this one, it looks a lot better I think:LoadPlugin "mt_masktools-26.dll")
## version a48 required
## http://forum.doom9.org/showthread.php?t=98985

## Last == YV12
return scanlines2(size=2, strength=0.25, flicker=false)

#######################################
## Add scanlines (light & dark horizontal bars) to a video.
##
## @ size - 1 to 4; default 2
## @ strength - 0.0 to 1.0; default 0.25
## @ flicker - default false
##
function scanlines2(clip C, int "size", float "strength", bool "flicker")
{
size = Min(Max(1, Default(size, 2)), 4)
strength = Min(Max(0.0, Default(strength, 0.25)), 1.0)
flicker = Default(flicker, false)

C
A=mt_lutspa(
\ mode="absolute",
\ expr=mt_polish("(((y/(2*"+String(0.25*size)+"))%2)>0)?128+64:128-64"),
\ u=-128, v=-128
\ )

B = (flicker)
\ ? ScriptClip(A, """(current_frame % 2) > 0 ? Last : Last.FlipVertical""")
\ : A

return Overlay(B, opacity=0.25*strength, mode="luma")
}

osgZach
29th April 2015, 11:43
That's a bit easier to tweak, thanks :)

One last question. For some reason if I try to put my resize/addborders calls after this function is called, they do not work. No error is given, it just shows the image at original resolution. Was that intended? I was hoping to see if there was a big difference in applying the script before / after a resize.

raffriff42
29th April 2015, 13:29
For some reason if I try to put my resize/addborders calls after this function is called, they do not work. No error is given, it just shows the image at original resolution.That does not happen for me. Please post your script.

osgZach
29th April 2015, 14:36
AviSource("whip_000.avi", audio=false)
ConvertToYV12()
## LoadPlugin ("mt_masktools-26.dll")
## version a48 required
## http://forum.doom9.org/showthread.php?t=98985

## Last == YV12

return scanlines2(size=2, strength=0.75, flicker=false)
LanczosResize(1152,720)
AddBorders(64,0,64,0)

#######################################
## Add scanlines (light & dark horizontal bars) to a video.
##
## @ size - 1 to 4; default 2
## @ strength - 0.0 to 1.0; default 0.25
## @ flicker - default false
##
function scanlines2(clip C, int "size", float "strength", bool "flicker")
{
size = Min(Max(1, Default(size, 2)), 4)
strength = Min(Max(0.0, Default(strength, 0.25)), 1.0)
flicker = Default(flicker, false)

C ## Last==C
A=mt_lutspa(
\ mode="absolute",
\ expr=("""(((y/(2*$s))%2)>0) ? 128+64 : 128-64""")
\ .StrReplace("$s", String(0.25*size))
\ .mt_polish,
\ u=-128, v=-128
\ )

B = (flicker)
\ ? ScriptClip(A, """(current_frame % 2) > 0 ? Last : Last.FlipVertical""")
\ : A

return Overlay(B, opacity=0.5*strength, mode="softlight")
}

# http://avisynth.nl/index.php/HDColorBars
function StrReplace(string base, string sought, string rep)
{
pos = FindStr(base, sought)
return (sought == "") || (pos == 0) \
? base \
: StrReplace( \
LeftStr(base, pos - 1) + rep + \
MidStr(base, pos + StrLen(sought)), \
sought, rep)
}




I only really modified it to comment out the DLL loading (in plugins directory already) and then to add the resize/addborders. But for w/e reason if I move them back before the call to the function, they work.

ndjamena
29th April 2015, 14:48
Lose the "return".

I didn't even know you could return from the base of the script. It looks a tad better than "__END__".

osgZach
29th April 2015, 15:14
thank you :cool:

StainlessS
29th April 2015, 17:23
I didn't even know you could return from the base of the script. It looks a tad better than "__END__".

The functionality of Return and __END__ is a little different.
Return allows to return a named clip eg 'myclip' rather than default Last clip, and is needed if the final function call before the end of script does not explicitly or implicitly set Last clip.
It (return) also allows you to return early where you want to temporarily disable some following lines of script.

__END__, makes anything following it COMMENT.
Below will produce an error (EDIT: due to ',' COMMA), try remove '#' hash comment (no error).

return Colorbars

#__END__
,


EDIT: Can also use C style comments eg

return Colorbars

/*
, # No error
*/

osgZach
30th April 2015, 01:34
I did 2 tests. I'm a little partial to the second one at this point (scanlines after resizing). All I have to do now is see if I can tweak the brightness or gamma to reduce some of the washed out look.

Test 1 - Resize after Scanlines (https://www.youtube.com/watch?v=JamoA0KiDL4)

Test 2 - Resize before Scanlines (https://www.youtube.com/watch?v=Wqew-FBbjvI)

Chrome / 720p / 60fps for best experience.

raffriff42
30th April 2015, 05:38
Looks great! However I find it a bit difficult to watch for more than a few seconds. Maybe with lower strength?

When using the effect after resizing, suggest setting the scanline size to match the native pixel size, for most realistic effect IMHO.

Regarding your brightness issue, here's yet another version with a brightness adjustment, and a few other minor changes. # http://manao4.free.fr/mt_masktools.html
## version a48 required
LoadPlugin("mt_masktools-26.dll")

# http://forum.doom9.org/showthread.php?p=1719737#post1719737
#######################################
## Add scanlines (light & dark horizontal bars) to a video.
##
## @ size - 1 to 16; default 2 (scanline size)
## @ strength - 0.0 to 1.0; default 0.25 (scanline strength)
## @ bright - min -128, max +128; default 0 (brightness adjustment)
## @ flicker - default false (if true, swap light & dark lines on each frame)
## (only allowed if bright == 0)
##
function scanlines2(clip C, int "size", float "strength", int "bright", bool "flicker")
{
Assert(IsYV12(C),
\ "scanlines2: source must be YV12")

size = Min(Max(1, Default(size, 2)), 16)
strength = Min(Max(0.0, Default(strength, 0.25)), 1.0)
bright = Min(Max(-128, Default(bright, 0)), +128)
flicker = Default(flicker, false)

C ## Last==C
A=mt_lutspa(
\ mode="absolute",
\ expr=("""(((y/(2*$s))%2)>0) ? 128+64+$b : 128-64+$b""")
\ .StrReplace("$s", String(0.25*size))
\ .StrReplace("$b", String(bright))
\ .mt_polish,
\ u=-128, v=-128
\ )

B = (flicker && bright==0)
\ ? ScriptClip(A, """(current_frame % 2) > 0 ? Last : Last.Invert""")
\ : A

return Overlay(B, opacity=0.5*strength, mode="softlight")
}

# http://avisynth.nl/index.php/HDColorBars
function StrReplace(string base, string sought, string rep)
{
pos = FindStr(base, sought)
return (sought == "") || (pos == 0) \
? base \
: StrReplace( \
LeftStr(base, pos - 1) + rep + \
MidStr(base, pos + StrLen(sought)), \
sought, rep)
}(Sorry if hijacking the topic. Maybe discussion of this script belongs in a new thread?)

osgZach
30th April 2015, 13:43
(If a mod would like to split this off into new thread that would be cool)

What do you mean by "difficult to watch" though? I'll admit personally my scanline preferences are a little weird. I like having smallish looking ones. I'll give the new version a try in a little while. Thanks

cretindesalpes
30th April 2015, 16:53
You can also disable most of the crt_display features and keep the scanline effect. For example:
crt_display (2, 2, scandist=1.5, phosphor=false, cromaclear=0)
You can play with the scandist parameter to change the effect strength.
Then resize to the target frame size. However the scanlines will be correctly preserved only if it is a vertical upscale, not a downscale.

The script will be faster than with all the features enabled. The good thing is that colors and contrast will be left almost intact.

osgZach
30th April 2015, 17:24
You can also disable most of the crt_display features and keep the scanline effect. For example:
crt_display (2, 2, scandist=1.5, phosphor=false, cromaclear=0)
You can play with the scandist parameter to change the effect strength.
Then resize to the target frame size. However the scanlines will be correctly preserved only if it is a vertical upscale, not a downscale.

The script will be faster than with all the features enabled. The good thing is that colors and contrast will be left almost intact.

I'm not so sure.. I changed the scaling numbers from "2" to "1.7" to get the needed 1152x720 output, so I wouldn't have to downscale it.

But the end result is the same as if I had not changed from "2" and then applied a downsize. Scanlines still look funky

The speed did improve quite a bit, but in terms of the effect + speed I think raffriff's script is a pretty good contender as it is orders of magnitudes faster.

cretindesalpes
30th April 2015, 18:12
What you actually see as funky scanlines is pure aliasing left by imperfect resizers (from a spectral content PoV). If you downsize, the scanlines should disappear because their frequencies are over the new Nyquist frequency. This happens if you use a resizer with a large kernel, for example BlackmanResize(w, h, taps=16).

NightSprinter
16th November 2015, 00:55
Been a while since I responded to this thread, but outside of upgrading to a beefier Core i7 and more than 6GB of memory what else can I do to make loading video with the script and rendering the final video faster and not hog so much memory? I've ran into some still high-cpu usage even with MT mode on, and even sometimes I just get out of memory errors trying to render a 15-second clip of Pac-Mania (which is also rotated so it's in proper vertical orientation) to a final video.

creaothceann
16th November 2015, 03:23
I've ran into some still high-cpu usage even with MT mode on

High CPU usage is good, imo (and especially expected when using multithreading). It means that your encoding is completed sooner.

NightSprinter
16th November 2015, 03:27
But should I expect an out of memory error even for 6GB of memory? I understand the memory usage for video editing rises exponentially when the video size gets bigger (and moreso if the video and audio are in raw format). It's just all I'm doing is trying to maybe render it at a final resolution (after rotation) of 720x960 with the effects. I'm going to guess that for my current system rendering a 20-minute video will be an all-day process?

NightSprinter
16th November 2015, 04:29
Oh this is sweet. With the 64-bit AVISynth+ (though I'm not sure what plugins exactly will need the MT options), my CPU usage in 64-bit VirtualDub for rendering the video is topping out at 60% on my i7-920. Not getting any "out of memory" errors so far. I am going to have to leave the rather shoddy gameplay of mine to test this filter chain out to run all night to render (6076 frames, and time to complete already over 5 hours). I can upload a YT video or post it to my Dropbox afterwards to see the final result.

[Edit] Wow, I guess even my current system seems to be quite weak. Just this four minute clip of some brief gameplay (PS1 Arcade's Greatest Hits: The Midway Collection 1, BurgerTime) is taking a total of nearly 30 hours to render with the effects chain. At least the 64-bit VDub and AVISynth+ plugins are letting me render it. Going to see if I can't find 64-bit versions of the encoders.

NightSprinter
18th November 2015, 17:49
The script's working more and more for me now. It doesn't seem to get along with multithreading too well (especially if working with huge aspect ratio multiples and/or the ppp setting at higher than 1, or even setting the prefetch parameter in any manner).

If need-be, I can upload my script in order to debug. I can also upload the gameplay clip I recorded that I'm using the script on.

NightSprinter
20th November 2015, 15:47
So, since all of this is stuck at single-threaded (settings I used take literally a week with AVISynth+ 64-bit and 64-bit VDub), I'd thought I'd just take a screenshot to show how nice very extreme phosphor mask settings can get. I'll also post my crt_display line in said script.

https://www.dropbox.com/s/o1or7s3izwxazlh/Old-TV3000000.bmp?raw=1

Import ("crt_display.avsi")
#Import("dotcrawlplus.avsi")
SetFilterMTMode("DEFAULT_MT_MODE", 2)
SetFilterMTMode("AVISource", 3)
LoadPlugin ("C:\AviSynth+\plugins64\mt_masktools-26-x64.dll")
AVISource("C:\Amarectv310\amarec(20151117-1402).avi")
## version a48 required
## http://forum.doom9.org/showthread.php?t=98985
crop (50,0,640,240)
pointresize(320,240)
converttorgb()
ar = 1.0/1.0
crt_display (6*ar, 6, ppp=3*ar, sharpv=0.75, sharph=0.25, blurh=1.5, scandist=1, cutoff=0.8, gamma=2, glowgain=0.125, halgain=0.03, contrast=3, phosphor=true, maskpp=3, beamshape=1.0, vcs=0.25, cromaclear=1, voff=0, pgrid=true, halrange=3, mix=2)
pointresize(960,720)
#converttoyv12()
#dotcrawlpreset("medium")
#prefetch(2)

Note that I had to comment out prefectch. All the masktools dll files I'm linked to for AVISynth+ are not compiled for MT support.

cretindesalpes
20th November 2015, 20:48
I tried your script and you don’t need a 64-bit Avisynth to make it work. With x264 defaults it uses just 2.1 GB (*) of address space and runs at 0.6+ fps (i7 4770K @ 4.2 GHz) with single-treading and “standard” Avisynth (not avs+). Multi-threading probably won’t work because of the memory requirement but you can try to split your video in multiple parts and run simultaneously 2 or 3 instances of x264 or VDub or whatever you use to encode, then join all the parts together.

I don’t know if the pointresize(960,720) is the intended final resolution, but if this is the case, you’d probably better render it directly in 960x720, disable Cromaclear which cannot be shown at this resolution and adjust voff to get the same result as you had previously.

(*) Don’t forget to increase the default Avisynth cache memory by adding something like SetMemoryMax(1024) at the beginning of your script.

NightSprinter
20th November 2015, 21:06
I had to set the limit to 4096, even with the cromaclear off and ppp/maskpp dialed all the way down to 2. Will look up on how to split the video, then stitch back together. Otherwise the encode time for the posted settings would keep my render/encode time at over 18 days. :P

creaothceann
20th November 2015, 23:37
Here's some SNES TV screen code that should be relatively fast. It's intended for encoding SNES video clips created by BizHawk (a frontend for multiple emulator cores, intended for TASing):

Final_Height = 720


# SNES clip (width=256/512, height=224/239/448/478)
# AVISource(FileName)
BlankClip(1, 256, 224, "RGB32", 60, 1, 32000, color=$FFFFFF)

# change to 60 fps and adjust audio sample rate
r = 60.0 / (1.0 * FrameRateNumerator / FrameRateDenominator)
AssumeFPS(60)
AssumeSampleRate(round(r * AudioRate))
Trim(0, 0)

# pad to 240 or 480 lines
(Height == 224) ? AddBorders(0, 8, 0, 8) :\
(Height == 239) ? AddBorders(0, 1, 0, 0) :\
(Height == 448) ? AddBorders(0, 16, 0, 16) :\
(Height == 478) ? AddBorders(0, 1, 0, 1) : nop

# non-interlaced: repeat 3 lines and add a black one, then blur
(Height == 240) ? Interleave(BlankClip(last), last, last, last).AssumeFieldBased.Weave.AssumeFieldBased.Weave.BilinearResize(Width, 240 * 4 * 2) : nop

# lowres: double width
(Width == 256) ? PointResize(256 * 2, Height) : nop

# final resize (aspect ratio = 292:240)
BilinearResize(round(292.0 / 240 * Final_Height), Final_Height)

(it adds vertical borders to avoid lines clumping together)

NightSprinter
21st November 2015, 19:07
I will try that script out sometime (once I figure out how to correctly resize a 720x240 capture to 256x224). Apparently the only thing that I really wanted to try the filter chain for, was multithreading. Unfortunately, the file everyone keeps linking me to in another thread fails when calling (mt_lut).

creaothceann
22nd November 2015, 01:09
I will try that script out sometime (once I figure out how to correctly resize a 720x240 capture to 256x224)
That's a bit easier:

Final_Height = 720


# source clip (width=720, height=240)
# AVISource(FileName)
BlankClip(1, 720, 240, "RGB32", 60, 1, 44100, color=$FFFFFF)

# change to 60 fps and adjust audio sample rate
r = 60.0 / (1.0 * FrameRateNumerator / FrameRateDenominator)
AssumeFPS(60)
AssumeSampleRate(round(r * AudioRate))
Trim(0, 0)

# repeat 3 lines and add a black one, then blur
Interleave(BlankClip(last), last, last, last).AssumeFieldBased.Weave.AssumeFieldBased.Weave.BilinearResize(Width, 240 * 4 * 2)

# final resize (aspect ratio = 4:3)
BilinearResize(Final_Height * 4 / 3, Final_Height)
Skip the AssumeFPS/AssumeSampleRate part if your source file is already 60.0fps.

bxyhxyh
18th April 2016, 17:01
Hello, how can I resize 640x480 to 1440x1080 with crt display?
It works great on 256x224 etc...

But on 640x480, it just don't work as I expected.

It should look like this right? - https://dl.dropboxusercontent.com/u/58215671/mkgold2.png - downscaled with bicubicresize(480,360,-0.48,0.24) and crt_display(3,3) for test purpose)
source - https://dl.dropboxusercontent.com/u/58215671/mkgold.png

So is there anyway to make it look like first one without downscaling?

real.finder
5th September 2021, 10:19
basic update to AVS+ https://github.com/realfinder/AVS-Stuff/blob/Community/for%20AVSPlus/crt_display.avsi

it need 16 bit PlanarRGB for now, more updates also needed to make it work without old workarounds

DTL
5th September 2021, 10:32
Heh - the whole point of CRT is analog line-drawing tool being feed from sinc-based DAC and having close to gauss dispersion beam shaping. But with H-scanning it cause the vertical direction is gauss-shaped and horizontal direction mostly not. And I do not see horizontal sinc-based scaling to simulate DAC before CRT. At least as an option because today many footages are non-conditioned for sinc-based scaling and will expose lots of ringing.

real.finder
5th September 2021, 16:25
Heh - the whole point of CRT is analog line-drawing tool being feed from sinc-based DAC and having close to gauss dispersion beam shaping. But with H-scanning it cause the vertical direction is gauss-shaped and horizontal direction mostly not. And I do not see horizontal sinc-based scaling to simulate DAC before CRT. At least as an option because today many footages are non-conditioned for sinc-based scaling and will expose lots of ringing.

maybe these (https://forum.doom9.org/showpost.php?p=1924679&postcount=19) can help? or better HackTV (https://github.com/fsphil/hacktv) with LD-Decode (https://github.com/happycube/ld-decode)/VHS-Decode (https://github.com/oyvindln/ld-decode) will give real thing :cool: see here https://forum.videohelp.com/threads/394168-Current-status-of-ld-decode-vhs-decode-%28true-backup-of-RF-signals%29

real.finder
11th February 2025, 11:03
it will be nice if someone port this https://github.com/SnowflakePowered/librashader to avs/avs+, there are some mind blowing crt (and others) shaders in retroarch and if librashader get avs plugin we can enjoy their so many effects too

Reel.Deel
12th February 2025, 06:19
it will be nice if someone port this https://github.com/SnowflakePowered/librashader to avs/avs+, there are some mind blowing crt (and others) shaders in retroarch and if librashader get avs plugin we can enjoy their so many effects too

That would be great.

StvG
12th February 2025, 06:32
it will be nice if someone port this https://github.com/SnowflakePowered/librashader to avs/avs+, there are some mind blowing crt (and others) shaders in retroarch and if librashader get avs plugin we can enjoy their so many effects too

Cannot you use these shaders with libplacebo_Shader?

Reel.Deel
12th February 2025, 07:58
Cannot you use these shaders with libplacebo_Shader?

I believe you need to convert them first, see Automatic porting of libretro shaders to mpv (https://github.com/mpv-player/mpv/discussions/14246). Here's some already converted shaders: https://github.com/hhirtz/mpv-retro-shaders - (have not tried them in avslibplacebo).

real.finder
2nd April 2026, 07:25
new Function that use crt_display https://github.com/realfinder/AVS-Stuff/blob/master/avs%202.6%20and%20up/crt_tv_interlace.avsi

crt_tv_interlace() can be used as a crt deinterlacer for 480i/576i (like DVD) and a crt upscaler in the same time

enjoy the quality of good old days of crt tv :)

Edit: small update that add SMiniPhosphorPersistence() and Afterglow bool to crt_tv_interlace()

Edit2: it's better to be used with my avs+ mod of crt_display.avsi (https://github.com/realfinder/AVS-Stuff/blob/master/for%20AVSPlus/crt_display.avsi)