diff mbox series

[FFmpeg-devel] avformat/hls: Fixes overwriting existing #EXT-X-PROGRAM-DATE-TIME value in HLS playlist

Message ID 20201201101040.28338-1-vignesh.ravichandran02@gmail.com
State Accepted
Commit 45a673ebee2e603a87c0ecb259c0027c14321018
Headers show
Series [FFmpeg-devel] avformat/hls: Fixes overwriting existing #EXT-X-PROGRAM-DATE-TIME value in HLS playlist | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Vignesh Ravichandran Dec. 1, 2020, 10:10 a.m. UTC
Bug ID: 8989

This is is due to the following behavior in the current code:
1. The initial_prog_date_time gets set to the current local time
2. The existing playlist (.m3u8) file gets parsed and the segments present are added to the variant stream
3. The new segment is created and added
4. The existing segments and the new segment are written to the playlist file. The initial_prog_date_time from point 1 is used for calculating "#EXT-X-PROGRAM-DATE-TIME" for the segments, which results in incorrect "#EXT-X-PROGRAM-DATE-TIME" values for existing segments

The following approach fixes this bug:
1. Add a new variable "discont_program_date_time" of type double to HLSSegment struct
2. Store the "EXT-X-PROGRAM-DATE-TIME" value from the existing segments in this variable
3. When writing to playlist file if "discont_program_date_time" is set, then use that value for "EXT-X-PROGRAM-DATE-TIME" else use the value present in vs->initial_prog_date_time

Signed-off-by: Vignesh Ravichandran <vignesh.ravichandran02@gmail.com>
---
 libavformat/hlsenc.c | 33 ++++++++++++++++++++++++++++++---
 1 file changed, 30 insertions(+), 3 deletions(-)

Comments

