As defined in section 5.12 from ISO/IEC FDIS 23009-1:2019 Initial implementation using capture time. Will be replaced by a following commit.
Signed-off-by: James Almer <jamr...@gmail.com> --- libavformat/dashenc.c | 50 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 7be22b268f..63a3853110 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -116,9 +116,11 @@ typedef struct OutputStream { char full_path[1024]; char temp_path[1024]; double availability_time_offset; + char producer_reference_time[100]; int total_pkt_size; int total_pkt_duration; int muxer_overhead; + int64_t start_time_us; } OutputStream; typedef struct DASHContext { @@ -143,6 +145,7 @@ typedef struct DASHContext { int64_t total_duration; char availability_start_time[100]; time_t start_time_s; + int64_t presentation_time_offset; char dirname[1024]; const char *single_file_name; /* file names as specified in options */ const char *init_seg_name; @@ -167,6 +170,7 @@ typedef struct DASHContext { int nr_of_streams_to_flush; int nr_of_streams_flushed; int frag_type; + int write_prft; } DASHContext; static struct codec_string { @@ -636,7 +640,10 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont avio_printf(out, "availabilityTimeOffset=\"%.3f\" ", os->availability_time_offset); } - avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", os->init_seg_name, os->media_seg_name, c->use_timeline ? start_number : 1); + avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\"", os->init_seg_name, os->media_seg_name, c->use_timeline ? start_number : 1); + if (c->presentation_time_offset) + avio_printf(out, " presentationTimeOffset=\"%"PRId64"\"", c->presentation_time_offset); + avio_printf(out, ">\n"); if (c->use_timeline) { int64_t cur_time = 0; avio_printf(out, "\t\t\t\t\t<SegmentTimeline>\n"); @@ -745,10 +752,9 @@ static void write_time(AVIOContext *out, int64_t time) avio_printf(out, "%d.%dS", seconds, fractions / (AV_TIME_BASE / 10)); } -static void format_date_now(char *buf, int size) +static void format_date(char *buf, int size, int64_t time_us) { struct tm *ptm, tmbuf; - int64_t time_us = av_gettime(); int64_t time_ms = time_us / 1000; const time_t time_s = time_ms / 1000; int millisec = time_ms - (time_s * 1000); @@ -787,6 +793,7 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind if (as->descriptor) avio_printf(out, "\t\t\t%s\n", as->descriptor); for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; OutputStream *os = &c->streams[i]; char bandwidth_str[64] = {'\0'}; @@ -798,7 +805,6 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind os->bit_rate); if (as->media_type == AVMEDIA_TYPE_VIDEO) { - AVStream *st = s->streams[i]; avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"", i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); if (st->avg_frame_rate.num) @@ -810,6 +816,12 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", s->streams[i]->codecpar->channels); } + if (!final && c->write_prft && os->producer_reference_time[0]) { + avio_printf(out, "\t\t\t\t<ProducerReferenceTime id=\"%d\" inband=\"true\" type=\"captured\" wallclockTime=\"%s\" presentationTime=\"%"PRId64"\">\n", + i, os->producer_reference_time, c->presentation_time_offset); + avio_printf(out, "\t\t\t\t\t<UTCTiming schemeIdUri=\"urn:mpeg:dash:utc:http-xsdate:2014\" value=\"%s\"/>\n", c->utc_timing_url); + avio_printf(out, "\t\t\t\t</ProducerReferenceTime>\n"); + } output_segment_list(os, out, s, i, final); avio_printf(out, "\t\t\t</Representation>\n"); } @@ -1038,7 +1050,7 @@ static int write_manifest(AVFormatContext *s, int final) 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(now_str, sizeof(now_str)); + format_date(now_str, sizeof(now_str), av_gettime()); if (now_str[0]) avio_printf(out, "\tpublishTime=\"%s\"\n", now_str); if (c->window_size && c->use_template) { @@ -1230,6 +1242,16 @@ static int dash_init(AVFormatContext *s) c->frag_type = FRAG_TYPE_EVERY_FRAME; } + if (c->write_prft && !c->utc_timing_url) { + av_log(s, AV_LOG_WARNING, "Producer Reference Time element option will be ignored as utc_timing_url is not set\n"); + c->write_prft = 0; + } + + if (c->write_prft && !c->streaming) { + av_log(s, AV_LOG_WARNING, "Producer Reference Time element option will be ignored as streaming is not enabled\n"); + c->write_prft = 0; + } + av_strlcpy(c->dirname, s->url, sizeof(c->dirname)); ptr = strrchr(c->dirname, '/'); if (ptr) { @@ -1793,15 +1815,16 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) pkt->dts = 0; } - if (os->first_pts == AV_NOPTS_VALUE) + if (os->first_pts == AV_NOPTS_VALUE) { os->first_pts = pkt->pts; + os->start_time_us = av_gettime(); + } os->last_pts = pkt->pts; if (!c->availability_start_time[0]) { - int64_t start_time_us = av_gettime(); - c->start_time_s = start_time_us / 1000000; - format_date_now(c->availability_start_time, - sizeof(c->availability_start_time)); + c->start_time_s = os->start_time_us / 1000000; + format_date(c->availability_start_time, + sizeof(c->availability_start_time), os->start_time_us); } if (!os->packets_written) @@ -1858,6 +1881,12 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) } } + if (c->write_prft && !os->producer_reference_time[0]) + format_date(os->producer_reference_time, + sizeof(os->producer_reference_time), + os->start_time_us + (av_rescale_q(os->first_pts, st->time_base, AV_TIME_BASE_Q) - + c->presentation_time_offset)); + if ((ret = dash_flush(s, 0, pkt->stream_index)) < 0) return ret; } @@ -2060,6 +2089,7 @@ static const AVOption options[] = { { "ignore_io_errors", "Ignore IO errors during open and write. Useful for long-duration runs with network output", OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "lhls", "Enable Low-latency HLS(Experimental). Adds #EXT-X-PREFETCH tag with current segment's URI", OFFSET(lhls), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "master_m3u8_publish_rate", "Publish master playlist every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E}, + { "write_prft", "Write producer reference time element", OFFSET(write_prft), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E}, { NULL }, }; -- 2.23.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".