diff mbox series

[FFmpeg-devel,2/3] avformat/fifo: add option to write packets in paced way

Message ID 1588166736-82427-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 April 29, 2020, 1:25 p.m. UTC
Signed-off-by: leozhang <leozhang@qiyi.com>
---
 doc/muxers.texi    |  3 +++
 libavformat/fifo.c | 19 +++++++++++++++++++
 2 files changed, 22 insertions(+)

Comments

Nicolas George April 29, 2020, 1:51 p.m. UTC | #1
leozhang (12020-04-29):
> Signed-off-by: leozhang <leozhang@qiyi.com>
> ---
>  doc/muxers.texi    |  3 +++
>  libavformat/fifo.c | 19 +++++++++++++++++++
>  2 files changed, 22 insertions(+)
> 
> diff --git a/doc/muxers.texi b/doc/muxers.texi
> index a74cbc4..5140c00 100644
> --- a/doc/muxers.texi
> +++ b/doc/muxers.texi
> @@ -2274,6 +2274,9 @@ queue overflow or failure. This option is set to 0 (false) by default.
>  @item output_delay
>  Time to delay output, in microseconds. Default value is 0.
>  

> +@item paced
> +If set to 1 (true), write packets in paced way. Default value is 0 (false).

This does not explain to somebody who does not already know. Please have
a look at the doc for the filter "realtime" and use a similar wording,
preferably with cross-references.

