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:
parent
a02e3b60df
commit
2cf673055c
|
@ -34,13 +34,13 @@ void MpdNotifyMuxerListener::SetContentProtectionSchemeIdUri(
|
||||||
|
|
||||||
void MpdNotifyMuxerListener::OnMediaStart(
|
void MpdNotifyMuxerListener::OnMediaStart(
|
||||||
const MuxerOptions& muxer_options,
|
const MuxerOptions& muxer_options,
|
||||||
const std::vector<StreamInfo*>& stream_infos,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type,
|
||||||
bool is_encrypted) {
|
bool is_encrypted) {
|
||||||
scoped_ptr<MediaInfo> media_info(new MediaInfo());
|
scoped_ptr<MediaInfo> media_info(new MediaInfo());
|
||||||
if (!internal::GenerateMediaInfo(muxer_options,
|
if (!internal::GenerateMediaInfo(muxer_options,
|
||||||
stream_infos,
|
stream_info,
|
||||||
time_scale,
|
time_scale,
|
||||||
container_type,
|
container_type,
|
||||||
media_info.get())) {
|
media_info.get())) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
||||||
/// @name MuxerListener implementation overrides.
|
/// @name MuxerListener implementation overrides.
|
||||||
/// @{
|
/// @{
|
||||||
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const std::vector<StreamInfo*>& stream_infos,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type,
|
||||||
bool is_encrypted) OVERRIDE;
|
bool is_encrypted) OVERRIDE;
|
||||||
|
|
|
@ -37,10 +37,10 @@ class MuxerListener {
|
||||||
// Called when muxing starts. This event happens before any other events.
|
// Called when muxing starts. This event happens before any other events.
|
||||||
// For MPEG DASH Live profile, the initialization segment information is
|
// For MPEG DASH Live profile, the initialization segment information is
|
||||||
// available from StreamInfo.
|
// available from StreamInfo.
|
||||||
// |time_scale| is a reference time scale regardless of the time scale(s)
|
// |time_scale| is a reference time scale that overrides the time scale
|
||||||
// specified in |stream_infos|.
|
// specified in |stream_info|.
|
||||||
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const std::vector<StreamInfo*>& stream_infos,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type,
|
||||||
bool is_encrypted) = 0;
|
bool is_encrypted) = 0;
|
||||||
|
|
|
@ -80,7 +80,7 @@ void AddVideoInfo(const VideoStreamInfo* video_stream_info,
|
||||||
MediaInfo* media_info) {
|
MediaInfo* media_info) {
|
||||||
DCHECK(video_stream_info);
|
DCHECK(video_stream_info);
|
||||||
DCHECK(media_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_codec(video_stream_info->codec_string());
|
||||||
video_info->set_width(video_stream_info->width());
|
video_info->set_width(video_stream_info->width());
|
||||||
video_info->set_height(video_stream_info->height());
|
video_info->set_height(video_stream_info->height());
|
||||||
|
@ -96,7 +96,7 @@ void AddAudioInfo(const AudioStreamInfo* audio_stream_info,
|
||||||
MediaInfo* media_info) {
|
MediaInfo* media_info) {
|
||||||
DCHECK(audio_stream_info);
|
DCHECK(audio_stream_info);
|
||||||
DCHECK(media_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_codec(audio_stream_info->codec_string());
|
||||||
audio_info->set_sampling_frequency(audio_stream_info->sampling_frequency());
|
audio_info->set_sampling_frequency(audio_stream_info->sampling_frequency());
|
||||||
audio_info->set_time_scale(audio_stream_info->time_scale());
|
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) {
|
MediaInfo* media_info) {
|
||||||
typedef std::vector<StreamInfo*>::const_iterator StreamInfoIterator;
|
if (stream_info.stream_type() == kStreamAudio) {
|
||||||
for (StreamInfoIterator it = stream_infos.begin();
|
AddAudioInfo(static_cast<const AudioStreamInfo*>(&stream_info),
|
||||||
it != stream_infos.end();
|
media_info);
|
||||||
++it) {
|
} else {
|
||||||
const StreamInfo* stream_info = *it;
|
DCHECK_EQ(stream_info.stream_type(), kStreamVideo);
|
||||||
if (!stream_info)
|
AddVideoInfo(static_cast<const VideoStreamInfo*>(&stream_info),
|
||||||
continue;
|
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
|
} // namespace
|
||||||
|
|
||||||
bool GenerateMediaInfo(const MuxerOptions& muxer_options,
|
bool GenerateMediaInfo(const MuxerOptions& muxer_options,
|
||||||
const std::vector<StreamInfo*>& stream_infos,
|
const StreamInfo& stream_info,
|
||||||
uint32_t reference_time_scale,
|
uint32_t reference_time_scale,
|
||||||
MuxerListener::ContainerType container_type,
|
MuxerListener::ContainerType container_type,
|
||||||
MediaInfo* media_info) {
|
MediaInfo* media_info) {
|
||||||
DCHECK(media_info);
|
DCHECK(media_info);
|
||||||
|
|
||||||
SetMediaInfoMuxerOptions(muxer_options, 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);
|
media_info->set_reference_time_scale(reference_time_scale);
|
||||||
SetMediaInfoContainerType(container_type, media_info);
|
SetMediaInfoContainerType(container_type, media_info);
|
||||||
if (muxer_options.bandwidth > 0)
|
if (muxer_options.bandwidth > 0)
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace internal {
|
||||||
/// @param[out] media_info points to the MediaInfo object to be filled.
|
/// @param[out] media_info points to the MediaInfo object to be filled.
|
||||||
/// @return true on success, false otherwise.
|
/// @return true on success, false otherwise.
|
||||||
bool GenerateMediaInfo(const MuxerOptions& muxer_options,
|
bool GenerateMediaInfo(const MuxerOptions& muxer_options,
|
||||||
const std::vector<StreamInfo*>& stream_infos,
|
const StreamInfo& stream_info,
|
||||||
uint32_t reference_time_scale_,
|
uint32_t reference_time_scale_,
|
||||||
MuxerListener::ContainerType container_type,
|
MuxerListener::ContainerType container_type,
|
||||||
MediaInfo* media_info);
|
MediaInfo* media_info);
|
||||||
|
|
|
@ -31,14 +31,14 @@ void VodMediaInfoDumpMuxerListener::SetContentProtectionSchemeIdUri(
|
||||||
|
|
||||||
void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
||||||
const MuxerOptions& muxer_options,
|
const MuxerOptions& muxer_options,
|
||||||
const std::vector<StreamInfo*>& stream_infos,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type,
|
||||||
bool is_encrypted) {
|
bool is_encrypted) {
|
||||||
DCHECK(muxer_options.single_segment);
|
DCHECK(muxer_options.single_segment);
|
||||||
media_info_.reset(new MediaInfo());
|
media_info_.reset(new MediaInfo());
|
||||||
if (!internal::GenerateMediaInfo(muxer_options,
|
if (!internal::GenerateMediaInfo(muxer_options,
|
||||||
stream_infos,
|
stream_info,
|
||||||
time_scale,
|
time_scale,
|
||||||
container_type,
|
container_type,
|
||||||
media_info_.get())) {
|
media_info_.get())) {
|
||||||
|
@ -58,8 +58,8 @@ void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
||||||
void VodMediaInfoDumpMuxerListener::OnSampleDurationReady(
|
void VodMediaInfoDumpMuxerListener::OnSampleDurationReady(
|
||||||
uint32_t sample_duration) {
|
uint32_t sample_duration) {
|
||||||
// Assume one VideoInfo.
|
// Assume one VideoInfo.
|
||||||
if (media_info_->video_info_size() > 0) {
|
if (media_info_->has_video_info()) {
|
||||||
media_info_->mutable_video_info(0)->set_frame_duration(sample_duration);
|
media_info_->mutable_video_info()->set_frame_duration(sample_duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
|
||||||
/// @name MuxerListener implementation overrides.
|
/// @name MuxerListener implementation overrides.
|
||||||
/// @{
|
/// @{
|
||||||
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const std::vector<StreamInfo*>& stream_infos,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type,
|
||||||
bool is_encrypted) OVERRIDE;
|
bool is_encrypted) OVERRIDE;
|
||||||
|
|
|
@ -167,13 +167,13 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FireOnMediaStartWithDefaultMuxerOptions(
|
void FireOnMediaStartWithDefaultMuxerOptions(
|
||||||
const std::vector<StreamInfo*> stream_infos,
|
const StreamInfo& stream_info,
|
||||||
bool enable_encryption) {
|
bool enable_encryption) {
|
||||||
MuxerOptions muxer_options;
|
MuxerOptions muxer_options;
|
||||||
SetDefaultMuxerOptionsValues(&muxer_options);
|
SetDefaultMuxerOptionsValues(&muxer_options);
|
||||||
const uint32_t kReferenceTimeScale = 1000;
|
const uint32_t kReferenceTimeScale = 1000;
|
||||||
listener_->OnMediaStart(muxer_options,
|
listener_->OnMediaStart(muxer_options,
|
||||||
stream_infos,
|
stream_info,
|
||||||
kReferenceTimeScale,
|
kReferenceTimeScale,
|
||||||
MuxerListener::kContainerMp4,
|
MuxerListener::kContainerMp4,
|
||||||
enable_encryption);
|
enable_encryption);
|
||||||
|
@ -212,10 +212,8 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
|
||||||
TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) {
|
TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) {
|
||||||
scoped_refptr<StreamInfo> stream_info =
|
scoped_refptr<StreamInfo> stream_info =
|
||||||
CreateVideoStreamInfo(GetDefaultVideoStreamInfoParams());
|
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();
|
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
|
||||||
FireOnMediaEndWithParams(media_end_param);
|
FireOnMediaEndWithParams(media_end_param);
|
||||||
|
|
||||||
|
@ -247,10 +245,8 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
|
||||||
|
|
||||||
scoped_refptr<StreamInfo> stream_info =
|
scoped_refptr<StreamInfo> stream_info =
|
||||||
CreateVideoStreamInfo(GetDefaultVideoStreamInfoParams());
|
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();
|
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
|
||||||
FireOnMediaEndWithParams(media_end_param);
|
FireOnMediaEndWithParams(media_end_param);
|
||||||
|
|
|
@ -204,15 +204,6 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info,
|
||||||
sample_description.audio_entries.push_back(audio);
|
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) {
|
bool MP4Muxer::GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end) {
|
||||||
DCHECK(start && end);
|
DCHECK(start && end);
|
||||||
size_t range_offset = 0;
|
size_t range_offset = 0;
|
||||||
|
@ -243,11 +234,15 @@ void MP4Muxer::FireOnMediaStartEvent() {
|
||||||
if (!muxer_listener())
|
if (!muxer_listener())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<StreamInfo*> stream_info_vec;
|
if (streams().size() > 1) {
|
||||||
GetStreamInfo(&stream_info_vec);
|
LOG(ERROR) << "MuxerListener cannot take more than 1 stream.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DCHECK(!streams().empty()) << "Media started without a stream.";
|
||||||
|
|
||||||
const uint32_t timescale = segmenter_->GetReferenceTimeScale();
|
const uint32_t timescale = segmenter_->GetReferenceTimeScale();
|
||||||
muxer_listener()->OnMediaStart(options(),
|
muxer_listener()->OnMediaStart(options(),
|
||||||
stream_info_vec,
|
*streams().front()->info(),
|
||||||
timescale,
|
timescale,
|
||||||
MuxerListener::kContainerMp4,
|
MuxerListener::kContainerMp4,
|
||||||
encryption_key_source() != NULL);
|
encryption_key_source() != NULL);
|
||||||
|
|
|
@ -51,9 +51,6 @@ class MP4Muxer : public Muxer {
|
||||||
Track* trak,
|
Track* trak,
|
||||||
uint32_t track_id);
|
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
|
// Gets |start| and |end| initialization range. Returns true if there is an
|
||||||
// init range and sets start-end byte-range-spec specified in RFC2616.
|
// init range and sets start-end byte-range-spec specified in RFC2616.
|
||||||
bool GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end);
|
bool GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end);
|
||||||
|
|
|
@ -77,9 +77,12 @@ message MediaInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
optional uint32 bandwidth = 1;
|
optional uint32 bandwidth = 1;
|
||||||
repeated VideoInfo video_info = 2;
|
|
||||||
repeated AudioInfo audio_info = 3;
|
// Note that DASH IOP v3.0 explicitly mentions that a segment should only
|
||||||
repeated TextInfo text_info = 4;
|
// 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;
|
repeated ContentProtectionXml content_protections = 5;
|
||||||
|
|
||||||
// This is the reference time scale if there are multiple VideoInfo and/or
|
// This is the reference time scale if there are multiple VideoInfo and/or
|
||||||
|
|
|
@ -119,12 +119,12 @@ uint32_t GetTimeScale(const MediaInfo& media_info) {
|
||||||
return media_info.reference_time_scale();
|
return media_info.reference_time_scale();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media_info.video_info_size() > 0) {
|
if (media_info.has_video_info()) {
|
||||||
return media_info.video_info(0).time_scale();
|
return media_info.video_info().time_scale();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media_info.audio_info_size() > 0) {
|
if (media_info.has_audio_info()) {
|
||||||
return media_info.audio_info(0).time_scale();
|
return media_info.audio_info().time_scale();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(WARNING) << "No timescale specified, using 1 as timescale.";
|
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;
|
return (path.find(mpd_dir) == 0) ? path.substr(mpd_dir.size()) : path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether all the video infos have width and height.
|
// Check whether the video info has width and height.
|
||||||
// DASH IOP defines required fields for video representations, namely
|
// DASH IOP also requires several other fields for video representations, namely
|
||||||
// width, height, framerate, and sar.
|
// width, height, framerate, and sar.
|
||||||
bool HasRequiredVideoFields(
|
bool HasRequiredVideoFields(const MediaInfo_VideoInfo& video_info) {
|
||||||
::google::protobuf::RepeatedPtrField<MediaInfo_VideoInfo> video_infos) {
|
if (!video_info.has_height() || !video_info.has_width()) {
|
||||||
CHECK_GT(video_infos.size(), 0);
|
LOG(ERROR)
|
||||||
for (int i = 0; i < video_infos.size(); ++i) {
|
<< "Width and height are required fields for generating a valid MPD.";
|
||||||
const MediaInfo::VideoInfo& info = video_infos.Get(i);
|
return false;
|
||||||
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.";
|
|
||||||
}
|
}
|
||||||
|
// 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;
|
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
|
// For videos, record the width, height, and the frame rate to calculate the
|
||||||
// max {width,height,framerate} required for DASH IOP.
|
// max {width,height,framerate} required for DASH IOP.
|
||||||
if(media_info.video_info_size() > 0) {
|
if(media_info.has_video_info()) {
|
||||||
const MediaInfo::VideoInfo& video_info = media_info.video_info(0);
|
const MediaInfo::VideoInfo& video_info = media_info.video_info();
|
||||||
DCHECK(video_info.has_width());
|
DCHECK(video_info.has_width());
|
||||||
DCHECK(video_info.has_height());
|
DCHECK(video_info.has_height());
|
||||||
video_widths_.insert(video_info.width());
|
video_widths_.insert(video_info.width());
|
||||||
|
@ -642,8 +637,8 @@ bool Representation::Init() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool has_video_info = media_info_.video_info_size() > 0;
|
const bool has_video_info = media_info_.has_video_info();
|
||||||
const bool has_audio_info = media_info_.audio_info_size() > 0;
|
const bool has_audio_info = media_info_.has_audio_info();
|
||||||
|
|
||||||
if (!has_video_info && !has_audio_info) {
|
if (!has_video_info && !has_audio_info) {
|
||||||
// This is an error. Segment information can be in AdaptationSet, Period, or
|
// 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) {
|
void Representation::SetSampleDuration(uint32_t sample_duration) {
|
||||||
// Assume single video info.
|
// Assume single video info.
|
||||||
if (media_info_.video_info_size() > 0)
|
if (media_info_.has_video_info())
|
||||||
media_info_.mutable_video_info(0)->set_frame_duration(sample_duration);
|
media_info_.mutable_video_info()->set_frame_duration(sample_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses info in |media_info_| and |content_protection_elements_| to create a
|
// 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("codecs", codecs_);
|
||||||
representation.SetStringAttribute("mimeType", mime_type_);
|
representation.SetStringAttribute("mimeType", mime_type_);
|
||||||
|
|
||||||
const bool has_video_info = media_info_.video_info_size() > 0;
|
const bool has_video_info = media_info_.has_video_info();
|
||||||
const bool has_audio_info = media_info_.audio_info_size() > 0;
|
const bool has_audio_info = media_info_.has_audio_info();
|
||||||
|
|
||||||
if (has_video_info &&
|
if (has_video_info &&
|
||||||
!representation.AddVideoInfo(media_info_.video_info())) {
|
!representation.AddVideoInfo(media_info_.video_info())) {
|
||||||
|
|
|
@ -613,7 +613,7 @@ TEST_F(CommonMpdBuilderTest, SetSampleDuration) {
|
||||||
EXPECT_TRUE(representation.Init());
|
EXPECT_TRUE(representation.Init());
|
||||||
representation.SetSampleDuration(2u);
|
representation.SetSampleDuration(2u);
|
||||||
EXPECT_EQ(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.
|
// Add one video check the output.
|
||||||
|
|
|
@ -14,27 +14,6 @@
|
||||||
#include "packager/mpd/base/media_info.pb.h"
|
#include "packager/mpd/base/media_info.pb.h"
|
||||||
#include "packager/mpd/base/xml/scoped_xml_ptr.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 {
|
namespace edash_packager {
|
||||||
|
|
||||||
bool HasVODOnlyFields(const MediaInfo& media_info) {
|
bool HasVODOnlyFields(const MediaInfo& media_info) {
|
||||||
|
@ -63,20 +42,20 @@ void RemoveDuplicateAttributes(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetCodecs(const MediaInfo& media_info) {
|
std::string GetCodecs(const MediaInfo& media_info) {
|
||||||
std::string video_codecs;
|
std::string video_codec;
|
||||||
if (media_info.video_info_size() > 0)
|
if (media_info.has_video_info())
|
||||||
video_codecs = CodecsString(media_info.video_info());
|
video_codec = media_info.video_info().codec();
|
||||||
|
|
||||||
std::string audio_codecs;
|
std::string audio_codec;
|
||||||
if (media_info.audio_info_size() > 0)
|
if (media_info.has_audio_info())
|
||||||
audio_codecs = CodecsString(media_info.audio_info());
|
audio_codec = media_info.audio_info().codec();
|
||||||
|
|
||||||
if (!video_codecs.empty() && !audio_codecs.empty()) {
|
if (!video_codec.empty() && !audio_codec.empty()) {
|
||||||
return video_codecs + "," + audio_codecs;
|
return video_codec + "," + audio_codec;
|
||||||
} else if (!video_codecs.empty()) {
|
} else if (!video_codec.empty()) {
|
||||||
return video_codecs;
|
return video_codec;
|
||||||
} else if (!audio_codecs.empty()) {
|
} else if (!audio_codec.empty()) {
|
||||||
return audio_codecs;
|
return audio_codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -49,8 +49,8 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
|
||||||
// TODO(kqyang): Consider adding a new method MpdBuilder::AddRepresentation.
|
// TODO(kqyang): Consider adding a new method MpdBuilder::AddRepresentation.
|
||||||
// Most of the codes here can be moved inside.
|
// Most of the codes here can be moved inside.
|
||||||
std::string lang;
|
std::string lang;
|
||||||
if (media_info.audio_info().size() > 0) {
|
if (media_info.has_audio_info()) {
|
||||||
lang = media_info.audio_info(0).language();
|
lang = media_info.audio_info().language();
|
||||||
}
|
}
|
||||||
AdaptationSet** adaptation_set = &adaptation_set_map_[content_type][lang];
|
AdaptationSet** adaptation_set = &adaptation_set_map_[content_type][lang];
|
||||||
if (*adaptation_set == NULL)
|
if (*adaptation_set == NULL)
|
||||||
|
@ -110,9 +110,9 @@ bool SimpleMpdNotifier::AddContentProtectionElement(
|
||||||
|
|
||||||
SimpleMpdNotifier::ContentType SimpleMpdNotifier::GetContentType(
|
SimpleMpdNotifier::ContentType SimpleMpdNotifier::GetContentType(
|
||||||
const MediaInfo& media_info) {
|
const MediaInfo& media_info) {
|
||||||
const bool has_video = media_info.video_info().size() > 0;
|
const bool has_video = media_info.has_video_info();
|
||||||
const bool has_audio = media_info.audio_info().size() > 0;
|
const bool has_audio = media_info.has_audio_info();
|
||||||
const bool has_text = media_info.text_info().size() > 0;
|
const bool has_text = media_info.has_text_info();
|
||||||
|
|
||||||
if (MoreThanOneTrue(has_video, has_audio, has_text)) {
|
if (MoreThanOneTrue(has_video, has_audio, has_text)) {
|
||||||
NOTIMPLEMENTED() << "MediaInfo with more than one stream is not supported.";
|
NOTIMPLEMENTED() << "MediaInfo with more than one stream is not supported.";
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
using edash_packager::xml::XmlNode;
|
using edash_packager::xml::XmlNode;
|
||||||
|
|
||||||
using edash_packager::MediaInfo;
|
using edash_packager::MediaInfo;
|
||||||
|
typedef edash_packager::MediaInfo::AudioInfo AudioInfo;
|
||||||
|
typedef edash_packager::MediaInfo::VideoInfo VideoInfo;
|
||||||
typedef MediaInfo::ContentProtectionXml ContentProtectionXml;
|
typedef MediaInfo::ContentProtectionXml ContentProtectionXml;
|
||||||
typedef ContentProtectionXml::AttributeNameValuePair AttributeNameValuePair;
|
typedef ContentProtectionXml::AttributeNameValuePair AttributeNameValuePair;
|
||||||
|
|
||||||
|
@ -322,55 +324,27 @@ RepresentationXmlNode::RepresentationXmlNode()
|
||||||
: RepresentationBaseXmlNode("Representation") {}
|
: RepresentationBaseXmlNode("Representation") {}
|
||||||
RepresentationXmlNode::~RepresentationXmlNode() {}
|
RepresentationXmlNode::~RepresentationXmlNode() {}
|
||||||
|
|
||||||
bool RepresentationXmlNode::AddVideoInfo(
|
bool RepresentationXmlNode::AddVideoInfo(const VideoInfo& video_info) {
|
||||||
const RepeatedVideoInfo& repeated_video_info) {
|
if (!video_info.has_width() || !video_info.has_height()) {
|
||||||
uint32_t width = 0;
|
LOG(ERROR) << "Missing width or height for adding a video info.";
|
||||||
uint32_t height = 0;
|
return false;
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width != 0)
|
SetIntegerAttribute("width", video_info.width());
|
||||||
SetIntegerAttribute("width", width);
|
SetIntegerAttribute("height", video_info.height());
|
||||||
|
|
||||||
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);
|
|
||||||
SetStringAttribute("frameRate",
|
SetStringAttribute("frameRate",
|
||||||
base::IntToString(video_info.time_scale()) + "/" +
|
base::IntToString(video_info.time_scale()) + "/" +
|
||||||
base::IntToString(video_info.frame_duration()));
|
base::IntToString(video_info.frame_duration()));
|
||||||
|
|
||||||
SetStringAttribute("sar", base::IntToString(video_info.pixel_width()) + ":" +
|
SetStringAttribute("sar", base::IntToString(video_info.pixel_width()) + ":" +
|
||||||
base::IntToString(video_info.pixel_height()));
|
base::IntToString(video_info.pixel_height()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RepresentationXmlNode::AddAudioInfo(
|
bool RepresentationXmlNode::AddAudioInfo(const AudioInfo& audio_info) {
|
||||||
const RepeatedAudioInfo& repeated_audio_info) {
|
if (!AddAudioChannelInfo(audio_info))
|
||||||
if (!AddAudioChannelInfo(repeated_audio_info))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
AddAudioSamplingRateInfo(repeated_audio_info);
|
AddAudioSamplingRateInfo(audio_info);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,64 +440,24 @@ bool RepresentationXmlNode::AddLiveOnlyInfo(
|
||||||
AddChild(segment_template.PassScopedPtr());
|
AddChild(segment_template.PassScopedPtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all the unique number-of-channels in |repeated_audio_info|, and make
|
bool RepresentationXmlNode::AddAudioChannelInfo(const AudioInfo& audio_info) {
|
||||||
// AudioChannelConfiguration for each number-of-channels.
|
const uint32_t num_channels = audio_info.num_channels();
|
||||||
bool RepresentationXmlNode::AddAudioChannelInfo(
|
XmlNode audio_channel_config("AudioChannelConfiguration");
|
||||||
const RepeatedAudioInfo& repeated_audio_info) {
|
const char kAudioChannelConfigScheme[] =
|
||||||
std::set<uint32_t> num_channels;
|
"urn:mpeg:dash:23003:3:audio_channel_configuration:2011";
|
||||||
for (int i = 0; i < repeated_audio_info.size(); ++i) {
|
audio_channel_config.SetStringAttribute("schemeIdUri",
|
||||||
if (repeated_audio_info.Get(i).has_num_channels())
|
kAudioChannelConfigScheme);
|
||||||
num_channels.insert(repeated_audio_info.Get(i).num_channels());
|
audio_channel_config.SetIntegerAttribute("value", num_channels);
|
||||||
}
|
|
||||||
|
|
||||||
std::set<uint32_t>::const_iterator num_channels_it = num_channels.begin();
|
return AddChild(audio_channel_config.PassScopedPtr());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MPD expects one number for sampling frequency, or if it is a range it should
|
// MPD expects one number for sampling frequency, or if it is a range it should
|
||||||
// be space separated.
|
// be space separated.
|
||||||
void RepresentationXmlNode::AddAudioSamplingRateInfo(
|
void RepresentationXmlNode::AddAudioSamplingRateInfo(
|
||||||
const RepeatedAudioInfo& repeated_audio_info) {
|
const AudioInfo& audio_info) {
|
||||||
bool has_sampling_frequency = false;
|
if (audio_info.has_sampling_frequency())
|
||||||
uint32_t min_sampling_frequency = std::numeric_limits<uint32_t>::max();
|
SetIntegerAttribute("audioSamplingRate", audio_info.sampling_frequency());
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xml
|
} // namespace xml
|
||||||
|
|
|
@ -124,28 +124,20 @@ class AdaptationSetXmlNode : public RepresentationBaseXmlNode {
|
||||||
/// RepresentationType in MPD.
|
/// RepresentationType in MPD.
|
||||||
class RepresentationXmlNode : public RepresentationBaseXmlNode {
|
class RepresentationXmlNode : public RepresentationBaseXmlNode {
|
||||||
public:
|
public:
|
||||||
typedef ::google::protobuf::RepeatedPtrField<MediaInfo_VideoInfo>
|
|
||||||
RepeatedVideoInfo;
|
|
||||||
|
|
||||||
typedef ::google::protobuf::RepeatedPtrField<MediaInfo_AudioInfo>
|
|
||||||
RepeatedAudioInfo;
|
|
||||||
|
|
||||||
RepresentationXmlNode();
|
RepresentationXmlNode();
|
||||||
virtual ~RepresentationXmlNode();
|
virtual ~RepresentationXmlNode();
|
||||||
|
|
||||||
/// Adds video metadata to the MPD.
|
/// Adds video metadata to the MPD.
|
||||||
/// @param repeated_video_info constains the VideoInfos for Representation.
|
/// @param video_info constains the VideoInfo for a Representation.
|
||||||
/// Input of size 0 is valid.
|
|
||||||
/// @return true if successfully set attributes and children elements (if
|
/// @return true if successfully set attributes and children elements (if
|
||||||
/// applicable), false otherwise.
|
/// applicable), false otherwise.
|
||||||
bool AddVideoInfo(const RepeatedVideoInfo& repeated_video_info);
|
bool AddVideoInfo(const MediaInfo::VideoInfo& video_info);
|
||||||
|
|
||||||
/// Adds audio metadata to the MPD.
|
/// Adds audio metadata to the MPD.
|
||||||
/// @param repeated_audio_info constains the AudioInfos for Representation.
|
/// @param audio_info constains the AudioInfos for a Representation.
|
||||||
/// Input of size 0 is valid.
|
|
||||||
/// @return true if successfully set attributes and children elements (if
|
/// @return true if successfully set attributes and children elements (if
|
||||||
/// applicable), false otherwise.
|
/// 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
|
/// Adds fields that are specific to VOD. This ignores @a media_info fields
|
||||||
/// for Live.
|
/// for Live.
|
||||||
|
@ -160,13 +152,12 @@ class RepresentationXmlNode : public RepresentationBaseXmlNode {
|
||||||
uint32_t start_number);
|
uint32_t start_number);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Add AudioChannelConfiguration elements. This will add multiple
|
// Add AudioChannelConfiguration element. Note that it is a required element
|
||||||
// AudioChannelConfiguration if @a repeated_audio_info contains multiple
|
// for audio Representations.
|
||||||
// distinct channel configs (e.g. 2 channels and 6 channels adds 2 elements).
|
bool AddAudioChannelInfo(const MediaInfo::AudioInfo& audio_info);
|
||||||
bool AddAudioChannelInfo(const RepeatedAudioInfo& repeated_audio_info);
|
|
||||||
|
|
||||||
// Add audioSamplingRate attribute to this element.
|
// Add audioSamplingRate attribute to this element, if present.
|
||||||
void AddAudioSamplingRateInfo(const RepeatedAudioInfo& repeated_audio_info);
|
void AddAudioSamplingRateInfo(const MediaInfo::AudioInfo& audio_info);
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(RepresentationXmlNode);
|
DISALLOW_COPY_AND_ASSIGN(RepresentationXmlNode);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,17 +17,6 @@ using edash_packager::media::File;
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
|
||||||
namespace {
|
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 entry set |has_video|, |has_audio|, and |has_text| to false.
|
||||||
// On success, return true and set appropriate |has_*| variables. Otherwise
|
// 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 != media_infos.end();
|
||||||
++it) {
|
++it) {
|
||||||
const MediaInfo& media_info = *it;
|
const MediaInfo& media_info = *it;
|
||||||
const bool media_info_has_video = HasVideo(media_info);
|
const bool media_info_has_video = media_info.has_video_info();
|
||||||
const bool media_info_has_audio = HasAudio(media_info);
|
const bool media_info_has_audio = media_info.has_audio_info();
|
||||||
const bool media_info_has_text = HasText(media_info);
|
const bool media_info_has_text = media_info.has_text_info();
|
||||||
|
|
||||||
if (MoreThanOneTrue(
|
if (MoreThanOneTrue(
|
||||||
media_info_has_video, media_info_has_audio, media_info_has_text)) {
|
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 != media_infos.end();
|
||||||
++it) {
|
++it) {
|
||||||
const MediaInfo& media_info = *it;
|
const MediaInfo& media_info = *it;
|
||||||
DCHECK(OnlyOneTrue(
|
DCHECK(OnlyOneTrue(media_info.has_video_info(),
|
||||||
HasVideo(media_info), HasAudio(media_info), HasText(media_info)));
|
media_info.has_audio_info(),
|
||||||
|
media_info.has_text_info()));
|
||||||
|
|
||||||
std::string lang;
|
std::string lang;
|
||||||
AdaptationSet** adaptation_set = NULL;
|
AdaptationSet** adaptation_set = NULL;
|
||||||
if (HasVideo(media_info)) {
|
if (media_info.has_video_info()) {
|
||||||
adaptation_set = &map["video"][lang];
|
adaptation_set = &map["video"][lang];
|
||||||
} else if (HasAudio(media_info)) {
|
} else if (media_info.has_audio_info()) {
|
||||||
lang = media_info.audio_info(0).language();
|
lang = media_info.audio_info().language();
|
||||||
adaptation_set = &map["audio"][lang];
|
adaptation_set = &map["audio"][lang];
|
||||||
} else if (HasText(media_info)) {
|
} else if (media_info.has_text_info()) {
|
||||||
adaptation_set = &map["text"][lang];
|
adaptation_set = &map["text"][lang];
|
||||||
}
|
}
|
||||||
if (!*adaptation_set) {
|
if (!*adaptation_set) {
|
||||||
|
|
Loading…
Reference in New Issue