| /* readyuv.c - read an Abekas A66 style image file. Steve Simon, 2003 */ |
| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| #include <draw.h> |
| #include <ctype.h> |
| #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 { |
| PAL = 576, NTSC = 486 }; |
| |
| |
| static int lsbtab[] = { 6, 4, 2, 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; |
| Rawimage * a, **array; |
| char *e, ebuf[128]; |
| ushort * mux, *end, *frm; |
| uchar buf[720 * 2], *r, *g, *b; |
| int y1, y2, cb, cr, sz, c, l, w, base, bits, lines; |
| |
| frm = 0; |
| 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 720x576x10bit\n"); |
| sz = 720 * PAL * 2L + (720 * PAL / 2L); |
| } |
| |
| switch (sz) { |
| case 720 * PAL * 2: /* 625 x 8bit */ |
| bits = 8; |
| lines = PAL; |
| break; |
| case 720 * NTSC * 2: /* 525 x 8bit */ |
| bits = 8; |
| lines = NTSC; |
| break; |
| case 720 * PAL * 2 + (720 * PAL / 2) : /* 625 x 10bit */ |
| bits = 10; |
| lines = PAL; |
| break; |
| case 720 * NTSC * 2 + (720 * NTSC / 2) : /* 525 x 10bit */ |
| bits = 10; |
| lines = NTSC; |
| break; |
| default: |
| e = "unknown file size"; |
| goto Error; |
| } |
| |
| /* print("bits=%d pixels=%d lines=%d\n", bits, 720, lines); */ |
| /* */ |
| a->nchans = 3; |
| a->chandesc = CRGB; |
| a->chanlen = 720 * lines; |
| a->r = Rect(0, 0, 720, lines); |
| |
| e = "no memory"; |
| if ((frm = malloc(720 * 2 * lines * sizeof(ushort))) == nil) |
| goto Error; |
| |
| for (c = 0; c < 3; c++) |
| if ((a->chans[c] = malloc(720 * lines)) == nil) |
| goto Error; |
| |
| e = "read file"; |
| for (l = 0; l < lines; l++) { |
| if (Bread(bp, buf, 720 * 2) == -1) |
| goto Error; |
| |
| base = l * 720 * 2; |
| for (w = 0; w < 720 * 2; w++) |
| frm[base + w] = ((ushort)buf[w]) << 2; |
| } |
| |
| |
| if (bits == 10) |
| for (l = 0; l < lines; l++) { |
| if (Bread(bp, buf, 720 / 2) == -1) |
| goto Error; |
| |
| |
| base = l * 720 * 2; |
| for (w = 0; w < 720 * 2; w++) |
| frm[base + w] |= buf[w / 4] >> lsbtab[w % 4]; |
| } |
| |
| mux = frm; |
| end = frm + 720 * lines * 2; |
| r = a->chans[0]; |
| g = a->chans[1]; |
| b = a->chans[2]; |
| |
| 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); |
| 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); |
| 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; |
| } |
| |
| |