Option removes segments no longer in playlist when older than playlist + segment duration
Signed-off-by: Christian Suloway <csulo...@globaleagleent.com> --- libavformat/hlsenc.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 0a48919..11817a9 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -19,8 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" #include <float.h> #include <stdint.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdio.h> #include "libavutil/avassert.h" #include "libavutil/mathematics.h" @@ -58,6 +63,7 @@ typedef struct HLSContext { float time; // Set by a private option. int max_nb_segments; // Set by a private option. int wrap; // Set by a private option. + int delete_segments; uint32_t flags; // enum HLSFlags int allowcache; @@ -72,6 +78,7 @@ typedef struct HLSContext { HLSSegment *segments; HLSSegment *last_segment; + HLSSegment *old_segments; char *dirname; char *basename; @@ -90,6 +97,52 @@ static void hls_free_segment(HLSSegment *en) av_freep(&en); } +static int hls_delete_old_segments(HLSContext *hls) { + + HLSSegment *segment, *previous_segment = NULL; + float playlist_duration = 0.0f; + int path_size; + char *path; + + segment = hls->segments; + while (segment) { + playlist_duration += segment->duration; + segment = segment->next; + } + + segment = hls->old_segments; + while (segment) { + playlist_duration -= segment->duration; + previous_segment = segment; + segment = segment->next; + if (playlist_duration <= 0.0f) { + previous_segment->next = NULL; + break; + } + } + + while (segment) { + av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n", + segment->filename); + path_size = strlen(hls->dirname) + strlen(segment->filename) + 1; + path = av_malloc(path_size); + if (!path) + return AVERROR(ENOMEM); + av_strlcpy(path, hls->dirname, path_size); + av_strlcat(path, segment->filename, path_size); + if (unlink(path) < 0) { + av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", + path, strerror(errno)); + } + av_free(path); + previous_segment = segment; + segment = segment->next; + hls_free_segment(previous_segment); + } + + return 0; +} + static int hls_mux_init(AVFormatContext *s) { HLSContext *hls = s->priv_data; @@ -124,6 +177,7 @@ static int hls_append_segment(HLSContext *hls, double duration, int64_t pos, int64_t size) { HLSSegment *en = av_malloc(sizeof(*en)); + int ret; if (!en) return AVERROR(ENOMEM); @@ -147,7 +201,14 @@ static int hls_append_segment(HLSContext *hls, double duration, int64_t pos, if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) { en = hls->segments; hls->segments = en->next; - hls_free_segment(en); + + if (en && hls->delete_segments && !hls->wrap) { + en->next = hls->old_segments; + hls->old_segments = en; + if ((ret = hls_delete_old_segments(hls)) < 0) + return ret; + } else + hls_free_segment(en); } else hls->nb_entries++; @@ -156,9 +217,9 @@ static int hls_append_segment(HLSContext *hls, double duration, int64_t pos, return 0; } -static void hls_free_segments(HLSContext *hls) +static void hls_free_segments(HLSSegment *p) { - HLSSegment *p = hls->segments, *en; + HLSSegment *en; while(p) { en = p; @@ -197,7 +258,6 @@ static int hls_window(AVFormatContext *s, int last) sequence); for (en = hls->segments; en; en = en->next) { - avio_printf(hls->pb, "#EXTINF:%f,\n", en->duration); if (hls->flags & HLS_SINGLE_FILE) avio_printf(hls->pb, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n", @@ -442,7 +502,8 @@ static int hls_write_trailer(struct AVFormatContext *s) hls->avf = NULL; hls_window(s, 1); - hls_free_segments(hls); + hls_free_segments(hls->segments); + hls_free_segments(hls->old_segments); av_free(hls->dirname); avio_close(hls->pb); @@ -458,6 +519,7 @@ static const AVOption options[] = { {"hls_list_size", "set maximum number of playlist entries", OFFSET(max_nb_segments), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E}, {"hls_ts_options","set hls mpegts list of options for the container format used for hls", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_wrap", "set number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E}, + {"hls_delete", "delete segment files that are no longer part of the playlist", OFFSET(delete_segments), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E}, {"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_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"}, -- 1.9.3 (Apple Git-50) _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel