diff options
author | Hauke Duden <H.NS.Duden@gmx.net> | 2004-02-19 22:34:13 +0000 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2004-02-19 22:34:13 +0000 |
commit | 245159265267f0636142114cef3ea33b26e99510 (patch) | |
tree | 532adb5d8355939b0776c9c7d50f6105483048cb | |
parent | 16806499fc13ec0a7664186a42a48d9154b2a8a3 (diff) | |
download | ffmpeg-245159265267f0636142114cef3ea33b26e99510.tar.gz |
improved VCD support patch by ("Hauke Duden" <H.NS.Duden at gmx dot net>)
- the first audio and video packs now contain only a system header and lots
of padding.
- no system headers in any packs other than the first ones
- the two system headers only contain information about "their" stream
- fixed some header values (muxrate, some flags, ...) so that they have the
values specified by the standard
- padding packs are inserted if the mux rate would be below 75 packs per
second (the rate must not be below or above that value).
- fixed the SCR of the packs
- 20 zero bytes are now inserted at the end of each audio pack, after the
data packet
Originally committed as revision 2804 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | ffmpeg.c | 2 | ||||
-rw-r--r-- | libavformat/mpeg.c | 593 |
2 files changed, 452 insertions, 143 deletions
@@ -3001,7 +3001,7 @@ static void opt_target(const char *arg) opt_video_codec("mpeg2video"); opt_audio_codec("mp2"); - opt_format("vcd"); + opt_format("svcd"); opt_frame_size(norm ? "480x480" : "480x576"); opt_gop_size(norm ? "18" : "15"); diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index 4362e1b1a6..6ba516370f 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -50,9 +50,14 @@ typedef struct { int video_bound; int is_mpeg2; int is_vcd; + int is_svcd; int scr_stream_index; /* stream from which the system clock is computed (VBR case) */ int64_t last_scr; /* current system clock */ + + double vcd_padding_bitrate; + int64_t vcd_padding_bytes_written; + } MpegMuxContext; #define PACK_START_CODE ((unsigned int)0x000001ba) @@ -80,6 +85,7 @@ static const int lpcm_freq_tab[4] = { 48000, 96000, 44100, 32000 }; extern AVOutputFormat mpeg1system_mux; extern AVOutputFormat mpeg1vcd_mux; extern AVOutputFormat mpeg2vob_mux; +extern AVOutputFormat mpeg2svcd_mux; static int put_pack_header(AVFormatContext *ctx, uint8_t *buf, int64_t timestamp) @@ -117,7 +123,7 @@ static int put_pack_header(AVFormatContext *ctx, return pbBufPtr(&pb) - pb.buf; } -static int put_system_header(AVFormatContext *ctx, uint8_t *buf) +static int put_system_header(AVFormatContext *ctx, uint8_t *buf,int only_for_stream_id) { MpegMuxContext *s = ctx->priv_data; int size, rate_bound, i, private_stream_coded, id; @@ -132,40 +138,67 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf) rate_bound = s->mux_rate; /* maximum bit rate of the multiplexed stream */ put_bits(&pb, 22, rate_bound); put_bits(&pb, 1, 1); /* marker */ - put_bits(&pb, 6, s->audio_bound); + if (s->is_vcd && only_for_stream_id==VIDEO_ID) { + /* This header applies only to the video stream (see VCD standard p. IV-7)*/ + put_bits(&pb, 6, 0); + } else + put_bits(&pb, 6, s->audio_bound); - put_bits(&pb, 1, 1); /* variable bitrate */ + 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 */ - put_bits(&pb, 1, 0); /* audio locked */ - put_bits(&pb, 1, 0); /* video locked */ + if (s->is_vcd) { + /* see VCD standard p IV-7 */ + put_bits(&pb, 1, 1); /* audio locked */ + put_bits(&pb, 1, 1); /* video locked */ + } else { + put_bits(&pb, 1, 0); /* audio locked */ + put_bits(&pb, 1, 0); /* video locked */ + } + put_bits(&pb, 1, 1); /* marker */ - put_bits(&pb, 5, s->video_bound); + if (s->is_vcd && only_for_stream_id==AUDIO_ID) { + /* This header applies only to the audio stream (see VCD standard p. IV-7)*/ + put_bits(&pb, 5, 0); + } else + put_bits(&pb, 5, s->video_bound); + put_bits(&pb, 8, 0xff); /* reserved byte */ /* audio stream info */ private_stream_coded = 0; for(i=0;i<ctx->nb_streams;i++) { StreamInfo *stream = ctx->streams[i]->priv_data; - id = stream->id; - if (id < 0xc0) { - /* special case for private streams (AC3 use that) */ - if (private_stream_coded) - continue; - private_stream_coded = 1; - id = 0xbd; - } - put_bits(&pb, 8, id); /* stream ID */ - put_bits(&pb, 2, 3); - if (id < 0xe0) { - /* audio */ - put_bits(&pb, 1, 0); - put_bits(&pb, 13, stream->max_buffer_size / 128); - } else { - /* video */ - put_bits(&pb, 1, 1); - put_bits(&pb, 13, stream->max_buffer_size / 1024); + + /* For VCDs, only include the stream info for the stream + that the pack which contains this system belongs to. + (see VCD standard p. IV-7) */ + if ( !s->is_vcd || stream->id==only_for_stream_id + || only_for_stream_id==0) { + + id = stream->id; + if (id < 0xc0) { + /* special case for private streams (AC3 use that) */ + if (private_stream_coded) + continue; + private_stream_coded = 1; + id = 0xbd; + } + put_bits(&pb, 8, id); /* stream ID */ + put_bits(&pb, 2, 3); + if (id < 0xe0) { + /* audio */ + put_bits(&pb, 1, 0); + put_bits(&pb, 13, stream->max_buffer_size / 128); + } else { + /* video */ + put_bits(&pb, 1, 1); + put_bits(&pb, 13, stream->max_buffer_size / 1024); + } } } flush_put_bits(&pb); @@ -202,15 +235,21 @@ static int mpeg_mux_init(AVFormatContext *ctx) int bitrate, i, mpa_id, mpv_id, ac3_id, lpcm_id, j; AVStream *st; StreamInfo *stream; + int audio_bitrate; + int video_bitrate; s->packet_number = 0; s->is_vcd = (ctx->oformat == &mpeg1vcd_mux); - s->is_mpeg2 = (ctx->oformat == &mpeg2vob_mux); + s->is_svcd = (ctx->oformat == &mpeg2svcd_mux); + s->is_mpeg2 = (ctx->oformat == &mpeg2vob_mux || ctx->oformat == &mpeg2svcd_mux); - if (s->is_vcd) - s->packet_size = 2324; /* VCD packet size */ + if (s->is_vcd || s->is_svcd) + s->packet_size = 2324; /* VCD/SVCD packet size */ else s->packet_size = 2048; + + s->vcd_padding_bytes_written = 0; + s->vcd_padding_bitrate=0; s->audio_bound = 0; s->video_bound = 0; @@ -266,14 +305,55 @@ static int mpeg_mux_init(AVFormatContext *ctx) if (s->scr_stream_index == -1) s->scr_stream_index = 0; - /* we increase slightly the bitrate to take into account the - headers. XXX: compute it exactly */ - bitrate = 2000; + bitrate = 0; + audio_bitrate = 0; + video_bitrate = 0; for(i=0;i<ctx->nb_streams;i++) { st = ctx->streams[i]; + stream = (StreamInfo*) st->priv_data; + bitrate += st->codec.bit_rate; + + if (stream->id==AUDIO_ID) + audio_bitrate += st->codec.bit_rate; + else if (stream->id==VIDEO_ID) + video_bitrate += st->codec.bit_rate; + } + + if (s->is_vcd) { + double overhead_rate; + + /* The VCD standard mandates that the mux_rate field is 3528 + (see standard p. IV-6). + The value is actually "wrong", i.e. if you calculate + it using the normal formula and the 75 sectors per second transfer + rate you get a different value because the real pack size is 2324, + not 2352. But the standard explicitly specifies that the mux_rate + field in the header must have this value.*/ + s->mux_rate=2352 * 75 / 50; /* = 3528*/ + + /* The VCD standard states that the muxed stream must be + exactly 75 packs / second (the data rate of a single speed cdrom). + Since the video bitrate (probably 1150000 bits/sec) will be below + the theoretical maximum we have to add some padding packets + to make up for the lower data rate. + (cf. VCD standard p. IV-6 )*/ + + /* Add the header overhead to the data rate. + 2279 data bytes per audio pack, 2294 data bytes per video pack*/ + overhead_rate = ((audio_bitrate / 8.0) / 2279) * (2324 - 2279); + overhead_rate += ((video_bitrate / 8.0) / 2294) * (2324 - 2294); + overhead_rate *= 8; + + /* Add padding so that the full bitrate is 2324*75 bytes/sec */ + s->vcd_padding_bitrate = 2324 * 75 * 8 - (bitrate + overhead_rate); + + } else { + /* we increase slightly the bitrate to take into account the + headers. XXX: compute it exactly */ + bitrate += 2000; + s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50); } - s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50); if (s->is_vcd || s->is_mpeg2) /* every packet */ @@ -290,8 +370,10 @@ static int mpeg_mux_init(AVFormatContext *ctx) /* every 200 packets. Need to look at the spec. */ s->system_header_freq = s->pack_header_freq * 40; else if (s->is_vcd) - /* every 40 packets, this is my invention */ - s->system_header_freq = s->pack_header_freq * 40; + /* the standard mandates that there are only two system headers + in the whole file: one in the first packet of each stream. + (see standard p. IV-7 and IV-8) */ + s->system_header_freq = 0x7fffffff; else s->system_header_freq = s->pack_header_freq * 5; @@ -323,6 +405,30 @@ static inline void put_timestamp(ByteIOContext *pb, int id, int64_t timestamp) } +/* return the number of padding bytes that should be inserted into + the multiplexed stream.*/ +static int get_vcd_padding_size(AVFormatContext *ctx, int64_t pts) +{ + MpegMuxContext *s = ctx->priv_data; + int pad_bytes = 0; + + if (s->vcd_padding_bitrate > 0 && pts!=AV_NOPTS_VALUE) + { + int64_t full_pad_bytes; + + full_pad_bytes = (int64_t)((s->vcd_padding_bitrate * (pts / 90000.0)) / 8.0); + pad_bytes = (int) (full_pad_bytes - s->vcd_padding_bytes_written); + + if (pad_bytes<0) + /* might happen if we have already padded to a later timestamp. This + can occur if another stream has already advanced further.*/ + pad_bytes=0; + } + + return pad_bytes; +} + + /* return the exact available payload size for the next packet for stream 'stream_index'. 'pts' and 'dts' are only used to know if timestamps are needed in the packet header. */ @@ -333,6 +439,8 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index, int buf_index; StreamInfo *stream; + stream = ctx->streams[stream_index]->priv_data; + buf_index = 0; if (((s->packet_number % s->pack_header_freq) == 0)) { /* pack header size */ @@ -340,41 +448,100 @@ static int get_packet_payload_size(AVFormatContext *ctx, int stream_index, buf_index += 14; else buf_index += 12; - if ((s->packet_number % s->system_header_freq) == 0) - buf_index += s->system_header_size; + + if (s->is_vcd) { + /* there is exactly one system header for each stream in a VCD MPEG, + One in the very first video packet and one in the very first + audio packet (see VCD standard p. IV-7 and IV-8).*/ + + if (stream->packet_number==0) + /* The system headers refer only to the stream they occur in, + so they have a constant size.*/ + buf_index += 15; + + } else { + if ((s->packet_number % s->system_header_freq) == 0) + buf_index += s->system_header_size; + } } - /* packet header size */ - buf_index += 6; - if (s->is_mpeg2) - buf_index += 3; - if (pts != AV_NOPTS_VALUE) { - if (dts != pts) - buf_index += 5 + 5; - else - buf_index += 5; - } else { - if (!s->is_mpeg2) - buf_index++; - } - - stream = ctx->streams[stream_index]->priv_data; - if (stream->id < 0xc0) { - /* AC3/LPCM private data header */ - buf_index += 4; - if (stream->id >= 0xa0) { - int n; + if (s->is_vcd && stream->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.*/ + buf_index += s->packet_size - buf_index; + else { + /* packet header size */ + buf_index += 6; + if (s->is_mpeg2) buf_index += 3; - /* NOTE: we round the payload size to an integer number of - LPCM samples */ - n = (s->packet_size - buf_index) % stream->lpcm_align; - if (n) - buf_index += (stream->lpcm_align - n); + if (pts != AV_NOPTS_VALUE) { + if (dts != pts) + buf_index += 5 + 5; + else + buf_index += 5; + + } else { + if (!s->is_mpeg2) + buf_index++; + } + + if (stream->id < 0xc0) { + /* AC3/LPCM private data header */ + buf_index += 4; + if (stream->id >= 0xa0) { + int n; + buf_index += 3; + /* NOTE: we round the payload size to an integer number of + LPCM samples */ + n = (s->packet_size - buf_index) % stream->lpcm_align; + if (n) + buf_index += (stream->lpcm_align - n); + } } + + if (s->is_vcd && stream->id == AUDIO_ID) + /* The VCD standard demands that 20 zero bytes follow + each audio packet (see standard p. IV-8).*/ + buf_index+=20; } return s->packet_size - buf_index; } +/* Write an MPEG padding packet header. */ +static int put_padding_header(AVFormatContext *ctx,uint8_t* buf, int full_padding_size) +{ + MpegMuxContext *s = ctx->priv_data; + int size = full_padding_size - 6; /* subtract header length */ + + buf[0] = (uint8_t)(PADDING_STREAM >> 24); + buf[1] = (uint8_t)(PADDING_STREAM >> 16); + buf[2] = (uint8_t)(PADDING_STREAM >> 8); + buf[3] = (uint8_t)(PADDING_STREAM); + buf[4] = (uint8_t)(size >> 8); + buf[5] = (uint8_t)(size & 0xff); + + if (!s->is_mpeg2) { + buf[6] = 0x0f; + return 7; + } else + return 6; +} + +static void put_padding_packet(AVFormatContext *ctx, ByteIOContext *pb,int packet_bytes) +{ + uint8_t buffer[7]; + int size, i; + + size = put_padding_header(ctx,buffer, packet_bytes); + put_buffer(pb, buffer, size); + packet_bytes -= size; + + for(i=0;i<packet_bytes;i++) + put_byte(pb, 0xff); +} + + /* flush the packet on stream stream_index */ static void flush_packet(AVFormatContext *ctx, int stream_index, int64_t pts, int64_t dts, int64_t scr) @@ -385,6 +552,8 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, int size, payload_size, startcode, id, stuffing_size, i, header_len; int packet_size; uint8_t buffer[128]; + int zero_trail_bytes = 0; + int pad_packet_bytes = 0; id = stream->id; @@ -394,109 +563,151 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, #endif buf_ptr = buffer; + if (((s->packet_number % s->pack_header_freq) == 0)) { /* output pack and systems header if needed */ size = put_pack_header(ctx, buf_ptr, scr); buf_ptr += size; - if ((s->packet_number % s->system_header_freq) == 0) { - size = put_system_header(ctx, buf_ptr); - buf_ptr += size; + + if (s->is_vcd) { + /* there is exactly one system header for each stream in a VCD MPEG, + One in the very first video packet and one in the very first + audio packet (see VCD standard p. IV-7 and IV-8).*/ + + if (stream->packet_number==0) { + size = put_system_header(ctx, buf_ptr, id); + buf_ptr += size; + } + } else { + if ((s->packet_number % s->system_header_freq) == 0) { + size = put_system_header(ctx, buf_ptr, 0); + buf_ptr += size; + } } } size = buf_ptr - buffer; put_buffer(&ctx->pb, buffer, size); - /* packet header */ - if (s->is_mpeg2) { - header_len = 3; - } else { - header_len = 0; - } - if (pts != AV_NOPTS_VALUE) { - if (dts != pts) - header_len += 5 + 5; - else - header_len += 5; - } else { - if (!s->is_mpeg2) - header_len++; + packet_size = s->packet_size - size; + + if (s->is_vcd && id == AUDIO_ID) + /* The VCD standard demands that 20 zero bytes follow + 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, + 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.*/ + pad_packet_bytes = packet_size - zero_trail_bytes; } - packet_size = s->packet_size - (size + 6); - payload_size = packet_size - header_len; - if (id < 0xc0) { - startcode = PRIVATE_STREAM_1; - payload_size -= 4; - if (id >= 0xa0) - payload_size -= 3; - } else { - startcode = 0x100 + id; - } + packet_size -= pad_packet_bytes + zero_trail_bytes; - stuffing_size = payload_size - stream->buffer_ptr; - if (stuffing_size < 0) - stuffing_size = 0; - put_be32(&ctx->pb, startcode); + if (packet_size > 0) { - put_be16(&ctx->pb, packet_size); + /* packet header size */ + packet_size -= 6; + + /* packet header */ + if (s->is_mpeg2) { + header_len = 3; + } else { + header_len = 0; + } + if (pts != AV_NOPTS_VALUE) { + if (dts != pts) + header_len += 5 + 5; + else + header_len += 5; + } else { + if (!s->is_mpeg2) + header_len++; + } - if (!s->is_mpeg2) - for(i=0;i<stuffing_size;i++) - put_byte(&ctx->pb, 0xff); + payload_size = packet_size - header_len; + if (id < 0xc0) { + startcode = PRIVATE_STREAM_1; + payload_size -= 4; + if (id >= 0xa0) + payload_size -= 3; + } else { + startcode = 0x100 + id; + } - if (s->is_mpeg2) { - put_byte(&ctx->pb, 0x80); /* mpeg2 id */ + stuffing_size = payload_size - stream->buffer_ptr; + if (stuffing_size < 0) + stuffing_size = 0; + put_be32(&ctx->pb, startcode); - 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); + put_be16(&ctx->pb, packet_size); + + if (!s->is_mpeg2) + for(i=0;i<stuffing_size;i++) + put_byte(&ctx->pb, 0xff); + + if (s->is_mpeg2) { + put_byte(&ctx->pb, 0x80); /* mpeg2 id */ + + 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, 0x80); /* flags */ + put_byte(&ctx->pb, 0x00); /* 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); - } - } else { - if (pts != AV_NOPTS_VALUE) { - if (dts != pts) { - put_timestamp(&ctx->pb, 0x03, pts); - put_timestamp(&ctx->pb, 0x01, dts); + 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_timestamp(&ctx->pb, 0x02, pts); + put_byte(&ctx->pb, 0x0f); } - } else { - put_byte(&ctx->pb, 0x0f); } - } - 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 { - /* AC3 */ - put_byte(&ctx->pb, stream->nb_frames); - put_be16(&ctx->pb, stream->frame_start_offset); + 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 { + /* AC3 */ + put_byte(&ctx->pb, stream->nb_frames); + put_be16(&ctx->pb, stream->frame_start_offset); + } } + + if (s->is_mpeg2) + for(i=0;i<stuffing_size;i++) + put_byte(&ctx->pb, 0xff); + + /* output data */ + put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size); } - if (s->is_mpeg2) - for(i=0;i<stuffing_size;i++) - put_byte(&ctx->pb, 0xff); + if (pad_packet_bytes > 0) + put_padding_packet(ctx,&ctx->pb, pad_packet_bytes); - /* output data */ - put_buffer(&ctx->pb, stream->buffer, payload_size - stuffing_size); + for(i=0;i<zero_trail_bytes;i++) + put_byte(&ctx->pb, 0x00); + put_flush_packet(&ctx->pb); s->packet_number++; @@ -505,6 +716,31 @@ static void flush_packet(AVFormatContext *ctx, int stream_index, stream->frame_start_offset = 0; } +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++; +} + /* XXX: move that to upper layer */ /* XXX: we assume that there are always 'max_b_frames' between reference frames. A better solution would be to use the AVFrame pts @@ -549,6 +785,43 @@ static void compute_pts_dts(AVStream *st, int64_t *ppts, int64_t *pdts, *pdts = dts & ((1LL << 33) - 1); } +static int64_t update_scr(AVFormatContext *ctx,int stream_index,int64_t pts) +{ + MpegMuxContext *s = ctx->priv_data; + int64_t scr; + + 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. + 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; + 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. */ + + /* XXX: system clock should be computed precisely, especially for + CBR case. The current mode gives at least something coherent */ + if (stream_index == s->scr_stream_index + && pts != AV_NOPTS_VALUE) + scr = pts; + else + scr = s->last_scr; + } + + s->last_scr=scr; + + return scr; +} + + static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, const uint8_t *buf, int size, int64_t timestamp) @@ -558,15 +831,13 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, StreamInfo *stream = st->priv_data; int64_t pts, dts, new_start_pts, new_start_dts; int len, avail_size; - + compute_pts_dts(st, &pts, &dts, timestamp); - /* XXX: system clock should be computed precisely, especially for - CBR case. The current mode gives at least something coherent */ - if (stream_index == s->scr_stream_index) - s->last_scr = pts; #if 0 + update_scr(ctx,stream_index,pts); + printf("%d: pts=%0.3f dts=%0.3f scr=%0.3f\n", stream_index, pts / 90000.0, @@ -586,10 +857,15 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, new_start_pts, new_start_dts); if (stream->buffer_ptr >= avail_size) { + + update_scr(ctx,stream_index,stream->start_pts); + /* unlikely case: outputing the pts or dts increase the packet size so that we cannot write the start of the next packet. In this case, we must flush the current packet with - padding */ + padding. + Note: this always happens for the first audio and video packet + in a VCD file, since they do not carry any data.*/ flush_packet(ctx, stream_index, stream->start_pts, stream->start_dts, s->last_scr); stream->buffer_ptr = 0; @@ -611,10 +887,23 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, int stream_index, buf += len; size -= len; if (stream->buffer_ptr >= avail_size) { + + update_scr(ctx,stream_index,stream->start_pts); + /* if packet full, we send it now */ flush_packet(ctx, stream_index, stream->start_pts, stream->start_dts, s->last_scr); stream->buffer_ptr = 0; + + 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->start_pts) ) >= s->packet_size) + put_vcd_padding_sector(ctx); + } + /* Make sure only the FIRST pes packet for this frame has a timestamp */ stream->start_pts = AV_NOPTS_VALUE; @@ -635,6 +924,8 @@ static int mpeg_mux_end(AVFormatContext *ctx) for(i=0;i<ctx->nb_streams;i++) { stream = ctx->streams[i]->priv_data; if (stream->buffer_ptr > 0) { + update_scr(ctx,i,stream->start_pts); + /* NOTE: we can always write the remaining data as it was tested before in mpeg_mux_write_packet() */ flush_packet(ctx, i, stream->start_pts, stream->start_dts, @@ -1139,7 +1430,7 @@ static int mpegps_read_seek(AVFormatContext *s, start_pos= pos; // read the next timestamp - dts = mpegps_read_dts(s, stream_index, &pos, 1); + dts = mpegps_read_dts(s, stream_index, &pos, 1); if(pos == pos_max) no_change++; else @@ -1214,6 +1505,23 @@ static AVOutputFormat mpeg2vob_mux = { mpeg_mux_write_packet, mpeg_mux_end, }; + +/* Same as mpeg2vob_mux except that the pack size is 2324 */ +static AVOutputFormat mpeg2svcd_mux = { + "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 //CONFIG_ENCODERS AVInputFormat mpegps_demux = { @@ -1233,6 +1541,7 @@ int mpegps_init(void) av_register_output_format(&mpeg1system_mux); av_register_output_format(&mpeg1vcd_mux); av_register_output_format(&mpeg2vob_mux); + av_register_output_format(&mpeg2svcd_mux); #endif //CONFIG_ENCODERS av_register_input_format(&mpegps_demux); return 0; |