
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