FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/hlsenc.c
Date: 2022-11-26 13:19:19
Exec Total Coverage
Lines: 708 1831 38.7%
Branches: 417 1350 30.9%

Line Branch Exec Source
1 /*
2 * Apple HTTP Live Streaming segmenter
3 * Copyright (c) 2012, Luca Barbato
4 * Copyright (c) 2017 Akamai Technologies, Inc.
5 *
6 * This file is part of FFmpeg.
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include "config.h"
24 #include "config_components.h"
25 #include <stdint.h>
26 #if HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 #if CONFIG_GCRYPT
31 #include <gcrypt.h>
32 #elif CONFIG_OPENSSL
33 #include <openssl/rand.h>
34 #endif
35
36 #include "libavutil/avassert.h"
37 #include "libavutil/mathematics.h"
38 #include "libavutil/avstring.h"
39 #include "libavutil/bprint.h"
40 #include "libavutil/intreadwrite.h"
41 #include "libavutil/opt.h"
42 #include "libavutil/log.h"
43 #include "libavutil/time.h"
44 #include "libavutil/time_internal.h"
45
46 #include "libavcodec/avcodec.h"
47
48 #include "avformat.h"
49 #include "avio_internal.h"
50 #include "avc.h"
51 #if CONFIG_HTTP_PROTOCOL
52 #include "http.h"
53 #endif
54 #include "hlsplaylist.h"
55 #include "internal.h"
56 #include "mux.h"
57 #include "os_support.h"
58
59 typedef enum {
60 HLS_START_SEQUENCE_AS_START_NUMBER = 0,
61 HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH = 1,
62 HLS_START_SEQUENCE_AS_FORMATTED_DATETIME = 2, // YYYYMMDDhhmmss
63 HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH = 3,
64 HLS_START_SEQUENCE_LAST, // unused
65 } StartSequenceSourceType;
66
67 typedef enum {
68 CODEC_ATTRIBUTE_WRITTEN = 0,
69 CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN,
70 } CodecAttributeStatus;
71
72 #define KEYSIZE 16
73 #define LINE_BUFFER_SIZE MAX_URL_SIZE
74 #define HLS_MICROSECOND_UNIT 1000000
75 #define BUFSIZE (16 * 1024)
76 #define POSTFIX_PATTERN "_%d"
77
78 typedef struct HLSSegment {
79 char filename[MAX_URL_SIZE];
80 char sub_filename[MAX_URL_SIZE];
81 double duration; /* in seconds */
82 int discont;
83 int64_t pos;
84 int64_t size;
85 int64_t keyframe_pos;
86 int64_t keyframe_size;
87 unsigned var_stream_idx;
88
89 char key_uri[LINE_BUFFER_SIZE + 1];
90 char iv_string[KEYSIZE*2 + 1];
91
92 struct HLSSegment *next;
93 double discont_program_date_time;
94 } HLSSegment;
95
96 typedef enum HLSFlags {
97 // Generate a single media file and use byte ranges in the playlist.
98 HLS_SINGLE_FILE = (1 << 0),
99 HLS_DELETE_SEGMENTS = (1 << 1),
100 HLS_ROUND_DURATIONS = (1 << 2),
101 HLS_DISCONT_START = (1 << 3),
102 HLS_OMIT_ENDLIST = (1 << 4),
103 HLS_SPLIT_BY_TIME = (1 << 5),
104 HLS_APPEND_LIST = (1 << 6),
105 HLS_PROGRAM_DATE_TIME = (1 << 7),
106 HLS_SECOND_LEVEL_SEGMENT_INDEX = (1 << 8), // include segment index in segment filenames when use_localtime e.g.: %%03d
107 HLS_SECOND_LEVEL_SEGMENT_DURATION = (1 << 9), // include segment duration (microsec) in segment filenames when use_localtime e.g.: %%09t
108 HLS_SECOND_LEVEL_SEGMENT_SIZE = (1 << 10), // include segment size (bytes) in segment filenames when use_localtime e.g.: %%014s
109 HLS_TEMP_FILE = (1 << 11),
110 HLS_PERIODIC_REKEY = (1 << 12),
111 HLS_INDEPENDENT_SEGMENTS = (1 << 13),
112 HLS_I_FRAMES_ONLY = (1 << 14),
113 } HLSFlags;
114
115 typedef enum {
116 SEGMENT_TYPE_MPEGTS,
117 SEGMENT_TYPE_FMP4,
118 } SegmentType;
119
120 typedef struct VariantStream {
121 unsigned var_stream_idx;
122 unsigned number;
123 int64_t sequence;
124 const AVOutputFormat *oformat;
125 const AVOutputFormat *vtt_oformat;
126 AVIOContext *out;
127 AVIOContext *out_single_file;
128 int packets_written;
129 int init_range_length;
130 uint8_t *temp_buffer;
131 uint8_t *init_buffer;
132
133 AVFormatContext *avf;
134 AVFormatContext *vtt_avf;
135
136 int has_video;
137 int has_subtitle;
138 int new_start;
139 int start_pts_from_audio;
140 double dpp; // duration per packet
141 int64_t start_pts;
142 int64_t end_pts;
143 int64_t video_lastpos;
144 int64_t video_keyframe_pos;
145 int64_t video_keyframe_size;
146 double duration; // last segment duration computed so far, in seconds
147 int64_t start_pos; // last segment starting position
148 int64_t size; // last segment size
149 int nb_entries;
150 int discontinuity_set;
151 int discontinuity;
152 int reference_stream_index;
153
154 HLSSegment *segments;
155 HLSSegment *last_segment;
156 HLSSegment *old_segments;
157
158 char *basename_tmp;
159 char *basename;
160 char *vtt_basename;
161 char *vtt_m3u8_name;
162 char *m3u8_name;
163
164 double initial_prog_date_time;
165 char current_segment_final_filename_fmt[MAX_URL_SIZE]; // when renaming segments
166
167 char *fmp4_init_filename;
168 char *base_output_dirname;
169
170 int encrypt_started;
171
172 char key_file[LINE_BUFFER_SIZE + 1];
173 char key_uri[LINE_BUFFER_SIZE + 1];
174 char key_string[KEYSIZE*2 + 1];
175 char iv_string[KEYSIZE*2 + 1];
176
177 AVStream **streams;
178 char codec_attr[128];
179 CodecAttributeStatus attr_status;
180 unsigned int nb_streams;
181 int m3u8_created; /* status of media play-list creation */
182 int is_default; /* default status of audio group */
183 const char *language; /* audio language name */
184 const char *agroup; /* audio group name */
185 const char *sgroup; /* subtitle group name */
186 const char *ccgroup; /* closed caption group name */
187 const char *varname; /* variant name */
188 } VariantStream;
189
190 typedef struct ClosedCaptionsStream {
191 const char *ccgroup; /* closed caption group name */
192 const char *instreamid; /* closed captions INSTREAM-ID */
193 const char *language; /* closed captions language */
194 } ClosedCaptionsStream;
195
196 typedef struct HLSContext {
197 const AVClass *class; // Class for private options.
198 int64_t start_sequence;
199 uint32_t start_sequence_source_type; // enum StartSequenceSourceType
200
201 int64_t time; // Set by a private option.
202 int64_t init_time; // Set by a private option.
203 int max_nb_segments; // Set by a private option.
204 int hls_delete_threshold; // Set by a private option.
205 uint32_t flags; // enum HLSFlags
206 uint32_t pl_type; // enum PlaylistType
207 char *segment_filename;
208 char *fmp4_init_filename;
209 int segment_type;
210 int resend_init_file; ///< resend init file into disk after refresh m3u8
211
212 int use_localtime; ///< flag to expand filename with localtime
213 int use_localtime_mkdir;///< flag to mkdir dirname in timebased filename
214 int allowcache;
215 int64_t recording_time;
216 int64_t max_seg_size; // every segment file max size
217
218 char *baseurl;
219 char *vtt_format_options_str;
220 char *subtitle_filename;
221 AVDictionary *format_options;
222
223 int encrypt;
224 char *key;
225 char *key_url;
226 char *iv;
227 char *key_basename;
228 int encrypt_started;
229
230 char *key_info_file;
231 char key_file[LINE_BUFFER_SIZE + 1];
232 char key_uri[LINE_BUFFER_SIZE + 1];
233 char key_string[KEYSIZE*2 + 1];
234 char iv_string[KEYSIZE*2 + 1];
235 AVDictionary *vtt_format_options;
236
237 char *method;
238 char *user_agent;
239
240 VariantStream *var_streams;
241 unsigned int nb_varstreams;
242 ClosedCaptionsStream *cc_streams;
243 unsigned int nb_ccstreams;
244
245 int master_m3u8_created; /* status of master play-list creation */
246 char *master_m3u8_url; /* URL of the master m3u8 file */
247 int version; /* HLS version */
248 char *var_stream_map; /* user specified variant stream map string */
249 char *cc_stream_map; /* user specified closed caption streams map string */
250 char *master_pl_name;
251 unsigned int master_publish_rate;
252 int http_persistent;
253 AVIOContext *m3u8_out;
254 AVIOContext *sub_m3u8_out;
255 int64_t timeout;
256 int ignore_io_errors;
257 char *headers;
258 int has_default_key; /* has DEFAULT field of var_stream_map */
259 int has_video_m3u8; /* has video stream m3u8 list */
260 } HLSContext;
261
262 static int strftime_expand(const char *fmt, char **dest)
263 {
264 int r = 1;
265 time_t now0;
266 struct tm *tm, tmpbuf;
267 char *buf;
268
269 buf = av_mallocz(MAX_URL_SIZE);
270 if (!buf)
271 return AVERROR(ENOMEM);
272
273 time(&now0);
274 tm = localtime_r(&now0, &tmpbuf);
275 r = strftime(buf, MAX_URL_SIZE, fmt, tm);
276 if (!r) {
277 av_free(buf);
278 return AVERROR(EINVAL);
279 }
280 *dest = buf;
281
282 return r;
283 }
284
285 119 static int hlsenc_io_open(AVFormatContext *s, AVIOContext **pb, const char *filename,
286 AVDictionary **options)
287 {
288 119 HLSContext *hls = s->priv_data;
289
1/2
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
119 int http_base_proto = filename ? ff_is_http_proto(filename) : 0;
290 119 int err = AVERROR_MUXER_NOT_FOUND;
291
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
119 if (!*pb || !http_base_proto || !hls->http_persistent) {
292 119 err = s->io_open(s, pb, filename, AVIO_FLAG_WRITE, options);
293 #if CONFIG_HTTP_PROTOCOL
294 } else {
295 URLContext *http_url_context = ffio_geturlcontext(*pb);
296 av_assert0(http_url_context);
297 err = ff_http_do_new_request(http_url_context, filename);
298 if (err < 0)
299 ff_format_io_close(s, pb);
300
301 #endif
302 }
303 119 return err;
304 }
305
306 185 static int hlsenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename)
307 {
308 185 HLSContext *hls = s->priv_data;
309
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 66 times.
185 int http_base_proto = filename ? ff_is_http_proto(filename) : 0;
310 185 int ret = 0;
311
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 119 times.
185 if (!*pb)
312 66 return ret;
313
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
119 if (!http_base_proto || !hls->http_persistent || hls->key_info_file || hls->encrypt) {
314 119 ff_format_io_close(s, pb);
315 #if CONFIG_HTTP_PROTOCOL
316 } else {
317 URLContext *http_url_context = ffio_geturlcontext(*pb);
318 av_assert0(http_url_context);
319 avio_flush(*pb);
320 ret = ffurl_shutdown(http_url_context, AVIO_FLAG_WRITE);
321 #endif
322 }
323 119 return ret;
324 }
325
326 118 static void set_http_options(AVFormatContext *s, AVDictionary **options, HLSContext *c)
327 {
328 118 int http_base_proto = ff_is_http_proto(s->url);
329
330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (c->method) {
331 av_dict_set(options, "method", c->method, 0);
332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 } else if (http_base_proto) {
333 av_dict_set(options, "method", "PUT", 0);
334 }
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (c->user_agent)
336 av_dict_set(options, "user_agent", c->user_agent, 0);
337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (c->http_persistent)
338 av_dict_set_int(options, "multiple_requests", 1, 0);
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (c->timeout >= 0)
340 av_dict_set_int(options, "timeout", c->timeout, 0);
341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
118 if (c->headers)
342 av_dict_set(options, "headers", c->headers, 0);
343 118 }
344
345 10 static void write_codec_attr(AVStream *st, VariantStream *vs)
346 {
347 10 int codec_strlen = strlen(vs->codec_attr);
348 char attr[32];
349
350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
351 return;
352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (vs->attr_status == CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN)
353 return;
354
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
356 uint8_t *data = st->codecpar->extradata;
357 if (data && (data[0] | data[1] | data[2]) == 0 && data[3] == 1 && (data[4] & 0x1F) == 7) {
358 snprintf(attr, sizeof(attr),
359 "avc1.%02x%02x%02x", data[5], data[6], data[7]);
360 } else {
361 goto fail;
362 }
363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC) {
364 uint8_t *data = st->codecpar->extradata;
365 int profile = FF_PROFILE_UNKNOWN;
366 int level = FF_LEVEL_UNKNOWN;
367
368 if (st->codecpar->profile != FF_PROFILE_UNKNOWN)
369 profile = st->codecpar->profile;
370 if (st->codecpar->level != FF_LEVEL_UNKNOWN)
371 level = st->codecpar->level;
372
373 /* check the boundary of data which from current position is small than extradata_size */
374 while (data && (data - st->codecpar->extradata + 19) < st->codecpar->extradata_size) {
375 /* get HEVC SPS NAL and seek to profile_tier_level */
376 if (!(data[0] | data[1] | data[2]) && data[3] == 1 && ((data[4] & 0x7E) == 0x42)) {
377 uint8_t *rbsp_buf;
378 int remain_size = 0;
379 int rbsp_size = 0;
380 /* skip start code + nalu header */
381 data += 6;
382 /* process by reference General NAL unit syntax */
383 remain_size = st->codecpar->extradata_size - (data - st->codecpar->extradata);
384 rbsp_buf = ff_nal_unit_extract_rbsp(data, remain_size, &rbsp_size, 0);
385 if (!rbsp_buf)
386 return;
387 if (rbsp_size < 13) {
388 av_freep(&rbsp_buf);
389 break;
390 }
391 /* skip sps_video_parameter_set_id u(4),
392 * sps_max_sub_layers_minus1 u(3),
393 * and sps_temporal_id_nesting_flag u(1) */
394 profile = rbsp_buf[1] & 0x1f;
395 /* skip 8 + 8 + 32 + 4 + 43 + 1 bit */
396 level = rbsp_buf[12];
397 av_freep(&rbsp_buf);
398 break;
399 }
400 data++;
401 }
402 if (st->codecpar->codec_tag == MKTAG('h','v','c','1') &&
403 profile != FF_PROFILE_UNKNOWN &&
404 level != FF_LEVEL_UNKNOWN) {
405 snprintf(attr, sizeof(attr), "%s.%d.4.L%d.B01", av_fourcc2str(st->codecpar->codec_tag), profile, level);
406 } else
407 goto fail;
408
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 } else if (st->codecpar->codec_id == AV_CODEC_ID_MP2) {
409 9 snprintf(attr, sizeof(attr), "mp4a.40.33");
410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } else if (st->codecpar->codec_id == AV_CODEC_ID_MP3) {
411 snprintf(attr, sizeof(attr), "mp4a.40.34");
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } else if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
413 /* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 5 and 29 respectively */
414 snprintf(attr, sizeof(attr), "mp4a.40.2");
415
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (st->codecpar->codec_id == AV_CODEC_ID_AC3) {
416 1 snprintf(attr, sizeof(attr), "ac-3");
417 } else if (st->codecpar->codec_id == AV_CODEC_ID_EAC3) {
418 snprintf(attr, sizeof(attr), "ec-3");
419 } else {
420 goto fail;
421 }
422 // Don't write the same attribute multiple times
423
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 if (!av_stristr(vs->codec_attr, attr)) {
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 snprintf(vs->codec_attr + codec_strlen,
425 sizeof(vs->codec_attr) - codec_strlen,
426 "%s%s", codec_strlen ? "," : "", attr);
427 }
428 10 return;
429
430 fail:
431 vs->codec_attr[0] = '\0';
432 vs->attr_status = CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN;
433 return;
434 }
435
436 static int replace_str_data_in_filename(char **s, const char *filename, char placeholder, const char *datastring)
437 {
438 const char *p;
439 char c;
440 int addchar_count;
441 int found_count = 0;
442 AVBPrint buf;
443 int ret;
444
445 av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
446
447 p = filename;
448 for (;;) {
449 c = *p;
450 if (c == '\0')
451 break;
452 if (c == '%' && *(p+1) == '%') // %%
453 addchar_count = 2;
454 else if (c == '%' && *(p+1) == placeholder) {
455 av_bprintf(&buf, "%s", datastring);
456 p += 2;
457 addchar_count = 0;
458 found_count ++;
459 } else
460 addchar_count = 1;
461
462 if (addchar_count > 0) {
463 av_bprint_append_data(&buf, p, addchar_count);
464 p += addchar_count;
465 }
466 }
467 if (!av_bprint_is_complete(&buf)) {
468 av_bprint_finalize(&buf, NULL);
469 return AVERROR(ENOMEM);
470 }
471 if ((ret = av_bprint_finalize(&buf, s)) < 0)
472 return ret;
473 return found_count;
474 }
475
476 50 static int replace_int_data_in_filename(char **s, const char *filename, char placeholder, int64_t number)
477 {
478 const char *p;
479 char c;
480 int nd, addchar_count;
481 50 int found_count = 0;
482 AVBPrint buf;
483 int ret;
484
485 50 av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
486
487 50 p = filename;
488 for (;;) {
489 4329 c = *p;
490
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 4279 times.
4329 if (c == '\0')
491 50 break;
492
3/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 4229 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
4279 if (c == '%' && *(p+1) == '%') // %%
493 addchar_count = 2;
494
5/6
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 4229 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
4279 else if (c == '%' && (av_isdigit(*(p+1)) || *(p+1) == placeholder)) {
495 50 nd = 0;
496 50 addchar_count = 1;
497
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 50 times.
82 while (av_isdigit(*(p + addchar_count))) {
498 32 nd = nd * 10 + *(p + addchar_count) - '0';
499 32 addchar_count++;
500 }
501
502
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (*(p + addchar_count) == placeholder) {
503
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 av_bprintf(&buf, "%0*"PRId64, (number < 0) ? nd : nd++, number);
504 50 p += (addchar_count + 1);
505 50 addchar_count = 0;
506 50 found_count++;
507 }
508
509 } else
510 4229 addchar_count = 1;
511
512 4279 av_bprint_append_data(&buf, p, addchar_count);
513 4279 p += addchar_count;
514 }
515
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
50 if (!av_bprint_is_complete(&buf)) {
516 av_bprint_finalize(&buf, NULL);
517 return AVERROR(ENOMEM);
518 }
519
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
50 if ((ret = av_bprint_finalize(&buf, s)) < 0)
520 return ret;
521 50 return found_count;
522 }
523
524 5 static void write_styp(AVIOContext *pb)
525 {
526 5 avio_wb32(pb, 24);
527 5 ffio_wfourcc(pb, "styp");
528 5 ffio_wfourcc(pb, "msdh");
529 5 avio_wb32(pb, 0); /* minor */
530 5 ffio_wfourcc(pb, "msdh");
531 5 ffio_wfourcc(pb, "msix");
532 5 }
533
534 60 static int flush_dynbuf(VariantStream *vs, int *range_length)
535 {
536 60 AVFormatContext *ctx = vs->avf;
537
538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (!ctx->pb) {
539 return AVERROR(EINVAL);
540 }
541
542 // flush
543 60 av_write_frame(ctx, NULL);
544
545 // write out to file
546 60 *range_length = avio_close_dyn_buf(ctx->pb, &vs->temp_buffer);
547 60 ctx->pb = NULL;
548 60 avio_write(vs->out, vs->temp_buffer, *range_length);
549 60 avio_flush(vs->out);
550
551 // re-open buffer
552 60 return avio_open_dyn_buf(&ctx->pb);
553 }
554
555 static void reflush_dynbuf(VariantStream *vs, int *range_length)
556 {
557 // re-open buffer
558 avio_write(vs->out, vs->temp_buffer, *range_length);
559 }
560
561 #if HAVE_DOS_PATHS
562 #define SEPARATOR '\\'
563 #else
564 #define SEPARATOR '/'
565 #endif
566
567 static int hls_delete_file(HLSContext *hls, AVFormatContext *avf,
568 const char *path, const char *proto)
569 {
570 if (hls->method || (proto && !av_strcasecmp(proto, "http"))) {
571 AVDictionary *opt = NULL;
572 AVIOContext *out = NULL;
573 int ret;
574 set_http_options(avf, &opt, hls);
575 av_dict_set(&opt, "method", "DELETE", 0);
576 ret = avf->io_open(avf, &out, path, AVIO_FLAG_WRITE, &opt);
577 av_dict_free(&opt);
578 if (ret < 0)
579 return hls->ignore_io_errors ? 1 : ret;
580 ff_format_io_close(avf, &out);
581 } else if (unlink(path) < 0) {
582 av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n",
583 path, strerror(errno));
584 }
585 return 0;
586 }
587
588 static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls,
589 VariantStream *vs)
590 {
591
592 HLSSegment *segment, *previous_segment = NULL;
593 float playlist_duration = 0.0f;
594 int ret = 0;
595 int segment_cnt = 0;
596 AVBPrint path;
597 const char *dirname = NULL;
598 char *dirname_r = NULL;
599 char *dirname_repl = NULL;
600 const char *vtt_dirname = NULL;
601 char *vtt_dirname_r = NULL;
602 const char *proto = NULL;
603
604 av_bprint_init(&path, 0, AV_BPRINT_SIZE_UNLIMITED);
605
606 segment = vs->segments;
607 while (segment) {
608 playlist_duration += segment->duration;
609 segment = segment->next;
610 }
611
612 segment = vs->old_segments;
613 segment_cnt = 0;
614 while (segment) {
615 playlist_duration -= segment->duration;
616 previous_segment = segment;
617 segment = previous_segment->next;
618 segment_cnt++;
619 if (playlist_duration <= -previous_segment->duration) {
620 previous_segment->next = NULL;
621 break;
622 }
623 if (segment_cnt >= hls->hls_delete_threshold) {
624 previous_segment->next = NULL;
625 break;
626 }
627 }
628
629 if (segment && !hls->use_localtime_mkdir) {
630 dirname_r = hls->segment_filename ? av_strdup(hls->segment_filename): av_strdup(vs->avf->url);
631 dirname = av_dirname(dirname_r);
632 }
633
634 /* if %v is present in the file's directory
635 * all segment belongs to the same variant, so do it only once before the loop*/
636 if (dirname && av_stristr(dirname, "%v")) {
637 if (!vs->varname) {
638 if (replace_int_data_in_filename(&dirname_repl, dirname, 'v', segment->var_stream_idx) < 1) {
639 ret = AVERROR(EINVAL);
640 goto fail;
641 }
642 } else {
643 if (replace_str_data_in_filename(&dirname_repl, dirname, 'v', vs->varname) < 1) {
644 ret = AVERROR(EINVAL);
645 goto fail;
646 }
647 }
648
649 dirname = dirname_repl;
650 }
651
652 while (segment) {
653 av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n",
654 segment->filename);
655 if (!hls->use_localtime_mkdir) // segment->filename contains basename only
656 av_bprintf(&path, "%s%c", dirname, SEPARATOR);
657 av_bprintf(&path, "%s", segment->filename);
658
659 if (!av_bprint_is_complete(&path)) {
660 ret = AVERROR(ENOMEM);
661 goto fail;
662 }
663
664 proto = avio_find_protocol_name(s->url);
665 if (ret = hls_delete_file(hls, vs->avf, path.str, proto))
666 goto fail;
667
668 if ((segment->sub_filename[0] != '\0')) {
669 vtt_dirname_r = av_strdup(vs->vtt_avf->url);
670 vtt_dirname = av_dirname(vtt_dirname_r);
671
672 av_bprint_clear(&path);
673 av_bprintf(&path, "%s%c%s", vtt_dirname, SEPARATOR,
674 segment->sub_filename);
675 av_freep(&vtt_dirname_r);
676
677 if (!av_bprint_is_complete(&path)) {
678 ret = AVERROR(ENOMEM);
679 goto fail;
680 }
681
682 if (ret = hls_delete_file(hls, vs->vtt_avf, path.str, proto))
683 goto fail;
684 }
685 av_bprint_clear(&path);
686 previous_segment = segment;
687 segment = previous_segment->next;
688 av_freep(&previous_segment);
689 }
690
691 fail:
692 av_bprint_finalize(&path, NULL);
693 av_freep(&dirname_r);
694 av_freep(&dirname_repl);
695
696 return ret;
697 }
698
699 static int randomize(uint8_t *buf, int len)
700 {
701 #if CONFIG_GCRYPT
702 gcry_randomize(buf, len, GCRY_VERY_STRONG_RANDOM);
703 return 0;
704 #elif CONFIG_OPENSSL
705 if (RAND_bytes(buf, len))
706 return 0;
707 #else
708 return AVERROR(ENOSYS);
709 #endif
710 return AVERROR(EINVAL);
711 }
712
713 static int do_encrypt(AVFormatContext *s, VariantStream *vs)
714 {
715 HLSContext *hls = s->priv_data;
716 int ret;
717 int len;
718 AVIOContext *pb;
719 uint8_t key[KEYSIZE];
720 char * key_basename_source = (hls->master_m3u8_url) ? hls->master_m3u8_url : s->url;
721
722 len = strlen(key_basename_source) + 4 + 1;
723 hls->key_basename = av_mallocz(len);
724 if (!hls->key_basename)
725 return AVERROR(ENOMEM);
726
727 av_strlcpy(hls->key_basename, key_basename_source, len);
728 av_strlcat(hls->key_basename, ".key", len);
729
730 if (hls->key_url) {
731 av_strlcpy(hls->key_file, hls->key_url, sizeof(hls->key_file));
732 av_strlcpy(hls->key_uri, hls->key_url, sizeof(hls->key_uri));
733 } else {
734 av_strlcpy(hls->key_file, hls->key_basename, sizeof(hls->key_file));
735 av_strlcpy(hls->key_uri, hls->key_basename, sizeof(hls->key_uri));
736 }
737
738 if (!*hls->iv_string) {
739 uint8_t iv[16] = { 0 };
740 char buf[33];
741
742 if (!hls->iv) {
743 AV_WB64(iv + 8, vs->sequence);
744 } else {
745 memcpy(iv, hls->iv, sizeof(iv));
746 }
747 ff_data_to_hex(buf, iv, sizeof(iv), 0);
748 memcpy(hls->iv_string, buf, sizeof(hls->iv_string));
749 }
750
751 if (!*hls->key_uri) {
752 av_log(hls, AV_LOG_ERROR, "no key URI specified in key info file\n");
753 return AVERROR(EINVAL);
754 }
755
756 if (!*hls->key_file) {
757 av_log(hls, AV_LOG_ERROR, "no key file specified in key info file\n");
758 return AVERROR(EINVAL);
759 }
760
761 if (!*hls->key_string) {
762 AVDictionary *options = NULL;
763 if (!hls->key) {
764 if ((ret = randomize(key, sizeof(key))) < 0) {
765 av_log(s, AV_LOG_ERROR, "Cannot generate a strong random key\n");
766 return ret;
767 }
768 } else {
769 memcpy(key, hls->key, sizeof(key));
770 }
771
772 ff_data_to_hex(hls->key_string, key, sizeof(key), 0);
773 set_http_options(s, &options, hls);
774 ret = s->io_open(s, &pb, hls->key_file, AVIO_FLAG_WRITE, &options);
775 av_dict_free(&options);
776 if (ret < 0)
777 return ret;
778 avio_seek(pb, 0, SEEK_CUR);
779 avio_write(pb, key, KEYSIZE);
780 avio_close(pb);
781 }
782 return 0;
783 }
784
785
786 static int hls_encryption_start(AVFormatContext *s, VariantStream *vs)
787 {
788 HLSContext *hls = s->priv_data;
789 int ret;
790 AVIOContext *pb;
791 uint8_t key[KEYSIZE];
792 AVDictionary *options = NULL;
793
794 set_http_options(s, &options, hls);
795 ret = s->io_open(s, &pb, hls->key_info_file, AVIO_FLAG_READ, &options);
796 av_dict_free(&options);
797 if (ret < 0) {
798 av_log(hls, AV_LOG_ERROR,
799 "error opening key info file %s\n", hls->key_info_file);
800 return ret;
801 }
802
803 ff_get_line(pb, vs->key_uri, sizeof(vs->key_uri));
804 vs->key_uri[strcspn(vs->key_uri, "\r\n")] = '\0';
805
806 ff_get_line(pb, vs->key_file, sizeof(vs->key_file));
807 vs->key_file[strcspn(vs->key_file, "\r\n")] = '\0';
808
809 ff_get_line(pb, vs->iv_string, sizeof(vs->iv_string));
810 vs->iv_string[strcspn(vs->iv_string, "\r\n")] = '\0';
811
812 ff_format_io_close(s, &pb);
813
814 if (!*vs->key_uri) {
815 av_log(hls, AV_LOG_ERROR, "no key URI specified in key info file\n");
816 return AVERROR(EINVAL);
817 }
818
819 if (!*vs->key_file) {
820 av_log(hls, AV_LOG_ERROR, "no key file specified in key info file\n");
821 return AVERROR(EINVAL);
822 }
823
824 set_http_options(s, &options, hls);
825 ret = s->io_open(s, &pb, vs->key_file, AVIO_FLAG_READ, &options);
826 av_dict_free(&options);
827 if (ret < 0) {
828 av_log(hls, AV_LOG_ERROR, "error opening key file %s\n", vs->key_file);
829 return ret;
830 }
831
832 ret = avio_read(pb, key, sizeof(key));
833 ff_format_io_close(s, &pb);
834 if (ret != sizeof(key)) {
835 av_log(hls, AV_LOG_ERROR, "error reading key file %s\n", vs->key_file);
836 if (ret >= 0 || ret == AVERROR_EOF)
837 ret = AVERROR(EINVAL);
838 return ret;
839 }
840 ff_data_to_hex(vs->key_string, key, sizeof(key), 0);
841
842 return 0;
843 }
844
845 10 static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
846 {
847 10 AVDictionary *options = NULL;
848 10 HLSContext *hls = s->priv_data;
849 AVFormatContext *oc;
850 10 AVFormatContext *vtt_oc = NULL;
851
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 8 times.
10 int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
852 int remaining_options;
853 int i, ret;
854
855 10 ret = avformat_alloc_output_context2(&vs->avf, vs->oformat, NULL, NULL);
856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
857 return ret;
858 10 oc = vs->avf;
859
860 10 oc->url = av_strdup("");
861
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!oc->url)
862 return AVERROR(ENOMEM);
863
864 10 oc->interrupt_callback = s->interrupt_callback;
865 10 oc->max_delay = s->max_delay;
866 10 oc->opaque = s->opaque;
867 10 oc->io_open = s->io_open;
868 10 oc->io_close = s->io_close;
869 10 oc->io_close2 = s->io_close2;
870 10 oc->strict_std_compliance = s->strict_std_compliance;
871 10 av_dict_copy(&oc->metadata, s->metadata, 0);
872
873
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (vs->vtt_oformat) {
874 ret = avformat_alloc_output_context2(&vs->vtt_avf, vs->vtt_oformat, NULL, NULL);
875 if (ret < 0)
876 return ret;
877 vtt_oc = vs->vtt_avf;
878 av_dict_copy(&vtt_oc->metadata, s->metadata, 0);
879 }
880
881
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (i = 0; i < vs->nb_streams; i++) {
882 AVStream *st;
883 AVFormatContext *loc;
884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (vs->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)
885 loc = vtt_oc;
886 else
887 10 loc = oc;
888
889
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (!(st = avformat_new_stream(loc, NULL)))
890 return AVERROR(ENOMEM);
891 10 avcodec_parameters_copy(st->codecpar, vs->streams[i]->codecpar);
892
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (!oc->oformat->codec_tag ||
893
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
2 av_codec_get_id (oc->oformat->codec_tag, vs->streams[i]->codecpar->codec_tag) == st->codecpar->codec_id ||
894 1 av_codec_get_tag(oc->oformat->codec_tag, vs->streams[i]->codecpar->codec_id) <= 0) {
895 9 st->codecpar->codec_tag = vs->streams[i]->codecpar->codec_tag;
896 } else {
897 1 st->codecpar->codec_tag = 0;
898 }
899
900 10 st->sample_aspect_ratio = vs->streams[i]->sample_aspect_ratio;
901 10 st->time_base = vs->streams[i]->time_base;
902 10 av_dict_copy(&st->metadata, vs->streams[i]->metadata, 0);
903 10 st->id = vs->streams[i]->id;
904 }
905
906 10 vs->start_pos = 0;
907 10 vs->new_start = 1;
908
909
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
10 if (hls->segment_type == SEGMENT_TYPE_FMP4 && hls->max_seg_size > 0) {
910 if (hls->http_persistent > 0) {
911 //TODO: Support fragment fmp4 for http persistent in HLS muxer.
912 av_log(s, AV_LOG_WARNING, "http persistent mode is currently unsupported for fragment mp4 in the HLS muxer.\n");
913 }
914 if (hls->max_seg_size > 0) {
915 av_log(s, AV_LOG_WARNING, "Multi-file byterange mode is currently unsupported in the HLS muxer.\n");
916 return AVERROR_PATCHWELCOME;
917 }
918 }
919
920
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if ((ret = avio_open_dyn_buf(&oc->pb)) < 0)
921 return ret;
922
923
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
924 1 set_http_options(s, &options, hls);
925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (byterange_mode) {
926 ret = hlsenc_io_open(s, &vs->out, vs->basename, &options);
927 } else {
928 1 ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options);
929 }
930 1 av_dict_free(&options);
931 }
932
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
933 av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename);
934 return ret;
935 }
936
937 10 av_dict_copy(&options, hls->format_options, 0);
938
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
939 1 av_dict_set(&options, "fflags", "-autobsf", 0);
940 1 av_dict_set(&options, "movflags", "+frag_custom+dash+delay_moov", AV_DICT_APPEND);
941 } else {
942 /* We only require one PAT/PMT per segment. */
943 char period[21];
944 9 snprintf(period, sizeof(period), "%d", (INT_MAX / 2) - 1);
945 9 av_dict_set(&options, "sdt_period", period, AV_DICT_DONT_OVERWRITE);
946 9 av_dict_set(&options, "pat_period", period, AV_DICT_DONT_OVERWRITE);
947 }
948 10 ret = avformat_init_output(oc, &options);
949 10 remaining_options = av_dict_count(options);
950 10 av_dict_free(&options);
951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
952 return ret;
953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (remaining_options) {
954 av_log(s, AV_LOG_ERROR, "Some of the provided format options are not recognized\n");
955 return AVERROR(EINVAL);
956 }
957 10 avio_flush(oc->pb);
958 10 return 0;
959 }
960
961 121 static HLSSegment *find_segment_by_filename(HLSSegment *segment, const char *filename)
962 {
963
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 106 times.
279 while (segment) {
964
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 158 times.
173 if (!av_strcasecmp(segment->filename,filename))
965 15 return segment;
966 158 segment = segment->next;
967 }
968 106 return (HLSSegment *) NULL;
969 }
970
971 68 static int sls_flags_filename_process(struct AVFormatContext *s, HLSContext *hls,
972 VariantStream *vs, HLSSegment *en,
973 double duration, int64_t pos, int64_t size)
974 {
975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) &&
976 strlen(vs->current_segment_final_filename_fmt)) {
977 char * new_url = av_strdup(vs->current_segment_final_filename_fmt);
978 if (!new_url) {
979 return AVERROR(ENOMEM);
980 }
981 ff_format_set_url(vs->avf, new_url);
982 if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) {
983 char *filename = NULL;
984 if (replace_int_data_in_filename(&filename, vs->avf->url, 's', pos + size) < 1) {
985 av_log(hls, AV_LOG_ERROR,
986 "Invalid second level segment filename template '%s', "
987 "you can try to remove second_level_segment_size flag\n",
988 vs->avf->url);
989 av_freep(&filename);
990 return AVERROR(EINVAL);
991 }
992 ff_format_set_url(vs->avf, filename);
993 }
994 if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) {
995 char *filename = NULL;
996 if (replace_int_data_in_filename(&filename, vs->avf->url,
997 't', (int64_t)round(duration * HLS_MICROSECOND_UNIT)) < 1) {
998 av_log(hls, AV_LOG_ERROR,
999 "Invalid second level segment filename template '%s', "
1000 "you can try to remove second_level_segment_time flag\n",
1001 vs->avf->url);
1002 av_freep(&filename);
1003 return AVERROR(EINVAL);
1004 }
1005 ff_format_set_url(vs->avf, filename);
1006 }
1007 }
1008 68 return 0;
1009 }
1010
1011 10 static int sls_flag_check_duration_size_index(HLSContext *hls)
1012 {
1013 10 int ret = 0;
1014
1015
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) {
1016 av_log(hls, AV_LOG_ERROR,
1017 "second_level_segment_duration hls_flag requires strftime to be true\n");
1018 ret = AVERROR(EINVAL);
1019 }
1020
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) {
1021 av_log(hls, AV_LOG_ERROR,
1022 "second_level_segment_size hls_flag requires strfime to be true\n");
1023 ret = AVERROR(EINVAL);
1024 }
1025
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX) {
1026 av_log(hls, AV_LOG_ERROR,
1027 "second_level_segment_index hls_flag requires strftime to be true\n");
1028 ret = AVERROR(EINVAL);
1029 }
1030
1031 10 return ret;
1032 }
1033
1034 static int sls_flag_check_duration_size(HLSContext *hls, VariantStream *vs)
1035 {
1036 const char *proto = avio_find_protocol_name(vs->basename);
1037 int segment_renaming_ok = proto && !strcmp(proto, "file");
1038 int ret = 0;
1039
1040 if ((hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) && !segment_renaming_ok) {
1041 av_log(hls, AV_LOG_ERROR,
1042 "second_level_segment_duration hls_flag works only with file protocol segment names\n");
1043 ret = AVERROR(EINVAL);
1044 }
1045 if ((hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) && !segment_renaming_ok) {
1046 av_log(hls, AV_LOG_ERROR,
1047 "second_level_segment_size hls_flag works only with file protocol segment names\n");
1048 ret = AVERROR(EINVAL);
1049 }
1050
1051 return ret;
1052 }
1053
1054 51 static void sls_flag_file_rename(HLSContext *hls, VariantStream *vs, char *old_filename) {
1055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) &&
1056 strlen(vs->current_segment_final_filename_fmt)) {
1057 ff_rename(old_filename, vs->avf->url, hls);
1058 }
1059 51 }
1060
1061 static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c, VariantStream *vs)
1062 {
1063 if (c->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX) {
1064 char *filename = NULL;
1065 if (replace_int_data_in_filename(&filename,
1066 oc->url, 'd', vs->sequence) < 1) {
1067 av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', "
1068 "you can try to remove second_level_segment_index flag\n",
1069 oc->url);
1070 av_freep(&filename);
1071 return AVERROR(EINVAL);
1072 }
1073 ff_format_set_url(oc, filename);
1074 }
1075 if (c->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) {
1076 av_strlcpy(vs->current_segment_final_filename_fmt, oc->url,
1077 sizeof(vs->current_segment_final_filename_fmt));
1078 if (c->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) {
1079 char *filename = NULL;
1080 if (replace_int_data_in_filename(&filename, oc->url, 's', 0) < 1) {
1081 av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', "
1082 "you can try to remove second_level_segment_size flag\n",
1083 oc->url);
1084 av_freep(&filename);
1085 return AVERROR(EINVAL);
1086 }
1087 ff_format_set_url(oc, filename);
1088 }
1089 if (c->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) {
1090 char *filename = NULL;
1091 if (replace_int_data_in_filename(&filename, oc->url, 't', 0) < 1) {
1092 av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', "
1093 "you can try to remove second_level_segment_time flag\n",
1094 oc->url);
1095 av_freep(&filename);
1096 return AVERROR(EINVAL);
1097 }
1098 ff_format_set_url(oc, filename);
1099 }
1100 }
1101 return 0;
1102 }
1103
1104 /* Create a new segment and append it to the segment list */
1105 68 static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
1106 VariantStream *vs, double duration, int64_t pos,
1107 int64_t size)
1108 {
1109 68 HLSSegment *en = av_malloc(sizeof(*en));
1110 const char *filename;
1111
4/4
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 48 times.
68 int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
1112 int ret;
1113
1114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (!en)
1115 return AVERROR(ENOMEM);
1116
1117 68 en->var_stream_idx = vs->var_stream_idx;
1118 68 ret = sls_flags_filename_process(s, hls, vs, en, duration, pos, size);
1119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (ret < 0) {
1120 av_freep(&en);
1121 return ret;
1122 }
1123
1124 68 filename = av_basename(vs->avf->url);
1125
1126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (hls->use_localtime_mkdir) {
1127 filename = vs->avf->url;
1128 }
1129
3/4
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 15 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 53 times.
68 if ((find_segment_by_filename(vs->segments, filename) || find_segment_by_filename(vs->old_segments, filename))
1130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 && !byterange_mode) {
1131 av_log(hls, AV_LOG_WARNING, "Duplicated segment filename detected: %s\n", filename);
1132 }
1133 68 av_strlcpy(en->filename, filename, sizeof(en->filename));
1134
1135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (vs->has_subtitle)
1136 av_strlcpy(en->sub_filename, av_basename(vs->vtt_avf->url), sizeof(en->sub_filename));
1137 else
1138 68 en->sub_filename[0] = '\0';
1139
1140 68 en->duration = duration;
1141 68 en->pos = pos;
1142 68 en->size = size;
1143 68 en->keyframe_pos = vs->video_keyframe_pos;
1144 68 en->keyframe_size = vs->video_keyframe_size;
1145 68 en->next = NULL;
1146 68 en->discont = 0;
1147 68 en->discont_program_date_time = 0;
1148
1149
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
68 if (vs->discontinuity) {
1150 1 en->discont = 1;
1151 1 vs->discontinuity = 0;
1152 }
1153
1154
2/4
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
68 if (hls->key_info_file || hls->encrypt) {
1155 av_strlcpy(en->key_uri, vs->key_uri, sizeof(en->key_uri));
1156 av_strlcpy(en->iv_string, vs->iv_string, sizeof(en->iv_string));
1157 }
1158
1159
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 58 times.
68 if (!vs->segments)
1160 10 vs->segments = en;
1161 else
1162 58 vs->last_segment->next = en;
1163
1164 68 vs->last_segment = en;
1165
1166 // EVENT or VOD playlists imply sliding window cannot be used
1167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (hls->pl_type != PLAYLIST_TYPE_NONE)
1168 hls->max_nb_segments = 0;
1169
1170
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 23 times.
68 if (hls->max_nb_segments && vs->nb_entries >= hls->max_nb_segments) {
1171 8 en = vs->segments;
1172
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 if (!en->next->discont_program_date_time && !en->discont_program_date_time)
1173 8 vs->initial_prog_date_time += en->duration;
1174 8 vs->segments = en->next;
1175
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 if (en && hls->flags & HLS_DELETE_SEGMENTS &&
1176 !(hls->flags & HLS_SINGLE_FILE)) {
1177 en->next = vs->old_segments;
1178 vs->old_segments = en;
1179 if ((ret = hls_delete_old_segments(s, hls, vs)) < 0)
1180 return ret;
1181 } else
1182 8 av_freep(&en);
1183 } else
1184 60 vs->nb_entries++;
1185
1186
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 58 times.
68 if (hls->max_seg_size > 0) {
1187 10 return 0;
1188 }
1189 58 vs->sequence++;
1190
1191 58 return 0;
1192 }
1193
1194 1 static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs)
1195 {
1196 1 HLSContext *hls = s->priv_data;
1197 AVIOContext *in;
1198 1 int ret = 0, is_segment = 0;
1199 int64_t new_start_pos;
1200 char line[MAX_URL_SIZE];
1201 const char *ptr;
1202 const char *end;
1203 1 double discont_program_date_time = 0;
1204
1205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ,
1206 1 &s->interrupt_callback, NULL,
1207 1 s->protocol_whitelist, s->protocol_blacklist)) < 0)
1208 return ret;
1209
1210 1 ff_get_chomp_line(in, line, sizeof(line));
1211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (strcmp(line, "#EXTM3U")) {
1212 ret = AVERROR_INVALIDDATA;
1213 goto fail;
1214 }
1215
1216 1 vs->discontinuity = 0;
1217
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 times.
11 while (!avio_feof(in)) {
1218 10 ff_get_chomp_line(in, line, sizeof(line));
1219
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 9 times.
10 if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
1220 1 int64_t tmp_sequence = strtoll(ptr, NULL, 10);
1221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (tmp_sequence < vs->sequence)
1222 av_log(hls, AV_LOG_VERBOSE,
1223 "Found playlist sequence number was smaller """
1224 "than specified start sequence number: %"PRId64" < %"PRId64", "
1225 "omitting\n", tmp_sequence, hls->start_sequence);
1226 else {
1227 1 av_log(hls, AV_LOG_DEBUG, "Found playlist sequence number: %"PRId64"\n", tmp_sequence);
1228 1 vs->sequence = tmp_sequence;
1229 }
1230
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 } else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) {
1231 is_segment = 1;
1232 vs->discontinuity = 1;
1233
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
9 } else if (av_strstart(line, "#EXTINF:", &ptr)) {
1234 2 is_segment = 1;
1235 2 vs->duration = atof(ptr);
1236
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 } else if (av_stristart(line, "#EXT-X-KEY:", &ptr)) {
1237 ptr = av_stristr(line, "URI=\"");
1238 if (ptr) {
1239 ptr += strlen("URI=\"");
1240 end = av_stristr(ptr, ",");
1241 if (end) {
1242 av_strlcpy(vs->key_uri, ptr, end - ptr);
1243 } else {
1244 av_strlcpy(vs->key_uri, ptr, sizeof(vs->key_uri));
1245 }
1246 }
1247
1248 ptr = av_stristr(line, "IV=0x");
1249 if (ptr) {
1250 ptr += strlen("IV=0x");
1251 end = av_stristr(ptr, ",");
1252 if (end) {
1253 av_strlcpy(vs->iv_string, ptr, end - ptr);
1254 } else {
1255 av_strlcpy(vs->iv_string, ptr, sizeof(vs->iv_string));
1256 }
1257 }
1258
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 } else if (av_strstart(line, "#EXT-X-PROGRAM-DATE-TIME:", &ptr)) {
1259 struct tm program_date_time;
1260 int y,M,d,h,m,s;
1261 double ms;
1262 if (sscanf(ptr, "%d-%d-%dT%d:%d:%d.%lf", &y, &M, &d, &h, &m, &s, &ms) != 7) {
1263 ret = AVERROR_INVALIDDATA;
1264 goto fail;
1265 }
1266
1267 program_date_time.tm_year = y - 1900;
1268 program_date_time.tm_mon = M - 1;
1269 program_date_time.tm_mday = d;
1270 program_date_time.tm_hour = h;
1271 program_date_time.tm_min = m;
1272 program_date_time.tm_sec = s;
1273 program_date_time.tm_isdst = -1;
1274
1275 discont_program_date_time = mktime(&program_date_time);
1276 discont_program_date_time += (double)(ms / 1000);
1277
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
7 } else if (av_strstart(line, "#", NULL)) {
1278 4 continue;
1279
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 } else if (line[0]) {
1280
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (is_segment) {
1281 2 char *new_file = av_strdup(line);
1282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!new_file) {
1283 ret = AVERROR(ENOMEM);
1284 goto fail;
1285 }
1286 2 ff_format_set_url(vs->avf, new_file);
1287 2 is_segment = 0;
1288 2 new_start_pos = avio_tell(vs->avf->pb);
1289 2 vs->size = new_start_pos - vs->start_pos;
1290 2 ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size);
1291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (discont_program_date_time) {
1292 vs->last_segment->discont_program_date_time = discont_program_date_time;
1293 discont_program_date_time += vs->duration;
1294 }
1295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
1296 goto fail;
1297 2 vs->start_pos = new_start_pos;
1298 }
1299 }
1300 }
1301
1302 1 fail:
1303 1 avio_close(in);
1304 1 return ret;
1305 }
1306
1307 20 static void hls_free_segments(HLSSegment *p)
1308 {
1309 HLSSegment *en;
1310
1311
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 20 times.
80 while (p) {
1312 60 en = p;
1313 60 p = p->next;
1314 60 av_freep(&en);
1315 }
1316 20 }
1317
1318 static int hls_rename_temp_file(AVFormatContext *s, AVFormatContext *oc)
1319 {
1320 size_t len = strlen(oc->url);
1321 char *final_filename = av_strdup(oc->url);
1322 int ret;
1323
1324 if (!final_filename)
1325 return AVERROR(ENOMEM);
1326 final_filename[len-4] = '\0';
1327 ret = ff_rename(oc->url, final_filename, s);
1328 oc->url[len-4] = '\0';
1329 av_freep(&final_filename);
1330 return ret;
1331 }
1332
1333 static const char* get_relative_url(const char *master_url, const char *media_url)
1334 {
1335 const char *p = strrchr(master_url, '/');
1336 size_t base_len = 0;
1337
1338 if (!p) p = strrchr(master_url, '\\');
1339
1340 if (p) {
1341 base_len = p - master_url;
1342 if (av_strncasecmp(master_url, media_url, base_len)) {
1343 av_log(NULL, AV_LOG_WARNING, "Unable to find relative url\n");
1344 return NULL;
1345 }
1346 } else {
1347 return media_url;
1348 }
1349
1350 return media_url + base_len + 1;
1351 }
1352
1353 static int64_t get_stream_bit_rate(AVStream *stream)
1354 {
1355 AVCPBProperties *props = (AVCPBProperties*)av_stream_get_side_data(
1356 stream,
1357 AV_PKT_DATA_CPB_PROPERTIES,
1358 NULL
1359 );
1360
1361 if (stream->codecpar->bit_rate)
1362 return stream->codecpar->bit_rate;
1363 else if (props)
1364 return props->max_bitrate;
1365
1366 return 0;
1367 }
1368
1369 static int create_master_playlist(AVFormatContext *s,
1370 VariantStream * const input_vs)
1371 {
1372 HLSContext *hls = s->priv_data;
1373 VariantStream *vs, *temp_vs;
1374 AVStream *vid_st, *aud_st;
1375 AVDictionary *options = NULL;
1376 unsigned int i, j;
1377 int ret, bandwidth;
1378 const char *m3u8_rel_name = NULL;
1379 const char *vtt_m3u8_rel_name = NULL;
1380 const char *ccgroup;
1381 const char *sgroup = NULL;
1382 ClosedCaptionsStream *ccs;
1383 const char *proto = avio_find_protocol_name(hls->master_m3u8_url);
1384 int is_file_proto = proto && !strcmp(proto, "file");
1385 int use_temp_file = is_file_proto && ((hls->flags & HLS_TEMP_FILE) || hls->master_publish_rate);
1386 char temp_filename[MAX_URL_SIZE];
1387
1388 input_vs->m3u8_created = 1;
1389 if (!hls->master_m3u8_created) {
1390 /* For the first time, wait until all the media playlists are created */
1391 for (i = 0; i < hls->nb_varstreams; i++)
1392 if (!hls->var_streams[i].m3u8_created)
1393 return 0;
1394 } else {
1395 /* Keep publishing the master playlist at the configured rate */
1396 if (&hls->var_streams[0] != input_vs || !hls->master_publish_rate ||
1397 input_vs->number % hls->master_publish_rate)
1398 return 0;
1399 }
1400
1401 set_http_options(s, &options, hls);
1402 snprintf(temp_filename, sizeof(temp_filename), use_temp_file ? "%s.tmp" : "%s", hls->master_m3u8_url);
1403 ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options);
1404 av_dict_free(&options);
1405 if (ret < 0) {
1406 av_log(s, AV_LOG_ERROR, "Failed to open master play list file '%s'\n",
1407 temp_filename);
1408 goto fail;
1409 }
1410
1411 ff_hls_write_playlist_version(hls->m3u8_out, hls->version);
1412
1413 for (i = 0; i < hls->nb_ccstreams; i++) {
1414 ccs = &(hls->cc_streams[i]);
1415 avio_printf(hls->m3u8_out, "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS");
1416 avio_printf(hls->m3u8_out, ",GROUP-ID=\"%s\"", ccs->ccgroup);
1417 avio_printf(hls->m3u8_out, ",NAME=\"%s\"", ccs->instreamid);
1418 if (ccs->language)
1419 avio_printf(hls->m3u8_out, ",LANGUAGE=\"%s\"", ccs->language);
1420 avio_printf(hls->m3u8_out, ",INSTREAM-ID=\"%s\"\n", ccs->instreamid);
1421 }
1422
1423 /* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/
1424 for (i = 0; i < hls->nb_varstreams; i++) {
1425 vs = &(hls->var_streams[i]);
1426
1427 if (vs->has_video || vs->has_subtitle || !vs->agroup)
1428 continue;
1429
1430 m3u8_rel_name = get_relative_url(hls->master_m3u8_url, vs->m3u8_name);
1431 if (!m3u8_rel_name) {
1432 av_log(s, AV_LOG_ERROR, "Unable to find relative URL\n");
1433 goto fail;
1434 }
1435
1436 ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, vs->language, i, hls->has_default_key ? vs->is_default : 1);
1437 }
1438
1439 /* For variant streams with video add #EXT-X-STREAM-INF tag with attributes*/
1440 for (i = 0; i < hls->nb_varstreams; i++) {
1441 vs = &(hls->var_streams[i]);
1442
1443 m3u8_rel_name = get_relative_url(hls->master_m3u8_url, vs->m3u8_name);
1444 if (!m3u8_rel_name) {
1445 av_log(s, AV_LOG_ERROR, "Unable to find relative URL\n");
1446 goto fail;
1447 }
1448
1449 vid_st = NULL;
1450 aud_st = NULL;
1451 for (j = 0; j < vs->nb_streams; j++) {
1452 if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
1453 vid_st = vs->streams[j];
1454 else if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
1455 aud_st = vs->streams[j];
1456 }
1457
1458 if (!vid_st && !aud_st) {
1459 av_log(s, AV_LOG_WARNING, "Media stream not found\n");
1460 continue;
1461 }
1462
1463 /**
1464 * Traverse through the list of audio only rendition streams and find
1465 * the rendition which has highest bitrate in the same audio group
1466 */
1467 if (vs->agroup) {
1468 for (j = 0; j < hls->nb_varstreams; j++) {
1469 temp_vs = &(hls->var_streams[j]);
1470 if (!temp_vs->has_video && !temp_vs->has_subtitle &&
1471 temp_vs->agroup &&
1472 !av_strcasecmp(temp_vs->agroup, vs->agroup)) {
1473 if (!aud_st)
1474 aud_st = temp_vs->streams[0];
1475 if (temp_vs->streams[0]->codecpar->bit_rate >
1476 aud_st->codecpar->bit_rate)
1477 aud_st = temp_vs->streams[0];
1478 }
1479 }
1480 }
1481
1482 bandwidth = 0;
1483 if (vid_st)
1484 bandwidth += get_stream_bit_rate(vid_st);
1485 if (aud_st)
1486 bandwidth += get_stream_bit_rate(aud_st);
1487 bandwidth += bandwidth / 10;
1488
1489 ccgroup = NULL;
1490 if (vid_st && vs->ccgroup) {
1491 /* check if this group name is available in the cc map string */
1492 for (j = 0; j < hls->nb_ccstreams; j++) {
1493 ccs = &(hls->cc_streams[j]);
1494 if (!av_strcasecmp(ccs->ccgroup, vs->ccgroup)) {
1495 ccgroup = vs->ccgroup;
1496 break;
1497 }
1498 }
1499 if (j == hls->nb_ccstreams)
1500 av_log(s, AV_LOG_WARNING, "mapping ccgroup %s not found\n",
1501 vs->ccgroup);
1502 }
1503
1504 if (vid_st && vs->sgroup) {
1505 sgroup = vs->sgroup;
1506 vtt_m3u8_rel_name = get_relative_url(hls->master_m3u8_url, vs->vtt_m3u8_name);
1507 if (!vtt_m3u8_rel_name) {
1508 av_log(s, AV_LOG_WARNING, "Unable to find relative subtitle URL\n");
1509 break;
1510 }
1511
1512 ff_hls_write_subtitle_rendition(hls->m3u8_out, sgroup, vtt_m3u8_rel_name, vs->language, i, hls->has_default_key ? vs->is_default : 1);
1513 }
1514
1515 if (!hls->has_default_key || !hls->has_video_m3u8) {
1516 ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name,
1517 aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup, sgroup);
1518 } else {
1519 if (vid_st) {
1520 ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name,
1521 aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup, sgroup);
1522 }
1523 }
1524 }
1525 fail:
1526 if (ret >=0)
1527 hls->master_m3u8_created = 1;
1528 hlsenc_io_close(s, &hls->m3u8_out, temp_filename);
1529 if (use_temp_file)
1530 ff_rename(temp_filename, hls->master_m3u8_url, s);
1531
1532 return ret;
1533 }
1534
1535 66 static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
1536 {
1537 66 HLSContext *hls = s->priv_data;
1538 HLSSegment *en;
1539 66 int target_duration = 0;
1540 66 int ret = 0;
1541 char temp_filename[MAX_URL_SIZE];
1542 char temp_vtt_filename[MAX_URL_SIZE];
1543 66 int64_t sequence = FFMAX(hls->start_sequence, vs->sequence - vs->nb_entries);
1544 66 const char *proto = avio_find_protocol_name(vs->m3u8_name);
1545
2/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
66 int is_file_proto = proto && !strcmp(proto, "file");
1546
3/6
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
66 int use_temp_file = is_file_proto && ((hls->flags & HLS_TEMP_FILE) || !(hls->pl_type == PLAYLIST_TYPE_VOD));
1547 static unsigned warned_non_file;
1548 66 char *key_uri = NULL;
1549 66 char *iv_string = NULL;
1550 66 AVDictionary *options = NULL;
1551 66 double prog_date_time = vs->initial_prog_date_time;
1552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 double *prog_date_time_p = (hls->flags & HLS_PROGRAM_DATE_TIME) ? &prog_date_time : NULL;
1553
4/4
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 46 times.
66 int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
1554
1555 66 hls->version = 2;
1556
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 if (!(hls->flags & HLS_ROUND_DURATIONS)) {
1557 66 hls->version = 3;
1558 }
1559
1560
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 46 times.
66 if (byterange_mode) {
1561 20 hls->version = 4;
1562 20 sequence = 0;
1563 }
1564
1565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if (hls->flags & HLS_I_FRAMES_ONLY) {
1566 hls->version = 4;
1567 }
1568
1569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if (hls->flags & HLS_INDEPENDENT_SEGMENTS) {
1570 hls->version = 6;
1571 }
1572
1573
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 61 times.
66 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
1574 5 hls->version = 7;
1575 }
1576
1577
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
66 if (!is_file_proto && (hls->flags & HLS_TEMP_FILE) && !warned_non_file++)
1578 av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n");
1579
1580 66 set_http_options(s, &options, hls);
1581
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 snprintf(temp_filename, sizeof(temp_filename), use_temp_file ? "%s.tmp" : "%s", vs->m3u8_name);
1582
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
66 if ((ret = hlsenc_io_open(s, byterange_mode ? &hls->m3u8_out : &vs->out, temp_filename, &options)) < 0) {
1583 if (hls->ignore_io_errors)
1584 ret = 0;
1585 goto fail;
1586 }
1587
1588
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 66 times.
335 for (en = vs->segments; en; en = en->next) {
1589
2/2
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 80 times.
269 if (target_duration <= en->duration)
1590 189 target_duration = lrint(en->duration);
1591 }
1592
1593 66 vs->discontinuity_set = 0;
1594 66 ff_hls_write_playlist_header(byterange_mode ? hls->m3u8_out : vs->out, hls->version, hls->allowcache,
1595
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 46 times.
66 target_duration, sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY);
1596
1597
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
66 if ((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0) {
1598 avio_printf(byterange_mode ? hls->m3u8_out : vs->out, "#EXT-X-DISCONTINUITY\n");
1599 vs->discontinuity_set = 1;
1600 }
1601
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
66 if (vs->has_video && (hls->flags & HLS_INDEPENDENT_SEGMENTS)) {
1602 avio_printf(byterange_mode ? hls->m3u8_out : vs->out, "#EXT-X-INDEPENDENT-SEGMENTS\n");
1603 }
1604
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 66 times.
335 for (en = vs->segments; en; en = en->next) {
1605
2/10
✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 269 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
269 if ((hls->encrypt || hls->key_info_file) && (!key_uri || strcmp(en->key_uri, key_uri) ||
1606 av_strcasecmp(en->iv_string, iv_string))) {
1607 avio_printf(byterange_mode ? hls->m3u8_out : vs->out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri);
1608 if (*en->iv_string)
1609 avio_printf(byterange_mode ? hls->m3u8_out : vs->out, ",IV=0x%s", en->iv_string);
1610 avio_printf(byterange_mode ? hls->m3u8_out : vs->out, "\n");
1611 key_uri = en->key_uri;
1612 iv_string = en->iv_string;
1613 }
1614
1615
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 254 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 10 times.
269 if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == vs->segments)) {
1616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 ff_hls_write_init_file(byterange_mode ? hls->m3u8_out : vs->out, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename,
1617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 hls->flags & HLS_SINGLE_FILE, vs->init_range_length, 0);
1618 }
1619
1620 538 ret = ff_hls_write_file_entry(byterange_mode ? hls->m3u8_out : vs->out, en->discont, byterange_mode,
1621 269 en->duration, hls->flags & HLS_ROUND_DURATIONS,
1622 269 en->size, en->pos, hls->baseurl,
1623
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 159 times.
269 en->filename,
1624 269 en->discont_program_date_time ? &en->discont_program_date_time : prog_date_time_p,
1625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
269 en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY);
1626
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
269 if (en->discont_program_date_time)
1627 en->discont_program_date_time -= en->duration;
1628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
269 if (ret < 0) {
1629 av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
1630 }
1631 }
1632
1633
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1 times.
66 if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
1634
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 ff_hls_write_end_list(byterange_mode ? hls->m3u8_out : vs->out);
1635
1636
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 if (vs->vtt_m3u8_name) {
1637 snprintf(temp_vtt_filename, sizeof(temp_vtt_filename), use_temp_file ? "%s.tmp" : "%s", vs->vtt_m3u8_name);
1638 if ((ret = hlsenc_io_open(s, &hls->sub_m3u8_out, temp_vtt_filename, &options)) < 0) {
1639 if (hls->ignore_io_errors)
1640 ret = 0;
1641 goto fail;
1642 }
1643 ff_hls_write_playlist_header(hls->sub_m3u8_out, hls->version, hls->allowcache,
1644 target_duration, sequence, PLAYLIST_TYPE_NONE, 0);
1645 for (en = vs->segments; en; en = en->next) {
1646 ret = ff_hls_write_file_entry(hls->sub_m3u8_out, 0, byterange_mode,
1647 en->duration, 0, en->size, en->pos,
1648 hls->baseurl, en->sub_filename, NULL, 0, 0, 0);
1649 if (ret < 0) {
1650 av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n");
1651 }
1652 }
1653
1654 if (last)
1655 ff_hls_write_end_list(hls->sub_m3u8_out);
1656
1657 }
1658
1659 66 fail:
1660 66 av_dict_free(&options);
1661
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 46 times.
66 ret = hlsenc_io_close(s, byterange_mode ? &hls->m3u8_out : &vs->out, temp_filename);
1662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if (ret < 0) {
1663 return ret;
1664 }
1665 66 hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name);
1666
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 if (use_temp_file) {
1667 66 ff_rename(temp_filename, vs->m3u8_name, s);
1668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if (vs->vtt_m3u8_name)
1669 ff_rename(temp_vtt_filename, vs->vtt_m3u8_name, s);
1670 }
1671
2/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 66 times.
66 if (ret >= 0 && hls->master_pl_name)
1672 if (create_master_playlist(s, vs) < 0)
1673 av_log(s, AV_LOG_WARNING, "Master playlist creation failed\n");
1674
1675 66 return ret;
1676 }
1677
1678 51 static int hls_start(AVFormatContext *s, VariantStream *vs)
1679 {
1680 51 HLSContext *c = s->priv_data;
1681 51 AVFormatContext *oc = vs->avf;
1682 51 AVFormatContext *vtt_oc = vs->vtt_avf;
1683 51 AVDictionary *options = NULL;
1684 51 const char *proto = NULL;
1685 51 int use_temp_file = 0;
1686 char iv_string[KEYSIZE*2 + 1];
1687 51 int err = 0;
1688
1689
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 50 times.
51 if (c->flags & HLS_SINGLE_FILE) {
1690 1 char *new_name = av_strdup(vs->basename);
1691
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!new_name)
1692 return AVERROR(ENOMEM);
1693 1 ff_format_set_url(oc, new_name);
1694
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (vs->vtt_basename) {
1695 new_name = av_strdup(vs->vtt_basename);
1696 if (!new_name)
1697 return AVERROR(ENOMEM);
1698 ff_format_set_url(vtt_oc, new_name);
1699 }
1700
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 46 times.
50 } else if (c->max_seg_size > 0) {
1701 4 char *filename = NULL;
1702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (replace_int_data_in_filename(&filename,
1703 4 vs->basename, 'd', vs->sequence) < 1) {
1704 av_freep(&filename);
1705 av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -strftime 1 with it\n", vs->basename);
1706 return AVERROR(EINVAL);
1707 }
1708 4 ff_format_set_url(oc, filename);
1709 } else {
1710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (c->use_localtime) {
1711 int r;
1712 char *expanded = NULL;
1713
1714 r = strftime_expand(vs->basename, &expanded);
1715 if (r < 0) {
1716 av_log(oc, AV_LOG_ERROR, "Could not get segment filename with strftime\n");
1717 return r;
1718 }
1719 ff_format_set_url(oc, expanded);
1720
1721 err = sls_flag_use_localtime_filename(oc, c, vs);
1722 if (err < 0) {
1723 return AVERROR(ENOMEM);
1724 }
1725
1726 if (c->use_localtime_mkdir) {
1727 const char *dir;
1728 char *fn_copy = av_strdup(oc->url);
1729 if (!fn_copy)
1730 return AVERROR(ENOMEM);
1731 dir = av_dirname(fn_copy);
1732 if (ff_mkdir_p(dir) == -1 && errno != EEXIST) {
1733 av_log(oc, AV_LOG_ERROR, "Could not create directory %s with use_localtime_mkdir\n", dir);
1734 av_freep(&fn_copy);
1735 return AVERROR(errno);
1736 }
1737 av_freep(&fn_copy);
1738 }
1739 } else {
1740 46 char *filename = NULL;
1741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (replace_int_data_in_filename(&filename,
1742 46 vs->basename, 'd', vs->sequence) < 1) {
1743 av_freep(&filename);
1744 av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -strftime 1 with it\n", vs->basename);
1745 return AVERROR(EINVAL);
1746 }
1747 46 ff_format_set_url(oc, filename);
1748 }
1749
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (vs->vtt_basename) {
1750 char *filename = NULL;
1751 if (replace_int_data_in_filename(&filename,
1752 vs->vtt_basename, 'd', vs->sequence) < 1) {
1753 av_freep(&filename);
1754 av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", vs->vtt_basename);
1755 return AVERROR(EINVAL);
1756 }
1757 ff_format_set_url(vtt_oc, filename);
1758 }
1759 }
1760
1761 51 proto = avio_find_protocol_name(oc->url);
1762
3/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 51 times.
51 use_temp_file = proto && !strcmp(proto, "file") && (c->flags & HLS_TEMP_FILE);
1763
1764
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if (use_temp_file) {
1765 char *new_name = av_asprintf("%s.tmp", oc->url);
1766 if (!new_name)
1767 return AVERROR(ENOMEM);
1768 ff_format_set_url(oc, new_name);
1769 }
1770
1771
2/4
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 51 times.
51 if (c->key_info_file || c->encrypt) {
1772 if (c->segment_type == SEGMENT_TYPE_FMP4) {
1773 av_log(s, AV_LOG_ERROR, "Encrypted fmp4 not yet supported\n");
1774 return AVERROR_PATCHWELCOME;
1775 }
1776
1777 if (c->key_info_file && c->encrypt) {
1778 av_log(s, AV_LOG_WARNING, "Cannot use both -hls_key_info_file and -hls_enc,"
1779 " ignoring -hls_enc\n");
1780 }
1781
1782 if (!vs->encrypt_started || (c->flags & HLS_PERIODIC_REKEY)) {
1783 if (c->key_info_file) {
1784 if ((err = hls_encryption_start(s, vs)) < 0)
1785 goto fail;
1786 } else {
1787 if (!c->encrypt_started) {
1788 if ((err = do_encrypt(s, vs)) < 0)
1789 goto fail;
1790 c->encrypt_started = 1;
1791 }
1792 av_strlcpy(vs->key_uri, c->key_uri, sizeof(vs->key_uri));
1793 av_strlcpy(vs->key_string, c->key_string, sizeof(vs->key_string));
1794 av_strlcpy(vs->iv_string, c->iv_string, sizeof(vs->iv_string));
1795 }
1796 vs->encrypt_started = 1;
1797 }
1798 err = av_strlcpy(iv_string, vs->iv_string, sizeof(iv_string));
1799 if (!err) {
1800 snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, vs->sequence);
1801 memset(vs->iv_string, 0, sizeof(vs->iv_string));
1802 memcpy(vs->iv_string, iv_string, sizeof(iv_string));
1803 }
1804 }
1805
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 5 times.
51 if (c->segment_type != SEGMENT_TYPE_FMP4) {
1806
2/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
46 if (oc->oformat->priv_class && oc->priv_data) {
1807 46 av_opt_set(oc->priv_data, "mpegts_flags", "resend_headers", 0);
1808 }
1809
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 45 times.
46 if (c->flags & HLS_SINGLE_FILE) {
1810
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (c->key_info_file || c->encrypt) {
1811 av_dict_set(&options, "encryption_key", vs->key_string, 0);
1812 av_dict_set(&options, "encryption_iv", vs->iv_string, 0);
1813
1814 /* Write temp file with cryption content */
1815 av_freep(&vs->basename_tmp);
1816 vs->basename_tmp = av_asprintf("crypto:%s.tmp", oc->url);
1817
1818 /* append temp file content into single file */
1819 av_freep(&vs->basename);
1820 vs->basename = av_asprintf("%s", oc->url);
1821 } else {
1822 1 vs->basename_tmp = vs->basename;
1823 }
1824 1 set_http_options(s, &options, c);
1825
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!vs->out_single_file)
1826
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((err = hlsenc_io_open(s, &vs->out_single_file, vs->basename, &options)) < 0) {
1827 if (c->ignore_io_errors)
1828 err = 0;
1829 goto fail;
1830 }
1831
1832
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((err = hlsenc_io_open(s, &vs->out, vs->basename_tmp, &options)) < 0) {
1833 if (c->ignore_io_errors)
1834 err = 0;
1835 goto fail;
1836 }
1837
1838 }
1839 }
1840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if (vs->vtt_basename) {
1841 set_http_options(s, &options, c);
1842 if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->url, &options)) < 0) {
1843 if (c->ignore_io_errors)
1844 err = 0;
1845 goto fail;
1846 }
1847 }
1848 51 av_dict_free(&options);
1849
1850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if (vs->vtt_basename) {
1851 err = avformat_write_header(vtt_oc,NULL);
1852 if (err < 0)
1853 return err;
1854 }
1855
1856 51 return 0;
1857 fail:
1858 av_dict_free(&options);
1859
1860 return err;
1861 }
1862
1863 static const char * get_default_pattern_localtime_fmt(AVFormatContext *s)
1864 {
1865 char b[21];
1866 time_t t = time(NULL);
1867 struct tm *p, tmbuf;
1868 HLSContext *hls = s->priv_data;
1869
1870 p = localtime_r(&t, &tmbuf);
1871 // no %s support when strftime returned error or left format string unchanged
1872 // also no %s support on MSVC, which invokes the invalid parameter handler on unsupported format strings, instead of returning an error
1873 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
1874 return (HAVE_LIBC_MSVCRT || !strftime(b, sizeof(b), "%s", p) || !strcmp(b, "%s")) ? "-%Y%m%d%H%M%S.m4s" : "-%s.m4s";
1875 }
1876 return (HAVE_LIBC_MSVCRT || !strftime(b, sizeof(b), "%s", p) || !strcmp(b, "%s")) ? "-%Y%m%d%H%M%S.ts" : "-%s.ts";
1877 }
1878
1879 static int append_postfix(char *name, int name_buf_len, int i)
1880 {
1881 char *p;
1882 char extension[10] = {'\0'};
1883
1884 p = strrchr(name, '.');
1885 if (p) {
1886 av_strlcpy(extension, p, sizeof(extension));
1887 *p = '\0';
1888 }
1889
1890 snprintf(name + strlen(name), name_buf_len - strlen(name), POSTFIX_PATTERN, i);
1891
1892 if (strlen(extension))
1893 av_strlcat(name, extension, name_buf_len);
1894
1895 return 0;
1896 }
1897
1898 22 static int validate_name(int nb_vs, const char *fn)
1899 {
1900 const char *filename, *subdir_name;
1901 22 char *fn_dup = NULL;
1902 22 int ret = 0;
1903
1904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!fn)
1905 return AVERROR(EINVAL);
1906
1907 22 fn_dup = av_strdup(fn);
1908
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!fn_dup)
1909 return AVERROR(ENOMEM);
1910 22 filename = av_basename(fn);
1911 22 subdir_name = av_dirname(fn_dup);
1912
1913
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
22 if (nb_vs > 1 && !av_stristr(filename, "%v") && !av_stristr(subdir_name, "%v")) {
1914 av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, %%v is expected "
1915 "either in the filename or in the sub-directory name of file %s\n", fn);
1916 ret = AVERROR(EINVAL);
1917 goto fail;
1918 }
1919
1920
1/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
22 if (av_stristr(filename, "%v") && av_stristr(subdir_name, "%v")) {
1921 av_log(NULL, AV_LOG_ERROR, "%%v is expected either in the filename or "
1922 "in the sub-directory name of file %s, but only in one of them\n", fn);
1923 ret = AVERROR(EINVAL);
1924 goto fail;
1925 }
1926
1927 22 fail:
1928 22 av_freep(&fn_dup);
1929 22 return ret;
1930 }
1931
1932 20 static int format_name(const char *buf, char **s, int index, const char *varname)
1933 {
1934 const char *proto, *dir;
1935 20 char *orig_buf_dup = NULL, *mod_buf_dup = NULL;
1936 20 int ret = 0;
1937
1938 20 orig_buf_dup = av_strdup(buf);
1939
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (!orig_buf_dup)
1940 return AVERROR(ENOMEM);
1941
1942
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 if (!av_stristr(buf, "%v")) {
1943 20 *s = orig_buf_dup;
1944 20 return 0;
1945 }
1946
1947 if (!varname) {
1948 if (replace_int_data_in_filename(s, orig_buf_dup, 'v', index) < 1) {
1949 ret = AVERROR(EINVAL);
1950 goto fail;
1951 }
1952 } else {
1953 if (replace_str_data_in_filename(s, orig_buf_dup, 'v', varname) < 1) {
1954 ret = AVERROR(EINVAL);
1955 goto fail;
1956 }
1957 }
1958
1959 proto = avio_find_protocol_name(orig_buf_dup);
1960 dir = av_dirname(orig_buf_dup);
1961
1962 /* if %v is present in the file's directory, create sub-directory */
1963 if (av_stristr(dir, "%v") && proto && !strcmp(proto, "file")) {
1964 mod_buf_dup = av_strdup(*s);
1965 dir = av_dirname(mod_buf_dup);
1966 if (ff_mkdir_p(dir) == -1 && errno != EEXIST) {
1967 ret = AVERROR(errno);
1968 goto fail;
1969 }
1970 }
1971
1972 fail:
1973 av_freep(&orig_buf_dup);
1974 av_freep(&mod_buf_dup);
1975 return ret;
1976 }
1977
1978 static int get_nth_codec_stream_index(AVFormatContext *s,
1979 enum AVMediaType codec_type,
1980 int64_t stream_id)
1981 {
1982 unsigned int stream_index, cnt;
1983 if (stream_id < 0 || stream_id > s->nb_streams - 1)
1984 return -1;
1985 cnt = 0;
1986 for (stream_index = 0; stream_index < s->nb_streams; stream_index++) {
1987 if (s->streams[stream_index]->codecpar->codec_type != codec_type)
1988 continue;
1989 if (cnt == stream_id)
1990 return stream_index;
1991 cnt++;
1992 }
1993 return -1;
1994 }
1995
1996 static int parse_variant_stream_mapstring(AVFormatContext *s)
1997 {
1998 HLSContext *hls = s->priv_data;
1999 VariantStream *vs;
2000 int stream_index, i, j;
2001 enum AVMediaType codec_type;
2002 int nb_varstreams = 0, nb_streams;
2003 char *p, *q, *saveptr1, *saveptr2, *varstr, *keyval;
2004 const char *val;
2005
2006 /**
2007 * Expected format for var_stream_map string is as below:
2008 * "a:0,v:0 a:1,v:1"
2009 * "a:0,agroup:a0,default:1,language:ENG a:1,agroup:a1,default:0 v:0,agroup:a0 v:1,agroup:a1"
2010 * This string specifies how to group the audio, video and subtitle streams
2011 * into different variant streams. The variant stream groups are separated
2012 * by space.
2013 *
2014 * a:, v:, s: are keys to specify audio, video and subtitle streams
2015 * respectively. Allowed values are 0 to 9 digits (limited just based on
2016 * practical usage)
2017 *
2018 * agroup: is key to specify audio group. A string can be given as value.
2019 * sgroup: is key to specify subtitle group. A string can be given as value.
2020 */
2021 p = av_strdup(hls->var_stream_map);
2022 if (!p)
2023 return AVERROR(ENOMEM);
2024
2025 q = p;
2026 while (av_strtok(q, " \t", &saveptr1)) {
2027 q = NULL;
2028 nb_varstreams++;
2029 }
2030 av_freep(&p);
2031
2032 hls->var_streams = av_mallocz(sizeof(*hls->var_streams) * nb_varstreams);
2033 if (!hls->var_streams)
2034 return AVERROR(ENOMEM);
2035 hls->nb_varstreams = nb_varstreams;
2036
2037 p = hls->var_stream_map;
2038 nb_varstreams = 0;
2039 while (varstr = av_strtok(p, " \t", &saveptr1)) {
2040 p = NULL;
2041
2042 if (nb_varstreams < hls->nb_varstreams) {
2043 vs = &(hls->var_streams[nb_varstreams]);
2044 vs->var_stream_idx = nb_varstreams;
2045 vs->is_default = 0;
2046 nb_varstreams++;
2047 } else
2048 return AVERROR(EINVAL);
2049
2050 q = varstr;
2051 while (1) {
2052 if (!av_strncasecmp(q, "a:", 2) || !av_strncasecmp(q, "v:", 2) ||
2053 !av_strncasecmp(q, "s:", 2))
2054 vs->nb_streams++;
2055 q = strchr(q, ',');
2056 if (!q)
2057 break;
2058 q++;
2059 }
2060 vs->streams = av_mallocz(sizeof(AVStream *) * vs->nb_streams);
2061 if (!vs->streams)
2062 return AVERROR(ENOMEM);
2063
2064 nb_streams = 0;
2065 while (keyval = av_strtok(varstr, ",", &saveptr2)) {
2066 int64_t num;
2067 char *end;
2068 varstr = NULL;
2069 if (av_strstart(keyval, "language:", &val)) {
2070 vs->language = val;
2071 continue;
2072 } else if (av_strstart(keyval, "default:", &val)) {
2073 vs->is_default = (!av_strncasecmp(val, "YES", strlen("YES")) ||
2074 (!av_strncasecmp(val, "1", strlen("1"))));
2075 hls->has_default_key = 1;
2076 continue;
2077 } else if (av_strstart(keyval, "name:", &val)) {
2078 vs->varname = val;
2079 continue;
2080 } else if (av_strstart(keyval, "agroup:", &val)) {
2081 vs->agroup = val;
2082 continue;
2083 } else if (av_strstart(keyval, "sgroup:", &val)) {
2084 vs->sgroup = val;
2085 continue;
2086 } else if (av_strstart(keyval, "ccgroup:", &val)) {
2087 vs->ccgroup = val;
2088 continue;
2089 } else if (av_strstart(keyval, "v:", &val)) {
2090 codec_type = AVMEDIA_TYPE_VIDEO;
2091 hls->has_video_m3u8 = 1;
2092 } else if (av_strstart(keyval, "a:", &val)) {
2093 codec_type = AVMEDIA_TYPE_AUDIO;
2094 } else if (av_strstart(keyval, "s:", &val)) {
2095 codec_type = AVMEDIA_TYPE_SUBTITLE;
2096 } else {
2097 av_log(s, AV_LOG_ERROR, "Invalid keyval %s\n", keyval);
2098 return AVERROR(EINVAL);
2099 }
2100
2101 num = strtoll(val, &end, 10);
2102 if (!av_isdigit(*val) || *end != '\0') {
2103 av_log(s, AV_LOG_ERROR, "Invalid stream number: '%s'\n", val);
2104 return AVERROR(EINVAL);
2105 }
2106 stream_index = get_nth_codec_stream_index(s, codec_type, num);
2107
2108 if (stream_index >= 0 && nb_streams < vs->nb_streams) {
2109 for (i = 0; nb_streams > 0 && i < nb_streams; i++) {
2110 if (vs->streams[i] == s->streams[stream_index]) {
2111 av_log(s, AV_LOG_ERROR, "Same elementary stream found more than once inside "
2112 "variant definition #%d\n", nb_varstreams - 1);
2113 return AVERROR(EINVAL);
2114 }
2115 }
2116 for (j = 0; nb_varstreams > 1 && j < nb_varstreams - 1; j++) {
2117 for (i = 0; i < hls->var_streams[j].nb_streams; i++) {
2118 if (hls->var_streams[j].streams[i] == s->streams[stream_index]) {
2119 av_log(s, AV_LOG_ERROR, "Same elementary stream found more than once "
2120 "in two different variant definitions #%d and #%d\n",
2121 j, nb_varstreams - 1);
2122 return AVERROR(EINVAL);
2123 }
2124 }
2125 }
2126 vs->streams[nb_streams++] = s->streams[stream_index];
2127 } else {
2128 av_log(s, AV_LOG_ERROR, "Unable to map stream at %s\n", keyval);
2129 return AVERROR(EINVAL);
2130 }
2131 }
2132 }
2133 av_log(s, AV_LOG_DEBUG, "Number of variant streams %d\n",
2134 hls->nb_varstreams);
2135
2136 return 0;
2137 }
2138
2139 static int parse_cc_stream_mapstring(AVFormatContext *s)
2140 {
2141 HLSContext *hls = s->priv_data;
2142 int nb_ccstreams = 0;
2143 char *p, *q, *ccstr, *keyval;
2144 char *saveptr1 = NULL, *saveptr2 = NULL;
2145 const char *val;
2146 ClosedCaptionsStream *ccs;
2147
2148 p = av_strdup(hls->cc_stream_map);
2149 if(!p)
2150 return AVERROR(ENOMEM);
2151
2152 q = p;
2153 while (av_strtok(q, " \t", &saveptr1)) {
2154 q = NULL;
2155 nb_ccstreams++;
2156 }
2157 av_freep(&p);
2158
2159 hls->cc_streams = av_mallocz(sizeof(*hls->cc_streams) * nb_ccstreams);
2160 if (!hls->cc_streams)
2161 return AVERROR(ENOMEM);
2162 hls->nb_ccstreams = nb_ccstreams;
2163
2164 p = hls->cc_stream_map;
2165 nb_ccstreams = 0;
2166 while (ccstr = av_strtok(p, " \t", &saveptr1)) {
2167 p = NULL;
2168
2169 if (nb_ccstreams < hls->nb_ccstreams)
2170 ccs = &(hls->cc_streams[nb_ccstreams++]);
2171 else
2172 return AVERROR(EINVAL);
2173
2174 while (keyval = av_strtok(ccstr, ",", &saveptr2)) {
2175 ccstr = NULL;
2176
2177 if (av_strstart(keyval, "ccgroup:", &val)) {
2178 ccs->ccgroup = val;
2179 } else if (av_strstart(keyval, "instreamid:", &val)) {
2180 ccs->instreamid = val;
2181 } else if (av_strstart(keyval, "language:", &val)) {
2182 ccs->language = val;
2183 } else {
2184 av_log(s, AV_LOG_ERROR, "Invalid keyval %s\n", keyval);
2185 return AVERROR(EINVAL);
2186 }
2187 }
2188
2189 if (!ccs->ccgroup || !ccs->instreamid) {
2190 av_log(s, AV_LOG_ERROR, "Insufficient parameters in cc stream map string\n");
2191 return AVERROR(EINVAL);
2192 }
2193
2194 if (av_strstart(ccs->instreamid, "CC", &val)) {
2195 if (atoi(val) < 1 || atoi(val) > 4) {
2196 av_log(s, AV_LOG_ERROR, "Invalid instream ID CC index %d in %s, range 1-4\n",
2197 atoi(val), ccs->instreamid);
2198 return AVERROR(EINVAL);
2199 }
2200 } else if (av_strstart(ccs->instreamid, "SERVICE", &val)) {
2201 if (atoi(val) < 1 || atoi(val) > 63) {
2202 av_log(s, AV_LOG_ERROR, "Invalid instream ID SERVICE index %d in %s, range 1-63 \n",
2203 atoi(val), ccs->instreamid);
2204 return AVERROR(EINVAL);
2205 }
2206 } else {
2207 av_log(s, AV_LOG_ERROR, "Invalid instream ID %s, supported are CCn or SERVICEn\n",
2208 ccs->instreamid);
2209 return AVERROR(EINVAL);
2210 }
2211 }
2212
2213 return 0;
2214 }
2215
2216 10 static int update_variant_stream_info(AVFormatContext *s)
2217 {
2218 10 HLSContext *hls = s->priv_data;
2219 unsigned int i;
2220 10 int ret = 0;
2221
2222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->cc_stream_map) {
2223 ret = parse_cc_stream_mapstring(s);
2224 if (ret < 0)
2225 return ret;
2226 }
2227
2228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->var_stream_map) {
2229 return parse_variant_stream_mapstring(s);
2230 } else {
2231 //By default, a single variant stream with all the codec streams is created
2232 10 hls->var_streams = av_mallocz(sizeof(*hls->var_streams));
2233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!hls->var_streams)
2234 return AVERROR(ENOMEM);
2235 10 hls->nb_varstreams = 1;
2236
2237 10 hls->var_streams[0].var_stream_idx = 0;
2238 10 hls->var_streams[0].nb_streams = s->nb_streams;
2239 20 hls->var_streams[0].streams = av_mallocz(sizeof(AVStream *) *
2240 10 hls->var_streams[0].nb_streams);
2241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!hls->var_streams[0].streams)
2242 return AVERROR(ENOMEM);
2243
2244 //by default, the first available ccgroup is mapped to the variant stream
2245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->nb_ccstreams)
2246 hls->var_streams[0].ccgroup = hls->cc_streams[0].ccgroup;
2247
2248
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (i = 0; i < s->nb_streams; i++)
2249 10 hls->var_streams[0].streams[i] = s->streams[i];
2250 }
2251 10 return 0;
2252 }
2253
2254 static int update_master_pl_info(AVFormatContext *s)
2255 {
2256 HLSContext *hls = s->priv_data;
2257 const char *dir;
2258 char *fn1= NULL, *fn2 = NULL;
2259 int ret = 0;
2260
2261 fn1 = av_strdup(s->url);
2262 if (!fn1)
2263 return AVERROR(ENOMEM);
2264 dir = av_dirname(fn1);
2265
2266 /**
2267 * if output file's directory has %v, variants are created in sub-directories
2268 * then master is created at the sub-directories level
2269 */
2270 if (dir && av_stristr(av_basename(dir), "%v")) {
2271 fn2 = av_strdup(dir);
2272 if (!fn2) {
2273 ret = AVERROR(ENOMEM);
2274 goto fail;
2275 }
2276 dir = av_dirname(fn2);
2277 }
2278
2279 if (dir && strcmp(dir, "."))
2280 hls->master_m3u8_url = av_append_path_component(dir, hls->master_pl_name);
2281 else
2282 hls->master_m3u8_url = av_strdup(hls->master_pl_name);
2283
2284 if (!hls->master_m3u8_url) {
2285 ret = AVERROR(ENOMEM);
2286 goto fail;
2287 }
2288
2289 fail:
2290 av_freep(&fn1);
2291 av_freep(&fn2);
2292
2293 return ret;
2294 }
2295
2296 10 static int hls_write_header(AVFormatContext *s)
2297 {
2298 10 HLSContext *hls = s->priv_data;
2299 int ret, i, j;
2300 10 VariantStream *vs = NULL;
2301
2302
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (i = 0; i < hls->nb_varstreams; i++) {
2303 10 int subtitle_streams = 0;
2304 10 vs = &hls->var_streams[i];
2305
2306 10 ret = avformat_write_header(vs->avf, NULL);
2307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
2308 return ret;
2309 //av_assert0(s->nb_streams == hls->avf->nb_streams);
2310
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (j = 0; j < vs->nb_streams; j++) {
2311 AVStream *inner_st;
2312 10 AVStream *outer_st = vs->streams[j];
2313
2314
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (hls->max_seg_size > 0) {
2315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if ((outer_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
2316 (outer_st->codecpar->bit_rate > hls->max_seg_size)) {
2317 av_log(s, AV_LOG_WARNING, "Your video bitrate is bigger than hls_segment_size, "
2318 "(%"PRId64 " > %"PRId64 "), the result maybe not be what you want.",
2319 outer_st->codecpar->bit_rate, hls->max_seg_size);
2320 }
2321 }
2322
2323
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
2324 10 inner_st = vs->avf->streams[j - subtitle_streams];
2325 else if (vs->vtt_avf) {
2326 inner_st = vs->vtt_avf->streams[0];
2327 subtitle_streams++;
2328 } else {
2329 /* We have a subtitle stream, when the user does not want one */
2330 inner_st = NULL;
2331 continue;
2332 }
2333 10 avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den);
2334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (outer_st->codecpar->codec_id == AV_CODEC_ID_HEVC &&
2335 outer_st->codecpar->codec_tag != MKTAG('h','v','c','1')) {
2336 av_log(s, AV_LOG_WARNING, "Stream HEVC is not hvc1, you should use tag:v hvc1 to set it.\n");
2337 }
2338 10 write_codec_attr(outer_st, vs);
2339
2340 }
2341 /* Update the Codec Attr string for the mapped audio groups */
2342
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if (vs->has_video && vs->agroup) {
2343 for (j = 0; j < hls->nb_varstreams; j++) {
2344 VariantStream *vs_agroup = &(hls->var_streams[j]);
2345 if (!vs_agroup->has_video && !vs_agroup->has_subtitle &&
2346 vs_agroup->agroup &&
2347 !av_strcasecmp(vs_agroup->agroup, vs->agroup)) {
2348 write_codec_attr(vs_agroup->streams[0], vs);
2349 }
2350 }
2351 }
2352 }
2353
2354 10 return ret;
2355 }
2356
2357 static int hls_init_file_resend(AVFormatContext *s, VariantStream *vs)
2358 {
2359 HLSContext *hls = s->priv_data;
2360 AVDictionary *options = NULL;
2361 int ret = 0;
2362
2363 set_http_options(s, &options, hls);
2364 ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options);
2365 av_dict_free(&options);
2366 if (ret < 0)
2367 return ret;
2368 avio_write(vs->out, vs->init_buffer, vs->init_range_length);
2369 hlsenc_io_close(s, &vs->out, hls->fmp4_init_filename);
2370
2371 return ret;
2372 }
2373
2374 static int64_t append_single_file(AVFormatContext *s, VariantStream *vs)
2375 {
2376 int ret = 0;
2377 int64_t read_byte = 0;
2378 int64_t total_size = 0;
2379 char *filename = NULL;
2380 char buf[BUFSIZE];
2381 AVFormatContext *oc = vs->avf;
2382
2383 hlsenc_io_close(s, &vs->out, vs->basename_tmp);
2384 filename = av_asprintf("%s.tmp", oc->url);
2385 ret = s->io_open(s, &vs->out, filename, AVIO_FLAG_READ, NULL);
2386 if (ret < 0) {
2387 av_free(filename);
2388 return ret;
2389 }
2390
2391 do {
2392 read_byte = avio_read(vs->out, buf, BUFSIZE);
2393 if (read_byte > 0) {
2394 avio_write(vs->out_single_file, buf, read_byte);
2395 total_size += read_byte;
2396 ret = total_size;
2397 }
2398 } while (read_byte > 0);
2399
2400 hlsenc_io_close(s, &vs->out, filename);
2401 av_free(filename);
2402
2403 return ret;
2404 }
2405 6256 static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
2406 {
2407 6256 HLSContext *hls = s->priv_data;
2408 6256 AVFormatContext *oc = NULL;
2409 6256 AVStream *st = s->streams[pkt->stream_index];
2410 6256 int64_t end_pts = 0;
2411 6256 int is_ref_pkt = 1;
2412 6256 int ret = 0, can_split = 1, i, j;
2413 6256 int stream_index = 0;
2414 6256 int subtitle_streams = 0;
2415 6256 int range_length = 0;
2416 6256 const char *proto = NULL;
2417 6256 int use_temp_file = 0;
2418 6256 VariantStream *vs = NULL;
2419 6256 char *old_filename = NULL;
2420
2421
1/2
✓ Branch 0 taken 6256 times.
✗ Branch 1 not taken.
6256 for (i = 0; i < hls->nb_varstreams; i++) {
2422 6256 vs = &hls->var_streams[i];
2423
1/2
✓ Branch 0 taken 6256 times.
✗ Branch 1 not taken.
6256 for (j = 0; j < vs->nb_streams; j++) {
2424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6256 times.
6256 if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
2425 subtitle_streams++;
2426 }
2427
1/2
✓ Branch 0 taken 6256 times.
✗ Branch 1 not taken.
6256 if (vs->streams[j] == st) {
2428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6256 times.
6256 if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
2429 oc = vs->vtt_avf;
2430 stream_index = 0;
2431 } else {
2432 6256 oc = vs->avf;
2433 6256 stream_index = j - subtitle_streams;
2434 }
2435 6256 break;
2436 }
2437 }
2438
2439
1/2
✓ Branch 0 taken 6256 times.
✗ Branch 1 not taken.
6256 if (oc)
2440 6256 break;
2441 }
2442
2443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6256 times.
6256 if (!oc) {
2444 av_log(s, AV_LOG_ERROR, "Unable to find mapping variant stream\n");
2445 return AVERROR(ENOMEM);
2446 }
2447
2448 6256 end_pts = hls->recording_time * vs->number;
2449
2450
4/4
✓ Branch 0 taken 341 times.
✓ Branch 1 taken 5915 times.
✓ Branch 2 taken 191 times.
✓ Branch 3 taken 150 times.
6256 if (vs->sequence - vs->nb_entries > hls->start_sequence && hls->init_time > 0) {
2451 /* reset end_pts, hls->recording_time at end of the init hls list */
2452 191 int64_t init_list_dur = hls->init_time * vs->nb_entries;
2453 191 int64_t after_init_list_dur = (vs->sequence - hls->start_sequence - vs->nb_entries) * hls->time;
2454 191 hls->recording_time = hls->time;
2455 191 end_pts = init_list_dur + after_init_list_dur ;
2456 }
2457
2458
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6246 times.
6256 if (vs->start_pts == AV_NOPTS_VALUE) {
2459 10 vs->start_pts = pkt->pts;
2460
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
2461 10 vs->start_pts_from_audio = 1;
2462 }
2463
2/6
✓ Branch 0 taken 6256 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6256 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6256 if (vs->start_pts_from_audio && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && vs->start_pts > pkt->pts) {
2464 vs->start_pts = pkt->pts;
2465 vs->start_pts_from_audio = 0;
2466 }
2467
2468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6256 times.
6256 if (vs->has_video) {
2469 can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
2470 ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME));
2471 is_ref_pkt = (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->stream_index == vs->reference_stream_index);
2472 }
2473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6256 times.
6256 if (pkt->pts == AV_NOPTS_VALUE)
2474 is_ref_pkt = can_split = 0;
2475
2476
1/2
✓ Branch 0 taken 6256 times.
✗ Branch 1 not taken.
6256 if (is_ref_pkt) {
2477
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6246 times.
6256 if (vs->end_pts == AV_NOPTS_VALUE)
2478 10 vs->end_pts = pkt->pts;
2479
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6246 times.
6256 if (vs->new_start) {
2480 10 vs->new_start = 0;
2481 10 vs->duration = (double)(pkt->pts - vs->end_pts)
2482 10 * st->time_base.num / st->time_base.den;
2483 10 vs->dpp = (double)(pkt->duration) * st->time_base.num / st->time_base.den;
2484 } else {
2485
1/2
✓ Branch 0 taken 6246 times.
✗ Branch 1 not taken.
6246 if (pkt->duration) {
2486 6246 vs->duration += (double)(pkt->duration) * st->time_base.num / st->time_base.den;
2487 } else {
2488 av_log(s, AV_LOG_WARNING, "Stream %d packet with pts %" PRId64 " has duration 0. The segment duration may not be precise.\n",
2489 pkt->stream_index, pkt->pts);
2490 vs->duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den;
2491 }
2492 }
2493 }
2494
2495
3/4
✓ Branch 0 taken 6256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6246 times.
✓ Branch 3 taken 10 times.
6256 can_split = can_split && (pkt->pts - vs->end_pts > 0);
2496
5/6
✓ Branch 0 taken 6246 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 6246 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 56 times.
✓ Branch 5 taken 6190 times.
12502 if (vs->packets_written && can_split && av_compare_ts(pkt->pts - vs->start_pts, st->time_base,
2497 6246 end_pts, AV_TIME_BASE_Q) >= 0) {
2498 int64_t new_start_pos;
2499
4/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 38 times.
56 int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
2500
2501 56 av_write_frame(oc, NULL); /* Flush any buffered data */
2502 56 new_start_pos = avio_tell(oc->pb);
2503 56 vs->size = new_start_pos - vs->start_pos;
2504 56 avio_flush(oc->pb);
2505
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 52 times.
56 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
2506
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (!vs->init_range_length) {
2507 1 range_length = avio_close_dyn_buf(oc->pb, &vs->init_buffer);
2508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (range_length <= 0)
2509 return AVERROR(EINVAL);
2510 1 avio_write(vs->out, vs->init_buffer, range_length);
2511
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!hls->resend_init_file)
2512 1 av_freep(&vs->init_buffer);
2513 1 vs->init_range_length = range_length;
2514 1 avio_open_dyn_buf(&oc->pb);
2515 1 vs->packets_written = 0;
2516 1 vs->start_pos = range_length;
2517
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!byterange_mode) {
2518 1 hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
2519 }
2520 }
2521 }
2522
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 18 times.
56 if (!byterange_mode) {
2523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (vs->vtt_avf) {
2524 hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->url);
2525 }
2526 }
2527
2528
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 47 times.
56 if (hls->flags & HLS_SINGLE_FILE) {
2529 9 ret = flush_dynbuf(vs, &range_length);
2530 9 av_freep(&vs->temp_buffer);
2531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0) {
2532 return ret;
2533 }
2534 9 vs->size = range_length;
2535
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (hls->key_info_file || hls->encrypt)
2536 vs->size = append_single_file(s, vs);
2537 } else {
2538
1/2
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
47 if (oc->url[0]) {
2539 47 proto = avio_find_protocol_name(oc->url);
2540
1/2
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
94 use_temp_file = proto && !strcmp(proto, "file")
2541
2/4
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
94 && (hls->flags & HLS_TEMP_FILE);
2542 }
2543
2544
6/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 6 times.
47 if ((hls->max_seg_size > 0 && (vs->size + vs->start_pos >= hls->max_seg_size)) || !byterange_mode) {
2545 41 AVDictionary *options = NULL;
2546 41 char *filename = NULL;
2547
2/4
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 41 times.
41 if (hls->key_info_file || hls->encrypt) {
2548 av_dict_set(&options, "encryption_key", vs->key_string, 0);
2549 av_dict_set(&options, "encryption_iv", vs->iv_string, 0);
2550 filename = av_asprintf("crypto:%s", oc->url);
2551 } else {
2552 41 filename = av_asprintf("%s", oc->url);
2553 }
2554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (!filename) {
2555 av_dict_free(&options);
2556 return AVERROR(ENOMEM);
2557 }
2558
2559 // look to rename the asset name
2560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (use_temp_file)
2561 av_dict_set(&options, "mpegts_flags", "resend_headers", 0);
2562
2563 41 set_http_options(s, &options, hls);
2564
2565 41 ret = hlsenc_io_open(s, &vs->out, filename, &options);
2566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (ret < 0) {
2567 av_log(s, hls->ignore_io_errors ? AV_LOG_WARNING : AV_LOG_ERROR,
2568 "Failed to open file '%s'\n", filename);
2569 av_freep(&filename);
2570 av_dict_free(&options);
2571 return hls->ignore_io_errors ? 0 : ret;
2572 }
2573
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 37 times.
41 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
2574 4 write_styp(vs->out);
2575 }
2576 41 ret = flush_dynbuf(vs, &range_length);
2577
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (ret < 0) {
2578 av_freep(&filename);
2579 av_dict_free(&options);
2580 return ret;
2581 }
2582 41 ret = hlsenc_io_close(s, &vs->out, filename);
2583
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (ret < 0) {
2584 av_log(s, AV_LOG_WARNING, "upload segment failed,"
2585 " will retry with a new http session.\n");
2586 ff_format_io_close(s, &vs->out);
2587 ret = hlsenc_io_open(s, &vs->out, filename, &options);
2588 reflush_dynbuf(vs, &range_length);
2589 ret = hlsenc_io_close(s, &vs->out, filename);
2590 }
2591 41 av_dict_free(&options);
2592 41 av_freep(&vs->temp_buffer);
2593 41 av_freep(&filename);
2594 }
2595
2596
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
47 if (use_temp_file)
2597 hls_rename_temp_file(s, oc);
2598 }
2599
2600 56 old_filename = av_strdup(oc->url);
2601
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (!old_filename) {
2602 return AVERROR(ENOMEM);
2603 }
2604
2605
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
56 if (vs->start_pos || hls->segment_type != SEGMENT_TYPE_FMP4) {
2606 56 double cur_duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den;
2607 56 ret = hls_append_segment(s, hls, vs, cur_duration, vs->start_pos, vs->size);
2608 56 vs->end_pts = pkt->pts;
2609 56 vs->duration = 0;
2610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ret < 0) {
2611 av_freep(&old_filename);
2612 return ret;
2613 }
2614 }
2615
2616 // if we're building a VOD playlist, skip writing the manifest multiple times, and just wait until the end
2617
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (hls->pl_type != PLAYLIST_TYPE_VOD) {
2618
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
56 if ((ret = hls_window(s, 0, vs)) < 0) {
2619 av_log(s, AV_LOG_WARNING, "upload playlist failed, will retry with a new http session.\n");
2620 ff_format_io_close(s, &vs->out);
2621 if ((ret = hls_window(s, 0, vs)) < 0) {
2622 av_freep(&old_filename);
2623 return ret;
2624 }
2625 }
2626 }
2627
2628
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
56 if (hls->resend_init_file && hls->segment_type == SEGMENT_TYPE_FMP4) {
2629 ret = hls_init_file_resend(s, vs);
2630 if (ret < 0) {
2631 av_freep(&old_filename);
2632 return ret;
2633 }
2634 }
2635
2636
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 47 times.
56 if (hls->flags & HLS_SINGLE_FILE) {
2637 9 vs->start_pos += vs->size;
2638
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (hls->key_info_file || hls->encrypt)
2639 ret = hls_start(s, vs);
2640
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 if (hls->segment_type == SEGMENT_TYPE_MPEGTS && oc->oformat->priv_class && oc->priv_data) {
2641 9 av_opt_set(oc->priv_data, "mpegts_flags", "resend_headers", 0);
2642 }
2643
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 38 times.
47 } else if (hls->max_seg_size > 0) {
2644
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if (vs->size + vs->start_pos >= hls->max_seg_size) {
2645 3 vs->sequence++;
2646 3 sls_flag_file_rename(hls, vs, old_filename);
2647 3 ret = hls_start(s, vs);
2648 3 vs->start_pos = 0;
2649 /* When split segment by byte, the duration is short than hls_time,
2650 * so it is not enough one segment duration as hls_time, */
2651 } else {
2652 6 vs->start_pos = new_start_pos;
2653 }
2654 } else {
2655 38 vs->start_pos = new_start_pos;
2656 38 sls_flag_file_rename(hls, vs, old_filename);
2657 38 ret = hls_start(s, vs);
2658 }
2659 56 vs->number++;
2660 56 av_freep(&old_filename);
2661
2662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ret < 0) {
2663 return ret;
2664 }
2665 }
2666
2667 6256 vs->packets_written++;
2668
1/2
✓ Branch 0 taken 6256 times.
✗ Branch 1 not taken.
6256 if (oc->pb) {
2669 6256 ret = ff_write_chained(oc, stream_index, pkt, s, 0);
2670 6256 vs->video_keyframe_size += pkt->size;
2671
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6256 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6256 if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) {
2672 vs->video_keyframe_size = avio_tell(oc->pb);
2673 } else {
2674 6256 vs->video_keyframe_pos = avio_tell(vs->out);
2675 }
2676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6256 times.
6256 if (hls->ignore_io_errors)
2677 ret = 0;
2678 }
2679
2680 6256 return ret;
2681 }
2682
2683 10 static void hls_deinit(AVFormatContext *s)
2684 {
2685 10 HLSContext *hls = s->priv_data;
2686 10 int i = 0;
2687 10 VariantStream *vs = NULL;
2688
2689
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (i = 0; i < hls->nb_varstreams; i++) {
2690 10 vs = &hls->var_streams[i];
2691
2692 10 av_freep(&vs->basename);
2693 10 av_freep(&vs->base_output_dirname);
2694 10 av_freep(&vs->fmp4_init_filename);
2695 10 av_freep(&vs->vtt_basename);
2696 10 av_freep(&vs->vtt_m3u8_name);
2697
2698 10 avformat_free_context(vs->vtt_avf);
2699 10 avformat_free_context(vs->avf);
2700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->resend_init_file)
2701 av_freep(&vs->init_buffer);
2702 10 hls_free_segments(vs->segments);
2703 10 hls_free_segments(vs->old_segments);
2704 10 av_freep(&vs->m3u8_name);
2705 10 av_freep(&vs->streams);
2706 }
2707
2708 10 ff_format_io_close(s, &hls->m3u8_out);
2709 10 ff_format_io_close(s, &hls->sub_m3u8_out);
2710 10 av_freep(&hls->key_basename);
2711 10 av_freep(&hls->var_streams);
2712 10 av_freep(&hls->cc_streams);
2713 10 av_freep(&hls->master_m3u8_url);
2714 10 }
2715
2716 10 static int hls_write_trailer(struct AVFormatContext *s)
2717 {
2718 10 HLSContext *hls = s->priv_data;
2719 10 AVFormatContext *oc = NULL;
2720 10 AVFormatContext *vtt_oc = NULL;
2721 10 char *old_filename = NULL;
2722 10 const char *proto = NULL;
2723 10 int use_temp_file = 0;
2724 int i;
2725 10 int ret = 0;
2726 10 VariantStream *vs = NULL;
2727 10 AVDictionary *options = NULL;
2728 int range_length, byterange_mode;
2729
2730
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (i = 0; i < hls->nb_varstreams; i++) {
2731 10 char *filename = NULL;
2732 10 vs = &hls->var_streams[i];
2733 10 oc = vs->avf;
2734 10 vtt_oc = vs->vtt_avf;
2735 10 old_filename = av_strdup(oc->url);
2736 10 use_temp_file = 0;
2737
2738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!old_filename) {
2739 return AVERROR(ENOMEM);
2740 }
2741
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (hls->key_info_file || hls->encrypt) {
2742 av_dict_set(&options, "encryption_key", vs->key_string, 0);
2743 av_dict_set(&options, "encryption_iv", vs->iv_string, 0);
2744 filename = av_asprintf("crypto:%s", oc->url);
2745 } else {
2746 10 filename = av_asprintf("%s", oc->url);
2747 }
2748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!filename) {
2749 av_freep(&old_filename);
2750 return AVERROR(ENOMEM);
2751 }
2752
2753
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
2754 1 int range_length = 0;
2755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!vs->init_range_length) {
2756 uint8_t *buffer = NULL;
2757 av_write_frame(oc, NULL); /* Flush any buffered data */
2758
2759 range_length = avio_close_dyn_buf(oc->pb, &buffer);
2760 avio_write(vs->out, buffer, range_length);
2761 av_freep(&buffer);
2762 vs->init_range_length = range_length;
2763 avio_open_dyn_buf(&oc->pb);
2764 vs->packets_written = 0;
2765 vs->start_pos = range_length;
2766 byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
2767 if (!byterange_mode) {
2768 ff_format_io_close(s, &vs->out);
2769 hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
2770 }
2771 }
2772 }
2773
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 if (!(hls->flags & HLS_SINGLE_FILE)) {
2774 9 set_http_options(s, &options, hls);
2775 9 ret = hlsenc_io_open(s, &vs->out, filename, &options);
2776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0) {
2777 av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", oc->url);
2778 goto failed;
2779 }
2780
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (hls->segment_type == SEGMENT_TYPE_FMP4)
2781 1 write_styp(vs->out);
2782 }
2783 10 ret = flush_dynbuf(vs, &range_length);
2784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
2785 goto failed;
2786
2787 10 vs->size = range_length;
2788 10 ret = hlsenc_io_close(s, &vs->out, filename);
2789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
2790 av_log(s, AV_LOG_WARNING, "upload segment failed, will retry with a new http session.\n");
2791 ff_format_io_close(s, &vs->out);
2792 ret = hlsenc_io_open(s, &vs->out, filename, &options);
2793 if (ret < 0) {
2794 av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", oc->url);
2795 goto failed;
2796 }
2797 reflush_dynbuf(vs, &range_length);
2798 ret = hlsenc_io_close(s, &vs->out, filename);
2799 if (ret < 0)
2800 av_log(s, AV_LOG_WARNING, "Failed to upload file '%s' at the end.\n", oc->url);
2801 }
2802
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 if (hls->flags & HLS_SINGLE_FILE) {
2803
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (hls->key_info_file || hls->encrypt) {
2804 vs->size = append_single_file(s, vs);
2805 }
2806 1 hlsenc_io_close(s, &vs->out_single_file, vs->basename);
2807 }
2808 9 failed:
2809 10 av_freep(&vs->temp_buffer);
2810 10 av_dict_free(&options);
2811 10 av_freep(&filename);
2812 10 av_write_trailer(oc);
2813
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (oc->url[0]) {
2814 10 proto = avio_find_protocol_name(oc->url);
2815
3/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
10 use_temp_file = proto && !strcmp(proto, "file") && (hls->flags & HLS_TEMP_FILE);
2816 }
2817
2818 // rename that segment from .tmp to the real one
2819
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if (use_temp_file && !(hls->flags & HLS_SINGLE_FILE)) {
2820 hls_rename_temp_file(s, oc);
2821 av_freep(&old_filename);
2822 old_filename = av_strdup(oc->url);
2823
2824 if (!old_filename) {
2825 return AVERROR(ENOMEM);
2826 }
2827 }
2828
2829 /* after av_write_trailer, then duration + 1 duration per packet */
2830 10 hls_append_segment(s, hls, vs, vs->duration + vs->dpp, vs->start_pos, vs->size);
2831
2832 10 sls_flag_file_rename(hls, vs, old_filename);
2833
2834
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (vtt_oc) {
2835 if (vtt_oc->pb)
2836 av_write_trailer(vtt_oc);
2837 vs->size = avio_tell(vs->vtt_avf->pb) - vs->start_pos;
2838 ff_format_io_close(s, &vtt_oc->pb);
2839 }
2840 10 ret = hls_window(s, 1, vs);
2841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
2842 av_log(s, AV_LOG_WARNING, "upload playlist failed, will retry with a new http session.\n");
2843 ff_format_io_close(s, &vs->out);
2844 hls_window(s, 1, vs);
2845 }
2846 10 ffio_free_dyn_buf(&oc->pb);
2847
2848 10 av_free(old_filename);
2849 }
2850
2851 10 return 0;
2852 }
2853
2854
2855 10 static int hls_init(AVFormatContext *s)
2856 {
2857 10 int ret = 0;
2858 10 int i = 0;
2859 10 int j = 0;
2860 10 HLSContext *hls = s->priv_data;
2861 const char *pattern;
2862 10 VariantStream *vs = NULL;
2863
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 const char *vtt_pattern = hls->flags & HLS_SINGLE_FILE ? ".vtt" : "%d.vtt";
2864 10 char *p = NULL;
2865 10 int http_base_proto = ff_is_http_proto(s->url);
2866 10 int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1;
2867 10 double initial_program_date_time = av_gettime() / 1000000.0;
2868
2869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->use_localtime) {
2870 pattern = get_default_pattern_localtime_fmt(s);
2871 } else {
2872
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 pattern = hls->segment_type == SEGMENT_TYPE_FMP4 ? "%d.m4s" : "%d.ts";
2873
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (hls->flags & HLS_SINGLE_FILE)
2874 1 pattern += 2;
2875 }
2876
2877 10 hls->has_default_key = 0;
2878 10 hls->has_video_m3u8 = 0;
2879 10 ret = update_variant_stream_info(s);
2880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0) {
2881 av_log(s, AV_LOG_ERROR, "Variant stream info update failed with status %x\n",
2882 ret);
2883 return ret;
2884 }
2885
2886
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (!hls->method && http_base_proto) {
2887 av_log(hls, AV_LOG_WARNING, "No HTTP method set, hls muxer defaulting to method PUT.\n");
2888 }
2889
2890 10 ret = validate_name(hls->nb_varstreams, s->url);
2891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
2892 return ret;
2893
2894
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (hls->segment_filename) {
2895 10 ret = validate_name(hls->nb_varstreams, hls->segment_filename);
2896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
2897 return ret;
2898 }
2899
2900
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
10 if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) {
2901 2 ret = validate_name(hls->nb_varstreams, hls->fmp4_init_filename);
2902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
2903 return ret;
2904 }
2905
2906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->subtitle_filename) {
2907 ret = validate_name(hls->nb_varstreams, hls->subtitle_filename);
2908 if (ret < 0)
2909 return ret;
2910 }
2911
2912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (hls->master_pl_name) {
2913 ret = update_master_pl_info(s);
2914 if (ret < 0) {
2915 av_log(s, AV_LOG_ERROR, "Master stream info update failed with status %x\n",
2916 ret);
2917 return ret;
2918 }
2919 }
2920
2921
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if ((hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) ||
2922
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH) ||
2923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME)) {
2924 time_t t = time(NULL);
2925 if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH) {
2926 hls->start_sequence = av_gettime();
2927 } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) {
2928 hls->start_sequence = (int64_t)t;
2929 } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME) {
2930 char b[15];
2931 struct tm *p, tmbuf;
2932 if (!(p = localtime_r(&t, &tmbuf)))
2933 return AVERROR(errno);
2934 if (!strftime(b, sizeof(b), "%Y%m%d%H%M%S", p))
2935 return AVERROR(ENOMEM);
2936 hls->start_sequence = strtoll(b, NULL, 10);
2937 }
2938 av_log(hls, AV_LOG_DEBUG, "start_number evaluated to %"PRId64"\n", hls->start_sequence);
2939 }
2940
2941
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 hls->recording_time = hls->init_time ? hls->init_time : hls->time;
2942
2943
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if (hls->flags & HLS_SPLIT_BY_TIME && hls->flags & HLS_INDEPENDENT_SEGMENTS) {
2944 // Independent segments cannot be guaranteed when splitting by time
2945 hls->flags &= ~HLS_INDEPENDENT_SEGMENTS;
2946 av_log(s, AV_LOG_WARNING,
2947 "'split_by_time' and 'independent_segments' cannot be "
2948 "enabled together. Disabling 'independent_segments' flag\n");
2949 }
2950
2951
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (i = 0; i < hls->nb_varstreams; i++) {
2952 10 vs = &hls->var_streams[i];
2953
2954 10 ret = format_name(s->url, &vs->m3u8_name, i, vs->varname);
2955
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
2956 return ret;
2957
2958 10 vs->sequence = hls->start_sequence;
2959 10 vs->start_pts = AV_NOPTS_VALUE;
2960 10 vs->end_pts = AV_NOPTS_VALUE;
2961 10 vs->current_segment_final_filename_fmt[0] = '\0';
2962 10 vs->initial_prog_date_time = initial_program_date_time;
2963
2964
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (j = 0; j < vs->nb_streams; j++) {
2965 10 vs->has_video += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
2966 /* Get one video stream to reference for split segments
2967 * so use the first video stream index. */
2968
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if ((vs->has_video == 1) && (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)) {
2969 vs->reference_stream_index = vs->streams[j]->index;
2970 }
2971 10 vs->has_subtitle += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE;
2972 }
2973
2974
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (vs->has_video > 1)
2975 av_log(s, AV_LOG_WARNING, "More than a single video stream present, expect issues decoding it.\n");
2976
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
2977 1 vs->oformat = av_guess_format("mp4", NULL, NULL);
2978 } else {
2979 9 vs->oformat = av_guess_format("mpegts", NULL, NULL);
2980 }
2981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!vs->oformat)
2982 return AVERROR_MUXER_NOT_FOUND;
2983
2984
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (hls->segment_filename) {
2985 10 ret = format_name(hls->segment_filename, &vs->basename, i, vs->varname);
2986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
2987 return ret;
2988 } else {
2989 p = strrchr(vs->m3u8_name, '.');
2990 if (p)
2991 *p = '\0';
2992
2993 vs->basename = av_asprintf("%s%s", vs->m3u8_name, pattern);
2994 if (!vs->basename)
2995 return AVERROR(ENOMEM);
2996
2997 if (p)
2998 *p = '.';
2999 }
3000
3001
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (hls->segment_type == SEGMENT_TYPE_FMP4) {
3002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hls->nb_varstreams > 1)
3003 fmp4_init_filename_len += strlen(POSTFIX_PATTERN);
3004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hls->flags & HLS_SINGLE_FILE) {
3005 vs->fmp4_init_filename = av_strdup(vs->basename);
3006 if (!vs->fmp4_init_filename)
3007 return AVERROR(ENOMEM);
3008 } else {
3009 1 vs->fmp4_init_filename = av_malloc(fmp4_init_filename_len);
3010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!vs->fmp4_init_filename)
3011 return AVERROR(ENOMEM);
3012 1 av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename,
3013 fmp4_init_filename_len);
3014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hls->nb_varstreams > 1) {
3015 if (av_stristr(vs->fmp4_init_filename, "%v")) {
3016 av_freep(&vs->fmp4_init_filename);
3017 ret = format_name(hls->fmp4_init_filename,
3018 &vs->fmp4_init_filename, i, vs->varname);
3019 } else {
3020 ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i);
3021 }
3022 if (ret < 0)
3023 return ret;
3024 }
3025
3026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hls->use_localtime) {
3027 int r;
3028 char *expanded = NULL;
3029
3030 r = strftime_expand(vs->fmp4_init_filename, &expanded);
3031 if (r < 0) {
3032 av_log(s, AV_LOG_ERROR, "Could not get segment filename with strftime\n");
3033 return r;
3034 }
3035 av_free(vs->fmp4_init_filename);
3036 vs->fmp4_init_filename = expanded;
3037 }
3038
3039 1 p = strrchr(vs->m3u8_name, '/');
3040
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (p) {
3041 1 char tmp = *(++p);
3042 1 *p = '\0';
3043 1 vs->base_output_dirname = av_asprintf("%s%s", vs->m3u8_name,
3044 vs->fmp4_init_filename);
3045 1 *p = tmp;
3046 } else {
3047 vs->base_output_dirname = av_strdup(vs->fmp4_init_filename);
3048 }
3049
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!vs->base_output_dirname)
3050 return AVERROR(ENOMEM);
3051 }
3052 }
3053
3054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 ret = hls->use_localtime ? sls_flag_check_duration_size(hls, vs) : sls_flag_check_duration_size_index(hls);
3055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
3056 return ret;
3057
3058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (vs->has_subtitle) {
3059 vs->vtt_oformat = av_guess_format("webvtt", NULL, NULL);
3060 if (!vs->vtt_oformat)
3061 return AVERROR_MUXER_NOT_FOUND;
3062
3063 p = strrchr(vs->m3u8_name, '.');
3064 if (p)
3065 *p = '\0';
3066
3067 vs->vtt_basename = av_asprintf("%s%s", vs->m3u8_name, vtt_pattern);
3068 if (!vs->vtt_basename)
3069 return AVERROR(ENOMEM);
3070
3071 if (hls->subtitle_filename) {
3072 ret = format_name(hls->subtitle_filename, &vs->vtt_m3u8_name, i, vs->varname);
3073 if (ret < 0)
3074 return ret;
3075 } else {
3076 vs->vtt_m3u8_name = av_asprintf("%s_vtt.m3u8", vs->m3u8_name);
3077 if (!vs->vtt_m3u8_name)
3078 return AVERROR(ENOMEM);
3079 }
3080 if (p)
3081 *p = '.';
3082 }
3083
3084
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if ((ret = hls_mux_init(s, vs)) < 0)
3085 return ret;
3086
3087
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (hls->flags & HLS_APPEND_LIST) {
3088 1 parse_playlist(s, vs->m3u8_name, vs);
3089 1 vs->discontinuity = 1;
3090
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (hls->init_time > 0) {
3091 av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time,"
3092 " hls_init_time value will have no effect\n");
3093 hls->init_time = 0;
3094 hls->recording_time = hls->time;
3095 }
3096 }
3097
3098
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if ((ret = hls_start(s, vs)) < 0)
3099 return ret;
3100 10 vs->number++;
3101 }
3102
3103 10 return ret;
3104 }
3105
3106 #define OFFSET(x) offsetof(HLSContext, x)
3107 #define E AV_OPT_FLAG_ENCODING_PARAM
3108 static const AVOption options[] = {
3109 {"start_number", "set first number in the sequence", OFFSET(start_sequence),AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E},
3110 {"hls_time", "set segment length", OFFSET(time), AV_OPT_TYPE_DURATION, {.i64 = 2000000}, 0, INT64_MAX, E},
3111 {"hls_init_time", "set segment length at init list", OFFSET(init_time), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, E},
3112 {"hls_list_size", "set maximum number of playlist entries", OFFSET(max_nb_segments), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E},
3113 {"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},
3114 #if FF_HLS_TS_OPTIONS
3115 {"hls_ts_options","set hls mpegts list of options for the container format used for hls (deprecated, use hls_segment_options instead of it.)", OFFSET(format_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E | AV_OPT_FLAG_DEPRECATED},
3116 #endif
3117 {"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},
3118 {"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},
3119 {"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
3120 {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
3121 {"hls_segment_options","set segments files format options of hls", OFFSET(format_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E},
3122 {"hls_segment_size", "maximum size per segment file, (in bytes)", OFFSET(max_seg_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E},
3123 {"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},
3124 {"hls_enc", "enable AES128 encryption support", OFFSET(encrypt), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E},
3125 {"hls_enc_key", "hex-coded 16 byte key to encrypt the segments", OFFSET(key), AV_OPT_TYPE_STRING, .flags = E},
3126 {"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},
3127 {"hls_enc_iv", "hex-coded 16 byte initialization vector", OFFSET(iv), AV_OPT_TYPE_STRING, .flags = E},
3128 {"hls_subtitle_path", "set path of hls subtitles", OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
3129 {"hls_segment_type", "set hls segment files type", OFFSET(segment_type), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_MPEGTS }, 0, SEGMENT_TYPE_FMP4, E, "segment_type"},
3130 {"mpegts", "make segment file to mpegts files in m3u8", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MPEGTS }, 0, UINT_MAX, E, "segment_type"},
3131 {"fmp4", "make segment file to fragment mp4 files in m3u8", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_FMP4 }, 0, UINT_MAX, E, "segment_type"},
3132 {"hls_fmp4_init_filename", "set fragment mp4 file init filename", OFFSET(fmp4_init_filename), AV_OPT_TYPE_STRING, {.str = "init.mp4"}, 0, 0, E},
3133 {"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 },
3134 {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"},
3135 {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"},
3136 {"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, "flags"},
3137 {"delete_segments", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0, UINT_MAX, E, "flags"},
3138 {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX, E, "flags"},
3139 {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX, E, "flags"},
3140 {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX, E, "flags"},
3141 {"split_by_time", "split the hls segment by time which user set by hls_time", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SPLIT_BY_TIME }, 0, UINT_MAX, E, "flags"},
3142 {"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_APPEND_LIST }, 0, UINT_MAX, E, "flags"},
3143 {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"},
3144 {"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, "flags"},
3145 {"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, "flags"},
3146 {"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, "flags"},
3147 {"periodic_rekey", "reload keyinfo file periodically for re-keying", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PERIODIC_REKEY }, 0, UINT_MAX, E, "flags"},
3148 {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_INDEPENDENT_SEGMENTS }, 0, UINT_MAX, E, "flags"},
3149 {"iframes_only", "add EXT-X-I-FRAMES-ONLY, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_I_FRAMES_ONLY }, 0, UINT_MAX, E, "flags"},
3150 {"strftime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
3151 {"strftime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
3152 {"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, "pl_type" },
3153 {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" },
3154 {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" },
3155 {"method", "set the HTTP method(default: PUT)", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
3156 {"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, "start_sequence_source_type" },
3157 {"generic", "start_number value (default)", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_START_NUMBER }, INT_MIN, INT_MAX, E, "start_sequence_source_type" },
3158 {"epoch", "seconds since epoch", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH }, INT_MIN, INT_MAX, E, "start_sequence_source_type" },
3159 {"epoch_us", "microseconds since epoch", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_MICROSECONDS_SINCE_EPOCH }, INT_MIN, INT_MAX, E, "start_sequence_source_type" },
3160 {"datetime", "current datetime as YYYYMMDDhhmmss", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_FORMATTED_DATETIME }, INT_MIN, INT_MAX, E, "start_sequence_source_type" },
3161 {"http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
3162 {"var_stream_map", "Variant stream map string", OFFSET(var_stream_map), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
3163 {"cc_stream_map", "Closed captions stream map string", OFFSET(cc_stream_map), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
3164 {"master_pl_name", "Create HLS master playlist with this name", OFFSET(master_pl_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
3165 {"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},
3166 {"http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
3167 {"timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
3168 {"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 },
3169 {"headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
3170 { NULL },
3171 };
3172
3173 static const AVClass hls_class = {
3174 .class_name = "hls muxer",
3175 .item_name = av_default_item_name,
3176 .option = options,
3177 .version = LIBAVUTIL_VERSION_INT,
3178 };
3179
3180
3181 const AVOutputFormat ff_hls_muxer = {
3182 .name = "hls",
3183 .long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
3184 .extensions = "m3u8",
3185 .priv_data_size = sizeof(HLSContext),
3186 .audio_codec = AV_CODEC_ID_AAC,
3187 .video_codec = AV_CODEC_ID_H264,
3188 .subtitle_codec = AV_CODEC_ID_WEBVTT,
3189 .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_NODIMENSIONS,
3190 .init = hls_init,
3191 .write_header = hls_write_header,
3192 .write_packet = hls_write_packet,
3193 .write_trailer = hls_write_trailer,
3194 .deinit = hls_deinit,
3195 .priv_class = &hls_class,
3196 };
3197