diff mbox series

[FFmpeg-devel,v2] avformat/dashdec: Differentiate unassigned and zero attributes

Message ID 30896212-1aca-4cb6-c415-5f86c98dc6a3@gmail.com
State New
Headers show
Series [FFmpeg-devel,v2] avformat/dashdec: Differentiate unassigned and zero attributes | expand

Checks

Context Check Description
yinshiyou/configure_loongarch64 warning Failed to apply patch
andriy/configure_x86 warning Failed to apply patch

Commit Message

Gregor Riepl Oct. 18, 2022, 6:23 p.m. UTC
This fixes an issue where a timestamp attribute may have a valid zero
value (the UNIX epoch 1970-01-01T00:00:00), but is misinterpreted by
dashdec as being unassigned. This changes the logic that calculates
segment numbers and makes the stream undecodable by dashdec.

The fix originally posted to the issue tracker was incorrect and
changed other parts of the segment calculation logic. With this
patch, only the interpretation of the attributes is changed.
Some warnings are added to account for potential errors in manifests.

v2 change: Use int, 0 and 1 instead of C99 stdbool.
This similar to what's done in fftools/ffmpeg_opt.c.

Fixes: #8522
Signed-off-by: Gregor Riepl <onitake@gmail.com>
---
  libavformat/dashdec.c | 209 ++++++++++++++++++++++++++++++++----------
  1 file changed, 161 insertions(+), 48 deletions(-)

Comments

