|  | /* 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; | 
|  | } | 
|  |  | 
|  |  |