191 lines
3.4 KiB
C
191 lines
3.4 KiB
C
/* 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;
|
|
}
|
|
|
|
|