diff mbox series

[FFmpeg-devel,v5] avformat/hls: Add option to retry failed segments for hls

Message ID 20221020121138.98198-1-gnattuoc@me.com
State Accepted
Commit d09254a658365b89fc4430e88e18fef04de432be
Headers show
Series [FFmpeg-devel,v5] avformat/hls: Add option to retry failed segments for hls | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

gnattu Oct. 20, 2022, 12:11 p.m. UTC
Current HLS implementation simply skip a failed segment to catch up
the stream, but this is not optimal for some use cases like livestream
recording.
Add an option to retry a failed segment to ensure the output file is
a complete stream.

Signed-off-by: gnattu <gnattuoc@me.com>
---
v5 changed coding style as requested
v4 added documentation for the new seg_max_try option

 doc/demuxers.texi |  4 ++++
 libavformat/hls.c | 15 ++++++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

Comments

Steven Liu Oct. 21, 2022, 9:19 a.m. UTC | #1
gnattu <gnattuoc@me.com> 于2022年10月20日周四 20:12写道:
>
> Current HLS implementation simply skip a failed segment to catch up
> the stream, but this is not optimal for some use cases like livestream
> recording.
> Add an option to retry a failed segment to ensure the output file is
> a complete stream.
>
> Signed-off-by: gnattu <gnattuoc@me.com>
> ---
> v5 changed coding style as requested
> v4 added documentation for the new seg_max_try option
>
>  doc/demuxers.texi |  4 ++++
>  libavformat/hls.c | 15 ++++++++++++++-
>  2 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/doc/demuxers.texi b/doc/demuxers.texi
> index 2b6dd86c2a..3e09a0f14e 100644
> --- a/doc/demuxers.texi
> +++ b/doc/demuxers.texi
> @@ -401,6 +401,10 @@ Use HTTP partial requests for downloading HTTP segments.
>
>  @item seg_format_options
>  Set options for the demuxer of media segments using a list of key=value pairs separated by @code{:}.
> +
> +@item seg_max_retry
> +Maximum number of times to reload a segment on error, useful when segment skip on network error is not desired.
> +Default value is 0.
>  @end table
>
>  @section image2
> diff --git a/libavformat/hls.c b/libavformat/hls.c
> index e622425e80..2a5ffb927f 100644
> --- a/libavformat/hls.c
> +++ b/libavformat/hls.c
> @@ -225,6 +225,7 @@ typedef struct HLSContext {
>      int http_persistent;
>      int http_multiple;
>      int http_seekable;
> +    int seg_max_retry;
>      AVIOContext *playlist_pb;
>      HLSCryptoContext  crypto_ctx;
>  } HLSContext;
> @@ -1472,6 +1473,7 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size)
>      int ret;
>      int just_opened = 0;
>      int reload_count = 0;
> +    int segment_retries = 0;
>      struct segment *seg;
>
>  restart:
> @@ -1563,9 +1565,18 @@ reload:
>              av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %"PRId64" of playlist %d\n",
>                     v->cur_seq_no,
>                     v->index);
> -            v->cur_seq_no += 1;
> +            if (segment_retries >= c->seg_max_retry) {
> +                av_log(v->parent, AV_LOG_WARNING, "Segment %"PRId64" of playlist %d failed too many times, skipping\n",
> +                       v->cur_seq_no,
> +                       v->index);
> +                v->cur_seq_no++;
> +                segment_retries = 0;
> +            } else {
> +                segment_retries++;
> +            }
>              goto reload;
>          }
> +        segment_retries = 0;
>          just_opened = 1;
>      }
>
> @@ -2549,6 +2560,8 @@ static const AVOption hls_options[] = {
>          OFFSET(http_seekable), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 1, FLAGS},
>      {"seg_format_options", "Set options for segment demuxer",
>          OFFSET(seg_format_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, FLAGS},
> +    {"seg_max_retry", "Maximum number of times to reload a segment on error.",
> +     OFFSET(seg_max_retry), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS},
>      {NULL}
>  };
>
> --
> 2.37.0 (Apple Git-136)
>
> _______________________________________________
> 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".

LGTM

