📄 mpeg.c
字号:
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 + -