hlsenc.c 39.2 KB
Newer Older
L
Luca Barbato 已提交
1 2 3 4
/*
 * Apple HTTP Live Streaming segmenter
 * Copyright (c) 2012, Luca Barbato
 *
5
 * This file is part of FFmpeg.
L
Luca Barbato 已提交
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
L
Luca Barbato 已提交
8 9 10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
L
Luca Barbato 已提交
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
L
Luca Barbato 已提交
19 20 21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

22
#include "config.h"
L
Luca Barbato 已提交
23
#include <float.h>
24
#include <stdint.h>
25 26 27
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
L
Luca Barbato 已提交
28

29
#include "libavutil/avassert.h"
L
Luca Barbato 已提交
30 31 32 33 34
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#include "libavutil/log.h"
35
#include "libavutil/time_internal.h"
L
Luca Barbato 已提交
36 37

#include "avformat.h"
38
#include "avio_internal.h"
L
Luca Barbato 已提交
39
#include "internal.h"
40
#include "os_support.h"
L
Luca Barbato 已提交
41

42 43 44
#define KEYSIZE 16
#define LINE_BUFFER_SIZE 1024

45 46
typedef struct HLSSegment {
    char filename[1024];
47
    char sub_filename[1024];
48
    double duration; /* in seconds */
49 50
    int64_t pos;
    int64_t size;
51

52 53 54
    char key_uri[LINE_BUFFER_SIZE + 1];
    char iv_string[KEYSIZE*2 + 1];

55 56
    struct HLSSegment *next;
} HLSSegment;
L
Luca Barbato 已提交
57

58 59 60
typedef enum HLSFlags {
    // Generate a single media file and use byte ranges in the playlist.
    HLS_SINGLE_FILE = (1 << 0),
61
    HLS_DELETE_SEGMENTS = (1 << 1),
62
    HLS_ROUND_DURATIONS = (1 << 2),
63
    HLS_DISCONT_START = (1 << 3),
64
    HLS_OMIT_ENDLIST = (1 << 4),
65
    HLS_SPLIT_BY_TIME = (1 << 5),
66
    HLS_APPEND_LIST = (1 << 6),
67
    HLS_PROGRAM_DATE_TIME = (1 << 7),
68 69
} HLSFlags;

70 71 72 73 74 75 76
typedef enum {
    PLAYLIST_TYPE_NONE,
    PLAYLIST_TYPE_EVENT,
    PLAYLIST_TYPE_VOD,
    PLAYLIST_TYPE_NB,
} PlaylistType;

L
Luca Barbato 已提交
77 78
typedef struct HLSContext {
    const AVClass *class;  // Class for private options.
79
    unsigned number;
80
    int64_t sequence;
81
    int64_t start_sequence;
L
Luca Barbato 已提交
82
    AVOutputFormat *oformat;
83
    AVOutputFormat *vtt_oformat;
84

L
Luca Barbato 已提交
85
    AVFormatContext *avf;
86
    AVFormatContext *vtt_avf;
87

L
Luca Barbato 已提交
88
    float time;            // Set by a private option.
89
    float init_time;       // Set by a private option.
90
    int max_nb_segments;   // Set by a private option.
L
Luca Barbato 已提交
91
    int  wrap;             // Set by a private option.
92
    uint32_t flags;        // enum HLSFlags
93
    uint32_t pl_type;      // enum PlaylistType
94
    char *segment_filename;
95

96
    int use_localtime;      ///< flag to expand filename with localtime
97
    int use_localtime_mkdir;///< flag to mkdir dirname in timebased filename
98
    int allowcache;
L
Luca Barbato 已提交
99 100
    int64_t recording_time;
    int has_video;
101
    int has_subtitle;
L
Luca Barbato 已提交
102 103
    int64_t start_pts;
    int64_t end_pts;
104
    double duration;      // last segment duration computed so far, in seconds
105 106
    int64_t start_pos;    // last segment starting position
    int64_t size;         // last segment size
107
    int64_t max_seg_size; // every segment file max size
108
    int nb_entries;
109
    int discontinuity_set;
110

111 112
    HLSSegment *segments;
    HLSSegment *last_segment;
113
    HLSSegment *old_segments;
114

L
Luca Barbato 已提交
115
    char *basename;
116 117
    char *vtt_basename;
    char *vtt_m3u8_name;
118
    char *baseurl;
liuqi_123's avatar
liuqi_123 已提交
119
    char *format_options_str;
120 121
    char *vtt_format_options_str;
    char *subtitle_filename;
liuqi_123's avatar
liuqi_123 已提交
122
    AVDictionary *format_options;
123 124 125 126 127 128

    char *key_info_file;
    char key_file[LINE_BUFFER_SIZE + 1];
    char key_uri[LINE_BUFFER_SIZE + 1];
    char key_string[KEYSIZE*2 + 1];
    char iv_string[KEYSIZE*2 + 1];
129 130
    AVDictionary *vtt_format_options;

131 132
    char *method;

133
    double initial_prog_date_time;
L
Luca Barbato 已提交
134 135
} HLSContext;

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
static int mkdir_p(const char *path) {
    int ret = 0;
    char *temp = av_strdup(path);
    char *pos = temp;
    char tmp_ch = '\0';

    if (!path || !temp) {
        return -1;
    }

    if (!strncmp(temp, "/", 1) || !strncmp(temp, "\\", 1)) {
        pos++;
    } else if (!strncmp(temp, "./", 2) || !strncmp(temp, ".\\", 2)) {
        pos += 2;
    }

    for ( ; *pos != '\0'; ++pos) {
        if (*pos == '/' || *pos == '\\') {
            tmp_ch = *pos;
            *pos = '\0';
            ret = mkdir(temp, 0755);
            *pos = tmp_ch;
        }
    }

    if ((*(pos - 1) != '/') || (*(pos - 1) != '\\')) {
        ret = mkdir(temp, 0755);
    }

    av_free(temp);
    return ret;
}

169 170 171 172
static int hls_delete_old_segments(HLSContext *hls) {

    HLSSegment *segment, *previous_segment = NULL;
    float playlist_duration = 0.0f;
173
    int ret = 0, path_size, sub_path_size;
174 175
    char *dirname = NULL, *p, *sub_path;
    char *path = NULL;
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

    segment = hls->segments;
    while (segment) {
        playlist_duration += segment->duration;
        segment = segment->next;
    }

    segment = hls->old_segments;
    while (segment) {
        playlist_duration -= segment->duration;
        previous_segment = segment;
        segment = previous_segment->next;
        if (playlist_duration <= -previous_segment->duration) {
            previous_segment->next = NULL;
            break;
        }
    }

    if (segment) {
        if (hls->segment_filename) {
            dirname = av_strdup(hls->segment_filename);
        } else {
            dirname = av_strdup(hls->avf->filename);
        }
        if (!dirname) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
        p = (char *)av_basename(dirname);
        *p = '\0';
    }

    while (segment) {
        av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n",
                                  segment->filename);
        path_size = strlen(dirname) + strlen(segment->filename) + 1;
        path = av_malloc(path_size);
        if (!path) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
217

218 219 220 221 222 223
        av_strlcpy(path, dirname, path_size);
        av_strlcat(path, segment->filename, path_size);
        if (unlink(path) < 0) {
            av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n",
                                     path, strerror(errno));
        }
224

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
        if (segment->sub_filename[0] != '\0') {
            sub_path_size = strlen(dirname) + strlen(segment->sub_filename) + 1;
            sub_path = av_malloc(sub_path_size);
            if (!sub_path) {
                ret = AVERROR(ENOMEM);
                goto fail;
            }

            av_strlcpy(sub_path, dirname, sub_path_size);
            av_strlcat(sub_path, segment->sub_filename, sub_path_size);
            if (unlink(sub_path) < 0) {
                av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n",
                                         sub_path, strerror(errno));
            }
            av_free(sub_path);
240
        }
241
        av_freep(&path);
242 243 244 245 246 247
        previous_segment = segment;
        segment = previous_segment->next;
        av_free(previous_segment);
    }

fail:
248
    av_free(path);
249 250 251 252 253
    av_free(dirname);

    return ret;
}

254 255 256 257 258 259 260
static int hls_encryption_start(AVFormatContext *s)
{
    HLSContext *hls = s->priv_data;
    int ret;
    AVIOContext *pb;
    uint8_t key[KEYSIZE];

261
    if ((ret = s->io_open(s, &pb, hls->key_info_file, AVIO_FLAG_READ, NULL)) < 0) {
262 263 264 265 266 267 268 269 270 271 272 273 274 275
        av_log(hls, AV_LOG_ERROR,
                "error opening key info file %s\n", hls->key_info_file);
        return ret;
    }

    ff_get_line(pb, hls->key_uri, sizeof(hls->key_uri));
    hls->key_uri[strcspn(hls->key_uri, "\r\n")] = '\0';

    ff_get_line(pb, hls->key_file, sizeof(hls->key_file));
    hls->key_file[strcspn(hls->key_file, "\r\n")] = '\0';

    ff_get_line(pb, hls->iv_string, sizeof(hls->iv_string));
    hls->iv_string[strcspn(hls->iv_string, "\r\n")] = '\0';

276
    ff_format_io_close(s, &pb);
277 278 279 280 281 282 283 284 285 286 287

    if (!*hls->key_uri) {
        av_log(hls, AV_LOG_ERROR, "no key URI specified in key info file\n");
        return AVERROR(EINVAL);
    }

    if (!*hls->key_file) {
        av_log(hls, AV_LOG_ERROR, "no key file specified in key info file\n");
        return AVERROR(EINVAL);
    }

288
    if ((ret = s->io_open(s, &pb, hls->key_file, AVIO_FLAG_READ, NULL)) < 0) {
289 290 291 292 293
        av_log(hls, AV_LOG_ERROR, "error opening key file %s\n", hls->key_file);
        return ret;
    }

    ret = avio_read(pb, key, sizeof(key));
294
    ff_format_io_close(s, &pb);
295 296 297 298 299 300 301 302 303 304 305
    if (ret != sizeof(key)) {
        av_log(hls, AV_LOG_ERROR, "error reading key file %s\n", hls->key_file);
        if (ret >= 0 || ret == AVERROR_EOF)
            ret = AVERROR(EINVAL);
        return ret;
    }
    ff_data_to_hex(hls->key_string, key, sizeof(key), 0);

    return 0;
}

306 307 308 309 310 311 312 313
static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
{
    int len = ff_get_line(s, buf, maxlen);
    while (len > 0 && av_isspace(buf[len - 1]))
        buf[--len] = '\0';
    return len;
}

L
Luca Barbato 已提交
314 315 316 317
static int hls_mux_init(AVFormatContext *s)
{
    HLSContext *hls = s->priv_data;
    AVFormatContext *oc;
318
    AVFormatContext *vtt_oc = NULL;
319
    int i, ret;
L
Luca Barbato 已提交
320

321 322 323 324
    ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL);
    if (ret < 0)
        return ret;
    oc = hls->avf;
L
Luca Barbato 已提交
325 326 327

    oc->oformat            = hls->oformat;
    oc->interrupt_callback = s->interrupt_callback;
328
    oc->max_delay          = s->max_delay;
329 330 331
    oc->opaque             = s->opaque;
    oc->io_open            = s->io_open;
    oc->io_close           = s->io_close;
332
    av_dict_copy(&oc->metadata, s->metadata, 0);
L
Luca Barbato 已提交
333

334 335 336 337 338 339 340 341 342
    if(hls->vtt_oformat) {
        ret = avformat_alloc_output_context2(&hls->vtt_avf, hls->vtt_oformat, NULL, NULL);
        if (ret < 0)
            return ret;
        vtt_oc          = hls->vtt_avf;
        vtt_oc->oformat = hls->vtt_oformat;
        av_dict_copy(&vtt_oc->metadata, s->metadata, 0);
    }

L
Luca Barbato 已提交
343 344
    for (i = 0; i < s->nb_streams; i++) {
        AVStream *st;
345
        AVFormatContext *loc;
346
        if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
347 348 349 350 351
            loc = vtt_oc;
        else
            loc = oc;

        if (!(st = avformat_new_stream(loc, NULL)))
L
Luca Barbato 已提交
352
            return AVERROR(ENOMEM);
353
        avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar);
L
Luca Barbato 已提交
354
        st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
355
        st->time_base = s->streams[i]->time_base;
L
Luca Barbato 已提交
356
    }
357
    hls->start_pos = 0;
L
Luca Barbato 已提交
358 359 360 361

    return 0;
}

362
/* Create a new segment and append it to the segment list */
363 364
static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double duration,
                              int64_t pos, int64_t size)
L
Luca Barbato 已提交
365
{
366
    HLSSegment *en = av_malloc(sizeof(*en));
367
    const char  *filename;
368
    int ret;
L
Luca Barbato 已提交
369 370 371 372

    if (!en)
        return AVERROR(ENOMEM);

373 374 375
    filename = av_basename(hls->avf->filename);

    if (hls->use_localtime_mkdir) {
376
        filename = hls->avf->filename;
377 378
    }
    av_strlcpy(en->filename, filename, sizeof(en->filename));
L
Luca Barbato 已提交
379

380 381
    if(hls->has_subtitle)
        av_strlcpy(en->sub_filename, av_basename(hls->vtt_avf->filename), sizeof(en->sub_filename));
382 383
    else
        en->sub_filename[0] = '\0';
384

L
Luca Barbato 已提交
385
    en->duration = duration;
386 387
    en->pos      = pos;
    en->size     = size;
L
Luca Barbato 已提交
388 389
    en->next     = NULL;

390 391 392 393 394
    if (hls->key_info_file) {
        av_strlcpy(en->key_uri, hls->key_uri, sizeof(en->key_uri));
        av_strlcpy(en->iv_string, hls->iv_string, sizeof(en->iv_string));
    }

395 396
    if (!hls->segments)
        hls->segments = en;
L
Luca Barbato 已提交
397
    else
398
        hls->last_segment->next = en;
L
Luca Barbato 已提交
399

400
    hls->last_segment = en;
L
Luca Barbato 已提交
401

402 403 404 405
    // EVENT or VOD playlists imply sliding window cannot be used
    if (hls->pl_type != PLAYLIST_TYPE_NONE)
        hls->max_nb_segments = 0;

406 407 408
    if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) {
        en = hls->segments;
        hls->segments = en->next;
409 410 411 412 413 414 415 416
        if (en && hls->flags & HLS_DELETE_SEGMENTS &&
                !(hls->flags & HLS_SINGLE_FILE || hls->wrap)) {
            en->next = hls->old_segments;
            hls->old_segments = en;
            if ((ret = hls_delete_old_segments(hls)) < 0)
                return ret;
        } else
            av_free(en);
417 418
    } else
        hls->nb_entries++;
L
Luca Barbato 已提交
419

420 421 422
    if (hls->max_seg_size > 0) {
        return 0;
    }
423 424
    hls->sequence++;

L
Luca Barbato 已提交
425 426 427
    return 0;
}

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
static int parse_playlist(AVFormatContext *s, const char *url)
{
    HLSContext *hls = s->priv_data;
    AVIOContext *in;
    int ret = 0, is_segment = 0;
    int64_t new_start_pos;
    char line[1024];
    const char *ptr;

    if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ,
                                   &s->interrupt_callback, NULL,
                                   s->protocol_whitelist, s->protocol_blacklist)) < 0)
        return ret;

    read_chomp_line(in, line, sizeof(line));
    if (strcmp(line, "#EXTM3U")) {
        ret = AVERROR_INVALIDDATA;
        goto fail;
    }

    while (!avio_feof(in)) {
        read_chomp_line(in, line, sizeof(line));
        if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
            hls->sequence = atoi(ptr);
        } else if (av_strstart(line, "#EXTINF:", &ptr)) {
            is_segment = 1;
            hls->duration = atof(ptr);
        } else if (av_strstart(line, "#", NULL)) {
            continue;
        } else if (line[0]) {
            if (is_segment) {
                is_segment = 0;
                new_start_pos = avio_tell(hls->avf->pb);
                hls->size = new_start_pos - hls->start_pos;
                av_strlcpy(hls->avf->filename, line, sizeof(line));
                ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size);
                if (ret < 0)
                    goto fail;
                hls->start_pos = new_start_pos;
            }
        }
    }

