Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 20th September 2008, 20:24   #1  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
adding grain on h264 in ffdshow ?

hi there,

I already use LSF+Ulevels() in realtime in ffdshow...it looks awesome

but a lot of h264 lack cinema grain badly

like the new FAST & FURIOUS trailer :
http://movies.apple.com/movies/unive...tlr1_h720p.mov

or the SPEED RACER bluray

anyhow, I've found an old masktools v1 script from Didée called "GrainFactory" that looks really great!

the FAST & FURIOUS trailer looks awesome with (3,5,100,100)

and adding grain also deblocks really well, it seems to increase the picture depth

you can set a different grain level for mid and high/low tones to simulate real movie silver grain......but it's sucking a helluvalot of CPU time

benchmarking in VDUB lowers from 88fps to 48....which gives problems on high bitrate 1.78 HD

anyone knows a similar script that might be usable in realtime in ffdshow ?

Addgrain is too static I think, it's not realistic at all.

or anyone would be up to the task of converting it to masktools v2 please please please ?

I'm an AVS n00b, not quite a coder

here's a version fixed by Didée this morning(picture was two notches too bright before the fix) and modded to spline36 by me :

Code:
function GrainFactory(clip last,int "grain1_strength",int "grain2_strength",int "grain1_sharpness",int "grain2_sharpness")
{

grain1_strength=default(grain1_strength,5)
grain2_strength=default(grain2_strength,2)
grain1_sharpness=default(grain1_sharpness,75)
grain2_sharpness=default(grain2_sharpness,75)

#grain1_strength  = 7      # [  0 - ???]  strength of grain / for mid-tone areas
grain1_size      = 1.15    # [0.5 - 4.0]  size of grain     / for mid-tone areas 

#grain2_strength  = 0       # [  0 - ???]  strength of grain / for dark & bright areas
grain2_size      = 0.8     # [0.5 - 4.0]  size of grain     / for dark & bright areas 

#grain1_sharpness = 75     # [  0 - 100]  very soft (0) to very sharp(100) 
#grain2_sharpness = 75     # [  0 - 100]                     grain definition 

grain1_texture   = 0     # [  0 - 100]  strength of "material texture" appearance
grain2_texture   = 0      # [  0 - 100]                   (in fact: 'bump' effect)

ontop_grain      = 0       # [  0 - ???]  additional grain to put on top of prev. generated grain 

temp_avg         = 20      # [  0 - 100]  percentage of noise's temporal averaging 

brightness_bias  = 0.96    # [0.5 - 2.0]  bias for  dark|bright --> midtone  fading 

#----------------------------------------------------------------------------------- 
o    = last
ox   = o.width
oy   = o.height
sx1  = m4(ox/grain1_size)
sy1  = m4(oy/grain1_size)
sx1a = m4((ox+sx1)/2.0)
sy1a = m4((oy+sy1)/2.0)
sx2  = m4(ox/grain2_size)
sy2  = m4(oy/grain2_size)
sx2a = m4((ox+sx2)/2.0)
sy2a = m4((oy+sy2)/2.0)
b1   = grain1_sharpness/(-50.0) + 1.0
b2   = grain2_sharpness/(-50.0) + 1.0
b1a  = b1/2.0
b2a  = b2/2.0
c1   = (1.0-b1)/2.0
c2   = (1.0-b2)/2.0
c1a  = c1/2.0
c2a  = c2/2.0
t1a  = string(grain1_texture)
t1b  = string(100-grain1_texture)
t2a  = string(grain2_texture)
t2b  = string(100-grain2_texture)
tmpavg = temp_avg/100.0

#-----------------------------------------------------------------------------------

ADD_DIFF    = "x y - 128 +"
BUMPKERNEL1 = T1a + " 0 0 0 " + T1b + " 0 0 0 0"
BUMPKERNEL2 = T2a + " 0 0 0 " + T2b + " 0 0 0 0"
CENTER2MAX_BIAS = "x 120 - abs "+string(brightness_bias)+" ^ 2.5 *"

#-----------------------------------------------------------------------------------

grainlayer1 = blankclip(o, width=sx1, height=sy1, color_yuv=$808080) .AddGrain(grain1_strength, 0, 0)

grainlayer1 = (grain1_texture==0)
 \           ? grainlayer1
 \           : yv12lutxy(grainlayer1,grainlayer1.DEdgeMask(0,255,0,255, BUMPKERNEL1), ADD_DIFF)

grainlayer1 = (grain1_size == 1.0) ? grainlayer1
 \          : (grain1_size < 0.75) ? grainlayer1.spline36resize(sx1a,sy1a, b1a, c1a).spline36resize(ox,oy, b1a,c1a)
 \          :                        grainlayer1.spline36resize(ox,oy, b1,c1)

#-----------------------------------------------------------------------------------

grainlayer2 = blankclip(o, width=sx2, height=sy2, color_yuv=$808080) .AddGrain(grain2_strength, 0, 0)

grainlayer2 = (grain2_texture==0)
 \           ? grainlayer2
 \           : yv12lutxy(grainlayer2,grainlayer2.DEdgeMask(0,255,0,255, BUMPKERNEL1), ADD_DIFF)

grainlayer2 = (grain2_size == 1.0) ? grainlayer2
 \          : (grain2_size < 0.75) ? grainlayer2.spline36resize(sx2a,sy2a, b2a, c2a).spline36resize(ox,oy, b2a,c2a)
 \          :                        grainlayer2.spline36resize(ox,oy, b2,c2)

#-----------------------------------------------------------------------------------

grainlayer = MaskedMerge(grainlayer1, grainlayer2, o.yv12lut(CENTER2MAX_BIAS), U=1,V=1)

grainlayer = (temp_avg==0) ? grainlayer
 \                         : grainlayer.mergeluma(grainlayer.temporalsoften(1,255,255,255,2), tmpavg)
grainlayer = (ontop_grain==0) ? grainlayer
 \                            : grainlayer.AddGrain(ontop_grain,0,0)

#-----------------------------------------------------------------------------------

result = yv12lutxy(o, grainlayer, ADD_DIFF, U=2,V=2)

return result
}
#-----------------------------------------------------------------------------------
function m4(float x) {return( x<16?16:int(round(x/4.0)*4)) }
#===================================================================================
for your help!

