1/*
2 * Copyright 2010, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * This is a conversion of a conversion of a cg shader from Chrome:
34 * http://src.chromium.org/viewvc/chrome/trunk/src/o3d/samples/shaders/yuv2rgb.shader
35 */
36
37/*
38 * This shader takes a Y'UV420p image as a single greyscale plane, and
39 * converts it to RGB by sampling the correct parts of the image, and
40 * by converting the colorspace to RGB on the fly.
41 */
42
43/*
44 * These represent the image dimensions of the SOURCE IMAGE (not the
45 * Y'UV420p image).  This is the same as the dimensions of the Y'
46 * portion of the Y'UV420p image.  They are set from JavaScript.
47 */
48uniform float imageWidth;
49uniform float imageHeight;
50
51/*
52 * This is the texture sampler where the greyscale Y'UV420p image is
53 * accessed.
54 */
55uniform sampler2D textureSampler;
56
57#if defined (USE_UNIFORM_MATRIX)
58uniform mat4 conversion;
59#endif
60
61varying vec4 v1;
62
63/**
64 * Given the texture coordinates, our pixel shader grabs the right
65 * value from each channel of the source image, converts it from Y'UV
66 * to RGB, and returns the result.
67 *
68 * Each Y texel provides luminance information for one pixel in the image.
69 * Each U and V texel provides color information for a 2x2 block of pixels.
70 * The U and V texels are just appended to the Y texels.
71 *
72 * For images that have a height divisible by 4, things work out nicely.
73 * For images that are merely divisible by 2, it's not so nice
74 * (and YUV420 doesn't work for image sizes not divisible by 2).
75 *
76 * Here is a 6x6 image, with the layout of the planes of U and V.
77 * Notice that the V plane starts halfway through the last scanline
78 * that has U on it.
79 *
80 * 0  +---+---+---+---+---+---+
81 *    | Y0| Y0| Y1| Y1| Y2| Y2|
82 *    +---+---+---+---+---+---+
83 *    | Y0| Y0| Y1| Y1| Y2| Y2|
84 *    +---+---+---+---+---+---+
85 *    | Y3| Y3| Y4| Y4| Y5| Y5|
86 *    +---+---+---+---+---+---+
87 *    | Y3| Y3| Y4| Y4| Y5| Y5|
88 *    +---+---+---+---+---+---+
89 *    | Y6| Y6| Y7| Y7| Y8| Y8|
90 *    +---+---+---+---+---+---+
91 *    | Y6| Y6| Y7| Y7| Y8| Y8|
92 *2/3 +---+---+---+---+---+---+
93 *    | U0| U1| U2| U3| U4| U5|
94 *    +---+---+---+---+---+---+
95 *5/6 | U6| U7| U8| V0| V1| V2|
96 *    +---+---+---+---+---+---+
97 *    | V3| V4| V5| V6| V7| V8|
98 * 1  +---+---+---+---+---+---+
99 *    0          0.5          1
100 *
101 * Here is a 4x4 image, where the U and V planes are nicely split into
102 * separable blocks.
103 *
104 * 0  +---+---+---+---+
105 *    | Y0| Y0| Y1| Y1|
106 *    +---+---+---+---+
107 *    | Y0| Y0| Y1| Y1|
108 *    +---+---+---+---+
109 *    | Y2| Y2| Y3| Y3|
110 *    +---+---+---+---+
111 *    | Y2| Y2| Y3| Y3|
112 *2/3 +---+---+---+---+
113 *    | U0| U1| U2| U3|
114 *5/6 +---+---+---+---+
115 *    | V0| V1| V2| V3|
116 * 1  +---+---+---+---+
117 *    0      0.5      1
118 *
119 * The number in a cell indicates which U and V values map onto
120 * the cell: Un and Vn are used to color the four 'n' cells.  As the
121 * image is drawn its texture coordinates range from 0 to 1.  The 'y'
122 * coordinate is scaled by 2/3 to map from the Y texels, scaled by 1/6
123 * and shifted down 2/3 to map from the U texels, and scaled by 1/6
124 * and shifted down 5/6 to map from the V texels.  To map from U or V
125 * texels the 'x' coordinate is scaled by 1/2 always and shifted right
126 * 1/2 when needed.  For example rows 0 and 1 use left side U texels
127 * (U0-U2 in the first example) while rows 2 and 3 right side U texels
128 * (U3-U5 in the first example), and so on for the remaining rows.
129 * When the image height is a multiple of 4, the 'V side' is the same
130 * as the 'U side,' otherwise it is opposite.
131*/
132
133
134void main() {
135  float uside, vside;
136
137  // texture origin at top left, vertex origin at bottom left
138  vec2 t = vec2(v1.x, (1. - v1.y));
139
140  // y position in pixels
141  float ypixel = floor(t.y * imageHeight);
142
143  if (mod(ypixel, 4.) < 2.) {
144    // rows 0-1, U on left side
145    uside = 0.;
146  } else {
147    // rows 2-3, U on right side
148    uside = .5;
149  }
150
151  if (mod(imageHeight, 4.) == 0.) {
152    // multiple of 4, V same side as U
153    vside = uside;
154  } else {
155    // assume multiple of 2, V opposite side to U
156    vside = .5 - uside;
157  }
158
159  // shrink y tex. coord. by 2/3 to cover Y section
160  vec2 y = t * vec2(1., 2./3.);
161
162  // for U and V shrink x tex. coord. by 0.5, y by 1/6
163  t *= vec2(.5, 1./6.);
164
165  // shift to proper side and translate down...
166  vec2 u = t + vec2(uside, 2./3.); // ...to U section
167  vec2 v = t + vec2(vside, 5./6.); // ...to V section
168
169  float yChannel = texture2D(textureSampler, y).x;
170  float uChannel = texture2D(textureSampler, u).x;
171  float vChannel = texture2D(textureSampler, v).x;
172
173  /*
174   * This does the colorspace conversion from Y'UV to RGB as a matrix
175   * multiply.  It also does the offset of the U and V channels from
176   * [0,1] to [-.5,.5] as part of the transform.
177   */
178  vec4 channels = vec4(yChannel, uChannel, vChannel, 1.0);
179#if !defined(USE_UNIFORM_MATRIX)
180  mat4 conversion = mat4( 1.0,    1.0,    1.0,   0.0,
181                          0.0,   -0.344,  1.772, 0.0,
182                          1.402, -0.714,  0.0,   0.0,
183                         -0.701,  0.529, -0.886, 1.0);
184#endif
185
186  gl_FragColor = conversion * channels;
187}
188