[FFmpeg-devel] [PATCH] lavf/segment: [WIP] add support to segmentation expression

Stefano Sabatini stefasab at gmail.com
Fri Mar 13 19:34:14 CET 2015


TODO: add documentation, add support to chapters.
---
 libavformat/segment.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/libavformat/segment.c b/libavformat/segment.c
index b65a2eb..794504a 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -33,6 +33,7 @@
 #include "internal.h"
 
 #include "libavutil/avassert.h"
+#include "libavutil/eval.h"
 #include "libavutil/log.h"
 #include "libavutil/opt.h"
 #include "libavutil/avstring.h"
@@ -62,6 +63,28 @@ typedef enum {
     LIST_TYPE_NB,
 } ListType;
 
+static const char *const var_names[] = {
+    "segment_n",    ///< segment count
+    "segment_packets_n",
+    "segment_size",
+
+    "packet_pos",   ///< position in the file
+    "packet_n",
+    "packet_t",
+    NULL
+};
+
+enum var_name {
+    VAR_SEGMENT_N,
+    VAR_SEGMENT_PACKETS_N,
+    VAR_SEGMENT_SIZE,
+
+    VAR_PACKET_POS,
+    VAR_PACKET_N,
+    VAR_PACKET_T,
+    VAR_VARS_NB
+};
+
 #define SEGMENT_LIST_FLAG_CACHE 1
 #define SEGMENT_LIST_FLAG_LIVE  2
 
@@ -71,6 +94,11 @@ typedef struct SegmentContext {
     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
+
+    char *segment_expr;
+    AVExpr *segment_pexpr;
+    double var_values[VAR_VARS_NB];
+
     AVOutputFormat *oformat;
     AVFormatContext *avf;
     char *format;              ///< format to use for output segment files
@@ -225,6 +253,10 @@ static int segment_start(AVFormatContext *s, int write_header)
     }
 
     seg->segment_idx++;
+
+    seg->var_values[VAR_SEGMENT_SIZE] = 0;
+    seg->var_values[VAR_SEGMENT_PACKETS_N] = 0;
+
     if ((seg->segment_idx_wrap) && (seg->segment_idx%seg->segment_idx_wrap == 0))
         seg->segment_idx_wrap_nb++;
 
@@ -606,6 +638,15 @@ static int seg_write_header(AVFormatContext *s)
     } else if (seg->frames_str) {
         if ((ret = parse_frames(s, &seg->frames, &seg->nb_frames, seg->frames_str)) < 0)
             return ret;
+    } else if (seg->segment_expr) {
+        ret = av_expr_parse(&seg->segment_pexpr, seg->segment_expr, var_names,
+                            NULL, NULL, NULL, NULL, 0, s);
+        if (ret < 0) {
+            av_log(s, AV_LOG_ERROR,
+                   "Error when evaluating the segment expression '%s'\n",
+                   seg->segment_expr);
+            return ret;
+        }
     } else {
         /* set default value if not specified */
         if (!seg->time_str)
@@ -732,12 +773,26 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
     if (!seg->avf)
         return AVERROR(EINVAL);
 
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb))
+    seg->var_values[VAR_SEGMENT_N] = seg->segment_count;
+
+    seg->var_values[VAR_SEGMENT_SIZE] += pkt->size;
+    seg->var_values[VAR_SEGMENT_PACKETS_N] += 1;
+
+    seg->var_values[VAR_PACKET_POS] = pkt->pos;
+    seg->var_values[VAR_PACKET_T] = TS2T(pkt->pts, st->time_base);
+    seg->var_values[VAR_PACKET_N] += 1;
+
     if (seg->times) {
         end_pts = seg->segment_count < seg->nb_times ?
             seg->times[seg->segment_count] : INT64_MAX;
     } else if (seg->frames) {
         start_frame = seg->segment_count < seg->nb_frames ?
             seg->frames[seg->segment_count] : INT_MAX;
+    } else if (seg->segment_expr) {
+        double res = av_expr_eval(seg->segment_pexpr, seg->var_values, NULL);
+        if (res != 0)
+            seg->cut_pending = 1;
     } else {
         if (seg->use_clocktime) {
             int64_t avgt = av_gettime();
@@ -855,6 +910,7 @@ fail:
     av_opt_free(seg);
     av_freep(&seg->times);
     av_freep(&seg->frames);
+    av_expr_free(seg->segment_pexpr); seg->segment_pexpr = NULL;
 
     cur = seg->segment_list_entries;
     while (cur) {
@@ -891,6 +947,7 @@ static const AVOption options[] = {
     { "m3u8", "M3U8 format",     0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
     { "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
 
+    { "segment_expr",       "set segmentation expression",               OFFSET(segment_expr), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
     { "segment_atclocktime",      "set segment to be cut at clocktime",  OFFSET(use_clocktime), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E},
     { "segment_time",      "set segment duration",                       OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
     { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E },
-- 
1.8.3.2



More information about the ffmpeg-devel mailing list