⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpegenc.c

📁 ffmpeg的完整源代码和作者自己写的文档。不但有在Linux的工程哦
💻 C
📖 第 1 页 / 共 3 页
字号:
           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);
    }

    if (s->is_vcd || s->is_mpeg2)
        /* 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;

    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);
    s->last_scr = 0;
    return 0;
 fail:
    for(i=0;i<ctx->nb_streams;i++) {
        av_free(ctx->streams[i]->priv_data);
    }
    return AVERROR(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;
}


#if 0 /* unused, remove? */
/* 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)
            buf_index += 14;
        else
            buf_index += 12;

        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;

        } else {
            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;
        if (s->is_mpeg2) {
            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;
}
#endif

/* Write an MPEG padding packet header. */
static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packet_bytes)
{
    MpegMuxContext *s = ctx->priv_data;
    int i;

    put_be32(pb, PADDING_STREAM);
    put_be16(pb, packet_bytes - 6);
    if (!s->is_mpeg2) {
        put_byte(pb, 0x0f);
        packet_bytes -= 7;
    } else
        packet_bytes -= 6;

    for(i=0;i<packet_bytes;i++)
        put_byte(pb, 0xff);
}

static int get_nb_frames(AVFormatContext *ctx, StreamInfo *stream, int len){
    int nb_frames=0;
    PacketDesc *pkt_desc= stream->premux_packet;

    while(len>0){
        if(pkt_desc->size == pkt_desc->unwritten_size)
            nb_frames++;
        len -= pkt_desc->unwritten_size;
        pkt_desc= pkt_desc->next;
    }

    return nb_frames;
}

/* 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)
{
    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;

    id = stream->id;

#if 0
    printf("packet ID=%2x PTS=%0.3f\n",
           id, pts / 90000.0);
#endif

    buf_ptr = buffer;

    if ((s->packet_number % s->pack_header_freq) == 0 || s->last_scr != scr) {
        /* output pack and systems header if needed */
        size = put_pack_header(ctx, buf_ptr, scr);
        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 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 (stream->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 (stream->bytes_to_iframe < PES_bytes_to_fill) {
                    pad_packet_bytes = PES_bytes_to_fill - stream->bytes_to_iframe;
                }
            }
        } else {
            if ((s->packet_number % s->system_header_freq) == 0) {
                size = put_system_header(ctx, buf_ptr, 0);
                buf_ptr += size;
            }
        }
    }
    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;

    if (packet_size > 0) {

        /* 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) {
                payload_size -= 3;
                if (id >= 0xa0)
                    payload_size -= 3;
            }
        } else {
            startcode = 0x100 + id;
        }

        stuffing_size = payload_size - av_fifo_size(&stream->fifo);

        // first byte does not fit -> reset pts/dts + stuffing
        if(payload_size <= trailer_size && pts != AV_NOPTS_VALUE){
            int timestamp_len=0;
            if(dts != pts)
                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);

        put_be32(&ctx->pb, startcode);

        put_be16(&ctx->pb, packet_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=0;

            if (pts != AV_NOPTS_VALUE) {
                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*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -