suppressed mpeg demux mess - use now dynamic stream creation api
authorFabrice Bellard <fabrice@bellard.org>
Mon, 20 May 2002 16:29:40 +0000 (16:29 +0000)
committerFabrice Bellard <fabrice@bellard.org>
Mon, 20 May 2002 16:29:40 +0000 (16:29 +0000)
Originally committed as revision 546 to svn://svn.ffmpeg.org/ffmpeg/trunk

libav/mpeg.c

index f14ce0a..902e6bf 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Output a MPEG1 multiplexed video/audio stream
- * Copyright (c) 2000 Gerard Lantau.
+ * MPEG1 mux/demux
+ * Copyright (c) 2000, 2001, 2002 Gerard Lantau.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -62,8 +62,6 @@ typedef struct {
 #define AUDIO_ID 0xc0
 #define VIDEO_ID 0xe0
 
-static int mpeg_mux_check_packet(AVFormatContext *s, int *size);
-
 static int put_pack_header(AVFormatContext *ctx, 
                            UINT8 *buf, INT64 timestamp)
 {
@@ -150,15 +148,11 @@ static int put_system_header(AVFormatContext *ctx, UINT8 *buf)
 
 static int mpeg_mux_init(AVFormatContext *ctx)
 {
-    MpegMuxContext *s;
+    MpegMuxContext *s = ctx->priv_data;
     int bitrate, i, mpa_id, mpv_id, ac3_id;
     AVStream *st;
     StreamInfo *stream;
 
-    s = av_mallocz(sizeof(MpegMuxContext));
-    if (!s)
-        return -1;
-    ctx->priv_data = s;
     s->packet_number = 0;
 
     /* XXX: hardcoded */
@@ -252,7 +246,6 @@ static int mpeg_mux_init(AVFormatContext *ctx)
     for(i=0;i<ctx->nb_streams;i++) {
         av_free(ctx->streams[i]->priv_data);
     }
-    av_free(s);
     return -ENOMEM;
 }
 
@@ -409,9 +402,37 @@ static int mpeg_mux_end(AVFormatContext *ctx)
 
 #define MAX_SYNC_SIZE 100000
 
+static int mpegps_probe(AVProbeData *p)
+{
+    int code, c, i;
+    code = 0xff;
+
+    /* we search the first start code. If it is a packet start code,
+       then we decide it is mpeg ps. We do not send highest value to
+       give a chance to mpegts */
+    for(i=0;i<p->buf_size;i++) {
+        c = p->buf[i];
+        code = (code << 8) | c;
+        if ((code & 0xffffff00) == 0x100) {
+            if (code == PACK_START_CODE ||
+                code == SYSTEM_HEADER_START_CODE ||
+                (code >= 0x1e0 && code <= 0x1ef) ||
+                (code >= 0x1c0 && code <= 0x1df) ||
+                code == PRIVATE_STREAM_2 ||
+                code == PROGRAM_STREAM_MAP ||
+                code == PRIVATE_STREAM_1 ||
+                code == PADDING_STREAM)
+                return AVPROBE_SCORE_MAX - 1;
+            else
+                return 0;
+        }
+    }
+    return 0;
+}
+
+
 typedef struct MpegDemuxContext {
     int header_state;
-    int mux_rate; /* 50 byte/s unit */
 } MpegDemuxContext;
 
 static int find_start_code(ByteIOContext *pb, int *size_ptr, 
@@ -441,188 +462,12 @@ static int find_start_code(ByteIOContext *pb, int *size_ptr,
     return val;
 }
 
-static int check_stream_id(AVFormatContext *s, int c_id)
-{
-    AVStream *st;
-    int i;
-    
-    for(i = 0;i < s->nb_streams;i++) {
-        st = s->streams[i];
-        if (st && st->id == c_id)
-            return 1;
-    }
-    return 0;   
-}
-
-static int mpeg_mux_read_header(AVFormatContext *s,
-                                AVFormatParameters *ap)
+static int mpegps_read_header(AVFormatContext *s,
+                                  AVFormatParameters *ap)
 {
-    MpegDemuxContext *m;
-    int size, startcode, c, rate_bound, audio_bound, video_bound, mux_rate, val;
-    int codec_id, n, i, type, seems_dvd;
-    AVStream *st;
-    offset_t start_pos;
-
-    m = av_mallocz(sizeof(MpegDemuxContext));
-    if (!m)
-        return -ENOMEM;
-    s->priv_data = m;
-    seems_dvd = 0;
-    
-    /* search first pack header */
+    MpegDemuxContext *m = s->priv_data;
     m->header_state = 0xff;
-    size = MAX_SYNC_SIZE;
-    start_pos = url_ftell(&s->pb); /* remember this pos */
-    for(;;) {
-        /*while (size > 0) {
-            startcode = find_start_code(&s->pb, &size, &m->header_state);
-            if (startcode == PACK_START_CODE)
-                goto found;
-        }*/
-        /* System Header not found find streams searching through file */
-        //fprintf(stderr,"libav: MPEG-PS System Header not found!\n");
-        url_fseek(&s->pb, start_pos, SEEK_SET);
-        video_bound = 0;
-        audio_bound = 0;
-        c = 0;
-        s->nb_streams = 0;
-        //size = 15*MAX_SYNC_SIZE;
-        while (size > 0) {
-            type = 0;
-            codec_id = 0;
-            n = 0;
-            startcode = find_start_code(&s->pb, &size, &m->header_state);
-            //fprintf(stderr,"\nstartcode: %x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
-            if (startcode == 0x1bd) {
-                url_fseek(&s->pb, -4, SEEK_CUR);
-                size += 4;
-                startcode = mpeg_mux_check_packet(s, &size);
-                //fprintf(stderr,"\nstartcode: %x pos=0x%Lx\n", startcode, url_ftell(&s->pb));
-                if (startcode >= 0x80 && startcode <= 0x9f && !check_stream_id(s, startcode)) {
-                    //fprintf(stderr,"Found AC3 stream ID: 0x%x\n", startcode);
-                    type = CODEC_TYPE_AUDIO;
-                    codec_id = CODEC_ID_AC3;
-                    audio_bound++;
-                    n = 1;
-                    c = startcode;
-                    seems_dvd = 1;
-                }    
-            } else if (startcode == 0x1e0 && !check_stream_id(s, startcode)) {
-                //fprintf(stderr,"Found MPEGVIDEO stream ID: 0x%x\n", startcode);
-                type = CODEC_TYPE_VIDEO;
-                codec_id = CODEC_ID_MPEG1VIDEO;
-                n = 1;
-                c = startcode;
-                video_bound++;
-            } else if (startcode >= 0x1c0 && startcode <= 0x1df && !seems_dvd && !check_stream_id(s, startcode)) {
-                //fprintf(stderr,"Found MPEGAUDIO stream ID: 0x%x\n", startcode);
-                type = CODEC_TYPE_AUDIO;
-                codec_id = CODEC_ID_MP2;
-                n = 1;
-                c = startcode;
-                audio_bound++;
-            } 
-            for(i=0;i<n;i++) {
-                st = av_mallocz(sizeof(AVStream));
-                if (!st)
-                    return -ENOMEM;
-                s->streams[s->nb_streams++] = st;
-                st->id = c;
-                st->codec.codec_type = type;
-                st->codec.codec_id = codec_id;
-            }
-        }
-        if (video_bound || audio_bound) {
-            url_fseek(&s->pb, start_pos, SEEK_SET);
-            return 0;
-        } else
-            return -ENODATA;
-    found:
-        /* search system header just after pack header */
-        /* parse pack header */
-        get_byte(&s->pb); /* ts1 */
-        get_be16(&s->pb); /* ts2 */
-        get_be16(&s->pb); /* ts3 */
-
-        mux_rate = get_byte(&s->pb) << 16; 
-        mux_rate |= get_byte(&s->pb) << 8;
-        mux_rate |= get_byte(&s->pb);
-        mux_rate &= (1 << 22) - 1;
-        m->mux_rate = mux_rate;
-
-        startcode = find_start_code(&s->pb, &size, &m->header_state);
-        if (startcode == SYSTEM_HEADER_START_CODE)
-            break;
-    }
-    size = get_be16(&s->pb);
-    rate_bound = get_byte(&s->pb) << 16;
-    rate_bound |= get_byte(&s->pb) << 8;
-    rate_bound |= get_byte(&s->pb);
-    rate_bound = (rate_bound >> 1) & ((1 << 22) - 1);
-    audio_bound = get_byte(&s->pb) >> 2;
-    video_bound = get_byte(&s->pb) & 0x1f;
-    get_byte(&s->pb); /* reserved byte */
-#if 0
-    printf("mux_rate=%d kbit/s\n", (m->mux_rate * 50 * 8) / 1000);
-    printf("rate_bound=%d\n", rate_bound);
-    printf("audio_bound=%d\n", audio_bound);
-    printf("video_bound=%d\n", video_bound);
-#endif
-    size -= 6;
-    s->nb_streams = 0;
-    while (size > 0) {
-        c = get_byte(&s->pb);
-        size--;
-        if ((c & 0x80) == 0)
-            break;
-        val = get_be16(&s->pb);
-        size -= 2;
-        if (c >= 0xc0 && c <= 0xdf) {
-            /* mpeg audio stream */
-            type = CODEC_TYPE_AUDIO;
-            codec_id = CODEC_ID_MP2;
-            n = 1;
-            c = c | 0x100;
-        } else if (c >= 0xe0 && c <= 0xef) {
-            type = CODEC_TYPE_VIDEO;
-            codec_id = CODEC_ID_MPEG1VIDEO;
-            n = 1;
-            c = c | 0x100;
-        } else if (c == 0xb8) {
-            /* all audio streams */
-            /* XXX: hack for DVD: we force AC3, although we do not
-               know that this codec will be used */
-            type = CODEC_TYPE_AUDIO;
-            codec_id = CODEC_ID_AC3;
-            /* XXX: Another hack for DVD: it seems, that AC3 streams
-               aren't signaled on audio_bound on some DVDs (Matrix) */
-            if (audio_bound == 0)
-               audio_bound++;
-            n = audio_bound;
-            c = 0x80;
-            //c = 0x1c0;
-        } else if (c == 0xb9) {
-            /* all video streams */
-            type = CODEC_TYPE_VIDEO;
-            codec_id = CODEC_ID_MPEG1VIDEO;
-            n = video_bound;
-            c = 0x1e0;
-        } else {
-            type = 0;
-            codec_id = 0;
-            n = 0;
-        }
-        for(i=0;i<n;i++) {
-            st = av_mallocz(sizeof(AVStream));
-            if (!st)
-                return -ENOMEM;
-            s->streams[s->nb_streams++] = st;
-            st->id = c + i;
-            st->codec.codec_type = type;
-            st->codec.codec_id = codec_id;
-        }
-    }
-
+    /* no need to do more */
     return 0;
 }
 
@@ -641,12 +486,12 @@ static INT64 get_pts(ByteIOContext *pb, int c)
     return pts;
 }
 
-static int mpeg_mux_read_packet(AVFormatContext *s,
-                                AVPacket *pkt)
+static int mpegps_read_packet(AVFormatContext *s,
+                                  AVPacket *pkt)
 {
     MpegDemuxContext *m = s->priv_data;
     AVStream *st;
-    int len, size, startcode, i, c, flags, header_len;
+    int len, size, startcode, i, c, flags, header_len, type, codec_id;
     INT64 pts, dts;
 
     /* next start code (should be immediately after */
@@ -745,149 +590,69 @@ static int mpeg_mux_read_packet(AVFormatContext *s,
         if (st->id == startcode)
             goto found;
     }
-    /* skip packet */
-    url_fskip(&s->pb, len);
-    goto redo;
+    /* no stream found: add a new stream */
+    st = av_new_stream(s, startcode);
+    if (!st) 
+        goto skip;
+    if (startcode >= 0x1e0 && startcode <= 0x1ef) {
+        type = CODEC_TYPE_VIDEO;
+        codec_id = CODEC_ID_MPEG1VIDEO;
+    } else if (startcode >= 0x1c0 && startcode <= 0x1df) {
+        type = CODEC_TYPE_AUDIO;
+        codec_id = CODEC_ID_MP2;
+    } else if (startcode >= 0x80 && startcode <= 0x9f) {
+        type = CODEC_TYPE_AUDIO;
+        codec_id = CODEC_ID_AC3;
+    } else {
+    skip:
+        /* skip packet */
+        url_fskip(&s->pb, len);
+        goto redo;
+    }
+    st->codec.codec_type = type;
+    st->codec.codec_id = codec_id;
  found:
     av_new_packet(pkt, len);
     //printf("\nRead Packet ID: %x PTS: %f Size: %d", startcode,
     //       (float)pts/90000, len);
     get_buffer(&s->pb, pkt->data, pkt->size);
     pkt->pts = pts;
-    pkt->stream_index = i;
+    pkt->stream_index = st->index;
     return 0;
 }
 
-static int mpeg_mux_check_packet(AVFormatContext *s, int *size)
-{
-    MpegDemuxContext *m = s->priv_data;
-    int len, startcode, c, n, flags, header_len;
-    INT64 pts, dts;
-
-    /* next start code (should be immediately after */
- redo:
-    m->header_state = 0xff;
-    startcode = find_start_code(&s->pb, size, &m->header_state);
-    
-    if (startcode < 0)
-        return -EIO;
-    if (startcode == PACK_START_CODE)
-        goto redo;
-    if (startcode == SYSTEM_HEADER_START_CODE)
-        goto redo;
-    if (startcode == PADDING_STREAM ||
-        startcode == PRIVATE_STREAM_2) {
-        /* skip them */
-        len = get_be16(&s->pb);
-        url_fskip(&s->pb, len);
-        goto redo;
-    }
-    /* find matching stream */
-    if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
-          (startcode >= 0x1e0 && startcode <= 0x1ef) ||
-          (startcode == 0x1bd)))
-        goto redo;
-
-    n = *size;
-    len = get_be16(&s->pb);
-    n -= 2;
-    pts = 0;
-    dts = 0;
-    /* stuffing */
-    for(;;) {
-        c = get_byte(&s->pb);
-        len--;
-        n--;
-        /* XXX: for mpeg1, should test only bit 7 */
-        if (c != 0xff) 
-            break;
-    }
-    if ((c & 0xc0) == 0x40) {
-        /* buffer scale & size */
-        get_byte(&s->pb);
-        c = get_byte(&s->pb);
-        len -= 2;
-        n -= 2;
-    }
-    if ((c & 0xf0) == 0x20) {
-        pts = get_pts(&s->pb, c);
-        len -= 4;
-        n -= 4;
-        dts = pts;
-    } else if ((c & 0xf0) == 0x30) {
-        pts = get_pts(&s->pb, c);
-        dts = get_pts(&s->pb, -1);
-        len -= 9;
-        n -= 9;
-    } else if ((c & 0xc0) == 0x80) {
-        /* mpeg 2 PES */
-        if ((c & 0x30) != 0) {
-            fprintf(stderr, "Encrypted multiplex not handled\n");
-            return -EIO;
-        }
-        flags = get_byte(&s->pb);
-        header_len = get_byte(&s->pb);
-        len -= 2;
-        n -= 2;
-        if (header_len > len)
-            goto redo;
-        if ((flags & 0xc0) == 0x40) {
-            pts = get_pts(&s->pb, -1);
-            dts = pts;
-            header_len -= 5;
-            len -= 5;
-            n -= 5;
-        } if ((flags & 0xc0) == 0xc0) {
-            pts = get_pts(&s->pb, -1);
-            dts = get_pts(&s->pb, -1);
-            header_len -= 10;
-            len -= 10;
-            n -= 10;
-        }
-        len -= header_len;
-        n -= header_len;
-        while (header_len > 0) {
-            get_byte(&s->pb);
-            header_len--;
-        }
-    }
-    if (startcode == 0x1bd) {
-        startcode = get_byte(&s->pb);
-        len--;
-        n--;
-        if (startcode >= 0x80 && startcode <= 0xbf) {
-            /* audio: skip header */
-            get_byte(&s->pb);
-            get_byte(&s->pb);
-            get_byte(&s->pb);
-            len -= 3;
-            n -= 3;
-        }
-    }
-    *size = n;
-    return startcode;
-}
-
-
-static int mpeg_mux_read_close(AVFormatContext *s)
+static int mpegps_read_close(AVFormatContext *s)
 {
-    MpegDemuxContext *m = s->priv_data;
-    av_free(m);
     return 0;
 }
 
-AVFormat mpeg_mux_format = {
+static AVOutputFormat mpegps_mux = {
     "mpeg",
-    "MPEG multiplex format",
+    "MPEG PS format",
     "video/x-mpeg",
     "mpg,mpeg,vob",
+    sizeof(MpegMuxContext),
     CODEC_ID_MP2,
     CODEC_ID_MPEG1VIDEO,
     mpeg_mux_init,
     mpeg_mux_write_packet,
     mpeg_mux_end,
+};
 
-    mpeg_mux_read_header,
-    mpeg_mux_read_packet,
-    mpeg_mux_read_close,
+static AVInputFormat mpegps_demux = {
+    "mpeg",
+    "MPEG PS format",
+    sizeof(MpegDemuxContext),
+    mpegps_probe,
+    mpegps_read_header,
+    mpegps_read_packet,
+    mpegps_read_close,
+    flags: AVFMT_NOHEADER,
 };
+
+int mpegps_init(void)
+{
+    av_register_output_format(&mpegps_mux);
+    av_register_input_format(&mpegps_demux);
+    return 0;
+}