fail:
    avio_close(in);
    return ret;
}

476
static void hls_free_segments(HLSSegment *p)
L
Luca Barbato 已提交
477
{
478
    HLSSegment *en;
L
Luca Barbato 已提交
479 480 481 482 483 484 485 486

    while(p) {
        en = p;
        p = p->next;
        av_free(en);
    }
}

487 488 489 490 491 492
static void set_http_options(AVDictionary **options, HLSContext *c)
{
    if (c->method)
        av_dict_set(options, "method", c->method, 0);
}

L
Luca Barbato 已提交
493 494 495
static int hls_window(AVFormatContext *s, int last)
{
    HLSContext *hls = s->priv_data;
496
    HLSSegment *en;
497
    int target_duration = 0;
L
Luca Barbato 已提交
498
    int ret = 0;
499
    AVIOContext *out = NULL;
500
    AVIOContext *sub_out = NULL;
501
    char temp_filename[1024];
502
    int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries);
503
    int version = 3;
504 505
    const char *proto = avio_find_protocol_name(s->filename);
    int use_rename = proto && !strcmp(proto, "file");
506
    static unsigned warned_non_file;
507 508
    char *key_uri = NULL;
    char *iv_string = NULL;
509
    AVDictionary *options = NULL;
510
    double prog_date_time = hls->initial_prog_date_time;
511 512 513 514 515 516
    int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);

    if (byterange_mode) {
        version = 4;
        sequence = 0;
    }
517 518

    if (!use_rename && !warned_non_file++)
M
Moritz Barsnick 已提交
519
        av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n");
L
Luca Barbato 已提交
520

521
    set_http_options(&options, hls);
522
    snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename);
523
    if ((ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, &options)) < 0)
L
Luca Barbato 已提交
524 525
        goto fail;

526
    for (en = hls->segments; en; en = en->next) {
527
        if (target_duration < en->duration)
528
            target_duration = ceil(en->duration);
529 530
    }

531
    hls->discontinuity_set = 0;
532 533
    avio_printf(out, "#EXTM3U\n");
    avio_printf(out, "#EXT-X-VERSION:%d\n", version);
534
    if (hls->allowcache == 0 || hls->allowcache == 1) {
535
        avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
536
    }
537 538
    avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration);
    avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);
539 540 541 542 543
    if (hls->pl_type == PLAYLIST_TYPE_EVENT) {
        avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n");
    } else if (hls->pl_type == PLAYLIST_TYPE_VOD) {
        avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n");
    }
L
Luca Barbato 已提交
544

545
    av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n",
546
           sequence);
547 548 549 550
    if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && hls->discontinuity_set==0 ){
        avio_printf(out, "#EXT-X-DISCONTINUITY\n");
        hls->discontinuity_set = 1;
    }
551
    for (en = hls->segments; en; en = en->next) {
552 553 554 555 556 557 558 559 560 561
        if (hls->key_info_file && (!key_uri || strcmp(en->key_uri, key_uri) ||
                                    av_strcasecmp(en->iv_string, iv_string))) {
            avio_printf(out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri);
            if (*en->iv_string)
                avio_printf(out, ",IV=0x%s", en->iv_string);
            avio_printf(out, "\n");
            key_uri = en->key_uri;
            iv_string = en->iv_string;
        }

562
        if (hls->flags & HLS_ROUND_DURATIONS)
563
            avio_printf(out, "#EXTINF:%ld,\n",  lrint(en->duration));
564 565
        else
            avio_printf(out, "#EXTINF:%f,\n", en->duration);
566
        if (byterange_mode)
567
             avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
568
                         en->size, en->pos);
569
        if (hls->flags & HLS_PROGRAM_DATE_TIME) {
570
            time_t tt, wrongsecs;
571 572 573 574 575 576
            int milli;
            struct tm *tm, tmpbuf;
            char buf0[128], buf1[128];
            tt = (int64_t)prog_date_time;
            milli = av_clip(lrint(1000*(prog_date_time - tt)), 0, 999);
            tm = localtime_r(&tt, &tmpbuf);
577
            strftime(buf0, sizeof(buf0), "%Y-%m-%dT%H:%M:%S", tm);
578 579 580 581 582 583 584 585 586 587 588 589
            if (!strftime(buf1, sizeof(buf1), "%z", tm) || buf1[1]<'0' ||buf1[1]>'2') {
                int tz_min, dst = tm->tm_isdst;
                tm = gmtime_r(&tt, &tmpbuf);
                tm->tm_isdst = dst;
                wrongsecs = mktime(tm);
                tz_min = (abs(wrongsecs - tt) + 30) / 60;
                snprintf(buf1, sizeof(buf1),
                         "%c%02d%02d",
                         wrongsecs <= tt ? '+' : '-',
                         tz_min / 60,
                         tz_min % 60);
            }
590 591 592
            avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1);
            prog_date_time += en->duration;
        }
593
        if (hls->baseurl)
594 595
            avio_printf(out, "%s", hls->baseurl);
        avio_printf(out, "%s\n", en->filename);
L
Luca Barbato 已提交
596 597
    }

598
    if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
599
        avio_printf(out, "#EXT-X-ENDLIST\n");
L
Luca Barbato 已提交
600

