[FFmpeg-devel,v2] avformat/mpegts: reduce buffering during initialization

Submitted by Andriy Gelman on March 6, 2019, 6:01 a.m.

Details

Message ID 20190306060158.17003-1-andriy.gelman@gmail.com
State New
Headers show

Commit Message

Andriy Gelman March 6, 2019, 6:01 a.m.
From: Andriy Gelman <andriy.gelman@gmail.com>

Reduces buffering latency with low bitrate streams, where
8192 bytes can mean several seconds.
---
 libavformat/mpegts.c | 60 +++++++++++++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 23 deletions(-)

Comments

Carl Eugen Hoyos March 6, 2019, 7:50 a.m.
2019-03-06 7:01 GMT+01:00, Andriy Gelman <andriy.gelman@gmail.com>:
> From: Andriy Gelman <andriy.gelman@gmail.com>
>
> Reduces buffering latency with low bitrate streams, where
> 8192 bytes can mean several seconds.

Would it be an alternative to add an option that allows to force
the packet size?

Carl Eugen
Andriy Gelman March 6, 2019, 3:33 p.m.
> Would it be an alternative to add an option that allows to force
> the packet size?

I like the idea. I guess the options are:
1. Set packet size + Use old version (fixed 8192 buffer) to estimate
parameter if not set by user.
2. Set packet size + Use new version (adaptive buffer) to estimate
parameter if not set by user.

Regards,
Andriy


On Wed, 6 Mar 2019 at 02:51, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:

> 2019-03-06 7:01 GMT+01:00, Andriy Gelman <andriy.gelman@gmail.com>:
> > From: Andriy Gelman <andriy.gelman@gmail.com>
> >
> > Reduces buffering latency with low bitrate streams, where
> > 8192 bytes can mean several seconds.
>
> Would it be an alternative to add an option that allows to force
> the packet size?
>
> Carl Eugen
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Marton Balint March 6, 2019, 8:45 p.m.
On Wed, 6 Mar 2019, Andriy Gelman wrote:

