1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Dynamic Adaptive Streaming over HTTP demux 3cabdff1aSopenharmony_ci * Copyright (c) 2017 samsamsam@o2.pl based on HLS demux 4cabdff1aSopenharmony_ci * Copyright (c) 2017 Steven Liu 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is part of FFmpeg. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 12cabdff1aSopenharmony_ci * 13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16cabdff1aSopenharmony_ci * Lesser General Public License for more details. 17cabdff1aSopenharmony_ci * 18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21cabdff1aSopenharmony_ci */ 22cabdff1aSopenharmony_ci#include <libxml/parser.h> 23cabdff1aSopenharmony_ci#include "libavutil/bprint.h" 24cabdff1aSopenharmony_ci#include "libavutil/opt.h" 25cabdff1aSopenharmony_ci#include "libavutil/time.h" 26cabdff1aSopenharmony_ci#include "libavutil/parseutils.h" 27cabdff1aSopenharmony_ci#include "internal.h" 28cabdff1aSopenharmony_ci#include "avio_internal.h" 29cabdff1aSopenharmony_ci#include "dash.h" 30cabdff1aSopenharmony_ci#include "demux.h" 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_ci#define INITIAL_BUFFER_SIZE 32768 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_cistruct fragment { 35cabdff1aSopenharmony_ci int64_t url_offset; 36cabdff1aSopenharmony_ci int64_t size; 37cabdff1aSopenharmony_ci char *url; 38cabdff1aSopenharmony_ci}; 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_ci/* 41cabdff1aSopenharmony_ci * reference to : ISO_IEC_23009-1-DASH-2012 42cabdff1aSopenharmony_ci * Section: 5.3.9.6.2 43cabdff1aSopenharmony_ci * Table: Table 17 — Semantics of SegmentTimeline element 44cabdff1aSopenharmony_ci * */ 45cabdff1aSopenharmony_cistruct timeline { 46cabdff1aSopenharmony_ci /* starttime: Element or Attribute Name 47cabdff1aSopenharmony_ci * specifies the MPD start time, in @timescale units, 48cabdff1aSopenharmony_ci * the first Segment in the series starts relative to the beginning of the Period. 49cabdff1aSopenharmony_ci * The value of this attribute must be equal to or greater than the sum of the previous S 50cabdff1aSopenharmony_ci * element earliest presentation time and the sum of the contiguous Segment durations. 51cabdff1aSopenharmony_ci * If the value of the attribute is greater than what is expressed by the previous S element, 52cabdff1aSopenharmony_ci * it expresses discontinuities in the timeline. 53cabdff1aSopenharmony_ci * If not present then the value shall be assumed to be zero for the first S element 54cabdff1aSopenharmony_ci * and for the subsequent S elements, the value shall be assumed to be the sum of 55cabdff1aSopenharmony_ci * the previous S element's earliest presentation time and contiguous duration 56cabdff1aSopenharmony_ci * (i.e. previous S@starttime + @duration * (@repeat + 1)). 57cabdff1aSopenharmony_ci * */ 58cabdff1aSopenharmony_ci int64_t starttime; 59cabdff1aSopenharmony_ci /* repeat: Element or Attribute Name 60cabdff1aSopenharmony_ci * specifies the repeat count of the number of following contiguous Segments with 61cabdff1aSopenharmony_ci * the same duration expressed by the value of @duration. This value is zero-based 62cabdff1aSopenharmony_ci * (e.g. a value of three means four Segments in the contiguous series). 63cabdff1aSopenharmony_ci * */ 64cabdff1aSopenharmony_ci int64_t repeat; 65cabdff1aSopenharmony_ci /* duration: Element or Attribute Name 66cabdff1aSopenharmony_ci * specifies the Segment duration, in units of the value of the @timescale. 67cabdff1aSopenharmony_ci * */ 68cabdff1aSopenharmony_ci int64_t duration; 69cabdff1aSopenharmony_ci}; 70cabdff1aSopenharmony_ci 71cabdff1aSopenharmony_ci/* 72cabdff1aSopenharmony_ci * Each playlist has its own demuxer. If it is currently active, 73cabdff1aSopenharmony_ci * it has an opened AVIOContext too, and potentially an AVPacket 74cabdff1aSopenharmony_ci * containing the next packet from this stream. 75cabdff1aSopenharmony_ci */ 76cabdff1aSopenharmony_cistruct representation { 77cabdff1aSopenharmony_ci char *url_template; 78cabdff1aSopenharmony_ci FFIOContext pb; 79cabdff1aSopenharmony_ci AVIOContext *input; 80cabdff1aSopenharmony_ci AVFormatContext *parent; 81cabdff1aSopenharmony_ci AVFormatContext *ctx; 82cabdff1aSopenharmony_ci int stream_index; 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci char *id; 85cabdff1aSopenharmony_ci char *lang; 86cabdff1aSopenharmony_ci int bandwidth; 87cabdff1aSopenharmony_ci AVRational framerate; 88cabdff1aSopenharmony_ci AVStream *assoc_stream; /* demuxer stream associated with this representation */ 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_ci int n_fragments; 91cabdff1aSopenharmony_ci struct fragment **fragments; /* VOD list of fragment for profile */ 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci int n_timelines; 94cabdff1aSopenharmony_ci struct timeline **timelines; 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci int64_t first_seq_no; 97cabdff1aSopenharmony_ci int64_t last_seq_no; 98cabdff1aSopenharmony_ci int64_t start_number; /* used in case when we have dynamic list of segment to know which segments are new one*/ 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci int64_t fragment_duration; 101cabdff1aSopenharmony_ci int64_t fragment_timescale; 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_ci int64_t presentation_timeoffset; 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci int64_t cur_seq_no; 106cabdff1aSopenharmony_ci int64_t cur_seg_offset; 107cabdff1aSopenharmony_ci int64_t cur_seg_size; 108cabdff1aSopenharmony_ci struct fragment *cur_seg; 109cabdff1aSopenharmony_ci 110cabdff1aSopenharmony_ci /* Currently active Media Initialization Section */ 111cabdff1aSopenharmony_ci struct fragment *init_section; 112cabdff1aSopenharmony_ci uint8_t *init_sec_buf; 113cabdff1aSopenharmony_ci uint32_t init_sec_buf_size; 114cabdff1aSopenharmony_ci uint32_t init_sec_data_len; 115cabdff1aSopenharmony_ci uint32_t init_sec_buf_read_offset; 116cabdff1aSopenharmony_ci int64_t cur_timestamp; 117cabdff1aSopenharmony_ci int is_restart_needed; 118cabdff1aSopenharmony_ci}; 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_citypedef struct DASHContext { 121cabdff1aSopenharmony_ci const AVClass *class; 122cabdff1aSopenharmony_ci char *base_url; 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci int n_videos; 125cabdff1aSopenharmony_ci struct representation **videos; 126cabdff1aSopenharmony_ci int n_audios; 127cabdff1aSopenharmony_ci struct representation **audios; 128cabdff1aSopenharmony_ci int n_subtitles; 129cabdff1aSopenharmony_ci struct representation **subtitles; 130cabdff1aSopenharmony_ci 131cabdff1aSopenharmony_ci /* MediaPresentationDescription Attribute */ 132cabdff1aSopenharmony_ci uint64_t media_presentation_duration; 133cabdff1aSopenharmony_ci uint64_t suggested_presentation_delay; 134cabdff1aSopenharmony_ci uint64_t availability_start_time; 135cabdff1aSopenharmony_ci uint64_t availability_end_time; 136cabdff1aSopenharmony_ci uint64_t publish_time; 137cabdff1aSopenharmony_ci uint64_t minimum_update_period; 138cabdff1aSopenharmony_ci uint64_t time_shift_buffer_depth; 139cabdff1aSopenharmony_ci uint64_t min_buffer_time; 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_ci /* Period Attribute */ 142cabdff1aSopenharmony_ci uint64_t period_duration; 143cabdff1aSopenharmony_ci uint64_t period_start; 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci /* AdaptationSet Attribute */ 146cabdff1aSopenharmony_ci char *adaptionset_lang; 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci int is_live; 149cabdff1aSopenharmony_ci AVIOInterruptCB *interrupt_callback; 150cabdff1aSopenharmony_ci char *allowed_extensions; 151cabdff1aSopenharmony_ci AVDictionary *avio_opts; 152cabdff1aSopenharmony_ci int max_url_size; 153cabdff1aSopenharmony_ci char *cenc_decryption_key; 154cabdff1aSopenharmony_ci 155cabdff1aSopenharmony_ci /* Flags for init section*/ 156cabdff1aSopenharmony_ci int is_init_section_common_video; 157cabdff1aSopenharmony_ci int is_init_section_common_audio; 158cabdff1aSopenharmony_ci int is_init_section_common_subtitle; 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci} DASHContext; 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_cistatic int ishttp(char *url) 163cabdff1aSopenharmony_ci{ 164cabdff1aSopenharmony_ci const char *proto_name = avio_find_protocol_name(url); 165cabdff1aSopenharmony_ci return proto_name && av_strstart(proto_name, "http", NULL); 166cabdff1aSopenharmony_ci} 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_cistatic int aligned(int val) 169cabdff1aSopenharmony_ci{ 170cabdff1aSopenharmony_ci return ((val + 0x3F) >> 6) << 6; 171cabdff1aSopenharmony_ci} 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_cistatic uint64_t get_current_time_in_sec(void) 174cabdff1aSopenharmony_ci{ 175cabdff1aSopenharmony_ci return av_gettime() / 1000000; 176cabdff1aSopenharmony_ci} 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_cistatic uint64_t get_utc_date_time_insec(AVFormatContext *s, const char *datetime) 179cabdff1aSopenharmony_ci{ 180cabdff1aSopenharmony_ci struct tm timeinfo; 181cabdff1aSopenharmony_ci int year = 0; 182cabdff1aSopenharmony_ci int month = 0; 183cabdff1aSopenharmony_ci int day = 0; 184cabdff1aSopenharmony_ci int hour = 0; 185cabdff1aSopenharmony_ci int minute = 0; 186cabdff1aSopenharmony_ci int ret = 0; 187cabdff1aSopenharmony_ci float second = 0.0; 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci /* ISO-8601 date parser */ 190cabdff1aSopenharmony_ci if (!datetime) 191cabdff1aSopenharmony_ci return 0; 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci ret = sscanf(datetime, "%d-%d-%dT%d:%d:%fZ", &year, &month, &day, &hour, &minute, &second); 194cabdff1aSopenharmony_ci /* year, month, day, hour, minute, second 6 arguments */ 195cabdff1aSopenharmony_ci if (ret != 6) { 196cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "get_utc_date_time_insec get a wrong time format\n"); 197cabdff1aSopenharmony_ci } 198cabdff1aSopenharmony_ci timeinfo.tm_year = year - 1900; 199cabdff1aSopenharmony_ci timeinfo.tm_mon = month - 1; 200cabdff1aSopenharmony_ci timeinfo.tm_mday = day; 201cabdff1aSopenharmony_ci timeinfo.tm_hour = hour; 202cabdff1aSopenharmony_ci timeinfo.tm_min = minute; 203cabdff1aSopenharmony_ci timeinfo.tm_sec = (int)second; 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci return av_timegm(&timeinfo); 206cabdff1aSopenharmony_ci} 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_cistatic uint32_t get_duration_insec(AVFormatContext *s, const char *duration) 209cabdff1aSopenharmony_ci{ 210cabdff1aSopenharmony_ci /* ISO-8601 duration parser */ 211cabdff1aSopenharmony_ci uint32_t days = 0; 212cabdff1aSopenharmony_ci uint32_t hours = 0; 213cabdff1aSopenharmony_ci uint32_t mins = 0; 214cabdff1aSopenharmony_ci uint32_t secs = 0; 215cabdff1aSopenharmony_ci int size = 0; 216cabdff1aSopenharmony_ci float value = 0; 217cabdff1aSopenharmony_ci char type = '\0'; 218cabdff1aSopenharmony_ci const char *ptr = duration; 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci while (*ptr) { 221cabdff1aSopenharmony_ci if (*ptr == 'P' || *ptr == 'T') { 222cabdff1aSopenharmony_ci ptr++; 223cabdff1aSopenharmony_ci continue; 224cabdff1aSopenharmony_ci } 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci if (sscanf(ptr, "%f%c%n", &value, &type, &size) != 2) { 227cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "get_duration_insec get a wrong time format\n"); 228cabdff1aSopenharmony_ci return 0; /* parser error */ 229cabdff1aSopenharmony_ci } 230cabdff1aSopenharmony_ci switch (type) { 231cabdff1aSopenharmony_ci case 'D': 232cabdff1aSopenharmony_ci days = (uint32_t)value; 233cabdff1aSopenharmony_ci break; 234cabdff1aSopenharmony_ci case 'H': 235cabdff1aSopenharmony_ci hours = (uint32_t)value; 236cabdff1aSopenharmony_ci break; 237cabdff1aSopenharmony_ci case 'M': 238cabdff1aSopenharmony_ci mins = (uint32_t)value; 239cabdff1aSopenharmony_ci break; 240cabdff1aSopenharmony_ci case 'S': 241cabdff1aSopenharmony_ci secs = (uint32_t)value; 242cabdff1aSopenharmony_ci break; 243cabdff1aSopenharmony_ci default: 244cabdff1aSopenharmony_ci // handle invalid type 245cabdff1aSopenharmony_ci break; 246cabdff1aSopenharmony_ci } 247cabdff1aSopenharmony_ci ptr += size; 248cabdff1aSopenharmony_ci } 249cabdff1aSopenharmony_ci return ((days * 24 + hours) * 60 + mins) * 60 + secs; 250cabdff1aSopenharmony_ci} 251cabdff1aSopenharmony_ci 252cabdff1aSopenharmony_cistatic int64_t get_segment_start_time_based_on_timeline(struct representation *pls, int64_t cur_seq_no) 253cabdff1aSopenharmony_ci{ 254cabdff1aSopenharmony_ci int64_t start_time = 0; 255cabdff1aSopenharmony_ci int64_t i = 0; 256cabdff1aSopenharmony_ci int64_t j = 0; 257cabdff1aSopenharmony_ci int64_t num = 0; 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_ci if (pls->n_timelines) { 260cabdff1aSopenharmony_ci for (i = 0; i < pls->n_timelines; i++) { 261cabdff1aSopenharmony_ci if (pls->timelines[i]->starttime > 0) { 262cabdff1aSopenharmony_ci start_time = pls->timelines[i]->starttime; 263cabdff1aSopenharmony_ci } 264cabdff1aSopenharmony_ci if (num == cur_seq_no) 265cabdff1aSopenharmony_ci goto finish; 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci start_time += pls->timelines[i]->duration; 268cabdff1aSopenharmony_ci 269cabdff1aSopenharmony_ci if (pls->timelines[i]->repeat == -1) { 270cabdff1aSopenharmony_ci start_time = pls->timelines[i]->duration * cur_seq_no; 271cabdff1aSopenharmony_ci goto finish; 272cabdff1aSopenharmony_ci } 273cabdff1aSopenharmony_ci 274cabdff1aSopenharmony_ci for (j = 0; j < pls->timelines[i]->repeat; j++) { 275cabdff1aSopenharmony_ci num++; 276cabdff1aSopenharmony_ci if (num == cur_seq_no) 277cabdff1aSopenharmony_ci goto finish; 278cabdff1aSopenharmony_ci start_time += pls->timelines[i]->duration; 279cabdff1aSopenharmony_ci } 280cabdff1aSopenharmony_ci num++; 281cabdff1aSopenharmony_ci } 282cabdff1aSopenharmony_ci } 283cabdff1aSopenharmony_cifinish: 284cabdff1aSopenharmony_ci return start_time; 285cabdff1aSopenharmony_ci} 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_cistatic int64_t calc_next_seg_no_from_timelines(struct representation *pls, int64_t cur_time) 288cabdff1aSopenharmony_ci{ 289cabdff1aSopenharmony_ci int64_t i = 0; 290cabdff1aSopenharmony_ci int64_t j = 0; 291cabdff1aSopenharmony_ci int64_t num = 0; 292cabdff1aSopenharmony_ci int64_t start_time = 0; 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci for (i = 0; i < pls->n_timelines; i++) { 295cabdff1aSopenharmony_ci if (pls->timelines[i]->starttime > 0) { 296cabdff1aSopenharmony_ci start_time = pls->timelines[i]->starttime; 297cabdff1aSopenharmony_ci } 298cabdff1aSopenharmony_ci if (start_time > cur_time) 299cabdff1aSopenharmony_ci goto finish; 300cabdff1aSopenharmony_ci 301cabdff1aSopenharmony_ci start_time += pls->timelines[i]->duration; 302cabdff1aSopenharmony_ci for (j = 0; j < pls->timelines[i]->repeat; j++) { 303cabdff1aSopenharmony_ci num++; 304cabdff1aSopenharmony_ci if (start_time > cur_time) 305cabdff1aSopenharmony_ci goto finish; 306cabdff1aSopenharmony_ci start_time += pls->timelines[i]->duration; 307cabdff1aSopenharmony_ci } 308cabdff1aSopenharmony_ci num++; 309cabdff1aSopenharmony_ci } 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ci return -1; 312cabdff1aSopenharmony_ci 313cabdff1aSopenharmony_cifinish: 314cabdff1aSopenharmony_ci return num; 315cabdff1aSopenharmony_ci} 316cabdff1aSopenharmony_ci 317cabdff1aSopenharmony_cistatic void free_fragment(struct fragment **seg) 318cabdff1aSopenharmony_ci{ 319cabdff1aSopenharmony_ci if (!(*seg)) { 320cabdff1aSopenharmony_ci return; 321cabdff1aSopenharmony_ci } 322cabdff1aSopenharmony_ci av_freep(&(*seg)->url); 323cabdff1aSopenharmony_ci av_freep(seg); 324cabdff1aSopenharmony_ci} 325cabdff1aSopenharmony_ci 326cabdff1aSopenharmony_cistatic void free_fragment_list(struct representation *pls) 327cabdff1aSopenharmony_ci{ 328cabdff1aSopenharmony_ci int i; 329cabdff1aSopenharmony_ci 330cabdff1aSopenharmony_ci for (i = 0; i < pls->n_fragments; i++) { 331cabdff1aSopenharmony_ci free_fragment(&pls->fragments[i]); 332cabdff1aSopenharmony_ci } 333cabdff1aSopenharmony_ci av_freep(&pls->fragments); 334cabdff1aSopenharmony_ci pls->n_fragments = 0; 335cabdff1aSopenharmony_ci} 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_cistatic void free_timelines_list(struct representation *pls) 338cabdff1aSopenharmony_ci{ 339cabdff1aSopenharmony_ci int i; 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ci for (i = 0; i < pls->n_timelines; i++) { 342cabdff1aSopenharmony_ci av_freep(&pls->timelines[i]); 343cabdff1aSopenharmony_ci } 344cabdff1aSopenharmony_ci av_freep(&pls->timelines); 345cabdff1aSopenharmony_ci pls->n_timelines = 0; 346cabdff1aSopenharmony_ci} 347cabdff1aSopenharmony_ci 348cabdff1aSopenharmony_cistatic void free_representation(struct representation *pls) 349cabdff1aSopenharmony_ci{ 350cabdff1aSopenharmony_ci free_fragment_list(pls); 351cabdff1aSopenharmony_ci free_timelines_list(pls); 352cabdff1aSopenharmony_ci free_fragment(&pls->cur_seg); 353cabdff1aSopenharmony_ci free_fragment(&pls->init_section); 354cabdff1aSopenharmony_ci av_freep(&pls->init_sec_buf); 355cabdff1aSopenharmony_ci av_freep(&pls->pb.pub.buffer); 356cabdff1aSopenharmony_ci ff_format_io_close(pls->parent, &pls->input); 357cabdff1aSopenharmony_ci if (pls->ctx) { 358cabdff1aSopenharmony_ci pls->ctx->pb = NULL; 359cabdff1aSopenharmony_ci avformat_close_input(&pls->ctx); 360cabdff1aSopenharmony_ci } 361cabdff1aSopenharmony_ci 362cabdff1aSopenharmony_ci av_freep(&pls->url_template); 363cabdff1aSopenharmony_ci av_freep(&pls->lang); 364cabdff1aSopenharmony_ci av_freep(&pls->id); 365cabdff1aSopenharmony_ci av_freep(&pls); 366cabdff1aSopenharmony_ci} 367cabdff1aSopenharmony_ci 368cabdff1aSopenharmony_cistatic void free_video_list(DASHContext *c) 369cabdff1aSopenharmony_ci{ 370cabdff1aSopenharmony_ci int i; 371cabdff1aSopenharmony_ci for (i = 0; i < c->n_videos; i++) { 372cabdff1aSopenharmony_ci struct representation *pls = c->videos[i]; 373cabdff1aSopenharmony_ci free_representation(pls); 374cabdff1aSopenharmony_ci } 375cabdff1aSopenharmony_ci av_freep(&c->videos); 376cabdff1aSopenharmony_ci c->n_videos = 0; 377cabdff1aSopenharmony_ci} 378cabdff1aSopenharmony_ci 379cabdff1aSopenharmony_cistatic void free_audio_list(DASHContext *c) 380cabdff1aSopenharmony_ci{ 381cabdff1aSopenharmony_ci int i; 382cabdff1aSopenharmony_ci for (i = 0; i < c->n_audios; i++) { 383cabdff1aSopenharmony_ci struct representation *pls = c->audios[i]; 384cabdff1aSopenharmony_ci free_representation(pls); 385cabdff1aSopenharmony_ci } 386cabdff1aSopenharmony_ci av_freep(&c->audios); 387cabdff1aSopenharmony_ci c->n_audios = 0; 388cabdff1aSopenharmony_ci} 389cabdff1aSopenharmony_ci 390cabdff1aSopenharmony_cistatic void free_subtitle_list(DASHContext *c) 391cabdff1aSopenharmony_ci{ 392cabdff1aSopenharmony_ci int i; 393cabdff1aSopenharmony_ci for (i = 0; i < c->n_subtitles; i++) { 394cabdff1aSopenharmony_ci struct representation *pls = c->subtitles[i]; 395cabdff1aSopenharmony_ci free_representation(pls); 396cabdff1aSopenharmony_ci } 397cabdff1aSopenharmony_ci av_freep(&c->subtitles); 398cabdff1aSopenharmony_ci c->n_subtitles = 0; 399cabdff1aSopenharmony_ci} 400cabdff1aSopenharmony_ci 401cabdff1aSopenharmony_cistatic int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, 402cabdff1aSopenharmony_ci AVDictionary **opts, AVDictionary *opts2, int *is_http) 403cabdff1aSopenharmony_ci{ 404cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 405cabdff1aSopenharmony_ci AVDictionary *tmp = NULL; 406cabdff1aSopenharmony_ci const char *proto_name = NULL; 407cabdff1aSopenharmony_ci int proto_name_len; 408cabdff1aSopenharmony_ci int ret; 409cabdff1aSopenharmony_ci 410cabdff1aSopenharmony_ci if (av_strstart(url, "crypto", NULL)) { 411cabdff1aSopenharmony_ci if (url[6] == '+' || url[6] == ':') 412cabdff1aSopenharmony_ci proto_name = avio_find_protocol_name(url + 7); 413cabdff1aSopenharmony_ci } 414cabdff1aSopenharmony_ci 415cabdff1aSopenharmony_ci if (!proto_name) 416cabdff1aSopenharmony_ci proto_name = avio_find_protocol_name(url); 417cabdff1aSopenharmony_ci 418cabdff1aSopenharmony_ci if (!proto_name) 419cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 420cabdff1aSopenharmony_ci 421cabdff1aSopenharmony_ci proto_name_len = strlen(proto_name); 422cabdff1aSopenharmony_ci // only http(s) & file are allowed 423cabdff1aSopenharmony_ci if (av_strstart(proto_name, "file", NULL)) { 424cabdff1aSopenharmony_ci if (strcmp(c->allowed_extensions, "ALL") && !av_match_ext(url, c->allowed_extensions)) { 425cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 426cabdff1aSopenharmony_ci "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n" 427cabdff1aSopenharmony_ci "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n", 428cabdff1aSopenharmony_ci url); 429cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 430cabdff1aSopenharmony_ci } 431cabdff1aSopenharmony_ci } else if (av_strstart(proto_name, "http", NULL)) { 432cabdff1aSopenharmony_ci ; 433cabdff1aSopenharmony_ci } else 434cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 435cabdff1aSopenharmony_ci 436cabdff1aSopenharmony_ci if (!strncmp(proto_name, url, proto_name_len) && url[proto_name_len] == ':') 437cabdff1aSopenharmony_ci ; 438cabdff1aSopenharmony_ci else if (av_strstart(url, "crypto", NULL) && !strncmp(proto_name, url + 7, proto_name_len) && url[7 + proto_name_len] == ':') 439cabdff1aSopenharmony_ci ; 440cabdff1aSopenharmony_ci else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5)) 441cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 442cabdff1aSopenharmony_ci 443cabdff1aSopenharmony_ci av_freep(pb); 444cabdff1aSopenharmony_ci av_dict_copy(&tmp, *opts, 0); 445cabdff1aSopenharmony_ci av_dict_copy(&tmp, opts2, 0); 446cabdff1aSopenharmony_ci ret = avio_open2(pb, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); 447cabdff1aSopenharmony_ci if (ret >= 0) { 448cabdff1aSopenharmony_ci // update cookies on http response with setcookies. 449cabdff1aSopenharmony_ci char *new_cookies = NULL; 450cabdff1aSopenharmony_ci 451cabdff1aSopenharmony_ci if (!(s->flags & AVFMT_FLAG_CUSTOM_IO)) 452cabdff1aSopenharmony_ci av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies); 453cabdff1aSopenharmony_ci 454cabdff1aSopenharmony_ci if (new_cookies) { 455cabdff1aSopenharmony_ci av_dict_set(opts, "cookies", new_cookies, AV_DICT_DONT_STRDUP_VAL); 456cabdff1aSopenharmony_ci } 457cabdff1aSopenharmony_ci 458cabdff1aSopenharmony_ci } 459cabdff1aSopenharmony_ci 460cabdff1aSopenharmony_ci av_dict_free(&tmp); 461cabdff1aSopenharmony_ci 462cabdff1aSopenharmony_ci if (is_http) 463cabdff1aSopenharmony_ci *is_http = av_strstart(proto_name, "http", NULL); 464cabdff1aSopenharmony_ci 465cabdff1aSopenharmony_ci return ret; 466cabdff1aSopenharmony_ci} 467cabdff1aSopenharmony_ci 468cabdff1aSopenharmony_cistatic char *get_content_url(xmlNodePtr *baseurl_nodes, 469cabdff1aSopenharmony_ci int n_baseurl_nodes, 470cabdff1aSopenharmony_ci int max_url_size, 471cabdff1aSopenharmony_ci char *rep_id_val, 472cabdff1aSopenharmony_ci char *rep_bandwidth_val, 473cabdff1aSopenharmony_ci char *val) 474cabdff1aSopenharmony_ci{ 475cabdff1aSopenharmony_ci int i; 476cabdff1aSopenharmony_ci char *text; 477cabdff1aSopenharmony_ci char *url = NULL; 478cabdff1aSopenharmony_ci char *tmp_str = av_mallocz(max_url_size); 479cabdff1aSopenharmony_ci 480cabdff1aSopenharmony_ci if (!tmp_str) 481cabdff1aSopenharmony_ci return NULL; 482cabdff1aSopenharmony_ci 483cabdff1aSopenharmony_ci for (i = 0; i < n_baseurl_nodes; ++i) { 484cabdff1aSopenharmony_ci if (baseurl_nodes[i] && 485cabdff1aSopenharmony_ci baseurl_nodes[i]->children && 486cabdff1aSopenharmony_ci baseurl_nodes[i]->children->type == XML_TEXT_NODE) { 487cabdff1aSopenharmony_ci text = xmlNodeGetContent(baseurl_nodes[i]->children); 488cabdff1aSopenharmony_ci if (text) { 489cabdff1aSopenharmony_ci memset(tmp_str, 0, max_url_size); 490cabdff1aSopenharmony_ci ff_make_absolute_url(tmp_str, max_url_size, "", text); 491cabdff1aSopenharmony_ci xmlFree(text); 492cabdff1aSopenharmony_ci } 493cabdff1aSopenharmony_ci } 494cabdff1aSopenharmony_ci } 495cabdff1aSopenharmony_ci 496cabdff1aSopenharmony_ci if (val) 497cabdff1aSopenharmony_ci ff_make_absolute_url(tmp_str, max_url_size, tmp_str, val); 498cabdff1aSopenharmony_ci 499cabdff1aSopenharmony_ci if (rep_id_val) { 500cabdff1aSopenharmony_ci url = av_strireplace(tmp_str, "$RepresentationID$", rep_id_val); 501cabdff1aSopenharmony_ci if (!url) { 502cabdff1aSopenharmony_ci goto end; 503cabdff1aSopenharmony_ci } 504cabdff1aSopenharmony_ci av_strlcpy(tmp_str, url, max_url_size); 505cabdff1aSopenharmony_ci } 506cabdff1aSopenharmony_ci if (rep_bandwidth_val && tmp_str[0] != '\0') { 507cabdff1aSopenharmony_ci // free any previously assigned url before reassigning 508cabdff1aSopenharmony_ci av_free(url); 509cabdff1aSopenharmony_ci url = av_strireplace(tmp_str, "$Bandwidth$", rep_bandwidth_val); 510cabdff1aSopenharmony_ci if (!url) { 511cabdff1aSopenharmony_ci goto end; 512cabdff1aSopenharmony_ci } 513cabdff1aSopenharmony_ci } 514cabdff1aSopenharmony_ciend: 515cabdff1aSopenharmony_ci av_free(tmp_str); 516cabdff1aSopenharmony_ci return url; 517cabdff1aSopenharmony_ci} 518cabdff1aSopenharmony_ci 519cabdff1aSopenharmony_cistatic char *get_val_from_nodes_tab(xmlNodePtr *nodes, const int n_nodes, const char *attrname) 520cabdff1aSopenharmony_ci{ 521cabdff1aSopenharmony_ci int i; 522cabdff1aSopenharmony_ci char *val; 523cabdff1aSopenharmony_ci 524cabdff1aSopenharmony_ci for (i = 0; i < n_nodes; ++i) { 525cabdff1aSopenharmony_ci if (nodes[i]) { 526cabdff1aSopenharmony_ci val = xmlGetProp(nodes[i], attrname); 527cabdff1aSopenharmony_ci if (val) 528cabdff1aSopenharmony_ci return val; 529cabdff1aSopenharmony_ci } 530cabdff1aSopenharmony_ci } 531cabdff1aSopenharmony_ci 532cabdff1aSopenharmony_ci return NULL; 533cabdff1aSopenharmony_ci} 534cabdff1aSopenharmony_ci 535cabdff1aSopenharmony_cistatic xmlNodePtr find_child_node_by_name(xmlNodePtr rootnode, const char *nodename) 536cabdff1aSopenharmony_ci{ 537cabdff1aSopenharmony_ci xmlNodePtr node = rootnode; 538cabdff1aSopenharmony_ci if (!node) { 539cabdff1aSopenharmony_ci return NULL; 540cabdff1aSopenharmony_ci } 541cabdff1aSopenharmony_ci 542cabdff1aSopenharmony_ci node = xmlFirstElementChild(node); 543cabdff1aSopenharmony_ci while (node) { 544cabdff1aSopenharmony_ci if (!av_strcasecmp(node->name, nodename)) { 545cabdff1aSopenharmony_ci return node; 546cabdff1aSopenharmony_ci } 547cabdff1aSopenharmony_ci node = xmlNextElementSibling(node); 548cabdff1aSopenharmony_ci } 549cabdff1aSopenharmony_ci return NULL; 550cabdff1aSopenharmony_ci} 551cabdff1aSopenharmony_ci 552cabdff1aSopenharmony_cistatic enum AVMediaType get_content_type(xmlNodePtr node) 553cabdff1aSopenharmony_ci{ 554cabdff1aSopenharmony_ci enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN; 555cabdff1aSopenharmony_ci int i = 0; 556cabdff1aSopenharmony_ci const char *attr; 557cabdff1aSopenharmony_ci char *val = NULL; 558cabdff1aSopenharmony_ci 559cabdff1aSopenharmony_ci if (node) { 560cabdff1aSopenharmony_ci for (i = 0; i < 2; i++) { 561cabdff1aSopenharmony_ci attr = i ? "mimeType" : "contentType"; 562cabdff1aSopenharmony_ci val = xmlGetProp(node, attr); 563cabdff1aSopenharmony_ci if (val) { 564cabdff1aSopenharmony_ci if (av_stristr(val, "video")) { 565cabdff1aSopenharmony_ci type = AVMEDIA_TYPE_VIDEO; 566cabdff1aSopenharmony_ci } else if (av_stristr(val, "audio")) { 567cabdff1aSopenharmony_ci type = AVMEDIA_TYPE_AUDIO; 568cabdff1aSopenharmony_ci } else if (av_stristr(val, "text")) { 569cabdff1aSopenharmony_ci type = AVMEDIA_TYPE_SUBTITLE; 570cabdff1aSopenharmony_ci } 571cabdff1aSopenharmony_ci xmlFree(val); 572cabdff1aSopenharmony_ci } 573cabdff1aSopenharmony_ci } 574cabdff1aSopenharmony_ci } 575cabdff1aSopenharmony_ci return type; 576cabdff1aSopenharmony_ci} 577cabdff1aSopenharmony_ci 578cabdff1aSopenharmony_cistatic struct fragment * get_Fragment(char *range) 579cabdff1aSopenharmony_ci{ 580cabdff1aSopenharmony_ci struct fragment * seg = av_mallocz(sizeof(struct fragment)); 581cabdff1aSopenharmony_ci 582cabdff1aSopenharmony_ci if (!seg) 583cabdff1aSopenharmony_ci return NULL; 584cabdff1aSopenharmony_ci 585cabdff1aSopenharmony_ci seg->size = -1; 586cabdff1aSopenharmony_ci if (range) { 587cabdff1aSopenharmony_ci char *str_end_offset; 588cabdff1aSopenharmony_ci char *str_offset = av_strtok(range, "-", &str_end_offset); 589cabdff1aSopenharmony_ci seg->url_offset = strtoll(str_offset, NULL, 10); 590cabdff1aSopenharmony_ci seg->size = strtoll(str_end_offset, NULL, 10) - seg->url_offset + 1; 591cabdff1aSopenharmony_ci } 592cabdff1aSopenharmony_ci 593cabdff1aSopenharmony_ci return seg; 594cabdff1aSopenharmony_ci} 595cabdff1aSopenharmony_ci 596cabdff1aSopenharmony_cistatic int parse_manifest_segmenturlnode(AVFormatContext *s, struct representation *rep, 597cabdff1aSopenharmony_ci xmlNodePtr fragmenturl_node, 598cabdff1aSopenharmony_ci xmlNodePtr *baseurl_nodes, 599cabdff1aSopenharmony_ci char *rep_id_val, 600cabdff1aSopenharmony_ci char *rep_bandwidth_val) 601cabdff1aSopenharmony_ci{ 602cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 603cabdff1aSopenharmony_ci char *initialization_val = NULL; 604cabdff1aSopenharmony_ci char *media_val = NULL; 605cabdff1aSopenharmony_ci char *range_val = NULL; 606cabdff1aSopenharmony_ci int max_url_size = c ? c->max_url_size: MAX_URL_SIZE; 607cabdff1aSopenharmony_ci int err; 608cabdff1aSopenharmony_ci 609cabdff1aSopenharmony_ci if (!av_strcasecmp(fragmenturl_node->name, "Initialization")) { 610cabdff1aSopenharmony_ci initialization_val = xmlGetProp(fragmenturl_node, "sourceURL"); 611cabdff1aSopenharmony_ci range_val = xmlGetProp(fragmenturl_node, "range"); 612cabdff1aSopenharmony_ci if (initialization_val || range_val) { 613cabdff1aSopenharmony_ci free_fragment(&rep->init_section); 614cabdff1aSopenharmony_ci rep->init_section = get_Fragment(range_val); 615cabdff1aSopenharmony_ci xmlFree(range_val); 616cabdff1aSopenharmony_ci if (!rep->init_section) { 617cabdff1aSopenharmony_ci xmlFree(initialization_val); 618cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 619cabdff1aSopenharmony_ci } 620cabdff1aSopenharmony_ci rep->init_section->url = get_content_url(baseurl_nodes, 4, 621cabdff1aSopenharmony_ci max_url_size, 622cabdff1aSopenharmony_ci rep_id_val, 623cabdff1aSopenharmony_ci rep_bandwidth_val, 624cabdff1aSopenharmony_ci initialization_val); 625cabdff1aSopenharmony_ci xmlFree(initialization_val); 626cabdff1aSopenharmony_ci if (!rep->init_section->url) { 627cabdff1aSopenharmony_ci av_freep(&rep->init_section); 628cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 629cabdff1aSopenharmony_ci } 630cabdff1aSopenharmony_ci } 631cabdff1aSopenharmony_ci } else if (!av_strcasecmp(fragmenturl_node->name, "SegmentURL")) { 632cabdff1aSopenharmony_ci media_val = xmlGetProp(fragmenturl_node, "media"); 633cabdff1aSopenharmony_ci range_val = xmlGetProp(fragmenturl_node, "mediaRange"); 634cabdff1aSopenharmony_ci if (media_val || range_val) { 635cabdff1aSopenharmony_ci struct fragment *seg = get_Fragment(range_val); 636cabdff1aSopenharmony_ci xmlFree(range_val); 637cabdff1aSopenharmony_ci if (!seg) { 638cabdff1aSopenharmony_ci xmlFree(media_val); 639cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 640cabdff1aSopenharmony_ci } 641cabdff1aSopenharmony_ci seg->url = get_content_url(baseurl_nodes, 4, 642cabdff1aSopenharmony_ci max_url_size, 643cabdff1aSopenharmony_ci rep_id_val, 644cabdff1aSopenharmony_ci rep_bandwidth_val, 645cabdff1aSopenharmony_ci media_val); 646cabdff1aSopenharmony_ci xmlFree(media_val); 647cabdff1aSopenharmony_ci if (!seg->url) { 648cabdff1aSopenharmony_ci av_free(seg); 649cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 650cabdff1aSopenharmony_ci } 651cabdff1aSopenharmony_ci err = av_dynarray_add_nofree(&rep->fragments, &rep->n_fragments, seg); 652cabdff1aSopenharmony_ci if (err < 0) { 653cabdff1aSopenharmony_ci free_fragment(&seg); 654cabdff1aSopenharmony_ci return err; 655cabdff1aSopenharmony_ci } 656cabdff1aSopenharmony_ci } 657cabdff1aSopenharmony_ci } 658cabdff1aSopenharmony_ci 659cabdff1aSopenharmony_ci return 0; 660cabdff1aSopenharmony_ci} 661cabdff1aSopenharmony_ci 662cabdff1aSopenharmony_cistatic int parse_manifest_segmenttimeline(AVFormatContext *s, struct representation *rep, 663cabdff1aSopenharmony_ci xmlNodePtr fragment_timeline_node) 664cabdff1aSopenharmony_ci{ 665cabdff1aSopenharmony_ci xmlAttrPtr attr = NULL; 666cabdff1aSopenharmony_ci char *val = NULL; 667cabdff1aSopenharmony_ci int err; 668cabdff1aSopenharmony_ci 669cabdff1aSopenharmony_ci if (!av_strcasecmp(fragment_timeline_node->name, "S")) { 670cabdff1aSopenharmony_ci struct timeline *tml = av_mallocz(sizeof(struct timeline)); 671cabdff1aSopenharmony_ci if (!tml) { 672cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 673cabdff1aSopenharmony_ci } 674cabdff1aSopenharmony_ci attr = fragment_timeline_node->properties; 675cabdff1aSopenharmony_ci while (attr) { 676cabdff1aSopenharmony_ci val = xmlGetProp(fragment_timeline_node, attr->name); 677cabdff1aSopenharmony_ci 678cabdff1aSopenharmony_ci if (!val) { 679cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "parse_manifest_segmenttimeline attr->name = %s val is NULL\n", attr->name); 680cabdff1aSopenharmony_ci continue; 681cabdff1aSopenharmony_ci } 682cabdff1aSopenharmony_ci 683cabdff1aSopenharmony_ci if (!av_strcasecmp(attr->name, "t")) { 684cabdff1aSopenharmony_ci tml->starttime = (int64_t)strtoll(val, NULL, 10); 685cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "r")) { 686cabdff1aSopenharmony_ci tml->repeat =(int64_t) strtoll(val, NULL, 10); 687cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "d")) { 688cabdff1aSopenharmony_ci tml->duration = (int64_t)strtoll(val, NULL, 10); 689cabdff1aSopenharmony_ci } 690cabdff1aSopenharmony_ci attr = attr->next; 691cabdff1aSopenharmony_ci xmlFree(val); 692cabdff1aSopenharmony_ci } 693cabdff1aSopenharmony_ci err = av_dynarray_add_nofree(&rep->timelines, &rep->n_timelines, tml); 694cabdff1aSopenharmony_ci if (err < 0) { 695cabdff1aSopenharmony_ci av_free(tml); 696cabdff1aSopenharmony_ci return err; 697cabdff1aSopenharmony_ci } 698cabdff1aSopenharmony_ci } 699cabdff1aSopenharmony_ci 700cabdff1aSopenharmony_ci return 0; 701cabdff1aSopenharmony_ci} 702cabdff1aSopenharmony_ci 703cabdff1aSopenharmony_cistatic int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes) 704cabdff1aSopenharmony_ci{ 705cabdff1aSopenharmony_ci char *tmp_str = NULL; 706cabdff1aSopenharmony_ci char *path = NULL; 707cabdff1aSopenharmony_ci char *mpdName = NULL; 708cabdff1aSopenharmony_ci xmlNodePtr node = NULL; 709cabdff1aSopenharmony_ci char *baseurl = NULL; 710cabdff1aSopenharmony_ci char *root_url = NULL; 711cabdff1aSopenharmony_ci char *text = NULL; 712cabdff1aSopenharmony_ci char *tmp = NULL; 713cabdff1aSopenharmony_ci int isRootHttp = 0; 714cabdff1aSopenharmony_ci char token ='/'; 715cabdff1aSopenharmony_ci int start = 0; 716cabdff1aSopenharmony_ci int rootId = 0; 717cabdff1aSopenharmony_ci int updated = 0; 718cabdff1aSopenharmony_ci int size = 0; 719cabdff1aSopenharmony_ci int i; 720cabdff1aSopenharmony_ci int tmp_max_url_size = strlen(url); 721cabdff1aSopenharmony_ci 722cabdff1aSopenharmony_ci for (i = n_baseurl_nodes-1; i >= 0 ; i--) { 723cabdff1aSopenharmony_ci text = xmlNodeGetContent(baseurl_nodes[i]); 724cabdff1aSopenharmony_ci if (!text) 725cabdff1aSopenharmony_ci continue; 726cabdff1aSopenharmony_ci tmp_max_url_size += strlen(text); 727cabdff1aSopenharmony_ci if (ishttp(text)) { 728cabdff1aSopenharmony_ci xmlFree(text); 729cabdff1aSopenharmony_ci break; 730cabdff1aSopenharmony_ci } 731cabdff1aSopenharmony_ci xmlFree(text); 732cabdff1aSopenharmony_ci } 733cabdff1aSopenharmony_ci 734cabdff1aSopenharmony_ci tmp_max_url_size = aligned(tmp_max_url_size); 735cabdff1aSopenharmony_ci text = av_mallocz(tmp_max_url_size); 736cabdff1aSopenharmony_ci if (!text) { 737cabdff1aSopenharmony_ci updated = AVERROR(ENOMEM); 738cabdff1aSopenharmony_ci goto end; 739cabdff1aSopenharmony_ci } 740cabdff1aSopenharmony_ci av_strlcpy(text, url, strlen(url)+1); 741cabdff1aSopenharmony_ci tmp = text; 742cabdff1aSopenharmony_ci while (mpdName = av_strtok(tmp, "/", &tmp)) { 743cabdff1aSopenharmony_ci size = strlen(mpdName); 744cabdff1aSopenharmony_ci } 745cabdff1aSopenharmony_ci av_free(text); 746cabdff1aSopenharmony_ci 747cabdff1aSopenharmony_ci path = av_mallocz(tmp_max_url_size); 748cabdff1aSopenharmony_ci tmp_str = av_mallocz(tmp_max_url_size); 749cabdff1aSopenharmony_ci if (!tmp_str || !path) { 750cabdff1aSopenharmony_ci updated = AVERROR(ENOMEM); 751cabdff1aSopenharmony_ci goto end; 752cabdff1aSopenharmony_ci } 753cabdff1aSopenharmony_ci 754cabdff1aSopenharmony_ci av_strlcpy (path, url, strlen(url) - size + 1); 755cabdff1aSopenharmony_ci for (rootId = n_baseurl_nodes - 1; rootId > 0; rootId --) { 756cabdff1aSopenharmony_ci if (!(node = baseurl_nodes[rootId])) { 757cabdff1aSopenharmony_ci continue; 758cabdff1aSopenharmony_ci } 759cabdff1aSopenharmony_ci text = xmlNodeGetContent(node); 760cabdff1aSopenharmony_ci if (ishttp(text)) { 761cabdff1aSopenharmony_ci xmlFree(text); 762cabdff1aSopenharmony_ci break; 763cabdff1aSopenharmony_ci } 764cabdff1aSopenharmony_ci xmlFree(text); 765cabdff1aSopenharmony_ci } 766cabdff1aSopenharmony_ci 767cabdff1aSopenharmony_ci node = baseurl_nodes[rootId]; 768cabdff1aSopenharmony_ci baseurl = xmlNodeGetContent(node); 769cabdff1aSopenharmony_ci root_url = (av_strcasecmp(baseurl, "")) ? baseurl : path; 770cabdff1aSopenharmony_ci if (node) { 771cabdff1aSopenharmony_ci xmlNodeSetContent(node, root_url); 772cabdff1aSopenharmony_ci updated = 1; 773cabdff1aSopenharmony_ci } 774cabdff1aSopenharmony_ci 775cabdff1aSopenharmony_ci size = strlen(root_url); 776cabdff1aSopenharmony_ci isRootHttp = ishttp(root_url); 777cabdff1aSopenharmony_ci 778cabdff1aSopenharmony_ci if (size > 0 && root_url[size - 1] != token) { 779cabdff1aSopenharmony_ci av_strlcat(root_url, "/", size + 2); 780cabdff1aSopenharmony_ci size += 2; 781cabdff1aSopenharmony_ci } 782cabdff1aSopenharmony_ci 783cabdff1aSopenharmony_ci for (i = 0; i < n_baseurl_nodes; ++i) { 784cabdff1aSopenharmony_ci if (i == rootId) { 785cabdff1aSopenharmony_ci continue; 786cabdff1aSopenharmony_ci } 787cabdff1aSopenharmony_ci text = xmlNodeGetContent(baseurl_nodes[i]); 788cabdff1aSopenharmony_ci if (text && !av_strstart(text, "/", NULL)) { 789cabdff1aSopenharmony_ci memset(tmp_str, 0, strlen(tmp_str)); 790cabdff1aSopenharmony_ci if (!ishttp(text) && isRootHttp) { 791cabdff1aSopenharmony_ci av_strlcpy(tmp_str, root_url, size + 1); 792cabdff1aSopenharmony_ci } 793cabdff1aSopenharmony_ci start = (text[0] == token); 794cabdff1aSopenharmony_ci if (start && av_stristr(tmp_str, text)) { 795cabdff1aSopenharmony_ci char *p = tmp_str; 796cabdff1aSopenharmony_ci if (!av_strncasecmp(tmp_str, "http://", 7)) { 797cabdff1aSopenharmony_ci p += 7; 798cabdff1aSopenharmony_ci } else if (!av_strncasecmp(tmp_str, "https://", 8)) { 799cabdff1aSopenharmony_ci p += 8; 800cabdff1aSopenharmony_ci } 801cabdff1aSopenharmony_ci p = strchr(p, '/'); 802cabdff1aSopenharmony_ci memset(p + 1, 0, strlen(p)); 803cabdff1aSopenharmony_ci } 804cabdff1aSopenharmony_ci av_strlcat(tmp_str, text + start, tmp_max_url_size); 805cabdff1aSopenharmony_ci xmlNodeSetContent(baseurl_nodes[i], tmp_str); 806cabdff1aSopenharmony_ci updated = 1; 807cabdff1aSopenharmony_ci xmlFree(text); 808cabdff1aSopenharmony_ci } 809cabdff1aSopenharmony_ci } 810cabdff1aSopenharmony_ci 811cabdff1aSopenharmony_ciend: 812cabdff1aSopenharmony_ci if (tmp_max_url_size > *max_url_size) { 813cabdff1aSopenharmony_ci *max_url_size = tmp_max_url_size; 814cabdff1aSopenharmony_ci } 815cabdff1aSopenharmony_ci av_free(path); 816cabdff1aSopenharmony_ci av_free(tmp_str); 817cabdff1aSopenharmony_ci xmlFree(baseurl); 818cabdff1aSopenharmony_ci return updated; 819cabdff1aSopenharmony_ci 820cabdff1aSopenharmony_ci} 821cabdff1aSopenharmony_ci 822cabdff1aSopenharmony_cistatic int parse_manifest_representation(AVFormatContext *s, const char *url, 823cabdff1aSopenharmony_ci xmlNodePtr node, 824cabdff1aSopenharmony_ci xmlNodePtr adaptionset_node, 825cabdff1aSopenharmony_ci xmlNodePtr mpd_baseurl_node, 826cabdff1aSopenharmony_ci xmlNodePtr period_baseurl_node, 827cabdff1aSopenharmony_ci xmlNodePtr period_segmenttemplate_node, 828cabdff1aSopenharmony_ci xmlNodePtr period_segmentlist_node, 829cabdff1aSopenharmony_ci xmlNodePtr fragment_template_node, 830cabdff1aSopenharmony_ci xmlNodePtr content_component_node, 831cabdff1aSopenharmony_ci xmlNodePtr adaptionset_baseurl_node, 832cabdff1aSopenharmony_ci xmlNodePtr adaptionset_segmentlist_node, 833cabdff1aSopenharmony_ci xmlNodePtr adaptionset_supplementalproperty_node) 834cabdff1aSopenharmony_ci{ 835cabdff1aSopenharmony_ci int32_t ret = 0; 836cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 837cabdff1aSopenharmony_ci struct representation *rep = NULL; 838cabdff1aSopenharmony_ci struct fragment *seg = NULL; 839cabdff1aSopenharmony_ci xmlNodePtr representation_segmenttemplate_node = NULL; 840cabdff1aSopenharmony_ci xmlNodePtr representation_baseurl_node = NULL; 841cabdff1aSopenharmony_ci xmlNodePtr representation_segmentlist_node = NULL; 842cabdff1aSopenharmony_ci xmlNodePtr segmentlists_tab[3]; 843cabdff1aSopenharmony_ci xmlNodePtr fragment_timeline_node = NULL; 844cabdff1aSopenharmony_ci xmlNodePtr fragment_templates_tab[5]; 845cabdff1aSopenharmony_ci char *val = NULL; 846cabdff1aSopenharmony_ci xmlNodePtr baseurl_nodes[4]; 847cabdff1aSopenharmony_ci xmlNodePtr representation_node = node; 848cabdff1aSopenharmony_ci char *rep_bandwidth_val; 849cabdff1aSopenharmony_ci enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN; 850cabdff1aSopenharmony_ci 851cabdff1aSopenharmony_ci // try get information from representation 852cabdff1aSopenharmony_ci if (type == AVMEDIA_TYPE_UNKNOWN) 853cabdff1aSopenharmony_ci type = get_content_type(representation_node); 854cabdff1aSopenharmony_ci // try get information from contentComponen 855cabdff1aSopenharmony_ci if (type == AVMEDIA_TYPE_UNKNOWN) 856cabdff1aSopenharmony_ci type = get_content_type(content_component_node); 857cabdff1aSopenharmony_ci // try get information from adaption set 858cabdff1aSopenharmony_ci if (type == AVMEDIA_TYPE_UNKNOWN) 859cabdff1aSopenharmony_ci type = get_content_type(adaptionset_node); 860cabdff1aSopenharmony_ci if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO && 861cabdff1aSopenharmony_ci type != AVMEDIA_TYPE_SUBTITLE) { 862cabdff1aSopenharmony_ci av_log(s, AV_LOG_VERBOSE, "Parsing '%s' - skipp not supported representation type\n", url); 863cabdff1aSopenharmony_ci return 0; 864cabdff1aSopenharmony_ci } 865cabdff1aSopenharmony_ci 866cabdff1aSopenharmony_ci // convert selected representation to our internal struct 867cabdff1aSopenharmony_ci rep = av_mallocz(sizeof(struct representation)); 868cabdff1aSopenharmony_ci if (!rep) 869cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 870cabdff1aSopenharmony_ci if (c->adaptionset_lang) { 871cabdff1aSopenharmony_ci rep->lang = av_strdup(c->adaptionset_lang); 872cabdff1aSopenharmony_ci if (!rep->lang) { 873cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "alloc language memory failure\n"); 874cabdff1aSopenharmony_ci av_freep(&rep); 875cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 876cabdff1aSopenharmony_ci } 877cabdff1aSopenharmony_ci } 878cabdff1aSopenharmony_ci rep->parent = s; 879cabdff1aSopenharmony_ci representation_segmenttemplate_node = find_child_node_by_name(representation_node, "SegmentTemplate"); 880cabdff1aSopenharmony_ci representation_baseurl_node = find_child_node_by_name(representation_node, "BaseURL"); 881cabdff1aSopenharmony_ci representation_segmentlist_node = find_child_node_by_name(representation_node, "SegmentList"); 882cabdff1aSopenharmony_ci rep_bandwidth_val = xmlGetProp(representation_node, "bandwidth"); 883cabdff1aSopenharmony_ci val = xmlGetProp(representation_node, "id"); 884cabdff1aSopenharmony_ci if (val) { 885cabdff1aSopenharmony_ci rep->id = av_strdup(val); 886cabdff1aSopenharmony_ci xmlFree(val); 887cabdff1aSopenharmony_ci if (!rep->id) 888cabdff1aSopenharmony_ci goto enomem; 889cabdff1aSopenharmony_ci } 890cabdff1aSopenharmony_ci 891cabdff1aSopenharmony_ci baseurl_nodes[0] = mpd_baseurl_node; 892cabdff1aSopenharmony_ci baseurl_nodes[1] = period_baseurl_node; 893cabdff1aSopenharmony_ci baseurl_nodes[2] = adaptionset_baseurl_node; 894cabdff1aSopenharmony_ci baseurl_nodes[3] = representation_baseurl_node; 895cabdff1aSopenharmony_ci 896cabdff1aSopenharmony_ci ret = resolve_content_path(s, url, &c->max_url_size, baseurl_nodes, 4); 897cabdff1aSopenharmony_ci c->max_url_size = aligned(c->max_url_size 898cabdff1aSopenharmony_ci + (rep->id ? strlen(rep->id) : 0) 899cabdff1aSopenharmony_ci + (rep_bandwidth_val ? strlen(rep_bandwidth_val) : 0)); 900cabdff1aSopenharmony_ci if (ret == AVERROR(ENOMEM) || ret == 0) 901cabdff1aSopenharmony_ci goto free; 902cabdff1aSopenharmony_ci if (representation_segmenttemplate_node || fragment_template_node || period_segmenttemplate_node) { 903cabdff1aSopenharmony_ci fragment_timeline_node = NULL; 904cabdff1aSopenharmony_ci fragment_templates_tab[0] = representation_segmenttemplate_node; 905cabdff1aSopenharmony_ci fragment_templates_tab[1] = adaptionset_segmentlist_node; 906cabdff1aSopenharmony_ci fragment_templates_tab[2] = fragment_template_node; 907cabdff1aSopenharmony_ci fragment_templates_tab[3] = period_segmenttemplate_node; 908cabdff1aSopenharmony_ci fragment_templates_tab[4] = period_segmentlist_node; 909cabdff1aSopenharmony_ci 910cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(fragment_templates_tab, 4, "initialization"); 911cabdff1aSopenharmony_ci if (val) { 912cabdff1aSopenharmony_ci rep->init_section = av_mallocz(sizeof(struct fragment)); 913cabdff1aSopenharmony_ci if (!rep->init_section) { 914cabdff1aSopenharmony_ci xmlFree(val); 915cabdff1aSopenharmony_ci goto enomem; 916cabdff1aSopenharmony_ci } 917cabdff1aSopenharmony_ci c->max_url_size = aligned(c->max_url_size + strlen(val)); 918cabdff1aSopenharmony_ci rep->init_section->url = get_content_url(baseurl_nodes, 4, 919cabdff1aSopenharmony_ci c->max_url_size, rep->id, 920cabdff1aSopenharmony_ci rep_bandwidth_val, val); 921cabdff1aSopenharmony_ci xmlFree(val); 922cabdff1aSopenharmony_ci if (!rep->init_section->url) 923cabdff1aSopenharmony_ci goto enomem; 924cabdff1aSopenharmony_ci rep->init_section->size = -1; 925cabdff1aSopenharmony_ci } 926cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(fragment_templates_tab, 4, "media"); 927cabdff1aSopenharmony_ci if (val) { 928cabdff1aSopenharmony_ci c->max_url_size = aligned(c->max_url_size + strlen(val)); 929cabdff1aSopenharmony_ci rep->url_template = get_content_url(baseurl_nodes, 4, 930cabdff1aSopenharmony_ci c->max_url_size, rep->id, 931cabdff1aSopenharmony_ci rep_bandwidth_val, val); 932cabdff1aSopenharmony_ci xmlFree(val); 933cabdff1aSopenharmony_ci } 934cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(fragment_templates_tab, 4, "presentationTimeOffset"); 935cabdff1aSopenharmony_ci if (val) { 936cabdff1aSopenharmony_ci rep->presentation_timeoffset = (int64_t) strtoll(val, NULL, 10); 937cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "rep->presentation_timeoffset = [%"PRId64"]\n", rep->presentation_timeoffset); 938cabdff1aSopenharmony_ci xmlFree(val); 939cabdff1aSopenharmony_ci } 940cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(fragment_templates_tab, 4, "duration"); 941cabdff1aSopenharmony_ci if (val) { 942cabdff1aSopenharmony_ci rep->fragment_duration = (int64_t) strtoll(val, NULL, 10); 943cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "rep->fragment_duration = [%"PRId64"]\n", rep->fragment_duration); 944cabdff1aSopenharmony_ci xmlFree(val); 945cabdff1aSopenharmony_ci } 946cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(fragment_templates_tab, 4, "timescale"); 947cabdff1aSopenharmony_ci if (val) { 948cabdff1aSopenharmony_ci rep->fragment_timescale = (int64_t) strtoll(val, NULL, 10); 949cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "rep->fragment_timescale = [%"PRId64"]\n", rep->fragment_timescale); 950cabdff1aSopenharmony_ci xmlFree(val); 951cabdff1aSopenharmony_ci } 952cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(fragment_templates_tab, 4, "startNumber"); 953cabdff1aSopenharmony_ci if (val) { 954cabdff1aSopenharmony_ci rep->start_number = rep->first_seq_no = (int64_t) strtoll(val, NULL, 10); 955cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "rep->first_seq_no = [%"PRId64"]\n", rep->first_seq_no); 956cabdff1aSopenharmony_ci xmlFree(val); 957cabdff1aSopenharmony_ci } 958cabdff1aSopenharmony_ci if (adaptionset_supplementalproperty_node) { 959cabdff1aSopenharmony_ci char *scheme_id_uri = xmlGetProp(adaptionset_supplementalproperty_node, "schemeIdUri"); 960cabdff1aSopenharmony_ci if (scheme_id_uri) { 961cabdff1aSopenharmony_ci int is_last_segment_number = !av_strcasecmp(scheme_id_uri, "http://dashif.org/guidelines/last-segment-number"); 962cabdff1aSopenharmony_ci xmlFree(scheme_id_uri); 963cabdff1aSopenharmony_ci if (is_last_segment_number) { 964cabdff1aSopenharmony_ci val = xmlGetProp(adaptionset_supplementalproperty_node,"value"); 965cabdff1aSopenharmony_ci if (!val) { 966cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Missing value attribute in adaptionset_supplementalproperty_node\n"); 967cabdff1aSopenharmony_ci } else { 968cabdff1aSopenharmony_ci rep->last_seq_no =(int64_t) strtoll(val, NULL, 10) - 1; 969cabdff1aSopenharmony_ci xmlFree(val); 970cabdff1aSopenharmony_ci } 971cabdff1aSopenharmony_ci } 972cabdff1aSopenharmony_ci } 973cabdff1aSopenharmony_ci } 974cabdff1aSopenharmony_ci 975cabdff1aSopenharmony_ci fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline"); 976cabdff1aSopenharmony_ci 977cabdff1aSopenharmony_ci if (!fragment_timeline_node) 978cabdff1aSopenharmony_ci fragment_timeline_node = find_child_node_by_name(fragment_template_node, "SegmentTimeline"); 979cabdff1aSopenharmony_ci if (!fragment_timeline_node) 980cabdff1aSopenharmony_ci fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline"); 981cabdff1aSopenharmony_ci if (!fragment_timeline_node) 982cabdff1aSopenharmony_ci fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline"); 983cabdff1aSopenharmony_ci if (fragment_timeline_node) { 984cabdff1aSopenharmony_ci fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node); 985cabdff1aSopenharmony_ci while (fragment_timeline_node) { 986cabdff1aSopenharmony_ci ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node); 987cabdff1aSopenharmony_ci if (ret < 0) 988cabdff1aSopenharmony_ci goto free; 989cabdff1aSopenharmony_ci fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node); 990cabdff1aSopenharmony_ci } 991cabdff1aSopenharmony_ci } 992cabdff1aSopenharmony_ci } else if (representation_baseurl_node && !representation_segmentlist_node) { 993cabdff1aSopenharmony_ci seg = av_mallocz(sizeof(struct fragment)); 994cabdff1aSopenharmony_ci if (!seg) 995cabdff1aSopenharmony_ci goto enomem; 996cabdff1aSopenharmony_ci ret = av_dynarray_add_nofree(&rep->fragments, &rep->n_fragments, seg); 997cabdff1aSopenharmony_ci if (ret < 0) { 998cabdff1aSopenharmony_ci av_free(seg); 999cabdff1aSopenharmony_ci goto free; 1000cabdff1aSopenharmony_ci } 1001cabdff1aSopenharmony_ci seg->url = get_content_url(baseurl_nodes, 4, c->max_url_size, 1002cabdff1aSopenharmony_ci rep->id, rep_bandwidth_val, NULL); 1003cabdff1aSopenharmony_ci if (!seg->url) 1004cabdff1aSopenharmony_ci goto enomem; 1005cabdff1aSopenharmony_ci seg->size = -1; 1006cabdff1aSopenharmony_ci } else if (representation_segmentlist_node) { 1007cabdff1aSopenharmony_ci // TODO: https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html 1008cabdff1aSopenharmony_ci // http://www-itec.uni-klu.ac.at/dash/ddash/mpdGenerator.php?fragmentlength=15&type=full 1009cabdff1aSopenharmony_ci xmlNodePtr fragmenturl_node = NULL; 1010cabdff1aSopenharmony_ci segmentlists_tab[0] = representation_segmentlist_node; 1011cabdff1aSopenharmony_ci segmentlists_tab[1] = adaptionset_segmentlist_node; 1012cabdff1aSopenharmony_ci segmentlists_tab[2] = period_segmentlist_node; 1013cabdff1aSopenharmony_ci 1014cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(segmentlists_tab, 3, "duration"); 1015cabdff1aSopenharmony_ci if (val) { 1016cabdff1aSopenharmony_ci rep->fragment_duration = (int64_t) strtoll(val, NULL, 10); 1017cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "rep->fragment_duration = [%"PRId64"]\n", rep->fragment_duration); 1018cabdff1aSopenharmony_ci xmlFree(val); 1019cabdff1aSopenharmony_ci } 1020cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(segmentlists_tab, 3, "timescale"); 1021cabdff1aSopenharmony_ci if (val) { 1022cabdff1aSopenharmony_ci rep->fragment_timescale = (int64_t) strtoll(val, NULL, 10); 1023cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "rep->fragment_timescale = [%"PRId64"]\n", rep->fragment_timescale); 1024cabdff1aSopenharmony_ci xmlFree(val); 1025cabdff1aSopenharmony_ci } 1026cabdff1aSopenharmony_ci val = get_val_from_nodes_tab(segmentlists_tab, 3, "startNumber"); 1027cabdff1aSopenharmony_ci if (val) { 1028cabdff1aSopenharmony_ci rep->start_number = rep->first_seq_no = (int64_t) strtoll(val, NULL, 10); 1029cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "rep->first_seq_no = [%"PRId64"]\n", rep->first_seq_no); 1030cabdff1aSopenharmony_ci xmlFree(val); 1031cabdff1aSopenharmony_ci } 1032cabdff1aSopenharmony_ci 1033cabdff1aSopenharmony_ci fragmenturl_node = xmlFirstElementChild(representation_segmentlist_node); 1034cabdff1aSopenharmony_ci while (fragmenturl_node) { 1035cabdff1aSopenharmony_ci ret = parse_manifest_segmenturlnode(s, rep, fragmenturl_node, 1036cabdff1aSopenharmony_ci baseurl_nodes, rep->id, 1037cabdff1aSopenharmony_ci rep_bandwidth_val); 1038cabdff1aSopenharmony_ci if (ret < 0) 1039cabdff1aSopenharmony_ci goto free; 1040cabdff1aSopenharmony_ci fragmenturl_node = xmlNextElementSibling(fragmenturl_node); 1041cabdff1aSopenharmony_ci } 1042cabdff1aSopenharmony_ci 1043cabdff1aSopenharmony_ci fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline"); 1044cabdff1aSopenharmony_ci if (!fragment_timeline_node) 1045cabdff1aSopenharmony_ci fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline"); 1046cabdff1aSopenharmony_ci if (fragment_timeline_node) { 1047cabdff1aSopenharmony_ci fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node); 1048cabdff1aSopenharmony_ci while (fragment_timeline_node) { 1049cabdff1aSopenharmony_ci ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node); 1050cabdff1aSopenharmony_ci if (ret < 0) 1051cabdff1aSopenharmony_ci goto free; 1052cabdff1aSopenharmony_ci fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node); 1053cabdff1aSopenharmony_ci } 1054cabdff1aSopenharmony_ci } 1055cabdff1aSopenharmony_ci } else { 1056cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unknown format of Representation node id '%s' \n", 1057cabdff1aSopenharmony_ci rep->id ? rep->id : ""); 1058cabdff1aSopenharmony_ci goto free; 1059cabdff1aSopenharmony_ci } 1060cabdff1aSopenharmony_ci 1061cabdff1aSopenharmony_ci if (rep->fragment_duration > 0 && !rep->fragment_timescale) 1062cabdff1aSopenharmony_ci rep->fragment_timescale = 1; 1063cabdff1aSopenharmony_ci rep->bandwidth = rep_bandwidth_val ? atoi(rep_bandwidth_val) : 0; 1064cabdff1aSopenharmony_ci rep->framerate = av_make_q(0, 0); 1065cabdff1aSopenharmony_ci if (type == AVMEDIA_TYPE_VIDEO) { 1066cabdff1aSopenharmony_ci char *rep_framerate_val = xmlGetProp(representation_node, "frameRate"); 1067cabdff1aSopenharmony_ci if (rep_framerate_val) { 1068cabdff1aSopenharmony_ci ret = av_parse_video_rate(&rep->framerate, rep_framerate_val); 1069cabdff1aSopenharmony_ci if (ret < 0) 1070cabdff1aSopenharmony_ci av_log(s, AV_LOG_VERBOSE, "Ignoring invalid frame rate '%s'\n", rep_framerate_val); 1071cabdff1aSopenharmony_ci xmlFree(rep_framerate_val); 1072cabdff1aSopenharmony_ci } 1073cabdff1aSopenharmony_ci } 1074cabdff1aSopenharmony_ci 1075cabdff1aSopenharmony_ci switch (type) { 1076cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: 1077cabdff1aSopenharmony_ci ret = av_dynarray_add_nofree(&c->videos, &c->n_videos, rep); 1078cabdff1aSopenharmony_ci break; 1079cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: 1080cabdff1aSopenharmony_ci ret = av_dynarray_add_nofree(&c->audios, &c->n_audios, rep); 1081cabdff1aSopenharmony_ci break; 1082cabdff1aSopenharmony_ci case AVMEDIA_TYPE_SUBTITLE: 1083cabdff1aSopenharmony_ci ret = av_dynarray_add_nofree(&c->subtitles, &c->n_subtitles, rep); 1084cabdff1aSopenharmony_ci break; 1085cabdff1aSopenharmony_ci } 1086cabdff1aSopenharmony_ci if (ret < 0) 1087cabdff1aSopenharmony_ci goto free; 1088cabdff1aSopenharmony_ci 1089cabdff1aSopenharmony_ciend: 1090cabdff1aSopenharmony_ci if (rep_bandwidth_val) 1091cabdff1aSopenharmony_ci xmlFree(rep_bandwidth_val); 1092cabdff1aSopenharmony_ci 1093cabdff1aSopenharmony_ci return ret; 1094cabdff1aSopenharmony_cienomem: 1095cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 1096cabdff1aSopenharmony_cifree: 1097cabdff1aSopenharmony_ci free_representation(rep); 1098cabdff1aSopenharmony_ci goto end; 1099cabdff1aSopenharmony_ci} 1100cabdff1aSopenharmony_ci 1101cabdff1aSopenharmony_cistatic int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adaptionset_node) 1102cabdff1aSopenharmony_ci{ 1103cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 1104cabdff1aSopenharmony_ci 1105cabdff1aSopenharmony_ci if (!adaptionset_node) { 1106cabdff1aSopenharmony_ci av_log(s, AV_LOG_WARNING, "Cannot get AdaptionSet\n"); 1107cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1108cabdff1aSopenharmony_ci } 1109cabdff1aSopenharmony_ci c->adaptionset_lang = xmlGetProp(adaptionset_node, "lang"); 1110cabdff1aSopenharmony_ci 1111cabdff1aSopenharmony_ci return 0; 1112cabdff1aSopenharmony_ci} 1113cabdff1aSopenharmony_ci 1114cabdff1aSopenharmony_cistatic int parse_manifest_adaptationset(AVFormatContext *s, const char *url, 1115cabdff1aSopenharmony_ci xmlNodePtr adaptionset_node, 1116cabdff1aSopenharmony_ci xmlNodePtr mpd_baseurl_node, 1117cabdff1aSopenharmony_ci xmlNodePtr period_baseurl_node, 1118cabdff1aSopenharmony_ci xmlNodePtr period_segmenttemplate_node, 1119cabdff1aSopenharmony_ci xmlNodePtr period_segmentlist_node) 1120cabdff1aSopenharmony_ci{ 1121cabdff1aSopenharmony_ci int ret = 0; 1122cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 1123cabdff1aSopenharmony_ci xmlNodePtr fragment_template_node = NULL; 1124cabdff1aSopenharmony_ci xmlNodePtr content_component_node = NULL; 1125cabdff1aSopenharmony_ci xmlNodePtr adaptionset_baseurl_node = NULL; 1126cabdff1aSopenharmony_ci xmlNodePtr adaptionset_segmentlist_node = NULL; 1127cabdff1aSopenharmony_ci xmlNodePtr adaptionset_supplementalproperty_node = NULL; 1128cabdff1aSopenharmony_ci xmlNodePtr node = NULL; 1129cabdff1aSopenharmony_ci 1130cabdff1aSopenharmony_ci ret = parse_manifest_adaptationset_attr(s, adaptionset_node); 1131cabdff1aSopenharmony_ci if (ret < 0) 1132cabdff1aSopenharmony_ci return ret; 1133cabdff1aSopenharmony_ci 1134cabdff1aSopenharmony_ci node = xmlFirstElementChild(adaptionset_node); 1135cabdff1aSopenharmony_ci while (node) { 1136cabdff1aSopenharmony_ci if (!av_strcasecmp(node->name, "SegmentTemplate")) { 1137cabdff1aSopenharmony_ci fragment_template_node = node; 1138cabdff1aSopenharmony_ci } else if (!av_strcasecmp(node->name, "ContentComponent")) { 1139cabdff1aSopenharmony_ci content_component_node = node; 1140cabdff1aSopenharmony_ci } else if (!av_strcasecmp(node->name, "BaseURL")) { 1141cabdff1aSopenharmony_ci adaptionset_baseurl_node = node; 1142cabdff1aSopenharmony_ci } else if (!av_strcasecmp(node->name, "SegmentList")) { 1143cabdff1aSopenharmony_ci adaptionset_segmentlist_node = node; 1144cabdff1aSopenharmony_ci } else if (!av_strcasecmp(node->name, "SupplementalProperty")) { 1145cabdff1aSopenharmony_ci adaptionset_supplementalproperty_node = node; 1146cabdff1aSopenharmony_ci } else if (!av_strcasecmp(node->name, "Representation")) { 1147cabdff1aSopenharmony_ci ret = parse_manifest_representation(s, url, node, 1148cabdff1aSopenharmony_ci adaptionset_node, 1149cabdff1aSopenharmony_ci mpd_baseurl_node, 1150cabdff1aSopenharmony_ci period_baseurl_node, 1151cabdff1aSopenharmony_ci period_segmenttemplate_node, 1152cabdff1aSopenharmony_ci period_segmentlist_node, 1153cabdff1aSopenharmony_ci fragment_template_node, 1154cabdff1aSopenharmony_ci content_component_node, 1155cabdff1aSopenharmony_ci adaptionset_baseurl_node, 1156cabdff1aSopenharmony_ci adaptionset_segmentlist_node, 1157cabdff1aSopenharmony_ci adaptionset_supplementalproperty_node); 1158cabdff1aSopenharmony_ci if (ret < 0) 1159cabdff1aSopenharmony_ci goto err; 1160cabdff1aSopenharmony_ci } 1161cabdff1aSopenharmony_ci node = xmlNextElementSibling(node); 1162cabdff1aSopenharmony_ci } 1163cabdff1aSopenharmony_ci 1164cabdff1aSopenharmony_cierr: 1165cabdff1aSopenharmony_ci xmlFree(c->adaptionset_lang); 1166cabdff1aSopenharmony_ci c->adaptionset_lang = NULL; 1167cabdff1aSopenharmony_ci return ret; 1168cabdff1aSopenharmony_ci} 1169cabdff1aSopenharmony_ci 1170cabdff1aSopenharmony_cistatic int parse_programinformation(AVFormatContext *s, xmlNodePtr node) 1171cabdff1aSopenharmony_ci{ 1172cabdff1aSopenharmony_ci xmlChar *val = NULL; 1173cabdff1aSopenharmony_ci 1174cabdff1aSopenharmony_ci node = xmlFirstElementChild(node); 1175cabdff1aSopenharmony_ci while (node) { 1176cabdff1aSopenharmony_ci if (!av_strcasecmp(node->name, "Title")) { 1177cabdff1aSopenharmony_ci val = xmlNodeGetContent(node); 1178cabdff1aSopenharmony_ci if (val) { 1179cabdff1aSopenharmony_ci av_dict_set(&s->metadata, "Title", val, 0); 1180cabdff1aSopenharmony_ci } 1181cabdff1aSopenharmony_ci } else if (!av_strcasecmp(node->name, "Source")) { 1182cabdff1aSopenharmony_ci val = xmlNodeGetContent(node); 1183cabdff1aSopenharmony_ci if (val) { 1184cabdff1aSopenharmony_ci av_dict_set(&s->metadata, "Source", val, 0); 1185cabdff1aSopenharmony_ci } 1186cabdff1aSopenharmony_ci } else if (!av_strcasecmp(node->name, "Copyright")) { 1187cabdff1aSopenharmony_ci val = xmlNodeGetContent(node); 1188cabdff1aSopenharmony_ci if (val) { 1189cabdff1aSopenharmony_ci av_dict_set(&s->metadata, "Copyright", val, 0); 1190cabdff1aSopenharmony_ci } 1191cabdff1aSopenharmony_ci } 1192cabdff1aSopenharmony_ci node = xmlNextElementSibling(node); 1193cabdff1aSopenharmony_ci xmlFree(val); 1194cabdff1aSopenharmony_ci val = NULL; 1195cabdff1aSopenharmony_ci } 1196cabdff1aSopenharmony_ci return 0; 1197cabdff1aSopenharmony_ci} 1198cabdff1aSopenharmony_ci 1199cabdff1aSopenharmony_cistatic int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) 1200cabdff1aSopenharmony_ci{ 1201cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 1202cabdff1aSopenharmony_ci int ret = 0; 1203cabdff1aSopenharmony_ci int close_in = 0; 1204cabdff1aSopenharmony_ci AVBPrint buf; 1205cabdff1aSopenharmony_ci AVDictionary *opts = NULL; 1206cabdff1aSopenharmony_ci xmlDoc *doc = NULL; 1207cabdff1aSopenharmony_ci xmlNodePtr root_element = NULL; 1208cabdff1aSopenharmony_ci xmlNodePtr node = NULL; 1209cabdff1aSopenharmony_ci xmlNodePtr period_node = NULL; 1210cabdff1aSopenharmony_ci xmlNodePtr tmp_node = NULL; 1211cabdff1aSopenharmony_ci xmlNodePtr mpd_baseurl_node = NULL; 1212cabdff1aSopenharmony_ci xmlNodePtr period_baseurl_node = NULL; 1213cabdff1aSopenharmony_ci xmlNodePtr period_segmenttemplate_node = NULL; 1214cabdff1aSopenharmony_ci xmlNodePtr period_segmentlist_node = NULL; 1215cabdff1aSopenharmony_ci xmlNodePtr adaptionset_node = NULL; 1216cabdff1aSopenharmony_ci xmlAttrPtr attr = NULL; 1217cabdff1aSopenharmony_ci char *val = NULL; 1218cabdff1aSopenharmony_ci uint32_t period_duration_sec = 0; 1219cabdff1aSopenharmony_ci uint32_t period_start_sec = 0; 1220cabdff1aSopenharmony_ci 1221cabdff1aSopenharmony_ci if (!in) { 1222cabdff1aSopenharmony_ci close_in = 1; 1223cabdff1aSopenharmony_ci 1224cabdff1aSopenharmony_ci av_dict_copy(&opts, c->avio_opts, 0); 1225cabdff1aSopenharmony_ci ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); 1226cabdff1aSopenharmony_ci av_dict_free(&opts); 1227cabdff1aSopenharmony_ci if (ret < 0) 1228cabdff1aSopenharmony_ci return ret; 1229cabdff1aSopenharmony_ci } 1230cabdff1aSopenharmony_ci 1231cabdff1aSopenharmony_ci if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&c->base_url) < 0) 1232cabdff1aSopenharmony_ci c->base_url = av_strdup(url); 1233cabdff1aSopenharmony_ci 1234cabdff1aSopenharmony_ci av_bprint_init(&buf, 0, INT_MAX); // xmlReadMemory uses integer bufsize 1235cabdff1aSopenharmony_ci 1236cabdff1aSopenharmony_ci if ((ret = avio_read_to_bprint(in, &buf, SIZE_MAX)) < 0 || 1237cabdff1aSopenharmony_ci !avio_feof(in)) { 1238cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to read to manifest '%s'\n", url); 1239cabdff1aSopenharmony_ci if (ret == 0) 1240cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 1241cabdff1aSopenharmony_ci } else { 1242cabdff1aSopenharmony_ci LIBXML_TEST_VERSION 1243cabdff1aSopenharmony_ci 1244cabdff1aSopenharmony_ci doc = xmlReadMemory(buf.str, buf.len, c->base_url, NULL, 0); 1245cabdff1aSopenharmony_ci root_element = xmlDocGetRootElement(doc); 1246cabdff1aSopenharmony_ci node = root_element; 1247cabdff1aSopenharmony_ci 1248cabdff1aSopenharmony_ci if (!node) { 1249cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 1250cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing root node\n", url); 1251cabdff1aSopenharmony_ci goto cleanup; 1252cabdff1aSopenharmony_ci } 1253cabdff1aSopenharmony_ci 1254cabdff1aSopenharmony_ci if (node->type != XML_ELEMENT_NODE || 1255cabdff1aSopenharmony_ci av_strcasecmp(node->name, "MPD")) { 1256cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 1257cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - wrong root node name[%s] type[%d]\n", url, node->name, (int)node->type); 1258cabdff1aSopenharmony_ci goto cleanup; 1259cabdff1aSopenharmony_ci } 1260cabdff1aSopenharmony_ci 1261cabdff1aSopenharmony_ci val = xmlGetProp(node, "type"); 1262cabdff1aSopenharmony_ci if (!val) { 1263cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing type attrib\n", url); 1264cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 1265cabdff1aSopenharmony_ci goto cleanup; 1266cabdff1aSopenharmony_ci } 1267cabdff1aSopenharmony_ci if (!av_strcasecmp(val, "dynamic")) 1268cabdff1aSopenharmony_ci c->is_live = 1; 1269cabdff1aSopenharmony_ci xmlFree(val); 1270cabdff1aSopenharmony_ci 1271cabdff1aSopenharmony_ci attr = node->properties; 1272cabdff1aSopenharmony_ci while (attr) { 1273cabdff1aSopenharmony_ci val = xmlGetProp(node, attr->name); 1274cabdff1aSopenharmony_ci 1275cabdff1aSopenharmony_ci if (!av_strcasecmp(attr->name, "availabilityStartTime")) { 1276cabdff1aSopenharmony_ci c->availability_start_time = get_utc_date_time_insec(s, val); 1277cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time); 1278cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "availabilityEndTime")) { 1279cabdff1aSopenharmony_ci c->availability_end_time = get_utc_date_time_insec(s, val); 1280cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time); 1281cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "publishTime")) { 1282cabdff1aSopenharmony_ci c->publish_time = get_utc_date_time_insec(s, val); 1283cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time); 1284cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "minimumUpdatePeriod")) { 1285cabdff1aSopenharmony_ci c->minimum_update_period = get_duration_insec(s, val); 1286cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period); 1287cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "timeShiftBufferDepth")) { 1288cabdff1aSopenharmony_ci c->time_shift_buffer_depth = get_duration_insec(s, val); 1289cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth); 1290cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "minBufferTime")) { 1291cabdff1aSopenharmony_ci c->min_buffer_time = get_duration_insec(s, val); 1292cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time); 1293cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "suggestedPresentationDelay")) { 1294cabdff1aSopenharmony_ci c->suggested_presentation_delay = get_duration_insec(s, val); 1295cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay); 1296cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "mediaPresentationDuration")) { 1297cabdff1aSopenharmony_ci c->media_presentation_duration = get_duration_insec(s, val); 1298cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration); 1299cabdff1aSopenharmony_ci } 1300cabdff1aSopenharmony_ci attr = attr->next; 1301cabdff1aSopenharmony_ci xmlFree(val); 1302cabdff1aSopenharmony_ci } 1303cabdff1aSopenharmony_ci 1304cabdff1aSopenharmony_ci tmp_node = find_child_node_by_name(node, "BaseURL"); 1305cabdff1aSopenharmony_ci if (tmp_node) { 1306cabdff1aSopenharmony_ci mpd_baseurl_node = xmlCopyNode(tmp_node,1); 1307cabdff1aSopenharmony_ci } else { 1308cabdff1aSopenharmony_ci mpd_baseurl_node = xmlNewNode(NULL, "BaseURL"); 1309cabdff1aSopenharmony_ci } 1310cabdff1aSopenharmony_ci 1311cabdff1aSopenharmony_ci // at now we can handle only one period, with the longest duration 1312cabdff1aSopenharmony_ci node = xmlFirstElementChild(node); 1313cabdff1aSopenharmony_ci while (node) { 1314cabdff1aSopenharmony_ci if (!av_strcasecmp(node->name, "Period")) { 1315cabdff1aSopenharmony_ci period_duration_sec = 0; 1316cabdff1aSopenharmony_ci period_start_sec = 0; 1317cabdff1aSopenharmony_ci attr = node->properties; 1318cabdff1aSopenharmony_ci while (attr) { 1319cabdff1aSopenharmony_ci val = xmlGetProp(node, attr->name); 1320cabdff1aSopenharmony_ci if (!av_strcasecmp(attr->name, "duration")) { 1321cabdff1aSopenharmony_ci period_duration_sec = get_duration_insec(s, val); 1322cabdff1aSopenharmony_ci } else if (!av_strcasecmp(attr->name, "start")) { 1323cabdff1aSopenharmony_ci period_start_sec = get_duration_insec(s, val); 1324cabdff1aSopenharmony_ci } 1325cabdff1aSopenharmony_ci attr = attr->next; 1326cabdff1aSopenharmony_ci xmlFree(val); 1327cabdff1aSopenharmony_ci } 1328cabdff1aSopenharmony_ci if ((period_duration_sec) >= (c->period_duration)) { 1329cabdff1aSopenharmony_ci period_node = node; 1330cabdff1aSopenharmony_ci c->period_duration = period_duration_sec; 1331cabdff1aSopenharmony_ci c->period_start = period_start_sec; 1332cabdff1aSopenharmony_ci if (c->period_start > 0) 1333cabdff1aSopenharmony_ci c->media_presentation_duration = c->period_duration; 1334cabdff1aSopenharmony_ci } 1335cabdff1aSopenharmony_ci } else if (!av_strcasecmp(node->name, "ProgramInformation")) { 1336cabdff1aSopenharmony_ci parse_programinformation(s, node); 1337cabdff1aSopenharmony_ci } 1338cabdff1aSopenharmony_ci node = xmlNextElementSibling(node); 1339cabdff1aSopenharmony_ci } 1340cabdff1aSopenharmony_ci if (!period_node) { 1341cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing Period node\n", url); 1342cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 1343cabdff1aSopenharmony_ci goto cleanup; 1344cabdff1aSopenharmony_ci } 1345cabdff1aSopenharmony_ci 1346cabdff1aSopenharmony_ci adaptionset_node = xmlFirstElementChild(period_node); 1347cabdff1aSopenharmony_ci while (adaptionset_node) { 1348cabdff1aSopenharmony_ci if (!av_strcasecmp(adaptionset_node->name, "BaseURL")) { 1349cabdff1aSopenharmony_ci period_baseurl_node = adaptionset_node; 1350cabdff1aSopenharmony_ci } else if (!av_strcasecmp(adaptionset_node->name, "SegmentTemplate")) { 1351cabdff1aSopenharmony_ci period_segmenttemplate_node = adaptionset_node; 1352cabdff1aSopenharmony_ci } else if (!av_strcasecmp(adaptionset_node->name, "SegmentList")) { 1353cabdff1aSopenharmony_ci period_segmentlist_node = adaptionset_node; 1354cabdff1aSopenharmony_ci } else if (!av_strcasecmp(adaptionset_node->name, "AdaptationSet")) { 1355cabdff1aSopenharmony_ci parse_manifest_adaptationset(s, url, adaptionset_node, mpd_baseurl_node, period_baseurl_node, period_segmenttemplate_node, period_segmentlist_node); 1356cabdff1aSopenharmony_ci } 1357cabdff1aSopenharmony_ci adaptionset_node = xmlNextElementSibling(adaptionset_node); 1358cabdff1aSopenharmony_ci } 1359cabdff1aSopenharmony_cicleanup: 1360cabdff1aSopenharmony_ci /*free the document */ 1361cabdff1aSopenharmony_ci xmlFreeDoc(doc); 1362cabdff1aSopenharmony_ci xmlCleanupParser(); 1363cabdff1aSopenharmony_ci xmlFreeNode(mpd_baseurl_node); 1364cabdff1aSopenharmony_ci } 1365cabdff1aSopenharmony_ci 1366cabdff1aSopenharmony_ci av_bprint_finalize(&buf, NULL); 1367cabdff1aSopenharmony_ci if (close_in) { 1368cabdff1aSopenharmony_ci avio_close(in); 1369cabdff1aSopenharmony_ci } 1370cabdff1aSopenharmony_ci return ret; 1371cabdff1aSopenharmony_ci} 1372cabdff1aSopenharmony_ci 1373cabdff1aSopenharmony_cistatic int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls) 1374cabdff1aSopenharmony_ci{ 1375cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 1376cabdff1aSopenharmony_ci int64_t num = 0; 1377cabdff1aSopenharmony_ci int64_t start_time_offset = 0; 1378cabdff1aSopenharmony_ci 1379cabdff1aSopenharmony_ci if (c->is_live) { 1380cabdff1aSopenharmony_ci if (pls->n_fragments) { 1381cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "in n_fragments mode\n"); 1382cabdff1aSopenharmony_ci num = pls->first_seq_no; 1383cabdff1aSopenharmony_ci } else if (pls->n_timelines) { 1384cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "in n_timelines mode\n"); 1385cabdff1aSopenharmony_ci start_time_offset = get_segment_start_time_based_on_timeline(pls, 0xFFFFFFFF) - 60 * pls->fragment_timescale; // 60 seconds before end 1386cabdff1aSopenharmony_ci num = calc_next_seg_no_from_timelines(pls, start_time_offset); 1387cabdff1aSopenharmony_ci if (num == -1) 1388cabdff1aSopenharmony_ci num = pls->first_seq_no; 1389cabdff1aSopenharmony_ci else 1390cabdff1aSopenharmony_ci num += pls->first_seq_no; 1391cabdff1aSopenharmony_ci } else if (pls->fragment_duration){ 1392cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "in fragment_duration mode fragment_timescale = %"PRId64", presentation_timeoffset = %"PRId64"\n", pls->fragment_timescale, pls->presentation_timeoffset); 1393cabdff1aSopenharmony_ci if (pls->presentation_timeoffset) { 1394cabdff1aSopenharmony_ci 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; 1395cabdff1aSopenharmony_ci } else if (c->publish_time > 0 && !c->availability_start_time) { 1396cabdff1aSopenharmony_ci if (c->min_buffer_time) { 1397cabdff1aSopenharmony_ci 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; 1398cabdff1aSopenharmony_ci } else { 1399cabdff1aSopenharmony_ci 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; 1400cabdff1aSopenharmony_ci } 1401cabdff1aSopenharmony_ci } else { 1402cabdff1aSopenharmony_ci num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration; 1403cabdff1aSopenharmony_ci } 1404cabdff1aSopenharmony_ci } 1405cabdff1aSopenharmony_ci } else { 1406cabdff1aSopenharmony_ci num = pls->first_seq_no; 1407cabdff1aSopenharmony_ci } 1408cabdff1aSopenharmony_ci return num; 1409cabdff1aSopenharmony_ci} 1410cabdff1aSopenharmony_ci 1411cabdff1aSopenharmony_cistatic int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls) 1412cabdff1aSopenharmony_ci{ 1413cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 1414cabdff1aSopenharmony_ci int64_t num = 0; 1415cabdff1aSopenharmony_ci 1416cabdff1aSopenharmony_ci if (c->is_live && pls->fragment_duration) { 1417cabdff1aSopenharmony_ci av_log(s, AV_LOG_TRACE, "in live mode\n"); 1418cabdff1aSopenharmony_ci 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; 1419cabdff1aSopenharmony_ci } else { 1420cabdff1aSopenharmony_ci num = pls->first_seq_no; 1421cabdff1aSopenharmony_ci } 1422cabdff1aSopenharmony_ci return num; 1423cabdff1aSopenharmony_ci} 1424cabdff1aSopenharmony_ci 1425cabdff1aSopenharmony_cistatic int64_t calc_max_seg_no(struct representation *pls, DASHContext *c) 1426cabdff1aSopenharmony_ci{ 1427cabdff1aSopenharmony_ci int64_t num = 0; 1428cabdff1aSopenharmony_ci 1429cabdff1aSopenharmony_ci if (pls->n_fragments) { 1430cabdff1aSopenharmony_ci num = pls->first_seq_no + pls->n_fragments - 1; 1431cabdff1aSopenharmony_ci } else if (pls->n_timelines) { 1432cabdff1aSopenharmony_ci int i = 0; 1433cabdff1aSopenharmony_ci num = pls->first_seq_no + pls->n_timelines - 1; 1434cabdff1aSopenharmony_ci for (i = 0; i < pls->n_timelines; i++) { 1435cabdff1aSopenharmony_ci if (pls->timelines[i]->repeat == -1) { 1436cabdff1aSopenharmony_ci int length_of_each_segment = pls->timelines[i]->duration / pls->fragment_timescale; 1437cabdff1aSopenharmony_ci num = c->period_duration / length_of_each_segment; 1438cabdff1aSopenharmony_ci } else { 1439cabdff1aSopenharmony_ci num += pls->timelines[i]->repeat; 1440cabdff1aSopenharmony_ci } 1441cabdff1aSopenharmony_ci } 1442cabdff1aSopenharmony_ci } else if (c->is_live && pls->fragment_duration) { 1443cabdff1aSopenharmony_ci num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time)) * pls->fragment_timescale) / pls->fragment_duration; 1444cabdff1aSopenharmony_ci } else if (pls->fragment_duration) { 1445cabdff1aSopenharmony_ci num = pls->first_seq_no + av_rescale_rnd(1, c->media_presentation_duration * pls->fragment_timescale, pls->fragment_duration, AV_ROUND_UP); 1446cabdff1aSopenharmony_ci } 1447cabdff1aSopenharmony_ci 1448cabdff1aSopenharmony_ci return num; 1449cabdff1aSopenharmony_ci} 1450cabdff1aSopenharmony_ci 1451cabdff1aSopenharmony_cistatic void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c) 1452cabdff1aSopenharmony_ci{ 1453cabdff1aSopenharmony_ci if (rep_dest && rep_src ) { 1454cabdff1aSopenharmony_ci free_timelines_list(rep_dest); 1455cabdff1aSopenharmony_ci rep_dest->timelines = rep_src->timelines; 1456cabdff1aSopenharmony_ci rep_dest->n_timelines = rep_src->n_timelines; 1457cabdff1aSopenharmony_ci rep_dest->first_seq_no = rep_src->first_seq_no; 1458cabdff1aSopenharmony_ci rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c); 1459cabdff1aSopenharmony_ci rep_src->timelines = NULL; 1460cabdff1aSopenharmony_ci rep_src->n_timelines = 0; 1461cabdff1aSopenharmony_ci rep_dest->cur_seq_no = rep_src->cur_seq_no; 1462cabdff1aSopenharmony_ci } 1463cabdff1aSopenharmony_ci} 1464cabdff1aSopenharmony_ci 1465cabdff1aSopenharmony_cistatic void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c) 1466cabdff1aSopenharmony_ci{ 1467cabdff1aSopenharmony_ci if (rep_dest && rep_src ) { 1468cabdff1aSopenharmony_ci free_fragment_list(rep_dest); 1469cabdff1aSopenharmony_ci if (rep_src->start_number > (rep_dest->start_number + rep_dest->n_fragments)) 1470cabdff1aSopenharmony_ci rep_dest->cur_seq_no = 0; 1471cabdff1aSopenharmony_ci else 1472cabdff1aSopenharmony_ci rep_dest->cur_seq_no += rep_src->start_number - rep_dest->start_number; 1473cabdff1aSopenharmony_ci rep_dest->fragments = rep_src->fragments; 1474cabdff1aSopenharmony_ci rep_dest->n_fragments = rep_src->n_fragments; 1475cabdff1aSopenharmony_ci rep_dest->parent = rep_src->parent; 1476cabdff1aSopenharmony_ci rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c); 1477cabdff1aSopenharmony_ci rep_src->fragments = NULL; 1478cabdff1aSopenharmony_ci rep_src->n_fragments = 0; 1479cabdff1aSopenharmony_ci } 1480cabdff1aSopenharmony_ci} 1481cabdff1aSopenharmony_ci 1482cabdff1aSopenharmony_ci 1483cabdff1aSopenharmony_cistatic int refresh_manifest(AVFormatContext *s) 1484cabdff1aSopenharmony_ci{ 1485cabdff1aSopenharmony_ci int ret = 0, i; 1486cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 1487cabdff1aSopenharmony_ci // save current context 1488cabdff1aSopenharmony_ci int n_videos = c->n_videos; 1489cabdff1aSopenharmony_ci struct representation **videos = c->videos; 1490cabdff1aSopenharmony_ci int n_audios = c->n_audios; 1491cabdff1aSopenharmony_ci struct representation **audios = c->audios; 1492cabdff1aSopenharmony_ci int n_subtitles = c->n_subtitles; 1493cabdff1aSopenharmony_ci struct representation **subtitles = c->subtitles; 1494cabdff1aSopenharmony_ci char *base_url = c->base_url; 1495cabdff1aSopenharmony_ci 1496cabdff1aSopenharmony_ci c->base_url = NULL; 1497cabdff1aSopenharmony_ci c->n_videos = 0; 1498cabdff1aSopenharmony_ci c->videos = NULL; 1499cabdff1aSopenharmony_ci c->n_audios = 0; 1500cabdff1aSopenharmony_ci c->audios = NULL; 1501cabdff1aSopenharmony_ci c->n_subtitles = 0; 1502cabdff1aSopenharmony_ci c->subtitles = NULL; 1503cabdff1aSopenharmony_ci ret = parse_manifest(s, s->url, NULL); 1504cabdff1aSopenharmony_ci if (ret) 1505cabdff1aSopenharmony_ci goto finish; 1506cabdff1aSopenharmony_ci 1507cabdff1aSopenharmony_ci if (c->n_videos != n_videos) { 1508cabdff1aSopenharmony_ci av_log(c, AV_LOG_ERROR, 1509cabdff1aSopenharmony_ci "new manifest has mismatched no. of video representations, %d -> %d\n", 1510cabdff1aSopenharmony_ci n_videos, c->n_videos); 1511cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1512cabdff1aSopenharmony_ci } 1513cabdff1aSopenharmony_ci if (c->n_audios != n_audios) { 1514cabdff1aSopenharmony_ci av_log(c, AV_LOG_ERROR, 1515cabdff1aSopenharmony_ci "new manifest has mismatched no. of audio representations, %d -> %d\n", 1516cabdff1aSopenharmony_ci n_audios, c->n_audios); 1517cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1518cabdff1aSopenharmony_ci } 1519cabdff1aSopenharmony_ci if (c->n_subtitles != n_subtitles) { 1520cabdff1aSopenharmony_ci av_log(c, AV_LOG_ERROR, 1521cabdff1aSopenharmony_ci "new manifest has mismatched no. of subtitles representations, %d -> %d\n", 1522cabdff1aSopenharmony_ci n_subtitles, c->n_subtitles); 1523cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 1524cabdff1aSopenharmony_ci } 1525cabdff1aSopenharmony_ci 1526cabdff1aSopenharmony_ci for (i = 0; i < n_videos; i++) { 1527cabdff1aSopenharmony_ci struct representation *cur_video = videos[i]; 1528cabdff1aSopenharmony_ci struct representation *ccur_video = c->videos[i]; 1529cabdff1aSopenharmony_ci if (cur_video->timelines) { 1530cabdff1aSopenharmony_ci // calc current time 1531cabdff1aSopenharmony_ci int64_t currentTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale; 1532cabdff1aSopenharmony_ci // update segments 1533cabdff1aSopenharmony_ci ccur_video->cur_seq_no = calc_next_seg_no_from_timelines(ccur_video, currentTime * cur_video->fragment_timescale - 1); 1534cabdff1aSopenharmony_ci if (ccur_video->cur_seq_no >= 0) { 1535cabdff1aSopenharmony_ci move_timelines(ccur_video, cur_video, c); 1536cabdff1aSopenharmony_ci } 1537cabdff1aSopenharmony_ci } 1538cabdff1aSopenharmony_ci if (cur_video->fragments) { 1539cabdff1aSopenharmony_ci move_segments(ccur_video, cur_video, c); 1540cabdff1aSopenharmony_ci } 1541cabdff1aSopenharmony_ci } 1542cabdff1aSopenharmony_ci for (i = 0; i < n_audios; i++) { 1543cabdff1aSopenharmony_ci struct representation *cur_audio = audios[i]; 1544cabdff1aSopenharmony_ci struct representation *ccur_audio = c->audios[i]; 1545cabdff1aSopenharmony_ci if (cur_audio->timelines) { 1546cabdff1aSopenharmony_ci // calc current time 1547cabdff1aSopenharmony_ci int64_t currentTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale; 1548cabdff1aSopenharmony_ci // update segments 1549cabdff1aSopenharmony_ci ccur_audio->cur_seq_no = calc_next_seg_no_from_timelines(ccur_audio, currentTime * cur_audio->fragment_timescale - 1); 1550cabdff1aSopenharmony_ci if (ccur_audio->cur_seq_no >= 0) { 1551cabdff1aSopenharmony_ci move_timelines(ccur_audio, cur_audio, c); 1552cabdff1aSopenharmony_ci } 1553cabdff1aSopenharmony_ci } 1554cabdff1aSopenharmony_ci if (cur_audio->fragments) { 1555cabdff1aSopenharmony_ci move_segments(ccur_audio, cur_audio, c); 1556cabdff1aSopenharmony_ci } 1557cabdff1aSopenharmony_ci } 1558cabdff1aSopenharmony_ci 1559cabdff1aSopenharmony_cifinish: 1560cabdff1aSopenharmony_ci // restore context 1561cabdff1aSopenharmony_ci if (c->base_url) 1562cabdff1aSopenharmony_ci av_free(base_url); 1563cabdff1aSopenharmony_ci else 1564cabdff1aSopenharmony_ci c->base_url = base_url; 1565cabdff1aSopenharmony_ci 1566cabdff1aSopenharmony_ci if (c->subtitles) 1567cabdff1aSopenharmony_ci free_subtitle_list(c); 1568cabdff1aSopenharmony_ci if (c->audios) 1569cabdff1aSopenharmony_ci free_audio_list(c); 1570cabdff1aSopenharmony_ci if (c->videos) 1571cabdff1aSopenharmony_ci free_video_list(c); 1572cabdff1aSopenharmony_ci 1573cabdff1aSopenharmony_ci c->n_subtitles = n_subtitles; 1574cabdff1aSopenharmony_ci c->subtitles = subtitles; 1575cabdff1aSopenharmony_ci c->n_audios = n_audios; 1576cabdff1aSopenharmony_ci c->audios = audios; 1577cabdff1aSopenharmony_ci c->n_videos = n_videos; 1578cabdff1aSopenharmony_ci c->videos = videos; 1579cabdff1aSopenharmony_ci return ret; 1580cabdff1aSopenharmony_ci} 1581cabdff1aSopenharmony_ci 1582cabdff1aSopenharmony_cistatic struct fragment *get_current_fragment(struct representation *pls) 1583cabdff1aSopenharmony_ci{ 1584cabdff1aSopenharmony_ci int64_t min_seq_no = 0; 1585cabdff1aSopenharmony_ci int64_t max_seq_no = 0; 1586cabdff1aSopenharmony_ci struct fragment *seg = NULL; 1587cabdff1aSopenharmony_ci struct fragment *seg_ptr = NULL; 1588cabdff1aSopenharmony_ci DASHContext *c = pls->parent->priv_data; 1589cabdff1aSopenharmony_ci 1590cabdff1aSopenharmony_ci while (( !ff_check_interrupt(c->interrupt_callback)&& pls->n_fragments > 0)) { 1591cabdff1aSopenharmony_ci if (pls->cur_seq_no < pls->n_fragments) { 1592cabdff1aSopenharmony_ci seg_ptr = pls->fragments[pls->cur_seq_no]; 1593cabdff1aSopenharmony_ci seg = av_mallocz(sizeof(struct fragment)); 1594cabdff1aSopenharmony_ci if (!seg) { 1595cabdff1aSopenharmony_ci return NULL; 1596cabdff1aSopenharmony_ci } 1597cabdff1aSopenharmony_ci seg->url = av_strdup(seg_ptr->url); 1598cabdff1aSopenharmony_ci if (!seg->url) { 1599cabdff1aSopenharmony_ci av_free(seg); 1600cabdff1aSopenharmony_ci return NULL; 1601cabdff1aSopenharmony_ci } 1602cabdff1aSopenharmony_ci seg->size = seg_ptr->size; 1603cabdff1aSopenharmony_ci seg->url_offset = seg_ptr->url_offset; 1604cabdff1aSopenharmony_ci return seg; 1605cabdff1aSopenharmony_ci } else if (c->is_live) { 1606cabdff1aSopenharmony_ci refresh_manifest(pls->parent); 1607cabdff1aSopenharmony_ci } else { 1608cabdff1aSopenharmony_ci break; 1609cabdff1aSopenharmony_ci } 1610cabdff1aSopenharmony_ci } 1611cabdff1aSopenharmony_ci if (c->is_live) { 1612cabdff1aSopenharmony_ci min_seq_no = calc_min_seg_no(pls->parent, pls); 1613cabdff1aSopenharmony_ci max_seq_no = calc_max_seg_no(pls, c); 1614cabdff1aSopenharmony_ci 1615cabdff1aSopenharmony_ci if (pls->timelines || pls->fragments) { 1616cabdff1aSopenharmony_ci refresh_manifest(pls->parent); 1617cabdff1aSopenharmony_ci } 1618cabdff1aSopenharmony_ci if (pls->cur_seq_no <= min_seq_no) { 1619cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_VERBOSE, "old fragment: cur[%"PRId64"] min[%"PRId64"] max[%"PRId64"]\n", (int64_t)pls->cur_seq_no, min_seq_no, max_seq_no); 1620cabdff1aSopenharmony_ci pls->cur_seq_no = calc_cur_seg_no(pls->parent, pls); 1621cabdff1aSopenharmony_ci } else if (pls->cur_seq_no > max_seq_no) { 1622cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_VERBOSE, "new fragment: min[%"PRId64"] max[%"PRId64"]\n", min_seq_no, max_seq_no); 1623cabdff1aSopenharmony_ci } 1624cabdff1aSopenharmony_ci seg = av_mallocz(sizeof(struct fragment)); 1625cabdff1aSopenharmony_ci if (!seg) { 1626cabdff1aSopenharmony_ci return NULL; 1627cabdff1aSopenharmony_ci } 1628cabdff1aSopenharmony_ci } else if (pls->cur_seq_no <= pls->last_seq_no) { 1629cabdff1aSopenharmony_ci seg = av_mallocz(sizeof(struct fragment)); 1630cabdff1aSopenharmony_ci if (!seg) { 1631cabdff1aSopenharmony_ci return NULL; 1632cabdff1aSopenharmony_ci } 1633cabdff1aSopenharmony_ci } 1634cabdff1aSopenharmony_ci if (seg) { 1635cabdff1aSopenharmony_ci char *tmpfilename; 1636cabdff1aSopenharmony_ci if (!pls->url_template) { 1637cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_ERROR, "Cannot get fragment, missing template URL\n"); 1638cabdff1aSopenharmony_ci av_free(seg); 1639cabdff1aSopenharmony_ci return NULL; 1640cabdff1aSopenharmony_ci } 1641cabdff1aSopenharmony_ci tmpfilename = av_mallocz(c->max_url_size); 1642cabdff1aSopenharmony_ci if (!tmpfilename) { 1643cabdff1aSopenharmony_ci av_free(seg); 1644cabdff1aSopenharmony_ci return NULL; 1645cabdff1aSopenharmony_ci } 1646cabdff1aSopenharmony_ci ff_dash_fill_tmpl_params(tmpfilename, c->max_url_size, pls->url_template, 0, pls->cur_seq_no, 0, get_segment_start_time_based_on_timeline(pls, pls->cur_seq_no)); 1647cabdff1aSopenharmony_ci seg->url = av_strireplace(pls->url_template, pls->url_template, tmpfilename); 1648cabdff1aSopenharmony_ci if (!seg->url) { 1649cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_WARNING, "Unable to resolve template url '%s', try to use origin template\n", pls->url_template); 1650cabdff1aSopenharmony_ci seg->url = av_strdup(pls->url_template); 1651cabdff1aSopenharmony_ci if (!seg->url) { 1652cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_ERROR, "Cannot resolve template url '%s'\n", pls->url_template); 1653cabdff1aSopenharmony_ci av_free(tmpfilename); 1654cabdff1aSopenharmony_ci av_free(seg); 1655cabdff1aSopenharmony_ci return NULL; 1656cabdff1aSopenharmony_ci } 1657cabdff1aSopenharmony_ci } 1658cabdff1aSopenharmony_ci av_free(tmpfilename); 1659cabdff1aSopenharmony_ci seg->size = -1; 1660cabdff1aSopenharmony_ci } 1661cabdff1aSopenharmony_ci 1662cabdff1aSopenharmony_ci return seg; 1663cabdff1aSopenharmony_ci} 1664cabdff1aSopenharmony_ci 1665cabdff1aSopenharmony_cistatic int read_from_url(struct representation *pls, struct fragment *seg, 1666cabdff1aSopenharmony_ci uint8_t *buf, int buf_size) 1667cabdff1aSopenharmony_ci{ 1668cabdff1aSopenharmony_ci int ret; 1669cabdff1aSopenharmony_ci 1670cabdff1aSopenharmony_ci /* limit read if the fragment was only a part of a file */ 1671cabdff1aSopenharmony_ci if (seg->size >= 0) 1672cabdff1aSopenharmony_ci buf_size = FFMIN(buf_size, pls->cur_seg_size - pls->cur_seg_offset); 1673cabdff1aSopenharmony_ci 1674cabdff1aSopenharmony_ci ret = avio_read(pls->input, buf, buf_size); 1675cabdff1aSopenharmony_ci if (ret > 0) 1676cabdff1aSopenharmony_ci pls->cur_seg_offset += ret; 1677cabdff1aSopenharmony_ci 1678cabdff1aSopenharmony_ci return ret; 1679cabdff1aSopenharmony_ci} 1680cabdff1aSopenharmony_ci 1681cabdff1aSopenharmony_cistatic int open_input(DASHContext *c, struct representation *pls, struct fragment *seg) 1682cabdff1aSopenharmony_ci{ 1683cabdff1aSopenharmony_ci AVDictionary *opts = NULL; 1684cabdff1aSopenharmony_ci char *url = NULL; 1685cabdff1aSopenharmony_ci int ret = 0; 1686cabdff1aSopenharmony_ci 1687cabdff1aSopenharmony_ci url = av_mallocz(c->max_url_size); 1688cabdff1aSopenharmony_ci if (!url) { 1689cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 1690cabdff1aSopenharmony_ci goto cleanup; 1691cabdff1aSopenharmony_ci } 1692cabdff1aSopenharmony_ci 1693cabdff1aSopenharmony_ci if (seg->size >= 0) { 1694cabdff1aSopenharmony_ci /* try to restrict the HTTP request to the part we want 1695cabdff1aSopenharmony_ci * (if this is in fact a HTTP request) */ 1696cabdff1aSopenharmony_ci av_dict_set_int(&opts, "offset", seg->url_offset, 0); 1697cabdff1aSopenharmony_ci av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0); 1698cabdff1aSopenharmony_ci } 1699cabdff1aSopenharmony_ci 1700cabdff1aSopenharmony_ci ff_make_absolute_url(url, c->max_url_size, c->base_url, seg->url); 1701cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_VERBOSE, "DASH request for url '%s', offset %"PRId64"\n", 1702cabdff1aSopenharmony_ci url, seg->url_offset); 1703cabdff1aSopenharmony_ci ret = open_url(pls->parent, &pls->input, url, &c->avio_opts, opts, NULL); 1704cabdff1aSopenharmony_ci 1705cabdff1aSopenharmony_cicleanup: 1706cabdff1aSopenharmony_ci av_free(url); 1707cabdff1aSopenharmony_ci av_dict_free(&opts); 1708cabdff1aSopenharmony_ci pls->cur_seg_offset = 0; 1709cabdff1aSopenharmony_ci pls->cur_seg_size = seg->size; 1710cabdff1aSopenharmony_ci return ret; 1711cabdff1aSopenharmony_ci} 1712cabdff1aSopenharmony_ci 1713cabdff1aSopenharmony_cistatic int update_init_section(struct representation *pls) 1714cabdff1aSopenharmony_ci{ 1715cabdff1aSopenharmony_ci static const int max_init_section_size = 1024 * 1024; 1716cabdff1aSopenharmony_ci DASHContext *c = pls->parent->priv_data; 1717cabdff1aSopenharmony_ci int64_t sec_size; 1718cabdff1aSopenharmony_ci int64_t urlsize; 1719cabdff1aSopenharmony_ci int ret; 1720cabdff1aSopenharmony_ci 1721cabdff1aSopenharmony_ci if (!pls->init_section || pls->init_sec_buf) 1722cabdff1aSopenharmony_ci return 0; 1723cabdff1aSopenharmony_ci 1724cabdff1aSopenharmony_ci ret = open_input(c, pls, pls->init_section); 1725cabdff1aSopenharmony_ci if (ret < 0) { 1726cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_WARNING, 1727cabdff1aSopenharmony_ci "Failed to open an initialization section\n"); 1728cabdff1aSopenharmony_ci return ret; 1729cabdff1aSopenharmony_ci } 1730cabdff1aSopenharmony_ci 1731cabdff1aSopenharmony_ci if (pls->init_section->size >= 0) 1732cabdff1aSopenharmony_ci sec_size = pls->init_section->size; 1733cabdff1aSopenharmony_ci else if ((urlsize = avio_size(pls->input)) >= 0) 1734cabdff1aSopenharmony_ci sec_size = urlsize; 1735cabdff1aSopenharmony_ci else 1736cabdff1aSopenharmony_ci sec_size = max_init_section_size; 1737cabdff1aSopenharmony_ci 1738cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_DEBUG, 1739cabdff1aSopenharmony_ci "Downloading an initialization section of size %"PRId64"\n", 1740cabdff1aSopenharmony_ci sec_size); 1741cabdff1aSopenharmony_ci 1742cabdff1aSopenharmony_ci sec_size = FFMIN(sec_size, max_init_section_size); 1743cabdff1aSopenharmony_ci 1744cabdff1aSopenharmony_ci av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size); 1745cabdff1aSopenharmony_ci 1746cabdff1aSopenharmony_ci ret = read_from_url(pls, pls->init_section, pls->init_sec_buf, 1747cabdff1aSopenharmony_ci pls->init_sec_buf_size); 1748cabdff1aSopenharmony_ci ff_format_io_close(pls->parent, &pls->input); 1749cabdff1aSopenharmony_ci 1750cabdff1aSopenharmony_ci if (ret < 0) 1751cabdff1aSopenharmony_ci return ret; 1752cabdff1aSopenharmony_ci 1753cabdff1aSopenharmony_ci pls->init_sec_data_len = ret; 1754cabdff1aSopenharmony_ci pls->init_sec_buf_read_offset = 0; 1755cabdff1aSopenharmony_ci 1756cabdff1aSopenharmony_ci return 0; 1757cabdff1aSopenharmony_ci} 1758cabdff1aSopenharmony_ci 1759cabdff1aSopenharmony_cistatic int64_t seek_data(void *opaque, int64_t offset, int whence) 1760cabdff1aSopenharmony_ci{ 1761cabdff1aSopenharmony_ci struct representation *v = opaque; 1762cabdff1aSopenharmony_ci if (v->n_fragments && !v->init_sec_data_len) { 1763cabdff1aSopenharmony_ci return avio_seek(v->input, offset, whence); 1764cabdff1aSopenharmony_ci } 1765cabdff1aSopenharmony_ci 1766cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 1767cabdff1aSopenharmony_ci} 1768cabdff1aSopenharmony_ci 1769cabdff1aSopenharmony_cistatic int read_data(void *opaque, uint8_t *buf, int buf_size) 1770cabdff1aSopenharmony_ci{ 1771cabdff1aSopenharmony_ci int ret = 0; 1772cabdff1aSopenharmony_ci struct representation *v = opaque; 1773cabdff1aSopenharmony_ci DASHContext *c = v->parent->priv_data; 1774cabdff1aSopenharmony_ci 1775cabdff1aSopenharmony_cirestart: 1776cabdff1aSopenharmony_ci if (!v->input) { 1777cabdff1aSopenharmony_ci free_fragment(&v->cur_seg); 1778cabdff1aSopenharmony_ci v->cur_seg = get_current_fragment(v); 1779cabdff1aSopenharmony_ci if (!v->cur_seg) { 1780cabdff1aSopenharmony_ci ret = AVERROR_EOF; 1781cabdff1aSopenharmony_ci goto end; 1782cabdff1aSopenharmony_ci } 1783cabdff1aSopenharmony_ci 1784cabdff1aSopenharmony_ci /* load/update Media Initialization Section, if any */ 1785cabdff1aSopenharmony_ci ret = update_init_section(v); 1786cabdff1aSopenharmony_ci if (ret) 1787cabdff1aSopenharmony_ci goto end; 1788cabdff1aSopenharmony_ci 1789cabdff1aSopenharmony_ci ret = open_input(c, v, v->cur_seg); 1790cabdff1aSopenharmony_ci if (ret < 0) { 1791cabdff1aSopenharmony_ci if (ff_check_interrupt(c->interrupt_callback)) { 1792cabdff1aSopenharmony_ci ret = AVERROR_EXIT; 1793cabdff1aSopenharmony_ci goto end; 1794cabdff1aSopenharmony_ci } 1795cabdff1aSopenharmony_ci av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist\n"); 1796cabdff1aSopenharmony_ci v->cur_seq_no++; 1797cabdff1aSopenharmony_ci goto restart; 1798cabdff1aSopenharmony_ci } 1799cabdff1aSopenharmony_ci } 1800cabdff1aSopenharmony_ci 1801cabdff1aSopenharmony_ci if (v->init_sec_buf_read_offset < v->init_sec_data_len) { 1802cabdff1aSopenharmony_ci /* Push init section out first before first actual fragment */ 1803cabdff1aSopenharmony_ci int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size); 1804cabdff1aSopenharmony_ci memcpy(buf, v->init_sec_buf, copy_size); 1805cabdff1aSopenharmony_ci v->init_sec_buf_read_offset += copy_size; 1806cabdff1aSopenharmony_ci ret = copy_size; 1807cabdff1aSopenharmony_ci goto end; 1808cabdff1aSopenharmony_ci } 1809cabdff1aSopenharmony_ci 1810cabdff1aSopenharmony_ci /* check the v->cur_seg, if it is null, get current and double check if the new v->cur_seg*/ 1811cabdff1aSopenharmony_ci if (!v->cur_seg) { 1812cabdff1aSopenharmony_ci v->cur_seg = get_current_fragment(v); 1813cabdff1aSopenharmony_ci } 1814cabdff1aSopenharmony_ci if (!v->cur_seg) { 1815cabdff1aSopenharmony_ci ret = AVERROR_EOF; 1816cabdff1aSopenharmony_ci goto end; 1817cabdff1aSopenharmony_ci } 1818cabdff1aSopenharmony_ci ret = read_from_url(v, v->cur_seg, buf, buf_size); 1819cabdff1aSopenharmony_ci if (ret > 0) 1820cabdff1aSopenharmony_ci goto end; 1821cabdff1aSopenharmony_ci 1822cabdff1aSopenharmony_ci if (c->is_live || v->cur_seq_no < v->last_seq_no) { 1823cabdff1aSopenharmony_ci if (!v->is_restart_needed) 1824cabdff1aSopenharmony_ci v->cur_seq_no++; 1825cabdff1aSopenharmony_ci v->is_restart_needed = 1; 1826cabdff1aSopenharmony_ci } 1827cabdff1aSopenharmony_ci 1828cabdff1aSopenharmony_ciend: 1829cabdff1aSopenharmony_ci return ret; 1830cabdff1aSopenharmony_ci} 1831cabdff1aSopenharmony_ci 1832cabdff1aSopenharmony_cistatic int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url, 1833cabdff1aSopenharmony_ci int flags, AVDictionary **opts) 1834cabdff1aSopenharmony_ci{ 1835cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, 1836cabdff1aSopenharmony_ci "A DASH playlist item '%s' referred to an external file '%s'. " 1837cabdff1aSopenharmony_ci "Opening this file was forbidden for security reasons\n", 1838cabdff1aSopenharmony_ci s->url, url); 1839cabdff1aSopenharmony_ci return AVERROR(EPERM); 1840cabdff1aSopenharmony_ci} 1841cabdff1aSopenharmony_ci 1842cabdff1aSopenharmony_cistatic void close_demux_for_component(struct representation *pls) 1843cabdff1aSopenharmony_ci{ 1844cabdff1aSopenharmony_ci /* note: the internal buffer could have changed */ 1845cabdff1aSopenharmony_ci av_freep(&pls->pb.pub.buffer); 1846cabdff1aSopenharmony_ci memset(&pls->pb, 0x00, sizeof(pls->pb)); 1847cabdff1aSopenharmony_ci pls->ctx->pb = NULL; 1848cabdff1aSopenharmony_ci avformat_close_input(&pls->ctx); 1849cabdff1aSopenharmony_ci} 1850cabdff1aSopenharmony_ci 1851cabdff1aSopenharmony_cistatic int reopen_demux_for_component(AVFormatContext *s, struct representation *pls) 1852cabdff1aSopenharmony_ci{ 1853cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 1854cabdff1aSopenharmony_ci const AVInputFormat *in_fmt = NULL; 1855cabdff1aSopenharmony_ci AVDictionary *in_fmt_opts = NULL; 1856cabdff1aSopenharmony_ci uint8_t *avio_ctx_buffer = NULL; 1857cabdff1aSopenharmony_ci int ret = 0, i; 1858cabdff1aSopenharmony_ci 1859cabdff1aSopenharmony_ci if (pls->ctx) { 1860cabdff1aSopenharmony_ci close_demux_for_component(pls); 1861cabdff1aSopenharmony_ci } 1862cabdff1aSopenharmony_ci 1863cabdff1aSopenharmony_ci if (ff_check_interrupt(&s->interrupt_callback)) { 1864cabdff1aSopenharmony_ci ret = AVERROR_EXIT; 1865cabdff1aSopenharmony_ci goto fail; 1866cabdff1aSopenharmony_ci } 1867cabdff1aSopenharmony_ci 1868cabdff1aSopenharmony_ci if (!(pls->ctx = avformat_alloc_context())) { 1869cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 1870cabdff1aSopenharmony_ci goto fail; 1871cabdff1aSopenharmony_ci } 1872cabdff1aSopenharmony_ci 1873cabdff1aSopenharmony_ci avio_ctx_buffer = av_malloc(INITIAL_BUFFER_SIZE); 1874cabdff1aSopenharmony_ci if (!avio_ctx_buffer ) { 1875cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 1876cabdff1aSopenharmony_ci avformat_free_context(pls->ctx); 1877cabdff1aSopenharmony_ci pls->ctx = NULL; 1878cabdff1aSopenharmony_ci goto fail; 1879cabdff1aSopenharmony_ci } 1880cabdff1aSopenharmony_ci ffio_init_context(&pls->pb, avio_ctx_buffer, INITIAL_BUFFER_SIZE, 0, 1881cabdff1aSopenharmony_ci pls, read_data, NULL, c->is_live ? NULL : seek_data); 1882cabdff1aSopenharmony_ci pls->pb.pub.seekable = 0; 1883cabdff1aSopenharmony_ci 1884cabdff1aSopenharmony_ci if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0) 1885cabdff1aSopenharmony_ci goto fail; 1886cabdff1aSopenharmony_ci 1887cabdff1aSopenharmony_ci pls->ctx->flags = AVFMT_FLAG_CUSTOM_IO; 1888cabdff1aSopenharmony_ci pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4; 1889cabdff1aSopenharmony_ci pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE; 1890cabdff1aSopenharmony_ci pls->ctx->interrupt_callback = s->interrupt_callback; 1891cabdff1aSopenharmony_ci ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, "", NULL, 0, 0); 1892cabdff1aSopenharmony_ci if (ret < 0) { 1893cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Error when loading first fragment of playlist\n"); 1894cabdff1aSopenharmony_ci avformat_free_context(pls->ctx); 1895cabdff1aSopenharmony_ci pls->ctx = NULL; 1896cabdff1aSopenharmony_ci goto fail; 1897cabdff1aSopenharmony_ci } 1898cabdff1aSopenharmony_ci 1899cabdff1aSopenharmony_ci pls->ctx->pb = &pls->pb.pub; 1900cabdff1aSopenharmony_ci pls->ctx->io_open = nested_io_open; 1901cabdff1aSopenharmony_ci 1902cabdff1aSopenharmony_ci if (c->cenc_decryption_key) 1903cabdff1aSopenharmony_ci av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0); 1904cabdff1aSopenharmony_ci 1905cabdff1aSopenharmony_ci // provide additional information from mpd if available 1906cabdff1aSopenharmony_ci ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url 1907cabdff1aSopenharmony_ci av_dict_free(&in_fmt_opts); 1908cabdff1aSopenharmony_ci if (ret < 0) 1909cabdff1aSopenharmony_ci goto fail; 1910cabdff1aSopenharmony_ci if (pls->n_fragments) { 1911cabdff1aSopenharmony_ci#if FF_API_R_FRAME_RATE 1912cabdff1aSopenharmony_ci if (pls->framerate.den) { 1913cabdff1aSopenharmony_ci for (i = 0; i < pls->ctx->nb_streams; i++) 1914cabdff1aSopenharmony_ci pls->ctx->streams[i]->r_frame_rate = pls->framerate; 1915cabdff1aSopenharmony_ci } 1916cabdff1aSopenharmony_ci#endif 1917cabdff1aSopenharmony_ci ret = avformat_find_stream_info(pls->ctx, NULL); 1918cabdff1aSopenharmony_ci if (ret < 0) 1919cabdff1aSopenharmony_ci goto fail; 1920cabdff1aSopenharmony_ci } 1921cabdff1aSopenharmony_ci 1922cabdff1aSopenharmony_cifail: 1923cabdff1aSopenharmony_ci return ret; 1924cabdff1aSopenharmony_ci} 1925cabdff1aSopenharmony_ci 1926cabdff1aSopenharmony_cistatic int open_demux_for_component(AVFormatContext *s, struct representation *pls) 1927cabdff1aSopenharmony_ci{ 1928cabdff1aSopenharmony_ci int ret = 0; 1929cabdff1aSopenharmony_ci int i; 1930cabdff1aSopenharmony_ci 1931cabdff1aSopenharmony_ci pls->parent = s; 1932cabdff1aSopenharmony_ci pls->cur_seq_no = calc_cur_seg_no(s, pls); 1933cabdff1aSopenharmony_ci 1934cabdff1aSopenharmony_ci if (!pls->last_seq_no) { 1935cabdff1aSopenharmony_ci pls->last_seq_no = calc_max_seg_no(pls, s->priv_data); 1936cabdff1aSopenharmony_ci } 1937cabdff1aSopenharmony_ci 1938cabdff1aSopenharmony_ci ret = reopen_demux_for_component(s, pls); 1939cabdff1aSopenharmony_ci if (ret < 0) { 1940cabdff1aSopenharmony_ci goto fail; 1941cabdff1aSopenharmony_ci } 1942cabdff1aSopenharmony_ci for (i = 0; i < pls->ctx->nb_streams; i++) { 1943cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 1944cabdff1aSopenharmony_ci AVStream *ist = pls->ctx->streams[i]; 1945cabdff1aSopenharmony_ci if (!st) { 1946cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 1947cabdff1aSopenharmony_ci goto fail; 1948cabdff1aSopenharmony_ci } 1949cabdff1aSopenharmony_ci st->id = i; 1950cabdff1aSopenharmony_ci avcodec_parameters_copy(st->codecpar, ist->codecpar); 1951cabdff1aSopenharmony_ci avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); 1952cabdff1aSopenharmony_ci 1953cabdff1aSopenharmony_ci // copy disposition 1954cabdff1aSopenharmony_ci st->disposition = ist->disposition; 1955cabdff1aSopenharmony_ci 1956cabdff1aSopenharmony_ci // copy side data 1957cabdff1aSopenharmony_ci for (int i = 0; i < ist->nb_side_data; i++) { 1958cabdff1aSopenharmony_ci const AVPacketSideData *sd_src = &ist->side_data[i]; 1959cabdff1aSopenharmony_ci uint8_t *dst_data; 1960cabdff1aSopenharmony_ci 1961cabdff1aSopenharmony_ci dst_data = av_stream_new_side_data(st, sd_src->type, sd_src->size); 1962cabdff1aSopenharmony_ci if (!dst_data) 1963cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1964cabdff1aSopenharmony_ci memcpy(dst_data, sd_src->data, sd_src->size); 1965cabdff1aSopenharmony_ci } 1966cabdff1aSopenharmony_ci } 1967cabdff1aSopenharmony_ci 1968cabdff1aSopenharmony_ci return 0; 1969cabdff1aSopenharmony_cifail: 1970cabdff1aSopenharmony_ci return ret; 1971cabdff1aSopenharmony_ci} 1972cabdff1aSopenharmony_ci 1973cabdff1aSopenharmony_cistatic int is_common_init_section_exist(struct representation **pls, int n_pls) 1974cabdff1aSopenharmony_ci{ 1975cabdff1aSopenharmony_ci struct fragment *first_init_section = pls[0]->init_section; 1976cabdff1aSopenharmony_ci char *url =NULL; 1977cabdff1aSopenharmony_ci int64_t url_offset = -1; 1978cabdff1aSopenharmony_ci int64_t size = -1; 1979cabdff1aSopenharmony_ci int i = 0; 1980cabdff1aSopenharmony_ci 1981cabdff1aSopenharmony_ci if (first_init_section == NULL || n_pls == 0) 1982cabdff1aSopenharmony_ci return 0; 1983cabdff1aSopenharmony_ci 1984cabdff1aSopenharmony_ci url = first_init_section->url; 1985cabdff1aSopenharmony_ci url_offset = first_init_section->url_offset; 1986cabdff1aSopenharmony_ci size = pls[0]->init_section->size; 1987cabdff1aSopenharmony_ci for (i=0;i<n_pls;i++) { 1988cabdff1aSopenharmony_ci if (!pls[i]->init_section) 1989cabdff1aSopenharmony_ci continue; 1990cabdff1aSopenharmony_ci 1991cabdff1aSopenharmony_ci if (av_strcasecmp(pls[i]->init_section->url, url) || 1992cabdff1aSopenharmony_ci pls[i]->init_section->url_offset != url_offset || 1993cabdff1aSopenharmony_ci pls[i]->init_section->size != size) { 1994cabdff1aSopenharmony_ci return 0; 1995cabdff1aSopenharmony_ci } 1996cabdff1aSopenharmony_ci } 1997cabdff1aSopenharmony_ci return 1; 1998cabdff1aSopenharmony_ci} 1999cabdff1aSopenharmony_ci 2000cabdff1aSopenharmony_cistatic int copy_init_section(struct representation *rep_dest, struct representation *rep_src) 2001cabdff1aSopenharmony_ci{ 2002cabdff1aSopenharmony_ci rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size); 2003cabdff1aSopenharmony_ci if (!rep_dest->init_sec_buf) { 2004cabdff1aSopenharmony_ci av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n"); 2005cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2006cabdff1aSopenharmony_ci } 2007cabdff1aSopenharmony_ci memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len); 2008cabdff1aSopenharmony_ci rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size; 2009cabdff1aSopenharmony_ci rep_dest->init_sec_data_len = rep_src->init_sec_data_len; 2010cabdff1aSopenharmony_ci rep_dest->cur_timestamp = rep_src->cur_timestamp; 2011cabdff1aSopenharmony_ci 2012cabdff1aSopenharmony_ci return 0; 2013cabdff1aSopenharmony_ci} 2014cabdff1aSopenharmony_ci 2015cabdff1aSopenharmony_cistatic void move_metadata(AVStream *st, const char *key, char **value) 2016cabdff1aSopenharmony_ci{ 2017cabdff1aSopenharmony_ci if (*value) { 2018cabdff1aSopenharmony_ci av_dict_set(&st->metadata, key, *value, AV_DICT_DONT_STRDUP_VAL); 2019cabdff1aSopenharmony_ci *value = NULL; 2020cabdff1aSopenharmony_ci } 2021cabdff1aSopenharmony_ci} 2022cabdff1aSopenharmony_ci 2023cabdff1aSopenharmony_cistatic int dash_read_header(AVFormatContext *s) 2024cabdff1aSopenharmony_ci{ 2025cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 2026cabdff1aSopenharmony_ci struct representation *rep; 2027cabdff1aSopenharmony_ci AVProgram *program; 2028cabdff1aSopenharmony_ci int ret = 0; 2029cabdff1aSopenharmony_ci int stream_index = 0; 2030cabdff1aSopenharmony_ci int i; 2031cabdff1aSopenharmony_ci 2032cabdff1aSopenharmony_ci c->interrupt_callback = &s->interrupt_callback; 2033cabdff1aSopenharmony_ci 2034cabdff1aSopenharmony_ci if ((ret = ffio_copy_url_options(s->pb, &c->avio_opts)) < 0) 2035cabdff1aSopenharmony_ci return ret; 2036cabdff1aSopenharmony_ci 2037cabdff1aSopenharmony_ci if ((ret = parse_manifest(s, s->url, s->pb)) < 0) 2038cabdff1aSopenharmony_ci return ret; 2039cabdff1aSopenharmony_ci 2040cabdff1aSopenharmony_ci /* If this isn't a live stream, fill the total duration of the 2041cabdff1aSopenharmony_ci * stream. */ 2042cabdff1aSopenharmony_ci if (!c->is_live) { 2043cabdff1aSopenharmony_ci s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE; 2044cabdff1aSopenharmony_ci } else { 2045cabdff1aSopenharmony_ci av_dict_set(&c->avio_opts, "seekable", "0", 0); 2046cabdff1aSopenharmony_ci } 2047cabdff1aSopenharmony_ci 2048cabdff1aSopenharmony_ci if(c->n_videos) 2049cabdff1aSopenharmony_ci c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos); 2050cabdff1aSopenharmony_ci 2051cabdff1aSopenharmony_ci /* Open the demuxer for video and audio components if available */ 2052cabdff1aSopenharmony_ci for (i = 0; i < c->n_videos; i++) { 2053cabdff1aSopenharmony_ci rep = c->videos[i]; 2054cabdff1aSopenharmony_ci if (i > 0 && c->is_init_section_common_video) { 2055cabdff1aSopenharmony_ci ret = copy_init_section(rep, c->videos[0]); 2056cabdff1aSopenharmony_ci if (ret < 0) 2057cabdff1aSopenharmony_ci return ret; 2058cabdff1aSopenharmony_ci } 2059cabdff1aSopenharmony_ci ret = open_demux_for_component(s, rep); 2060cabdff1aSopenharmony_ci 2061cabdff1aSopenharmony_ci if (ret) 2062cabdff1aSopenharmony_ci return ret; 2063cabdff1aSopenharmony_ci rep->stream_index = stream_index; 2064cabdff1aSopenharmony_ci ++stream_index; 2065cabdff1aSopenharmony_ci } 2066cabdff1aSopenharmony_ci 2067cabdff1aSopenharmony_ci if(c->n_audios) 2068cabdff1aSopenharmony_ci c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios); 2069cabdff1aSopenharmony_ci 2070cabdff1aSopenharmony_ci for (i = 0; i < c->n_audios; i++) { 2071cabdff1aSopenharmony_ci rep = c->audios[i]; 2072cabdff1aSopenharmony_ci if (i > 0 && c->is_init_section_common_audio) { 2073cabdff1aSopenharmony_ci ret = copy_init_section(rep, c->audios[0]); 2074cabdff1aSopenharmony_ci if (ret < 0) 2075cabdff1aSopenharmony_ci return ret; 2076cabdff1aSopenharmony_ci } 2077cabdff1aSopenharmony_ci ret = open_demux_for_component(s, rep); 2078cabdff1aSopenharmony_ci 2079cabdff1aSopenharmony_ci if (ret) 2080cabdff1aSopenharmony_ci return ret; 2081cabdff1aSopenharmony_ci rep->stream_index = stream_index; 2082cabdff1aSopenharmony_ci ++stream_index; 2083cabdff1aSopenharmony_ci } 2084cabdff1aSopenharmony_ci 2085cabdff1aSopenharmony_ci if (c->n_subtitles) 2086cabdff1aSopenharmony_ci c->is_init_section_common_subtitle = is_common_init_section_exist(c->subtitles, c->n_subtitles); 2087cabdff1aSopenharmony_ci 2088cabdff1aSopenharmony_ci for (i = 0; i < c->n_subtitles; i++) { 2089cabdff1aSopenharmony_ci rep = c->subtitles[i]; 2090cabdff1aSopenharmony_ci if (i > 0 && c->is_init_section_common_subtitle) { 2091cabdff1aSopenharmony_ci ret = copy_init_section(rep, c->subtitles[0]); 2092cabdff1aSopenharmony_ci if (ret < 0) 2093cabdff1aSopenharmony_ci return ret; 2094cabdff1aSopenharmony_ci } 2095cabdff1aSopenharmony_ci ret = open_demux_for_component(s, rep); 2096cabdff1aSopenharmony_ci 2097cabdff1aSopenharmony_ci if (ret) 2098cabdff1aSopenharmony_ci return ret; 2099cabdff1aSopenharmony_ci rep->stream_index = stream_index; 2100cabdff1aSopenharmony_ci ++stream_index; 2101cabdff1aSopenharmony_ci } 2102cabdff1aSopenharmony_ci 2103cabdff1aSopenharmony_ci if (!stream_index) 2104cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 2105cabdff1aSopenharmony_ci 2106cabdff1aSopenharmony_ci /* Create a program */ 2107cabdff1aSopenharmony_ci program = av_new_program(s, 0); 2108cabdff1aSopenharmony_ci if (!program) 2109cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 2110cabdff1aSopenharmony_ci 2111cabdff1aSopenharmony_ci for (i = 0; i < c->n_videos; i++) { 2112cabdff1aSopenharmony_ci rep = c->videos[i]; 2113cabdff1aSopenharmony_ci av_program_add_stream_index(s, 0, rep->stream_index); 2114cabdff1aSopenharmony_ci rep->assoc_stream = s->streams[rep->stream_index]; 2115cabdff1aSopenharmony_ci if (rep->bandwidth > 0) 2116cabdff1aSopenharmony_ci av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0); 2117cabdff1aSopenharmony_ci move_metadata(rep->assoc_stream, "id", &rep->id); 2118cabdff1aSopenharmony_ci } 2119cabdff1aSopenharmony_ci for (i = 0; i < c->n_audios; i++) { 2120cabdff1aSopenharmony_ci rep = c->audios[i]; 2121cabdff1aSopenharmony_ci av_program_add_stream_index(s, 0, rep->stream_index); 2122cabdff1aSopenharmony_ci rep->assoc_stream = s->streams[rep->stream_index]; 2123cabdff1aSopenharmony_ci if (rep->bandwidth > 0) 2124cabdff1aSopenharmony_ci av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0); 2125cabdff1aSopenharmony_ci move_metadata(rep->assoc_stream, "id", &rep->id); 2126cabdff1aSopenharmony_ci move_metadata(rep->assoc_stream, "language", &rep->lang); 2127cabdff1aSopenharmony_ci } 2128cabdff1aSopenharmony_ci for (i = 0; i < c->n_subtitles; i++) { 2129cabdff1aSopenharmony_ci rep = c->subtitles[i]; 2130cabdff1aSopenharmony_ci av_program_add_stream_index(s, 0, rep->stream_index); 2131cabdff1aSopenharmony_ci rep->assoc_stream = s->streams[rep->stream_index]; 2132cabdff1aSopenharmony_ci move_metadata(rep->assoc_stream, "id", &rep->id); 2133cabdff1aSopenharmony_ci move_metadata(rep->assoc_stream, "language", &rep->lang); 2134cabdff1aSopenharmony_ci } 2135cabdff1aSopenharmony_ci 2136cabdff1aSopenharmony_ci return 0; 2137cabdff1aSopenharmony_ci} 2138cabdff1aSopenharmony_ci 2139cabdff1aSopenharmony_cistatic void recheck_discard_flags(AVFormatContext *s, struct representation **p, int n) 2140cabdff1aSopenharmony_ci{ 2141cabdff1aSopenharmony_ci int i, j; 2142cabdff1aSopenharmony_ci 2143cabdff1aSopenharmony_ci for (i = 0; i < n; i++) { 2144cabdff1aSopenharmony_ci struct representation *pls = p[i]; 2145cabdff1aSopenharmony_ci int needed = !pls->assoc_stream || pls->assoc_stream->discard < AVDISCARD_ALL; 2146cabdff1aSopenharmony_ci 2147cabdff1aSopenharmony_ci if (needed && !pls->ctx) { 2148cabdff1aSopenharmony_ci pls->cur_seg_offset = 0; 2149cabdff1aSopenharmony_ci pls->init_sec_buf_read_offset = 0; 2150cabdff1aSopenharmony_ci /* Catch up */ 2151cabdff1aSopenharmony_ci for (j = 0; j < n; j++) { 2152cabdff1aSopenharmony_ci pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no); 2153cabdff1aSopenharmony_ci } 2154cabdff1aSopenharmony_ci reopen_demux_for_component(s, pls); 2155cabdff1aSopenharmony_ci av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index); 2156cabdff1aSopenharmony_ci } else if (!needed && pls->ctx) { 2157cabdff1aSopenharmony_ci close_demux_for_component(pls); 2158cabdff1aSopenharmony_ci ff_format_io_close(pls->parent, &pls->input); 2159cabdff1aSopenharmony_ci av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index); 2160cabdff1aSopenharmony_ci } 2161cabdff1aSopenharmony_ci } 2162cabdff1aSopenharmony_ci} 2163cabdff1aSopenharmony_ci 2164cabdff1aSopenharmony_cistatic int dash_read_packet(AVFormatContext *s, AVPacket *pkt) 2165cabdff1aSopenharmony_ci{ 2166cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 2167cabdff1aSopenharmony_ci int ret = 0, i; 2168cabdff1aSopenharmony_ci int64_t mints = 0; 2169cabdff1aSopenharmony_ci struct representation *cur = NULL; 2170cabdff1aSopenharmony_ci struct representation *rep = NULL; 2171cabdff1aSopenharmony_ci 2172cabdff1aSopenharmony_ci recheck_discard_flags(s, c->videos, c->n_videos); 2173cabdff1aSopenharmony_ci recheck_discard_flags(s, c->audios, c->n_audios); 2174cabdff1aSopenharmony_ci recheck_discard_flags(s, c->subtitles, c->n_subtitles); 2175cabdff1aSopenharmony_ci 2176cabdff1aSopenharmony_ci for (i = 0; i < c->n_videos; i++) { 2177cabdff1aSopenharmony_ci rep = c->videos[i]; 2178cabdff1aSopenharmony_ci if (!rep->ctx) 2179cabdff1aSopenharmony_ci continue; 2180cabdff1aSopenharmony_ci if (!cur || rep->cur_timestamp < mints) { 2181cabdff1aSopenharmony_ci cur = rep; 2182cabdff1aSopenharmony_ci mints = rep->cur_timestamp; 2183cabdff1aSopenharmony_ci } 2184cabdff1aSopenharmony_ci } 2185cabdff1aSopenharmony_ci for (i = 0; i < c->n_audios; i++) { 2186cabdff1aSopenharmony_ci rep = c->audios[i]; 2187cabdff1aSopenharmony_ci if (!rep->ctx) 2188cabdff1aSopenharmony_ci continue; 2189cabdff1aSopenharmony_ci if (!cur || rep->cur_timestamp < mints) { 2190cabdff1aSopenharmony_ci cur = rep; 2191cabdff1aSopenharmony_ci mints = rep->cur_timestamp; 2192cabdff1aSopenharmony_ci } 2193cabdff1aSopenharmony_ci } 2194cabdff1aSopenharmony_ci 2195cabdff1aSopenharmony_ci for (i = 0; i < c->n_subtitles; i++) { 2196cabdff1aSopenharmony_ci rep = c->subtitles[i]; 2197cabdff1aSopenharmony_ci if (!rep->ctx) 2198cabdff1aSopenharmony_ci continue; 2199cabdff1aSopenharmony_ci if (!cur || rep->cur_timestamp < mints) { 2200cabdff1aSopenharmony_ci cur = rep; 2201cabdff1aSopenharmony_ci mints = rep->cur_timestamp; 2202cabdff1aSopenharmony_ci } 2203cabdff1aSopenharmony_ci } 2204cabdff1aSopenharmony_ci 2205cabdff1aSopenharmony_ci if (!cur) { 2206cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 2207cabdff1aSopenharmony_ci } 2208cabdff1aSopenharmony_ci while (!ff_check_interrupt(c->interrupt_callback) && !ret) { 2209cabdff1aSopenharmony_ci ret = av_read_frame(cur->ctx, pkt); 2210cabdff1aSopenharmony_ci if (ret >= 0) { 2211cabdff1aSopenharmony_ci /* If we got a packet, return it */ 2212cabdff1aSopenharmony_ci cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den); 2213cabdff1aSopenharmony_ci pkt->stream_index = cur->stream_index; 2214cabdff1aSopenharmony_ci return 0; 2215cabdff1aSopenharmony_ci } 2216cabdff1aSopenharmony_ci if (cur->is_restart_needed) { 2217cabdff1aSopenharmony_ci cur->cur_seg_offset = 0; 2218cabdff1aSopenharmony_ci cur->init_sec_buf_read_offset = 0; 2219cabdff1aSopenharmony_ci ff_format_io_close(cur->parent, &cur->input); 2220cabdff1aSopenharmony_ci ret = reopen_demux_for_component(s, cur); 2221cabdff1aSopenharmony_ci cur->is_restart_needed = 0; 2222cabdff1aSopenharmony_ci } 2223cabdff1aSopenharmony_ci } 2224cabdff1aSopenharmony_ci return AVERROR_EOF; 2225cabdff1aSopenharmony_ci} 2226cabdff1aSopenharmony_ci 2227cabdff1aSopenharmony_cistatic int dash_close(AVFormatContext *s) 2228cabdff1aSopenharmony_ci{ 2229cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 2230cabdff1aSopenharmony_ci free_audio_list(c); 2231cabdff1aSopenharmony_ci free_video_list(c); 2232cabdff1aSopenharmony_ci free_subtitle_list(c); 2233cabdff1aSopenharmony_ci av_dict_free(&c->avio_opts); 2234cabdff1aSopenharmony_ci av_freep(&c->base_url); 2235cabdff1aSopenharmony_ci return 0; 2236cabdff1aSopenharmony_ci} 2237cabdff1aSopenharmony_ci 2238cabdff1aSopenharmony_cistatic int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run) 2239cabdff1aSopenharmony_ci{ 2240cabdff1aSopenharmony_ci int ret = 0; 2241cabdff1aSopenharmony_ci int i = 0; 2242cabdff1aSopenharmony_ci int j = 0; 2243cabdff1aSopenharmony_ci int64_t duration = 0; 2244cabdff1aSopenharmony_ci 2245cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms] %s\n", 2246cabdff1aSopenharmony_ci seek_pos_msec, dry_run ? " (dry)" : ""); 2247cabdff1aSopenharmony_ci 2248cabdff1aSopenharmony_ci // single fragment mode 2249cabdff1aSopenharmony_ci if (pls->n_fragments == 1) { 2250cabdff1aSopenharmony_ci pls->cur_timestamp = 0; 2251cabdff1aSopenharmony_ci pls->cur_seg_offset = 0; 2252cabdff1aSopenharmony_ci if (dry_run) 2253cabdff1aSopenharmony_ci return 0; 2254cabdff1aSopenharmony_ci ff_read_frame_flush(pls->ctx); 2255cabdff1aSopenharmony_ci return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags); 2256cabdff1aSopenharmony_ci } 2257cabdff1aSopenharmony_ci 2258cabdff1aSopenharmony_ci ff_format_io_close(pls->parent, &pls->input); 2259cabdff1aSopenharmony_ci 2260cabdff1aSopenharmony_ci // find the nearest fragment 2261cabdff1aSopenharmony_ci if (pls->n_timelines > 0 && pls->fragment_timescale > 0) { 2262cabdff1aSopenharmony_ci int64_t num = pls->first_seq_no; 2263cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline start n_timelines[%d] " 2264cabdff1aSopenharmony_ci "last_seq_no[%"PRId64"].\n", 2265cabdff1aSopenharmony_ci (int)pls->n_timelines, (int64_t)pls->last_seq_no); 2266cabdff1aSopenharmony_ci for (i = 0; i < pls->n_timelines; i++) { 2267cabdff1aSopenharmony_ci if (pls->timelines[i]->starttime > 0) { 2268cabdff1aSopenharmony_ci duration = pls->timelines[i]->starttime; 2269cabdff1aSopenharmony_ci } 2270cabdff1aSopenharmony_ci duration += pls->timelines[i]->duration; 2271cabdff1aSopenharmony_ci if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) { 2272cabdff1aSopenharmony_ci goto set_seq_num; 2273cabdff1aSopenharmony_ci } 2274cabdff1aSopenharmony_ci for (j = 0; j < pls->timelines[i]->repeat; j++) { 2275cabdff1aSopenharmony_ci duration += pls->timelines[i]->duration; 2276cabdff1aSopenharmony_ci num++; 2277cabdff1aSopenharmony_ci if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) { 2278cabdff1aSopenharmony_ci goto set_seq_num; 2279cabdff1aSopenharmony_ci } 2280cabdff1aSopenharmony_ci } 2281cabdff1aSopenharmony_ci num++; 2282cabdff1aSopenharmony_ci } 2283cabdff1aSopenharmony_ci 2284cabdff1aSopenharmony_ciset_seq_num: 2285cabdff1aSopenharmony_ci pls->cur_seq_no = num > pls->last_seq_no ? pls->last_seq_no : num; 2286cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline end cur_seq_no[%"PRId64"].\n", 2287cabdff1aSopenharmony_ci (int64_t)pls->cur_seq_no); 2288cabdff1aSopenharmony_ci } else if (pls->fragment_duration > 0) { 2289cabdff1aSopenharmony_ci pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000; 2290cabdff1aSopenharmony_ci } else { 2291cabdff1aSopenharmony_ci av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n"); 2292cabdff1aSopenharmony_ci pls->cur_seq_no = pls->first_seq_no; 2293cabdff1aSopenharmony_ci } 2294cabdff1aSopenharmony_ci pls->cur_timestamp = 0; 2295cabdff1aSopenharmony_ci pls->cur_seg_offset = 0; 2296cabdff1aSopenharmony_ci pls->init_sec_buf_read_offset = 0; 2297cabdff1aSopenharmony_ci ret = dry_run ? 0 : reopen_demux_for_component(s, pls); 2298cabdff1aSopenharmony_ci 2299cabdff1aSopenharmony_ci return ret; 2300cabdff1aSopenharmony_ci} 2301cabdff1aSopenharmony_ci 2302cabdff1aSopenharmony_cistatic int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) 2303cabdff1aSopenharmony_ci{ 2304cabdff1aSopenharmony_ci int ret = 0, i; 2305cabdff1aSopenharmony_ci DASHContext *c = s->priv_data; 2306cabdff1aSopenharmony_ci int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000, 2307cabdff1aSopenharmony_ci s->streams[stream_index]->time_base.den, 2308cabdff1aSopenharmony_ci flags & AVSEEK_FLAG_BACKWARD ? 2309cabdff1aSopenharmony_ci AV_ROUND_DOWN : AV_ROUND_UP); 2310cabdff1aSopenharmony_ci if ((flags & AVSEEK_FLAG_BYTE) || c->is_live) 2311cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 2312cabdff1aSopenharmony_ci 2313cabdff1aSopenharmony_ci /* Seek in discarded streams with dry_run=1 to avoid reopening them */ 2314cabdff1aSopenharmony_ci for (i = 0; i < c->n_videos; i++) { 2315cabdff1aSopenharmony_ci if (!ret) 2316cabdff1aSopenharmony_ci ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx); 2317cabdff1aSopenharmony_ci } 2318cabdff1aSopenharmony_ci for (i = 0; i < c->n_audios; i++) { 2319cabdff1aSopenharmony_ci if (!ret) 2320cabdff1aSopenharmony_ci ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx); 2321cabdff1aSopenharmony_ci } 2322cabdff1aSopenharmony_ci for (i = 0; i < c->n_subtitles; i++) { 2323cabdff1aSopenharmony_ci if (!ret) 2324cabdff1aSopenharmony_ci ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx); 2325cabdff1aSopenharmony_ci } 2326cabdff1aSopenharmony_ci 2327cabdff1aSopenharmony_ci return ret; 2328cabdff1aSopenharmony_ci} 2329cabdff1aSopenharmony_ci 2330cabdff1aSopenharmony_cistatic int dash_probe(const AVProbeData *p) 2331cabdff1aSopenharmony_ci{ 2332cabdff1aSopenharmony_ci if (!av_stristr(p->buf, "<MPD")) 2333cabdff1aSopenharmony_ci return 0; 2334cabdff1aSopenharmony_ci 2335cabdff1aSopenharmony_ci if (av_stristr(p->buf, "dash:profile:isoff-on-demand:2011") || 2336cabdff1aSopenharmony_ci av_stristr(p->buf, "dash:profile:isoff-live:2011") || 2337cabdff1aSopenharmony_ci av_stristr(p->buf, "dash:profile:isoff-live:2012") || 2338cabdff1aSopenharmony_ci av_stristr(p->buf, "dash:profile:isoff-main:2011") || 2339cabdff1aSopenharmony_ci av_stristr(p->buf, "3GPP:PSS:profile:DASH1")) { 2340cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 2341cabdff1aSopenharmony_ci } 2342cabdff1aSopenharmony_ci if (av_stristr(p->buf, "dash:profile")) { 2343cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 2344cabdff1aSopenharmony_ci } 2345cabdff1aSopenharmony_ci 2346cabdff1aSopenharmony_ci return 0; 2347cabdff1aSopenharmony_ci} 2348cabdff1aSopenharmony_ci 2349cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(DASHContext, x) 2350cabdff1aSopenharmony_ci#define FLAGS AV_OPT_FLAG_DECODING_PARAM 2351cabdff1aSopenharmony_cistatic const AVOption dash_options[] = { 2352cabdff1aSopenharmony_ci {"allowed_extensions", "List of file extensions that dash is allowed to access", 2353cabdff1aSopenharmony_ci OFFSET(allowed_extensions), AV_OPT_TYPE_STRING, 2354cabdff1aSopenharmony_ci {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"}, 2355cabdff1aSopenharmony_ci INT_MIN, INT_MAX, FLAGS}, 2356cabdff1aSopenharmony_ci { "cenc_decryption_key", "Media decryption key (hex)", OFFSET(cenc_decryption_key), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS }, 2357cabdff1aSopenharmony_ci {NULL} 2358cabdff1aSopenharmony_ci}; 2359cabdff1aSopenharmony_ci 2360cabdff1aSopenharmony_cistatic const AVClass dash_class = { 2361cabdff1aSopenharmony_ci .class_name = "dash", 2362cabdff1aSopenharmony_ci .item_name = av_default_item_name, 2363cabdff1aSopenharmony_ci .option = dash_options, 2364cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 2365cabdff1aSopenharmony_ci}; 2366cabdff1aSopenharmony_ci 2367cabdff1aSopenharmony_ciconst AVInputFormat ff_dash_demuxer = { 2368cabdff1aSopenharmony_ci .name = "dash", 2369cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Dynamic Adaptive Streaming over HTTP"), 2370cabdff1aSopenharmony_ci .priv_class = &dash_class, 2371cabdff1aSopenharmony_ci .priv_data_size = sizeof(DASHContext), 2372cabdff1aSopenharmony_ci .flags_internal = FF_FMT_INIT_CLEANUP, 2373cabdff1aSopenharmony_ci .read_probe = dash_probe, 2374cabdff1aSopenharmony_ci .read_header = dash_read_header, 2375cabdff1aSopenharmony_ci .read_packet = dash_read_packet, 2376cabdff1aSopenharmony_ci .read_close = dash_close, 2377cabdff1aSopenharmony_ci .read_seek = dash_read_seek, 2378cabdff1aSopenharmony_ci .flags = AVFMT_NO_BYTE_SEEK, 2379cabdff1aSopenharmony_ci}; 2380