/* readyuv.c - read an Abekas A66 style image file. Steve Simon, 2003 */ #include #include #include #include #include #include "imagefile.h" enum { Pixels = 720, R601pal = 576, R601ntsc = 486, Shift = 13 }; static int lsbtab[] = { 6, 4, 2, 0}; static int looksize(char *file, vlong size, int *pixels, int *lines, int *bits) { Biobuf *bp; uvlong l, p; char *s, *a[12]; /* * This may not always work, there could be an alias between file * sizes of different standards stored in 8bits and 10 bits. */ if ((bp = Bopen(file, OREAD)) == nil) return -1; while((s = Brdstr(bp, '\n', 1)) != nil){ if (tokenize(s, a, nelem(a)) < 3) continue; if (a[0][0] == '#') continue; p = atoll(a[3]); l = atoll(a[5]); l += atoll(a[7]); if (l*p*2 == size){ *pixels = p; *lines = l; *bits = 8; break; } if ((l*p*20)/8 == size){ *pixels = p; *lines = l; *bits = 10; break; } } Bterm(bp); if (s == nil) return -1; return 0; } static int clip(int x) { x >>= (Shift+2); // +2 as we assume all input images are 10 bit if (x > 255) return 0xff; if (x <= 0) return 0; return x; } Rawimage** Breadyuv(Biobuf *bp, int colourspace) { Dir *d; uvlong sz; Rawimage *a, **array; ushort * mux, *end, *frm; uchar *buf, *r, *g, *b; int y1, y2, cb, cr, c, l, w, base; int bits, lines, pixels; int F1, F2, F3, F4; if ((d = dirfstat(Bfildes(bp))) != nil){ sz = d->length; free(d); } else{ fprint(2, "cannot stat input, assuming pixelsx576x10bit\n"); sz = Pixels * R601pal * 2L + (Pixels * R601pal / 2L); } if (looksize("/lib/video.specs", sz, &pixels, &lines, &bits) == -1){ werrstr("file size not listed in /lib/video.specs"); return nil; } buf = nil; if (colourspace != CYCbCr) { werrstr("ReadYUV: unknown colour space %d", colourspace); return nil; } if ((a = calloc(sizeof(Rawimage), 1)) == nil) sysfatal("no memory"); if ((array = calloc(sizeof(Rawimage * ), 2)) == nil) sysfatal("no memory"); array[0] = a; array[1] = nil; a->nchans = 3; a->chandesc = CRGB; a->chanlen = pixels * lines; a->r = Rect(0, 0, pixels, lines); if ((frm = malloc(pixels*2*lines*sizeof(ushort))) == nil) goto Error; for (c = 0; c < 3; c++) if ((a->chans[c] = malloc(pixels*lines)) == nil) goto Error; if ((buf = malloc(pixels*2)) == nil) goto Error; for (l = 0; l < lines; l++) { if (Bread(bp, buf, pixels *2) == -1) goto Error; base = l*pixels*2; for (w = 0; w < pixels *2; w++) frm[base + w] = ((ushort)buf[w]) << 2; } if (bits == 10) for (l = 0; l < lines; l++) { if (Bread(bp, buf, pixels / 2) == -1) goto Error; base = l * pixels * 2; for (w = 0; w < pixels * 2; w++) frm[base + w] |= (buf[w / 4] >> lsbtab[w % 4]) & 3; } mux = frm; end = frm + pixels * lines * 2; r = a->chans[0]; g = a->chans[1]; b = a->chans[2]; if(pixels == Pixels && lines != R601pal){ // 625 F1 = floor(1.402 * (1 << Shift)); F2 = floor(0.34414 * (1 << Shift)); F3 = floor(0.71414 * (1 << Shift)); F4 = floor(1.772 * (1 << Shift)); } else{ // 525 F1 = floor(1.5748 * (1 << Shift)); F2 = floor(0.1874 * (1 << Shift)); F3 = floor(0.4681 * (1 << Shift)); F4 = floor(1.8560 * (1 << Shift)); } /* * Fixme: fixed colourspace conversion at present */ while (mux < end) { cb = *mux++ - 512; y1 = (int)*mux++ << Shift; cr = *mux++ - 512; y2 = (int)*mux++ << Shift; *r++ = clip(y1 + F1*cr); *g++ = clip(y1 - F2*cb - F3*cr); *b++ = clip((y1 + F4*cb)); *r++ = clip(y2 + F1*cr); *g++ = clip(y2 - F2*cb - F3*cr); *b++ = clip((y2 + F4*cb)); } free(frm); free(buf); return array; Error: for (c = 0; c < 3; c++) free(a->chans[c]); free(a->cmap); free(array[0]); free(array); free(frm); free(buf); return nil; } Rawimage** readyuv(int fd, int colorspace) { Rawimage * *a; Biobuf b; if (Binit(&b, fd, OREAD) < 0) return nil; a = Breadyuv(&b, colorspace); Bterm(&b); return a; }