PDA

View Full Version : ReDeblock - another deblocking script


redfordxx
8th May 2006, 22:13
Hi,
I tried Deblock_QED but it seemed a bit weak for my purposes, so I used some of its ideas and produced something as follows (first version, probably needs tuning, your ideas are welcome, I you find it interesting to bother with). It should be stronger than QED, but still should preserve detail.

BTW: I several times refer to QED here, because who knows it might faster understand this...

ReDeblock.avsi:

###################################
# ReDeblock 0.1 by Redford
#
# Thanx to all doom9 members and non-members for tools and inspiration,
# especially to Didee (QED presence here is obvious)
#
# imported Patterns.avsi
# plugged mt_masktools.dll and LinearBlock_02Nov05.dll
#
###################################


function ReDeblock(clip "orig",clip "debl", int "correction", int "q", int "a", int "b", int "reduce", int "test")
{
test=default(test,0) #to set different outputs for testing purposes

correction=default(correction,2) #correction of wildly shifted values 0=off, else acc. to convolutions
reduce=default(reduce,1) #reducing the second deblocking, 0=off

q=default(q,0) #parameters for Deblock, by default, the deblocker does nothing
a=default(a,10)
b=default(b,10)

#find blocking
ptrn1=PtrnBlock(orig,3,0,1,2,4)
diff1=mt_makediff(debl,orig,y=3,u=3,v=3)
diff2=mt_lutxy(diff1,ptrn1,"y 0 == x 128 ?",y=3,u=3,v=3)
linb=diff2.LinearBlock()

#try to restore medium-size detail
mask1=linb.mt_convolution("1 2 2 2 1","1 2 2 2 1",y=3,u=3,v=3)
mask2=linb.mt_convolution("1 1 1 1 1 1 1","1 1 1 1 1 1 1",y=3,u=3,v=3)
mask3=mask2 # future --- nice to have an adaptive one, coz on really hard blocking the mask1 is contraproductive, on small and normal blocking the mask2 doesnot restore the detail so much
linb2=Select(correction,linb,mt_makediff(linb,mask1,y=3,u=3,v=3),mt_makediff(linb,mask2,y=3,u=3,v=3),mt_makediff(linb,mask3,y=3,u=3,v=3))

#apply deblocking
debl2=mt_adddiff(orig,linb2,y=3,u=3,v=3)

#here maybe some spatial smoothing, not to confuse the second deblocker
debl3=debl2

#second deblocking
debl4=debl3.Deblock(q,a,b)

#reducing the second deblocking
diff3=mt_lutxy(debl4,debl3,"x y > x y - 1 - 128 + x y == 128 x y - 1 + 128 + ? ?",y=3,u=3,v=3)
debl5=Select(reduce,debl4,mt_adddiff(debl3,diff3,y=3,u=3,v=3))

return(Select(test, debl5, \
debl4, \
debl3, \
debl2, \
linb2.mt_lut("x 128 - 20 * 128 +",y=3,u=3,v=3), \
linb.mt_lut("x 128 - 20 * 128 +",y=3,u=3,v=3), \
diff3.mt_lut("x 128 - 20 * 128 +",y=3,u=3,v=3), \
diff2.mt_lut("x 128 - 20 * 128 +",y=3,u=3,v=3), \
diff1.mt_lut("x 128 - 20 * 128 +",y=3,u=3,v=3)))
#return(debl5)
}






function ReDeblockLite(clip "orig",clip "debl", int "correction")
{
correction=default(correction,2)

#find blocking
ptrn1=PtrnBlock(orig,3,0,1,2,4)
diff1=mt_makediff(debl,orig,y=3,u=3,v=3)
diff2=mt_lutxy(diff1,ptrn1,"y 0 == x 128 ?",y=3,u=3,v=3)
linb=diff2.LinearBlock()

#try to restore medium-size detail
mask1=linb.mt_convolution("1 2 2 2 1","1 2 2 2 1",y=3,u=3,v=3)
mask2=linb.mt_convolution("1 1 1 1 1 1 1","1 1 1 1 1 1 1",y=3,u=3,v=3)
mask3=mask2 # future --- nice to have an adaptive one, coz on really hard blocking the mask1 is contraproductive, on small and normal blocking the mask2 doesnot restore the detail so much
linb2=Select(correction,linb,mt_makediff(linb,mask1,y=3,u=3,v=3),mt_makediff(linb,mask2,y=3,u=3,v=3),mt_makediff(linb,mask3,y=3,u=3,v=3))

#apply deblocking
debl2=mt_adddiff(orig,linb2,y=3,u=3,v=3)

return(debl2)
}

