char *allowed_extensions;
AVDictionary *avio_opts;
int max_url_size;
+
+ /* Flags for init section*/
+ int is_init_section_common_video;
+ int is_init_section_common_audio;
+
} DASHContext;
static int ishttp(char *url)
if (av_strstart(proto_name, "file", NULL)) {
if (strcmp(c->allowed_extensions, "ALL") && !av_match_ext(url, c->allowed_extensions)) {
av_log(s, AV_LOG_ERROR,
- "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n"
- "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n",
- url);
+ "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n"
+ "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n",
+ url);
return AVERROR_INVALIDDATA;
}
} else if (av_strstart(proto_name, "http", NULL)) {
char *baseurl = NULL;
char *root_url = NULL;
char *text = NULL;
+ char *tmp = NULL;
int isRootHttp = 0;
char token ='/';
goto end;
}
av_strlcpy(text, url, strlen(url)+1);
- while (mpdName = av_strtok(text, "/", &text)) {
+ tmp = text;
+ while (mpdName = av_strtok(tmp, "/", &tmp)) {
size = strlen(mpdName);
}
+ av_free(text);
path = av_mallocz(tmp_max_url_size);
tmp_str = av_mallocz(tmp_max_url_size);
}
av_free(path);
av_free(tmp_str);
+ xmlFree(baseurl);
return updated;
}
xmlNodePtr fragment_template_node,
xmlNodePtr content_component_node,
xmlNodePtr adaptionset_baseurl_node,
- xmlNodePtr adaptionset_segmentlist_node)
+ xmlNodePtr adaptionset_segmentlist_node,
+ xmlNodePtr adaptionset_supplementalproperty_node)
{
int32_t ret = 0;
int32_t audio_rep_idx = 0;
char *timescale_val = NULL;
char *initialization_val = NULL;
char *media_val = NULL;
+ char *val = NULL;
xmlNodePtr baseurl_nodes[4];
xmlNodePtr representation_node = node;
char *rep_id_val = xmlGetProp(representation_node, "id");
rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10);
xmlFree(startnumber_val);
}
+ if (adaptionset_supplementalproperty_node) {
+ if (!av_strcasecmp(xmlGetProp(adaptionset_supplementalproperty_node,"schemeIdUri"), "http://dashif.org/guidelines/last-segment-number")) {
+ val = xmlGetProp(adaptionset_supplementalproperty_node,"value");
+ if (!val) {
+ av_log(s, AV_LOG_ERROR, "Missing value attribute in adaptionset_supplementalproperty_node\n");
+ } else {
+ rep->last_seq_no =(int64_t) strtoll(val, NULL, 10) - 1;
+ xmlFree(val);
+ }
+ }
+ }
fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline");
xmlNodePtr content_component_node = NULL;
xmlNodePtr adaptionset_baseurl_node = NULL;
xmlNodePtr adaptionset_segmentlist_node = NULL;
+ xmlNodePtr adaptionset_supplementalproperty_node = NULL;
xmlNodePtr node = NULL;
node = xmlFirstElementChild(adaptionset_node);
adaptionset_baseurl_node = node;
} else if (!av_strcasecmp(node->name, (const char *)"SegmentList")) {
adaptionset_segmentlist_node = node;
+ } else if (!av_strcasecmp(node->name, (const char *)"SupplementalProperty")) {
+ adaptionset_supplementalproperty_node = node;
} else if (!av_strcasecmp(node->name, (const char *)"Representation")) {
ret = parse_manifest_representation(s, url, node,
adaptionset_node,
fragment_template_node,
content_component_node,
adaptionset_baseurl_node,
- adaptionset_segmentlist_node);
+ adaptionset_segmentlist_node,
+ adaptionset_supplementalproperty_node);
if (ret < 0) {
return ret;
}
xmlNodePtr root_element = NULL;
xmlNodePtr node = NULL;
xmlNodePtr period_node = NULL;
+ xmlNodePtr tmp_node = NULL;
xmlNodePtr mpd_baseurl_node = NULL;
xmlNodePtr period_baseurl_node = NULL;
xmlNodePtr period_segmenttemplate_node = NULL;
xmlNodePtr adaptionset_node = NULL;
xmlAttrPtr attr = NULL;
char *val = NULL;
- uint32_t perdiod_duration_sec = 0;
- uint32_t perdiod_start_sec = 0;
+ uint32_t period_duration_sec = 0;
+ uint32_t period_start_sec = 0;
if (!in) {
close_in = 1;
} else {
LIBXML_TEST_VERSION
- doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0);
+ doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0);
root_element = xmlDocGetRootElement(doc);
node = root_element;
xmlFree(val);
}
- mpd_baseurl_node = find_child_node_by_name(node, "BaseURL");
- if (!mpd_baseurl_node) {
+ tmp_node = find_child_node_by_name(node, "BaseURL");
+ if (tmp_node) {
+ mpd_baseurl_node = xmlCopyNode(tmp_node,1);
+ } else {
mpd_baseurl_node = xmlNewNode(NULL, "BaseURL");
}
node = xmlFirstElementChild(node);
while (node) {
if (!av_strcasecmp(node->name, (const char *)"Period")) {
- perdiod_duration_sec = 0;
- perdiod_start_sec = 0;
+ period_duration_sec = 0;
+ period_start_sec = 0;
attr = node->properties;
while (attr) {
val = xmlGetProp(node, attr->name);
if (!av_strcasecmp(attr->name, (const char *)"duration")) {
- perdiod_duration_sec = get_duration_insec(s, (const char *)val);
+ period_duration_sec = get_duration_insec(s, (const char *)val);
} else if (!av_strcasecmp(attr->name, (const char *)"start")) {
- perdiod_start_sec = get_duration_insec(s, (const char *)val);
+ period_start_sec = get_duration_insec(s, (const char *)val);
}
attr = attr->next;
xmlFree(val);
}
- if ((perdiod_duration_sec) >= (c->period_duration)) {
+ if ((period_duration_sec) >= (c->period_duration)) {
period_node = node;
- c->period_duration = perdiod_duration_sec;
- c->period_start = perdiod_start_sec;
+ c->period_duration = period_duration_sec;
+ c->period_start = period_start_sec;
if (c->period_start > 0)
c->media_presentation_duration = c->period_duration;
}
/*free the document */
xmlFreeDoc(doc);
xmlCleanupParser();
+ xmlFreeNode(mpd_baseurl_node);
}
av_free(new_url);
c->videos = NULL;
c->n_audios = 0;
c->audios = NULL;
- ret = parse_manifest(s, s->filename, NULL);
+ ret = parse_manifest(s, s->url, NULL);
if (ret)
goto finish;
if (c->n_videos != n_videos) {
av_log(c, AV_LOG_ERROR,
- "new manifest has mismatched no. of video representations, %d -> %d\n",
- n_videos, c->n_videos);
+ "new manifest has mismatched no. of video representations, %d -> %d\n",
+ n_videos, c->n_videos);
return AVERROR_INVALIDDATA;
}
if (c->n_audios != n_audios) {
av_log(c, AV_LOG_ERROR,
- "new manifest has mismatched no. of audio representations, %d -> %d\n",
- n_audios, c->n_audios);
+ "new manifest has mismatched no. of audio representations, %d -> %d\n",
+ n_audios, c->n_audios);
return AVERROR_INVALIDDATA;
}
av_log(s, AV_LOG_ERROR,
"A DASH playlist item '%s' referred to an external file '%s'. "
"Opening this file was forbidden for security reasons\n",
- s->filename, url);
+ s->url, url);
return AVERROR(EPERM);
}
pls->parent = s;
pls->cur_seq_no = calc_cur_seg_no(s, pls);
- pls->last_seq_no = calc_max_seg_no(pls, s->priv_data);
+
+ if (!pls->last_seq_no) {
+ pls->last_seq_no = calc_max_seg_no(pls, s->priv_data);
+ }
ret = reopen_demux_for_component(s, pls);
if (ret < 0) {
return ret;
}
+static int is_common_init_section_exist(struct representation **pls, int n_pls)
+{
+ struct fragment *first_init_section = pls[0]->init_section;
+ char *url =NULL;
+ int64_t url_offset = -1;
+ int64_t size = -1;
+ int i = 0;
+
+ if (first_init_section == NULL || n_pls == 0)
+ return 0;
+
+ url = first_init_section->url;
+ url_offset = first_init_section->url_offset;
+ size = pls[0]->init_section->size;
+ for (i=0;i<n_pls;i++) {
+ if (av_strcasecmp(pls[i]->init_section->url,url) || pls[i]->init_section->url_offset != url_offset || pls[i]->init_section->size != size) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void copy_init_section(struct representation *rep_dest, struct representation *rep_src)
+{
+ *rep_dest->init_section = *rep_src->init_section;
+ rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size);
+ memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len);
+ rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size;
+ rep_dest->init_sec_data_len = rep_src->init_sec_data_len;
+ rep_dest->cur_timestamp = rep_src->cur_timestamp;
+}
+
+
static int dash_read_header(AVFormatContext *s)
{
void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb;
update_options(&c->headers, "headers", u);
}
- if ((ret = parse_manifest(s, s->filename, s->pb)) < 0)
+ if ((ret = parse_manifest(s, s->url, s->pb)) < 0)
goto fail;
if ((ret = save_avio_options(s)) < 0)
s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
}
+ c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos);
+
/* Open the demuxer for video and audio components if available */
for (i = 0; i < c->n_videos; i++) {
struct representation *cur_video = c->videos[i];
+ if (i > 0 && c->is_init_section_common_video) {
+ copy_init_section(cur_video,c->videos[0]);
+ }
ret = open_demux_for_component(s, cur_video);
+
if (ret)
goto fail;
cur_video->stream_index = stream_index;
++stream_index;
}
+ c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios);
+
for (i = 0; i < c->n_audios; i++) {
struct representation *cur_audio = c->audios[i];
+ if (i > 0 && c->is_init_section_common_audio) {
+ copy_init_section(cur_audio,c->audios[0]);
+ }
ret = open_demux_for_component(s, cur_audio);
+
if (ret)
goto fail;
cur_audio->stream_index = stream_index;
av_dict_set_int(&pls->assoc_stream->metadata, "variant_bitrate", pls->bandwidth, 0);
if (pls->id[0])
av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0);
- }
+ }
for (i = 0; i < c->n_audios; i++) {
struct representation *pls = c->audios[i];
int64_t duration = 0;
av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms], playlist %d%s\n",
- seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : "");
+ seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : "");
// single fragment mode
if (pls->n_fragments == 1) {