This is an automated email from the git hooks/post-receive script.
Git pushed a commit to branch master
in repository ffmpeg.
The following commit(s) were added to refs/heads/master by this push:
new 468a743af1 avformat/dashenc: add options for live MPD timing
468a743af1 is described below
commit 468a743af1653a08f47081aa0a18dc6dacff543a
Author: Jerome Berclaz <[email protected]>
AuthorDate: Thu May 21 08:40:19 2026 -0700
Commit: michaelni <[email protected]>
CommitDate: Fri May 29 03:25:53 2026 +0000
avformat/dashenc: add options for live MPD timing
---
doc/muxers.texi | 10 ++++++++++
libavformat/dashenc.c | 21 ++++++++++++++++++---
tests/Makefile | 1 +
tests/fate/dashenc.mak | 28 ++++++++++++++++++++++++++++
tests/ref/fate/dash-mpd-timing | 2 ++
5 files changed, 59 insertions(+), 3 deletions(-)
diff --git a/doc/muxers.texi b/doc/muxers.texi
index 26199ad836..b2c02fb906 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1330,11 +1330,21 @@ element. Imply that the @option{single_file} option is
set to
@var{true}. In the template, @code{$ext$} is replaced with the file
name extension specific for the segment format.
+@item availability_start_time_ms @var{milliseconds}
+Set the MPD @code{availabilityStartTime} attribute as Unix epoch time in
+milliseconds. If set to @code{0}, the wall clock is used when the first
+packet is written. This is useful for live outputs that need a stable
+availability start time across restarts.
+
@item streaming @var{bool}
Enable or disable chunk streaming mode of output. In chunk streaming
mode, each frame will be a @code{moof} fragment which forms a
chunk. This is disabled by default.
+@item suggested_presentation_delay @var{duration}
+Set the MPD @code{suggestedPresentationDelay} attribute. If set to
+@code{0}, the last segment duration is used.
+
@item target_latency @var{target_latency}
Set an intended target latency in seconds for serving (fractional
value can be set). Applicable only when the @option{streaming} and
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 1b9c6a601f..a0417dc73e 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -71,6 +71,8 @@ enum {
#define MPD_PROFILE_DASH 1
#define MPD_PROFILE_DVB 2
+#define DASH_MAX_AVAILABILITY_START_TIME_MS (INT64_MAX / 1000)
+#define DASH_MAX_SUGGESTED_PRESENTATION_DELAY ((int64_t)INT_MAX * AV_TIME_BASE
+ AV_TIME_BASE - 1)
typedef struct Segment {
char file[1024];
@@ -200,6 +202,8 @@ typedef struct DASHContext {
AVRational min_playback_rate;
AVRational max_playback_rate;
int64_t update_period;
+ int64_t availability_start_time_ms;
+ int64_t suggested_presentation_delay;
} DASHContext;
static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char
*filename,
@@ -1046,8 +1050,14 @@ static int write_manifest(AVFormatContext *s, int final)
if (c->update_period)
update_period = c->update_period;
avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n",
update_period);
- if (!c->ldash)
- avio_printf(out,
"\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", c->last_duration /
AV_TIME_BASE);
+ if (!c->ldash) {
+ if (c->suggested_presentation_delay) {
+ avio_printf(out, "\tsuggestedPresentationDelay=\"");
+ write_time(out, c->suggested_presentation_delay);
+ avio_printf(out, "\"\n");
+ } else
+ avio_printf(out,
"\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", c->last_duration /
AV_TIME_BASE);
+ }
if (c->availability_start_time[0])
avio_printf(out, "\tavailabilityStartTime=\"%s\"\n",
c->availability_start_time);
format_date(now_str, sizeof(now_str), av_gettime());
@@ -1982,9 +1992,12 @@ static int dash_write_packet(AVFormatContext *s,
AVPacket *pkt)
if (!c->availability_start_time[0]) {
int64_t start_time_us = av_gettime();
+ int64_t mpd_start_time_us = c->availability_start_time_ms ?
+ c->availability_start_time_ms * 1000 :
+ start_time_us;
c->start_time_s = start_time_us / 1000000;
format_date(c->availability_start_time,
- sizeof(c->availability_start_time), start_time_us);
+ sizeof(c->availability_start_time), mpd_start_time_us);
}
if (!os->packets_written)
@@ -2266,7 +2279,9 @@ static const AVOption options[] = {
{ "seg_duration", "segment duration (in seconds, fractional value can be
set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 5000000 }, 0,
INT_MAX, E },
{ "single_file", "Store all segments in one file, accessed using byte
ranges", OFFSET(single_file), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
{ "single_file_name", "DASH-templated name to be used for baseURL. Implies
storing all segments in one file, accessed using byte ranges",
OFFSET(single_file_name), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
+ { "availability_start_time_ms", "set MPD availabilityStartTime as epoch
milliseconds", OFFSET(availability_start_time_ms), AV_OPT_TYPE_INT64, { .i64 =
0 }, 0, DASH_MAX_AVAILABILITY_START_TIME_MS, E },
{ "streaming", "Enable/Disable streaming mode of output. Each frame will
be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
+ { "suggested_presentation_delay", "set MPD suggestedPresentationDelay",
OFFSET(suggested_presentation_delay), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0,
DASH_MAX_SUGGESTED_PRESENTATION_DELAY, E },
{ "target_latency", "Set desired target latency for Low-latency dash",
OFFSET(target_latency), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, E },
{ "timeout", "set timeout for socket I/O operations", OFFSET(timeout),
AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
{ "update_period", "Set the mpd update interval", OFFSET(update_period),
AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E},
diff --git a/tests/Makefile b/tests/Makefile
index 26b29c72d2..585d0bd3c7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -175,6 +175,7 @@ include $(SRC_PATH)/tests/fate/checkasm.mak
# Must be included after lavf-container.mak
include $(SRC_PATH)/tests/fate/concatdec.mak
include $(SRC_PATH)/tests/fate/cover-art.mak
+include $(SRC_PATH)/tests/fate/dashenc.mak
include $(SRC_PATH)/tests/fate/dca.mak
include $(SRC_PATH)/tests/fate/demux.mak
include $(SRC_PATH)/tests/fate/dfa.mak
diff --git a/tests/fate/dashenc.mak b/tests/fate/dashenc.mak
new file mode 100644
index 0000000000..df9571f0b4
--- /dev/null
+++ b/tests/fate/dashenc.mak
@@ -0,0 +1,28 @@
+tests/data/dash_mpd_timing.mpd: TAG = GEN
+tests/data/dash_mpd_timing.mpd: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data
+ $(RM) $(TARGET_PATH)/tests/data/dash_mpd_timing*
+ $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< -nostdin -loglevel error -re \
+ -f lavfi -i "testsrc2=size=128x72:rate=1" -map 0:v \
+ -c:v mpeg4 -g 1 -streaming 1 -window_size 5 \
+ -availability_start_time_ms 1700000000123 -suggested_presentation_delay
2s \
+ -f dash $(TARGET_PATH)/tests/data/dash_mpd_timing.mpd & \
+ pid=$$!; \
+ i=0; \
+ while ! test -s $(TARGET_PATH)/tests/data/dash_mpd_timing.mpd && test
$$i -lt 100; do \
+ sleep 0.1; \
+ i=$$((i + 1)); \
+ done; \
+ test -s $(TARGET_PATH)/tests/data/dash_mpd_timing.mpd; \
+ cp $(TARGET_PATH)/tests/data/dash_mpd_timing.mpd
$(TARGET_PATH)/tests/data/dash_mpd_timing.live.mpd; \
+ kill $$pid 2>/dev/null || true; \
+ wait $$pid 2>/dev/null || true; \
+ cp $(TARGET_PATH)/tests/data/dash_mpd_timing.live.mpd
$(TARGET_PATH)/tests/data/dash_mpd_timing.mpd; \
+ test -s $(TARGET_PATH)/tests/data/dash_mpd_timing.mpd
+
+FATE_DASHENC_LAVFI-$(call ALLYES, TESTSRC2_FILTER LAVFI_INDEV MPEG4_ENCODER
DASH_MUXER MP4_MUXER FILE_PROTOCOL) += fate-dash-mpd-timing
+fate-dash-mpd-timing: tests/data/dash_mpd_timing.mpd
+fate-dash-mpd-timing: CMD = sed -n -e /suggestedPresentationDelay=/p -e
/availabilityStartTime=/p $(TARGET_PATH)/tests/data/dash_mpd_timing.mpd
+fate-dash-mpd-timing: CMP = diff
+
+FATE_FFMPEG += $(FATE_DASHENC_LAVFI-yes)
+fate-dashenc: $(FATE_DASHENC_LAVFI-yes)
diff --git a/tests/ref/fate/dash-mpd-timing b/tests/ref/fate/dash-mpd-timing
new file mode 100644
index 0000000000..b725ba9182
--- /dev/null
+++ b/tests/ref/fate/dash-mpd-timing
@@ -0,0 +1,2 @@
+ suggestedPresentationDelay="PT2.0S"
+ availabilityStartTime="2023-11-14T22:13:20.123Z"
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]