Thanks
Steven
Gyan Doshi Feb. 8, 2023, 7:55 a.m. UTC | #2
On 2022-10-21 02:49 pm, Steven Liu wrote:
> gnattu <gnattuoc@me.com> 于2022年10月20日周四 20:12写道:
>> Current HLS implementation simply skip a failed segment to catch up
>> the stream, but this is not optimal for some use cases like livestream
>> recording.
>> Add an option to retry a failed segment to ensure the output file is
>> a complete stream.
>>
>> Signed-off-by: gnattu <gnattuoc@me.com>
>> ---
>> v5 changed coding style as requested
>> v4 added documentation for the new seg_max_try option
>>
>>   doc/demuxers.texi |  4 ++++
>>   libavformat/hls.c | 15 ++++++++++++++-
>>   2 files changed, 18 insertions(+), 1 deletion(-)
>>
>> diff --git a/doc/demuxers.texi b/doc/demuxers.texi
>> index 2b6dd86c2a..3e09a0f14e 100644
>> --- a/doc/demuxers.texi
>> +++ b/doc/demuxers.texi
>> @@ -401,6 +401,10 @@ Use HTTP partial requests for downloading HTTP segments.
>>
>>   @item seg_format_options
>>   Set options for the demuxer of media segments using a list of key=value pairs separated by @code{:}.
>> +
>> +@item seg_max_retry
>> +Maximum number of times to reload a segment on error, useful when segment skip on network error is not desired.
>> +Default value is 0.
>>   @end table
>>
>>   @section image2
>> diff --git a/libavformat/hls.c b/libavformat/hls.c
>> index e622425e80..2a5ffb927f 100644
>> --- a/libavformat/hls.c
>> +++ b/libavformat/hls.c
>> @@ -225,6 +225,7 @@ typedef struct HLSContext {
>>       int http_persistent;
>>       int http_multiple;
>>       int http_seekable;
>> +    int seg_max_retry;
>>       AVIOContext *playlist_pb;
>>       HLSCryptoContext  crypto_ctx;
>>   } HLSContext;
>> @@ -1472,6 +1473,7 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size)
>>       int ret;
>>       int just_opened = 0;
>>       int reload_count = 0;
>> +    int segment_retries = 0;
>>       struct segment *seg;
>>
>>   restart:
>> @@ -1563,9 +1565,18 @@ reload:
>>               av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %"PRId64" of playlist %d\n",
>>                      v->cur_seq_no,
>>                      v->index);
>> -            v->cur_seq_no += 1;
>> +            if (segment_retries >= c->seg_max_retry) {
>> +                av_log(v->parent, AV_LOG_WARNING, "Segment %"PRId64" of playlist %d failed too many times, skipping\n",
>> +                       v->cur_seq_no,
>> +                       v->index);
>> +                v->cur_seq_no++;
>> +                segment_retries = 0;
>> +            } else {
>> +                segment_retries++;
>> +            }
>>               goto reload;
>>           }
>> +        segment_retries = 0;
>>           just_opened = 1;
>>       }
>>
>> @@ -2549,6 +2560,8 @@ static const AVOption hls_options[] = {
>>           OFFSET(http_seekable), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 1, FLAGS},
>>       {"seg_format_options", "Set options for segment demuxer",
>>           OFFSET(seg_format_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, FLAGS},
>> +    {"seg_max_retry", "Maximum number of times to reload a segment on error.",
>> +     OFFSET(seg_max_retry), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS},
>>       {NULL}
>>   };
>>
>> --
>> 2.37.0 (Apple Git-136)
>>
>> _______________________________________________
>> 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".
> LGTM
>
> Thanks
> Steven

This doesn't appear to have been pushed.
Plan to push tomorrow.