Steven Liu Oct. 20, 2022, 9:34 a.m. UTC | #1
Gregor Riepl <onitake@gmail.com> 于2022年10月19日周三 02:24写道:
>
> This fixes an issue where a timestamp attribute may have a valid zero
> value (the UNIX epoch 1970-01-01T00:00:00), but is misinterpreted by
> dashdec as being unassigned. This changes the logic that calculates
> segment numbers and makes the stream undecodable by dashdec.
>
> The fix originally posted to the issue tracker was incorrect and
> changed other parts of the segment calculation logic. With this
> patch, only the interpretation of the attributes is changed.
> Some warnings are added to account for potential errors in manifests.
>
> v2 change: Use int, 0 and 1 instead of C99 stdbool.
> This similar to what's done in fftools/ffmpeg_opt.c.
>
> Fixes: #8522
> Signed-off-by: Gregor Riepl <onitake@gmail.com>
> ---
>   libavformat/dashdec.c | 209 ++++++++++++++++++++++++++++++++----------
>   1 file changed, 161 insertions(+), 48 deletions(-)
>
> diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c
> index 29d4680c68..df5d453c5a 100644
> --- a/libavformat/dashdec.c
> +++ b/libavformat/dashdec.c
> @@ -129,21 +129,34 @@ typedef struct DASHContext {
>       struct representation **subtitles;
>
>       /* MediaPresentationDescription Attribute */
> -    uint64_t media_presentation_duration;
> -    uint64_t suggested_presentation_delay;
> -    uint64_t availability_start_time;
> -    uint64_t availability_end_time;
> -    uint64_t publish_time;
> -    uint64_t minimum_update_period;
> -    uint64_t time_shift_buffer_depth;
> -    uint64_t min_buffer_time;
> +    uint64_t media_presentation_duration_value;
> +    uint64_t suggested_presentation_delay_value;
> +    uint64_t availability_start_time_value;
> +    uint64_t availability_end_time_value;
> +    uint64_t publish_time_value;
> +    uint64_t minimum_update_period_value;
> +    uint64_t time_shift_buffer_depth_value;
> +    uint64_t min_buffer_time_value;
>
>       /* Period Attribute */
> -    uint64_t period_duration;
> -    uint64_t period_start;
> +    uint64_t period_duration_value;
> +    uint64_t period_start_value;
>
>       /* AdaptationSet Attribute */
> -    char *adaptionset_lang;
> +    char *adaptionset_lang_value;
> +
> +    /* Attribute valid flags (true if the attribute exists in the XML manifest) */
> +    int media_presentation_duration_assigned;
> +    int suggested_presentation_delay_assigned;
> +    int availability_start_time_assigned;
> +    int availability_end_time_assigned;
> +    int publish_time_assigned;
> +    int minimum_update_period_assigned;
> +    int time_shift_buffer_depth_assigned;
> +    int min_buffer_time_assigned;
> +    int period_duration_assigned;
> +    int period_start_assigned;
> +    int adaptionset_lang_assigned;
>
>       int is_live;
>       AVIOInterruptCB *interrupt_callback;
> @@ -867,8 +880,8 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url,
>       rep = av_mallocz(sizeof(struct representation));
>       if (!rep)
>           return AVERROR(ENOMEM);
> -    if (c->adaptionset_lang) {
> -        rep->lang = av_strdup(c->adaptionset_lang);
> +    if (c->adaptionset_lang_assigned) {
> +        rep->lang = av_strdup(c->adaptionset_lang_value);
>           if (!rep->lang) {
>               av_log(s, AV_LOG_ERROR, "alloc language memory failure\n");
>               av_freep(&rep);
> @@ -1106,7 +1119,10 @@ static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adap
>           av_log(s, AV_LOG_WARNING, "Cannot get AdaptionSet\n");
>           return AVERROR(EINVAL);
>       }
> -    c->adaptionset_lang = xmlGetProp(adaptionset_node, "lang");
> +    c->adaptionset_lang_value = xmlGetProp(adaptionset_node, "lang");
> +    if (c->adaptionset_lang_value) {
> +        c->adaptionset_lang_assigned = 1;
> +    }
>
>       return 0;
>   }
> @@ -1162,8 +1178,9 @@ static int parse_manifest_adaptationset(AVFormatContext *s, const char *url,
>       }
>
>   err:
> -    xmlFree(c->adaptionset_lang);
> -    c->adaptionset_lang = NULL;
> +    xmlFree(c->adaptionset_lang_value);
> +    c->adaptionset_lang_value = NULL;
> +    c->adaptionset_lang_assigned = 0;
>       return ret;
>   }
>
> @@ -1273,29 +1290,37 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
>               val = xmlGetProp(node, attr->name);
>
>               if (!av_strcasecmp(attr->name, "availabilityStartTime")) {
> -                c->availability_start_time = get_utc_date_time_insec(s, val);
> -                av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time);
> +                c->availability_start_time_value = get_utc_date_time_insec(s, val);
> +                c->availability_start_time_assigned = 1;
> +                av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time_value);
>               } else if (!av_strcasecmp(attr->name, "availabilityEndTime")) {
> -                c->availability_end_time = get_utc_date_time_insec(s, val);
> -                av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time);
> +                c->availability_end_time_value = get_utc_date_time_insec(s, val);
> +                c->availability_end_time_assigned = 1;
> +                av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time_value);
>               } else if (!av_strcasecmp(attr->name, "publishTime")) {
> -                c->publish_time = get_utc_date_time_insec(s, val);
> -                av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time);
> +                c->publish_time_value = get_utc_date_time_insec(s, val);
> +                c->publish_time_assigned = 1;
> +                av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time_value);
>               } else if (!av_strcasecmp(attr->name, "minimumUpdatePeriod")) {
> -                c->minimum_update_period = get_duration_insec(s, val);
> -                av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period);
> +                c->minimum_update_period_value = get_duration_insec(s, val);
> +                c->minimum_update_period_assigned = 1;
> +                av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period_value);
>               } else if (!av_strcasecmp(attr->name, "timeShiftBufferDepth")) {
> -                c->time_shift_buffer_depth = get_duration_insec(s, val);
> -                av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth);
> +                c->time_shift_buffer_depth_value = get_duration_insec(s, val);
> +                c->time_shift_buffer_depth_assigned = 1;
> +                av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth_value);
>               } else if (!av_strcasecmp(attr->name, "minBufferTime")) {
> -                c->min_buffer_time = get_duration_insec(s, val);
> -                av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time);
> +                c->min_buffer_time_value = get_duration_insec(s, val);
> +                c->min_buffer_time_assigned = 1;
> +                av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time_value);
>               } else if (!av_strcasecmp(attr->name, "suggestedPresentationDelay")) {
> -                c->suggested_presentation_delay = get_duration_insec(s, val);
> -                av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay);
> +                c->suggested_presentation_delay_value = get_duration_insec(s, val);
> +                c->suggested_presentation_delay_assigned = 1;
> +                av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay_value);
>               } else if (!av_strcasecmp(attr->name, "mediaPresentationDuration")) {
> -                c->media_presentation_duration = get_duration_insec(s, val);
> -                av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration);
> +                c->media_presentation_duration_value = get_duration_insec(s, val);
> +                c->media_presentation_duration_assigned = 1;
> +                av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration_value);
>               }
>               attr = attr->next;
>               xmlFree(val);
> @@ -1325,12 +1350,30 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
>                       attr = attr->next;
>                       xmlFree(val);
>                   }
> -                if ((period_duration_sec) >= (c->period_duration)) {
> +                if (c->period_duration_assigned) {
> +                    if ((period_duration_sec) >= (c->period_duration_value)) {
> +                        period_node = node;
> +                        c->period_duration_value = period_duration_sec;
> +                        c->period_start_value = period_start_sec;
> +                        c->period_start_assigned = 1;
> +                        if (c->period_start_value > 0) {
> +                            c->media_presentation_duration_value = c->period_duration_value;
> +                            c->media_presentation_duration_assigned = 1;
> +                        }
> +                    } else {
> +                        av_log(s, AV_LOG_VERBOSE, "previous period_duration is larger than new value. ignoring.\n");
> +                    }
> +                } else {
> +                    av_log(s, AV_LOG_VERBOSE, "period_duration attribute unset - updating from calculated value.\n");
>                       period_node = node;
> -                    c->period_duration = period_duration_sec;
> -                    c->period_start = period_start_sec;
> -                    if (c->period_start > 0)
> -                        c->media_presentation_duration = c->period_duration;
> +                    c->period_duration_value = period_duration_sec;
> +                    c->period_duration_assigned = 1;
> +                    c->period_start_value = period_start_sec;
> +                    c->period_start_assigned = 1;
> +                    if (c->period_start_value > 0) {
> +                        c->media_presentation_duration_value = c->period_duration_value;
> +                        c->media_presentation_duration_assigned = 1;
> +                    }
>                   }
>               } else if (!av_strcasecmp(node->name, "ProgramInformation")) {
>                   parse_programinformation(s, node);
> @@ -1391,15 +1434,54 @@ static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls)
>           } else if (pls->fragment_duration){
>               av_log(s, AV_LOG_TRACE, "in fragment_duration mode fragment_timescale = %"PRId64", presentation_timeoffset = %"PRId64"\n", pls->fragment_timescale, pls->presentation_timeoffset);
>               if (pls->presentation_timeoffset) {
> -                num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time;
> -            } else if (c->publish_time > 0 && !c->availability_start_time) {
> -                if (c->min_buffer_time) {
> -                    num = pls->first_seq_no + (((c->publish_time + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time;
> +                if (c->availability_start_time_assigned && c->min_buffer_time_assigned) {
> +                    num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time_assigned;
>                   } else {
> -                    num = pls->first_seq_no + (((c->publish_time - c->time_shift_buffer_depth + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
> +                    av_log(s, AV_LOG_WARNING, "availability_start_time and/or min_buffer_time attributes unset - using zero values. segment numbers may be incorrect.\n");
> +                    if (c->availability_start_time_assigned) {
> +                        num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration;
> +                    } else if (c->min_buffer_time_assigned) {
> +                        num = pls->first_seq_no + (((get_current_time_in_sec()) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time_value;
> +                    } else {
> +                        num = pls->first_seq_no + (((get_current_time_in_sec()) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration;
> +                    }
> +                }
> +            } else if (c->publish_time_assigned && c->publish_time_value > 0 && !c->availability_start_time_assigned) {
> +                // FIXME is publish_time_value > 0 a required condition, or are we only checking for existence of the attribute?
> +                if (c->min_buffer_time_assigned) {
> +                    if (c->suggested_presentation_delay_assigned) {
> +                        num = pls->first_seq_no + (((c->publish_time_value + pls->fragment_duration) - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time_value;
> +                    } else {
> +                        av_log(s, AV_LOG_WARNING, "suggested_presentation_delay attribute unset - using zero value. segment numbers may be incorrect.\n");
> +                        num = pls->first_seq_no + ((c->publish_time_value + pls->fragment_duration) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time_value;
> +                    }
> +                } else {
> +                    if (c->time_shift_buffer_depth_assigned && c->suggested_presentation_delay_assigned) {
> +                        num = pls->first_seq_no + (((c->publish_time_value - c->time_shift_buffer_depth_value + pls->fragment_duration) - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration;
> +                    } else {
> +                        av_log(s, AV_LOG_WARNING, "time_shift_buffer_depth and/or suggested_presentation_delay attributes unset - using zero values. segment numbers may be incorrect.\n");
> +                        if (c->time_shift_buffer_depth_assigned) {
> +                            num = pls->first_seq_no + ((c->publish_time_value - c->time_shift_buffer_depth_value + pls->fragment_duration) * pls->fragment_timescale) / pls->fragment_duration;
> +                        } else if (c->suggested_presentation_delay_assigned) {
> +                            num = pls->first_seq_no + (((c->publish_time_value + pls->fragment_duration) - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration;
> +                        } else {
> +                            num = pls->first_seq_no + ((c->publish_time_value + pls->fragment_duration) * pls->fragment_timescale) / pls->fragment_duration;
> +                        }
> +                    }
>                   }
>               } else {
> -                num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
> +                if (c->availability_start_time_assigned && c->suggested_presentation_delay_assigned) {
> +                    num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value) - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration;
> +                } else {
> +                    av_log(s, AV_LOG_WARNING, "availability_start_time and/or suggested_presentation_delay attributes unset - using zero values. segment numbers may be incorrect.\n");
> +                    if (c->availability_start_time_assigned) {
> +                        num = pls->first_seq_no + ((get_current_time_in_sec() - c->availability_start_time_value) * pls->fragment_timescale) / pls->fragment_duration;
> +                    } else if (c->suggested_presentation_delay_assigned) {
> +                        num = pls->first_seq_no + ((get_current_time_in_sec() - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration;
> +                    } else {
> +                        num = pls->first_seq_no + (get_current_time_in_sec() * pls->fragment_timescale) / pls->fragment_duration;
> +                    }
> +                }
>               }
>           }
>       } else {
> @@ -1415,7 +1497,18 @@ static int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls)
>
>       if (c->is_live && pls->fragment_duration) {
>           av_log(s, AV_LOG_TRACE, "in live mode\n");
> -        num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->time_shift_buffer_depth) * pls->fragment_timescale) / pls->fragment_duration;
> +        if (c->availability_start_time_assigned && c->time_shift_buffer_depth_assigned) {
> +            num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value) - c->time_shift_buffer_depth_value) * pls->fragment_timescale) / pls->fragment_duration;
> +        } else {
> +            av_log(s, AV_LOG_WARNING, "availability_start_time and/or time_shift_buffer_depth attributes unset - using zero values. segment numbers may be incorrect.\n");
> +            if (c->availability_start_time_assigned) {
> +                num = pls->first_seq_no + ((get_current_time_in_sec() - c->availability_start_time_value) * pls->fragment_timescale) / pls->fragment_duration;
> +            } else if (c->time_shift_buffer_depth_assigned) {
> +                num = pls->first_seq_no + ((get_current_time_in_sec() - c->time_shift_buffer_depth_value) * pls->fragment_timescale) / pls->fragment_duration;
> +            } else {
> +                num = pls->first_seq_no + (get_current_time_in_sec() * pls->fragment_timescale) / pls->fragment_duration;
> +            }
> +        }
>       } else {
>           num = pls->first_seq_no;
>       }
> @@ -1434,15 +1527,30 @@ static int64_t calc_max_seg_no(struct representation *pls, DASHContext *c)
>           for (i = 0; i < pls->n_timelines; i++) {
>               if (pls->timelines[i]->repeat == -1) {
>                   int length_of_each_segment = pls->timelines[i]->duration / pls->fragment_timescale;
> -                num =  c->period_duration / length_of_each_segment;
> +                if (c->period_duration_assigned) {
> +                    num = c->period_duration_value / length_of_each_segment;
> +                } else {
> +                    av_log(NULL, AV_LOG_WARNING, "period_duration attribute unset - using zero value. segment numbers may be incorrect.\n");
> +                    num = 0;
> +                }
>               } else {
>                   num += pls->timelines[i]->repeat;
>               }
>           }
>       } else if (c->is_live && pls->fragment_duration) {
> -        num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time)) * pls->fragment_timescale)  / pls->fragment_duration;
> +        if (c->availability_start_time_assigned) {
> +            num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value)) * pls->fragment_timescale)  / pls->fragment_duration;
> +        } else {
> +            av_log(NULL, AV_LOG_WARNING, "availability_start_time attribute unset - using zero value. segment numbers may be incorrect.\n");
> +            num = pls->first_seq_no + (get_current_time_in_sec() * pls->fragment_timescale)  / pls->fragment_duration;
> +        }
>       } else if (pls->fragment_duration) {
> -        num = pls->first_seq_no + av_rescale_rnd(1, c->media_presentation_duration * pls->fragment_timescale, pls->fragment_duration, AV_ROUND_UP);
> +        if (c->media_presentation_duration_assigned) {
> +            num = pls->first_seq_no + av_rescale_rnd(1, c->media_presentation_duration_value * pls->fragment_timescale, pls->fragment_duration, AV_ROUND_UP);
> +        } else {
> +            av_log(NULL, AV_LOG_WARNING, "media_presentation_duration attribute unset - using zero value. segment numbers may be incorrect.\n");
> +            num = pls->first_seq_no + av_rescale_rnd(1, 0, pls->fragment_duration, AV_ROUND_UP);
> +        }
>       }
>
>       return num;
> @@ -2040,7 +2148,12 @@ static int dash_read_header(AVFormatContext *s)
>       /* If this isn't a live stream, fill the total duration of the
>        * stream. */
>       if (!c->is_live) {
> -        s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
> +        if (c->media_presentation_duration_assigned) {
> +            s->duration = (int64_t) c->media_presentation_duration_value * AV_TIME_BASE;
> +        } else {
> +            av_log(NULL, AV_LOG_WARNING, "media_presentation_duration attribute unset - using zero value. segment numbers may be incorrect.\n");
> +            s->duration = 0;
> +        }
>       } else {
>           av_dict_set(&c->avio_opts, "seekable", "0", 0);
>       }
> --
> 2.35.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".

lgtm

btw, i cannot sure if we use c99 stdbool.h, if no body objection, i
will push this version of patch.

Thanks
Steven
diff mbox series

Patch

diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c
index 29d4680c68..df5d453c5a 100644
--- a/libavformat/dashdec.c
+++ b/libavformat/dashdec.c
@@ -129,21 +129,34 @@  typedef struct DASHContext {
      struct representation **subtitles;
  
      /* MediaPresentationDescription Attribute */
-    uint64_t media_presentation_duration;
-    uint64_t suggested_presentation_delay;
-    uint64_t availability_start_time;
-    uint64_t availability_end_time;
-    uint64_t publish_time;
-    uint64_t minimum_update_period;
-    uint64_t time_shift_buffer_depth;
-    uint64_t min_buffer_time;
+    uint64_t media_presentation_duration_value;
+    uint64_t suggested_presentation_delay_value;
+    uint64_t availability_start_time_value;
+    uint64_t availability_end_time_value;
+    uint64_t publish_time_value;
+    uint64_t minimum_update_period_value;
+    uint64_t time_shift_buffer_depth_value;
+    uint64_t min_buffer_time_value;
  
      /* Period Attribute */
-    uint64_t period_duration;
-    uint64_t period_start;
+    uint64_t period_duration_value;
+    uint64_t period_start_value;
  
      /* AdaptationSet Attribute */
-    char *adaptionset_lang;
+    char *adaptionset_lang_value;
+
+    /* Attribute valid flags (true if the attribute exists in the XML manifest) */
+    int media_presentation_duration_assigned;
+    int suggested_presentation_delay_assigned;
+    int availability_start_time_assigned;
+    int availability_end_time_assigned;
+    int publish_time_assigned;
+    int minimum_update_period_assigned;
+    int time_shift_buffer_depth_assigned;
+    int min_buffer_time_assigned;
+    int period_duration_assigned;
+    int period_start_assigned;
+    int adaptionset_lang_assigned;
  
      int is_live;
      AVIOInterruptCB *interrupt_callback;
@@ -867,8 +880,8 @@  static int parse_manifest_representation(AVFormatContext *s, const char *url,
      rep = av_mallocz(sizeof(struct representation));
      if (!rep)
          return AVERROR(ENOMEM);
-    if (c->adaptionset_lang) {
-        rep->lang = av_strdup(c->adaptionset_lang);
+    if (c->adaptionset_lang_assigned) {
+        rep->lang = av_strdup(c->adaptionset_lang_value);
          if (!rep->lang) {
              av_log(s, AV_LOG_ERROR, "alloc language memory failure\n");
              av_freep(&rep);
@@ -1106,7 +1119,10 @@  static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adap
          av_log(s, AV_LOG_WARNING, "Cannot get AdaptionSet\n");
          return AVERROR(EINVAL);
      }
-    c->adaptionset_lang = xmlGetProp(adaptionset_node, "lang");
+    c->adaptionset_lang_value = xmlGetProp(adaptionset_node, "lang");
+    if (c->adaptionset_lang_value) {
+        c->adaptionset_lang_assigned = 1;
+    }
  
      return 0;
  }
@@ -1162,8 +1178,9 @@  static int parse_manifest_adaptationset(AVFormatContext *s, const char *url,
      }
  
  err:
-    xmlFree(c->adaptionset_lang);
-    c->adaptionset_lang = NULL;
+    xmlFree(c->adaptionset_lang_value);
+    c->adaptionset_lang_value = NULL;
+    c->adaptionset_lang_assigned = 0;
      return ret;
  }
  
@@ -1273,29 +1290,37 @@  static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
              val = xmlGetProp(node, attr->name);
  
              if (!av_strcasecmp(attr->name, "availabilityStartTime")) {
-                c->availability_start_time = get_utc_date_time_insec(s, val);
-                av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time);
+                c->availability_start_time_value = get_utc_date_time_insec(s, val);
+                c->availability_start_time_assigned = 1;
+                av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time_value);
              } else if (!av_strcasecmp(attr->name, "availabilityEndTime")) {
-                c->availability_end_time = get_utc_date_time_insec(s, val);
-                av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time);
+                c->availability_end_time_value = get_utc_date_time_insec(s, val);
+                c->availability_end_time_assigned = 1;
+                av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time_value);
              } else if (!av_strcasecmp(attr->name, "publishTime")) {
-                c->publish_time = get_utc_date_time_insec(s, val);
-                av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time);
+                c->publish_time_value = get_utc_date_time_insec(s, val);
+                c->publish_time_assigned = 1;
+                av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time_value);
              } else if (!av_strcasecmp(attr->name, "minimumUpdatePeriod")) {
-                c->minimum_update_period = get_duration_insec(s, val);
-                av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period);
+                c->minimum_update_period_value = get_duration_insec(s, val);
+                c->minimum_update_period_assigned = 1;
+                av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period_value);
              } else if (!av_strcasecmp(attr->name, "timeShiftBufferDepth")) {
-                c->time_shift_buffer_depth = get_duration_insec(s, val);
-                av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth);
+                c->time_shift_buffer_depth_value = get_duration_insec(s, val);
+                c->time_shift_buffer_depth_assigned = 1;
+                av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth_value);
              } else if (!av_strcasecmp(attr->name, "minBufferTime")) {
-                c->min_buffer_time = get_duration_insec(s, val);
-                av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time);
+                c->min_buffer_time_value = get_duration_insec(s, val);
+                c->min_buffer_time_assigned = 1;
+                av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time_value);
              } else if (!av_strcasecmp(attr->name, "suggestedPresentationDelay")) {
-                c->suggested_presentation_delay = get_duration_insec(s, val);
-                av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay);
+                c->suggested_presentation_delay_value = get_duration_insec(s, val);
+                c->suggested_presentation_delay_assigned = 1;
+                av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay_value);
              } else if (!av_strcasecmp(attr->name, "mediaPresentationDuration")) {
-                c->media_presentation_duration = get_duration_insec(s, val);
-                av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration);
+                c->media_presentation_duration_value = get_duration_insec(s, val);
+                c->media_presentation_duration_assigned = 1;
+                av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration_value);
              }
              attr = attr->next;
              xmlFree(val);
