[FFmpeg-devel] [PATCH 2/3] avformat/hlsenc: added segment file deletion

Christian Suloway csuloway at row44.com
Fri Dec 5 00:05:25 CET 2014


Option removes segments no longer in playlist when older than playlist + segment duration

Signed-off-by: Christian Suloway <csuloway at 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)



More information about the ffmpeg-devel mailing list