[NUT-devel] [NUT] (ods15): r117 - in /trunk/nututils: Makefile demux_avi.c demux_ogg.c framer_mpeg4.c framer_vorbis.c nutmerge.c nutmerge.h

syncmail at mplayerhq.hu syncmail at mplayerhq.hu
Fri Mar 31 22:05:04 CEST 2006


Author: ods15
Date: Fri Mar 31 22:05:02 2006
New Revision: 117

Log:
huge nutmerge framer api change. I expect much cola for this.
There are still improovements to be made, like e_null of demux_avi

Added:
    trunk/nututils/framer_mpeg4.c
    trunk/nututils/framer_vorbis.c
Modified:
    trunk/nututils/Makefile
    trunk/nututils/demux_avi.c
    trunk/nututils/demux_ogg.c
    trunk/nututils/nutmerge.c
    trunk/nututils/nutmerge.h

Modified: trunk/nututils/Makefile
==============================================================================
--- trunk/nututils/Makefile (original)
+++ trunk/nututils/Makefile Fri Mar 31 22:05:02 2006
@@ -2,7 +2,7 @@
 
 CFLAGS += -I../libnut -lm
 
-all: riffreader avireader oggreader nutmerge nutindex
+all: riffreader avireader nutmerge nutindex # oggreader
 
 riffreader: demux_avi.c
 	${CC} ${CFLAGS} -DRIFF_PROG $^ -o $@
@@ -10,7 +10,7 @@
 	${CC} ${CFLAGS} -DAVI_PROG $^ -o $@
 oggreader: demux_ogg.c
 	${CC} ${CFLAGS} -DOGG_PROG $^ -o $@
-nutmerge: demux_ogg.c demux_nut.c demux_avi.c nutmerge.c ../libnut/libnut.so
+nutmerge: demux_ogg.c demux_avi.c framer_vorbis.c framer_mpeg4.c nutmerge.c ../libnut/libnut.so # demux_nut.c
 	${CC} ${CFLAGS} $^ -o $@
 nutindex: nutindex.c
 	${CC} ${CFLAGS} $^ -o $@

Modified: trunk/nututils/demux_avi.c
==============================================================================
--- trunk/nututils/demux_avi.c (original)
+++ trunk/nututils/demux_avi.c Fri Mar 31 22:05:02 2006
@@ -1,6 +1,3 @@
-#define N 0
-
-
 #include "nutmerge.h"
 #include <string.h>
 
@@ -112,14 +109,14 @@
 } AVIStreamContext;
 
 struct demuxer_priv_s {
+	FILE * in;
 	full_riff_tree_t * riff;
+	stream_t * s;
 	MainAVIHeader * avih;
 	AVIStreamContext * stream; // this is an array, free this
 	AVIINDEXENTRY * index; // this is an array and data
 	int packets;
-	FILE * in;
 	int cur;
-	uint8_t * buf;
 };
 
 static int mk_riff_tree(FILE * in, riff_tree_t * tree) {
@@ -329,89 +326,58 @@
 	return 0;
 }
 
-static void * init(FILE * in) {
-	demuxer_priv_t * avi = malloc(sizeof(demuxer_priv_t));
-	avi->avih = NULL;
-	avi->stream = NULL;
-	avi->index = NULL;
-	avi->in = in;
-	avi->riff = init_riff();
-	avi->cur = 0;
-	avi->buf = NULL;
-	return avi;
-}
-
-static void uninit(demuxer_priv_t * avi) {
-	if (!avi) return;
-
-	uninit_riff(avi->riff);
-	free(avi->stream);
-	free(avi->buf);
-	free(avi);
-}
-
-static int read_headers(demuxer_priv_t * avi, nut_stream_header_t ** nut_streams) {
-	nut_stream_header_t * s;
+static int read_headers(demuxer_priv_t * avi, stream_t ** streams) {
 	int i;
 	if ((i = avi_read_headers(avi))) return i;
-	*nut_streams = s = malloc(sizeof(nut_stream_header_t) * (avi->avih->dwStreams + 1 + N));
+	*streams = avi->s = malloc(sizeof(stream_t) * (avi->avih->dwStreams + 1));
 	for (i = 0; i < avi->avih->dwStreams; i++) {
-		s[i].type = avi->stream[i].type;
-		s[i].time_base.den = avi->stream[i].strh->dwRate;
-		s[i].time_base.nom = avi->stream[i].strh->dwScale;
-		s[i].fixed_fps = 1;
-		s[i].decode_delay = !i; // FIXME
-		s[i].codec_specific_len = avi->stream[i].extra_len;
-		s[i].codec_specific = avi->stream[i].extra;
+		extern demuxer_t avi_demuxer;
+		avi->s[i].stream_id = i;
+		avi->s[i].demuxer = avi_demuxer;
+		avi->s[i].demuxer.priv = avi;
+		avi->s[i].packets_alloc = avi->s[i].npackets = 0;
+		avi->s[i].packets = NULL;
+		if (i == 0) avi->s[i].codec_id = e_mpeg4;
+		else avi->s[i].codec_id = e_null;
+
+		avi->s[i].sh.type = avi->stream[i].type;
+		avi->s[i].sh.time_base.den = avi->stream[i].strh->dwRate;
+		avi->s[i].sh.time_base.nom = avi->stream[i].strh->dwScale;
+		avi->s[i].sh.fixed_fps = 1;
+		avi->s[i].sh.decode_delay = !i; // FIXME
+		avi->s[i].sh.codec_specific_len = avi->stream[i].extra_len;
+		avi->s[i].sh.codec_specific = avi->stream[i].extra;
 		if (avi->stream[i].type == 0) { // video
-			s[i].fourcc_len = 4;
-			s[i].fourcc = avi->stream[i].video->biCompression;
-
-			s[i].width = avi->stream[i].video->biWidth;
-			s[i].height = avi->stream[i].video->biHeight;
-			s[i].sample_width = 0;
-			s[i].sample_height = 0;
-			s[i].colorspace_type = 0;
+			avi->s[i].sh.fourcc_len = 4;
+			avi->s[i].sh.fourcc = avi->stream[i].video->biCompression;
+
+			avi->s[i].sh.width = avi->stream[i].video->biWidth;
+			avi->s[i].sh.height = avi->stream[i].video->biHeight;
+			avi->s[i].sh.sample_width = 0;
+			avi->s[i].sh.sample_height = 0;
+			avi->s[i].sh.colorspace_type = 0;
 		} else { // audio
-			s[i].fourcc_len = 2;
-			s[i].fourcc = avi->stream[i].audio->wFormatTag;
-
-			s[i].samplerate_nom = 1;
-			s[i].samplerate_denom = avi->stream[i].audio->nSamplesPerSec;
-			s[i].channel_count = avi->stream[i].audio->nChannels;
-		}
-	}
-	while (i < N + 2) { s[i] = s[0]; s[i++].decode_delay = 0; }
-	s[i].type = -1;
+			avi->s[i].sh.fourcc_len = 2;
+			avi->s[i].sh.fourcc = avi->stream[i].audio->wFormatTag;
+
+			avi->s[i].sh.samplerate_nom = 1;
+			avi->s[i].sh.samplerate_denom = avi->stream[i].audio->nSamplesPerSec;
+			avi->s[i].sh.channel_count = avi->stream[i].audio->nChannels;
+		}
+	}
+	avi->s[i].stream_id = -1;
 	return 0;
 }
 
