xref: /plan9-contrib/sys/src/cmd/jpg/readv210.c (revision d1be6b086622eecc0da76db1fbd64349a5e85293)
1*d1be6b08SDavid du Colombier /*
2*d1be6b08SDavid du Colombier  * readV210.c - read single uncompressed Quicktime YUV image.
3*d1be6b08SDavid du Colombier  * http://developer.apple.com/quicktime/icefloe/dispatch019.html#v210
4*d1be6b08SDavid du Colombier  * Steve Simon, 2009
5*d1be6b08SDavid du Colombier  */
6*d1be6b08SDavid du Colombier #include <u.h>
7*d1be6b08SDavid du Colombier #include <libc.h>
8*d1be6b08SDavid du Colombier #include <bio.h>
9*d1be6b08SDavid du Colombier #include <draw.h>
10*d1be6b08SDavid du Colombier #include <ctype.h>
11*d1be6b08SDavid du Colombier #include "imagefile.h"
12*d1be6b08SDavid du Colombier 
13*d1be6b08SDavid du Colombier enum {
14*d1be6b08SDavid du Colombier 	Pixels = 720,
15*d1be6b08SDavid du Colombier 	R601pal = 576,
16*d1be6b08SDavid du Colombier 	R601ntsc = 486,
17*d1be6b08SDavid du Colombier 	Shift = 13
18*d1be6b08SDavid du Colombier };
19*d1be6b08SDavid du Colombier 
20*d1be6b08SDavid du Colombier static int
looksize(char * file,vlong size,int * pixels,int * lines,int * chunk)21*d1be6b08SDavid du Colombier looksize(char *file, vlong size, int *pixels, int *lines, int *chunk)
22*d1be6b08SDavid du Colombier {
23*d1be6b08SDavid du Colombier 	Biobuf *bp;
24*d1be6b08SDavid du Colombier 	uvlong l, p, c;
25*d1be6b08SDavid du Colombier 	char *s, *a[12];
26*d1be6b08SDavid du Colombier 
27*d1be6b08SDavid du Colombier 	/*
28*d1be6b08SDavid du Colombier 	 * This may not always work, there could be an alias between file
29*d1be6b08SDavid du Colombier 	 * sizes of different standards stored in 8bits and 10 bits.
30*d1be6b08SDavid du Colombier 	 */
31*d1be6b08SDavid du Colombier 	if((bp = Bopen(file, OREAD)) == nil)
32*d1be6b08SDavid du Colombier 		return -1;
33*d1be6b08SDavid du Colombier 	while((s = Brdstr(bp, '\n', 1)) != nil){
34*d1be6b08SDavid du Colombier 		if(tokenize(s, a, nelem(a)) < 3)
35*d1be6b08SDavid du Colombier 			continue;
36*d1be6b08SDavid du Colombier 		if(a[0][0] == '#')
37*d1be6b08SDavid du Colombier 			continue;
38*d1be6b08SDavid du Colombier 		p = atoll(a[3]);
39*d1be6b08SDavid du Colombier 		l = atoll(a[5]);
40*d1be6b08SDavid du Colombier 		l += atoll(a[7]);
41*d1be6b08SDavid du Colombier 		c = 128 * ceil(p/48);
42*d1be6b08SDavid du Colombier 		if(l*c == size){
43*d1be6b08SDavid du Colombier 			*pixels = p;
44*d1be6b08SDavid du Colombier 			*lines = l;
45*d1be6b08SDavid du Colombier 			*chunk = c;
46*d1be6b08SDavid du Colombier 			break;
47*d1be6b08SDavid du Colombier 		}
48*d1be6b08SDavid du Colombier 	}
49*d1be6b08SDavid du Colombier 	Bterm(bp);
50*d1be6b08SDavid du Colombier 	if(s == nil)
51*d1be6b08SDavid du Colombier 		return -1;
52*d1be6b08SDavid du Colombier 	return 0;
53*d1be6b08SDavid du Colombier }
54*d1be6b08SDavid du Colombier 
55*d1be6b08SDavid du Colombier static int
clip(int x)56*d1be6b08SDavid du Colombier clip(int x)
57*d1be6b08SDavid du Colombier {
58*d1be6b08SDavid du Colombier 	x >>= Shift + 2;	/* +2 as we assume all input images are 10 bit */
59*d1be6b08SDavid du Colombier 	if(x > 255)
60*d1be6b08SDavid du Colombier 		return 0xff;
61*d1be6b08SDavid du Colombier 	if(x <= 0)
62*d1be6b08SDavid du Colombier 		return 0;
63*d1be6b08SDavid du Colombier 	return x;
64*d1be6b08SDavid du Colombier }
65*d1be6b08SDavid du Colombier 
66*d1be6b08SDavid du Colombier Rawimage**
BreadV210(Biobuf * bp,int colourspace)67*d1be6b08SDavid du Colombier BreadV210(Biobuf *bp, int colourspace)
68*d1be6b08SDavid du Colombier {
69*d1be6b08SDavid du Colombier 	Dir *d;
70*d1be6b08SDavid du Colombier 	uvlong sz;
71*d1be6b08SDavid du Colombier 	Rawimage *a, **array;
72*d1be6b08SDavid du Colombier 	ushort *mux, *end, *frm, *wr;
73*d1be6b08SDavid du Colombier 	uchar *buf, *r, *g, *b;
74*d1be6b08SDavid du Colombier 	uint i, t;
75*d1be6b08SDavid du Colombier 	int y1, y2, cb, cr, c, l, rd;
76*d1be6b08SDavid du Colombier 	int chunk, lines, pixels;
77*d1be6b08SDavid du Colombier 	int F1, F2, F3, F4;
78*d1be6b08SDavid du Colombier 
79*d1be6b08SDavid du Colombier 	buf = nil;
80*d1be6b08SDavid du Colombier 	if(colourspace != CYCbCr){
81*d1be6b08SDavid du Colombier 		werrstr("BreadV210: unknown colour space %d", colourspace);
82*d1be6b08SDavid du Colombier 		return nil;
83*d1be6b08SDavid du Colombier 	}
84*d1be6b08SDavid 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, &chunk) == -1){
95*d1be6b08SDavid du Colombier 		werrstr("file spec not in /lib/video.specs\n");
96*d1be6b08SDavid du Colombier 		return nil;
97*d1be6b08SDavid du Colombier 	}
98*d1be6b08SDavid du Colombier 
99*d1be6b08SDavid du Colombier 	if((a = calloc(sizeof(Rawimage), 1)) == nil)
100*d1be6b08SDavid du Colombier 		sysfatal("no memory");
101*d1be6b08SDavid du Colombier 
102*d1be6b08SDavid du Colombier 	if((array = calloc(sizeof(Rawimage * ), 2)) == nil)
103*d1be6b08SDavid du Colombier 		sysfatal("no memory");
104*d1be6b08SDavid du Colombier 	array[0] = a;
105*d1be6b08SDavid du Colombier 	array[1] = nil;
106*d1be6b08SDavid du Colombier 
107*d1be6b08SDavid du Colombier 	a->nchans = 3;
108*d1be6b08SDavid du Colombier 	a->chandesc = CRGB;
109*d1be6b08SDavid du Colombier 	a->chanlen = pixels * lines;
110*d1be6b08SDavid du Colombier 	a->r = Rect(0, 0, pixels, lines);
111*d1be6b08SDavid du Colombier 
112*d1be6b08SDavid du Colombier 	if((frm = malloc(pixels*2*lines*sizeof(ushort))) == nil)
113*d1be6b08SDavid du Colombier 		goto Error;
114*d1be6b08SDavid du Colombier 
115*d1be6b08SDavid du Colombier 	for(c = 0; c  < 3; c++)
116*d1be6b08SDavid du Colombier 		if((a->chans[c] = malloc(pixels*lines)) == nil)
117*d1be6b08SDavid du Colombier 			goto Error;
118*d1be6b08SDavid du Colombier 
119*d1be6b08SDavid du Colombier 	if((buf = malloc(chunk)) == nil)
120*d1be6b08SDavid du Colombier 		goto Error;
121*d1be6b08SDavid du Colombier 
122*d1be6b08SDavid du Colombier 	for(l = 0; l < lines; l++){
123*d1be6b08SDavid du Colombier 		if(Bread(bp, buf, chunk) == -1)
124*d1be6b08SDavid du Colombier 			goto Error;
125*d1be6b08SDavid du Colombier 
126*d1be6b08SDavid du Colombier 		rd = 0;
127*d1be6b08SDavid du Colombier 		wr = &frm[l*pixels*2];
128*d1be6b08SDavid du Colombier 		end = &frm[(l+1)*pixels*2];
129*d1be6b08SDavid du Colombier 		while(wr < end){
130*d1be6b08SDavid du Colombier 			t = 0;
131*d1be6b08SDavid du Colombier 			for(i = 0; i < 4; i++)
132*d1be6b08SDavid du Colombier 				t += buf[rd+i] << 8*i;
133*d1be6b08SDavid du Colombier 			*wr++ = t & 0x3ff;
134*d1be6b08SDavid du Colombier 			*wr++ = t>>10 & 0x3ff;
135*d1be6b08SDavid du Colombier 			*wr++ = t>>20 & 0x3ff;
136*d1be6b08SDavid du Colombier 			rd += 4;
137*d1be6b08SDavid du Colombier 		}
138*d1be6b08SDavid du Colombier 	}
139*d1be6b08SDavid du Colombier 
140*d1be6b08SDavid du Colombier 	mux = frm;
141*d1be6b08SDavid du Colombier 	end = frm + pixels * lines * 2;
142*d1be6b08SDavid du Colombier 	r = a->chans[0];
143*d1be6b08SDavid du Colombier 	g = a->chans[1];
144*d1be6b08SDavid du Colombier 	b = a->chans[2];
145*d1be6b08SDavid du Colombier 
146*d1be6b08SDavid du Colombier 	if(pixels == Pixels && lines != R601pal){	// 625
147*d1be6b08SDavid du Colombier 		F1 = floor(1.402 * (1 << Shift));
148*d1be6b08SDavid du Colombier 		F2 = floor(0.34414 * (1 << Shift));
149*d1be6b08SDavid du Colombier 		F3 = floor(0.71414 * (1 << Shift));
150*d1be6b08SDavid du Colombier 		F4 = floor(1.772 * (1 << Shift));
151*d1be6b08SDavid du Colombier 	}
152*d1be6b08SDavid du Colombier 	else{						// 525 and HD
153*d1be6b08SDavid du Colombier 		F1 = floor(1.5748 * (1 << Shift));
154*d1be6b08SDavid du Colombier 		F2 = floor(0.1874 * (1 << Shift));
155*d1be6b08SDavid du Colombier 		F3 = floor(0.4681 * (1 << Shift));
156*d1be6b08SDavid du Colombier 		F4 = floor(1.8560 * (1 << Shift));
157*d1be6b08SDavid du Colombier 	}
158*d1be6b08SDavid du Colombier 
159*d1be6b08SDavid du Colombier 	/*
160*d1be6b08SDavid du Colombier 	 * Fixme: fixed colourspace conversion at present
161*d1be6b08SDavid du Colombier 	 */
162*d1be6b08SDavid du Colombier 	while(mux < end){
163*d1be6b08SDavid du Colombier 
164*d1be6b08SDavid du Colombier 		cb = *mux++ - 512;
165*d1be6b08SDavid du Colombier 		y1 = (int)*mux++ << Shift;
166*d1be6b08SDavid du Colombier 		cr = *mux++ - 512;
167*d1be6b08SDavid du Colombier 		y2 = (int)*mux++ << Shift;
168*d1be6b08SDavid du Colombier 
169*d1be6b08SDavid du Colombier 		*r++ = clip(y1 + F1*cr);
170*d1be6b08SDavid du Colombier 		*g++ = clip(y1 - F2*cb - F3*cr);
171*d1be6b08SDavid du Colombier 		*b++ = clip((y1 + F4*cb));
172*d1be6b08SDavid du Colombier 
173*d1be6b08SDavid du Colombier 		*r++ = clip(y2 + F1*cr);
174*d1be6b08SDavid du Colombier 		*g++ = clip(y2 - F2*cb - F3*cr);
175*d1be6b08SDavid du Colombier 		*b++ = clip((y2 + F4*cb));
176*d1be6b08SDavid du Colombier 	}
177*d1be6b08SDavid du Colombier 	free(frm);
178*d1be6b08SDavid du Colombier 	free(buf);
179*d1be6b08SDavid du Colombier 	return array;
180*d1be6b08SDavid du Colombier 
181*d1be6b08SDavid du Colombier Error:
182*d1be6b08SDavid du Colombier 	for(c = 0; c < 3; c++)
183*d1be6b08SDavid du Colombier 		free(a->chans[c]);
184*d1be6b08SDavid du Colombier 	free(a->cmap);
185*d1be6b08SDavid du Colombier 	free(array[0]);
186*d1be6b08SDavid du Colombier 	free(array);
187*d1be6b08SDavid du Colombier 	free(frm);
188*d1be6b08SDavid du Colombier 	free(buf);
189*d1be6b08SDavid du Colombier 	return nil;
190*d1be6b08SDavid du Colombier }
191*d1be6b08SDavid du Colombier 
192*d1be6b08SDavid du Colombier Rawimage**
readV210(int fd,int colorspace)193*d1be6b08SDavid du Colombier readV210(int fd, int colorspace)
194*d1be6b08SDavid du Colombier {
195*d1be6b08SDavid du Colombier 	Rawimage * *a;
196*d1be6b08SDavid du Colombier 	Biobuf b;
197*d1be6b08SDavid du Colombier 
198*d1be6b08SDavid du Colombier 	if(Binit(&b, fd, OREAD) < 0)
199*d1be6b08SDavid du Colombier 		return nil;
200*d1be6b08SDavid du Colombier 	a = BreadV210(&b, colorspace);
201*d1be6b08SDavid du Colombier 	Bterm(&b);
202*d1be6b08SDavid du Colombier 	return a;
203*d1be6b08SDavid du Colombier }
204