Mercurial > libavformat.hg
changeset 452:11d07f14b077 libavformat
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>)
author | michael |
---|---|
date | Mon, 26 Apr 2004 22:16:06 +0000 |
parents | 31784bdb76ee |
children | a699cf5c703d |
files | mpeg.c |
diffstat | 1 files changed, 138 insertions(+), 26 deletions(-) [+] |
line wrap: on
line diff
--- a/mpeg.c Sun Apr 25 13:30:21 2004 +0000 +++ b/mpeg.c Mon Apr 26 22:16:06 2004 +0000 @@ -144,11 +144,14 @@ } 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 @@ } 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 @@ 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 @@ } } - 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ } } - 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 @@ 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 @@ pts = timestamp; dts = timestamp; } + *ppts = pts & ((1LL << 33) - 1); *pdts = dts & ((1LL << 33) - 1); } @@ -789,8 +852,10 @@ { 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 @@ 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 @@ 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 @@ 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);