[FFmpeg-devel] [PATCH 1/2] avformat/segment: add delete segment_list flag
Simon Thelen
ffmpeg-dev at c-14.de
Sat Oct 8 17:02:41 EEST 2016
Works in the same manner as the hls segment_delete flag.
Signed-off-by: Simon Thelen <ffmpeg-dev at c-14.de>
---
doc/muxers.texi | 5 +++
libavformat/segment.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+)
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 9ec2e31..4002473 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1228,6 +1228,11 @@ Allow caching (only affects M3U8 list files).
@item live
Allow live-friendly file generation.
+
+ at item delete
+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
@item segment_list_size @var{size}
diff --git a/libavformat/segment.c b/libavformat/segment.c
index 33a5cf0..82872fa 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -26,8 +26,12 @@
/* #define DEBUG */
+#include "config.h"
#include <float.h>
#include <time.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include "avformat.h"
#include "avio_internal.h"
@@ -67,6 +71,7 @@ typedef enum {
#define SEGMENT_LIST_FLAG_CACHE 1
#define SEGMENT_LIST_FLAG_LIVE 2
+#define SEGMENT_LIST_FLAG_DELETE 4
typedef struct SegmentContext {
const AVClass *class; /**< Class for private options. */
@@ -126,6 +131,7 @@ typedef struct SegmentContext {
SegmentListEntry cur_entry;
SegmentListEntry *segment_list_entries;
SegmentListEntry *segment_list_entries_end;
+ SegmentListEntry *segment_list_old;
} SegmentContext;
static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
@@ -144,6 +150,72 @@ static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
avio_w8(ctx, '"');
}
+static int delete_old_segments(SegmentContext *seg)
+{
+ SegmentListEntry *segment, *previous_segment = NULL;
+ float playlist_duration = 0.0f;
+ int ret = 0, path_size;
+ char *dirname = NULL, *p;
+ char *path = NULL;
+
+ segment = seg->segment_list_entries;
+ while (segment) {
+ playlist_duration += segment->end_time - segment->start_time;
+ segment = segment->next;
+ }
+
+ segment = seg->segment_list_old;
+ while (segment) {
+ playlist_duration -= segment->end_time - segment->start_time;
+ previous_segment = segment;
+ segment = previous_segment->next;
+ if (playlist_duration <= -(previous_segment->end_time - previous_segment->start_time)) {
+ previous_segment->next = NULL;
+ break;
+ }
+ }
+
+ if (segment) {
+ dirname = av_strdup(seg->avf->filename);
+ if (!dirname) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ p = (char *)av_basename(dirname);
+ *p = '\0';
+ }
+
+ while (segment) {
+ av_log(seg, 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(segment, AV_LOG_ERROR, "failed to delete old segment %s: %s\n",
+ path, strerror(errno));
+ }
+ av_freep(&path);
+ previous_segment = segment;
+ segment = previous_segment->next;
+ av_freep(&previous_segment->filename);
+ av_free(previous_segment);
+ }
+
+fail:
+ av_free(path);
+ av_free(dirname);
+
+ return ret;
+}
+
+
static int segment_mux_init(AVFormatContext *s)
{
SegmentContext *seg = s->priv_data;
@@ -381,8 +453,16 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
if (seg->list_size && seg->segment_count >= seg->list_size) {
entry = seg->segment_list_entries;
seg->segment_list_entries = seg->segment_list_entries->next;
+ if (entry && seg->list_flags & SEGMENT_LIST_FLAG_DELETE &&
+ !seg->segment_idx_wrap) {
+ entry->next = seg->segment_list_old;
+ seg->segment_list_old = entry;
+ if ((ret = delete_old_segments(seg)) < 0)
+ return ret;
+ } else {
av_freep(&entry->filename);
av_freep(&entry);
+ }
}
if ((ret = segment_list_open(s)) < 0)
@@ -957,6 +1037,14 @@ fail:
cur = next;
}
+ cur = seg->segment_list_old;
+ while (cur) {
+ next = cur->next;
+ av_freep(&cur->filename);
+ av_free(cur);
+ cur = next;
+ }
+
avformat_free_context(oc);
seg->avf = NULL;
return ret;
@@ -974,6 +1062,7 @@ static const AVOption options[] = {
{ "segment_list_flags","set flags affecting segment list generation", OFFSET(list_flags), AV_OPT_TYPE_FLAGS, {.i64 = SEGMENT_LIST_FLAG_CACHE }, 0, UINT_MAX, E, "list_flags"},
{ "cache", "allow list caching", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_CACHE }, INT_MIN, INT_MAX, E, "list_flags"},
{ "live", "enable live-friendly list generation (useful for HLS)", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_LIVE }, INT_MIN, INT_MAX, E, "list_flags"},
+ { "delete", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_DELETE }, INT_MIN, INT_MAX, E, "list_flags"},
{ "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
--
2.10.0
More information about the ffmpeg-devel
mailing list