mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
lavf/segment: add reset_timestamps option
The new options reset the timestamps at each new segment, so that the generated segments will have timestamps starting close to 0. It is meant to address trac ticket #1425.
This commit is contained in:
parent
22e4988673
commit
8e9056559e
@ -598,8 +598,15 @@ the specified time and the time set by @var{force_key_frames}.
|
|||||||
@item segment_times @var{times}
|
@item segment_times @var{times}
|
||||||
Specify a list of split points. @var{times} contains a list of comma
|
Specify a list of split points. @var{times} contains a list of comma
|
||||||
separated duration specifications, in increasing order.
|
separated duration specifications, in increasing order.
|
||||||
|
|
||||||
@item segment_wrap @var{limit}
|
@item segment_wrap @var{limit}
|
||||||
Wrap around segment index once it reaches @var{limit}.
|
Wrap around segment index once it reaches @var{limit}.
|
||||||
|
|
||||||
|
@item reset_timestamps @var{1|0}
|
||||||
|
Reset timestamps at the begin of each segment, so that each segment
|
||||||
|
will start with near-zero timestamps. It is meant to ease the playback
|
||||||
|
of the generated segments. May not work with some combinations of
|
||||||
|
muxers/codecs. It is set to @code{0} by default.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
Some examples follow.
|
Some examples follow.
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "libavutil/avstring.h"
|
#include "libavutil/avstring.h"
|
||||||
#include "libavutil/parseutils.h"
|
#include "libavutil/parseutils.h"
|
||||||
#include "libavutil/mathematics.h"
|
#include "libavutil/mathematics.h"
|
||||||
|
#include "libavutil/timestamp.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LIST_TYPE_UNDEFINED = -1,
|
LIST_TYPE_UNDEFINED = -1,
|
||||||
@ -71,8 +72,11 @@ typedef struct {
|
|||||||
int64_t time_delta;
|
int64_t time_delta;
|
||||||
int individual_header_trailer; /**< Set by a private option. */
|
int individual_header_trailer; /**< Set by a private option. */
|
||||||
int write_header_trailer; /**< Set by a private option. */
|
int write_header_trailer; /**< Set by a private option. */
|
||||||
|
|
||||||
|
int reset_timestamps; ///< reset timestamps at the begin of each segment
|
||||||
int has_video;
|
int has_video;
|
||||||
double start_time, end_time;
|
double start_time, end_time;
|
||||||
|
int64_t start_pts, start_dts;
|
||||||
} SegmentContext;
|
} SegmentContext;
|
||||||
|
|
||||||
static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
|
static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
|
||||||
@ -467,6 +471,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
|
|
||||||
/* if the segment has video, start a new segment *only* with a key video frame */
|
/* if the segment has video, start a new segment *only* with a key video frame */
|
||||||
if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO || !seg->has_video) &&
|
if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO || !seg->has_video) &&
|
||||||
|
pkt->pts != AV_NOPTS_VALUE &&
|
||||||
av_compare_ts(pkt->pts, st->time_base,
|
av_compare_ts(pkt->pts, st->time_base,
|
||||||
end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0 &&
|
end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0 &&
|
||||||
pkt->flags & AV_PKT_FLAG_KEY) {
|
pkt->flags & AV_PKT_FLAG_KEY) {
|
||||||
@ -485,11 +490,29 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
oc = seg->avf;
|
oc = seg->avf;
|
||||||
|
|
||||||
seg->start_time = (double)pkt->pts * av_q2d(st->time_base);
|
seg->start_time = (double)pkt->pts * av_q2d(st->time_base);
|
||||||
|
seg->start_pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q);
|
||||||
|
seg->start_dts = pkt->dts != AV_NOPTS_VALUE ?
|
||||||
|
av_rescale_q(pkt->dts, st->time_base, AV_TIME_BASE_Q) : seg->start_pts;
|
||||||
} else if (pkt->pts != AV_NOPTS_VALUE) {
|
} else if (pkt->pts != AV_NOPTS_VALUE) {
|
||||||
seg->end_time = FFMAX(seg->end_time,
|
seg->end_time = FFMAX(seg->end_time,
|
||||||
(double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
|
(double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (seg->reset_timestamps) {
|
||||||
|
av_log(s, AV_LOG_DEBUG, "start_pts:%s pts:%s start_dts:%s dts:%s",
|
||||||
|
av_ts2timestr(seg->start_pts, &AV_TIME_BASE_Q), av_ts2timestr(pkt->pts, &st->time_base),
|
||||||
|
av_ts2timestr(seg->start_dts, &AV_TIME_BASE_Q), av_ts2timestr(pkt->dts, &st->time_base));
|
||||||
|
|
||||||
|
/* compute new timestamps */
|
||||||
|
if (pkt->pts != AV_NOPTS_VALUE)
|
||||||
|
pkt->pts -= av_rescale_q(seg->start_pts, AV_TIME_BASE_Q, st->time_base);
|
||||||
|
if (pkt->dts != AV_NOPTS_VALUE)
|
||||||
|
pkt->dts -= av_rescale_q(seg->start_dts, AV_TIME_BASE_Q, st->time_base);
|
||||||
|
|
||||||
|
av_log(s, AV_LOG_DEBUG, " -> pts:%s dts:%s\n",
|
||||||
|
av_ts2timestr(pkt->pts, &st->time_base), av_ts2timestr(pkt->dts, &st->time_base));
|
||||||
|
}
|
||||||
|
|
||||||
ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
|
ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
@ -548,8 +571,10 @@ static const AVOption options[] = {
|
|||||||
{ "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E },
|
{ "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E },
|
||||||
{ "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E },
|
{ "segment_times", "set segment split time points", OFFSET(times_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 },
|
{ "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
|
||||||
|
|
||||||
{ "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
|
{ "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
|
||||||
{ "write_header_trailer", "write a header to the first segment and a trailer to the last one", OFFSET(write_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
|
{ "write_header_trailer", "write a header to the first segment and a trailer to the last one", OFFSET(write_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
|
||||||
|
{ "reset_timestamps", "reset timestamps at the begin of each segment", OFFSET(reset_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
|
||||||
{ NULL },
|
{ NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_MAJOR 54
|
#define LIBAVFORMAT_VERSION_MAJOR 54
|
||||||
#define LIBAVFORMAT_VERSION_MINOR 49
|
#define LIBAVFORMAT_VERSION_MINOR 49
|
||||||
#define LIBAVFORMAT_VERSION_MICRO 100
|
#define LIBAVFORMAT_VERSION_MICRO 101
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||||
LIBAVFORMAT_VERSION_MINOR, \
|
LIBAVFORMAT_VERSION_MINOR, \
|
||||||
|
Loading…
Reference in New Issue
Block a user