Browse Source

Improve hls VOD mode hls performance problem.

This fixes the creation of the hls manifest in hlsenc.c by writing the
entire manifest at the end for VOD playlists. Live & Event Playlists are unaffected.
This also fixes the behavior with HLS_TEMP_FILE to work correctly when
-hlsflags temp_file is specified, instead of always relying on use_rename, which caused these problems.

Files that would previously take over a week to fragment now take
1 minute on the same hardware. This was a 153 hour audio file (2.2GB of audio).

Signed-off-by: Ronak Patel <ronak2121@yahoo.com>
tags/n4.1
Ronak Patel Steven Liu 7 years ago
parent
commit
223d2bde22
1 changed files with 33 additions and 11 deletions
  1. +33
    -11
      libavformat/hlsenc.c

+ 33
- 11
libavformat/hlsenc.c View File

@@ -1374,7 +1374,7 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
char temp_filename[1024]; char temp_filename[1024];
int64_t sequence = FFMAX(hls->start_sequence, vs->sequence - vs->nb_entries); int64_t sequence = FFMAX(hls->start_sequence, vs->sequence - vs->nb_entries);
const char *proto = avio_find_protocol_name(s->url); const char *proto = avio_find_protocol_name(s->url);
int use_rename = proto && !strcmp(proto, "file");
int use_temp_file = proto && !strcmp(proto, "file") && (s->flags & HLS_TEMP_FILE);
static unsigned warned_non_file; static unsigned warned_non_file;
char *key_uri = NULL; char *key_uri = NULL;
char *iv_string = NULL; char *iv_string = NULL;
@@ -1397,11 +1397,11 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
hls->version = 7; hls->version = 7;
} }


if (!use_rename && !warned_non_file++)
if (!use_temp_file && !warned_non_file++)
av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n");


set_http_options(s, &options, hls); set_http_options(s, &options, hls);
snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", vs->m3u8_name);
snprintf(temp_filename, sizeof(temp_filename), use_temp_file ? "%s.tmp" : "%s", vs->m3u8_name);
if ((ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options)) < 0) if ((ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options)) < 0)
goto fail; goto fail;


@@ -1472,7 +1472,7 @@ fail:
av_dict_free(&options); av_dict_free(&options);
hlsenc_io_close(s, &hls->m3u8_out, temp_filename); hlsenc_io_close(s, &hls->m3u8_out, temp_filename);
hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name); hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name);
if (ret >= 0 && use_rename)
if (use_temp_file)
ff_rename(temp_filename, vs->m3u8_name, s); ff_rename(temp_filename, vs->m3u8_name, s);


if (ret >= 0 && hls->master_pl_name) if (ret >= 0 && hls->master_pl_name)
@@ -1488,6 +1488,8 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
AVFormatContext *oc = vs->avf; AVFormatContext *oc = vs->avf;
AVFormatContext *vtt_oc = vs->vtt_avf; AVFormatContext *vtt_oc = vs->vtt_avf;
AVDictionary *options = NULL; AVDictionary *options = NULL;
const char *proto = avio_find_protocol_name(s->url);
int use_temp_file = proto && !strcmp(proto, "file") && (s->flags & HLS_TEMP_FILE);
char *filename, iv_string[KEYSIZE*2 + 1]; char *filename, iv_string[KEYSIZE*2 + 1];
int err = 0; int err = 0;


@@ -1583,7 +1585,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)


set_http_options(s, &options, c); set_http_options(s, &options, c);


if (c->flags & HLS_TEMP_FILE) {
if (use_temp_file) {
char *new_name = av_asprintf("%s.tmp", oc->url); char *new_name = av_asprintf("%s.tmp", oc->url);
if (!new_name) if (!new_name)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
@@ -2145,6 +2147,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
int ret = 0, can_split = 1, i, j; int ret = 0, can_split = 1, i, j;
int stream_index = 0; int stream_index = 0;
int range_length = 0; int range_length = 0;
const char *proto = avio_find_protocol_name(s->url);
int use_temp_file = proto && !strcmp(proto, "file") && (s->flags & HLS_TEMP_FILE);
uint8_t *buffer = NULL; uint8_t *buffer = NULL;
VariantStream *vs = NULL; VariantStream *vs = NULL;
AVDictionary *options = NULL; AVDictionary *options = NULL;
@@ -2214,10 +2218,10 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)


} }