Last edited by pitch.fr; 20th September 2008 at 20:46.
pitch.fr is offline   Reply With Quote
Old 20th September 2008, 21:05   #2  |  Link
Didée
Registered User
 
Join Date: Apr 2002
Location: Germany
Posts: 5,389
Ah, a public thread. That's better.


Quote:
Originally Posted by Didée
It's not a gamma issue. It's a plain +2 shift on all pixels, caused by a RGB<>YUV mismatch.

See those lines in GrainFactory:
Code:
#-----------------------------------------------------------------------------------

grainlayer1 = blankclip(o, width=sx1, height=sy1, color=$808080) .AddGrain(grain1_strength, 0, 0)

...

#-----------------------------------------------------------------------------------

grainlayer2 = blankclip(o, width=sx2, height=sy2, color=$808080) .AddGrain(grain2_strength, 0, 0)

...
Problem is that color=X in blankclip interprets X as an RGB color, even if the input is YUV. Now, RGB=$808080 is YUV=$7E8080. Consequently, the grainlayers are based on [126,128,128] grey clips, where it should be [128,128,128].

Easiest way is to use "color_yuv":
Code:
#-----------------------------------------------------------------------------------

grainlayer1 = blankclip(o, width=sx1, height=sy1, color_yuv=$808080) .AddGrain(grain1_strength, 0, 0)

...

#-----------------------------------------------------------------------------------

grainlayer2 = blankclip(o, width=sx2, height=sy2, color_yuv=$808080) .AddGrain(grain2_strength, 0, 0)

...
It's an old function (almost forgot it), and I'm not sure if the "color_yuv" verb already existed in Avisynth at that time. Also, it looks like that function should be converted to MaskTools v2 ... I get grey hair when I see functions still using the old v1 MaskTools. <g>

Quote:
Originally Posted by Didée
Adapting to MaskTools v2 is no prob at all, but there's no speed gain to expect. It's the inpand/expand/inflate/deflate filters that got a big speedup from v1 -> v2, but those aren't even used here. Some filters are even a bit slower in v2 ... e.g. MaskedMerge -> mt_merge is a bit slower now, and this filter IS used in the script.

The most reasonable speedup would be to set temp_avg to zero, to disable any temporal filtering. The value for temp_avg has to be changed manually in the script, it's not a parameter. To help a little more, you could set grain2_size from 0.8 to 1.0, avoiding one resize operation.
(Note that I didn't even make this *function* ... I once put together a plain script on request of a user, the surrounding function code was made by someone else. It's easy to see ... several things in the function are either hardcoded and/or silently disabled ... that's not the way that I usually make my functions)

If it's still too slow with temp_avg=0 and grain2_size=1.0, then you've to use plain AddGrain (the ffdshow ones, then).

Or, another one: Mug Funky once suggested to apply blurred grain, to make it a little more film-ish. Don't have his script anymore, but it's easy to do ... like so:

Code:
# make some blurred grain
x1 = 15     #  strenght of grain, 0 ~ 255
x2 = 0.66  #  strength of grain blurring, 0.0 ~ 1.0
mt_makediff(mt_makediff(last,last.AddGrain(x1)).blur(x2),U=2,V=2)
In a nutshell:
a) converting to MaskTools v2 would be good as a matter of principle, but it won't help the speed.
b) for realtime usage, don't use monster scripts that were made for offline processing. Reflect about what you need barely, then use the most simple approach to get there.
__________________
- We´re at the beginning of the end of mankind´s childhood -

