Hooked MPD flags up to MpdOptions.
Added calculation of availabilityStartTime MPD attribute. Change-Id: I00876005c71f28ea83fb5d9ba0ad1f19f1d08e69
This commit is contained in:
parent
6651ae1c3d
commit
79d3c4f4ec
|
@ -29,3 +29,25 @@ DEFINE_string(base_urls,
|
||||||
"",
|
"",
|
||||||
"Comma separated BaseURLs for the MPD. The values will be added "
|
"Comma separated BaseURLs for the MPD. The values will be added "
|
||||||
"as <BaseURL> element(s) immediately under the <MPD> element.");
|
"as <BaseURL> element(s) immediately under the <MPD> element.");
|
||||||
|
DEFINE_double(min_buffer_time,
|
||||||
|
2.0,
|
||||||
|
"Specifies, in seconds, a common duration used in the definition "
|
||||||
|
"of the MPD Representation data rate.");
|
||||||
|
DEFINE_double(availability_time_offset,
|
||||||
|
10.0,
|
||||||
|
"Offset with respect to the wall clock time for MPD "
|
||||||
|
"availabilityStartTime and availabilityEndTime values, in "
|
||||||
|
" seconds. This value is used for live profile only.");
|
||||||
|
DEFINE_double(minimum_update_period,
|
||||||
|
5.0,
|
||||||
|
"Indicates to the player how often to refresh the media "
|
||||||
|
"presentation description in seconds. This value is used for "
|
||||||
|
"live profile only.");
|
||||||
|
DEFINE_double(time_shift_buffer_depth,
|
||||||
|
1800.0,
|
||||||
|
"Guaranteed duration of the time shifting buffer for dynamic "
|
||||||
|
"media presentations, in seconds.");
|
||||||
|
DEFINE_double(suggested_presentation_delay,
|
||||||
|
0.0,
|
||||||
|
"Specifies a delay, in seconds, to be added to the media "
|
||||||
|
"presentation time. This value is used for live profile only.");
|
||||||
|
|
|
@ -15,5 +15,10 @@ DECLARE_bool(output_media_info);
|
||||||
DECLARE_string(mpd_output);
|
DECLARE_string(mpd_output);
|
||||||
DECLARE_string(scheme_id_uri);
|
DECLARE_string(scheme_id_uri);
|
||||||
DECLARE_string(base_urls);
|
DECLARE_string(base_urls);
|
||||||
|
DECLARE_double(availability_time_offset);
|
||||||
|
DECLARE_double(minimum_update_period);
|
||||||
|
DECLARE_double(min_buffer_time);
|
||||||
|
DECLARE_double(time_shift_buffer_depth);
|
||||||
|
DECLARE_double(suggested_presentation_delay);
|
||||||
|
|
||||||
#endif // APP_MPD_FLAGS_H_
|
#endif // APP_MPD_FLAGS_H_
|
||||||
|
|
|
@ -234,6 +234,10 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
||||||
if (!GetMuxerOptions(&muxer_options))
|
if (!GetMuxerOptions(&muxer_options))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
MpdOptions mpd_options;
|
||||||
|
if (!GetMpdOptions(&mpd_options))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Create encryption key source if needed.
|
// Create encryption key source if needed.
|
||||||
scoped_ptr<EncryptionKeySource> encryption_key_source;
|
scoped_ptr<EncryptionKeySource> encryption_key_source;
|
||||||
if (FLAGS_enable_widevine_encryption || FLAGS_enable_fixed_key_encryption) {
|
if (FLAGS_enable_widevine_encryption || FLAGS_enable_fixed_key_encryption) {
|
||||||
|
@ -248,8 +252,7 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
||||||
FLAGS_single_segment ? kOnDemandProfile : kLiveProfile;
|
FLAGS_single_segment ? kOnDemandProfile : kLiveProfile;
|
||||||
std::vector<std::string> base_urls;
|
std::vector<std::string> base_urls;
|
||||||
base::SplitString(FLAGS_base_urls, ',', &base_urls);
|
base::SplitString(FLAGS_base_urls, ',', &base_urls);
|
||||||
// TODO(rkuroiwa,kqyang): Get mpd options from command line.
|
mpd_notifier.reset(new SimpleMpdNotifier(profile, mpd_options, base_urls,
|
||||||
mpd_notifier.reset(new SimpleMpdNotifier(profile, MpdOptions(), base_urls,
|
|
||||||
FLAGS_mpd_output));
|
FLAGS_mpd_output));
|
||||||
if (!mpd_notifier->Init()) {
|
if (!mpd_notifier->Init()) {
|
||||||
LOG(ERROR) << "MpdNotifier failed to initialize.";
|
LOG(ERROR) << "MpdNotifier failed to initialize.";
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "app/fixed_key_encryption_flags.h"
|
#include "app/fixed_key_encryption_flags.h"
|
||||||
|
#include "app/mpd_flags.h"
|
||||||
#include "app/muxer_flags.h"
|
#include "app/muxer_flags.h"
|
||||||
#include "app/widevine_encryption_flags.h"
|
#include "app/widevine_encryption_flags.h"
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
|
@ -19,9 +20,12 @@
|
||||||
#include "media/base/stream_info.h"
|
#include "media/base/stream_info.h"
|
||||||
#include "media/base/widevine_encryption_key_source.h"
|
#include "media/base/widevine_encryption_key_source.h"
|
||||||
#include "media/file/file.h"
|
#include "media/file/file.h"
|
||||||
|
#include "mpd/base/mpd_builder.h"
|
||||||
|
|
||||||
DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
|
DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
|
||||||
|
|
||||||
|
using dash_packager::MpdOptions;
|
||||||
|
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
void DumpStreamInfo(const std::vector<MediaStream*>& streams) {
|
void DumpStreamInfo(const std::vector<MediaStream*>& streams) {
|
||||||
|
@ -128,6 +132,18 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetMpdOptions(MpdOptions* mpd_options) {
|
||||||
|
DCHECK(mpd_options);
|
||||||
|
|
||||||
|
mpd_options->availability_time_offset = FLAGS_availability_time_offset;
|
||||||
|
mpd_options->minimum_update_period = FLAGS_minimum_update_period;
|
||||||
|
mpd_options->min_buffer_time = FLAGS_min_buffer_time;
|
||||||
|
mpd_options->time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
|
||||||
|
mpd_options->suggested_presentation_delay =
|
||||||
|
FLAGS_suggested_presentation_delay;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
MediaStream* FindFirstStreamOfType(const std::vector<MediaStream*>& streams,
|
MediaStream* FindFirstStreamOfType(const std::vector<MediaStream*>& streams,
|
||||||
StreamType stream_type) {
|
StreamType stream_type) {
|
||||||
typedef std::vector<MediaStream*>::const_iterator StreamIterator;
|
typedef std::vector<MediaStream*>::const_iterator StreamIterator;
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
|
|
||||||
DECLARE_bool(dump_stream_info);
|
DECLARE_bool(dump_stream_info);
|
||||||
|
|
||||||
|
namespace dash_packager {
|
||||||
|
struct MpdOptions;
|
||||||
|
}
|
||||||
|
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
class EncryptionKeySource;
|
class EncryptionKeySource;
|
||||||
|
@ -39,6 +43,9 @@ bool AssignFlagsFromProfile();
|
||||||
/// Fill MuxerOptions members using provided command line options.
|
/// Fill MuxerOptions members using provided command line options.
|
||||||
bool GetMuxerOptions(MuxerOptions* muxer_options);
|
bool GetMuxerOptions(MuxerOptions* muxer_options);
|
||||||
|
|
||||||
|
/// Fill MpdOptions members using provided command line options.
|
||||||
|
bool GetMpdOptions(dash_packager::MpdOptions* mpd_options);
|
||||||
|
|
||||||
/// Select and add a stream from a provided set to a muxer.
|
/// Select and add a stream from a provided set to a muxer.
|
||||||
/// @param streams contains the set of MediaStreams from which to select.
|
/// @param streams contains the set of MediaStreams from which to select.
|
||||||
/// @param stream_selector is a string containing one of the following values:
|
/// @param stream_selector is a string containing one of the following values:
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#ifndef MEDIA_BASE_MUXER_OPTIONS_H_
|
#ifndef MEDIA_BASE_MUXER_OPTIONS_H_
|
||||||
#define MEDIA_BASE_MUXER_OPTIONS_H_
|
#define MEDIA_BASE_MUXER_OPTIONS_H_
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
|
@ -65,7 +67,8 @@ struct MuxerOptions {
|
||||||
/// Specify temporary directory for intermediate files.
|
/// Specify temporary directory for intermediate files.
|
||||||
std::string temp_dir;
|
std::string temp_dir;
|
||||||
|
|
||||||
/// User-specified bandwidth for the stream. zero means "unspecified".
|
/// User-specified bit rate for the media stream. If zero, the muxer will
|
||||||
|
/// attempt to estimate.
|
||||||
uint32 bandwidth;
|
uint32 bandwidth;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "mpd/base/mpd_builder.h"
|
#include "mpd/base/mpd_builder.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -90,18 +91,19 @@ bool Positive(double d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return current time in XML DateTime format.
|
// Return current time in XML DateTime format.
|
||||||
std::string XmlDateTimeNow() {
|
std::string XmlDateTimeNowWithOffset(int32 offset_seconds) {
|
||||||
base::Time now = base::Time::Now();
|
base::Time time = base::Time::Now();
|
||||||
base::Time::Exploded now_exploded;
|
time += base::TimeDelta::FromSeconds(offset_seconds);
|
||||||
now.UTCExplode(&now_exploded);
|
base::Time::Exploded time_exploded;
|
||||||
|
time.UTCExplode(&time_exploded);
|
||||||
|
|
||||||
return base::StringPrintf("%4d-%02d-%02dT%02d:%02d:%02d",
|
return base::StringPrintf("%4d-%02d-%02dT%02d:%02d:%02d",
|
||||||
now_exploded.year,
|
time_exploded.year,
|
||||||
now_exploded.month,
|
time_exploded.month,
|
||||||
now_exploded.day_of_month,
|
time_exploded.day_of_month,
|
||||||
now_exploded.hour,
|
time_exploded.hour,
|
||||||
now_exploded.minute,
|
time_exploded.minute,
|
||||||
now_exploded.second);
|
time_exploded.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetIfPositive(const char* attr_name, double value, XmlNode* mpd) {
|
void SetIfPositive(const char* attr_name, double value, XmlNode* mpd) {
|
||||||
|
@ -157,13 +159,12 @@ int SearchTimedOutRepeatIndex(uint64 timeshift_limit,
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
MpdOptions::MpdOptions()
|
MpdOptions::MpdOptions()
|
||||||
: minimum_update_period(),
|
: availability_time_offset(0),
|
||||||
min_buffer_time(),
|
minimum_update_period(0),
|
||||||
time_shift_buffer_depth(),
|
// TODO(tinskip): Set min_buffer_time in unit tests rather than here.
|
||||||
suggested_presentation_delay(),
|
min_buffer_time(2.0),
|
||||||
max_segment_duration(),
|
time_shift_buffer_depth(0),
|
||||||
max_subsegment_duration(),
|
suggested_presentation_delay(0) {}
|
||||||
number_of_blocks_for_bandwidth_estimation() {}
|
|
||||||
|
|
||||||
MpdOptions::~MpdOptions() {}
|
MpdOptions::~MpdOptions() {}
|
||||||
|
|
||||||
|
@ -222,9 +223,6 @@ xmlDocPtr MpdBuilder::GenerateMpd() {
|
||||||
static const char kXmlVersion[] = "1.0";
|
static const char kXmlVersion[] = "1.0";
|
||||||
xml::ScopedXmlPtr<xmlDoc>::type doc(xmlNewDoc(BAD_CAST kXmlVersion));
|
xml::ScopedXmlPtr<xmlDoc>::type doc(xmlNewDoc(BAD_CAST kXmlVersion));
|
||||||
XmlNode mpd("MPD");
|
XmlNode mpd("MPD");
|
||||||
AddMpdNameSpaceInfo(&mpd);
|
|
||||||
|
|
||||||
SetMpdOptionsValues(&mpd);
|
|
||||||
|
|
||||||
// Iterate thru AdaptationSets and add them to one big Period element.
|
// Iterate thru AdaptationSets and add them to one big Period element.
|
||||||
XmlNode period("Period");
|
XmlNode period("Period");
|
||||||
|
@ -254,6 +252,8 @@ xmlDocPtr MpdBuilder::GenerateMpd() {
|
||||||
if (!mpd.AddChild(period.PassScopedPtr()))
|
if (!mpd.AddChild(period.PassScopedPtr()))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
AddMpdNameSpaceInfo(&mpd);
|
||||||
|
AddCommonMpdInfo(&mpd);
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case kStatic:
|
case kStatic:
|
||||||
AddStaticMpdInfo(&mpd);
|
AddStaticMpdInfo(&mpd);
|
||||||
|
@ -271,6 +271,17 @@ xmlDocPtr MpdBuilder::GenerateMpd() {
|
||||||
return doc.release();
|
return doc.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MpdBuilder::AddCommonMpdInfo(XmlNode* mpd_node) {
|
||||||
|
if (Positive(mpd_options_.min_buffer_time)) {
|
||||||
|
mpd_node->SetStringAttribute(
|
||||||
|
"minBufferTime",
|
||||||
|
SecondsToXmlDuration(mpd_options_.min_buffer_time));
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "minBufferTime value not specified.";
|
||||||
|
// TODO(tinskip): Propagate error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MpdBuilder::AddStaticMpdInfo(XmlNode* mpd_node) {
|
void MpdBuilder::AddStaticMpdInfo(XmlNode* mpd_node) {
|
||||||
DCHECK(mpd_node);
|
DCHECK(mpd_node);
|
||||||
DCHECK_EQ(MpdBuilder::kStatic, type_);
|
DCHECK_EQ(MpdBuilder::kStatic, type_);
|
||||||
|
@ -294,6 +305,38 @@ void MpdBuilder::AddDynamicMpdInfo(XmlNode* mpd_node) {
|
||||||
"urn:mpeg:dash:profile:isoff-live:2011";
|
"urn:mpeg:dash:profile:isoff-live:2011";
|
||||||
mpd_node->SetStringAttribute("type", kDynamicMpdType);
|
mpd_node->SetStringAttribute("type", kDynamicMpdType);
|
||||||
mpd_node->SetStringAttribute("profiles", kDynamicMpdProfile);
|
mpd_node->SetStringAttribute("profiles", kDynamicMpdProfile);
|
||||||
|
|
||||||
|
// 'availabilityStartTime' is required for dynamic profile. Calculate if
|
||||||
|
// not already calculated.
|
||||||
|
if (availability_start_time_.empty()) {
|
||||||
|
double earliest_presentation_time;
|
||||||
|
if (GetEarliestTimestamp(&earliest_presentation_time)) {
|
||||||
|
availability_start_time_ =
|
||||||
|
XmlDateTimeNowWithOffset(mpd_options_.availability_time_offset
|
||||||
|
- std::ceil(earliest_presentation_time));
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "Could not determine the earliest segment presentation "
|
||||||
|
"time for availabilityStartTime calculation.";
|
||||||
|
// TODO(tinskip). Propagate an error.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!availability_start_time_.empty())
|
||||||
|
mpd_node->SetStringAttribute("availabilityStartTime", availability_start_time_);
|
||||||
|
|
||||||
|
if (Positive(mpd_options_.minimum_update_period)) {
|
||||||
|
mpd_node->SetStringAttribute(
|
||||||
|
"minimumUpdatePeriod",
|
||||||
|
SecondsToXmlDuration(mpd_options_.minimum_update_period));
|
||||||
|
} else {
|
||||||
|
LOG(WARNING) << "The profile is dynamic but no minimumUpdatePeriod "
|
||||||
|
"specified.";
|
||||||
|
}
|
||||||
|
|
||||||
|
SetIfPositive(
|
||||||
|
"timeShiftBufferDepth", mpd_options_.time_shift_buffer_depth, mpd_node);
|
||||||
|
SetIfPositive("suggestedPresentationDelay",
|
||||||
|
mpd_options_.suggested_presentation_delay,
|
||||||
|
mpd_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
float MpdBuilder::GetStaticMpdDuration(XmlNode* mpd_node) {
|
float MpdBuilder::GetStaticMpdDuration(XmlNode* mpd_node) {
|
||||||
|
@ -328,62 +371,25 @@ float MpdBuilder::GetStaticMpdDuration(XmlNode* mpd_node) {
|
||||||
return max_duration;
|
return max_duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpdBuilder::SetMpdOptionsValues(XmlNode* mpd) {
|
bool MpdBuilder::GetEarliestTimestamp(double* timestamp_seconds) {
|
||||||
if (type_ == kStatic) {
|
DCHECK(timestamp_seconds);
|
||||||
if (!mpd_options_.availability_start_time.empty()) {
|
|
||||||
mpd->SetStringAttribute("availabilityStartTime",
|
double earliest_timestamp(-1);
|
||||||
mpd_options_.availability_start_time);
|
for (std::list<AdaptationSet*>::const_iterator iter =
|
||||||
|
adaptation_sets_.begin();
|
||||||
|
iter != adaptation_sets_.end();
|
||||||
|
++iter) {
|
||||||
|
double timestamp;
|
||||||
|
if ((*iter)->GetEarliestTimestamp(×tamp) &&
|
||||||
|
((earliest_timestamp < 0) || (timestamp < earliest_timestamp))) {
|
||||||
|
earliest_timestamp = timestamp;
|
||||||
}
|
}
|
||||||
LOG_IF(WARNING, Positive(mpd_options_.minimum_update_period))
|
|
||||||
<< "minimumUpdatePeriod should not be present in 'static' profile. "
|
|
||||||
"Ignoring.";
|
|
||||||
LOG_IF(WARNING, Positive(mpd_options_.time_shift_buffer_depth))
|
|
||||||
<< "timeShiftBufferDepth will not be used for 'static' profile. "
|
|
||||||
"Ignoring.";
|
|
||||||
LOG_IF(WARNING, Positive(mpd_options_.suggested_presentation_delay))
|
|
||||||
<< "suggestedPresentationDelay will not be used for 'static' profile. "
|
|
||||||
"Ignoring.";
|
|
||||||
} else if (type_ == kDynamic) {
|
|
||||||
// 'availabilityStartTime' is required for dynamic profile, so use current
|
|
||||||
// time if not specified.
|
|
||||||
const std::string avail_start =
|
|
||||||
!mpd_options_.availability_start_time.empty()
|
|
||||||
? mpd_options_.availability_start_time
|
|
||||||
: XmlDateTimeNow();
|
|
||||||
mpd->SetStringAttribute("availabilityStartTime", avail_start);
|
|
||||||
|
|
||||||
if (Positive(mpd_options_.minimum_update_period)) {
|
|
||||||
mpd->SetStringAttribute(
|
|
||||||
"minimumUpdatePeriod",
|
|
||||||
SecondsToXmlDuration(mpd_options_.minimum_update_period));
|
|
||||||
} else {
|
|
||||||
// TODO(rkuroiwa): Set minimumUpdatePeriod to some default value.
|
|
||||||
LOG(WARNING) << "The profile is dynamic but no minimumUpdatePeriod "
|
|
||||||
"specified. Setting minimumUpdatePeriod to 0.";
|
|
||||||
}
|
|
||||||
|
|
||||||
SetIfPositive(
|
|
||||||
"timeShiftBufferDepth", mpd_options_.time_shift_buffer_depth, mpd);
|
|
||||||
SetIfPositive("suggestedPresentationDelay",
|
|
||||||
mpd_options_.suggested_presentation_delay,
|
|
||||||
mpd);
|
|
||||||
}
|
}
|
||||||
|
if (earliest_timestamp < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
const double kDefaultMinBufferTime = 2.0;
|
*timestamp_seconds = earliest_timestamp;
|
||||||
const double min_buffer_time = Positive(mpd_options_.min_buffer_time)
|
return true;
|
||||||
? mpd_options_.min_buffer_time
|
|
||||||
: kDefaultMinBufferTime;
|
|
||||||
mpd->SetStringAttribute("minBufferTime",
|
|
||||||
SecondsToXmlDuration(min_buffer_time));
|
|
||||||
|
|
||||||
if (!mpd_options_.availability_end_time.empty()) {
|
|
||||||
mpd->SetStringAttribute("availabilityEndTime",
|
|
||||||
mpd_options_.availability_end_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetIfPositive("maxSegmentDuration", mpd_options_.max_segment_duration, mpd);
|
|
||||||
SetIfPositive(
|
|
||||||
"maxSubsegmentDuration", mpd_options_.max_subsegment_duration, mpd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AdaptationSet::AdaptationSet(uint32 adaptation_set_id,
|
AdaptationSet::AdaptationSet(uint32 adaptation_set_id,
|
||||||
|
@ -441,6 +447,29 @@ xml::ScopedXmlPtr<xmlNode>::type AdaptationSet::GetXml() {
|
||||||
return adaptation_set.PassScopedPtr();
|
return adaptation_set.PassScopedPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AdaptationSet::GetEarliestTimestamp(double* timestamp_seconds) {
|
||||||
|
DCHECK(timestamp_seconds);
|
||||||
|
|
||||||
|
base::AutoLock scoped_lock(lock_);
|
||||||
|
double earliest_timestamp(-1);
|
||||||
|
for (std::list<Representation*>::const_iterator iter =
|
||||||
|
representations_.begin();
|
||||||
|
iter != representations_.end();
|
||||||
|
++iter) {
|
||||||
|
double timestamp;
|
||||||
|
if ((*iter)->GetEarliestTimestamp(×tamp) &&
|
||||||
|
((earliest_timestamp < 0) || (timestamp < earliest_timestamp))) {
|
||||||
|
earliest_timestamp = timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (earliest_timestamp < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*timestamp_seconds = earliest_timestamp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Representation::Representation(const MediaInfo& media_info,
|
Representation::Representation(const MediaInfo& media_info,
|
||||||
const MpdOptions& mpd_options,
|
const MpdOptions& mpd_options,
|
||||||
uint32 id)
|
uint32 id)
|
||||||
|
@ -715,4 +744,17 @@ std::string Representation::GetAudioMimeType() const {
|
||||||
return GetMimeType("audio", media_info_.container_type());
|
return GetMimeType("audio", media_info_.container_type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Representation::GetEarliestTimestamp(double* timestamp_seconds) {
|
||||||
|
DCHECK(timestamp_seconds);
|
||||||
|
|
||||||
|
base::AutoLock scoped_lock(lock_);
|
||||||
|
if (segment_infos_.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*timestamp_seconds =
|
||||||
|
static_cast<double>(segment_infos_.begin()->start_time) /
|
||||||
|
GetTimeScale(media_info_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dash_packager
|
} // namespace dash_packager
|
||||||
|
|
|
@ -41,18 +41,11 @@ struct MpdOptions {
|
||||||
MpdOptions();
|
MpdOptions();
|
||||||
~MpdOptions();
|
~MpdOptions();
|
||||||
|
|
||||||
std::string availability_start_time;
|
double availability_time_offset;
|
||||||
std::string availability_end_time;
|
|
||||||
double minimum_update_period;
|
double minimum_update_period;
|
||||||
double min_buffer_time;
|
double min_buffer_time;
|
||||||
double time_shift_buffer_depth;
|
double time_shift_buffer_depth;
|
||||||
double suggested_presentation_delay;
|
double suggested_presentation_delay;
|
||||||
double max_segment_duration;
|
|
||||||
double max_subsegment_duration;
|
|
||||||
|
|
||||||
/// Value passed to BandwidthEstimator's contructor. See BandwidthEstimator
|
|
||||||
/// for more.
|
|
||||||
int number_of_blocks_for_bandwidth_estimation;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This class generates DASH MPDs (Media Presentation Descriptions).
|
/// This class generates DASH MPDs (Media Presentation Descriptions).
|
||||||
|
@ -86,8 +79,8 @@ class MpdBuilder {
|
||||||
MpdType type() { return type_; }
|
MpdType type() { return type_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// DynamicMpdBuilderTest uses SetMpdOptionsValues to set availabilityStartTime
|
// DynamicMpdBuilderTest needs to set availabilityStartTime so that the test
|
||||||
// so that the test doesn't need to depend on current time.
|
// doesn't need to depend on current time.
|
||||||
friend class DynamicMpdBuilderTest;
|
friend class DynamicMpdBuilderTest;
|
||||||
|
|
||||||
bool ToStringImpl(std::string* output);
|
bool ToStringImpl(std::string* output);
|
||||||
|
@ -97,6 +90,10 @@ class MpdBuilder {
|
||||||
// On failure, this returns NULL.
|
// On failure, this returns NULL.
|
||||||
xmlDocPtr GenerateMpd();
|
xmlDocPtr GenerateMpd();
|
||||||
|
|
||||||
|
// Set MPD attributes common to all profiles. Uses non-zero |mpd_options_| to
|
||||||
|
// set attributes for the MPD.
|
||||||
|
void AddCommonMpdInfo(xml::XmlNode* mpd_node);
|
||||||
|
|
||||||
// Adds 'static' MPD attributes and elements to |mpd_node|. This assumes that
|
// Adds 'static' MPD attributes and elements to |mpd_node|. This assumes that
|
||||||
// the first child element is a Period element.
|
// the first child element is a Period element.
|
||||||
void AddStaticMpdInfo(xml::XmlNode* mpd_node);
|
void AddStaticMpdInfo(xml::XmlNode* mpd_node);
|
||||||
|
@ -106,10 +103,13 @@ class MpdBuilder {
|
||||||
|
|
||||||
float GetStaticMpdDuration(xml::XmlNode* mpd_node);
|
float GetStaticMpdDuration(xml::XmlNode* mpd_node);
|
||||||
|
|
||||||
// Use |mpd_options_| to set attributes for MPD. Only values that are set will be
|
// Set MPD attributes for dynamic profile MPD. Uses non-zero |mpd_options_| as
|
||||||
// used, i.e. if a string field is not empty and numeric field is not 0.
|
// well as various calculations to set attributes for the MPD.
|
||||||
// Required fields will be set with some reasonable values.
|
void SetDynamicMpdAttributes(xml::XmlNode* mpd_node);
|
||||||
void SetMpdOptionsValues(xml::XmlNode* mpd_node);
|
|
||||||
|
// Gets the earliest, normalized segment timestamp. Returns true if
|
||||||
|
// successful, false otherwise.
|
||||||
|
bool GetEarliestTimestamp(double* timestamp_seconds);
|
||||||
|
|
||||||
MpdType type_;
|
MpdType type_;
|
||||||
MpdOptions mpd_options_;
|
MpdOptions mpd_options_;
|
||||||
|
@ -117,6 +117,7 @@ class MpdBuilder {
|
||||||
::STLElementDeleter<std::list<AdaptationSet*> > adaptation_sets_deleter_;
|
::STLElementDeleter<std::list<AdaptationSet*> > adaptation_sets_deleter_;
|
||||||
|
|
||||||
std::list<std::string> base_urls_;
|
std::list<std::string> base_urls_;
|
||||||
|
std::string availability_start_time_;
|
||||||
|
|
||||||
base::Lock lock_;
|
base::Lock lock_;
|
||||||
base::AtomicSequenceNumber adaptation_set_counter_;
|
base::AtomicSequenceNumber adaptation_set_counter_;
|
||||||
|
@ -167,6 +168,10 @@ class AdaptationSet {
|
||||||
const MpdOptions& mpd_options_,
|
const MpdOptions& mpd_options_,
|
||||||
base::AtomicSequenceNumber* representation_counter);
|
base::AtomicSequenceNumber* representation_counter);
|
||||||
|
|
||||||
|
// Gets the earliest, normalized segment timestamp. Returns true if
|
||||||
|
// successful, false otherwise.
|
||||||
|
bool GetEarliestTimestamp(double* timestamp_seconds);
|
||||||
|
|
||||||
std::list<ContentProtectionElement> content_protection_elements_;
|
std::list<ContentProtectionElement> content_protection_elements_;
|
||||||
std::list<Representation*> representations_;
|
std::list<Representation*> representations_;
|
||||||
::STLElementDeleter<std::list<Representation*> > representations_deleter_;
|
::STLElementDeleter<std::list<Representation*> > representations_deleter_;
|
||||||
|
@ -248,6 +253,10 @@ class Representation {
|
||||||
std::string GetVideoMimeType() const;
|
std::string GetVideoMimeType() const;
|
||||||
std::string GetAudioMimeType() const;
|
std::string GetAudioMimeType() const;
|
||||||
|
|
||||||
|
// Gets the earliest, normalized segment timestamp. Returns true if
|
||||||
|
// successful, false otherwise.
|
||||||
|
bool GetEarliestTimestamp(double* timestamp_seconds);
|
||||||
|
|
||||||
MediaInfo media_info_;
|
MediaInfo media_info_;
|
||||||
std::list<ContentProtectionElement> content_protection_elements_;
|
std::list<ContentProtectionElement> content_protection_elements_;
|
||||||
std::list<SegmentInfo> segment_infos_;
|
std::list<SegmentInfo> segment_infos_;
|
||||||
|
@ -258,7 +267,7 @@ class Representation {
|
||||||
std::string mime_type_;
|
std::string mime_type_;
|
||||||
std::string codecs_;
|
std::string codecs_;
|
||||||
BandwidthEstimator bandwidth_estimator_;
|
BandwidthEstimator bandwidth_estimator_;
|
||||||
const MpdOptions& mpd_options_;;
|
const MpdOptions& mpd_options_;
|
||||||
|
|
||||||
// startNumber attribute for SegmentTemplate.
|
// startNumber attribute for SegmentTemplate.
|
||||||
// Starts from 1.
|
// Starts from 1.
|
||||||
|
|
|
@ -99,7 +99,7 @@ class DynamicMpdBuilderTest : public MpdBuilderTest<MpdBuilder::kDynamic> {
|
||||||
// Anchors availabilityStartTime so that the test result doesn't depend on the
|
// Anchors availabilityStartTime so that the test result doesn't depend on the
|
||||||
// current time.
|
// current time.
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
mpd_.mpd_options_.availability_start_time = "2011-12-25T12:30:00";
|
mpd_.availability_start_time_ = "2011-12-25T12:30:00";
|
||||||
}
|
}
|
||||||
|
|
||||||
MpdOptions* mutable_mpd_options() { return &mpd_.mpd_options_; }
|
MpdOptions* mutable_mpd_options() { return &mpd_.mpd_options_; }
|
||||||
|
@ -370,9 +370,9 @@ TEST_F(DynamicMpdBuilderTest, CheckMpdAttributes) {
|
||||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||||
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
|
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
|
||||||
"xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 "
|
"xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 "
|
||||||
"DASH-MPD.xsd\" availabilityStartTime=\"2011-12-25T12:30:00\" "
|
"DASH-MPD.xsd\" minBufferTime=\"PT2S\" type=\"dynamic\" "
|
||||||
"minBufferTime=\"PT2S\" type=\"dynamic\" "
|
"profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" "
|
||||||
"profiles=\"urn:mpeg:dash:profile:isoff-live:2011\">\n"
|
"availabilityStartTime=\"2011-12-25T12:30:00\">\n"
|
||||||
" <Period start=\"PT0S\"/>\n"
|
" <Period start=\"PT0S\"/>\n"
|
||||||
"</MPD>\n";
|
"</MPD>\n";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue