2 * Apple HTTP Live Streaming segmenter
3 * Copyright (c) 2012, Luca Barbato
4 * Copyright (c) 2017 Akamai Technologies, Inc.
6 * This file is part of FFmpeg.
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "config_components.h"
31 #include "libavutil/avassert.h"
32 #include "libavutil/mathematics.h"
33 #include "libavutil/avstring.h"
34 #include "libavutil/bprint.h"
35 #include "libavutil/intreadwrite.h"
36 #include "libavutil/mem.h"
37 #include "libavutil/opt.h"
38 #include "libavutil/log.h"
39 #include "libavutil/random_seed.h"
40 #include "libavutil/time.h"
41 #include "libavutil/time_internal.h"
43 #include "libavcodec/defs.h"
46 #include "avio_internal.h"
47 #if CONFIG_HTTP_PROTOCOL
50 #include "hlsplaylist.h"
53 #include "os_support.h"
57 HLS_START_SEQUENCE_AS_START_NUMBER
= 0,
58 HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH
= 1,
59 HLS_START_SEQUENCE_AS_FORMATTED_DATETIME
= 2, // YYYYMMDDhhmmss
60 HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH
= 3,
61 HLS_START_SEQUENCE_LAST
, // unused
62 } StartSequenceSourceType
;
65 CODEC_ATTRIBUTE_WRITTEN
= 0,
66 CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN
,
67 } CodecAttributeStatus
;
70 #define LINE_BUFFER_SIZE MAX_URL_SIZE
71 #define HLS_MICROSECOND_UNIT 1000000
72 #define BUFSIZE (16 * 1024)
73 #define POSTFIX_PATTERN "_%d"
75 typedef struct HLSSegment
{
76 char filename
[MAX_URL_SIZE
];
77 char sub_filename
[MAX_URL_SIZE
];
78 double duration
; /* in seconds */
83 int64_t keyframe_size
;
84 unsigned var_stream_idx
;
86 char key_uri
[LINE_BUFFER_SIZE
+ 1];
87 char iv_string
[KEYSIZE
*2 + 1];
89 struct HLSSegment
*next
;
90 double discont_program_date_time
;
93 typedef enum HLSFlags
{
94 // Generate a single media file and use byte ranges in the playlist.
95 HLS_SINGLE_FILE
= (1 << 0),
96 HLS_DELETE_SEGMENTS
= (1 << 1),
97 HLS_ROUND_DURATIONS
= (1 << 2),
98 HLS_DISCONT_START
= (1 << 3),
99 HLS_OMIT_ENDLIST
= (1 << 4),
100 HLS_SPLIT_BY_TIME
= (1 << 5),
101 HLS_APPEND_LIST
= (1 << 6),
102 HLS_PROGRAM_DATE_TIME
= (1 << 7),
103 HLS_SECOND_LEVEL_SEGMENT_INDEX
= (1 << 8), // include segment index in segment filenames when use_localtime e.g.: %%03d
104 HLS_SECOND_LEVEL_SEGMENT_DURATION
= (1 << 9), // include segment duration (microsec) in segment filenames when use_localtime e.g.: %%09t
105 HLS_SECOND_LEVEL_SEGMENT_SIZE
= (1 << 10), // include segment size (bytes) in segment filenames when use_localtime e.g.: %%014s
106 HLS_TEMP_FILE
= (1 << 11),
107 HLS_PERIODIC_REKEY
= (1 << 12),
108 HLS_INDEPENDENT_SEGMENTS
= (1 << 13),
109 HLS_I_FRAMES_ONLY
= (1 << 14),
117 typedef struct VariantStream
{
118 unsigned var_stream_idx
;
121 const AVOutputFormat
*oformat
;
122 const AVOutputFormat
*vtt_oformat
;
124 AVIOContext
*out_single_file
;
126 int init_range_length
;
127 uint8_t *temp_buffer
;
128 uint8_t *init_buffer
;
130 AVFormatContext
*avf
;
131 AVFormatContext
*vtt_avf
;
136 int start_pts_from_audio
;
137 double dpp
; // duration per packet
140 int64_t video_lastpos
;
141 int64_t video_keyframe_pos
;
142 int64_t video_keyframe_size
;
143 double duration
; // last segment duration computed so far, in seconds
144 int64_t start_pos
; // last segment starting position
145 int64_t size
; // last segment size
147 int discontinuity_set
;
149 int reference_stream_index
;
152 double total_duration
;
156 HLSSegment
*segments
;
157 HLSSegment
*last_segment
;
158 HLSSegment
*old_segments
;
166 double initial_prog_date_time
;
167 char current_segment_final_filename_fmt
[MAX_URL_SIZE
]; // when renaming segments
169 char *fmp4_init_filename
;
170 char *base_output_dirname
;
174 char key_file
[LINE_BUFFER_SIZE
+ 1];
175 char key_uri
[LINE_BUFFER_SIZE
+ 1];
176 char key_string
[KEYSIZE
*2 + 1];
177 char iv_string
[KEYSIZE
*2 + 1];
180 char codec_attr
[128];
181 CodecAttributeStatus attr_status
;
182 unsigned int nb_streams
;
183 int m3u8_created
; /* status of media play-list creation */
184 int is_default
; /* default status of audio group */
185 const char *language
; /* audio language name */
186 const char *agroup
; /* audio group name */
187 const char *sgroup
; /* subtitle group name */
188 const char *ccgroup
; /* closed caption group name */
189 const char *varname
; /* variant name */
190 const char *subtitle_varname
; /* subtitle variant name */
193 typedef struct ClosedCaptionsStream
{
194 const char *ccgroup
; /* closed caption group name */
195 const char *instreamid
; /* closed captions INSTREAM-ID */
196 const char *language
; /* closed captions language */
197 } ClosedCaptionsStream
;
199 typedef struct HLSContext
{
200 const AVClass
*class; // Class for private options.
201 int64_t start_sequence
;
202 uint32_t start_sequence_source_type
; // enum StartSequenceSourceType
204 int64_t time
; // Set by a private option.
205 int64_t init_time
; // Set by a private option.
206 int max_nb_segments
; // Set by a private option.
207 int hls_delete_threshold
; // Set by a private option.
208 uint32_t flags
; // enum HLSFlags
209 uint32_t pl_type
; // enum PlaylistType
210 char *segment_filename
;
211 char *fmp4_init_filename
;
213 int resend_init_file
; ///< resend init file into disk after refresh m3u8
215 int use_localtime
; ///< flag to expand filename with localtime
216 int use_localtime_mkdir
;///< flag to mkdir dirname in timebased filename
218 int64_t recording_time
;
219 int64_t max_seg_size
; // every segment file max size
222 char *vtt_format_options_str
;
223 char *subtitle_filename
;
224 AVDictionary
*format_options
;
234 char key_file
[LINE_BUFFER_SIZE
+ 1];
235 char key_uri
[LINE_BUFFER_SIZE
+ 1];
236 char key_string
[KEYSIZE
*2 + 1];
237 char iv_string
[KEYSIZE
*2 + 1];
238 AVDictionary
*vtt_format_options
;
243 VariantStream
*var_streams
;
244 unsigned int nb_varstreams
;
245 ClosedCaptionsStream
*cc_streams
;
246 unsigned int nb_ccstreams
;
248 int master_m3u8_created
; /* status of master play-list creation */
249 char *master_m3u8_url
; /* URL of the master m3u8 file */
250 int version
; /* HLS version */
251 char *var_stream_map
; /* user specified variant stream map string */
252 char *cc_stream_map
; /* user specified closed caption streams map string */
253 char *master_pl_name
;
254 unsigned int master_publish_rate
;
256 AVIOContext
*m3u8_out
;
257 AVIOContext
*sub_m3u8_out
;
258 AVIOContext
*http_delete
;
260 int ignore_io_errors
;
262 int has_default_key
; /* has DEFAULT field of var_stream_map */
263 int has_video_m3u8
; /* has video stream m3u8 list */
266 static int strftime_expand(const char *fmt
, char **dest
)
270 struct tm
*tm
, tmpbuf
;
273 buf
= av_mallocz(MAX_URL_SIZE
);
275 return AVERROR(ENOMEM
);
278 tm
= localtime_r(&now0
, &tmpbuf
);
279 r
= strftime(buf
, MAX_URL_SIZE
, fmt
, tm
);
282 return AVERROR(EINVAL
);
289 static int hlsenc_io_open(AVFormatContext
*s
, AVIOContext
**pb
, const char *filename
,
290 AVDictionary
**options
)
292 HLSContext
*hls
= s
->priv_data
;
293 int http_base_proto
= filename
? ff_is_http_proto(filename
) : 0;
294 int err
= AVERROR_MUXER_NOT_FOUND
;
295 if (!*pb
|| !http_base_proto
|| !hls
->http_persistent
) {
296 err
= s
->io_open(s
, pb
, filename
, AVIO_FLAG_WRITE
, options
);
297 #if CONFIG_HTTP_PROTOCOL
299 URLContext
*http_url_context
= ffio_geturlcontext(*pb
);
300 av_assert0(http_url_context
);
301 err
= ff_http_do_new_request(http_url_context
, filename
);
303 ff_format_io_close(s
, pb
);
310 static int hlsenc_io_close(AVFormatContext
*s
, AVIOContext
**pb
, char *filename
)
312 HLSContext
*hls
= s
->priv_data
;
313 int http_base_proto
= filename
? ff_is_http_proto(filename
) : 0;
317 if (!http_base_proto
|| !hls
->http_persistent
|| hls
->key_info_file
|| hls
->encrypt
) {
318 ff_format_io_close(s
, pb
);
319 #if CONFIG_HTTP_PROTOCOL
321 URLContext
*http_url_context
= ffio_geturlcontext(*pb
);
322 av_assert0(http_url_context
);
324 ret
= ffurl_shutdown(http_url_context
, AVIO_FLAG_WRITE
);
330 static void set_http_options(AVFormatContext
*s
, AVDictionary
**options
, HLSContext
*c
)
332 int http_base_proto
= ff_is_http_proto(s
->url
);
335 av_dict_set(options
, "method", c
->method
, 0);
336 } else if (http_base_proto
) {
337 av_dict_set(options
, "method", "PUT", 0);
340 av_dict_set(options
, "user_agent", c
->user_agent
, 0);
341 if (c
->http_persistent
)
342 av_dict_set_int(options
, "multiple_requests", 1, 0);
344 av_dict_set_int(options
, "timeout", c
->timeout
, 0);
346 av_dict_set(options
, "headers", c
->headers
, 0);
349 static void write_codec_attr(AVStream
*st
, VariantStream
*vs
)
351 int codec_strlen
= strlen(vs
->codec_attr
);
355 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_SUBTITLE
)
357 if (vs
->attr_status
== CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN
)
360 av_bprint_init_for_buffer(&buffer
, attr
, sizeof(attr
));
361 if (ff_make_codec_str(vs
->avf
, st
->codecpar
, &st
->avg_frame_rate
,
365 // Don't write the same attribute multiple times
366 if (!av_stristr(vs
->codec_attr
, attr
)) {
367 snprintf(vs
->codec_attr
+ codec_strlen
,
368 sizeof(vs
->codec_attr
) - codec_strlen
,
369 "%s%s", codec_strlen
? "," : "", attr
);
374 vs
->codec_attr
[0] = '\0';
375 vs
->attr_status
= CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN
;
379 static int replace_str_data_in_filename(char **s
, const char *filename
, char placeholder
, const char *datastring
)
388 av_bprint_init(&buf
, 0, AV_BPRINT_SIZE_UNLIMITED
);
395 if (c
== '%' && *(p
+1) == '%') // %%
397 else if (c
== '%' && *(p
+1) == placeholder
) {
398 av_bprintf(&buf
, "%s", datastring
);
405 if (addchar_count
> 0) {
406 av_bprint_append_data(&buf
, p
, addchar_count
);
410 if (!av_bprint_is_complete(&buf
)) {
411 av_bprint_finalize(&buf
, NULL
);
412 return AVERROR(ENOMEM
);
414 if ((ret
= av_bprint_finalize(&buf
, s
)) < 0)
419 static int replace_int_data_in_filename(char **s
, const char *filename
, char placeholder
, int64_t number
)
423 int nd
, addchar_count
;
428 av_bprint_init(&buf
, 0, AV_BPRINT_SIZE_UNLIMITED
);
435 if (c
== '%' && *(p
+1) == '%') // %%
437 else if (c
== '%' && (av_isdigit(*(p
+1)) || *(p
+1) == placeholder
)) {
440 while (av_isdigit(*(p
+ addchar_count
))) {
441 nd
= nd
* 10 + *(p
+ addchar_count
) - '0';
445 if (*(p
+ addchar_count
) == placeholder
) {
446 av_bprintf(&buf
, "%0*"PRId64
, (number
< 0) ? nd
: nd
++, number
);
447 p
+= (addchar_count
+ 1);
455 av_bprint_append_data(&buf
, p
, addchar_count
);
458 if (!av_bprint_is_complete(&buf
)) {
459 av_bprint_finalize(&buf
, NULL
);
460 return AVERROR(ENOMEM
);
462 if ((ret
= av_bprint_finalize(&buf
, s
)) < 0)
467 static void write_styp(AVIOContext
*pb
)
470 ffio_wfourcc(pb
, "styp");
471 ffio_wfourcc(pb
, "msdh");
472 avio_wb32(pb
, 0); /* minor */
473 ffio_wfourcc(pb
, "msdh");
474 ffio_wfourcc(pb
, "msix");
477 static int flush_dynbuf(VariantStream
*vs
, int *range_length
)
479 AVFormatContext
*ctx
= vs
->avf
;
482 return AVERROR(EINVAL
);
486 av_write_frame(ctx
, NULL
);
489 *range_length
= avio_close_dyn_buf(ctx
->pb
, &vs
->temp_buffer
);
491 avio_write(vs
->out
, vs
->temp_buffer
, *range_length
);
495 return avio_open_dyn_buf(&ctx
->pb
);
498 static void reflush_dynbuf(VariantStream
*vs
, int *range_length
)
501 avio_write(vs
->out
, vs
->temp_buffer
, *range_length
);
504 static int hls_delete_file(HLSContext
*hls
, AVFormatContext
*avf
,
505 char *path
, const char *proto
)
507 if (hls
->method
|| (proto
&& !av_strcasecmp(proto
, "http"))) {
508 AVDictionary
*opt
= NULL
;
511 set_http_options(avf
, &opt
, hls
);
512 av_dict_set(&opt
, "method", "DELETE", 0);
514 ret
= hlsenc_io_open(avf
, &hls
->http_delete
, path
, &opt
);
517 return hls
->ignore_io_errors
? 1 : ret
;
520 hlsenc_io_close(avf
, &hls
->http_delete
, path
);
521 } else if (unlink(path
) < 0) {
522 av_log(hls
, AV_LOG_ERROR
, "failed to delete old segment %s: %s\n",
523 path
, strerror(errno
));
528 static int hls_delete_old_segments(AVFormatContext
*s
, HLSContext
*hls
,
532 HLSSegment
*segment
, *previous_segment
= NULL
;
533 float playlist_duration
= 0.0f
;
537 const char *dirname
= NULL
;
538 char *dirname_r
= NULL
;
539 char *dirname_repl
= NULL
;
540 const char *vtt_dirname
= NULL
;
541 char *vtt_dirname_r
= NULL
;
542 const char *proto
= NULL
;
544 av_bprint_init(&path
, 0, AV_BPRINT_SIZE_UNLIMITED
);
546 segment
= vs
->segments
;
548 playlist_duration
+= segment
->duration
;
549 segment
= segment
->next
;
552 segment
= vs
->old_segments
;
555 playlist_duration
-= segment
->duration
;
556 previous_segment
= segment
;
557 segment
= previous_segment
->next
;
559 if (playlist_duration
<= -previous_segment
->duration
) {
560 previous_segment
->next
= NULL
;
563 if (segment_cnt
>= hls
->hls_delete_threshold
) {
564 previous_segment
->next
= NULL
;
569 if (segment
&& !hls
->use_localtime_mkdir
) {
570 dirname_r
= hls
->segment_filename
? av_strdup(hls
->segment_filename
): av_strdup(vs
->avf
->url
);
571 dirname
= av_dirname(dirname_r
);
574 /* if %v is present in the file's directory
575 * all segment belongs to the same variant, so do it only once before the loop*/
576 if (dirname
&& av_stristr(dirname
, "%v")) {
578 if (replace_int_data_in_filename(&dirname_repl
, dirname
, 'v', segment
->var_stream_idx
) < 1) {
579 ret
= AVERROR(EINVAL
);
583 if (replace_str_data_in_filename(&dirname_repl
, dirname
, 'v', vs
->varname
) < 1) {
584 ret
= AVERROR(EINVAL
);
589 dirname
= dirname_repl
;
593 av_log(hls
, AV_LOG_DEBUG
, "deleting old segment %s\n",
595 if (!hls
->use_localtime_mkdir
) // segment->filename contains basename only
596 av_bprintf(&path
, "%s/", dirname
);
597 av_bprintf(&path
, "%s", segment
->filename
);
599 if (!av_bprint_is_complete(&path
)) {
600 ret
= AVERROR(ENOMEM
);
604 proto
= avio_find_protocol_name(s
->url
);
605 if (ret
= hls_delete_file(hls
, s
, path
.str
, proto
))
608 if ((segment
->sub_filename
[0] != '\0')) {
609 vtt_dirname_r
= av_strdup(vs
->vtt_avf
->url
);
610 vtt_dirname
= av_dirname(vtt_dirname_r
);
612 av_bprint_clear(&path
);
613 av_bprintf(&path
, "%s/%s", vtt_dirname
, segment
->sub_filename
);
614 av_freep(&vtt_dirname_r
);
616 if (!av_bprint_is_complete(&path
)) {
617 ret
= AVERROR(ENOMEM
);
621 if (ret
= hls_delete_file(hls
, s
, path
.str
, proto
))
624 av_bprint_clear(&path
);
625 previous_segment
= segment
;
626 segment
= previous_segment
->next
;
627 av_freep(&previous_segment
);
631 av_bprint_finalize(&path
, NULL
);
632 av_freep(&dirname_r
);
633 av_freep(&dirname_repl
);
638 static int do_encrypt(AVFormatContext
*s
, VariantStream
*vs
)
640 HLSContext
*hls
= s
->priv_data
;
644 uint8_t key
[KEYSIZE
];
645 char * key_basename_source
= (hls
->master_m3u8_url
) ? hls
->master_m3u8_url
: s
->url
;
647 len
= strlen(key_basename_source
) + 4 + 1;
648 hls
->key_basename
= av_mallocz(len
);
649 if (!hls
->key_basename
)
650 return AVERROR(ENOMEM
);
652 av_strlcpy(hls
->key_basename
, key_basename_source
, len
);
653 av_strlcat(hls
->key_basename
, ".key", len
);
656 av_strlcpy(hls
->key_file
, hls
->key_url
, sizeof(hls
->key_file
));
657 av_strlcpy(hls
->key_uri
, hls
->key_url
, sizeof(hls
->key_uri
));
659 av_strlcpy(hls
->key_file
, hls
->key_basename
, sizeof(hls
->key_file
));
660 av_strlcpy(hls
->key_uri
, hls
->key_basename
, sizeof(hls
->key_uri
));
663 if (!*hls
->iv_string
) {
664 uint8_t iv
[16] = { 0 };
668 AV_WB64(iv
+ 8, vs
->sequence
);
670 memcpy(iv
, hls
->iv
, sizeof(iv
));
672 ff_data_to_hex(buf
, iv
, sizeof(iv
), 0);
673 memcpy(hls
->iv_string
, buf
, sizeof(hls
->iv_string
));
676 if (!*hls
->key_uri
) {
677 av_log(hls
, AV_LOG_ERROR
, "no key URI specified in key info file\n");
678 return AVERROR(EINVAL
);
681 if (!*hls
->key_file
) {
682 av_log(hls
, AV_LOG_ERROR
, "no key file specified in key info file\n");
683 return AVERROR(EINVAL
);
686 if (!*hls
->key_string
) {
687 AVDictionary
*options
= NULL
;
689 if ((ret
= av_random_bytes(key
, sizeof(key
))) < 0) {
690 av_log(s
, AV_LOG_ERROR
, "Cannot generate a strong random key\n");
694 memcpy(key
, hls
->key
, sizeof(key
));
697 ff_data_to_hex(hls
->key_string
, key
, sizeof(key
), 0);
698 set_http_options(s
, &options
, hls
);
699 ret
= s
->io_open(s
, &pb
, hls
->key_file
, AVIO_FLAG_WRITE
, &options
);
700 av_dict_free(&options
);
703 avio_seek(pb
, 0, SEEK_CUR
);
704 avio_write(pb
, key
, KEYSIZE
);
711 static int hls_encryption_start(AVFormatContext
*s
, VariantStream
*vs
)
713 HLSContext
*hls
= s
->priv_data
;
716 uint8_t key
[KEYSIZE
];
717 AVDictionary
*options
= NULL
;
719 set_http_options(s
, &options
, hls
);
720 ret
= s
->io_open(s
, &pb
, hls
->key_info_file
, AVIO_FLAG_READ
, &options
);
721 av_dict_free(&options
);
723 av_log(hls
, AV_LOG_ERROR
,
724 "error opening key info file %s\n", hls
->key_info_file
);
728 ff_get_line(pb
, vs
->key_uri
, sizeof(vs
->key_uri
));
729 vs
->key_uri
[strcspn(vs
->key_uri
, "\r\n")] = '\0';
731 ff_get_line(pb
, vs
->key_file
, sizeof(vs
->key_file
));
732 vs
->key_file
[strcspn(vs
->key_file
, "\r\n")] = '\0';
734 ff_get_line(pb
, vs
->iv_string
, sizeof(vs
->iv_string
));
735 vs
->iv_string
[strcspn(vs
->iv_string
, "\r\n")] = '\0';
737 ff_format_io_close(s
, &pb
);
740 av_log(hls
, AV_LOG_ERROR
, "no key URI specified in key info file\n");
741 return AVERROR(EINVAL
);
744 if (!*vs
->key_file
) {
745 av_log(hls
, AV_LOG_ERROR
, "no key file specified in key info file\n");
746 return AVERROR(EINVAL
);
749 set_http_options(s
, &options
, hls
);
750 ret
= s
->io_open(s
, &pb
, vs
->key_file
, AVIO_FLAG_READ
, &options
);
751 av_dict_free(&options
);
753 av_log(hls
, AV_LOG_ERROR
, "error opening key file %s\n", vs
->key_file
);
757 ret
= avio_read(pb
, key
, sizeof(key
));
758 ff_format_io_close(s
, &pb
);
759 if (ret
!= sizeof(key
)) {
760 av_log(hls
, AV_LOG_ERROR
, "error reading key file %s\n", vs
->key_file
);
761 if (ret
>= 0 || ret
== AVERROR_EOF
)
762 ret
= AVERROR(EINVAL
);
765 ff_data_to_hex(vs
->key_string
, key
, sizeof(key
), 0);
770 static int hls_mux_init(AVFormatContext
*s
, VariantStream
*vs
)
772 AVDictionary
*options
= NULL
;
773 HLSContext
*hls
= s
->priv_data
;
775 AVFormatContext
*vtt_oc
= NULL
;
776 int byterange_mode
= (hls
->flags
& HLS_SINGLE_FILE
) || (hls
->max_seg_size
> 0);
777 int remaining_options
;
780 ret
= avformat_alloc_output_context2(&vs
->avf
, vs
->oformat
, NULL
, NULL
);
785 oc
->url
= av_strdup("");
787 return AVERROR(ENOMEM
);
789 oc
->interrupt_callback
= s
->interrupt_callback
;
790 oc
->max_delay
= s
->max_delay
;
791 oc
->opaque
= s
->opaque
;
792 oc
->io_open
= s
->io_open
;
793 oc
->io_close2
= s
->io_close2
;
794 oc
->strict_std_compliance
= s
->strict_std_compliance
;
795 av_dict_copy(&oc
->metadata
, s
->metadata
, 0);
797 if (vs
->vtt_oformat
) {
798 ret
= avformat_alloc_output_context2(&vs
->vtt_avf
, vs
->vtt_oformat
, NULL
, NULL
);
801 vtt_oc
= vs
->vtt_avf
;
802 av_dict_copy(&vtt_oc
->metadata
, s
->metadata
, 0);
805 for (i
= 0; i
< vs
->nb_streams
; i
++) {
807 AVFormatContext
*loc
;
808 if (vs
->streams
[i
]->codecpar
->codec_type
== AVMEDIA_TYPE_SUBTITLE
)
813 if (!(st
= avformat_new_stream(loc
, NULL
)))
814 return AVERROR(ENOMEM
);
815 ret
= avcodec_parameters_copy(st
->codecpar
, vs
->streams
[i
]->codecpar
);
818 if (!oc
->oformat
->codec_tag
||
819 av_codec_get_id (oc
->oformat
->codec_tag
, vs
->streams
[i
]->codecpar
->codec_tag
) == st
->codecpar
->codec_id
||
820 av_codec_get_tag(oc
->oformat
->codec_tag
, vs
->streams
[i
]->codecpar
->codec_id
) <= 0) {
821 st
->codecpar
->codec_tag
= vs
->streams
[i
]->codecpar
->codec_tag
;
823 st
->codecpar
->codec_tag
= 0;
826 st
->sample_aspect_ratio
= vs
->streams
[i
]->sample_aspect_ratio
;
827 st
->time_base
= vs
->streams
[i
]->time_base
;
828 av_dict_copy(&st
->metadata
, vs
->streams
[i
]->metadata
, 0);
829 st
->id
= vs
->streams
[i
]->id
;
835 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
&& hls
->max_seg_size
> 0) {
836 if (hls
->http_persistent
> 0) {
837 //TODO: Support fragment fmp4 for http persistent in HLS muxer.
838 av_log(s
, AV_LOG_WARNING
, "http persistent mode is currently unsupported for fragment mp4 in the HLS muxer.\n");
840 if (hls
->max_seg_size
> 0) {
841 av_log(s
, AV_LOG_WARNING
, "Multi-file byterange mode is currently unsupported in the HLS muxer.\n");
842 return AVERROR_PATCHWELCOME
;
846 if ((ret
= avio_open_dyn_buf(&oc
->pb
)) < 0)
849 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
850 set_http_options(s
, &options
, hls
);
851 if (byterange_mode
) {
852 ret
= hlsenc_io_open(s
, &vs
->out
, vs
->basename
, &options
);
854 ret
= hlsenc_io_open(s
, &vs
->out
, vs
->base_output_dirname
, &options
);
856 av_dict_free(&options
);
859 av_log(s
, AV_LOG_ERROR
, "Failed to open segment '%s'\n", vs
->fmp4_init_filename
);
863 av_dict_copy(&options
, hls
->format_options
, 0);
864 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
865 av_dict_set(&options
, "fflags", "-autobsf", 0);
866 av_dict_set(&options
, "movflags", "+frag_custom+dash+delay_moov", AV_DICT_APPEND
);
868 /* We only require one PAT/PMT per segment. */
870 snprintf(period
, sizeof(period
), "%d", (INT_MAX
/ 2) - 1);
871 av_dict_set(&options
, "sdt_period", period
, AV_DICT_DONT_OVERWRITE
);
872 av_dict_set(&options
, "pat_period", period
, AV_DICT_DONT_OVERWRITE
);
874 ret
= avformat_init_output(oc
, &options
);
875 remaining_options
= av_dict_count(options
);
876 av_dict_free(&options
);
879 if (remaining_options
) {
880 av_log(s
, AV_LOG_ERROR
, "Some of the provided format options are not recognized\n");
881 return AVERROR(EINVAL
);
887 static HLSSegment
*find_segment_by_filename(HLSSegment
*segment
, const char *filename
)
890 if (!av_strcasecmp(segment
->filename
,filename
))
892 segment
= segment
->next
;
894 return (HLSSegment
*) NULL
;
897 static int sls_flags_filename_process(struct AVFormatContext
*s
, HLSContext
*hls
,
898 VariantStream
*vs
, HLSSegment
*en
,
899 double duration
, int64_t pos
, int64_t size
)
901 if ((hls
->flags
& (HLS_SECOND_LEVEL_SEGMENT_SIZE
| HLS_SECOND_LEVEL_SEGMENT_DURATION
)) &&
902 strlen(vs
->current_segment_final_filename_fmt
)) {
903 char * new_url
= av_strdup(vs
->current_segment_final_filename_fmt
);
905 return AVERROR(ENOMEM
);
907 ff_format_set_url(vs
->avf
, new_url
);
908 if (hls
->flags
& HLS_SECOND_LEVEL_SEGMENT_SIZE
) {
909 char *filename
= NULL
;
910 if (replace_int_data_in_filename(&filename
, vs
->avf
->url
, 's', pos
+ size
) < 1) {
911 av_log(hls
, AV_LOG_ERROR
,
912 "Invalid second level segment filename template '%s', "
913 "you can try to remove second_level_segment_size flag\n",
916 return AVERROR(EINVAL
);
918 ff_format_set_url(vs
->avf
, filename
);
920 if (hls
->flags
& HLS_SECOND_LEVEL_SEGMENT_DURATION
) {
921 char *filename
= NULL
;
922 if (replace_int_data_in_filename(&filename
, vs
->avf
->url
,
923 't', (int64_t)round(duration
* HLS_MICROSECOND_UNIT
)) < 1) {
924 av_log(hls
, AV_LOG_ERROR
,
925 "Invalid second level segment filename template '%s', "
926 "you can try to remove second_level_segment_duration flag\n",
929 return AVERROR(EINVAL
);
931 ff_format_set_url(vs
->avf
, filename
);
937 static int sls_flag_check_duration_size_index(HLSContext
*hls
)
941 if (hls
->flags
& HLS_SECOND_LEVEL_SEGMENT_DURATION
) {
942 av_log(hls
, AV_LOG_ERROR
,
943 "second_level_segment_duration hls_flag requires strftime to be true\n");
944 ret
= AVERROR(EINVAL
);
946 if (hls
->flags
& HLS_SECOND_LEVEL_SEGMENT_SIZE
) {
947 av_log(hls
, AV_LOG_ERROR
,
948 "second_level_segment_size hls_flag requires strfime to be true\n");
949 ret
= AVERROR(EINVAL
);
951 if (hls
->flags
& HLS_SECOND_LEVEL_SEGMENT_INDEX
) {
952 av_log(hls
, AV_LOG_ERROR
,
953 "second_level_segment_index hls_flag requires strftime to be true\n");
954 ret
= AVERROR(EINVAL
);
960 static int sls_flag_check_duration_size(HLSContext
*hls
, VariantStream
*vs
)
962 const char *proto
= avio_find_protocol_name(vs
->basename
);
963 int segment_renaming_ok
= proto
&& !strcmp(proto
, "file");
966 if ((hls
->flags
& HLS_SECOND_LEVEL_SEGMENT_DURATION
) && !segment_renaming_ok
) {
967 av_log(hls
, AV_LOG_ERROR
,
968 "second_level_segment_duration hls_flag works only with file protocol segment names\n");
969 ret
= AVERROR(EINVAL
);
971 if ((hls
->flags
& HLS_SECOND_LEVEL_SEGMENT_SIZE
) && !segment_renaming_ok
) {
972 av_log(hls
, AV_LOG_ERROR
,
973 "second_level_segment_size hls_flag works only with file protocol segment names\n");
974 ret
= AVERROR(EINVAL
);
980 static void sls_flag_file_rename(HLSContext
*hls
, VariantStream
*vs
, char *old_filename
) {
981 if ((hls
->flags
& (HLS_SECOND_LEVEL_SEGMENT_SIZE
| HLS_SECOND_LEVEL_SEGMENT_DURATION
)) &&
982 strlen(vs
->current_segment_final_filename_fmt
)) {
983 ff_rename(old_filename
, vs
->avf
->url
, hls
);
987 static int sls_flag_use_localtime_filename(AVFormatContext
*oc
, HLSContext
*c
, VariantStream
*vs
)
989 if (c
->flags
& HLS_SECOND_LEVEL_SEGMENT_INDEX
) {
990 char *filename
= NULL
;
991 if (replace_int_data_in_filename(&filename
,
992 oc
->url
, 'd', vs
->sequence
) < 1) {
993 av_log(c
, AV_LOG_ERROR
, "Invalid second level segment filename template '%s', "
994 "you can try to remove second_level_segment_index flag\n",
997 return AVERROR(EINVAL
);
999 ff_format_set_url(oc
, filename
);
1001 if (c
->flags
& (HLS_SECOND_LEVEL_SEGMENT_SIZE
| HLS_SECOND_LEVEL_SEGMENT_DURATION
)) {
1002 av_strlcpy(vs
->current_segment_final_filename_fmt
, oc
->url
,
1003 sizeof(vs
->current_segment_final_filename_fmt
));
1004 if (c
->flags
& HLS_SECOND_LEVEL_SEGMENT_SIZE
) {
1005 char *filename
= NULL
;
1006 if (replace_int_data_in_filename(&filename
, oc
->url
, 's', 0) < 1) {
1007 av_log(c
, AV_LOG_ERROR
, "Invalid second level segment filename template '%s', "
1008 "you can try to remove second_level_segment_size flag\n",
1010 av_freep(&filename
);
1011 return AVERROR(EINVAL
);
1013 ff_format_set_url(oc
, filename
);
1015 if (c
->flags
& HLS_SECOND_LEVEL_SEGMENT_DURATION
) {
1016 char *filename
= NULL
;
1017 if (replace_int_data_in_filename(&filename
, oc
->url
, 't', 0) < 1) {
1018 av_log(c
, AV_LOG_ERROR
, "Invalid second level segment filename template '%s', "
1019 "you can try to remove second_level_segment_duration flag\n",
1021 av_freep(&filename
);
1022 return AVERROR(EINVAL
);
1024 ff_format_set_url(oc
, filename
);
1030 /* Create a new segment and append it to the segment list */
1031 static int hls_append_segment(struct AVFormatContext
*s
, HLSContext
*hls
,
1032 VariantStream
*vs
, double duration
, int64_t pos
,
1035 HLSSegment
*en
= av_malloc(sizeof(*en
));
1036 const char *filename
;
1037 int byterange_mode
= (hls
->flags
& HLS_SINGLE_FILE
) || (hls
->max_seg_size
> 0);
1041 return AVERROR(ENOMEM
);
1043 vs
->total_size
+= size
;
1044 vs
->total_duration
+= duration
;
1045 if (duration
> 0.5) {
1046 // Don't include the final, possibly very short segment in the
1047 // calculation of the max bitrate.
1048 int cur_bitrate
= (int)(8 * size
/ duration
);
1049 if (cur_bitrate
> vs
->max_bitrate
)
1050 vs
->max_bitrate
= cur_bitrate
;
1052 if (vs
->total_duration
> 0)
1053 vs
->avg_bitrate
= (int)(8 * vs
->total_size
/ vs
->total_duration
);
1055 en
->var_stream_idx
= vs
->var_stream_idx
;
1056 ret
= sls_flags_filename_process(s
, hls
, vs
, en
, duration
, pos
, size
);
1062 filename
= av_basename(vs
->avf
->url
);
1064 if (hls
->use_localtime_mkdir
) {
1065 filename
= vs
->avf
->url
;
1067 if (vs
->nb_entries
<= 5000 && (find_segment_by_filename(vs
->segments
, filename
) || find_segment_by_filename(vs
->old_segments
, filename
))
1068 && !byterange_mode
) {
1069 av_log(hls
, AV_LOG_WARNING
, "Duplicated segment filename detected: %s\n", filename
);
1071 av_strlcpy(en
->filename
, filename
, sizeof(en
->filename
));
1073 if (vs
->has_subtitle
)
1074 av_strlcpy(en
->sub_filename
, av_basename(vs
->vtt_avf
->url
), sizeof(en
->sub_filename
));
1076 en
->sub_filename
[0] = '\0';
1078 en
->duration
= duration
;
1081 en
->keyframe_pos
= vs
->video_keyframe_pos
;
1082 en
->keyframe_size
= vs
->video_keyframe_size
;
1085 en
->discont_program_date_time
= 0;
1087 if (vs
->discontinuity
) {
1089 vs
->discontinuity
= 0;
1092 if (hls
->key_info_file
|| hls
->encrypt
) {
1093 av_strlcpy(en
->key_uri
, vs
->key_uri
, sizeof(en
->key_uri
));
1094 av_strlcpy(en
->iv_string
, vs
->iv_string
, sizeof(en
->iv_string
));
1100 vs
->last_segment
->next
= en
;
1102 vs
->last_segment
= en
;
1104 // EVENT or VOD playlists imply sliding window cannot be used
1105 if (hls
->pl_type
!= PLAYLIST_TYPE_NONE
)
1106 hls
->max_nb_segments
= 0;
1108 if (hls
->max_nb_segments
&& vs
->nb_entries
>= hls
->max_nb_segments
) {
1110 if (!en
->next
->discont_program_date_time
&& !en
->discont_program_date_time
)
1111 vs
->initial_prog_date_time
+= en
->duration
;
1112 vs
->segments
= en
->next
;
1113 if (en
&& hls
->flags
& HLS_DELETE_SEGMENTS
&&
1114 !(hls
->flags
& HLS_SINGLE_FILE
)) {
1115 en
->next
= vs
->old_segments
;
1116 vs
->old_segments
= en
;
1117 if ((ret
= hls_delete_old_segments(s
, hls
, vs
)) < 0)
1124 if (hls
->max_seg_size
> 0) {
1132 static int extract_segment_number(const char *filename
) {
1133 const char *dot
= strrchr(filename
, '.');
1134 const char *num_start
= dot
- 1;
1136 while (num_start
> filename
&& *num_start
>= '0' && *num_start
<= '9') {
1142 if (num_start
== dot
)
1145 return atoi(num_start
);
1148 static int parse_playlist(AVFormatContext
*s
, const char *url
, VariantStream
*vs
)
1150 HLSContext
*hls
= s
->priv_data
;
1152 int ret
= 0, is_segment
= 0;
1153 int64_t new_start_pos
;
1154 char line
[MAX_URL_SIZE
];
1157 double discont_program_date_time
= 0;
1159 if ((ret
= ffio_open_whitelist(&in
, url
, AVIO_FLAG_READ
,
1160 &s
->interrupt_callback
, NULL
,
1161 s
->protocol_whitelist
, s
->protocol_blacklist
)) < 0)
1164 ff_get_chomp_line(in
, line
, sizeof(line
));
1165 if (strcmp(line
, "#EXTM3U")) {
1166 ret
= AVERROR_INVALIDDATA
;
1170 vs
->discontinuity
= 0;
1171 while (!avio_feof(in
)) {
1172 ff_get_chomp_line(in
, line
, sizeof(line
));
1173 if (av_strstart(line
, "#EXT-X-MEDIA-SEQUENCE:", &ptr
)) {
1174 int64_t tmp_sequence
= strtoll(ptr
, NULL
, 10);
1175 if (tmp_sequence
< vs
->sequence
)
1176 av_log(hls
, AV_LOG_VERBOSE
,
1177 "Found playlist sequence number was smaller """
1178 "than specified start sequence number: %"PRId64
" < %"PRId64
", "
1179 "omitting\n", tmp_sequence
, hls
->start_sequence
);
1181 av_log(hls
, AV_LOG_DEBUG
, "Found playlist sequence number: %"PRId64
"\n", tmp_sequence
);
1182 vs
->sequence
= tmp_sequence
;
1184 } else if (av_strstart(line
, "#EXT-X-DISCONTINUITY", &ptr
)) {
1186 vs
->discontinuity
= 1;
1187 } else if (av_strstart(line
, "#EXTINF:", &ptr
)) {
1189 vs
->duration
= atof(ptr
);
1190 } else if (av_stristart(line
, "#EXT-X-KEY:", &ptr
)) {
1191 ptr
= av_stristr(line
, "URI=\"");
1193 ptr
+= strlen("URI=\"");
1194 end
= av_stristr(ptr
, ",");
1196 av_strlcpy(vs
->key_uri
, ptr
, end
- ptr
);
1198 av_strlcpy(vs
->key_uri
, ptr
, sizeof(vs
->key_uri
));
1202 ptr
= av_stristr(line
, "IV=0x");
1204 ptr
+= strlen("IV=0x");
1205 end
= av_stristr(ptr
, ",");
1207 av_strlcpy(vs
->iv_string
, ptr
, end
- ptr
);
1209 av_strlcpy(vs
->iv_string
, ptr
, sizeof(vs
->iv_string
));
1212 } else if (av_strstart(line
, "#EXT-X-PROGRAM-DATE-TIME:", &ptr
)) {
1213 struct tm program_date_time
;
1216 if (sscanf(ptr
, "%d-%d-%dT%d:%d:%d.%lf", &y
, &M
, &d
, &h
, &m
, &s
, &ms
) != 7) {
1217 ret
= AVERROR_INVALIDDATA
;
1221 program_date_time
.tm_year
= y
- 1900;
1222 program_date_time
.tm_mon
= M
- 1;
1223 program_date_time
.tm_mday
= d
;
1224 program_date_time
.tm_hour
= h
;
1225 program_date_time
.tm_min
= m
;
1226 program_date_time
.tm_sec
= s
;
1227 program_date_time
.tm_isdst
= -1;
1229 discont_program_date_time
= mktime(&program_date_time
);
1230 discont_program_date_time
+= (double)(ms
/ 1000);
1231 } else if (av_strstart(line
, "#", NULL
)) {
1233 } else if (line
[0]) {
1235 char *new_file
= av_strdup(line
);
1237 ret
= AVERROR(ENOMEM
);
1240 ff_format_set_url(vs
->avf
, new_file
);
1242 if (vs
->has_subtitle
) {
1243 int vtt_index
= extract_segment_number(line
);
1244 const char *vtt_basename
= av_basename(vs
->vtt_basename
);
1245 int len
= strlen(vtt_basename
) + 11;
1246 char *vtt_file
= av_mallocz(len
);
1248 ret
= AVERROR(ENOMEM
);
1251 snprintf(vtt_file
, len
, vtt_basename
, vtt_index
);
1252 ff_format_set_url(vs
->vtt_avf
, vtt_file
);
1256 new_start_pos
= avio_tell(vs
->avf
->pb
);
1257 vs
->size
= new_start_pos
- vs
->start_pos
;
1258 ret
= hls_append_segment(s
, hls
, vs
, vs
->duration
, vs
->start_pos
, vs
->size
);
1259 if (discont_program_date_time
) {
1260 vs
->last_segment
->discont_program_date_time
= discont_program_date_time
;
1261 discont_program_date_time
+= vs
->duration
;
1265 vs
->start_pos
= new_start_pos
;
1275 static void hls_free_segments(HLSSegment
*p
)
1286 static int hls_rename_temp_file(AVFormatContext
*s
, AVFormatContext
*oc
)
1288 size_t len
= strlen(oc
->url
);
1289 char *final_filename
= av_strdup(oc
->url
);
1292 if (!final_filename
)
1293 return AVERROR(ENOMEM
);
1294 final_filename
[len
-4] = '\0';
1295 ret
= ff_rename(oc
->url
, final_filename
, s
);
1296 oc
->url
[len
-4] = '\0';
1297 av_freep(&final_filename
);
1301 static const char* get_relative_url(const char *master_url
, const char *media_url
)
1303 const char *p
= strrchr(master_url
, '/');
1304 size_t base_len
= 0;
1306 if (!p
) p
= strrchr(master_url
, '\\');
1309 base_len
= p
- master_url
;
1310 if (av_strncasecmp(master_url
, media_url
, base_len
)) {
1311 av_log(NULL
, AV_LOG_WARNING
, "Unable to find relative url\n");
1318 return media_url
+ base_len
+ 1;
1321 static int64_t get_stream_bit_rate(AVStream
*stream
)
1323 const AVPacketSideData
*sd
= av_packet_side_data_get(
1324 stream
->codecpar
->coded_side_data
, stream
->codecpar
->nb_coded_side_data
,
1325 AV_PKT_DATA_CPB_PROPERTIES
1328 if (stream
->codecpar
->bit_rate
)
1329 return stream
->codecpar
->bit_rate
;
1331 AVCPBProperties
*props
= (AVCPBProperties
*)sd
->data
;
1332 return props
->max_bitrate
;
1338 static int create_master_playlist(AVFormatContext
*s
,
1339 VariantStream
* const input_vs
,
1342 HLSContext
*hls
= s
->priv_data
;
1343 VariantStream
*vs
, *temp_vs
;
1344 AVStream
*vid_st
, *aud_st
;
1345 AVDictionary
*options
= NULL
;
1347 int ret
, bandwidth
, avg_bandwidth
;
1348 const char *m3u8_rel_name
= NULL
;
1349 const char *vtt_m3u8_rel_name
= NULL
;
1350 const char *ccgroup
;
1351 const char *sgroup
= NULL
;
1352 ClosedCaptionsStream
*ccs
;
1353 const char *proto
= avio_find_protocol_name(hls
->master_m3u8_url
);
1354 int is_file_proto
= proto
&& !strcmp(proto
, "file");
1355 int use_temp_file
= is_file_proto
&& ((hls
->flags
& HLS_TEMP_FILE
) || hls
->master_publish_rate
);
1356 char temp_filename
[MAX_URL_SIZE
];
1359 input_vs
->m3u8_created
= 1;
1360 if (!hls
->master_m3u8_created
) {
1361 /* For the first time, wait until all the media playlists are created */
1362 for (i
= 0; i
< hls
->nb_varstreams
; i
++)
1363 if (!hls
->var_streams
[i
].m3u8_created
)
1366 /* Keep publishing the master playlist at the configured rate */
1367 if ((&hls
->var_streams
[0] != input_vs
|| !hls
->master_publish_rate
||
1368 input_vs
->number
% hls
->master_publish_rate
) && !final
)
1372 set_http_options(s
, &options
, hls
);
1373 snprintf(temp_filename
, sizeof(temp_filename
), use_temp_file
? "%s.tmp" : "%s", hls
->master_m3u8_url
);
1374 ret
= hlsenc_io_open(s
, &hls
->m3u8_out
, temp_filename
, &options
);
1375 av_dict_free(&options
);
1377 av_log(s
, AV_LOG_ERROR
, "Failed to open master play list file '%s'\n",
1382 ff_hls_write_playlist_version(hls
->m3u8_out
, hls
->version
);
1384 for (i
= 0; i
< hls
->nb_ccstreams
; i
++) {
1385 ccs
= &(hls
->cc_streams
[i
]);
1386 avio_printf(hls
->m3u8_out
, "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS");
1387 avio_printf(hls
->m3u8_out
, ",GROUP-ID=\"%s\"", ccs
->ccgroup
);
1388 avio_printf(hls
->m3u8_out
, ",NAME=\"%s\"", ccs
->instreamid
);
1390 avio_printf(hls
->m3u8_out
, ",LANGUAGE=\"%s\"", ccs
->language
);
1391 avio_printf(hls
->m3u8_out
, ",INSTREAM-ID=\"%s\"\n", ccs
->instreamid
);
1394 /* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/
1395 for (i
= 0; i
< hls
->nb_varstreams
; i
++) {
1396 vs
= &(hls
->var_streams
[i
]);
1398 if (vs
->has_video
|| vs
->has_subtitle
|| !vs
->agroup
)
1401 m3u8_rel_name
= get_relative_url(hls
->master_m3u8_url
, vs
->m3u8_name
);
1402 if (!m3u8_rel_name
) {
1403 av_log(s
, AV_LOG_ERROR
, "Unable to find relative URL\n");
1407 for (j
= 0; j
< vs
->nb_streams
; j
++)
1408 if (vs
->streams
[j
]->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
)
1409 if (vs
->streams
[j
]->codecpar
->ch_layout
.nb_channels
> nb_channels
)
1410 nb_channels
= vs
->streams
[j
]->codecpar
->ch_layout
.nb_channels
;
1412 ff_hls_write_audio_rendition(hls
->m3u8_out
, vs
->agroup
, m3u8_rel_name
, vs
->language
, i
, hls
->has_default_key
? vs
->is_default
: 1, nb_channels
);
1415 /* For variant streams with video add #EXT-X-STREAM-INF tag with attributes*/
1416 for (i
= 0; i
< hls
->nb_varstreams
; i
++) {
1417 vs
= &(hls
->var_streams
[i
]);
1419 m3u8_rel_name
= get_relative_url(hls
->master_m3u8_url
, vs
->m3u8_name
);
1420 if (!m3u8_rel_name
) {
1421 av_log(s
, AV_LOG_ERROR
, "Unable to find relative URL\n");
1427 for (j
= 0; j
< vs
->nb_streams
; j
++) {
1428 if (vs
->streams
[j
]->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
)
1429 vid_st
= vs
->streams
[j
];
1430 else if (vs
->streams
[j
]->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
)
1431 aud_st
= vs
->streams
[j
];
1434 if (!vid_st
&& !aud_st
) {
1435 av_log(s
, AV_LOG_WARNING
, "Media stream not found\n");
1440 * Traverse through the list of audio only rendition streams and find
1441 * the rendition which has highest bitrate in the same audio group
1444 for (j
= 0; j
< hls
->nb_varstreams
; j
++) {
1445 temp_vs
= &(hls
->var_streams
[j
]);
1446 if (!temp_vs
->has_video
&& !temp_vs
->has_subtitle
&&
1448 !av_strcasecmp(temp_vs
->agroup
, vs
->agroup
)) {
1450 aud_st
= temp_vs
->streams
[0];
1451 if (temp_vs
->streams
[0]->codecpar
->bit_rate
>
1452 aud_st
->codecpar
->bit_rate
)
1453 aud_st
= temp_vs
->streams
[0];
1459 bandwidth
= vs
->max_bitrate
;
1460 avg_bandwidth
= vs
->avg_bitrate
;
1464 bandwidth
+= get_stream_bit_rate(vid_st
);
1466 bandwidth
+= get_stream_bit_rate(aud_st
);
1467 bandwidth
+= bandwidth
/ 10;
1471 if (vid_st
&& vs
->ccgroup
) {
1472 /* check if this group name is available in the cc map string */
1473 for (j
= 0; j
< hls
->nb_ccstreams
; j
++) {
1474 ccs
= &(hls
->cc_streams
[j
]);
1475 if (!av_strcasecmp(ccs
->ccgroup
, vs
->ccgroup
)) {
1476 ccgroup
= vs
->ccgroup
;
1480 if (j
== hls
->nb_ccstreams
)
1481 av_log(s
, AV_LOG_WARNING
, "mapping ccgroup %s not found\n",
1485 if (vid_st
&& vs
->sgroup
) {
1486 sgroup
= vs
->sgroup
;
1487 vtt_m3u8_rel_name
= get_relative_url(hls
->master_m3u8_url
, vs
->vtt_m3u8_name
);
1488 if (!vtt_m3u8_rel_name
) {
1489 av_log(s
, AV_LOG_WARNING
, "Unable to find relative subtitle URL\n");
1493 ff_hls_write_subtitle_rendition(hls
->m3u8_out
, sgroup
, vtt_m3u8_rel_name
, vs
->language
,
1494 vs
->subtitle_varname
, i
, hls
->has_default_key
? vs
->is_default
: 1);
1497 if (!hls
->has_default_key
|| !hls
->has_video_m3u8
) {
1498 ff_hls_write_stream_info(vid_st
, hls
->m3u8_out
, bandwidth
, avg_bandwidth
, m3u8_rel_name
,
1499 aud_st
? vs
->agroup
: NULL
, vs
->codec_attr
, ccgroup
, sgroup
);
1502 ff_hls_write_stream_info(vid_st
, hls
->m3u8_out
, bandwidth
, avg_bandwidth
, m3u8_rel_name
,
1503 aud_st
? vs
->agroup
: NULL
, vs
->codec_attr
, ccgroup
, sgroup
);
1509 hls
->master_m3u8_created
= 1;
1510 hlsenc_io_close(s
, &hls
->m3u8_out
, temp_filename
);
1512 ff_rename(temp_filename
, hls
->master_m3u8_url
, s
);
1517 static int hls_window(AVFormatContext
*s
, int last
, VariantStream
*vs
)
1519 HLSContext
*hls
= s
->priv_data
;
1521 int target_duration
= 0;
1523 char temp_filename
[MAX_URL_SIZE
];
1524 char temp_vtt_filename
[MAX_URL_SIZE
];
1525 int64_t sequence
= FFMAX(hls
->start_sequence
, vs
->sequence
- vs
->nb_entries
);
1526 const char *proto
= avio_find_protocol_name(vs
->m3u8_name
);
1527 int is_file_proto
= proto
&& !strcmp(proto
, "file");
1528 int use_temp_file
= is_file_proto
&& ((hls
->flags
& HLS_TEMP_FILE
) || !(hls
->pl_type
== PLAYLIST_TYPE_VOD
));
1529 static unsigned warned_non_file
;
1530 char *key_uri
= NULL
;
1531 char *iv_string
= NULL
;
1532 AVDictionary
*options
= NULL
;
1533 double prog_date_time
= vs
->initial_prog_date_time
;
1534 double *prog_date_time_p
= (hls
->flags
& HLS_PROGRAM_DATE_TIME
) ? &prog_date_time
: NULL
;
1535 int byterange_mode
= (hls
->flags
& HLS_SINGLE_FILE
) || (hls
->max_seg_size
> 0);
1538 if (!(hls
->flags
& HLS_ROUND_DURATIONS
)) {
1542 if (byterange_mode
) {
1547 if (hls
->flags
& HLS_I_FRAMES_ONLY
) {
1551 if (hls
->flags
& HLS_INDEPENDENT_SEGMENTS
) {
1555 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
1559 if (!is_file_proto
&& (hls
->flags
& HLS_TEMP_FILE
) && !warned_non_file
++)
1560 av_log(s
, AV_LOG_ERROR
, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n");
1562 set_http_options(s
, &options
, hls
);
1563 snprintf(temp_filename
, sizeof(temp_filename
), use_temp_file
? "%s.tmp" : "%s", vs
->m3u8_name
);
1564 ret
= hlsenc_io_open(s
, byterange_mode
? &hls
->m3u8_out
: &vs
->out
, temp_filename
, &options
);
1565 av_dict_free(&options
);
1570 for (en
= vs
->segments
; en
; en
= en
->next
) {
1571 if (target_duration
<= en
->duration
)
1572 target_duration
= lrint(en
->duration
);
1575 vs
->discontinuity_set
= 0;
1576 ff_hls_write_playlist_header(byterange_mode
? hls
->m3u8_out
: vs
->out
, hls
->version
, hls
->allowcache
,
1577 target_duration
, sequence
, hls
->pl_type
, hls
->flags
& HLS_I_FRAMES_ONLY
);
1579 if ((hls
->flags
& HLS_DISCONT_START
) && sequence
==hls
->start_sequence
&& vs
->discontinuity_set
==0) {
1580 avio_printf(byterange_mode
? hls
->m3u8_out
: vs
->out
, "#EXT-X-DISCONTINUITY\n");
1581 vs
->discontinuity_set
= 1;
1583 if (vs
->has_video
&& (hls
->flags
& HLS_INDEPENDENT_SEGMENTS
)) {
1584 avio_printf(byterange_mode
? hls
->m3u8_out
: vs
->out
, "#EXT-X-INDEPENDENT-SEGMENTS\n");
1586 for (en
= vs
->segments
; en
; en
= en
->next
) {
1587 if ((hls
->encrypt
|| hls
->key_info_file
) && (!key_uri
|| strcmp(en
->key_uri
, key_uri
) ||
1588 av_strcasecmp(en
->iv_string
, iv_string
))) {
1589 avio_printf(byterange_mode
? hls
->m3u8_out
: vs
->out
, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en
->key_uri
);
1591 avio_printf(byterange_mode
? hls
->m3u8_out
: vs
->out
, ",IV=0x%s", en
->iv_string
);
1592 avio_printf(byterange_mode
? hls
->m3u8_out
: vs
->out
, "\n");
1593 key_uri
= en
->key_uri
;
1594 iv_string
= en
->iv_string
;
1597 if ((hls
->segment_type
== SEGMENT_TYPE_FMP4
) && (en
== vs
->segments
)) {
1598 ff_hls_write_init_file(byterange_mode
? hls
->m3u8_out
: vs
->out
, (hls
->flags
& HLS_SINGLE_FILE
) ? en
->filename
: vs
->fmp4_init_filename
,
1599 hls
->flags
& HLS_SINGLE_FILE
, vs
->init_range_length
, 0);
1602 ret
= ff_hls_write_file_entry(byterange_mode
? hls
->m3u8_out
: vs
->out
, en
->discont
, byterange_mode
,
1603 en
->duration
, hls
->flags
& HLS_ROUND_DURATIONS
,
1604 en
->size
, en
->pos
, hls
->baseurl
,
1606 en
->discont_program_date_time
? &en
->discont_program_date_time
: prog_date_time_p
,
1607 en
->keyframe_size
, en
->keyframe_pos
, hls
->flags
& HLS_I_FRAMES_ONLY
);
1608 if (en
->discont_program_date_time
)
1609 en
->discont_program_date_time
-= en
->duration
;
1611 av_log(s
, AV_LOG_WARNING
, "ff_hls_write_file_entry get error\n");
1615 if (last
&& (hls
->flags
& HLS_OMIT_ENDLIST
)==0)
1616 ff_hls_write_end_list(byterange_mode
? hls
->m3u8_out
: vs
->out
);
1618 if (vs
->vtt_m3u8_name
) {
1619 set_http_options(vs
->vtt_avf
, &options
, hls
);
1620 snprintf(temp_vtt_filename
, sizeof(temp_vtt_filename
), use_temp_file
? "%s.tmp" : "%s", vs
->vtt_m3u8_name
);
1621 ret
= hlsenc_io_open(s
, &hls
->sub_m3u8_out
, temp_vtt_filename
, &options
);
1622 av_dict_free(&options
);
1626 ff_hls_write_playlist_header(hls
->sub_m3u8_out
, hls
->version
, hls
->allowcache
,
1627 target_duration
, sequence
, PLAYLIST_TYPE_NONE
, 0);
1628 for (en
= vs
->segments
; en
; en
= en
->next
) {
1629 ret
= ff_hls_write_file_entry(hls
->sub_m3u8_out
, en
->discont
, byterange_mode
,
1630 en
->duration
, 0, en
->size
, en
->pos
,
1631 hls
->baseurl
, en
->sub_filename
, NULL
, 0, 0, 0);
1633 av_log(s
, AV_LOG_WARNING
, "ff_hls_write_file_entry get error\n");
1637 if (last
&& !(hls
->flags
& HLS_OMIT_ENDLIST
))
1638 ff_hls_write_end_list(hls
->sub_m3u8_out
);
1643 av_dict_free(&options
);
1644 ret
= hlsenc_io_close(s
, byterange_mode
? &hls
->m3u8_out
: &vs
->out
, temp_filename
);
1648 hlsenc_io_close(s
, &hls
->sub_m3u8_out
, vs
->vtt_m3u8_name
);
1649 if (use_temp_file
) {
1650 ff_rename(temp_filename
, vs
->m3u8_name
, s
);
1651 if (vs
->vtt_m3u8_name
)
1652 ff_rename(temp_vtt_filename
, vs
->vtt_m3u8_name
, s
);
1654 if (ret
>= 0 && hls
->master_pl_name
)
1655 if (create_master_playlist(s
, vs
, last
) < 0)
1656 av_log(s
, AV_LOG_WARNING
, "Master playlist creation failed\n");
1661 static int hls_start(AVFormatContext
*s
, VariantStream
*vs
)
1663 HLSContext
*c
= s
->priv_data
;
1664 AVFormatContext
*oc
= vs
->avf
;
1665 AVFormatContext
*vtt_oc
= vs
->vtt_avf
;
1666 AVDictionary
*options
= NULL
;
1667 const char *proto
= NULL
;
1668 int use_temp_file
= 0;
1669 char iv_string
[KEYSIZE
*2 + 1];
1672 if (c
->flags
& HLS_SINGLE_FILE
) {
1673 char *new_name
= av_strdup(vs
->basename
);
1675 return AVERROR(ENOMEM
);
1676 ff_format_set_url(oc
, new_name
);
1677 if (vs
->vtt_basename
) {
1678 new_name
= av_strdup(vs
->vtt_basename
);
1680 return AVERROR(ENOMEM
);
1681 ff_format_set_url(vtt_oc
, new_name
);
1683 } else if (c
->max_seg_size
> 0) {
1684 char *filename
= NULL
;
1685 if (replace_int_data_in_filename(&filename
,
1686 vs
->basename
, 'd', vs
->sequence
) < 1) {
1687 av_freep(&filename
);
1688 av_log(oc
, AV_LOG_ERROR
, "Invalid segment filename template '%s', you can try to use -strftime 1 with it\n", vs
->basename
);
1689 return AVERROR(EINVAL
);
1691 ff_format_set_url(oc
, filename
);
1693 if (c
->use_localtime
) {
1695 char *expanded
= NULL
;
1697 r
= strftime_expand(vs
->basename
, &expanded
);
1699 av_log(oc
, AV_LOG_ERROR
, "Could not get segment filename with strftime\n");
1702 ff_format_set_url(oc
, expanded
);
1704 err
= sls_flag_use_localtime_filename(oc
, c
, vs
);
1706 return AVERROR(ENOMEM
);
1709 if (c
->use_localtime_mkdir
) {
1711 char *fn_copy
= av_strdup(oc
->url
);
1713 return AVERROR(ENOMEM
);
1714 dir
= av_dirname(fn_copy
);
1715 if (ff_mkdir_p(dir
) == -1 && errno
!= EEXIST
) {
1716 av_log(oc
, AV_LOG_ERROR
, "Could not create directory %s with use_localtime_mkdir\n", dir
);
1718 return AVERROR(errno
);
1723 char *filename
= NULL
;
1724 if (replace_int_data_in_filename(&filename
,
1725 vs
->basename
, 'd', vs
->sequence
) < 1) {
1726 av_freep(&filename
);
1727 av_log(oc
, AV_LOG_ERROR
, "Invalid segment filename template '%s' you can try to use -strftime 1 with it\n", vs
->basename
);
1728 return AVERROR(EINVAL
);
1730 ff_format_set_url(oc
, filename
);
1732 if (vs
->vtt_basename
) {
1733 char *filename
= NULL
;
1734 if (replace_int_data_in_filename(&filename
,
1735 vs
->vtt_basename
, 'd', vs
->sequence
) < 1) {
1736 av_freep(&filename
);
1737 av_log(vtt_oc
, AV_LOG_ERROR
, "Invalid segment filename template '%s'\n", vs
->vtt_basename
);
1738 return AVERROR(EINVAL
);
1740 ff_format_set_url(vtt_oc
, filename
);
1744 proto
= avio_find_protocol_name(oc
->url
);
1745 use_temp_file
= proto
&& !strcmp(proto
, "file") && (c
->flags
& HLS_TEMP_FILE
);
1747 if (use_temp_file
) {
1748 char *new_name
= av_asprintf("%s.tmp", oc
->url
);
1750 return AVERROR(ENOMEM
);
1751 ff_format_set_url(oc
, new_name
);
1754 if (c
->key_info_file
|| c
->encrypt
) {
1755 if (c
->segment_type
== SEGMENT_TYPE_FMP4
) {
1756 av_log(s
, AV_LOG_ERROR
, "Encrypted fmp4 not yet supported\n");
1757 return AVERROR_PATCHWELCOME
;
1760 if (c
->key_info_file
&& c
->encrypt
) {
1761 av_log(s
, AV_LOG_WARNING
, "Cannot use both -hls_key_info_file and -hls_enc,"
1762 " ignoring -hls_enc\n");
1765 if (!vs
->encrypt_started
|| (c
->flags
& HLS_PERIODIC_REKEY
)) {
1766 if (c
->key_info_file
) {
1767 if ((err
= hls_encryption_start(s
, vs
)) < 0)
1770 if (!c
->encrypt_started
) {
1771 if ((err
= do_encrypt(s
, vs
)) < 0)
1773 c
->encrypt_started
= 1;
1775 av_strlcpy(vs
->key_uri
, c
->key_uri
, sizeof(vs
->key_uri
));
1776 av_strlcpy(vs
->key_string
, c
->key_string
, sizeof(vs
->key_string
));
1777 av_strlcpy(vs
->iv_string
, c
->iv_string
, sizeof(vs
->iv_string
));
1779 vs
->encrypt_started
= 1;
1781 err
= av_strlcpy(iv_string
, vs
->iv_string
, sizeof(iv_string
));
1783 snprintf(iv_string
, sizeof(iv_string
), "%032"PRIx64
, vs
->sequence
);
1784 memset(vs
->iv_string
, 0, sizeof(vs
->iv_string
));
1785 memcpy(vs
->iv_string
, iv_string
, sizeof(iv_string
));
1788 if (c
->segment_type
!= SEGMENT_TYPE_FMP4
) {
1789 if (oc
->oformat
->priv_class
&& oc
->priv_data
) {
1790 av_opt_set(oc
->priv_data
, "mpegts_flags", "resend_headers", 0);
1792 if (c
->flags
& HLS_SINGLE_FILE
) {
1793 if (c
->key_info_file
|| c
->encrypt
) {
1794 av_dict_set(&options
, "encryption_key", vs
->key_string
, 0);
1795 av_dict_set(&options
, "encryption_iv", vs
->iv_string
, 0);
1797 /* Write temp file with cryption content */
1798 av_freep(&vs
->basename_tmp
);
1799 vs
->basename_tmp
= av_asprintf("crypto:%s.tmp", oc
->url
);
1801 /* append temp file content into single file */
1802 av_freep(&vs
->basename
);
1803 vs
->basename
= av_asprintf("%s", oc
->url
);
1805 vs
->basename_tmp
= vs
->basename
;
1807 set_http_options(s
, &options
, c
);
1808 if (!vs
->out_single_file
)
1809 if ((err
= hlsenc_io_open(s
, &vs
->out_single_file
, vs
->basename
, &options
)) < 0) {
1810 if (c
->ignore_io_errors
)
1815 if ((err
= hlsenc_io_open(s
, &vs
->out
, vs
->basename_tmp
, &options
)) < 0) {
1816 if (c
->ignore_io_errors
)
1823 if (vs
->vtt_basename
) {
1824 set_http_options(s
, &options
, c
);
1825 if ((err
= hlsenc_io_open(s
, &vtt_oc
->pb
, vtt_oc
->url
, &options
)) < 0) {
1826 if (c
->ignore_io_errors
)
1831 av_dict_free(&options
);
1833 if (vs
->vtt_basename
) {
1834 err
= avformat_write_header(vtt_oc
,NULL
);
1841 av_dict_free(&options
);
1846 static const char * get_default_pattern_localtime_fmt(AVFormatContext
*s
)
1848 HLSContext
*hls
= s
->priv_data
;
1849 #if HAVE_LIBC_MSVCRT
1850 // no %s support on MSVC, which invokes the invalid parameter handler
1851 // on unsupported format strings, instead of returning an error
1852 int strftime_s_supported
= 0;
1855 time_t t
= time(NULL
);
1856 struct tm tmbuf
, *p
= localtime_r(&t
, &tmbuf
);
1857 // no %s support when strftime returned error or left format string unchanged
1858 int strftime_s_supported
= strftime(b
, sizeof(b
), "%s", p
) && strcmp(b
, "%s");
1861 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
1862 return strftime_s_supported
? "-%s.m4s" : "-%Y%m%d%H%M%S.m4s";
1864 return strftime_s_supported
? "-%s.ts" : "-%Y%m%d%H%M%S.ts";
1867 static int append_postfix(char *name
, int name_buf_len
, int i
)
1870 char extension
[10] = {'\0'};
1872 p
= strrchr(name
, '.');
1874 av_strlcpy(extension
, p
, sizeof(extension
));
1878 snprintf(name
+ strlen(name
), name_buf_len
- strlen(name
), POSTFIX_PATTERN
, i
);
1880 if (strlen(extension
))
1881 av_strlcat(name
, extension
, name_buf_len
);
1886 static int validate_name(int nb_vs
, const char *fn
)
1888 const char *filename
, *subdir_name
;
1889 char *fn_dup
= NULL
;
1893 return AVERROR(EINVAL
);
1895 fn_dup
= av_strdup(fn
);
1897 return AVERROR(ENOMEM
);
1898 filename
= av_basename(fn
);
1899 subdir_name
= av_dirname(fn_dup
);
1901 if (nb_vs
> 1 && !av_stristr(filename
, "%v") && !av_stristr(subdir_name
, "%v")) {
1902 av_log(NULL
, AV_LOG_ERROR
, "More than 1 variant streams are present, %%v is expected "
1903 "either in the filename or in the sub-directory name of file %s\n", fn
);
1904 ret
= AVERROR(EINVAL
);
1908 if (av_stristr(filename
, "%v") && av_stristr(subdir_name
, "%v")) {
1909 av_log(NULL
, AV_LOG_ERROR
, "%%v is expected either in the filename or "
1910 "in the sub-directory name of file %s, but only in one of them\n", fn
);
1911 ret
= AVERROR(EINVAL
);
1920 static int format_name(const char *buf
, char **s
, int index
, const char *varname
)
1922 const char *proto
, *dir
;
1923 char *orig_buf_dup
= NULL
, *mod_buf_dup
= NULL
;
1926 orig_buf_dup
= av_strdup(buf
);
1928 return AVERROR(ENOMEM
);
1930 if (!av_stristr(buf
, "%v")) {
1936 if (replace_int_data_in_filename(s
, orig_buf_dup
, 'v', index
) < 1) {
1937 ret
= AVERROR(EINVAL
);
1941 if (replace_str_data_in_filename(s
, orig_buf_dup
, 'v', varname
) < 1) {
1942 ret
= AVERROR(EINVAL
);
1947 proto
= avio_find_protocol_name(orig_buf_dup
);
1948 dir
= av_dirname(orig_buf_dup
);
1950 /* if %v is present in the file's directory, create sub-directory */
1951 if (av_stristr(dir
, "%v") && proto
&& !strcmp(proto
, "file")) {
1952 mod_buf_dup
= av_strdup(*s
);
1953 dir
= av_dirname(mod_buf_dup
);
1954 if (ff_mkdir_p(dir
) == -1 && errno
!= EEXIST
) {
1955 ret
= AVERROR(errno
);
1961 av_freep(&orig_buf_dup
);
1962 av_freep(&mod_buf_dup
);
1966 static int get_nth_codec_stream_index(AVFormatContext
*s
,
1967 enum AVMediaType codec_type
,
1970 unsigned int stream_index
, cnt
;
1971 if (stream_id
< 0 || stream_id
> s
->nb_streams
- 1)
1974 for (stream_index
= 0; stream_index
< s
->nb_streams
; stream_index
++) {
1975 if (s
->streams
[stream_index
]->codecpar
->codec_type
!= codec_type
)
1977 if (cnt
== stream_id
)
1978 return stream_index
;
1984 static int parse_variant_stream_mapstring(AVFormatContext
*s
)
1986 HLSContext
*hls
= s
->priv_data
;
1988 int stream_index
, i
, j
;
1989 enum AVMediaType codec_type
;
1990 int nb_varstreams
= 0, nb_streams
;
1991 char *p
, *q
, *saveptr1
, *saveptr2
, *varstr
, *keyval
;
1995 * Expected format for var_stream_map string is as below:
1997 * "a:0,agroup:a0,default:1,language:ENG a:1,agroup:a1,default:0 v:0,agroup:a0 v:1,agroup:a1"
1998 * This string specifies how to group the audio, video and subtitle streams
1999 * into different variant streams. The variant stream groups are separated
2002 * a:, v:, s: are keys to specify audio, video and subtitle streams
2003 * respectively. Allowed values are 0 to 9 digits (limited just based on
2006 * agroup: is key to specify audio group. A string can be given as value.
2007 * sgroup: is key to specify subtitle group. A string can be given as value.
2009 p
= av_strdup(hls
->var_stream_map
);
2011 return AVERROR(ENOMEM
);
2014 while (av_strtok(q
, " \t", &saveptr1
)) {
2020 hls
->var_streams
= av_mallocz(sizeof(*hls
->var_streams
) * nb_varstreams
);
2021 if (!hls
->var_streams
)
2022 return AVERROR(ENOMEM
);
2023 hls
->nb_varstreams
= nb_varstreams
;
2025 p
= hls
->var_stream_map
;
2027 while (varstr
= av_strtok(p
, " \t", &saveptr1
)) {
2030 if (nb_varstreams
< hls
->nb_varstreams
) {
2031 vs
= &(hls
->var_streams
[nb_varstreams
]);
2032 vs
->var_stream_idx
= nb_varstreams
;
2036 return AVERROR(EINVAL
);
2040 if (!av_strncasecmp(q
, "a:", 2) || !av_strncasecmp(q
, "v:", 2) ||
2041 !av_strncasecmp(q
, "s:", 2))
2048 vs
->streams
= av_mallocz(sizeof(AVStream
*) * vs
->nb_streams
);
2050 return AVERROR(ENOMEM
);
2053 while (keyval
= av_strtok(varstr
, ",", &saveptr2
)) {
2057 if (av_strstart(keyval
, "language:", &val
)) {
2060 } else if (av_strstart(keyval
, "default:", &val
)) {
2061 vs
->is_default
= (!av_strncasecmp(val
, "YES", strlen("YES")) ||
2062 (!av_strncasecmp(val
, "1", strlen("1"))));
2063 hls
->has_default_key
= 1;
2065 } else if (av_strstart(keyval
, "name:", &val
)) {
2068 } else if (av_strstart(keyval
, "sname:", &val
)) {
2069 vs
->subtitle_varname
= val
;
2071 } else if (av_strstart(keyval
, "agroup:", &val
)) {
2074 } else if (av_strstart(keyval
, "sgroup:", &val
)) {
2077 } else if (av_strstart(keyval
, "ccgroup:", &val
)) {
2080 } else if (av_strstart(keyval
, "v:", &val
)) {
2081 codec_type
= AVMEDIA_TYPE_VIDEO
;
2082 hls
->has_video_m3u8
= 1;
2083 } else if (av_strstart(keyval
, "a:", &val
)) {
2084 codec_type
= AVMEDIA_TYPE_AUDIO
;
2085 } else if (av_strstart(keyval
, "s:", &val
)) {
2086 codec_type
= AVMEDIA_TYPE_SUBTITLE
;
2088 av_log(s
, AV_LOG_ERROR
, "Invalid keyval %s\n", keyval
);
2089 return AVERROR(EINVAL
);
2092 num
= strtoll(val
, &end
, 10);
2093 if (!av_isdigit(*val
) || *end
!= '\0') {
2094 av_log(s
, AV_LOG_ERROR
, "Invalid stream number: '%s'\n", val
);
2095 return AVERROR(EINVAL
);
2097 stream_index
= get_nth_codec_stream_index(s
, codec_type
, num
);
2099 if (stream_index
>= 0 && nb_streams
< vs
->nb_streams
) {
2100 for (i
= 0; nb_streams
> 0 && i
< nb_streams
; i
++) {
2101 if (vs
->streams
[i
] == s
->streams
[stream_index
]) {
2102 av_log(s
, AV_LOG_ERROR
, "Same elementary stream found more than once inside "
2103 "variant definition #%d\n", nb_varstreams
- 1);
2104 return AVERROR(EINVAL
);
2107 for (j
= 0; nb_varstreams
> 1 && j
< nb_varstreams
- 1; j
++) {
2108 for (i
= 0; i
< hls
->var_streams
[j
].nb_streams
; i
++) {
2109 if (hls
->var_streams
[j
].streams
[i
] == s
->streams
[stream_index
]) {
2110 av_log(s
, AV_LOG_ERROR
, "Same elementary stream found more than once "
2111 "in two different variant definitions #%d and #%d\n",
2112 j
, nb_varstreams
- 1);
2113 return AVERROR(EINVAL
);
2117 vs
->streams
[nb_streams
++] = s
->streams
[stream_index
];
2119 av_log(s
, AV_LOG_ERROR
, "Unable to map stream at %s\n", keyval
);
2120 return AVERROR(EINVAL
);
2124 av_log(s
, AV_LOG_DEBUG
, "Number of variant streams %d\n",
2125 hls
->nb_varstreams
);
2130 static int parse_cc_stream_mapstring(AVFormatContext
*s
)
2132 HLSContext
*hls
= s
->priv_data
;
2133 int nb_ccstreams
= 0;
2134 char *p
, *q
, *ccstr
, *keyval
;
2135 char *saveptr1
= NULL
, *saveptr2
= NULL
;
2137 ClosedCaptionsStream
*ccs
;
2139 p
= av_strdup(hls
->cc_stream_map
);
2141 return AVERROR(ENOMEM
);
2144 while (av_strtok(q
, " \t", &saveptr1
)) {
2150 hls
->cc_streams
= av_mallocz(sizeof(*hls
->cc_streams
) * nb_ccstreams
);
2151 if (!hls
->cc_streams
)
2152 return AVERROR(ENOMEM
);
2153 hls
->nb_ccstreams
= nb_ccstreams
;
2155 p
= hls
->cc_stream_map
;
2157 while (ccstr
= av_strtok(p
, " \t", &saveptr1
)) {
2160 if (nb_ccstreams
< hls
->nb_ccstreams
)
2161 ccs
= &(hls
->cc_streams
[nb_ccstreams
++]);
2163 return AVERROR(EINVAL
);
2165 while (keyval
= av_strtok(ccstr
, ",", &saveptr2
)) {
2168 if (av_strstart(keyval
, "ccgroup:", &val
)) {
2170 } else if (av_strstart(keyval
, "instreamid:", &val
)) {
2171 ccs
->instreamid
= val
;
2172 } else if (av_strstart(keyval
, "language:", &val
)) {
2173 ccs
->language
= val
;
2175 av_log(s
, AV_LOG_ERROR
, "Invalid keyval %s\n", keyval
);
2176 return AVERROR(EINVAL
);
2180 if (!ccs
->ccgroup
|| !ccs
->instreamid
) {
2181 av_log(s
, AV_LOG_ERROR
, "Insufficient parameters in cc stream map string\n");
2182 return AVERROR(EINVAL
);
2185 if (av_strstart(ccs
->instreamid
, "CC", &val
)) {
2186 if (atoi(val
) < 1 || atoi(val
) > 4) {
2187 av_log(s
, AV_LOG_ERROR
, "Invalid instream ID CC index %d in %s, range 1-4\n",
2188 atoi(val
), ccs
->instreamid
);
2189 return AVERROR(EINVAL
);
2191 } else if (av_strstart(ccs
->instreamid
, "SERVICE", &val
)) {
2192 if (atoi(val
) < 1 || atoi(val
) > 63) {
2193 av_log(s
, AV_LOG_ERROR
, "Invalid instream ID SERVICE index %d in %s, range 1-63 \n",
2194 atoi(val
), ccs
->instreamid
);
2195 return AVERROR(EINVAL
);
2198 av_log(s
, AV_LOG_ERROR
, "Invalid instream ID %s, supported are CCn or SERVICEn\n",
2200 return AVERROR(EINVAL
);
2207 static int update_variant_stream_info(AVFormatContext
*s
)
2209 HLSContext
*hls
= s
->priv_data
;
2213 if (hls
->cc_stream_map
) {
2214 ret
= parse_cc_stream_mapstring(s
);
2219 if (hls
->var_stream_map
) {
2220 return parse_variant_stream_mapstring(s
);
2222 //By default, a single variant stream with all the codec streams is created
2223 hls
->var_streams
= av_mallocz(sizeof(*hls
->var_streams
));
2224 if (!hls
->var_streams
)
2225 return AVERROR(ENOMEM
);
2226 hls
->nb_varstreams
= 1;
2228 hls
->var_streams
[0].var_stream_idx
= 0;
2229 hls
->var_streams
[0].nb_streams
= s
->nb_streams
;
2230 hls
->var_streams
[0].streams
= av_mallocz(sizeof(AVStream
*) *
2231 hls
->var_streams
[0].nb_streams
);
2232 if (!hls
->var_streams
[0].streams
)
2233 return AVERROR(ENOMEM
);
2235 //by default, the first available ccgroup is mapped to the variant stream
2236 if (hls
->nb_ccstreams
)
2237 hls
->var_streams
[0].ccgroup
= hls
->cc_streams
[0].ccgroup
;
2239 for (i
= 0; i
< s
->nb_streams
; i
++)
2240 hls
->var_streams
[0].streams
[i
] = s
->streams
[i
];
2245 static int update_master_pl_info(AVFormatContext
*s
)
2247 HLSContext
*hls
= s
->priv_data
;
2249 char *fn1
= NULL
, *fn2
= NULL
;
2252 fn1
= av_strdup(s
->url
);
2254 return AVERROR(ENOMEM
);
2255 dir
= av_dirname(fn1
);
2258 * if output file's directory has %v, variants are created in sub-directories
2259 * then master is created at the sub-directories level
2261 if (dir
&& av_stristr(av_basename(dir
), "%v")) {
2262 fn2
= av_strdup(dir
);
2264 ret
= AVERROR(ENOMEM
);
2267 dir
= av_dirname(fn2
);
2270 if (dir
&& strcmp(dir
, "."))
2271 hls
->master_m3u8_url
= av_append_path_component(dir
, hls
->master_pl_name
);
2273 hls
->master_m3u8_url
= av_strdup(hls
->master_pl_name
);
2275 if (!hls
->master_m3u8_url
) {
2276 ret
= AVERROR(ENOMEM
);
2287 static int hls_write_header(AVFormatContext
*s
)
2289 HLSContext
*hls
= s
->priv_data
;
2291 VariantStream
*vs
= NULL
;
2293 for (i
= 0; i
< hls
->nb_varstreams
; i
++) {
2294 int subtitle_streams
= 0;
2295 vs
= &hls
->var_streams
[i
];
2297 ret
= avformat_write_header(vs
->avf
, NULL
);
2300 //av_assert0(s->nb_streams == hls->avf->nb_streams);
2301 for (j
= 0; j
< vs
->nb_streams
; j
++) {
2303 AVStream
*outer_st
= vs
->streams
[j
];
2305 if (hls
->max_seg_size
> 0) {
2306 if ((outer_st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) &&
2307 (outer_st
->codecpar
->bit_rate
> hls
->max_seg_size
)) {
2308 av_log(s
, AV_LOG_WARNING
, "Your video bitrate is bigger than hls_segment_size, "
2309 "(%"PRId64
" > %"PRId64
"), the result maybe not be what you want.",
2310 outer_st
->codecpar
->bit_rate
, hls
->max_seg_size
);
2314 if (outer_st
->codecpar
->codec_type
!= AVMEDIA_TYPE_SUBTITLE
)
2315 inner_st
= vs
->avf
->streams
[j
- subtitle_streams
];
2316 else if (vs
->vtt_avf
) {
2317 inner_st
= vs
->vtt_avf
->streams
[0];
2320 /* We have a subtitle stream, when the user does not want one */
2324 avpriv_set_pts_info(outer_st
, inner_st
->pts_wrap_bits
, inner_st
->time_base
.num
, inner_st
->time_base
.den
);
2325 if (outer_st
->codecpar
->codec_id
== AV_CODEC_ID_HEVC
&&
2326 outer_st
->codecpar
->codec_tag
!= MKTAG('h','v','c','1')) {
2327 av_log(s
, AV_LOG_WARNING
, "Stream HEVC is not hvc1, you should use tag:v hvc1 to set it.\n");
2329 write_codec_attr(outer_st
, vs
);
2332 /* Update the Codec Attr string for the mapped audio groups */
2333 if (vs
->has_video
&& vs
->agroup
) {
2334 for (j
= 0; j
< hls
->nb_varstreams
; j
++) {
2335 VariantStream
*vs_agroup
= &(hls
->var_streams
[j
]);
2336 if (!vs_agroup
->has_video
&& !vs_agroup
->has_subtitle
&&
2337 vs_agroup
->agroup
&&
2338 !av_strcasecmp(vs_agroup
->agroup
, vs
->agroup
)) {
2339 write_codec_attr(vs_agroup
->streams
[0], vs
);
2348 static int hls_init_file_resend(AVFormatContext
*s
, VariantStream
*vs
)
2350 HLSContext
*hls
= s
->priv_data
;
2351 AVDictionary
*options
= NULL
;
2354 set_http_options(s
, &options
, hls
);
2355 ret
= hlsenc_io_open(s
, &vs
->out
, vs
->base_output_dirname
, &options
);
2356 av_dict_free(&options
);
2359 avio_write(vs
->out
, vs
->init_buffer
, vs
->init_range_length
);
2360 hlsenc_io_close(s
, &vs
->out
, hls
->fmp4_init_filename
);
2365 static int64_t append_single_file(AVFormatContext
*s
, VariantStream
*vs
)
2368 int64_t read_byte
= 0;
2369 int64_t total_size
= 0;
2370 char *filename
= NULL
;
2372 AVFormatContext
*oc
= vs
->avf
;
2374 hlsenc_io_close(s
, &vs
->out
, vs
->basename_tmp
);
2375 filename
= av_asprintf("%s.tmp", oc
->url
);
2376 ret
= s
->io_open(s
, &vs
->out
, filename
, AVIO_FLAG_READ
, NULL
);
2383 read_byte
= avio_read(vs
->out
, buf
, BUFSIZE
);
2384 if (read_byte
> 0) {
2385 avio_write(vs
->out_single_file
, buf
, read_byte
);
2386 total_size
+= read_byte
;
2389 } while (read_byte
> 0);
2391 hlsenc_io_close(s
, &vs
->out
, filename
);
2396 static int hls_write_packet(AVFormatContext
*s
, AVPacket
*pkt
)
2398 HLSContext
*hls
= s
->priv_data
;
2399 AVFormatContext
*oc
= NULL
;
2400 AVStream
*st
= s
->streams
[pkt
->stream_index
];
2401 int64_t end_pts
= 0;
2403 int ret
= 0, can_split
= 1, i
, j
;
2404 int stream_index
= 0;
2405 int range_length
= 0;
2406 const char *proto
= NULL
;
2407 int use_temp_file
= 0;
2408 VariantStream
*vs
= NULL
;
2409 char *old_filename
= NULL
;
2411 for (i
= 0; i
< hls
->nb_varstreams
; i
++) {
2412 int subtitle_streams
= 0;
2413 vs
= &hls
->var_streams
[i
];
2414 for (j
= 0; j
< vs
->nb_streams
; j
++) {
2415 if (vs
->streams
[j
]->codecpar
->codec_type
== AVMEDIA_TYPE_SUBTITLE
) {
2418 if (vs
->streams
[j
] == st
) {
2419 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_SUBTITLE
) {
2424 stream_index
= j
- subtitle_streams
;
2435 av_log(s
, AV_LOG_ERROR
, "Unable to find mapping variant stream\n");
2436 return AVERROR(ENOMEM
);
2439 end_pts
= hls
->recording_time
* vs
->number
;
2441 if (vs
->sequence
- vs
->nb_entries
> hls
->start_sequence
&& hls
->init_time
> 0) {
2442 /* reset end_pts, hls->recording_time at end of the init hls list */
2443 int64_t init_list_dur
= hls
->init_time
* vs
->nb_entries
;
2444 int64_t after_init_list_dur
= (vs
->sequence
- hls
->start_sequence
- vs
->nb_entries
) * hls
->time
;
2445 hls
->recording_time
= hls
->time
;
2446 end_pts
= init_list_dur
+ after_init_list_dur
;
2449 if (vs
->start_pts
== AV_NOPTS_VALUE
) {
2450 vs
->start_pts
= pkt
->pts
;
2451 if (st
->codecpar
->codec_type
== AVMEDIA_TYPE_AUDIO
)
2452 vs
->start_pts_from_audio
= 1;
2454 if (vs
->start_pts_from_audio
&& st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
&& vs
->start_pts
> pkt
->pts
) {
2455 vs
->start_pts
= pkt
->pts
;
2456 vs
->start_pts_from_audio
= 0;
2459 if (vs
->has_video
) {
2460 can_split
= st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
&&
2461 ((pkt
->flags
& AV_PKT_FLAG_KEY
) || (hls
->flags
& HLS_SPLIT_BY_TIME
));
2462 is_ref_pkt
= (st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) && (pkt
->stream_index
== vs
->reference_stream_index
);
2464 if (pkt
->pts
== AV_NOPTS_VALUE
)
2465 is_ref_pkt
= can_split
= 0;
2468 if (vs
->end_pts
== AV_NOPTS_VALUE
)
2469 vs
->end_pts
= pkt
->pts
;
2470 if (vs
->new_start
) {
2472 vs
->duration
= (double)(pkt
->pts
- vs
->end_pts
)
2473 * st
->time_base
.num
/ st
->time_base
.den
;
2474 vs
->dpp
= (double)(pkt
->duration
) * st
->time_base
.num
/ st
->time_base
.den
;
2476 if (pkt
->duration
) {
2477 vs
->duration
+= (double)(pkt
->duration
) * st
->time_base
.num
/ st
->time_base
.den
;
2479 av_log(s
, AV_LOG_WARNING
, "Stream %d packet with pts %" PRId64
" has duration 0. The segment duration may not be precise.\n",
2480 pkt
->stream_index
, pkt
->pts
);
2481 vs
->duration
= (double)(pkt
->pts
- vs
->end_pts
) * st
->time_base
.num
/ st
->time_base
.den
;
2486 can_split
= can_split
&& (pkt
->pts
- vs
->end_pts
> 0);
2487 if (vs
->packets_written
&& can_split
&& av_compare_ts(pkt
->pts
- vs
->start_pts
, st
->time_base
,
2488 end_pts
, AV_TIME_BASE_Q
) >= 0) {
2489 int64_t new_start_pos
;
2490 int byterange_mode
= (hls
->flags
& HLS_SINGLE_FILE
) || (hls
->max_seg_size
> 0);
2491 double cur_duration
;
2493 av_write_frame(oc
, NULL
); /* Flush any buffered data */
2494 new_start_pos
= avio_tell(oc
->pb
);
2495 vs
->size
= new_start_pos
- vs
->start_pos
;
2497 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
2498 if (!vs
->init_range_length
) {
2499 range_length
= avio_close_dyn_buf(oc
->pb
, &vs
->init_buffer
);
2500 if (range_length
<= 0)
2501 return AVERROR(EINVAL
);
2502 avio_write(vs
->out
, vs
->init_buffer
, range_length
);
2503 if (!hls
->resend_init_file
)
2504 av_freep(&vs
->init_buffer
);
2505 vs
->init_range_length
= range_length
;
2506 avio_open_dyn_buf(&oc
->pb
);
2507 vs
->packets_written
= 0;
2508 vs
->start_pos
= range_length
;
2509 if (!byterange_mode
) {
2510 hlsenc_io_close(s
, &vs
->out
, vs
->base_output_dirname
);
2514 if (!byterange_mode
) {
2516 hlsenc_io_close(s
, &vs
->vtt_avf
->pb
, vs
->vtt_avf
->url
);
2520 if (hls
->flags
& HLS_SINGLE_FILE
) {
2521 ret
= flush_dynbuf(vs
, &range_length
);
2522 av_freep(&vs
->temp_buffer
);
2526 vs
->size
= range_length
;
2527 if (hls
->key_info_file
|| hls
->encrypt
)
2528 vs
->size
= append_single_file(s
, vs
);
2531 proto
= avio_find_protocol_name(oc
->url
);
2532 use_temp_file
= proto
&& !strcmp(proto
, "file")
2533 && (hls
->flags
& HLS_TEMP_FILE
);
2536 if ((hls
->max_seg_size
> 0 && (vs
->size
+ vs
->start_pos
>= hls
->max_seg_size
)) || !byterange_mode
) {
2537 AVDictionary
*options
= NULL
;
2538 char *filename
= NULL
;
2539 if (hls
->key_info_file
|| hls
->encrypt
) {
2540 av_dict_set(&options
, "encryption_key", vs
->key_string
, 0);
2541 av_dict_set(&options
, "encryption_iv", vs
->iv_string
, 0);
2542 filename
= av_asprintf("crypto:%s", oc
->url
);
2544 filename
= av_asprintf("%s", oc
->url
);
2547 av_dict_free(&options
);
2548 return AVERROR(ENOMEM
);
2551 // look to rename the asset name
2553 av_dict_set(&options
, "mpegts_flags", "resend_headers", 0);
2555 set_http_options(s
, &options
, hls
);
2557 ret
= hlsenc_io_open(s
, &vs
->out
, filename
, &options
);
2559 av_log(s
, hls
->ignore_io_errors
? AV_LOG_WARNING
: AV_LOG_ERROR
,
2560 "Failed to open file '%s'\n", filename
);
2561 av_freep(&filename
);
2562 av_dict_free(&options
);
2563 return hls
->ignore_io_errors
? 0 : ret
;
2565 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
2566 write_styp(vs
->out
);
2568 ret
= flush_dynbuf(vs
, &range_length
);
2570 av_freep(&filename
);
2571 av_dict_free(&options
);
2574 vs
->size
= range_length
;
2575 ret
= hlsenc_io_close(s
, &vs
->out
, filename
);
2577 av_log(s
, AV_LOG_WARNING
, "upload segment failed,"
2578 " will retry with a new http session.\n");
2579 ff_format_io_close(s
, &vs
->out
);
2580 ret
= hlsenc_io_open(s
, &vs
->out
, filename
, &options
);
2582 reflush_dynbuf(vs
, &range_length
);
2583 ret
= hlsenc_io_close(s
, &vs
->out
, filename
);
2586 av_dict_free(&options
);
2587 av_freep(&vs
->temp_buffer
);
2588 av_freep(&filename
);
2592 hls_rename_temp_file(s
, oc
);
2598 old_filename
= av_strdup(oc
->url
);
2599 if (!old_filename
) {
2600 return AVERROR(ENOMEM
);
2603 cur_duration
= (double)(pkt
->pts
- vs
->end_pts
) * st
->time_base
.num
/ st
->time_base
.den
;
2604 ret
= hls_append_segment(s
, hls
, vs
, cur_duration
, vs
->start_pos
, vs
->size
);
2605 vs
->end_pts
= pkt
->pts
;
2608 av_freep(&old_filename
);
2612 // if we're building a VOD playlist, skip writing the manifest multiple times, and just wait until the end
2613 if (hls
->pl_type
!= PLAYLIST_TYPE_VOD
) {
2614 if ((ret
= hls_window(s
, 0, vs
)) < 0) {
2615 av_log(s
, AV_LOG_WARNING
, "upload playlist failed, will retry with a new http session.\n");
2616 ff_format_io_close(s
, &vs
->out
);
2617 if ((ret
= hls_window(s
, 0, vs
)) < 0) {
2618 av_freep(&old_filename
);
2624 if (hls
->resend_init_file
&& hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
2625 ret
= hls_init_file_resend(s
, vs
);
2627 av_freep(&old_filename
);
2632 if (hls
->flags
& HLS_SINGLE_FILE
) {
2633 vs
->start_pos
+= vs
->size
;
2634 if (hls
->key_info_file
|| hls
->encrypt
)
2635 ret
= hls_start(s
, vs
);
2636 if (hls
->segment_type
== SEGMENT_TYPE_MPEGTS
&& oc
->oformat
->priv_class
&& oc
->priv_data
) {
2637 av_opt_set(oc
->priv_data
, "mpegts_flags", "resend_headers", 0);
2639 } else if (hls
->max_seg_size
> 0) {
2640 if (vs
->size
+ vs
->start_pos
>= hls
->max_seg_size
) {
2642 sls_flag_file_rename(hls
, vs
, old_filename
);
2643 ret
= hls_start(s
, vs
);
2645 /* When split segment by byte, the duration is short than hls_time,
2646 * so it is not enough one segment duration as hls_time, */
2648 vs
->start_pos
= new_start_pos
;
2652 sls_flag_file_rename(hls
, vs
, old_filename
);
2653 ret
= hls_start(s
, vs
);
2656 av_freep(&old_filename
);
2663 vs
->packets_written
++;
2665 ret
= ff_write_chained(oc
, stream_index
, pkt
, s
, 0);
2666 vs
->video_keyframe_size
+= pkt
->size
;
2667 if ((st
->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
) && (pkt
->flags
& AV_PKT_FLAG_KEY
)) {
2668 vs
->video_keyframe_size
= avio_tell(oc
->pb
);
2670 vs
->video_keyframe_pos
= avio_tell(vs
->out
);
2672 if (hls
->ignore_io_errors
)
2679 static void hls_deinit(AVFormatContext
*s
)
2681 HLSContext
*hls
= s
->priv_data
;
2683 VariantStream
*vs
= NULL
;
2685 for (i
= 0; i
< hls
->nb_varstreams
; i
++) {
2686 vs
= &hls
->var_streams
[i
];
2688 av_freep(&vs
->basename
);
2689 av_freep(&vs
->base_output_dirname
);
2690 av_freep(&vs
->fmp4_init_filename
);
2691 av_freep(&vs
->vtt_basename
);
2692 av_freep(&vs
->vtt_m3u8_name
);
2694 avformat_free_context(vs
->vtt_avf
);
2695 avformat_free_context(vs
->avf
);
2696 if (hls
->resend_init_file
)
2697 av_freep(&vs
->init_buffer
);
2698 hls_free_segments(vs
->segments
);
2699 hls_free_segments(vs
->old_segments
);
2700 av_freep(&vs
->m3u8_name
);
2701 av_freep(&vs
->streams
);
2704 ff_format_io_close(s
, &hls
->m3u8_out
);
2705 ff_format_io_close(s
, &hls
->sub_m3u8_out
);
2706 ff_format_io_close(s
, &hls
->http_delete
);
2707 av_freep(&hls
->key_basename
);
2708 av_freep(&hls
->var_streams
);
2709 av_freep(&hls
->cc_streams
);
2710 av_freep(&hls
->master_m3u8_url
);
2713 static int hls_write_trailer(struct AVFormatContext
*s
)
2715 HLSContext
*hls
= s
->priv_data
;
2716 AVFormatContext
*oc
= NULL
;
2717 AVFormatContext
*vtt_oc
= NULL
;
2718 char *old_filename
= NULL
;
2719 const char *proto
= NULL
;
2720 int use_temp_file
= 0;
2723 VariantStream
*vs
= NULL
;
2724 AVDictionary
*options
= NULL
;
2725 int range_length
, byterange_mode
;
2727 for (i
= 0; i
< hls
->nb_varstreams
; i
++) {
2728 char *filename
= NULL
;
2729 vs
= &hls
->var_streams
[i
];
2731 vtt_oc
= vs
->vtt_avf
;
2732 old_filename
= av_strdup(oc
->url
);
2735 if (!old_filename
) {
2736 return AVERROR(ENOMEM
);
2738 if (hls
->key_info_file
|| hls
->encrypt
) {
2739 av_dict_set(&options
, "encryption_key", vs
->key_string
, 0);
2740 av_dict_set(&options
, "encryption_iv", vs
->iv_string
, 0);
2741 filename
= av_asprintf("crypto:%s", oc
->url
);
2743 filename
= av_asprintf("%s", oc
->url
);
2746 av_dict_free(&options
);
2747 av_freep(&old_filename
);
2748 return AVERROR(ENOMEM
);
2751 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
2752 int range_length
= 0;
2753 if (!vs
->init_range_length
) {
2754 uint8_t *buffer
= NULL
;
2755 av_write_frame(oc
, NULL
); /* Flush any buffered data */
2757 range_length
= avio_close_dyn_buf(oc
->pb
, &buffer
);
2758 avio_write(vs
->out
, buffer
, range_length
);
2760 vs
->init_range_length
= range_length
;
2761 avio_open_dyn_buf(&oc
->pb
);
2762 vs
->packets_written
= 0;
2763 vs
->start_pos
= range_length
;
2764 byterange_mode
= (hls
->flags
& HLS_SINGLE_FILE
) || (hls
->max_seg_size
> 0);
2765 if (!byterange_mode
) {
2766 ff_format_io_close(s
, &vs
->out
);
2767 hlsenc_io_close(s
, &vs
->out
, vs
->base_output_dirname
);
2771 if (!(hls
->flags
& HLS_SINGLE_FILE
)) {
2772 set_http_options(s
, &options
, hls
);
2773 ret
= hlsenc_io_open(s
, &vs
->out
, filename
, &options
);
2775 av_log(s
, AV_LOG_ERROR
, "Failed to open file '%s'\n", oc
->url
);
2778 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
)
2779 write_styp(vs
->out
);
2781 ret
= flush_dynbuf(vs
, &range_length
);
2785 vs
->size
= range_length
;
2786 ret
= hlsenc_io_close(s
, &vs
->out
, filename
);
2788 av_log(s
, AV_LOG_WARNING
, "upload segment failed, will retry with a new http session.\n");
2789 ff_format_io_close(s
, &vs
->out
);
2790 ret
= hlsenc_io_open(s
, &vs
->out
, filename
, &options
);
2792 av_log(s
, AV_LOG_ERROR
, "Failed to open file '%s'\n", oc
->url
);
2795 reflush_dynbuf(vs
, &range_length
);
2796 ret
= hlsenc_io_close(s
, &vs
->out
, filename
);
2798 av_log(s
, AV_LOG_WARNING
, "Failed to upload file '%s' at the end.\n", oc
->url
);
2800 if (hls
->flags
& HLS_SINGLE_FILE
) {
2801 if (hls
->key_info_file
|| hls
->encrypt
) {
2802 vs
->size
= append_single_file(s
, vs
);
2804 hlsenc_io_close(s
, &vs
->out_single_file
, vs
->basename
);
2807 av_freep(&vs
->temp_buffer
);
2808 av_dict_free(&options
);
2809 av_freep(&filename
);
2810 av_write_trailer(oc
);
2812 proto
= avio_find_protocol_name(oc
->url
);
2813 use_temp_file
= proto
&& !strcmp(proto
, "file") && (hls
->flags
& HLS_TEMP_FILE
);
2816 // rename that segment from .tmp to the real one
2817 if (use_temp_file
&& !(hls
->flags
& HLS_SINGLE_FILE
)) {
2818 hls_rename_temp_file(s
, oc
);
2819 av_freep(&old_filename
);
2820 old_filename
= av_strdup(oc
->url
);
2822 if (!old_filename
) {
2823 return AVERROR(ENOMEM
);
2827 /* after av_write_trailer, then duration + 1 duration per packet */
2828 hls_append_segment(s
, hls
, vs
, vs
->duration
+ vs
->dpp
, vs
->start_pos
, vs
->size
);
2830 sls_flag_file_rename(hls
, vs
, old_filename
);
2834 av_write_trailer(vtt_oc
);
2835 vs
->size
= avio_tell(vs
->vtt_avf
->pb
) - vs
->start_pos
;
2836 ff_format_io_close(s
, &vtt_oc
->pb
);
2838 ret
= hls_window(s
, 1, vs
);
2840 av_log(s
, AV_LOG_WARNING
, "upload playlist failed, will retry with a new http session.\n");
2841 ff_format_io_close(s
, &vs
->out
);
2842 hls_window(s
, 1, vs
);
2844 ffio_free_dyn_buf(&oc
->pb
);
2846 av_free(old_filename
);
2853 static int hls_init(AVFormatContext
*s
)
2858 HLSContext
*hls
= s
->priv_data
;
2859 const char *pattern
;
2860 VariantStream
*vs
= NULL
;
2861 const char *vtt_pattern
= hls
->flags
& HLS_SINGLE_FILE
? ".vtt" : "%d.vtt";
2863 int http_base_proto
= ff_is_http_proto(s
->url
);
2864 int fmp4_init_filename_len
= strlen(hls
->fmp4_init_filename
) + 1;
2865 double initial_program_date_time
= av_gettime() / 1000000.0;
2867 if (hls
->use_localtime
) {
2868 pattern
= get_default_pattern_localtime_fmt(s
);
2870 pattern
= hls
->segment_type
== SEGMENT_TYPE_FMP4
? "%d.m4s" : "%d.ts";
2871 if (hls
->flags
& HLS_SINGLE_FILE
)
2875 hls
->has_default_key
= 0;
2876 hls
->has_video_m3u8
= 0;
2877 ret
= update_variant_stream_info(s
);
2879 av_log(s
, AV_LOG_ERROR
, "Variant stream info update failed with status %x\n",
2884 if (!hls
->method
&& http_base_proto
) {
2885 av_log(hls
, AV_LOG_WARNING
, "No HTTP method set, hls muxer defaulting to method PUT.\n");
2888 ret
= validate_name(hls
->nb_varstreams
, s
->url
);
2892 if (hls
->segment_filename
) {
2893 ret
= validate_name(hls
->nb_varstreams
, hls
->segment_filename
);
2898 if (av_strcasecmp(hls
->fmp4_init_filename
, "init.mp4")) {
2899 ret
= validate_name(hls
->nb_varstreams
, hls
->fmp4_init_filename
);
2904 if (hls
->subtitle_filename
) {
2905 ret
= validate_name(hls
->nb_varstreams
, hls
->subtitle_filename
);
2910 if (hls
->master_pl_name
) {
2911 ret
= update_master_pl_info(s
);
2913 av_log(s
, AV_LOG_ERROR
, "Master stream info update failed with status %x\n",
2919 if ((hls
->start_sequence_source_type
== HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH
) ||
2920 (hls
->start_sequence_source_type
== HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH
) ||
2921 (hls
->start_sequence_source_type
== HLS_START_SEQUENCE_AS_FORMATTED_DATETIME
)) {
2922 time_t t
= time(NULL
);
2923 if (hls
->start_sequence_source_type
== HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH
) {
2924 hls
->start_sequence
= av_gettime();
2925 } else if (hls
->start_sequence_source_type
== HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH
) {
2926 hls
->start_sequence
= (int64_t)t
;
2927 } else if (hls
->start_sequence_source_type
== HLS_START_SEQUENCE_AS_FORMATTED_DATETIME
) {
2929 struct tm
*p
, tmbuf
;
2930 if (!(p
= localtime_r(&t
, &tmbuf
)))
2931 return AVERROR(errno
);
2932 if (!strftime(b
, sizeof(b
), "%Y%m%d%H%M%S", p
))
2933 return AVERROR(ENOMEM
);
2934 hls
->start_sequence
= strtoll(b
, NULL
, 10);
2936 av_log(hls
, AV_LOG_DEBUG
, "start_number evaluated to %"PRId64
"\n", hls
->start_sequence
);
2939 hls
->recording_time
= hls
->init_time
&& hls
->max_nb_segments
> 0 ? hls
->init_time
: hls
->time
;
2941 if (hls
->flags
& HLS_SPLIT_BY_TIME
&& hls
->flags
& HLS_INDEPENDENT_SEGMENTS
) {
2942 // Independent segments cannot be guaranteed when splitting by time
2943 hls
->flags
&= ~HLS_INDEPENDENT_SEGMENTS
;
2944 av_log(s
, AV_LOG_WARNING
,
2945 "'split_by_time' and 'independent_segments' cannot be "
2946 "enabled together. Disabling 'independent_segments' flag\n");
2949 for (i
= 0; i
< hls
->nb_varstreams
; i
++) {
2950 vs
= &hls
->var_streams
[i
];
2952 ret
= format_name(s
->url
, &vs
->m3u8_name
, i
, vs
->varname
);
2956 vs
->sequence
= hls
->start_sequence
;
2957 vs
->start_pts
= AV_NOPTS_VALUE
;
2958 vs
->end_pts
= AV_NOPTS_VALUE
;
2959 vs
->current_segment_final_filename_fmt
[0] = '\0';
2960 vs
->initial_prog_date_time
= initial_program_date_time
;
2962 for (j
= 0; j
< vs
->nb_streams
; j
++) {
2963 vs
->has_video
+= vs
->streams
[j
]->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
;
2964 /* Get one video stream to reference for split segments
2965 * so use the first video stream index. */
2966 if ((vs
->has_video
== 1) && (vs
->streams
[j
]->codecpar
->codec_type
== AVMEDIA_TYPE_VIDEO
)) {
2967 vs
->reference_stream_index
= vs
->streams
[j
]->index
;
2969 vs
->has_subtitle
+= vs
->streams
[j
]->codecpar
->codec_type
== AVMEDIA_TYPE_SUBTITLE
;
2972 if (vs
->has_video
> 1)
2973 av_log(s
, AV_LOG_WARNING
, "More than a single video stream present, expect issues decoding it.\n");
2974 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
2975 vs
->oformat
= av_guess_format("mp4", NULL
, NULL
);
2977 vs
->oformat
= av_guess_format("mpegts", NULL
, NULL
);
2980 return AVERROR_MUXER_NOT_FOUND
;
2982 if (hls
->segment_filename
) {
2983 ret
= format_name(hls
->segment_filename
, &vs
->basename
, i
, vs
->varname
);
2987 p
= strrchr(vs
->m3u8_name
, '.');
2991 vs
->basename
= av_asprintf("%s%s", vs
->m3u8_name
, pattern
);
2993 return AVERROR(ENOMEM
);
2999 if (hls
->segment_type
== SEGMENT_TYPE_FMP4
) {
3000 if (hls
->nb_varstreams
> 1)
3001 fmp4_init_filename_len
+= strlen(POSTFIX_PATTERN
);
3002 if (hls
->flags
& HLS_SINGLE_FILE
) {
3003 vs
->fmp4_init_filename
= av_strdup(vs
->basename
);
3004 if (!vs
->fmp4_init_filename
)
3005 return AVERROR(ENOMEM
);
3007 vs
->fmp4_init_filename
= av_malloc(fmp4_init_filename_len
);
3008 if (!vs
->fmp4_init_filename
)
3009 return AVERROR(ENOMEM
);
3010 av_strlcpy(vs
->fmp4_init_filename
, hls
->fmp4_init_filename
,
3011 fmp4_init_filename_len
);
3012 if (hls
->nb_varstreams
> 1) {
3013 if (av_stristr(vs
->fmp4_init_filename
, "%v")) {
3014 av_freep(&vs
->fmp4_init_filename
);
3015 ret
= format_name(hls
->fmp4_init_filename
,
3016 &vs
->fmp4_init_filename
, i
, vs
->varname
);
3018 ret
= append_postfix(vs
->fmp4_init_filename
, fmp4_init_filename_len
, i
);
3024 if (hls
->use_localtime
) {
3026 char *expanded
= NULL
;
3028 r
= strftime_expand(vs
->fmp4_init_filename
, &expanded
);
3030 av_log(s
, AV_LOG_ERROR
, "Could not get segment filename with strftime\n");
3033 av_free(vs
->fmp4_init_filename
);
3034 vs
->fmp4_init_filename
= expanded
;
3037 p
= strrchr(vs
->m3u8_name
, '/');
3041 vs
->base_output_dirname
= av_asprintf("%s%s", vs
->m3u8_name
,
3042 vs
->fmp4_init_filename
);
3045 vs
->base_output_dirname
= av_strdup(vs
->fmp4_init_filename
);
3047 if (!vs
->base_output_dirname
)
3048 return AVERROR(ENOMEM
);
3052 ret
= hls
->use_localtime
? sls_flag_check_duration_size(hls
, vs
) : sls_flag_check_duration_size_index(hls
);
3056 if (vs
->has_subtitle
) {
3057 vs
->vtt_oformat
= av_guess_format("webvtt", NULL
, NULL
);
3058 if (!vs
->vtt_oformat
)
3059 return AVERROR_MUXER_NOT_FOUND
;
3061 p
= strrchr(vs
->m3u8_name
, '.');
3065 vs
->vtt_basename
= av_asprintf("%s%s", vs
->m3u8_name
, vtt_pattern
);
3066 if (!vs
->vtt_basename
)
3067 return AVERROR(ENOMEM
);
3069 if (hls
->subtitle_filename
) {
3070 ret
= format_name(hls
->subtitle_filename
, &vs
->vtt_m3u8_name
, i
, vs
->varname
);
3074 vs
->vtt_m3u8_name
= av_asprintf("%s_vtt.m3u8", vs
->m3u8_name
);
3075 if (!vs
->vtt_m3u8_name
)
3076 return AVERROR(ENOMEM
);
3082 if ((ret
= hls_mux_init(s
, vs
)) < 0)
3085 if (hls
->flags
& HLS_APPEND_LIST
) {
3086 parse_playlist(s
, vs
->m3u8_name
, vs
);
3087 vs
->discontinuity
= 1;
3088 if (hls
->init_time
> 0) {
3089 av_log(s
, AV_LOG_WARNING
, "append_list mode does not support hls_init_time,"
3090 " hls_init_time value will have no effect\n");
3092 hls
->recording_time
= hls
->time
;
3096 if ((ret
= hls_start(s
, vs
)) < 0)
3104 #define OFFSET(x) offsetof(HLSContext, x)
3105 #define E AV_OPT_FLAG_ENCODING_PARAM
3106 static const AVOption options
[] = {
3107 {"start_number", "set first number in the sequence", OFFSET(start_sequence
),AV_OPT_TYPE_INT64
, {.i64
= 0}, 0, INT64_MAX
, E
},
3108 {"hls_time", "set segment length", OFFSET(time
), AV_OPT_TYPE_DURATION
, {.i64
= 2000000}, 0, INT64_MAX
, E
},
3109 {"hls_init_time", "set segment length at init list", OFFSET(init_time
), AV_OPT_TYPE_DURATION
, {.i64
= 0}, 0, INT64_MAX
, E
},
3110 {"hls_list_size", "set maximum number of playlist entries", OFFSET(max_nb_segments
), AV_OPT_TYPE_INT
, {.i64
= 5}, 0, INT_MAX
, E
},
3111 {"hls_delete_threshold", "set number of unreferenced segments to keep before deleting", OFFSET(hls_delete_threshold
), AV_OPT_TYPE_INT
, {.i64
= 1}, 1, INT_MAX
, E
},
3112 {"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
},
3113 {"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
},
3114 {"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3115 {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3116 {"hls_segment_options","set segments files format options of hls", OFFSET(format_options
), AV_OPT_TYPE_DICT
, {.str
= NULL
}, 0, 0, E
},
3117 {"hls_segment_size", "maximum size per segment file, (in bytes)", OFFSET(max_seg_size
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, INT_MAX
, E
},
3118 {"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
},
3119 {"hls_enc", "enable AES128 encryption support", OFFSET(encrypt
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, E
},
3120 {"hls_enc_key", "hex-coded 16 byte key to encrypt the segments", OFFSET(key
), AV_OPT_TYPE_STRING
, .flags
= E
},
3121 {"hls_enc_key_url", "url to access the key to decrypt the segments", OFFSET(key_url
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3122 {"hls_enc_iv", "hex-coded 16 byte initialization vector", OFFSET(iv
), AV_OPT_TYPE_STRING
, .flags
= E
},
3123 {"hls_subtitle_path", "set path of hls subtitles", OFFSET(subtitle_filename
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3124 {"hls_segment_type", "set hls segment files type", OFFSET(segment_type
), AV_OPT_TYPE_INT
, {.i64
= SEGMENT_TYPE_MPEGTS
}, 0, SEGMENT_TYPE_FMP4
, E
, .unit
= "segment_type"},
3125 {"mpegts", "make segment file to mpegts files in m3u8", 0, AV_OPT_TYPE_CONST
, {.i64
= SEGMENT_TYPE_MPEGTS
}, 0, UINT_MAX
, E
, .unit
= "segment_type"},
3126 {"fmp4", "make segment file to fragment mp4 files in m3u8", 0, AV_OPT_TYPE_CONST
, {.i64
= SEGMENT_TYPE_FMP4
}, 0, UINT_MAX
, E
, .unit
= "segment_type"},
3127 {"hls_fmp4_init_filename", "set fragment mp4 file init filename", OFFSET(fmp4_init_filename
), AV_OPT_TYPE_STRING
, {.str
= "init.mp4"}, 0, 0, E
},
3128 {"hls_fmp4_init_resend", "resend fragment mp4 init file after refresh m3u8 every time", OFFSET(resend_init_file
), AV_OPT_TYPE_BOOL
, {.i64
= 0 }, 0, 1, E
},
3129 {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags
), AV_OPT_TYPE_FLAGS
, {.i64
= 0 }, 0, UINT_MAX
, E
, .unit
= "flags"},
3130 {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_SINGLE_FILE
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3131 {"temp_file", "write segment and playlist to temporary file and rename when complete", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_TEMP_FILE
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3132 {"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
, .unit
= "flags"},
3133 {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_ROUND_DURATIONS
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3134 {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_DISCONT_START
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3135 {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_OMIT_ENDLIST
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3136 {"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
, .unit
= "flags"},
3137 {"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_APPEND_LIST
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3138 {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_PROGRAM_DATE_TIME
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3139 {"second_level_segment_index", "include segment index in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_SECOND_LEVEL_SEGMENT_INDEX
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3140 {"second_level_segment_duration", "include segment duration in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_SECOND_LEVEL_SEGMENT_DURATION
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3141 {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_SECOND_LEVEL_SEGMENT_SIZE
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3142 {"periodic_rekey", "reload keyinfo file periodically for re-keying", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_PERIODIC_REKEY
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3143 {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST
, { .i64
= HLS_INDEPENDENT_SEGMENTS
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3144 {"iframes_only", "add EXT-X-I-FRAMES-ONLY, whenever applicable", 0, AV_OPT_TYPE_CONST
, { .i64
= HLS_I_FRAMES_ONLY
}, 0, UINT_MAX
, E
, .unit
= "flags"},
3145 {"strftime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime
), AV_OPT_TYPE_BOOL
, {.i64
= 0 }, 0, 1, E
},
3146 {"strftime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir
), AV_OPT_TYPE_BOOL
, {.i64
= 0 }, 0, 1, E
},
3147 {"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
, .unit
= "pl_type" },
3148 {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST
, {.i64
= PLAYLIST_TYPE_EVENT
}, INT_MIN
, INT_MAX
, E
, .unit
= "pl_type" },
3149 {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST
, {.i64
= PLAYLIST_TYPE_VOD
}, INT_MIN
, INT_MAX
, E
, .unit
= "pl_type" },
3150 {"method", "set the HTTP method(default: PUT)", OFFSET(method
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3151 {"hls_start_number_source", "set source of first number in sequence", OFFSET(start_sequence_source_type
), AV_OPT_TYPE_INT
, {.i64
= HLS_START_SEQUENCE_AS_START_NUMBER
}, 0, HLS_START_SEQUENCE_LAST
-1, E
, .unit
= "start_sequence_source_type" },
3152 {"generic", "start_number value (default)", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_START_SEQUENCE_AS_START_NUMBER
}, INT_MIN
, INT_MAX
, E
, .unit
= "start_sequence_source_type" },
3153 {"epoch", "seconds since epoch", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH
}, INT_MIN
, INT_MAX
, E
, .unit
= "start_sequence_source_type" },
3154 {"epoch_us", "microseconds since epoch", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH
}, INT_MIN
, INT_MAX
, E
, .unit
= "start_sequence_source_type" },
3155 {"datetime", "current datetime as YYYYMMDDhhmmss", 0, AV_OPT_TYPE_CONST
, {.i64
= HLS_START_SEQUENCE_AS_FORMATTED_DATETIME
}, INT_MIN
, INT_MAX
, E
, .unit
= "start_sequence_source_type" },
3156 {"http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3157 {"var_stream_map", "Variant stream map string", OFFSET(var_stream_map
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3158 {"cc_stream_map", "Closed captions stream map string", OFFSET(cc_stream_map
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3159 {"master_pl_name", "Create HLS master playlist with this name", OFFSET(master_pl_name
), AV_OPT_TYPE_STRING
, {.str
= NULL
}, 0, 0, E
},
3160 {"master_pl_publish_rate", "Publish master play list every after this many segment intervals", OFFSET(master_publish_rate
), AV_OPT_TYPE_INT
, {.i64
= 0}, 0, UINT_MAX
, E
},
3161 {"http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent
), AV_OPT_TYPE_BOOL
, {.i64
= 0 }, 0, 1, E
},
3162 {"timeout", "set timeout for socket I/O operations", OFFSET(timeout
), AV_OPT_TYPE_DURATION
, { .i64
= -1 }, -1, INT_MAX
, .flags
= E
},
3163 {"ignore_io_errors", "Ignore IO errors for stable long-duration runs with network output", OFFSET(ignore_io_errors
), AV_OPT_TYPE_BOOL
, { .i64
= 0 }, 0, 1, E
},
3164 {"headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers
), AV_OPT_TYPE_STRING
, { .str
= NULL
}, 0, 0, E
},
3168 static const AVClass hls_class
= {
3169 .class_name
= "hls muxer",
3170 .item_name
= av_default_item_name
,
3172 .version
= LIBAVUTIL_VERSION_INT
,
3176 const FFOutputFormat ff_hls_muxer
= {
3178 .p
.long_name
= NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
3179 .p
.extensions
= "m3u8",
3180 .p
.audio_codec
= AV_CODEC_ID_AAC
,
3181 .p
.video_codec
= AV_CODEC_ID_H264
,
3182 .p
.subtitle_codec
= AV_CODEC_ID_WEBVTT
,
3183 .p
.flags
= AVFMT_NOFILE
| AVFMT_GLOBALHEADER
| AVFMT_NODIMENSIONS
,
3184 .p
.priv_class
= &hls_class
,
3185 .flags_internal
= FF_OFMT_FLAG_ALLOW_FLUSH
,
3186 .priv_data_size
= sizeof(HLSContext
),
3188 .write_header
= hls_write_header
,
3189 .write_packet
= hls_write_packet
,
3190 .write_trailer
= hls_write_trailer
,
3191 .deinit
= hls_deinit
,