hlsenc.c 30 KB
Newer Older
1 2 3 4
/*
 * Apple HTTP Live Streaming segmenter
 * Copyright (c) 2012, Luca Barbato
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
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,
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
19 20 21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

22
#include "config.h"
23
#include <float.h>
24
#include <stdint.h>
25 26 27
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
28

29
#include "libavutil/avassert.h"
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"
36 37 38

#include "avformat.h"
#include "internal.h"
39
#include "os_support.h"
40

41 42 43
#define KEYSIZE 16
#define LINE_BUFFER_SIZE 1024

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

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

54 55
    struct HLSSegment *next;
} HLSSegment;
56

57 58 59
typedef enum HLSFlags {
    // Generate a single media file and use byte ranges in the playlist.
    HLS_SINGLE_FILE = (1 << 0),
60
    HLS_DELETE_SEGMENTS = (1 << 1),
61
    HLS_ROUND_DURATIONS = (1 << 2),
62
    HLS_DISCONT_START = (1 << 3),
63
    HLS_OMIT_ENDLIST = (1 << 4),
64 65
} HLSFlags;

66 67
typedef struct HLSContext {
    const AVClass *class;  // Class for private options.
68
    unsigned number;
69
    int64_t sequence;
70
    int64_t start_sequence;
71
    AVOutputFormat *oformat;
72
    AVOutputFormat *vtt_oformat;
73

74
    AVFormatContext *avf;
75
    AVFormatContext *vtt_avf;
76

77
    float time;            // Set by a private option.
78
    int max_nb_segments;   // Set by a private option.
79
    int  wrap;             // Set by a private option.
80
    uint32_t flags;        // enum HLSFlags
81
    char *segment_filename;
82

83
    int use_localtime;      ///< flag to expand filename with localtime
84
    int allowcache;
85 86
    int64_t recording_time;
    int has_video;
87
    int has_subtitle;
88 89
    int64_t start_pts;
    int64_t end_pts;
90
    double duration;      // last segment duration computed so far, in seconds
91 92
    int64_t start_pos;    // last segment starting position
    int64_t size;         // last segment size
93
    int nb_entries;
94
    int discontinuity_set;
95

96 97
    HLSSegment *segments;
    HLSSegment *last_segment;
98
    HLSSegment *old_segments;
99

100
    char *basename;
101 102
    char *vtt_basename;
    char *vtt_m3u8_name;
103
    char *baseurl;
Steven Liu's avatar
Steven Liu committed
104
    char *format_options_str;
105 106
    char *vtt_format_options_str;
    char *subtitle_filename;
Steven Liu's avatar
Steven Liu committed
107
    AVDictionary *format_options;
108 109 110 111 112 113

    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];
114 115
    AVDictionary *vtt_format_options;

116 117
    char *method;

118 119
} HLSContext;

120 121 122 123
static int hls_delete_old_segments(HLSContext *hls) {

    HLSSegment *segment, *previous_segment = NULL;
    float playlist_duration = 0.0f;
124
    int ret = 0, path_size, sub_path_size;
125 126
    char *dirname = NULL, *p, *sub_path;
    char *path = NULL;
127 128 129 130 131 132 133 134 135 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

    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;
        }
168

169 170 171 172 173 174
        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));
        }
175

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
        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);
191
        }
192
        av_freep(&path);
193 194 195 196 197 198
        previous_segment = segment;
        segment = previous_segment->next;
        av_free(previous_segment);
    }

fail:
199
    av_free(path);
200 201 202 203 204
    av_free(dirname);

    return ret;
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
static int hls_encryption_start(AVFormatContext *s)
{
    HLSContext *hls = s->priv_data;
    int ret;
    AVIOContext *pb;
    uint8_t key[KEYSIZE];

    if ((ret = avio_open2(&pb, hls->key_info_file, AVIO_FLAG_READ,
                           &s->interrupt_callback, NULL)) < 0) {
        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';

    avio_close(pb);

    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);
    }

    if ((ret = avio_open2(&pb, hls->key_file, AVIO_FLAG_READ,
                           &s->interrupt_callback, NULL)) < 0) {
        av_log(hls, AV_LOG_ERROR, "error opening key file %s\n", hls->key_file);
        return ret;
    }

    ret = avio_read(pb, key, sizeof(key));
    avio_close(pb);
    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;
}

259 260 261 262
static int hls_mux_init(AVFormatContext *s)
{
    HLSContext *hls = s->priv_data;
    AVFormatContext *oc;
263
    AVFormatContext *vtt_oc = NULL;
264
    int i, ret;
265

266 267 268 269
    ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL);
    if (ret < 0)
        return ret;
    oc = hls->avf;
270 271 272

    oc->oformat            = hls->oformat;
    oc->interrupt_callback = s->interrupt_callback;
273
    oc->max_delay          = s->max_delay;
274
    av_dict_copy(&oc->metadata, s->metadata, 0);
275

276 277 278 279 280 281 282 283 284
    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);
    }

285 286
    for (i = 0; i < s->nb_streams; i++) {
        AVStream *st;
287 288 289 290 291 292 293
        AVFormatContext *loc;
        if (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
            loc = vtt_oc;
        else
            loc = oc;

        if (!(st = avformat_new_stream(loc, NULL)))
294 295 296
            return AVERROR(ENOMEM);
        avcodec_copy_context(st->codec, s->streams[i]->codec);
        st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
297
        st->time_base = s->streams[i]->time_base;
298
    }
299
    hls->start_pos = 0;
300 301 302 303

    return 0;
}

304
/* Create a new segment and append it to the segment list */
305 306
static int hls_append_segment(HLSContext *hls, double duration, int64_t pos,
                              int64_t size)
307
{
308
    HLSSegment *en = av_malloc(sizeof(*en));
309
    int ret;
310 311 312 313

    if (!en)
        return AVERROR(ENOMEM);

314
    av_strlcpy(en->filename, av_basename(hls->avf->filename), sizeof(en->filename));
315

316 317
    if(hls->has_subtitle)
        av_strlcpy(en->sub_filename, av_basename(hls->vtt_avf->filename), sizeof(en->sub_filename));
318 319
    else
        en->sub_filename[0] = '\0';
320

321
    en->duration = duration;
322 323
    en->pos      = pos;
    en->size     = size;
324 325
    en->next     = NULL;

326 327 328 329 330
    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));
    }

331 332
    if (!hls->segments)
        hls->segments = en;
333
    else
334
        hls->last_segment->next = en;
335

336
    hls->last_segment = en;
337

338 339 340
    if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) {
        en = hls->segments;
        hls->segments = en->next;
341 342 343 344 345 346 347 348
        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);
349 350
    } else
        hls->nb_entries++;
351

352 353
    hls->sequence++;

354 355 356
    return 0;
}

357
static void hls_free_segments(HLSSegment *p)
358
{
359
    HLSSegment *en;
360 361 362 363 364 365 366 367

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

368 369 370 371 372 373
static void set_http_options(AVDictionary **options, HLSContext *c)
{
    if (c->method)
        av_dict_set(options, "method", c->method, 0);
}

374 375 376
static int hls_window(AVFormatContext *s, int last)
{
    HLSContext *hls = s->priv_data;
377
    HLSSegment *en;
378
    int target_duration = 0;
379
    int ret = 0;
380
    AVIOContext *out = NULL;
381
    AVIOContext *sub_out = NULL;
382
    char temp_filename[1024];
383
    int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries);
384
    int version = hls->flags & HLS_SINGLE_FILE ? 4 : 3;
385 386
    const char *proto = avio_find_protocol_name(s->filename);
    int use_rename = proto && !strcmp(proto, "file");
387
    static unsigned warned_non_file;
388 389
    char *key_uri = NULL;
    char *iv_string = NULL;
390
    AVDictionary *options = NULL;
391 392 393

    if (!use_rename && !warned_non_file++)
        av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporarly partial files\n");
394

395
    set_http_options(&options, hls);
396
    snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename);
397
    if ((ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE,
398
                          &s->interrupt_callback, &options)) < 0)
399 400
        goto fail;

401
    for (en = hls->segments; en; en = en->next) {
402
        if (target_duration < en->duration)
403
            target_duration = ceil(en->duration);
404 405
    }

406
    hls->discontinuity_set = 0;
407 408
    avio_printf(out, "#EXTM3U\n");
    avio_printf(out, "#EXT-X-VERSION:%d\n", version);
409
    if (hls->allowcache == 0 || hls->allowcache == 1) {
410
        avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
411
    }
412 413
    avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration);
    avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence);
414

415
    av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n",
416
           sequence);
417 418 419 420
    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;
    }
421
    for (en = hls->segments; en; en = en->next) {
422 423 424 425 426 427 428 429 430 431
        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;
        }

432
        if (hls->flags & HLS_ROUND_DURATIONS)
