|
|
@@ -144,11 +144,14 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_str |
|
|
|
} else |
|
|
|
put_bits(&pb, 6, s->audio_bound); |
|
|
|
|
|
|
|
if (s->is_vcd) |
|
|
|
put_bits(&pb, 1, 0); /* see VCD standard, p. IV-7*/ |
|
|
|
else |
|
|
|
put_bits(&pb, 1, 1); /* variable bitrate*/ |
|
|
|
put_bits(&pb, 1, 1); /* non constrainted bit stream */ |
|
|
|
if (s->is_vcd) { |
|
|
|
/* see VCD standard, p. IV-7*/ |
|
|
|
put_bits(&pb, 1, 0); |
|
|
|
put_bits(&pb, 1, 1); |
|
|
|
} else { |
|
|
|
put_bits(&pb, 1, 0); /* variable bitrate*/ |
|
|
|
put_bits(&pb, 1, 0); /* non constrainted bit stream */ |
|
|
|
} |
|
|
|
|
|
|
|
if (s->is_vcd) { |
|
|
|
/* see VCD standard p IV-7 */ |
|
|
@@ -286,6 +289,9 @@ static int mpeg_mux_init(AVFormatContext *ctx) |
|
|
|
} else { |
|
|
|
stream->id = mpa_id++; |
|
|
|
} |
|
|
|
|
|
|
|
/* This value HAS to be used for VCD (see VCD standard, p. IV-7). |
|
|
|
Right now it is also used for everything else.*/ |
|
|
|
stream->max_buffer_size = 4 * 1024; |
|
|
|
s->audio_bound++; |
|
|
|
break; |
|
|
@@ -294,7 +300,13 @@ static int mpeg_mux_init(AVFormatContext *ctx) |
|
|
|
if (s->scr_stream_index == -1) |
|
|
|
s->scr_stream_index = i; |
|
|
|
stream->id = mpv_id++; |
|
|
|
stream->max_buffer_size = 46 * 1024; |
|
|
|
if (s->is_vcd) |
|
|
|
/* see VCD standard, p. IV-7*/ |
|
|
|
stream->max_buffer_size = 46 * 1024; |
|
|
|
else |
|
|
|
/* This value HAS to be used for SVCD (see SVCD standard, p. 26 V.2.3.2). |
|
|
|
Right now it is also used for everything else.*/ |
|
|
|
stream->max_buffer_size = 230 * 1024; |
|
|
|
s->video_bound++; |
|
|
|
break; |
|
|
|
default: |
|
|
@@ -465,7 +477,8 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (s->is_vcd && stream->packet_number==0) |
|
|
|
if ((s->is_vcd && stream->packet_number==0) |
|
|
|
|| (s->is_svcd && s->packet_number==0)) |
|
|
|
/* 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.*/ |
|
|
@@ -473,8 +486,12 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index, |
|
|
|
else { |
|
|
|
/* packet header size */ |
|
|
|
buf_index += 6; |
|
|
|
if (s->is_mpeg2) |
|
|
|
if (s->is_mpeg2) { |
|
|
|
buf_index += 3; |
|
|
|
if (stream->packet_number==0) |
|
|
|
buf_index += 3; /* PES extension */ |
|
|
|
buf_index += 1; /* obligatory stuffing byte */ |
|
|
|
} |
|
|
|
if (pts != AV_NOPTS_VALUE) { |
|
|
|
if (dts != pts) |
|
|
|
buf_index += 5 + 5; |
|
|
@@ -554,6 +571,8 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
uint8_t buffer[128]; |
|
|
|
int zero_trail_bytes = 0; |
|
|
|
int pad_packet_bytes = 0; |
|
|
|
int pes_flags; |
|
|
|
int general_pack = 0; /*"general" pack without data specific to one stream?*/ |
|
|
|
|
|
|
|
id = stream->id; |
|
|
|
|
|
|
@@ -595,11 +614,16 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
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, |
|
|
|
if ((s->is_vcd && stream->packet_number==0) |
|
|
|
|| (s->is_svcd && s->packet_number==0)) { |
|
|
|
/* for VCD 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.*/ |
|
|
|
/* For SVCD we fill the very first pack to increase compatibility with |
|
|
|
some DVD players. Not mandated by the standard.*/ |
|
|
|
if (s->is_svcd) |
|
|
|
general_pack = 1; /* the system header refers to both streams and no stream data*/ |
|
|
|
pad_packet_bytes = packet_size - zero_trail_bytes; |
|
|
|
} |
|
|
|
|
|
|
@@ -613,6 +637,9 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
/* packet header */ |
|
|
|
if (s->is_mpeg2) { |
|
|
|
header_len = 3; |
|
|
|
if (stream->packet_number==0) |
|
|
|
header_len += 3; /* PES extension */ |
|
|
|
header_len += 1; /* obligatory stuffing byte */ |
|
|
|
} else { |
|
|
|
header_len = 0; |
|
|
|
} |
|
|
@@ -639,6 +666,13 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
stuffing_size = payload_size - stream->buffer_ptr; |
|
|
|
if (stuffing_size < 0) |
|
|
|
stuffing_size = 0; |
|
|
|
if (stuffing_size > 16) { /*<=16 for MPEG-1, <=32 for MPEG-2*/ |
|
|
|
pad_packet_bytes += stuffing_size; |
|
|
|
packet_size -= stuffing_size; |
|
|
|
payload_size -= stuffing_size; |
|
|
|
stuffing_size = 0; |
|
|
|
} |
|
|
|
|
|
|
|
put_be32(&ctx->pb, startcode); |
|
|
|
|
|
|
|
put_be16(&ctx->pb, packet_size); |
|
|
@@ -650,21 +684,39 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
if (s->is_mpeg2) { |
|
|
|
put_byte(&ctx->pb, 0x80); /* mpeg2 id */ |
|
|
|
|
|
|
|
pes_flags=0; |
|
|
|
|
|
|
|
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); |
|
|
|
pes_flags |= 0x80; |
|
|
|
if (dts != pts) |
|
|
|
pes_flags |= 0x40; |
|
|
|
} |
|
|
|
|
|
|
|
/* Both the MPEG-2 and the SVCD standards demand that the |
|
|
|
P-STD_buffer_size field be included in the first packet of |
|
|
|
every stream. (see SVCD standard p. 26 V.2.3.1 and V.2.3.2 |
|
|
|
and MPEG-2 standard 2.7.7) */ |
|
|
|
if (stream->packet_number == 0) |
|
|
|
pes_flags |= 0x01; |
|
|
|
|
|
|
|
put_byte(&ctx->pb, pes_flags); /* flags */ |
|
|
|
put_byte(&ctx->pb, header_len - 3 + stuffing_size); |
|
|
|
|
|
|
|
if (pes_flags & 0x80) /*write pts*/ |
|
|
|
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) { |
|
|
@@ -694,9 +746,14 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (s->is_mpeg2) |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
/* output data */ |
|
|
|
put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size); |
|
|
@@ -711,7 +768,12 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
put_flush_packet(&ctx->pb); |
|
|
|
|
|
|
|
s->packet_number++; |
|
|
|
stream->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++; |
|
|
|
stream->nb_frames = 0; |
|
|
|
stream->frame_start_offset = 0; |
|
|
|
} |
|
|
@@ -781,6 +843,7 @@ static void compute_pts_dts(AVStream *st, int64_t *ppts, int64_t *pdts, |
|
|
|
pts = timestamp; |
|
|
|
dts = timestamp; |
|
|
|
} |
|
|
|
|
|
|
|
*ppts = pts & ((1LL << 33) - 1); |
|
|
|
*pdts = dts & ((1LL << 33) - 1); |
|
|
|
} |
|
|
@@ -789,8 +852,10 @@ static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts) |
|
|
|
{ |
|
|
|
MpegMuxContext *s = ctx->priv_data; |
|
|
|
int64_t scr; |
|
|
|
StreamInfo *stream; |
|
|
|
int i; |
|
|
|
|
|
|
|
if (s->is_vcd) |
|
|
|
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. |
|
|
@@ -802,7 +867,21 @@ static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts) |
|
|
|
will still be correct according to the standard. It just won't have |
|
|
|
the "recommended" value).*/ |
|
|
|
scr = 36000 + s->packet_number * 1200; |
|
|
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
for(i=0;i<ctx->nb_streams;i++) { |
|
|
|
stream = ctx->streams[i]->priv_data; |
|
|
|
|
|
|
|
if(scr > stream->start_pts && stream->start_pts!=AV_NOPTS_VALUE) { |
|
|
|
av_log(ctx, AV_LOG_DEBUG, "mpeg vcd: SCR above PTS (scr=%0.3f, stream index=%d, stream_pts=%0.3f).\n", scr/90000.0, i, stream->start_pts / 90000.0); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
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. */ |
|
|
@@ -814,6 +893,17 @@ static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts) |
|
|
|
scr = pts; |
|
|
|
else |
|
|
|
scr = s->last_scr; |
|
|
|
|
|
|
|
/* "Sanity hack": make sure that the SCR does not overtake the pts of |
|
|
|
buffered data that is still waiting to be written.*/ |
|
|
|
for(i=0;i<ctx->nb_streams;i++) { |
|
|
|
stream = ctx->streams[i]->priv_data; |
|
|
|
|
|
|
|
if(scr > stream->start_pts && stream->start_pts!=AV_NOPTS_VALUE) { |
|
|
|
/* av_log(ctx, AV_LOG_DEBUG, "mpeg: restricting scr to stream pts (scr=%0.3f, stream index=%d, stream_pts=%0.3f).\n", scr/90000.0, i, stream->start_pts / 90000.0); */ |
|
|
|
scr = stream->start_pts; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
s->last_scr=scr; |
|
|
@@ -834,6 +924,28 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, |
|
|
|
|
|
|
|
compute_pts_dts(st, &pts, &dts, timestamp); |
|
|
|
|
|
|
|
if(s->is_svcd) { |
|
|
|
/* offset pts and dts slightly into the future to be able |
|
|
|
to do the compatibility fix below.*/ |
|
|
|
pts = (pts + 2) & ((1LL << 33) - 1); |
|
|
|
dts = (dts + 2) & ((1LL << 33) - 1); |
|
|
|
|
|
|
|
if (stream->packet_number == 0 && dts == pts) |
|
|
|
/* For the very first packet we want to force the DTS to be included. |
|
|
|
This increases compatibility with lots of DVD players. |
|
|
|
Since the MPEG-2 standard mandates that DTS is only written when |
|
|
|
it is different from PTS we have to move it slightly into the past.*/ |
|
|
|
dts = (dts - 2) & ((1LL << 33) - 1); |
|
|
|
} |
|
|
|
if(s->is_vcd) { |
|
|
|
/* We have to offset the PTS, so that it is consistent with the SCR. |
|
|
|
SCR starts at 36000, but the first two packs contain only padding |
|
|
|
and the first pack from the other stream, respectively, may also have |
|
|
|
been written before. |
|
|
|
So the real data starts at SCR 36000+3*1200. */ |
|
|
|
pts = (pts + 36000 + 3600) & ((1LL << 33) - 1); |
|
|
|
dts = (dts + 36000 + 3600) & ((1LL << 33) - 1); |
|
|
|
} |
|
|
|
|
|
|
|
#if 0 |
|
|
|
update_scr(ctx,stream_index,pts); |
|
|
|