You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1278 lines
46KB

  1. /*
  2. * MPEG-DASH ISO BMFF segmenter
  3. * Copyright (c) 2014 Martin Storsjo
  4. *
  5. * This file is part of Libav.
  6. *
  7. * Libav 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. * Libav 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 Libav; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "config.h"
  22. #if HAVE_UNISTD_H
  23. #include <unistd.h>
  24. #endif
  25. #include "libavutil/avutil.h"
  26. #include "libavutil/avstring.h"
  27. #include "libavutil/intreadwrite.h"
  28. #include "libavutil/mathematics.h"
  29. #include "libavutil/opt.h"
  30. #include "libavutil/time_internal.h"
  31. #include "avc.h"
  32. #include "avformat.h"
  33. #include "avio_internal.h"
  34. #include "internal.h"
  35. #include "isom.h"
  36. #include "os_support.h"
  37. #include "url.h"
  38. // See ISO/IEC 23009-1:2014 5.3.9.4.4
  39. typedef enum {
  40. DASH_TMPL_ID_UNDEFINED = -1,
  41. DASH_TMPL_ID_ESCAPE,
  42. DASH_TMPL_ID_REP_ID,
  43. DASH_TMPL_ID_NUMBER,
  44. DASH_TMPL_ID_BANDWIDTH,
  45. DASH_TMPL_ID_TIME,
  46. } DASHTmplId;
  47. typedef struct Segment {
  48. char file[1024];
  49. int64_t start_pos;
  50. int range_length, index_length;
  51. int64_t time;
  52. int duration;
  53. int n;
  54. } Segment;
  55. typedef struct AdaptationSet {
  56. char id[10];
  57. enum AVMediaType media_type;
  58. AVDictionary *metadata;
  59. } AdaptationSet;
  60. typedef struct OutputStream {
  61. AVFormatContext *ctx;
  62. int ctx_inited, as_idx;
  63. AVIOContext *out;
  64. char format_name[8];
  65. int packets_written;
  66. char initfile[1024];
  67. int64_t init_start_pos, pos;
  68. int init_range_length;
  69. int nb_segments, segments_size, segment_index;
  70. Segment **segments;
  71. int64_t first_pts, start_pts, max_pts;
  72. int64_t last_dts;
  73. int bit_rate;
  74. char bandwidth_str[64];
  75. char codec_str[100];
  76. } OutputStream;
  77. typedef struct DASHContext {
  78. const AVClass *class; /* Class for private options. */
  79. char *adaptation_sets;
  80. AdaptationSet *as;
  81. int nb_as;
  82. int window_size;
  83. int extra_window_size;
  84. int min_seg_duration;
  85. int remove_at_exit;
  86. int use_template;
  87. int use_timeline;
  88. int single_file;
  89. OutputStream *streams;
  90. int has_video;
  91. int64_t last_duration;
  92. int64_t total_duration;
  93. char availability_start_time[100];
  94. char dirname[1024];
  95. const char *single_file_name;
  96. const char *init_seg_name;
  97. const char *media_seg_name;
  98. const char *utc_timing_url;
  99. } DASHContext;
  100. static struct codec_string {
  101. int id;
  102. const char *str;
  103. } codecs[] = {
  104. { AV_CODEC_ID_VP8, "vp8" },
  105. { AV_CODEC_ID_VP9, "vp9" },
  106. { AV_CODEC_ID_VORBIS, "vorbis" },
  107. { AV_CODEC_ID_OPUS, "opus" },
  108. { 0, NULL }
  109. };
  110. static void set_codec_str(AVFormatContext *s, AVCodecParameters *par,
  111. char *str, int size)
  112. {
  113. const AVCodecTag *tags[2] = { NULL, NULL };
  114. uint32_t tag;
  115. int i;
  116. // common Webm codecs are not part of RFC 6381
  117. for (i = 0; codecs[i].id; i++)
  118. if (codecs[i].id == par->codec_id) {
  119. av_strlcpy(str, codecs[i].str, size);
  120. return;
  121. }
  122. // for codecs part of RFC 6381
  123. if (par->codec_type == AVMEDIA_TYPE_VIDEO)
  124. tags[0] = ff_codec_movvideo_tags;
  125. else if (par->codec_type == AVMEDIA_TYPE_AUDIO)
  126. tags[0] = ff_codec_movaudio_tags;
  127. else
  128. return;
  129. tag = av_codec_get_tag(tags, par->codec_id);
  130. if (!tag)
  131. return;
  132. if (size < 5)
  133. return;
  134. AV_WL32(str, tag);
  135. str[4] = '\0';
  136. if (!strcmp(str, "mp4a") || !strcmp(str, "mp4v")) {
  137. uint32_t oti;
  138. tags[0] = ff_mp4_obj_type;
  139. oti = av_codec_get_tag(tags, par->codec_id);
  140. if (oti)
  141. av_strlcatf(str, size, ".%02"SCNx32, oti);
  142. else
  143. return;
  144. if (tag == MKTAG('m', 'p', '4', 'a')) {
  145. if (par->extradata_size >= 2) {
  146. int aot = par->extradata[0] >> 3;
  147. if (aot == 31)
  148. aot = ((AV_RB16(par->extradata) >> 5) & 0x3f) + 32;
  149. av_strlcatf(str, size, ".%d", aot);
  150. }
  151. } else if (tag == MKTAG('m', 'p', '4', 'v')) {
  152. // Unimplemented, should output ProfileLevelIndication as a decimal number
  153. av_log(s, AV_LOG_WARNING, "Incomplete RFC 6381 codec string for mp4v\n");
  154. }
  155. } else if (!strcmp(str, "avc1")) {
  156. uint8_t *tmpbuf = NULL;
  157. uint8_t *extradata = par->extradata;
  158. int extradata_size = par->extradata_size;
  159. if (!extradata_size)
  160. return;
  161. if (extradata[0] != 1) {
  162. AVIOContext *pb;
  163. if (avio_open_dyn_buf(&pb) < 0)
  164. return;
  165. if (ff_isom_write_avcc(pb, extradata, extradata_size) < 0) {
  166. ffio_free_dyn_buf(&pb);
  167. return;
  168. }
  169. extradata_size = avio_close_dyn_buf(pb, &extradata);
  170. tmpbuf = extradata;
  171. }
  172. if (extradata_size >= 4)
  173. av_strlcatf(str, size, ".%02x%02x%02x",
  174. extradata[1], extradata[2], extradata[3]);
  175. av_free(tmpbuf);
  176. }
  177. }
  178. static int flush_dynbuf(OutputStream *os, int *range_length)
  179. {
  180. uint8_t *buffer;
  181. if (!os->ctx->pb) {
  182. return AVERROR(EINVAL);
  183. }
  184. // flush
  185. av_write_frame(os->ctx, NULL);
  186. avio_flush(os->ctx->pb);
  187. // write out to file
  188. *range_length = avio_close_dyn_buf(os->ctx->pb, &buffer);
  189. os->ctx->pb = NULL;
  190. avio_write(os->out, buffer, *range_length);
  191. av_free(buffer);
  192. // re-open buffer
  193. return avio_open_dyn_buf(&os->ctx->pb);
  194. }
  195. static int flush_init_segment(AVFormatContext *s, OutputStream *os)
  196. {
  197. DASHContext *c = s->priv_data;
  198. int ret, range_length;
  199. ret = flush_dynbuf(os, &range_length);
  200. if (ret < 0)
  201. return ret;
  202. os->pos = os->init_range_length = range_length;
  203. if (!c->single_file)
  204. ff_format_io_close(s, &os->out);
  205. return 0;
  206. }
  207. static void dash_free(AVFormatContext *s)
  208. {
  209. DASHContext *c = s->priv_data;
  210. int i, j;
  211. if (c->as) {
  212. for (i = 0; i < c->nb_as; i++)
  213. av_dict_free(&c->as[i].metadata);
  214. av_freep(&c->as);
  215. c->nb_as = 0;
  216. }
  217. if (!c->streams)
  218. return;
  219. for (i = 0; i < s->nb_streams; i++) {
  220. OutputStream *os = &c->streams[i];
  221. if (os->ctx && os->ctx_inited)
  222. av_write_trailer(os->ctx);
  223. if (os->ctx && os->ctx->pb)
  224. ffio_free_dyn_buf(&os->ctx->pb);
  225. ff_format_io_close(s, &os->out);
  226. if (os->ctx)
  227. avformat_free_context(os->ctx);
  228. for (j = 0; j < os->nb_segments; j++)
  229. av_free(os->segments[j]);
  230. av_free(os->segments);
  231. }
  232. av_freep(&c->streams);
  233. }
  234. static void output_segment_list(OutputStream *os, AVIOContext *out, DASHContext *c)
  235. {
  236. int i, start_index = 0, start_number = 1;
  237. if (c->window_size) {
  238. start_index = FFMAX(os->nb_segments - c->window_size, 0);
  239. start_number = FFMAX(os->segment_index - c->window_size, 1);
  240. }
  241. if (c->use_template) {
  242. int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : AV_TIME_BASE;
  243. avio_printf(out, "\t\t\t\t<SegmentTemplate timescale=\"%d\" ", timescale);
  244. if (!c->use_timeline)
  245. avio_printf(out, "duration=\"%"PRId64"\" ", c->last_duration);
  246. avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? start_number : 1);
  247. if (c->use_timeline) {
  248. int64_t cur_time = 0;
  249. avio_printf(out, "\t\t\t\t\t<SegmentTimeline>\n");
  250. for (i = start_index; i < os->nb_segments; ) {
  251. Segment *seg = os->segments[i];
  252. int repeat = 0;
  253. avio_printf(out, "\t\t\t\t\t\t<S ");
  254. if (i == start_index || seg->time != cur_time) {
  255. cur_time = seg->time;
  256. avio_printf(out, "t=\"%"PRId64"\" ", seg->time);
  257. }
  258. avio_printf(out, "d=\"%d\" ", seg->duration);
  259. while (i + repeat + 1 < os->nb_segments &&
  260. os->segments[i + repeat + 1]->duration == seg->duration &&
  261. os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]->duration)
  262. repeat++;
  263. if (repeat > 0)
  264. avio_printf(out, "r=\"%d\" ", repeat);
  265. avio_printf(out, "/>\n");
  266. i += 1 + repeat;
  267. cur_time += (1 + repeat) * seg->duration;
  268. }
  269. avio_printf(out, "\t\t\t\t\t</SegmentTimeline>\n");
  270. }
  271. avio_printf(out, "\t\t\t\t</SegmentTemplate>\n");
  272. } else if (c->single_file) {
  273. avio_printf(out, "\t\t\t\t<BaseURL>%s</BaseURL>\n", os->initfile);
  274. avio_printf(out, "\t\t\t\t<SegmentList timescale=\"%d\" duration=\"%"PRId64"\" startNumber=\"%d\">\n", AV_TIME_BASE, c->last_duration, start_number);
  275. 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);
  276. for (i = start_index; i < os->nb_segments; i++) {
  277. Segment *seg = os->segments[i];
  278. avio_printf(out, "\t\t\t\t\t<SegmentURL mediaRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->range_length - 1);
  279. if (seg->index_length)
  280. avio_printf(out, "indexRange=\"%"PRId64"-%"PRId64"\" ", seg->start_pos, seg->start_pos + seg->index_length - 1);
  281. avio_printf(out, "/>\n");
  282. }
  283. avio_printf(out, "\t\t\t\t</SegmentList>\n");
  284. } else {
  285. avio_printf(out, "\t\t\t\t<SegmentList timescale=\"%d\" duration=\"%"PRId64"\" startNumber=\"%d\">\n", AV_TIME_BASE, c->last_duration, start_number);
  286. avio_printf(out, "\t\t\t\t\t<Initialization sourceURL=\"%s\" />\n", os->initfile);
  287. for (i = start_index; i < os->nb_segments; i++) {
  288. Segment *seg = os->segments[i];
  289. avio_printf(out, "\t\t\t\t\t<SegmentURL media=\"%s\" />\n", seg->file);
  290. }
  291. avio_printf(out, "\t\t\t\t</SegmentList>\n");
  292. }
  293. }
  294. static DASHTmplId dash_read_tmpl_id(const char *identifier, char *format_tag,
  295. size_t format_tag_size, const char **ptr) {
  296. const char *next_ptr;
  297. DASHTmplId id_type = DASH_TMPL_ID_UNDEFINED;
  298. if (av_strstart(identifier, "$$", &next_ptr)) {
  299. id_type = DASH_TMPL_ID_ESCAPE;
  300. *ptr = next_ptr;
  301. } else if (av_strstart(identifier, "$RepresentationID$", &next_ptr)) {
  302. id_type = DASH_TMPL_ID_REP_ID;
  303. // default to basic format, as $RepresentationID$ identifiers
  304. // are not allowed to have custom format-tags.
  305. av_strlcpy(format_tag, "%d", format_tag_size);
  306. *ptr = next_ptr;
  307. } else { // the following identifiers may have an explicit format_tag
  308. if (av_strstart(identifier, "$Number", &next_ptr))
  309. id_type = DASH_TMPL_ID_NUMBER;
  310. else if (av_strstart(identifier, "$Bandwidth", &next_ptr))
  311. id_type = DASH_TMPL_ID_BANDWIDTH;
  312. else if (av_strstart(identifier, "$Time", &next_ptr))
  313. id_type = DASH_TMPL_ID_TIME;
  314. else
  315. id_type = DASH_TMPL_ID_UNDEFINED;
  316. // next parse the dash format-tag and generate a c-string format tag
  317. // (next_ptr now points at the first '%' at the beginning of the format-tag)
  318. if (id_type != DASH_TMPL_ID_UNDEFINED) {
  319. const char *number_format = (id_type == DASH_TMPL_ID_TIME) ? PRId64 : "d";
  320. if (next_ptr[0] == '$') { // no dash format-tag
  321. snprintf(format_tag, format_tag_size, "%%%s", number_format);
  322. *ptr = &next_ptr[1];
  323. } else {
  324. const char *width_ptr;
  325. // only tolerate single-digit width-field (i.e. up to 9-digit width)
  326. if (av_strstart(next_ptr, "%0", &width_ptr) &&
  327. av_isdigit(width_ptr[0]) &&
  328. av_strstart(&width_ptr[1], "d$", &next_ptr)) {
  329. // yes, we're using a format tag to build format_tag.
  330. snprintf(format_tag, format_tag_size, "%s%c%s", "%0", width_ptr[0], number_format);
  331. *ptr = next_ptr;
  332. } else {
  333. av_log(NULL, AV_LOG_WARNING, "Failed to parse format-tag beginning with %s. Expected either a "
  334. "closing '$' character or a format-string like '%%0[width]d', "
  335. "where width must be a single digit\n", next_ptr);
  336. id_type = DASH_TMPL_ID_UNDEFINED;
  337. }
  338. }
  339. }
  340. }
  341. return id_type;
  342. }
  343. static void dash_fill_tmpl_params(char *dst, size_t buffer_size,
  344. const char *template, int rep_id,
  345. int number, int bit_rate,
  346. int64_t time) {
  347. int dst_pos = 0;
  348. const char *t_cur = template;
  349. while (dst_pos < buffer_size - 1 && *t_cur) {
  350. char format_tag[7]; // May be "%d", "%0Xd", or "%0Xlld" (for $Time$), where X is in [0-9]
  351. int n = 0;
  352. DASHTmplId id_type;
  353. const char *t_next = strchr(t_cur, '$'); // copy over everything up to the first '$' character
  354. if (t_next) {
  355. int num_copy_bytes = FFMIN(t_next - t_cur, buffer_size - dst_pos - 1);
  356. av_strlcpy(&dst[dst_pos], t_cur, num_copy_bytes + 1);
  357. // advance
  358. dst_pos += num_copy_bytes;
  359. t_cur = t_next;
  360. } else { // no more DASH identifiers to substitute - just copy the rest over and break
  361. av_strlcpy(&dst[dst_pos], t_cur, buffer_size - dst_pos);
  362. break;
  363. }
  364. if (dst_pos >= buffer_size - 1 || !*t_cur)
  365. break;
  366. // t_cur is now pointing to a '$' character
  367. id_type = dash_read_tmpl_id(t_cur, format_tag, sizeof(format_tag), &t_next);
  368. switch (id_type) {
  369. case DASH_TMPL_ID_ESCAPE:
  370. av_strlcpy(&dst[dst_pos], "$", 2);
  371. n = 1;
  372. break;
  373. case DASH_TMPL_ID_REP_ID:
  374. n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, rep_id);
  375. break;
  376. case DASH_TMPL_ID_NUMBER:
  377. n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, number);
  378. break;
  379. case DASH_TMPL_ID_BANDWIDTH:
  380. n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, bit_rate);
  381. break;
  382. case DASH_TMPL_ID_TIME:
  383. n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, time);
  384. break;
  385. case DASH_TMPL_ID_UNDEFINED:
  386. // copy over one byte and advance
  387. av_strlcpy(&dst[dst_pos], t_cur, 2);
  388. n = 1;
  389. t_next = &t_cur[1];
  390. break;
  391. }
  392. // t_next points just past the processed identifier
  393. // n is the number of bytes that were attempted to be written to dst
  394. // (may have failed to write all because buffer_size).
  395. // advance
  396. dst_pos += FFMIN(n, buffer_size - dst_pos - 1);
  397. t_cur = t_next;
  398. }
  399. }
  400. static char *xmlescape(const char *str) {
  401. int outlen = strlen(str)*3/2 + 6;
  402. char *out = av_realloc(NULL, outlen + 1);
  403. int pos = 0;
  404. if (!out)
  405. return NULL;
  406. for (; *str; str++) {
  407. if (pos + 6 > outlen) {
  408. char *tmp;
  409. outlen = 2 * outlen + 6;
  410. tmp = av_realloc(out, outlen + 1);
  411. if (!tmp) {
  412. av_free(out);
  413. return NULL;
  414. }
  415. out = tmp;
  416. }
  417. if (*str == '&') {
  418. memcpy(&out[pos], "&amp;", 5);
  419. pos += 5;
  420. } else if (*str == '<') {
  421. memcpy(&out[pos], "&lt;", 4);
  422. pos += 4;
  423. } else if (*str == '>') {
  424. memcpy(&out[pos], "&gt;", 4);
  425. pos += 4;
  426. } else if (*str == '\'') {
  427. memcpy(&out[pos], "&apos;", 6);
  428. pos += 6;
  429. } else if (*str == '\"') {
  430. memcpy(&out[pos], "&quot;", 6);
  431. pos += 6;
  432. } else {
  433. out[pos++] = *str;
  434. }
  435. }
  436. out[pos] = '\0';
  437. return out;
  438. }
  439. static void write_time(AVIOContext *out, int64_t time)
  440. {
  441. int seconds = time / AV_TIME_BASE;
  442. int fractions = time % AV_TIME_BASE;
  443. int minutes = seconds / 60;
  444. int hours = minutes / 60;
  445. seconds %= 60;
  446. minutes %= 60;
  447. avio_printf(out, "PT");
  448. if (hours)
  449. avio_printf(out, "%dH", hours);
  450. if (hours || minutes)
  451. avio_printf(out, "%dM", minutes);
  452. avio_printf(out, "%d.%dS", seconds, fractions / (AV_TIME_BASE / 10));
  453. }
  454. static void format_date_now(char *buf, int size)
  455. {
  456. time_t t = time(NULL);
  457. struct tm *ptm, tmbuf;
  458. ptm = gmtime_r(&t, &tmbuf);
  459. if (ptm) {
  460. if (!strftime(buf, size, "%Y-%m-%dT%H:%M:%SZ", ptm))
  461. buf[0] = '\0';
  462. }
  463. }
  464. static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index)
  465. {
  466. DASHContext *c = s->priv_data;
  467. AdaptationSet *as = &c->as[as_index];
  468. AVDictionaryEntry *lang, *role;
  469. int i;
  470. avio_printf(out, "\t\t<AdaptationSet id=\"%s\" contentType=\"%s\" segmentAlignment=\"true\" bitstreamSwitching=\"true\"",
  471. as->id, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
  472. lang = av_dict_get(as->metadata, "language", NULL, 0);
  473. if (lang)
  474. avio_printf(out, " lang=\"%s\"", lang->value);
  475. avio_printf(out, ">\n");
  476. role = av_dict_get(as->metadata, "role", NULL, 0);
  477. if (role)
  478. avio_printf(out, "\t\t\t<Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"%s\"/>\n", role->value);
  479. for (i = 0; i < s->nb_streams; i++) {
  480. OutputStream *os = &c->streams[i];
  481. if (os->as_idx - 1 != as_index)
  482. continue;
  483. if (as->media_type == AVMEDIA_TYPE_VIDEO) {
  484. avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\">\n",
  485. i, os->format_name, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
  486. } else {
  487. avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
  488. i, os->format_name, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->sample_rate);
  489. avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n",
  490. s->streams[i]->codecpar->channels);
  491. }
  492. output_segment_list(os, out, c);
  493. avio_printf(out, "\t\t\t</Representation>\n");
  494. }
  495. avio_printf(out, "\t\t</AdaptationSet>\n");
  496. return 0;
  497. }
  498. static int add_adaptation_set(AVFormatContext *s, AdaptationSet **as, enum AVMediaType type)
  499. {
  500. DASHContext *c = s->priv_data;
  501. void *mem = av_realloc(c->as, sizeof(*c->as) * (c->nb_as + 1));
  502. if (!mem)
  503. return AVERROR(ENOMEM);
  504. c->as = mem;
  505. ++c->nb_as;
  506. *as = &c->as[c->nb_as - 1];
  507. memset(*as, 0, sizeof(**as));
  508. (*as)->media_type = type;
  509. return 0;
  510. }
  511. static int adaptation_set_add_stream(AVFormatContext *s, int as_idx, int i)
  512. {
  513. DASHContext *c = s->priv_data;
  514. AdaptationSet *as = &c->as[as_idx - 1];
  515. OutputStream *os = &c->streams[i];
  516. if (as->media_type != s->streams[i]->codecpar->codec_type) {
  517. av_log(s, AV_LOG_ERROR, "Codec type of stream %d doesn't match AdaptationSet's media type\n", i);
  518. return AVERROR(EINVAL);
  519. } else if (os->as_idx) {
  520. av_log(s, AV_LOG_ERROR, "Stream %d is already assigned to an AdaptationSet\n", i);
  521. return AVERROR(EINVAL);
  522. }
  523. os->as_idx = as_idx;
  524. return 0;
  525. }
  526. static int parse_adaptation_sets(AVFormatContext *s)
  527. {
  528. DASHContext *c = s->priv_data;
  529. const char *p = c->adaptation_sets;
  530. enum { new_set, parse_id, parsing_streams } state;
  531. AdaptationSet *as;
  532. int i, n, ret;
  533. // default: one AdaptationSet for each stream
  534. if (!p) {
  535. for (i = 0; i < s->nb_streams; i++) {
  536. if ((ret = add_adaptation_set(s, &as, s->streams[i]->codecpar->codec_type)) < 0)
  537. return ret;
  538. snprintf(as->id, sizeof(as->id), "%d", i);
  539. c->streams[i].as_idx = c->nb_as;
  540. }
  541. goto end;
  542. }
  543. // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
  544. state = new_set;
  545. while (*p) {
  546. if (*p == ' ') {
  547. p++;
  548. continue;
  549. } else if (state == new_set && av_strstart(p, "id=", &p)) {
  550. if ((ret = add_adaptation_set(s, &as, AVMEDIA_TYPE_UNKNOWN)) < 0)
  551. return ret;
  552. n = strcspn(p, ",");
  553. snprintf(as->id, sizeof(as->id), "%.*s", n, p);
  554. p += n;
  555. if (*p)
  556. p++;
  557. state = parse_id;
  558. } else if (state == parse_id && av_strstart(p, "streams=", &p)) {
  559. state = parsing_streams;
  560. } else if (state == parsing_streams) {
  561. AdaptationSet *as = &c->as[c->nb_as - 1];
  562. char idx_str[8], *end_str;
  563. n = strcspn(p, " ,");
  564. snprintf(idx_str, sizeof(idx_str), "%.*s", n, p);
  565. p += n;
  566. // if value is "a" or "v", map all streams of that type
  567. if (as->media_type == AVMEDIA_TYPE_UNKNOWN && (idx_str[0] == 'v' || idx_str[0] == 'a')) {
  568. enum AVMediaType type = (idx_str[0] == 'v') ? AVMEDIA_TYPE_VIDEO : AVMEDIA_TYPE_AUDIO;
  569. av_log(s, AV_LOG_DEBUG, "Map all streams of type %s\n", idx_str);
  570. for (i = 0; i < s->nb_streams; i++) {
  571. if (s->streams[i]->codecpar->codec_type != type)
  572. continue;
  573. as->media_type = s->streams[i]->codecpar->codec_type;
  574. if ((ret = adaptation_set_add_stream(s, c->nb_as, i)) < 0)
  575. return ret;
  576. }
  577. } else { // select single stream
  578. i = strtol(idx_str, &end_str, 10);
  579. if (idx_str == end_str || i < 0 || i >= s->nb_streams) {
  580. av_log(s, AV_LOG_ERROR, "Selected stream \"%s\" not found!\n", idx_str);
  581. return AVERROR(EINVAL);
  582. }
  583. av_log(s, AV_LOG_DEBUG, "Map stream %d\n", i);
  584. if (as->media_type == AVMEDIA_TYPE_UNKNOWN) {
  585. as->media_type = s->streams[i]->codecpar->codec_type;
  586. }
  587. if ((ret = adaptation_set_add_stream(s, c->nb_as, i)) < 0)
  588. return ret;
  589. }
  590. if (*p == ' ')
  591. state = new_set;
  592. if (*p)
  593. p++;
  594. } else {
  595. return AVERROR(EINVAL);
  596. }
  597. }
  598. end:
  599. // check for unassigned streams
  600. for (i = 0; i < s->nb_streams; i++) {
  601. OutputStream *os = &c->streams[i];
  602. if (!os->as_idx) {
  603. av_log(s, AV_LOG_ERROR, "Stream %d is not mapped to an AdaptationSet\n", i);
  604. return AVERROR(EINVAL);
  605. }
  606. }
  607. return 0;
  608. }
  609. static int write_manifest(AVFormatContext *s, int final)
  610. {
  611. DASHContext *c = s->priv_data;
  612. AVIOContext *out;
  613. char temp_filename[1024];
  614. int ret, i;
  615. AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
  616. snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", s->filename);
  617. ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL);
  618. if (ret < 0) {
  619. av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename);
  620. return ret;
  621. }
  622. avio_printf(out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
  623. avio_printf(out, "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
  624. "\txmlns=\"urn:mpeg:dash:schema:mpd:2011\"\n"
  625. "\txmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
  626. "\txsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\"\n"
  627. "\tprofiles=\"urn:mpeg:dash:profile:isoff-live:2011\"\n"
  628. "\ttype=\"%s\"\n", final ? "static" : "dynamic");
  629. if (final) {
  630. avio_printf(out, "\tmediaPresentationDuration=\"");
  631. write_time(out, c->total_duration);
  632. avio_printf(out, "\"\n");
  633. } else {
  634. int64_t update_period = c->last_duration / AV_TIME_BASE;
  635. char now_str[100];
  636. if (c->use_template && !c->use_timeline)
  637. update_period = 500;
  638. avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", update_period);
  639. avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", c->last_duration / AV_TIME_BASE);
  640. if (!c->availability_start_time[0] && s->nb_streams > 0 && c->streams[0].nb_segments > 0) {
  641. format_date_now(c->availability_start_time, sizeof(c->availability_start_time));
  642. }
  643. if (c->availability_start_time[0])
  644. avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", c->availability_start_time);
  645. format_date_now(now_str, sizeof(now_str));
  646. if (now_str[0])
  647. avio_printf(out, "\tpublishTime=\"%s\"\n", now_str);
  648. if (c->window_size && c->use_template) {
  649. avio_printf(out, "\ttimeShiftBufferDepth=\"");
  650. write_time(out, c->last_duration * c->window_size);
  651. avio_printf(out, "\"\n");
  652. }
  653. }
  654. avio_printf(out, "\tminBufferTime=\"");
  655. write_time(out, c->last_duration * 2);
  656. avio_printf(out, "\">\n");
  657. avio_printf(out, "\t<ProgramInformation>\n");
  658. if (title) {
  659. char *escaped = xmlescape(title->value);
  660. avio_printf(out, "\t\t<Title>%s</Title>\n", escaped);
  661. av_free(escaped);
  662. }
  663. avio_printf(out, "\t</ProgramInformation>\n");
  664. if (c->utc_timing_url)
  665. avio_printf(out, "\t<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:http-xsdate:2014\" value=\"%s\"/>\n", c->utc_timing_url);
  666. if (c->window_size && s->nb_streams > 0 && c->streams[0].nb_segments > 0 && !c->use_template) {
  667. OutputStream *os = &c->streams[0];
  668. int start_index = FFMAX(os->nb_segments - c->window_size, 0);
  669. int64_t start_time = av_rescale_q(os->segments[start_index]->time, s->streams[0]->time_base, AV_TIME_BASE_Q);
  670. avio_printf(out, "\t<Period id=\"0\" start=\"");
  671. write_time(out, start_time);
  672. avio_printf(out, "\">\n");
  673. } else {
  674. avio_printf(out, "\t<Period id=\"0\" start=\"PT0.0S\">\n");
  675. }
  676. for (i = 0; i < c->nb_as; i++) {
  677. if ((ret = write_adaptation_set(s, out, i)) < 0)
  678. return ret;
  679. }
  680. avio_printf(out, "\t</Period>\n");
  681. avio_printf(out, "</MPD>\n");
  682. avio_flush(out);
  683. ff_format_io_close(s, &out);
  684. return ff_rename(temp_filename, s->filename);
  685. }
  686. static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const char *key)
  687. {
  688. AVDictionaryEntry *entry = av_dict_get(src, key, NULL, 0);
  689. if (entry)
  690. av_dict_set(dst, key, entry->value, AV_DICT_DONT_OVERWRITE);
  691. return 0;
  692. }
  693. static int dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
  694. {
  695. char valuestr[22];
  696. snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
  697. flags &= ~AV_DICT_DONT_STRDUP_VAL;
  698. return av_dict_set(pm, key, valuestr, flags);
  699. }
  700. static int dash_write_header(AVFormatContext *s)
  701. {
  702. DASHContext *c = s->priv_data;
  703. int ret = 0, i;
  704. char *ptr;
  705. char basename[1024];
  706. if (c->single_file_name)
  707. c->single_file = 1;
  708. if (c->single_file)
  709. c->use_template = 0;
  710. av_strlcpy(c->dirname, s->filename, sizeof(c->dirname));
  711. ptr = strrchr(c->dirname, '/');
  712. if (ptr) {
  713. av_strlcpy(basename, &ptr[1], sizeof(basename));
  714. ptr[1] = '\0';
  715. } else {
  716. c->dirname[0] = '\0';
  717. av_strlcpy(basename, s->filename, sizeof(basename));
  718. }
  719. ptr = strrchr(basename, '.');
  720. if (ptr)
  721. *ptr = '\0';
  722. c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
  723. if (!c->streams) {
  724. ret = AVERROR(ENOMEM);
  725. goto fail;
  726. }
  727. if ((ret = parse_adaptation_sets(s)) < 0)
  728. goto fail;
  729. for (i = 0; i < s->nb_streams; i++) {
  730. OutputStream *os = &c->streams[i];
  731. AdaptationSet *as = &c->as[os->as_idx - 1];
  732. AVFormatContext *ctx;
  733. AVStream *st;
  734. AVDictionary *opts = NULL;
  735. char filename[1024];
  736. os->bit_rate = s->streams[i]->codecpar->bit_rate;
  737. if (os->bit_rate) {
  738. snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
  739. " bandwidth=\"%d\"", os->bit_rate);
  740. } else {
  741. int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ?
  742. AV_LOG_ERROR : AV_LOG_WARNING;
  743. av_log(s, level, "No bit rate set for stream %d\n", i);
  744. if (s->strict_std_compliance >= FF_COMPLIANCE_STRICT) {
  745. ret = AVERROR(EINVAL);
  746. goto fail;
  747. }
  748. }
  749. // copy AdaptationSet language and role from stream metadata
  750. dict_copy_entry(&as->metadata, s->streams[i]->metadata, "language");
  751. dict_copy_entry(&as->metadata, s->streams[i]->metadata, "role");
  752. ctx = avformat_alloc_context();
  753. if (!ctx) {
  754. ret = AVERROR(ENOMEM);
  755. goto fail;
  756. }
  757. // choose muxer based on codec: webm for VP8/9 and opus, mp4 otherwise
  758. // note: os->format_name is also used as part of the mimetype of the
  759. // representation, e.g. video/<format_name>
  760. if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP8 ||
  761. s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP9 ||
  762. s->streams[i]->codecpar->codec_id == AV_CODEC_ID_OPUS ||
  763. s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VORBIS) {
  764. snprintf(os->format_name, sizeof(os->format_name), "webm");
  765. } else {
  766. snprintf(os->format_name, sizeof(os->format_name), "mp4");
  767. }
  768. ctx->oformat = av_guess_format(os->format_name, NULL, NULL);
  769. if (!ctx->oformat) {
  770. ret = AVERROR_MUXER_NOT_FOUND;
  771. goto fail;
  772. }
  773. os->ctx = ctx;
  774. ctx->interrupt_callback = s->interrupt_callback;
  775. ctx->opaque = s->opaque;
  776. ctx->io_close = s->io_close;
  777. ctx->io_open = s->io_open;
  778. if (!(st = avformat_new_stream(ctx, NULL))) {
  779. ret = AVERROR(ENOMEM);
  780. goto fail;
  781. }
  782. avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar);
  783. st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
  784. st->time_base = s->streams[i]->time_base;
  785. ctx->avoid_negative_ts = s->avoid_negative_ts;
  786. if ((ret = avio_open_dyn_buf(&ctx->pb)) < 0)
  787. goto fail;
  788. if (c->single_file) {
  789. if (c->single_file_name)
  790. dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->single_file_name, i, 0, os->bit_rate, 0);
  791. else
  792. snprintf(os->initfile, sizeof(os->initfile), "%s-stream%d.m4s", basename, i);
  793. } else {
  794. dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->init_seg_name, i, 0, os->bit_rate, 0);
  795. }
  796. snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
  797. ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, NULL);
  798. if (ret < 0)
  799. goto fail;
  800. os->init_start_pos = 0;
  801. if (!strcmp(os->format_name, "mp4")) {
  802. av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
  803. } else {
  804. dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0);
  805. dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit
  806. }
  807. if ((ret = avformat_write_header(ctx, &opts)) < 0) {
  808. goto fail;
  809. }
  810. os->ctx_inited = 1;
  811. avio_flush(ctx->pb);
  812. av_dict_free(&opts);
  813. av_log(s, AV_LOG_VERBOSE, "Representation %d init segment will be written to: %s\n", i, filename);
  814. // Flush init segment
  815. // except for mp4, since delay_moov is set and the init segment
  816. // is then flushed after the first packets
  817. if (strcmp(os->format_name, "mp4")) {
  818. flush_init_segment(s, os);
  819. }
  820. s->streams[i]->time_base = st->time_base;
  821. // If the muxer wants to shift timestamps, request to have them shifted
  822. // already before being handed to this muxer, so we don't have mismatches
  823. // between the MPD and the actual segments.
  824. s->avoid_negative_ts = ctx->avoid_negative_ts;
  825. if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
  826. c->has_video = 1;
  827. set_codec_str(s, st->codecpar, os->codec_str, sizeof(os->codec_str));
  828. os->first_pts = AV_NOPTS_VALUE;
  829. os->max_pts = AV_NOPTS_VALUE;
  830. os->last_dts = AV_NOPTS_VALUE;
  831. os->segment_index = 1;
  832. }
  833. if (!c->has_video && c->min_seg_duration <= 0) {
  834. av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration set\n");
  835. ret = AVERROR(EINVAL);
  836. }
  837. ret = write_manifest(s, 0);
  838. if (!ret)
  839. av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->filename);
  840. fail:
  841. if (ret)
  842. dash_free(s);
  843. return ret;
  844. }
  845. static int add_segment(OutputStream *os, const char *file,
  846. int64_t time, int duration,
  847. int64_t start_pos, int64_t range_length,
  848. int64_t index_length)
  849. {
  850. int err;
  851. Segment *seg;
  852. if (os->nb_segments >= os->segments_size) {
  853. os->segments_size = (os->segments_size + 1) * 2;
  854. if ((err = av_reallocp(&os->segments, sizeof(*os->segments) *
  855. os->segments_size)) < 0) {
  856. os->segments_size = 0;
  857. os->nb_segments = 0;
  858. return err;
  859. }
  860. }
  861. seg = av_mallocz(sizeof(*seg));
  862. if (!seg)
  863. return AVERROR(ENOMEM);
  864. av_strlcpy(seg->file, file, sizeof(seg->file));
  865. seg->time = time;
  866. seg->duration = duration;
  867. if (seg->time < 0) { // If pts<0, it is expected to be cut away with an edit list
  868. seg->duration += seg->time;
  869. seg->time = 0;
  870. }
  871. seg->start_pos = start_pos;
  872. seg->range_length = range_length;
  873. seg->index_length = index_length;
  874. os->segments[os->nb_segments++] = seg;
  875. os->segment_index++;
  876. return 0;
  877. }
  878. static void write_styp(AVIOContext *pb)
  879. {
  880. avio_wb32(pb, 24);
  881. ffio_wfourcc(pb, "styp");
  882. ffio_wfourcc(pb, "msdh");
  883. avio_wb32(pb, 0); /* minor */
  884. ffio_wfourcc(pb, "msdh");
  885. ffio_wfourcc(pb, "msix");
  886. }
  887. static void find_index_range(AVFormatContext *s, const char *full_path,
  888. int64_t pos, int *index_length)
  889. {
  890. uint8_t buf[8];
  891. AVIOContext *pb;
  892. int ret;
  893. ret = s->io_open(s, &pb, full_path, AVIO_FLAG_READ, NULL);
  894. if (ret < 0)
  895. return;
  896. if (avio_seek(pb, pos, SEEK_SET) != pos) {
  897. ff_format_io_close(s, &pb);
  898. return;
  899. }
  900. ret = avio_read(pb, buf, 8);
  901. ff_format_io_close(s, &pb);
  902. if (ret < 8)
  903. return;
  904. if (AV_RL32(&buf[4]) != MKTAG('s', 'i', 'd', 'x'))
  905. return;
  906. *index_length = AV_RB32(&buf[0]);
  907. }
  908. static int update_stream_extradata(AVFormatContext *s, OutputStream *os,
  909. AVCodecParameters *par)
  910. {
  911. uint8_t *extradata;
  912. if (os->ctx->streams[0]->codecpar->extradata_size || !par->extradata_size)
  913. return 0;
  914. extradata = av_malloc(par->extradata_size);
  915. if (!extradata)
  916. return AVERROR(ENOMEM);
  917. memcpy(extradata, par->extradata, par->extradata_size);
  918. os->ctx->streams[0]->codecpar->extradata = extradata;
  919. os->ctx->streams[0]->codecpar->extradata_size = par->extradata_size;
  920. set_codec_str(s, par, os->codec_str, sizeof(os->codec_str));
  921. return 0;
  922. }
  923. static int dash_flush(AVFormatContext *s, int final, int stream)
  924. {
  925. DASHContext *c = s->priv_data;
  926. int i, ret = 0;
  927. int cur_flush_segment_index = 0;
  928. if (stream >= 0)
  929. cur_flush_segment_index = c->streams[stream].segment_index;
  930. for (i = 0; i < s->nb_streams; i++) {
  931. OutputStream *os = &c->streams[i];
  932. char filename[1024] = "", full_path[1024], temp_path[1024];
  933. int range_length, index_length = 0;
  934. if (!os->packets_written)
  935. continue;
  936. // Flush the single stream that got a keyframe right now.
  937. // Flush all audio streams as well, in sync with video keyframes,
  938. // but not the other video streams.
  939. if (stream >= 0 && i != stream) {
  940. if (s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
  941. continue;
  942. // Make sure we don't flush audio streams multiple times, when
  943. // all video streams are flushed one at a time.
  944. if (c->has_video && os->segment_index > cur_flush_segment_index)
  945. continue;
  946. }
  947. if (!os->init_range_length) {
  948. flush_init_segment(s, os);
  949. }
  950. if (!c->single_file) {
  951. dash_fill_tmpl_params(filename, sizeof(filename), c->media_seg_name, i, os->segment_index, os->bit_rate, os->start_pts);
  952. snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, filename);
  953. snprintf(temp_path, sizeof(temp_path), "%s.tmp", full_path);
  954. ret = s->io_open(s, &os->out, temp_path, AVIO_FLAG_WRITE, NULL);
  955. if (ret < 0)
  956. break;
  957. if (!strcmp(os->format_name, "mp4"))
  958. write_styp(os->ctx->pb);
  959. } else {
  960. snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, os->initfile);
  961. }
  962. ret = flush_dynbuf(os, &range_length);
  963. if (ret < 0)
  964. break;
  965. os->packets_written = 0;
  966. if (c->single_file) {
  967. find_index_range(s, full_path, os->pos, &index_length);
  968. } else {
  969. ff_format_io_close(s, &os->out);
  970. ret = ff_rename(temp_path, full_path);
  971. if (ret < 0)
  972. break;
  973. }
  974. if (!os->bit_rate) {
  975. // calculate average bitrate of first segment
  976. int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / (os->max_pts - os->start_pts);
  977. if (bitrate >= 0) {
  978. os->bit_rate = bitrate;
  979. snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
  980. " bandwidth=\"%d\"", os->bit_rate);
  981. }
  982. }
  983. add_segment(os, filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length);
  984. av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, full_path);
  985. os->pos += range_length;
  986. }
  987. if (c->window_size || (final && c->remove_at_exit)) {
  988. for (i = 0; i < s->nb_streams; i++) {
  989. OutputStream *os = &c->streams[i];
  990. int j;
  991. int remove = os->nb_segments - c->window_size - c->extra_window_size;
  992. if (final && c->remove_at_exit)
  993. remove = os->nb_segments;
  994. if (remove > 0) {
  995. for (j = 0; j < remove; j++) {
  996. char filename[1024];
  997. snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->segments[j]->file);
  998. unlink(filename);
  999. av_free(os->segments[j]);
  1000. }
  1001. os->nb_segments -= remove;
  1002. memmove(os->segments, os->segments + remove, os->nb_segments * sizeof(*os->segments));
  1003. }
  1004. }
  1005. }
  1006. if (ret >= 0)
  1007. ret = write_manifest(s, final);
  1008. return ret;
  1009. }
  1010. static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
  1011. {
  1012. DASHContext *c = s->priv_data;
  1013. AVStream *st = s->streams[pkt->stream_index];
  1014. OutputStream *os = &c->streams[pkt->stream_index];
  1015. int ret;
  1016. ret = update_stream_extradata(s, os, st->codecpar);
  1017. if (ret < 0)
  1018. return ret;
  1019. // Fill in a heuristic guess of the packet duration, if none is available.
  1020. // The mp4 muxer will do something similar (for the last packet in a fragment)
  1021. // if nothing is set (setting it for the other packets doesn't hurt).
  1022. // By setting a nonzero duration here, we can be sure that the mp4 muxer won't
  1023. // invoke its heuristic (this doesn't have to be identical to that algorithm),
  1024. // so that we know the exact timestamps of fragments.
  1025. if (!pkt->duration && os->last_dts != AV_NOPTS_VALUE)
  1026. pkt->duration = pkt->dts - os->last_dts;
  1027. os->last_dts = pkt->dts;
  1028. // If forcing the stream to start at 0, the mp4 muxer will set the start
  1029. // timestamps to 0. Do the same here, to avoid mismatches in duration/timestamps.
  1030. if (os->first_pts == AV_NOPTS_VALUE &&
  1031. s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
  1032. pkt->pts -= pkt->dts;
  1033. pkt->dts = 0;
  1034. }
  1035. if (os->first_pts == AV_NOPTS_VALUE)
  1036. os->first_pts = pkt->pts;
  1037. if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
  1038. pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
  1039. av_compare_ts(pkt->pts - os->start_pts, st->time_base,
  1040. c->min_seg_duration, AV_TIME_BASE_Q) >= 0) {
  1041. int64_t prev_duration = c->last_duration;
  1042. c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
  1043. st->time_base,
  1044. AV_TIME_BASE_Q);
  1045. c->total_duration = av_rescale_q(pkt->pts - os->first_pts,
  1046. st->time_base,
  1047. AV_TIME_BASE_Q);
  1048. if ((!c->use_timeline || !c->use_template) && prev_duration) {
  1049. if (c->last_duration < prev_duration*9/10 ||
  1050. c->last_duration > prev_duration*11/10) {
  1051. av_log(s, AV_LOG_WARNING,
  1052. "Segment durations differ too much, enable use_timeline "
  1053. "and use_template, or keep a stricter keyframe interval\n");
  1054. }
  1055. }
  1056. if ((ret = dash_flush(s, 0, pkt->stream_index)) < 0)
  1057. return ret;
  1058. }
  1059. if (!os->packets_written) {
  1060. // If we wrote a previous segment, adjust the start time of the segment
  1061. // to the end of the previous one (which is the same as the mp4 muxer
  1062. // does). This avoids gaps in the timeline.
  1063. if (os->max_pts != AV_NOPTS_VALUE)
  1064. os->start_pts = os->max_pts;
  1065. else
  1066. os->start_pts = pkt->pts;
  1067. }
  1068. if (os->max_pts == AV_NOPTS_VALUE)
  1069. os->max_pts = pkt->pts + pkt->duration;
  1070. else
  1071. os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
  1072. os->packets_written++;
  1073. return ff_write_chained(os->ctx, 0, pkt, s);
  1074. }
  1075. static int dash_write_trailer(AVFormatContext *s)
  1076. {
  1077. DASHContext *c = s->priv_data;
  1078. if (s->nb_streams > 0) {
  1079. OutputStream *os = &c->streams[0];
  1080. // If no segments have been written so far, try to do a crude
  1081. // guess of the segment duration
  1082. if (!c->last_duration)
  1083. c->last_duration = av_rescale_q(os->max_pts - os->start_pts,
  1084. s->streams[0]->time_base,
  1085. AV_TIME_BASE_Q);
  1086. c->total_duration = av_rescale_q(os->max_pts - os->first_pts,
  1087. s->streams[0]->time_base,
  1088. AV_TIME_BASE_Q);
  1089. }
  1090. dash_flush(s, 1, -1);
  1091. if (c->remove_at_exit) {
  1092. char filename[1024];
  1093. int i;
  1094. for (i = 0; i < s->nb_streams; i++) {
  1095. OutputStream *os = &c->streams[i];
  1096. snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile);
  1097. unlink(filename);
  1098. }
  1099. unlink(s->filename);
  1100. }
  1101. dash_free(s);
  1102. return 0;
  1103. }
  1104. #define OFFSET(x) offsetof(DASHContext, x)
  1105. #define E AV_OPT_FLAG_ENCODING_PARAM
  1106. static const AVOption options[] = {
  1107. { "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 },
  1108. { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
  1109. { "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 },
  1110. { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT64, { .i64 = 5000000 }, 0, INT_MAX, E },
  1111. { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, E },
  1112. { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
  1113. { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
  1114. { "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, E },
  1115. { "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 },
  1116. { "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 },
  1117. { "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 },
  1118. { "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, AV_OPT_FLAG_ENCODING_PARAM },
  1119. { NULL },
  1120. };
  1121. static const AVClass dash_class = {
  1122. .class_name = "dash muxer",
  1123. .item_name = av_default_item_name,
  1124. .option = options,
  1125. .version = LIBAVUTIL_VERSION_INT,
  1126. };
  1127. AVOutputFormat ff_dash_muxer = {
  1128. .name = "dash",
  1129. .long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"),
  1130. .priv_data_size = sizeof(DASHContext),
  1131. .audio_codec = AV_CODEC_ID_AAC,
  1132. .video_codec = AV_CODEC_ID_H264,
  1133. .flags = AVFMT_GLOBALHEADER | AVFMT_NOFILE | AVFMT_TS_NEGATIVE,
  1134. .write_header = dash_write_header,
  1135. .write_packet = dash_write_packet,
  1136. .write_trailer = dash_write_trailer,
  1137. .codec_tag = (const AVCodecTag* const []){ ff_mp4_obj_type, 0 },
  1138. .priv_class = &dash_class,
  1139. };