From 5abf4bdc2775e4514f9cf8e2bf842f685eba2fd8 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 19 Oct 2012 10:55:41 +1100 Subject: [PATCH] image/draw: fast-path for 4:4:0 chroma subsampled sources. R=r CC=golang-dev https://golang.org/cl/6699049 --- src/pkg/image/draw/draw.go | 33 +++++++++++++----- src/pkg/image/jpeg/reader_test.go | 1 + src/pkg/image/testdata/video-001.q50.440.jpeg | Bin 0 -> 3662 bytes .../video-001.q50.440.progressive.jpeg | Bin 0 -> 3529 bytes 4 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 src/pkg/image/testdata/video-001.q50.440.jpeg create mode 100644 src/pkg/image/testdata/video-001.q50.440.progressive.jpeg diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go index bef325c0c9d..56d30dd6f82 100644 --- a/src/pkg/image/draw/draw.go +++ b/src/pkg/image/draw/draw.go @@ -81,8 +81,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas drawNRGBAOver(dst0, r, src0, sp) return case *image.YCbCr: - drawYCbCr(dst0, r, src0, sp) - return + if drawYCbCr(dst0, r, src0, sp) { + return + } } } else if mask0, ok := mask.(*image.Alpha); ok { switch src0 := src.(type) { @@ -104,8 +105,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas drawNRGBASrc(dst0, r, src0, sp) return case *image.YCbCr: - drawYCbCr(dst0, r, src0, sp) - return + if drawYCbCr(dst0, r, src0, sp) { + return + } } } } @@ -345,7 +347,7 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image } } -func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) { +func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) { // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil // (i.e. fully opaque) then the op is effectively always Src. x0 := (r.Min.X - dst.Rect.Min.X) * 4 @@ -353,6 +355,19 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po y0 := r.Min.Y - dst.Rect.Min.Y y1 := r.Max.Y - dst.Rect.Min.Y switch src.SubsampleRatio { + case image.YCbCrSubsampleRatio444: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } case image.YCbCrSubsampleRatio422: for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { dpix := dst.Pix[y*dst.Stride:] @@ -381,12 +396,11 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po dpix[x+3] = 255 } } - default: - // Default to 4:4:4 subsampling. + case image.YCbCrSubsampleRatio440: for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { dpix := dst.Pix[y*dst.Stride:] yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) - ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X) + ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X) for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) dpix[x+0] = rr @@ -395,7 +409,10 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po dpix[x+3] = 255 } } + default: + return false } + return true } func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) { diff --git a/src/pkg/image/jpeg/reader_test.go b/src/pkg/image/jpeg/reader_test.go index c3c33a2bc58..f7fbd9a8a5e 100644 --- a/src/pkg/image/jpeg/reader_test.go +++ b/src/pkg/image/jpeg/reader_test.go @@ -21,6 +21,7 @@ func TestDecodeProgressive(t *testing.T) { "../testdata/video-001", "../testdata/video-001.q50.420", "../testdata/video-001.q50.422", + "../testdata/video-001.q50.440", "../testdata/video-001.q50.444", "../testdata/video-005.gray.q50", } diff --git a/src/pkg/image/testdata/video-001.q50.440.jpeg b/src/pkg/image/testdata/video-001.q50.440.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..32eeeaef6fc3cb82c21b76689139c8faac8738c1 GIT binary patch literal 3662 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 s?0?A{)usGUpf-pBESuRO*;Vqbvgaz ze%9uXd_?2ma06!prz(%)2=V<=Ptd8|>8{`nuBu#_RdWius%_?i_N|ycv!%vM zOM`+QKQ6;!lvbooU53gDBrTW1r@f`R)*kI?#2wSOrNR8!lHd6f^Br+DMgBQ>4fnS7 z?*}2TuYUO4@8m4E@41(#lv{STBr`L!e~S+M@{b><4i0oW$?W;DBio2`)GU@>)CLn| z@s>87Y#}(EY%pEY|Ed-Qh9giA7*beK;TOmBHfVzmmbT0$ClTD6dsEE`Y250=u88 zRO?T4Bc1u&B0?_b$4GTaMVHFdY?#;dk!lw_1~I4jrOu_GVnNM=6=NG>H)SE1fZeTDYm=VJG7YMpp;lgyep_K3nx*|@#NqG=t znB|r5>bbu}$D|GZ&bk84sR^{46E?c^4vn&u{XU z+%$(8trWK4-s>9TmQIw@!07He2o<>wxcHXx+T2nIpI@iNY08Ru3+_jHN_=zNFCx1k zyQ;=ADg)+@D4Qo@l)2kKlu=RWq71g6V&6vQP?iMPJsWD1UHBBNPd%Q|8gj?+cjF_Y zgi`1t{>Z(?+>6XgVRA~ixbvs*qu4@mVjxl z6`p_&g3CLzN-WR5vjMIwpib&q_nspw<`A%<#M^v8x~o@MdrEvi@#D9wW$hMoeo4q8 z|C<5cN34>ndaraY{OMK*0H!A(h~e)Zg6QPw!thS0u)Jzt1=_~vr1rmw18EDdGRvhr z65b73S_zKABKG7>d}f#AXY!QYWvfq!>`-}evEE6{IOOBWQK=p;-{Q(x@Axt7QE0b0 znxn~eNZzSt3x4Wegs?{N{Bl#@!-Y(>S$S+hjyR!y&v13t%5bZevK<^9A!UnZO1QLt zoK_KmO3x6tOb*1V^f_9RJe4PL~y1&atz(;p>hdqqJ{-~ zvApDFpCrY5jMB0T?Uuu|nEpW~VnfOu>ZdA~ne$i`ABJ~m;%{KHy))k;Yy!o&N&PSH z90DP0Ap+vx40AV0iwboNmdM^-kL0%nsyNT)ksTQ?2Z2`wNpZ?@sH)Pbc$R_!1oUzu zm9sJC`7~n0C6FcM*^7gk)t;`bDZvYSN5AcH%z6D_>St%l7%xw3gg%#35c_ou(wRsM<%tM<&T{K7R=-;)>CMM7Gf^OUjE z8pp{Q^#mawyD7>wyhxMU+5z{L2X zLQ*W9zxM%&#ya|gJe7mIc8Lnjt>}oom^~GqJN?;K8@ZTr;fmQdR%QKUq0-R7<)_Wb z<7`OT!B6uDIAZeeTiyrtWb{r zgw%p{j9W_<9vdSZQ)-o3C^0E%KxN98lSsMAsdAb{RNy@Qrv#NLoZFX=lry)E=$M_s z!QST;eB7n4m-d#J^S>f~(Vg|0?=J!En%_<)s6@qB^40-=kh)TD z_*Aesu`wsDn-EtX1cg|i*+2`%P#5*uY3oRtN(KE;7OByvH*p@=fm^aa<_nH;_nBOC zN#E8)6jB_M=3B8QZfM^A*g%&U`fB z`ReEy3pgIJ+cvSvXE?DQ_Qnly4FwYX zRxe!V9*dI*!LNY;FaAz2xllB@gQ(ov8X>K*i(z2X%h=3c);m() z`N~F@5toq12=%@-P^C#Al5 zMvm#OJr!CqcPlpaWoN-kxA)dejI;hDNiW*kcFb9gLm*5l(mL}pr|WHZL$+QdAL729 zK@|RzqRrjgK@*x{xo%+=;&TGjH16j8_LG4xHoTgj?-bR~>SSpeJgXn%ts3SxZF8$U z=6OZ6MWEfV@bk#Ro~C|G*~Snyv^;-0(*h|nG41%JfZ=U`)AND6^9@s|_X)XMOvT67Sz8aQoMovskZ~yGwiyfNteTL={6Udyp6*CknK^qd)jt|f0W7goCKC! z1Ez7A+woco$t%L3=Z@4TRsOM;>`;~8gk{T;Oligb(rDSB2M;g9^~W`Q}6zL8y!}z)pqCwp?Pvq>xoeL;)bQt@JueXhrom$qh{* zvxLk$nJ00J6=K%$Y{kg66VCRet&B9aUPSY(2T9=3_$jmZT