/* readyuv.c - read an Abekas A66 style image file. Steve Simon, 2003 */ #include #include #include #include #include #include "imagefile.h" /* * ITU/CCIR Rec601 states: * * R = y + 1.402 * Cr * B = Y + 1.77305 * Cb * G = Y - 0.72414 * Cr - 0.34414 * Cb * * using 8 bit traffic * Y = 16 + 219 * Y * Cr = 128 + 224 * Cr * Cb = 128 + 224 * Cb * or, if 10bit is used * Y = 64 + 876 * Y * Cr = 512 + 896 * Cr * Cb = 512 + 896 * Cb */ enum { pixels = 720, r601pal = 576, r601ntsc = 486 }; static int lsbtab[] = { 6, 4, 2, 0}; 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]); 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 >>= 18; 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; char *e, ebuf[128]; ushort * mux, *end, *frm; uchar *buf, *r, *g, *b; int y1, y2, cb, cr, c, l, w, base; int bits, lines, pixels; frm = nil; buf = nil; if (colourspace != CYCbCr) { errstr(ebuf, sizeof ebuf); /* throw it away */ 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; 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){ e = "file size not listed in /lib/video.specs"; goto Error; } a->nchans = 3; a->chandesc = CRGB; a->chanlen = pixels * lines; a->r = Rect(0, 0, pixels, lines); e = "no memory"; 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; e = "read file"; 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]; } mux = frm; end = frm + pixels * lines * 2; r = a->chans[0]; g = a->chans[1]; b = a->chans[2]; /* * Fixme: fixed colourspace conversion at present */ while (mux < end) { cb = *mux++ - 512; y1 = (*mux++ - 64) * 76310; cr = *mux++ - 512; y2 = (*mux++ - 64) * 76310; *r++ = clip((104635 * cr) + y1); *g++ = clip((-25690 * cb + -53294 * cr) + y1); *b++ = clip((132278 * cb) + y1); *r++ = clip((104635 * cr) + y2); *g++ = clip((-25690 * cb + -53294 * cr) + y2); *b++ = clip((132278 * cb) + y2); } free(frm); free(buf); return array; Error: errstr(ebuf, sizeof ebuf); // if (ebuf[0] == 0) strcpy(ebuf, e); errstr(ebuf, sizeof ebuf); 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; }