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