-static int find_frame_type(FILE * in, int len, int * type) {
-	uint8_t buf[len];
-	int i;
-	if (!len) { *type = 1; return 0; }
-	FREAD(in, len, buf);
-	fseek(in, -len, SEEK_CUR);
-	for (i = 0; i < len; i++) {
-		if (buf[i] != 0xB6) continue;
-
-		if (i == len - 1) return 11;
-		*type = buf[i+1] >> 6;
-		return 0;
-	}
-	return 13;
-}
-
-static int get_packet(demuxer_priv_t * avi, nut_packet_t * p, uint8_t ** buf) {
+static int fill_buffer(demuxer_priv_t * avi) {
 	char fourcc[4];
-	int err = 0;
-	int s; // stream
 	uint32_t len;
+	packet_t p;
 	if (ftell(avi->in) & 1) fgetc(avi->in);
 
 	if (avi->cur >= avi->packets) return -1;
 
-	if ((avi->stream[0].last_pts % 1000) < N && avi->buf) {
+	/*if ((avi->stream[0].last_pts % 1000) < N && avi->buf) {
 		p->next_pts = 0;
 		p->len = 5;
 		p->flags = NUT_FLAG_KEY;
@@ -422,79 +388,100 @@
 		free(avi->buf);
 		avi->buf = NULL;
 		return 0;
-	}
+	}*/
 
 	FREAD(avi->in, 4, fourcc);
 	FREAD(avi->in, 4, &len);
 	FIXENDIAN32(len);
-	p->next_pts = 0;
-	p->len = len;
-	p->flags = (avi->index[avi->cur++].dwFlags & 0x10) ? NUT_FLAG_KEY : 0;
-	p->stream = s = (fourcc[0] - '0') * 10 + (fourcc[1] - '0');
-	if (s == 0) { // 1 frame of video
-		int type;
-		p->pts = avi->stream[0].last_pts++; // FIXME
-		if ((err = find_frame_type(avi->in, len, &type))) return err;
-		if (stats) fprintf(stats, "%c", type==0?'I':type==1?'P':type==2?'B':'S');
-		switch (type) {
-			case 0: // I
-				if (!(p->flags & NUT_FLAG_KEY)) printf("Error detected stream %d frame %d\n", s, (int)p->pts);
-				p->flags |= NUT_FLAG_KEY;
-				break;
-			case 3: // S
-				printf("S-Frame %d\n", (int)ftell(avi->in));
-				//err = 12;
-				//goto err_out;
-				// FALL THROUGH!
-			case 1: { // P
-				off_t where = ftell(avi->in);
-				while (fourcc[0] != 'i') {
-					len += len & 1; // round up
-					fseek(avi->in, len, SEEK_CUR);
-					FREAD(avi->in, 4, fourcc);
-					FREAD(avi->in, 4, &len);
-					FIXENDIAN32(len);
-					if ((fourcc[0] - '0') * 10 + (fourcc[1] - '0') != 0) continue;
-					if ((err = find_frame_type(avi->in, len, &type))) goto err_out;
-					if (type != 2) break;
-					p->pts++;
-				}
-				fseek(avi->in, where, SEEK_SET);
-				break;
-			}
-			case 2: // B
-				p->pts--;
-				break;
-		}
-	} else if (s < avi->avih->dwStreams) { // 0.5 secs of audio or a single packet
-		int samplesize = avi->stream[s].strh->dwSampleSize;
-
-		p->pts = avi->stream[s].last_pts;
-		if (samplesize) avi->stream[s].last_pts += p->len / samplesize;
-		else avi->stream[s].last_pts++;
-
-		if (!(p->flags & NUT_FLAG_KEY)) printf("Error detected stream %d frame %d\n", s, (int)p->pts);
-		p->flags |= NUT_FLAG_KEY;
-	} else {
-		printf("%d %4.4s\n", avi->cur, fourcc);
-		err = 10;
-		goto err_out;
-	}
-	*buf = avi->buf = realloc(avi->buf, p->len);
-	FREAD(avi->in, p->len, *buf);
-err_out:
-	return err;
-}
-
-struct demuxer_t avi_demuxer = {
+	p.p.len = len;
+	p.p.flags = (avi->index[avi->cur++].dwFlags & 0x10) ? NUT_FLAG_KEY : 0;
+	p.p.stream = (fourcc[0] - '0') * 10 + (fourcc[1] - '0');
+	p.p.next_pts = p.p.pts = 0;
+	if ((unsigned)(fourcc[0] - '0') > 9 || (unsigned)(fourcc[1] - '0') > 9 || p.p.stream >= avi->avih->dwStreams) {
+		fprintf(stderr, "%d %4.4s\n", avi->cur, fourcc);
+		return 3;
+	}
+	if (p.p.stream == 1) {
+		// 0.5 secs of audio or a single packet
+		int samplesize = avi->stream[p.p.stream].strh->dwSampleSize;
+
+		p.p.pts = avi->stream[p.p.stream].last_pts;
+		if (samplesize) avi->stream[p.p.stream].last_pts += p.p.len / samplesize;
+		else avi->stream[p.p.stream].last_pts++;
+
+		if (!(p.p.flags & NUT_FLAG_KEY)) printf("Error detected stream %d frame %d\n", p.p.stream, (int)p.p.pts);
+		p.p.flags |= NUT_FLAG_KEY;
+	}
+	p.buf = malloc(p.p.len);
+	FREAD(avi->in, p.p.len, p.buf);
+	push_packet(&avi->s[p.p.stream], &p);
+	return 0;
+}
+
+static demuxer_priv_t * init(FILE * in) {
+	demuxer_priv_t * avi = malloc(sizeof(demuxer_priv_t));
+	avi->avih = NULL;
+	avi->stream = NULL;
+	avi->index = NULL;
+	avi->in = in;
+	avi->riff = init_riff();
+	avi->cur = 0;
+	avi->s = NULL;
+	return avi;
+}
+
+static void uninit(demuxer_priv_t * avi) {
+	uninit_riff(avi->riff);
+	free(avi->stream);
+	free_streams(avi->s);
+	free(avi->s);
+	free(avi);
+}
+
+demuxer_t avi_demuxer = {
 	"avi",
 	init,
 	read_headers,
-	get_packet,
+	fill_buffer,
 	uninit
 };
 
+struct framer_priv_s { stream_t * stream; };
+
+static int n_get_packet(framer_priv_t * mc, packet_t * p) {
+	return get_stream_packet(mc->stream, p);
+}
+
+static int n_setup_headers(framer_priv_t * mc, nut_stream_header_t * s) {
+	*s = mc->stream->sh;
+	return 0; // nothing to do
+}
+
+static framer_priv_t * n_init(stream_t * s) {
+	framer_priv_t * mc = malloc(sizeof(framer_priv_t));
+	mc->stream = s;
+	return mc;
+}
+
+static void n_uninit(framer_priv_t * mc) {
+	free(mc);
+}
+
+framer_t null_framer = {
+	e_null,
+	n_init,
+	n_setup_headers,
+	n_get_packet,
+	n_uninit,
+	NULL
+};
+
+
 #ifdef RIFF_PROG
+void ready_stream(stream_t * streams){}
+void push_packet(stream_t * stream, packet_t * p){}
+void free_streams(stream_t * streams){}
+int get_stream_packet(stream_t * stream, packet_t * p){return 0;}
 void print_riff_tree(riff_tree_t * tree, int indent) {
 	char ind[indent + 1];
 	int i;
@@ -535,6 +522,10 @@
 #endif
 
 #ifdef AVI_PROG
+void ready_stream(stream_t * streams){}
+void push_packet(stream_t * stream, packet_t * p){}
+void free_streams(stream_t * streams){}
+int get_stream_packet(stream_t * stream, packet_t * p){return 0;}
 FILE * stats = NULL;
 int main(int argc, char * argv []) {
 	FILE * in;

Modified: trunk/nututils/demux_ogg.c
==============================================================================
--- trunk/nututils/demux_ogg.c (original)
+++ trunk/nututils/demux_ogg.c Fri Mar 31 22:05:02 2006
@@ -5,583 +5,152 @@
 #include "nutmerge.h"
 #define FREAD(file, len, var) do { if (fread((var), 1, (len), (file)) != (len)) return -1; }while(0)
 
-#define PAGE_ALLOC 65000
-
 typedef struct ogg_stream_s ogg_stream_t;
 
-typedef struct ogg_codec_s {
-	char * magic;
-	int magic_len;
-	char * fourcc;
-	int fourcc_len;
-	int type;
-	int (*read_headers)(demuxer_priv_t * ogg, int stream);
-	int (*get_pts)(ogg_stream_t * os);
-	int (*is_key)(ogg_stream_t * os);
-	void (*uninit)(ogg_stream_t * os);
-} ogg_codec_t;
-
 struct ogg_stream_s {
-	int serial; // serial of stream
-	uint8_t * buf; // buffer, always re-alloced
-	int buf_pos; // position to read from
-	int buf_end; // total data in buf
-	int sizes[256]; // sizes of segments in buf
-	int totpos; // amount of segments
-	int pos; // pos in sizes
-
-	ogg_codec_t * oc;
-	void * oc_priv;
-
-	// oc->read_headers must fill all of these.
-	int time_base_denom;
-	int time_base_nom;
-	int fixed_fps;
-	int decode_delay;
-	int codec_specific_len;
-	uint8_t * codec_specific;
-	int width;
-	int height;
-	int sample_width;
-	int sample_height;
-	int colorspace_type;
-	int samplerate_nom;
-	int samplerate_denom;
-	int channel_count;
+	int serial;
+	int leftover; // buffer for "next page" nonsense. always re-alloced
+	uint8_t * leftover_buf;
 };
 
 struct demuxer_priv_s {
 	FILE * in;
-	ogg_stream_t * streams;
+	ogg_stream_t * os;
+	stream_t * s;
 	int nstreams;
-	int last_stream;
+	int stream_count; // when nutmerge_streams was handed to api...
 };
 
-typedef struct __attribute__((packed)) ogg_header_s {
-	char magic[4];
-	uint8_t version;
-	uint8_t type;
-	uint64_t gp; // discarded
-	uint32_t serial;
-	uint32_t page; // discarded
-	uint32_t crc; // discarded
-	uint8_t segments;
-} ogg_header_t;
-
-static int vorbis_read_headers(demuxer_priv_t * ogg, int stream);
-static int vorbis_get_pts(ogg_stream_t * os);
-static void vorbis_uninit(ogg_stream_t * os);
-
-static ogg_codec_t vorbis_ogg_codec = {
-	"\001vorbis", 7, // magic
-	"vrbs", 4, // fourcc
-	1, // type
-	vorbis_read_headers,
-	vorbis_get_pts,
-	NULL, // is_key
-	vorbis_uninit
-};
-
-static ogg_codec_t * ogg_codecs[] = {
-	&vorbis_ogg_codec,
-	NULL
+static struct { enum nutmerge_codecs id; uint8_t * magic; int magic_len; } codecs[] = {
+       { e_vorbis, "\001vorbis", 7 },
+       { 0, NULL, 0 }
 };
 
 static int find_stream(demuxer_priv_t * ogg, int serial) {
-	ogg_stream_t * os;
+	extern demuxer_t ogg_demuxer;
 	int i;
 	for (i = 0; i < ogg->nstreams; i++) {
-		if (ogg->streams[i].serial == serial) return i;
+		if (ogg->os[i].serial == serial) return i;
 	}
-	ogg->streams = realloc(ogg->streams, sizeof(ogg_stream_t) * ++ogg->nstreams);
-	os = &ogg->streams[i];
-	os->serial = serial;
-	os->buf = malloc(PAGE_ALLOC);
-	os->buf_pos = 0;
-	os->buf_end = 0;
-	os->pos = 0;
-	os->totpos = 0;
-	os->oc = NULL;
-	os->oc_priv = NULL;
+	ogg->os = realloc(ogg->os, sizeof(ogg_stream_t) * ++ogg->nstreams);
+	ogg->s = realloc(ogg->s, sizeof(stream_t) * (ogg->nstreams+1));
+	ogg->os[i].serial = serial;
+	ogg->os[i].leftover_buf = NULL;
+	ogg->os[i].leftover = 0;
+	ogg->s[i].stream_id = i;
+	ogg->s[i].demuxer = ogg_demuxer;
+	ogg->s[i].demuxer.priv = ogg;
+	ogg->s[i].packets_alloc = ogg->s[i].npackets = 0;
+	ogg->s[i].packets = NULL;
+	ogg->s[i+1].stream_id = -1;
 	return i;
 }
 
 static int read_page(demuxer_priv_t * ogg, int * stream) {
-	ogg_header_t tmp;
 	ogg_stream_t * os;
-	uint8_t seg[256];
-	int i, tot = 0, totseg;
+	int i, serial, segments;
+	char tmp_header[27];
+	uint8_t sizes[256];
+	int len, tot = 0;
 
-	FREAD(ogg->in, sizeof(ogg_header_t), &tmp);
-	if (strncmp(tmp.magic, "OggS", 4)) return 2;
-	if (tmp.version != 0) return 3;
-	// FIXENDIAN32(tmp.serial); // endianess of serial doesn't matter, it's still unique
+	FREAD(ogg->in, 27, tmp_header);
+	if (strncmp(tmp_header, "OggS", 5)) return 2; // including version
 
-	*stream = find_stream(ogg, tmp.serial);
-	os = &ogg->streams[*stream];
+	serial = (tmp_header[14] << 24) |
+		 (tmp_header[15] << 16) |
+		 (tmp_header[16] <<  8) |
+		 (tmp_header[17]      );
+	*stream = find_stream(ogg, serial);
+	os = &ogg->os[*stream];
 
-	FREAD(ogg->in, tmp.segments, seg);
+	segments = tmp_header[26];
+	FREAD(ogg->in, segments, sizes);
 
-	if (os->buf_pos) memmove(os->buf, os->buf + os->buf_pos, os->buf_end - os->buf_pos);
-	if (os->pos) for (i = os->pos; i < os->totpos; i++) os->sizes[i - os->pos] = os->sizes[i];
-
-	os->totpos -= os->pos;
-	os->pos = 0;
-	os->buf_end -= os->buf_pos;
-	os->buf_pos = 0;
-
-	totseg = os->buf_end;
-	for (i = 0; i < os->totpos; i++) totseg -= os->sizes[i];
-	for (i = 0; i < tmp.segments; i++) {
-		tot += seg[i];
-		totseg += seg[i];
-		if (seg[i] < 255) {
-			if (os->totpos > 255) return 4;
-			os->sizes[os->totpos++] = totseg;
-			totseg = 0;
+	len = os->leftover;
+	for (i = 0; i < segments; i++) {
+		len += sizes[i];
+		if (sizes[i] != 255) {
+			packet_t p;
+			p.buf = malloc(len);
+			p.p.len = len;
+			p.p.stream = *stream;
+			p.p.flags = p.p.pts = p.p.next_pts = 0; // ogg sucks
+			memcpy(p.buf, os->leftover_buf, os->leftover);
+			FREAD(ogg->in, len - os->leftover, p.buf + os->leftover);
+			push_packet(&ogg->s[*stream], &p);
+			tot++;
+			len = 0;
+			os->leftover = 0;
 		}
 	}
-	if (os->buf_end + tot > PAGE_ALLOC) os->buf = realloc(os->buf, os->buf_end + tot);
-	FREAD(ogg->in, tot, os->buf + os->buf_end);
-	os->buf_end += tot;
-	if (os->totpos == 0) // this page gave nothing, move on to next page
-		return read_page(ogg, stream);
+
+	if (len) {
+		os->leftover_buf = realloc(os->leftover_buf, len);
+		FREAD(ogg->in, len - os->leftover, os->leftover_buf + os->leftover);
+		os->leftover = len;
+	}
+	if (!tot) return read_page(ogg, stream); // this page gave nothing, move on to next page
 
 	return 0;
 }
 
-static int get_headers(demuxer_priv_t * ogg) {
+static int read_headers(demuxer_priv_t * ogg, stream_t ** streams) {
 	int i;
 	int err;
-	int stream;
 
-	if ((err = read_page(ogg, &stream))) return err;
-	do {
-		if ((err = read_page(ogg, &stream))) return err;
-	} while (stream != 0);
-	stream = ogg->nstreams;
+	if ((err = read_page(ogg, &i))) return err;
+	do { if ((err = read_page(ogg, &i))) return err; } while (i != 0);
+	ogg->stream_count = ogg->nstreams;
 
-	for (i = 0; i < stream; i++) {
-		ogg_stream_t * os = &ogg->streams[i];
+	for (i = 0; i < ogg->stream_count; i++) {
 		int j;
-		for (j = 0; ogg_codecs[j]; j++) {
-			if (ogg_codecs[j]->magic_len > os->buf_end) continue;
-			if (!memcmp(ogg_codecs[j]->magic, os->buf, ogg_codecs[j]->magic_len))
-				break;
+		for (j = 0; codecs[j].magic; j++) {
+			if (codecs[j].magic_len > ogg->s[i].packets[0].p.len) continue;
+			if (!memcmp(codecs[j].magic, ogg->s[i].packets[0].buf, codecs[j].magic_len)) break;
 		}
-		if (!ogg_codecs[j]) return 5;
-		os->oc = ogg_codecs[j];
-		if ((err = os->oc->read_headers(ogg, i))) return err;
+		if (!codecs[j].magic) return 6;
+		ogg->s[i].codec_id = codecs[j].id;
 	}
-	if (stream != ogg->nstreams) return 6; // non-perfect-interleaved!
+
+	*streams = ogg->s;
+
 	return 0;
 }
 
-// BEGIN vorbis
+static int fill_buffer(demuxer_priv_t * ogg) {
+	int err, dummy;
 
-static int gcd(int a, int b) {
-	while (b != 0) {
-		int t = b;
-		b = a % b;
-		a = t;
-	}
-	return a;
-}
-static int ilog(int a) {
-	int i;
-	for (i = 0; (a >> i) > 0; i++);
-	return i;
-}
+	if ((err = read_page(ogg, &dummy))) return err;
+	if (ogg->stream_count != ogg->nstreams) return 2;
 
-typedef struct bit_packer_s {
-	int pos;
-	int left;
-	uint8_t * buf_ptr;
-} bit_packer_t;
-
-static int get_bits(bit_packer_t * bp, int bits, uint64_t * res) {
-	uint64_t val = 0;
-	int pos = 0;
-	bp->left -= bits;
-	if (bp->left < 0) return 1;
-
-	if (!bits) return 0;
-	if (bp->pos) {
-		if (bp->pos > bits) {
-			val = *bp->buf_ptr >> (8 - bp->pos);
-			val &= (1ULL << bits) - 1;
-			bp->pos -= bits;
-			pos = bits;
-		} else {
-			val = *bp->buf_ptr >> (8 - bp->pos);
-			pos = bp->pos;
-			bp->pos = 0;
-			bp->buf_ptr++;
-		}
-	}
-	for (; bits - pos >= 8; pos += 8) val |= *bp->buf_ptr++ << pos;
-	if (bits - pos) {
-		val |= (*bp->buf_ptr & ((1ULL << (bits - pos)) - 1)) << pos;
-		bp->pos = 8 - (bits - pos);
-	}
-	if (res) *res = val;
-	//printf("read %d bits: %d\n", bits, (int)val);
 	return 0;
 }
 
-#define CHECK(x) do{ if ((err = (x))) return err; }while(0)
-
-static int vorbis_read_headers(demuxer_priv_t * ogg, int stream) {
-	ogg_stream_t * os = &ogg->streams[stream];
-	bit_packer_t bp;
-	uint64_t num;
-	int err;
-	int i, tmp;
-	int channels;
-	int sample_rate;
-	int blocksize0, blocksize1;
-	int * priv;
-	os->codec_specific = NULL;
-
-	while (os->totpos < 3) { // read more pages
-		CHECK(read_page(ogg, &i));
-	}
-
-	if (os->sizes[0] < 30) return 1;
-	channels = os->buf[11];
-	sample_rate = (os->buf[15] << 24) | (os->buf[14] << 16) | (os->buf[13] << 8) | os->buf[12];
-	blocksize0 = 1 << (os->buf[28] & 0xF);
-	blocksize1 = 1 << (os->buf[28] >> 4);
-	if (blocksize0 == blocksize1) i = blocksize0/2;
-	else i = blocksize0/4;
-	blocksize0 /= i;
-	blocksize1 /= i;
-
-	os->time_base_denom = sample_rate / gcd(sample_rate, i);
-	os->time_base_nom = i / gcd(sample_rate, i);
-	os->fixed_fps = 0;
-	os->decode_delay = 0;
-	os->codec_specific_len = 0;
-	os->codec_specific = NULL;
-	os->samplerate_nom = sample_rate;
-	os->samplerate_denom = 1;
-	os->channel_count = channels;
-
-	os->codec_specific_len = 1 + os->sizes[0]/255 + 1 + os->sizes[1]/255 + 1 +
-				os->sizes[0] + os->sizes[1] + os->sizes[2];
-	os->codec_specific = malloc(os->codec_specific_len);
-	os->codec_specific[0] = 2;
-	tmp = 1;
-	i = os->sizes[0];
-	while (i >= 255) { os->codec_specific[tmp++] = 255; i -= 255; }
-	os->codec_specific[tmp++] = i;
-	i = os->sizes[1];
-	while (i >= 255) { os->codec_specific[tmp++] = 255; i -= 255; }
-	os->codec_specific[tmp++] = i;
-	memcpy(os->codec_specific + tmp, os->buf, os->sizes[0] + os->sizes[1] + os->sizes[2]);
-
-	bp.buf_ptr = os->buf + os->sizes[0] + os->sizes[1];
-	bp.left = os->sizes[2]*8;
-	bp.pos = 0;
-
-	CHECK(get_bits(&bp, 8, &num)); if (num != 5) return 2;
-	CHECK(get_bits(&bp, 8*6, NULL)); // "vorbis"
-
-	// codebook
-	CHECK(get_bits(&bp, 8, &num)); i = num + 1;
-	for (; i > 0; i--) {
-		int dimentions, entries;
-		int j;
-		CHECK(get_bits(&bp, 24, &num)); // magic
-		CHECK(get_bits(&bp, 16, &num)); dimentions = num;
-		CHECK(get_bits(&bp, 24, &num)); entries = num;
-		CHECK(get_bits(&bp, 1, &num));
-		if (num) { // ordered
-			CHECK(get_bits(&bp, 5, NULL)); // len
-			j = 0;
-			while (j < entries) {
-				CHECK(get_bits(&bp, ilog(entries - j), &num));
-				j += num;
-			}
-		} else { // not ordered
-			CHECK(get_bits(&bp, 1, &num));
-			if (num) { // sparse
-				for (j = 0; j < entries; j++) {
-					CHECK(get_bits(&bp, 1, &num)); // flag
-					if (num) CHECK(get_bits(&bp, 5, NULL));
-				}
-			} else { // not sparse
-				CHECK(get_bits(&bp, 5 * entries, NULL));
-			}
-		}
-		CHECK(get_bits(&bp, 4, &num)); // lookup
-		switch (num) {
-			case 0: j = -1; break;
-			case 1: for (j = 0; ; j++) {
-					int n = 1, i;
-					for (i = 0; i < dimentions; i++) n*= j;
-					if (n > entries) break;
-				}
-				j--;
-				break;
-			case 2: j = dimentions * entries; break;
-			default:
-				return 3;
-		}
-		if (j >= 0) {
-			int bits;
-			CHECK(get_bits(&bp, 32, NULL)); // float minimum
-			CHECK(get_bits(&bp, 32, NULL)); // float delta
-			CHECK(get_bits(&bp, 4, &num)); bits = num + 1;
-			CHECK(get_bits(&bp, 1, NULL)); // sequence_p
-			CHECK(get_bits(&bp, j*bits, NULL));
-		}
-	}
-
-	// time domain
-	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
-	CHECK(get_bits(&bp, i*16, NULL));
-
-	// floors
-	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
-	for (; i > 0; i--) {
-		CHECK(get_bits(&bp, 16, &num));
-		if (num == 0) { // floor type 0
-			CHECK(get_bits(&bp, 16, NULL)); // floor0_order
-			CHECK(get_bits(&bp, 16, NULL)); // floor0_rate
-			CHECK(get_bits(&bp, 16, NULL)); // floor0_bark_map_size
-			CHECK(get_bits(&bp, 6, NULL)); // floor0_amplitude_bits
-			CHECK(get_bits(&bp, 8, NULL)); // floor0_amplitude_offset
-			CHECK(get_bits(&bp, 4, &num)); // floor0_number_of_books
-			CHECK(get_bits(&bp, 8 * (num+1), NULL)); // floor0_book_list
-		} else if (num == 1) { // floor type 1
-			int partitions, j, max = -1, rangebits;
-			CHECK(get_bits(&bp, 5, &num)); partitions = num;
-			{ int class_list[partitions];
-			for (j = 0; j < partitions; j++) {
-				CHECK(get_bits(&bp, 4, &num));
-				class_list[j] = num;
-				max = MAX(max, (int)num);
-			}
-			{ int classes[max + 1];
-			for (j = 0; j <= max; j++) {
-				int n;
-				CHECK(get_bits(&bp, 3, &num));
-				classes[j] = num + 1;
-				CHECK(get_bits(&bp, 2, &num));
-				if (num) CHECK(get_bits(&bp, 8, NULL));
-				for (n = 0; n <= ((1 << num) - 1); n++) CHECK(get_bits(&bp, 8, NULL));
-			}
-			CHECK(get_bits(&bp, 2, NULL)); // multiplier
-			CHECK(get_bits(&bp, 4, &num)); rangebits = num;
-
-			for (j = 0; j < partitions; j++) {
-				CHECK(get_bits(&bp, classes[class_list[j]]*rangebits, NULL));
-			}
-			}}
-		} else return 5; // unknown floor
-	}
-
-	// residues
-	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
-	for (; i > 0; i--) {
-		int j, classifications;
-		CHECK(get_bits(&bp, 16, &num));
-		if ((int)num > 2) return 6; // unkown residue
-		CHECK(get_bits(&bp, 24, NULL)); // residue_begin
-		CHECK(get_bits(&bp, 24, NULL)); // residue_end
-		CHECK(get_bits(&bp, 24, NULL)); // residue_partition_size
-		CHECK(get_bits(&bp, 6, &num)); classifications = num + 1;
-		CHECK(get_bits(&bp, 8, NULL)); // residue_classbook
-		{int bits[classifications];
-		for (j = 0; j < classifications; j++) {
-			CHECK(get_bits(&bp, 3, &num)); bits[j] = num;
-			CHECK(get_bits(&bp, 1, &num));
-			if (num) {
-				CHECK(get_bits(&bp, 5, &num));
-				bits[j] |= num << 3;
-			}
-		}
-		for (j = 0; j < classifications; j++){
-			int bit;
-			for (bit = 0; bit < 8; bit++) {
-				if (bits[j] & (1 << bit)) CHECK(get_bits(&bp, 8, NULL));
-			}
-		}
-		}
-	}
-
-	// mappings
-	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
-	for (; i > 0; i--) {
-		int submaps = 1;
-		CHECK(get_bits(&bp, 16, &num)); // type
-		if (num) return 7; // bad mapping type
-		CHECK(get_bits(&bp, 1, &num)); // is submaps
-		if (num) {
-			CHECK(get_bits(&bp, 4, &num));
-			submaps = num + 1;
-		}
-		CHECK(get_bits(&bp, 1, &num)); // square polar
-		if (num) {
-			CHECK(get_bits(&bp, 8, &num));
-			CHECK(get_bits(&bp, ilog(channels - 1) * 2 * (num + 1), NULL));
-		}
-		CHECK(get_bits(&bp, 2, &num)); // reserved
-		if (num) return 8;
-		if (submaps > 1) CHECK(get_bits(&bp, 4 * channels, NULL));
-		CHECK(get_bits(&bp, submaps*(8+8+8), NULL));
-	}
-
-	// modes
-	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
-	priv = os->oc_priv = malloc(sizeof(int) * (i + 4));
-	priv[0] = blocksize0;
-	priv[1] = blocksize1;
-	priv[2] = i; // mode count
-	priv[3] = -1; // initial pts
-	for (i = 0; i < priv[2]; i++) {
-		CHECK(get_bits(&bp, 1, &num)); // block flag
-		priv[i+4] = num;
-		CHECK(get_bits(&bp, 16 + 16 + 8, NULL));
-	}
-	CHECK(get_bits(&bp, 1, &num)); // framing
-	if (!num) { free(os->oc_priv); return 9; }
-
-	os->buf_pos = os->sizes[0] + os->sizes[1] + os->sizes[2];
-	os->pos = 3;
-	return 0;
-}
-
-static int vorbis_get_pts(ogg_stream_t * os) {
-	bit_packer_t bp;
-	uint64_t num;
-	int * priv = os->oc_priv;
-	int last_pts = MAX(priv[3], 0); // -1 is not valid
-	int mode;
-	int mybs, prevbs, nextbs;
-	bp.buf_ptr = os->buf + os->buf_pos;
-	bp.left = os->sizes[os->pos]*8;
-	bp.pos = 0;
-	get_bits(&bp, 1, NULL);
-	get_bits(&bp, ilog(priv[2] - 1), &num);
-	if ((int)num >= priv[2]) return 0; // ERROR
-
-	mode = priv[num+4];
-	prevbs = nextbs = mybs = priv[mode];
-	if (mode) { // big window
-		get_bits(&bp, 1, &num); prevbs = priv[num];
-		get_bits(&bp, 1, &num); nextbs = priv[num];
-	}
-
-	if (priv[3] == -1) priv[3] = -MIN(prevbs, mybs)/2; // negative pts for first frame
-
-	priv[3] += MIN(prevbs, mybs)/2; // overlapped with prev
-	priv[3] += (mybs - prevbs)/4; // self contained
-	priv[3] += (mybs - nextbs)/4;
-
-	return last_pts;
-}
-
-static void vorbis_uninit(ogg_stream_t * os) {
-	free(os->oc_priv);
-	free(os->codec_specific);
-}
-
-// END
-
-static void * init(FILE * in) {
+static demuxer_priv_t * init(FILE * in) {
 	demuxer_priv_t * ogg = malloc(sizeof(demuxer_priv_t));
-	ogg->streams = NULL;
-	ogg->nstreams = 0;
 	ogg->in = in;
-	ogg->last_stream = 0;
+	ogg->os = NULL;
+	ogg->s = NULL;
+	ogg->stream_count = ogg->nstreams = 0;
 	return ogg;
 }
 
 static void uninit(demuxer_priv_t * ogg) {
 	int i;
-	for (i = 0; i < ogg->nstreams; i++) {
-		if (ogg->streams[i].oc && ogg->streams[i].oc->uninit)
-			ogg->streams[i].oc->uninit(&ogg->streams[i]);
-		free(ogg->streams[i].buf);
-	}
-	free(ogg->streams);
+	for (i = 0; i < ogg->nstreams; i++) free(ogg->os[i].leftover_buf);
+	free(ogg->os);
+	free_streams(ogg->s);
+	free(ogg->s);
 	free(ogg);
 }
 
-static int read_headers(demuxer_priv_t * ogg, nut_stream_header_t ** nut_streams) {
-	nut_stream_header_t * s;
-	int i;
-	int err;
-
-	if ((err = get_headers(ogg))) return err;
-
-	*nut_streams = s = malloc(sizeof(nut_stream_header_t) * (ogg->nstreams+1));
-
-	for (i = 0; i < ogg->nstreams; i++) {
-		ogg_stream_t * os = &ogg->streams[i];
-		s[i].type = os->oc->type;
-		s[i].fourcc = os->oc->fourcc;
-		s[i].fourcc_len = os->oc->fourcc_len;
-		s[i].time_base.den = os->time_base_denom;
-		s[i].time_base.nom = os->time_base_nom;
-		s[i].fixed_fps = os->fixed_fps;
-		s[i].decode_delay = os->decode_delay;
-		s[i].codec_specific = os->codec_specific;
-		s[i].codec_specific_len = os->codec_specific_len;
-		switch (os->oc->type) {
-			case 0: // video
-				s[i].width = os->width;
-				s[i].height = os->height;
-				s[i].sample_width = os->sample_width;
-				s[i].sample_height = os->sample_height;
-				s[i].colorspace_type = os->colorspace_type;
-				break;
-			case 1: // audio
-				s[i].samplerate_nom = os->samplerate_nom;
-				s[i].samplerate_denom = os->samplerate_denom;
-				s[i].channel_count = os->channel_count;
-		}
-	}
-	s[i].type = -1;
-	return 0;
-}
-
-static int get_packet(demuxer_priv_t * ogg, nut_packet_t * p, uint8_t ** buf) {
-	int stream = ogg->last_stream;
-	ogg_stream_t * os = &ogg->streams[stream];
-	int err;
-	int size;
-
-	if (os->pos == os->totpos) {
-		if ((err = read_page(ogg, &stream))) return err;
-		ogg->last_stream = stream;
-		os = &ogg->streams[stream];
-	}
-
-	size = os->sizes[os->pos];
-	p->len = size;
-
-	p->next_pts = 0;
-	p->stream = stream;
-	p->flags = !os->oc->is_key || os->oc->is_key(os) ? NUT_FLAG_KEY : 0;
-	p->pts = os->oc->get_pts(os);
-
-	*buf = os->buf + os->buf_pos;
-
-	os->buf_pos += size;
-	os->pos++;
-
-	return 0;
-}
-
-struct demuxer_t ogg_demuxer = {
+demuxer_t ogg_demuxer = {
 	"ogg",
 	init,
 	read_headers,
-	get_packet,
-	uninit
+	fill_buffer,
+	uninit,
+	NULL
 };
 
 #ifdef OGG_PROG

Added: trunk/nututils/framer_mpeg4.c
==============================================================================
--- trunk/nututils/framer_mpeg4.c (added)
+++ trunk/nututils/framer_mpeg4.c Fri Mar 31 22:05:02 2006
@@ -1,0 +1,75 @@
+#include "nutmerge.h"
+
+struct framer_priv_s {
+	stream_t * stream;
+	int64_t cur_pts;
+};
+
+static int find_frame_type(int len, uint8_t * buf, int * type) {
+	//if (!len) { *type = 1; return 0; }
+	while (--len) { // not including last byte
+		if (*buf++ != 0xB6) continue;
+		*type = *buf >> 6;
+		return 0;
+	}
+	return 13;
+}
+
+#define CHECK(x) do{ if ((err = (x))) return err; }while(0)
+
+static int get_packet(framer_priv_t * mc, packet_t * p) {
+	packet_t tmp_p;
+	int n = 0;
+	int type, err = 0;
+
+	CHECK(get_stream_packet(mc->stream, p));
+
+	p->p.pts = mc->cur_pts++;
+	p->p.next_pts = 0;
+
+	CHECK(find_frame_type(p->p.len, p->buf, &type));
+
+	if (stats) fprintf(stats, "%c", type==0?'I':type==1?'P':type==2?'B':'S');
+
+	if (!(p->p.flags & NUT_FLAG_KEY) ^ (type != 0)) printf("Error detected stream %d frame %d\n", p->p.stream, (int)p->p.pts);
+	p->p.flags |= (type == 0 ? NUT_FLAG_KEY : 0);
+
+	if (type == 2) { p->p.pts--; return 0; } // B frame, simple
+	if (type == 3) printf("S-Frame %d\n", (int)p->p.pts);
+
+	// I, P or S, needs forward B frame check
+
+	while ((err = peek_stream_packet(mc->stream, &tmp_p, n++)) != -1) {
+		if (err) return err;
+		CHECK(find_frame_type(tmp_p.p.len, tmp_p.buf, &type));
+		if (type != 2) break; // not b frame, we're done.
+		p->p.pts++;
+	}
+
+	return 0;
+}
+
+static int setup_headers(framer_priv_t * mc, nut_stream_header_t * s) {
+	*s = mc->stream->sh;
+	return 0; // nothing to do
+}
+
+static framer_priv_t * init(stream_t * s) {
+	framer_priv_t * mc = malloc(sizeof(framer_priv_t));
+	mc->stream = s;
+	mc->cur_pts = 0;
+	return mc;
+}
+
+static void uninit(framer_priv_t * mc) {
+	free(mc);
+}
+
+framer_t mpeg4_framer = {
+	e_mpeg4,
+	init,
+	setup_headers,
+	get_packet,
+	uninit,
+	NULL
+};

Added: trunk/nututils/framer_vorbis.c
==============================================================================
--- trunk/nututils/framer_vorbis.c (added)
+++ trunk/nututils/framer_vorbis.c Fri Mar 31 22:05:02 2006
@@ -1,0 +1,341 @@
+#include <string.h>
+#include "nutmerge.h"
+
+struct framer_priv_s {
+	int blocksize[2];
+	stream_t * stream;
+	int mode_count;
+	int * modes;
+	uint8_t * codec_specific;
+	int64_t pts;
+};
+
+static int gcd(int a, int b) {
+	while (b != 0) {
+		int t = b;
+		b = a % b;
+		a = t;
+	}
+	return a;
+}
+static int ilog(int a) {
+	int i;
+	for (i = 0; (a >> i) > 0; i++);
+	return i;
+}
+
+typedef struct bit_packer_s {
+	int pos;
+	int left;
+	uint8_t * buf_ptr;
+} bit_packer_t;
+
+static int get_bits(bit_packer_t * bp, int bits, uint64_t * res) {
+	uint64_t val = 0;
+	int pos = 0;
+	bp->left -= bits;
+	if (bp->left < 0) return 1;
+
+	if (!bits) return 0;
+	if (bp->pos) {
+		if (bp->pos > bits) {
+			val = *bp->buf_ptr >> (8 - bp->pos);
+			val &= (1ULL << bits) - 1;
+			bp->pos -= bits;
+			pos = bits;
+		} else {
+			val = *bp->buf_ptr >> (8 - bp->pos);
+			pos = bp->pos;
+			bp->pos = 0;
+			bp->buf_ptr++;
+		}
+	}
+	for (; bits - pos >= 8; pos += 8) val |= *bp->buf_ptr++ << pos;
+	if (bits - pos) {
+		val |= (*bp->buf_ptr & ((1ULL << (bits - pos)) - 1)) << pos;
+		bp->pos = 8 - (bits - pos);
+	}
+	if (res) *res = val;
+	//printf("read %d bits: %d\n", bits, (int)val);
+	return 0;
+}
+
+#define CHECK(x) do{ if ((err = (x))) goto err_out; }while(0)
+
+static int setup_headers(framer_priv_t * vc, nut_stream_header_t * s) {
+	bit_packer_t bp;
+	uint64_t num;
+	int i, err = 0, pd_read = 0;
+	int channels, sample_rate, codec_specific_len;
+	uint8_t * p;
+	packet_t pd[3];
+
+	// need first 3 packets - TODO - support work directly from good codec_specific instead of ogg crap
+	CHECK(get_stream_packet(vc->stream, &pd[0])); pd_read++;
+	CHECK(get_stream_packet(vc->stream, &pd[1])); pd_read++;
+	CHECK(get_stream_packet(vc->stream, &pd[2])); pd_read++;
+
+	codec_specific_len = 1 + pd[0].p.len/255 + 1 + pd[1].p.len/255 + 1 + pd[0].p.len + pd[1].p.len + pd[2].p.len;
+	p = vc->codec_specific = malloc(codec_specific_len);
+	*p++ = 2;
+	for (i = 0; i < 2; i++) {
+		int tmp = pd[i].p.len;
+		while (tmp >= 255) { *p++ = 255; tmp -= 255; }
+		*p++ = tmp;
+	}
+	for (i = 0; i < 3; i++) { memcpy(p, pd[i].buf, pd[i].p.len); p += pd[i].p.len; }
+
+	if (pd[0].p.len < 30) { err = 1; goto err_out; }
+	p = pd[0].buf;
+	channels = p[11];
+	sample_rate = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
+	vc->blocksize[0] = 1 << (p[28] & 0xF);
+	vc->blocksize[1] = 1 << (p[28] >> 4);
+	if (vc->blocksize[0] == vc->blocksize[1]) i = vc->blocksize[0]/2;
+	else i = vc->blocksize[0]/4;
+	vc->blocksize[0] /= i;
+	vc->blocksize[1] /= i;
+
+	s->type = NUT_AUDIO_CLASS;
+	s->fourcc_len = 4;
+	s->fourcc = "vrbs";
+	s->time_base.den = sample_rate / gcd(sample_rate, i);
+	s->time_base.nom = i / gcd(sample_rate, i);
+	s->fixed_fps = 0;
+	s->decode_delay = 0;
+	s->codec_specific_len = codec_specific_len;
+	s->codec_specific = vc->codec_specific;
+	s->samplerate_nom = sample_rate;
+	s->samplerate_denom = 1;
+	s->channel_count = channels;
+
+	bp.buf_ptr = pd[2].buf;
+	bp.left = pd[2].p.len*8;
+	bp.pos = 0;
+
+	CHECK(get_bits(&bp, 8, &num)); if (num != 5) { err = 2; goto err_out; }
+	CHECK(get_bits(&bp, 8*6, NULL)); // "vorbis"
+
+	// codebook
+	CHECK(get_bits(&bp, 8, &num)); i = num + 1;
+	for (; i > 0; i--) {
+		int dimentions, entries;
+		int j;
+		CHECK(get_bits(&bp, 24, &num)); // magic
+		CHECK(get_bits(&bp, 16, &num)); dimentions = num;
+		CHECK(get_bits(&bp, 24, &num)); entries = num;
+		CHECK(get_bits(&bp, 1, &num));
+		if (num) { // ordered
+			CHECK(get_bits(&bp, 5, NULL)); // len
+			j = 0;
+			while (j < entries) {
+				CHECK(get_bits(&bp, ilog(entries - j), &num));
+				j += num;
+			}
+		} else { // not ordered
+			CHECK(get_bits(&bp, 1, &num));
+			if (num) { // sparse
+				for (j = 0; j < entries; j++) {
+					CHECK(get_bits(&bp, 1, &num)); // flag
+					if (num) CHECK(get_bits(&bp, 5, NULL));
+				}
+			} else { // not sparse
+				CHECK(get_bits(&bp, 5 * entries, NULL));
+			}
+		}
+		CHECK(get_bits(&bp, 4, &num)); // lookup
+		switch (num) {
+			case 0: j = -1; break;
+			case 1: for (j = 0; ; j++) {
+					int n = 1, i;
+					for (i = 0; i < dimentions; i++) n*= j;
+					if (n > entries) break;
+				}
+				j--;
+				break;
+			case 2: j = dimentions * entries; break;
+			default:
+				err = 3;
+				goto err_out;
+		}
+		if (j >= 0) {
+			int bits;
+			CHECK(get_bits(&bp, 32, NULL)); // float minimum
+			CHECK(get_bits(&bp, 32, NULL)); // float delta
+			CHECK(get_bits(&bp, 4, &num)); bits = num + 1;
+			CHECK(get_bits(&bp, 1, NULL)); // sequence_p
+			CHECK(get_bits(&bp, j*bits, NULL));
+		}
+	}
+
+	// time domain
+	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
+	CHECK(get_bits(&bp, i*16, NULL));
+
+	// floors
+	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
+	for (; i > 0; i--) {
+		CHECK(get_bits(&bp, 16, &num));
+		if (num == 0) { // floor type 0
+			CHECK(get_bits(&bp, 16, NULL)); // floor0_order
+			CHECK(get_bits(&bp, 16, NULL)); // floor0_rate
+			CHECK(get_bits(&bp, 16, NULL)); // floor0_bark_map_size
+			CHECK(get_bits(&bp, 6, NULL)); // floor0_amplitude_bits
+			CHECK(get_bits(&bp, 8, NULL)); // floor0_amplitude_offset
+			CHECK(get_bits(&bp, 4, &num)); // floor0_number_of_books
+			CHECK(get_bits(&bp, 8 * (num+1), NULL)); // floor0_book_list
+		} else if (num == 1) { // floor type 1
+			int partitions, j, max = -1, rangebits;
+			CHECK(get_bits(&bp, 5, &num)); partitions = num;
+			{ int class_list[partitions];
+			for (j = 0; j < partitions; j++) {
+				CHECK(get_bits(&bp, 4, &num));
+				class_list[j] = num;
+				max = MAX(max, (int)num);
+			}
+			{ int classes[max + 1];
+			for (j = 0; j <= max; j++) {
+				int n;
+				CHECK(get_bits(&bp, 3, &num));
+				classes[j] = num + 1;
+				CHECK(get_bits(&bp, 2, &num));
+				if (num) CHECK(get_bits(&bp, 8, NULL));
+				for (n = 0; n <= ((1 << num) - 1); n++) CHECK(get_bits(&bp, 8, NULL));
+			}
+			CHECK(get_bits(&bp, 2, NULL)); // multiplier
+			CHECK(get_bits(&bp, 4, &num)); rangebits = num;
+
+			for (j = 0; j < partitions; j++) {
+				CHECK(get_bits(&bp, classes[class_list[j]]*rangebits, NULL));
+			}
+			}}
+		} else { err = 5; goto err_out; } // unknown floor
+	}
+
+	// residues
+	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
+	for (; i > 0; i--) {
+		int j, classifications;
+		CHECK(get_bits(&bp, 16, &num));
+		if ((int)num > 2) { err = 6; goto err_out; } // unkown residue
+		CHECK(get_bits(&bp, 24, NULL)); // residue_begin
+		CHECK(get_bits(&bp, 24, NULL)); // residue_end
+		CHECK(get_bits(&bp, 24, NULL)); // residue_partition_size
+		CHECK(get_bits(&bp, 6, &num)); classifications = num + 1;
+		CHECK(get_bits(&bp, 8, NULL)); // residue_classbook
+		{int bits[classifications];
+		for (j = 0; j < classifications; j++) {
+			CHECK(get_bits(&bp, 3, &num)); bits[j] = num;
+			CHECK(get_bits(&bp, 1, &num));
+			if (num) {
+				CHECK(get_bits(&bp, 5, &num));
+				bits[j] |= num << 3;
+			}
+		}
+		for (j = 0; j < classifications; j++){
+			int bit;
+			for (bit = 0; bit < 8; bit++) {
+				if (bits[j] & (1 << bit)) CHECK(get_bits(&bp, 8, NULL));
+			}
+		}
+		}
+	}
+
+	// mappings
+	CHECK(get_bits(&bp, 6, &num)); i = num + 1;
+	for (; i > 0; i--) {
+		int submaps = 1;
+		CHECK(get_bits(&bp, 16, &num)); // type
+		if (num) { err = 7; goto err_out; } // bad mapping type
+		CHECK(get_bits(&bp, 1, &num)); // is submaps
+		if (num) {
+			CHECK(get_bits(&bp, 4, &num));
+			submaps = num + 1;
+		}
+		CHECK(get_bits(&bp, 1, &num)); // square polar
+		if (num) {
+			CHECK(get_bits(&bp, 8, &num));
+			CHECK(get_bits(&bp, ilog(channels - 1) * 2 * (num + 1), NULL));
+		}
+		CHECK(get_bits(&bp, 2, &num)); // reserved
+		if (num) { err = 8; goto err_out; }
+		if (submaps > 1) CHECK(get_bits(&bp, 4 * channels, NULL));
+		CHECK(get_bits(&bp, submaps*(8+8+8), NULL));
+	}
+
+	// finally! modes
+	CHECK(get_bits(&bp, 6, &num)); vc->mode_count = num + 1;
+	vc->modes = malloc(vc->mode_count * sizeof(int));
+	for (i = 0; i < vc->mode_count; i++) {
+		CHECK(get_bits(&bp, 1, &num)); // block flag
+		vc->modes[i] = num;
+		CHECK(get_bits(&bp, 16 + 16 + 8, NULL));
+	}
+	CHECK(get_bits(&bp, 1, &num)); // framing
+	if (!num) { err = 9; goto err_out; }
+
+err_out:
+	for (i = 0; i < pd_read; i++) free(pd[i].buf);
+
+	return err;
+}
+
+static int get_packet(framer_priv_t * vc, packet_t * p) {
+	bit_packer_t bp;
+	uint64_t num;
+	int64_t last_pts = MAX(vc->pts, 0); // -1 is not valid
+	int mode, err = 0;
+	int mybs, prevbs, nextbs;
+
+	CHECK(get_stream_packet(vc->stream, p));
+
+	bp.buf_ptr = p->buf;
+	bp.left = p->p.len*8;
+	bp.pos = 0;
+	CHECK(get_bits(&bp, 1, NULL));
+	CHECK(get_bits(&bp, ilog(vc->mode_count - 1), &num));
+	if ((int)num >= vc->mode_count) return 10; // ERROR
+
+	mode = vc->modes[num];
+	prevbs = nextbs = mybs = vc->blocksize[mode];
+	if (mode) { // big window
+		CHECK(get_bits(&bp, 1, &num)); prevbs = vc->blocksize[num];
+		CHECK(get_bits(&bp, 1, &num)); nextbs = vc->blocksize[num];
+	}
+
+	if (vc->pts == -1) vc->pts = -MIN(prevbs, mybs)/2; // negative pts for first frame
+
+	vc->pts += MIN(prevbs, mybs)/2; // overlapped with prev
+	vc->pts += (mybs - prevbs)/4; // self contained
+	vc->pts += (mybs - nextbs)/4;
+
+	p->p.pts = last_pts;
+	p->p.next_pts = vc->pts;
+	p->p.flags = NUT_FLAG_KEY;
+err_out:
+	return err;
+}
+
+static framer_priv_t * init(stream_t * s) {
+	framer_priv_t * vc = malloc(sizeof(framer_priv_t));
+	vc->stream = s;
+	vc->modes = NULL;
+	vc->codec_specific = NULL;
+	vc->pts = -1;
+	return vc;
+}
+
+static void uninit(framer_priv_t * vc) {
+	free(vc->modes);
+	free(vc->codec_specific);
+	free(vc);
+}
+
+framer_t vorbis_framer = {
+	e_vorbis,
+	init,
+	setup_headers,
+	get_packet,
+	uninit,
+	NULL
+};

Modified: trunk/nututils/nutmerge.c
==============================================================================
--- trunk/nututils/nutmerge.c (original)
+++ trunk/nututils/nutmerge.c Fri Mar 31 22:05:02 2006
@@ -4,14 +4,25 @@
 
 FILE * stats = NULL;
 
-extern struct demuxer_t avi_demuxer;
-extern struct demuxer_t nut_demuxer;
-extern struct demuxer_t ogg_demuxer;
+extern demuxer_t avi_demuxer;
+extern demuxer_t nut_demuxer;
+extern demuxer_t ogg_demuxer;
 
-struct demuxer_t * demuxers[] = {
+demuxer_t * ndemuxers[] = {
 	&avi_demuxer,
-	&nut_demuxer,
+	//&nut_demuxer,
 	&ogg_demuxer,
+	NULL
+};
+
+extern framer_t vorbis_framer;
+extern framer_t mpeg4_framer;
+extern framer_t null_framer;
+
+framer_t * nframers[] = {
+	&vorbis_framer,
+	&mpeg4_framer,
+	&null_framer,
 	NULL
 };
 
@@ -43,103 +54,139 @@
 	  {   -1,      0,   0,   0,      0,    0,     0 }, // end
 };
 
-int main(int argc, char * argv []) {
-	FILE * in = NULL, * out = NULL;
-	struct demuxer_t demuxer = { .extention = NULL, .priv = NULL };
+void push_packet(stream_t * stream, packet_t * p) {
+	if (stream->npackets == stream->packets_alloc) {
+		stream->packets_alloc += 20;
+		stream->packets = realloc(stream->packets, stream->packets_alloc * sizeof(packet_t));
+	}
+	stream->packets[stream->npackets++] = *p;
+}
+
+int peek_stream_packet(stream_t * stream, packet_t * p, int n) {
+	while (stream->npackets <= n) {
+		int err;
+		if ((err = stream->demuxer.fill_buffer(stream->demuxer.priv))) return err;
+	}
+	*p = stream->packets[n];
+	return 0;
+}
+
+int get_stream_packet(stream_t * stream, packet_t * p) {
+	while (!stream->npackets) {
+		int err;
+		if ((err = stream->demuxer.fill_buffer(stream->demuxer.priv))) return err;
+	}
+	*p = stream->packets[0];
+	stream->npackets--;
+	memmove(&stream->packets[0], &stream->packets[1], stream->npackets * sizeof(packet_t));
+	return 0;
+}
+
+void free_streams(stream_t * streams) {
+	int i;
+	if (!streams) return;
+	for (i = 0; streams[i].stream_id >= 0; i++) {
+		int j;
+		for (j = 0; j < streams[i].npackets; j++) free(streams[i].packets[j].buf);
+		free(streams[i].packets);
+	}
+}
+
+static int pick(stream_t * streams, int stream_count) {
+	int i, n = 0;
+	for (i = 1; i < stream_count; i++) if (streams[i].npackets > streams[n].npackets) n = i;
+	return n;
+}
+
+#define fget_packet(framer, p) (framer).get_packet((framer).priv, p)
+
+static int convert(FILE * out, demuxer_t * demuxer, stream_t * streams, int stream_count) {
 	nut_context_t * nut = NULL;
-	nut_stream_header_t * nut_stream = NULL;
+	nut_stream_header_t nut_stream[stream_count+1];
 	nut_muxer_opts_t mopts;
-	uint8_t * buf;
-	int err = 0;
-	int i;
-	nut_packet_t p;
-	const char * extention;
-	fprintf(stderr, "==============================================================\n");
-	fprintf(stderr, "PLEASE NOTE THAT NUTMERGE FOR NOW CREATES _INVALID_ NUT FILES.\n");
-	fprintf(stderr, "DO NOT USE THESE FILES FOR ANYTHING BUT TESTING LIBNUT.\n");
-	fprintf(stderr, "==============================================================\n");
-	if (argc > 4 && !strcmp(argv[1], "-v")) {
-		stats = fopen(argv[2], "w");
-		argv += 2;
-		argc -= 2;
+	framer_t framers[stream_count];
+	int i, err = 0;
+	packet_t p;
+	int pts[stream_count];
+
+	memset(framers, 0, sizeof framers);
+	memset(pts, 0, sizeof pts);
+
+	for (i = 0; i < stream_count; i++) {
+		int j;
+		for (j = 0; nframers[j]; j++) if (nframers[j]->codec_id == streams[i].codec_id) break;
+		if (!nframers[j]) fprintf(stderr, "unsupported file format\n");
+		framers[i] = *nframers[j];
+		framers[i].priv = framers[i].init(&streams[i]);
+		if ((err = framers[i].setup_headers(framers[i].priv, &nut_stream[i]))) goto err_out;
 	}
-	if (argc < 3) { printf("bleh, more params you fool...\n"); return 1; }
-	extention = argv[1];
-	for (i = 0; argv[1][i]; i++) if (argv[1][i] == '.') extention = &argv[1][i+1];
-	for (i = 0; demuxers[i]; i++)
-		if (!strcmp(demuxers[i]->extention, extention)) demuxer = *demuxers[i];
+	nut_stream[i].type = -1;
 
-	if (!demuxer.extention) {
-		printf("unsupported file format\n");
-		err = 1;
-		goto err_out;
-	}
-
-	in = fopen(argv[1], "rb");
-	out = fopen(argv[2], "wb");
-
-	demuxer.priv = demuxer.init(in);
-
-	if ((err = demuxer.read_headers(demuxer.priv, &nut_stream))) goto err_out;
 	mopts.output = (nut_output_stream_t){ .priv = out, .write = NULL };
 	mopts.write_index = 1;
 	mopts.fti = ft_default;
 	mopts.max_distance = 32768;
 	nut = nut_muxer_init(&mopts, nut_stream, NULL);
 
-	for (i = 0; nut_stream[i].type >= 0; i++);
+	if (stats) fprintf(stats, "%10s%10s%10s%10s\n", "stream", "len", "pts_diff", "flags");
+	while (!(err = fget_packet(framers[pick(streams, stream_count)], &p))) {
+		int s = p.p.stream;
+		nut_write_frame_reorder(nut, &p.p, p.buf);
+		if (stats) fprintf(stats, "%10d%10d%10d%10d\n", p.p.stream, p.p.len, (int)p.p.pts - pts[s], p.p.flags);
+		pts[s] = p.p.pts;
+		if (!(p.p.pts % 5000)) {
+			for (i = 0; i < stream_count; i++) fprintf(stderr, "%d: %5d ", i, pts[i]);
+			fprintf(stderr, "\r");
+		}
+		free(p.buf);
+	}
+	if (err == -1) err = 0;
+err_out:
+	nut_muxer_uninit_reorder(nut);
+	for (i = 0; i < stream_count; i++) if (framers[i].priv) framers[i].uninit(framers[i].priv);
+	return err;
+}
 
-	{
-	int pts[i];
-	int * frames[i];
-	int frames_pos[i];
-	int frames_alloc[i];
+int main(int argc, char * argv []) {
+	FILE * in = NULL, * out = NULL;
+	demuxer_t demuxer = { .priv = NULL };
+	stream_t * streams;
+	int i, err = 0;
+	const char * extension;
 
-	for (i = 0; nut_stream[i].type >= 0; i++) {
-		frames_alloc[i] = frames_pos[i] = pts[i] = 0;
-		frames[i] = NULL;
+	fprintf(stderr, "==============================================================\n");
+	fprintf(stderr, "PLEASE NOTE THAT NUTMERGE FOR NOW CREATES _INVALID_ NUT FILES.\n");
+	fprintf(stderr, "DO NOT USE THESE FILES FOR ANYTHING BUT TESTING LIBNUT.\n");
+	fprintf(stderr, "==============================================================\n");
+
+	if (argc > 4 && !strcmp(argv[1], "-v")) {
+		stats = fopen(argv[2], "w");
+		argv += 2;
+		argc -= 2;
+	}
+	if (argc < 3) { fprintf(stderr, "bleh, more params you fool...\n"); return 1; }
+	extension = argv[1];
+	for (i = 0; argv[1][i]; i++) if (argv[1][i] == '.') extension = &argv[1][i+1];
+	for (i = 0; ndemuxers[i]; i++) if (!strcmp(ndemuxers[i]->extension, extension)) break;
+	if (!ndemuxers[i]) {
+		fprintf(stderr, "unsupported file format\n");
+		err = 1;
+		goto err_out;
 	}
 
-	if (stats) fprintf(stats, "%10s%10s%10s%10s\n", "stream", "len", "pts_diff", "flags");
-	while (!(err = demuxer.get_packet(demuxer.priv, &p, &buf))) {
-		int s = p.stream;
-		nut_write_frame_reorder(nut, &p, buf);
-		if (++frames_pos[s] > frames_alloc[s]) {
-			frames_alloc[s] = frames_pos[s] + 4096;
-			frames[s] = realloc(frames[s], sizeof(int) * frames_alloc[s]);
-		}
-		frames[s][frames_pos[s] - 1] = p.len;
-		if (stats) fprintf(stats, "%10d%10d%10d%10d\n", p.stream, p.len, (int)p.pts - pts[s], p.flags);
-		pts[s] = p.pts;
-		if (!(p.pts % 5000)) {
-			for (i = 0; nut_stream[i].type >= 0; i++) {
-				fprintf(stderr, "%d: %5d ", i, frames_pos[i]);
-			}
-			fprintf(stderr, "\r");
-		}
-	}
-	if (err == -1) err = 0;
-	nut_muxer_uninit_reorder(nut);
-	nut = NULL;
-	for (i = 0; nut_stream[i].type >= 0; i++) {
-		int j;
-		uint64_t total = 0;
-		double avg;
-		double std = 0;
-		for (j = 0; j < frames_pos[i]; j++) total += frames[i][j];
-		avg = (double)total / frames_pos[i];
-		for (j = 0; j < frames_pos[i]; j++) {
-			std += (frames[i][j] - avg)*(frames[i][j] - avg);
-		}
-		std /= frames_pos[i];
-		std = sqrt(std);
-		fprintf(stderr, "Stream %d: Standard Deviation %.2lf\n", i, std);
-		free(frames[i]);
-	}
-	}
+	demuxer = *ndemuxers[i];
+
+	in = fopen(argv[1], "rb");
+	out = fopen(argv[2], "wb");
+
+	demuxer.priv = demuxer.init(in);
+	if ((err = demuxer.read_headers(demuxer.priv, &streams))) goto err_out;
+
+	for (i = 0; streams[i].stream_id >= 0; i++);
+
+	convert(out, &demuxer, streams, i);
+
 err_out:
-	nut_muxer_uninit_reorder(nut);
-	free(nut_stream);
 	if (demuxer.priv) demuxer.uninit(demuxer.priv);
 	if (in) fclose(in);
 	if (out) fclose(out);

Modified: trunk/nututils/nutmerge.h
==============================================================================
--- trunk/nututils/nutmerge.h (original)
+++ trunk/nututils/nutmerge.h Fri Mar 31 22:05:02 2006
@@ -11,14 +11,56 @@
 extern FILE * stats;
 
 typedef struct demuxer_priv_s demuxer_priv_t;
+typedef struct framer_priv_s framer_priv_t;
+typedef struct stream_s stream_t;
 
-struct demuxer_t {
-	char * extention;
-	void * (*init)(FILE * in); ///< returns priv
-	/// nut_streams must be free()'d!! nut_streams becomes invalid after uninit!!
-	int (*read_headers)(demuxer_priv_t * priv, nut_stream_header_t ** nut_streams);
-	/// buf must be handled by demuxer! no free-ing or mallocing done by controller.
-	int (*get_packet)(demuxer_priv_t * priv, nut_packet_t * p, uint8_t ** buf);
+enum nutmerge_codecs {
+	e_vorbis,
+	e_mpeg4,
+	e_null,
+};
+
+typedef struct {
+	nut_packet_t p;
+	uint8_t * buf; // the demuxer mallocs this, nutmerge (or framer) evantually frees it
+} packet_t;
+
+typedef struct {
+	char * extension;
+	demuxer_priv_t * (*init)(FILE * in);
+	/// streams is -1 terminated, handled and freed by demuxer
+	int (*read_headers)(demuxer_priv_t * priv, stream_t ** streams);
+	int (*fill_buffer)(demuxer_priv_t * priv);
 	void (*uninit)(demuxer_priv_t * priv);
 	demuxer_priv_t * priv;
+} demuxer_t;
+
+typedef struct {
+	enum nutmerge_codecs codec_id;
+	framer_priv_t * (*init)(stream_t * stream);
+	int (*setup_headers)(framer_priv_t * priv, nut_stream_header_t * s); // fill 's'
+	int (*get_packet)(framer_priv_t * priv, packet_t * p); // 'p->buf' is now controlled by caller
+	void (*uninit)(framer_priv_t * priv);
+	framer_priv_t * priv;
+} framer_t;
+
+struct stream_s {
+	int stream_id; // -1 terminated
+	demuxer_t demuxer;
+	enum nutmerge_codecs codec_id;
+
+	nut_stream_header_t sh;
+
+	int npackets;
+	int packets_alloc;
+	packet_t * packets;
 };
+
+void ready_stream(stream_t * streams); // setup default stream info
+
+void push_packet(stream_t * stream, packet_t * p);
+
+int peek_stream_packet(stream_t * stream, packet_t * p, int n); // n = 0 means next packet, n = 1 means 1 after that
+int get_stream_packet(stream_t * stream, packet_t * p);
+
+void free_streams(stream_t * streams); // all the way to -1 terminated list, not the actual 'streams' though




More information about the NUT-devel mailing list