Make {Video,Audio,Text}Info optional

- The fields used to be repeated but there is no use case at the moment.
- DASH IOP explicitly disallows segments with multiple tracks.

Change-Id: Ia0af2048210c546dfaa178735605a81052ea1123
This commit is contained in:
Rintaro Kuroiwa 2015-06-09 16:58:32 -07:00
parent a02e3b60df
commit 2cf673055c
18 changed files with 134 additions and 263 deletions

View File

@ -34,13 +34,13 @@ void MpdNotifyMuxerListener::SetContentProtectionSchemeIdUri(
void MpdNotifyMuxerListener::OnMediaStart(
const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos,
const StreamInfo& stream_info,
uint32_t time_scale,
ContainerType container_type,
bool is_encrypted) {
scoped_ptr<MediaInfo> media_info(new MediaInfo());
if (!internal::GenerateMediaInfo(muxer_options,
stream_infos,
stream_info,
time_scale,
container_type,
media_info.get())) {

View File

@ -37,7 +37,7 @@ class MpdNotifyMuxerListener : public MuxerListener {
/// @name MuxerListener implementation overrides.
/// @{
virtual void OnMediaStart(const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos,
const StreamInfo& stream_info,
uint32_t time_scale,
ContainerType container_type,
bool is_encrypted) OVERRIDE;

View File

@ -37,10 +37,10 @@ class MuxerListener {
// Called when muxing starts. This event happens before any other events.
// For MPEG DASH Live profile, the initialization segment information is
// available from StreamInfo.
// |time_scale| is a reference time scale regardless of the time scale(s)
// specified in |stream_infos|.
// |time_scale| is a reference time scale that overrides the time scale
// specified in |stream_info|.
virtual void OnMediaStart(const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos,
const StreamInfo& stream_info,
uint32_t time_scale,
ContainerType container_type,
bool is_encrypted) = 0;

View File

@ -80,7 +80,7 @@ void AddVideoInfo(const VideoStreamInfo* video_stream_info,
MediaInfo* media_info) {
DCHECK(video_stream_info);
DCHECK(media_info);
MediaInfo_VideoInfo* video_info = media_info->add_video_info();
MediaInfo_VideoInfo* video_info = media_info->mutable_video_info();
video_info->set_codec(video_stream_info->codec_string());
video_info->set_width(video_stream_info->width());
video_info->set_height(video_stream_info->height());
@ -96,7 +96,7 @@ void AddAudioInfo(const AudioStreamInfo* audio_stream_info,
MediaInfo* media_info) {
DCHECK(audio_stream_info);
DCHECK(media_info);
MediaInfo_AudioInfo* audio_info = media_info->add_audio_info();
MediaInfo_AudioInfo* audio_info = media_info->mutable_audio_info();
audio_info->set_codec(audio_stream_info->codec_string());
audio_info->set_sampling_frequency(audio_stream_info->sampling_frequency());
audio_info->set_time_scale(audio_stream_info->time_scale());
@ -114,24 +114,15 @@ void AddAudioInfo(const AudioStreamInfo* audio_stream_info,
}
}
void SetMediaInfoStreamInfo(const std::vector<StreamInfo*>& stream_infos,
void SetMediaInfoStreamInfo(const StreamInfo& stream_info,
MediaInfo* media_info) {
typedef std::vector<StreamInfo*>::const_iterator StreamInfoIterator;
for (StreamInfoIterator it = stream_infos.begin();
it != stream_infos.end();
++it) {
const StreamInfo* stream_info = *it;
if (!stream_info)
continue;
if (stream_info->stream_type() == kStreamAudio) {
AddAudioInfo(static_cast<const AudioStreamInfo*>(stream_info),
media_info);
} else {
DCHECK_EQ(stream_info->stream_type(), kStreamVideo);
AddVideoInfo(static_cast<const VideoStreamInfo*>(stream_info),
media_info);
}
if (stream_info.stream_type() == kStreamAudio) {
AddAudioInfo(static_cast<const AudioStreamInfo*>(&stream_info),
media_info);
} else {
DCHECK_EQ(stream_info.stream_type(), kStreamVideo);
AddVideoInfo(static_cast<const VideoStreamInfo*>(&stream_info),
media_info);
}
}
@ -150,14 +141,14 @@ void SetMediaInfoMuxerOptions(const MuxerOptions& muxer_options,
} // namespace
bool GenerateMediaInfo(const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos,
const StreamInfo& stream_info,
uint32_t reference_time_scale,
MuxerListener::ContainerType container_type,
MediaInfo* media_info) {
DCHECK(media_info);
SetMediaInfoMuxerOptions(muxer_options, media_info);
SetMediaInfoStreamInfo(stream_infos, media_info);
SetMediaInfoStreamInfo(stream_info, media_info);
media_info->set_reference_time_scale(reference_time_scale);
SetMediaInfoContainerType(container_type, media_info);
if (muxer_options.bandwidth > 0)

View File

@ -28,7 +28,7 @@ namespace internal {
/// @param[out] media_info points to the MediaInfo object to be filled.
/// @return true on success, false otherwise.
bool GenerateMediaInfo(const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos,
const StreamInfo& stream_info,
uint32_t reference_time_scale_,
MuxerListener::ContainerType container_type,
MediaInfo* media_info);

View File

@ -31,14 +31,14 @@ void VodMediaInfoDumpMuxerListener::SetContentProtectionSchemeIdUri(
void VodMediaInfoDumpMuxerListener::OnMediaStart(
const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos,
const StreamInfo& stream_info,
uint32_t time_scale,
ContainerType container_type,
bool is_encrypted) {
DCHECK(muxer_options.single_segment);
media_info_.reset(new MediaInfo());
if (!internal::GenerateMediaInfo(muxer_options,
stream_infos,
stream_info,
time_scale,
container_type,
media_info_.get())) {
@ -58,8 +58,8 @@ void VodMediaInfoDumpMuxerListener::OnMediaStart(
void VodMediaInfoDumpMuxerListener::OnSampleDurationReady(
uint32_t sample_duration) {
// Assume one VideoInfo.
if (media_info_->video_info_size() > 0) {
media_info_->mutable_video_info(0)->set_frame_duration(sample_duration);
if (media_info_->has_video_info()) {
media_info_->mutable_video_info()->set_frame_duration(sample_duration);
}
}

View File

@ -37,7 +37,7 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
/// @name MuxerListener implementation overrides.
/// @{
virtual void OnMediaStart(const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos,
const StreamInfo& stream_info,
uint32_t time_scale,
ContainerType container_type,
bool is_encrypted) OVERRIDE;

View File

@ -167,13 +167,13 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
}
void FireOnMediaStartWithDefaultMuxerOptions(
const std::vector<StreamInfo*> stream_infos,
const StreamInfo& stream_info,
bool enable_encryption) {
MuxerOptions muxer_options;
SetDefaultMuxerOptionsValues(&muxer_options);
const uint32_t kReferenceTimeScale = 1000;
listener_->OnMediaStart(muxer_options,
stream_infos,
stream_info,
kReferenceTimeScale,
MuxerListener::kContainerMp4,
enable_encryption);
@ -212,10 +212,8 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) {
scoped_refptr<StreamInfo> stream_info =
CreateVideoStreamInfo(GetDefaultVideoStreamInfoParams());
std::vector<StreamInfo*> stream_infos;
stream_infos.push_back(stream_info.get());
FireOnMediaStartWithDefaultMuxerOptions(stream_infos, !kEnableEncryption);
FireOnMediaStartWithDefaultMuxerOptions(*stream_info, !kEnableEncryption);
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
FireOnMediaEndWithParams(media_end_param);
@ -247,10 +245,8 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
scoped_refptr<StreamInfo> stream_info =
CreateVideoStreamInfo(GetDefaultVideoStreamInfoParams());
std::vector<StreamInfo*> stream_infos;
stream_infos.push_back(stream_info.get());
FireOnMediaStartWithDefaultMuxerOptions(stream_infos, kEnableEncryption);
FireOnMediaStartWithDefaultMuxerOptions(*stream_info, kEnableEncryption);
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
FireOnMediaEndWithParams(media_end_param);

View File

@ -204,15 +204,6 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info,
sample_description.audio_entries.push_back(audio);
}
void MP4Muxer::GetStreamInfo(std::vector<StreamInfo*>* stream_infos) {
DCHECK(stream_infos);
const std::vector<MediaStream*>& media_stream_vec = streams();
stream_infos->reserve(media_stream_vec.size());
for (size_t i = 0; i < media_stream_vec.size(); ++i) {
stream_infos->push_back(media_stream_vec[i]->info().get());
}
}
bool MP4Muxer::GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end) {
DCHECK(start && end);
size_t range_offset = 0;
@ -243,11 +234,15 @@ void MP4Muxer::FireOnMediaStartEvent() {
if (!muxer_listener())
return;
std::vector<StreamInfo*> stream_info_vec;
GetStreamInfo(&stream_info_vec);
if (streams().size() > 1) {
LOG(ERROR) << "MuxerListener cannot take more than 1 stream.";
return;
}
DCHECK(!streams().empty()) << "Media started without a stream.";
const uint32_t timescale = segmenter_->GetReferenceTimeScale();
muxer_listener()->OnMediaStart(options(),
stream_info_vec,
*streams().front()->info(),
timescale,
MuxerListener::kContainerMp4,
encryption_key_source() != NULL);

View File

@ -51,9 +51,6 @@ class MP4Muxer : public Muxer {
Track* trak,
uint32_t track_id);
// Helper functions for events.
void GetStreamInfo(std::vector<StreamInfo*>* stream_infos);
// Gets |start| and |end| initialization range. Returns true if there is an
// init range and sets start-end byte-range-spec specified in RFC2616.
bool GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end);

View File

@ -77,9 +77,12 @@ message MediaInfo {
}
optional uint32 bandwidth = 1;
repeated VideoInfo video_info = 2;
repeated AudioInfo audio_info = 3;
repeated TextInfo text_info = 4;
// Note that DASH IOP v3.0 explicitly mentions that a segment should only
// have one {video, audio, text} track.
optional VideoInfo video_info = 2;
optional AudioInfo audio_info = 3;
optional TextInfo text_info = 4;
repeated ContentProtectionXml content_protections = 5;
// This is the reference time scale if there are multiple VideoInfo and/or

View File

@ -119,12 +119,12 @@ uint32_t GetTimeScale(const MediaInfo& media_info) {
return media_info.reference_time_scale();
}
if (media_info.video_info_size() > 0) {
return media_info.video_info(0).time_scale();
if (media_info.has_video_info()) {
return media_info.video_info().time_scale();
}
if (media_info.audio_info_size() > 0) {
return media_info.audio_info(0).time_scale();
if (media_info.has_audio_info()) {
return media_info.audio_info().time_scale();
}
LOG(WARNING) << "No timescale specified, using 1 as timescale.";
@ -186,34 +186,29 @@ std::string MakePathRelative(const std::string& path,
return (path.find(mpd_dir) == 0) ? path.substr(mpd_dir.size()) : path;
}
// Check whether all the video infos have width and height.
// DASH IOP defines required fields for video representations, namely
// Check whether the video info has width and height.
// DASH IOP also requires several other fields for video representations, namely
// width, height, framerate, and sar.
bool HasRequiredVideoFields(
::google::protobuf::RepeatedPtrField<MediaInfo_VideoInfo> video_infos) {
CHECK_GT(video_infos.size(), 0);
for (int i = 0; i < video_infos.size(); ++i) {
const MediaInfo::VideoInfo& info = video_infos.Get(i);
if (!info.has_height() || !info.has_width()) {
LOG(ERROR)
<< "Width and height are required fields for generating a valid MPD.";
return false;
}
// These fields are not required for a valid MPD, but required for DASH IOP
// compliant MPD. MpdBuilder can keep generating MPDs without these fields.
LOG_IF(WARNING, !info.has_time_scale())
<< "Video info does not contain timescale required for "
"calculating framerate. @frameRate is required for DASH IOP.";
LOG_IF(WARNING, !info.has_frame_duration())
<< "Video info does not contain frame duration required "
"for calculating framerate. @frameRate is required for DASH IOP.";
LOG_IF(WARNING, !info.has_pixel_width())
<< "Video info does not contain pixel_width to calculate the sample "
"aspect ratio required for DASH IOP.";
LOG_IF(WARNING, !info.has_pixel_height())
<< "Video info does not contain pixel_height to calculate the sample "
"aspect ratio required for DASH IOP.";
bool HasRequiredVideoFields(const MediaInfo_VideoInfo& video_info) {
if (!video_info.has_height() || !video_info.has_width()) {
LOG(ERROR)
<< "Width and height are required fields for generating a valid MPD.";
return false;
}
// These fields are not required for a valid MPD, but required for DASH IOP
// compliant MPD. MpdBuilder can keep generating MPDs without these fields.
LOG_IF(WARNING, !video_info.has_time_scale())
<< "Video info does not contain timescale required for "
"calculating framerate. @frameRate is required for DASH IOP.";
LOG_IF(WARNING, !video_info.has_frame_duration())
<< "Video info does not contain frame duration required "
"for calculating framerate. @frameRate is required for DASH IOP.";
LOG_IF(WARNING, !video_info.has_pixel_width())
<< "Video info does not contain pixel_width to calculate the sample "
"aspect ratio required for DASH IOP.";
LOG_IF(WARNING, !video_info.has_pixel_height())
<< "Video info does not contain pixel_height to calculate the sample "
"aspect ratio required for DASH IOP.";
return true;
}
@ -528,8 +523,8 @@ Representation* AdaptationSet::AddRepresentation(const MediaInfo& media_info) {
// For videos, record the width, height, and the frame rate to calculate the
// max {width,height,framerate} required for DASH IOP.
if(media_info.video_info_size() > 0) {
const MediaInfo::VideoInfo& video_info = media_info.video_info(0);
if(media_info.has_video_info()) {
const MediaInfo::VideoInfo& video_info = media_info.video_info();
DCHECK(video_info.has_width());
DCHECK(video_info.has_height());
video_widths_.insert(video_info.width());
@ -642,8 +637,8 @@ bool Representation::Init() {
return false;
}
const bool has_video_info = media_info_.video_info_size() > 0;
const bool has_audio_info = media_info_.audio_info_size() > 0;
const bool has_video_info = media_info_.has_video_info();
const bool has_audio_info = media_info_.has_audio_info();
if (!has_video_info && !has_audio_info) {
// This is an error. Segment information can be in AdaptationSet, Period, or
@ -705,8 +700,8 @@ void Representation::AddNewSegment(uint64_t start_time,
void Representation::SetSampleDuration(uint32_t sample_duration) {
// Assume single video info.
if (media_info_.video_info_size() > 0)
media_info_.mutable_video_info(0)->set_frame_duration(sample_duration);
if (media_info_.has_video_info())
media_info_.mutable_video_info()->set_frame_duration(sample_duration);
}
// Uses info in |media_info_| and |content_protection_elements_| to create a
@ -736,8 +731,8 @@ xml::ScopedXmlPtr<xmlNode>::type Representation::GetXml() {
representation.SetStringAttribute("codecs", codecs_);
representation.SetStringAttribute("mimeType", mime_type_);
const bool has_video_info = media_info_.video_info_size() > 0;
const bool has_audio_info = media_info_.audio_info_size() > 0;
const bool has_video_info = media_info_.has_video_info();
const bool has_audio_info = media_info_.has_audio_info();
if (has_video_info &&
!representation.AddVideoInfo(media_info_.video_info())) {

View File

@ -613,7 +613,7 @@ TEST_F(CommonMpdBuilderTest, SetSampleDuration) {
EXPECT_TRUE(representation.Init());
representation.SetSampleDuration(2u);
EXPECT_EQ(2u,
representation.media_info_.video_info(0).frame_duration());
representation.media_info_.video_info().frame_duration());
}
// Add one video check the output.

View File

@ -14,27 +14,6 @@
#include "packager/mpd/base/media_info.pb.h"
#include "packager/mpd/base/xml/scoped_xml_ptr.h"
namespace {
// Concatenate all the codecs in |repeated_stream_info|.
template <typename RepeatedStreamInfoType>
std::string CodecsString(const RepeatedStreamInfoType& repeated_stream_info) {
std::string codecs;
for (int i = 0; i < repeated_stream_info.size(); ++i) {
codecs.append(repeated_stream_info.Get(i).codec());
codecs.append(",");
}
if (!codecs.empty()) {
DCHECK_EQ(codecs[codecs.size() - 1], ',');
codecs.resize(codecs.size() - 1); // Cut off ',' at the end.
}
return codecs;
}
} // namespace
namespace edash_packager {
bool HasVODOnlyFields(const MediaInfo& media_info) {
@ -63,20 +42,20 @@ void RemoveDuplicateAttributes(
}
std::string GetCodecs(const MediaInfo& media_info) {
std::string video_codecs;
if (media_info.video_info_size() > 0)
video_codecs = CodecsString(media_info.video_info());
std::string video_codec;
if (media_info.has_video_info())
video_codec = media_info.video_info().codec();
std::string audio_codecs;
if (media_info.audio_info_size() > 0)
audio_codecs = CodecsString(media_info.audio_info());
std::string audio_codec;
if (media_info.has_audio_info())
audio_codec = media_info.audio_info().codec();
if (!video_codecs.empty() && !audio_codecs.empty()) {
return video_codecs + "," + audio_codecs;
} else if (!video_codecs.empty()) {
return video_codecs;
} else if (!audio_codecs.empty()) {
return audio_codecs;
if (!video_codec.empty() && !audio_codec.empty()) {
return video_codec + "," + audio_codec;
} else if (!video_codec.empty()) {
return video_codec;
} else if (!audio_codec.empty()) {
return audio_codec;
}
return "";

View File

@ -49,8 +49,8 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
// TODO(kqyang): Consider adding a new method MpdBuilder::AddRepresentation.
// Most of the codes here can be moved inside.
std::string lang;
if (media_info.audio_info().size() > 0) {
lang = media_info.audio_info(0).language();
if (media_info.has_audio_info()) {
lang = media_info.audio_info().language();
}
AdaptationSet** adaptation_set = &adaptation_set_map_[content_type][lang];
if (*adaptation_set == NULL)
@ -110,9 +110,9 @@ bool SimpleMpdNotifier::AddContentProtectionElement(
SimpleMpdNotifier::ContentType SimpleMpdNotifier::GetContentType(
const MediaInfo& media_info) {
const bool has_video = media_info.video_info().size() > 0;
const bool has_audio = media_info.audio_info().size() > 0;
const bool has_text = media_info.text_info().size() > 0;
const bool has_video = media_info.has_video_info();
const bool has_audio = media_info.has_audio_info();
const bool has_text = media_info.has_text_info();
if (MoreThanOneTrue(has_video, has_audio, has_text)) {
NOTIMPLEMENTED() << "MediaInfo with more than one stream is not supported.";

View File

@ -19,6 +19,8 @@
using edash_packager::xml::XmlNode;
using edash_packager::MediaInfo;
typedef edash_packager::MediaInfo::AudioInfo AudioInfo;
typedef edash_packager::MediaInfo::VideoInfo VideoInfo;
typedef MediaInfo::ContentProtectionXml ContentProtectionXml;
typedef ContentProtectionXml::AttributeNameValuePair AttributeNameValuePair;
@ -322,55 +324,27 @@ RepresentationXmlNode::RepresentationXmlNode()
: RepresentationBaseXmlNode("Representation") {}
RepresentationXmlNode::~RepresentationXmlNode() {}
bool RepresentationXmlNode::AddVideoInfo(
const RepeatedVideoInfo& repeated_video_info) {
uint32_t width = 0;
uint32_t height = 0;
// Make sure that all the widths and heights match.
for (int i = 0; i < repeated_video_info.size(); ++i) {
const MediaInfo_VideoInfo& video_info = repeated_video_info.Get(i);
if (video_info.width() == 0 || video_info.height() == 0)
return false;
if (width == 0) {
width = video_info.width();
} else if (width != video_info.width()) {
return false;
}
if (height == 0) {
height = video_info.height();
} else if (height != video_info.height()) {
return false;
}
bool RepresentationXmlNode::AddVideoInfo(const VideoInfo& video_info) {
if (!video_info.has_width() || !video_info.has_height()) {
LOG(ERROR) << "Missing width or height for adding a video info.";
return false;
}
if (width != 0)
SetIntegerAttribute("width", width);
if (height != 0)
SetIntegerAttribute("height", height);
// TODO(rkuroiwa): Because we are going ot make video_info optional instead
// of repeated, just using the first video_info.
const MediaInfo_VideoInfo& video_info = repeated_video_info.Get(0);
SetIntegerAttribute("width", video_info.width());
SetIntegerAttribute("height", video_info.height());
SetStringAttribute("frameRate",
base::IntToString(video_info.time_scale()) + "/" +
base::IntToString(video_info.frame_duration()));
SetStringAttribute("sar", base::IntToString(video_info.pixel_width()) + ":" +
base::IntToString(video_info.pixel_height()));
return true;
}
bool RepresentationXmlNode::AddAudioInfo(
const RepeatedAudioInfo& repeated_audio_info) {
if (!AddAudioChannelInfo(repeated_audio_info))
bool RepresentationXmlNode::AddAudioInfo(const AudioInfo& audio_info) {
if (!AddAudioChannelInfo(audio_info))
return false;
AddAudioSamplingRateInfo(repeated_audio_info);
AddAudioSamplingRateInfo(audio_info);
return true;
}
@ -466,64 +440,24 @@ bool RepresentationXmlNode::AddLiveOnlyInfo(
AddChild(segment_template.PassScopedPtr());
}
// Find all the unique number-of-channels in |repeated_audio_info|, and make
// AudioChannelConfiguration for each number-of-channels.
bool RepresentationXmlNode::AddAudioChannelInfo(
const RepeatedAudioInfo& repeated_audio_info) {
std::set<uint32_t> num_channels;
for (int i = 0; i < repeated_audio_info.size(); ++i) {
if (repeated_audio_info.Get(i).has_num_channels())
num_channels.insert(repeated_audio_info.Get(i).num_channels());
}
bool RepresentationXmlNode::AddAudioChannelInfo(const AudioInfo& audio_info) {
const uint32_t num_channels = audio_info.num_channels();
XmlNode audio_channel_config("AudioChannelConfiguration");
const char kAudioChannelConfigScheme[] =
"urn:mpeg:dash:23003:3:audio_channel_configuration:2011";
audio_channel_config.SetStringAttribute("schemeIdUri",
kAudioChannelConfigScheme);
audio_channel_config.SetIntegerAttribute("value", num_channels);
std::set<uint32_t>::const_iterator num_channels_it = num_channels.begin();
for (; num_channels_it != num_channels.end(); ++num_channels_it) {
XmlNode audio_channel_config("AudioChannelConfiguration");
const char kAudioChannelConfigScheme[] =
"urn:mpeg:dash:23003:3:audio_channel_configuration:2011";
audio_channel_config.SetStringAttribute("schemeIdUri",
kAudioChannelConfigScheme);
audio_channel_config.SetIntegerAttribute("value", *num_channels_it);
if (!AddChild(audio_channel_config.PassScopedPtr()))
return false;
}
return true;
return AddChild(audio_channel_config.PassScopedPtr());
}
// MPD expects one number for sampling frequency, or if it is a range it should
// be space separated.
void RepresentationXmlNode::AddAudioSamplingRateInfo(
const RepeatedAudioInfo& repeated_audio_info) {
bool has_sampling_frequency = false;
uint32_t min_sampling_frequency = std::numeric_limits<uint32_t>::max();
uint32_t max_sampling_frequency = 0;
for (int i = 0; i < repeated_audio_info.size(); ++i) {
const MediaInfo_AudioInfo &audio_info = repeated_audio_info.Get(i);
if (audio_info.has_sampling_frequency()) {
has_sampling_frequency = true;
const uint32_t sampling_frequency = audio_info.sampling_frequency();
if (sampling_frequency < min_sampling_frequency)
min_sampling_frequency = sampling_frequency;
if (sampling_frequency > max_sampling_frequency)
max_sampling_frequency = sampling_frequency;
}
}
if (has_sampling_frequency) {
if (min_sampling_frequency == max_sampling_frequency) {
SetIntegerAttribute("audioSamplingRate", min_sampling_frequency);
} else {
std::string sample_rate_string =
base::UintToString(min_sampling_frequency) + " " +
base::UintToString(max_sampling_frequency);
SetStringAttribute("audioSamplingRate", sample_rate_string);
}
}
const AudioInfo& audio_info) {
if (audio_info.has_sampling_frequency())
SetIntegerAttribute("audioSamplingRate", audio_info.sampling_frequency());
}
} // namespace xml

View File

@ -124,28 +124,20 @@ class AdaptationSetXmlNode : public RepresentationBaseXmlNode {
/// RepresentationType in MPD.
class RepresentationXmlNode : public RepresentationBaseXmlNode {
public:
typedef ::google::protobuf::RepeatedPtrField<MediaInfo_VideoInfo>
RepeatedVideoInfo;
typedef ::google::protobuf::RepeatedPtrField<MediaInfo_AudioInfo>
RepeatedAudioInfo;
RepresentationXmlNode();
virtual ~RepresentationXmlNode();
/// Adds video metadata to the MPD.
/// @param repeated_video_info constains the VideoInfos for Representation.
/// Input of size 0 is valid.
/// @param video_info constains the VideoInfo for a Representation.
/// @return true if successfully set attributes and children elements (if
/// applicable), false otherwise.
bool AddVideoInfo(const RepeatedVideoInfo& repeated_video_info);
bool AddVideoInfo(const MediaInfo::VideoInfo& video_info);
/// Adds audio metadata to the MPD.
/// @param repeated_audio_info constains the AudioInfos for Representation.
/// Input of size 0 is valid.
/// @param audio_info constains the AudioInfos for a Representation.
/// @return true if successfully set attributes and children elements (if
/// applicable), false otherwise.
bool AddAudioInfo(const RepeatedAudioInfo& repeated_audio_info);
bool AddAudioInfo(const MediaInfo::AudioInfo& audio_info);
/// Adds fields that are specific to VOD. This ignores @a media_info fields
/// for Live.
@ -160,13 +152,12 @@ class RepresentationXmlNode : public RepresentationBaseXmlNode {
uint32_t start_number);
private:
// Add AudioChannelConfiguration elements. This will add multiple
// AudioChannelConfiguration if @a repeated_audio_info contains multiple
// distinct channel configs (e.g. 2 channels and 6 channels adds 2 elements).
bool AddAudioChannelInfo(const RepeatedAudioInfo& repeated_audio_info);
// Add AudioChannelConfiguration element. Note that it is a required element
// for audio Representations.
bool AddAudioChannelInfo(const MediaInfo::AudioInfo& audio_info);
// Add audioSamplingRate attribute to this element.
void AddAudioSamplingRateInfo(const RepeatedAudioInfo& repeated_audio_info);
// Add audioSamplingRate attribute to this element, if present.
void AddAudioSamplingRateInfo(const MediaInfo::AudioInfo& audio_info);
DISALLOW_COPY_AND_ASSIGN(RepresentationXmlNode);
};

View File

@ -17,17 +17,6 @@ using edash_packager::media::File;
namespace edash_packager {
namespace {
bool HasVideo(const MediaInfo& media_info) {
return media_info.video_info().size() > 0;
}
bool HasAudio(const MediaInfo& media_info) {
return media_info.audio_info().size() > 0;
}
bool HasText(const MediaInfo& media_info) {
return media_info.text_info().size() > 0;
}
// On entry set |has_video|, |has_audio|, and |has_text| to false.
// On success, return true and set appropriate |has_*| variables. Otherwise
@ -48,9 +37,9 @@ bool HasVideoAudioText(const std::list<MediaInfo>& media_infos,
it != media_infos.end();
++it) {
const MediaInfo& media_info = *it;
const bool media_info_has_video = HasVideo(media_info);
const bool media_info_has_audio = HasAudio(media_info);
const bool media_info_has_text = HasText(media_info);
const bool media_info_has_video = media_info.has_video_info();
const bool media_info_has_audio = media_info.has_audio_info();
const bool media_info_has_text = media_info.has_text_info();
if (MoreThanOneTrue(
media_info_has_video, media_info_has_audio, media_info_has_text)) {
@ -101,17 +90,18 @@ bool SetMediaInfosToMpdBuilder(const std::list<MediaInfo>& media_infos,
it != media_infos.end();
++it) {
const MediaInfo& media_info = *it;
DCHECK(OnlyOneTrue(
HasVideo(media_info), HasAudio(media_info), HasText(media_info)));
DCHECK(OnlyOneTrue(media_info.has_video_info(),
media_info.has_audio_info(),
media_info.has_text_info()));
std::string lang;
AdaptationSet** adaptation_set = NULL;
if (HasVideo(media_info)) {
if (media_info.has_video_info()) {
adaptation_set = &map["video"][lang];
} else if (HasAudio(media_info)) {
lang = media_info.audio_info(0).language();
} else if (media_info.has_audio_info()) {
lang = media_info.audio_info().language();
adaptation_set = &map["audio"][lang];
} else if (HasText(media_info)) {
} else if (media_info.has_text_info()) {
adaptation_set = &map["text"][lang];
}
if (!*adaptation_set) {