summaryrefslogtreecommitdiff
path: root/libavformat/mpeg.c
diff options
context:
space:
mode:
authorHauke Duden <H.NS.Duden@gmx.net>2004-04-26 22:16:06 +0000
committerMichael Niedermayer <michaelni@gmx.at>2004-04-26 22:16:06 +0000
commit224944895efe6ac23e3b8f9d35abfee9f5c6c440 (patch)
tree347f09ff0827c270706be1c8f2dcb4f8587ae578 /libavformat/mpeg.c
parentae4b7d5947c0c5ae68141c9d9fe0588a554fad94 (diff)
mpeg SVCD compatibility, SCR fixes, standard compliance
- fixed VBR+constrained bitstream header flags for non-VCD - more sane (and SVCD compatible) value for video stream->max_buffer_size - always write at least one PES header stuffing byte for MPEG-2 to prevent accidental start code generation - do not write more than 16 stuffing bytes in a PES header (not allowed). Use padding packets instead. - include a PES extension in the first MPEG-2 packet - fill the first pack of SVCD files with padding - "sanity hack" that prevents the SCR from overtaking the PTS for non-VCD - fixed VCD PTS values to correspond to the SCR - always include DTS in the first SVCD packet (fixes lots of compatibility problems with DVD players) patch by (Hauke Duden <H.NS.Duden at gmx dot net>) Originally committed as revision 3078 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/mpeg.c')
-rw-r--r--libavformat/mpeg.c164
1 files changed, 138 insertions, 26 deletions
diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c
index 6112d75192..a5feba8758 100644
--- a/libavformat/mpeg.c
+++ b/libavformat/mpeg.c
@@ -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);