📄 mpegenc.c
字号:
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(av_fifo_generic_read(&stream->fifo, payload_size - stuffing_size, &put_buffer, &ctx->pb) < 0)
return -1;
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;
}
#endif
static 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, 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 + 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->bytes_to_iframe = av_fifo_size(&stream->fifo);
stream->align_iframe = 1;
stream->vobu_start_pts = pts;
}
}
av_fifo_write(&stream->fifo, buf, size);
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_MUXER
AVOutputFormat mpeg1system_muxer = {
"mpeg",
"MPEG1 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_MUXER
AVOutputFormat mpeg1vcd_muxer = {
"vcd",
"MPEG1 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_MUXER
AVOutputFormat mpeg2vob_muxer = {
"vob",
"MPEG2 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_MUXER
AVOutputFormat mpeg2svcd_muxer = {
"svcd",
"MPEG2 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_MUXER
AVOutputFormat mpeg2dvd_muxer = {
"dvd",
"MPEG2 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 + -