601
    if( hls->vtt_m3u8_name ) {
602
        if ((ret = s->io_open(s, &sub_out, hls->vtt_m3u8_name, AVIO_FLAG_WRITE, &options)) < 0)
603 604 605 606 607 608 609 610 611 612 613 614 615 616
            goto fail;
        avio_printf(sub_out, "#EXTM3U\n");
        avio_printf(sub_out, "#EXT-X-VERSION:%d\n", version);
        if (hls->allowcache == 0 || hls->allowcache == 1) {
            avio_printf(sub_out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
        }
        avio_printf(sub_out, "#EXT-X-TARGETDURATION:%d\n", target_duration);
        avio_printf(sub_out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);

        av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n",
               sequence);

        for (en = hls->segments; en; en = en->next) {
            avio_printf(sub_out, "#EXTINF:%f,\n", en->duration);
617
            if (byterange_mode)
618 619 620 621 622 623 624 625 626 627 628 629
                 avio_printf(sub_out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
                         en->size, en->pos);
            if (hls->baseurl)
                avio_printf(sub_out, "%s", hls->baseurl);
            avio_printf(sub_out, "%s\n", en->sub_filename);
        }

        if (last)
            avio_printf(sub_out, "#EXT-X-ENDLIST\n");

    }

L
Luca Barbato 已提交
630
fail:
631
    av_dict_free(&options);
632
    ff_format_io_close(s, &out);
633
    ff_format_io_close(s, &sub_out);
634
    if (ret >= 0 && use_rename)
635
        ff_rename(temp_filename, s->filename, s);
L
Luca Barbato 已提交
636 637 638 639 640 641 642
    return ret;
}

static int hls_start(AVFormatContext *s)
{
    HLSContext *c = s->priv_data;
    AVFormatContext *oc = c->avf;
643
    AVFormatContext *vtt_oc = c->vtt_avf;
644 645
    AVDictionary *options = NULL;
    char *filename, iv_string[KEYSIZE*2 + 1];
L
Luca Barbato 已提交
646 647
    int err = 0;

648
    if (c->flags & HLS_SINGLE_FILE) {
649 650
        av_strlcpy(oc->filename, c->basename,
                   sizeof(oc->filename));
651 652 653
        if (c->vtt_basename)
            av_strlcpy(vtt_oc->filename, c->vtt_basename,
                  sizeof(vtt_oc->filename));
654 655 656
    } else if (c->max_seg_size > 0) {
        if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
            c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
657
            AV_FRAME_FILENAME_FLAGS_MULTIPLE, 0) < 0) {
658 659 660
                av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename);
                return AVERROR(EINVAL);
        }
661
    } else {
662 663 664 665 666 667 668 669 670
        if (c->use_localtime) {
            time_t now0;
            struct tm *tm, tmpbuf;
            time(&now0);
            tm = localtime_r(&now0, &tmpbuf);
            if (!strftime(oc->filename, sizeof(oc->filename), c->basename, tm)) {
                av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n");
                return AVERROR(EINVAL);
            }
671 672 673 674 675 676 677 678

            if (c->use_localtime_mkdir) {
                const char *dir;
                char *fn_copy = av_strdup(oc->filename);
                if (!fn_copy) {
                    return AVERROR(ENOMEM);
                }
                dir = av_dirname(fn_copy);
679
                if (mkdir_p(dir) == -1 && errno != EEXIST) {
680 681 682 683 684 685
                    av_log(oc, AV_LOG_ERROR, "Could not create directory %s with use_localtime_mkdir\n", dir);
                    av_free(fn_copy);
                    return AVERROR(errno);
                }
                av_free(fn_copy);
            }
686 687
        } else if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
                                  c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
688
                                  AV_FRAME_FILENAME_FLAGS_MULTIPLE, 0) < 0) {
M
Moritz Barsnick 已提交
689
            av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", c->basename);
690 691
            return AVERROR(EINVAL);
        }
692
        if( c->vtt_basename) {
693 694
            if (av_get_frame_filename2(vtt_oc->filename, sizeof(vtt_oc->filename),
                              c->vtt_basename, c->wrap ? c->sequence % c->wrap : c->sequence,
695
                              AV_FRAME_FILENAME_FLAGS_MULTIPLE, 0) < 0) {
696 697 698 699 700
                av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename);
                return AVERROR(EINVAL);
            }
       }
    }
701
    c->number++;
L
Luca Barbato 已提交
702

703 704
    set_http_options(&options, c);

705 706
    if (c->key_info_file) {
        if ((err = hls_encryption_start(s)) < 0)
707
            goto fail;
708 709
        if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0))
                < 0)
710
            goto fail;
711 712 713 714
        err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string));
        if (!err)
            snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, c->sequence);
        if ((err = av_dict_set(&options, "encryption_iv", iv_string, 0)) < 0)
715
           goto fail;
716 717 718

        filename = av_asprintf("crypto:%s", oc->filename);
        if (!filename) {
719 720
            err = AVERROR(ENOMEM);
            goto fail;
721
        }
722
        err = s->io_open(s, &oc->pb, filename, AVIO_FLAG_WRITE, &options);
723 724 725 726 727
        av_free(filename);
        av_dict_free(&options);
        if (err < 0)
            return err;
    } else
728
        if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, &options)) < 0)
729
            goto fail;
730
    if (c->vtt_basename) {
731
        set_http_options(&options, c);
732
        if ((err = s->io_open(s, &vtt_oc->pb, vtt_oc->filename, AVIO_FLAG_WRITE, &options)) < 0)
733
            goto fail;
734
    }
735
    av_dict_free(&options);
