From 0be48dd9bb6e89c1632fdc95185b24d0bec32843 Mon Sep 17 00:00:00 2001 From: Bryan Huh Date: Wed, 18 Nov 2015 01:13:14 -0800 Subject: [PATCH] avformat/dashenc: Add framerate to dash manifest DASH manifest should have framerate specified as an attribute in the AdaptationSet element and Representation elements. Though ISO/IEC 23009-1:2014 doesn't seem to define frameRate as a required attribute, it is at least optional, and DASH-IF IOP 3.0 seems to require it. See section 3.2.4 of http://dashif.org/w/2015/04/DASH-IF-IOP-v3.0.pdf In the event that avg_frame_rate is not set in the muxer, we ignore the frameRate tag altogther. Signed-off-by: Michael Niedermayer --- libavformat/dashenc.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 7a932147e5..9c2b4dd5af 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -24,10 +24,12 @@ #include #endif +#include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" +#include "libavutil/rational.h" #include "libavutil/time_internal.h" #include "avc.h" @@ -94,6 +96,8 @@ typedef struct DASHContext { const char *single_file_name; const char *init_seg_name; const char *media_seg_name; + AVRational min_frame_rate, max_frame_rate; + int ambiguous_frame_rate; } DASHContext; static int dash_write(void *opaque, uint8_t *buf, int buf_size) @@ -503,7 +507,11 @@ static int write_manifest(AVFormatContext *s, int final) } if (c->has_video) { - avio_printf(out, "\t\t\n"); + avio_printf(out, "\t\tmax_frame_rate.num && !c->ambiguous_frame_rate) + avio_printf(out, " %s=\"%d/%d\"", (av_cmp_q(c->min_frame_rate, c->max_frame_rate) < 0) ? "maxFrameRate" : "frameRate", c->max_frame_rate.num, c->max_frame_rate.den); + avio_printf(out, ">\n"); + for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; OutputStream *os = &c->streams[i]; @@ -511,7 +519,11 @@ static int write_manifest(AVFormatContext *s, int final) if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) continue; - avio_printf(out, "\t\t\t\n", i, os->codec_str, os->bandwidth_str, st->codec->width, st->codec->height); + avio_printf(out, "\t\t\tcodec_str, os->bandwidth_str, st->codec->width, st->codec->height); + if (st->avg_frame_rate.num) + avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den); + avio_printf(out, ">\n"); + output_segment_list(&c->streams[i], out, c); avio_printf(out, "\t\t\t\n"); } @@ -552,6 +564,7 @@ static int dash_write_header(AVFormatContext *s) c->single_file = 1; if (c->single_file) c->use_template = 0; + c->ambiguous_frame_rate = 0; av_strlcpy(c->dirname, s->filename, sizeof(c->dirname)); ptr = strrchr(c->dirname, '/'); @@ -655,10 +668,20 @@ static int dash_write_header(AVFormatContext *s) // already before being handed to this muxer, so we don't have mismatches // between the MPD and the actual segments. s->avoid_negative_ts = ctx->avoid_negative_ts; - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + AVRational avg_frame_rate = s->streams[i]->avg_frame_rate; + if (avg_frame_rate.num > 0) { + if (av_cmp_q(avg_frame_rate, c->min_frame_rate) < 0) + c->min_frame_rate = avg_frame_rate; + if (av_cmp_q(c->max_frame_rate, avg_frame_rate) < 0) + c->max_frame_rate = avg_frame_rate; + } else { + c->ambiguous_frame_rate = 1; + } c->has_video = 1; - else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) + } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { c->has_audio = 1; + } set_codec_str(s, st->codec, os->codec_str, sizeof(os->codec_str)); os->first_pts = AV_NOPTS_VALUE;