My little flickr gallery. (Yes indeed, I do have hobbies other than digital video!)
Didée is offline   Reply With Quote
Old 20th September 2008, 21:13   #3  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
ok, thanks for your help Didée once more

well I love watching movies with LSF/Ulevels/GrainFactory/DDCC

that's why I got an o/c Q6600 in the first place

how would your blurry grain thingie work btw ? should I create a function out of it ?

Yeah, IanB told me I should understand all the scripts I'm using, and try to make an all-in-one to avoid wasting CPU.

thing is, it works fine as it is, except for that new GrainFactory(good name BTW )

ok back for some more benchmarks :

LSF/Ulevels on 4 threads
=88fps

+GrainFactor
=48 fps

+grain2_size=1
=55 fps

+temp_avg=0
=52 fps

+grain2_size=1 / temp_avg=0
=62 fps

I don't think I wanna turn off temporal smoothing, it doesn't look as good when it's disabled..

I'd like to try with grain2_size=1 but AVS gives me an error msg : "Clip's size must be the same (line 86)"

that's line 86 :
Code:
grainlayer = MaskedMerge(grainlayer1, grainlayer2, o.yv12lut(CENTER2MAX_BIAS), U=1,V=1)
I had to put back grain2_size=0.8....any idea of a fix please ?

PS : anyway DDCC is the real CPU hog...when Haali will offer PS gamut conversion in his renderer, I will have plenty of CPU cycles available again

Last edited by pitch.fr; 20th September 2008 at 23:11.
pitch.fr is offline   Reply With Quote
Old 20th September 2008, 23:19   #4  |  Link
Sagekilla
x264aholic
 
Join Date: Jul 2007
Location: New York
Posts: 1,752
Erm, do you use SetMTMode() or MT() by any chance? If you have a quadcore those would help..
__________________
You can't call your encoding speed slow until you start measuring in seconds per frame.
Sagekilla is offline   Reply With Quote
Old 21st September 2008, 00:10   #5  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
I do, don't worry

IanB helped me to balance all these scripts nicely

Code:
MT("""
LimitedSharpenFaster(ss_x=1.1,ss_y=1.1,strength=40)
ULevels(preset="tv2pc")
GrainFactory(3,5,100,100)
""",4)
never managed to get SetMTMode working in ffdshow, though.

Last edited by pitch.fr; 21st September 2008 at 00:19.
pitch.fr is offline   Reply With Quote
Old 21st September 2008, 05:23   #6  |  Link
Sagekilla
x264aholic
 
Join Date: Jul 2007
Location: New York
Posts: 1,752
If I'd wager a guess, that has to do with the fact that all the filters added to the ffdshow filter chain are probably added after the source filter. SetMTMode only likes being used when it's the first thing called, otherwise it borks if it's not the first to load.
__________________
You can't call your encoding speed slow until you start measuring in seconds per frame.
Sagekilla is offline   Reply With Quote
Old 21st September 2008, 16:27   #7  |  Link
Leak
ffdshow/AviSynth wrangler
 
Leak's Avatar
 
Join Date: Feb 2003
Location: Austria
Posts: 2,441
Quote:
Originally Posted by Sagekilla View Post
If I'd wager a guess, that has to do with the fact that all the filters added to the ffdshow filter chain are probably added after the source filter. SetMTMode only likes being used when it's the first thing called, otherwise it borks if it's not the first to load.
That can be fixed by unchecking "Add ffdshow video source" and adding a call to ffdshow_source() at the appropriate place...

But it'll also need a call to Distributor() at the end, I suppose...

np: Digital Mystikz - Conference (Soul Jazz Records Singles 2006-2007 (Disc 1))
__________________
now playing: [artist] - [track] ([album])
Leak is offline   Reply With Quote
Old 21st September 2008, 16:42   #8  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
thanks for clearing that up Leak

how would that take place in this script please ?

Code:
MT("""
LimitedSharpenFaster(ss_x=1.1,ss_y=1.1,strength=40)
ULevels(preset="tv2pc")
GrainFactory(3,5,100,100)
""",4)
Distributor()
pitch.fr is offline   Reply With Quote
Old 21st September 2008, 17:04   #9  |  Link
Leak
ffdshow/AviSynth wrangler
 
Leak's Avatar
 
Join Date: Feb 2003
Location: Austria
Posts: 2,441
Quote:
Originally Posted by pitch.fr View Post
how would that take place in this script please ?
Don't ask me, I'm using vanilla AviSynth 2.5.8 RCsomething... no need to use any multithreading when DVD decoding plus AviSynth filtering uses half a core on my Core 2 Quad...