> +
>  @end table
>  
>  @subsection Examples
> diff --git a/libavformat/fifo.c b/libavformat/fifo.c
> index bdecf2d..81b7e9e 100644
> --- a/libavformat/fifo.c
> +++ b/libavformat/fifo.c
> @@ -79,6 +79,12 @@ typedef struct FifoContext {
>  
>      /* Time to delay output, in microseconds */
>      uint64_t output_delay;
> +
> +    /* If set to 1, write packets in paced way */
> +    int paced;
> +
> +    /* Time to start */

> +    uint64_t start_time;

The return value of av_gettime_relative() is signed.

>  } FifoContext;
>  
>  typedef struct FifoThreadContext {
> @@ -184,6 +190,14 @@ static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt)
>      src_tb = avf->streams[s_idx]->time_base;
>      dst_tb = avf2->streams[s_idx]->time_base;
>      av_packet_rescale_ts(pkt, src_tb, dst_tb);
> +    if (fifo->paced) {
> +        uint64_t pts = av_rescale_q(pkt->dts, dst_tb, AV_TIME_BASE_Q);
> +        uint64_t now = av_gettime_relative() - fifo->start_time;

> +        av_assert0(now >= fifo->output_delay);

av_gettime_relative() is not guaranteed to be monotonic, an assert is
not acceptable here.

> +        if (pts > now - fifo->output_delay) {

You probably need to make provisions for when the process was paused and
then resumed, and for timestamps discontinuities.

> +            av_usleep(pts - (now - fifo->output_delay));

The argument to av_usleep() is unsigned, you are passing uint64_t, it
can overflow.

> +        }

> +    }
>  
>      ret = av_write_frame(avf2, pkt);
>      if (ret >= 0)
> @@ -515,6 +529,8 @@ static int fifo_init(AVFormatContext *avf)
>          return AVERROR(ret);
>      fifo->overflow_flag_lock_initialized = 1;
>  
> +    fifo->start_time = av_gettime_relative();
> +
>      return 0;
>  }
>  
> @@ -637,6 +653,9 @@ static const AVOption options[] = {
>          {"output_delay", "Time to delay output, in microseconds", OFFSET(output_delay),
>           AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
>  
> +        {"paced", "Write packets in paced way", OFFSET(paced),
> +         AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
> +
>          {NULL},
>  };
>  

Regards,
Tao Zhang April 30, 2020, 11:36 p.m. UTC | #2
Nicolas George <george@nsup.org> 于2020年4月29日周三 下午9:51写道:
>
> leozhang (12020-04-29):
> > Signed-off-by: leozhang <leozhang@qiyi.com>
> > ---
> >  doc/muxers.texi    |  3 +++
> >  libavformat/fifo.c | 19 +++++++++++++++++++
> >  2 files changed, 22 insertions(+)
> >
> > diff --git a/doc/muxers.texi b/doc/muxers.texi
> > index a74cbc4..5140c00 100644
> > --- a/doc/muxers.texi
> > +++ b/doc/muxers.texi
> > @@ -2274,6 +2274,9 @@ queue overflow or failure. This option is set to 0 (false) by default.
> >  @item output_delay
> >  Time to delay output, in microseconds. Default value is 0.
> >
>
> > +@item paced
> > +If set to 1 (true), write packets in paced way. Default value is 0 (false).
>
> This does not explain to somebody who does not already know. Please have
> a look at the doc for the filter "realtime" and use a similar wording,
> preferably with cross-references.
I'm reading the realtime filter and have learned a lot. Will make more
clear description in v2 version.
>
> > +
> >  @end table
> >
> >  @subsection Examples
> > diff --git a/libavformat/fifo.c b/libavformat/fifo.c
> > index bdecf2d..81b7e9e 100644
> > --- a/libavformat/fifo.c
> > +++ b/libavformat/fifo.c
> > @@ -79,6 +79,12 @@ typedef struct FifoContext {
> >
> >      /* Time to delay output, in microseconds */
> >      uint64_t output_delay;
> > +
> > +    /* If set to 1, write packets in paced way */
> > +    int paced;
> > +
> > +    /* Time to start */
>
> > +    uint64_t start_time;
>
> The return value of av_gettime_relative() is signed.
will fix it in v2 version.
>
> >  } FifoContext;
> >
> >  typedef struct FifoThreadContext {
> > @@ -184,6 +190,14 @@ static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt)
> >      src_tb = avf->streams[s_idx]->time_base;
> >      dst_tb = avf2->streams[s_idx]->time_base;
> >      av_packet_rescale_ts(pkt, src_tb, dst_tb);
> > +    if (fifo->paced) {
> > +        uint64_t pts = av_rescale_q(pkt->dts, dst_tb, AV_TIME_BASE_Q);
> > +        uint64_t now = av_gettime_relative() - fifo->start_time;
>
> > +        av_assert0(now >= fifo->output_delay);
>
> av_gettime_relative() is not guaranteed to be monotonic, an assert is
> not acceptable here.
will fix it in v2 version.
>
> > +        if (pts > now - fifo->output_delay) {
>
> You probably need to make provisions for when the process was paused and
> then resumed, and for timestamps discontinuities.
will fix it in v2 version.
>
> > +            av_usleep(pts - (now - fifo->output_delay));
>
> The argument to av_usleep() is unsigned, you are passing uint64_t, it
> can overflow.
will fix it in v2 version.
>
> > +        }
>
> > +    }
> >
> >      ret = av_write_frame(avf2, pkt);
> >      if (ret >= 0)
> > @@ -515,6 +529,8 @@ static int fifo_init(AVFormatContext *avf)
> >          return AVERROR(ret);
> >      fifo->overflow_flag_lock_initialized = 1;
> >
> > +    fifo->start_time = av_gettime_relative();
> > +
> >      return 0;
> >  }
> >
> > @@ -637,6 +653,9 @@ static const AVOption options[] = {
> >          {"output_delay", "Time to delay output, in microseconds", OFFSET(output_delay),
> >           AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
> >
> > +        {"paced", "Write packets in paced way", OFFSET(paced),
> > +         AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
> > +
> >          {NULL},
> >  };
> >
>
> Regards,
>
> --
>   Nicolas George
> _______________________________________________
> 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 a74cbc4..5140c00 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -2274,6 +2274,9 @@  queue overflow or failure. This option is set to 0 (false) by default.
 @item output_delay
 Time to delay output, in microseconds. Default value is 0.
 
+@item paced
+If set to 1 (true), write packets in paced way. Default value is 0 (false).
+
 @end table
 
 @subsection Examples
diff --git a/libavformat/fifo.c b/libavformat/fifo.c
index bdecf2d..81b7e9e 100644
--- a/libavformat/fifo.c
+++ b/libavformat/fifo.c
@@ -79,6 +79,12 @@  typedef struct FifoContext {
 
     /* Time to delay output, in microseconds */
     uint64_t output_delay;
+
+    /* If set to 1, write packets in paced way */
+    int paced;
+
+    /* Time to start */
+    uint64_t start_time;
 } FifoContext;
 
 typedef struct FifoThreadContext {
@@ -184,6 +190,14 @@  static int fifo_thread_write_packet(FifoThreadContext *ctx, AVPacket *pkt)
     src_tb = avf->streams[s_idx]->time_base;
     dst_tb = avf2->streams[s_idx]->time_base;
     av_packet_rescale_ts(pkt, src_tb, dst_tb);
+    if (fifo->paced) {
+        uint64_t pts = av_rescale_q(pkt->dts, dst_tb, AV_TIME_BASE_Q);
+        uint64_t now = av_gettime_relative() - fifo->start_time;
+        av_assert0(now >= fifo->output_delay);
+        if (pts > now - fifo->output_delay) {
+            av_usleep(pts - (now - fifo->output_delay));
+        }
+    }
 
     ret = av_write_frame(avf2, pkt);
     if (ret >= 0)
@@ -515,6 +529,8 @@  static int fifo_init(AVFormatContext *avf)
         return AVERROR(ret);
     fifo->overflow_flag_lock_initialized = 1;
 
+    fifo->start_time = av_gettime_relative();
+
     return 0;
 }
 
@@ -637,6 +653,9 @@  static const AVOption options[] = {
         {"output_delay", "Time to delay output, in microseconds", OFFSET(output_delay),
          AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
 
+        {"paced", "Write packets in paced way", OFFSET(paced),
+         AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
+
         {NULL},
 };