📄 mpegenc.c
字号:
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 */ assert(payload_size - stuffing_size <= av_fifo_size(&stream->fifo));#ifdef __CW32__ av_fifo_generic_read(&stream->fifo, payload_size - stuffing_size, (void (*)(void*, void*, int))&put_buffer, ctx->pb);#else av_fifo_generic_read(&stream->fifo, payload_size - stuffing_size, &put_buffer, ctx->pb);#endif stream->bytes_to_iframe -= payload_size - stuffing_size; }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; while((pkt_desc= stream->predecode_packet) && 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 i=%d bufi=%d size=%d\n", i, stream->buffer_index, pkt_desc->size); 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=0, 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= av_fifo_size(&stream->fifo); 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(av_fifo_size(&stream->fifo) > 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(av_fifo_size(&stream->fifo) == 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; av_fifo_realloc(&stream->fifo, av_fifo_size(&stream->fifo) + size); 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->bytes_to_iframe = av_fifo_size(&stream->fifo); stream->align_iframe = 1; stream->vobu_start_pts = pts; } } av_fifo_generic_write(&stream->fifo, buf, size, NULL); 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(av_fifo_size(&stream->fifo) == 0); av_fifo_free(&stream->fifo); } return 0;}#ifdef CONFIG_MPEG1SYSTEM_MUXERAVOutputFormat mpeg1system_muxer = { "mpeg", NULL_IF_CONFIG_SMALL("MPEG-1 System format"), "video/mpeg", "mpg,mpeg", sizeof(MpegMuxContext), CODEC_ID_MP2, CODEC_ID_MPEG1VIDEO, mpeg_mux_init, mpeg_mux_write_packet, mpeg_mux_end,};#endif#ifdef CONFIG_MPEG1VCD_MUXERAVOutputFormat mpeg1vcd_muxer = { "vcd", NULL_IF_CONFIG_SMALL("MPEG-1 System format (VCD)"), "video/mpeg", NULL, sizeof(MpegMuxContext), CODEC_ID_MP2, CODEC_ID_MPEG1VIDEO, mpeg_mux_init, mpeg_mux_write_packet, mpeg_mux_end,};#endif#ifdef CONFIG_MPEG2VOB_MUXERAVOutputFormat mpeg2vob_muxer = { "vob", NULL_IF_CONFIG_SMALL("MPEG-2 PS format (VOB)"), "video/mpeg", "vob", sizeof(MpegMuxContext), CODEC_ID_MP2, CODEC_ID_MPEG2VIDEO, mpeg_mux_init, mpeg_mux_write_packet, mpeg_mux_end,};#endif/* Same as mpeg2vob_mux except that the pack size is 2324 */#ifdef CONFIG_MPEG2SVCD_MUXERAVOutputFormat mpeg2svcd_muxer = { "svcd", NULL_IF_CONFIG_SMALL("MPEG-2 PS format (VOB)"), "video/mpeg", "vob", sizeof(MpegMuxContext), CODEC_ID_MP2, CODEC_ID_MPEG2VIDEO, mpeg_mux_init, mpeg_mux_write_packet, mpeg_mux_end,};#endif/* Same as mpeg2vob_mux except the 'is_dvd' flag is set to produce NAV pkts */#ifdef CONFIG_MPEG2DVD_MUXERAVOutputFormat mpeg2dvd_muxer = { "dvd", NULL_IF_CONFIG_SMALL("MPEG-2 PS format (DVD VOB)"), "video/mpeg", "dvd", sizeof(MpegMuxContext), CODEC_ID_MP2, CODEC_ID_MPEG2VIDEO, mpeg_mux_init, mpeg_mux_write_packet, mpeg_mux_end,};#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -