double duration; // last segment duration computed so far, in seconds
int64_t start_pos; // last segment starting position
int64_t size; // last segment size
+ int64_t max_seg_size; // every segment file max size
int nb_entries;
int discontinuity_set;
} else
hls->nb_entries++;
+ if (hls->max_seg_size > 0) {
+ return 0;
+ }
hls->sequence++;
return 0;
AVIOContext *sub_out = NULL;
char temp_filename[1024];
int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries);
- int version = hls->flags & HLS_SINGLE_FILE ? 4 : 3;
+ int version = 3;
const char *proto = avio_find_protocol_name(s->filename);
int use_rename = proto && !strcmp(proto, "file");
static unsigned warned_non_file;
char *iv_string = NULL;
AVDictionary *options = NULL;
double prog_date_time = hls->initial_prog_date_time;
+ int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
+
+ if (byterange_mode) {
+ version = 4;
+ sequence = 0;
+ }
if (!use_rename && !warned_non_file++)
av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporarly partial files\n");
avio_printf(out, "#EXTINF:%ld,\n", lrint(en->duration));
else
avio_printf(out, "#EXTINF:%f,\n", en->duration);
- if (hls->flags & HLS_SINGLE_FILE)
+ if (byterange_mode)
avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
en->size, en->pos);
if (hls->flags & HLS_PROGRAM_DATE_TIME) {
for (en = hls->segments; en; en = en->next) {
avio_printf(sub_out, "#EXTINF:%f,\n", en->duration);
- if (hls->flags & HLS_SINGLE_FILE)
+ if (byterange_mode)
avio_printf(sub_out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
en->size, en->pos);
if (hls->baseurl)
if (c->vtt_basename)
av_strlcpy(vtt_oc->filename, c->vtt_basename,
sizeof(vtt_oc->filename));
+ } else if (c->max_seg_size > 0) {
+ if (av_get_frame_filename2(oc->filename, sizeof(oc->filename),
+ c->basename, c->wrap ? c->sequence % c->wrap : c->sequence,
+ AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) {
+ av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename);
+ return AVERROR(EINVAL);
+ }
} else {
if (c->use_localtime) {
time_t now0;
for (i = 0; i < s->nb_streams; i++) {
AVStream *inner_st;
AVStream *outer_st = s->streams[i];
+
+ if (hls->max_seg_size > 0) {
+ if ((outer_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
+ (outer_st->codecpar->bit_rate > hls->max_seg_size)) {
+ av_log(s, AV_LOG_WARNING, "Your video bitrate is bigger than hls_segment_size, "
+ "(%"PRId64 " > %"PRId64 "), the result maybe not be what you want.",
+ outer_st->codecpar->bit_rate, hls->max_seg_size);
+ }
+ }
+
if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)
inner_st = hls->avf->streams[i];
else if (hls->vtt_avf)
if (hls->avf->oformat->priv_class && hls->avf->priv_data)
av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0);
hls->number++;
+ } else if (hls->max_seg_size > 0) {
+ if (hls->avf->oformat->priv_class && hls->avf->priv_data)
+ av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0);
+ if (hls->start_pos >= hls->max_seg_size) {
+ hls->sequence++;
+ ff_format_io_close(s, &oc->pb);
+ if (hls->vtt_avf)
+ ff_format_io_close(s, &hls->vtt_avf->pb);
+ ret = hls_start(s);
+ hls->start_pos = 0;
+ /* When split segment by byte, the duration is short than hls_time,
+ * so it is not enough one segment duration as hls_time, */
+ hls->number--;
+ }
+ hls->number++;
} else {
ff_format_io_close(s, &oc->pb);
if (hls->vtt_avf)
{"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},
{"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
{"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
+ {"hls_segment_size", "maximum size per segment file, (in bytes)", OFFSET(max_seg_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E},
{"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},
{"hls_subtitle_path", "set path of hls subtitles", OFFSET(subtitle_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
{"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"},