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

📄 mpeg.c

📁 ffmpeg源码分析
💻 C
📖 第 1 页 / 共 4 页
字号:
                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);            }        } 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 (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) {                /* AC3 */                put_byte(&ctx->pb, nb_frames);                put_be16(&ctx->pb, trailer_size+1);            }        }        /* output data */        if(put_fifo(&ctx->pb, &stream->fifo, payload_size - stuffing_size, &stream->fifo.rptr) < 0)            return -1;    }else{        payload_size=        stuffing_size= 0;    }    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++;    /* 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;    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++;}#if 0 /* unused, remove? */static int64_t get_vcd_scr(AVFormatContext *ctx,int stream_index,int64_t pts){    MpegMuxContext *s = ctx->priv_data;    int64_t scr;        /* 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;    return scr;}#endifstatic int remove_decoded_packets(AVFormatContext *ctx, int64_t scr){//    MpegMuxContext *s = ctx->priv_data;    int i;    for(i=0; i<ctx->nb_streams; i++){        AVStream *st = ctx->streams[i];        StreamInfo *stream = st->priv_data;        PacketDesc *pkt_desc= stream->predecode_packet;        while(pkt_desc && scr > pkt_desc->dts){ //FIXME > vs >=            if(stream->buffer_index < pkt_desc->size ||               stream->predecode_packet == stream->premux_packet){                av_log(ctx, AV_LOG_ERROR, "buffer underflow\n");                break;            }            stream->buffer_index -= pkt_desc->size;            stream->predecode_packet= pkt_desc->next;            av_freep(&pkt_desc);        }    }    return 0;}static int output_packet(AVFormatContext *ctx, int flush){    MpegMuxContext *s = ctx->priv_data;    AVStream *st;    StreamInfo *stream;    int i, avail_space, es_size, trailer_size;    int best_i= -1;    int best_score= INT_MIN;    int ignore_constraints=0;    int64_t scr= s->last_scr;    PacketDesc *timestamp_packet;    const int64_t max_delay= av_rescale(ctx->max_delay, 90000, AV_TIME_BASE);retry:    for(i=0; i<ctx->nb_streams; i++){        AVStream *st = ctx->streams[i];        StreamInfo *stream = st->priv_data;        const int avail_data=  fifo_size(&stream->fifo, stream->fifo.rptr);        const int space= stream->max_buffer_size - stream->buffer_index;        int rel_space= 1024*space / stream->max_buffer_size;        PacketDesc *next_pkt= stream->premux_packet;        /* for subtitle, a single PES packet must be generated,           so we flush after every single subtitle packet */        if(s->packet_size > avail_data && !flush           && st->codec->codec_type != CODEC_TYPE_SUBTITLE)            return 0;        if(avail_data==0)            continue;        assert(avail_data>0);        if(space < s->packet_size && !ignore_constraints)            continue;        if(next_pkt && next_pkt->dts - scr > max_delay)            continue;        if(rel_space > best_score){            best_score= rel_space;            best_i = i;            avail_space= space;        }    }    if(best_i < 0){        int64_t best_dts= INT64_MAX;        for(i=0; i<ctx->nb_streams; i++){            AVStream *st = ctx->streams[i];            StreamInfo *stream = st->priv_data;            PacketDesc *pkt_desc= stream->predecode_packet;            if(pkt_desc && pkt_desc->dts < best_dts)                best_dts= pkt_desc->dts;        }#if 0        av_log(ctx, AV_LOG_DEBUG, "bumping scr, scr:%f, dts:%f\n",               scr/90000.0, best_dts/90000.0);#endif        if(best_dts == INT64_MAX)            return 0;        if(scr >= best_dts+1 && !ignore_constraints){            av_log(ctx, AV_LOG_ERROR, "packet too large, ignoring buffer limits to mux it\n");            ignore_constraints= 1;        }        scr= FFMAX(best_dts+1, scr);        if(remove_decoded_packets(ctx, scr) < 0)            return -1;        goto retry;    }    assert(best_i >= 0);    st = ctx->streams[best_i];    stream = st->priv_data;    assert(fifo_size(&stream->fifo, stream->fifo.rptr) > 0);    assert(avail_space >= s->packet_size || ignore_constraints);    timestamp_packet= stream->premux_packet;    if(timestamp_packet->unwritten_size == timestamp_packet->size){        trailer_size= 0;    }else{        trailer_size= timestamp_packet->unwritten_size;        timestamp_packet= timestamp_packet->next;    }    if(timestamp_packet){//av_log(ctx, AV_LOG_DEBUG, "dts:%f pts:%f scr:%f stream:%d\n", timestamp_packet->dts/90000.0, timestamp_packet->pts/90000.0, scr/90000.0, best_i);        es_size= flush_packet(ctx, best_i, timestamp_packet->pts, timestamp_packet->dts, scr, trailer_size);    }else{        assert(fifo_size(&stream->fifo, stream->fifo.rptr) == trailer_size);        es_size= flush_packet(ctx, best_i, AV_NOPTS_VALUE, AV_NOPTS_VALUE, scr, trailer_size);    }    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->premux_packet->pts) ) >= s->packet_size){ //FIXME pts cannot be correct here            put_vcd_padding_sector(ctx);            s->last_scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet        }    }    stream->buffer_index += es_size;    s->last_scr += s->packet_size*90000LL / (s->mux_rate*50LL); //FIXME rounding and first few bytes of each packet    while(stream->premux_packet && stream->premux_packet->unwritten_size <= es_size){        es_size -= stream->premux_packet->unwritten_size;        stream->premux_packet= stream->premux_packet->next;    }    if(es_size)        stream->premux_packet->unwritten_size -= es_size;    if(remove_decoded_packets(ctx, s->last_scr) < 0)        return -1;    return 1;}static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt){    MpegMuxContext *s = ctx->priv_data;    int stream_index= pkt->stream_index;    int size= pkt->size;    uint8_t *buf= pkt->data;    AVStream *st = ctx->streams[stream_index];    StreamInfo *stream = st->priv_data;    int64_t pts, dts;    PacketDesc *pkt_desc;    const int preload= av_rescale(ctx->preload, 90000, AV_TIME_BASE);    const int is_iframe = st->codec->codec_type == CODEC_TYPE_VIDEO && (pkt->flags & PKT_FLAG_KEY);    pts= pkt->pts;    dts= pkt->dts;    if(pts != AV_NOPTS_VALUE) pts += preload;    if(dts != AV_NOPTS_VALUE) dts += preload;//av_log(ctx, AV_LOG_DEBUG, "dts:%f pts:%f flags:%d stream:%d nopts:%d\n", dts/90000.0, pts/90000.0, pkt->flags, pkt->stream_index, pts != AV_NOPTS_VALUE);    if (!stream->premux_packet)        stream->next_packet = &stream->premux_packet;    *stream->next_packet=    pkt_desc= av_mallocz(sizeof(PacketDesc));    pkt_desc->pts= pts;    pkt_desc->dts= dts;    pkt_desc->unwritten_size=    pkt_desc->size= size;    if(!stream->predecode_packet)        stream->predecode_packet= pkt_desc;    stream->next_packet= &pkt_desc->next;    fifo_realloc(&stream->fifo, fifo_size(&stream->fifo, NULL) + size + 1);    if (s->is_dvd){        if (is_iframe && (s->packet_number == 0 || (pts - stream->vobu_start_pts >= 36000))) { // min VOBU length 0.4 seconds (mpucoder)            stream->fifo_iframe_ptr = stream->fifo.wptr;            stream->align_iframe = 1;            stream->vobu_start_pts = pts;        } else {            stream->align_iframe = 0;        }    }    fifo_write(&stream->fifo, buf, size, &stream->fifo.wptr);    for(;;){        int ret= output_packet(ctx, 0);        if(ret<=0)            return ret;    }}static int mpeg_mux_end(AVFormatContext *ctx){//    MpegMuxContext *s = ctx->priv_data;    StreamInfo *stream;    int i;    for(;;){        int ret= output_packet(ctx, 1);        if(ret<0)            return ret;        else if(ret==0)            break;    }    /* End header according to MPEG1 systems standard. We do not write       it as it is usually not needed by decoders and because it       complicates MPEG stream concatenation. */    //put_be32(&ctx->pb, ISO_11172_END_CODE);    //put_flush_packet(&ctx->pb);    for(i=0;i<ctx->nb_streams;i++) {        stream = ctx->streams[i]->priv_data;        assert(fifo_size(&stream->fifo, stream->fifo.rptr) == 0);        fifo_free(&stream->fifo);    }    return 0;}#endif //CONFIG_MUXERS/*********************************************//* demux code */#define MAX_SYNC_SIZE 100000static int mpegps_probe(AVProbeData *p){    uint32_t code= -1;    int sys=0, pspack=0, priv1=0, vid=0;    int i;    for(i=0; i<p->buf_size; i++){        code = (code<<8) + p->buf[i];        if ((code & 0xffffff00) == 0x100) {            switch(code){            case SYSTEM_HEADER_START_CODE:    sys++; break;            case         PRIVATE_STREAM_1:  priv1++; break;            case          PACK_START_CODE: pspack++; break;            case       (VIDEO_ID + 0x100):    vid++; break;            }        }    }    if(sys && sys*9 <= pspack*10)        return AVPROBE_SCORE_MAX/2+2; // +1 for .mpg    if((priv1 || vid) && (priv1+vid)*9 <= pspack*10)        return AVPROBE_SCORE_MAX/2+2; // +1 for .mpg    return 0;}typedef struct MpegDemuxContext {    int header_state;    unsigned char psm_es_type[256];} MpegDemuxContext;static int mpegps_read_header(AVFormatContext *s,                              AVFormatParameters *ap){    MpegDemuxContext *m = s->priv_data;    m->header_state = 0xff;    s->ctx_flags |= AVFMTCTX_NOHEADER;    /* no need to do more */    return 0;}static int64_t get_pts(ByteIOContext *pb, int c){    int64_t pts;    int val;    if (c < 0)        c = get_byte(pb);    pts = (int64_t)((c >> 1) & 0x07) << 30;    val = get_be16(pb);    pts |= (int64_t)(val >> 1) << 15;    val = get_be16(pb);    pts |= (int64_t)(val >> 1);    return pts;}static int find_next_start_code(ByteIOContext *pb, int *size_ptr,                                uint32_t *header_state){    unsigned int state, v;    int val, n;    state = *header_state;    n = *size_ptr;    while (n > 0) {        if (url_feof(pb))            break;        v = get_byte(pb);        n--;        if (state == 0x000001) {            state = ((state << 8) | v) & 0xffffff;            val = state;            goto found;        }        state = ((state << 8) | v) & 0xffffff;    }    val = -1; found:    *header_state = state;    *size_ptr = n;    return val;}#if 0 /* unused, remove? *//* XXX: optimize */static int find_prev_start_code(ByteIOContext *pb, int *size_ptr){    int64_t pos, pos_start;

⌨️ 快捷键说明

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