L
Luca Barbato 已提交
736

737 738 739 740 741 742
    /* We only require one PAT/PMT per segment. */
    if (oc->oformat->priv_class && oc->priv_data) {
        char period[21];

        snprintf(period, sizeof(period), "%d", (INT_MAX / 2) - 1);

L
Luca Barbato 已提交
743
        av_opt_set(oc->priv_data, "mpegts_flags", "resend_headers", 0);
744 745 746
        av_opt_set(oc->priv_data, "sdt_period", period, 0);
        av_opt_set(oc->priv_data, "pat_period", period, 0);
    }
L
Luca Barbato 已提交
747

748 749 750 751 752
    if (c->vtt_basename) {
        err = avformat_write_header(vtt_oc,NULL);
        if (err < 0)
            return err;
    }
753

L
Luca Barbato 已提交
754
    return 0;
755 756 757 758
fail:
    av_dict_free(&options);

    return err;
L
Luca Barbato 已提交
759 760 761 762 763 764 765 766
}

static int hls_write_header(AVFormatContext *s)
{
    HLSContext *hls = s->priv_data;
    int ret, i;
    char *p;
    const char *pattern = "%d.ts";
767
    const char *pattern_localtime_fmt = "-%s.ts";
768
    const char *vtt_pattern = "%d.vtt";
liuqi_123's avatar
liuqi_123 已提交
769
    AVDictionary *options = NULL;
770
    int basename_size;
771
    int vtt_basename_size;
L
Luca Barbato 已提交
772

773
    hls->sequence       = hls->start_sequence;
774
    hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE;
L
Luca Barbato 已提交
775 776
    hls->start_pts      = AV_NOPTS_VALUE;

777 778 779 780 781 782
    if (hls->flags & HLS_PROGRAM_DATE_TIME) {
        time_t now0;
        time(&now0);
        hls->initial_prog_date_time = now0;
    }

liuqi_123's avatar
liuqi_123 已提交
783 784 785 786 787 788 789 790
    if (hls->format_options_str) {
        ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
        if (ret < 0) {
            av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str);
            goto fail;
        }
    }

791
    for (i = 0; i < s->nb_streams; i++) {
L
Luca Barbato 已提交
792
        hls->has_video +=
793
            s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
794
        hls->has_subtitle +=
795
            s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE;
796
    }
L
Luca Barbato 已提交
797 798 799 800 801 802 803 804 805 806 807 808 809

    if (hls->has_video > 1)
        av_log(s, AV_LOG_WARNING,
               "More than a single video stream present, "
               "expect issues decoding it.\n");

    hls->oformat = av_guess_format("mpegts", NULL, NULL);

    if (!hls->oformat) {
        ret = AVERROR_MUXER_NOT_FOUND;
        goto fail;
    }

810 811 812 813 814 815 816 817
    if(hls->has_subtitle) {
        hls->vtt_oformat = av_guess_format("webvtt", NULL, NULL);
        if (!hls->oformat) {
            ret = AVERROR_MUXER_NOT_FOUND;
            goto fail;
        }
    }

818 819 820 821 822 823 824 825 826
    if (hls->segment_filename) {
        hls->basename = av_strdup(hls->segment_filename);
        if (!hls->basename) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
    } else {
        if (hls->flags & HLS_SINGLE_FILE)
            pattern = ".ts";
L
Luca Barbato 已提交
827

828 829 830 831 832
        if (hls->use_localtime) {
            basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1;
        } else {
            basename_size = strlen(s->filename) + strlen(pattern) + 1;
        }
833 834 835 836 837
        hls->basename = av_malloc(basename_size);
        if (!hls->basename) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
L
Luca Barbato 已提交
838

839
        av_strlcpy(hls->basename, s->filename, basename_size);
L
Luca Barbato 已提交
840

841 842 843
        p = strrchr(hls->basename, '.');
        if (p)
            *p = '\0';
844 845 846 847 848
        if (hls->use_localtime) {
            av_strlcat(hls->basename, pattern_localtime_fmt, basename_size);
        } else {
            av_strlcat(hls->basename, pattern, basename_size);
        }
849
    }
L
Luca Barbato 已提交
850

851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
    if(hls->has_subtitle) {

        if (hls->flags & HLS_SINGLE_FILE)
            vtt_pattern = ".vtt";
        vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) + 1;
        hls->vtt_basename = av_malloc(vtt_basename_size);
        if (!hls->vtt_basename) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
        hls->vtt_m3u8_name = av_malloc(vtt_basename_size);
        if (!hls->vtt_m3u8_name ) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
        av_strlcpy(hls->vtt_basename, s->filename, vtt_basename_size);
        p = strrchr(hls->vtt_basename, '.');
        if (p)
            *p = '\0';

        if( hls->subtitle_filename ) {
            strcpy(hls->vtt_m3u8_name, hls->subtitle_filename);
        } else {
            strcpy(hls->vtt_m3u8_name, hls->vtt_basename);
            av_strlcat(hls->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size);
        }
        av_strlcat(hls->vtt_basename, vtt_pattern, vtt_basename_size);
    }

L
Luca Barbato 已提交
880 881 882
    if ((ret = hls_mux_init(s)) < 0)
        goto fail;

883 884
    if (hls->flags & HLS_APPEND_LIST) {
        parse_playlist(s, s->filename);
885 886 887 888 889 890
        if (hls->init_time > 0) {
            av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time,"
                   " hls_init_time value will have no effect\n");
            hls->init_time = 0;
            hls->recording_time = hls->time * AV_TIME_BASE;
        }
