On date Friday 2015-03-13 19:34:14 +0100, Stefano Sabatini encoded:
> TODO: add documentation, add support to chapters.
> ---
>  libavformat/segment.c | 57 
> +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)

Up, I'm a bit dissatisfied by the variable names verbosity,
suggestions are welcome.

About chapter support, I'm going to add it with another patch (my
initial use case was to have the ability to split an input file - a
ripped CD in my case - to multiple files each one containing a single
chapter).
-- 
FFmpeg = Forgiving & Fiendish Meaningless Pitiless Enlightened Generator
>From 787e19206a0a1b75bc2bf53fb39ceb72b4c5dade Mon Sep 17 00:00:00 2001
From: Stefano Sabatini <stefa...@gmail.com>
Date: Fri, 13 Mar 2015 19:30:46 +0100
Subject: [PATCH] lavf/segment: add support to segmentation expression

TODO: bump micro
---
 doc/muxers.texi       | 34 ++++++++++++++++++++++++++
 libavformat/segment.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 100 insertions(+)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index fe419ac..3e9476c 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -964,6 +964,40 @@ A list file with the suffix @code{".m3u8"} will auto-select this format.
 
 If not specified the type is guessed from the list file name suffix.
 
+@item segment_expr @var{expression}
+Set an expression, when evaluates to a value different from 0 enables
+segmentation.
+
+The expression accepts the following parameters:
+@table
+@table @option
+@item segment_n
+segment count, starting from 0
+
+@item segment_packets_n
+segment packets count
+
+@item segment_ref_packets_n
+segment reference stream packets count
+
+@item segment_packets_size
+total packets size in the segment, in bytes. Note that this only
+expresses the size of the packets payload, unregarding the container
+size overhead.
+
+@item packet_pos
+packet position, NAN if unspecified
+
+@item packet_n
+packet count, starting from 0
+
+@item packet_t
+packet time, expressed in seconds
+@end table
+
+For example to cut a file when a size of 10Mi bytes is reached, use
+the expression @code{gt(segment_packets_size,10Mi)}.
+
 @item segment_time @var{time}
 Set segment duration to @var{time}, the value must be a duration
 specification. A value of 0 means that it will try to split the
diff --git a/libavformat/segment.c b/libavformat/segment.c
index 8255843..0cf5360 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,32 @@ typedef enum {
     LIST_TYPE_NB,
 } ListType;
 
+static const char *const var_names[] = {
+    "segment_n",             ///< segment count
+    "segment_packets_n",     ///< segment frame count
+    "segment_ref_packets_n", ///< segment reference stream frame count
+    "segment_packets_size",  ///< total packets size
+
+    "packet_pos",   ///< packet position in the file
+    "packet_n",     ///< packet count
+    "packet_t",     ///< packet time
+
+    NULL
+};
+
+enum var_name {
+    VAR_SEGMENT_N,
+    VAR_SEGMENT_PACKETS_N,
+    VAR_SEGMENT_REF_PACKETS_N,
+    VAR_SEGMENT_PACKETS_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 +98,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 +257,12 @@ static int segment_start(AVFormatContext *s, int write_header)
     }
 
     seg->segment_idx++;
+
+    seg->var_values[VAR_SEGMENT_N] = seg->segment_count;
+    seg->var_values[VAR_SEGMENT_PACKETS_SIZE] = 0;
+    seg->var_values[VAR_SEGMENT_PACKETS_N] = 0;
+    seg->var_values[VAR_SEGMENT_REF_PACKETS_N] = 0;
+
     if ((seg->segment_idx_wrap) && (seg->segment_idx%seg->segment_idx_wrap == 0))
         seg->segment_idx_wrap_nb++;
 
@@ -617,6 +655,17 @@ static int seg_write_header(AVFormatContext *s)
         seg->time = -1;
     }
 
+    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;
+        }
+    }
+
     if (seg->format_options_str) {
         ret = av_dict_parse_string(&seg->format_options, seg->format_options_str, "=", ":", 0);
         if (ret < 0) {
@@ -731,6 +780,21 @@ 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_PACKETS_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 (pkt->stream_index == seg->reference_stream_index)
+        seg->var_values[VAR_SEGMENT_REF_PACKETS_N] += 1;
+
+    if (seg->segment_expr) {
+        double res = av_expr_eval(seg->segment_pexpr, seg->var_values, NULL);
+        seg->cut_pending = res;
+    }
+
     if (seg->times) {
         end_pts = seg->segment_count < seg->nb_times ?
             seg->times[seg->segment_count] : INT64_MAX;
@@ -854,6 +918,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) {
@@ -890,6 +955,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

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to