FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dashenc.c
Go to the documentation of this file.
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/rational.h"
36 
37 #include "avc.h"
38 #include "avformat.h"
39 #include "avio_internal.h"
40 #include "hlsplaylist.h"
41 #if CONFIG_HTTP_PROTOCOL
42 #include "http.h"
43 #endif
44 #include "internal.h"
45 #include "isom.h"
46 #include "os_support.h"
47 #include "url.h"
48 #include "vpcc.h"
49 #include "dash.h"
50 
51 typedef enum {
55 } SegmentType;
56 
57 typedef struct Segment {
58  char file[1024];
59  int64_t start_pos;
61  int64_t time;
62  int duration;
63  int n;
64 } Segment;
65 
66 typedef struct AdaptationSet {
67  char id[10];
73 
74 typedef struct OutputStream {
79  char initfile[1024];
80  int64_t init_start_pos, pos;
85  int64_t last_dts, last_pts;
86  int bit_rate;
87 
88  char codec_str[100];
90  char filename[1024];
91  char full_path[1024];
92  char temp_path[1024];
96 } OutputStream;
97 
98 typedef struct DASHContext {
99  const AVClass *class; /* Class for private options. */
102  int nb_as;
105 #if FF_API_DASH_MIN_SEG_DURATION
106  int min_seg_duration;
107 #endif
108  int64_t seg_duration;
115  int64_t last_duration;
116  int64_t total_duration;
118  char dirname[1024];
119  const char *single_file_name;
120  const char *init_seg_name;
121  const char *media_seg_name;
122  const char *utc_timing_url;
123  const char *method;
124  const char *user_agent;
131  int64_t timeout;
135  const char *format_name;
136 } DASHContext;
137 
138 static struct codec_string {
139  int id;
140  const char *str;
141 } codecs[] = {
142  { AV_CODEC_ID_VP8, "vp8" },
143  { AV_CODEC_ID_VP9, "vp9" },
144  { AV_CODEC_ID_VORBIS, "vorbis" },
145  { AV_CODEC_ID_OPUS, "opus" },
146  { 0, NULL }
147 };
148 
149 static struct format_string {
151  const char *str;
152 } formats[] = {
153  { SEGMENT_TYPE_MP4, "mp4" },
154  { SEGMENT_TYPE_WEBM, "webm" },
155  { 0, NULL }
156 };
157 
158 static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename,
159  AVDictionary **options) {
160  DASHContext *c = s->priv_data;
161  int http_base_proto = filename ? ff_is_http_proto(filename) : 0;
162  int err = AVERROR_MUXER_NOT_FOUND;
163  if (!*pb || !http_base_proto || !c->http_persistent) {
164  err = s->io_open(s, pb, filename, AVIO_FLAG_WRITE, options);
165 #if CONFIG_HTTP_PROTOCOL
166  } else {
167  URLContext *http_url_context = ffio_geturlcontext(*pb);
168  av_assert0(http_url_context);
169  err = ff_http_do_new_request(http_url_context, filename);
170 #endif
171  }
172  return err;
173 }
174 
175 static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename) {
176  DASHContext *c = s->priv_data;
177  int http_base_proto = filename ? ff_is_http_proto(filename) : 0;
178 
179  if (!http_base_proto || !c->http_persistent) {
180  ff_format_io_close(s, pb);
181 #if CONFIG_HTTP_PROTOCOL
182  } else {
183  URLContext *http_url_context = ffio_geturlcontext(*pb);
184  av_assert0(http_url_context);
185  avio_flush(*pb);
186  ffurl_shutdown(http_url_context, AVIO_FLAG_WRITE);
187 #endif
188  }
189 }
190 
191 static const char *get_format_str(SegmentType segment_type) {
192  int i;
193  for (i = 0; i < SEGMENT_TYPE_NB; i++)
194  if (formats[i].segment_type == segment_type)
195  return formats[i].str;
196  return NULL;
197 }
198 
199 static int check_file_extension(const char *filename, const char *extension) {
200  char *dot;
201  if (!filename || !extension)
202  return -1;
203  dot = strrchr(filename, '.');
204  if (dot && !strcmp(dot + 1, extension))
205  return 0;
206  return -1;
207 }
208 
210  AVRational *frame_rate, char *str, int size) {
211  VPCC vpcc;
212  int ret = ff_isom_get_vpcc_features(s, par, frame_rate, &vpcc);
213  if (ret == 0) {
214  av_strlcatf(str, size, "vp09.%02d.%02d.%02d",
215  vpcc.profile, vpcc.level, vpcc.bitdepth);
216  } else {
217  // Default to just vp9 in case of error while finding out profile or level
218  av_log(s, AV_LOG_WARNING, "Could not find VP9 profile and/or level\n");
219  av_strlcpy(str, "vp9", size);
220  }
221  return;
222 }
223 
225  AVRational *frame_rate, char *str, int size)
226 {
227  const AVCodecTag *tags[2] = { NULL, NULL };
228  uint32_t tag;
229  int i;
230 
231  // common Webm codecs are not part of RFC 6381
232  for (i = 0; codecs[i].id; i++)
233  if (codecs[i].id == par->codec_id) {
234  if (codecs[i].id == AV_CODEC_ID_VP9) {
235  set_vp9_codec_str(s, par, frame_rate, str, size);
236  } else {
237  av_strlcpy(str, codecs[i].str, size);
238  }
239  return;
240  }
241 
242  // for codecs part of RFC 6381
243  if (par->codec_type == AVMEDIA_TYPE_VIDEO)
244  tags[0] = ff_codec_movvideo_tags;
245  else if (par->codec_type == AVMEDIA_TYPE_AUDIO)
246  tags[0] = ff_codec_movaudio_tags;
247  else
248  return;
249 
250  tag = par->codec_tag;
251  if (!tag)
252  tag = av_codec_get_tag(tags, par->codec_id);
253  if (!tag)
254  return;
255  if (size < 5)
256  return;
257 
258  AV_WL32(str, tag);
259  str[4] = '\0';
260  if (!strcmp(str, "mp4a") || !strcmp(str, "mp4v")) {
261  uint32_t oti;
262  tags[0] = ff_mp4_obj_type;
263  oti = av_codec_get_tag(tags, par->codec_id);
264  if (oti)
265  av_strlcatf(str, size, ".%02"PRIx32, oti);
266  else
267  return;
268 
269  if (tag == MKTAG('m', 'p', '4', 'a')) {
270  if (par->extradata_size >= 2) {
271  int aot = par->extradata[0] >> 3;
272  if (aot == 31)
273  aot = ((AV_RB16(par->extradata) >> 5) & 0x3f) + 32;
274  av_strlcatf(str, size, ".%d", aot);
275  }
276  } else if (tag == MKTAG('m', 'p', '4', 'v')) {
277  // Unimplemented, should output ProfileLevelIndication as a decimal number
278  av_log(s, AV_LOG_WARNING, "Incomplete RFC 6381 codec string for mp4v\n");
279  }
280  } else if (!strcmp(str, "avc1")) {
281  uint8_t *tmpbuf = NULL;
282  uint8_t *extradata = par->extradata;
283  int extradata_size = par->extradata_size;
284  if (!extradata_size)
285  return;
286  if (extradata[0] != 1) {
287  AVIOContext *pb;
288  if (avio_open_dyn_buf(&pb) < 0)
289  return;
290  if (ff_isom_write_avcc(pb, extradata, extradata_size) < 0) {
291  ffio_free_dyn_buf(&pb);
292  return;
293  }
294  extradata_size = avio_close_dyn_buf(pb, &extradata);
295  tmpbuf = extradata;
296  }
297 
298  if (extradata_size >= 4)
299  av_strlcatf(str, size, ".%02x%02x%02x",
300  extradata[1], extradata[2], extradata[3]);
301  av_free(tmpbuf);
302  }
303 }
304 
305 static int flush_dynbuf(OutputStream *os, int *range_length)
306 {
307  uint8_t *buffer;
308 
309  if (!os->ctx->pb) {
310  return AVERROR(EINVAL);
311  }
312 
313  // flush
314  av_write_frame(os->ctx, NULL);
315  avio_flush(os->ctx->pb);
316 
317  // write out to file
318  *range_length = avio_close_dyn_buf(os->ctx->pb, &buffer);
319  os->ctx->pb = NULL;
320  avio_write(os->out, buffer + os->written_len, *range_length - os->written_len);
321  os->written_len = 0;
322  av_free(buffer);
323 
324  // re-open buffer
325  return avio_open_dyn_buf(&os->ctx->pb);
326 }
327 
329 {
330  if (c->method)
331  av_dict_set(options, "method", c->method, 0);
332  if (c->user_agent)
333  av_dict_set(options, "user_agent", c->user_agent, 0);
334  if (c->http_persistent)
335  av_dict_set_int(options, "multiple_requests", 1, 0);
336  if (c->timeout >= 0)
337  av_dict_set_int(options, "timeout", c->timeout, 0);
338 }
339 
340 static void get_hls_playlist_name(char *playlist_name, int string_size,
341  const char *base_url, int id) {
342  if (base_url)
343  snprintf(playlist_name, string_size, "%smedia_%d.m3u8", base_url, id);
344  else
345  snprintf(playlist_name, string_size, "media_%d.m3u8", id);
346 }
347 
349 {
350  DASHContext *c = s->priv_data;
351  int ret, range_length;
352 
353  ret = flush_dynbuf(os, &range_length);
354  if (ret < 0)
355  return ret;
356 
357  os->pos = os->init_range_length = range_length;
358  if (!c->single_file) {
359  char filename[1024];
360  snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
361  dashenc_io_close(s, &os->out, filename);
362  }
363  return 0;
364 }
365 
367 {
368  DASHContext *c = s->priv_data;
369  int i, j;
370 
371  if (c->as) {
372  for (i = 0; i < c->nb_as; i++)
373  av_dict_free(&c->as[i].metadata);
374  av_freep(&c->as);
375  c->nb_as = 0;
376  }
377 
378  if (!c->streams)
379  return;
380  for (i = 0; i < s->nb_streams; i++) {
381  OutputStream *os = &c->streams[i];
382  if (os->ctx && os->ctx_inited)
383  av_write_trailer(os->ctx);
384  if (os->ctx && os->ctx->pb)
385  ffio_free_dyn_buf(&os->ctx->pb);
386  ff_format_io_close(s, &os->out);
387  if (os->ctx)
389  for (j = 0; j < os->nb_segments; j++)
390  av_free(os->segments[j]);
391  av_free(os->segments);
392  }
393  av_freep(&c->streams);
394 
395  ff_format_io_close(s, &c->mpd_out);
397 }
398 
400  int representation_id, int final)
401 {
402  DASHContext *c = s->priv_data;
403  int i, start_index = 0, start_number = 1;
404  if (c->window_size) {
405  start_index = FFMAX(os->nb_segments - c->window_size, 0);
406  start_number = FFMAX(os->segment_index - c->window_size, 1);
407  }
408 
409  if (c->use_template) {
410  int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : AV_TIME_BASE;
411  avio_printf(out, "\t\t\t\t<SegmentTemplate timescale=\"%d\" ", timescale);
412  if (!c->use_timeline) {
413  avio_printf(out, "duration=\"%"PRId64"\" ", c->seg_duration);
414  if (c->streaming && os->availability_time_offset)
415  avio_printf(out, "availabilityTimeOffset=\"%.3f\" ",
417  }
418  avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? start_number : 1);
419  if (c->use_timeline) {
420  int64_t cur_time = 0;
421  avio_printf(out, "\t\t\t\t\t<SegmentTimeline>\n");
422  for (i = start_index; i < os->nb_segments; ) {
423  Segment *seg = os->segments[i];
424  int repeat = 0;
425  avio_printf(out, "\t\t\t\t\t\t<S ");
426  if (i == start_index || seg->time != cur_time) {
427  cur_time = seg->time;
428  avio_printf(out, "t=\"%"PRId64"\" ", seg->time);
429  }
430  avio_printf(out, "d=\"%d\" ", seg->duration);
431  while (i + repeat + 1 < os->nb_segments &&
432  os->segments[i + repeat + 1]->duration == seg->duration &&
433  os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]->duration)
434  repeat++;
435  if (repeat > 0)
436  avio_printf(out, "r=\"%d\" ", repeat);
437  avio_printf(out, "/>\n");
438  i += 1 + repeat;
439  cur_time += (1 + repeat) * seg->duration;
440  }
441  avio_printf(out, "\t\t\t\t\t</SegmentTimeline>\n");
442  }
443  avio_printf(out, "\t\t\t\t</SegmentTemplate>\n");
444  } else if (c->single_file) {
445  avio_printf(out, "\t\t\t\t<BaseURL>%s</BaseURL>\n", os->initfile);
446  avio_printf(out, "\t\t\t\t<SegmentList timescale=\"%d\" duration=\"%"PRId64"\" startNumber=\"%d\">\n", AV_TIME_BASE, c->last_duration, start_number);
447  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);
448  for (i = start_index; i < os->nb_segments; i++) {
449  Segment *seg = os->segments[i];
450  avio_printf(out, "\t\t\t\t\t<SegmentURL mediaRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->range_length - 1);
451  if (seg->index_length)
452  avio_printf(out, "indexRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->index_length - 1);
453  avio_printf(out, "/>\n");
454  }
455  avio_printf(out, "\t\t\t\t</SegmentList>\n");
456  } else {
457  avio_printf(out, "\t\t\t\t<SegmentList timescale=\"%d\" duration=\"%"PRId64"\" startNumber=\"%d\">\n", AV_TIME_BASE, c->last_duration, start_number);
458  avio_printf(out, "\t\t\t\t\t<Initialization sourceURL=\"%s\" />\n", os->initfile);
459  for (i = start_index; i < os->nb_segments; i++) {
460  Segment *seg = os->segments[i];
461  avio_printf(out, "\t\t\t\t\t<SegmentURL media=\"%s\" />\n", seg->file);
462  }
463  avio_printf(out, "\t\t\t\t</SegmentList>\n");
464  }
465  if (c->hls_playlist && start_index < os->nb_segments)
466  {
467  int timescale = os->ctx->streams[0]->time_base.den;
468  char temp_filename_hls[1024];
469  char filename_hls[1024];
470  AVDictionary *http_opts = NULL;
471  int target_duration = 0;
472  int ret = 0;
473  const char *proto = avio_find_protocol_name(c->dirname);
474  int use_rename = proto && !strcmp(proto, "file");
475 
476  get_hls_playlist_name(filename_hls, sizeof(filename_hls),
477  c->dirname, representation_id);
478 
479  snprintf(temp_filename_hls, sizeof(temp_filename_hls), use_rename ? "%s.tmp" : "%s", filename_hls);
480 
481  set_http_options(&http_opts, c);
482  dashenc_io_open(s, &c->m3u8_out, temp_filename_hls, &http_opts);
483  av_dict_free(&http_opts);
484  for (i = start_index; i < os->nb_segments; i++) {
485  Segment *seg = os->segments[i];
486  double duration = (double) seg->duration / timescale;
487  if (target_duration <= duration)
488  target_duration = lrint(duration);
489  }
490 
491  ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration,
492  start_number, PLAYLIST_TYPE_NONE);
493 
496 
497  for (i = start_index; i < os->nb_segments; i++) {
498  Segment *seg = os->segments[i];
500  (double) seg->duration / timescale, 0,
501  seg->range_length, seg->start_pos, NULL,
502  c->single_file ? os->initfile : seg->file,
503  NULL);
504  if (ret < 0) {
505  av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
506  }
507  }
508 
509  if (final)
511 
512  dashenc_io_close(s, &c->m3u8_out, temp_filename_hls);
513 
514  if (use_rename)
515  if (avpriv_io_move(temp_filename_hls, filename_hls) < 0) {
516  av_log(os->ctx, AV_LOG_WARNING, "renaming file %s to %s failed\n\n", temp_filename_hls, filename_hls);
517  }
518  }
519 
520 }
521 
522 static char *xmlescape(const char *str) {
523  int outlen = strlen(str)*3/2 + 6;
524  char *out = av_realloc(NULL, outlen + 1);
525  int pos = 0;
526  if (!out)
527  return NULL;
528  for (; *str; str++) {
529  if (pos + 6 > outlen) {
530  char *tmp;
531  outlen = 2 * outlen + 6;
532  tmp = av_realloc(out, outlen + 1);
533  if (!tmp) {
534  av_free(out);
535  return NULL;
536  }
537  out = tmp;
538  }
539  if (*str == '&') {
540  memcpy(&out[pos], "&amp;", 5);
541  pos += 5;
542  } else if (*str == '<') {
543  memcpy(&out[pos], "&lt;", 4);
544  pos += 4;
545  } else if (*str == '>') {
546  memcpy(&out[pos], "&gt;", 4);
547  pos += 4;
548  } else if (*str == '\'') {
549  memcpy(&out[pos], "&apos;", 6);
550  pos += 6;
551  } else if (*str == '\"') {
552  memcpy(&out[pos], "&quot;", 6);
553  pos += 6;
554  } else {
555  out[pos++] = *str;
556  }
557  }
558  out[pos] = '\0';
559  return out;
560 }
561 
562 static void write_time(AVIOContext *out, int64_t time)
563 {
564  int seconds = time / AV_TIME_BASE;
565  int fractions = time % AV_TIME_BASE;
566  int minutes = seconds / 60;
567  int hours = minutes / 60;
568  seconds %= 60;
569  minutes %= 60;
570  avio_printf(out, "PT");
571  if (hours)
572  avio_printf(out, "%dH", hours);
573  if (hours || minutes)
574  avio_printf(out, "%dM", minutes);
575  avio_printf(out, "%d.%dS", seconds, fractions / (AV_TIME_BASE / 10));
576 }
577 
578 static void format_date_now(char *buf, int size)
579 {
580  time_t t = time(NULL);
581  struct tm *ptm, tmbuf;
582  ptm = gmtime_r(&t, &tmbuf);
583  if (ptm) {
584  if (!strftime(buf, size, "%Y-%m-%dT%H:%M:%SZ", ptm))
585  buf[0] = '\0';
586  }
587 }
588 
590  int final)
591 {
592  DASHContext *c = s->priv_data;
593  AdaptationSet *as = &c->as[as_index];
594  AVDictionaryEntry *lang, *role;
595  int i;
596 
597  avio_printf(out, "\t\t<AdaptationSet id=\"%s\" contentType=\"%s\" segmentAlignment=\"true\" bitstreamSwitching=\"true\"",
598  as->id, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
600  avio_printf(out, " maxFrameRate=\"%d/%d\"", as->max_frame_rate.num, as->max_frame_rate.den);
601  lang = av_dict_get(as->metadata, "language", NULL, 0);
602  if (lang)
603  avio_printf(out, " lang=\"%s\"", lang->value);
604  avio_printf(out, ">\n");
605 
606  role = av_dict_get(as->metadata, "role", NULL, 0);
607  if (role)
608  avio_printf(out, "\t\t\t<Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"%s\"/>\n", role->value);
609 
610  for (i = 0; i < s->nb_streams; i++) {
611  OutputStream *os = &c->streams[i];
612  char bandwidth_str[64] = {'\0'};
613 
614  if (os->as_idx - 1 != as_index)
615  continue;
616 
617  if (os->bit_rate > 0)
618  snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
619  os->bit_rate);
620 
621  if (as->media_type == AVMEDIA_TYPE_VIDEO) {
622  AVStream *st = s->streams[i];
623  avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"",
624  i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
625  if (st->avg_frame_rate.num)
626  avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den);
627  avio_printf(out, ">\n");
628  } else {
629  avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
630  i, c->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate);
631  avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n",
632  s->streams[i]->codecpar->channels);
633  }
634  output_segment_list(os, out, s, i, final);
635  avio_printf(out, "\t\t\t</Representation>\n");
636  }
637  avio_printf(out, "\t\t</AdaptationSet>\n");
638 
639  return 0;
640 }
641 
643 {
644  DASHContext *c = s->priv_data;
645 
646  void *mem = av_realloc(c->as, sizeof(*c->as) * (c->nb_as + 1));
647  if (!mem)
648  return AVERROR(ENOMEM);
649  c->as = mem;
650  ++c->nb_as;
651 
652  *as = &c->as[c->nb_as - 1];
653  memset(*as, 0, sizeof(**as));
654  (*as)->media_type = type;
655 
656  return 0;
657 }
658 
659 static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i)
660 {
661  DASHContext *c = s->priv_data;
662  AdaptationSet *as = &c->as[as_idx - 1];
663  OutputStream *os = &c->streams[i];
664 
665  if (as->media_type != s->streams[i]->codecpar->codec_type) {
666  av_log(s, AV_LOG_ERROR, "Codec type of stream %d doesn't match AdaptationSet's media type\n", i);
667  return AVERROR(EINVAL);
668  } else if (os->as_idx) {
669  av_log(s, AV_LOG_ERROR, "Stream %d is already assigned to an AdaptationSet\n", i);
670  return AVERROR(EINVAL);
671  }
672  os->as_idx = as_idx;
673 
674  return 0;
675 }
676 
678 {
679  DASHContext *c = s->priv_data;
680  const char *p = c->adaptation_sets;
681  enum { new_set, parse_id, parsing_streams } state;
682  AdaptationSet *as;
683  int i, n, ret;
684 
685  // default: one AdaptationSet for each stream
686  if (!p) {
687  for (i = 0; i < s->nb_streams; i++) {
688  if ((ret = add_adaptation_set(s, &as, s->streams[i]->codecpar->codec_type)) < 0)
689  return ret;
690  snprintf(as->id, sizeof(as->id), "%d", i);
691 
692  c->streams[i].as_idx = c->nb_as;
693  }
694  goto end;
695  }
696 
697  // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
698  state = new_set;
699  while (*p) {
700  if (*p == ' ') {
701  p++;
702  continue;
703  } else if (state == new_set && av_strstart(p, "id=", &p)) {
704 
705  if ((ret = add_adaptation_set(s, &as, AVMEDIA_TYPE_UNKNOWN)) < 0)
706  return ret;
707 
708  n = strcspn(p, ",");
709  snprintf(as->id, sizeof(as->id), "%.*s", n, p);
710 
711  p += n;
712  if (*p)
713  p++;
714  state = parse_id;
715  } else if (state == parse_id && av_strstart(p, "streams=", &p)) {
716  state = parsing_streams;
717  } else if (state == parsing_streams) {
718  AdaptationSet *as = &c->as[c->nb_as - 1];
719  char idx_str[8], *end_str;
720 
721  n = strcspn(p, " ,");
722  snprintf(idx_str, sizeof(idx_str), "%.*s", n, p);
723  p += n;
724 
725  // if value is "a" or "v", map all streams of that type
726  if (as->media_type == AVMEDIA_TYPE_UNKNOWN && (idx_str[0] == 'v' || idx_str[0] == 'a')) {
727  enum AVMediaType type = (idx_str[0] == 'v') ? AVMEDIA_TYPE_VIDEO : AVMEDIA_TYPE_AUDIO;
728  av_log(s, AV_LOG_DEBUG, "Map all streams of type %s\n", idx_str);
729 
730  for (i = 0; i < s->nb_streams; i++) {
731  if (s->streams[i]->codecpar->codec_type != type)
732  continue;
733 
734  as->media_type = s->streams[i]->codecpar->codec_type;
735 
736  if ((ret = adaptation_set_add_stream(s, c->nb_as, i)) < 0)
737  return ret;
738  }
739  } else { // select single stream
740  i = strtol(idx_str, &end_str, 10);
741  if (idx_str == end_str || i < 0 || i >= s->nb_streams) {
742  av_log(s, AV_LOG_ERROR, "Selected stream \"%s\" not found!\n", idx_str);
743  return AVERROR(EINVAL);
744  }
745  av_log(s, AV_LOG_DEBUG, "Map stream %d\n", i);
746 
747  if (as->media_type == AVMEDIA_TYPE_UNKNOWN) {
748  as->media_type = s->streams[i]->codecpar->codec_type;
749  }
750 
751  if ((ret = adaptation_set_add_stream(s, c->nb_as, i)) < 0)
752  return ret;
753  }
754 
755  if (*p == ' ')
756  state = new_set;
757  if (*p)
758  p++;
759  } else {
760  return AVERROR(EINVAL);
761  }
762  }
763 
764 end:
765  // check for unassigned streams
766  for (i = 0; i < s->nb_streams; i++) {
767  OutputStream *os = &c->streams[i];
768  if (!os->as_idx) {
769  av_log(s, AV_LOG_ERROR, "Stream %d is not mapped to an AdaptationSet\n", i);
770  return AVERROR(EINVAL);
771  }
772  }
773  return 0;
774 }
775 
776 static int write_manifest(AVFormatContext *s, int final)
777 {
778  DASHContext *c = s->priv_data;
779  AVIOContext *out;
780  char temp_filename[1024];
781  int ret, i;
782  const char *proto = avio_find_protocol_name(s->url);
783  int use_rename = proto && !strcmp(proto, "file");
784  static unsigned int warned_non_file = 0;
785  AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
787 
788  if (!use_rename && !warned_non_file++)
789  av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n");
790 
791  snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->url);
792  set_http_options(&opts, c);
793  ret = dashenc_io_open(s, &c->mpd_out, temp_filename, &opts);
794  if (ret < 0) {
795  av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
796  return ret;
797  }
798  out = c->mpd_out;
799  av_dict_free(&opts);
800  avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
801  avio_printf(out, "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
802  "\txmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
803  "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
804  "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n"
805  "\tprofiles=\"urn:mpeg:dash:profile:isoff-live:2011\"\n"
806  "\ttype=\"%s\"\n", final ? "static" : "dynamic");
807  if (final) {
808  avio_printf(out, "\tmediaPresentationDuration=\"");
809  write_time(out, c->total_duration);
810  avio_printf(out, "\"\n");
811  } else {
812  int64_t update_period = c->last_duration / AV_TIME_BASE;
813  char now_str[100];
814  if (c->use_template && !c->use_timeline)
815  update_period = 500;
816  avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", update_period);
817  avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", c->last_duration / AV_TIME_BASE);
818  if (c->availability_start_time[0])
819  avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", c->availability_start_time);
820  format_date_now(now_str, sizeof(now_str));
821  if (now_str[0])
822  avio_printf(out, "\tpublishTime=\"%s\"\n", now_str);
823  if (c->window_size && c->use_template) {
824  avio_printf(out, "\ttimeShiftBufferDepth=\"");
825  write_time(out, c->last_duration * c->window_size);
826  avio_printf(out, "\"\n");
827  }
828  }
829  avio_printf(out, "\tminBufferTime=\"");
830  write_time(out, c->last_duration * 2);
831  avio_printf(out, "\">\n");
832  avio_printf(out, "\t<ProgramInformation>\n");
833  if (title) {
834  char *escaped = xmlescape(title->value);
835  avio_printf(out, "\t\t<Title>%s</Title>\n", escaped);
836  av_free(escaped);
837  }
838  avio_printf(out, "\t</ProgramInformation>\n");
839 
840  if (c->window_size && s->nb_streams > 0 && c->streams[0].nb_segments > 0 && !c->use_template) {
841  OutputStream *os = &c->streams[0];
842  int start_index = FFMAX(os->nb_segments - c->window_size, 0);
843  int64_t start_time = av_rescale_q(os->segments[start_index]->time, s->streams[0]->time_base, AV_TIME_BASE_Q);
844  avio_printf(out, "\t<Period id=\"0\" start=\"");
845  write_time(out, start_time);
846  avio_printf(out, "\">\n");
847  } else {
848  avio_printf(out, "\t<Period id=\"0\" start=\"PT0.0S\">\n");
849  }
850 
851  for (i = 0; i < c->nb_as; i++) {
852  if ((ret = write_adaptation_set(s, out, i, final)) < 0)
853  return ret;
854  }
855  avio_printf(out, "\t</Period>\n");
856 
857  if (c->utc_timing_url)
858  avio_printf(out, "\t<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:http-xsdate:2014\" value=\"%s\"/>\n", c->utc_timing_url);
859 
860  avio_printf(out, "</MPD>\n");
861  avio_flush(out);
862  dashenc_io_close(s, &c->mpd_out, temp_filename);
863 
864  if (use_rename) {
865  if ((ret = avpriv_io_move(temp_filename, s->url)) < 0)
866  return ret;
867  }
868 
869  if (c->hls_playlist && !c->master_playlist_created) {
870  char filename_hls[1024];
871  const char *audio_group = "A1";
872  char audio_codec_str[128] = "\0";
873  int is_default = 1;
874  int max_audio_bitrate = 0;
875 
876  if (*c->dirname)
877  snprintf(filename_hls, sizeof(filename_hls), "%smaster.m3u8", c->dirname);
878  else
879  snprintf(filename_hls, sizeof(filename_hls), "master.m3u8");
880 
881  snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", filename_hls);
882 
883  set_http_options(&opts, c);
884  ret = dashenc_io_open(s, &c->m3u8_out, temp_filename, &opts);
885  if (ret < 0) {
886  av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
887  return ret;
888  }
889  av_dict_free(&opts);
890 
892 
893  for (i = 0; i < s->nb_streams; i++) {
894  char playlist_file[64];
895  AVStream *st = s->streams[i];
896  OutputStream *os = &c->streams[i];
898  continue;
899  get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
900  ff_hls_write_audio_rendition(c->m3u8_out, (char *)audio_group,
901  playlist_file, i, is_default);
902  max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
903  os->muxer_overhead, max_audio_bitrate);
904  if (!av_strnstr(audio_codec_str, os->codec_str, sizeof(audio_codec_str))) {
905  if (strlen(audio_codec_str))
906  av_strlcat(audio_codec_str, ",", sizeof(audio_codec_str));
907  av_strlcat(audio_codec_str, os->codec_str, sizeof(audio_codec_str));
908  }
909  is_default = 0;
910  }
911 
912  for (i = 0; i < s->nb_streams; i++) {
913  char playlist_file[64];
914  char codec_str[128];
915  AVStream *st = s->streams[i];
916  OutputStream *os = &c->streams[i];
917  char *agroup = NULL;
918  int stream_bitrate = st->codecpar->bit_rate + os->muxer_overhead;
920  continue;
921  av_strlcpy(codec_str, os->codec_str, sizeof(codec_str));
922  if (max_audio_bitrate) {
923  agroup = (char *)audio_group;
924  stream_bitrate += max_audio_bitrate;
925  av_strlcat(codec_str, ",", sizeof(codec_str));
926  av_strlcat(codec_str, audio_codec_str, sizeof(codec_str));
927  }
928  get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
929  ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate,
930  playlist_file, agroup,
931  codec_str, NULL);
932  }
933  dashenc_io_close(s, &c->m3u8_out, temp_filename);
934  if (use_rename)
935  if ((ret = avpriv_io_move(temp_filename, filename_hls)) < 0)
936  return ret;
938  }
939 
940  return 0;
941 }
942 
943 static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key)
944 {
945  AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0);
946  if (entry)
947  av_dict_set(dst, key, entry->value, AV_DICT_DONT_OVERWRITE);
948  return 0;
949 }
950 
952 {
953  DASHContext *c = s->priv_data;
954  int ret = 0, i;
955  char *ptr;
956  char basename[1024];
957 
958  if (c->single_file_name)
959  c->single_file = 1;
960  if (c->single_file)
961  c->use_template = 0;
962 
963 #if FF_API_DASH_MIN_SEG_DURATION
964  if (c->min_seg_duration != 5000000) {
965  av_log(s, AV_LOG_WARNING, "The min_seg_duration option is deprecated and will be removed. Please use the -seg_duration\n");
966  c->seg_duration = c->min_seg_duration;
967  }
968 #endif
969 
970  av_strlcpy(c->dirname, s->url, sizeof(c->dirname));
971  ptr = strrchr(c->dirname, '/');
972  if (ptr) {
973  av_strlcpy(basename, &ptr[1], sizeof(basename));
974  ptr[1] = '\0';
975  } else {
976  c->dirname[0] = '\0';
977  av_strlcpy(basename, s->url, sizeof(basename));
978  }
979 
980  ptr = strrchr(basename, '.');
981  if (ptr)
982  *ptr = '\0';
983 
984  c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
985  if (!c->streams)
986  return AVERROR(ENOMEM);
987 
988  if ((ret = parse_adaptation_sets(s)) < 0)
989  return ret;
990 
991  for (i = 0; i < s->nb_streams; i++) {
992  OutputStream *os = &c->streams[i];
993  AdaptationSet *as = &c->as[os->as_idx - 1];
995  AVStream *st;
997  char filename[1024];
998 
999  os->bit_rate = s->streams[i]->codecpar->bit_rate;
1000  if (!os->bit_rate) {
1003  av_log(s, level, "No bit rate set for stream %d\n", i);
1005  return AVERROR(EINVAL);
1006  }
1007 
1008  // copy AdaptationSet language and role from stream metadata
1009  dict_copy_entry(&as->metadata, s->streams[i]->metadata, "language");
1010  dict_copy_entry(&as->metadata, s->streams[i]->metadata, "role");
1011 
1012  ctx = avformat_alloc_context();
1013  if (!ctx)
1014  return AVERROR(ENOMEM);
1015 
1017  if (!c->format_name)
1018  return AVERROR_MUXER_NOT_FOUND;
1019  if (c->segment_type == SEGMENT_TYPE_WEBM) {
1020  if ((!c->single_file && check_file_extension(c->init_seg_name, c->format_name) != 0) ||
1024  "One or many segment file names doesn't end with .webm. "
1025  "Override -init_seg_name and/or -media_seg_name and/or "
1026  "-single_file_name to end with the extension .webm\n");
1027  }
1028  }
1029 
1031  if (!ctx->oformat)
1032  return AVERROR_MUXER_NOT_FOUND;
1033  os->ctx = ctx;
1035  ctx->opaque = s->opaque;
1036  ctx->io_close = s->io_close;
1037  ctx->io_open = s->io_open;
1039 
1040  if (!(st = avformat_new_stream(ctx, NULL)))
1041  return AVERROR(ENOMEM);
1044  st->time_base = s->streams[i]->time_base;
1045  st->avg_frame_rate = s->streams[i]->avg_frame_rate;
1047  ctx->flags = s->flags;
1048 
1049  if ((ret = avio_open_dyn_buf(&ctx->pb)) < 0)
1050  return ret;
1051 
1052  if (c->single_file) {
1053  if (c->single_file_name)
1054  ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->single_file_name, i, 0, os->bit_rate, 0);
1055  else
1056  snprintf(os->initfile, sizeof(os->initfile), "%s-stream%d.m4s", basename, i);
1057  } else {
1058  ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->init_seg_name, i, 0, os->bit_rate, 0);
1059  }
1060  snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
1061  set_http_options(&opts, c);
1062  ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, &opts);
1063  if (ret < 0)
1064  return ret;
1065  av_dict_free(&opts);
1066  os->init_start_pos = 0;
1067 
1068  if (c->format_options_str) {
1069  ret = av_dict_parse_string(&opts, c->format_options_str, "=", ":", 0);
1070  if (ret < 0)
1071  return ret;
1072  }
1073 
1074  if (c->segment_type == SEGMENT_TYPE_MP4) {
1075  if (c->streaming)
1076  av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov+global_sidx", 0);
1077  else
1078  av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
1079  } else {
1080  av_dict_set_int(&opts, "cluster_time_limit", c->seg_duration / 1000, 0);
1081  av_dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit
1082  av_dict_set_int(&opts, "dash", 1, 0);
1083  av_dict_set_int(&opts, "dash_track_number", i + 1, 0);
1084  av_dict_set_int(&opts, "live", 1, 0);
1085  }
1086  if ((ret = avformat_init_output(ctx, &opts)) < 0)
1087  return ret;
1088  os->ctx_inited = 1;
1089  avio_flush(ctx->pb);
1090  av_dict_free(&opts);
1091 
1092  av_log(s, AV_LOG_VERBOSE, "Representation %d init segment will be written to: %s\n", i, filename);
1093 
1094  s->streams[i]->time_base = st->time_base;
1095  // If the muxer wants to shift timestamps, request to have them shifted
1096  // already before being handed to this muxer, so we don't have mismatches
1097  // between the MPD and the actual segments.
1099  if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
1100  AVRational avg_frame_rate = s->streams[i]->avg_frame_rate;
1101  if (avg_frame_rate.num > 0) {
1102  if (av_cmp_q(avg_frame_rate, as->min_frame_rate) < 0)
1103  as->min_frame_rate = avg_frame_rate;
1104  if (av_cmp_q(as->max_frame_rate, avg_frame_rate) < 0)
1105  as->max_frame_rate = avg_frame_rate;
1106  } else {
1107  as->ambiguous_frame_rate = 1;
1108  }
1109  c->has_video = 1;
1110  }
1111 
1112  set_codec_str(s, st->codecpar, &st->avg_frame_rate, os->codec_str,
1113  sizeof(os->codec_str));
1114  os->first_pts = AV_NOPTS_VALUE;
1115  os->max_pts = AV_NOPTS_VALUE;
1116  os->last_dts = AV_NOPTS_VALUE;
1117  os->segment_index = 1;
1118  }
1119 
1120  if (!c->has_video && c->seg_duration <= 0) {
1121  av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n");
1122  return AVERROR(EINVAL);
1123  }
1124  return 0;
1125 }
1126 
1128 {
1129  DASHContext *c = s->priv_data;
1130  int i, ret;
1131  for (i = 0; i < s->nb_streams; i++) {
1132  OutputStream *os = &c->streams[i];
1133  if ((ret = avformat_write_header(os->ctx, NULL)) < 0)
1134  return ret;
1135 
1136  // Flush init segment
1137  // Only for WebM segment, since for mp4 delay_moov is set and
1138  // the init segment is thus flushed after the first packets.
1139  if (c->segment_type == SEGMENT_TYPE_WEBM &&
1140  (ret = flush_init_segment(s, os)) < 0)
1141  return ret;
1142  }
1143  return ret;
1144 }
1145 
1146 static int add_segment(OutputStream *os, const char *file,
1147  int64_t time, int duration,
1148  int64_t start_pos, int64_t range_length,
1149  int64_t index_length, int next_exp_index)
1150 {
1151  int err;
1152  Segment *seg;
1153  if (os->nb_segments >= os->segments_size) {
1154  os->segments_size = (os->segments_size + 1) * 2;
1155  if ((err = av_reallocp(&os->segments, sizeof(*os->segments) *
1156  os->segments_size)) < 0) {
1157  os->segments_size = 0;
1158  os->nb_segments = 0;
1159  return err;
1160  }
1161  }
1162  seg = av_mallocz(sizeof(*seg));
1163  if (!seg)
1164  return AVERROR(ENOMEM);
1165  av_strlcpy(seg->file, file, sizeof(seg->file));
1166  seg->time = time;
1167  seg->duration = duration;
1168  if (seg->time < 0) { // If pts<0, it is expected to be cut away with an edit list
1169  seg->duration += seg->time;
1170  seg->time = 0;
1171  }
1172  seg->start_pos = start_pos;
1173  seg->range_length = range_length;
1174  seg->index_length = index_length;
1175  os->segments[os->nb_segments++] = seg;
1176  os->segment_index++;
1177  //correcting the segment index if it has fallen behind the expected value
1178  if (os->segment_index < next_exp_index) {
1179  av_log(NULL, AV_LOG_WARNING, "Correcting the segment index after file %s: current=%d corrected=%d\n",
1180  file, os->segment_index, next_exp_index);
1181  os->segment_index = next_exp_index;
1182  }
1183  return 0;
1184 }
1185 
1186 static void write_styp(AVIOContext *pb)
1187 {
1188  avio_wb32(pb, 24);
1189  ffio_wfourcc(pb, "styp");
1190  ffio_wfourcc(pb, "msdh");
1191  avio_wb32(pb, 0); /* minor */
1192  ffio_wfourcc(pb, "msdh");
1193  ffio_wfourcc(pb, "msix");
1194 }
1195 
1196 static void find_index_range(AVFormatContext *s, const char *full_path,
1197  int64_t pos, int *index_length)
1198 {
1199  uint8_t buf[8];
1200  AVIOContext *pb;
1201  int ret;
1202 
1203  ret = s->io_open(s, &pb, full_path, AVIO_FLAG_READ, NULL);
1204  if (ret < 0)
1205  return;
1206  if (avio_seek(pb, pos, SEEK_SET) != pos) {
1207  ff_format_io_close(s, &pb);
1208  return;
1209  }
1210  ret = avio_read(pb, buf, 8);
1211  ff_format_io_close(s, &pb);
1212  if (ret < 8)
1213  return;
1214  if (AV_RL32(&buf[4]) != MKTAG('s', 'i', 'd', 'x'))
1215  return;
1216  *index_length = AV_RB32(&buf[0]);
1217 }
1218 
1220  AVCodecParameters *par,
1221  AVRational *frame_rate)
1222 {
1223  uint8_t *extradata;
1224 
1225  if (os->ctx->streams[0]->codecpar->extradata_size || !par->extradata_size)
1226  return 0;
1227 
1228  extradata = av_malloc(par->extradata_size);
1229 
1230  if (!extradata)
1231  return AVERROR(ENOMEM);
1232 
1233  memcpy(extradata, par->extradata, par->extradata_size);
1234 
1235  os->ctx->streams[0]->codecpar->extradata = extradata;
1237 
1238  set_codec_str(s, par, frame_rate, os->codec_str, sizeof(os->codec_str));
1239 
1240  return 0;
1241 }
1242 
1243 static void dashenc_delete_file(AVFormatContext *s, char *filename) {
1244  DASHContext *c = s->priv_data;
1245  int http_base_proto = ff_is_http_proto(filename);
1246 
1247  if (http_base_proto) {
1248  AVIOContext *out = NULL;
1249  AVDictionary *http_opts = NULL;
1250 
1251  set_http_options(&http_opts, c);
1252  av_dict_set(&http_opts, "method", "DELETE", 0);
1253 
1254  if (dashenc_io_open(s, &out, filename, &http_opts) < 0) {
1255  av_log(s, AV_LOG_ERROR, "failed to delete %s\n", filename);
1256  }
1257 
1258  av_dict_free(&http_opts);
1259  ff_format_io_close(s, &out);
1260  } else if (unlink(filename) < 0) {
1261  av_log(s, AV_LOG_ERROR, "failed to delete %s: %s\n", filename, strerror(errno));
1262  }
1263 }
1264 
1265 static int dash_flush(AVFormatContext *s, int final, int stream)
1266 {
1267  DASHContext *c = s->priv_data;
1268  int i, ret = 0;
1269 
1270  const char *proto = avio_find_protocol_name(s->url);
1271  int use_rename = proto && !strcmp(proto, "file");
1272 
1273  int cur_flush_segment_index = 0, next_exp_index = -1;
1274  if (stream >= 0) {
1275  cur_flush_segment_index = c->streams[stream].segment_index;
1276 
1277  //finding the next segment's expected index, based on the current pts value
1278  if (c->use_template && !c->use_timeline && c->index_correction &&
1279  c->streams[stream].last_pts != AV_NOPTS_VALUE &&
1280  c->streams[stream].first_pts != AV_NOPTS_VALUE) {
1281  int64_t pts_diff = av_rescale_q(c->streams[stream].last_pts -
1282  c->streams[stream].first_pts,
1283  s->streams[stream]->time_base,
1284  AV_TIME_BASE_Q);
1285  next_exp_index = (pts_diff / c->seg_duration) + 1;
1286  }
1287  }
1288 
1289  for (i = 0; i < s->nb_streams; i++) {
1290  OutputStream *os = &c->streams[i];
1291  AVStream *st = s->streams[i];
1292  int range_length, index_length = 0;
1293 
1294  if (!os->packets_written)
1295  continue;
1296 
1297  // Flush the single stream that got a keyframe right now.
1298  // Flush all audio streams as well, in sync with video keyframes,
1299  // but not the other video streams.
1300  if (stream >= 0 && i != stream) {
1302  continue;
1303  // Make sure we don't flush audio streams multiple times, when
1304  // all video streams are flushed one at a time.
1305  if (c->has_video && os->segment_index > cur_flush_segment_index)
1306  continue;
1307  }
1308 
1309  if (!c->single_file) {
1310  if (c->segment_type == SEGMENT_TYPE_MP4 && !os->written_len)
1311  write_styp(os->ctx->pb);
1312  } else {
1313  snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile);
1314  }
1315 
1316  ret = flush_dynbuf(os, &range_length);
1317  if (ret < 0)
1318  break;
1319  os->packets_written = 0;
1320 
1321  if (c->single_file) {
1322  find_index_range(s, os->full_path, os->pos, &index_length);
1323  } else {
1324  dashenc_io_close(s, &os->out, os->temp_path);
1325 
1326  if (use_rename) {
1327  ret = avpriv_io_move(os->temp_path, os->full_path);
1328  if (ret < 0)
1329  break;
1330  }
1331  }
1332 
1333  if (!os->muxer_overhead)
1334  os->muxer_overhead = ((int64_t) (range_length - os->total_pkt_size) *
1335  8 * AV_TIME_BASE) /
1336  av_rescale_q(os->max_pts - os->start_pts,
1337  st->time_base, AV_TIME_BASE_Q);
1338  os->total_pkt_size = 0;
1339 
1340  if (!os->bit_rate) {
1341  // calculate average bitrate of first segment
1342  int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / av_rescale_q(os->max_pts - os->start_pts,
1343  st->time_base,
1344  AV_TIME_BASE_Q);
1345  if (bitrate >= 0)
1346  os->bit_rate = bitrate;
1347  }
1348  add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index);
1349  av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path);
1350 
1351  os->pos += range_length;
1352  }
1353 
1354  if (c->window_size || (final && c->remove_at_exit)) {
1355  for (i = 0; i < s->nb_streams; i++) {
1356  OutputStream *os = &c->streams[i];
1357  int j;
1358  int remove = os->nb_segments - c->window_size - c->extra_window_size;
1359  if (final && c->remove_at_exit)
1360  remove = os->nb_segments;
1361  if (remove > 0) {
1362  for (j = 0; j < remove; j++) {
1363  char filename[1024];
1364  snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->segments[j]->file);
1365  dashenc_delete_file(s, filename);
1366  av_free(os->segments[j]);
1367  }
1368  os->nb_segments -= remove;
1369  memmove(os->segments, os->segments + remove, os->nb_segments * sizeof(*os->segments));
1370  }
1371  }
1372  }
1373 
1374  if (ret >= 0)
1375  ret = write_manifest(s, final);
1376  return ret;
1377 }
1378 
1380 {
1381  DASHContext *c = s->priv_data;
1382  AVStream *st = s->streams[pkt->stream_index];
1383  OutputStream *os = &c->streams[pkt->stream_index];
1384  int64_t seg_end_duration, elapsed_duration;
1385  int ret;
1386 
1387  ret = update_stream_extradata(s, os, st->codecpar, &st->avg_frame_rate);
1388  if (ret < 0)
1389  return ret;
1390 
1391  // Fill in a heuristic guess of the packet duration, if none is available.
1392  // The mp4 muxer will do something similar (for the last packet in a fragment)
1393  // if nothing is set (setting it for the other packets doesn't hurt).
1394  // By setting a nonzero duration here, we can be sure that the mp4 muxer won't
1395  // invoke its heuristic (this doesn't have to be identical to that algorithm),
1396  // so that we know the exact timestamps of fragments.
1397  if (!pkt->duration && os->last_dts != AV_NOPTS_VALUE)
1398  pkt->duration = pkt->dts - os->last_dts;
1399  os->last_dts = pkt->dts;
1400 
1401  // If forcing the stream to start at 0, the mp4 muxer will set the start
1402  // timestamps to 0. Do the same here, to avoid mismatches in duration/timestamps.
1403  if (os->first_pts == AV_NOPTS_VALUE &&
1405  pkt->pts -= pkt->dts;
1406  pkt->dts = 0;
1407  }
1408 
1409  if (os->first_pts == AV_NOPTS_VALUE)
1410  os->first_pts = pkt->pts;
1411  os->last_pts = pkt->pts;
1412 
1413  if (!c->availability_start_time[0])
1415  sizeof(c->availability_start_time));
1416 
1417  if (!os->availability_time_offset && pkt->duration) {
1418  int64_t frame_duration = av_rescale_q(pkt->duration, st->time_base,
1419  AV_TIME_BASE_Q);
1420  os->availability_time_offset = ((double) c->seg_duration -
1421  frame_duration) / AV_TIME_BASE;
1422  }
1423 
1424  if (c->use_template && !c->use_timeline) {
1425  elapsed_duration = pkt->pts - os->first_pts;
1426  seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
1427  } else {
1428  elapsed_duration = pkt->pts - os->start_pts;
1429  seg_end_duration = c->seg_duration;
1430  }
1431 
1432  if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
1433  pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
1434  av_compare_ts(elapsed_duration, st->time_base,
1435  seg_end_duration, AV_TIME_BASE_Q) >= 0) {
1436  int64_t prev_duration = c->last_duration;
1437 
1438  c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
1439  st->time_base,
1440  AV_TIME_BASE_Q);
1441  c->total_duration = av_rescale_q(pkt->pts - os->first_pts,
1442  st->time_base,
1443  AV_TIME_BASE_Q);
1444 
1445  if ((!c->use_timeline || !c->use_template) && prev_duration) {
1446  if (c->last_duration < prev_duration*9/10 ||
1447  c->last_duration > prev_duration*11/10) {
1449  "Segment durations differ too much, enable use_timeline "
1450  "and use_template, or keep a stricter keyframe interval\n");
1451  }
1452  }
1453 
1454  if ((ret = dash_flush(s, 0, pkt->stream_index)) < 0)
1455  return ret;
1456  }
1457 
1458  if (!os->packets_written) {
1459  // If we wrote a previous segment, adjust the start time of the segment
1460  // to the end of the previous one (which is the same as the mp4 muxer
1461  // does). This avoids gaps in the timeline.
1462  if (os->max_pts != AV_NOPTS_VALUE)
1463  os->start_pts = os->max_pts;
1464  else
1465  os->start_pts = pkt->pts;
1466  }
1467  if (os->max_pts == AV_NOPTS_VALUE)
1468  os->max_pts = pkt->pts + pkt->duration;
1469  else
1470  os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
1471  os->packets_written++;
1472  os->total_pkt_size += pkt->size;
1473  if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
1474  return ret;
1475 
1476  if (!os->init_range_length)
1477  flush_init_segment(s, os);
1478 
1479  //open the output context when the first frame of a segment is ready
1480  if (!c->single_file && os->packets_written == 1) {
1481  AVDictionary *opts = NULL;
1482  const char *proto = avio_find_protocol_name(s->url);
1483  int use_rename = proto && !strcmp(proto, "file");
1484  os->filename[0] = os->full_path[0] = os->temp_path[0] = '\0';
1485  ff_dash_fill_tmpl_params(os->filename, sizeof(os->filename),
1486  c->media_seg_name, pkt->stream_index,
1487  os->segment_index, os->bit_rate, os->start_pts);
1488  snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname,
1489  os->filename);
1490  snprintf(os->temp_path, sizeof(os->temp_path),
1491  use_rename ? "%s.tmp" : "%s", os->full_path);
1492  set_http_options(&opts, c);
1493  ret = dashenc_io_open(s, &os->out, os->temp_path, &opts);
1494  if (ret < 0)
1495  return ret;
1496  av_dict_free(&opts);
1497  }
1498 
1499  //write out the data immediately in streaming mode
1500  if (c->streaming && c->segment_type == SEGMENT_TYPE_MP4) {
1501  int len = 0;
1502  uint8_t *buf = NULL;
1503  if (!os->written_len)
1504  write_styp(os->ctx->pb);
1505  avio_flush(os->ctx->pb);
1506  len = avio_get_dyn_buf (os->ctx->pb, &buf);
1507  avio_write(os->out, buf + os->written_len, len - os->written_len);
1508  os->written_len = len;
1509  avio_flush(os->out);
1510  }
1511 
1512  return ret;
1513 }
1514 
1516 {
1517  DASHContext *c = s->priv_data;
1518 
1519  if (s->nb_streams > 0) {
1520  OutputStream *os = &c->streams[0];
1521  // If no segments have been written so far, try to do a crude
1522  // guess of the segment duration
1523  if (!c->last_duration)
1525  s->streams[0]->time_base,
1526  AV_TIME_BASE_Q);
1528  s->streams[0]->time_base,
1529  AV_TIME_BASE_Q);
1530  }
1531  dash_flush(s, 1, -1);
1532 
1533  if (c->remove_at_exit) {
1534  char filename[1024];
1535  int i;
1536  for (i = 0; i < s->nb_streams; i++) {
1537  OutputStream *os = &c->streams[i];
1538  snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
1539  dashenc_delete_file(s, filename);
1540  }
1541  dashenc_delete_file(s, s->url);
1542  }
1543 
1544  return 0;
1545 }
1546 
1547 static int dash_check_bitstream(struct AVFormatContext *s, const AVPacket *avpkt)
1548 {
1549  DASHContext *c = s->priv_data;
1550  OutputStream *os = &c->streams[avpkt->stream_index];
1551  AVFormatContext *oc = os->ctx;
1552  if (oc->oformat->check_bitstream) {
1553  int ret;
1554  AVPacket pkt = *avpkt;
1555  pkt.stream_index = 0;
1556  ret = oc->oformat->check_bitstream(oc, &pkt);
1557  if (ret == 1) {
1558  AVStream *st = s->streams[avpkt->stream_index];
1559  AVStream *ost = oc->streams[0];
1560  st->internal->bsfcs = ost->internal->bsfcs;
1561  st->internal->nb_bsfcs = ost->internal->nb_bsfcs;
1562  ost->internal->bsfcs = NULL;
1563  ost->internal->nb_bsfcs = 0;
1564  }
1565  return ret;
1566  }
1567  return 1;
1568 }
1569 
1570 #define OFFSET(x) offsetof(DASHContext, x)
1571 #define E AV_OPT_FLAG_ENCODING_PARAM
1572 static const AVOption options[] = {
1573  { "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 },
1574  { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
1575  { "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 },
1576 #if FF_API_DASH_MIN_SEG_DURATION
1577  { "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 },
1578 #endif
1579  { "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 5000000 }, 0, INT_MAX, E },
1580  { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1581  { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
1582  { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
1583  { "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1584  { "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 },
1585  { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.m4s"}, 0, 0, E },
1586  { "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$.m4s"}, 0, 0, E },
1587  { "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 },
1588  { "method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
1589  { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
1590  { "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
1591  { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1592  { "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1593  { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
1594  { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
1595  { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
1596  { "dash_segment_type", "set dash segment files type", OFFSET(segment_type), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_MP4 }, 0, SEGMENT_TYPE_NB - 1, E, "segment_type"},
1597  { "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4 }, 0, UINT_MAX, E, "segment_type"},
1598  { "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM }, 0, UINT_MAX, E, "segment_type"},
1599  { NULL },
1600 };
1601 
1602 static const AVClass dash_class = {
1603  .class_name = "dash muxer",
1604  .item_name = av_default_item_name,
1605  .option = options,
1606  .version = LIBAVUTIL_VERSION_INT,
1607 };
1608 
1610  .name = "dash",
1611  .long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"),
1612  .extensions = "mpd",
1613  .priv_data_size = sizeof(DASHContext),
1614  .audio_codec = AV_CODEC_ID_AAC,
1615  .video_codec = AV_CODEC_ID_H264,
1617  .init = dash_init,
1621  .deinit = dash_free,
1622  .check_bitstream = dash_check_bitstream,
1623  .priv_class = &dash_class,
1624 };
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:689
#define NULL
Definition: coverity.c:32
char * format_options_str
Definition: dashenc.c:133
Bytestream IO Context.
Definition: avio.h:161
int use_timeline
Definition: dashenc.c:111
static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key)
Definition: dashenc.c:943
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1629
static void set_http_options(AVDictionary **options, DASHContext *c)
Definition: dashenc.c:328
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition: aviobuf.c:1420
AVOption.
Definition: opt.h:246
static int parse_adaptation_sets(AVFormatContext *s)
Definition: dashenc.c:677
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:135
static const AVOption options[]
Definition: dashenc.c:1572
AVIOContext * mpd_out
Definition: dashenc.c:128
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:878
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
int ambiguous_frame_rate
Definition: dashenc.c:71
#define AV_DICT_DONT_OVERWRITE
Don't overwrite existing entries.
Definition: dict.h:79
int range_length
Definition: dashenc.c:60
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, AVFormatContext *src, int interleave)
Write a packet to another muxer than the one the user originally intended.
Definition: mux.c:1311
int nb_segments
Definition: dashenc.c:82
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3900
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:936
int num
Numerator.
Definition: rational.h:59
static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename)
Definition: dashenc.c:175
int size
Definition: avcodec.h:1446
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:246
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
#define AVIO_FLAG_READ
read-only
Definition: avio.h:654
int n
Definition: dashenc.c:63
int(* check_bitstream)(struct AVFormatContext *, const AVPacket *pkt)
Set up any necessary bitstream filtering and extract any extra data needed for the global header...
Definition: avformat.h:632
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:655
char codec_str[100]
Definition: dashenc.c:88
Convenience header that includes libavutil's core.
char filename[1024]
Definition: dashenc.c:90
const char * str
Definition: dashenc.c:151
int64_t timeout
Definition: dashenc.c:131
const char * key
int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, int byterange_mode, double duration, int round_duration, int64_t size, int64_t pos, char *baseurl, char *filename, double *prog_date_time)
Definition: hlsplaylist.c:103
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
AVFormatContext * ctx
Definition: dashenc.c:75
int single_file
Definition: dashenc.c:112
static AVPacket pkt
int ff_is_http_proto(char *filename)
Utility function to check if the file uses http or https protocol.
Definition: utils.c:5677
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:87
#define src
Definition: vp8dsp.c:254
int packets_written
Definition: dashenc.c:78
int as_idx
Definition: dashenc.c:76
static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, AVRational *frame_rate, char *str, int size)
Definition: dashenc.c:224
int64_t start_pts
Definition: dashenc.c:84
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1391
int strict_std_compliance
Allow non-standard and experimental extension.
Definition: avformat.h:1659
static int dash_init(AVFormatContext *s)
Definition: dashenc.c:951
This struct describes the properties of an encoded stream.
Definition: avcodec.h:3892
int64_t last_pts
Definition: dashenc.c:85
int ffurl_shutdown(URLContext *h, int flags)
Signal the URLContext that we are done reading or writing the stream.
Definition: avio.c:657
int avpriv_io_move(const char *url_src, const char *url_dst)
Move or rename a resource.
Definition: avio.c:499
static struct codec_string codecs[]
int64_t last_dts
Definition: dashenc.c:85
Format I/O context.
Definition: avformat.h:1351
int64_t init_start_pos
Definition: dashenc.c:80
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
static int64_t start_time
Definition: ffplay.c:330
int streaming
Definition: dashenc.c:130
char * adaptation_sets
Definition: dashenc.c:100
int mem
Definition: avisynth_c.h:821
AdaptationSet * as
Definition: dashenc.c:101
uint8_t
#define av_malloc(s)
int width
Video only.
Definition: avcodec.h:3966
AVRational min_frame_rate
Definition: dashenc.c:70
AVOptions.
miscellaneous OS support macros and functions.
const AVCodecTag ff_codec_movvideo_tags[]
Definition: isom.c:75
static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMediaType type)
Definition: dashenc.c:642
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1463
void ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: utils.c:5670
int extra_window_size
Definition: dashenc.c:104
int ctx_inited
Definition: dashenc.c:76
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4455
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:87
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1419
int64_t duration
Definition: movenc.c:63
const char * method
Definition: dashenc.c:123
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:144
SegmentType segment_type
Definition: dashenc.c:134
SegmentType
Definition: dashenc.c:51
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:40
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1482
static int update_stream_extradata(AVFormatContext *s, OutputStream *os, AVCodecParameters *par, AVRational *frame_rate)
Definition: dashenc.c:1219
uint32_t tag
Definition: movenc.c:1483
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
AVIOContext * m3u8_out
Definition: dashenc.c:129
void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, char *filename, int name_id, int is_default)
Definition: hlsplaylist.c:38
ptrdiff_t size
Definition: opengl_enc.c:101
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:218
static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s)
Definition: avio_internal.h:58
uint64_t availability_start_time
Definition: dashdec.c:147
char initfile[1024]
Definition: dashenc.c:79
static void format_date_now(char *buf, int size)
Definition: dashenc.c:578
int64_t seg_duration
Definition: dashenc.c:108
#define av_log(a,...)
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:276
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:648
struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1370
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
Definition: avcodec.h:3929
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1477
static void get_hls_playlist_name(char *playlist_name, int string_size, const char *base_url, int id)
Definition: dashenc.c:340
static void write_time(AVIOContext *out, int64_t time)
Definition: dashenc.c:562
static int add_segment(OutputStream *os, const char *file, int64_t time, int duration, int64_t start_pos, int64_t range_length, int64_t index_length, int next_exp_index)
Definition: dashenc.c:1146
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
static int write_manifest(AVFormatContext *s, int final)
Definition: dashenc.c:776
#define E
Definition: dashenc.c:1571
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: utils.c:2013
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
AVDictionary * metadata
Metadata that applies to the whole file.
Definition: avformat.h:1591
int hls_playlist
Definition: dashenc.c:125
AVDictionary * metadata
Definition: dashenc.c:69
int remove_at_exit
Definition: dashenc.c:109
int bitdepth
Definition: vpcc.h:38
#define AVERROR(e)
Definition: error.h:43
int64_t last_duration
Definition: dashenc.c:115
static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dashenc.c:1379
int nb_as
Definition: dashenc.c:102
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
int duration
Definition: dashenc.c:62
char * url
input or output URL.
Definition: avformat.h:1447
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:203
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3896
simple assert() macros that are a bit more flexible than ISO C assert().
static int dash_check_bitstream(struct AVFormatContext *s, const AVPacket *avpkt)
Definition: dashenc.c:1547
const char * format_name
Definition: dashenc.c:135
static int flush_init_segment(AVFormatContext *s, OutputStream *os)
Definition: dashenc.c:348
int64_t start_pos
Definition: dashenc.c:59
double availability_time_offset
Definition: dashenc.c:93
AVRational avg_frame_rate
Average framerate.
Definition: avformat.h:947
#define FFMAX(a, b)
Definition: common.h:94
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:83
const AVCodecTag ff_mp4_obj_type[]
Definition: isom.c:34
static void dashenc_delete_file(AVFormatContext *s, char *filename)
Definition: dashenc.c:1243
static struct tm * gmtime_r(const time_t *clock, struct tm *result)
Definition: time_internal.h:26
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1451
int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
Compare two timestamps each in its own time base.
Definition: mathematics.c:147
int extradata_size
Size of the extradata content in bytes.
Definition: avcodec.h:3918
void * opaque
User data.
Definition: avformat.h:1857
AVOutputFormat ff_dash_muxer
Definition: dashenc.c:1609
static struct @303 state
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1407
void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, int target_duration, int64_t sequence, uint32_t playlist_type)
Definition: hlsplaylist.c:74
AVDictionary * opts
Definition: movenc.c:50
AVBSFContext ** bsfcs
bitstream filters to run on stream
Definition: internal.h:161
const char * media_seg_name
Definition: dashenc.c:121
int void avio_flush(AVIOContext *s)
Force flushing of buffered data.
Definition: aviobuf.c:238
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
av_warn_unused_result int avformat_write_header(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and write the stream header to an output media file.
Definition: mux.c:508
int segment_index
Definition: dashenc.c:82
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:94
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:468
const char * name
Definition: avformat.h:507
int master_playlist_created
Definition: dashenc.c:127
AVFormatContext * ctx
Definition: movenc.c:48
char full_path[1024]
Definition: dashenc.c:91
char dirname[1024]
Definition: dashenc.c:118
enum AVMediaType media_type
Definition: dashenc.c:68
#define s(width, name)
Definition: cbs_vp9.c:257
int avoid_negative_ts
Avoid negative timestamps during muxing.
Definition: avformat.h:1682
int index_correction
Definition: dashenc.c:132
int n
Definition: avisynth_c.h:684
AVDictionary * metadata
Definition: avformat.h:938
static void set_vp9_codec_str(AVFormatContext *s, AVCodecParameters *par, AVRational *frame_rate, char *str, int size)
Definition: dashenc.c:209
AVOutputFormat * av_guess_format(const char *short_name, const char *filename, const char *mime_type)
Return the output format in the list of registered output formats which best matches the provided par...
Definition: format.c:51
Usually treated as AVMEDIA_TYPE_DATA.
Definition: avutil.h:200
int64_t pos
Definition: dashenc.c:80
av_warn_unused_result int avformat_init_output(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and initialize the codec, but do not write the header.
Definition: mux.c:488
int segments_size
Definition: dashenc.c:82
#define OFFSET(x)
Definition: dashenc.c:1570
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1450
Stream structure.
Definition: avformat.h:874
void ff_dash_fill_tmpl_params(char *dst, size_t buffer_size, const char *template, int rep_id, int number, int bit_rate, int64_t time)
Definition: dash.c:96
int64_t time
Definition: dashenc.c:61
int av_dict_parse_string(AVDictionary **pm, const char *str, const char *key_val_sep, const char *pairs_sep, int flags)
Parse the key/value pairs list and add the parsed entries to a dictionary.
Definition: dict.c:180
Segment ** segments
Definition: dashenc.c:83
void ff_hls_write_playlist_version(AVIOContext *out, int version)
Definition: hlsplaylist.c:31
int index_length
Definition: dashenc.c:60
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition: mem.c:163
AVStreamInternal * internal
An opaque field for libavformat internal usage.
Definition: avformat.h:1231
const AVCodecTag ff_codec_movaudio_tags[]
Definition: isom.c:313
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:260
AVIOContext * pb
I/O context.
Definition: avformat.h:1393
int bit_rate
Definition: dashenc.c:86
SegmentType segment_type
Definition: dashenc.c:150
int use_template
Definition: dashenc.c:110
int written_len
Definition: dashenc.c:89
AVRational max_frame_rate
Definition: dashenc.c:70
void * buf
Definition: avisynth_c.h:690
Definition: url.h:38
GLint GLenum type
Definition: opengl_enc.c:105
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:70
Describe the class of an AVClass context structure.
Definition: log.h:67
const char * init_seg_name
Definition: dashenc.c:120
Rational number (pair of numerator and denominator).
Definition: rational.h:58
static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index, int final)
Definition: dashenc.c:589
AVMediaType
Definition: avutil.h:199
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
static const char * get_format_str(SegmentType segment_type)
Definition: dashenc.c:191
#define FF_COMPLIANCE_STRICT
Strictly conform to all the things in the spec no matter what consequences.
Definition: avcodec.h:2594
#define snprintf
Definition: snprintf.h:34
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:4389
static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i)
Definition: dashenc.c:659
int64_t total_duration
Definition: dashenc.c:116
size_t av_strlcat(char *dst, const char *src, size_t size)
Append the string src to the string dst, but to a total length of no more than size - 1 bytes...
Definition: avstring.c:93
static void find_index_range(AVFormatContext *s, const char *full_path, int64_t pos, int *index_length)
Definition: dashenc.c:1196
char file[1024]
Definition: dashenc.c:58
const char * avio_find_protocol_name(const char *url)
Return the name of the protocol that will handle the passed URL.
Definition: avio.c:473
static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, AVDictionary **options)
Definition: dashenc.c:158
URLContext * ffio_geturlcontext(AVIOContext *s)
Return the URLContext associated with the AVIOContext.
Definition: aviobuf.c:1039
#define flags(name, subs,...)
Definition: cbs_av1.c:596
static int flush_dynbuf(OutputStream *os, int *range_length)
Definition: dashenc.c:305
uint8_t level
Definition: svq3.c:207
OutputStream * streams
Definition: dashenc.c:113
void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, char *filename, char *agroup, char *codecs, char *ccgroup)
Definition: hlsplaylist.c:48
int init_range_length
Definition: dashenc.c:81
int ff_http_do_new_request(URLContext *h, const char *uri)
Send a new HTTP request, reusing the old connection.
Definition: http.c:307
Definition: vpcc.h:35
int sample_rate
Audio only.
Definition: avcodec.h:4010
#define AVFMT_AVOID_NEG_TS_MAKE_ZERO
Shift timestamps so that they start at 0.
Definition: avformat.h:1685
int64_t bitrate
Definition: h264_levels.c:89
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:34
static AVStream * ost
Main libavformat public API header.
char * av_strnstr(const char *haystack, const char *needle, size_t hay_length)
Locate the first occurrence of the string needle in the string haystack where not more than hay_lengt...
Definition: avstring.c:69
if(ret< 0)
Definition: vf_mcdeint.c:279
int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par, AVRational *frame_rate, VPCC *vpcc)
Definition: vpcc.c:116
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:465
Utilties for rational number calculation.
const char * user_agent
Definition: dashenc.c:124
const char * single_file_name
Definition: dashenc.c:119
static double c[64]
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set that converts the value to a string and stores it...
Definition: dict.c:147
int level
Definition: vpcc.h:37
void ff_hls_write_init_file(AVIOContext *out, char *filename, int byterange_mode, int64_t size, int64_t pos)
Definition: hlsplaylist.c:94
int muxer_overhead
Definition: dashenc.c:95
int den
Denominator.
Definition: rational.h:60
static void write_styp(AVIOContext *pb)
Definition: dashenc.c:1186
static int dash_write_header(AVFormatContext *s)
Definition: dashenc.c:1127
char id[10]
Definition: dashenc.c:67
static int check_file_extension(const char *filename, const char *extension)
Definition: dashenc.c:199
#define av_free(p)
char * value
Definition: dict.h:87
int len
const char * str
Definition: dashenc.c:140
void * priv_data
Format private data.
Definition: avformat.h:1379
const char * utc_timing_url
Definition: dashenc.c:122
int profile
Definition: vpcc.h:36
static int dash_write_trailer(AVFormatContext *s)
Definition: dashenc.c:1515
int window_size
Definition: dashenc.c:103
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:337
#define lrint
Definition: tablegen.h:53
static void dash_free(AVFormatContext *s)
Definition: dashenc.c:366
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:3914
int has_video
Definition: dashenc.c:114
int channels
Audio only.
Definition: avcodec.h:4006
int64_t max_pts
Definition: dashenc.c:84
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:1444
void ff_hls_write_end_list(AVIOContext *out)
Definition: hlsplaylist.c:156
int total_pkt_size
Definition: dashenc.c:94
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:1247
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:377
static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatContext *s, int representation_id, int final)
Definition: dashenc.c:399
FILE * out
Definition: movenc.c:54
#define av_freep(p)
internal header for VPx codec configuration utilities.
SegmentType
Definition: pgssubdec.c:41
unbuffered private I/O API
#define AVERROR_MUXER_NOT_FOUND
Muxer not found.
Definition: error.h:60
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1021
static char * xmlescape(const char *str)
Definition: dashenc.c:522
uint32_t codec_tag
Additional information about the codec (corresponds to the AVI FOURCC).
Definition: avcodec.h:3904
formats
Definition: signature.h:48
AVIOContext * out
Definition: dashenc.c:77
char temp_path[1024]
Definition: dashenc.c:92
static int dash_flush(AVFormatContext *s, int final, int stream)
Definition: dashenc.c:1265
int stream_index
Definition: avcodec.h:1447
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:903
int64_t first_pts
Definition: ffmpeg.h:455
#define MKTAG(a, b, c, d)
Definition: common.h:366
unsigned int av_codec_get_tag(const struct AVCodecTag *const *tags, enum AVCodecID id)
Get the codec tag for the given codec id id.
#define AVFMT_TS_NEGATIVE
Format allows muxing negative timestamps.
Definition: avformat.h:484
int(* io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options)
A callback for opening new IO streams.
Definition: avformat.h:1933
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:87
This structure stores compressed data.
Definition: avcodec.h:1422
void(* io_close)(struct AVFormatContext *s, AVIOContext *pb)
A callback for closing the streams opened with AVFormatContext.io_open().
Definition: avformat.h:1939
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1438
int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
Definition: avc.c:107
static const AVClass dash_class
Definition: dashenc.c:1602
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
GLuint buffer
Definition: opengl_enc.c:102
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
#define AV_WL32(p, v)
Definition: intreadwrite.h:426
int http_persistent
Definition: dashenc.c:126
int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition: aviobuf.c:1403
static uint8_t tmp[11]
Definition: aes_ctr.c:26