891 892
    }

L
Luca Barbato 已提交
893 894 895
    if ((ret = hls_start(s)) < 0)
        goto fail;

liuqi_123's avatar
liuqi_123 已提交
896 897 898 899 900
    av_dict_copy(&options, hls->format_options, 0);
    ret = avformat_write_header(hls->avf, &options);
    if (av_dict_count(options)) {
        av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s' are not recognized\n", hls->format_options_str);
        ret = AVERROR(EINVAL);
901
        goto fail;
liuqi_123's avatar
liuqi_123 已提交
902
    }
903
    //av_assert0(s->nb_streams == hls->avf->nb_streams);
904
    for (i = 0; i < s->nb_streams; i++) {
905
        AVStream *inner_st;
906
        AVStream *outer_st = s->streams[i];
907 908 909 910 911 912 913 914 915 916

        if (hls->max_seg_size > 0) {
            if ((outer_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
                (outer_st->codecpar->bit_rate > hls->max_seg_size)) {
                av_log(s, AV_LOG_WARNING, "Your video bitrate is bigger than hls_segment_size, "
                       "(%"PRId64 " > %"PRId64 "), the result maybe not be what you want.",
                       outer_st->codecpar->bit_rate, hls->max_seg_size);
            }
        }

917
        if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
918 919 920 921
            inner_st = hls->avf->streams[i];
        else if (hls->vtt_avf)
            inner_st = hls->vtt_avf->streams[0];
        else {
922
            /* We have a subtitle stream, when the user does not want one */
923 924 925
            inner_st = NULL;
            continue;
        }
926
        avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den);
927
    }
L
Luca Barbato 已提交
928
fail:
liuqi_123's avatar
liuqi_123 已提交
929 930

    av_dict_free(&options);
931
    if (ret < 0) {
932
        av_freep(&hls->basename);
933
        av_freep(&hls->vtt_basename);
L
Luca Barbato 已提交
934 935
        if (hls->avf)
            avformat_free_context(hls->avf);
936 937 938
        if (hls->vtt_avf)
            avformat_free_context(hls->vtt_avf);

L
Luca Barbato 已提交
939 940 941 942 943 944 945
    }
    return ret;
}

static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
{
    HLSContext *hls = s->priv_data;
946
    AVFormatContext *oc = NULL;
L
Luca Barbato 已提交
947 948
    AVStream *st = s->streams[pkt->stream_index];
    int64_t end_pts = hls->recording_time * hls->number;
949
    int is_ref_pkt = 1;
950
    int ret, can_split = 1;
951
    int stream_index = 0;
L
Luca Barbato 已提交
952

953 954 955 956 957 958 959 960
    if (hls->sequence - hls->nb_entries > hls->start_sequence && hls->init_time > 0) {
        /* reset end_pts, hls->recording_time at end of the init hls list */
        int init_list_dur = hls->init_time * hls->nb_entries * AV_TIME_BASE;
        int after_init_list_dur = (hls->sequence - hls->nb_entries ) * hls->time * AV_TIME_BASE;
        hls->recording_time = hls->time * AV_TIME_BASE;
        end_pts = init_list_dur + after_init_list_dur ;
    }

961
    if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) {
962 963 964 965 966 967
        oc = hls->vtt_avf;
        stream_index = 0;
    } else {
        oc = hls->avf;
        stream_index = pkt->stream_index;
    }
L
Luca Barbato 已提交
968 969 970 971 972
    if (hls->start_pts == AV_NOPTS_VALUE) {
        hls->start_pts = pkt->pts;
        hls->end_pts   = pkt->pts;
    }

973
    if (hls->has_video) {
974
        can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
975
                    ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME));
976
        is_ref_pkt = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
977
    }
978 979
    if (pkt->pts == AV_NOPTS_VALUE)
        is_ref_pkt = can_split = 0;
980

981
    if (is_ref_pkt)
982 983
        hls->duration = (double)(pkt->pts - hls->end_pts)
                                   * st->time_base.num / st->time_base.den;
L
Luca Barbato 已提交
984

985 986
    if (can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base,
                                   end_pts, AV_TIME_BASE_Q) >= 0) {
987 988 989 990 991
        int64_t new_start_pos;
        av_write_frame(oc, NULL); /* Flush any buffered data */

        new_start_pos = avio_tell(hls->avf->pb);
        hls->size = new_start_pos - hls->start_pos;
992
        ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size);
993
        hls->start_pos = new_start_pos;
994
        if (ret < 0)
995 996
            return ret;

L
Luca Barbato 已提交
997
        hls->end_pts = pkt->pts;
998
        hls->duration = 0;
L
Luca Barbato 已提交
999

1000 1001 1002 1003
        if (hls->flags & HLS_SINGLE_FILE) {
            if (hls->avf->oformat->priv_class && hls->avf->priv_data)
                av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0);
            hls->number++;
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
        } else if (hls->max_seg_size > 0) {
            if (hls->avf->oformat->priv_class && hls->avf->priv_data)
                av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0);
            if (hls->start_pos >= hls->max_seg_size) {
                hls->sequence++;
                ff_format_io_close(s, &oc->pb);
                if (hls->vtt_avf)
                    ff_format_io_close(s, &hls->vtt_avf->pb);
                ret = hls_start(s);
                hls->start_pos = 0;
                /* When split segment by byte, the duration is short than hls_time,
                 * so it is not enough one segment duration as hls_time, */
                hls->number--;
            }
            hls->number++;
