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 <stdint.h> 25cabdff1aSopenharmony_ci 26cabdff1aSopenharmony_ci#include "libavutil/time_internal.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include "avformat.h" 29cabdff1aSopenharmony_ci#include "hlsplaylist.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_civoid ff_hls_write_playlist_version(AVIOContext *out, int version) 32cabdff1aSopenharmony_ci{ 33cabdff1aSopenharmony_ci if (!out) 34cabdff1aSopenharmony_ci return; 35cabdff1aSopenharmony_ci avio_printf(out, "#EXTM3U\n"); 36cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-VERSION:%d\n", version); 37cabdff1aSopenharmony_ci} 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_civoid ff_hls_write_audio_rendition(AVIOContext *out, const char *agroup, 40cabdff1aSopenharmony_ci const char *filename, const char *language, 41cabdff1aSopenharmony_ci int name_id, int is_default) 42cabdff1aSopenharmony_ci{ 43cabdff1aSopenharmony_ci if (!out || !agroup || !filename) 44cabdff1aSopenharmony_ci return; 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup); 47cabdff1aSopenharmony_ci avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,", name_id, is_default ? "YES" : "NO"); 48cabdff1aSopenharmony_ci if (language) { 49cabdff1aSopenharmony_ci avio_printf(out, "LANGUAGE=\"%s\",", language); 50cabdff1aSopenharmony_ci } 51cabdff1aSopenharmony_ci avio_printf(out, "URI=\"%s\"\n", filename); 52cabdff1aSopenharmony_ci} 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_civoid ff_hls_write_subtitle_rendition(AVIOContext *out, const char *sgroup, 55cabdff1aSopenharmony_ci const char *filename, const char *language, 56cabdff1aSopenharmony_ci int name_id, int is_default) 57cabdff1aSopenharmony_ci{ 58cabdff1aSopenharmony_ci if (!out || !filename) 59cabdff1aSopenharmony_ci return; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"%s\"", sgroup); 62cabdff1aSopenharmony_ci avio_printf(out, ",NAME=\"subtitle_%d\",DEFAULT=%s,", name_id, is_default ? "YES" : "NO"); 63cabdff1aSopenharmony_ci if (language) { 64cabdff1aSopenharmony_ci avio_printf(out, "LANGUAGE=\"%s\",", language); 65cabdff1aSopenharmony_ci } 66cabdff1aSopenharmony_ci avio_printf(out, "URI=\"%s\"\n", filename); 67cabdff1aSopenharmony_ci} 68cabdff1aSopenharmony_ci 69cabdff1aSopenharmony_civoid ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, 70cabdff1aSopenharmony_ci const char *filename, const char *agroup, 71cabdff1aSopenharmony_ci const char *codecs, const char *ccgroup, 72cabdff1aSopenharmony_ci const char *sgroup) 73cabdff1aSopenharmony_ci{ 74cabdff1aSopenharmony_ci if (!out || !filename) 75cabdff1aSopenharmony_ci return; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci if (!bandwidth) { 78cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_WARNING, 79cabdff1aSopenharmony_ci "Bandwidth info not available, set audio and video bitrates\n"); 80cabdff1aSopenharmony_ci return; 81cabdff1aSopenharmony_ci } 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-STREAM-INF:BANDWIDTH=%d", bandwidth); 84cabdff1aSopenharmony_ci if (st && st->codecpar->width > 0 && st->codecpar->height > 0) 85cabdff1aSopenharmony_ci avio_printf(out, ",RESOLUTION=%dx%d", st->codecpar->width, 86cabdff1aSopenharmony_ci st->codecpar->height); 87cabdff1aSopenharmony_ci if (codecs && codecs[0]) 88cabdff1aSopenharmony_ci avio_printf(out, ",CODECS=\"%s\"", codecs); 89cabdff1aSopenharmony_ci if (agroup && agroup[0]) 90cabdff1aSopenharmony_ci avio_printf(out, ",AUDIO=\"group_%s\"", agroup); 91cabdff1aSopenharmony_ci if (ccgroup && ccgroup[0]) 92cabdff1aSopenharmony_ci avio_printf(out, ",CLOSED-CAPTIONS=\"%s\"", ccgroup); 93cabdff1aSopenharmony_ci if (sgroup && sgroup[0]) 94cabdff1aSopenharmony_ci avio_printf(out, ",SUBTITLES=\"%s\"", sgroup); 95cabdff1aSopenharmony_ci avio_printf(out, "\n%s\n\n", filename); 96cabdff1aSopenharmony_ci} 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_civoid ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, 99cabdff1aSopenharmony_ci int target_duration, int64_t sequence, 100cabdff1aSopenharmony_ci uint32_t playlist_type, int iframe_mode) 101cabdff1aSopenharmony_ci{ 102cabdff1aSopenharmony_ci if (!out) 103cabdff1aSopenharmony_ci return; 104cabdff1aSopenharmony_ci ff_hls_write_playlist_version(out, version); 105cabdff1aSopenharmony_ci if (allowcache == 0 || allowcache == 1) { 106cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", allowcache == 0 ? "NO" : "YES"); 107cabdff1aSopenharmony_ci } 108cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); 109cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); 110cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci if (playlist_type == PLAYLIST_TYPE_EVENT) { 113cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); 114cabdff1aSopenharmony_ci } else if (playlist_type == PLAYLIST_TYPE_VOD) { 115cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); 116cabdff1aSopenharmony_ci } 117cabdff1aSopenharmony_ci if (iframe_mode) { 118cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-I-FRAMES-ONLY\n"); 119cabdff1aSopenharmony_ci } 120cabdff1aSopenharmony_ci} 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_civoid ff_hls_write_init_file(AVIOContext *out, const char *filename, 123cabdff1aSopenharmony_ci int byterange_mode, int64_t size, int64_t pos) 124cabdff1aSopenharmony_ci{ 125cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-MAP:URI=\"%s\"", filename); 126cabdff1aSopenharmony_ci if (byterange_mode) { 127cabdff1aSopenharmony_ci avio_printf(out, ",BYTERANGE=\"%"PRId64"@%"PRId64"\"", size, pos); 128cabdff1aSopenharmony_ci } 129cabdff1aSopenharmony_ci avio_printf(out, "\n"); 130cabdff1aSopenharmony_ci} 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ciint ff_hls_write_file_entry(AVIOContext *out, int insert_discont, 133cabdff1aSopenharmony_ci int byterange_mode, double duration, 134cabdff1aSopenharmony_ci int round_duration, int64_t size, 135cabdff1aSopenharmony_ci int64_t pos /* Used only if HLS_SINGLE_FILE flag is set */, 136cabdff1aSopenharmony_ci const char *baseurl /* Ignored if NULL */, 137cabdff1aSopenharmony_ci const char *filename, double *prog_date_time, 138cabdff1aSopenharmony_ci int64_t video_keyframe_size, int64_t video_keyframe_pos, 139cabdff1aSopenharmony_ci int iframe_mode) 140cabdff1aSopenharmony_ci{ 141cabdff1aSopenharmony_ci if (!out || !filename) 142cabdff1aSopenharmony_ci return AVERROR(EINVAL); 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci if (insert_discont) { 145cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-DISCONTINUITY\n"); 146cabdff1aSopenharmony_ci } 147cabdff1aSopenharmony_ci if (round_duration) 148cabdff1aSopenharmony_ci avio_printf(out, "#EXTINF:%ld,\n", lrint(duration)); 149cabdff1aSopenharmony_ci else 150cabdff1aSopenharmony_ci avio_printf(out, "#EXTINF:%f,\n", duration); 151cabdff1aSopenharmony_ci if (byterange_mode) 152cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", iframe_mode ? video_keyframe_size : size, 153cabdff1aSopenharmony_ci iframe_mode ? video_keyframe_pos : pos); 154cabdff1aSopenharmony_ci 155cabdff1aSopenharmony_ci if (prog_date_time) { 156cabdff1aSopenharmony_ci time_t tt, wrongsecs; 157cabdff1aSopenharmony_ci int milli; 158cabdff1aSopenharmony_ci struct tm *tm, tmpbuf; 159cabdff1aSopenharmony_ci char buf0[128], buf1[128]; 160cabdff1aSopenharmony_ci tt = (int64_t)*prog_date_time; 161cabdff1aSopenharmony_ci milli = av_clip(lrint(1000*(*prog_date_time - tt)), 0, 999); 162cabdff1aSopenharmony_ci tm = localtime_r(&tt, &tmpbuf); 163cabdff1aSopenharmony_ci if (!strftime(buf0, sizeof(buf0), "%Y-%m-%dT%H:%M:%S", tm)) { 164cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_DEBUG, "strftime error in ff_hls_write_file_entry\n"); 165cabdff1aSopenharmony_ci return AVERROR_UNKNOWN; 166cabdff1aSopenharmony_ci } 167cabdff1aSopenharmony_ci if (!strftime(buf1, sizeof(buf1), "%z", tm) || buf1[1]<'0' ||buf1[1]>'2') { 168cabdff1aSopenharmony_ci int tz_min, dst = tm->tm_isdst; 169cabdff1aSopenharmony_ci tm = gmtime_r(&tt, &tmpbuf); 170cabdff1aSopenharmony_ci tm->tm_isdst = dst; 171cabdff1aSopenharmony_ci wrongsecs = mktime(tm); 172cabdff1aSopenharmony_ci tz_min = (FFABS(wrongsecs - tt) + 30) / 60; 173cabdff1aSopenharmony_ci snprintf(buf1, sizeof(buf1), 174cabdff1aSopenharmony_ci "%c%02d%02d", 175cabdff1aSopenharmony_ci wrongsecs <= tt ? '+' : '-', 176cabdff1aSopenharmony_ci tz_min / 60, 177cabdff1aSopenharmony_ci tz_min % 60); 178cabdff1aSopenharmony_ci } 179cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1); 180cabdff1aSopenharmony_ci *prog_date_time += duration; 181cabdff1aSopenharmony_ci } 182cabdff1aSopenharmony_ci if (baseurl) 183cabdff1aSopenharmony_ci avio_printf(out, "%s", baseurl); 184cabdff1aSopenharmony_ci avio_printf(out, "%s\n", filename); 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci return 0; 187cabdff1aSopenharmony_ci} 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_civoid ff_hls_write_end_list(AVIOContext *out) 190cabdff1aSopenharmony_ci{ 191cabdff1aSopenharmony_ci if (!out) 192cabdff1aSopenharmony_ci return; 193cabdff1aSopenharmony_ci avio_printf(out, "#EXT-X-ENDLIST\n"); 194cabdff1aSopenharmony_ci} 195cabdff1aSopenharmony_ci 196