There are two versions of it. Originally it was intended as the non-lite version, but it seems already the lite version does pretty good job.




[EDIT] 30.5.2006: I discovered some issues in this deblockers performance and I don't recommend using it. If you are searching for something new to try, I'll appreciate feedback on SmoothDeblock (http://forum.doom9.org/showthread.php?t=111526) which is still under developement but IMHO safe to use.

redfordxx
8th May 2006, 22:18
It's just a generalization of something Didée used in his QED.
Patterns.avsi
function Matrix (clip clp, int "uv")
{
uv = default(uv,3)

unit=blankclip(clp,width=4,height=4,pixel_type="YV12")
row=stackhorizontal( unit.mt_lut(y=0,u=2,v=2),
\ unit.mt_lut(y=-1,u=2,v=2),
\ unit.mt_lut(y=-2,u=2,v=2),
\ unit.mt_lut(y=-3,u=2,v=2),
\ unit.mt_lut(y=-4,u=2,v=2),
\ unit.mt_lut(y=-5,u=2,v=2),
\ unit.mt_lut(y=-6,u=2,v=2),
\ unit.mt_lut(y=-7,u=2,v=2))
square=stackvertical( row.mt_lut("x 0 +",y=3,u=2,v=2),
\ row.mt_lut("x 8 +",y=3,u=2,v=2),
\ row.mt_lut("x 16 +",y=3,u=2,v=2),
\ row.mt_lut("x 24 +",y=3,u=2,v=2),
\ row.mt_lut("x 32 +",y=3,u=2,v=2),
\ row.mt_lut("x 40 +",y=3,u=2,v=2),
\ row.mt_lut("x 48 +",y=3,u=2,v=2),
\ row.mt_lut("x 56 +",y=3,u=2,v=2))
block=square#.mt_lut("x 4 *",y=3,u=2,v=2)
block4=stackvertical(stackhorizontal(block,block),stackhorizontal(block,block)).pointresize(16,16)
block4 = (uv!=3) ? block4.mt_lut(y=3,u=uv,v=uv)
\ : YtoUV(block4.crop(0,0,8,8),block4.crop(0,0,8,8),block4)
return(block4.trim(1,1))
}




function PtrnFormat(clip clp, clip form)
{
fh=form.height
fw=form.width
clp=StackHorizontal(clp,clp,clp,clp,clp,clp,clp,clp,clp,clp)
clp=StackVertical(clp,clp,clp,clp,clp,clp,clp,clp)
clp=(fw > 160) ? StackHorizontal(clp,clp,clp,clp) : clp
clp=(fh > 128) ? StackVertical(clp,clp,clp,clp) : clp
clp=(fw > 640) ? StackHorizontal(clp,clp,clp) : clp
clp=(fh > 512) ? StackVertical(clp,clp,clp) : clp
clp=clp.crop(0,0,fw,fh)

return(clp.loop(framecount(form)))
}




function PtrnVertical(clip clp, int "uv", int "v0", int "v1", int "v2", int "v3", int "v4", int "v5", int "v6", int "v7")
{
v1 = default(v1,255-v0)
v2 = default(v2,v1)
v3 = default(v3,v2)
v4 = default(v4,v3)
v5 = default(v5,v2)
v6 = default(v6,v1)
v7 = default(v7,v0)

mtrx=Matrix(clp,uv)
ptrn=mt_lutxy(mtrx,mtrx,"x 8 % 0 == "+String(v0)+" "+String(v1)+" ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 8 % 2 == "+String(v2)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 8 % 3 == "+String(v3)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 8 % 4 == "+String(v4)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 8 % 5 == "+String(v5)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 8 % 6 == "+String(v6)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 8 % 7 == "+String(v7)+" y ?",y=3,u=uv,v=uv)

return(ptrn.PtrnFormat(clp))
}




function PtrnHorizontal(clip clp, int "uv", int "v0", int "v1", int "v2", int "v3", int "v4", int "v5", int "v6", int "v7")
{
v1 = default(v1,255-v0)
v2 = default(v2,v1)
v3 = default(v3,v2)
v4 = default(v4,v3)
v5 = default(v5,v2)
v6 = default(v6,v1)
v7 = default(v7,v0)

mtrx=Matrix(clp,uv)
ptrn=mt_lutxy(mtrx,mtrx,"x 4 - 8 / 8 % 0 == "+String(v0)+" "+String(v1)+" ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 2 == "+String(v2)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 3 == "+String(v3)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 4 == "+String(v4)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 5 == "+String(v5)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 6 == "+String(v6)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 7 == "+String(v7)+" y ?",y=3,u=uv,v=uv)

return(ptrn.PtrnFormat(clp))
}



function PtrnBlock(clip clp, int "uv", int "v0", int "v1", int "v2", int "v3")
{
v1 = default(v1,255-v0)
v2 = default(v2,v1)
v3 = default(v3,v2)

mtrx=Matrix(clp,uv)
ptrn=mt_lutxy(mtrx,mtrx,"x 4 - 8 / 8 % 1 >= x 4 - 8 / 8 % 6 <= & x 8 % 1 >= x 8 % 6 <= & & "+String(v1)+" "+String(v0)+" ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 2 >= x 4 - 8 / 8 % 5 <= & x 8 % 2 >= x 8 % 5 <= & & "+String(v2)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 3 >= x 4 - 8 / 8 % 4 <= & x 8 % 3 >= x 8 % 4 <= & & "+String(v3)+" y ?",y=3,u=uv,v=uv)

return(ptrn.PtrnFormat(clp))
}




function PtrnChess(clip clp, int "uv", int "v0", int "v1", int "v2", int "v3")
{
v1 = default(v1,255-v0)
v2 = default(v2,v0)
v3 = default(v3,v1)

mtrx=Matrix(clp,uv)
ptrn=mt_lutxy(mtrx,mtrx,"x 4 - 8 / 2 % 0 == x 2 % 0 == & "+String(v0)+" "+String(v1)+" ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 2 % 1 == x 2 % 1 == & "+String(v2)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 2 % 1 == x 2 % 0 == & "+String(v3)+" y ?",y=3,u=uv,v=uv)

return(ptrn.PtrnFormat(clp))
}




function PtrnSawH(clip clp, int "uv", string "shift", int "v0", int "v1", int "v2", int "v3", int "v4", int "v5", int "v6", int "v7")
{
v1 = default(v1,255-v0)
v2 = default(v2,v1)
v3 = default(v3,v2)
v4 = default(v4,v3)
v5 = default(v5,255-v4)
v6 = default(v6,v5)
v7 = default(v7,v6)

mtrx=Matrix(clp,uv)
ptrn=mt_lutxy(mtrx,mtrx,"x 4 - 8 / 8 % 0 == x 2 % "+shift+" 2 % == & x 4 + 8 / 8 % 0 == x 1 + 2 % "+shift+" 2 % == & | "+String(v0)+" "+String(v1)+" ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 2 == x 2 % "+shift+" 2 % == & x 4 + 8 / 8 % 2 == x 1 + 2 % "+shift+" 2 % == & | "+String(v2)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 3 == x 2 % "+shift+" 2 % == & x 4 + 8 / 8 % 3 == x 1 + 2 % "+shift+" 2 % == & | "+String(v3)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 4 == x 2 % "+shift+" 2 % == & x 4 + 8 / 8 % 4 == x 1 + 2 % "+shift+" 2 % == & | "+String(v4)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 5 == x 2 % "+shift+" 2 % == & x 4 + 8 / 8 % 5 == x 1 + 2 % "+shift+" 2 % == & | "+String(v5)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 6 == x 2 % "+shift+" 2 % == & x 4 + 8 / 8 % 6 == x 1 + 2 % "+shift+" 2 % == & | "+String(v6)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 8 % 7 == x 2 % "+shift+" 2 % == & x 4 + 8 / 8 % 7 == x 1 + 2 % "+shift+" 2 % == & | "+String(v7)+" y ?",y=3,u=uv,v=uv)

return(ptrn.PtrnFormat(clp))
}



function PtrnSawV(clip clp, int "uv", string "shift", int "v0", int "v1", int "v2", int "v3", int "v4", int "v5", int "v6", int "v7")
{
v1 = default(v1,255-v0)
v2 = default(v2,v1)
v3 = default(v3,v2)
v4 = default(v4,v3)
v5 = default(v5,255-v4)
v6 = default(v6,v5)
v7 = default(v7,v6)

mtrx=Matrix(clp,uv)
ptrn=mt_lutxy(mtrx,mtrx,"x 4 - 8 / 2 % "+shift+" 2 % == x 8 % 0 == & x 4 + 8 / 2 % "+shift+" 2 % == x 1 + 8 % 0 == & | "+String(v0)+" "+String(v1)+" ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 2 % "+shift+" 2 % == x 8 % 2 == & x 4 + 8 / 2 % "+shift+" 2 % == x 1 + 8 % 2 == & | "+String(v2)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 2 % "+shift+" 2 % == x 8 % 3 == & x 4 + 8 / 2 % "+shift+" 2 % == x 1 + 8 % 3 == & | "+String(v3)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 2 % "+shift+" 2 % == x 8 % 4 == & x 4 + 8 / 2 % "+shift+" 2 % == x 1 + 8 % 4 == & | "+String(v4)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 2 % "+shift+" 2 % == x 8 % 5 == & x 4 + 8 / 2 % "+shift+" 2 % == x 1 + 8 % 5 == & | "+String(v5)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 2 % "+shift+" 2 % == x 8 % 6 == & x 4 + 8 / 2 % "+shift+" 2 % == x 1 + 8 % 6 == & | "+String(v6)+" y ?",y=3,u=uv,v=uv)
ptrn=mt_lutxy(mtrx,ptrn,"x 4 - 8 / 2 % "+shift+" 2 % == x 8 % 7 == & x 4 + 8 / 2 % "+shift+" 2 % == x 1 + 8 % 7 == & | "+String(v7)+" y ?",y=3,u=uv,v=uv)

return(ptrn.PtrnFormat(clp))
}


function QuantMask (clip "orig", int "quant", int "lowpass", int "highpass", int "expand",int "output")
{
lowpass= default(lowpass,0)
highpass= default(highpass,255)
expand= default(expand,0)
output= default(output,5)

qm0=Select(quant,orig,orig.dctfilter(1,1,1,1,1,1,1,0),orig.dctfilter(1,1,1,1,1,1,0,0),orig.dctfilter(1,1,1,1,1,0,0,0),orig.dctfilter(1,1,1,1,0,0,0,0),orig.dctfilter(1,1,1,0,0,0,0,0),orig.dctfilter(1,1,0,0,0,0,0,0),orig.dctfilter(1,0,0,0,0,0,0,0))
qm1=qm0.mt_lutxy(orig,"x y - abs "+String(lowpass)+" - "+String(highpass)+" "+String(lowpass)+" - / 256 *",y=3,u=3,v=3)
qm2=qm1.mt_convolution("0 0 0 0 0 0 0 1 1 1 1 1 1 1 1","0 0 0 0 0 0 0 1 1 1 1 1 1 1 1",y=3,u=3,v=3)
qm3=qm2.pointresize(qm2.width/8,qm2.height/8)
qm4=Select(expand,qm3,qm3.mt_expand(y=3,u=3,v=3))
qm5=qm4.pointresize(qm4.width*8,qm4.height*8)

test6=qm0.mt_lutxy(orig,"x y - 128 +",y=3,u=3,v=3)

return(Select(output,qm0,qm1,qm2,qm3,qm4,qm5,test6))
} Not all these functions are necessary, but maybe you use them sometimes...
e.g. clip.PtrnBlock(3,255)=clip.PtrnBlock(3,255,0)=clip.PtrnBlock(3,255,0,0)=clip.PtrnBlock(3,255,0,0,0)
is same as block in QED

redfordxx
8th May 2006, 22:31
Usage example:
o0=mpeg2source("*.d2v").TFM(order=-1,field=0,mode=0,pp=6,MI=20).TDecimate()
b0=mpeg2source("*.d2v",cpu2="xxxxoo", moderate_h=15, moderate_v=25).TFM(order=-1,field=0,mode=0,pp=6,MI=20).TDecimate()

o0.ReDeblockLite(b0)
#o0.ReDeblockLite(b0,1)
#o0.ReDeblock(b0,1,20,10,10,1)#more detail, more blocktraces
#o0.ReDeblock(b0,0,20,10,10,0)#less detail, less blocks
#o0.ReDeblock(b0,0,20,10,10,0,5)#to see first deblocking mask

#compare following
#o0.ReDeblock(b0,0,0,10,10,1)
#o0.ReDeblock(b0,1,0,10,10,1)
#o0.ReDeblock(b0,2,0,10,10,1)
#o0.ReDeblock(b0,0,0,10,10,1,4)
#o0.ReDeblock(b0,1,0,10,10,1,4)
#o0.ReDeblock(b0,2,0,10,10,1,4)

In fact correction=0 is not recommended.
correction=2 is quite conservative (and still restores real edges a little)

danpos
9th May 2006, 03:14
@redfordxx

I tried your script and got this error:

http://img405.imageshack.us/img405/596/shot431oj.jpg (http://imageshack.us)

and I called the script as just as follows down:

RedDeblockLite()

So, I tried it expliciting the clip parameter:

RedDeblockLite(last)

so I got another error related to mt_masktools.dll:

http://img478.imageshack.us/img478/9654/shot445rj.jpg (http://imageshack.us)

I'm using latest MaskTools 2.0a28 / LinearBlock_02Nov05 / AviSynth 2.56

JFYI. :)

Cheers,

redfordxx
9th May 2006, 12:02
Well it was in hurry, so I didn't write much about.

Look at the example, it requires two clips
Original and (quite strongly) deblocked one.
And it's not RedDeblock but ReDeblock.

The original intension was to enable any deblocking you want.
For instance, in my example, the internal dgdecode (adaptive?) deblocker.
That's why you input whole deblocked clip and the deblocking is not done inside the script, like in QED...

danpos
9th May 2006, 13:01
@redfordxx

The "RedDeblock" was a typo and I fixed this into script. With regard on the parameters to be used, seems that I was blind :p

Now the script is working and I will play a bit with it.

THX mate! :)

Cheers,

redfordxx
9th May 2006, 14:12
If you mean really *play*, I will appreciate some suggestions. Because there is room for finetuning.
The easiest to explore:
1. medium-size detail restoration mt_convolution parameters
2. if you use MPEG2 source, then trying moderate_h, moderate_v... (I wonder how strong deblocking can this script correct...)

redfordxx
10th May 2006, 15:59
* (For interlaced material) Difference in deinterlacing (especially in line 1 or 8 of a DCT block) can sometimes produce artefacts. Not sure about the exact reasons yet... but sometimes I see residuals of PtrnBlock mask.

dukey
11th May 2006, 12:43
post some screenshots of this script working :)

foxyshadis
11th May 2006, 19:19
For interlaced deblocking, why not separatefields and deblock the fields separately? You just have to determine if it was encoded interlaced (8x8 blocks in fields) or progressive (8x4). Trying to compensate for inter-field motion seems like it'd be a losing battle that sucks up a lot of time, unless you start by bobbing it. (Maybe that'd be effective and fast enough, dunno.)

redfordxx
11th May 2006, 19:48
For interlaced deblocking, why not separatefields and deblock the fields separately? You just have to determine if it was encoded interlaced (8x8 blocks in fields) or progressive (8x4). Trying to compensate for inter-field motion seems like it'd be a losing battle that sucks up a lot of time, unless you start by bobbing it. (Maybe that'd be effective and fast enough, dunno.)
Not sure, but probably you are hitting topic I mentioned here (http://forum.doom9.org/showthread.php?p=826142#post826142)...

redfordxx
13th May 2006, 11:21
OOOps. LinearBlock does probably something different, than I thought. Can anybody tell me how it exactly works?

redfordxx
30th May 2006, 19:57
@danpos, or whoever else

this deblocker shows some artifacts here and there, hope you are not trying to use it anymore. I will probably never continue and fix it, because I am focusing on SmoothDeblock (http://forum.doom9.org/showthread.php?t=111526) (with screenshots for dukey;-) which performs much better although not yet finished, I have tested it more and will hopefully still improve it. Only it is much slower.

AVIL
30th May 2006, 20:58
OOOps. LinearBlock does probably something different, than I thought. Can anybody tell me how it exactly works?

From Kassandro site :

clip.LinearBlock()

Recalculates the middle 6 x 6 of every eight by eight block, using averaging. It doesn't deal with chroma, but that is easily added if you want it. I will also add chroma to the other filter.

redfordxx
31st May 2006, 01:51
From Kassandro site :
Could you give link pls?

Recalculates the middle 6 x 6 of every eight by eight block, using averaging.
So far I knew, but exactly...
It doesn't deal with chroma, but that is easily added if you want it. I will also add chroma to the other filter.Would be nice.

AVIL
31st May 2006, 07:20
Hi,

The link:

http://videoprocessing.11.forumer.com/viewtopic.php?t=12&start=15&sid=699107a9fd2be3e891d8d75bb631e52a

It's a post by Clouded (a.k.a mg262, author of linearblock) in a thread about kassandro's filter mdeblock.

|SeNsUi|
17th June 2009, 01:07
i get a error when loading redblock().

says there is no function named ptrnblock