[FFmpeg-devel] [PATCH] Add segment name id set by user defined

Steven Liu lingjiujianke at gmail.com
Thu May 8 19:29:14 CEST 2014


Hi!

Some times, m3u8 can be used for timeshift used segment id,
for example:
    xxx.m3u8?starttime=139xxxxxxx&endtime=139xxxxxxx,
    or
    xxx.m3u8?starttime=20140408121221&endtime=20140408131221
    or
    seek m3u8 file
    xxx.m3u8?starttime=14&endtime=3600

so add the parameters for the segment id for index,
for example:

segment name id by mpegts starttime, use the parameters:
-segment_name_flag starttime
    output-0.ts
    output-14.ts
    output-24.ts
    output-34.ts

segment name id by time(), use the parameters:
-segment_name_flag time
    output-1399568846.ts
    output-1399568856.ts
    output-1399568866.ts

segment name id by format time, use the parameters:
-segment_name_flag fmt_time
    output-20140509010807.ts
    output-20140509010817.ts
    output-20140509010827.ts

this parameters can use default, if use the default, it will as before
this functions can be used for m3u8 time shift

Signed-off-by: Steven Liu <qi.liu at chinacache.com>
---
 libavformat/avformat.h |  2 +-
 libavformat/segment.c  | 81 ++++++++++++++++++++++++++++++++++++++++++++++----
 libavformat/utils.c    |  4 +--
 3 files changed, 79 insertions(+), 8 deletions(-)

diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 7d2db6a..a11a9eb 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2465,7 +2465,7 @@ void av_dump_format(AVFormatContext *ic,
  * @return 0 if OK, -1 on format error
  */
 int av_get_frame_filename(char *buf, int buf_size,
-                          const char *path, int number);
+                          const char *path, int64_t number);

 /**
  * Check whether filename actually is a numbered sequence generator.
diff --git a/libavformat/segment.c b/libavformat/segment.c
index fe84f27..0b02752 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -58,12 +58,19 @@ typedef enum {
     LIST_TYPE_NB,
 } ListType;

+typedef enum {
+    SEG_NAME_FORMAT_INDEX_DEFAULT = 0,
+    SEG_NAME_FORMAT_TIME_FROM_0 = 1,
+    SEG_NAME_FORMAT_TIME_139XXX = 2,
+    SEG_NAME_FORMAT_TIME_YMDHMS = 3,
+} SegNameFmt;
+
 #define SEGMENT_LIST_FLAG_CACHE 1
 #define SEGMENT_LIST_FLAG_LIVE  2

 typedef struct {
     const AVClass *class;  /**< Class for private options. */
-    int segment_idx;       ///< index of the segment file to write, starting from 0
+    int64_t segment_idx;       ///< index of the segment file to write, starting from 0
     int segment_idx_wrap;  ///< number after which the index wraps
     int segment_idx_wrap_nb;  ///< number of time the index has wraped
     int segment_count;     ///< number of segment files already written
@@ -87,6 +94,8 @@ typedef struct {
     int *frames;           ///< list of frame number specification
     int nb_frames;         ///< number of elments in the frames array
     int frame_count;
+    int seg_name_format;   ///< segment name format flag
+    time_t start_by_systime; ///< get system time for start of the m3u8

     int64_t time_delta;
     int  individual_header_trailer; /**< Set by a private option. */
@@ -156,14 +165,44 @@ static int segment_mux_init(AVFormatContext *s)
     return 0;
 }

+static int64_t time_to_int64(struct tm *p)
+{
+    char time_str[16] = { 0, };
+
+    snprintf(time_str, sizeof(time_str), "%04d%02d%02d%02d%02d%02d",
+             1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday,
+             p->tm_hour, p->tm_min, p->tm_sec);
+
+    return strtoll((char *)time_str, NULL, 10);
+}
+
 static int set_segment_filename(AVFormatContext *s)
 {
     SegmentContext *seg = s->priv_data;
     AVFormatContext *oc = seg->avf;
     size_t size;
+    double seg_cur_val = seg->cur_entry.end_time - seg->cur_entry.start_time;
+    struct tm *p;
+
+    switch (seg->seg_name_format) {
+    case SEG_NAME_FORMAT_TIME_YMDHMS:
+        seg->start_by_systime += (int)seg_cur_val;
+        p = localtime(&(seg->start_by_systime));
+        seg->segment_idx = time_to_int64(p);
+        break;
+
+    case SEG_NAME_FORMAT_TIME_139XXX:
+    case SEG_NAME_FORMAT_TIME_FROM_0:
+        seg->segment_idx += (int) seg_cur_val;
+        break;
+    case SEG_NAME_FORMAT_INDEX_DEFAULT:
+    default:
+        seg->segment_idx++;
+        if (seg->segment_idx_wrap)
+            seg->segment_idx %= seg->segment_idx_wrap;
+        break;
+    }

-    if (seg->segment_idx_wrap)
-        seg->segment_idx %= seg->segment_idx_wrap;
     if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
                               s->filename, seg->segment_idx) < 0) {
         av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->filename);