433
            avio_printf(out, "#EXTINF:%ld,\n",  lrint(en->duration));
434 435
        else
            avio_printf(out, "#EXTINF:%f,\n", en->duration);
436
        if (hls->flags & HLS_SINGLE_FILE)
437
             avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
438
                         en->size, en->pos);
439
        if (hls->baseurl)
440 441
            avio_printf(out, "%s", hls->baseurl);
        avio_printf(out, "%s\n", en->filename);
442 443
    }

444
    if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
445
        avio_printf(out, "#EXT-X-ENDLIST\n");
446

447 448
    if( hls->vtt_m3u8_name ) {
        if ((ret = avio_open2(&sub_out, hls->vtt_m3u8_name, AVIO_FLAG_WRITE,
449
                          &s->interrupt_callback, &options)) < 0)
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 476
            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);
            if (hls->flags & HLS_SINGLE_FILE)
                 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");

    }

477
fail:
478
    av_dict_free(&options);
479
    avio_closep(&out);
480
    avio_closep(&sub_out);
481
    if (ret >= 0 && use_rename)
482
        ff_rename(temp_filename, s->filename, s);
483 484 485 486 487 488 489
    return ret;
}

static int hls_start(AVFormatContext *s)
{
    HLSContext *c = s->priv_data;
    AVFormatContext *oc = c->avf;
490
    AVFormatContext *vtt_oc = c->vtt_avf;
491 492
    AVDictionary *options = NULL;
    char *filename, iv_string[KEYSIZE*2 + 1];
493 494
    int err = 0;

495
    if (c->flags & HLS_SINGLE_FILE) {
496 497
        av_strlcpy(oc->filename, c->basename,
                   sizeof(oc->filename));
498 499 500 501
        if (c->vtt_basename)
            av_strlcpy(vtt_oc->filename, c->vtt_basename,
                  sizeof(vtt_oc->filename));
    } else {
502 503 504 505 506 507 508 509 510 511
        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);
            }
       } else if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
512
                                  c->basename, c->wrap ? c->sequence % c->wrap : c->sequence) < 0) {
513
            av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try use -use_localtime 1 with it\n", c->basename);
514 515
            return AVERROR(EINVAL);
        }
516 517 518 519 520 521 522 523
        if( c->vtt_basename) {
            if (av_get_frame_filename(vtt_oc->filename, sizeof(vtt_oc->filename),
                              c->vtt_basename, c->wrap ? c->sequence % c->wrap : c->sequence) < 0) {
                av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename);
                return AVERROR(EINVAL);
            }
       }
    }
524
    c->number++;
525

526 527
    set_http_options(&options, c);

528 529
    if (c->key_info_file) {
        if ((err = hls_encryption_start(s)) < 0)
530
            goto fail;
531 532
        if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0))
                < 0)
533
            goto fail;
534 535 536 537
        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)
538
           goto fail;
539 540 541

        filename = av_asprintf("crypto:%s", oc->filename);
        if (!filename) {
542 543
            err = AVERROR(ENOMEM);
            goto fail;
544 545 546 547 548 549 550 551 552
        }
        err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
                         &s->interrupt_callback, &options);
        av_free(filename);
        av_dict_free(&options);
        if (err < 0)
            return err;
    } else
        if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
553 554
                          &s->interrupt_callback, &options)) < 0)
            goto fail;
555
    if (c->vtt_basename) {
556
        set_http_options(&options, c);
557
        if ((err = avio_open2(&vtt_oc->pb, vtt_oc->filename, AVIO_FLAG_WRITE,
558 559
                         &s->interrupt_callback, &options)) < 0)
            goto fail;
560
    }
561
    av_dict_free(&options);
562