> From: Andriy Gelman <andriy.gelman@gmail.com>
>
> Reduces buffering latency with low bitrate streams, where
> 8192 bytes can mean several seconds.
> ---
> libavformat/mpegts.c | 60 +++++++++++++++++++++++++++-----------------
> 1 file changed, 37 insertions(+), 23 deletions(-)
>
> diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
> index b04fd7b4f4..fcb5b488d8 100644
> --- a/libavformat/mpegts.c
> +++ b/libavformat/mpegts.c
> @@ -53,6 +53,10 @@
>         (prev_dividend) = (dividend);                                          \
>     } while (0)
> 
> +#define PROBE_PACKET_MAX_BUF 8192
> +#define PROBE_PACKET_STEP 512
> +#define PROBE_PACKET_MARGIN 5
> +
> enum MpegTSFilterType {
>     MPEGTS_PES,
>     MPEGTS_SECTION,
> @@ -591,28 +595,42 @@ static int analyze(const uint8_t *buf, int size, int packet_size,
>     return best_score - FFMAX(stat_all - 10*best_score, 0)/10;
> }
> 
> -/* autodetect fec presence. Must have at least 1024 bytes  */
> -static int get_packet_size(const uint8_t *buf, int size)
> +/* autodetect fec presence */
> +static int get_packet_size(AVIOContext* pb)
> {
>     int score, fec_score, dvhs_score;
> +    int margin;
> +    int ret;
> 
> -    if (size < (TS_FEC_PACKET_SIZE * 5 + 1))
> -        return AVERROR_INVALIDDATA;
> +    /*init buffer to store stream for probing */
> +    uint8_t buf[PROBE_PACKET_MAX_BUF] = {0};
> +    int buf_size = 0;
> 
> -    score      = analyze(buf, size, TS_PACKET_SIZE,      0);
> -    dvhs_score = analyze(buf, size, TS_DVHS_PACKET_SIZE, 0);
> -    fec_score  = analyze(buf, size, TS_FEC_PACKET_SIZE,  0);
> -    av_log(NULL, AV_LOG_TRACE, "score: %d, dvhs_score: %d, fec_score: %d \n",
> -            score, dvhs_score, fec_score);
> -
> -    if (score > fec_score && score > dvhs_score)
> -        return TS_PACKET_SIZE;
> -    else if (dvhs_score > score && dvhs_score > fec_score)
> -        return TS_DVHS_PACKET_SIZE;
> -    else if (score < fec_score && dvhs_score < fec_score)
> -        return TS_FEC_PACKET_SIZE;
> -    else
> -        return AVERROR_INVALIDDATA;
> +    while (buf_size + PROBE_PACKET_STEP <= PROBE_PACKET_MAX_BUF) {
> +        ret = avio_read(pb, buf + buf_size, PROBE_PACKET_STEP);
> +        if (ret < 0)
> +            break;

If EOF happens on STEP boundary then you return INVALIDDATA instead 
of comparing last scores with 0 margin...

> +        buf_size += ret;
> +
> +        score      = analyze(buf, buf_size, TS_PACKET_SIZE,      0);
> +        dvhs_score = analyze(buf, buf_size, TS_DVHS_PACKET_SIZE, 0);
> +        fec_score  = analyze(buf, buf_size, TS_FEC_PACKET_SIZE,  0);
> +        av_log(NULL, AV_LOG_TRACE, "Probe: %d, score: %d, dvhs_score: %d, fec_score: %d \n",
> +            buf_size, score, dvhs_score, fec_score);
> +
> +        if (buf_size < PROBE_PACKET_MAX_BUF && ret == PROBE_PACKET_STEP)
> +          margin = PROBE_PACKET_MARGIN; /*if buffer not filled and no eof */
> +        else
> +          margin = 0;
> +
> +        if (score > FFMAX(fec_score, dvhs_score) + margin)
> +          return TS_PACKET_SIZE;
> +        else if (dvhs_score > FFMAX(score, fec_score) + margin)
> +          return TS_DVHS_PACKET_SIZE;
> +        else if (fec_score > FFMAX(score, dvhs_score) + margin)
> +          return TS_FEC_PACKET_SIZE;
> +    }
> +    return AVERROR_INVALIDDATA;
> }
> 
> typedef struct SectionHeader {
> @@ -2841,8 +2859,6 @@ static int mpegts_read_header(AVFormatContext *s)
> {
>     MpegTSContext *ts = s->priv_data;
>     AVIOContext *pb   = s->pb;
> -    uint8_t buf[8 * 1024] = {0};
> -    int len;
>     int64_t pos, probesize = s->probesize;
>
>     s->internal->prefer_codec_framerate = 1;
> @@ -2850,10 +2866,8 @@ static int mpegts_read_header(AVFormatContext *s)
>     if (ffio_ensure_seekback(pb, probesize) < 0)
>         av_log(s, AV_LOG_WARNING, "Failed to allocate buffers for seekback\n");
> 
> -    /* read the first 8192 bytes to get packet size */
>     pos = avio_tell(pb);
> -    len = avio_read(pb, buf, sizeof(buf));
> -    ts->raw_packet_size = get_packet_size(buf, len);
> +    ts->raw_packet_size = get_packet_size(pb);
>     if (ts->raw_packet_size <= 0) {
>         av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n");
>         ts->raw_packet_size = TS_PACKET_SIZE;
> --

Regards,
Marton

Patch hide | download patch | download mbox

diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index b04fd7b4f4..fcb5b488d8 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -53,6 +53,10 @@ 
         (prev_dividend) = (dividend);                                          \
     } while (0)
 
+#define PROBE_PACKET_MAX_BUF 8192
+#define PROBE_PACKET_STEP 512
+#define PROBE_PACKET_MARGIN 5
+
 enum MpegTSFilterType {
     MPEGTS_PES,
     MPEGTS_SECTION,
@@ -591,28 +595,42 @@  static int analyze(const uint8_t *buf, int size, int packet_size,
     return best_score - FFMAX(stat_all - 10*best_score, 0)/10;
 }
 
-/* autodetect fec presence. Must have at least 1024 bytes  */
-static int get_packet_size(const uint8_t *buf, int size)
+/* autodetect fec presence */
+static int get_packet_size(AVIOContext* pb)
 {
     int score, fec_score, dvhs_score;
+    int margin;
+    int ret;
 
-    if (size < (TS_FEC_PACKET_SIZE * 5 + 1))
-        return AVERROR_INVALIDDATA;
+    /*init buffer to store stream for probing */
+    uint8_t buf[PROBE_PACKET_MAX_BUF] = {0};
+    int buf_size = 0;
 
-    score      = analyze(buf, size, TS_PACKET_SIZE,      0);
-    dvhs_score = analyze(buf, size, TS_DVHS_PACKET_SIZE, 0);
-    fec_score  = analyze(buf, size, TS_FEC_PACKET_SIZE,  0);
-    av_log(NULL, AV_LOG_TRACE, "score: %d, dvhs_score: %d, fec_score: %d \n",
-            score, dvhs_score, fec_score);
-
-    if (score > fec_score && score > dvhs_score)
-        return TS_PACKET_SIZE;
-    else if (dvhs_score > score && dvhs_score > fec_score)
-        return TS_DVHS_PACKET_SIZE;
-    else if (score < fec_score && dvhs_score < fec_score)
-        return TS_FEC_PACKET_SIZE;
-    else
-        return AVERROR_INVALIDDATA;
+    while (buf_size + PROBE_PACKET_STEP <= PROBE_PACKET_MAX_BUF) {
+        ret = avio_read(pb, buf + buf_size, PROBE_PACKET_STEP);
+        if (ret < 0)
+            break;
+        buf_size += ret;
+
+        score      = analyze(buf, buf_size, TS_PACKET_SIZE,      0);
+        dvhs_score = analyze(buf, buf_size, TS_DVHS_PACKET_SIZE, 0);
+        fec_score  = analyze(buf, buf_size, TS_FEC_PACKET_SIZE,  0);
+        av_log(NULL, AV_LOG_TRACE, "Probe: %d, score: %d, dvhs_score: %d, fec_score: %d \n",
+            buf_size, score, dvhs_score, fec_score);
+
+        if (buf_size < PROBE_PACKET_MAX_BUF && ret == PROBE_PACKET_STEP)
+          margin = PROBE_PACKET_MARGIN; /*if buffer not filled and no eof */
+        else
+          margin = 0;
+
+        if (score > FFMAX(fec_score, dvhs_score) + margin)
+          return TS_PACKET_SIZE;
+        else if (dvhs_score > FFMAX(score, fec_score) + margin)
+          return TS_DVHS_PACKET_SIZE;
+        else if (fec_score > FFMAX(score, dvhs_score) + margin)
+          return TS_FEC_PACKET_SIZE;
+    }
+    return AVERROR_INVALIDDATA;
 }
 
 typedef struct SectionHeader {
@@ -2841,8 +2859,6 @@  static int mpegts_read_header(AVFormatContext *s)
 {
     MpegTSContext *ts = s->priv_data;
     AVIOContext *pb   = s->pb;
-    uint8_t buf[8 * 1024] = {0};
-    int len;
     int64_t pos, probesize = s->probesize;
 
     s->internal->prefer_codec_framerate = 1;
@@ -2850,10 +2866,8 @@  static int mpegts_read_header(AVFormatContext *s)
     if (ffio_ensure_seekback(pb, probesize) < 0)
         av_log(s, AV_LOG_WARNING, "Failed to allocate buffers for seekback\n");
 
-    /* read the first 8192 bytes to get packet size */
     pos = avio_tell(pb);
-    len = avio_read(pb, buf, sizeof(buf));
-    ts->raw_packet_size = get_packet_size(buf, len);
+    ts->raw_packet_size = get_packet_size(pb);
     if (ts->raw_packet_size <= 0) {
         av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n");
         ts->raw_packet_size = TS_PACKET_SIZE;