]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/readv210.c
cwfs: back to previous version
[plan9front.git] / sys / src / cmd / jpg / readv210.c
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
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
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**
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**
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 }