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.

1191 lines
41KB

  1. /*
  2. * Apple HTTP Live Streaming segmenter
  3. * Copyright (c) 2012, Luca Barbato
  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. #include "config.h"
  22. #include <float.h>
  23. #include <stdint.h>
  24. #if HAVE_UNISTD_H
  25. #include <unistd.h>
  26. #endif
  27. #include "libavutil/avassert.h"
  28. #include "libavutil/mathematics.h"
  29. #include "libavutil/parseutils.h"
  30. #include "libavutil/avstring.h"
  31. #include "libavutil/opt.h"
  32. #include "libavutil/log.h"
  33. #include "libavutil/time_internal.h"
  34. #include "avformat.h"
  35. #include "avio_internal.h"
  36. #include "internal.h"
  37. #include "os_support.h"
  38. #define KEYSIZE 16
  39. #define LINE_BUFFER_SIZE 1024
  40. typedef struct HLSSegment {
  41. char filename[1024];
  42. char sub_filename[1024];
  43. double duration; /* in seconds */
  44. int discont;
  45. int64_t pos;
  46. int64_t size;
  47. char key_uri[LINE_BUFFER_SIZE + 1];
  48. char iv_string[KEYSIZE*2 + 1];
  49. struct HLSSegment *next;
  50. } HLSSegment;
  51. typedef enum HLSFlags {
  52. // Generate a single media file and use byte ranges in the playlist.
  53. HLS_SINGLE_FILE = (1 << 0),
  54. HLS_DELETE_SEGMENTS = (1 << 1),
  55. HLS_ROUND_DURATIONS = (1 << 2),
  56. HLS_DISCONT_START = (1 << 3),
  57. HLS_OMIT_ENDLIST = (1 << 4),
  58. HLS_SPLIT_BY_TIME = (1 << 5),
  59. HLS_APPEND_LIST = (1 << 6),
  60. HLS_PROGRAM_DATE_TIME = (1 << 7),
  61. } HLSFlags;
  62. typedef enum {
  63. PLAYLIST_TYPE_NONE,
  64. PLAYLIST_TYPE_EVENT,
  65. PLAYLIST_TYPE_VOD,
  66. PLAYLIST_TYPE_NB,
  67. } PlaylistType;
  68. typedef struct HLSContext {
  69. const AVClass *class; // Class for private options.
  70. unsigned number;
  71. int64_t sequence;
  72. int64_t start_sequence;
  73. AVOutputFormat *oformat;
  74. AVOutputFormat *vtt_oformat;
  75. AVFormatContext *avf;
  76. AVFormatContext *vtt_avf;
  77. float time; // Set by a private option.
  78. float init_time; // Set by a private option.
  79. int max_nb_segments; // Set by a private option.
  80. int wrap; // Set by a private option.
  81. uint32_t flags; // enum HLSFlags
  82. uint32_t pl_type; // enum PlaylistType
  83. char *segment_filename;
  84. int use_localtime; ///< flag to expand filename with localtime
  85. int use_localtime_mkdir;///< flag to mkdir dirname in timebased filename
  86. int allowcache;
  87. int64_t recording_time;
  88. int has_video;
  89. int has_subtitle;
  90. int64_t start_pts;
  91. int64_t end_pts;
  92. double duration; // last segment duration computed so far, in seconds
  93. int64_t start_pos; // last segment starting position
  94. int64_t size; // last segment size
  95. int64_t max_seg_size; // every segment file max size
  96. int nb_entries;
  97. int discontinuity_set;
  98. int discontinuity;
  99. HLSSegment *segments;
  100. HLSSegment *last_segment;
  101. HLSSegment *old_segments;
  102. char *basename;
  103. char *vtt_basename;
  104. char *vtt_m3u8_name;
  105. char *baseurl;
  106. char *format_options_str;
  107. char *vtt_format_options_str;
  108. char *subtitle_filename;
  109. AVDictionary *format_options;
  110. char *key_info_file;
  111. char key_file[LINE_BUFFER_SIZE + 1];
  112. char key_uri[LINE_BUFFER_SIZE + 1];
  113. char key_string[KEYSIZE*2 + 1];
  114. char iv_string[KEYSIZE*2 + 1];
  115. AVDictionary *vtt_format_options;
  116. char *method;
  117. double initial_prog_date_time;
  118. } HLSContext;
  119. static int mkdir_p(const char *path) {
  120. int ret = 0;
  121. char *temp = av_strdup(path);
  122. char *pos = temp;
  123. char tmp_ch = '\0';
  124. if (!path || !temp) {
  125. return -1;
  126. }
  127. if (!strncmp(temp, "/", 1) || !strncmp(temp, "\\", 1)) {
  128. pos++;
  129. } else if (!strncmp(temp, "./", 2) || !strncmp(temp, ".\\", 2)) {
  130. pos += 2;
  131. }
  132. for ( ; *pos != '\0'; ++pos) {
  133. if (*pos == '/' || *pos == '\\') {
  134. tmp_ch = *pos;
  135. *pos = '\0';
  136. ret = mkdir(temp, 0755);
  137. *pos = tmp_ch;
  138. }
  139. }
  140. if ((*(pos - 1) != '/') || (*(pos - 1) != '\\')) {
  141. ret = mkdir(temp, 0755);
  142. }
  143. av_free(temp);
  144. return ret;
  145. }
  146. static int hls_delete_old_segments(HLSContext *hls) {
  147. HLSSegment *segment, *previous_segment = NULL;
  148. float playlist_duration = 0.0f;
  149. int ret = 0, path_size, sub_path_size;
  150. char *dirname = NULL, *p, *sub_path;
  151. char *path = NULL;
  152. segment = hls->segments;
  153. while (segment) {
  154. playlist_duration += segment->duration;
  155. segment = segment->next;
  156. }
  157. segment = hls->old_segments;
  158. while (segment) {
  159. playlist_duration -= segment->duration;
  160. hls->initial_prog_date_time += segment->duration;
  161. previous_segment = segment;
  162. segment = previous_segment->next;
  163. if (playlist_duration <= -previous_segment->duration) {
  164. previous_segment->next = NULL;
  165. break;
  166. }
  167. }
  168. if (segment) {
  169. if (hls->segment_filename) {
  170. dirname = av_strdup(hls->segment_filename);
  171. } else {
  172. dirname = av_strdup(hls->avf->filename);
  173. }
  174. if (!dirname) {
  175. ret = AVERROR(ENOMEM);
  176. goto fail;
  177. }
  178. p = (char *)av_basename(dirname);
  179. *p = '\0';
  180. }
  181. while (segment) {
  182. av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n",
  183. segment->filename);
  184. path_size = strlen(dirname) + strlen(segment->filename) + 1;
  185. path = av_malloc(path_size);
  186. if (!path) {
  187. ret = AVERROR(ENOMEM);
  188. goto fail;
  189. }
  190. av_strlcpy(path, dirname, path_size);
  191. av_strlcat(path, segment->filename, path_size);
  192. if (unlink(path) < 0) {
  193. av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n",
  194. path, strerror(errno));
  195. }
  196. if (segment->sub_filename[0] != '\0') {
  197. sub_path_size = strlen(dirname) + strlen(segment->sub_filename) + 1;
  198. sub_path = av_malloc(sub_path_size);
  199. if (!sub_path) {
  200. ret = AVERROR(ENOMEM);
  201. goto fail;
  202. }
  203. av_strlcpy(sub_path, dirname, sub_path_size);
  204. av_strlcat(sub_path, segment->sub_filename, sub_path_size);
  205. if (unlink(sub_path) < 0) {
  206. av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n",
  207. sub_path, strerror(errno));
  208. }
  209. av_free(sub_path);
  210. }
  211. av_freep(&path);
  212. previous_segment = segment;
  213. segment = previous_segment->next;
  214. av_free(previous_segment);
  215. }
  216. fail:
  217. av_free(path);
  218. av_free(dirname);
  219. return ret;
  220. }
  221. static int hls_encryption_start(AVFormatContext *s)
  222. {
  223. HLSContext *hls = s->priv_data;
  224. int ret;
  225. AVIOContext *pb;
  226. uint8_t key[KEYSIZE];
  227. if ((ret = s->io_open(s, &pb, hls->key_info_file, AVIO_FLAG_READ, NULL)) < 0) {
  228. av_log(hls, AV_LOG_ERROR,
  229. "error opening key info file %s\n", hls->key_info_file);
  230. return ret;
  231. }
  232. ff_get_line(pb, hls->key_uri, sizeof(hls->key_uri));
  233. hls->key_uri[strcspn(hls->key_uri, "\r\n")] = '\0';
  234. ff_get_line(pb, hls->key_file, sizeof(hls->key_file));
  235. hls->key_file[strcspn(hls->key_file, "\r\n")] = '\0';
  236. ff_get_line(pb, hls->iv_string, sizeof(hls->iv_string));
  237. hls->iv_string[strcspn(hls->iv_string, "\r\n")] = '\0';
  238. ff_format_io_close(s, &pb);
  239. if (!*hls->key_uri) {
  240. av_log(hls, AV_LOG_ERROR, "no key URI specified in key info file\n");
  241. return AVERROR(EINVAL);
  242. }
  243. if (!*hls->key_file) {
  244. av_log(hls, AV_LOG_ERROR, "no key file specified in key info file\n");
  245. return AVERROR(EINVAL);
  246. }
  247. if ((ret = s->io_open(s, &pb, hls->key_file, AVIO_FLAG_READ, NULL)) < 0) {
  248. av_log(hls, AV_LOG_ERROR, "error opening key file %s\n", hls->key_file);
  249. return ret;
  250. }
  251. ret = avio_read(pb, key, sizeof(key));
  252. ff_format_io_close(s, &pb);
  253. if (ret != sizeof(key)) {
  254. av_log(hls, AV_LOG_ERROR, "error reading key file %s\n", hls->key_file);
  255. if (ret >= 0 || ret == AVERROR_EOF)
  256. ret = AVERROR(EINVAL);
  257. return ret;
  258. }
  259. ff_data_to_hex(hls->key_string, key, sizeof(key), 0);
  260. return 0;
  261. }
  262. static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
  263. {
  264. int len = ff_get_line(s, buf, maxlen);
  265. while (len > 0 && av_isspace(buf[len - 1]))
  266. buf[--len] = '\0';
  267. return len;
  268. }
  269. static int hls_mux_init(AVFormatContext *s)
  270. {
  271. HLSContext *hls = s->priv_data;
  272. AVFormatContext *oc;
  273. AVFormatContext *vtt_oc = NULL;
  274. int i, ret;
  275. ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL);
  276. if (ret < 0)
  277. return ret;
  278. oc = hls->avf;
  279. oc->oformat = hls->oformat;
  280. oc->interrupt_callback = s->interrupt_callback;
  281. oc->max_delay = s->max_delay;
  282. oc->opaque = s->opaque;
  283. oc->io_open = s->io_open;
  284. oc->io_close = s->io_close;
  285. av_dict_copy(&oc->metadata, s->metadata, 0);
  286. if(hls->vtt_oformat) {
  287. ret = avformat_alloc_output_context2(&hls->vtt_avf, hls->vtt_oformat, NULL, NULL);
  288. if (ret < 0)
  289. return ret;
  290. vtt_oc = hls->vtt_avf;
  291. vtt_oc->oformat = hls->vtt_oformat;
  292. av_dict_copy(&vtt_oc->metadata, s->metadata, 0);
  293. }
  294. for (i = 0; i < s->nb_streams; i++) {
  295. AVStream *st;
  296. AVFormatContext *loc;
  297. if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
  298. loc = vtt_oc;
  299. else
  300. loc = oc;
  301. if (!(st = avformat_new_stream(loc, NULL)))
  302. return AVERROR(ENOMEM);
  303. avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar);
  304. st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
  305. st->time_base = s->streams[i]->time_base;
  306. }
  307. hls->start_pos = 0;
  308. return 0;
  309. }
  310. /* Create a new segment and append it to the segment list */
  311. static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double duration,
  312. int64_t pos, int64_t size)
  313. {
  314. HLSSegment *en = av_malloc(sizeof(*en));
  315. const char *filename;
  316. int ret;
  317. if (!en)
  318. return AVERROR(ENOMEM);
  319. filename = av_basename(hls->avf->filename);
  320. if (hls->use_localtime_mkdir) {
  321. filename = hls->avf->filename;
  322. }
  323. av_strlcpy(en->filename, filename, sizeof(en->filename));
  324. if(hls->has_subtitle)
  325. av_strlcpy(en->sub_filename, av_basename(hls->vtt_avf->filename), sizeof(en->sub_filename));
  326. else
  327. en->sub_filename[0] = '\0';
  328. en->duration = duration;
  329. en->pos = pos;
  330. en->size = size;
  331. en->next = NULL;
  332. en->discont = 0;
  333. if (hls->discontinuity) {
  334. en->discont = 1;
  335. hls->discontinuity = 0;
  336. }
  337. if (hls->key_info_file) {
  338. av_strlcpy(en->key_uri, hls->key_uri, sizeof(en->key_uri));
  339. av_strlcpy(en->iv_string, hls->iv_string, sizeof(en->iv_string));
  340. }
  341. if (!hls->segments)
  342. hls->segments = en;
  343. else
  344. hls->last_segment->next = en;
  345. hls->last_segment = en;
  346. // EVENT or VOD playlists imply sliding window cannot be used
  347. if (hls->pl_type != PLAYLIST_TYPE_NONE)
  348. hls->max_nb_segments = 0;
  349. if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) {
  350. en = hls->segments;
  351. hls->segments = en->next;
  352. if (en && hls->flags & HLS_DELETE_SEGMENTS &&
  353. !(hls->flags & HLS_SINGLE_FILE || hls->wrap)) {
  354. en->next = hls->old_segments;
  355. hls->old_segments = en;
  356. if ((ret = hls_delete_old_segments(hls)) < 0)
  357. return ret;
  358. } else
  359. av_free(en);
  360. } else
  361. hls->nb_entries++;
  362. if (hls->max_seg_size > 0) {
  363. return 0;
  364. }
  365. hls->sequence++;
  366. return 0;
  367. }
  368. static int parse_playlist(AVFormatContext *s, const char *url)
  369. {
  370. HLSContext *hls = s->priv_data;
  371. AVIOContext *in;
  372. int ret = 0, is_segment = 0;
  373. int64_t new_start_pos;
  374. char line[1024];
  375. const char *ptr;
  376. if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ,
  377. &s->interrupt_callback, NULL,
  378. s->protocol_whitelist, s->protocol_blacklist)) < 0)
  379. return ret;
  380. read_chomp_line(in, line, sizeof(line));
  381. if (strcmp(line, "#EXTM3U")) {
  382. ret = AVERROR_INVALIDDATA;
  383. goto fail;
  384. }
  385. hls->discontinuity = 0;
  386. while (!avio_feof(in)) {
  387. read_chomp_line(in, line, sizeof(line));
  388. if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
  389. hls->sequence = atoi(ptr);
  390. } else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) {
  391. is_segment = 1;
  392. hls->discontinuity = 1;
  393. } else if (av_strstart(line, "#EXTINF:", &ptr)) {
  394. is_segment = 1;
  395. hls->duration = atof(ptr);
  396. } else if (av_strstart(line, "#", NULL)) {
  397. continue;
  398. } else if (line[0]) {
  399. if (is_segment) {
  400. is_segment = 0;
  401. new_start_pos = avio_tell(hls->avf->pb);
  402. hls->size = new_start_pos - hls->start_pos;
  403. av_strlcpy(hls->avf->filename, line, sizeof(line));
  404. ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size);
  405. if (ret < 0)
  406. goto fail;
  407. hls->start_pos = new_start_pos;
  408. }
  409. }
  410. }
  411. fail:
  412. avio_close(in);
  413. return ret;
  414. }
  415. static void hls_free_segments(HLSSegment *p)
  416. {
  417. HLSSegment *en;
  418. while(p) {
  419. en = p;
  420. p = p->next;
  421. av_free(en);
  422. }
  423. }
  424. static void set_http_options(AVDictionary **options, HLSContext *c)
  425. {
  426. if (c->method)
  427. av_dict_set(options, "method", c->method, 0);
  428. }
  429. static int hls_window(AVFormatContext *s, int last)
  430. {
  431. HLSContext *hls = s->priv_data;
  432. HLSSegment *en;
  433. int target_duration = 0;
  434. int ret = 0;
  435. AVIOContext *out = NULL;
  436. AVIOContext *sub_out = NULL;
  437. char temp_filename[1024];
  438. int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries);
  439. int version = 3;
  440. const char *proto = avio_find_protocol_name(s->filename);
  441. int use_rename = proto && !strcmp(proto, "file");
  442. static unsigned warned_non_file;
  443. char *key_uri = NULL;
  444. char *iv_string = NULL;
  445. AVDictionary *options = NULL;
  446. double prog_date_time = hls->initial_prog_date_time;
  447. int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
  448. if (byterange_mode) {
  449. version = 4;
  450. sequence = 0;
  451. }
  452. if (!use_rename && !warned_non_file++)
  453. av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n");
  454. set_http_options(&options, hls);
  455. snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename);
  456. if ((ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, &options)) < 0)
  457. goto fail;
  458. for (en = hls->segments; en; en = en->next) {
  459. if (target_duration < en->duration)
  460. target_duration = ceil(en->duration);
  461. }
  462. hls->discontinuity_set = 0;
  463. avio_printf(out, "#EXTM3U\n");
  464. avio_printf(out, "#EXT-X-VERSION:%d\n", version);
  465. if (hls->allowcache == 0 || hls->allowcache == 1) {
  466. avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
  467. }
  468. avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration);
  469. avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);
  470. if (hls->pl_type == PLAYLIST_TYPE_EVENT) {
  471. avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n");
  472. } else if (hls->pl_type == PLAYLIST_TYPE_VOD) {
  473. avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n");
  474. }
  475. av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n",
  476. sequence);
  477. if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && hls->discontinuity_set==0 ){
  478. avio_printf(out, "#EXT-X-DISCONTINUITY\n");
  479. hls->discontinuity_set = 1;
  480. }
  481. for (en = hls->segments; en; en = en->next) {
  482. if (hls->key_info_file && (!key_uri || strcmp(en->key_uri, key_uri) ||
  483. av_strcasecmp(en->iv_string, iv_string))) {
  484. avio_printf(out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri);
  485. if (*en->iv_string)
  486. avio_printf(out, ",IV=0x%s", en->iv_string);
  487. avio_printf(out, "\n");
  488. key_uri = en->key_uri;
  489. iv_string = en->iv_string;
  490. }
  491. if (en->discont) {
  492. avio_printf(out, "#EXT-X-DISCONTINUITY\n");
  493. }
  494. if (hls->flags & HLS_ROUND_DURATIONS)
  495. avio_printf(out, "#EXTINF:%ld,\n", lrint(en->duration));
  496. else
  497. avio_printf(out, "#EXTINF:%f,\n", en->duration);
  498. if (byterange_mode)
  499. avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
  500. en->size, en->pos);
  501. if (hls->flags & HLS_PROGRAM_DATE_TIME) {
  502. time_t tt, wrongsecs;
  503. int milli;
  504. struct tm *tm, tmpbuf;
  505. char buf0[128], buf1[128];
  506. tt = (int64_t)prog_date_time;
  507. milli = av_clip(lrint(1000*(prog_date_time - tt)), 0, 999);
  508. tm = localtime_r(&tt, &tmpbuf);
  509. strftime(buf0, sizeof(buf0), "%Y-%m-%dT%H:%M:%S", tm);
  510. if (!strftime(buf1, sizeof(buf1), "%z", tm) || buf1[1]<'0' ||buf1[1]>'2') {
  511. int tz_min, dst = tm->tm_isdst;
  512. tm = gmtime_r(&tt, &tmpbuf);
  513. tm->tm_isdst = dst;
  514. wrongsecs = mktime(tm);
  515. tz_min = (abs(wrongsecs - tt) + 30) / 60;
  516. snprintf(buf1, sizeof(buf1),
  517. "%c%02d%02d",
  518. wrongsecs <= tt ? '+' : '-',
  519. tz_min / 60,
  520. tz_min % 60);
  521. }
  522. avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1);
  523. prog_date_time += en->duration;
  524. }
  525. if (hls->baseurl)
  526. avio_printf(out, "%s", hls->baseurl);
  527. avio_printf(out, "%s\n", en->filename);
  528. }
  529. if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
  530. avio_printf(out, "#EXT-X-ENDLIST\n");
  531. if( hls->vtt_m3u8_name ) {
  532. if ((ret = s->io_open(s, &sub_out, hls->vtt_m3u8_name, AVIO_FLAG_WRITE, &options)) < 0)
  533. goto fail;
  534. avio_printf(sub_out, "#EXTM3U\n");
  535. avio_printf(sub_out, "#EXT-X-VERSION:%d\n", version);
  536. if (hls->allowcache == 0 || hls->allowcache == 1) {
  537. avio_printf(sub_out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
  538. }
  539. avio_printf(sub_out, "#EXT-X-TARGETDURATION:%d\n", target_duration);
  540. avio_printf(sub_out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);
  541. av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n",
  542. sequence);
  543. for (en = hls->segments; en; en = en->next) {
  544. avio_printf(sub_out, "#EXTINF:%f,\n", en->duration);
  545. if (byterange_mode)
  546. avio_printf(sub_out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
  547. en->size, en->pos);
  548. if (hls->baseurl)
  549. avio_printf(sub_out, "%s", hls->baseurl);
  550. avio_printf(sub_out, "%s\n", en->sub_filename);
  551. }
  552. if (last)
  553. avio_printf(sub_out, "#EXT-X-ENDLIST\n");
  554. }
  555. fail:
  556. av_dict_free(&options);
  557. ff_format_io_close(s, &out);
  558. ff_format_io_close(s, &sub_out);
  559. if (ret >= 0 && use_rename)
  560. ff_rename(temp_filename, s->filename, s);
  561. return ret;
  562. }
  563. static HLSSegment *find_segment_by_filename(HLSSegment *segment, const char *filename)
  564. {
  565. /* filename may contain rel/abs path, but segments store only basename */
  566. char *p = NULL, *dirname = NULL, *path = NULL;
  567. int path_size;
  568. HLSSegment *ret_segment = NULL;
  569. dirname = av_strdup(filename);
  570. if (!dirname)
  571. return NULL;
  572. p = (char *)av_basename(dirname); // av_dirname would return . in case of no dir
  573. *p = '\0'; // maybe empty
  574. while (segment) {
  575. path_size = strlen(dirname) + strlen(segment->filename) + 1;
  576. path = av_malloc(path_size);
  577. if (!path)
  578. goto end;
  579. av_strlcpy(path, dirname, path_size);
  580. av_strlcat(path, segment->filename, path_size);
  581. if (!strcmp(path,filename)) {
  582. ret_segment = segment;
  583. av_free(path);
  584. goto end;
  585. }
  586. av_free(path);
  587. segment = segment->next;
  588. }
  589. end:
  590. av_free(dirname);
  591. return ret_segment;
  592. }
  593. static int hls_start(AVFormatContext *s)
  594. {
  595. HLSContext *c = s->priv_data;
  596. AVFormatContext *oc = c->avf;
  597. AVFormatContext *vtt_oc = c->vtt_avf;
  598. AVDictionary *options = NULL;
  599. char *filename, iv_string[KEYSIZE*2 + 1];
  600. int err = 0;
  601. if (c->flags & HLS_SINGLE_FILE) {
  602. av_strlcpy(oc->filename, c->basename,
  603. sizeof(oc->filename));
  604. if (c->vtt_basename)
  605. av_strlcpy(vtt_oc->filename, c->vtt_basename,
  606. sizeof(vtt_oc->filename));
  607. } else if (c->max_seg_size > 0) {
  608. if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
  609. c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
  610. AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
  611. av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename);
  612. return AVERROR(EINVAL);
  613. }
  614. } else {
  615. if (c->use_localtime) {
  616. time_t now0;
  617. struct tm *tm, tmpbuf;
  618. time(&now0);
  619. tm = localtime_r(&now0, &tmpbuf);
  620. if (!strftime(oc->filename, sizeof(oc->filename), c->basename, tm)) {
  621. av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n");
  622. return AVERROR(EINVAL);
  623. }
  624. if (find_segment_by_filename(c->segments, oc->filename)
  625. || find_segment_by_filename(c->old_segments, oc->filename)) {
  626. av_log(c, AV_LOG_WARNING, "Duplicated segment filename detected: %s\n", oc->filename);
  627. }
  628. if (c->use_localtime_mkdir) {
  629. const char *dir;
  630. char *fn_copy = av_strdup(oc->filename);
  631. if (!fn_copy) {
  632. return AVERROR(ENOMEM);
  633. }
  634. dir = av_dirname(fn_copy);
  635. if (mkdir_p(dir) == -1 && errno != EEXIST) {
  636. av_log(oc, AV_LOG_ERROR, "Could not create directory %s with use_localtime_mkdir\n", dir);
  637. av_free(fn_copy);
  638. return AVERROR(errno);
  639. }
  640. av_free(fn_copy);
  641. }
  642. } else if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
  643. c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
  644. AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
  645. av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", c->basename);
  646. return AVERROR(EINVAL);
  647. }
  648. if( c->vtt_basename) {
  649. if (av_get_frame_filename2(vtt_oc->filename, sizeof(vtt_oc->filename),
  650. c->vtt_basename, c->wrap ? c->sequence % c->wrap : c->sequence,
  651. AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
  652. av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename);
  653. return AVERROR(EINVAL);
  654. }
  655. }
  656. }
  657. c->number++;
  658. set_http_options(&options, c);
  659. if (c->key_info_file) {
  660. if ((err = hls_encryption_start(s)) < 0)
  661. goto fail;
  662. if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0))
  663. < 0)
  664. goto fail;
  665. err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string));
  666. if (!err)
  667. snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, c->sequence);
  668. if ((err = av_dict_set(&options, "encryption_iv", iv_string, 0)) < 0)
  669. goto fail;
  670. filename = av_asprintf("crypto:%s", oc->filename);
  671. if (!filename) {
  672. err = AVERROR(ENOMEM);
  673. goto fail;
  674. }
  675. err = s->io_open(s, &oc->pb, filename, AVIO_FLAG_WRITE, &options);
  676. av_free(filename);
  677. av_dict_free(&options);
  678. if (err < 0)
  679. return err;
  680. } else
  681. if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, &options)) < 0)
  682. goto fail;
  683. if (c->vtt_basename) {
  684. set_http_options(&options, c);
  685. if ((err = s->io_open(s, &vtt_oc->pb, vtt_oc->filename, AVIO_FLAG_WRITE, &options)) < 0)
  686. goto fail;
  687. }
  688. av_dict_free(&options);
  689. /* We only require one PAT/PMT per segment. */
  690. if (oc->oformat->priv_class && oc->priv_data) {
  691. char period[21];
  692. snprintf(period, sizeof(period), "%d", (INT_MAX / 2) - 1);
  693. av_opt_set(oc->priv_data, "mpegts_flags", "resend_headers", 0);
  694. av_opt_set(oc->priv_data, "sdt_period", period, 0);
  695. av_opt_set(oc->priv_data, "pat_period", period, 0);
  696. }
  697. if (c->vtt_basename) {
  698. err = avformat_write_header(vtt_oc,NULL);
  699. if (err < 0)
  700. return err;
  701. }
  702. return 0;
  703. fail:
  704. av_dict_free(&options);
  705. return err;
  706. }
  707. static int hls_write_header(AVFormatContext *s)
  708. {
  709. HLSContext *hls = s->priv_data;
  710. int ret, i;
  711. char *p;
  712. const char *pattern = "%d.ts";
  713. const char *pattern_localtime_fmt = "-%s.ts";
  714. const char *vtt_pattern = "%d.vtt";
  715. AVDictionary *options = NULL;
  716. int basename_size;
  717. int vtt_basename_size;
  718. hls->sequence = hls->start_sequence;
  719. hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE;
  720. hls->start_pts = AV_NOPTS_VALUE;
  721. if (hls->flags & HLS_PROGRAM_DATE_TIME) {
  722. time_t now0;
  723. time(&now0);
  724. hls->initial_prog_date_time = now0;
  725. }
  726. if (hls->format_options_str) {
  727. ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
  728. if (ret < 0) {
  729. av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str);
  730. goto fail;
  731. }
  732. }
  733. for (i = 0; i < s->nb_streams; i++) {
  734. hls->has_video +=
  735. s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
  736. hls->has_subtitle +=
  737. s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE;
  738. }
  739. if (hls->has_video > 1)
  740. av_log(s, AV_LOG_WARNING,
  741. "More than a single video stream present, "
  742. "expect issues decoding it.\n");
  743. hls->oformat = av_guess_format("mpegts", NULL, NULL);
  744. if (!hls->oformat) {
  745. ret = AVERROR_MUXER_NOT_FOUND;
  746. goto fail;
  747. }
  748. if(hls->has_subtitle) {
  749. hls->vtt_oformat = av_guess_format("webvtt", NULL, NULL);
  750. if (!hls->oformat) {
  751. ret = AVERROR_MUXER_NOT_FOUND;
  752. goto fail;
  753. }
  754. }
  755. if (hls->segment_filename) {
  756. hls->basename = av_strdup(hls->segment_filename);
  757. if (!hls->basename) {
  758. ret = AVERROR(ENOMEM);
  759. goto fail;
  760. }
  761. } else {
  762. if (hls->flags & HLS_SINGLE_FILE)
  763. pattern = ".ts";
  764. if (hls->use_localtime) {
  765. basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1;
  766. } else {
  767. basename_size = strlen(s->filename) + strlen(pattern) + 1;
  768. }
  769. hls->basename = av_malloc(basename_size);
  770. if (!hls->basename) {
  771. ret = AVERROR(ENOMEM);
  772. goto fail;
  773. }
  774. av_strlcpy(hls->basename, s->filename, basename_size);
  775. p = strrchr(hls->basename, '.');
  776. if (p)
  777. *p = '\0';
  778. if (hls->use_localtime) {
  779. av_strlcat(hls->basename, pattern_localtime_fmt, basename_size);
  780. } else {
  781. av_strlcat(hls->basename, pattern, basename_size);
  782. }
  783. }
  784. if(hls->has_subtitle) {
  785. if (hls->flags & HLS_SINGLE_FILE)
  786. vtt_pattern = ".vtt";
  787. vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) + 1;
  788. hls->vtt_basename = av_malloc(vtt_basename_size);
  789. if (!hls->vtt_basename) {
  790. ret = AVERROR(ENOMEM);
  791. goto fail;
  792. }
  793. hls->vtt_m3u8_name = av_malloc(vtt_basename_size);
  794. if (!hls->vtt_m3u8_name ) {
  795. ret = AVERROR(ENOMEM);
  796. goto fail;
  797. }
  798. av_strlcpy(hls->vtt_basename, s->filename, vtt_basename_size);
  799. p = strrchr(hls->vtt_basename, '.');
  800. if (p)
  801. *p = '\0';
  802. if( hls->subtitle_filename ) {
  803. strcpy(hls->vtt_m3u8_name, hls->subtitle_filename);
  804. } else {
  805. strcpy(hls->vtt_m3u8_name, hls->vtt_basename);
  806. av_strlcat(hls->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size);
  807. }
  808. av_strlcat(hls->vtt_basename, vtt_pattern, vtt_basename_size);
  809. }
  810. if ((ret = hls_mux_init(s)) < 0)
  811. goto fail;
  812. if (hls->flags & HLS_APPEND_LIST) {
  813. parse_playlist(s, s->filename);
  814. hls->discontinuity = 1;
  815. if (hls->init_time > 0) {
  816. av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time,"
  817. " hls_init_time value will have no effect\n");
  818. hls->init_time = 0;
  819. hls->recording_time = hls->time * AV_TIME_BASE;
  820. }
  821. }
  822. if ((ret = hls_start(s)) < 0)
  823. goto fail;
  824. av_dict_copy(&options, hls->format_options, 0);
  825. ret = avformat_write_header(hls->avf, &options);
  826. if (av_dict_count(options)) {
  827. av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s' are not recognized\n", hls->format_options_str);
  828. ret = AVERROR(EINVAL);
  829. goto fail;
  830. }
  831. //av_assert0(s->nb_streams == hls->avf->nb_streams);
  832. for (i = 0; i < s->nb_streams; i++) {
  833. AVStream *inner_st;
  834. AVStream *outer_st = s->streams[i];
  835. if (hls->max_seg_size > 0) {
  836. if ((outer_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
  837. (outer_st->codecpar->bit_rate > hls->max_seg_size)) {
  838. av_log(s, AV_LOG_WARNING, "Your video bitrate is bigger than hls_segment_size, "
  839. "(%"PRId64 " > %"PRId64 "), the result maybe not be what you want.",
  840. outer_st->codecpar->bit_rate, hls->max_seg_size);
  841. }
  842. }
  843. if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
  844. inner_st = hls->avf->streams[i];
  845. else if (hls->vtt_avf)
  846. inner_st = hls->vtt_avf->streams[0];
  847. else {
  848. /* We have a subtitle stream, when the user does not want one */
  849. inner_st = NULL;
  850. continue;
  851. }
  852. avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den);
  853. }
  854. fail:
  855. av_dict_free(&options);
  856. if (ret < 0) {
  857. av_freep(&hls->basename);
  858. av_freep(&hls->vtt_basename);
  859. if (hls->avf)
  860. avformat_free_context(hls->avf);
  861. if (hls->vtt_avf)
  862. avformat_free_context(hls->vtt_avf);
  863. }
  864. return ret;
  865. }
  866. static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
  867. {
  868. HLSContext *hls = s->priv_data;
  869. AVFormatContext *oc = NULL;
  870. AVStream *st = s->streams[pkt->stream_index];
  871. int64_t end_pts = hls->recording_time * hls->number;
  872. int is_ref_pkt = 1;
  873. int ret, can_split = 1;
  874. int stream_index = 0;
  875. if (hls->sequence - hls->nb_entries > hls->start_sequence && hls->init_time > 0) {
  876. /* reset end_pts, hls->recording_time at end of the init hls list */
  877. int init_list_dur = hls->init_time * hls->nb_entries * AV_TIME_BASE;
  878. int after_init_list_dur = (hls->sequence - hls->nb_entries ) * hls->time * AV_TIME_BASE;
  879. hls->recording_time = hls->time * AV_TIME_BASE;
  880. end_pts = init_list_dur + after_init_list_dur ;
  881. }
  882. if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) {
  883. oc = hls->vtt_avf;
  884. stream_index = 0;
  885. } else {
  886. oc = hls->avf;
  887. stream_index = pkt->stream_index;
  888. }
  889. if (hls->start_pts == AV_NOPTS_VALUE) {
  890. hls->start_pts = pkt->pts;
  891. hls->end_pts = pkt->pts;
  892. }
  893. if (hls->has_video) {
  894. can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
  895. ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME));
  896. is_ref_pkt = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
  897. }
  898. if (pkt->pts == AV_NOPTS_VALUE)
  899. is_ref_pkt = can_split = 0;
  900. if (is_ref_pkt)
  901. hls->duration = (double)(pkt->pts - hls->end_pts)
  902. * st->time_base.num / st->time_base.den;
  903. if (can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base,
  904. end_pts, AV_TIME_BASE_Q) >= 0) {
  905. int64_t new_start_pos;
  906. av_write_frame(oc, NULL); /* Flush any buffered data */
  907. new_start_pos = avio_tell(hls->avf->pb);
  908. hls->size = new_start_pos - hls->start_pos;
  909. ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size);
  910. hls->start_pos = new_start_pos;
  911. if (ret < 0)
  912. return ret;
  913. hls->end_pts = pkt->pts;
  914. hls->duration = 0;
  915. if (hls->flags & HLS_SINGLE_FILE) {
  916. if (hls->avf->oformat->priv_class && hls->avf->priv_data)
  917. av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0);
  918. hls->number++;
  919. } else if (hls->max_seg_size > 0) {
  920. if (hls->avf->oformat->priv_class && hls->avf->priv_data)
  921. av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0);
  922. if (hls->start_pos >= hls->max_seg_size) {
  923. hls->sequence++;
  924. ff_format_io_close(s, &oc->pb);
  925. if (hls->vtt_avf)
  926. ff_format_io_close(s, &hls->vtt_avf->pb);
  927. ret = hls_start(s);
  928. hls->start_pos = 0;
  929. /* When split segment by byte, the duration is short than hls_time,
  930. * so it is not enough one segment duration as hls_time, */
  931. hls->number--;
  932. }
  933. hls->number++;
  934. } else {
  935. ff_format_io_close(s, &oc->pb);
  936. if (hls->vtt_avf)
  937. ff_format_io_close(s, &hls->vtt_avf->pb);
  938. ret = hls_start(s);
  939. }
  940. if (ret < 0)
  941. return ret;
  942. if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE )
  943. oc = hls->vtt_avf;
  944. else
  945. oc = hls->avf;
  946. if ((ret = hls_window(s, 0)) < 0)
  947. return ret;
  948. }
  949. ret = ff_write_chained(oc, stream_index, pkt, s, 0);
  950. return ret;
  951. }
  952. static int hls_write_trailer(struct AVFormatContext *s)
  953. {
  954. HLSContext *hls = s->priv_data;
  955. AVFormatContext *oc = hls->avf;
  956. AVFormatContext *vtt_oc = hls->vtt_avf;
  957. av_write_trailer(oc);
  958. if (oc->pb) {
  959. hls->size = avio_tell(hls->avf->pb) - hls->start_pos;
  960. ff_format_io_close(s, &oc->pb);
  961. hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size);
  962. }
  963. if (vtt_oc) {
  964. if (vtt_oc->pb)
  965. av_write_trailer(vtt_oc);
  966. hls->size = avio_tell(hls->vtt_avf->pb) - hls->start_pos;
  967. ff_format_io_close(s, &vtt_oc->pb);
  968. }
  969. av_freep(&hls->basename);
  970. avformat_free_context(oc);
  971. hls->avf = NULL;
  972. hls_window(s, 1);
  973. if (vtt_oc) {
  974. av_freep(&hls->vtt_basename);
  975. av_freep(&hls->vtt_m3u8_name);
  976. avformat_free_context(vtt_oc);
  977. }
  978. hls_free_segments(hls->segments);
  979. hls_free_segments(hls->old_segments);
  980. return 0;
  981. }
  982. #define OFFSET(x) offsetof(HLSContext, x)
  983. #define E AV_OPT_FLAG_ENCODING_PARAM
  984. static const AVOption options[] = {
  985. {"start_number", "set first number in the sequence", OFFSET(start_sequence),AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E},
  986. {"hls_time", "set segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E},
  987. {"hls_init_time", "set segment length in seconds at init list", OFFSET(init_time), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, FLT_MAX, E},
  988. {"hls_list_size", "set maximum number of playlist entries", OFFSET(max_nb_segments), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E},
  989. {"hls_ts_options","set hls mpegts list of options for the container format used for hls", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
  990. {"hls_vtt_options","set hls vtt list of options for the container format used for hls", OFFSET(vtt_format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
  991. {"hls_wrap", "set number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E},
  992. {"hls_allow_cache", "explicitly set whether the client MAY (1) or MUST NOT (0) cache media segments", OFFSET(allowcache), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, E},
  993. {"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
  994. {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
  995. {"hls_segment_size", "maximum size per segment file, (in bytes)", OFFSET(max_seg_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E},
  996. {"hls_key_info_file", "file with key URI and key file path", OFFSET(key_info_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
  997. {"hls_subtitle_path", "set path of hls subtitles", OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
  998. {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"},
  999. {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"},
  1000. {"delete_segments", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0, UINT_MAX, E, "flags"},
  1001. {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX, E, "flags"},
  1002. {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX, E, "flags"},
  1003. {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX, E, "flags"},
  1004. {"split_by_time", "split the hls segment by time which user set by hls_time", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SPLIT_BY_TIME }, 0, UINT_MAX, E, "flags"},
  1005. {"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_APPEND_LIST }, 0, UINT_MAX, E, "flags"},
  1006. {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"},
  1007. {"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
  1008. {"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
  1009. {"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, "pl_type" },
  1010. {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" },
  1011. {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" },
  1012. {"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
  1013. { NULL },
  1014. };
  1015. static const AVClass hls_class = {
  1016. .class_name = "hls muxer",
  1017. .item_name = av_default_item_name,
  1018. .option = options,
  1019. .version = LIBAVUTIL_VERSION_INT,
  1020. };
  1021. AVOutputFormat ff_hls_muxer = {
  1022. .name = "hls",
  1023. .long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
  1024. .extensions = "m3u8",
  1025. .priv_data_size = sizeof(HLSContext),
  1026. .audio_codec = AV_CODEC_ID_AAC,
  1027. .video_codec = AV_CODEC_ID_H264,
  1028. .subtitle_codec = AV_CODEC_ID_WEBVTT,
  1029. .flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH,
  1030. .write_header = hls_write_header,
  1031. .write_packet = hls_write_packet,
  1032. .write_trailer = hls_write_trailer,
  1033. .priv_class = &hls_class,
  1034. };