1019
        } else {
1020
            ff_format_io_close(s, &oc->pb);
1021
            if (hls->vtt_avf)
1022
                ff_format_io_close(s, &hls->vtt_avf->pb);
L
Luca Barbato 已提交
1023

1024 1025
            ret = hls_start(s);
        }
L
Luca Barbato 已提交
1026

1027
        if (ret < 0)
L
Luca Barbato 已提交
1028 1029
            return ret;

1030
        if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE )
1031 1032
            oc = hls->vtt_avf;
        else
L
Luca Barbato 已提交
1033 1034 1035 1036 1037 1038
        oc = hls->avf;

        if ((ret = hls_window(s, 0)) < 0)
            return ret;
    }

1039
    ret = ff_write_chained(oc, stream_index, pkt, s, 0);
L
Luca Barbato 已提交
1040 1041 1042 1043 1044 1045 1046 1047

    return ret;
}

static int hls_write_trailer(struct AVFormatContext *s)
{
    HLSContext *hls = s->priv_data;
    AVFormatContext *oc = hls->avf;
1048
    AVFormatContext *vtt_oc = hls->vtt_avf;
L
Luca Barbato 已提交
1049 1050

    av_write_trailer(oc);
1051 1052
    if (oc->pb) {
        hls->size = avio_tell(hls->avf->pb) - hls->start_pos;
1053
        ff_format_io_close(s, &oc->pb);
1054
        hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size);
1055
    }
1056 1057 1058 1059 1060

    if (vtt_oc) {
        if (vtt_oc->pb)
            av_write_trailer(vtt_oc);
        hls->size = avio_tell(hls->vtt_avf->pb) - hls->start_pos;
1061
        ff_format_io_close(s, &vtt_oc->pb);
1062
    }
1063
    av_freep(&hls->basename);
1064
    avformat_free_context(oc);
1065

1066 1067 1068
    hls->avf = NULL;
    hls_window(s, 1);

1069 1070 1071 1072 1073 1074
    if (vtt_oc) {
        av_freep(&hls->vtt_basename);
        av_freep(&hls->vtt_m3u8_name);
        avformat_free_context(vtt_oc);
    }

1075 1076
    hls_free_segments(hls->segments);
    hls_free_segments(hls->old_segments);
L
Luca Barbato 已提交
1077 1078 1079 1080 1081 1082
    return 0;
}

#define OFFSET(x) offsetof(HLSContext, x)
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
1083
    {"start_number",  "set first number in the sequence",        OFFSET(start_sequence),AV_OPT_TYPE_INT64,  {.i64 = 0},     0, INT64_MAX, E},
1084
    {"hls_time",      "set segment length in seconds",           OFFSET(time),    AV_OPT_TYPE_FLOAT,  {.dbl = 2},     0, FLT_MAX, E},
1085
    {"hls_init_time", "set segment length in seconds at init list",           OFFSET(init_time),    AV_OPT_TYPE_FLOAT,  {.dbl = 0},     0, FLT_MAX, E},
1086
    {"hls_list_size", "set maximum number of playlist entries",  OFFSET(max_nb_segments),    AV_OPT_TYPE_INT,    {.i64 = 5},     0, INT_MAX, E},
liuqi_123's avatar
liuqi_123 已提交
1087
    {"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},
1088
    {"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},
1089
    {"hls_wrap",      "set number after which the index wraps",  OFFSET(wrap),    AV_OPT_TYPE_INT,    {.i64 = 0},     0, INT_MAX, E},
1090
    {"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},
1091
    {"hls_base_url",  "url to prepend to each playlist entry",   OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E},
1092
    {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename),   AV_OPT_TYPE_STRING, {.str = NULL},            0,       0,         E},
1093
    {"hls_segment_size", "maximum size per segment file, (in bytes)",  OFFSET(max_seg_size),    AV_OPT_TYPE_INT,    {.i64 = 0},               0,       INT_MAX,   E},
1094
    {"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},
1095
    {"hls_subtitle_path",     "set path of hls subtitles", OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,    E},
1096 1097
    {"hls_flags",     "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"},
    {"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"},
1098
    {"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"},
1099
    {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX,   E, "flags"},
1100
    {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX,   E, "flags"},
1101
    {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX,   E, "flags"},
1102
    {"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"},
1103
    {"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"},
1104
    {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX,   E, "flags"},
1105 1106
    {"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
    {"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
1107 1108 1109
    {"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" },
    {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" },
    {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" },
1110
    {"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,    E},
1111

L
Luca Barbato 已提交
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
    { NULL },
};

static const AVClass hls_class = {
    .class_name = "hls muxer",
    .item_name  = av_default_item_name,
    .option     = options,
    .version    = LIBAVUTIL_VERSION_INT,
};


AVOutputFormat ff_hls_muxer = {
    .name           = "hls",
L
Luca Barbato 已提交
1125
    .long_name      = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
L
Luca Barbato 已提交
1126 1127
    .extensions     = "m3u8",
    .priv_data_size = sizeof(HLSContext),
1128 1129
    .audio_codec    = AV_CODEC_ID_AAC,
    .video_codec    = AV_CODEC_ID_H264,
1130
    .subtitle_codec = AV_CODEC_ID_WEBVTT,
L
Luca Barbato 已提交
1131 1132 1133 1134 1135 1136
    .flags          = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH,
    .write_header   = hls_write_header,
    .write_packet   = hls_write_packet,
    .write_trailer  = hls_write_trailer,
    .priv_class     = &hls_class,
};