[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