diff options
author | Christian Suloway <csuloway@row44.com> | 2014-12-08 10:25:05 -0600 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2014-12-10 23:49:25 +0100 |
commit | 97b65f612617b9e238c8f95bcce82be145c2fafd (patch) | |
tree | 363c5cfa8780567c253dbb6975fcbd18548dcfce | |
parent | ae93965359e71c1f88ba170f8efd6a198344c235 (diff) | |
download | ffmpeg-97b65f612617b9e238c8f95bcce82be145c2fafd.tar.gz |
avformat/hlsenc: added segment file deletion
This option flag deletes segment files removed from the playlist after a
period of time equal to the duration of the segment plus the duration of
the playlist.
Signed-off-by: Christian Suloway <csuloway@globaleagleent.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | doc/muxers.texi | 4 | ||||
-rw-r--r-- | libavformat/hlsenc.c | 90 |
2 files changed, 90 insertions, 4 deletions
diff --git a/doc/muxers.texi b/doc/muxers.texi index 34e827cde7..a1264d2125 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -273,6 +273,10 @@ ffmpeg -i in.nut -hls_flags single_file out.m3u8 @end example Will produce the playlist, @file{out.m3u8}, and a single segment file, @file{out.ts}. + +@item hls_flags delete_segments +Segment files removed from the playlist are deleted after a period of time +equal to the duration of the segment plus the duration of the playlist. @end table @anchor{ico} diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index d5ea990476..79f3a2311d 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -19,8 +19,12 @@ * 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 "libavutil/avassert.h" #include "libavutil/mathematics.h" @@ -31,6 +35,7 @@ #include "avformat.h" #include "internal.h" +#include "os_support.h" typedef struct HLSSegment { char filename[1024]; @@ -44,6 +49,7 @@ typedef struct HLSSegment { typedef enum HLSFlags { // Generate a single media file and use byte ranges in the playlist. HLS_SINGLE_FILE = (1 << 0), + HLS_DELETE_SEGMENTS = (1 << 1), } HLSFlags; typedef struct HLSContext { @@ -73,6 +79,7 @@ typedef struct HLSContext { HLSSegment *segments; HLSSegment *last_segment; + HLSSegment *old_segments; char *basename; char *baseurl; @@ -82,6 +89,71 @@ typedef struct HLSContext { AVIOContext *pb; } HLSContext; +static int hls_delete_old_segments(HLSContext *hls) { + + HLSSegment *segment, *previous_segment = NULL; + float playlist_duration = 0.0f; + int ret = 0, path_size; + char *dirname = NULL, *p, *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 = previous_segment->next; + if (playlist_duration <= -previous_segment->duration) { + previous_segment->next = NULL; + break; + } + } + + if (segment) { + if (hls->segment_filename) { + dirname = av_strdup(hls->segment_filename); + } else { + dirname = av_strdup(hls->avf->filename); + } + if (!dirname) { + ret = AVERROR(ENOMEM); + goto fail; + } + p = (char *)av_basename(dirname); + *p = '\0'; + } + + while (segment) { + av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n", + segment->filename); + path_size = strlen(dirname) + strlen(segment->filename) + 1; + path = av_malloc(path_size); + if (!path) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(path, 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 = previous_segment->next; + av_free(previous_segment); + } + +fail: + av_free(dirname); + + return ret; +} + static int hls_mux_init(AVFormatContext *s) { HLSContext *hls = s->priv_data; @@ -116,6 +188,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); @@ -137,7 +210,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; - av_free(en); + if (en && hls->flags & HLS_DELETE_SEGMENTS && + !(hls->flags & HLS_SINGLE_FILE || hls->wrap)) { + en->next = hls->old_segments; + hls->old_segments = en; + if ((ret = hls_delete_old_segments(hls)) < 0) + return ret; + } else + av_free(en); } else hls->nb_entries++; @@ -146,9 +226,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; @@ -402,7 +482,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); avio_close(hls->pb); return 0; } @@ -420,6 +501,7 @@ static const AVOption options[] = { {"hls_segment_filename", "filename template for segment files", OFFSET(segment_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"}, {"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"}, + {"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"}, { NULL }, }; |