np: Subway - 44110 (Soul Jazz Records Singles 2006-2007 (Disc 1))
__________________
now playing: [artist] - [track] ([album])
Leak is offline   Reply With Quote
Old 21st September 2008, 17:13   #10  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
so it should added in the .avsi files ?

anyhow MT() works fine
pitch.fr is offline   Reply With Quote
Old 30th September 2008, 12:28   #11  |  Link
Didée
Registered User
 
Join Date: Apr 2002
Location: Germany
Posts: 5,389
Regarding the "GrainFactory" script - I've had a funny time to find and address all the faults, cracks and wrong twists in that script. In a sense, the script as a whole is just ONE BIG BUG from start to end.
Probably that is why originally I had only posted it as a plain linear script, as a suggestion upon some user request (on neuron2's forum, iirc). Function-izing was not done by me ...

A cleaned version will be posted shortly (today or tomorrow).
__________________
- We´re at the beginning of the end of mankind´s childhood -

My little flickr gallery. (Yes indeed, I do have hobbies other than digital video!)
Didée is offline   Reply With Quote
Old 30th September 2008, 12:49   #12  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
sounds great, thanks Didee!

I just wish it wasn't sucking so much CPU, but well nothing's free in this world.....except for your scripts that is

if you can also try w/ AddGrain 1.0 please, coz the newer versions make crazy memory leaks in MT..

maybe you could also add a third level of grain ? but in realtime that would put my o/c Q6600 to its kness I guess...

from what I understand silver film grain has different shapes depending on the ISO it was shot on, as SoulHunter explained here : http://forum.doom9.org/showpost.php?...0&postcount=12

I think you said BlockBuster() might be a better candidate than AddGrain() because it's luma aware, and can change shapes accordingly ?

to me the reference for grain is 21 grams in HD.....it was shot on very high ISO and the grain is simply mindblowing

it's hard to make proper stills of grainy movies, but you get the idea....the picture is fully deblocked and looks true to life :




Last edited by pitch.fr; 30th September 2008 at 13:14.
pitch.fr is offline   Reply With Quote
Old 1st October 2008, 12:25   #13  |  Link
Didée
Registered User
 
Join Date: Apr 2002
Location: Germany
Posts: 5,389
Using 3 different grain characteristics for dark/medium/bright would be an obvious thing to do. But that requires creating 3 layers, and subsequently using 2 times masked merge ... bad conditions for realtime usage on HD sources.

In clients like e.g. Vdub, I can *not* confirm any memory leakage. Not with AddGrain, and not with AddGrainC. (didn't try in ffdshow, though.)

Answer to all (PM'ed) questions about using PointResize: "No."

Quote:
I think you said BlockBuster() might be a better candidate than AddGrain() because it's luma aware, and can change shapes accordingly ?
Can't remember to have said sth like that. Blockbuster isn't "luma aware", and it doesn't change shapes.

---

Code:
GrainFactory Changelog:

- function GrainFactory(clip last,...) {... o=last ... }

  That's an outrageous construct, "Last" is not a free variable name. 
  (Spelled a curse, the creator will always line up in the longest and slowest queue until EOL.)
  Changed to sane syntax, not using a "custom LAST"

- exposed *all* possible variables as parameters (instead only those that the function maker happend to like personally.)

- Fixed erroneous luma offset. (color=X -> color_yuv=X in BlankClip())

- Made correct versions for both MaskTools-v2 and old MaskTools-v1: GrainFactory_MT1 / GrainFactory_MT2()
  MaskTools-v2 version is generally preferred. MaskTools-v1 version could be slightly faster (please test), 
  which might justify keeping the v1 version for realtime usage.

-- For the MaskTools-v1 version: Added possibility of internal padding. Target: multi-threading with MT(). 
   When grainX_size=1.0, padding seems needed to not make MaskTools-v1 stumble over the dimensions of 
   the frame slices. (MaskTools-v2 don't have this problem.)

- using temp_avg now is slightly faster. (don't process chroma in TemporalSoften)

- changed brightness_bias from 0.0~2.0 float range to 0~200 int range. 
  On some systems, the mixing process did not work at all. (string() function could convert decimal point to 
  decimal comma, confusing lutxy, resulting in a black mask, resulting in grain-mixing not functioning: 
  grainlayer2 had no effect at all on affected systems)

- 2-step resizing was used for small grainsizes, where it should be used for big grainsizes. Fixed.

-- fixed wrong b/c coefficient calculation for 2-step resizing

- added possibility to use only grain1 (with brightness_bias=0) or only grain2 (with brightness_bias=256).

- more small internal changes

Script containing both MT1 and MT2 version of GrainFactory:
Code:
function GrainFactory_MT1(clip clp,int "grain1_strength",int "grain2_strength",int "grain1_sharpness",int "grain2_sharpness", float "grain1_size", float "grain2_size",
 \                        int "grain1_texture", int "grain2_texture", int "temp_avg", float "brightness_bias", int "ontop_grain",
 \                        int "modH", int "modV")
{

grain1_strength  = default( grain1_strength,  8 )   # [ 0 - ???] strength of grain / for mid-tone areas
grain2_strength  = default( grain2_strength,  15 )  # [ 0 - ???] strength of grain / for dark & bright areas
grain1_sharpness = default( grain1_sharpness, 66 )  # [ 0 - 100] sharpness of grain / for mid-tone areas (NO EFFECT when grain1_size=1.0 !!)
grain2_sharpness = default( grain2_sharpness, 66 )  # [ 0 - 100] sharpness of grain / for dark & bright areas (NO EFFECT when grain2_size=1.0 !!)
grain1_size      = default( grain1_size,    1.00 )  # [0.5 - 4.0] size of grain / for mid-tone areas
grain2_size      = default( grain2_size,    1.41 )  # [0.5 - 4.0] size of grain / for dark & bright areas
grain1_texture   = default( grain1_texture,    0 )  # [ 0 - 100] strength of "material texture" appearance
grain2_texture   = default( grain2_texture,    0 )  # [ 0 - 100] (in fact: 'bump' effect)
temp_avg         = default( temp_avg,          0 )  # [ 0 - 100] percentage of noise's temporal averaging
brightness_bias  = default( brightness_bias,  96 )  # [50 - 200] bias for dark|bright --> midtone fading
ontop_grain      = default( ontop_grain,       0 )  # [ 0 - ???] additional grain to put on top of prev. generated grain

modH             = default( modH,              0 )  # use "4" when using MT(splitvertical=TRUE)
modV             = default( modV,              4 )  # needed for MT() (default:splitvertical=false) in combination with MaskTools v1.x


#-----------------------------------------------------------------------------------

ox0   = clp.width
oy0   = clp.height
padH = modH<1 ? 0 : (modH-(ox0%modH))%modH
padV = modV<1 ? 0 : (modV-(oy0%modV))%modV
o    = padH==0&&padV==0 ? clp : clp.addborders(0,0,padH,padV)
ox   = o.width()
oy   = o.height()
sx1  = m4(ox/float(grain1_size))
sy1  = m4(oy/float(grain1_size))
sx1a = m4((ox+sx1)/2.0)
sy1a = m4((oy+sy1)/2.0)
sx2  = m4(ox/float(grain2_size))
sy2  = m4(oy/float(grain2_size))
sx2a = m4((ox+sx2)/2.0)
sy2a = m4((oy+sy2)/2.0)
b1   = grain1_sharpness/(-50.0) + 1.0
b2   = grain2_sharpness/(-50.0) + 1.0
b1a  = b1/2.0
b2a  = b2/2.0
c1   = (1.0-b1)/2.0
c2   = (1.0-b2)/2.0
c1a  = (1.0-b1a)/2.0
c2a  = (1.0-b2a)/2.0
t1a  = string(grain1_texture)
t1b  = string(100-grain1_texture)
t2a  = string(grain2_texture)
t2b  = string(100-grain2_texture)
tmpavg = temp_avg/100.0



#-----------------------------------------------------------------------------------

ADD_DIFF = "x y - 128 +"
BUMPKERNEL1 = T1a + " 0 0 0 " + T1b + " 0 0 0 0"
BUMPKERNEL2 = T2a + " 0 0 0 " + T2b + " 0 0 0 0"
CENTER2MAX_BIAS = "x 120 - abs "+string(brightness_bias)+" 100 / ^ 2.5 *"

#-----------------------------------------------------------------------------------

grainlayer1 = blankclip(o, width=sx1, height=sy1, color_yuv=$808080) .AddGrainC(grain1_strength, 0,0,0)

grainlayer1 = (grain1_texture==0)
\           ? grainlayer1
\           : yv12lutxy(grainlayer1,grainlayer1.DEdgeMask(0,255,0,0, BUMPKERNEL1,U=1,V=1), ADD_DIFF,U=1,V=1)

grainlayer1 = (grain1_size == 1.0 || sx1==ox && sy1==oy) ? grainlayer1
\           : (grain1_size > 1.75) ? grainlayer1.bicubicresize(sx1a,sy1a, b1a,c1a).bicubicresize(ox,oy, b1a,c1a)
\                                  : grainlayer1.bicubicresize(ox,oy, b1,c1)

#-----------------------------------------------------------------------------------

grainlayer2 = blankclip(o, width=sx2, height=sy2, color_yuv=$808080) .AddGrainC(grain2_strength, 0,0,0)

grainlayer2 = (grain2_texture==0)
\           ? grainlayer2
\           : yv12lutxy(grainlayer2,grainlayer2.DEdgeMask(0,255,0,0, BUMPKERNEL2,U=1,V=1), ADD_DIFF,U=1,V=1)

grainlayer2 = (grain2_size==1.0 || sx2==ox && sy2==oy) ? grainlayer2
\           : (grain2_size > 1.75) ? grainlayer2.bicubicresize(sx2a,sy2a, b2a,c2a).bicubicresize(ox,oy, b2a,c2a)
\                                  : grainlayer2.bicubicresize(ox,oy, b2,c2)

#-----------------------------------------------------------------------------------

grainlayer = (brightness_bias >255) ? grainlayer2
 \         : (brightness_bias <  2) ? grainlayer1
 \                                  : MaskedMerge(grainlayer1, grainlayer2, o.yv12lut(CENTER2MAX_BIAS), U=1,V=1)

grainlayer = (temp_avg==0) ? grainlayer
\                          : grainlayer.mergeluma(grainlayer.temporalsoften(1,255,0,255,2), tmpavg)
grainlayer = (ontop_grain==0) ? grainlayer
\                             : grainlayer.AddGrainC(ontop_grain,0,0)

#-----------------------------------------------------------------------------------

result = yv12lutxy(o, grainlayer, ADD_DIFF, U=2,V=2)
result = ox0==ox&&oy0==oy ? result : result.crop(0,0,-padH,-padV) 

return( result) 
}
#-----------------------------------------------------------------------------------
function m4(float x) {return( x<16?16:int(round(x/4.0)*4)) }
#===================================================================================



function GrainFactory_MT2(clip clp,int "grain1_strength",int "grain2_strength",int "grain1_sharpness",int "grain2_sharpness", float "grain1_size", float "grain2_size",
 \                        int "grain1_texture", int "grain2_texture", int "temp_avg", float "brightness_bias", int "ontop_grain" )
{

grain1_strength  = default( grain1_strength,    8 )  # [ 0 - ???] strength of grain / for mid-tone areas
grain2_strength  = default( grain2_strength,   15 )  # [ 0 - ???] strength of grain / for dark & bright areas
grain1_sharpness = default( grain1_sharpness,  66 )  # [ 0 - 100] sharpness of grain / for mid-tone areas (NO EFFECT when grain1_size=1.0 !!)
grain2_sharpness = default( grain2_sharpness,  66 )  # [ 0 - 100] sharpness of grain / for dark & bright areas (NO EFFECT when grain2_size=1.0 !!)
grain1_size      = default( grain1_size,     1.00 )  # [0.5 - 4.0] size of grain / for mid-tone areas
grain2_size      = default( grain2_size,     1.41 )  # [0.5 - 4.0] size of grain / for dark & bright areas
grain1_texture   = default( grain1_texture,     0 )  # [ 0 - 100] strength of "material texture" appearance
grain2_texture   = default( grain2_texture,     0 )  # [ 0 - 100] (in fact: 'bump' effect)
temp_avg         = default( temp_avg,           0 )  # [ 0 - 100] percentage of noise's temporal averaging
brightness_bias  = default( brightness_bias,   96 )  # [50 - 200] bias for dark|bright --> midtone fading
ontop_grain      = default( ontop_grain,        0 )  # [ 0 - ???] additional grain to put on top of prev. generated grain


#-----------------------------------------------------------------------------------

o    = clp
ox   = o.width
oy   = o.height
sx1  = m4(ox/float(grain1_size))
sy1  = m4(oy/float(grain1_size))
sx1a = m4((ox+sx1)/2.0)
sy1a = m4((oy+sy1)/2.0)
sx2  = m4(ox/float(grain2_size))
sy2  = m4(oy/float(grain2_size))
sx2a = m4((ox+sx2)/2.0)
sy2a = m4((oy+sy2)/2.0)
b1   = grain1_sharpness/(-50.0) + 1.0
b2   = grain2_sharpness/(-50.0) + 1.0
b1a  = b1/2.0
b2a  = b2/2.0
c1   = (1.0-b1)/2.0
c2   = (1.0-b2)/2.0
c1a  = (1.0-b1a)/2.0
c2a  = (1.0-b2a)/2.0
T1a  = string(int(grain1_texture*1.28))
T1b  = string(128-int(grain1_texture*1.28))
T2a  = string(int(grain2_texture*1.28))
T2b  = string(128-int(grain2_texture*1.28))
tmpavg = temp_avg/100.0

#-----------------------------------------------------------------------------------

BUMPKERNEL1 = T1a + " 0 0 0 " + T1b + " 0 0 0 0 128"
BUMPKERNEL2 = T2a + " 0 0 0 " + T2b + " 0 0 0 0 128"
CENTER2MAX_BIAS = "x 120 - abs "+string(brightness_bias)+" 100 / ^ 2.5 *"

#-----------------------------------------------------------------------------------

grainlayer1 = blankclip(o, width=sx1, height=sy1, color_yuv=$808080) .AddGrainC(grain1_strength, 0,0,0)

grainlayer1 = (grain1_texture==0)
\           ? grainlayer1
\           : mt_makediff(grainlayer1,grainlayer1.mt_edge(BUMPKERNEL1, 0,255,0,0, U=1,V=1 ), U=1,V=1)

grainlayer1 = (grain1_size == 1.0 || sx1==ox && sy1==oy) ? grainlayer1
\           : (grain1_size > 1.5) ? grainlayer1.bicubicresize(sx1a,sy1a, b1a,c1a).bicubicresize(ox,oy, b1a,c1a)
\                                 : grainlayer1.bicubicresize(ox,oy, b1,c1)

#-----------------------------------------------------------------------------------

grainlayer2 = blankclip(o, width=sx2, height=sy2, color_yuv=$808080) .AddGrainC(grain2_strength, 0,0,0)

grainlayer2 = (grain2_texture==0)
\           ? grainlayer2
\           : mt_makediff(grainlayer2,grainlayer2.mt_edge(BUMPKERNEL2, 0,255,0,0, U=1,V=1 ), U=1,V=1)

grainlayer2 = (grain2_size==1.0 || sx2==ox && sy2==oy) ? grainlayer2
\           : (grain2_size > 1.5) ? grainlayer2.bicubicresize(sx2a,sy2a, b2a,c2a).bicubicresize(ox,oy, b2a,c2a)
\                                 : grainlayer2.bicubicresize(ox,oy, b2,c2)

#-----------------------------------------------------------------------------------

grainlayer = (brightness_bias >255) ? grainlayer2
 \         : (brightness_bias <  1) ? grainlayer1
 \                                  : mt_merge(grainlayer1, grainlayer2, o.mt_lut(CENTER2MAX_BIAS), U=1,V=1)

grainlayer = (temp_avg==0) ? grainlayer
\                          : grainlayer.mergeluma(grainlayer.temporalsoften(1,255,0,255,2), tmpavg)
grainlayer = (ontop_grain==0) ? grainlayer
\                             : grainlayer.AddGrainC(ontop_grain,0,0,0)

#-----------------------------------------------------------------------------------

result = o.mt_makediff(grainlayer, U=2,V=2) 

return( result ) 
}
__________________
- We´re at the beginning of the end of mankind´s childhood -

My little flickr gallery. (Yes indeed, I do have hobbies other than digital video!)
Didée is offline   Reply With Quote
Old 1st October 2008, 12:35   #14  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
oh cool, thanks! gonna try it right now

so by "no" you mean PointResize won't show any visible difference over spline/bicubic ?

w/ AddGrainC 1.1(newer versions make crazy memory leaks in ffdshow) and this test script in VDUB :

Code:
SetMemoryMax(512) # Adjust value as required

ColorBars(1280, 720, pixel_type="YV12") # Size and pixel type as appropriate

# Insert Code under test here
MT("GrainFactory(3,5,100,100)",4)

# Throw away most of the image we are not testing VD's i/o
Crop(0, 0, 16, 16)

Code:
MT("GrainFactory(3,5,100,100)",4)
=141 with AddGrain 1.0 | 142 w/ AddGrainC 1.1(139 if changing AddGrain to AddGrainC in the script)

Code:
MT("GrainFactory_MT1(3,5,100,100)",4)
=208

Code:
MT("GrainFactory_MT2(3,5,100,100)",4)
=233

maybe I'll change grainsize2 to something smaller ?

but anyhow benchmarks look promising

Last edited by pitch.fr; 1st October 2008 at 14:54.
pitch.fr is offline   Reply With Quote
Old 1st October 2008, 13:22   #15  |  Link
Didée
Registered User
 
Join Date: Apr 2002
Location: Germany
Posts: 5,389
Whoops. 228/141 is a 60% speedup ... not bad.

Using Pointresize for size-sampling of the added grain pretty much defeats the purpose of what the sampling is supposed to visually achieve. That's what I meant with "no".

Two times the exactly-same grain pattern (grainsize 1.75) ... left: Point / right: sharp bicubic :



Blargh. Pointresize looks ugly. If you're in need for speed so badly, then you can simply use a generic noise generator just as well.
__________________
- We´re at the beginning of the end of mankind´s childhood -

My little flickr gallery. (Yes indeed, I do have hobbies other than digital video!)
Didée is offline   Reply With Quote
Old 1st October 2008, 13:38   #16  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
wow, ok I'll just set it to spline36 then

you've changed the grain sizes from 1.15/0.8 to 1.0/1.41 to avoid one resize....but wouldn't that look any better to set grainsize2 to 0.8 or 0.65 ? I'll experiment

spline36 GrainF is 120fps, spline36 GrainF_MT2 is 220

my full LSF/Ulevels/GrainF/convertrgb32 script is 52 fps w/ or w/o AddGrain, 37 w/ GrainF and 43 w/ GrainF_MT2(LSF and all GrainF in spline)

Last edited by pitch.fr; 1st October 2008 at 14:53.
pitch.fr is offline   Reply With Quote
Old 1st October 2008, 18:38   #17  |  Link
Didée
Registered User
 
Join Date: Apr 2002
Location: Germany
Posts: 5,389
Grainsize1/2 is not a supersampling factor in the way like e.g. ss_x/y in LimitedSharpenFaster. Instead it refers to what the name says: to the size of grain. With grainsize=1.0, you get that kind of grain like when using AddGrain() directly. With smaller numbers like 0.8, you get smaller grain particles. With bigger numbers like 2.0, you get bigger grain particles.
Since film grain usually appears more coarse in dark areas, compared to more fine grain in the brighter midtones, the defaults are now set to reflect just that. Previously the sizes were reversed: very fine grain in the darks & brights, more coarse in the midtones.
If you liked the old settings more ... set the parameters to your liking. That's what parameters are for.


Quote:
Originally Posted by pitch.fr
LSF and all GrainF in spline
Question to you:
Please explain what are the benefits of modding GrainFactory to use SplineXResize instead of BicubicResize. I'm curious to hear the reasoning.
__________________
- We´re at the beginning of the end of mankind´s childhood -

My little flickr gallery. (Yes indeed, I do have hobbies other than digital video!)
Didée is offline   Reply With Quote
Old 1st October 2008, 18:49   #18  |  Link
pitch.fr
Didée 4 President
 
Join Date: Jun 2008
Posts: 239
oh OK, makes sense....they were reversed in the first version, but 1.4 seems too BIG for bright areas(eg open sky)

I will check on my DLP pj this evening coz on my 19" CRT I got a hard time seeing 0.65 grain size

Ideally we'd need 3 grain sizes I think for supreme grainness

well you just showed me that pointresize is terribly blocky compared to bicubic.
and bicubic(except in -1.0) is known not to be as sharp as spline36/lanczos4 ?
I got plenty of horse power, and I want VERY sharp grain so it doesn't ruin the sharpness of my HD movies

actually my pj has a full mineral glass lens so the grainier the merrier...it gives a crazy analog feel in 24Hz with Reclock

PS : I don't really see what the "grain_texture" do, but no biggy

Last edited by pitch.fr; 2nd October 2008 at 09:25.
pitch.fr is offline   Reply With Quote
Old 2nd October 2008, 01:23   #19  |  Link
CruNcher
Registered User
 
CruNcher's Avatar
 
Join Date: Apr 2002
Location: Germany
Posts: 4,926
Hmm Didée wouldn't it possible to record the original Grain Layer using mvdegrain and adding it back @ playback (instead of creating a artificial one) ?
so degrain with mvdegrain use the difference between the degrained and grained and regrain the compressed one with it or add it back @ playback, this way also the temporal information of the grainlayer could be preserved i think. Of course the recording of the whole layer wouldn't be necessary but i guess this way it could be easier to analyze different film stocks visual results and trying to match them as close as possible randomly generated. The final dream would be a selection box in ffdshow where you select the GrainLayer you want out of a Film Stock like Database
__________________
all my compares are riddles so please try to decipher them yourselves :)

It is about Time

Join the Revolution NOW before it is to Late !

http://forum.doom9.org/showthread.php?t=168004

Last edited by CruNcher; 2nd October 2008 at 01:49.
CruNcher is offline   Reply With Quote
Old 2nd October 2008, 03:17   #20  |  Link
Sagekilla
x264aholic
 
Join Date: Jul 2007
Location: New York
Posts: 1,752
Cruncher, I believe that would be possible.. It'd be like this, in pseudocode:

To encoder
Code:
source = last
degrain = source.MVDegrain()

grain = Overlay(source,degrain,mode="difference")
GrainFile(mode="output", file="grain.info")

output = degrain
Return(output)
From Decoder
Code:
source = last
GrainInfo = GrainFile(mode="input", file="grain.info")
You'd have to find a way to maybe do some averaging over a 5 second sample (with scenecut detection, cause grain might change then) and then include a little bit of data on how to vary the data for each new frame in that 5 second interval, so it's not static grain. Otherwise if you did it on a per frame basis, the file would be HUGE

That's what I came up in my head, probably not the best idea but it could work. You'd just have to deal with -massive- information files that detail how the grain is supposed to look like. If it came to that, I'd just go with FGO and include a few kbps of data on how to add grain back inside of the stream. Sort of like Spectral Band Replication for AAC.
__________________
You can't call your encoding speed slow until you start measuring in seconds per frame.

Last edited by Sagekilla; 2nd October 2008 at 03:34.
Sagekilla is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 08:37.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.