[FFmpeg-devel] [bug/patch] MPEG-TS muxer: PCR not in sync withPTS/DTS

Baptiste Coudurier baptiste.coudurier
Tue Oct 27 23:12:35 CET 2009


Hi,

On 10/22/2009 12:51 PM, Mike Scheutzow wrote:
> Attached is a patch for the MPEG-TS muxer which makes it generate an
> accurate Constant Bitrate transport stream. This requires null packet
> insertion so that the PCR values are correct.
>
> This patch incorporates the work done by Niobos in
> ffmpeg-mpegts-vbr-4.diff, and also includes the follow-on fix I
> suggested to him.
>
> This patch does not solve all the problems I'm aware of with the ffmpeg
> mpegts muxer.
>
> In particular, there are still situations where the estimated bitrate is
> too small. For example, it is wrong for H.264 video streams, and for
> audio-only streams. Those problems are separate bugs. For now, the
> -muxrate option can be used with these type of input streams.
>
> Comments?
>
> --
> Mike Scheutzow
> scheutzow at alcatel-lucent.com
>
>
> mpeg-mux-cbr-v1.patch
>
>
> Index: libavformat/mpegtsenc.c
> ===================================================================
> --- libavformat/mpegtsenc.c	(revision 20231)
> +++ libavformat/mpegtsenc.c	(working copy)
> @@ -384,7 +384,7 @@
>       MpegTSService *service;
>       AVStream *st;
>       AVMetadataTag *title;
> -    int i, total_bit_rate;
> +    int i, total_bit_rate, nb_pkt;
>       const char *service_name;
>       uint64_t sdt_size, pat_pmt_size, pos;
>
> @@ -448,15 +448,6 @@
>           service->pcr_pid = ts_st->pid;
>       }
>
> -    if (total_bit_rate<= 8 * 1024)
> -        total_bit_rate = 8 * 1024;
> -    service->pcr_packet_period = (total_bit_rate * PCR_RETRANS_TIME) /
> -        (TS_PACKET_SIZE * 8 * 1000);
> -    ts->sdt_packet_period = (total_bit_rate * SDT_RETRANS_TIME) /
> -        (TS_PACKET_SIZE * 8 * 1000);
> -    ts->pat_packet_period = (total_bit_rate * PAT_RETRANS_TIME) /
> -        (TS_PACKET_SIZE * 8 * 1000);
> -
>       ts->mux_rate = 1; // avoid div by 0
>
>       /* write info at the start of the file, so that it will be fast to
> @@ -471,23 +462,36 @@
>       }
>       pat_pmt_size = url_ftell(s->pb) - pos;
>
> -    total_bit_rate +=
> -        total_bit_rate *  4 / TS_PACKET_SIZE           + /* TS  header size */
> -        SDT_RETRANS_TIME * 8 * sdt_size     / 1000     + /* SDT size */
> -        PAT_RETRANS_TIME * 8 * pat_pmt_size / 1000     + /* PAT+PMT size */
> -        PCR_RETRANS_TIME * 8 * 8            / 1000;      /* PCR size */
> +    if (total_bit_rate<= 8 * 1024)
> +        total_bit_rate = 8 * 1024;
>
> -    av_log(s, AV_LOG_DEBUG, "muxrate %d freq sdt %d pat %d\n",
> -           total_bit_rate, ts->sdt_packet_period, ts->pat_packet_period);
> +    total_bit_rate += 1000 * 8 * 8 / PCR_RETRANS_TIME;            /* PCR size */
> +    total_bit_rate += 4 * total_bit_rate / (TS_PACKET_SIZE-4)   + /* TS  header size */
> +         1000 * 8 * sdt_size             / SDT_RETRANS_TIME     + /* SDT size */
> +         1000 * 8 * pat_pmt_size         / PAT_RETRANS_TIME;      /* PAT+PMT size */

I think TS header size must be added first, then PCR, then SDT/PAT. 
Let's compute the bitrate correctly :)

 > [...]
>
> +    // want to output a PCR as soon as possible
> +    service->pcr_packet_count = service->pcr_packet_period;

Ok.

> +    av_log(s, AV_LOG_INFO, "calculated bitrate %dbps, muxrate %dbps, sdt every %d, pat/pmt every %d pkts\n",
> +           total_bit_rate, ts->mux_rate, ts->sdt_packet_period, ts->pat_packet_period);
> +
> +    // calc current pcr value using new ts->mux_rate (first ts pkt is pcr=0)
> +    nb_pkt = (sdt_size + pat_pmt_size) / TS_PACKET_SIZE;
> +    ts->cur_pcr = (nb_pkt * TS_PACKET_SIZE * 8 * 90000LL) / ts->mux_rate;

This should not be needed. cur_pcr is already adjusted in write_pat and 
write_pmt. That's why cur_pcr is adjusted below in the code.

 > [...]
>
> +/* Write a single null transport stream packet */
> +static void mpegts_insert_null_packet( AVFormatContext *s )

No space after '(' and before ')', this applies to the whole patch.

> [...]
 >
> +
> +/* Add a pes header to the front of payload, and segment into an integer number of
> + * ts packets. The final ts packet is padded using an over-sized adaptation header
> + * to exactly fill the last ts packet.
> + * NOTE: 'payload' contains a complete PES payload.
> + */
>   static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
>                                const uint8_t *payload, int payload_size,
>                                int64_t pts, int64_t dts)
> @@ -545,6 +602,7 @@
>       int val, is_start, len, header_len, write_pcr, private_code, flags;
>       int afc_len, stuffing_len;
>       int64_t pcr = -1; /* avoid warning */
> +    int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
>
>       is_start = 1;
>       while (payload_size>  0) {
> @@ -560,6 +618,18 @@
>               }
>           }
>
> +        if ( dts != AV_NOPTS_VALUE&&  (dts - (int64_t)ts->cur_pcr)>  delay ) {
> +
> +            /* pcr insert gets priority over null packet insert */
> +            if ( write_pcr ) {
> +                mpegts_insert_pcr_only(s, st);
> +            } else {
> +                mpegts_insert_null_packet(s);
> +            }
> +
> +            continue; /* recalculate write_pcr and possibly retransmit si_info */
> +        }
> +

Can't pcr be written along with data ?

Maybe something like:

if (!write_pcr && dts != AV_NOPTS_VALUE && dts - .. > delay) {
     mpegts_insert_null_packet(s);
     ts_st->service->pcr_packet_count++;
     continue;
}

>           /* prepare packet header */
>           q = buf;
>           *q++ = 0x47;
> @@ -709,7 +779,7 @@
>       uint8_t *buf= pkt->data;
>       uint8_t *data= NULL;
>       MpegTSWriteStream *ts_st = st->priv_data;
> -    const uint64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
> +    const int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);

Left over ?

[...]

-- 
Baptiste COUDURIER
Key fingerprint                 8D77134D20CC9220201FC5DB0AC9325C5C1ABAAA
FFmpeg maintainer                                  http://www.ffmpeg.org



More information about the ffmpeg-devel mailing list