aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeti fliegl <fliegl@baycom.de>2014-07-07 21:35:43 +0200
committerMichael Niedermayer <michaelni@gmx.at>2014-07-07 22:56:55 +0200
commit8cda23f341bef315ace929d6bd5273a431f5c562 (patch)
tree84654c5d78e22140cde3111548aaa4d2f4f4fe5b
parent2229a6dfe66fd73126082bdf83c388ee4ea2c879 (diff)
downloadffmpeg-8cda23f341bef315ace929d6bd5273a431f5c562.tar.gz
avformat/segment: Support cutting at clocktime
Signed-off-by: Deti fliegl <fliegl@baycom.de> Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--doc/muxers.texi10
-rw-r--r--libavformat/segment.c37
2 files changed, 45 insertions, 2 deletions
diff --git a/doc/muxers.texi b/doc/muxers.texi
index da7f186dbc..dc2a08bbef 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -879,6 +879,16 @@ Note that splitting may not be accurate, unless you force the
reference stream key-frames at the given time. See the introductory
notice and the examples below.
+@item segment_atclocktime @var{1|0}
+If set to "1" split at regular clock time intervals starting from 00:00
+o'clock. The @var{time} value specified in @option{segment_time} is
+used for setting the length of the splitting interval.
+
+For example with @option{segment_time} set to "900" this makes it possible
+to create files at 12:00 o'clock, 12:15, 12:30, etc.
+
+Default value is "0".
+
@item segment_time_delta @var{delta}
Specify the accuracy time when selecting the start time for a
segment, expressed as a duration specification. Default value is "0".
diff --git a/libavformat/segment.c b/libavformat/segment.c
index fe84f2710d..a09d49d4bf 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -27,6 +27,8 @@
/* #define DEBUG */
#include <float.h>
+#include <time.h>
+#include <sys/time.h>
#include "avformat.h"
#include "internal.h"
@@ -73,6 +75,12 @@ typedef struct {
char *list; ///< filename for the segment list file
int list_flags; ///< flags affecting list generation
int list_size; ///< number of entries for the segment list file
+
+ int use_clocktime; ///< flag to cut segments at regular clock time
+ int64_t last_val; ///< remember last time for wrap around detection
+ int64_t last_cut; ///< remember last cut
+ int cut_pending;
+
char *entry_prefix; ///< prefix to add to list entry filenames
ListType list_type; ///< set the list type
AVIOContext *list_pb; ///< list file put-byte context
@@ -661,6 +669,13 @@ fail:
return ret;
}
+#if !HAVE_LOCALTIME_R
+static void localtime_r(const time_t *t, struct tm *tm)
+{
+ *tm = *localtime(t);
+}
+#endif
+
static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
{
SegmentContext *seg = s->priv_data;
@@ -668,6 +683,10 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
int64_t end_pts = INT64_MAX, offset;
int start_frame = INT_MAX;
int ret;
+ struct tm ti;
+ struct timeval now;
+ int64_t usecs;
+ int64_t wrapped_val;
if (seg->times) {
end_pts = seg->segment_count < seg->nb_times ?
@@ -676,7 +695,19 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
start_frame = seg->segment_count <= seg->nb_frames ?
seg->frames[seg->segment_count] : INT_MAX;
} else {
- end_pts = seg->time * (seg->segment_count+1);
+ if (seg->use_clocktime) {
+ gettimeofday(&now, NULL);
+ localtime_r(&now.tv_sec, &ti);
+ usecs = (int64_t)(ti.tm_hour*3600 + ti.tm_min*60 + ti.tm_sec) * 1000000 + now.tv_usec;
+ wrapped_val = usecs % seg->time;
+ if (seg->last_cut != usecs && wrapped_val < seg->last_val) {
+ seg->cut_pending = 1;
+ seg->last_cut = usecs;
+ }
+ seg->last_val = wrapped_val;
+ } else {
+ end_pts = seg->time * (seg->segment_count+1);
+ }
}
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)
if (pkt->stream_index == seg->reference_stream_index &&
pkt->flags & AV_PKT_FLAG_KEY &&
- (seg->frame_count >= start_frame ||
+ (seg->cut_pending || seg->frame_count >= start_frame ||
(pkt->pts != AV_NOPTS_VALUE &&
av_compare_ts(pkt->pts, st->time_base,
end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0))) {
@@ -696,6 +727,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
if ((ret = segment_start(s, seg->individual_header_trailer)) < 0)
goto fail;
+ seg->cut_pending = 0;
seg->cur_entry.index = seg->segment_idx + seg->segment_idx_wrap*seg->segment_idx_wrap_nb;
seg->cur_entry.start_time = (double)pkt->pts * av_q2d(st->time_base);
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[] = {
{ "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_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 },
{ "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E },