Signed-off-by: Deti fliegl <fliegl@baycom.de>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
... | ... |
@@ -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 }, |