char *old_filename = NULL;
if (vs->packets_written && can_split && av_compare_ts(pkt->pts - vs->start_pts, st->time_base, if (vs->packets_written && can_split && av_compare_ts(pkt->pts - vs->start_pts, st->time_base,
end_pts, AV_TIME_BASE_Q) >= 0) { end_pts, AV_TIME_BASE_Q) >= 0) {
int64_t new_start_pos; int64_t new_start_pos;
char *old_filename = NULL;
int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);


av_write_frame(vs->avf, NULL); /* Flush any buffered data */ av_write_frame(vs->avf, NULL); /* Flush any buffered data */
@@ -2253,11 +2257,13 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->url); hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->url);
} }
} }
if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) {

// look to rename the asset name
if (use_temp_file && oc->url[0]) {
if (!(hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size <= 0)) if (!(hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size <= 0))
if ((vs->avf->oformat->priv_class && vs->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4)
if ((vs->avf->oformat->priv_class && vs->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4) {
av_opt_set(vs->avf->priv_data, "mpegts_flags", "resend_headers", 0); av_opt_set(vs->avf->priv_data, "mpegts_flags", "resend_headers", 0);
hls_rename_temp_file(s, oc);
}
} }


if (vs->fmp4_init_mode) { if (vs->fmp4_init_mode) {
@@ -2286,6 +2292,17 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
return ret; return ret;
} }
ff_format_io_close(s, &vs->out); ff_format_io_close(s, &vs->out);

// rename that segment from .tmp to the real one
if (use_temp_file && oc->url[0]) {
hls_rename_temp_file(s, oc);
av_free(old_filename);
old_filename = av_strdup(vs->avf->url);

if (!old_filename) {
return AVERROR(ENOMEM);
}
}
} }
} }


@@ -2334,10 +2351,12 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
return ret; return ret;
} }


if (!vs->fmp4_init_mode || byterange_mode)
// if we're building a VOD playlist, skip writing the manifest multiple times, and just wait until the end
if (hls->pl_type != PLAYLIST_TYPE_VOD) {
if ((ret = hls_window(s, 0, vs)) < 0) { if ((ret = hls_window(s, 0, vs)) < 0) {
return ret; return ret;
} }
}
} }


vs->packets_written++; vs->packets_written++;
@@ -2352,6 +2371,8 @@ static int hls_write_trailer(struct AVFormatContext *s)
AVFormatContext *oc = NULL; AVFormatContext *oc = NULL;
AVFormatContext *vtt_oc = NULL; AVFormatContext *vtt_oc = NULL;
char *old_filename = NULL; char *old_filename = NULL;
const char *proto = avio_find_protocol_name(s->url);
int use_temp_file = proto && !strcmp(proto, "file") && (s->flags & HLS_TEMP_FILE);
int i; int i;
int ret = 0; int ret = 0;
VariantStream *vs = NULL; VariantStream *vs = NULL;
@@ -2394,7 +2415,8 @@ failed:
if (hls->segment_type != SEGMENT_TYPE_FMP4) if (hls->segment_type != SEGMENT_TYPE_FMP4)
ff_format_io_close(s, &oc->pb); ff_format_io_close(s, &oc->pb);


if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) {
// rename that segment from .tmp to the real one
if (use_temp_file && oc->url[0] && !(hls->flags & HLS_SINGLE_FILE)) {
hls_rename_temp_file(s, oc); hls_rename_temp_file(s, oc);
av_free(old_filename); av_free(old_filename);
old_filename = av_strdup(vs->avf->url); old_filename = av_strdup(vs->avf->url);


Loading…
Cancel
Save