Regards,
Gyan
Gyan Doshi Feb. 9, 2023, 9:12 a.m. UTC | #3
On 2023-02-08 01:25 pm, Gyan Doshi wrote:
>
>
> On 2022-10-21 02:49 pm, Steven Liu wrote:
>> gnattu <gnattuoc@me.com> 于2022年10月20日周四 20:12写道:
>>> Current HLS implementation simply skip a failed segment to catch up
>>> the stream, but this is not optimal for some use cases like livestream
>>> recording.
>>> Add an option to retry a failed segment to ensure the output file is
>>> a complete stream.
>>>
>>> Signed-off-by: gnattu <gnattuoc@me.com>
>>> ---
>>> v5 changed coding style as requested
>>> v4 added documentation for the new seg_max_try option
>>>
>>>   doc/demuxers.texi |  4 ++++
>>>   libavformat/hls.c | 15 ++++++++++++++-
>>>   2 files changed, 18 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/doc/demuxers.texi b/doc/demuxers.texi
>>> index 2b6dd86c2a..3e09a0f14e 100644
>>> --- a/doc/demuxers.texi
>>> +++ b/doc/demuxers.texi
>>> @@ -401,6 +401,10 @@ Use HTTP partial requests for downloading HTTP 
>>> segments.
>>>
>>>   @item seg_format_options
>>>   Set options for the demuxer of media segments using a list of 
>>> key=value pairs separated by @code{:}.
>>> +
>>> +@item seg_max_retry
>>> +Maximum number of times to reload a segment on error, useful when 
>>> segment skip on network error is not desired.
>>> +Default value is 0.
>>>   @end table
>>>
>>>   @section image2
>>> diff --git a/libavformat/hls.c b/libavformat/hls.c
>>> index e622425e80..2a5ffb927f 100644
>>> --- a/libavformat/hls.c
>>> +++ b/libavformat/hls.c
>>> @@ -225,6 +225,7 @@ typedef struct HLSContext {
>>>       int http_persistent;
>>>       int http_multiple;
>>>       int http_seekable;
>>> +    int seg_max_retry;
>>>       AVIOContext *playlist_pb;
>>>       HLSCryptoContext  crypto_ctx;
>>>   } HLSContext;
>>> @@ -1472,6 +1473,7 @@ static int read_data(void *opaque, uint8_t 
>>> *buf, int buf_size)
>>>       int ret;
>>>       int just_opened = 0;
>>>       int reload_count = 0;
>>> +    int segment_retries = 0;
>>>       struct segment *seg;
>>>
>>>   restart:
>>> @@ -1563,9 +1565,18 @@ reload:
>>>               av_log(v->parent, AV_LOG_WARNING, "Failed to open 
>>> segment %"PRId64" of playlist %d\n",
>>>                      v->cur_seq_no,
>>>                      v->index);
>>> -            v->cur_seq_no += 1;
>>> +            if (segment_retries >= c->seg_max_retry) {
>>> +                av_log(v->parent, AV_LOG_WARNING, "Segment 
>>> %"PRId64" of playlist %d failed too many times, skipping\n",
>>> +                       v->cur_seq_no,
>>> +                       v->index);
>>> +                v->cur_seq_no++;
>>> +                segment_retries = 0;
>>> +            } else {
>>> +                segment_retries++;
>>> +            }
>>>               goto reload;
>>>           }
>>> +        segment_retries = 0;
>>>           just_opened = 1;
>>>       }
>>>
>>> @@ -2549,6 +2560,8 @@ static const AVOption hls_options[] = {
>>>           OFFSET(http_seekable), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 
>>> 1, FLAGS},
>>>       {"seg_format_options", "Set options for segment demuxer",
>>>           OFFSET(seg_format_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 
>>> 0, 0, FLAGS},
>>> +    {"seg_max_retry", "Maximum number of times to reload a segment 
>>> on error.",
>>> +     OFFSET(seg_max_retry), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 
>>> INT_MAX, FLAGS},
>>>       {NULL}
>>>   };
>>>
>>> -- 
>>> 2.37.0 (Apple Git-136)
>>>
>>> _______________________________________________
>>> 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".
>> LGTM
>>
>> Thanks
>> Steven
>
> This doesn't appear to have been pushed.
> Plan to push tomorrow.

Pushed as d09254a658365b89fc4430e88e18fef04de432be

Regards,
Gyan
diff mbox series

Patch

diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index 2b6dd86c2a..3e09a0f14e 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -401,6 +401,10 @@  Use HTTP partial requests for downloading HTTP segments.
 
 @item seg_format_options
 Set options for the demuxer of media segments using a list of key=value pairs separated by @code{:}.
+
+@item seg_max_retry
+Maximum number of times to reload a segment on error, useful when segment skip on network error is not desired.
+Default value is 0.
 @end table
 
 @section image2
diff --git a/libavformat/hls.c b/libavformat/hls.c
index e622425e80..2a5ffb927f 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -225,6 +225,7 @@  typedef struct HLSContext {
     int http_persistent;
     int http_multiple;
     int http_seekable;
+    int seg_max_retry;
     AVIOContext *playlist_pb;
     HLSCryptoContext  crypto_ctx;
 } HLSContext;
@@ -1472,6 +1473,7 @@  static int read_data(void *opaque, uint8_t *buf, int buf_size)
     int ret;
     int just_opened = 0;
     int reload_count = 0;
+    int segment_retries = 0;
     struct segment *seg;
 
 restart:
@@ -1563,9 +1565,18 @@  reload:
             av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %"PRId64" of playlist %d\n",
                    v->cur_seq_no,
                    v->index);
-            v->cur_seq_no += 1;
+            if (segment_retries >= c->seg_max_retry) {
+                av_log(v->parent, AV_LOG_WARNING, "Segment %"PRId64" of playlist %d failed too many times, skipping\n",
+                       v->cur_seq_no,
+                       v->index);
+                v->cur_seq_no++;
+                segment_retries = 0;
+            } else {
+                segment_retries++;
+            }
             goto reload;
         }
+        segment_retries = 0;
         just_opened = 1;
     }
 
@@ -2549,6 +2560,8 @@  static const AVOption hls_options[] = {
         OFFSET(http_seekable), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 1, FLAGS},
     {"seg_format_options", "Set options for segment demuxer",
         OFFSET(seg_format_opts), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, FLAGS},
+    {"seg_max_retry", "Maximum number of times to reload a segment on error.",
+     OFFSET(seg_max_retry), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS},
     {NULL}
 };