xref: /plan9/sys/src/cmd/jpg/readyuv.c (revision d1be6b086622eecc0da76db1fbd64349a5e85293)
1 /* readyuv.c - read an Abekas A66 style image file.   Steve Simon, 2003 */
2 #include <u.h>
3 #include <libc.h>
4 #include <bio.h>
5 #include <draw.h>
6 #include <ctype.h>
7 #include "imagefile.h"
8 
9 
10 enum {
11 	Pixels = 720,
12 	R601pal = 576,
13 	R601ntsc = 486,
14 	Shift = 13
15 };
16 
17 
18 static int lsbtab[] = { 6, 4, 2, 0};
19 
20 static int
looksize(char * file,vlong size,int * pixels,int * lines,int * bits)21 looksize(char *file, vlong size, int *pixels, int *lines, int *bits)
22 {
23 	Biobuf *bp;
24 	uvlong l, p;
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 		if (l*p*2 == size){
42 			*pixels = p;
43 			*lines = l;
44 			*bits = 8;
45 			break;
46 		}
47 		if ((l*p*20)/8 == size){
48 			*pixels = p;
49 			*lines = l;
50 			*bits = 10;
51 			break;
52 		}
53 	}
54 	Bterm(bp);
55 	if (s == nil)
56 		return -1;
57 	return 0;
58 }
59 
60 
61 static int
clip(int x)62 clip(int x)
63 {
64 	x >>= (Shift+2); // +2 as we assume all input images are 10 bit
65 
66 	if (x > 255)
67 		return 0xff;
68 	if (x <= 0)
69 		return 0;
70 	return x;
71 }
72 
73 Rawimage**
Breadyuv(Biobuf * bp,int colourspace)74 Breadyuv(Biobuf *bp, int colourspace)
75 {
76 	Dir *d;
77 	uvlong sz;
78 	Rawimage *a, **array;
79 	ushort * mux, *end, *frm;
80 	uchar *buf, *r, *g, *b;
81 	int y1, y2, cb, cr, c, l, w, base;
82 	int bits, lines, pixels;
83 	int F1, F2, F3, F4;
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, &bits) == -1){
95 		werrstr("file size not listed in /lib/video.specs");
96 		return nil;
97 	}
98 
99 	buf = nil;
100 	if (colourspace != CYCbCr) {
101 		werrstr("ReadYUV: unknown colour space %d", colourspace);
102 		return nil;
103 	}
104 
105 	if ((a = calloc(sizeof(Rawimage), 1)) == nil)
106 		sysfatal("no memory");
107 
108 	if ((array = calloc(sizeof(Rawimage * ), 2)) == nil)
109 		sysfatal("no memory");
110 	array[0] = a;
111 	array[1] = nil;
112 
113 	a->nchans = 3;
114 	a->chandesc = CRGB;
115 	a->chanlen = pixels * lines;
116 	a->r = Rect(0, 0, pixels, lines);
117 
118 	if ((frm = malloc(pixels*2*lines*sizeof(ushort))) == nil)
119 		goto Error;
120 
121 	for (c = 0; c  < 3; c++)
122 		if ((a->chans[c] = malloc(pixels*lines)) == nil)
123 			goto Error;
124 
125 	if ((buf = malloc(pixels*2)) == nil)
126 		goto Error;
127 
128 	for (l = 0; l < lines; l++) {
129 		if (Bread(bp, buf, pixels *2) == -1)
130 			goto Error;
131 
132 		base = l*pixels*2;
133 		for (w = 0; w < pixels *2; w++)
134 			frm[base + w] = ((ushort)buf[w]) << 2;
135 	}
136 
137 
138 	if (bits == 10)
139 		for (l = 0; l < lines; l++) {
140 			if (Bread(bp, buf, pixels / 2) == -1)
141 				goto Error;
142 
143 
144 			base = l * pixels * 2;
145 			for (w = 0; w < pixels * 2; w++)
146 				frm[base + w] |= (buf[w / 4] >> lsbtab[w % 4]) & 3;
147 		}
148 
149 	mux = frm;
150 	end = frm + pixels * lines * 2;
151 	r = a->chans[0];
152 	g = a->chans[1];
153 	b = a->chans[2];
154 
155 	if(pixels == Pixels && lines != R601pal){	// 625
156 		F1 = floor(1.402 * (1 << Shift));
157 		F2 = floor(0.34414 * (1 << Shift));
158 		F3 = floor(0.71414 * (1 << Shift));
159 		F4 = floor(1.772 * (1 << Shift));
160 	}
161 	else{				// 525
162 		F1 = floor(1.5748 * (1 << Shift));
163 		F2 = floor(0.1874 * (1 << Shift));
164 		F3 = floor(0.4681 * (1 << Shift));
165 		F4 = floor(1.8560 * (1 << Shift));
166 	}
167 
168 	/*
169 	 * Fixme: fixed colourspace conversion at present
170 	 */
171 	while (mux < end) {
172 
173 		cb = *mux++ - 512;
174 		y1 = (int)*mux++ << Shift;
175 		cr = *mux++ - 512;
176 		y2 = (int)*mux++ << Shift;
177 
178 		*r++ = clip(y1 + F1*cr);
179 		*g++ = clip(y1 - F2*cb - F3*cr);
180 		*b++ = clip((y1 + F4*cb));
181 
182 		*r++ = clip(y2 + F1*cr);
183 		*g++ = clip(y2 - F2*cb - F3*cr);
184 		*b++ = clip((y2 + F4*cb));
185 	}
186 	free(frm);
187 	free(buf);
188 	return array;
189 
190 Error:
191 	for (c = 0; c < 3; c++)
192 		free(a->chans[c]);
193 	free(a->cmap);
194 	free(array[0]);
195 	free(array);
196 	free(frm);
197 	free(buf);
198 	return nil;
199 }
200 
201 
202 Rawimage**
readyuv(int fd,int colorspace)203 readyuv(int fd, int colorspace)
204 {
205 	Rawimage * *a;
206 	Biobuf b;
207 
208 	if (Binit(&b, fd, OREAD) < 0)
209 		return nil;
210 	a = Breadyuv(&b, colorspace);
211 	Bterm(&b);
212 	return a;
213 }
214 
215 
216