Browse code

avformat/segment: Support cutting at clocktime

Signed-off-by: Deti fliegl <fliegl@baycom.de>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Deti fliegl authored on 2014/07/08 04:35:43
Showing 2 changed files
... ...
@@ -879,6 +879,16 @@ Note that splitting may not be accurate, unless you force the
879 879
 reference stream key-frames at the given time. See the introductory
880 880
 notice and the examples below.
881 881
 
882
+@item segment_atclocktime @var{1|0}
883
+If set to "1" split at regular clock time intervals starting from 00:00
884
+o'clock. The @var{time} value specified in @option{segment_time} is
885
+used for setting the length of the splitting interval.
886
+
887
+For example with @option{segment_time} set to "900" this makes it possible
888
+to create files at 12:00 o'clock, 12:15, 12:30, etc.
889
+
890
+Default value is "0".
891
+
882 892
 @item segment_time_delta @var{delta}
883 893
 Specify the accuracy time when selecting the start time for a
884 894
 segment, expressed as a duration specification. Default value is "0".
... ...
@@ -27,6 +27,8 @@
27 27
 /* #define DEBUG */
28 28
 
29 29
 #include <float.h>
30
+#include <time.h>
31
+#include <sys/time.h>
30 32
 
31 33
 #include "avformat.h"
32 34
 #include "internal.h"
... ...
@@ -73,6 +75,12 @@ typedef struct {
73 73
     char *list;            ///< filename for the segment list file
74 74
     int   list_flags;      ///< flags affecting list generation
75 75
     int   list_size;       ///< number of entries for the segment list file
76
+
77
+    int use_clocktime;    ///< flag to cut segments at regular clock time
78
+    int64_t last_val;      ///< remember last time for wrap around detection
79
+    int64_t last_cut;      ///< remember last cut
80
+    int cut_pending;
81
+
76 82
     char *entry_prefix;    ///< prefix to add to list entry filenames
77 83
     ListType list_type;    ///< set the list type
78 84
     AVIOContext *list_pb;  ///< list file put-byte context
... ...
@@ -661,6 +669,13 @@ fail:
661 661
     return ret;
662 662
 }
663 663
 
664
+#if !HAVE_LOCALTIME_R
665
+static void localtime_r(const time_t *t, struct tm *tm)
666
+{
667
+    *tm = *localtime(t);
668
+}
669
+#endif
670
+
664 671
 static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
665 672
 {
666 673
     SegmentContext *seg = s->priv_data;
... ...
@@ -668,6 +683,10 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
668 668
     int64_t end_pts = INT64_MAX, offset;
669 669
     int start_frame = INT_MAX;
670 670
     int ret;
671
+    struct tm ti;
672
+    struct timeval now;
673
+    int64_t usecs;
674
+    int64_t wrapped_val;
671 675
 
672 676
     if (seg->times) {
673 677
         end_pts = seg->segment_count < seg->nb_times ?
... ...
@@ -676,7 +695,19 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
676 676
         start_frame = seg->segment_count <= seg->nb_frames ?
677 677
             seg->frames[seg->segment_count] : INT_MAX;
678 678
     } else {
679
-        end_pts = seg->time * (seg->segment_count+1);
679
+        if (seg->use_clocktime) {
680
+            gettimeofday(&now, NULL);
681
+            localtime_r(&now.tv_sec, &ti);
682
+            usecs = (int64_t)(ti.tm_hour*3600 + ti.tm_min*60 + ti.tm_sec) * 1000000 + now.tv_usec;
683
+            wrapped_val = usecs % seg->time;
684
+            if (seg->last_cut != usecs && wrapped_val < seg->last_val) {
685
+                seg->cut_pending = 1;
686
+                seg->last_cut = usecs;
687
+            }
688
+            seg->last_val = wrapped_val;
689
+        } else {
690
+            end_pts = seg->time * (seg->segment_count+1);
691
+        }
680 692
     }
681 693
 
682 694
     av_dlog(s, "packet stream:%d pts:%s pts_time:%s is_key:%d frame:%d\n",
... ...
@@ -686,7 +717,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
686 686
 
687 687
     if (pkt->stream_index == seg->reference_stream_index &&
688 688
         pkt->flags & AV_PKT_FLAG_KEY &&
689
-        (seg->frame_count >= start_frame ||
689
+        (seg->cut_pending || seg->frame_count >= start_frame ||
690 690
          (pkt->pts != AV_NOPTS_VALUE &&
691 691
           av_compare_ts(pkt->pts, st->time_base,
692 692
                         end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0))) {
... ...
@@ -696,6 +727,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
696 696
         if ((ret = segment_start(s, seg->individual_header_trailer)) < 0)
697 697
             goto fail;
698 698
 
699
+        seg->cut_pending = 0;
699 700
         seg->cur_entry.index = seg->segment_idx + seg->segment_idx_wrap*seg->segment_idx_wrap_nb;
700 701
         seg->cur_entry.start_time = (double)pkt->pts * av_q2d(st->time_base);
701 702
         seg->cur_entry.start_pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q);
... ...
@@ -795,6 +827,7 @@ static const AVOption options[] = {
795 795
     { "m3u8", "M3U8 format",     0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
796 796
     { "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
797 797
 
798
+    { "segment_atclocktime",      "set segment to be cut at clocktime",  OFFSET(use_clocktime), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E},
798 799
     { "segment_time",      "set segment duration",                       OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
799 800
     { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E },
800 801
     { "segment_times",     "set segment split time points",              OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },