/*
* readV210.c - read single uncompressed Quicktime YUV image.
* http://developer.apple.com/quicktime/icefloe/dispatch019.html#v210
* Steve Simon, 2009
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <ctype.h>
#include "imagefile.h"
enum {
Pixels = 720,
R601pal = 576,
R601ntsc = 486,
Shift = 13
};
static int
looksize(char *file, vlong size, int *pixels, int *lines, int *chunk)
{
Biobuf *bp;
uvlong l, p, c;
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]);
c = 128 * ceil(p/48);
if(l*c == size){
*pixels = p;
*lines = l;
*chunk = c;
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**
BreadV210(Biobuf *bp, int colourspace)
{
Dir *d;
uvlong sz;
Rawimage *a, **array;
ushort *mux, *end, *frm, *wr;
uchar *buf, *r, *g, *b;
uint i, t;
int y1, y2, cb, cr, c, l, rd;
int chunk, lines, pixels;
int F1, F2, F3, F4;
buf = nil;
if(colourspace != CYCbCr){
werrstr("BreadV210: unknown colour space %d", colourspace);
return 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, &chunk) == -1){
werrstr("file spec not in /lib/video.specs\n");
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(chunk)) == nil)
goto Error;
for(l = 0; l < lines; l++){
if(Bread(bp, buf, chunk) == -1)
goto Error;
rd = 0;
wr = &frm[l*pixels*2];
end = &frm[(l+1)*pixels*2];
while(wr < end){
t = 0;
for(i = 0; i < 4; i++)
t += buf[rd+i] << 8*i;
*wr++ = t & 0x3ff;
*wr++ = t>>10 & 0x3ff;
*wr++ = t>>20 & 0x3ff;
rd += 4;
}
}
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 and HD
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**
readV210(int fd, int colorspace)
{
Rawimage * *a;
Biobuf b;
if(Binit(&b, fd, OREAD) < 0)
return nil;
a = BreadV210(&b, colorspace);
Bterm(&b);
return a;
}
|