FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/hlsenc.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 721 1886 38.2%
Functions: 25 47 53.2%
Branches: 422 1388 30.4%

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