diff mbox series

[FFmpeg-devel,v2,1/3] avformat/fifo: add options to slow down writing packets to match real time approximately

Message ID 1588832208-63370-1-git-send-email-leozhang@qiyi.com
State New
Headers show
Series Patch set to delay output live stream
Related show

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

leozhang May 7, 2020, 6:16 a.m. UTC
Suggested-by: Nicolas George <george@nsup.org>
Reviewed-by:  Nicolas George <george@nsup.org>
Reviewed-by:  Marton Balint <cus@passwd.hu>
Reviewed-by:  Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
Signed-off-by: leozhang <leozhang@qiyi.com>
---
 doc/muxers.texi    | 21 +++++++++++++++++++++
 libavformat/fifo.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

Comments

Marton Balint May 7, 2020, 10:23 a.m. UTC | #1
On Thu, 7 May 2020, leozhang wrote:

> Suggested-by: Nicolas George <george@nsup.org>
> Reviewed-by:  Nicolas George <george@nsup.org>
> Reviewed-by:  Marton Balint <cus@passwd.hu>
> Reviewed-by:  Andreas Rheinhardt <andreas.rheinhardt@gmail.com>

You seem to misunderstand the use of this tag. You should only add these 
if you received an explict LGTM for your patches. This has not happened 
here, you only got suggestions, and those suggestions were concerning your 
earlier patch versions.

Also, what happened to the suggestion of using a buffer based approach and 
using realtime only for flushing? I will code something, and see how it 
goes, and will post a result as an RFC patch.

Regards,
Marton


