mpeg.c

来自「arm平台下的H264编码和解码源代码」· C语言 代码 · 共 1,402 行 · 第 1/3 页

C
1,402
字号
        /* 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 (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 int put_padding_header(AVFormatContext *ctx,uint8_t* buf, int full_padding_size){    MpegMuxContext *s = ctx->priv_data;    int size = full_padding_size - 6;    /* subtract header length */    buf[0] = (uint8_t)(PADDING_STREAM >> 24);    buf[1] = (uint8_t)(PADDING_STREAM >> 16);    buf[2] = (uint8_t)(PADDING_STREAM >> 8);    buf[3] = (uint8_t)(PADDING_STREAM);    buf[4] = (uint8_t)(size >> 8);    buf[5] = (uint8_t)(size & 0xff);    if (!s->is_mpeg2) {        buf[6] = 0x0f;        return 7;    } else        return 6;}static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packet_bytes){    uint8_t buffer[7];    int size, i;        size = put_padding_header(ctx,buffer, packet_bytes);    put_buffer(pb, buffer, size);    packet_bytes -= size;    for(i=0;i<packet_bytes;i++)        put_byte(pb, 0xff);}/* flush the packet on stream stream_index */static void flush_packet(AVFormatContext *ctx, int stream_index,                          int64_t pts, int64_t dts, int64_t scr){    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;        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)) {        /* output pack and systems header if needed */        size = put_pack_header(ctx, buf_ptr, scr);        buf_ptr += size;        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->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) {        /* 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.*/        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;        } 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 -= 4;            if (id >= 0xa0)                payload_size -= 3;        } else {            startcode = 0x100 + id;        }        stuffing_size = payload_size - stream->buffer_ptr;        if (stuffing_size < 0)            stuffing_size = 0;        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 */            if (pts != AV_NOPTS_VALUE) {                if (dts != pts) {                    put_byte(&ctx->pb, 0xc0); /* flags */                    put_byte(&ctx->pb, header_len - 3 + stuffing_size);                    put_timestamp(&ctx->pb, 0x03, pts);                    put_timestamp(&ctx->pb, 0x01, dts);                } else {                    put_byte(&ctx->pb, 0x80); /* flags */                    put_byte(&ctx->pb, header_len - 3 + stuffing_size);                    put_timestamp(&ctx->pb, 0x02, pts);                }            } else {                put_byte(&ctx->pb, 0x00); /* flags */                put_byte(&ctx->pb, header_len - 3 + stuffing_size);            }        } else {            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);                }            } else {                put_byte(&ctx->pb, 0x0f);            }        }        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 {                /* AC3 */                put_byte(&ctx->pb, stream->nb_frames);                put_be16(&ctx->pb, stream->frame_start_offset);            }        }        if (s->is_mpeg2)            for(i=0;i<stuffing_size;i++)                put_byte(&ctx->pb, 0xff);        /* output data */        put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size);    }    if (pad_packet_bytes > 0)        put_padding_packet(ctx,&ctx->pb, pad_packet_bytes);        for(i=0;i<zero_trail_bytes;i++)        put_byte(&ctx->pb, 0x00);            put_flush_packet(&ctx->pb);        s->packet_number++;    stream->packet_number++;    stream->nb_frames = 0;    stream->frame_start_offset = 0;}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;            put_flush_packet(&ctx->pb);        /* 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)       (see VCD standard p. IV-6)*/    s->packet_number++;}/* XXX: move that to upper layer *//* XXX: we assume that there are always 'max_b_frames' between   reference frames. A better solution would be to use the AVFrame pts   field */static void compute_pts_dts(AVStream *st, int64_t *ppts, int64_t *pdts,                             int64_t timestamp){    int frame_delay;    int64_t pts, dts;    if (st->codec.codec_type == CODEC_TYPE_VIDEO &&         st->codec.max_b_frames != 0) {        frame_delay = (st->codec.frame_rate_base * 90000LL) /             st->codec.frame_rate;        if (timestamp == 0) {            /* specific case for first frame : DTS just before */            pts = timestamp;            dts = timestamp - frame_delay;        } else {            timestamp -= frame_delay;            if (st->codec.coded_frame->pict_type == FF_B_TYPE) {                /* B frames has identical pts/dts */                pts = timestamp;                dts = timestamp;            } else {                /* a reference frame has a pts equal to the dts of the                   _next_ one */                dts = timestamp;                pts = timestamp + (st->codec.max_b_frames + 1) * frame_delay;            }        }#if 1        av_log(&st->codec, AV_LOG_DEBUG, "pts=%0.3f dts=%0.3f pict_type=%c\n",                pts / 90000.0, dts / 90000.0,                av_get_pict_type_char(st->codec.coded_frame->pict_type));#endif    } else {        pts = timestamp;        dts = timestamp;    }    *ppts = pts & ((1LL << 33) - 1);    *pdts = dts & ((1LL << 33) - 1);}static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts){    MpegMuxContext *s = ctx->priv_data;    int64_t scr;    if (s->is_vcd)        /* Since the data delivery rate is constant, SCR is computed           using the formula C + i * 1200 where C is the start constant           and i is the pack index.           It is recommended that SCR 0 is at the beginning of the VCD front           margin (a sequence of empty Form 2 sectors on the CD).           It is recommended that the front margin is 30 sectors long, so           we use C = 30*1200 = 36000           (Note that even if the front margin is not 30 sectors the file           will still be correct according to the standard. It just won't have           the "recommended" value).*/        scr = 36000 + s->packet_number * 1200;    else {        /* XXX I believe this calculation of SCR is wrong. SCR           specifies at which time the data should enter the decoder.           Two packs cannot enter the decoder at the same time. */        /* XXX: system clock should be computed precisely, especially for        CBR case. The current mode gives at least something coherent */        if (stream_index == s->scr_stream_index            && pts != AV_NOPTS_VALUE)            scr = pts;        else            scr = s->last_scr;    }    s->last_scr=scr;    return scr;}    static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index,                                 const uint8_t *buf, int size,                                  int64_t timestamp){    MpegMuxContext *s = ctx->priv_data;    AVStream *st = ctx->streams[stream_index];    StreamInfo *stream = st->priv_data;    int64_t pts, dts, new_start_pts, new_start_dts;    int len, avail_size;        compute_pts_dts(st, &pts, &dts, timestamp);    #if 0    update_scr(ctx,stream_index,pts);    printf("%d: pts=%0.3f dts=%0.3f scr=%0.3f\n",            stream_index,            pts / 90000.0,            dts / 90000.0,            s->last_scr / 90000.0);#endif        /* we assume here that pts != AV_NOPTS_VALUE */    new_start_pts = stream->start_pts;    new_start_dts = stream->start_dts;        if (stream->start_pts == AV_NOPTS_VALUE) {        new_start_pts = pts;        new_start_dts = dts;    }    avail_size = get_packet_payload_size(ctx, stream_index,                                         new_start_pts,                                          new_start_dts);    if (stream->buffer_ptr >= avail_size) {        update_scr(ctx,stream_index,stream->start_pts);        /* unlikely case: outputing the pts or dts increase the packet           size so that we cannot write the start of the next           packet. In this case, we must flush the current packet with           padding.           Note: this always happens for the first audio and video packet           in a VCD file, since they do not carry any data.*/        flush_packet(ctx, stream_index,                     stream->start_pts, stream->start_dts, s->last_scr);        stream->buffer_ptr = 0;    }    stream->start_pts = new_start_pts;    stream->start_dts = new_start_dts;    stream->nb_frames++;    if (stream->frame_start_offset == 0)        stream->frame_start_offset = stream->buffer_ptr;    while (size > 0) {        avail_size = get_packet_payload_size(ctx, stream_index,                                             stream->start_pts,                                              stream->start_dts);        len = avail_size - stream->buffer_ptr;        if (len > size)            len = size;        memcpy(stream->buffer + stream->buffer_ptr, buf, len);        stream->buffer_ptr += len;        buf += len;        size -= len;        if (stream->buffer_ptr >= avail_size) {            update_scr(ctx,stream_index,stream->start_pts);            /* if packet full, we send it now */            flush_packet(ctx, stream_index,                         stream->start_pts, stream->start_dts, s->last_scr);            stream->buffer_ptr = 0;            if (s->is_vcd) {                /* Write one or more padding sectors, if necessary, to reach                   the constant overall bitrate.*/                int vcd_pad_bytes;                            while((vcd_pad_bytes = get_vcd_padding_size(ctx,stream->start_pts) ) >= s->packet_size)                    put_vcd_padding_sector(ctx);            }            /* Make sure only the FIRST pes packet for this frame has               a timestamp */            stream->start_pts = AV_NOPTS_VALUE;            stream->start_dts = AV_NOPTS_VALUE;        }    }    return 0;}static int mpeg_mux_end(AVFormatContext *ctx){    MpegMuxContext *s = ctx->priv_data;    StreamInfo *stream;    int i;    /* flush each packet */    for(i=0;i<ctx->nb_streams;i++) {        stream = ctx->streams[i]->priv_data;        if (stream->buffer_ptr > 0) {            update_scr(ctx,i,stream->start_pts);            /* NOTE: we can always write the remaining data as it was               tested before in mpeg_mux_write_packet() */            flush_packet(ctx, i, stream->start_pts, stream->start_dts,                          s->last_scr);        }    }    /* End header according to MPEG1 systems standard. We do not write

⌨️ 快捷键说明

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