2015年8月19日水曜日

YV12ToYUY2

2chのソフトウェア板見てみたら、YV12->YUY2でちょっともりあがってたようなので久しぶりにエンコネタで書いてみる。

なんでもConvertToYUY2()を色差補間なしの可逆変換したい層がそこそこいるそうで、ddcc.dllのYV12ToYUY2をitype=0で使っているらしい。
で、今回ddcc.dllのコード見てみたのだけど、これってinterlaced=false,cplace=3の時以外は、ddcc.dll使わなくてもよさそう。

とりあえずitype=0の場合はavisynth2.6だとこのスクリプトで代用できる。
(itype=0の場合、cplaceは指定しても無視される)
#YV12ToYUY2_no_interp.avs

function YV12ToYUY2_ni(clip c, bool "interlaced")
{
    is_shit = default(interlaced, false)
    assert(c.IsYV12(), "input clip is not YV12.")
    return is_shit ? c.YV12ToYUY2_ni_i() : c.YV12ToYUY2_ni_p()
}

function YV12ToYUY2_ni_p(clip c)
{
    w = c.width() / 2
    h = c.height()
    u = c.UToY8().PointResize(w, h)
    v = c.VToY8().PointResize(w, h)
    return YToUV(u, v, c).ConvertToYUY2()
}

function YV12ToYUY2_ni_i(clip c)
{
    sep = c.SeparateFields()
    w = sep.width() / 2
    h = sep.height()
    u = sep.UToY8().PointResize(w, h)
    v = sep.VToY8().PointResize(w, h)
    return YToUV(u, v, sep).Weave().ConvertToYUY2()
}

ddcc.dllのyv12toyuy2はフレーム分割方式でマルチスレッド化はされてるけどCのみで書かれていてSIMDは使ってないので、threads=1だと上記のスクリプトのほうが速い。
もともと重い処理ではないのでシングルスレッドでもボトルネックにはならないと思うけど。

ちなみに上記の処理でYUY2にしたものをYV12に戻す場合はこうなる。
function YUY2ToYV12_ni(clip c, bool "interlaced")
{
    is_shit = default(interlaced, false)
    assert(c.IsYUY2(), "input clip is not YUY2.")
    assert(c.height() % 2 == 0, "height must be mod 2.")
    c = c.ConvertToYV16()
    return is_shit ? c.YUY2ToYV12_ni_i() : c.YUY2ToYV12_ni_p()
}

function YUY2ToYV12_ni_p(clip c)
{
    w = c.width() / 2
    h = c.height() / 2
    u = c.UToY8().PointResize(w, h)
    v = c.VToY8().PointResize(w, h)
    return YToUV(u, v, c)
}

function YUY2ToYV12_ni_i(clip c)
{
    sep = c.SeparateFields()
    w = sep.width() / 2
    h = sep.height() / 2
    u = sep.UToY8().PointResize(w, h)
    v = sep.VToY8().PointResize(w, h)
    return YToUV(u, v, sep).Weave()
}

出力に差があるかないか確認したい場合はこんな感じで
LoadPlugin("ddcc.dll")
LoadPlugin("masktools2.dll")
Import("YV12ToYUY2_no_interp.avs")

src = something_yv12_clip
v0 = src.YV12ToYUY2(interlaced=true, itype=0)
v1 = YV12ToYUY2_ni(interlaced=true)
v2 = v1.YUY2ToYV12(interlaced=true)

ShowDiffYUV(v0, v1)
#ShowDiffYUV(src, v2)

function ShowDiffYUV(clip c0, clip c1)
{
    assert(c0.IsYUV() && c1.IsYUV(), "not YUV clip was found")
    c0 = c0.IsYUY2() ? c0.ConvertToYV16() : c0
    c1 = c1.IsYUY2() ? c1.ConvertToYV16() : c1
    cond = c0.PixelType() == c1.PixelType() && c0.width() == c1.width() &&\
           c0.height() == c1.height()
    assert(cond, "It's impossible to compare.")

    return mt_makediff(c0, c1, chroma="process").mt_lut("x 128 == 128 255 ?", chroma="process")
}
もし出力に違いがあれば灰色以外のケバい色になるはずです。

追記:
20150820 default()の引数の順番間違えてたのを修正

0 件のコメント:

コメントを投稿