• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdio.h>
2 #include <debug.h>
3 #include <cmdline.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <sys/mman.h>
7 #include <fcntl.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <unistd.h>
11 
12 #ifndef max
13 #define max(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; })
14 #define min(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; })
15 #endif
16 
17 #define CONVERT_TYPE_PPM 0
18 #define CONVERT_TYPE_RGB 1
19 #define CONVERT_TYPE_ARGB 2
20 
21 /*
22    YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved
23    U/V plane containing 8 bit 2x2 subsampled chroma samples.
24    except the interleave order of U and V is reversed.
25 
26                         H V
27    Y Sample Period      1 1
28    U (Cb) Sample Period 2 2
29    V (Cr) Sample Period 2 2
30  */
31 
32 typedef struct rgb_context {
33     unsigned char *buffer;
34     int width;
35     int height;
36     int rotate;
37     int i;
38     int j;
39     int size; /* for debugging */
40 } rgb_context;
41 
42 typedef void (*rgb_cb)(
43     unsigned char r,
44     unsigned char g,
45     unsigned char b,
46     rgb_context *ctx);
47 
48 const int bytes_per_pixel = 2;
49 
color_convert_common(unsigned char * pY,unsigned char * pUV,int width,int height,unsigned char * buffer,int size,int gray,int rotate,rgb_cb cb)50 static void color_convert_common(
51     unsigned char *pY, unsigned char *pUV,
52     int width, int height,
53     unsigned char *buffer,
54     int size, /* buffer size in bytes */
55     int gray,
56     int rotate,
57     rgb_cb cb)
58 {
59 	int i, j;
60 	int nR, nG, nB;
61 	int nY, nU, nV;
62     rgb_context ctx;
63 
64     ctx.buffer = buffer;
65     ctx.size = size; /* debug */
66     ctx.width = width;
67     ctx.height = height;
68     ctx.rotate = rotate;
69 
70     if (gray) {
71         for (i = 0; i < height; i++) {
72             for (j = 0; j < width; j++) {
73                 nB = *(pY + i * width + j);
74                 ctx.i = i;
75                 ctx.j = j;
76                 cb(nB, nB, nB, &ctx);
77             }
78         }
79     } else {
80         // YUV 4:2:0
81         for (i = 0; i < height; i++) {
82             for (j = 0; j < width; j++) {
83                 nY = *(pY + i * width + j);
84                 nV = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
85                 nU = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
86 
87                 // Yuv Convert
88                 nY -= 16;
89                 nU -= 128;
90                 nV -= 128;
91 
92                 if (nY < 0)
93                     nY = 0;
94 
95                 // nR = (int)(1.164 * nY + 2.018 * nU);
96                 // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
97                 // nB = (int)(1.164 * nY + 1.596 * nV);
98 
99                 nB = (int)(1192 * nY + 2066 * nU);
100                 nG = (int)(1192 * nY - 833 * nV - 400 * nU);
101                 nR = (int)(1192 * nY + 1634 * nV);
102 
103                 nR = min(262143, max(0, nR));
104                 nG = min(262143, max(0, nG));
105                 nB = min(262143, max(0, nB));
106 
107                 nR >>= 10; nR &= 0xff;
108                 nG >>= 10; nG &= 0xff;
109                 nB >>= 10; nB &= 0xff;
110 
111                 ctx.i = i;
112                 ctx.j = j;
113                 cb(nR, nG, nB, &ctx);
114             }
115         }
116     }
117 }
118 
rgb16_cb(unsigned char r,unsigned char g,unsigned char b,rgb_context * ctx)119 static void rgb16_cb(
120     unsigned char r,
121     unsigned char g,
122     unsigned char b,
123     rgb_context *ctx)
124 {
125     unsigned short *rgb16 = (unsigned short *)ctx->buffer;
126     *(rgb16 + ctx->i * ctx->width + ctx->j) = b | (g << 5) | (r << 11);
127 }
128 
common_rgb_cb(unsigned char r,unsigned char g,unsigned char b,rgb_context * ctx,int alpha)129 static void common_rgb_cb(
130     unsigned char r,
131     unsigned char g,
132     unsigned char b,
133     rgb_context *ctx,
134     int alpha)
135 {
136     unsigned char *out = ctx->buffer;
137     int offset = 0;
138     int bpp;
139     int i = 0;
140     switch(ctx->rotate) {
141     case 0: /* no rotation */
142         offset = ctx->i * ctx->width + ctx->j;
143         break;
144     case 1: /* 90 degrees */
145         offset = ctx->height * (ctx->j + 1) - ctx->i;
146         break;
147     case 2: /* 180 degrees */
148         offset = (ctx->height - 1 - ctx->i) * ctx->width + ctx->j;
149         break;
150     case 3: /* 270 degrees */
151         offset = (ctx->width - 1 - ctx->j) * ctx->height + ctx->i;
152         break;
153     default:
154         FAILIF(1, "Unexpected roation value %d!\n", ctx->rotate);
155     }
156 
157     bpp = 3 + !!alpha;
158     offset *= bpp;
159     FAILIF(offset < 0, "point (%d, %d) generates a negative offset.\n", ctx->i, ctx->j);
160     FAILIF(offset + bpp > ctx->size, "point (%d, %d) at offset %d exceeds the size %d of the buffer.\n",
161            ctx->i, ctx->j,
162            offset,
163            ctx->size);
164 
165     out += offset;
166 
167     if (alpha) out[i++] = 0xff;
168     out[i++] = r;
169     out[i++] = g;
170     out[i] = b;
171 }
172 
rgb24_cb(unsigned char r,unsigned char g,unsigned char b,rgb_context * ctx)173 static void rgb24_cb(
174     unsigned char r,
175     unsigned char g,
176     unsigned char b,
177     rgb_context *ctx)
178 {
179     return common_rgb_cb(r,g,b,ctx,0);
180 }
181 
argb_cb(unsigned char r,unsigned char g,unsigned char b,rgb_context * ctx)182 static void argb_cb(
183     unsigned char r,
184     unsigned char g,
185     unsigned char b,
186     rgb_context *ctx)
187 {
188     return common_rgb_cb(r,g,b,ctx,1);
189 }
190 
convert(const char * infile,const char * outfile,int height,int width,int gray,int type,int rotate)191 static void convert(const char *infile,
192                     const char *outfile,
193                     int height,
194                     int width,
195                     int gray,
196                     int type,
197                     int rotate)
198 {
199     void *in, *out;
200     int ifd, ofd, rc;
201     int psz = getpagesize();
202     static char header[1024];
203     int header_size;
204     size_t outsize;
205 
206     int bpp = 3;
207     switch (type) {
208     case CONVERT_TYPE_PPM:
209         PRINT("encoding PPM\n");
210         if (rotate & 1)
211             header_size = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", height, width);
212         else
213             header_size = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", width, height);
214 	break;
215     case CONVERT_TYPE_RGB:
216         PRINT("encoding raw RGB24\n");
217         header_size = 0;
218         break;
219     case CONVERT_TYPE_ARGB:
220         PRINT("encoding raw ARGB\n");
221         header_size = 0;
222         bpp = 4;
223         break;
224     }
225 
226     outsize = header_size + width * height * bpp;
227     outsize = (outsize + psz - 1) & ~(psz - 1);
228 
229     INFO("Opening input file %s\n", infile);
230     ifd = open(infile, O_RDONLY);
231     FAILIF(ifd < 0, "open(%s) failed: %s (%d)\n",
232            infile, strerror(errno), errno);
233 
234     INFO("Opening output file %s\n", outfile);
235     ofd = open(outfile, O_RDWR | O_CREAT, 0664);
236     FAILIF(ofd < 0, "open(%s) failed: %s (%d)\n",
237            outfile, strerror(errno), errno);
238 
239     INFO("Memory-mapping input file %s\n", infile);
240     in = mmap(0, width * height * 3 / 2, PROT_READ, MAP_PRIVATE, ifd, 0);
241     FAILIF(in == MAP_FAILED, "could not mmap input file: %s (%d)\n",
242            strerror(errno), errno);
243 
244     INFO("Truncating output file %s to %d bytes\n", outfile, outsize);
245     FAILIF(ftruncate(ofd, outsize) < 0,
246            "Could not truncate output file to required size: %s (%d)\n",
247            strerror(errno), errno);
248 
249     INFO("Memory mapping output file %s\n", outfile);
250     out = mmap(0, outsize, PROT_WRITE, MAP_SHARED, ofd, 0);
251     FAILIF(out == MAP_FAILED, "could not mmap output file: %s (%d)\n",
252            strerror(errno), errno);
253 
254     INFO("PPM header (%d) bytes:\n%s\n", header_size, header);
255     FAILIF(write(ofd, header, header_size) != header_size,
256            "Error wrinting PPM header: %s (%d)\n",
257            strerror(errno), errno);
258 
259     INFO("Converting %dx%d YUV 4:2:0 to RGB24...\n", width, height);
260     color_convert_common(in, in + width * height,
261                          width, height,
262                          out + header_size, outsize - header_size,
263                          gray, rotate,
264                          type == CONVERT_TYPE_ARGB ? argb_cb : rgb24_cb);
265 }
266 
267 int verbose_flag;
268 int quiet_flag;
269 
main(int argc,char ** argv)270 int main(int argc, char **argv) {
271 
272     char *infile, *outfile, *type;
273     int height, width, gray, rotate;
274     int cmdline_error = 0;
275 
276     /* Parse command-line arguments. */
277 
278     int first = get_options(argc, argv,
279                             &outfile,
280                             &height,
281                             &width,
282                             &gray,
283                             &type,
284                             &rotate,
285                             &verbose_flag);
286 
287     if (first == argc) {
288         ERROR("You must specify an input file!\n");
289         cmdline_error++;
290     }
291     if (!outfile) {
292         ERROR("You must specify an output file!\n");
293         cmdline_error++;
294     }
295     if (height < 0 || width < 0) {
296         ERROR("You must specify both image height and width!\n");
297         cmdline_error++;
298     }
299 
300     FAILIF(rotate % 90, "Rotation angle must be a multiple of 90 degrees!\n");
301 
302     rotate /= 90;
303     rotate %= 4;
304     if (rotate < 0) rotate += 4;
305 
306     if (cmdline_error) {
307         print_help(argv[0]);
308         exit(1);
309     }
310 
311     infile = argv[first];
312 
313     INFO("input file: [%s]\n", infile);
314     INFO("output file: [%s]\n", outfile);
315     INFO("height: %d\n", height);
316     INFO("width: %d\n", width);
317     INFO("gray only: %d\n", gray);
318     INFO("encode as: %s\n", type);
319     INFO("rotation: %d\n", rotate);
320 
321     /* Convert the image */
322 
323     int conv_type;
324     if (!type || !strcmp(type, "ppm"))
325         conv_type = CONVERT_TYPE_PPM;
326     else if (!strcmp(type, "rgb"))
327         conv_type = CONVERT_TYPE_RGB;
328     else if (!strcmp(type, "argb"))
329         conv_type = CONVERT_TYPE_ARGB;
330     else FAILIF(1, "Unknown encoding type %s.\n", type);
331 
332     convert(infile, outfile,
333             height, width, gray,
334             conv_type,
335             rotate);
336 
337     free(outfile);
338     return 0;
339 }
340