563 564 565 566 567 568
    /* 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);

569
        av_opt_set(oc->priv_data, "mpegts_flags", "resend_headers", 0);
570 571 572
        av_opt_set(oc->priv_data, "sdt_period", period, 0);
        av_opt_set(oc->priv_data, "pat_period", period, 0);
    }
573

574 575 576 577 578
    if (c->vtt_basename) {
        err = avformat_write_header(vtt_oc,NULL);
        if (err < 0)
            return err;
    }
579

580
    return 0;
581 582 583 584
fail:
    av_dict_free(&options);

    return err;
585 586 587 588 589 590 591 592
}

static int hls_write_header(AVFormatContext *s)
{
    HLSContext *hls = s->priv_data;
    int ret, i;
    char *p;
    const char *pattern = "%d.ts";
593
    const char *pattern_localtime_fmt = "-%s.ts";
594
    const char *vtt_pattern = "%d.vtt";
Steven Liu's avatar
Steven Liu committed
595
    AVDictionary *options = NULL;
596
    int basename_size;
597
    int vtt_basename_size;
598

599
    hls->sequence       = hls->start_sequence;
600
    hls->recording_time = hls->time * AV_TIME_BASE;
601 602
    hls->start_pts      = AV_NOPTS_VALUE;

Steven Liu's avatar
Steven Liu committed
603 604 605 606 607 608 609 610
    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;
        }
    }

611
    for (i = 0; i < s->nb_streams; i++) {
612 613
        hls->has_video +=
            s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO;
614 615 616
        hls->has_subtitle +=
            s->streams[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE;
    }
617 618 619 620 621 622 623 624 625 626 627 628 629

    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;
    }

630 631 632 633 634 635 636 637
    if(hls->has_subtitle) {
        hls->vtt_oformat = av_guess_format("webvtt", NULL, NULL);
        if (!hls->oformat) {
            ret = AVERROR_MUXER_NOT_FOUND;
            goto fail;
        }
    }

638 639 640 641 642 643 644 645 646
    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";
647

648 649 650 651 652
        if (hls->use_localtime) {
            basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1;
        } else {
            basename_size = strlen(s->filename) + strlen(pattern) + 1;
        }
653 654 655 656 657
        hls->basename = av_malloc(basename_size);
        if (!hls->basename) {
            ret = AVERROR(ENOMEM);
            goto fail;
        }
658

659
        av_strlcpy(hls->basename, s->filename, basename_size);
660

661 662 663
        p = strrchr(hls->basename, '.');
        if (p)
            *p = '\0';
664 665 666 667 668
        if (hls->use_localtime) {
            av_strlcat(hls->basename, pattern_localtime_fmt, basename_size);
        } else {
            av_strlcat(hls->basename, pattern, basename_size);
        }
669
    }
670

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
    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);
    }

700 701 702 703 704 705
    if ((ret = hls_mux_init(s)) < 0)
        goto fail;

    if ((ret = hls_start(s)) < 0)
        goto fail;

Steven Liu's avatar
Steven Liu committed
706 707 708 709 710
    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);
711
        goto fail;
Steven Liu's avatar
Steven Liu committed
712
    }
713
    //av_assert0(s->nb_streams == hls->avf->nb_streams);
714
    for (i = 0; i < s->nb_streams; i++) {
715
        AVStream *inner_st;
716
        AVStream *outer_st = s->streams[i];
717 718 719 720 721
        if (outer_st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE)
            inner_st = hls->avf->streams[i];
        else if (hls->vtt_avf)
            inner_st = hls->vtt_avf->streams[0];
        else {
722
            /* We have a subtitle stream, when the user does not want one */
723 724 725
            inner_st = NULL;
            continue;
        }
726
        avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den);
727
    }
728
fail:
Steven Liu's avatar
Steven Liu committed
729 730

    av_dict_free(&options);
731
    if (ret < 0) {
732
        av_freep(&hls->basename);
733
        av_freep(&hls->vtt_basename);
734 735
        if (hls->avf)
            avformat_free_context(hls->avf);
736 737 738
        if (hls->vtt_avf)
            avformat_free_context(hls->vtt_avf);

739 740 741 742 743 744 745
    }
    return ret;
}

static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
{
    HLSContext *hls = s->priv_data;
746
    AVFormatContext *oc = NULL;
747 748
    AVStream *st = s->streams[pkt->stream_index];
    int64_t end_pts = hls->recording_time * hls->number;
749
    int is_ref_pkt = 1;
750
    int ret, can_split = 1;
751
    int stream_index = 0;
752

753 754 755 756 757 758 759
    if( st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE ) {
        oc = hls->vtt_avf;
        stream_index = 0;
    } else {
        oc = hls->avf;
        stream_index = pkt->stream_index;
    }
760 761 762 763 764
    if (hls->start_pts == AV_NOPTS_VALUE) {
        hls->start_pts = pkt->pts;
        hls->end_pts   = pkt->pts;
    }

765 766 767
    if (hls->has_video) {
        can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
                    pkt->flags & AV_PKT_FLAG_KEY;
768
        is_ref_pkt = st->codec->codec_type == AVMEDIA_TYPE_VIDEO;
769
    }
770 771
    if (pkt->pts == AV_NOPTS_VALUE)
        is_ref_pkt = can_split = 0;
772

773
    if (is_ref_pkt)
774 775
        hls->duration = (double)(pkt->pts - hls->end_pts)
                                   * st->time_base.num / st->time_base.den;
776

777 778
    if (can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base,
                                   end_pts, AV_TIME_BASE_Q) >= 0) {
779 780 781 782 783 784 785
        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;
        ret = hls_append_segment(hls, hls->duration, hls->start_pos, hls->size);
        hls->start_pos = new_start_pos;
786
        if (ret < 0)
787 788
            return ret;

789
        hls->end_pts = pkt->pts;
790
        hls->duration = 0;
791

792 793 794 795 796
        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++;
        } else {
797
            avio_closep(&oc->pb);
798 799
            if (hls->vtt_avf)
                avio_close(hls->vtt_avf->pb);
800

801 802
            ret = hls_start(s);
        }
