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  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "config.h"
23 #if HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 
27 #include "libavutil/avstring.h"
28 #include "libavutil/intreadwrite.h"
29 #include "libavutil/mathematics.h"
30 #include "libavutil/opt.h"
32 
33 #include "avc.h"
34 #include "avformat.h"
35 #include "avio_internal.h"
36 #include "internal.h"
37 #include "isom.h"
38 #include "os_support.h"
39 #include "url.h"
40 
41 // See ISO/IEC 23009-1:2014 5.3.9.4.4
42 typedef enum {
49 } DASHTmplId;
50 
51 typedef struct Segment {
52  char file[1024];
53  int64_t start_pos;
55  int64_t time;
56  int duration;
57  int n;
58 } Segment;
59 
60 typedef struct OutputStream {
63  uint8_t iobuf[32768];
66  char initfile[1024];
67  int64_t init_start_pos;
72  int64_t last_dts;
73  int bit_rate;
74  char bandwidth_str[64];
75 
76  char codec_str[100];
77 } OutputStream;
78 
79 typedef struct DASHContext {
80  const AVClass *class; /* Class for private options. */
90  int64_t last_duration;
91  int64_t total_duration;
93  char dirname[1024];
94  const char *single_file_name;
95  const char *init_seg_name;
96  const char *media_seg_name;
97 } DASHContext;
98 
99 static int dash_write(void *opaque, uint8_t *buf, int buf_size)
100 {
101  OutputStream *os = opaque;
102  if (os->out)
103  ffurl_write(os->out, buf, buf_size);
104  return buf_size;
105 }
106 
107 // RFC 6381
109  char *str, int size)
110 {
111  const AVCodecTag *tags[2] = { NULL, NULL };
112  uint32_t tag;
113  if (codec->codec_type == AVMEDIA_TYPE_VIDEO)
114  tags[0] = ff_codec_movvideo_tags;
115  else if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
116  tags[0] = ff_codec_movaudio_tags;
117  else
118  return;
119 
120  tag = av_codec_get_tag(tags, codec->codec_id);
121  if (!tag)
122  return;
123  if (size < 5)
124  return;
125 
126  AV_WL32(str, tag);
127  str[4] = '\0';
128  if (!strcmp(str, "mp4a") || !strcmp(str, "mp4v")) {
129  uint32_t oti;
130  tags[0] = ff_mp4_obj_type;
131  oti = av_codec_get_tag(tags, codec->codec_id);
132  if (oti)
133  av_strlcatf(str, size, ".%02x", oti);
134  else
135  return;
136 
137  if (tag == MKTAG('m', 'p', '4', 'a')) {
138  if (codec->extradata_size >= 2) {
139  int aot = codec->extradata[0] >> 3;
140  if (aot == 31)
141  aot = ((AV_RB16(codec->extradata) >> 5) & 0x3f) + 32;
142  av_strlcatf(str, size, ".%d", aot);
143  }
144  } else if (tag == MKTAG('m', 'p', '4', 'v')) {
145  // Unimplemented, should output ProfileLevelIndication as a decimal number
146  av_log(s, AV_LOG_WARNING, "Incomplete RFC 6381 codec string for mp4v\n");
147  }
148  } else if (!strcmp(str, "avc1")) {
149  uint8_t *tmpbuf = NULL;
150  uint8_t *extradata = codec->extradata;
151  int extradata_size = codec->extradata_size;
152  if (!extradata_size)
153  return;
154  if (extradata[0] != 1) {
155  AVIOContext *pb;
156  if (avio_open_dyn_buf(&pb) < 0)
157  return;
158  if (ff_isom_write_avcc(pb, extradata, extradata_size) < 0) {
159  ffio_free_dyn_buf(&pb);
160  return;
161  }
162  extradata_size = avio_close_dyn_buf(pb, &extradata);
163  tmpbuf = extradata;
164  }
165 
166  if (extradata_size >= 4)
167  av_strlcatf(str, size, ".%02x%02x%02x",
168  extradata[1], extradata[2], extradata[3]);
169  av_free(tmpbuf);
170  }
171 }
172 
174 {
175  DASHContext *c = s->priv_data;
176  int i, j;
177  if (!c->streams)
178  return;
179  for (i = 0; i < s->nb_streams; i++) {
180  OutputStream *os = &c->streams[i];
181  if (os->ctx && os->ctx_inited)
182  av_write_trailer(os->ctx);
183  if (os->ctx && os->ctx->pb)
184  av_free(os->ctx->pb);
185  ffurl_close(os->out);
186  os->out = NULL;
187  if (os->ctx)
189  for (j = 0; j < os->nb_segments; j++)
190  av_free(os->segments[j]);
191  av_free(os->segments);
192  }
193  av_freep(&c->streams);
194 }
195 
197 {
198  int i, start_index = 0, start_number = 1;
199  if (c->window_size) {
200  start_index = FFMAX(os->nb_segments - c->window_size, 0);
201  start_number = FFMAX(os->segment_index - c->window_size, 1);
202  }
203 
204  if (c->use_template) {
205  int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : AV_TIME_BASE;
206  avio_printf(out, "\t\t\t\t<SegmentTemplate timescale=\"%d\" ", timescale);
207  if (!c->use_timeline)
208  avio_printf(out, "duration=\"%"PRId64"\" ", c->last_duration);
209  avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? start_number : 1);
210  if (c->use_timeline) {
211  int64_t cur_time = 0;
212  avio_printf(out, "\t\t\t\t\t<SegmentTimeline>\n");
213  for (i = start_index; i < os->nb_segments; ) {
214  Segment *seg = os->segments[i];
215  int repeat = 0;
216  avio_printf(out, "\t\t\t\t\t\t<S ");
217  if (i == start_index || seg->time != cur_time) {
218  cur_time = seg->time;
219  avio_printf(out, "t=\"%"PRId64"\" ", seg->time);
220  }
221  avio_printf(out, "d=\"%d\" ", seg->duration);
222  while (i + repeat + 1 < os->nb_segments &&
223  os->segments[i + repeat + 1]->duration == seg->duration &&
224  os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]->duration)
225  repeat++;
226  if (repeat > 0)
227  avio_printf(out, "r=\"%d\" ", repeat);
228  avio_printf(out, "/>\n");
229  i += 1 + repeat;
230  cur_time += (1 + repeat) * seg->duration;
231  }
232  avio_printf(out, "\t\t\t\t\t</SegmentTimeline>\n");
233  }
234  avio_printf(out, "\t\t\t\t</SegmentTemplate>\n");
235  } else if (c->single_file) {
236  avio_printf(out, "\t\t\t\t<BaseURL>%s</BaseURL>\n", os->initfile);
237  avio_printf(out, "\t\t\t\t<SegmentList timescale=\"%d\" duration=\"%"PRId64"\" startNumber=\"%d\">\n", AV_TIME_BASE, c->last_duration, start_number);
238  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);
239  for (i = start_index; i < os->nb_segments; i++) {
240  Segment *seg = os->segments[i];
241  avio_printf(out, "\t\t\t\t\t<SegmentURL mediaRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->range_length - 1);
242  if (seg->index_length)
243  avio_printf(out, "indexRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->index_length - 1);
244  avio_printf(out, "/>\n");
245  }
246  avio_printf(out, "\t\t\t\t</SegmentList>\n");
247  } else {
248  avio_printf(out, "\t\t\t\t<SegmentList timescale=\"%d\" duration=\"%"PRId64"\" startNumber=\"%d\">\n", AV_TIME_BASE, c->last_duration, start_number);
249  avio_printf(out, "\t\t\t\t\t<Initialization sourceURL=\"%s\" />\n", os->initfile);
250  for (i = start_index; i < os->nb_segments; i++) {
251  Segment *seg = os->segments[i];
252  avio_printf(out, "\t\t\t\t\t<SegmentURL media=\"%s\" />\n", seg->file);
253  }
254  avio_printf(out, "\t\t\t\t</SegmentList>\n");
255  }
256 }
257 
258 static DASHTmplId dash_read_tmpl_id(const char *identifier, char *format_tag,
259  size_t format_tag_size, const char **ptr) {
260  const char *next_ptr;
262 
263  if (av_strstart(identifier, "$$", &next_ptr)) {
264  id_type = DASH_TMPL_ID_ESCAPE;
265  *ptr = next_ptr;
266  } else if (av_strstart(identifier, "$RepresentationID$", &next_ptr)) {
267  id_type = DASH_TMPL_ID_REP_ID;
268  // default to basic format, as $RepresentationID$ identifiers
269  // are not allowed to have custom format-tags.
270  av_strlcpy(format_tag, "%d", format_tag_size);
271  *ptr = next_ptr;
272  } else { // the following identifiers may have an explicit format_tag
273  if (av_strstart(identifier, "$Number", &next_ptr))
274  id_type = DASH_TMPL_ID_NUMBER;
275  else if (av_strstart(identifier, "$Bandwidth", &next_ptr))
276  id_type = DASH_TMPL_ID_BANDWIDTH;
277  else if (av_strstart(identifier, "$Time", &next_ptr))
278  id_type = DASH_TMPL_ID_TIME;
279  else
280  id_type = DASH_TMPL_ID_UNDEFINED;
281 
282  // next parse the dash format-tag and generate a c-string format tag
283  // (next_ptr now points at the first '%' at the beginning of the format-tag)
284  if (id_type != DASH_TMPL_ID_UNDEFINED) {
285  const char *number_format = (id_type == DASH_TMPL_ID_TIME) ? PRId64 : "d";
286  if (next_ptr[0] == '$') { // no dash format-tag
287  snprintf(format_tag, format_tag_size, "%%%s", number_format);
288  *ptr = &next_ptr[1];
289  } else {
290  const char *width_ptr;
291  // only tolerate single-digit width-field (i.e. up to 9-digit width)
292  if (av_strstart(next_ptr, "%0", &width_ptr) &&
293  av_isdigit(width_ptr[0]) &&
294  av_strstart(&width_ptr[1], "d$", &next_ptr)) {
295  // yes, we're using a format tag to build format_tag.
296  snprintf(format_tag, format_tag_size, "%s%c%s", "%0", width_ptr[0], number_format);
297  *ptr = next_ptr;
298  } else {
299  av_log(NULL, AV_LOG_WARNING, "Failed to parse format-tag beginning with %s. Expected either a "
300  "closing '$' character or a format-string like '%%0[width]d', "
301  "where width must be a single digit\n", next_ptr);
302  id_type = DASH_TMPL_ID_UNDEFINED;
303  }
304  }
305  }
306  }
307  return id_type;
308 }
309 
310 static void dash_fill_tmpl_params(char *dst, size_t buffer_size,
311  const char *template, int rep_id,
312  int number, int bit_rate,
313  int64_t time) {
314  int dst_pos = 0;
315  const char *t_cur = template;
316  while (dst_pos < buffer_size - 1 && *t_cur) {
317  char format_tag[7]; // May be "%d", "%0Xd", or "%0Xlld" (for $Time$), where X is in [0-9]
318  int n = 0;
319  DASHTmplId id_type;
320  const char *t_next = strchr(t_cur, '$'); // copy over everything up to the first '$' character
321  if (t_next) {
322  int num_copy_bytes = FFMIN(t_next - t_cur, buffer_size - dst_pos - 1);
323  av_strlcpy(&dst[dst_pos], t_cur, num_copy_bytes + 1);
324  // advance
325  dst_pos += num_copy_bytes;
326  t_cur = t_next;
327  } else { // no more DASH identifiers to substitute - just copy the rest over and break
328  av_strlcpy(&dst[dst_pos], t_cur, buffer_size - dst_pos);
329  break;
330  }
331 
332  if (dst_pos >= buffer_size - 1 || !*t_cur)
333  break;
334 
335  // t_cur is now pointing to a '$' character
336  id_type = dash_read_tmpl_id(t_cur, format_tag, sizeof(format_tag), &t_next);
337  switch (id_type) {
338  case DASH_TMPL_ID_ESCAPE:
339  av_strlcpy(&dst[dst_pos], "$", 2);
340  n = 1;
341  break;
342  case DASH_TMPL_ID_REP_ID:
343  n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, rep_id);
344  break;
345  case DASH_TMPL_ID_NUMBER:
346  n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, number);
347  break;
349  n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, bit_rate);
350  break;
351  case DASH_TMPL_ID_TIME:
352  n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, time);
353  break;
355  // copy over one byte and advance
356  av_strlcpy(&dst[dst_pos], t_cur, 2);
357  n = 1;
358  t_next = &t_cur[1];
359  break;
360  }
361  // t_next points just past the processed identifier
362  // n is the number of bytes that were attempted to be written to dst
363  // (may have failed to write all because buffer_size).
364 
365  // advance
366  dst_pos += FFMIN(n, buffer_size - dst_pos - 1);
367  t_cur = t_next;
368  }
369 }
370 
371 static char *xmlescape(const char *str) {
372  int outlen = strlen(str)*3/2 + 6;
373  char *out = av_realloc(NULL, outlen + 1);
374  int pos = 0;
375  if (!out)
376  return NULL;
377  for (; *str; str++) {
378  if (pos + 6 > outlen) {
379  char *tmp;
380  outlen = 2 * outlen + 6;
381  tmp = av_realloc(out, outlen + 1);
382  if (!tmp) {
383  av_free(out);
384  return NULL;
385  }
386  out = tmp;
387  }
388  if (*str == '&') {
389  memcpy(&out[pos], "&amp;", 5);
390  pos += 5;
391  } else if (*str == '<') {
392  memcpy(&out[pos], "&lt;", 4);
393  pos += 4;
394  } else if (*str == '>') {
395  memcpy(&out[pos], "&gt;", 4);
396  pos += 4;
397  } else if (*str == '\'') {
398  memcpy(&out[pos], "&apos;", 6);
399  pos += 6;
400  } else if (*str == '\"') {
401  memcpy(&out[pos], "&quot;", 6);
402  pos += 6;
403  } else {
404  out[pos++] = *str;
405  }
406  }
407  out[pos] = '\0';
408  return out;
409 }
410 
411 static void write_time(AVIOContext *out, int64_t time)
412 {
413  int seconds = time / AV_TIME_BASE;
414  int fractions = time % AV_TIME_BASE;
415  int minutes = seconds / 60;
416  int hours = minutes / 60;
417  seconds %= 60;
418  minutes %= 60;
419  avio_printf(out, "PT");
420  if (hours)
421  avio_printf(out, "%dH", hours);
422  if (hours || minutes)
423  avio_printf(out, "%dM", minutes);
424  avio_printf(out, "%d.%dS", seconds, fractions / (AV_TIME_BASE / 10));
425 }
426 
427 static void format_date_now(char *buf, int size)
428 {
429  time_t t = time(NULL);
430  struct tm *ptm, tmbuf;
431  ptm = gmtime_r(&t, &tmbuf);
432  if (ptm) {
433  if (!strftime(buf, size, "%Y-%m-%dT%H:%M:%S", ptm))
434  buf[0] = '\0';
435  }
436 }
437 
438 static int write_manifest(AVFormatContext *s, int final)
439 {
440  DASHContext *c = s->priv_data;
441  AVIOContext *out;
442  char temp_filename[1024];
443  int ret, i;
444  AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
445 
446  snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", s->filename);
447  ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
448  if (ret < 0) {
449  av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
450  return ret;
451  }
452  avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
453  avio_printf(out, "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
454  "\txmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
455  "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
456  "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n"
457  "\tprofiles=\"urn:mpeg:dash:profile:isoff-live:2011\"\n"
458  "\ttype=\"%s\"\n", final ? "static" : "dynamic");
459  if (final) {
460  avio_printf(out, "\tmediaPresentationDuration=\"");
461  write_time(out, c->total_duration);
462  avio_printf(out, "\"\n");
463  } else {
464  int64_t update_period = c->last_duration / AV_TIME_BASE;
465  char now_str[100];
466  if (c->use_template && !c->use_timeline)
467  update_period = 500;
468  avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", update_period);
469  avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", c->last_duration / AV_TIME_BASE);
470  if (!c->availability_start_time[0] && s->nb_streams > 0 && c->streams[0].nb_segments > 0) {
472  }
473  if (c->availability_start_time[0])
474  avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", c->availability_start_time);
475  format_date_now(now_str, sizeof(now_str));
476  if (now_str[0])
477  avio_printf(out, "\tpublishTime=\"%s\"\n", now_str);
478  if (c->window_size && c->use_template) {
479  avio_printf(out, "\ttimeShiftBufferDepth=\"");
480  write_time(out, c->last_duration * c->window_size);
481  avio_printf(out, "\"\n");
482  }
483  }
484  avio_printf(out, "\tminBufferTime=\"");
485  write_time(out, c->last_duration);
486  avio_printf(out, "\">\n");
487  avio_printf(out, "\t<ProgramInformation>\n");
488  if (title) {
489  char *escaped = xmlescape(title->value);
490  avio_printf(out, "\t\t<Title>%s</Title>\n", escaped);
491  av_free(escaped);
492  }
493  avio_printf(out, "\t</ProgramInformation>\n");
494  if (c->window_size && s->nb_streams > 0 && c->streams[0].nb_segments > 0 && !c->use_template) {
495  OutputStream *os = &c->streams[0];
496  int start_index = FFMAX(os->nb_segments - c->window_size, 0);
497  int64_t start_time = av_rescale_q(os->segments[start_index]->time, s->streams[0]->time_base, AV_TIME_BASE_Q);
498  avio_printf(out, "\t<Period start=\"");
499  write_time(out, start_time);
500  avio_printf(out, "\">\n");
501  } else {
502  avio_printf(out, "\t<Period start=\"PT0.0S\">\n");
503  }
504 
505  if (c->has_video) {
506  avio_printf(out, "\t\t<AdaptationSet contentType=\"video\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n");
507  for (i = 0; i < s->nb_streams; i++) {
508  AVStream *st = s->streams[i];
509  OutputStream *os = &c->streams[i];
510 
511  if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO)
512  continue;
513 
514  avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/mp4\" codecs=\"%s\"%s width=\"%d\" height=\"%d\">\n", i, os->codec_str, os->bandwidth_str, st->codec->width, st->codec->height);
515  output_segment_list(&c->streams[i], out, c);
516  avio_printf(out, "\t\t\t</Representation>\n");
517  }
518  avio_printf(out, "\t\t</AdaptationSet>\n");
519  }
520  if (c->has_audio) {
521  avio_printf(out, "\t\t<AdaptationSet contentType=\"audio\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">\n");
522  for (i = 0; i < s->nb_streams; i++) {
523  AVStream *st = s->streams[i];
524  OutputStream *os = &c->streams[i];
525 
526  if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
527  continue;
528 
529  avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/mp4\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n", i, os->codec_str, os->bandwidth_str, st->codec->sample_rate);
530  avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", st->codec->channels);
531  output_segment_list(&c->streams[i], out, c);
532  avio_printf(out, "\t\t\t</Representation>\n");
533  }
534  avio_printf(out, "\t\t</AdaptationSet>\n");
535  }
536  avio_printf(out, "\t</Period>\n");
537  avio_printf(out, "</MPD>\n");
538  avio_flush(out);
539  avio_close(out);
540  return ff_rename(temp_filename, s->filename, s);
541 }
542 
544 {
545  DASHContext *c = s->priv_data;
546  int ret = 0, i;
547  AVOutputFormat *oformat;
548  char *ptr;
549  char basename[1024];
550 
551  if (c->single_file_name)
552  c->single_file = 1;
553  if (c->single_file)
554  c->use_template = 0;
555 
556  av_strlcpy(c->dirname, s->filename, sizeof(c->dirname));
557  ptr = strrchr(c->dirname, '/');
558  if (ptr) {
559  av_strlcpy(basename, &ptr[1], sizeof(basename));
560  ptr[1] = '\0';
561  } else {
562  c->dirname[0] = '\0';
563  av_strlcpy(basename, s->filename, sizeof(basename));
564  }
565 
566  ptr = strrchr(basename, '.');
567  if (ptr)
568  *ptr = '\0';
569 
570  oformat = av_guess_format("mp4", NULL, NULL);
571  if (!oformat) {
573  goto fail;
574  }
575 
576  c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
577  if (!c->streams) {
578  ret = AVERROR(ENOMEM);
579  goto fail;
580  }
581 
582  for (i = 0; i < s->nb_streams; i++) {
583  OutputStream *os = &c->streams[i];
584  AVFormatContext *ctx;
585  AVStream *st;
586  AVDictionary *opts = NULL;
587  char filename[1024];
588 
589  os->bit_rate = s->streams[i]->codec->bit_rate ?
590  s->streams[i]->codec->bit_rate :
591  s->streams[i]->codec->rc_max_rate;
592  if (os->bit_rate) {
593  snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
594  " bandwidth=\"%d\"", os->bit_rate);
595  } else {
598  av_log(s, level, "No bit rate set for stream %d\n", i);
600  ret = AVERROR(EINVAL);
601  goto fail;
602  }
603  }
604 
605  ctx = avformat_alloc_context();
606  if (!ctx) {
607  ret = AVERROR(ENOMEM);
608  goto fail;
609  }
610  os->ctx = ctx;
611  ctx->oformat = oformat;
613 
614  if (!(st = avformat_new_stream(ctx, NULL))) {
615  ret = AVERROR(ENOMEM);
616  goto fail;
617  }
620  st->time_base = s->streams[i]->time_base;
622 
623  ctx->pb = avio_alloc_context(os->iobuf, sizeof(os->iobuf), AVIO_FLAG_WRITE, os, NULL, dash_write, NULL);
624  if (!ctx->pb) {
625  ret = AVERROR(ENOMEM);
626  goto fail;
627  }
628 
629  if (c->single_file) {
630  if (c->single_file_name)
631  dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->single_file_name, i, 0, os->bit_rate, 0);
632  else
633  snprintf(os->initfile, sizeof(os->initfile), "%s-stream%d.m4s", basename, i);
634  } else {
635  dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->init_seg_name, i, 0, os->bit_rate, 0);
636  }
637  snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
638  ret = ffurl_open(&os->out, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
639  if (ret < 0)
640  goto fail;
641  os->init_start_pos = 0;
642 
643  av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
644  if ((ret = avformat_write_header(ctx, &opts)) < 0) {
645  goto fail;
646  }
647  os->ctx_inited = 1;
648  avio_flush(ctx->pb);
649  av_dict_free(&opts);
650 
651  av_log(s, AV_LOG_VERBOSE, "Representation %d init segment will be written to: %s\n", i, filename);
652 
653  s->streams[i]->time_base = st->time_base;
654  // If the muxer wants to shift timestamps, request to have them shifted
655  // already before being handed to this muxer, so we don't have mismatches
656  // between the MPD and the actual segments.
658  if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
659  c->has_video = 1;
660  else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
661  c->has_audio = 1;
662 
663  set_codec_str(s, st->codec, os->codec_str, sizeof(os->codec_str));
665  os->max_pts = AV_NOPTS_VALUE;
666  os->last_dts = AV_NOPTS_VALUE;
667  os->segment_index = 1;
668  }
669 
670  if (!c->has_video && c->min_seg_duration <= 0) {
671  av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration set\n");
672  ret = AVERROR(EINVAL);
673  }
674  ret = write_manifest(s, 0);
675  if (!ret)
676  av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->filename);
677 
678 fail:
679  if (ret)
680  dash_free(s);
681  return ret;
682 }
683 
684 static int add_segment(OutputStream *os, const char *file,
685  int64_t time, int duration,
686  int64_t start_pos, int64_t range_length,
687  int64_t index_length)
688 {
689  int err;
690  Segment *seg;
691  if (os->nb_segments >= os->segments_size) {
692  os->segments_size = (os->segments_size + 1) * 2;
693  if ((err = av_reallocp(&os->segments, sizeof(*os->segments) *
694  os->segments_size)) < 0) {
695  os->segments_size = 0;
696  os->nb_segments = 0;
697  return err;
698  }
699  }
700  seg = av_mallocz(sizeof(*seg));
701  if (!seg)
702  return AVERROR(ENOMEM);
703  av_strlcpy(seg->file, file, sizeof(seg->file));
704  seg->time = time;
705  seg->duration = duration;
706  if (seg->time < 0) { // If pts<0, it is expected to be cut away with an edit list
707  seg->duration += seg->time;
708  seg->time = 0;
709  }
710  seg->start_pos = start_pos;
711  seg->range_length = range_length;
712  seg->index_length = index_length;
713  os->segments[os->nb_segments++] = seg;
714  os->segment_index++;
715  return 0;
716 }
717 
718 static void write_styp(AVIOContext *pb)
719 {
720  avio_wb32(pb, 24);
721  ffio_wfourcc(pb, "styp");
722  ffio_wfourcc(pb, "msdh");
723  avio_wb32(pb, 0); /* minor */
724  ffio_wfourcc(pb, "msdh");
725  ffio_wfourcc(pb, "msix");
726 }
727 
728 static void find_index_range(AVFormatContext *s, const char *full_path,
729  int64_t pos, int *index_length)
730 {
731  uint8_t buf[8];
732  URLContext *fd;
733  int ret;
734 
735  ret = ffurl_open(&fd, full_path, AVIO_FLAG_READ, &s->interrupt_callback, NULL);
736  if (ret < 0)
737  return;
738  if (ffurl_seek(fd, pos, SEEK_SET) != pos) {
739  ffurl_close(fd);
740  return;
741  }
742  ret = ffurl_read(fd, buf, 8);
743  ffurl_close(fd);
744  if (ret < 8)
745  return;
746  if (AV_RL32(&buf[4]) != MKTAG('s', 'i', 'd', 'x'))
747  return;
748  *index_length = AV_RB32(&buf[0]);
749 }
750 
752  AVCodecContext *codec)
753 {
754  uint8_t *extradata;
755 
756  if (os->ctx->streams[0]->codec->extradata_size || !codec->extradata_size)
757  return 0;
758 
759  extradata = av_malloc(codec->extradata_size);
760 
761  if (!extradata)
762  return AVERROR(ENOMEM);
763 
764  memcpy(extradata, codec->extradata, codec->extradata_size);
765 
766  os->ctx->streams[0]->codec->extradata = extradata;
767  os->ctx->streams[0]->codec->extradata_size = codec->extradata_size;
768 
769  set_codec_str(s, codec, os->codec_str, sizeof(os->codec_str));
770 
771  return 0;
772 }
773 
774 static int dash_flush(AVFormatContext *s, int final, int stream)
775 {
776  DASHContext *c = s->priv_data;
777  int i, ret = 0;
778  int cur_flush_segment_index = 0;
779  if (stream >= 0)
780  cur_flush_segment_index = c->streams[stream].segment_index;
781 
782  for (i = 0; i < s->nb_streams; i++) {
783  OutputStream *os = &c->streams[i];
784  char filename[1024] = "", full_path[1024], temp_path[1024];
785  int64_t start_pos;
786  int range_length, index_length = 0;
787 
788  if (!os->packets_written)
789  continue;
790 
791  // Flush the single stream that got a keyframe right now.
792  // Flush all audio streams as well, in sync with video keyframes,
793  // but not the other video streams.
794  if (stream >= 0 && i != stream) {
796  continue;
797  // Make sure we don't flush audio streams multiple times, when
798  // all video streams are flushed one at a time.
799  if (c->has_video && os->segment_index > cur_flush_segment_index)
800  continue;
801  }
802 
803  if (!os->init_range_length) {
804  av_write_frame(os->ctx, NULL);
805  os->init_range_length = avio_tell(os->ctx->pb);
806  if (!c->single_file) {
807  ffurl_close(os->out);
808  os->out = NULL;
809  }
810  }
811 
812  start_pos = avio_tell(os->ctx->pb);
813 
814  if (!c->single_file) {
815  dash_fill_tmpl_params(filename, sizeof(filename), c->media_seg_name, i, os->segment_index, os->bit_rate, os->start_pts);
816  snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, filename);
817  snprintf(temp_path, sizeof(temp_path), "%s.tmp", full_path);
818  ret = ffurl_open(&os->out, temp_path, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
819  if (ret < 0)
820  break;
821  write_styp(os->ctx->pb);
822  } else {
823  snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, os->initfile);
824  }
825 
826  av_write_frame(os->ctx, NULL);
827  avio_flush(os->ctx->pb);
828  os->packets_written = 0;
829 
830  range_length = avio_tell(os->ctx->pb) - start_pos;
831  if (c->single_file) {
832  find_index_range(s, full_path, start_pos, &index_length);
833  } else {
834  ffurl_close(os->out);
835  os->out = NULL;
836  ret = ff_rename(temp_path, full_path, s);
837  if (ret < 0)
838  break;
839  }
840  add_segment(os, filename, os->start_pts, os->max_pts - os->start_pts, start_pos, range_length, index_length);
841  av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, full_path);
842  }
843 
844  if (c->window_size || (final && c->remove_at_exit)) {
845  for (i = 0; i < s->nb_streams; i++) {
846  OutputStream *os = &c->streams[i];
847  int j;
848  int remove = os->nb_segments - c->window_size - c->extra_window_size;
849  if (final && c->remove_at_exit)
850  remove = os->nb_segments;
851  if (remove > 0) {
852  for (j = 0; j < remove; j++) {
853  char filename[1024];
854  snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->segments[j]->file);
855  unlink(filename);
856  av_free(os->segments[j]);
857  }
858  os->nb_segments -= remove;
859  memmove(os->segments, os->segments + remove, os->nb_segments * sizeof(*os->segments));
860  }
861  }
862  }
863 
864  if (ret >= 0)
865  ret = write_manifest(s, final);
866  return ret;
867 }
868 
870 {
871  DASHContext *c = s->priv_data;
872  AVStream *st = s->streams[pkt->stream_index];
873  OutputStream *os = &c->streams[pkt->stream_index];
874  int64_t seg_end_duration = (os->segment_index) * (int64_t) c->min_seg_duration;
875  int ret;
876 
877  ret = update_stream_extradata(s, os, st->codec);
878  if (ret < 0)
879  return ret;
880 
881  // Fill in a heuristic guess of the packet duration, if none is available.
882  // The mp4 muxer will do something similar (for the last packet in a fragment)
883  // if nothing is set (setting it for the other packets doesn't hurt).
884  // By setting a nonzero duration here, we can be sure that the mp4 muxer won't
885  // invoke its heuristic (this doesn't have to be identical to that algorithm),
886  // so that we know the exact timestamps of fragments.
887  if (!pkt->duration && os->last_dts != AV_NOPTS_VALUE)
888  pkt->duration = pkt->dts - os->last_dts;
889  os->last_dts = pkt->dts;
890 
891  // If forcing the stream to start at 0, the mp4 muxer will set the start
892  // timestamps to 0. Do the same here, to avoid mismatches in duration/timestamps.
893  if (os->first_pts == AV_NOPTS_VALUE &&
895  pkt->pts -= pkt->dts;
896  pkt->dts = 0;
897  }
898 
899  if (os->first_pts == AV_NOPTS_VALUE)
900  os->first_pts = pkt->pts;
901 
902  if ((!c->has_video || st->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
903  pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
904  av_compare_ts(pkt->pts - os->first_pts, st->time_base,
905  seg_end_duration, AV_TIME_BASE_Q) >= 0) {
906  int64_t prev_duration = c->last_duration;
907 
908  c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
909  st->time_base,
911  c->total_duration = av_rescale_q(pkt->pts - os->first_pts,
912  st->time_base,
914 
915  if ((!c->use_timeline || !c->use_template) && prev_duration) {
916  if (c->last_duration < prev_duration*9/10 ||
917  c->last_duration > prev_duration*11/10) {
919  "Segment durations differ too much, enable use_timeline "
920  "and use_template, or keep a stricter keyframe interval\n");
921  }
922  }
923 
924  if ((ret = dash_flush(s, 0, pkt->stream_index)) < 0)
925  return ret;
926  }
927 
928  if (!os->packets_written) {
929  // If we wrote a previous segment, adjust the start time of the segment
930  // to the end of the previous one (which is the same as the mp4 muxer
931  // does). This avoids gaps in the timeline.
932  if (os->max_pts != AV_NOPTS_VALUE)
933  os->start_pts = os->max_pts;
934  else
935  os->start_pts = pkt->pts;
936  }
937  if (os->max_pts == AV_NOPTS_VALUE)
938  os->max_pts = pkt->pts + pkt->duration;
939  else
940  os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
941  os->packets_written++;
942  return ff_write_chained(os->ctx, 0, pkt, s, 0);
943 }
944 
946 {
947  DASHContext *c = s->priv_data;
948 
949  if (s->nb_streams > 0) {
950  OutputStream *os = &c->streams[0];
951  // If no segments have been written so far, try to do a crude
952  // guess of the segment duration
953  if (!c->last_duration)
955  s->streams[0]->time_base,
958  s->streams[0]->time_base,
960  }
961  dash_flush(s, 1, -1);
962 
963  if (c->remove_at_exit) {
964  char filename[1024];
965  int i;
966  for (i = 0; i < s->nb_streams; i++) {
967  OutputStream *os = &c->streams[i];
968  snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
969  unlink(filename);
970  }
971  unlink(s->filename);
972  }
973 
974  dash_free(s);
975  return 0;
976 }
977 
978 #define OFFSET(x) offsetof(DASHContext, x)
979 #define E AV_OPT_FLAG_ENCODING_PARAM
980 static const AVOption options[] = {
981  { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
982  { "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 },
983  { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT64, { .i64 = 5000000 }, 0, INT_MAX, E },
984  { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, E },
985  { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
986  { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
987  { "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, E },
988  { "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 },
989  { "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 },
990  { "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 },
991  { NULL },
992 };
993 
994 static const AVClass dash_class = {
995  .class_name = "dash muxer",
996  .item_name = av_default_item_name,
997  .option = options,
998  .version = LIBAVUTIL_VERSION_INT,
999 };
1000 
1002  .name = "dash",
1003  .long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"),
1004  .priv_data_size = sizeof(DASHContext),
1005  .audio_codec = AV_CODEC_ID_AAC,
1006  .video_codec = AV_CODEC_ID_H264,
1011  .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
1012  .priv_class = &dash_class,
1013 };
#define NULL
Definition: coverity.c:32
int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
Definition: avstring.c:320
const char * s
Definition: avisynth_c.h:631
Bytestream IO Context.
Definition: avio.h:111
int use_timeline
Definition: dashenc.c:86
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1523
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition: aviobuf.c:1146
AVOption.
Definition: opt.h:255
int min_seg_duration
Definition: dashenc.c:83
static const AVOption options[]
Definition: dashenc.c:980
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:447
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:691
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
#define LIBAVUTIL_VERSION_INT
Definition: version.h:62
int range_length
Definition: dashenc.c:54
int ffurl_write(URLContext *h, const unsigned char *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: avio.c:367
static int64_t cur_time
Definition: ffserver.c:255
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:1041
int nb_segments
Definition: dashenc.c:69
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:914
#define AVIO_FLAG_READ
read-only
Definition: avio.h:485
int n
Definition: dashenc.c:57
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:486
char codec_str[100]
Definition: dashenc.c:76
AVFormatContext * ctx
Definition: dashenc.c:61
int single_file
Definition: dashenc.c:87
static AVPacket pkt
char availability_start_time[100]
Definition: dashenc.c:92
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
static void output_segment_list(OutputStream *os, AVIOContext *out, DASHContext *c)
Definition: dashenc.c:196
int packets_written
Definition: dashenc.c:65
int64_t start_pts
Definition: dashenc.c:71
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1134
int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
Copy the settings of the source AVCodecContext into the destination AVCodecContext.
Definition: options.c:182
int strict_std_compliance
Allow non-standard and experimental extension.
Definition: avformat.h:1553
int64_t last_dts
Definition: dashenc.c:72
Format I/O context.
Definition: avformat.h:1273
int64_t init_start_pos
Definition: dashenc.c:67
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
static int64_t start_time
Definition: ffplay.c:325
uint8_t
#define av_malloc(s)
AVOptions.
miscellaneous OS support macros and functions.
const AVCodecTag ff_codec_movvideo_tags[]
Definition: isom.c:71
int extra_window_size
Definition: dashenc.c:82
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:1617
int ctx_inited
Definition: dashenc.c:62
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:3749
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:1341
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:111
uint8_t iobuf[32768]
Definition: dashenc.c:63
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:39
int av_reallocp(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:187
uint32_t tag
Definition: movenc.c:1334
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
static void set_codec_str(AVFormatContext *s, AVCodecContext *codec, char *str, int size)
Definition: dashenc.c:108
ptrdiff_t size
Definition: opengl_enc.c:101
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:390
static int64_t duration
Definition: ffplay.c:326
static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s)
Definition: avio_internal.h:67
char initfile[1024]
Definition: dashenc.c:66
static void format_date_now(char *buf, int size)
Definition: dashenc.c:427
int duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1441
#define av_log(a,...)
struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1292
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1469
static void write_time(AVIOContext *out, int64_t time)
Definition: dashenc.c:411
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:140
static int write_manifest(AVFormatContext *s, int final)
Definition: dashenc.c:438
AVIOContext * avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Allocate and initialize an AVIOContext for buffered I/O.
Definition: aviobuf.c:112
#define E
Definition: dashenc.c:979
#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:1485
int remove_at_exit
Definition: dashenc.c:84
av_default_item_name
#define AVERROR(e)
Definition: error.h:43
int64_t last_duration
Definition: dashenc.c:90
static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dashenc.c:869
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:175
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:941
int duration
Definition: dashenc.c:56
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:199
int rc_max_rate
maximum bitrate
Definition: avcodec.h:2604
int64_t start_pos
Definition: dashenc.c:53
URLContext * out
Definition: dashenc.c:64
#define FFMAX(a, b)
Definition: common.h:79
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
#define fail()
Definition: checkasm.h:57
char bandwidth_str[64]
Definition: dashenc.c:74
const AVCodecTag ff_mp4_obj_type[]
Definition: isom.c:34
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:1429
int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
Compare 2 timestamps each in its own timebases.
Definition: mathematics.c:145
AVOutputFormat ff_dash_muxer
Definition: dashenc.c:1001
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:861
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1329
const char * media_seg_name
Definition: dashenc.c:96
int bit_rate
the average bitrate
Definition: avcodec.h:1567
int void avio_flush(AVIOContext *s)
Force flushing of buffered data.
Definition: aviobuf.c:198
char filename[1024]
input or output filename
Definition: avformat.h:1349
static DASHTmplId dash_read_tmpl_id(const char *identifier, char *format_tag, size_t format_tag_size, const char **ptr)
Definition: dashenc.c:258
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:246
#define FFMIN(a, b)
Definition: common.h:81
int segment_index
Definition: dashenc.c:69
int width
picture width / height.
Definition: avcodec.h:1681
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:94
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:471
const char * name
Definition: avformat.h:513
char dirname[1024]
Definition: dashenc.c:93
static int update_stream_extradata(AVFormatContext *s, OutputStream *os, AVCodecContext *codec)
Definition: dashenc.c:751
int avoid_negative_ts
Avoid negative timestamps during muxing.
Definition: avformat.h:1576
int n
Definition: avisynth_c.h:547
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:94
static int dash_write(void *opaque, uint8_t *buf, int buf_size)
Definition: dashenc.c:99
DASHTmplId
Definition: dashenc.c:42
int segments_size
Definition: dashenc.c:69
#define OFFSET(x)
Definition: dashenc.c:978
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1174
Stream structure.
Definition: avformat.h:842
int64_t time
Definition: dashenc.c:55
Segment ** segments
Definition: dashenc.c:70
int index_length
Definition: dashenc.c:54
enum AVMediaType codec_type
Definition: avcodec.h:1510
const AVCodecTag ff_codec_movaudio_tags[]
Definition: isom.c:268
enum AVCodecID codec_id
Definition: avcodec.h:1519
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:252
int sample_rate
samples per second
Definition: avcodec.h:2262
AVIOContext * pb
I/O context.
Definition: avformat.h:1315
int bit_rate
Definition: dashenc.c:73
main external API structure.
Definition: avcodec.h:1502
int use_template
Definition: dashenc.c:85
void * buf
Definition: avisynth_c.h:553
Definition: url.h:39
int extradata_size
Definition: avcodec.h:1618
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:69
static int ff_rename(const char *oldpath, const char *newpath, void *logctx)
Wrap errno on rename() error.
Definition: internal.h:447
Describe the class of an AVClass context structure.
Definition: log.h:67
const char * init_seg_name
Definition: dashenc.c:95
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:101
int avio_open2(AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: aviobuf.c:918
#define snprintf
Definition: snprintf.h:34
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:3686
int64_t total_duration
Definition: dashenc.c:91
static void find_index_range(AVFormatContext *s, const char *full_path, int64_t pos, int *index_length)
Definition: dashenc.c:728
char file[1024]
Definition: dashenc.c:52
static int flags
Definition: cpu.c:47
int ffurl_close(URLContext *h)
Definition: avio.c:412
uint8_t level
Definition: svq3.c:150
OutputStream * streams
Definition: dashenc.c:88
int init_range_length
Definition: dashenc.c:68
#define AVFMT_AVOID_NEG_TS_MAKE_ZERO
Shift timestamps so that they start at 0.
Definition: avformat.h:1579
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
Main libavformat public API header.
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:465
int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
Change the position that will be used by the next read/write operation on the resource accessed by h...
Definition: avio.c:380
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:145
int ffurl_open(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:292
const char * single_file_name
Definition: dashenc.c:94
static double c[64]
int den
denominator
Definition: rational.h:45
static void write_styp(AVIOContext *pb)
Definition: dashenc.c:718
static int dash_write_header(AVFormatContext *s)
Definition: dashenc.c:543
#define av_free(p)
char * value
Definition: dict.h:88
int channels
number of audio channels
Definition: avcodec.h:2263
#define FF_COMPLIANCE_STRICT
Strictly conform to all the things in the spec no matter what consequences.
Definition: avcodec.h:2822
void * priv_data
Format private data.
Definition: avformat.h:1301
static int dash_write_trailer(AVFormatContext *s)
Definition: dashenc.c:945
int window_size
Definition: dashenc.c:81
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:493
static void dash_free(AVFormatContext *s)
Definition: dashenc.c:173
int has_video
Definition: dashenc.c:89
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(constint16_t *) pi >>8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(constint32_t *) pi >>24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(constfloat *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(constfloat *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(constfloat *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(constdouble *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(constdouble *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(constdouble *) pi *(1U<< 31))))#defineSET_CONV_FUNC_GROUP(ofmt, ifmt) staticvoidset_generic_function(AudioConvert *ac){}voidff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enumAVSampleFormatout_fmt, enumAVSampleFormatin_fmt, intchannels, intsample_rate, intapply_map){AudioConvert *ac;intin_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) returnNULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt)>2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);returnNULL;}returnac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}elseif(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;elseac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);returnac;}intff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){intuse_generic=1;intlen=in->nb_samples;intp;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%dsamples-audio_convert:%sto%s(dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));returnff_convert_dither(ac-> out
int64_t max_pts
Definition: dashenc.c:71
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:1422
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:986
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:327
#define av_freep(p)
int has_audio
Definition: dashenc.c:89
unbuffered private I/O API
#define AVERROR_MUXER_NOT_FOUND
Muxer not found.
Definition: error.h:60
static void 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: dashenc.c:310
static char * xmlescape(const char *str)
Definition: dashenc.c:371
static int dash_flush(AVFormatContext *s, int final, int stream)
Definition: dashenc.c:774
int stream_index
Definition: avcodec.h:1425
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:884
int64_t first_pts
Definition: ffmpeg.h:395
#define MKTAG(a, b, c, d)
Definition: common.h:330
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:490
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:87
This structure stores compressed data.
Definition: avcodec.h:1400
static int write_packet(AVFormatContext *s1, AVPacket *pkt)
Definition: v4l2enc.c:86
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf...
Definition: avio.c:353
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:252
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1416
int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
Definition: avc.c:106
static const AVClass dash_class
Definition: dashenc.c:994
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:240
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
#define AV_WL32(p, v)
Definition: intreadwrite.h:426
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)
Definition: dashenc.c:684