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