@@ -185,6 +224,32 @@ static int set_segment_filename(AVFormatContext *s)
     return 0;
 }

+static int64_t get_seg_idx(AVFormatContext *s, int fmt)
+{
+    SegmentContext *seg = s->priv_data;
+
+    switch (fmt) {
+        case SEG_NAME_FORMAT_TIME_FROM_0:
+            seg->segment_idx = 0;
+        break;
+
+    case SEG_NAME_FORMAT_TIME_139XXX:
+        seg->segment_idx = time(0);
+        break;
+
+    case SEG_NAME_FORMAT_TIME_YMDHMS:
+        seg->segment_idx = time(&(seg->start_by_systime));
+        break;
+
+    case SEG_NAME_FORMAT_INDEX_DEFAULT:
+    default:
+        seg->segment_idx++;
+        break;
+    }
+
+    return seg->segment_idx;
+}
+
 static int segment_start(AVFormatContext *s, int write_header)
 {
     SegmentContext *seg = s->priv_data;
@@ -199,7 +264,6 @@ static int segment_start(AVFormatContext *s, int write_header)
         oc = seg->avf;
     }

-    seg->segment_idx++;
     if ((seg->segment_idx_wrap) && (seg->segment_idx%seg->segment_idx_wrap == 0))
         seg->segment_idx_wrap_nb++;

@@ -621,6 +685,8 @@ static int seg_write_header(AVFormatContext *s)
         goto fail;
     oc = seg->avf;

+    seg->segment_idx = get_seg_idx(s, seg->seg_name_format);
+
     if ((ret = set_segment_filename(s)) < 0)
         goto fail;

@@ -796,12 +862,17 @@ static const AVOption options[] = {
     { "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },

     { "segment_time",      "set segment duration",                       OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
+    { "segment_name_flag", "set segment name format",                       OFFSET(seg_name_format),AV_OPT_TYPE_INT, {.i64 = 0},  0, 3,       E, "name_flag" },
+    { "seq", "name id by sequence",     0, AV_OPT_TYPE_CONST, {.i64=SEG_NAME_FORMAT_INDEX_DEFAULT }, INT_MIN, INT_MAX, E, "name_flag" },
+    { "starttime", "name id by starttime",     0, AV_OPT_TYPE_CONST, {.i64=SEG_NAME_FORMAT_TIME_FROM_0 }, INT_MIN, INT_MAX, E, "name_flag" },
+    { "time",  "name id by 139XXXXXXX",      0, AV_OPT_TYPE_CONST, {.i64=SEG_NAME_FORMAT_TIME_139XXX  }, INT_MIN, INT_MAX, E, "name_flag" },
+    { "fmt_time",  "name id by YYYYMMDDhhmmss", 0, AV_OPT_TYPE_CONST, {.i64=SEG_NAME_FORMAT_TIME_YMDHMS  }, INT_MIN, INT_MAX, E, "name_flag" },
     { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E },
     { "segment_times",     "set segment split time points",              OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },
     { "segment_frames",    "set segment split frame numbers",            OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },
     { "segment_wrap",      "set number after which the index wraps",     OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
     { "segment_list_entry_prefix", "set base url prefix for segments", OFFSET(entry_prefix), AV_OPT_TYPE_STRING,  {.str = NULL}, 0, 0, E },
-    { "segment_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+    { "segment_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E },
     { "segment_wrap_number", "set the number of wrap before the first segment", OFFSET(segment_idx_wrap_nb), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },

     { "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 4f5b310..5a4e5e0 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -3985,7 +3985,7 @@ uint64_t ff_ntp_time(void)
     return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US;
 }

-int av_get_frame_filename(char *buf, int buf_size, const char *path, int number)
+int av_get_frame_filename(char *buf, int buf_size, const char *path, int64_t number)
 {
     const char *p;
     char *q, buf1[20], c;
@@ -4013,7 +4013,7 @@ int av_get_frame_filename(char *buf, int buf_size, const char *path, int number)
                 if (percentd_found)
                     goto fail;
                 percentd_found = 1;
-                snprintf(buf1, sizeof(buf1), "%0*d", nd, number);
+                snprintf(buf1, sizeof(buf1), "%0*lld", nd, number);
                 len = strlen(buf1);
                 if ((q - buf + len) > buf_size - 1)
                     goto fail;
--
1.8.5.2 (Apple Git-48)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Add-segment-name-id-set-by-user-defined.patch
Type: application/octet-stream
Size: 9399 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20140509/7bda3494/attachment.obj>


More information about the ffmpeg-devel mailing list