• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include "config.h"
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <stdint.h>
31 #include <sys/mman.h>
32 #include <sys/mman.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <fcntl.h>
38 #include <assert.h>
39 
40 #include <cairo.h>
41 
42 #include "wcap-decode.h"
43 
44 static void
write_png(struct wcap_decoder * decoder,const char * filename)45 write_png(struct wcap_decoder *decoder, const char *filename)
46 {
47 	cairo_surface_t *surface;
48 
49 	surface = cairo_image_surface_create_for_data((unsigned char *) decoder->frame,
50 						      CAIRO_FORMAT_ARGB32,
51 						      decoder->width,
52 						      decoder->height,
53 						      decoder->width * 4);
54 	cairo_surface_write_to_png(surface, filename);
55 	cairo_surface_destroy(surface);
56 }
57 
58 static inline int
rgb_to_yuv(uint32_t format,uint32_t p,int * u,int * v)59 rgb_to_yuv(uint32_t format, uint32_t p, int *u, int *v)
60 {
61 	int r, g, b, y;
62 
63 	switch (format) {
64 	case WCAP_FORMAT_XRGB8888:
65 		r = (p >> 16) & 0xff;
66 		g = (p >> 8) & 0xff;
67 		b = (p >> 0) & 0xff;
68 		break;
69 	case WCAP_FORMAT_XBGR8888:
70 		r = (p >> 0) & 0xff;
71 		g = (p >> 8) & 0xff;
72 		b = (p >> 16) & 0xff;
73 		break;
74 	default:
75 		assert(0);
76 	}
77 
78 	y = (19595 * r + 38469 * g + 7472 * b) >> 16;
79 	if (y > 255)
80 		y = 255;
81 
82 	*u += 46727 * (r - y);
83 	*v += 36962 * (b - y);
84 
85 	return y;
86 }
87 
88 static inline
clamp_uv(int u)89 int clamp_uv(int u)
90 {
91 	int clamp = (u >> 18) + 128;
92 
93 	if (clamp < 0)
94 		return 0;
95 	else if (clamp > 255)
96 		return 255;
97 	else
98 		return clamp;
99 }
100 
101 static void
convert_to_yv12(struct wcap_decoder * decoder,unsigned char * out)102 convert_to_yv12(struct wcap_decoder *decoder, unsigned char *out)
103 {
104 	unsigned char *y1, *y2, *u, *v;
105 	uint32_t *p1, *p2, *end;
106 	int i, u_accum, v_accum, stride0, stride1;
107 	uint32_t format = decoder->format;
108 
109 	stride0 = decoder->width;
110 	stride1 = decoder->width / 2;
111 	for (i = 0; i < decoder->height; i += 2) {
112 		y1 = out + stride0 * i;
113 		y2 = y1 + stride0;
114 		v = out + stride0 * decoder->height + stride1 * i / 2;
115 		u = v + stride1 * decoder->height / 2;
116 		p1 = decoder->frame + decoder->width * i;
117 		p2 = p1 + decoder->width;
118 		end = p1 + decoder->width;
119 
120 		while (p1 < end) {
121 			u_accum = 0;
122 			v_accum = 0;
123 			y1[0] = rgb_to_yuv(format, p1[0], &u_accum, &v_accum);
124 			y1[1] = rgb_to_yuv(format, p1[1], &u_accum, &v_accum);
125 			y2[0] = rgb_to_yuv(format, p2[0], &u_accum, &v_accum);
126 			y2[1] = rgb_to_yuv(format, p2[1], &u_accum, &v_accum);
127 			u[0] = clamp_uv(u_accum);
128 			v[0] = clamp_uv(v_accum);
129 
130 			y1 += 2;
131 			p1 += 2;
132 			y2 += 2;
133 			p2 += 2;
134 			u++;
135 			v++;
136 		}
137 	}
138 }
139 
140 static void
convert_to_yuv444(struct wcap_decoder * decoder,unsigned char * out)141 convert_to_yuv444(struct wcap_decoder *decoder, unsigned char *out)
142 {
143 
144 	unsigned char *yp, *up, *vp;
145 	uint32_t *rp, *end;
146 	int u, v;
147 	int i, stride, psize;
148 	uint32_t format = decoder->format;
149 
150 	stride = decoder->width;
151 	psize = stride * decoder->height;
152 	for (i = 0; i < decoder->height; i++) {
153 		yp = out + stride * i;
154 		up = yp + (psize * 2);
155 		vp = yp + (psize * 1);
156 		rp = decoder->frame + decoder->width * i;
157 		end = rp + decoder->width;
158 		while (rp < end) {
159 			u = 0;
160 			v = 0;
161 			yp[0] = rgb_to_yuv(format, rp[0], &u, &v);
162 			up[0] = clamp_uv(u/.3);
163 			vp[0] = clamp_uv(v/.3);
164 			up++;
165 			vp++;
166 			yp++;
167 			rp++;
168 		}
169 	}
170 }
171 
172 static void
output_yuv_frame(struct wcap_decoder * decoder,int depth)173 output_yuv_frame(struct wcap_decoder *decoder, int depth)
174 {
175 	static unsigned char *out;
176 	int size;
177 
178 	if (depth == 444) {
179 		size = decoder->width * decoder->height * 3;
180 	} else {
181 		size = decoder->width * decoder->height * 3 / 2;
182 	}
183 	if (out == NULL)
184 		out = malloc(size);
185 
186 	if (depth == 444) {
187 		convert_to_yuv444(decoder, out);
188 	} else {
189 		convert_to_yv12(decoder, out);
190 	}
191 
192 	printf("FRAME\n");
193 	fwrite(out, 1, size, stdout);
194 }
195 
196 static void
usage(int exit_code)197 usage(int exit_code)
198 {
199 	fprintf(stderr, "usage: wcap-decode "
200 		"[--help] [--yuv4mpeg2] [--frame=<frame>] [--all] \n"
201 		"\t[--rate=<num:denom>] <wcap file>\n\n"
202 		"\t--help\t\t\tthis help text\n"
203 		"\t--yuv4mpeg2\t\tdump wcap file to stdout in yuv4mpeg2 format\n"
204 		"\t--yuv4mpeg2-444\t\tdump wcap file to stdout in yuv4mpeg2 444 format\n"
205 		"\t--frame=<frame>\t\twrite out the given frame number as png\n"
206 		"\t--all\t\t\twrite all frames as pngs\n"
207 		"\t--rate=<num:denom>\treplay frame rate for yuv4mpeg2,\n"
208 		"\t\t\t\tspecified as an integer fraction\n\n");
209 
210 	exit(exit_code);
211 }
212 
main(int argc,char * argv[])213 int main(int argc, char *argv[])
214 {
215 	struct wcap_decoder *decoder;
216 	int i, j, output_frame = -1, yuv4mpeg2 = 0, all = 0, has_frame;
217 	int num = 30, denom = 1;
218 	char filename[200];
219 	char *mode;
220 	uint32_t msecs, frame_time;
221 
222 	for (i = 1, j = 1; i < argc; i++) {
223 		if (strcmp(argv[i], "--yuv4mpeg2-444") == 0) {
224 			yuv4mpeg2 = 444;
225 		} else if (strcmp(argv[i], "--yuv4mpeg2") == 0) {
226 			yuv4mpeg2 = 420;
227 		} else if (strcmp(argv[i], "--help") == 0) {
228 			usage(EXIT_SUCCESS);
229 		} else if (strcmp(argv[i], "--all") == 0) {
230 			all = 1;
231 		} else if (sscanf(argv[i], "--frame=%d", &output_frame) == 1) {
232 			;
233 		} else if (sscanf(argv[i], "--rate=%d", &num) == 1) {
234 			;
235 		} else if (sscanf(argv[i], "--rate=%d:%d", &num, &denom) == 2) {
236 			;
237 		} else if (strcmp(argv[i], "--") == 0) {
238 			break;
239 		} else if (argv[i][0] == '-') {
240 			fprintf(stderr,
241 				"unknown option or invalid argument: %s\n", argv[i]);
242 			usage(EXIT_FAILURE);
243 		} else {
244 			argv[j++] = argv[i];
245 		}
246 	}
247 	argc = j;
248 
249 	if (argc != 2)
250 		usage(EXIT_FAILURE);
251 	if (denom == 0) {
252 		fprintf(stderr, "invalid rate, denom can not be 0\n");
253 		exit(EXIT_FAILURE);
254 	}
255 
256 	decoder = wcap_decoder_create(argv[1]);
257 	if (decoder == NULL) {
258 		fprintf(stderr, "Creating wcap decoder failed\n");
259 		exit(EXIT_FAILURE);
260 	}
261 
262 	if (yuv4mpeg2 && isatty(1)) {
263 		fprintf(stderr, "Not dumping yuv4mpeg2 data to terminal.  Pipe output to a file or a process.\n");
264 		fprintf(stderr, "For example, to encode to webm, use something like\n\n");
265 		fprintf(stderr, "\t$ wcap-decode  --yuv4mpeg2 ../capture.wcap |\n"
266 			"\t\tvpxenc --target-bitrate=1024 --best -t 4 -o foo.webm -\n\n");
267 
268 		exit(EXIT_FAILURE);
269 	}
270 
271 	if (yuv4mpeg2) {
272 		if (yuv4mpeg2 == 444) {
273 			mode = "C444";
274 		} else {
275 			mode = "C420jpeg";
276 		}
277 		printf("YUV4MPEG2 %s W%d H%d F%d:%d Ip A0:0\n",
278 					 mode, decoder->width, decoder->height, num, denom);
279 		fflush(stdout);
280 	}
281 
282 	i = 0;
283 	has_frame = wcap_decoder_get_frame(decoder);
284 	msecs = decoder->msecs;
285 	frame_time = 1000 * denom / num;
286 	while (has_frame) {
287 		if (all || i == output_frame) {
288 			snprintf(filename, sizeof filename,
289 				 "wcap-frame-%d.png", i);
290 			write_png(decoder, filename);
291 			fprintf(stderr, "wrote %s\n", filename);
292 		}
293 		if (yuv4mpeg2)
294 			output_yuv_frame(decoder, yuv4mpeg2);
295 		i++;
296 		msecs += frame_time;
297 		while (decoder->msecs < msecs && has_frame)
298 			has_frame = wcap_decoder_get_frame(decoder);
299 	}
300 
301 	fprintf(stderr, "wcap file: size %dx%d, %d frames\n",
302 		decoder->width, decoder->height, i);
303 
304 	wcap_decoder_destroy(decoder);
305 
306 	return EXIT_SUCCESS;
307 }
308