code: purgatorio

ref: d3da2e1b89f30f404c3d11053680098f1b7bf677
dir: /appl/lib/quicktime.b/

View raw version
implement QuickTime;

include "sys.m";

sys: Sys;

include "quicktime.m";

init()
{
	sys = load Sys Sys->PATH;
}

open(file: string): (ref QD, string)
{
	fd := sys->open(file, sys->OREAD);
	if(fd == nil)
		return (nil, "open failed");

	r := ref QD;
	r.fd = fd;
	r.buf = array[DEFBUF] of byte;

	(hdr, l) := r.atomhdr();
	if(hdr != "mdat")
		return (nil, "not a QuickTime movie file");

	#
	# We are expecting a unified file with .data then .rsrc
	#
	r.skipatom(l);

	return (r, nil);
}

QD.atomhdr(r: self ref QD): (string, int)
{
	b := array[8] of byte;

	if(r.readn(b, 8) != 8)
		return (nil, -1);

for(i := 0; i < 8; i++)
sys->print("%.2ux ", int b[i]);
sys->print(" %s %d\n", string b[4:8], bedword(b, 0));

	return (string b[4:8], bedword(b, 0));
}

QD.skipatom(r: self ref QD, l: int): int
{
	return r.skip(l - AtomHDR);
}

QD.mvhd(q: self ref QD, l: int): string
{
	l -= AtomHDR;
	if(l != MvhdrSIZE)
		return "mvhd atom funny size";

	b := array[l] of byte;
	if(q.readn(b, l) != l)
		return "short read in mvhd";

	mvhdr := ref Mvhdr;

	mvhdr.version = bedword(b, 0);
	mvhdr.create = bedword(b, 4);
	mvhdr.modtime = bedword(b, 8);
	mvhdr.timescale = bedword(b, 12);
	mvhdr.duration = bedword(b, 16);
	mvhdr.rate = bedword(b, 20);
	mvhdr.vol = beword(b, 24);
	mvhdr.r1 = bedword(b, 26);
	mvhdr.r2 = bedword(b, 30);

	mvhdr.matrix = array[9] of int;
	for(i :=0; i<9; i++)
		mvhdr.matrix[i] = bedword(b, 34+i*4);

	mvhdr.r3 = beword(b, 70);
	mvhdr.r4 = bedword(b, 72);
	mvhdr.pvtime = bedword(b, 76);
	mvhdr.posttime = bedword(b, 80);
	mvhdr.seltime = bedword(b, 84);
	mvhdr.seldurat = bedword(b, 88);
	mvhdr.curtime = bedword(b, 92);
	mvhdr.nxttkid = bedword(b, 96);

	q.mvhdr = mvhdr;
	return nil;
}

QD.trak(q: self ref QD, l: int): string
{
	(tk, tkl) := q.atomhdr();
	if(tk != "tkhd")
		return "missing track header atom";

	l -= tkl;
	tkl -= AtomHDR;
	b := array[tkl] of byte;
	if(q.readn(b, tkl) != tkl)
		return "short read in tkhd";

	tkhdr := ref Tkhdr;

	tkhdr.version =	bedword(b, 0);
	tkhdr.creation = bedword(b, 4);
	tkhdr.modtime =	bedword(b, 8);
	tkhdr.trackid =	bedword(b, 12);
	tkhdr.timescale = bedword(b, 16);
	tkhdr.duration = bedword(b, 20);
	tkhdr.timeoff = bedword(b, 24);
	tkhdr.priority = bedword(b, 28);
	tkhdr.layer = beword(b, 32);
	tkhdr.altgrp = beword(b, 34);
	tkhdr.volume = beword(b, 36);

	tkhdr.matrix = array[9] of int;
	for(i := 0; i < 9; i++)
		tkhdr.matrix[i] = bedword(b, 38+i*4);

	tkhdr.width = bedword(b, 74);
	tkhdr.height = bedword(b, 78);

	(md, mdl) := q.atomhdr();
	if(md != "mdia")
		return "missing media atom";

	while(mdl != AtomHDR) {
		(atom, atoml) := q.atomhdr();
sys->print("\t%s %d\n", atom, atoml);
		q.skipatom(atoml);

		mdl -= atoml;
	}

	return nil;
}

QD.readn(r: self ref QD, b: array of byte, l: int): int
{
	if(r.nbyte < l) {
		c := 0;
		if(r.nbyte != 0) {
			b[0:] = r.buf[r.ptr:];
			l -= r.nbyte;
			c += r.nbyte;
			b = b[r.nbyte:];
		}
		bsize := len r.buf;
		while(l != 0) {
			r.nbyte = sys->read(r.fd, r.buf, bsize);
			if(r.nbyte <= 0) {
				r.nbyte = 0;
				return -1;
			}
			n := l;
			if(n > bsize)
				n = bsize;

			r.ptr = 0;
			b[0:] = r.buf[0:n];
			b = b[n:];
			r.nbyte -= n;
			r.ptr += n;
			l -= n;
			c += n;
		}
		return c;
	}
	b[0:] = r.buf[r.ptr:r.ptr+l];
	r.nbyte -= l;
	r.ptr += l;
	return l;
}

QD.skip(r: self ref QD, size: int): int
{
	if(r.nbyte != 0) {
		n := size;
		if(n > r.nbyte)
			n = r.nbyte;
		r.ptr += n;
		r.nbyte -= n;
		size -= n;
		if(size == 0)
			return 0;
	}
	return int sys->seek(r.fd, big size, sys->SEEKRELA);
}

beword(b: array of byte, o: int): int
{
	return 	(int b[o] << 8) | int b[o+1];
}

bedword(b: array of byte, o: int): int
{
	return	(int b[o] << 24) |
		(int b[o+1] << 16) |
		(int b[o+2] << 8) |
		int b[o+3];
}