@@ -1325,12 +1350,30 @@  static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
                      attr = attr->next;
                      xmlFree(val);
                  }
-                if ((period_duration_sec) >= (c->period_duration)) {
+                if (c->period_duration_assigned) {
+                    if ((period_duration_sec) >= (c->period_duration_value)) {
+                        period_node = node;
+                        c->period_duration_value = period_duration_sec;
+                        c->period_start_value = period_start_sec;
+                        c->period_start_assigned = 1;
+                        if (c->period_start_value > 0) {
+                            c->media_presentation_duration_value = c->period_duration_value;
+                            c->media_presentation_duration_assigned = 1;
+                        }
+                    } else {
+                        av_log(s, AV_LOG_VERBOSE, "previous period_duration is larger than new value. ignoring.\n");
+                    }
+                } else {
+                    av_log(s, AV_LOG_VERBOSE, "period_duration attribute unset - updating from calculated value.\n");
                      period_node = node;
-                    c->period_duration = period_duration_sec;
-                    c->period_start = period_start_sec;
-                    if (c->period_start > 0)
-                        c->media_presentation_duration = c->period_duration;
+                    c->period_duration_value = period_duration_sec;
+                    c->period_duration_assigned = 1;
+                    c->period_start_value = period_start_sec;
+                    c->period_start_assigned = 1;
+                    if (c->period_start_value > 0) {
+                        c->media_presentation_duration_value = c->period_duration_value;
+                        c->media_presentation_duration_assigned = 1;
+                    }
                  }
              } else if (!av_strcasecmp(node->name, "ProgramInformation")) {
                  parse_programinformation(s, node);
@@ -1391,15 +1434,54 @@  static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls)
          } else if (pls->fragment_duration){
              av_log(s, AV_LOG_TRACE, "in fragment_duration mode fragment_timescale = %"PRId64", presentation_timeoffset = %"PRId64"\n", pls->fragment_timescale, pls->presentation_timeoffset);
              if (pls->presentation_timeoffset) {
-                num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time;
-            } else if (c->publish_time > 0 && !c->availability_start_time) {
-                if (c->min_buffer_time) {
-                    num = pls->first_seq_no + (((c->publish_time + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time;
+                if (c->availability_start_time_assigned && c->min_buffer_time_assigned) {
+                    num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time_assigned;
                  } else {
-                    num = pls->first_seq_no + (((c->publish_time - c->time_shift_buffer_depth + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
+                    av_log(s, AV_LOG_WARNING, "availability_start_time and/or min_buffer_time attributes unset - using zero values. segment numbers may be incorrect.\n");
+                    if (c->availability_start_time_assigned) {
+                        num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration;
+                    } else if (c->min_buffer_time_assigned) {
+                        num = pls->first_seq_no + (((get_current_time_in_sec()) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time_value;
+                    } else {
+                        num = pls->first_seq_no + (((get_current_time_in_sec()) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration;
+                    }
+                }
+            } else if (c->publish_time_assigned && c->publish_time_value > 0 && !c->availability_start_time_assigned) {
+                // FIXME is publish_time_value > 0 a required condition, or are we only checking for existence of the attribute?
+                if (c->min_buffer_time_assigned) {
+                    if (c->suggested_presentation_delay_assigned) {
+                        num = pls->first_seq_no + (((c->publish_time_value + pls->fragment_duration) - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time_value;
+                    } else {
+                        av_log(s, AV_LOG_WARNING, "suggested_presentation_delay attribute unset - using zero value. segment numbers may be incorrect.\n");
+                        num = pls->first_seq_no + ((c->publish_time_value + pls->fragment_duration) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time_value;
+                    }
+                } else {
+                    if (c->time_shift_buffer_depth_assigned && c->suggested_presentation_delay_assigned) {
+                        num = pls->first_seq_no + (((c->publish_time_value - c->time_shift_buffer_depth_value + pls->fragment_duration) - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration;
+                    } else {
+                        av_log(s, AV_LOG_WARNING, "time_shift_buffer_depth and/or suggested_presentation_delay attributes unset - using zero values. segment numbers may be incorrect.\n");
+                        if (c->time_shift_buffer_depth_assigned) {
+                            num = pls->first_seq_no + ((c->publish_time_value - c->time_shift_buffer_depth_value + pls->fragment_duration) * pls->fragment_timescale) / pls->fragment_duration;
+                        } else if (c->suggested_presentation_delay_assigned) {
+                            num = pls->first_seq_no + (((c->publish_time_value + pls->fragment_duration) - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration;
+                        } else {
+                            num = pls->first_seq_no + ((c->publish_time_value + pls->fragment_duration) * pls->fragment_timescale) / pls->fragment_duration;
+                        }
+                    }
                  }
              } else {
-                num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
+                if (c->availability_start_time_assigned && c->suggested_presentation_delay_assigned) {
+                    num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value) - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration;
+                } else {
+                    av_log(s, AV_LOG_WARNING, "availability_start_time and/or suggested_presentation_delay attributes unset - using zero values. segment numbers may be incorrect.\n");
+                    if (c->availability_start_time_assigned) {
+                        num = pls->first_seq_no + ((get_current_time_in_sec() - c->availability_start_time_value) * pls->fragment_timescale) / pls->fragment_duration;
+                    } else if (c->suggested_presentation_delay_assigned) {
+                        num = pls->first_seq_no + ((get_current_time_in_sec() - c->suggested_presentation_delay_value) * pls->fragment_timescale) / pls->fragment_duration;
+                    } else {
+                        num = pls->first_seq_no + (get_current_time_in_sec() * pls->fragment_timescale) / pls->fragment_duration;
+                    }
+                }
              }
          }
      } else {
@@ -1415,7 +1497,18 @@  static int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls)
  
      if (c->is_live && pls->fragment_duration) {
          av_log(s, AV_LOG_TRACE, "in live mode\n");
-        num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->time_shift_buffer_depth) * pls->fragment_timescale) / pls->fragment_duration;
+        if (c->availability_start_time_assigned && c->time_shift_buffer_depth_assigned) {
+            num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value) - c->time_shift_buffer_depth_value) * pls->fragment_timescale) / pls->fragment_duration;
+        } else {
+            av_log(s, AV_LOG_WARNING, "availability_start_time and/or time_shift_buffer_depth attributes unset - using zero values. segment numbers may be incorrect.\n");
+            if (c->availability_start_time_assigned) {
+                num = pls->first_seq_no + ((get_current_time_in_sec() - c->availability_start_time_value) * pls->fragment_timescale) / pls->fragment_duration;
+            } else if (c->time_shift_buffer_depth_assigned) {
+                num = pls->first_seq_no + ((get_current_time_in_sec() - c->time_shift_buffer_depth_value) * pls->fragment_timescale) / pls->fragment_duration;
+            } else {
+                num = pls->first_seq_no + (get_current_time_in_sec() * pls->fragment_timescale) / pls->fragment_duration;
+            }
+        }
      } else {
          num = pls->first_seq_no;
      }
@@ -1434,15 +1527,30 @@  static int64_t calc_max_seg_no(struct representation *pls, DASHContext *c)
          for (i = 0; i < pls->n_timelines; i++) {
              if (pls->timelines[i]->repeat == -1) {
                  int length_of_each_segment = pls->timelines[i]->duration / pls->fragment_timescale;
-                num =  c->period_duration / length_of_each_segment;
+                if (c->period_duration_assigned) {
+                    num = c->period_duration_value / length_of_each_segment;
+                } else {
+                    av_log(NULL, AV_LOG_WARNING, "period_duration attribute unset - using zero value. segment numbers may be incorrect.\n");
+                    num = 0;
+                }
              } else {
                  num += pls->timelines[i]->repeat;
              }
          }
      } else if (c->is_live && pls->fragment_duration) {
-        num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time)) * pls->fragment_timescale)  / pls->fragment_duration;
+        if (c->availability_start_time_assigned) {
+            num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time_value)) * pls->fragment_timescale)  / pls->fragment_duration;
+        } else {
+            av_log(NULL, AV_LOG_WARNING, "availability_start_time attribute unset - using zero value. segment numbers may be incorrect.\n");
+            num = pls->first_seq_no + (get_current_time_in_sec() * pls->fragment_timescale)  / pls->fragment_duration;
+        }
      } else if (pls->fragment_duration) {
-        num = pls->first_seq_no + av_rescale_rnd(1, c->media_presentation_duration * pls->fragment_timescale, pls->fragment_duration, AV_ROUND_UP);
+        if (c->media_presentation_duration_assigned) {
+            num = pls->first_seq_no + av_rescale_rnd(1, c->media_presentation_duration_value * pls->fragment_timescale, pls->fragment_duration, AV_ROUND_UP);
+        } else {
+            av_log(NULL, AV_LOG_WARNING, "media_presentation_duration attribute unset - using zero value. segment numbers may be incorrect.\n");
+            num = pls->first_seq_no + av_rescale_rnd(1, 0, pls->fragment_duration, AV_ROUND_UP);
+        }
      }
  
      return num;
@@ -2040,7 +2148,12 @@  static int dash_read_header(AVFormatContext *s)
      /* If this isn't a live stream, fill the total duration of the
       * stream. */
      if (!c->is_live) {
-        s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
+        if (c->media_presentation_duration_assigned) {
+            s->duration = (int64_t) c->media_presentation_duration_value * AV_TIME_BASE;
+        } else {
+            av_log(NULL, AV_LOG_WARNING, "media_presentation_duration attribute unset - using zero value. segment numbers may be incorrect.\n");
+            s->duration = 0;
+        }
      } else {
          av_dict_set(&c->avio_opts, "seekable", "0", 0);
      }