xref: /plan9-contrib/sys/src/cmd/jpg/readyuv.c (revision d1be6b086622eecc0da76db1fbd64349a5e85293)
1e288d156SDavid du Colombier /* readyuv.c - read an Abekas A66 style image file.   Steve Simon, 2003 */
2e288d156SDavid du Colombier #include <u.h>
3e288d156SDavid du Colombier #include <libc.h>
4e288d156SDavid du Colombier #include <bio.h>
5e288d156SDavid du Colombier #include <draw.h>
6e288d156SDavid du Colombier #include <ctype.h>
7e288d156SDavid du Colombier #include "imagefile.h"
8e288d156SDavid du Colombier 
9e288d156SDavid du Colombier 
10e288d156SDavid du Colombier enum {
11*d1be6b08SDavid du Colombier 	Pixels = 720,
12*d1be6b08SDavid du Colombier 	R601pal = 576,
13*d1be6b08SDavid du Colombier 	R601ntsc = 486,
142bef681aSDavid du Colombier 	Shift = 13
1576783259SDavid du Colombier };
16e288d156SDavid du Colombier 
17e288d156SDavid du Colombier 
18e288d156SDavid du Colombier static int lsbtab[] = { 6, 4, 2, 0};
19e288d156SDavid du Colombier 
20*d1be6b08SDavid du Colombier static int
looksize(char * file,vlong size,int * pixels,int * lines,int * bits)2176783259SDavid du Colombier looksize(char *file, vlong size, int *pixels, int *lines, int *bits)
2276783259SDavid du Colombier {
2376783259SDavid du Colombier 	Biobuf *bp;
2476783259SDavid du Colombier 	uvlong l, p;
2576783259SDavid du Colombier 	char *s, *a[12];
2676783259SDavid du Colombier 
2776783259SDavid du Colombier 	/*
2876783259SDavid du Colombier 	 * This may not always work, there could be an alias between file
2976783259SDavid du Colombier 	 * sizes of different standards stored in 8bits and 10 bits.
3076783259SDavid du Colombier 	 */
3176783259SDavid du Colombier 	if ((bp = Bopen(file, OREAD)) == nil)
3276783259SDavid du Colombier 		return -1;
3376783259SDavid du Colombier 	while((s = Brdstr(bp, '\n', 1)) != nil){
3476783259SDavid du Colombier 		if (tokenize(s, a, nelem(a)) < 3)
3576783259SDavid du Colombier 			continue;
3676783259SDavid du Colombier 		if (a[0][0] == '#')
3776783259SDavid du Colombier 			continue;
3876783259SDavid du Colombier 		p = atoll(a[3]);
3976783259SDavid du Colombier 		l = atoll(a[5]);
403b86f2f8SDavid du Colombier 		l += atoll(a[7]);
4176783259SDavid du Colombier 		if (l*p*2 == size){
4276783259SDavid du Colombier 			*pixels = p;
4376783259SDavid du Colombier 			*lines = l;
4476783259SDavid du Colombier 			*bits = 8;
4576783259SDavid du Colombier 			break;
4676783259SDavid du Colombier 		}
4776783259SDavid du Colombier 		if ((l*p*20)/8 == size){
4876783259SDavid du Colombier 			*pixels = p;
4976783259SDavid du Colombier 			*lines = l;
5076783259SDavid du Colombier 			*bits = 10;
5176783259SDavid du Colombier 			break;
5276783259SDavid du Colombier 		}
5376783259SDavid du Colombier 	}
5476783259SDavid du Colombier 	Bterm(bp);
5576783259SDavid du Colombier 	if (s == nil)
5676783259SDavid du Colombier 		return -1;
5776783259SDavid du Colombier 	return 0;
5876783259SDavid du Colombier }
5976783259SDavid du Colombier 
6076783259SDavid du Colombier 
61e288d156SDavid du Colombier static int
clip(int x)62e288d156SDavid du Colombier clip(int x)
63e288d156SDavid du Colombier {
642bef681aSDavid du Colombier 	x >>= (Shift+2); // +2 as we assume all input images are 10 bit
65e288d156SDavid du Colombier 
66e288d156SDavid du Colombier 	if (x > 255)
67e288d156SDavid du Colombier 		return 0xff;
68e288d156SDavid du Colombier 	if (x <= 0)
69e288d156SDavid du Colombier 		return 0;
70e288d156SDavid du Colombier 	return x;
71e288d156SDavid du Colombier }
72e288d156SDavid du Colombier 
73e288d156SDavid du Colombier Rawimage**
Breadyuv(Biobuf * bp,int colourspace)74e288d156SDavid du Colombier Breadyuv(Biobuf *bp, int colourspace)
75e288d156SDavid du Colombier {
76e288d156SDavid du Colombier 	Dir *d;
7776783259SDavid du Colombier 	uvlong sz;
78e288d156SDavid du Colombier 	Rawimage *a, **array;
79e288d156SDavid du Colombier 	ushort * mux, *end, *frm;
8076783259SDavid du Colombier 	uchar *buf, *r, *g, *b;
8176783259SDavid du Colombier 	int y1, y2, cb, cr, c, l, w, base;
8276783259SDavid du Colombier 	int bits, lines, pixels;
832bef681aSDavid du Colombier 	int F1, F2, F3, F4;
84e288d156SDavid du Colombier 
85*d1be6b08SDavid du Colombier 	if ((d = dirfstat(Bfildes(bp))) != nil){
86*d1be6b08SDavid du Colombier 		sz = d->length;
87*d1be6b08SDavid du Colombier 		free(d);
88*d1be6b08SDavid du Colombier 	}
89*d1be6b08SDavid du Colombier 	else{
90*d1be6b08SDavid du Colombier 		fprint(2, "cannot stat input, assuming pixelsx576x10bit\n");
91*d1be6b08SDavid du Colombier 		sz = Pixels * R601pal * 2L + (Pixels * R601pal / 2L);
92*d1be6b08SDavid du Colombier 	}
93*d1be6b08SDavid du Colombier 
94*d1be6b08SDavid du Colombier 	if (looksize("/lib/video.specs", sz, &pixels, &lines, &bits) == -1){
95*d1be6b08SDavid du Colombier 		werrstr("file size not listed in /lib/video.specs");
96*d1be6b08SDavid du Colombier 		return nil;
97*d1be6b08SDavid du Colombier 	}
98*d1be6b08SDavid du Colombier 
9976783259SDavid du Colombier 	buf = nil;
100e288d156SDavid du Colombier 	if (colourspace != CYCbCr) {
101e288d156SDavid du Colombier 		werrstr("ReadYUV: unknown colour space %d", colourspace);
102e288d156SDavid du Colombier 		return nil;
103e288d156SDavid du Colombier 	}
104e288d156SDavid du Colombier 
105e288d156SDavid du Colombier 	if ((a = calloc(sizeof(Rawimage), 1)) == nil)
106e288d156SDavid du Colombier 		sysfatal("no memory");
107e288d156SDavid du Colombier 
108e288d156SDavid du Colombier 	if ((array = calloc(sizeof(Rawimage * ), 2)) == nil)
109e288d156SDavid du Colombier 		sysfatal("no memory");
110e288d156SDavid du Colombier 	array[0] = a;
111e288d156SDavid du Colombier 	array[1] = nil;
112e288d156SDavid du Colombier 
113e288d156SDavid du Colombier 	a->nchans = 3;
114e288d156SDavid du Colombier 	a->chandesc = CRGB;
11576783259SDavid du Colombier 	a->chanlen = pixels * lines;
11676783259SDavid du Colombier 	a->r = Rect(0, 0, pixels, lines);
117e288d156SDavid du Colombier 
11876783259SDavid du Colombier 	if ((frm = malloc(pixels*2*lines*sizeof(ushort))) == nil)
119e288d156SDavid du Colombier 		goto Error;
120e288d156SDavid du Colombier 
121e288d156SDavid du Colombier 	for (c = 0; c  < 3; c++)
12276783259SDavid du Colombier 		if ((a->chans[c] = malloc(pixels*lines)) == nil)
12376783259SDavid du Colombier 			goto Error;
12476783259SDavid du Colombier 
12576783259SDavid du Colombier 	if ((buf = malloc(pixels*2)) == nil)
126e288d156SDavid du Colombier 		goto Error;
127e288d156SDavid du Colombier 
128e288d156SDavid du Colombier 	for (l = 0; l < lines; l++) {
12976783259SDavid du Colombier 		if (Bread(bp, buf, pixels *2) == -1)
130e288d156SDavid du Colombier 			goto Error;
131e288d156SDavid du Colombier 
13276783259SDavid du Colombier 		base = l*pixels*2;
13376783259SDavid du Colombier 		for (w = 0; w < pixels *2; w++)
134e288d156SDavid du Colombier 			frm[base + w] = ((ushort)buf[w]) << 2;
135e288d156SDavid du Colombier 	}
136e288d156SDavid du Colombier 
137e288d156SDavid du Colombier 
138e288d156SDavid du Colombier 	if (bits == 10)
139e288d156SDavid du Colombier 		for (l = 0; l < lines; l++) {
14076783259SDavid du Colombier 			if (Bread(bp, buf, pixels / 2) == -1)
141e288d156SDavid du Colombier 				goto Error;
142e288d156SDavid du Colombier 
143e288d156SDavid du Colombier 
14476783259SDavid du Colombier 			base = l * pixels * 2;
14576783259SDavid du Colombier 			for (w = 0; w < pixels * 2; w++)
1462bef681aSDavid du Colombier 				frm[base + w] |= (buf[w / 4] >> lsbtab[w % 4]) & 3;
147e288d156SDavid du Colombier 		}
148e288d156SDavid du Colombier 
149e288d156SDavid du Colombier 	mux = frm;
15076783259SDavid du Colombier 	end = frm + pixels * lines * 2;
151e288d156SDavid du Colombier 	r = a->chans[0];
152e288d156SDavid du Colombier 	g = a->chans[1];
153e288d156SDavid du Colombier 	b = a->chans[2];
154e288d156SDavid du Colombier 
155*d1be6b08SDavid du Colombier 	if(pixels == Pixels && lines != R601pal){	// 625
1562bef681aSDavid du Colombier 		F1 = floor(1.402 * (1 << Shift));
1572bef681aSDavid du Colombier 		F2 = floor(0.34414 * (1 << Shift));
1582bef681aSDavid du Colombier 		F3 = floor(0.71414 * (1 << Shift));
1592bef681aSDavid du Colombier 		F4 = floor(1.772 * (1 << Shift));
1602bef681aSDavid du Colombier 	}
1612bef681aSDavid du Colombier 	else{				// 525
1622bef681aSDavid du Colombier 		F1 = floor(1.5748 * (1 << Shift));
1632bef681aSDavid du Colombier 		F2 = floor(0.1874 * (1 << Shift));
1642bef681aSDavid du Colombier 		F3 = floor(0.4681 * (1 << Shift));
1652bef681aSDavid du Colombier 		F4 = floor(1.8560 * (1 << Shift));
1662bef681aSDavid du Colombier 	}
1672bef681aSDavid du Colombier 
16876783259SDavid du Colombier 	/*
16976783259SDavid du Colombier 	 * Fixme: fixed colourspace conversion at present
17076783259SDavid du Colombier 	 */
171e288d156SDavid du Colombier 	while (mux < end) {
1722bef681aSDavid du Colombier 
173e288d156SDavid du Colombier 		cb = *mux++ - 512;
1742bef681aSDavid du Colombier 		y1 = (int)*mux++ << Shift;
175e288d156SDavid du Colombier 		cr = *mux++ - 512;
1762bef681aSDavid du Colombier 		y2 = (int)*mux++ << Shift;
177e288d156SDavid du Colombier 
1782bef681aSDavid du Colombier 		*r++ = clip(y1 + F1*cr);
1792bef681aSDavid du Colombier 		*g++ = clip(y1 - F2*cb - F3*cr);
1802bef681aSDavid du Colombier 		*b++ = clip((y1 + F4*cb));
181e288d156SDavid du Colombier 
1822bef681aSDavid du Colombier 		*r++ = clip(y2 + F1*cr);
1832bef681aSDavid du Colombier 		*g++ = clip(y2 - F2*cb - F3*cr);
1842bef681aSDavid du Colombier 		*b++ = clip((y2 + F4*cb));
185e288d156SDavid du Colombier 	}
186e288d156SDavid du Colombier 	free(frm);
18776783259SDavid du Colombier 	free(buf);
188e288d156SDavid du Colombier 	return array;
189e288d156SDavid du Colombier 
190e288d156SDavid du Colombier Error:
191e288d156SDavid du Colombier 	for (c = 0; c < 3; c++)
192e288d156SDavid du Colombier 		free(a->chans[c]);
193e288d156SDavid du Colombier 	free(a->cmap);
194e288d156SDavid du Colombier 	free(array[0]);
195e288d156SDavid du Colombier 	free(array);
196e288d156SDavid du Colombier 	free(frm);
19776783259SDavid du Colombier 	free(buf);
198e288d156SDavid du Colombier 	return nil;
199e288d156SDavid du Colombier }
200e288d156SDavid du Colombier 
201e288d156SDavid du Colombier 
202e288d156SDavid du Colombier Rawimage**
readyuv(int fd,int colorspace)203e288d156SDavid du Colombier readyuv(int fd, int colorspace)
204e288d156SDavid du Colombier {
205e288d156SDavid du Colombier 	Rawimage * *a;
206e288d156SDavid du Colombier 	Biobuf b;
207e288d156SDavid du Colombier 
208e288d156SDavid du Colombier 	if (Binit(&b, fd, OREAD) < 0)
209e288d156SDavid du Colombier 		return nil;
210e288d156SDavid du Colombier 	a = Breadyuv(&b, colorspace);
211e288d156SDavid du Colombier 	Bterm(&b);
212e288d156SDavid du Colombier 	return a;
213e288d156SDavid du Colombier }
214e288d156SDavid du Colombier 
215e288d156SDavid du Colombier 
216