Skip to content
Snippets Groups Projects
mpeg.c 55.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Fabrice Bellard's avatar
    Fabrice Bellard committed
    /*
    
     * Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 2 of the License, or (at your option) any later version.
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * This library is distributed in the hope that it will be useful,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
    
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * Lesser General Public License for more details.
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
    
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     */
    #include "avformat.h"
    
    #include "bitstream.h"
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    #define MAX_PAYLOAD_SIZE 4096
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    //#define DEBUG_SEEK
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    #undef NDEBUG
    #include <assert.h>
    
    
    typedef struct PacketDesc {
        int64_t pts;
        int64_t dts;
        int size;
        int unwritten_size;
        int flags;
        struct PacketDesc *next;
    } PacketDesc;
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    typedef struct {
    
        FifoBuffer fifo;
    
        uint8_t id;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        int max_buffer_size; /* in bytes */
    
        int buffer_index;
        PacketDesc *predecode_packet;
        PacketDesc *premux_packet;
        PacketDesc **next_packet;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        int packet_number;
    
        uint8_t lpcm_header[3];
        int lpcm_align;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    } StreamInfo;
    
    typedef struct {
        int packet_size; /* required packet size */
        int packet_number;
        int pack_header_freq;     /* frequency (in packets^-1) at which we send pack headers */
        int system_header_freq;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        int mux_rate; /* bitrate in units of 50 bytes/s */
        /* stream info */
        int audio_bound;
        int video_bound;
    
        int64_t last_scr; /* current system clock */
    
        double vcd_padding_bitrate; //FIXME floats
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    } MpegMuxContext;
    
    #define PACK_START_CODE             ((unsigned int)0x000001ba)
    #define SYSTEM_HEADER_START_CODE    ((unsigned int)0x000001bb)
    
    #define SEQUENCE_END_CODE           ((unsigned int)0x000001b7)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    #define PACKET_START_CODE_MASK      ((unsigned int)0xffffff00)
    #define PACKET_START_CODE_PREFIX    ((unsigned int)0x00000100)
    #define ISO_11172_END_CODE          ((unsigned int)0x000001b9)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /* mpeg2 */
    #define PROGRAM_STREAM_MAP 0x1bc
    #define PRIVATE_STREAM_1   0x1bd
    #define PADDING_STREAM     0x1be
    #define PRIVATE_STREAM_2   0x1bf
    
    
    #define AUDIO_ID 0xc0
    #define VIDEO_ID 0xe0
    
    #define AC3_ID   0x80
    
    #define LPCM_ID  0xa0
    
    #define SUB_ID   0x20
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    #define STREAM_TYPE_VIDEO_MPEG1     0x01
    #define STREAM_TYPE_VIDEO_MPEG2     0x02
    #define STREAM_TYPE_AUDIO_MPEG1     0x03
    #define STREAM_TYPE_AUDIO_MPEG2     0x04
    #define STREAM_TYPE_PRIVATE_SECTION 0x05
    #define STREAM_TYPE_PRIVATE_DATA    0x06
    #define STREAM_TYPE_AUDIO_AAC       0x0f
    #define STREAM_TYPE_VIDEO_MPEG4     0x10
    #define STREAM_TYPE_VIDEO_H264      0x1b
    
    #define STREAM_TYPE_AUDIO_AC3       0x81
    #define STREAM_TYPE_AUDIO_DTS       0x8a
    
    
    static const int lpcm_freq_tab[4] = { 48000, 96000, 44100, 32000 };
    
    
    Falk Hüffner's avatar
    Falk Hüffner committed
    static AVOutputFormat mpeg1system_mux;
    static AVOutputFormat mpeg1vcd_mux;
    static AVOutputFormat mpeg2vob_mux;
    static AVOutputFormat mpeg2svcd_mux;
    
    static int put_pack_header(AVFormatContext *ctx,
    
                               uint8_t *buf, int64_t timestamp)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        MpegMuxContext *s = ctx->priv_data;
        PutBitContext pb;
    
    Alex Beregszaszi's avatar
    Alex Beregszaszi committed
        init_put_bits(&pb, buf, 128);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        put_bits(&pb, 32, PACK_START_CODE);
    
        put_bits(&pb, 3, (uint32_t)((timestamp >> 30) & 0x07));
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        put_bits(&pb, 1, 1);
    
        put_bits(&pb, 15, (uint32_t)((timestamp >> 15) & 0x7fff));
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        put_bits(&pb, 1, 1);
    
        put_bits(&pb, 15, (uint32_t)((timestamp) & 0x7fff));
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        put_bits(&pb, 1, 1);
    
        if (s->is_mpeg2) {
            /* clock extension */
            put_bits(&pb, 9, 0);
        }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        put_bits(&pb, 1, 1);
        put_bits(&pb, 22, s->mux_rate);
        put_bits(&pb, 1, 1);
    
            put_bits(&pb, 5, 0x1f); /* reserved */
            put_bits(&pb, 3, 0); /* stuffing length */
        }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        flush_put_bits(&pb);
    
    static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_stream_id)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        MpegMuxContext *s = ctx->priv_data;
    
        int size, i, private_stream_coded, id;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        PutBitContext pb;
    
    
    Alex Beregszaszi's avatar
    Alex Beregszaszi committed
        init_put_bits(&pb, buf, 128);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        put_bits(&pb, 32, SYSTEM_HEADER_START_CODE);
        put_bits(&pb, 16, 0);
        put_bits(&pb, 1, 1);
    
        put_bits(&pb, 22, s->mux_rate); /* maximum bit rate of the multiplexed stream */
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        put_bits(&pb, 1, 1); /* marker */
    
        if (s->is_vcd && only_for_stream_id==VIDEO_ID) {
            /* This header applies only to the video stream (see VCD standard p. IV-7)*/
            put_bits(&pb, 6, 0);
        } else
            put_bits(&pb, 6, s->audio_bound);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
        if (s->is_vcd) {
            /* see VCD standard, p. IV-7*/
    
            put_bits(&pb, 1, 0);
    
            put_bits(&pb, 1, 1);
        } else {
            put_bits(&pb, 1, 0); /* variable bitrate*/
            put_bits(&pb, 1, 0); /* non constrainted bit stream */
        }
    
            /* see VCD standard p IV-7 */
            put_bits(&pb, 1, 1); /* audio locked */
            put_bits(&pb, 1, 1); /* video locked */
        } else {
            put_bits(&pb, 1, 0); /* audio locked */
            put_bits(&pb, 1, 0); /* video locked */
        }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        put_bits(&pb, 1, 1); /* marker */
    
    
        if (s->is_vcd && only_for_stream_id==AUDIO_ID) {
            /* This header applies only to the audio stream (see VCD standard p. IV-7)*/
            put_bits(&pb, 5, 0);
        } else
            put_bits(&pb, 5, s->video_bound);
    
        if (s->is_dvd) {
            put_bits(&pb, 1, 0);    /* packet_rate_restriction_flag */
            put_bits(&pb, 7, 0x7f); /* reserved byte */
        } else
            put_bits(&pb, 8, 0xff); /* reserved byte */
    
        id (0xB9) video, maximum P-STD for stream 0xE0. (P-STD_buffer_bound_scale = 1)
        id (0xB8) audio, maximum P-STD for any MPEG audio (0xC0 to 0xC7) streams. If there are none set to 4096 (32x128). (P-STD_buffer_bound_scale = 0)
        id (0xBD) private stream 1 (audio other than MPEG and subpictures). (P-STD_buffer_bound_scale = 1)
    
        id (0xBF) private stream 2, NAV packs, set to 2x1024. */
        if (s->is_dvd) {
    
            int P_STD_max_video = 0;
            int P_STD_max_mpeg_audio = 0;
            int P_STD_max_mpeg_PS1 = 0;
    
            for(i=0;i<ctx->nb_streams;i++) {
                StreamInfo *stream = ctx->streams[i]->priv_data;
    
                if (id == 0xbd && stream->max_buffer_size > P_STD_max_mpeg_PS1) {
                    P_STD_max_mpeg_PS1 = stream->max_buffer_size;
                } else if (id >= 0xc0 && id <= 0xc7 && stream->max_buffer_size > P_STD_max_mpeg_audio) {
                    P_STD_max_mpeg_audio = stream->max_buffer_size;
                } else if (id == 0xe0 && stream->max_buffer_size > P_STD_max_video) {
                    P_STD_max_video = stream->max_buffer_size;
    
            }
    
            /* video */
            put_bits(&pb, 8, 0xb9); /* stream ID */
            put_bits(&pb, 2, 3);
            put_bits(&pb, 1, 1);
            put_bits(&pb, 13, P_STD_max_video / 1024);
    
            /* audio */
            if (P_STD_max_mpeg_audio == 0)
                P_STD_max_mpeg_audio = 4096;
            put_bits(&pb, 8, 0xb8); /* stream ID */
            put_bits(&pb, 2, 3);
            put_bits(&pb, 1, 0);
            put_bits(&pb, 13, P_STD_max_mpeg_audio / 128);
    
            /* private stream 1 */
            put_bits(&pb, 8, 0xbd); /* stream ID */
            put_bits(&pb, 2, 3);
            put_bits(&pb, 1, 0);
            put_bits(&pb, 13, P_STD_max_mpeg_PS1 / 128);
    
            /* private stream 2 */
            put_bits(&pb, 8, 0xbf); /* stream ID */
            put_bits(&pb, 2, 3);
            put_bits(&pb, 1, 1);
            put_bits(&pb, 13, 2);
        }
        else {
            /* audio stream info */
            private_stream_coded = 0;
            for(i=0;i<ctx->nb_streams;i++) {
                StreamInfo *stream = ctx->streams[i]->priv_data;
    
    
                /* For VCDs, only include the stream info for the stream
                that the pack which contains this system belongs to.
                (see VCD standard p. IV-7) */
                if ( !s->is_vcd || stream->id==only_for_stream_id
                    || only_for_stream_id==0) {
    
                    id = stream->id;
                    if (id < 0xc0) {
                        /* special case for private streams (AC3 use that) */
                        if (private_stream_coded)
                            continue;
                        private_stream_coded = 1;
                        id = 0xbd;
                    }
                    put_bits(&pb, 8, id); /* stream ID */
                    put_bits(&pb, 2, 3);
                    if (id < 0xe0) {
                        /* audio */
                        put_bits(&pb, 1, 0);
                        put_bits(&pb, 13, stream->max_buffer_size / 128);
                    } else {
                        /* video */
                        put_bits(&pb, 1, 1);
                        put_bits(&pb, 13, stream->max_buffer_size / 1024);
                    }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            }
        }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        flush_put_bits(&pb);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        /* patch packet size */
        buf[4] = (size - 6) >> 8;
        buf[5] = (size - 6) & 0xff;
    
        return size;
    }
    
    
    static int get_system_header_size(AVFormatContext *ctx)
    {
        int buf_index, i, private_stream_coded;
        StreamInfo *stream;
    
        MpegMuxContext *s = ctx->priv_data;
    
        if (s->is_dvd)
           return 18; // DVD-Video system headers are 18 bytes fixed length.
    
    
        buf_index = 12;
        private_stream_coded = 0;
        for(i=0;i<ctx->nb_streams;i++) {
            stream = ctx->streams[i]->priv_data;
            if (stream->id < 0xc0) {
                if (private_stream_coded)
                    continue;
                private_stream_coded = 1;
            }
            buf_index += 3;
        }
        return buf_index;
    }
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    static int mpeg_mux_init(AVFormatContext *ctx)
    {
    
        MpegMuxContext *s = ctx->priv_data;
    
        int bitrate, i, mpa_id, mpv_id, mps_id, ac3_id, dts_id, lpcm_id, j;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        AVStream *st;
        StreamInfo *stream;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        s->packet_number = 0;
    
        s->is_vcd = (ctx->oformat == &mpeg1vcd_mux);
    
        s->is_svcd = (ctx->oformat == &mpeg2svcd_mux);
    
        s->is_mpeg2 = (ctx->oformat == &mpeg2vob_mux || ctx->oformat == &mpeg2svcd_mux || ctx->oformat == &mpeg2dvd_mux);
        s->is_dvd = (ctx->oformat == &mpeg2dvd_mux);
    
        if(ctx->packet_size)
            s->packet_size = ctx->packet_size;
    
        else
            s->packet_size = 2048;
    
        s->vcd_padding_bytes_written = 0;
        s->vcd_padding_bitrate=0;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        s->audio_bound = 0;
        s->video_bound = 0;
        mpa_id = AUDIO_ID;
    
        ac3_id = AC3_ID;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        mpv_id = VIDEO_ID;
    
        lpcm_id = LPCM_ID;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        for(i=0;i<ctx->nb_streams;i++) {
            st = ctx->streams[i];
            stream = av_mallocz(sizeof(StreamInfo));
            if (!stream)
                goto fail;
            st->priv_data = stream;
    
    
            av_set_pts_info(st, 64, 1, 90000);
    
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            case CODEC_TYPE_AUDIO:
    
                if (st->codec->codec_id == CODEC_ID_AC3) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    stream->id = ac3_id++;
    
                } else if (st->codec->codec_id == CODEC_ID_DTS) {
    
                } else if (st->codec->codec_id == CODEC_ID_PCM_S16BE) {
    
                    stream->id = lpcm_id++;
                    for(j = 0; j < 4; j++) {
    
                        if (lpcm_freq_tab[j] == st->codec->sample_rate)
    
                            break;
                    }
                    if (j == 4)
                        goto fail;
    
                        return -1;
                    stream->lpcm_header[0] = 0x0c;
    
                    stream->lpcm_header[1] = (st->codec->channels - 1) | (j << 4);
    
                    stream->lpcm_header[2] = 0x80;
    
                    stream->lpcm_align = st->codec->channels * 2;
    
                } else {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                    stream->id = mpa_id++;
    
    
                /* This value HAS to be used for VCD (see VCD standard, p. IV-7).
                   Right now it is also used for everything else.*/
    
                stream->max_buffer_size = 4 * 1024;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                s->audio_bound++;
                break;
            case CODEC_TYPE_VIDEO:
                stream->id = mpv_id++;
    
                if (st->codec->rc_buffer_size)
                    stream->max_buffer_size = 6*1024 + st->codec->rc_buffer_size/8;
    
                else
                    stream->max_buffer_size = 230*1024; //FIXME this is probably too small as default
    #if 0
    
                    /* see VCD standard, p. IV-7*/
    
                    stream->max_buffer_size = 46 * 1024;
    
                else
                    /* This value HAS to be used for SVCD (see SVCD standard, p. 26 V.2.3.2).
                       Right now it is also used for everything else.*/
    
                    stream->max_buffer_size = 230 * 1024;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
                s->video_bound++;
                break;
    
            case CODEC_TYPE_SUBTITLE:
                stream->id = mps_id++;
                stream->max_buffer_size = 16 * 1024;
                break;
    
                return -1;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            }
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
            fifo_init(&stream->fifo, 16);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
        bitrate = 0;
        audio_bitrate = 0;
        video_bitrate = 0;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        for(i=0;i<ctx->nb_streams;i++) {
    
            int codec_rate;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            st = ctx->streams[i];
    
            stream = (StreamInfo*) st->priv_data;
    
            if(st->codec->rc_max_rate || stream->id==VIDEO_ID)
                codec_rate= st->codec->rc_max_rate;
    
            if(!codec_rate)
                codec_rate= (1<<21)*8*50/ctx->nb_streams;
    
            bitrate += codec_rate;
    
                audio_bitrate += codec_rate;
    
                video_bitrate += codec_rate;
    
        if(ctx->mux_rate){
            s->mux_rate= (ctx->mux_rate + (8 * 50) - 1) / (8 * 50);
        } else {
            /* we increase slightly the bitrate to take into account the
               headers. XXX: compute it exactly */
            bitrate += bitrate*5/100;
            bitrate += 10000;
            s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50);
        }
    
    
        if (s->is_vcd) {
            double overhead_rate;
    
            /* The VCD standard mandates that the mux_rate field is 3528
               (see standard p. IV-6).
               The value is actually "wrong", i.e. if you calculate
               it using the normal formula and the 75 sectors per second transfer
               rate you get a different value because the real pack size is 2324,
               not 2352. But the standard explicitly specifies that the mux_rate
               field in the header must have this value.*/
    
    //        s->mux_rate=2352 * 75 / 50;    /* = 3528*/
    
    
            /* The VCD standard states that the muxed stream must be
               exactly 75 packs / second (the data rate of a single speed cdrom).
               Since the video bitrate (probably 1150000 bits/sec) will be below
               the theoretical maximum we have to add some padding packets
               to make up for the lower data rate.
               (cf. VCD standard p. IV-6 )*/
    
            /* Add the header overhead to the data rate.
               2279 data bytes per audio pack, 2294 data bytes per video pack*/
            overhead_rate = ((audio_bitrate / 8.0) / 2279) * (2324 - 2279);
            overhead_rate += ((video_bitrate / 8.0) / 2294) * (2324 - 2294);
            overhead_rate *= 8;
    
            /* Add padding so that the full bitrate is 2324*75 bytes/sec */
            s->vcd_padding_bitrate = 2324 * 75 * 8 - (bitrate + overhead_rate);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
    
            /* every packet */
            s->pack_header_freq = 1;
        else
            /* every 2 seconds */
            s->pack_header_freq = 2 * bitrate / s->packet_size / 8;
    
    
        /* the above seems to make pack_header_freq zero sometimes */
        if (s->pack_header_freq == 0)
           s->pack_header_freq = 1;
    
        if (s->is_mpeg2)
            /* every 200 packets. Need to look at the spec.  */
            s->system_header_freq = s->pack_header_freq * 40;
        else if (s->is_vcd)
    
            /* the standard mandates that there are only two system headers
               in the whole file: one in the first packet of each stream.
               (see standard p. IV-7 and IV-8) */
            s->system_header_freq = 0x7fffffff;
    
        else
            s->system_header_freq = s->pack_header_freq * 5;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        for(i=0;i<ctx->nb_streams;i++) {
            stream = ctx->streams[i]->priv_data;
            stream->packet_number = 0;
        }
    
        s->system_header_size = get_system_header_size(ctx);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        return 0;
     fail:
        for(i=0;i<ctx->nb_streams;i++) {
    
            av_free(ctx->streams[i]->priv_data);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        }
        return -ENOMEM;
    }
    
    
    static inline void put_timestamp(ByteIOContext *pb, int id, int64_t timestamp)
    {
    
        put_byte(pb,
                 (id << 4) |
                 (((timestamp >> 30) & 0x07) << 1) |
    
                 1);
        put_be16(pb, (uint16_t)((((timestamp >> 15) & 0x7fff) << 1) | 1));
        put_be16(pb, (uint16_t)((((timestamp) & 0x7fff) << 1) | 1));
    }
    
    
    /* return the number of padding bytes that should be inserted into
       the multiplexed stream.*/
    static int get_vcd_padding_size(AVFormatContext *ctx, int64_t pts)
    {
        MpegMuxContext *s = ctx->priv_data;
        int pad_bytes = 0;
    
        if (s->vcd_padding_bitrate > 0 && pts!=AV_NOPTS_VALUE)
        {
            int64_t full_pad_bytes;
    
            full_pad_bytes = (int64_t)((s->vcd_padding_bitrate * (pts / 90000.0)) / 8.0); //FIXME this is wrong
    
            pad_bytes = (int) (full_pad_bytes - s->vcd_padding_bytes_written);
    
            if (pad_bytes<0)
                /* might happen if we have already padded to a later timestamp. This
                   can occur if another stream has already advanced further.*/
                pad_bytes=0;
        }
    
        return pad_bytes;
    }
    
    
    
    /* return the exact available payload size for the next packet for
       stream 'stream_index'. 'pts' and 'dts' are only used to know if
       timestamps are needed in the packet header. */
    static int get_packet_payload_size(AVFormatContext *ctx, int stream_index,
                                       int64_t pts, int64_t dts)
    {
        MpegMuxContext *s = ctx->priv_data;
        int buf_index;
        StreamInfo *stream;
    
    
        stream = ctx->streams[stream_index]->priv_data;
    
    
        buf_index = 0;
        if (((s->packet_number % s->pack_header_freq) == 0)) {
            /* pack header size */
    
            if (s->is_mpeg2)
    
            if (s->is_vcd) {
                /* there is exactly one system header for each stream in a VCD MPEG,
                   One in the very first video packet and one in the very first
                   audio packet (see VCD standard p. IV-7 and IV-8).*/
    
                if (stream->packet_number==0)
                    /* The system headers refer only to the stream they occur in,
                       so they have a constant size.*/
                    buf_index += 15;
    
    
                if ((s->packet_number % s->system_header_freq) == 0)
                    buf_index += s->system_header_size;
            }
    
        if ((s->is_vcd && stream->packet_number==0)
            || (s->is_svcd && s->packet_number==0))
    
            /* the first pack of each stream contains only the pack header,
    
               the system header and some padding (see VCD standard p. IV-6)
    
               Add the padding size, so that the actual payload becomes 0.*/
            buf_index += s->packet_size - buf_index;
        else {
            /* packet header size */
            buf_index += 6;
    
                buf_index += 3;
    
                if (stream->packet_number==0)
                    buf_index += 3; /* PES extension */
                buf_index += 1;    /* obligatory stuffing byte */
            }
    
            if (pts != AV_NOPTS_VALUE) {
                if (dts != pts)
                    buf_index += 5 + 5;
                else
                    buf_index += 5;
    
            } else {
                if (!s->is_mpeg2)
                    buf_index++;
            }
    
            if (stream->id < 0xc0) {
                /* AC3/LPCM private data header */
                buf_index += 4;
                if (stream->id >= 0xa0) {
                    int n;
                    buf_index += 3;
                    /* NOTE: we round the payload size to an integer number of
                       LPCM samples */
                    n = (s->packet_size - buf_index) % stream->lpcm_align;
                    if (n)
                        buf_index += (stream->lpcm_align - n);
                }
    
    
            if (s->is_vcd && stream->id == AUDIO_ID)
                /* The VCD standard demands that 20 zero bytes follow
                   each audio packet (see standard p. IV-8).*/
                buf_index+=20;
    
        return s->packet_size - buf_index;
    
    /* Write an MPEG padding packet header. */
    
    static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packet_bytes)
    
        put_be32(pb, PADDING_STREAM);
        put_be16(pb, packet_bytes - 6);
    
            put_byte(pb, 0x0f);
            packet_bytes -= 7;
    
            packet_bytes -= 6;
    
    static int get_nb_frames(AVFormatContext *ctx, StreamInfo *stream, int len){
        int nb_frames=0;
        PacketDesc *pkt_desc= stream->premux_packet;
    
    
            if(pkt_desc->size == pkt_desc->unwritten_size)
                nb_frames++;
            len -= pkt_desc->unwritten_size;
            pkt_desc= pkt_desc->next;
        }
    
        return nb_frames;
    }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    /* flush the packet on stream stream_index */
    
    static int flush_packet(AVFormatContext *ctx, int stream_index,
    
                             int64_t pts, int64_t dts, int64_t scr, int trailer_size)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
        MpegMuxContext *s = ctx->priv_data;
        StreamInfo *stream = ctx->streams[stream_index]->priv_data;
    
        uint8_t *buf_ptr;
    
        int size, payload_size, startcode, id, stuffing_size, i, header_len;
        int packet_size;
    
        uint8_t buffer[128];
    
        int zero_trail_bytes = 0;
        int pad_packet_bytes = 0;
    
        int pes_flags;
        int general_pack = 0;  /*"general" pack without data specific to one stream?*/
    
        int nb_frames;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        id = stream->id;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    #if 0
    
        printf("packet ID=%2x PTS=%0.3f\n",
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    #endif
    
        buf_ptr = buffer;
    
        if ((s->packet_number % s->pack_header_freq) == 0 || s->last_scr != scr) {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            /* output pack and systems header if needed */
    
            size = put_pack_header(ctx, buf_ptr, scr);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            buf_ptr += size;
    
            s->last_scr= scr;
    
    
            if (s->is_vcd) {
                /* there is exactly one system header for each stream in a VCD MPEG,
                   One in the very first video packet and one in the very first
                   audio packet (see VCD standard p. IV-7 and IV-8).*/
    
                if (stream->packet_number==0) {
                    size = put_system_header(ctx, buf_ptr, id);
                    buf_ptr += size;
                }
    
            } else if (s->is_dvd) {
                if (stream->align_iframe || s->packet_number == 0){
                    int bytes_to_iframe;
                    int PES_bytes_to_fill;
                    if (stream->fifo_iframe_ptr >= stream->fifo.rptr) {
                        bytes_to_iframe = stream->fifo_iframe_ptr - stream->fifo.rptr;
                    } else {
                        bytes_to_iframe = (stream->fifo.end - stream->fifo.rptr) + (stream->fifo_iframe_ptr - stream->fifo.buffer);
                    }
                    PES_bytes_to_fill = s->packet_size - size - 10;
    
                    if (pts != AV_NOPTS_VALUE) {
                        if (dts != pts)
                            PES_bytes_to_fill -= 5 + 5;
                        else
                            PES_bytes_to_fill -= 5;
                    }
    
                    if (bytes_to_iframe == 0 || s->packet_number == 0) {
                        size = put_system_header(ctx, buf_ptr, 0);
                        buf_ptr += size;
                        size = buf_ptr - buffer;
                        put_buffer(&ctx->pb, buffer, size);
    
                        put_be32(&ctx->pb, PRIVATE_STREAM_2);
                        put_be16(&ctx->pb, 0x03d4);         // length
                        put_byte(&ctx->pb, 0x00);           // substream ID, 00=PCI
                        for (i = 0; i < 979; i++)
                            put_byte(&ctx->pb, 0x00);
    
                        put_be32(&ctx->pb, PRIVATE_STREAM_2);
                        put_be16(&ctx->pb, 0x03fa);         // length
                        put_byte(&ctx->pb, 0x01);           // substream ID, 01=DSI
                        for (i = 0; i < 1017; i++)
                            put_byte(&ctx->pb, 0x00);
    
                        memset(buffer, 0, 128);
                        buf_ptr = buffer;
                        s->packet_number++;
                        stream->align_iframe = 0;
                        scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet
                        size = put_pack_header(ctx, buf_ptr, scr);
                        s->last_scr= scr;
                        buf_ptr += size;
                        /* GOP Start */
                    } else if (bytes_to_iframe < PES_bytes_to_fill) {
                        pad_packet_bytes = PES_bytes_to_fill - bytes_to_iframe;
                    }
                }
    
            } else {
                if ((s->packet_number % s->system_header_freq) == 0) {
                    size = put_system_header(ctx, buf_ptr, 0);
                    buf_ptr += size;
                }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            }
        }
        size = buf_ptr - buffer;
        put_buffer(&ctx->pb, buffer, size);
    
    
        packet_size = s->packet_size - size;
    
        if (s->is_vcd && id == AUDIO_ID)
            /* The VCD standard demands that 20 zero bytes follow
               each audio pack (see standard p. IV-8).*/
            zero_trail_bytes += 20;
    
        if ((s->is_vcd && stream->packet_number==0)
            || (s->is_svcd && s->packet_number==0)) {
            /* for VCD the first pack of each stream contains only the pack header,
    
               the system header and lots of padding (see VCD standard p. IV-6).
               In the case of an audio pack, 20 zero bytes are also added at
               the end.*/
    
            /* For SVCD we fill the very first pack to increase compatibility with
               some DVD players. Not mandated by the standard.*/
            if (s->is_svcd)
                general_pack = 1;    /* the system header refers to both streams and no stream data*/
    
            pad_packet_bytes = packet_size - zero_trail_bytes;
    
        packet_size -= pad_packet_bytes + zero_trail_bytes;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
            /* packet header size */
            packet_size -= 6;
    
            /* packet header */
            if (s->is_mpeg2) {
                header_len = 3;
    
                if (stream->packet_number==0)
                    header_len += 3; /* PES extension */
                header_len += 1; /* obligatory stuffing byte */
    
            } else {
                header_len = 0;
            }
            if (pts != AV_NOPTS_VALUE) {
                if (dts != pts)
                    header_len += 5 + 5;
                else
                    header_len += 5;
            } else {
                if (!s->is_mpeg2)
                    header_len++;
            }
    
            payload_size = packet_size - header_len;
            if (id < 0xc0) {
                startcode = PRIVATE_STREAM_1;
    
                payload_size -= 1;
                if (id >= 0x40) {
    
                    if (id >= 0xa0)
                        payload_size -= 3;
                }
    
            stuffing_size = payload_size - fifo_size(&stream->fifo, stream->fifo.rptr);
    
            // first byte doesnt fit -> reset pts/dts + stuffing
            if(payload_size <= trailer_size && pts != AV_NOPTS_VALUE){
                int timestamp_len=0;
    
                    timestamp_len += 5;
                if(pts != AV_NOPTS_VALUE)
                    timestamp_len += s->is_mpeg2 ? 5 : 4;
                pts=dts= AV_NOPTS_VALUE;
                header_len -= timestamp_len;
    
                if (s->is_dvd && stream->align_iframe) {
                    pad_packet_bytes += timestamp_len;
                    packet_size -= timestamp_len;
                } else {
                    payload_size += timestamp_len;
                }
    
                stuffing_size += timestamp_len;
                if(payload_size > trailer_size)
                    stuffing_size += payload_size - trailer_size;
            }
    
    
            if (pad_packet_bytes > 0 && pad_packet_bytes <= 7) { // can't use padding, so use stuffing
                packet_size += pad_packet_bytes;
                payload_size += pad_packet_bytes; // undo the previous adjustment
                if (stuffing_size < 0) {
                    stuffing_size = pad_packet_bytes;
                } else {
                    stuffing_size += pad_packet_bytes;
                }
                pad_packet_bytes = 0;
            }
    
    
            if (stuffing_size < 0)
                stuffing_size = 0;
    
            if (stuffing_size > 16) {    /*<=16 for MPEG-1, <=32 for MPEG-2*/
                pad_packet_bytes += stuffing_size;
                packet_size -= stuffing_size;
                payload_size -= stuffing_size;
                stuffing_size = 0;
            }
    
            nb_frames= get_nb_frames(ctx, stream, payload_size - stuffing_size);
    
            if (!s->is_mpeg2)
                for(i=0;i<stuffing_size;i++)
                    put_byte(&ctx->pb, 0xff);
    
            if (s->is_mpeg2) {
                put_byte(&ctx->pb, 0x80); /* mpeg2 id */
    
    
                    pes_flags |= 0x80;
                    if (dts != pts)
                        pes_flags |= 0x40;
    
    
                /* Both the MPEG-2 and the SVCD standards demand that the
                   P-STD_buffer_size field be included in the first packet of
                   every stream. (see SVCD standard p. 26 V.2.3.1 and V.2.3.2
                   and MPEG-2 standard 2.7.7) */
                if (stream->packet_number == 0)
                    pes_flags |= 0x01;
    
                put_byte(&ctx->pb, pes_flags); /* flags */
                put_byte(&ctx->pb, header_len - 3 + stuffing_size);
    
                if (pes_flags & 0x80)  /*write pts*/
                    put_timestamp(&ctx->pb, (pes_flags & 0x40) ? 0x03 : 0x02, pts);
                if (pes_flags & 0x40)  /*write dts*/
                    put_timestamp(&ctx->pb, 0x01, dts);
    
                if (pes_flags & 0x01) {  /*write pes extension*/
                    put_byte(&ctx->pb, 0x10); /* flags */
    
    
                    /* P-STD buffer info */
    
                    if (id == AUDIO_ID)
                        put_be16(&ctx->pb, 0x4000 | stream->max_buffer_size/128);
                    else
                        put_be16(&ctx->pb, 0x6000 | stream->max_buffer_size/1024);
                }
    
    
                if (pts != AV_NOPTS_VALUE) {
                    if (dts != pts) {
                        put_timestamp(&ctx->pb, 0x03, pts);
                        put_timestamp(&ctx->pb, 0x01, dts);
                    } else {
                        put_timestamp(&ctx->pb, 0x02, pts);
                    }
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
            if (s->is_mpeg2) {
                /* special stuffing byte that is always written
                   to prevent accidental generation of start codes. */
                put_byte(&ctx->pb, 0xff);
    
                for(i=0;i<stuffing_size;i++)
                    put_byte(&ctx->pb, 0xff);
            }
    
    
            if (startcode == PRIVATE_STREAM_1) {
                put_byte(&ctx->pb, id);
                if (id >= 0xa0) {
                    /* LPCM (XXX: check nb_frames) */
                    put_byte(&ctx->pb, 7);
                    put_be16(&ctx->pb, 4); /* skip 3 header bytes */
                    put_byte(&ctx->pb, stream->lpcm_header[0]);
                    put_byte(&ctx->pb, stream->lpcm_header[1]);
                    put_byte(&ctx->pb, stream->lpcm_header[2]);
    
                } else if (id >= 0x40) {
    
                    put_byte(&ctx->pb, nb_frames);
                    put_be16(&ctx->pb, trailer_size+1);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            }
    
            if(put_fifo(&ctx->pb, &stream->fifo, payload_size - stuffing_size, &stream->fifo.rptr) < 0)
                return -1;
        }else{
            payload_size=
            stuffing_size= 0;
    
            put_padding_packet(ctx,&ctx->pb, pad_packet_bytes);
    
        for(i=0;i<zero_trail_bytes;i++)
            put_byte(&ctx->pb, 0x00);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        put_flush_packet(&ctx->pb);
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
        s->packet_number++;
    
    
        /* only increase the stream packet number if this pack actually contains
           something that is specific to this stream! I.e. a dedicated header
           or some data.*/
        if (!general_pack)
            stream->packet_number++;
    
        return payload_size - stuffing_size;
    
    static void put_vcd_padding_sector(AVFormatContext *ctx)
    {
        /* There are two ways to do this padding: writing a sector/pack
           of 0 values, or writing an MPEG padding pack. Both seem to
           work with most decoders, BUT the VCD standard only allows a 0-sector
           (see standard p. IV-4, IV-5).
           So a 0-sector it is...*/
    
        MpegMuxContext *s = ctx->priv_data;
        int i;
    
        for(i=0;i<s->packet_size;i++)
            put_byte(&ctx->pb, 0);
    
        s->vcd_padding_bytes_written += s->packet_size;
    
        /* increasing the packet number is correct. The SCR of the following packs
           is calculated from the packet_number and it has to include the padding
           sector (it represents the sector index, not the MPEG pack index)