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