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