Skip to content

Commit

Permalink
avformat/segment: add option min_seg_duration
Browse files Browse the repository at this point in the history
New option can be used to avoid creating very short segments with inputs
whose GOP size is variable or unharmonic with segment_time.

Only effective with segment_time.
  • Loading branch information
GyanD committed Dec 29, 2022
1 parent aee0f32 commit d39b341
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 1 deletion.
5 changes: 5 additions & 0 deletions doc/muxers.texi
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,11 @@ 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 min_seg_duration @var{time}
Set minimum segment duration to @var{time}, the value must be a duration
specification. This prevents the muxer ending segments at a duration below
this value. Only effective with @code{segment_time}. Default value is "0".

@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
Expand Down
15 changes: 14 additions & 1 deletion libavformat/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ typedef struct SegmentContext {
int list_type; ///< set the list type
AVIOContext *list_pb; ///< list file put-byte context
int64_t time; ///< segment duration
int64_t min_seg_duration; ///< minimum segment duration
int use_strftime; ///< flag to expand filename with strftime
int increment_tc; ///< flag to increment timecode if found

Expand Down Expand Up @@ -696,6 +697,9 @@ static int seg_init(AVFormatContext *s)
return AVERROR(EINVAL);
}

if (seg->times_str || seg->frames_str)
seg->min_seg_duration = 0;

if (seg->times_str) {
if ((ret = parse_times(s, &seg->times, &seg->nb_times, seg->times_str)) < 0)
return ret;
Expand All @@ -710,6 +714,10 @@ static int seg_init(AVFormatContext *s)
}
seg->clocktime_offset = seg->time - (seg->clocktime_offset % seg->time);
}
if (seg->min_seg_duration > seg->time) {
av_log(s, AV_LOG_ERROR, "min_seg_duration cannot be greater than segment_time\n");
return AVERROR(EINVAL);
}
}

if (seg->list) {
Expand Down Expand Up @@ -839,7 +847,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
{
SegmentContext *seg = s->priv_data;
AVStream *st = s->streams[pkt->stream_index];
int64_t end_pts = INT64_MAX, offset;
int64_t end_pts = INT64_MAX, offset, pkt_pts_avtb;
int start_frame = INT_MAX;
int ret;
struct tm ti;
Expand Down Expand Up @@ -890,11 +898,15 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
pkt->flags & AV_PKT_FLAG_KEY,
pkt->stream_index == seg->reference_stream_index ? seg->frame_count : -1);

if (pkt->pts != AV_NOPTS_VALUE)
pkt_pts_avtb = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q);

if (pkt->stream_index == seg->reference_stream_index &&
(pkt->flags & AV_PKT_FLAG_KEY || seg->break_non_keyframes) &&
(seg->segment_frame_count > 0 || seg->write_empty) &&
(seg->cut_pending || seg->frame_count >= start_frame ||
(pkt->pts != AV_NOPTS_VALUE &&
pkt_pts_avtb - seg->cur_entry.start_pts >= seg->min_seg_duration &&
av_compare_ts(pkt->pts, st->time_base,
end_pts - seg->time_delta, AV_TIME_BASE_Q) >= 0))) {
/* sanitize end time in case last packet didn't have a defined duration */
Expand Down Expand Up @@ -1031,6 +1043,7 @@ static const AVOption options[] = {
{ "segment_clocktime_wrap_duration", "set segment clocktime wrapping duration", OFFSET(clocktime_wrap_duration), AV_OPT_TYPE_DURATION, {.i64 = INT64_MAX}, 0, INT64_MAX, E},
{ "segment_time", "set segment duration", OFFSET(time),AV_OPT_TYPE_DURATION, {.i64 = 2000000}, INT64_MIN, INT64_MAX, E },
{ "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, E },
{ "min_seg_duration", "set minimum segment duration", OFFSET(min_seg_duration), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, E },
{ "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E },
{ "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E },
{ "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
Expand Down

0 comments on commit d39b341

Please sign in to comment.