Home | History | Annotate | Download | only in src
      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  */
     48 uniform float imageWidth;
     49 uniform float imageHeight;
     50 
     51 /*
     52  * This is the texture sampler where the greyscale Y'UV420p image is
     53  * accessed.
     54  */
     55 uniform sampler2D textureSampler;
     56 
     57 #if defined (USE_UNIFORM_MATRIX)
     58 uniform mat4 conversion;
     59 #endif
     60 
     61 varying 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 
    134 void 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