1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 /*
7  * This code is based on the rgbtoycc.c code from the MPEG-1 Video
8  * Software Encoder (Version 1.5; February 1, 1995), by Lawrence
9  * A. Rowe, Kevin Gong, Eugene Hung, Ketan Patel, Steve Smoot and Dan
10  * Wallach Computer Science Division-EECS, Univ. of Calif. at Berkeley
11  *
12  * Copyright (c) 1995 The Regents of the University of California.
13  * All rights reserved.
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose, without fee, and without written agreement is
17  * hereby granted, provided that the above copyright notice and the following
18  * two paragraphs appear in all copies of this software.
19  *
20  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
21  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
22  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
23  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
26  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
28  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
29  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
30  */
31 
32 #include "MallocUtils.h"
33 #include "gl2yuv.h"
34 
create_yuv(FILE * outfile,PixelBuffer * buffer)35 void create_yuv(FILE *outfile, PixelBuffer *buffer)
36 {
37   if(buffer->getFormat() != GL_RGB || buffer->getType() != GL_UNSIGNED_BYTE) {
38     Msg::Error("YUV only implemented for GL_RGB and GL_UNSIGNED_BYTE");
39     return;
40   }
41 
42   int x, y;
43   unsigned char *dy0, *dy1;
44   unsigned char *dcr, *dcb;
45   unsigned char *src0, *src1;
46   int cdivisor;
47 
48   static int first = 1;
49   static float mult299[1024], mult587[1024], mult114[1024];
50   static float mult16874[1024], mult33126[1024], mult5[1024];
51   static float mult41869[1024], mult08131[1024];
52 
53   unsigned char **orig_y, **orig_cr, **orig_cb;
54 
55   if(first) {
56     int index;
57     int maxValue;
58 
59     maxValue = 255;
60 
61     for(index = 0; index <= maxValue; index++) {
62       mult299[index] = index * 0.29900F;
63       mult587[index] = index * 0.58700F;
64       mult114[index] = index * 0.11400F;
65       mult16874[index] = -0.16874F * index;
66       mult33126[index] = -0.33126F * index;
67       mult5[index] = index * 0.50000F;
68       mult41869[index] = -0.41869F * index;
69       mult08131[index] = -0.08131F * index;
70     }
71 
72     first = 0;
73   }
74 
75   int width = buffer->getWidth();
76   int height = buffer->getHeight();
77   unsigned char *pixels = (unsigned char *)buffer->getPixels();
78 
79   // yuv format assumes even number of rows and columns
80   height -= height % 2;
81   width -= width % 2;
82 
83   int row_stride = width * 3;
84 
85   orig_y = (unsigned char **)Malloc(sizeof(unsigned char *) * height);
86   for(y = 0; y < height; y++) {
87     orig_y[y] = (unsigned char *)Malloc(sizeof(unsigned char) * width);
88   }
89 
90   orig_cr = (unsigned char **)Malloc(sizeof(char *) * height / 2);
91   for(y = 0; y < height / 2; y++) {
92     orig_cr[y] = (unsigned char *)Malloc(sizeof(char) * width / 2);
93   }
94 
95   orig_cb = (unsigned char **)Malloc(sizeof(char *) * height / 2);
96   for(y = 0; y < height / 2; y++) {
97     orig_cb[y] = (unsigned char *)Malloc(sizeof(char) * width / 2);
98   }
99 
100   // assume ydivisor = 1, so cdivisor = 4
101   cdivisor = 4;
102 
103   for(y = 0; y < height; y += 2) {
104     src0 = &(pixels[y * row_stride]);
105     src1 = &(pixels[(y + 1) * row_stride]);
106     dy0 = orig_y[y];
107     dy1 = orig_y[y + 1];
108     dcr = orig_cr[y / 2];
109     dcb = orig_cb[y / 2];
110 
111     for(x = 0; x < width;
112         x += 2, dy0 += 2, dy1 += 2, dcr++, dcb++, src0 += 6, src1 += 6) {
113       *dy0 =
114         (unsigned char)(mult299[*src0] + mult587[src0[1]] + mult114[src0[2]]);
115 
116       *dy1 =
117         (unsigned char)(mult299[*src1] + mult587[src1[1]] + mult114[src1[2]]);
118 
119       dy0[1] =
120         (unsigned char)(mult299[src0[3]] + mult587[src0[4]] + mult114[src0[5]]);
121 
122       dy1[1] =
123         (unsigned char)(mult299[src1[3]] + mult587[src1[4]] + mult114[src1[5]]);
124 
125       *dcb = (unsigned char)((mult16874[*src0] + mult33126[src0[1]] +
126                               mult5[src0[2]] + mult16874[*src1] +
127                               mult33126[src1[1]] + mult5[src1[2]] +
128                               mult16874[src0[3]] + mult33126[src0[4]] +
129                               mult5[src0[5]] + mult16874[src1[3]] +
130                               mult33126[src1[4]] + mult5[src1[5]]) /
131                              cdivisor) +
132              128;
133 
134       *dcr = (unsigned char)((mult5[*src0] + mult41869[src0[1]] +
135                               mult08131[src0[2]] + mult5[*src1] +
136                               mult41869[src1[1]] + mult08131[src1[2]] +
137                               mult5[src0[3]] + mult41869[src0[4]] +
138                               mult08131[src0[5]] + mult5[src1[3]] +
139                               mult41869[src1[4]] + mult08131[src1[5]]) /
140                              cdivisor) +
141              128;
142     }
143   }
144 
145   // Y
146   for(y = height - 1; y >= 0; y--) fwrite(orig_y[y], 1, width, outfile);
147 
148   // U
149   for(y = height / 2 - 1; y >= 0; y--)
150     fwrite(orig_cb[y], 1, width / 2, outfile);
151 
152   // V
153   for(y = height / 2 - 1; y >= 0; y--)
154     fwrite(orig_cr[y], 1, width / 2, outfile);
155 
156   for(y = 0; y < height; y++) Free(orig_y[y]);
157   Free(orig_y);
158 
159   for(y = 0; y < height / 2; y++) Free(orig_cr[y]);
160   Free(orig_cr);
161 
162   for(y = 0; y < height / 2; y++) Free(orig_cb[y]);
163   Free(orig_cb);
164 }
165