[FFmpeg-devel] [PATCH] lavf/segment: add logic to track chapter, and add segment_n and segment_id variables

Stefano Sabatini stefasab at gmail.com
Fri Mar 20 14:14:24 CET 2015


---
 doc/muxers.texi       | 12 ++++++++++++
 libavformat/segment.c | 38 +++++++++++++++++++++++++++++++++++---
 2 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 3e9476c..fcb121b 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -985,6 +985,15 @@ total packets size in the segment, in bytes. Note that this only
 expresses the size of the packets payload, unregarding the container
 size overhead.
 
+ at item chapter_n
+number of the chapter, starting from 0, it is set to NAN if
+there are no chapters. This variable is only updated when a new
+reference stream packet is processed.
+
+ at item chapter_id
+id number of the chapter, starting from 0, it is set to NAN if
+there are no chapters
+
 @item packet_pos
 packet position, NAN if unspecified
 
@@ -998,6 +1007,9 @@ packet time, expressed in seconds
 For example to cut a file when a size of 10Mi bytes is reached, use
 the expression @code{gt(segment_packets_size,10Mi)}.
 
+To cut then input at each chapter start, use the expression
+ at code{gt(chapter_n,segment_n)}.
+
 @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 0cf5360..947a0c6 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -69,6 +69,9 @@ static const char *const var_names[] = {
     "segment_ref_packets_n", ///< segment reference stream frame count
     "segment_packets_size",  ///< total packets size
 
+    "chapter_n",             ///< chapter number
+    "chapter_id",            ///< chapter id
+
     "packet_pos",   ///< packet position in the file
     "packet_n",     ///< packet count
     "packet_t",     ///< packet time
@@ -82,6 +85,9 @@ enum var_name {
     VAR_SEGMENT_REF_PACKETS_N,
     VAR_SEGMENT_PACKETS_SIZE,
 
+    VAR_CHAPTER_N,
+    VAR_CHAPTER_ID,
+
     VAR_PACKET_POS,
     VAR_PACKET_N,
     VAR_PACKET_T,
@@ -146,6 +152,9 @@ typedef struct SegmentContext {
     SegmentListEntry cur_entry;
     SegmentListEntry *segment_list_entries;
     SegmentListEntry *segment_list_entries_end;
+
+    int chapter_index;     ///< index used to keep track of the current chapter
+    double next_chapter_start;
 } SegmentContext;
 
 static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
@@ -655,6 +664,14 @@ static int seg_write_header(AVFormatContext *s)
         seg->time = -1;
     }
 
+    seg->chapter_index = -1;
+    if (s->nb_chapters) {
+        AVChapter *chapter = s->chapters[0];
+        seg->next_chapter_start = chapter->start * av_q2d(chapter->time_base);
+    }
+    seg->var_values[VAR_CHAPTER_N]  = NAN;
+    seg->var_values[VAR_CHAPTER_ID] = NAN;
+
     if (seg->segment_expr) {
         ret = av_expr_parse(&seg->segment_pexpr, seg->segment_expr, var_names,
                             NULL, NULL, NULL, NULL, 0, s);
@@ -766,6 +783,8 @@ fail:
     return ret;
 }
 
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb))
+
 static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     SegmentContext *seg = s->priv_data;
@@ -773,6 +792,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
     int64_t end_pts = INT64_MAX, offset;
     int start_frame = INT_MAX;
     int ret;
+    double ts = TS2T(pkt->pts, st->time_base);
     struct tm ti;
     int64_t usecs;
     int64_t wrapped_val;
@@ -780,7 +800,18 @@ 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))
+    /* update chapter index */
+    if (pkt->stream_index == seg->reference_stream_index &&
+        s->nb_chapters && ts >= seg->next_chapter_start) {
+        seg->chapter_index++;
+        seg->var_values[VAR_CHAPTER_N]  = seg->chapter_index;
+        seg->var_values[VAR_CHAPTER_ID] = s->chapters[seg->chapter_index]->id;
+        seg->next_chapter_start =
+            seg->chapter_index >= s->nb_chapters-1 ? FLT_MAX : // last chapter
+            s->chapters[seg->chapter_index+1]->start *
+            av_q2d(s->chapters[seg->chapter_index+1]->time_base);
+    }
+
     seg->var_values[VAR_SEGMENT_PACKETS_SIZE] += pkt->size;
     seg->var_values[VAR_SEGMENT_PACKETS_N] += 1;
 
@@ -818,11 +849,12 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
         }
     }
 
-    av_dlog(s, "packet stream:%d pts:%s pts_time:%s duration_time:%s is_key:%d frame:%d\n",
+    av_dlog(s, "packet stream:%d pts:%s pts_time:%s duration_time:%s is_key:%d frame:%d chapter:%d\n",
             pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
             av_ts2timestr(pkt->duration, &st->time_base),
             pkt->flags & AV_PKT_FLAG_KEY,
-            pkt->stream_index == seg->reference_stream_index ? seg->frame_count : -1);
+            pkt->stream_index == seg->reference_stream_index ? seg->frame_count : -1,
+            seg->chapter_index);
 
     if (pkt->stream_index == seg->reference_stream_index &&
         pkt->flags & AV_PKT_FLAG_KEY &&
-- 
1.8.3.2



More information about the ffmpeg-devel mailing list