]> git.sesse.net Git - ffmpeg/blob - libavformat/dashenc.c
avformat/dashenc: allow setting segment durations per AdaptationSet
[ffmpeg] / libavformat / dashenc.c
1 /*
2  * MPEG-DASH ISO BMFF segmenter
3  * Copyright (c) 2014 Martin Storsjo
4  * Copyright (c) 2018 Akamai Technologies, Inc.
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 #include "config.h"
24 #if HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #include "libavutil/avassert.h"
29 #include "libavutil/avutil.h"
30 #include "libavutil/avstring.h"
31 #include "libavutil/intreadwrite.h"
32 #include "libavutil/mathematics.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/parseutils.h"
35 #include "libavutil/rational.h"
36 #include "libavutil/time.h"
37 #include "libavutil/time_internal.h"
38
39 #include "av1.h"
40 #include "avc.h"
41 #include "avformat.h"
42 #include "avio_internal.h"
43 #include "hlsplaylist.h"
44 #if CONFIG_HTTP_PROTOCOL
45 #include "http.h"
46 #endif
47 #include "internal.h"
48 #include "isom.h"
49 #include "os_support.h"
50 #include "url.h"
51 #include "vpcc.h"
52 #include "dash.h"
53
54 typedef enum {
55     SEGMENT_TYPE_AUTO = 0,
56     SEGMENT_TYPE_MP4,
57     SEGMENT_TYPE_WEBM,
58     SEGMENT_TYPE_NB
59 } SegmentType;
60
61 typedef struct Segment {
62     char file[1024];
63     int64_t start_pos;
64     int range_length, index_length;
65     int64_t time;
66     double prog_date_time;
67     int64_t duration;
68     int n;
69 } Segment;
70
71 typedef struct AdaptationSet {
72     char id[10];
73     char *descriptor;
74     int64_t seg_duration;
75     enum AVMediaType media_type;
76     AVDictionary *metadata;
77     AVRational min_frame_rate, max_frame_rate;
78     int ambiguous_frame_rate;
79 } AdaptationSet;
80
81 typedef struct OutputStream {
82     AVFormatContext *ctx;
83     int ctx_inited, as_idx;
84     AVIOContext *out;
85     int packets_written;
86     char initfile[1024];
87     int64_t init_start_pos, pos;
88     int init_range_length;
89     int nb_segments, segments_size, segment_index;
90     int64_t seg_duration;
91     int64_t last_duration;
92     Segment **segments;
93     int64_t first_pts, start_pts, max_pts;
94     int64_t last_dts, last_pts;
95     int bit_rate;
96     SegmentType segment_type;  /* segment type selected for this particular stream */
97     const char *format_name;
98     const char *extension_name;
99     const char *single_file_name;  /* file names selected for this particular stream */
100     const char *init_seg_name;
101     const char *media_seg_name;
102
103     char codec_str[100];
104     int written_len;
105     char filename[1024];
106     char full_path[1024];
107     char temp_path[1024];
108     double availability_time_offset;
109     int total_pkt_size;
110     int muxer_overhead;
111 } OutputStream;
112
113 typedef struct DASHContext {
114     const AVClass *class;  /* Class for private options. */
115     char *adaptation_sets;
116     AdaptationSet *as;
117     int nb_as;
118     int window_size;
119     int extra_window_size;
120 #if FF_API_DASH_MIN_SEG_DURATION
121     int min_seg_duration;
122 #endif
123     int64_t seg_duration;
124     int remove_at_exit;
125     int use_template;
126     int use_timeline;
127     int single_file;
128     OutputStream *streams;
129     int has_video;
130     int64_t last_duration;
131     int64_t total_duration;
132     char availability_start_time[100];
133     time_t start_time_s;
134     char dirname[1024];
135     const char *single_file_name;  /* file names as specified in options */
136     const char *init_seg_name;
137     const char *media_seg_name;
138     const char *utc_timing_url;
139     const char *method;
140     const char *user_agent;
141     int hls_playlist;
142     int http_persistent;
143     int master_playlist_created;
144     AVIOContext *mpd_out;
145     AVIOContext *m3u8_out;
146     int streaming;
147     int64_t timeout;
148     int index_correction;
149     AVDictionary *format_options;
150     int global_sidx;
151     SegmentType segment_type_option;  /* segment type as specified in options */
152     int ignore_io_errors;
153     int lhls;
154     int master_publish_rate;
155     int nr_of_streams_to_flush;
156     int nr_of_streams_flushed;
157 } DASHContext;
158
159 static struct codec_string {
160     int id;
161     const char *str;
162 } codecs[] = {
163     { AV_CODEC_ID_VP8, "vp8" },
164     { AV_CODEC_ID_VP9, "vp9" },
165     { AV_CODEC_ID_VORBIS, "vorbis" },
166     { AV_CODEC_ID_OPUS, "opus" },
167     { AV_CODEC_ID_FLAC, "flac" },
168     { 0, NULL }
169 };
170
171 static struct format_string {
172     SegmentType segment_type;
173     const char *str;
174 } formats[] = {
175     { SEGMENT_TYPE_AUTO, "auto" },
176     { SEGMENT_TYPE_MP4, "mp4" },
177     { SEGMENT_TYPE_WEBM, "webm" },
178     { 0, NULL }
179 };
180
181 static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename,
182                            AVDictionary **options) {
183     DASHContext *c = s->priv_data;
184     int http_base_proto = filename ? ff_is_http_proto(filename) : 0;
185     int err = AVERROR_MUXER_NOT_FOUND;
186     if (!*pb || !http_base_proto || !c->http_persistent) {
187         err = s->io_open(s, pb, filename, AVIO_FLAG_WRITE, options);
188 #if CONFIG_HTTP_PROTOCOL
189     } else {
190         URLContext *http_url_context = ffio_geturlcontext(*pb);
191         av_assert0(http_url_context);
192         err = ff_http_do_new_request(http_url_context, filename);
193         if (err < 0)
194             ff_format_io_close(s, pb);
195 #endif
196     }
197     return err;
198 }
199
200 static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename) {
201     DASHContext *c = s->priv_data;
202     int http_base_proto = filename ? ff_is_http_proto(filename) : 0;
203
204     if (!*pb)
205         return;
206
207     if (!http_base_proto || !c->http_persistent) {
208         ff_format_io_close(s, pb);
209 #if CONFIG_HTTP_PROTOCOL
210     } else {
211         URLContext *http_url_context = ffio_geturlcontext(*pb);
212         av_assert0(http_url_context);
213         avio_flush(*pb);
214         ffurl_shutdown(http_url_context, AVIO_FLAG_WRITE);
215 #endif
216     }
217 }
218
219 static const char *get_format_str(SegmentType segment_type) {
220     int i;
221     for (i = 0; i < SEGMENT_TYPE_NB; i++)
222         if (formats[i].segment_type == segment_type)
223             return formats[i].str;
224     return NULL;
225 }
226
227 static const char *get_extension_str(SegmentType type, int single_file)
228 {
229     switch (type) {
230
231     case SEGMENT_TYPE_MP4:  return single_file ? "mp4" : "m4s";
232     case SEGMENT_TYPE_WEBM: return "webm";
233     default: return NULL;
234     }
235 }
236
237 static int handle_io_open_error(AVFormatContext *s, int err, char *url) {
238     DASHContext *c = s->priv_data;
239     char errbuf[AV_ERROR_MAX_STRING_SIZE];
240     av_strerror(err, errbuf, sizeof(errbuf));
241     av_log(s, c->ignore_io_errors ? AV_LOG_WARNING : AV_LOG_ERROR,
242            "Unable to open %s for writing: %s\n", url, errbuf);
243     return c->ignore_io_errors ? 0 : err;
244 }
245
246 static inline SegmentType select_segment_type(SegmentType segment_type, enum AVCodecID codec_id)
247 {
248     if (segment_type == SEGMENT_TYPE_AUTO) {
249         if (codec_id == AV_CODEC_ID_OPUS || codec_id == AV_CODEC_ID_VORBIS ||
250             codec_id == AV_CODEC_ID_VP8 || codec_id == AV_CODEC_ID_VP9) {
251             segment_type = SEGMENT_TYPE_WEBM;
252         } else {
253             segment_type = SEGMENT_TYPE_MP4;
254         }
255     }
256
257     return segment_type;
258 }
259
260 static int init_segment_types(AVFormatContext *s)
261 {
262     DASHContext *c = s->priv_data;
263     int has_mp4_streams = 0;
264     for (int i = 0; i < s->nb_streams; ++i) {
265         OutputStream *os = &c->streams[i];
266         SegmentType segment_type = select_segment_type(
267             c->segment_type_option, s->streams[i]->codecpar->codec_id);
268         os->segment_type = segment_type;
269         os->format_name = get_format_str(segment_type);
270         if (!os->format_name) {
271             av_log(s, AV_LOG_ERROR, "Could not select DASH segment type for stream %d\n", i);
272             return AVERROR_MUXER_NOT_FOUND;
273         }
274         os->extension_name = get_extension_str(segment_type, c->single_file);
275         if (!os->extension_name) {
276             av_log(s, AV_LOG_ERROR, "Could not get extension type for stream %d\n", i);
277             return AVERROR_MUXER_NOT_FOUND;
278         }
279
280         has_mp4_streams |= segment_type == SEGMENT_TYPE_MP4;
281     }
282
283     if (c->hls_playlist && !has_mp4_streams) {
284          av_log(s, AV_LOG_WARNING, "No mp4 streams, disabling HLS manifest generation\n");
285          c->hls_playlist = 0;
286     }
287
288     return 0;
289 }
290
291 static int check_file_extension(const char *filename, const char *extension) {
292     char *dot;
293     if (!filename || !extension)
294         return -1;
295     dot = strrchr(filename, '.');
296     if (dot && !strcmp(dot + 1, extension))
297         return 0;
298     return -1;
299 }
300
301 static void set_vp9_codec_str(AVFormatContext *s, AVCodecParameters *par,
302                               AVRational *frame_rate, char *str, int size) {
303     VPCC vpcc;
304     int ret = ff_isom_get_vpcc_features(s, par, frame_rate, &vpcc);
305     if (ret == 0) {
306         av_strlcatf(str, size, "vp09.%02d.%02d.%02d",
307                     vpcc.profile, vpcc.level, vpcc.bitdepth);
308     } else {
309         // Default to just vp9 in case of error while finding out profile or level
310         av_log(s, AV_LOG_WARNING, "Could not find VP9 profile and/or level\n");
311         av_strlcpy(str, "vp9", size);
312     }
313     return;
314 }
315
316 static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,
317                           AVRational *frame_rate, char *str, int size)
318 {
319     const AVCodecTag *tags[2] = { NULL, NULL };
320     uint32_t tag;
321     int i;
322
323     // common Webm codecs are not part of RFC 6381
324     for (i = 0; codecs[i].id; i++)
325         if (codecs[i].id == par->codec_id) {
326             if (codecs[i].id == AV_CODEC_ID_VP9) {
327                 set_vp9_codec_str(s, par, frame_rate, str, size);
328             } else {
329                 av_strlcpy(str, codecs[i].str, size);
330             }
331             return;
332         }
333
334     // for codecs part of RFC 6381
335     if (par->codec_type == AVMEDIA_TYPE_VIDEO)
336         tags[0] = ff_codec_movvideo_tags;
337     else if (par->codec_type == AVMEDIA_TYPE_AUDIO)
338         tags[0] = ff_codec_movaudio_tags;
339     else
340         return;
341
342     tag = par->codec_tag;
343     if (!tag)
344         tag = av_codec_get_tag(tags, par->codec_id);
345     if (!tag)
346         return;
347     if (size < 5)
348         return;
349
350     AV_WL32(str, tag);
351     str[4] = '\0';
352     if (!strcmp(str, "mp4a") || !strcmp(str, "mp4v")) {
353         uint32_t oti;
354         tags[0] = ff_mp4_obj_type;
355         oti = av_codec_get_tag(tags, par->codec_id);
356         if (oti)
357             av_strlcatf(str, size, ".%02"PRIx32, oti);
358         else
359             return;
360
361         if (tag == MKTAG('m', 'p', '4', 'a')) {
362             if (par->extradata_size >= 2) {
363                 int aot = par->extradata[0] >> 3;
364                 if (aot == 31)
365                     aot = ((AV_RB16(par->extradata) >> 5) & 0x3f) + 32;
366                 av_strlcatf(str, size, ".%d", aot);
367             }
368         } else if (tag == MKTAG('m', 'p', '4', 'v')) {
369             // Unimplemented, should output ProfileLevelIndication as a decimal number
370             av_log(s, AV_LOG_WARNING, "Incomplete RFC 6381 codec string for mp4v\n");
371         }
372     } else if (!strcmp(str, "avc1")) {
373         uint8_t *tmpbuf = NULL;
374         uint8_t *extradata = par->extradata;
375         int extradata_size = par->extradata_size;
376         if (!extradata_size)
377             return;
378         if (extradata[0] != 1) {
379             AVIOContext *pb;
380             if (avio_open_dyn_buf(&pb) < 0)
381                 return;
382             if (ff_isom_write_avcc(pb, extradata, extradata_size) < 0) {
383                 ffio_free_dyn_buf(&pb);
384                 return;
385             }
386             extradata_size = avio_close_dyn_buf(pb, &extradata);
387             tmpbuf = extradata;
388         }
389
390         if (extradata_size >= 4)
391             av_strlcatf(str, size, ".%02x%02x%02x",
392                         extradata[1], extradata[2], extradata[3]);
393         av_free(tmpbuf);
394     } else if (!strcmp(str, "av01")) {
395         AV1SequenceParameters seq;
396         if (!par->extradata_size)
397             return;
398         if (ff_av1_parse_seq_header(&seq, par->extradata, par->extradata_size) < 0)
399             return;
400
401         av_strlcatf(str, size, ".%01u.%02u%s.%02u",
402                     seq.profile, seq.level, seq.tier ? "H" : "M", seq.bitdepth);
403         if (seq.color_description_present_flag)
404             av_strlcatf(str, size, ".%01u.%01u%01u%01u.%02u.%02u.%02u.%01u",
405                         seq.monochrome,
406                         seq.chroma_subsampling_x, seq.chroma_subsampling_y, seq.chroma_sample_position,
407                         seq.color_primaries, seq.transfer_characteristics, seq.matrix_coefficients,
408                         seq.color_range);
409     }
410 }
411
412 static int flush_dynbuf(DASHContext *c, OutputStream *os, int *range_length)
413 {
414     uint8_t *buffer;
415
416     if (!os->ctx->pb) {
417         return AVERROR(EINVAL);
418     }
419
420     // flush
421     av_write_frame(os->ctx, NULL);
422     avio_flush(os->ctx->pb);
423
424     if (!c->single_file) {
425         // write out to file
426         *range_length = avio_close_dyn_buf(os->ctx->pb, &buffer);
427         os->ctx->pb = NULL;
428         if (os->out)
429             avio_write(os->out, buffer + os->written_len, *range_length - os->written_len);
430         os->written_len = 0;
431         av_free(buffer);
432
433         // re-open buffer
434         return avio_open_dyn_buf(&os->ctx->pb);
435     } else {
436         *range_length = avio_tell(os->ctx->pb) - os->pos;
437         return 0;
438     }
439 }
440
441 static void set_http_options(AVDictionary **options, DASHContext *c)
442 {
443     if (c->method)
444         av_dict_set(options, "method", c->method, 0);
445     if (c->user_agent)
446         av_dict_set(options, "user_agent", c->user_agent, 0);
447     if (c->http_persistent)
448         av_dict_set_int(options, "multiple_requests", 1, 0);
449     if (c->timeout >= 0)
450         av_dict_set_int(options, "timeout", c->timeout, 0);
451 }
452
453 static void get_hls_playlist_name(char *playlist_name, int string_size,
454                                   const char *base_url, int id) {
455     if (base_url)
456         snprintf(playlist_name, string_size, "%smedia_%d.m3u8", base_url, id);
457     else
458         snprintf(playlist_name, string_size, "media_%d.m3u8", id);
459 }
460
461 static void get_start_index_number(OutputStream *os, DASHContext *c,
462                                    int *start_index, int *start_number) {
463     *start_index = 0;
464     *start_number = 1;
465     if (c->window_size) {
466         *start_index  = FFMAX(os->nb_segments   - c->window_size, 0);
467         *start_number = FFMAX(os->segment_index - c->window_size, 1);
468     }
469 }
470
471 static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s,
472                                      int representation_id, int final,
473                                      char *prefetch_url) {
474     DASHContext *c = s->priv_data;
475     int timescale = os->ctx->streams[0]->time_base.den;
476     char temp_filename_hls[1024];
477     char filename_hls[1024];
478     AVDictionary *http_opts = NULL;
479     int target_duration = 0;
480     int ret = 0;
481     const char *proto = avio_find_protocol_name(c->dirname);
482     int use_rename = proto && !strcmp(proto, "file");
483     int i, start_index, start_number;
484     double prog_date_time = 0;
485
486     get_start_index_number(os, c, &start_index, &start_number);
487
488     if (!c->hls_playlist || start_index >= os->nb_segments ||
489         os->segment_type != SEGMENT_TYPE_MP4)
490         return;
491
492     get_hls_playlist_name(filename_hls, sizeof(filename_hls),
493                           c->dirname, representation_id);
494
495     snprintf(temp_filename_hls, sizeof(temp_filename_hls), use_rename ? "%s.tmp" : "%s", filename_hls);
496
497     set_http_options(&http_opts, c);
498     ret = dashenc_io_open(s, &c->m3u8_out, temp_filename_hls, &http_opts);
499     av_dict_free(&http_opts);
500     if (ret < 0) {
501         handle_io_open_error(s, ret, temp_filename_hls);
502         return;
503     }
504     for (i = start_index; i < os->nb_segments; i++) {
505         Segment *seg = os->segments[i];
506         double duration = (double) seg->duration / timescale;
507         if (target_duration <= duration)
508             target_duration = lrint(duration);
509     }
510
511     ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration,
512                                  start_number, PLAYLIST_TYPE_NONE, 0);
513
514     ff_hls_write_init_file(c->m3u8_out, os->initfile, c->single_file,
515                            os->init_range_length, os->init_start_pos);
516
517     for (i = start_index; i < os->nb_segments; i++) {
518         Segment *seg = os->segments[i];
519
520         if (prog_date_time == 0) {
521             if (os->nb_segments == 1)
522                 prog_date_time = c->start_time_s;
523             else
524                 prog_date_time = seg->prog_date_time;
525         }
526         seg->prog_date_time = prog_date_time;
527
528         ret = ff_hls_write_file_entry(c->m3u8_out, 0, c->single_file,
529                                 (double) seg->duration / timescale, 0,
530                                 seg->range_length, seg->start_pos, NULL,
531                                 c->single_file ? os->initfile : seg->file,
532                                 &prog_date_time, 0, 0, 0);
533         if (ret < 0) {
534             av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
535         }
536     }
537
538     if (prefetch_url)
539         avio_printf(c->m3u8_out, "#EXT-X-PREFETCH:%s\n", prefetch_url);
540
541     if (final)
542         ff_hls_write_end_list(c->m3u8_out);
543
544     dashenc_io_close(s, &c->m3u8_out, temp_filename_hls);
545
546     if (use_rename)
547         if (avpriv_io_move(temp_filename_hls, filename_hls) < 0) {
548             av_log(os->ctx, AV_LOG_WARNING, "renaming file %s to %s failed\n\n", temp_filename_hls, filename_hls);
549         }
550 }
551
552 static int flush_init_segment(AVFormatContext *s, OutputStream *os)
553 {
554     DASHContext *c = s->priv_data;
555     int ret, range_length;
556
557     ret = flush_dynbuf(c, os, &range_length);
558     if (ret < 0)
559         return ret;
560
561     os->pos = os->init_range_length = range_length;
562     if (!c->single_file) {
563         char filename[1024];
564         snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
565         dashenc_io_close(s, &os->out, filename);
566     }
567     return 0;
568 }
569
570 static void dash_free(AVFormatContext *s)
571 {
572     DASHContext *c = s->priv_data;
573     int i, j;
574
575     if (c->as) {
576         for (i = 0; i < c->nb_as; i++) {
577             av_dict_free(&c->as[i].metadata);
578             av_freep(&c->as[i].descriptor);
579         }
580         av_freep(&c->as);
581         c->nb_as = 0;
582     }
583
584     if (!c->streams)
585         return;
586     for (i = 0; i < s->nb_streams; i++) {
587         OutputStream *os = &c->streams[i];
588         if (os->ctx && os->ctx->pb) {
589             if (!c->single_file)
590                 ffio_free_dyn_buf(&os->ctx->pb);
591             else
592                 avio_close(os->ctx->pb);
593         }
594         ff_format_io_close(s, &os->out);
595         avformat_free_context(os->ctx);
596         for (j = 0; j < os->nb_segments; j++)
597             av_free(os->segments[j]);
598         av_free(os->segments);
599         av_freep(&os->single_file_name);
600         av_freep(&os->init_seg_name);
601         av_freep(&os->media_seg_name);
602     }
603     av_freep(&c->streams);
604
605     ff_format_io_close(s, &c->mpd_out);
606     ff_format_io_close(s, &c->m3u8_out);
607 }
608
609 static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatContext *s,
610                                 int representation_id, int final)
611 {
612     DASHContext *c = s->priv_data;
613     int i, start_index, start_number;
614     get_start_index_number(os, c, &start_index, &start_number);
615
616     if (c->use_template) {
617         int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : AV_TIME_BASE;
618         avio_printf(out, "\t\t\t\t<SegmentTemplate timescale=\"%d\" ", timescale);
619         if (!c->use_timeline) {
620             avio_printf(out, "duration=\"%"PRId64"\" ", os->seg_duration);
621             if (c->streaming && os->availability_time_offset)
622                 avio_printf(out, "availabilityTimeOffset=\"%.3f\" ",
623                             os->availability_time_offset);
624         }
625         avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", os->init_seg_name, os->media_seg_name, c->use_timeline ? start_number : 1);
626         if (c->use_timeline) {
627             int64_t cur_time = 0;
628             avio_printf(out, "\t\t\t\t\t<SegmentTimeline>\n");
629             for (i = start_index; i < os->nb_segments; ) {
630                 Segment *seg = os->segments[i];
631                 int repeat = 0;
632                 avio_printf(out, "\t\t\t\t\t\t<S ");
633                 if (i == start_index || seg->time != cur_time) {
634                     cur_time = seg->time;
635                     avio_printf(out, "t=\"%"PRId64"\" ", seg->time);
636                 }
637                 avio_printf(out, "d=\"%"PRId64"\" ", seg->duration);
638                 while (i + repeat + 1 < os->nb_segments &&
639                        os->segments[i + repeat + 1]->duration == seg->duration &&
640                        os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]->duration)
641                     repeat++;
642                 if (repeat > 0)
643                     avio_printf(out, "r=\"%d\" ", repeat);
644                 avio_printf(out, "/>\n");
645                 i += 1 + repeat;
646                 cur_time += (1 + repeat) * seg->duration;
647             }
648             avio_printf(out, "\t\t\t\t\t</SegmentTimeline>\n");
649         }
650         avio_printf(out, "\t\t\t\t</SegmentTemplate>\n");
651     } else if (c->single_file) {
652         avio_printf(out, "\t\t\t\t<BaseURL>%s</BaseURL>\n", os->initfile);
653         avio_printf(out, "\t\t\t\t<SegmentList timescale=\"%d\" duration=\"%"PRId64"\" startNumber=\"%d\">\n", AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number);
654         avio_printf(out, "\t\t\t\t\t<Initialization range=\"%"PRId64"-%"PRId64"\" />\n", os->init_start_pos, os->init_start_pos + os->init_range_length - 1);
655         for (i = start_index; i < os->nb_segments; i++) {
656             Segment *seg = os->segments[i];
657             avio_printf(out, "\t\t\t\t\t<SegmentURL mediaRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->range_length - 1);
658             if (seg->index_length)
659                 avio_printf(out, "indexRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->index_length - 1);
660             avio_printf(out, "/>\n");
661         }
662         avio_printf(out, "\t\t\t\t</SegmentList>\n");
663     } else {
664         avio_printf(out, "\t\t\t\t<SegmentList timescale=\"%d\" duration=\"%"PRId64"\" startNumber=\"%d\">\n", AV_TIME_BASE, FFMIN(os->seg_duration, os->last_duration), start_number);
665         avio_printf(out, "\t\t\t\t\t<Initialization sourceURL=\"%s\" />\n", os->initfile);
666         for (i = start_index; i < os->nb_segments; i++) {
667             Segment *seg = os->segments[i];
668             avio_printf(out, "\t\t\t\t\t<SegmentURL media=\"%s\" />\n", seg->file);
669         }
670         avio_printf(out, "\t\t\t\t</SegmentList>\n");
671     }
672     if (!c->lhls || final) {
673         write_hls_media_playlist(os, s, representation_id, final, NULL);
674     }
675
676 }
677
678 static char *xmlescape(const char *str) {
679     int outlen = strlen(str)*3/2 + 6;
680     char *out = av_realloc(NULL, outlen + 1);
681     int pos = 0;
682     if (!out)
683         return NULL;
684     for (; *str; str++) {
685         if (pos + 6 > outlen) {
686             char *tmp;
687             outlen = 2 * outlen + 6;
688             tmp = av_realloc(out, outlen + 1);
689             if (!tmp) {
690                 av_free(out);
691                 return NULL;
692             }
693             out = tmp;
694         }
695         if (*str == '&') {
696             memcpy(&out[pos], "&amp;", 5);
697             pos += 5;
698         } else if (*str == '<') {
699             memcpy(&out[pos], "&lt;", 4);
700             pos += 4;
701         } else if (*str == '>') {
702             memcpy(&out[pos], "&gt;", 4);
703             pos += 4;
704         } else if (*str == '\'') {
705             memcpy(&out[pos], "&apos;", 6);
706             pos += 6;
707         } else if (*str == '\"') {
708             memcpy(&out[pos], "&quot;", 6);
709             pos += 6;
710         } else {
711             out[pos++] = *str;
712         }
713     }
714     out[pos] = '\0';
715     return out;
716 }
717
718 static void write_time(AVIOContext *out, int64_t time)
719 {
720     int seconds = time / AV_TIME_BASE;
721     int fractions = time % AV_TIME_BASE;
722     int minutes = seconds / 60;
723     int hours = minutes / 60;
724     seconds %= 60;
725     minutes %= 60;
726     avio_printf(out, "PT");
727     if (hours)
728         avio_printf(out, "%dH", hours);
729     if (hours || minutes)
730         avio_printf(out, "%dM", minutes);
731     avio_printf(out, "%d.%dS", seconds, fractions / (AV_TIME_BASE / 10));
732 }
733
734 static void format_date_now(char *buf, int size)
735 {
736     struct tm *ptm, tmbuf;
737     int64_t time_us = av_gettime();
738     int64_t time_ms = time_us / 1000;
739     const time_t time_s = time_ms / 1000;
740     int millisec = time_ms - (time_s * 1000);
741     ptm = gmtime_r(&time_s, &tmbuf);
742     if (ptm) {
743         int len;
744         if (!strftime(buf, size, "%Y-%m-%dT%H:%M:%S", ptm)) {
745             buf[0] = '\0';
746             return;
747         }
748         len = strlen(buf);
749         snprintf(buf + len, size - len, ".%03dZ", millisec);
750     }
751 }
752
753 static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index,
754                                 int final)
755 {
756     DASHContext *c = s->priv_data;
757     AdaptationSet *as = &c->as[as_index];
758     AVDictionaryEntry *lang, *role;
759     int i;
760
761     avio_printf(out, "\t\t<AdaptationSet id=\"%s\" contentType=\"%s\" segmentAlignment=\"true\" bitstreamSwitching=\"true\"",
762                 as->id, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
763     if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && av_cmp_q(as->min_frame_rate, as->max_frame_rate) < 0)
764         avio_printf(out, " maxFrameRate=\"%d/%d\"", as->max_frame_rate.num, as->max_frame_rate.den);
765     lang = av_dict_get(as->metadata, "language", NULL, 0);
766     if (lang)
767         avio_printf(out, " lang=\"%s\"", lang->value);
768     avio_printf(out, ">\n");
769
770     role = av_dict_get(as->metadata, "role", NULL, 0);
771     if (role)
772         avio_printf(out, "\t\t\t<Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"%s\"/>\n", role->value);
773     if (as->descriptor)
774         avio_printf(out, "\t\t\t%s\n", as->descriptor);
775     for (i = 0; i < s->nb_streams; i++) {
776         OutputStream *os = &c->streams[i];
777         char bandwidth_str[64] = {'\0'};
778
779         if (os->as_idx - 1 != as_index)
780             continue;
781
782         if (os->bit_rate > 0)
783             snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
784                      os->bit_rate);
785
786         if (as->media_type == AVMEDIA_TYPE_VIDEO) {
787             AVStream *st = s->streams[i];
788             avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"",
789                 i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
790             if (st->avg_frame_rate.num)
791                 avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den);
792             avio_printf(out, ">\n");
793         } else {
794             avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
795                 i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate);
796             avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n",
797                 s->streams[i]->codecpar->channels);
798         }
799         output_segment_list(os, out, s, i, final);
800         avio_printf(out, "\t\t\t</Representation>\n");
801     }
802     avio_printf(out, "\t\t</AdaptationSet>\n");
803
804     return 0;
805 }
806
807 static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMediaType type)
808 {
809     DASHContext *c = s->priv_data;
810
811     void *mem = av_realloc(c->as, sizeof(*c->as) * (c->nb_as + 1));
812     if (!mem)
813         return AVERROR(ENOMEM);
814     c->as = mem;
815     ++c->nb_as;
816
817     *as = &c->as[c->nb_as - 1];
818     memset(*as, 0, sizeof(**as));
819     (*as)->media_type = type;
820
821     return 0;
822 }
823
824 static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i)
825 {
826     DASHContext *c = s->priv_data;
827     AdaptationSet *as = &c->as[as_idx - 1];
828     OutputStream *os = &c->streams[i];
829
830     if (as->media_type != s->streams[i]->codecpar->codec_type) {
831         av_log(s, AV_LOG_ERROR, "Codec type of stream %d doesn't match AdaptationSet's media type\n", i);
832         return AVERROR(EINVAL);
833     } else if (os->as_idx) {
834         av_log(s, AV_LOG_ERROR, "Stream %d is already assigned to an AdaptationSet\n", i);
835         return AVERROR(EINVAL);
836     }
837     os->as_idx = as_idx;
838
839     return 0;
840 }
841
842 static int parse_adaptation_sets(AVFormatContext *s)
843 {
844     DASHContext *c = s->priv_data;
845     const char *p = c->adaptation_sets;
846     enum { new_set, parse_id, parsing_streams, parse_descriptor, parse_seg_duration } state;
847     AdaptationSet *as;
848     int i, n, ret;
849
850     // default: one AdaptationSet for each stream
851     if (!p) {
852         for (i = 0; i < s->nb_streams; i++) {
853             if ((ret = add_adaptation_set(s, &as, s->streams[i]->codecpar->codec_type)) < 0)
854                 return ret;
855             snprintf(as->id, sizeof(as->id), "%d", i);
856
857             c->streams[i].as_idx = c->nb_as;
858         }
859         goto end;
860     }
861
862     // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
863     // option id=0,descriptor=descriptor_str,streams=0,1,2 and so on
864     // option id=0,seg_duration=2.5,streams=0,1,2 and so on
865     // descriptor is useful to the scheme defined by ISO/IEC 23009-1:2014/Amd.2:2015
866     // descriptor_str should be a self-closing xml tag.
867     // seg_duration has the same syntax as the global seg_duration option, and has
868     // precedence over it if set.
869     state = new_set;
870     while (*p) {
871         if (*p == ' ') {
872             p++;
873             continue;
874         } else if (state == new_set && av_strstart(p, "id=", &p)) {
875
876             if ((ret = add_adaptation_set(s, &as, AVMEDIA_TYPE_UNKNOWN)) < 0)
877                 return ret;
878
879             n = strcspn(p, ",");
880             snprintf(as->id, sizeof(as->id), "%.*s", n, p);
881
882             p += n;
883             if (*p)
884                 p++;
885             state = parse_id;
886         } else if (state != new_set && av_strstart(p, "seg_duration=", &p)) {
887             char str[32];
888             int64_t usecs = 0;
889
890             n = strcspn(p, ",");
891             snprintf(str, sizeof(str), "%.*s", n, p);
892             p += n;
893             if (*p)
894                 p++;
895
896             ret = av_parse_time(&usecs, str, 1);
897             if (ret < 0) {
898                 av_log(s, AV_LOG_ERROR, "Unable to parse option value \"%s\" as duration\n", str);
899                 return ret;
900             }
901
902             as->seg_duration = usecs;
903             state = parse_seg_duration;
904         } else if (state != new_set && av_strstart(p, "descriptor=", &p)) {
905             n = strcspn(p, ">") + 1; //followed by one comma, so plus 1
906             if (n < strlen(p)) {
907                 as->descriptor = av_strndup(p, n);
908             } else {
909                 av_log(s, AV_LOG_ERROR, "Parse error, descriptor string should be a self-closing xml tag\n");
910                 return AVERROR(EINVAL);
911             }
912             p += n;
913             if (*p)
914                 p++;
915             state = parse_descriptor;
916         } else if ((state != new_set) && av_strstart(p, "streams=", &p)) { //descriptor and duration are optional
917             state = parsing_streams;
918         } else if (state == parsing_streams) {
919             AdaptationSet *as = &c->as[c->nb_as - 1];
920             char idx_str[8], *end_str;
921
922             n = strcspn(p, " ,");
923             snprintf(idx_str, sizeof(idx_str), "%.*s", n, p);
924             p += n;
925
926             // if value is "a" or "v", map all streams of that type
927             if (as->media_type == AVMEDIA_TYPE_UNKNOWN && (idx_str[0] == 'v' || idx_str[0] == 'a')) {
928                 enum AVMediaType type = (idx_str[0] == 'v') ? AVMEDIA_TYPE_VIDEO : AVMEDIA_TYPE_AUDIO;
929                 av_log(s, AV_LOG_DEBUG, "Map all streams of type %s\n", idx_str);
930
931                 for (i = 0; i < s->nb_streams; i++) {
932                     if (s->streams[i]->codecpar->codec_type != type)
933                         continue;
934
935                     as->media_type = s->streams[i]->codecpar->codec_type;
936
937                     if ((ret = adaptation_set_add_stream(s, c->nb_as, i)) < 0)
938                         return ret;
939                 }
940             } else { // select single stream
941                 i = strtol(idx_str, &end_str, 10);
942                 if (idx_str == end_str || i < 0 || i >= s->nb_streams) {
943                     av_log(s, AV_LOG_ERROR, "Selected stream \"%s\" not found!\n", idx_str);
944                     return AVERROR(EINVAL);
945                 }
946                 av_log(s, AV_LOG_DEBUG, "Map stream %d\n", i);
947
948                 if (as->media_type == AVMEDIA_TYPE_UNKNOWN) {
949                     as->media_type = s->streams[i]->codecpar->codec_type;
950                 }
951
952                 if ((ret = adaptation_set_add_stream(s, c->nb_as, i)) < 0)
953                     return ret;
954             }
955
956             if (*p == ' ')
957                 state = new_set;
958             if (*p)
959                 p++;
960         } else {
961             return AVERROR(EINVAL);
962         }
963     }
964
965 end:
966     // check for unassigned streams
967     for (i = 0; i < s->nb_streams; i++) {
968         OutputStream *os = &c->streams[i];
969         if (!os->as_idx) {
970             av_log(s, AV_LOG_ERROR, "Stream %d is not mapped to an AdaptationSet\n", i);
971             return AVERROR(EINVAL);
972         }
973     }
974     return 0;
975 }
976
977 static int write_manifest(AVFormatContext *s, int final)
978 {
979     DASHContext *c = s->priv_data;
980     AVIOContext *out;
981     char temp_filename[1024];
982     int ret, i;
983     const char *proto = avio_find_protocol_name(s->url);
984     int use_rename = proto && !strcmp(proto, "file");
985     static unsigned int warned_non_file = 0;
986     AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
987     AVDictionary *opts = NULL;
988
989     if (!use_rename && !warned_non_file++)
990         av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n");
991
992     snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->url);
993     set_http_options(&opts, c);
994     ret = dashenc_io_open(s, &c->mpd_out, temp_filename, &opts);
995     av_dict_free(&opts);
996     if (ret < 0) {
997         return handle_io_open_error(s, ret, temp_filename);
998     }
999     out = c->mpd_out;
1000     avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1001     avio_printf(out, "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
1002                 "\txmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
1003                 "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
1004                 "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n"
1005                 "\tprofiles=\"urn:mpeg:dash:profile:isoff-live:2011\"\n"
1006                 "\ttype=\"%s\"\n", final ? "static" : "dynamic");
1007     if (final) {
1008         avio_printf(out, "\tmediaPresentationDuration=\"");
1009         write_time(out, c->total_duration);
1010         avio_printf(out, "\"\n");
1011     } else {
1012         int64_t update_period = c->last_duration / AV_TIME_BASE;
1013         char now_str[100];
1014         if (c->use_template && !c->use_timeline)
1015             update_period = 500;
1016         avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", update_period);
1017         avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", c->last_duration / AV_TIME_BASE);
1018         if (c->availability_start_time[0])
1019             avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", c->availability_start_time);
1020         format_date_now(now_str, sizeof(now_str));
1021         if (now_str[0])
1022             avio_printf(out, "\tpublishTime=\"%s\"\n", now_str);
1023         if (c->window_size && c->use_template) {
1024             avio_printf(out, "\ttimeShiftBufferDepth=\"");
1025             write_time(out, c->last_duration * c->window_size);
1026             avio_printf(out, "\"\n");
1027         }
1028     }
1029     avio_printf(out, "\tminBufferTime=\"");
1030     write_time(out, c->last_duration * 2);
1031     avio_printf(out, "\">\n");
1032     avio_printf(out, "\t<ProgramInformation>\n");
1033     if (title) {
1034         char *escaped = xmlescape(title->value);
1035         avio_printf(out, "\t\t<Title>%s</Title>\n", escaped);
1036         av_free(escaped);
1037     }
1038     avio_printf(out, "\t</ProgramInformation>\n");
1039
1040     if (c->window_size && s->nb_streams > 0 && c->streams[0].nb_segments > 0 && !c->use_template) {
1041         OutputStream *os = &c->streams[0];
1042         int start_index = FFMAX(os->nb_segments - c->window_size, 0);
1043         int64_t start_time = av_rescale_q(os->segments[start_index]->time, s->streams[0]->time_base, AV_TIME_BASE_Q);
1044         avio_printf(out, "\t<Period id=\"0\" start=\"");
1045         write_time(out, start_time);
1046         avio_printf(out, "\">\n");
1047     } else {
1048         avio_printf(out, "\t<Period id=\"0\" start=\"PT0.0S\">\n");
1049     }
1050
1051     for (i = 0; i < c->nb_as; i++) {
1052         if ((ret = write_adaptation_set(s, out, i, final)) < 0)
1053             return ret;
1054     }
1055     avio_printf(out, "\t</Period>\n");
1056
1057     if (c->utc_timing_url)
1058         avio_printf(out, "\t<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:http-xsdate:2014\" value=\"%s\"/>\n", c->utc_timing_url);
1059
1060     avio_printf(out, "</MPD>\n");
1061     avio_flush(out);
1062     dashenc_io_close(s, &c->mpd_out, temp_filename);
1063
1064     if (use_rename) {
1065         if ((ret = avpriv_io_move(temp_filename, s->url)) < 0)
1066             return ret;
1067     }
1068
1069     if (c->hls_playlist) {
1070         char filename_hls[1024];
1071         const char *audio_group = "A1";
1072         char audio_codec_str[128] = "\0";
1073         int is_default = 1;
1074         int max_audio_bitrate = 0;
1075
1076         // Publish master playlist only the configured rate
1077         if (c->master_playlist_created && (!c->master_publish_rate ||
1078              c->streams[0].segment_index % c->master_publish_rate))
1079             return 0;
1080
1081         if (*c->dirname)
1082             snprintf(filename_hls, sizeof(filename_hls), "%smaster.m3u8", c->dirname);
1083         else
1084             snprintf(filename_hls, sizeof(filename_hls), "master.m3u8");
1085
1086         snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", filename_hls);
1087
1088         set_http_options(&opts, c);
1089         ret = dashenc_io_open(s, &c->m3u8_out, temp_filename, &opts);
1090         av_dict_free(&opts);
1091         if (ret < 0) {
1092             return handle_io_open_error(s, ret, temp_filename);
1093         }
1094
1095         ff_hls_write_playlist_version(c->m3u8_out, 7);
1096
1097         for (i = 0; i < s->nb_streams; i++) {
1098             char playlist_file[64];
1099             AVStream *st = s->streams[i];
1100             OutputStream *os = &c->streams[i];
1101             if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
1102                 continue;
1103             if (os->segment_type != SEGMENT_TYPE_MP4)
1104                 continue;
1105             get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
1106             ff_hls_write_audio_rendition(c->m3u8_out, (char *)audio_group,
1107                                          playlist_file, NULL, i, is_default);
1108             max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
1109                                       os->muxer_overhead, max_audio_bitrate);
1110             if (!av_strnstr(audio_codec_str, os->codec_str, sizeof(audio_codec_str))) {
1111                 if (strlen(audio_codec_str))
1112                     av_strlcat(audio_codec_str, ",", sizeof(audio_codec_str));
1113                 av_strlcat(audio_codec_str, os->codec_str, sizeof(audio_codec_str));
1114             }
1115             is_default = 0;
1116         }
1117
1118         for (i = 0; i < s->nb_streams; i++) {
1119             char playlist_file[64];
1120             char codec_str[128];
1121             AVStream *st = s->streams[i];
1122             OutputStream *os = &c->streams[i];
1123             char *agroup = NULL;
1124             char *codec_str_ptr = NULL;
1125             int stream_bitrate = st->codecpar->bit_rate + os->muxer_overhead;
1126             if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
1127                 continue;
1128             if (os->segment_type != SEGMENT_TYPE_MP4)
1129                 continue;
1130             av_strlcpy(codec_str, os->codec_str, sizeof(codec_str));
1131             if (max_audio_bitrate) {
1132                 agroup = (char *)audio_group;
1133                 stream_bitrate += max_audio_bitrate;
1134                 av_strlcat(codec_str, ",", sizeof(codec_str));
1135                 av_strlcat(codec_str, audio_codec_str, sizeof(codec_str));
1136             }
1137             if (st->codecpar->codec_id != AV_CODEC_ID_HEVC) {
1138                 codec_str_ptr = codec_str;
1139             }
1140             get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
1141             ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate,
1142                                      playlist_file, agroup,
1143                                      codec_str_ptr, NULL);
1144         }
1145         dashenc_io_close(s, &c->m3u8_out, temp_filename);
1146         if (use_rename)
1147             if ((ret = avpriv_io_move(temp_filename, filename_hls)) < 0)
1148                 return ret;
1149         c->master_playlist_created = 1;
1150     }
1151
1152     return 0;
1153 }
1154
1155 static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key)
1156 {
1157     AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0);
1158     if (entry)
1159         av_dict_set(dst, key, entry->value, AV_DICT_DONT_OVERWRITE);
1160     return 0;
1161 }
1162
1163 static int dash_init(AVFormatContext *s)
1164 {
1165     DASHContext *c = s->priv_data;
1166     int ret = 0, i;
1167     char *ptr;
1168     char basename[1024];
1169
1170     c->nr_of_streams_to_flush = 0;
1171     if (c->single_file_name)
1172         c->single_file = 1;
1173     if (c->single_file)
1174         c->use_template = 0;
1175
1176 #if FF_API_DASH_MIN_SEG_DURATION
1177     if (c->min_seg_duration != 5000000) {
1178         av_log(s, AV_LOG_WARNING, "The min_seg_duration option is deprecated and will be removed. Please use the -seg_duration\n");
1179         c->seg_duration = c->min_seg_duration;
1180     }
1181 #endif
1182     if (c->lhls && s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
1183         av_log(s, AV_LOG_ERROR,
1184                "LHLS is experimental, Please set -strict experimental in order to enable it.\n");
1185         return AVERROR_EXPERIMENTAL;
1186     }
1187
1188     if (c->lhls && !c->streaming) {
1189         av_log(s, AV_LOG_WARNING, "LHLS option will be ignored as streaming is not enabled\n");
1190         c->lhls = 0;
1191     }
1192
1193     if (c->lhls && !c->hls_playlist) {
1194         av_log(s, AV_LOG_WARNING, "LHLS option will be ignored as hls_playlist is not enabled\n");
1195         c->lhls = 0;
1196     }
1197
1198     if (c->global_sidx && !c->single_file) {
1199         av_log(s, AV_LOG_WARNING, "Global SIDX option will be ignored as single_file is not enabled\n");
1200         c->global_sidx = 0;
1201     }
1202
1203     if (c->global_sidx && c->streaming) {
1204         av_log(s, AV_LOG_WARNING, "Global SIDX option will be ignored as streaming is enabled\n");
1205         c->global_sidx = 0;
1206     }
1207
1208     av_strlcpy(c->dirname, s->url, sizeof(c->dirname));
1209     ptr = strrchr(c->dirname, '/');
1210     if (ptr) {
1211         av_strlcpy(basename, &ptr[1], sizeof(basename));
1212         ptr[1] = '\0';
1213     } else {
1214         c->dirname[0] = '\0';
1215         av_strlcpy(basename, s->url, sizeof(basename));
1216     }
1217
1218     ptr = strrchr(basename, '.');
1219     if (ptr)
1220         *ptr = '\0';
1221
1222     c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
1223     if (!c->streams)
1224         return AVERROR(ENOMEM);
1225
1226     if ((ret = parse_adaptation_sets(s)) < 0)
1227         return ret;
1228
1229     if ((ret = init_segment_types(s)) < 0)
1230         return ret;
1231
1232     for (i = 0; i < s->nb_streams; i++) {
1233         OutputStream *os = &c->streams[i];
1234         AdaptationSet *as = &c->as[os->as_idx - 1];
1235         AVFormatContext *ctx;
1236         AVStream *st;
1237         AVDictionary *opts = NULL;
1238         char filename[1024];
1239
1240         os->bit_rate = s->streams[i]->codecpar->bit_rate;
1241         if (!os->bit_rate) {
1242             int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ?
1243                         AV_LOG_ERROR : AV_LOG_WARNING;
1244             av_log(s, level, "No bit rate set for stream %d\n", i);
1245             if (s->strict_std_compliance >= FF_COMPLIANCE_STRICT)
1246                 return AVERROR(EINVAL);
1247         }
1248
1249         // copy AdaptationSet language and role from stream metadata
1250         dict_copy_entry(&as->metadata, s->streams[i]->metadata, "language");
1251         dict_copy_entry(&as->metadata, s->streams[i]->metadata, "role");
1252
1253         if (c->init_seg_name) {
1254             os->init_seg_name = av_strireplace(c->init_seg_name, "$ext$", os->extension_name);
1255             if (!os->init_seg_name)
1256                 return AVERROR(ENOMEM);
1257         }
1258         if (c->media_seg_name) {
1259             os->media_seg_name = av_strireplace(c->media_seg_name, "$ext$", os->extension_name);
1260             if (!os->media_seg_name)
1261                 return AVERROR(ENOMEM);
1262         }
1263         if (c->single_file_name) {
1264             os->single_file_name = av_strireplace(c->single_file_name, "$ext$", os->extension_name);
1265             if (!os->single_file_name)
1266                 return AVERROR(ENOMEM);
1267         }
1268
1269         if (os->segment_type == SEGMENT_TYPE_WEBM) {
1270             if ((!c->single_file && check_file_extension(os->init_seg_name, os->format_name) != 0) ||
1271                 (!c->single_file && check_file_extension(os->media_seg_name, os->format_name) != 0) ||
1272                 (c->single_file && check_file_extension(os->single_file_name, os->format_name) != 0)) {
1273                 av_log(s, AV_LOG_WARNING,
1274                        "One or many segment file names doesn't end with .webm. "
1275                        "Override -init_seg_name and/or -media_seg_name and/or "
1276                        "-single_file_name to end with the extension .webm\n");
1277             }
1278             if (c->streaming) {
1279                 // Streaming not supported as matroskaenc buffers internally before writing the output
1280                 av_log(s, AV_LOG_WARNING, "One or more streams in WebM output format. Streaming option will be ignored\n");
1281                 c->streaming = 0;
1282             }
1283         }
1284
1285         os->ctx = ctx = avformat_alloc_context();
1286         if (!ctx)
1287             return AVERROR(ENOMEM);
1288
1289         ctx->oformat = av_guess_format(os->format_name, NULL, NULL);
1290         if (!ctx->oformat)
1291             return AVERROR_MUXER_NOT_FOUND;
1292         ctx->interrupt_callback    = s->interrupt_callback;
1293         ctx->opaque                = s->opaque;
1294         ctx->io_close              = s->io_close;
1295         ctx->io_open               = s->io_open;
1296         ctx->strict_std_compliance = s->strict_std_compliance;
1297
1298         if (!(st = avformat_new_stream(ctx, NULL)))
1299             return AVERROR(ENOMEM);
1300         avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar);
1301         st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
1302         st->time_base = s->streams[i]->time_base;
1303         st->avg_frame_rate = s->streams[i]->avg_frame_rate;
1304         ctx->avoid_negative_ts = s->avoid_negative_ts;
1305         ctx->flags = s->flags;
1306
1307         if (c->single_file) {
1308             if (os->single_file_name)
1309                 ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->single_file_name, i, 0, os->bit_rate, 0);
1310             else
1311                 snprintf(os->initfile, sizeof(os->initfile), "%s-stream%d.%s", basename, i, os->format_name);
1312         } else {
1313             ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->init_seg_name, i, 0, os->bit_rate, 0);
1314         }
1315         snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
1316         set_http_options(&opts, c);
1317         if (!c->single_file) {
1318             if ((ret = avio_open_dyn_buf(&ctx->pb)) < 0)
1319                 return ret;
1320             ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, &opts);
1321         } else {
1322             ctx->url = av_strdup(filename);
1323             ret = avio_open2(&ctx->pb, filename, AVIO_FLAG_WRITE, NULL, &opts);
1324         }
1325         av_dict_free(&opts);
1326         if (ret < 0)
1327             return ret;
1328         os->init_start_pos = 0;
1329
1330         av_dict_copy(&opts, c->format_options, 0);
1331         os->seg_duration = as->seg_duration ? as->seg_duration : c->seg_duration;
1332
1333         if (os->segment_type == SEGMENT_TYPE_MP4) {
1334             if (c->streaming)
1335                 // frag_every_frame : Allows lower latency streaming
1336                 // skip_sidx : Reduce bitrate overhead
1337                 // skip_trailer : Avoids growing memory usage with time
1338                 av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov+skip_sidx+skip_trailer", 0);
1339             else {
1340                 if (c->global_sidx)
1341                     av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov+global_sidx+skip_trailer", 0);
1342                 else
1343                     av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov+skip_trailer", 0);
1344             }
1345         } else {
1346             av_dict_set_int(&opts, "cluster_time_limit", c->seg_duration / 1000, 0);
1347             av_dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit
1348             av_dict_set_int(&opts, "dash", 1, 0);
1349             av_dict_set_int(&opts, "dash_track_number", i + 1, 0);
1350             av_dict_set_int(&opts, "live", 1, 0);
1351         }
1352         ret = avformat_init_output(ctx, &opts);
1353         av_dict_free(&opts);
1354         if (ret < 0)
1355             return ret;
1356         os->ctx_inited = 1;
1357         avio_flush(ctx->pb);
1358
1359         av_log(s, AV_LOG_VERBOSE, "Representation %d init segment will be written to: %s\n", i, filename);
1360
1361         s->streams[i]->time_base = st->time_base;
1362         // If the muxer wants to shift timestamps, request to have them shifted
1363         // already before being handed to this muxer, so we don't have mismatches
1364         // between the MPD and the actual segments.
1365         s->avoid_negative_ts = ctx->avoid_negative_ts;
1366         if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
1367             AVRational avg_frame_rate = s->streams[i]->avg_frame_rate;
1368             if (avg_frame_rate.num > 0) {
1369                 if (av_cmp_q(avg_frame_rate, as->min_frame_rate) < 0)
1370                     as->min_frame_rate = avg_frame_rate;
1371                 if (av_cmp_q(as->max_frame_rate, avg_frame_rate) < 0)
1372                     as->max_frame_rate = avg_frame_rate;
1373             } else {
1374                 as->ambiguous_frame_rate = 1;
1375             }
1376             c->has_video = 1;
1377         }
1378
1379         set_codec_str(s, st->codecpar, &st->avg_frame_rate, os->codec_str,
1380                       sizeof(os->codec_str));
1381         os->first_pts = AV_NOPTS_VALUE;
1382         os->max_pts = AV_NOPTS_VALUE;
1383         os->last_dts = AV_NOPTS_VALUE;
1384         os->segment_index = 1;
1385
1386         if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
1387             c->nr_of_streams_to_flush++;
1388     }
1389
1390     if (!c->has_video && c->seg_duration <= 0) {
1391         av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n");
1392         return AVERROR(EINVAL);
1393     }
1394
1395     c->nr_of_streams_flushed = 0;
1396
1397     return 0;
1398 }
1399
1400 static int dash_write_header(AVFormatContext *s)
1401 {
1402     DASHContext *c = s->priv_data;
1403     int i, ret;
1404     for (i = 0; i < s->nb_streams; i++) {
1405         OutputStream *os = &c->streams[i];
1406         if ((ret = avformat_write_header(os->ctx, NULL)) < 0)
1407             return ret;
1408
1409         // Flush init segment
1410         // Only for WebM segment, since for mp4 delay_moov is set and
1411         // the init segment is thus flushed after the first packets.
1412         if (os->segment_type == SEGMENT_TYPE_WEBM &&
1413             (ret = flush_init_segment(s, os)) < 0)
1414             return ret;
1415     }
1416     return ret;
1417 }
1418
1419 static int add_segment(OutputStream *os, const char *file,
1420                        int64_t time, int64_t duration,
1421                        int64_t start_pos, int64_t range_length,
1422                        int64_t index_length, int next_exp_index)
1423 {
1424     int err;
1425     Segment *seg;
1426     if (os->nb_segments >= os->segments_size) {
1427         os->segments_size = (os->segments_size + 1) * 2;
1428         if ((err = av_reallocp(&os->segments, sizeof(*os->segments) *
1429                                os->segments_size)) < 0) {
1430             os->segments_size = 0;
1431             os->nb_segments = 0;
1432             return err;
1433         }
1434     }
1435     seg = av_mallocz(sizeof(*seg));
1436     if (!seg)
1437         return AVERROR(ENOMEM);
1438     av_strlcpy(seg->file, file, sizeof(seg->file));
1439     seg->time = time;
1440     seg->duration = duration;
1441     if (seg->time < 0) { // If pts<0, it is expected to be cut away with an edit list
1442         seg->duration += seg->time;
1443         seg->time = 0;
1444     }
1445     seg->start_pos = start_pos;
1446     seg->range_length = range_length;
1447     seg->index_length = index_length;
1448     os->segments[os->nb_segments++] = seg;
1449     os->segment_index++;
1450     //correcting the segment index if it has fallen behind the expected value
1451     if (os->segment_index < next_exp_index) {
1452         av_log(NULL, AV_LOG_WARNING, "Correcting the segment index after file %s: current=%d corrected=%d\n",
1453                file, os->segment_index, next_exp_index);
1454         os->segment_index = next_exp_index;
1455     }
1456     return 0;
1457 }
1458
1459 static void write_styp(AVIOContext *pb)
1460 {
1461     avio_wb32(pb, 24);
1462     ffio_wfourcc(pb, "styp");
1463     ffio_wfourcc(pb, "msdh");
1464     avio_wb32(pb, 0); /* minor */
1465     ffio_wfourcc(pb, "msdh");
1466     ffio_wfourcc(pb, "msix");
1467 }
1468
1469 static void find_index_range(AVFormatContext *s, const char *full_path,
1470                              int64_t pos, int *index_length)
1471 {
1472     uint8_t buf[8];
1473     AVIOContext *pb;
1474     int ret;
1475
1476     ret = s->io_open(s, &pb, full_path, AVIO_FLAG_READ, NULL);
1477     if (ret < 0)
1478         return;
1479     if (avio_seek(pb, pos, SEEK_SET) != pos) {
1480         ff_format_io_close(s, &pb);
1481         return;
1482     }
1483     ret = avio_read(pb, buf, 8);
1484     ff_format_io_close(s, &pb);
1485     if (ret < 8)
1486         return;
1487     if (AV_RL32(&buf[4]) != MKTAG('s', 'i', 'd', 'x'))
1488         return;
1489     *index_length = AV_RB32(&buf[0]);
1490 }
1491
1492 static int update_stream_extradata(AVFormatContext *s, OutputStream *os,
1493                                    AVPacket *pkt, AVRational *frame_rate)
1494 {
1495     AVCodecParameters *par = os->ctx->streams[0]->codecpar;
1496     uint8_t *extradata;
1497     int ret, extradata_size;
1498
1499     if (par->extradata_size)
1500         return 0;
1501
1502     extradata = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &extradata_size);
1503     if (!extradata_size)
1504         return 0;
1505
1506     ret = ff_alloc_extradata(par, extradata_size);
1507     if (ret < 0)
1508         return ret;
1509
1510     memcpy(par->extradata, extradata, extradata_size);
1511
1512     set_codec_str(s, par, frame_rate, os->codec_str, sizeof(os->codec_str));
1513
1514     return 0;
1515 }
1516
1517 static void dashenc_delete_file(AVFormatContext *s, char *filename) {
1518     DASHContext *c = s->priv_data;
1519     int http_base_proto = ff_is_http_proto(filename);
1520
1521     if (http_base_proto) {
1522         AVIOContext *out = NULL;
1523         AVDictionary *http_opts = NULL;
1524
1525         set_http_options(&http_opts, c);
1526         av_dict_set(&http_opts, "method", "DELETE", 0);
1527
1528         if (dashenc_io_open(s, &out, filename, &http_opts) < 0) {
1529             av_log(s, AV_LOG_ERROR, "failed to delete %s\n", filename);
1530         }
1531
1532         av_dict_free(&http_opts);
1533         ff_format_io_close(s, &out);
1534     } else {
1535         int res = avpriv_io_delete(filename);
1536         if (res < 0) {
1537             char errbuf[AV_ERROR_MAX_STRING_SIZE];
1538             av_strerror(res, errbuf, sizeof(errbuf));
1539             av_log(s, (res == AVERROR(ENOENT) ? AV_LOG_WARNING : AV_LOG_ERROR), "failed to delete %s: %s\n", filename, errbuf);
1540         }
1541     }
1542 }
1543
1544 static int dashenc_delete_segment_file(AVFormatContext *s, const char* file)
1545 {
1546     DASHContext *c = s->priv_data;
1547     size_t dirname_len, file_len;
1548     char filename[1024];
1549
1550     dirname_len = strlen(c->dirname);
1551     if (dirname_len >= sizeof(filename)) {
1552         av_log(s, AV_LOG_WARNING, "Cannot delete segments as the directory path is too long: %"PRIu64" characters: %s\n",
1553             (uint64_t)dirname_len, c->dirname);
1554         return AVERROR(ENAMETOOLONG);
1555     }
1556
1557     memcpy(filename, c->dirname, dirname_len);
1558
1559     file_len = strlen(file);
1560     if ((dirname_len + file_len) >= sizeof(filename)) {
1561         av_log(s, AV_LOG_WARNING, "Cannot delete segments as the path is too long: %"PRIu64" characters: %s%s\n",
1562             (uint64_t)(dirname_len + file_len), c->dirname, file);
1563         return AVERROR(ENAMETOOLONG);
1564     }
1565
1566     memcpy(filename + dirname_len, file, file_len + 1); // include the terminating zero
1567     dashenc_delete_file(s, filename);
1568
1569     return 0;
1570 }
1571
1572 static inline void dashenc_delete_media_segments(AVFormatContext *s, OutputStream *os, int remove_count)
1573 {
1574     for (int i = 0; i < remove_count; ++i) {
1575         dashenc_delete_segment_file(s, os->segments[i]->file);
1576
1577         // Delete the segment regardless of whether the file was successfully deleted
1578         av_free(os->segments[i]);
1579     }
1580
1581     os->nb_segments -= remove_count;
1582     memmove(os->segments, os->segments + remove_count, os->nb_segments * sizeof(*os->segments));
1583 }
1584
1585 static int dash_flush(AVFormatContext *s, int final, int stream)
1586 {
1587     DASHContext *c = s->priv_data;
1588     int i, ret = 0;
1589
1590     const char *proto = avio_find_protocol_name(s->url);
1591     int use_rename = proto && !strcmp(proto, "file");
1592
1593     int cur_flush_segment_index = 0, next_exp_index = -1;
1594     if (stream >= 0) {
1595         cur_flush_segment_index = c->streams[stream].segment_index;
1596
1597         //finding the next segment's expected index, based on the current pts value
1598         if (c->use_template && !c->use_timeline && c->index_correction &&
1599             c->streams[stream].last_pts != AV_NOPTS_VALUE &&
1600             c->streams[stream].first_pts != AV_NOPTS_VALUE) {
1601             int64_t pts_diff = av_rescale_q(c->streams[stream].last_pts -
1602                                             c->streams[stream].first_pts,
1603                                             s->streams[stream]->time_base,
1604                                             AV_TIME_BASE_Q);
1605             next_exp_index = (pts_diff / c->streams[stream].seg_duration) + 1;
1606         }
1607     }
1608
1609     for (i = 0; i < s->nb_streams; i++) {
1610         OutputStream *os = &c->streams[i];
1611         AVStream *st = s->streams[i];
1612         int range_length, index_length = 0;
1613
1614         if (!os->packets_written)
1615             continue;
1616
1617         // Flush the single stream that got a keyframe right now.
1618         // Flush all audio streams as well, in sync with video keyframes,
1619         // but not the other video streams.
1620         if (stream >= 0 && i != stream) {
1621             if (s->streams[stream]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
1622                 s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)
1623                 continue;
1624             if (s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
1625                 continue;
1626             // Make sure we don't flush audio streams multiple times, when
1627             // all video streams are flushed one at a time.
1628             if (c->has_video && os->segment_index > cur_flush_segment_index)
1629                 continue;
1630         }
1631
1632         if (!c->single_file) {
1633             if (os->segment_type == SEGMENT_TYPE_MP4 && !os->written_len)
1634                 write_styp(os->ctx->pb);
1635         } else {
1636             snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile);
1637         }
1638
1639         ret = flush_dynbuf(c, os, &range_length);
1640         if (ret < 0)
1641             break;
1642         os->packets_written = 0;
1643
1644         if (c->single_file) {
1645             find_index_range(s, os->full_path, os->pos, &index_length);
1646         } else {
1647             dashenc_io_close(s, &os->out, os->temp_path);
1648
1649             if (use_rename) {
1650                 ret = avpriv_io_move(os->temp_path, os->full_path);
1651                 if (ret < 0)
1652                     break;
1653             }
1654         }
1655
1656         os->last_duration = FFMAX(os->last_duration, av_rescale_q(os->max_pts - os->start_pts,
1657                                                                   st->time_base,
1658                                                                   AV_TIME_BASE_Q));
1659
1660         if (!os->muxer_overhead)
1661             os->muxer_overhead = ((int64_t) (range_length - os->total_pkt_size) *
1662                                   8 * AV_TIME_BASE) /
1663                                  av_rescale_q(os->max_pts - os->start_pts,
1664                                               st->time_base, AV_TIME_BASE_Q);
1665         os->total_pkt_size = 0;
1666
1667         if (!os->bit_rate) {
1668             // calculate average bitrate of first segment
1669             int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / av_rescale_q(os->max_pts - os->start_pts,
1670                                                                                        st->time_base,
1671                                                                                        AV_TIME_BASE_Q);
1672             if (bitrate >= 0)
1673                 os->bit_rate = bitrate;
1674         }
1675         add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index);
1676         av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path);
1677
1678         os->pos += range_length;
1679     }
1680
1681     if (c->window_size) {
1682         for (i = 0; i < s->nb_streams; i++) {
1683             OutputStream *os = &c->streams[i];
1684             int remove_count = os->nb_segments - c->window_size - c->extra_window_size;
1685             if (remove_count > 0)
1686                 dashenc_delete_media_segments(s, os, remove_count);
1687         }
1688     }
1689
1690     if (final) {
1691         for (i = 0; i < s->nb_streams; i++) {
1692             OutputStream *os = &c->streams[i];
1693             if (os->ctx && os->ctx_inited) {
1694                 int64_t file_size = avio_tell(os->ctx->pb);
1695                 av_write_trailer(os->ctx);
1696                 if (c->global_sidx) {
1697                     int j, start_index, start_number;
1698                     int64_t sidx_size = avio_tell(os->ctx->pb) - file_size;
1699                     get_start_index_number(os, c, &start_index, &start_number);
1700                     if (start_index >= os->nb_segments ||
1701                         os->segment_type != SEGMENT_TYPE_MP4)
1702                         continue;
1703                     os->init_range_length += sidx_size;
1704                     for (j = start_index; j < os->nb_segments; j++) {
1705                         Segment *seg = os->segments[j];
1706                         seg->start_pos += sidx_size;
1707                     }
1708                 }
1709
1710             }
1711         }
1712     }
1713     if (ret >= 0) {
1714         if (c->has_video && !final) {
1715             c->nr_of_streams_flushed++;
1716             if (c->nr_of_streams_flushed != c->nr_of_streams_to_flush)
1717                 return ret;
1718
1719             c->nr_of_streams_flushed = 0;
1720         }
1721         ret = write_manifest(s, final);
1722     }
1723     return ret;
1724 }
1725
1726 static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
1727 {
1728     DASHContext *c = s->priv_data;
1729     AVStream *st = s->streams[pkt->stream_index];
1730     OutputStream *os = &c->streams[pkt->stream_index];
1731     int64_t seg_end_duration, elapsed_duration;
1732     int ret;
1733
1734     ret = update_stream_extradata(s, os, pkt, &st->avg_frame_rate);
1735     if (ret < 0)
1736         return ret;
1737
1738     // Fill in a heuristic guess of the packet duration, if none is available.
1739     // The mp4 muxer will do something similar (for the last packet in a fragment)
1740     // if nothing is set (setting it for the other packets doesn't hurt).
1741     // By setting a nonzero duration here, we can be sure that the mp4 muxer won't
1742     // invoke its heuristic (this doesn't have to be identical to that algorithm),
1743     // so that we know the exact timestamps of fragments.
1744     if (!pkt->duration && os->last_dts != AV_NOPTS_VALUE)
1745         pkt->duration = pkt->dts - os->last_dts;
1746     os->last_dts = pkt->dts;
1747
1748     // If forcing the stream to start at 0, the mp4 muxer will set the start
1749     // timestamps to 0. Do the same here, to avoid mismatches in duration/timestamps.
1750     if (os->first_pts == AV_NOPTS_VALUE &&
1751         s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
1752         pkt->pts -= pkt->dts;
1753         pkt->dts  = 0;
1754     }
1755
1756     if (os->first_pts == AV_NOPTS_VALUE)
1757         os->first_pts = pkt->pts;
1758     os->last_pts = pkt->pts;
1759
1760     if (!c->availability_start_time[0]) {
1761         int64_t start_time_us = av_gettime();
1762         c->start_time_s = start_time_us / 1000000;
1763         format_date_now(c->availability_start_time,
1764                         sizeof(c->availability_start_time));
1765     }
1766
1767     if (!os->availability_time_offset && pkt->duration) {
1768         int64_t frame_duration = av_rescale_q(pkt->duration, st->time_base,
1769                                               AV_TIME_BASE_Q);
1770          os->availability_time_offset = ((double) os->seg_duration -
1771                                          frame_duration) / AV_TIME_BASE;
1772     }
1773
1774     if (c->use_template && !c->use_timeline) {
1775         elapsed_duration = pkt->pts - os->first_pts;
1776         seg_end_duration = (int64_t) os->segment_index * os->seg_duration;
1777     } else {
1778         elapsed_duration = pkt->pts - os->start_pts;
1779         seg_end_duration = os->seg_duration;
1780     }
1781
1782     if (pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
1783         av_compare_ts(elapsed_duration, st->time_base,
1784                       seg_end_duration, AV_TIME_BASE_Q) >= 0) {
1785         if (!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
1786         c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
1787                                         st->time_base,
1788                                         AV_TIME_BASE_Q);
1789         c->total_duration = av_rescale_q(pkt->pts - os->first_pts,
1790                                          st->time_base,
1791                                          AV_TIME_BASE_Q);
1792
1793         if ((!c->use_timeline || !c->use_template) && os->last_duration) {
1794             if (c->last_duration < os->last_duration*9/10 ||
1795                 c->last_duration > os->last_duration*11/10) {
1796                 av_log(s, AV_LOG_WARNING,
1797                        "Segment durations differ too much, enable use_timeline "
1798                        "and use_template, or keep a stricter keyframe interval\n");
1799             }
1800         }
1801         }
1802
1803         if ((ret = dash_flush(s, 0, pkt->stream_index)) < 0)
1804             return ret;
1805     }
1806
1807     if (!os->packets_written) {
1808         // If we wrote a previous segment, adjust the start time of the segment
1809         // to the end of the previous one (which is the same as the mp4 muxer
1810         // does). This avoids gaps in the timeline.
1811         if (os->max_pts != AV_NOPTS_VALUE)
1812             os->start_pts = os->max_pts;
1813         else
1814             os->start_pts = pkt->pts;
1815     }
1816     if (os->max_pts == AV_NOPTS_VALUE)
1817         os->max_pts = pkt->pts + pkt->duration;
1818     else
1819         os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
1820     os->packets_written++;
1821     os->total_pkt_size += pkt->size;
1822     if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
1823         return ret;
1824
1825     if (!os->init_range_length)
1826         flush_init_segment(s, os);
1827
1828     //open the output context when the first frame of a segment is ready
1829     if (!c->single_file && os->packets_written == 1) {
1830         AVDictionary *opts = NULL;
1831         const char *proto = avio_find_protocol_name(s->url);
1832         int use_rename = proto && !strcmp(proto, "file");
1833         os->filename[0] = os->full_path[0] = os->temp_path[0] = '\0';
1834         ff_dash_fill_tmpl_params(os->filename, sizeof(os->filename),
1835                                  os->media_seg_name, pkt->stream_index,
1836                                  os->segment_index, os->bit_rate, os->start_pts);
1837         snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname,
1838                  os->filename);
1839         snprintf(os->temp_path, sizeof(os->temp_path),
1840                  use_rename ? "%s.tmp" : "%s", os->full_path);
1841         set_http_options(&opts, c);
1842         ret = dashenc_io_open(s, &os->out, os->temp_path, &opts);
1843         av_dict_free(&opts);
1844         if (ret < 0) {
1845             return handle_io_open_error(s, ret, os->temp_path);
1846         }
1847         if (c->lhls) {
1848             char *prefetch_url = use_rename ? NULL : os->filename;
1849             write_hls_media_playlist(os, s, pkt->stream_index, 0, prefetch_url);
1850         }
1851     }
1852
1853     //write out the data immediately in streaming mode
1854     if (c->streaming && os->segment_type == SEGMENT_TYPE_MP4) {
1855         int len = 0;
1856         uint8_t *buf = NULL;
1857         if (!os->written_len)
1858             write_styp(os->ctx->pb);
1859         avio_flush(os->ctx->pb);
1860         len = avio_get_dyn_buf (os->ctx->pb, &buf);
1861         if (os->out) {
1862             avio_write(os->out, buf + os->written_len, len - os->written_len);
1863             avio_flush(os->out);
1864         }
1865         os->written_len = len;
1866     }
1867
1868     return ret;
1869 }
1870
1871 static int dash_write_trailer(AVFormatContext *s)
1872 {
1873     DASHContext *c = s->priv_data;
1874     int i;
1875
1876     if (s->nb_streams > 0) {
1877         OutputStream *os = &c->streams[0];
1878         // If no segments have been written so far, try to do a crude
1879         // guess of the segment duration
1880         if (!c->last_duration)
1881             c->last_duration = av_rescale_q(os->max_pts - os->start_pts,
1882                                             s->streams[0]->time_base,
1883                                             AV_TIME_BASE_Q);
1884         c->total_duration = av_rescale_q(os->max_pts - os->first_pts,
1885                                          s->streams[0]->time_base,
1886                                          AV_TIME_BASE_Q);
1887     }
1888     dash_flush(s, 1, -1);
1889
1890     if (c->remove_at_exit) {
1891         for (i = 0; i < s->nb_streams; ++i) {
1892             OutputStream *os = &c->streams[i];
1893             dashenc_delete_media_segments(s, os, os->nb_segments);
1894             dashenc_delete_segment_file(s, os->initfile);
1895             if (c->hls_playlist && os->segment_type == SEGMENT_TYPE_MP4) {
1896                 char filename[1024];
1897                 get_hls_playlist_name(filename, sizeof(filename), c->dirname, i);
1898                 dashenc_delete_file(s, filename);
1899             }
1900         }
1901         dashenc_delete_file(s, s->url);
1902
1903         if (c->hls_playlist && c->master_playlist_created) {
1904             char filename[1024];
1905             snprintf(filename, sizeof(filename), "%smaster.m3u8", c->dirname);
1906             dashenc_delete_file(s, filename);
1907         }
1908     }
1909
1910     return 0;
1911 }
1912
1913 static int dash_check_bitstream(struct AVFormatContext *s, const AVPacket *avpkt)
1914 {
1915     DASHContext *c = s->priv_data;
1916     OutputStream *os = &c->streams[avpkt->stream_index];
1917     AVFormatContext *oc = os->ctx;
1918     if (oc->oformat->check_bitstream) {
1919         int ret;
1920         AVPacket pkt = *avpkt;
1921         pkt.stream_index = 0;
1922         ret = oc->oformat->check_bitstream(oc, &pkt);
1923         if (ret == 1) {
1924             AVStream *st = s->streams[avpkt->stream_index];
1925             AVStream *ost = oc->streams[0];
1926             st->internal->bsfcs = ost->internal->bsfcs;
1927             st->internal->nb_bsfcs = ost->internal->nb_bsfcs;
1928             ost->internal->bsfcs = NULL;
1929             ost->internal->nb_bsfcs = 0;
1930         }
1931         return ret;
1932     }
1933     return 1;
1934 }
1935
1936 #define OFFSET(x) offsetof(DASHContext, x)
1937 #define E AV_OPT_FLAG_ENCODING_PARAM
1938 static const AVOption options[] = {
1939     { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
1940     { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
1941     { "extra_window_size", "number of segments kept outside of the manifest before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 = 5 }, 0, INT_MAX, E },
1942 #if FF_API_DASH_MIN_SEG_DURATION
1943     { "min_seg_duration", "minimum segment duration (in microseconds) (will be deprecated)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E },
1944 #endif
1945     { "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 5000000 }, 0, INT_MAX, E },
1946     { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1947     { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
1948     { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
1949     { "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1950     { "single_file_name", "DASH-templated name to be used for baseURL. Implies storing all segments in one file, accessed using byte ranges", OFFSET(single_file_name), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
1951     { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.$ext$"}, 0, 0, E },
1952     { "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.$ext$"}, 0, 0, E },
1953     { "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), AV_OPT_TYPE_STRING, { 0 }, 0, 0, E },
1954     { "method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
1955     { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
1956     { "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
1957     { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1958     { "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1959     { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
1960     { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1961     { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options), AV_OPT_TYPE_DICT, {.str = NULL},  0, 0, E},
1962     { "global_sidx", "Write global SIDX atom. Applicable only for single file, mp4 output, non-streaming mode", OFFSET(global_sidx), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1963     { "dash_segment_type", "set dash segment files type", OFFSET(segment_type_option), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_AUTO }, 0, SEGMENT_TYPE_NB - 1, E, "segment_type"},
1964     { "auto", "select segment file format based on codec", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_AUTO }, 0, UINT_MAX,   E, "segment_type"},
1965     { "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4 }, 0, UINT_MAX,   E, "segment_type"},
1966     { "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM }, 0, UINT_MAX,   E, "segment_type"},
1967     { "ignore_io_errors", "Ignore IO errors during open and write. Useful for long-duration runs with network output", OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1968     { "lhls", "Enable Low-latency HLS(Experimental). Adds #EXT-X-PREFETCH tag with current segment's URI", OFFSET(lhls), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1969     { "master_m3u8_publish_rate", "Publish master playlist every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E},
1970     { NULL },
1971 };
1972
1973 static const AVClass dash_class = {
1974     .class_name = "dash muxer",
1975     .item_name  = av_default_item_name,
1976     .option     = options,
1977     .version    = LIBAVUTIL_VERSION_INT,
1978 };
1979
1980 AVOutputFormat ff_dash_muxer = {
1981     .name           = "dash",
1982     .long_name      = NULL_IF_CONFIG_SMALL("DASH Muxer"),
1983     .extensions     = "mpd",
1984     .priv_data_size = sizeof(DASHContext),
1985     .audio_codec    = AV_CODEC_ID_AAC,
1986     .video_codec    = AV_CODEC_ID_H264,
1987     .flags          = AVFMT_GLOBALHEADER | AVFMT_NOFILE | AVFMT_TS_NEGATIVE,
1988     .init           = dash_init,
1989     .write_header   = dash_write_header,
1990     .write_packet   = dash_write_packet,
1991     .write_trailer  = dash_write_trailer,
1992     .deinit         = dash_free,
1993     .check_bitstream = dash_check_bitstream,
1994     .priv_class     = &dash_class,
1995 };