> Signed-off-by: leozhang <leozhang@qiyi.com>
> ---
> doc/muxers.texi    | 21 +++++++++++++++++++++
> libavformat/fifo.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 67 insertions(+)
>
> diff --git a/doc/muxers.texi b/doc/muxers.texi
> index 536433b..14528f1 100644
> --- a/doc/muxers.texi
> +++ b/doc/muxers.texi
> @@ -2274,6 +2274,17 @@ certain (usually permanent) errors the recovery is not attempted even when
> Specify whether to wait for the keyframe after recovering from
> queue overflow or failure. This option is set to 0 (false) by default.
> 
> +@item realtime @var{bool}
> +If set to 1 (true), slow down writing packets to match real time approximately.
> +This is similar to @ref{the realtime or arealtime filters,,the "realtime_002c-arealtime" section in the ffmpeg-filters manual,ffmpeg-filters}.
> +Please note that in some cases without filtering, such as stream copy, you can also use it.
> +
> +@item realtime_speed
> +It is the same as the speed option to realtime or arealtime filters.
> +
> +@item realtime_limit @var{duration}
> +It is the same as the limit option to realtime or arealtime filters.
> +
> @end table
> 
> @subsection Examples
> @@ -2291,6 +2302,16 @@ ffmpeg -re -i ... -c:v libx264 -c:a aac -f fifo -fifo_format flv -map 0:v -map 0
> 
> @end itemize
> 
> +@itemize
> +
> +@item
> +Stream something to rtmp server, instead of using -re option.
> +@example
> +ffmpeg -i your_input_file -c copy -map 0:v -map 0:a -f fifo -fifo_format flv -realtime 1 rtmp://example.com/live/stream_name
> +@end example
> +
> +@end itemize
> +
> @anchor{tee}
> @section tee
> 
> diff --git a/libavformat/fifo.c b/libavformat/fifo.c
> index d11dc66..7acc420 100644
> --- a/libavformat/fifo.c
> +++ b/libavformat/fifo.c
> @@ -26,6 +26,7 @@
> #include "libavutil/threadmessage.h"
> #include "avformat.h"
> #include "internal.h"
> +#include <float.h>
> 
> #define FIFO_DEFAULT_QUEUE_SIZE              60
> #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   0
> @@ -77,6 +78,17 @@ typedef struct FifoContext {
>     /* Value > 0 signals queue overflow */
>     volatile uint8_t overflow_flag;
> 
> +    /* Slow down writing packets to match real time approximately */
> +    int realtime;
> +
> +    /* Speed factor for the processing when realtime */
> +    double realtime_speed;
> +
> +    /* Time limit for the pauses when realtime */
> +    int64_t realtime_limit;
> +
> +    int64_t delta;
> +    unsigned inited;
> } FifoContext;
> 
> typedef struct FifoThreadContext {
> @@ -183,6 +195,31 @@ static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt)
>     dst_tb = avf2->streams[s_idx]->time_base;
>     av_packet_rescale_ts(pkt, src_tb, dst_tb);
> 
> +    if (fifo->realtime) {
> +        int64_t pts = av_rescale_q(pkt->dts, dst_tb, AV_TIME_BASE_Q) / fifo->realtime_speed;
> +        int64_t now = av_gettime_relative();
> +        int64_t sleep = pts - now + fifo->delta;
> +
> +        if (!fifo->inited) {
> +            sleep = 0;
> +            fifo->delta = now - pts;
> +            fifo->inited = 1;
> +        }
> +
> +        if (FFABS(sleep) > fifo->realtime_limit / fifo->realtime_speed) {
> +            av_log(avf, AV_LOG_WARNING, "time discontinuity detected: %"PRIi64" us, resetting\n", sleep);
> +            sleep = 0;
> +            fifo->delta = now - pts;
> +        }
> +
> +        if (sleep > 0) {
> +            av_log(avf, AV_LOG_DEBUG, "sleeping %"PRIi64" us\n", sleep);
> +            for (; sleep > 600000000; sleep -= 600000000)
> +                av_usleep(600000000);
> +            av_usleep(sleep);
> +        }
> +    }
> +
>     ret = av_write_frame(avf2, pkt);
>     if (ret >= 0)
>         av_packet_unref(pkt);
> @@ -630,6 +667,15 @@ static const AVOption options[] = {
>         {"recover_any_error", "Attempt recovery regardless of type of the error", OFFSET(recover_any_error),
>          AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
> 
> +        {"realtime", "Slow down writing packets to match real time approximately", OFFSET(realtime),
> +         AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
> +
> +        {"realtime_speed", "Speed factor for the processing when realtime", OFFSET(realtime_speed),
> +         AV_OPT_TYPE_DOUBLE, {.dbl = 1.0}, DBL_MIN, DBL_MAX, AV_OPT_FLAG_ENCODING_PARAM},
> +
> +        {"realtime_limit", "Time limit for the pauses when realtime", OFFSET(realtime_limit),
> +         AV_OPT_TYPE_DURATION, {.i64 = 2000000}, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM},
> +
>         {NULL},
> };
> 
> -- 
> 1.8.3.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Tao Zhang May 7, 2020, 11:52 p.m. UTC | #2
Marton Balint <cus@passwd.hu> 于2020年5月7日周四 下午6:23写道:
>
>
>
> On Thu, 7 May 2020, leozhang wrote:
>
> > Suggested-by: Nicolas George <george@nsup.org>
> > Reviewed-by:  Nicolas George <george@nsup.org>
> > Reviewed-by:  Marton Balint <cus@passwd.hu>
> > Reviewed-by:  Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
>
> You seem to misunderstand the use of this tag. You should only add these
> if you received an explict LGTM for your patches. This has not happened
> here, you only got suggestions, and those suggestions were concerning your
> earlier patch versions.
Yes, I have. Please ignore above Reviewed-by
>
> Also, what happened to the suggestion of using a buffer based approach and
> using realtime only for flushing? I will code something, and see how it
> goes, and will post a result as an RFC patch.
I didn't try using a buffer based approach in fifo.c. If you're
willing to post such RFC patch, I'm OK. Thanks
>
> Regards,
> Marton
>
>
> > Signed-off-by: leozhang <leozhang@qiyi.com>
> > ---
> > doc/muxers.texi    | 21 +++++++++++++++++++++
> > libavformat/fifo.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 67 insertions(+)
> >
> > diff --git a/doc/muxers.texi b/doc/muxers.texi
> > index 536433b..14528f1 100644
> > --- a/doc/muxers.texi
> > +++ b/doc/muxers.texi
> > @@ -2274,6 +2274,17 @@ certain (usually permanent) errors the recovery is not attempted even when
> > Specify whether to wait for the keyframe after recovering from
> > queue overflow or failure. This option is set to 0 (false) by default.
> >
> > +@item realtime @var{bool}
> > +If set to 1 (true), slow down writing packets to match real time approximately.
> > +This is similar to @ref{the realtime or arealtime filters,,the "realtime_002c-arealtime" section in the ffmpeg-filters manual,ffmpeg-filters}.
> > +Please note that in some cases without filtering, such as stream copy, you can also use it.
> > +
> > +@item realtime_speed
> > +It is the same as the speed option to realtime or arealtime filters.
> > +
> > +@item realtime_limit @var{duration}
> > +It is the same as the limit option to realtime or arealtime filters.
> > +
> > @end table
> >
> > @subsection Examples
> > @@ -2291,6 +2302,16 @@ ffmpeg -re -i ... -c:v libx264 -c:a aac -f fifo -fifo_format flv -map 0:v -map 0
> >
> > @end itemize
> >
> > +@itemize
> > +
> > +@item
> > +Stream something to rtmp server, instead of using -re option.
> > +@example
> > +ffmpeg -i your_input_file -c copy -map 0:v -map 0:a -f fifo -fifo_format flv -realtime 1 rtmp://example.com/live/stream_name
> > +@end example
> > +
> > +@end itemize
> > +
> > @anchor{tee}
> > @section tee
> >
> > diff --git a/libavformat/fifo.c b/libavformat/fifo.c
> > index d11dc66..7acc420 100644
> > --- a/libavformat/fifo.c
> > +++ b/libavformat/fifo.c
> > @@ -26,6 +26,7 @@
> > #include "libavutil/threadmessage.h"
> > #include "avformat.h"
> > #include "internal.h"
> > +#include <float.h>
> >
> > #define FIFO_DEFAULT_QUEUE_SIZE              60
> > #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   0
> > @@ -77,6 +78,17 @@ typedef struct FifoContext {
> >     /* Value > 0 signals queue overflow */
> >     volatile uint8_t overflow_flag;
> >
> > +    /* Slow down writing packets to match real time approximately */
> > +    int realtime;
> > +
> > +    /* Speed factor for the processing when realtime */
> > +    double realtime_speed;
> > +
> > +    /* Time limit for the pauses when realtime */
> > +    int64_t realtime_limit;
> > +
> > +    int64_t delta;
> > +    unsigned inited;
> > } FifoContext;
> >
> > typedef struct FifoThreadContext {
> > @@ -183,6 +195,31 @@ static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt)
> >     dst_tb = avf2->streams[s_idx]->time_base;
> >     av_packet_rescale_ts(pkt, src_tb, dst_tb);
> >
> > +    if (fifo->realtime) {
> > +        int64_t pts = av_rescale_q(pkt->dts, dst_tb, AV_TIME_BASE_Q) / fifo->realtime_speed;
> > +        int64_t now = av_gettime_relative();
> > +        int64_t sleep = pts - now + fifo->delta;
> > +
> > +        if (!fifo->inited) {
> > +            sleep = 0;
> > +            fifo->delta = now - pts;
> > +            fifo->inited = 1;
> > +        }
> > +
> > +        if (FFABS(sleep) > fifo->realtime_limit / fifo->realtime_speed) {
> > +            av_log(avf, AV_LOG_WARNING, "time discontinuity detected: %"PRIi64" us, resetting\n", sleep);
> > +            sleep = 0;
> > +            fifo->delta = now - pts;
> > +        }
> > +
> > +        if (sleep > 0) {
> > +            av_log(avf, AV_LOG_DEBUG, "sleeping %"PRIi64" us\n", sleep);
> > +            for (; sleep > 600000000; sleep -= 600000000)
> > +                av_usleep(600000000);
> > +            av_usleep(sleep);
> > +        }
> > +    }
> > +
> >     ret = av_write_frame(avf2, pkt);
> >     if (ret >= 0)
> >         av_packet_unref(pkt);
> > @@ -630,6 +667,15 @@ static const AVOption options[] = {
> >         {"recover_any_error", "Attempt recovery regardless of type of the error", OFFSET(recover_any_error),
> >          AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
> >
> > +        {"realtime", "Slow down writing packets to match real time approximately", OFFSET(realtime),
> > +         AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
> > +
> > +        {"realtime_speed", "Speed factor for the processing when realtime", OFFSET(realtime_speed),
> > +         AV_OPT_TYPE_DOUBLE, {.dbl = 1.0}, DBL_MIN, DBL_MAX, AV_OPT_FLAG_ENCODING_PARAM},
> > +
> > +        {"realtime_limit", "Time limit for the pauses when realtime", OFFSET(realtime_limit),
> > +         AV_OPT_TYPE_DURATION, {.i64 = 2000000}, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM},
> > +
> >         {NULL},
> > };
> >
> > --
> > 1.8.3.1
> >
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel@ffmpeg.org
> > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> >
> > To unsubscribe, visit link above, or email
> > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 536433b..14528f1 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -2274,6 +2274,17 @@  certain (usually permanent) errors the recovery is not attempted even when
 Specify whether to wait for the keyframe after recovering from
 queue overflow or failure. This option is set to 0 (false) by default.
 
+@item realtime @var{bool}
+If set to 1 (true), slow down writing packets to match real time approximately.
+This is similar to @ref{the realtime or arealtime filters,,the "realtime_002c-arealtime" section in the ffmpeg-filters manual,ffmpeg-filters}.
+Please note that in some cases without filtering, such as stream copy, you can also use it.
+
+@item realtime_speed
+It is the same as the speed option to realtime or arealtime filters.
+
+@item realtime_limit @var{duration}
+It is the same as the limit option to realtime or arealtime filters.
+
 @end table
 
 @subsection Examples
@@ -2291,6 +2302,16 @@  ffmpeg -re -i ... -c:v libx264 -c:a aac -f fifo -fifo_format flv -map 0:v -map 0
 
 @end itemize
 
+@itemize
+
+@item
+Stream something to rtmp server, instead of using -re option.
+@example
+ffmpeg -i your_input_file -c copy -map 0:v -map 0:a -f fifo -fifo_format flv -realtime 1 rtmp://example.com/live/stream_name
+@end example
+
+@end itemize
+
 @anchor{tee}
 @section tee
 
diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index d11dc66..7acc420 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -26,6 +26,7 @@ 
 #include "libavutil/threadmessage.h"
 #include "avformat.h"
 #include "internal.h"
+#include <float.h>
 
 #define FIFO_DEFAULT_QUEUE_SIZE              60
 #define FIFO_DEFAULT_MAX_RECOVERY_ATTEMPTS   0
@@ -77,6 +78,17 @@  typedef struct FifoContext {
     /* Value > 0 signals queue overflow */
     volatile uint8_t overflow_flag;
 
+    /* Slow down writing packets to match real time approximately */
+    int realtime;
+
+    /* Speed factor for the processing when realtime */
+    double realtime_speed;
+
+    /* Time limit for the pauses when realtime */
+    int64_t realtime_limit;
+
+    int64_t delta;
+    unsigned inited;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -183,6 +195,31 @@  static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt)
     dst_tb = avf2->streams[s_idx]->time_base;
     av_packet_rescale_ts(pkt, src_tb, dst_tb);
 
+    if (fifo->realtime) {
+        int64_t pts = av_rescale_q(pkt->dts, dst_tb, AV_TIME_BASE_Q) / fifo->realtime_speed;
+        int64_t now = av_gettime_relative();
+        int64_t sleep = pts - now + fifo->delta;
+
+        if (!fifo->inited) {
+            sleep = 0;
+            fifo->delta = now - pts;
+            fifo->inited = 1;
+        }
+
+        if (FFABS(sleep) > fifo->realtime_limit / fifo->realtime_speed) {
+            av_log(avf, AV_LOG_WARNING, "time discontinuity detected: %"PRIi64" us, resetting\n", sleep);
+            sleep = 0;
+            fifo->delta = now - pts;
+        }
+
+        if (sleep > 0) {
+            av_log(avf, AV_LOG_DEBUG, "sleeping %"PRIi64" us\n", sleep);
+            for (; sleep > 600000000; sleep -= 600000000)
+                av_usleep(600000000);
+            av_usleep(sleep);
+        }
+    }
+
     ret = av_write_frame(avf2, pkt);
     if (ret >= 0)
         av_packet_unref(pkt);
@@ -630,6 +667,15 @@  static const AVOption options[] = {
         {"recover_any_error", "Attempt recovery regardless of type of the error", OFFSET(recover_any_error),
          AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
 
+        {"realtime", "Slow down writing packets to match real time approximately", OFFSET(realtime),
+         AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
+
+        {"realtime_speed", "Speed factor for the processing when realtime", OFFSET(realtime_speed),
+         AV_OPT_TYPE_DOUBLE, {.dbl = 1.0}, DBL_MIN, DBL_MAX, AV_OPT_FLAG_ENCODING_PARAM},
+
+        {"realtime_limit", "Time limit for the pauses when realtime", OFFSET(realtime_limit),
+         AV_OPT_TYPE_DURATION, {.i64 = 2000000}, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM},
+
         {NULL},
 };