Liu Steven Dec. 4, 2020, 2:34 a.m. UTC | #1
> 2020年12月1日 下午6:10,Vignesh Ravichandran <vignesh.ravichandran02@gmail.com> 写道:
> 
> Bug ID: 8989
> 
> This is is due to the following behavior in the current code:
> 1. The initial_prog_date_time gets set to the current local time
> 2. The existing playlist (.m3u8) file gets parsed and the segments present are added to the variant stream
> 3. The new segment is created and added
> 4. The existing segments and the new segment are written to the playlist file. The initial_prog_date_time from point 1 is used for calculating "#EXT-X-PROGRAM-DATE-TIME" for the segments, which results in incorrect "#EXT-X-PROGRAM-DATE-TIME" values for existing segments
> 
> The following approach fixes this bug:
> 1. Add a new variable "discont_program_date_time" of type double to HLSSegment struct
> 2. Store the "EXT-X-PROGRAM-DATE-TIME" value from the existing segments in this variable
> 3. When writing to playlist file if "discont_program_date_time" is set, then use that value for "EXT-X-PROGRAM-DATE-TIME" else use the value present in vs->initial_prog_date_time
> 
> Signed-off-by: Vignesh Ravichandran <vignesh.ravichandran02@gmail.com>
> ---
> libavformat/hlsenc.c | 33 ++++++++++++++++++++++++++++++---
> 1 file changed, 30 insertions(+), 3 deletions(-)
> 
> diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
> index cbfd8f7c0d..9bce374605 100644
> --- a/libavformat/hlsenc.c
> +++ b/libavformat/hlsenc.c
> @@ -88,6 +88,7 @@ typedef struct HLSSegment {
>     char iv_string[KEYSIZE*2 + 1];
> 
>     struct HLSSegment *next;
> +    double discont_program_date_time;
> } HLSSegment;
> 
> typedef enum HLSFlags {
> @@ -1124,6 +1125,7 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
>     en->keyframe_size     = vs->video_keyframe_size;
>     en->next     = NULL;
>     en->discont  = 0;
> +    en->discont_program_date_time = 0;
> 
>     if (vs->discontinuity) {
>         en->discont = 1;
> @@ -1148,7 +1150,8 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
> 
>     if (hls->max_nb_segments && vs->nb_entries >= hls->max_nb_segments) {
>         en = vs->segments;
> -        vs->initial_prog_date_time += en->duration;
> +        if (!en->next->discont_program_date_time && !en->discont_program_date_time)
> +            vs->initial_prog_date_time += en->duration;
>         vs->segments = en->next;
>         if (en && hls->flags & HLS_DELETE_SEGMENTS &&
> #if FF_API_HLS_WRAP
> @@ -1182,6 +1185,7 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
>     char line[MAX_URL_SIZE];
>     const char *ptr;
>     const char *end;
> +    double discont_program_date_time = 0;
> 
>     if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ,
>                                    &s->interrupt_callback, NULL,
> @@ -1236,7 +1240,25 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
>                     av_strlcpy(vs->iv_string, ptr, sizeof(vs->iv_string));
>                 }
>             }
> +        } else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) {
> +            struct tm program_date_time;
> +            int y,M,d,h,m,s;
> +            double ms;
> +            if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) {
> +                ret = AVERROR_INVALIDDATA;
> +                goto fail;
> +            }
> +
> +            program_date_time.tm_year = y - 1900;
> +            program_date_time.tm_mon = M - 1;
> +            program_date_time.tm_mday = d;
> +            program_date_time.tm_hour = h;
> +            program_date_time.tm_min = m;
> +            program_date_time.tm_sec = s;
> +            program_date_time.tm_isdst = -1;
> 
> +            discont_program_date_time = mktime(&program_date_time);
> +            discont_program_date_time += (double)(ms / 1000);
>         } else if (av_strstart(line, "#", NULL)) {
>             continue;
>         } else if (line[0]) {
> @@ -1250,8 +1272,9 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
>                 is_segment = 0;
>                 new_start_pos = avio_tell(vs->avf->pb);
>                 vs->size = new_start_pos - vs->start_pos;
> -                vs->initial_prog_date_time -= vs->duration; // this is a previously existing segment
>                 ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size);
> +                vs->last_segment->discont_program_date_time = discont_program_date_time;
> +                discont_program_date_time += vs->duration;
>                 if (ret < 0)
>                     goto fail;
>                 vs->start_pos = new_start_pos;
> @@ -1572,7 +1595,11 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
>         ret = ff_hls_write_file_entry(byterange_mode ? hls->m3u8_out : vs->out, en->discont, byterange_mode,
>                                       en->duration, hls->flags & HLS_ROUND_DURATIONS,
>                                       en->size, en->pos, hls->baseurl,
> -                                      en->filename, prog_date_time_p, en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
> +                                      en->filename,
> +                                      en->discont_program_date_time ? &en->discont_program_date_time : prog_date_time_p,
> +                                      en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
> +        if (en->discont_program_date_time)
> +            en->discont_program_date_time -= en->duration;
>         if (ret < 0) {
>             av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
>         }
> -- 
> 2.24.2 (Apple Git-127)
> 
> _______________________________________________
> 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".

LGTN

Will push if no objections. 

Thanks

Steven Liu
Vignesh Ravichandran Dec. 8, 2020, 6:49 a.m. UTC | #2
Friendly ping to check if the patch has been pushed.

Thanks,
Vignesh

On Fri, Dec 4, 2020 at 8:04 AM Steven Liu <lq@chinaffmpeg.org> wrote:

>
>
> > 2020年12月1日 下午6:10,Vignesh Ravichandran <vignesh.ravichandran02@gmail.com>
> 写道:
> >
> > Bug ID: 8989
> >
> > This is is due to the following behavior in the current code:
> > 1. The initial_prog_date_time gets set to the current local time
> > 2. The existing playlist (.m3u8) file gets parsed and the segments
> present are added to the variant stream
> > 3. The new segment is created and added
> > 4. The existing segments and the new segment are written to the playlist
> file. The initial_prog_date_time from point 1 is used for calculating
> "#EXT-X-PROGRAM-DATE-TIME" for the segments, which results in incorrect
> "#EXT-X-PROGRAM-DATE-TIME" values for existing segments
> >
> > The following approach fixes this bug:
> > 1. Add a new variable "discont_program_date_time" of type double to
> HLSSegment struct
> > 2. Store the "EXT-X-PROGRAM-DATE-TIME" value from the existing segments
> in this variable
> > 3. When writing to playlist file if "discont_program_date_time" is set,
> then use that value for "EXT-X-PROGRAM-DATE-TIME" else use the value
> present in vs->initial_prog_date_time
> >
> > Signed-off-by: Vignesh Ravichandran <vignesh.ravichandran02@gmail.com>
> > ---
> > libavformat/hlsenc.c | 33 ++++++++++++++++++++++++++++++---
> > 1 file changed, 30 insertions(+), 3 deletions(-)
> >
> > diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
> > index cbfd8f7c0d..9bce374605 100644
> > --- a/libavformat/hlsenc.c
> > +++ b/libavformat/hlsenc.c
> > @@ -88,6 +88,7 @@ typedef struct HLSSegment {
> >     char iv_string[KEYSIZE*2 + 1];
> >
> >     struct HLSSegment *next;
> > +    double discont_program_date_time;
> > } HLSSegment;
> >
> > typedef enum HLSFlags {
> > @@ -1124,6 +1125,7 @@ static int hls_append_segment(struct
> AVFormatContext *s, HLSContext *hls,
> >     en->keyframe_size     = vs->video_keyframe_size;
> >     en->next     = NULL;
> >     en->discont  = 0;
> > +    en->discont_program_date_time = 0;
> >
> >     if (vs->discontinuity) {
> >         en->discont = 1;
> > @@ -1148,7 +1150,8 @@ static int hls_append_segment(struct
> AVFormatContext *s, HLSContext *hls,
> >
> >     if (hls->max_nb_segments && vs->nb_entries >= hls->max_nb_segments) {
> >         en = vs->segments;
> > -        vs->initial_prog_date_time += en->duration;
> > +        if (!en->next->discont_program_date_time &&
> !en->discont_program_date_time)
> > +            vs->initial_prog_date_time += en->duration;
> >         vs->segments = en->next;
> >         if (en && hls->flags & HLS_DELETE_SEGMENTS &&
> > #if FF_API_HLS_WRAP
> > @@ -1182,6 +1185,7 @@ static int parse_playlist(AVFormatContext *s,
> const char *url, VariantStream *vs
> >     char line[MAX_URL_SIZE];
> >     const char *ptr;
> >     const char *end;
> > +    double discont_program_date_time = 0;
> >
> >     if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ,
> >                                    &s->interrupt_callback, NULL,
> > @@ -1236,7 +1240,25 @@ static int parse_playlist(AVFormatContext *s,
> const char *url, VariantStream *vs
> >                     av_strlcpy(vs->iv_string, ptr,
> sizeof(vs->iv_string));
> >                 }
> >             }
> > +        } else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:",
> &ptr)) {
> > +            struct tm program_date_time;
> > +            int y,M,d,h,m,s;
> > +            double ms;
> > +            if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h,
> &m, &s, &ms) != 7) {
> > +                ret = AVERROR_INVALIDDATA;
> > +                goto fail;
> > +            }
> > +
> > +            program_date_time.tm_year = y - 1900;
> > +            program_date_time.tm_mon = M - 1;
> > +            program_date_time.tm_mday = d;
> > +            program_date_time.tm_hour = h;
> > +            program_date_time.tm_min = m;
> > +            program_date_time.tm_sec = s;
> > +            program_date_time.tm_isdst = -1;
> >
> > +            discont_program_date_time = mktime(&program_date_time);
> > +            discont_program_date_time += (double)(ms / 1000);
> >         } else if (av_strstart(line, "#", NULL)) {
> >             continue;
> >         } else if (line[0]) {
> > @@ -1250,8 +1272,9 @@ static int parse_playlist(AVFormatContext *s,
> const char *url, VariantStream *vs
> >                 is_segment = 0;
> >                 new_start_pos = avio_tell(vs->avf->pb);
> >                 vs->size = new_start_pos - vs->start_pos;
> > -                vs->initial_prog_date_time -= vs->duration; // this is
> a previously existing segment
> >                 ret = hls_append_segment(s, hls, vs, vs->duration,
> vs->start_pos, vs->size);
> > +                vs->last_segment->discont_program_date_time =
> discont_program_date_time;
> > +                discont_program_date_time += vs->duration;
> >                 if (ret < 0)
> >                     goto fail;
> >                 vs->start_pos = new_start_pos;
> > @@ -1572,7 +1595,11 @@ static int hls_window(AVFormatContext *s, int
> last, VariantStream *vs)
> >         ret = ff_hls_write_file_entry(byterange_mode ? hls->m3u8_out :
> vs->out, en->discont, byterange_mode,
> >                                       en->duration, hls->flags &
> HLS_ROUND_DURATIONS,
> >                                       en->size, en->pos, hls->baseurl,
> > -                                      en->filename, prog_date_time_p,
> en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
> > +                                      en->filename,
> > +                                      en->discont_program_date_time ?
> &en->discont_program_date_time : prog_date_time_p,
> > +                                      en->keyframe_size,
> en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
> > +        if (en->discont_program_date_time)
> > +            en->discont_program_date_time -= en->duration;
> >         if (ret < 0) {
> >             av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get
> error\n");
> >         }
> > --
> > 2.24.2 (Apple Git-127)
> >
> > _______________________________________________
> > 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".
>
> LGTN
>
> Will push if no objections.
>
> Thanks
>
> Steven Liu
>
>
>
> _______________________________________________
> 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".
Gyan Doshi Dec. 8, 2020, 7:52 a.m. UTC | #3
On 08-12-2020 12:19 pm, Vignesh Ravichandran wrote:
> Friendly ping to check if the patch has been pushed.

No. You can check its status at 
https://patchwork.ffmpeg.org/project/ffmpeg/patch/20201201101040.28338-1-vignesh.ravichandran02@gmail.com/
State will be 'Accepted' when pushed.

Regards,
Gyan
diff mbox series

Patch

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index cbfd8f7c0d..9bce374605 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -88,6 +88,7 @@  typedef struct HLSSegment {
     char iv_string[KEYSIZE*2 + 1];
 
     struct HLSSegment *next;
+    double discont_program_date_time;
 } HLSSegment;
 
 typedef enum HLSFlags {
@@ -1124,6 +1125,7 @@  static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
     en->keyframe_size     = vs->video_keyframe_size;
     en->next     = NULL;
     en->discont  = 0;
+    en->discont_program_date_time = 0;
 
     if (vs->discontinuity) {
         en->discont = 1;
@@ -1148,7 +1150,8 @@  static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
 
     if (hls->max_nb_segments && vs->nb_entries >= hls->max_nb_segments) {
         en = vs->segments;
-        vs->initial_prog_date_time += en->duration;
+        if (!en->next->discont_program_date_time && !en->discont_program_date_time)
+            vs->initial_prog_date_time += en->duration;
         vs->segments = en->next;
         if (en && hls->flags & HLS_DELETE_SEGMENTS &&
 #if FF_API_HLS_WRAP
@@ -1182,6 +1185,7 @@  static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
     char line[MAX_URL_SIZE];
     const char *ptr;
     const char *end;
+    double discont_program_date_time = 0;
 
     if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ,
                                    &s->interrupt_callback, NULL,
@@ -1236,7 +1240,25 @@  static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
                     av_strlcpy(vs->iv_string, ptr, sizeof(vs->iv_string));
                 }
             }
+        } else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) {
+            struct tm program_date_time;
+            int y,M,d,h,m,s;
+            double ms;
+            if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) {
+                ret = AVERROR_INVALIDDATA;
+                goto fail;
+            }
+
+            program_date_time.tm_year = y - 1900;
+            program_date_time.tm_mon = M - 1;
+            program_date_time.tm_mday = d;
+            program_date_time.tm_hour = h;
+            program_date_time.tm_min = m;
+            program_date_time.tm_sec = s;
+            program_date_time.tm_isdst = -1;
 
+            discont_program_date_time = mktime(&program_date_time);
+            discont_program_date_time += (double)(ms / 1000);
         } else if (av_strstart(line, "#", NULL)) {
             continue;
         } else if (line[0]) {
@@ -1250,8 +1272,9 @@  static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
                 is_segment = 0;
                 new_start_pos = avio_tell(vs->avf->pb);
                 vs->size = new_start_pos - vs->start_pos;
-                vs->initial_prog_date_time -= vs->duration; // this is a previously existing segment
                 ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size);
+                vs->last_segment->discont_program_date_time = discont_program_date_time;
+                discont_program_date_time += vs->duration;
                 if (ret < 0)
                     goto fail;
                 vs->start_pos = new_start_pos;
@@ -1572,7 +1595,11 @@  static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
         ret = ff_hls_write_file_entry(byterange_mode ? hls->m3u8_out : vs->out, en->discont, byterange_mode,
                                       en->duration, hls->flags & HLS_ROUND_DURATIONS,
                                       en->size, en->pos, hls->baseurl,
-                                      en->filename, prog_date_time_p, en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
+                                      en->filename,
+                                      en->discont_program_date_time ? &en->discont_program_date_time : prog_date_time_p,
+                                      en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
+        if (en->discont_program_date_time)
+            en->discont_program_date_time -= en->duration;
         if (ret < 0) {
             av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
         }