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