int max_width, max_height;
int nb_streams;
AVRational par;
+ int trick_idx;
} AdaptationSet;
typedef struct OutputStream {
int frag_type;
int64_t gop_size;
AVRational sar;
+ int coding_dependency;
} OutputStream;
typedef struct DASHContext {
avio_printf(out, "availabilityTimeOffset=\"%.3f\" ",
os->availability_time_offset);
}
- if (c->ldash && !final && os->frag_type != FRAG_TYPE_NONE &&
- (os->frag_type != FRAG_TYPE_DURATION || os->frag_duration != os->seg_duration))
+ if (c->streaming && os->availability_time_offset && !final)
avio_printf(out, "availabilityTimeComplete=\"false\" ");
avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\"", os->init_seg_name, os->media_seg_name, c->use_timeline ? start_number : 1);
avio_printf(out, " lang=\"%s\"", lang->value);
avio_printf(out, ">\n");
- if (!final && c->ldash && as->max_frag_duration)
+ if (!final && c->ldash && as->max_frag_duration && !(c->profile & MPD_PROFILE_DVB))
avio_printf(out, "\t\t\t<Resync dT=\"%"PRId64"\" type=\"0\"/>\n", as->max_frag_duration);
+ if (as->trick_idx >= 0)
+ avio_printf(out, "\t\t\t<EssentialProperty id=\"%d\" schemeIdUri=\"http://dashif.org/guidelines/trickmode\" value=\"%d\"/>\n", as->id, as->trick_idx);
role = av_dict_get(as->metadata, "role", NULL, 0);
if (role)
avio_printf(out, "\t\t\t<Role schemeIdUri=\"urn:mpeg:dash:role:2011\" value=\"%s\"/>\n", role->value);
avio_printf(out, " sar=\"%d:%d\"", os->sar.num, os->sar.den);
if (st->avg_frame_rate.num && av_cmp_q(as->min_frame_rate, as->max_frame_rate) < 0)
avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den);
+ if (as->trick_idx >= 0) {
+ AdaptationSet *tas = &c->as[as->trick_idx];
+ if (!as->ambiguous_frame_rate && !tas->ambiguous_frame_rate)
+ avio_printf(out, " maxPlayoutRate=\"%d\"", FFMAX((int)av_q2d(av_div_q(tas->min_frame_rate, as->min_frame_rate)), 1));
+ }
+ if (!os->coding_dependency)
+ avio_printf(out, " codingDependency=\"false\"");
avio_printf(out, ">\n");
} else {
avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
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");
}
- if (!final && c->ldash && os->gop_size && os->frag_type != FRAG_TYPE_NONE &&
+ if (!final && c->ldash && os->gop_size && os->frag_type != FRAG_TYPE_NONE && !(c->profile & MPD_PROFILE_DVB) &&
(os->frag_type != FRAG_TYPE_DURATION || os->frag_duration != os->seg_duration))
avio_printf(out, "\t\t\t\t<Resync dT=\"%"PRId64"\" type=\"1\"/>\n", os->gop_size);
output_segment_list(os, out, s, i, final);
memset(*as, 0, sizeof(**as));
(*as)->media_type = type;
(*as)->frag_type = -1;
+ (*as)->trick_idx = -1;
return 0;
}
// syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
// option id=0,descriptor=descriptor_str,streams=0,1,2 and so on
- // option id=0,seg_duration=2.5,frag_duration=0.5,streams=0,1,2 and so on
+ // option id=0,seg_duration=2.5,frag_duration=0.5,streams=0,1,2
+ // id=1,trick_id=0,seg_duration=10,frag_type=none,streams=3 and so on
// descriptor is useful to the scheme defined by ISO/IEC 23009-1:2014/Amd.2:2015
// descriptor_str should be a self-closing xml tag.
// seg_duration and frag_duration have the same syntax as the global options of
return AVERROR(EINVAL);
}
p += n;
+ if (*p)
+ p++;
+ state = parse_default;
+ } else if ((state != new_set) && av_strstart(p, "trick_id=", &p)) {
+ char trick_id_str[10], *end_str;
+
+ n = strcspn(p, ",");
+ snprintf(trick_id_str, sizeof(trick_id_str), "%.*s", n, p);
+ p += n;
+
+ as->trick_idx = strtol(trick_id_str, &end_str, 10);
+ if (trick_id_str == end_str || as->trick_idx < 0)
+ return AVERROR(EINVAL);
+
if (*p)
p++;
state = parse_default;
return AVERROR(EINVAL);
}
}
+
+ // check references for trick mode AdaptationSet
+ for (i = 0; i < c->nb_as; i++) {
+ as = &c->as[i];
+ if (as->trick_idx < 0)
+ continue;
+ for (n = 0; n < c->nb_as; n++) {
+ if (c->as[n].id == as->trick_idx)
+ break;
+ }
+ if (n >= c->nb_as) {
+ av_log(s, AV_LOG_ERROR, "reference AdaptationSet id \"%d\" not found for trick mode AdaptationSet id \"%d\"\n", as->trick_idx, as->id);
+ return AVERROR(EINVAL);
+ }
+ }
+
return 0;
}
c->write_prft = 0;
}
+ if (c->ldash && !c->write_prft) {
+ av_log(s, AV_LOG_WARNING, "Low Latency mode enabled without Producer Reference Time element option! Resulting manifest may not be complaint\n");
+ }
+
if (c->target_latency && !c->write_prft) {
av_log(s, AV_LOG_WARNING, "Target latency option will be ignored as Producer Reference Time element will not be written\n");
c->target_latency = 0;
av_log(s, AV_LOG_WARNING, "frag_type set to P-Frame reordering, but no parser found for stream %d\n", i);
os->frag_type = c->streaming ? FRAG_TYPE_EVERY_FRAME : FRAG_TYPE_NONE;
}
+ if (os->frag_type != FRAG_TYPE_PFRAMES && as->trick_idx < 0)
+ // Set this now if a parser isn't used
+ os->coding_dependency = 1;
if (os->segment_type == SEGMENT_TYPE_MP4) {
if (c->streaming)
if (!os->availability_time_offset &&
((os->frag_type == FRAG_TYPE_DURATION && os->seg_duration != os->frag_duration) ||
(os->frag_type == FRAG_TYPE_EVERY_FRAME && pkt->duration))) {
+ AdaptationSet *as = &c->as[os->as_idx - 1];
int64_t frame_duration = 0;
switch (os->frag_type) {
seg_end_duration = os->seg_duration;
}
+ if (os->parser &&
+ (os->frag_type == FRAG_TYPE_PFRAMES ||
+ as->trick_idx >= 0)) {
+ // Parse the packets only in scenarios where it's needed
+ uint8_t *data;
+ int size;
+ av_parser_parse2(os->parser, os->parser_avctx,
+ &data, &size, pkt->data, pkt->size,
+ pkt->pts, pkt->dts, pkt->pos);
+
+ os->coding_dependency |= os->parser->pict_type != AV_PICTURE_TYPE_I;
+ }
+
if (pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
av_compare_ts(elapsed_duration, st->time_base,
seg_end_duration, AV_TIME_BASE_Q) >= 0) {
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
os->frag_type == FRAG_TYPE_PFRAMES &&
os->packets_written) {
- uint8_t *data;
- int size;
-
av_assert0(os->parser);
- av_parser_parse2(os->parser, os->parser_avctx,
- &data, &size, pkt->data, pkt->size,
- pkt->pts, pkt->dts, pkt->pos);
-
if ((os->parser->pict_type == AV_PICTURE_TYPE_P &&
st->codecpar->video_delay &&
!(os->last_flags & AV_PKT_FLAG_KEY)) ||
}
}
- if (pkt->flags & AV_PKT_FLAG_KEY && (os->packets_written || os->nb_segments) && !os->gop_size) {
+ if (pkt->flags & AV_PKT_FLAG_KEY && (os->packets_written || os->nb_segments) && !os->gop_size && as->trick_idx < 0) {
os->gop_size = os->last_duration + av_rescale_q(os->total_pkt_duration, st->time_base, AV_TIME_BASE_Q);
c->max_gop_size = FFMAX(c->max_gop_size, os->gop_size);
}