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