]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/nut.c
* providing MPEG codecs with a generic fields in AVFrame to use.
[ffmpeg] / libavformat / nut.c
index f08ec325a8018582f8ab89d9c0caea0403fc1ac4..4a0d9418de201a99164e393cc308dc7b0e507c7a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * NUT (de)muxer based on initial draft
+ * "NUT" Container Format muxer and demuxer (DRAFT-20031003)
  * Copyright (c) 2003 Alex Beregszaszi
  *
  * This library is free software; you can redistribute it and/or
  *
  * NUT DRAFT can be found in MPlayer CVS at DOCS/tech/mpcf.txt
  *
- * Compatible with draft version 20030906
+ * AND http://people.fsn.hu/~alex/nut/ (TeX, pdf, ps, dvi, ..)
  *
  */
 
 /*
  * TODO:
  * - checksumming
- * - correct rate denom/nom and sample_mul
- * - correct timestamp handling
+ * - optimal timestamp handling
  * - index writing
  * - info and index packet reading support
  * - startcode searching for broken streams
  * - subpacket support
- * - handling of codec specific headers
 */
 
 //#define DEBUG 1
 
 #include "avformat.h"
 #include "mpegaudio.h"
+#include "avi.h"
 
 //from /dev/random
 
@@ -62,7 +61,6 @@ static uint64_t get_v(ByteIOContext *bc)
 {
     uint64_t val = 0;
 
-//    for (; bytes_left(s)*8 > 0; )
     for(; bytes_left(bc) > 0; )
     {
        int tmp = get_byte(bc);
@@ -92,16 +90,25 @@ static int get_b(ByteIOContext *bc, char *data, int maxlen)
     len = get_v(bc);
     for (i = 0; i < len && i < maxlen; i++)
        data[i] = get_byte(bc);
-    if (i < len)
-    {
-       len = i;
-       for (i = 0; i < len; i++)
-           get_byte(bc);
-    }
+    /* skip remaining bytes */
+    url_fskip(bc, len-i);
 
     return 0;
 }
 
+static int get_bi(ByteIOContext *bc)
+{
+   int i, len, val = 0;
+    
+    len = get_v(bc);
+    for (i = 0; i < len && i <= 4; i++)
+        val |= get_byte(bc) << (i * 8);
+    /* skip remaining bytes */
+    url_fskip(bc, len-i);
+
+    return val;
+}
+
 static int get_packetheader(NUTContext *nut, ByteIOContext *bc)
 {
     nut->curr_frame_start = url_ftell(bc);
@@ -126,6 +133,7 @@ static int get_length(uint64_t val){
     return 7; //not reached
 }
 
+#ifdef CONFIG_ENCODERS
 static int put_v(ByteIOContext *bc, uint64_t val)
 {
     int i;
@@ -167,6 +175,13 @@ static int put_b(ByteIOContext *bc, char *data, int len)
     return 0;
 }
 
+static int put_bi(ByteIOContext *bc, int val)
+{
+    put_v(bc, 4);
+    put_le32(bc, val);
+    return 0;
+}
+
 static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size)
 {
     put_flush_packet(bc);
@@ -209,22 +224,12 @@ static int nut_write_header(AVFormatContext *s)
     ByteIOContext *bc = &s->pb;
     AVCodecContext *codec;
     int i;
-    int stream_length = 0;
 
-    for (i = 0; i < s->nb_streams; i++)
-    {
-       if (stream_length < (s->streams[i]->duration * (AV_TIME_BASE / 1000)))
-           stream_length = s->streams[i]->duration * (AV_TIME_BASE / 1000);
-    }
-
-    put_packetheader(nut, bc, 120);
-    
     /* main header */
     put_be64(bc, MAIN_STARTCODE);
+    put_packetheader(nut, bc, 120);
     put_v(bc, 0); /* version */
     put_v(bc, s->nb_streams);
-    put_v(bc, 0); /* file size */
-    put_v(bc, stream_length); /* len in msec */
     put_be32(bc, 0); /* FIXME: checksum */
     
     update_packetheader(nut, bc, 0);
@@ -232,33 +237,42 @@ static int nut_write_header(AVFormatContext *s)
     /* stream headers */
     for (i = 0; i < s->nb_streams; i++)
     {
+       int nom, denom;
+
        codec = &s->streams[i]->codec;
        
-       put_packetheader(nut, bc, 120);
        put_be64(bc, STREAM_STARTCODE);
+       put_packetheader(nut, bc, 120);
        put_v(bc, i /*s->streams[i]->index*/);
        put_v(bc, (codec->codec_type == CODEC_TYPE_AUDIO) ? 32 : 0);
        if (codec->codec_tag)
-           put_b(bc, &codec->codec_tag, 4);
+           put_bi(bc, codec->codec_tag);
        else if (codec->codec_type == CODEC_TYPE_VIDEO)
        {
            int tmp = codec_get_bmp_tag(codec->codec_id);
-           put_b(bc, &tmp, 4);
-//         put_v(bc, 4); /* len */
-//         put_be32(bc, codec_get_bmp_tag(codec->codec_id));
+           put_bi(bc, tmp);
        }
        else if (codec->codec_type == CODEC_TYPE_AUDIO)
        {
            int tmp = codec_get_wav_tag(codec->codec_id);
-           put_b(bc, &tmp, 4);
-//         put_v(bc, 4); /* len */
-//         put_be32(bc, codec_get_wav_tag(codec->codec_id));
+           put_bi(bc, tmp);
+       }
+
+       if (codec->codec_type == CODEC_TYPE_VIDEO)
+       {
+           nom = codec->frame_rate;
+           denom = codec->frame_rate_base;
+       }
+       else
+       {
+           nom = codec->sample_rate/8;
+           denom = 8;
        }
        put_v(bc, codec->bit_rate);
        put_v(bc, 0); /* no language code */
-       put_v(bc, codec->frame_rate_base);
-       put_v(bc, codec->frame_rate);
-       put_v(bc, 0); /* timestamp_shift */
+       put_v(bc, nom);
+       put_v(bc, denom);
+       put_v(bc, 0); /* msb timestamp_shift */
        put_v(bc, 0); /* shuffle type */
        put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */
        
@@ -267,7 +281,7 @@ static int nut_write_header(AVFormatContext *s)
        switch(codec->codec_type)
        {
            case CODEC_TYPE_AUDIO:
-               put_v(bc, codec->sample_rate / (double)(codec->frame_rate_base / codec->frame_rate));
+               put_v(bc, (codec->sample_rate * denom) / nom);
                put_v(bc, codec->channels);
                put_be32(bc, 0); /* FIXME: checksum */
                break;
@@ -279,15 +293,17 @@ static int nut_write_header(AVFormatContext *s)
                put_v(bc, 0); /* csp type -- unknown */
                put_be32(bc, 0); /* FIXME: checksum */
                break;
+            default:
+                break;
        }
         update_packetheader(nut, bc, 0);
     }
 
 #if 0
     /* info header */
+    put_be64(bc, INFO_STARTCODE);
     put_packetheader(nut, bc, 16+strlen(s->author)+strlen(s->title)+
         strlen(s->comment)+strlen(s->copyright)); 
-    put_be64(bc, INFO_STARTCODE);
     if (s->author[0])
     {
         put_v(bc, 5); /* type */
@@ -324,22 +340,19 @@ static int nut_write_header(AVFormatContext *s)
 }
 
 static int nut_write_packet(AVFormatContext *s, int stream_index, 
-                           uint8_t *buf, int size, int force_pts)
+                           const uint8_t *buf, int size, int64_t pts)
 {
     NUTContext *nut = s->priv_data;
     ByteIOContext *bc = &s->pb;
     int key_frame = 0;
-    int flags, size2;
+    int flags;
     AVCodecContext *enc;
 
     if (stream_index > s->nb_streams)
        return 1;
 
     enc = &s->streams[stream_index]->codec;
-    if (enc->codec_type == CODEC_TYPE_VIDEO)
-       key_frame = enc->coded_frame->key_frame;
-
-    put_packetheader(nut, bc, size+(key_frame?8:0)+20);
+    key_frame = enc->coded_frame->key_frame;
 
     if (key_frame)
        put_be64(bc, KEYFRAME_STARTCODE);
@@ -352,8 +365,10 @@ static int nut_write_packet(AVFormatContext *s, int stream_index,
     flags<<=1; flags|=0; //reserved
 
     put_byte(bc, flags);
+
+    put_packetheader(nut, bc, size+20);
     put_v(bc, stream_index);
-    put_s(bc, force_pts); /* lsb_timestamp */
+    put_s(bc, pts); /* lsb_timestamp */
     update_packetheader(nut, bc, size);
     
     put_buffer(bc, buf, size);
@@ -365,7 +380,6 @@ static int nut_write_packet(AVFormatContext *s, int stream_index,
 
 static int nut_write_trailer(AVFormatContext *s)
 {
-    NUTContext *nut = s->priv_data;
     ByteIOContext *bc = &s->pb;
 #if 0
     int i;
@@ -374,8 +388,8 @@ static int nut_write_trailer(AVFormatContext *s)
 
     for (i = 0; s->nb_streams; i++)
     {
-       put_packetheader(nut, bc, 64);
        put_be64(bc, INDEX_STARTCODE);
+       put_packetheader(nut, bc, 64);
        put_v(bc, s->streams[i]->id);
        put_v(bc, ...);
        put_be32(bc, 0); /* FIXME: checksum */
@@ -387,6 +401,7 @@ static int nut_write_trailer(AVFormatContext *s)
 
     return 0;
 }
+#endif //CONFIG_ENCODERS
 
 static int nut_probe(AVProbeData *p)
 {
@@ -397,7 +412,6 @@ static int nut_probe(AVProbeData *p)
     for (i = 0; i < p->buf_size; i++) {
         int c = p->buf[i];
         code = (code << 8) | c;
-        code &= 0xFFFFFFFFFFFFFFFFULL;
         if (code == MAIN_STARTCODE)
             return AVPROBE_SCORE_MAX;
     }
@@ -412,20 +426,16 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
     int cur_stream, nb_streams;
     
     /* main header */
-    get_packetheader(nut, bc);
     tmp = get_be64(bc);
     if (tmp != MAIN_STARTCODE)
        fprintf(stderr, "damaged? startcode!=1 (%Ld)\n", tmp);
+    get_packetheader(nut, bc);
     
     tmp = get_v(bc);
     if (tmp != 0)
        fprintf(stderr, "bad version (%Ld)\n", tmp);
     
     nb_streams = get_v(bc);
-    
-    s->file_size = get_v(bc);
-    s->duration = get_v(bc) / (AV_TIME_BASE / 1000);
-
     get_be32(bc); /* checkusm */
     
     s->bit_rate = 0;
@@ -433,33 +443,28 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
     /* stream header */
     for (cur_stream = 0; cur_stream < nb_streams; cur_stream++)
     {
-       int class;
+       int class, nom, denom;
        AVStream *st;
        
-       get_packetheader(nut, bc);
        tmp = get_be64(bc);
        if (tmp != STREAM_STARTCODE)
            fprintf(stderr, "damaged? startcode!=1 (%Ld)\n", tmp);
+       get_packetheader(nut, bc);
        st = av_new_stream(s, get_v(bc));
        if (!st)
            return AVERROR_NOMEM;
        class = get_v(bc);
+       tmp = get_bi(bc);
        switch(class)
        {
            case 0:
                st->codec.codec_type = CODEC_TYPE_VIDEO;
-//             get_v(bc);
-//             tmp = get_be32(bc);
-               get_b(bc, (char*)&tmp, 4);
                st->codec.codec_id = codec_get_bmp_id(tmp);
                if (st->codec.codec_id == CODEC_ID_NONE)
                    fprintf(stderr, "Unknown codec?!\n");
                break;
            case 32:
                st->codec.codec_type = CODEC_TYPE_AUDIO;
-//             tmp = get_v(bc);
-//             tmp = get_be32(bc);
-               get_b(bc, (char*)&tmp, 4);
                st->codec.codec_id = codec_get_wav_id(tmp);
                if (st->codec.codec_id == CODEC_ID_NONE)
                    fprintf(stderr, "Unknown codec?!\n");
@@ -469,16 +474,16 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
                return -1;
        }
        s->bit_rate += get_v(bc);
-       tmp = get_v(bc); /* language code */
-       while(tmp--)
-           get_byte(bc);
-       st->codec.frame_rate_base = get_v(bc);
-       st->codec.frame_rate = get_v(bc);
+       get_b(bc, NULL, 0); /* language code */
+       nom = get_v(bc);
+       denom = get_v(bc);
        get_v(bc); /* FIXME: msb timestamp base */
        get_v(bc); /* shuffle type */
        get_byte(bc); /* flags */
-       
-       get_v(bc); /* FIXME: codec specific data headers */
+
+       /* codec specific data headers */
+       while(get_v(bc) != 0)
+           url_fskip(bc, get_v(bc));
        
        if (class == 0) /* VIDEO */
        {
@@ -487,13 +492,16 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
            get_v(bc); /* aspected w */
            get_v(bc); /* aspected h */
            get_v(bc); /* csp type */
-           get_le32(bc); /* checksum */
+           get_be32(bc); /* checksum */
+
+           st->codec.frame_rate = nom;
+           st->codec.frame_rate_base = denom;
        }
        if (class == 32) /* AUDIO */
        {
-           st->codec.sample_rate = get_v(bc) * (double)(st->codec.frame_rate_base / st->codec.frame_rate);
+           st->codec.sample_rate = (get_v(bc) * nom) / denom;
            st->codec.channels = get_v(bc);
-           get_le32(bc); /* checksum */
+           get_be32(bc); /* checksum */
        }
     }    
     
@@ -508,7 +516,6 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
     int key_frame = 0;
     uint64_t tmp;
 
-    get_packetheader(nut, bc);
 
     if (url_feof(bc))
        return -1;
@@ -527,6 +534,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
        else
            fprintf(stderr, "error in zero bit / startcode %LX\n", tmp);
     }
+    get_packetheader(nut, bc);
 #if 0
     if (((tmp & 0x60)>>5) > 3) /* priority <= 3 */
        fprintf(stderr, "sanity check failed!\n");
@@ -562,6 +570,7 @@ static AVInputFormat nut_iformat = {
     .extensions = "nut",
 };
 
+#ifdef CONFIG_ENCODERS
 static AVOutputFormat nut_oformat = {
     "nut",
     "nut format",
@@ -571,19 +580,22 @@ static AVOutputFormat nut_oformat = {
 #ifdef CONFIG_VORBIS
     CODEC_ID_VORBIS,
 #elif defined(CONFIG_MP3LAME)
-    CODEC_ID_MP3LAME,
+    CODEC_ID_MP3,
 #else
-    CODEC_ID_AC3,
+    CODEC_ID_MP2, /* AC3 needs liba52 decoder */
 #endif
     CODEC_ID_MPEG4,
     nut_write_header,
     nut_write_packet,
     nut_write_trailer,
 };
+#endif //CONFIG_ENCODERS
 
 int nut_init(void)
 {
     av_register_input_format(&nut_iformat);
+#ifdef CONFIG_ENCODERS
     av_register_output_format(&nut_oformat);
+#endif //CONFIG_ENCODERS
     return 0;
 }