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