803

804
        if (ret < 0)
805 806
            return ret;

807 808 809
        if( st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE )
            oc = hls->vtt_avf;
        else
810 811 812 813 814 815
        oc = hls->avf;

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

816
    ret = ff_write_chained(oc, stream_index, pkt, s, 0);
817 818 819 820 821 822 823 824

    return ret;
}

static int hls_write_trailer(struct AVFormatContext *s)
{
    HLSContext *hls = s->priv_data;
    AVFormatContext *oc = hls->avf;
825
    AVFormatContext *vtt_oc = hls->vtt_avf;
826 827

    av_write_trailer(oc);
828 829 830 831 832
    if (oc->pb) {
        hls->size = avio_tell(hls->avf->pb) - hls->start_pos;
        avio_closep(&oc->pb);
        hls_append_segment(hls, hls->duration, hls->start_pos, hls->size);
    }
833 834 835 836 837 838 839

    if (vtt_oc) {
        if (vtt_oc->pb)
            av_write_trailer(vtt_oc);
        hls->size = avio_tell(hls->vtt_avf->pb) - hls->start_pos;
        avio_closep(&vtt_oc->pb);
    }
840
    av_freep(&hls->basename);
841
    avformat_free_context(oc);
842 843 844 845 846 847 848

    if (vtt_oc) {
        av_freep(&hls->vtt_basename);
        av_freep(&hls->vtt_m3u8_name);
        avformat_free_context(vtt_oc);
    }

849
    hls->avf = NULL;
850 851
    hls_window(s, 1);

852 853
    hls_free_segments(hls->segments);
    hls_free_segments(hls->old_segments);
854 855 856 857 858 859
    return 0;
}

#define OFFSET(x) offsetof(HLSContext, x)
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
860
    {"start_number",  "set first number in the sequence",        OFFSET(start_sequence),AV_OPT_TYPE_INT64,  {.i64 = 0},     0, INT64_MAX, E},
861
    {"hls_time",      "set segment length in seconds",           OFFSET(time),    AV_OPT_TYPE_FLOAT,  {.dbl = 2},     0, FLT_MAX, E},
862
    {"hls_list_size", "set maximum number of playlist entries",  OFFSET(max_nb_segments),    AV_OPT_TYPE_INT,    {.i64 = 5},     0, INT_MAX, E},
Steven Liu's avatar
Steven Liu committed
863
    {"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},
864
    {"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},
865
    {"hls_wrap",      "set number after which the index wraps",  OFFSET(wrap),    AV_OPT_TYPE_INT,    {.i64 = 0},     0, INT_MAX, E},
866
    {"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},
867
    {"hls_base_url",  "url to prepend to each playlist entry",   OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E},
868
    {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename),   AV_OPT_TYPE_STRING, {.str = NULL},            0,       0,         E},
869
    {"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},
870
    {"hls_subtitle_path",     "set path of hls subtitles", OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,    E},
871 872
    {"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"},
873
    {"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"},
874
    {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX,   E, "flags"},
875
    {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX,   E, "flags"},
876
    {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX,   E, "flags"},
877
    { "use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
878
    {"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,    E},
879

880 881 882 883 884 885 886 887 888 889 890 891 892
    { 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",
893
    .long_name      = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
894 895
    .extensions     = "m3u8",
    .priv_data_size = sizeof(HLSContext),
896 897
    .audio_codec    = AV_CODEC_ID_AAC,
    .video_codec    = AV_CODEC_ID_H264,
898
    .subtitle_codec = AV_CODEC_ID_WEBVTT,
899 900 901 902 903 904
    .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,
};