Implement MpdNotifyMuxerListener

Change-Id: I08742839c2be5e5da104914ec841b8c5dd57f0b7
This commit is contained in:
KongQun Yang 2014-05-16 16:32:10 -07:00 committed by Kongqun Yang
parent 1899d5c3b0
commit 6837ac45b7
12 changed files with 256 additions and 229 deletions

View File

@ -15,44 +15,72 @@
#include "mpd/base/media_info.pb.h" #include "mpd/base/media_info.pb.h"
#include "mpd/base/mpd_notifier.h" #include "mpd/base/mpd_notifier.h"
using dash_packager::MediaInfo;
namespace media { namespace media {
namespace event { namespace event {
MpdNotifyMuxerListener::MpdNotifyMuxerListener( MpdNotifyMuxerListener::MpdNotifyMuxerListener(
dash_packager::MpdNotifier* mpd_notifier) dash_packager::MpdNotifier* mpd_notifier)
: mpd_notifier_(mpd_notifier), : mpd_notifier_(mpd_notifier),
reference_time_scale_(0), notification_id_(0) {
container_type_(kContainerUnknown) {
DCHECK(mpd_notifier); DCHECK(mpd_notifier);
DCHECK(mpd_notifier->dash_profile() == dash_packager::kOnDemandProfile ||
mpd_notifier->dash_profile() == dash_packager::kLiveProfile);
} }
MpdNotifyMuxerListener::~MpdNotifyMuxerListener() {} MpdNotifyMuxerListener::~MpdNotifyMuxerListener() {}
void MpdNotifyMuxerListener::SetContentProtectionSchemeIdUri(
const std::string& scheme_id_uri) {
scheme_id_uri_ = scheme_id_uri;
}
void MpdNotifyMuxerListener::OnMediaStart( void MpdNotifyMuxerListener::OnMediaStart(
const MuxerOptions& muxer_options, const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos, const std::vector<StreamInfo*>& stream_infos,
uint32 time_scale, uint32 time_scale,
ContainerType container_type) { ContainerType container_type,
muxer_options_ = muxer_options; bool is_encrypted) {
reference_time_scale_ = time_scale; scoped_ptr<MediaInfo> media_info(new MediaInfo());
container_type_ = container_type; if (!internal::GenerateMediaInfo(muxer_options,
stream_infos,
time_scale,
container_type,
media_info.get())) {
LOG(ERROR) << "Failed to generate MediaInfo from input.";
return;
}
if (is_encrypted) {
if (!internal::AddContentProtectionElements(
container_type, scheme_id_uri_, media_info.get())) {
LOG(ERROR) << "Failed to add content protection elements.";
return;
}
}
if (mpd_notifier_->dash_profile() == dash_packager::kLiveProfile) {
// TODO(kqyang): Check return result.
mpd_notifier_->NotifyNewContainer(*media_info, &notification_id_);
} else {
media_info_ = media_info.Pass();
}
} }
void MpdNotifyMuxerListener::OnMediaEnd( void MpdNotifyMuxerListener::OnMediaEnd(bool has_init_range,
const std::vector<StreamInfo*>& stream_infos,
bool has_init_range,
uint64 init_range_start, uint64 init_range_start,
uint64 init_range_end, uint64 init_range_end,
bool has_index_range, bool has_index_range,
uint64 index_range_start, uint64 index_range_start,
uint64 index_range_end, uint64 index_range_end,
float duration_seconds, float duration_seconds,
uint64 file_size, uint64 file_size) {
bool is_encrypted) { if (mpd_notifier_->dash_profile() == dash_packager::kLiveProfile)
dash_packager::MediaInfo media_info; return;
if (!internal::GenerateMediaInfo(muxer_options_,
stream_infos, DCHECK(media_info_);
has_init_range, if (!internal::SetVodInformation(has_init_range,
init_range_start, init_range_start,
init_range_end, init_range_end,
has_index_range, has_index_range,
@ -60,20 +88,24 @@ void MpdNotifyMuxerListener::OnMediaEnd(
index_range_end, index_range_end,
duration_seconds, duration_seconds,
file_size, file_size,
reference_time_scale_, media_info_.get())) {
container_type_, LOG(ERROR) << "Failed to generate VOD information from input.";
&media_info)) {
LOG(ERROR) << "Failed to generate MediaInfo from input.";
return; return;
} }
uint32 id; // Result unused. uint32 id; // Result unused.
mpd_notifier_->NotifyNewContainer(media_info, &id); // TODO(kqyang): Check return result.
mpd_notifier_->NotifyNewContainer(*media_info_, &id);
} }
void MpdNotifyMuxerListener::OnNewSegment(uint64 start_time, void MpdNotifyMuxerListener::OnNewSegment(uint64 start_time,
uint64 duration, uint64 duration,
uint64 segment_file_size) {} uint64 segment_file_size) {
if (mpd_notifier_->dash_profile() != dash_packager::kLiveProfile)
return;
// TODO(kqyang): Check return result.
mpd_notifier_->NotifyNewSegment(notification_id_, start_time, duration);
}
} // namespace event } // namespace event
} // namespace media } // namespace media

View File

@ -12,10 +12,12 @@
#include <vector> #include <vector>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/muxer_options.h" #include "media/base/muxer_options.h"
#include "media/event/muxer_listener.h" #include "media/event/muxer_listener.h"
namespace dash_packager { namespace dash_packager {
class MediaInfo;
class MpdNotifier; class MpdNotifier;
} // namespace dash_packager } // namespace dash_packager
@ -24,37 +26,42 @@ namespace event {
class MpdNotifyMuxerListener : public MuxerListener { class MpdNotifyMuxerListener : public MuxerListener {
public: public:
// |mpd_notifier| must be initialized, i.e mpd_notifier->Init() must be /// @param mpd_notifier must be initialized, i.e mpd_notifier->Init() must be
// called. /// called.
MpdNotifyMuxerListener(dash_packager::MpdNotifier* mpd_notifier); MpdNotifyMuxerListener(dash_packager::MpdNotifier* mpd_notifier);
virtual ~MpdNotifyMuxerListener(); virtual ~MpdNotifyMuxerListener();
// MuxerListener implementation. /// If the stream is encrypted use this as 'schemeIdUri' attribute for
/// ContentProtection element.
void SetContentProtectionSchemeIdUri(const std::string& scheme_id_uri);
/// @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 std::vector<StreamInfo*>& stream_infos,
uint32 time_scale, uint32 time_scale,
ContainerType container_type) OVERRIDE; ContainerType container_type,
bool is_encrypted) OVERRIDE;
virtual void OnMediaEnd(const std::vector<StreamInfo*>& stream_infos, virtual void OnMediaEnd(bool has_init_range,
bool has_init_range,
uint64 init_range_start, uint64 init_range_start,
uint64 init_range_end, uint64 init_range_end,
bool has_index_range, bool has_index_range,
uint64 index_range_start, uint64 index_range_start,
uint64 index_range_end, uint64 index_range_end,
float duration_seconds, float duration_seconds,
uint64 file_size, uint64 file_size) OVERRIDE;
bool is_encrypted) OVERRIDE;
virtual void OnNewSegment(uint64 start_time, virtual void OnNewSegment(uint64 start_time,
uint64 duration, uint64 duration,
uint64 segment_file_size) OVERRIDE; uint64 segment_file_size) OVERRIDE;
/// @}
private: private:
dash_packager::MpdNotifier* const mpd_notifier_; dash_packager::MpdNotifier* const mpd_notifier_;
MuxerOptions muxer_options_; uint32 notification_id_;
uint32 reference_time_scale_; scoped_ptr<dash_packager::MediaInfo> media_info_;
ContainerType container_type_; std::string scheme_id_uri_;
DISALLOW_COPY_AND_ASSIGN(MpdNotifyMuxerListener); DISALLOW_COPY_AND_ASSIGN(MpdNotifyMuxerListener);
}; };

View File

@ -39,7 +39,8 @@ class MuxerListener {
virtual void OnMediaStart(const MuxerOptions& muxer_options, virtual void OnMediaStart(const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos, const std::vector<StreamInfo*>& stream_infos,
uint32 time_scale, uint32 time_scale,
ContainerType container_type) = 0; ContainerType container_type,
bool is_encrypted) = 0;
// Called when all files are written out and the muxer object does not output // Called when all files are written out and the muxer object does not output
// any more files. // any more files.
@ -51,16 +52,14 @@ class MuxerListener {
// Both ranges are inclusive. // Both ranges are inclusive.
// Media length of |duration_seconds|. // Media length of |duration_seconds|.
// |file_size| of the media in bytes. // |file_size| of the media in bytes.
virtual void OnMediaEnd(const std::vector<StreamInfo*>& stream_infos, virtual void OnMediaEnd(bool has_init_range,
bool has_init_range,
uint64 init_range_start, uint64 init_range_start,
uint64 init_range_end, uint64 init_range_end,
bool has_index_range, bool has_index_range,
uint64 index_range_start, uint64 index_range_start,
uint64 index_range_end, uint64 index_range_end,
float duration_seconds, float duration_seconds,
uint64 file_size, uint64 file_size) = 0;
bool is_encrypted) = 0;
// Called when a segment has been muxed and the file has been written. // Called when a segment has been muxed and the file has been written.
// Note: For video on demand (VOD), this would be for subsegments. // Note: For video on demand (VOD), this would be for subsegments.

View File

@ -81,23 +81,6 @@ void SetMediaInfoContainerType(MuxerListener::ContainerType container_type,
} }
} }
void SetMediaInfoCommonInfo(float duration_seconds,
uint64 file_size,
uint32 reference_time_scale,
MuxerListener::ContainerType container_type,
MediaInfo* media_info) {
DCHECK(media_info);
DCHECK_GT(file_size, 0u);
DCHECK_GT(duration_seconds, 0.0f);
media_info->set_media_duration_seconds(duration_seconds);
media_info->set_bandwidth(
EstimateRequiredBandwidth(file_size, duration_seconds));
media_info->set_reference_time_scale(reference_time_scale);
SetMediaInfoContainerType(container_type, media_info);
}
void AddVideoInfo(const VideoStreamInfo* video_stream_info, void AddVideoInfo(const VideoStreamInfo* video_stream_info,
MediaInfo* media_info) { MediaInfo* media_info) {
DCHECK(video_stream_info); DCHECK(video_stream_info);
@ -160,14 +143,32 @@ void SetMediaInfoStreamInfo(const std::vector<StreamInfo*>& stream_infos,
void SetMediaInfoMuxerOptions(const MuxerOptions& muxer_options, void SetMediaInfoMuxerOptions(const MuxerOptions& muxer_options,
MediaInfo* media_info) { MediaInfo* media_info) {
DCHECK(media_info); DCHECK(media_info);
if (muxer_options.single_segment) {
media_info->set_media_file_name(muxer_options.output_file_name); media_info->set_media_file_name(muxer_options.output_file_name);
DCHECK(muxer_options.segment_template.empty());
} else {
media_info->set_init_segment_name(muxer_options.output_file_name);
media_info->set_segment_template(muxer_options.segment_template);
}
} }
} // namespace } // namespace
bool GenerateMediaInfo(const MuxerOptions& muxer_options, bool GenerateMediaInfo(const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos, const std::vector<StreamInfo*>& stream_infos,
bool has_init_range, uint32 reference_time_scale,
MuxerListener::ContainerType container_type,
MediaInfo* media_info) {
DCHECK(media_info);
SetMediaInfoMuxerOptions(muxer_options, media_info);
SetMediaInfoStreamInfo(stream_infos, media_info);
media_info->set_reference_time_scale(reference_time_scale);
SetMediaInfoContainerType(container_type, media_info);
return true;
}
bool SetVodInformation(bool has_init_range,
uint64 init_range_start, uint64 init_range_start,
uint64 init_range_end, uint64 init_range_end,
bool has_index_range, bool has_index_range,
@ -175,8 +176,6 @@ bool GenerateMediaInfo(const MuxerOptions& muxer_options,
uint64 index_range_end, uint64 index_range_end,
float duration_seconds, float duration_seconds,
uint64 file_size, uint64 file_size,
uint32 reference_time_scale,
MuxerListener::ContainerType container_type,
MediaInfo* media_info) { MediaInfo* media_info) {
DCHECK(media_info); DCHECK(media_info);
if (file_size == 0) { if (file_size == 0) {
@ -187,10 +186,9 @@ bool GenerateMediaInfo(const MuxerOptions& muxer_options,
if (duration_seconds <= 0.0f) { if (duration_seconds <= 0.0f) {
// Non positive second media must be invalid media. // Non positive second media must be invalid media.
LOG(ERROR) << "Duration is not positive: " << duration_seconds; LOG(ERROR) << "Duration is not positive: " << duration_seconds;
return false;; return false;
} }
SetMediaInfoMuxerOptions(muxer_options, media_info);
SetMediaInfoRanges(has_init_range, SetMediaInfoRanges(has_init_range,
init_range_start, init_range_start,
init_range_end, init_range_end,
@ -198,14 +196,48 @@ bool GenerateMediaInfo(const MuxerOptions& muxer_options,
index_range_start, index_range_start,
index_range_end, index_range_end,
media_info); media_info);
SetMediaInfoCommonInfo(duration_seconds,
file_size, media_info->set_media_duration_seconds(duration_seconds);
reference_time_scale, media_info->set_bandwidth(
container_type, EstimateRequiredBandwidth(file_size, duration_seconds));
media_info);
SetMediaInfoStreamInfo(stream_infos, media_info);
return true; return true;
}; }
bool AddContentProtectionElements(MuxerListener::ContainerType container_type,
const std::string& user_scheme_id_uri,
MediaInfo* media_info) {
DCHECK(media_info);
const char kEncryptedMp4Uri[] = "urn:mpeg:dash:mp4protection:2011";
const char kEncryptedMp4Value[] = "cenc";
// DASH MPD spec specifies a default ContentProtection element for ISO BMFF
// (MP4) files.
const bool is_mp4_container = container_type == MuxerListener::kContainerMp4;
if (is_mp4_container) {
MediaInfo::ContentProtectionXml* mp4_protection =
media_info->add_content_protections();
mp4_protection->set_scheme_id_uri(kEncryptedMp4Uri);
mp4_protection->set_value(kEncryptedMp4Value);
}
if (!user_scheme_id_uri.empty()) {
MediaInfo::ContentProtectionXml* content_protection =
media_info->add_content_protections();
content_protection->set_scheme_id_uri(user_scheme_id_uri);
} else if (is_mp4_container) {
LOG(WARNING) << "schemeIdUri is not specified. Added default "
"ContentProtection only.";
}
if (media_info->content_protections_size() == 0) {
LOG(ERROR) << "The stream is encrypted but no schemeIdUri specified for "
"ContentProtection.";
return false;
}
return true;
}
} // namespace internal } // namespace internal
} // namespace event } // namespace event

View File

@ -7,6 +7,7 @@
#ifndef MEDIA_EVENT_MUXER_LISTENER_INTERNAL_H_ #ifndef MEDIA_EVENT_MUXER_LISTENER_INTERNAL_H_
#define MEDIA_EVENT_MUXER_LISTENER_INTERNAL_H_ #define MEDIA_EVENT_MUXER_LISTENER_INTERNAL_H_
#include <string>
#include <vector> #include <vector>
#include "base/basictypes.h" #include "base/basictypes.h"
@ -24,11 +25,17 @@ struct MuxerOptions;
namespace event { namespace event {
namespace internal { namespace internal {
// On success fill |media_info| with input data and return true, otherwise /// @param[out] media_info points to the MediaInfo object to be filled.
// return false. /// @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 std::vector<StreamInfo*>& stream_infos,
bool has_init_range, uint32 reference_time_scale_,
MuxerListener::ContainerType container_type,
dash_packager::MediaInfo* media_info);
/// @param[in,out] media_info points to the MediaInfo object to be filled.
/// @return true on success, false otherwise.
bool SetVodInformation(bool has_init_range,
uint64 init_range_start, uint64 init_range_start,
uint64 init_range_end, uint64 init_range_end,
bool has_index_range, bool has_index_range,
@ -36,8 +43,15 @@ bool GenerateMediaInfo(const MuxerOptions& muxer_options,
uint64 index_range_end, uint64 index_range_end,
float duration_seconds, float duration_seconds,
uint64 file_size, uint64 file_size,
uint32 reference_time_scale_, dash_packager::MediaInfo* media_info);
MuxerListener::ContainerType container_type,
/// @param container_type specifies container type. A default ContentProtection
/// element will be added if the container is MP4.
/// @param user_scheme_id_uri is the user specified schemeIdUri for
/// ContentProtection.
/// @return true if a ContentProtectionXml is added, false otherwise.
bool AddContentProtectionElements(MuxerListener::ContainerType container_type,
const std::string& user_scheme_id_uri,
dash_packager::MediaInfo* media_info); dash_packager::MediaInfo* media_info);
} // namespace internal } // namespace internal

View File

@ -19,54 +19,8 @@ namespace event {
using dash_packager::MediaInfo; using dash_packager::MediaInfo;
namespace {
const char kEncryptedMp4Uri[] = "urn:mpeg:dash:mp4protection:2011";
const char kEncryptedMp4Value[] = "cenc";
// |user_scheme_id_uri| is the user specified schemeIdUri for ContentProtection.
// This adds a default ContentProtection element if the container is MP4.
// Returns true if a ContentProtectionXml is added to |media_info|, otherwise
// false.
bool AddContentProtectionElements(MuxerListener::ContainerType container_type,
const std::string& user_scheme_id_uri,
MediaInfo* media_info) {
DCHECK(media_info);
// DASH MPD spec specifies a default ContentProtection element for ISO BMFF
// (MP4) files.
const bool is_mp4_container = container_type == MuxerListener::kContainerMp4;
if (is_mp4_container) {
MediaInfo::ContentProtectionXml* mp4_protection =
media_info->add_content_protections();
mp4_protection->set_scheme_id_uri(kEncryptedMp4Uri);
mp4_protection->set_value(kEncryptedMp4Value);
}
if (!user_scheme_id_uri.empty()) {
MediaInfo::ContentProtectionXml* content_protection =
media_info->add_content_protections();
content_protection->set_scheme_id_uri(user_scheme_id_uri);
} else if (is_mp4_container) {
LOG(WARNING) << "schemeIdUri is not specified. Added default "
"ContentProtection only.";
}
if (media_info->content_protections_size() == 0) {
LOG(ERROR) << "The stream is encrypted but no schemeIdUri specified for "
"ContentProtection.";
return false;
}
return true;
}
} // namespace
VodMediaInfoDumpMuxerListener::VodMediaInfoDumpMuxerListener(File* output_file) VodMediaInfoDumpMuxerListener::VodMediaInfoDumpMuxerListener(File* output_file)
: file_(output_file), : file_(output_file) {}
reference_time_scale_(0),
container_type_(kContainerUnknown) {}
VodMediaInfoDumpMuxerListener::~VodMediaInfoDumpMuxerListener() {} VodMediaInfoDumpMuxerListener::~VodMediaInfoDumpMuxerListener() {}
@ -79,27 +33,38 @@ void VodMediaInfoDumpMuxerListener::OnMediaStart(
const MuxerOptions& muxer_options, const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos, const std::vector<StreamInfo*>& stream_infos,
uint32 time_scale, uint32 time_scale,
ContainerType container_type) { ContainerType container_type,
muxer_options_ = muxer_options; bool is_encrypted) {
reference_time_scale_ = time_scale; DCHECK(muxer_options.single_segment);
container_type_ = container_type; media_info_.reset(new MediaInfo());
if (!internal::GenerateMediaInfo(muxer_options,
stream_infos,
time_scale,
container_type,
media_info_.get())) {
LOG(ERROR) << "Failed to generate MediaInfo from input.";
return;
}
if (is_encrypted) {
if (!internal::AddContentProtectionElements(
container_type, scheme_id_uri_, media_info_.get())) {
LOG(ERROR) << "Failed to add content protection elements.";
return;
}
}
} }
void VodMediaInfoDumpMuxerListener::OnMediaEnd( void VodMediaInfoDumpMuxerListener::OnMediaEnd(bool has_init_range,
const std::vector<StreamInfo*>& stream_infos,
bool has_init_range,
uint64 init_range_start, uint64 init_range_start,
uint64 init_range_end, uint64 init_range_end,
bool has_index_range, bool has_index_range,
uint64 index_range_start, uint64 index_range_start,
uint64 index_range_end, uint64 index_range_end,
float duration_seconds, float duration_seconds,
uint64 file_size, uint64 file_size) {
bool is_encrypted) { DCHECK(media_info_);
MediaInfo media_info; if (!internal::SetVodInformation(has_init_range,
if (!internal::GenerateMediaInfo(muxer_options_,
stream_infos,
has_init_range,
init_range_start, init_range_start,
init_range_end, init_range_end,
has_index_range, has_index_range,
@ -107,22 +72,11 @@ void VodMediaInfoDumpMuxerListener::OnMediaEnd(
index_range_end, index_range_end,
duration_seconds, duration_seconds,
file_size, file_size,
reference_time_scale_, media_info_.get())) {
container_type_, LOG(ERROR) << "Failed to generate VOD information from input.";
&media_info)) {
LOG(ERROR) << "Failed to generate MediaInfo from input.";
return; return;
} }
SerializeMediaInfoToFile();
if (is_encrypted) {
if (!AddContentProtectionElements(
container_type_, scheme_id_uri_, &media_info)) {
LOG(ERROR) << "Failed to add content protection elements.";
return;
}
}
SerializeMediaInfoToFile(media_info);
} }
void VodMediaInfoDumpMuxerListener::OnNewSegment(uint64 start_time, void VodMediaInfoDumpMuxerListener::OnNewSegment(uint64 start_time,
@ -131,10 +85,9 @@ void VodMediaInfoDumpMuxerListener::OnNewSegment(uint64 start_time,
NOTIMPLEMENTED(); NOTIMPLEMENTED();
} }
void VodMediaInfoDumpMuxerListener::SerializeMediaInfoToFile( void VodMediaInfoDumpMuxerListener::SerializeMediaInfoToFile() {
const MediaInfo& media_info) {
std::string output_string; std::string output_string;
if (!google::protobuf::TextFormat::PrintToString(media_info, if (!google::protobuf::TextFormat::PrintToString(*media_info_,
&output_string)) { &output_string)) {
LOG(ERROR) << "Failed to serialize MediaInfo to string."; LOG(ERROR) << "Failed to serialize MediaInfo to string.";
return; return;

View File

@ -15,6 +15,7 @@
#include <vector> #include <vector>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/muxer_options.h" #include "media/base/muxer_options.h"
#include "media/event/muxer_listener.h" #include "media/event/muxer_listener.h"
@ -44,31 +45,28 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
virtual void OnMediaStart(const MuxerOptions& muxer_options, virtual void OnMediaStart(const MuxerOptions& muxer_options,
const std::vector<StreamInfo*>& stream_infos, const std::vector<StreamInfo*>& stream_infos,
uint32 time_scale, uint32 time_scale,
ContainerType container_type) OVERRIDE; ContainerType container_type,
bool is_encrypted) OVERRIDE;
virtual void OnMediaEnd(const std::vector<StreamInfo*>& stream_infos, virtual void OnMediaEnd(bool has_init_range,
bool has_init_range,
uint64 init_range_start, uint64 init_range_start,
uint64 init_range_end, uint64 init_range_end,
bool has_index_range, bool has_index_range,
uint64 index_range_start, uint64 index_range_start,
uint64 index_range_end, uint64 index_range_end,
float duration_seconds, float duration_seconds,
uint64 file_size, uint64 file_size) OVERRIDE;
bool is_encrypted) OVERRIDE;
virtual void OnNewSegment(uint64 start_time, virtual void OnNewSegment(uint64 start_time,
uint64 duration, uint64 duration,
uint64 segment_file_size) OVERRIDE; uint64 segment_file_size) OVERRIDE;
private: private:
// Write |media_info| to |file_|. // Write |media_info_| to |file_|.
void SerializeMediaInfoToFile(const dash_packager::MediaInfo& media_info); void SerializeMediaInfoToFile();
File* file_; File* file_;
std::string scheme_id_uri_; std::string scheme_id_uri_;
MuxerOptions muxer_options_; scoped_ptr<dash_packager::MediaInfo> media_info_;
uint32 reference_time_scale_;
ContainerType container_type_;
DISALLOW_COPY_AND_ASSIGN(VodMediaInfoDumpMuxerListener); DISALLOW_COPY_AND_ASSIGN(VodMediaInfoDumpMuxerListener);
}; };

View File

@ -19,6 +19,10 @@
using dash_packager::MediaInfo; using dash_packager::MediaInfo;
namespace {
const bool kEnableEncryption = true;
} // namespace
namespace media { namespace media {
namespace event { namespace event {
@ -47,7 +51,6 @@ struct OnMediaEndParameters {
uint64 index_range_end; uint64 index_range_end;
float duration_seconds; float duration_seconds;
uint64 file_size; uint64 file_size;
bool is_encrypted;
}; };
scoped_refptr<StreamInfo> CreateVideoStreamInfo( scoped_refptr<StreamInfo> CreateVideoStreamInfo(
@ -109,7 +112,7 @@ OnMediaEndParameters GetDefaultOnMediaEndParams() {
} }
void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) { void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) {
muxer_options->single_segment = false; muxer_options->single_segment = true;
muxer_options->segment_duration = 10.0; muxer_options->segment_duration = 10.0;
muxer_options->fragment_duration = 10.0; muxer_options->fragment_duration = 10.0;
muxer_options->segment_sap_aligned = true; muxer_options->segment_sap_aligned = true;
@ -149,7 +152,7 @@ void ExpectTextFormatMediaInfoEqual(const std::string& expect,
class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test { class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
public: public:
VodMediaInfoDumpMuxerListenerTest() {} VodMediaInfoDumpMuxerListenerTest() : temp_file_(NULL) {}
virtual ~VodMediaInfoDumpMuxerListenerTest() {} virtual ~VodMediaInfoDumpMuxerListenerTest() {}
virtual void SetUp() OVERRIDE { virtual void SetUp() OVERRIDE {
@ -165,30 +168,29 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
base::DeleteFile(temp_file_path_, false); base::DeleteFile(temp_file_path_, false);
} }
void FireOnMediaStartWithDefaultValues( void FireOnMediaStartWithDefaultMuxerOptions(
const std::vector<StreamInfo*> stream_infos) { const std::vector<StreamInfo*> stream_infos,
bool enable_encryption) {
MuxerOptions muxer_options; MuxerOptions muxer_options;
SetDefaultMuxerOptionsValues(&muxer_options); SetDefaultMuxerOptionsValues(&muxer_options);
const uint32 kReferenceTimeScale = 1000; const uint32 kReferenceTimeScale = 1000;
listener_->OnMediaStart(muxer_options, listener_->OnMediaStart(muxer_options,
stream_infos, stream_infos,
kReferenceTimeScale, kReferenceTimeScale,
MuxerListener::kContainerMp4); MuxerListener::kContainerMp4,
enable_encryption);
} }
void FireOnMediaEndWithParams(const std::vector<StreamInfo*> stream_infos, void FireOnMediaEndWithParams(const OnMediaEndParameters& params) {
const OnMediaEndParameters& params) {
// On success, this writes the result to |temp_file_|. // On success, this writes the result to |temp_file_|.
listener_->OnMediaEnd(stream_infos, listener_->OnMediaEnd(params.has_init_range,
params.has_init_range,
params.init_range_start, params.init_range_start,
params.init_range_end, params.init_range_end,
params.has_index_range, params.has_index_range,
params.index_range_start, params.index_range_start,
params.index_range_end, params.index_range_end,
params.duration_seconds, params.duration_seconds,
params.file_size, params.file_size);
params.is_encrypted);
} }
void ExpectTempFileToEqual(const std::string& expected_protobuf) { void ExpectTempFileToEqual(const std::string& expected_protobuf) {
@ -216,10 +218,9 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) {
std::vector<StreamInfo*> stream_infos; std::vector<StreamInfo*> stream_infos;
stream_infos.push_back(stream_info.get()); stream_infos.push_back(stream_info.get());
FireOnMediaStartWithDefaultValues(stream_infos); FireOnMediaStartWithDefaultMuxerOptions(stream_infos, !kEnableEncryption);
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams(); OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
media_end_param.is_encrypted = false; FireOnMediaEndWithParams(media_end_param);
FireOnMediaEndWithParams(stream_infos, media_end_param);
ASSERT_TRUE(temp_file_->Close()); ASSERT_TRUE(temp_file_->Close());
const char kExpectedProtobufOutput[] = const char kExpectedProtobufOutput[] =
@ -253,11 +254,10 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
std::vector<StreamInfo*> stream_infos; std::vector<StreamInfo*> stream_infos;
stream_infos.push_back(stream_info.get()); stream_infos.push_back(stream_info.get());
FireOnMediaStartWithDefaultValues(stream_infos); FireOnMediaStartWithDefaultMuxerOptions(stream_infos, kEnableEncryption);
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams(); OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
media_end_param.is_encrypted = true; FireOnMediaEndWithParams(media_end_param);
FireOnMediaEndWithParams(stream_infos, media_end_param);
ASSERT_TRUE(temp_file_->Close()); ASSERT_TRUE(temp_file_->Close());
const char kExpectedProtobufOutput[] = const char kExpectedProtobufOutput[] =

View File

@ -241,16 +241,14 @@ void MP4Muxer::FireOnMediaStartEvent() {
muxer_listener()->OnMediaStart(options(), muxer_listener()->OnMediaStart(options(),
stream_info_vec, stream_info_vec,
timescale, timescale,
event::MuxerListener::kContainerMp4); event::MuxerListener::kContainerMp4,
encryption_key_source());
} }
void MP4Muxer::FireOnMediaEndEvent() { void MP4Muxer::FireOnMediaEndEvent() {
if (!muxer_listener()) if (!muxer_listener())
return; return;
std::vector<StreamInfo*> stream_info_vec;
GetStreamInfo(&stream_info_vec);
uint32 init_range_start = 0; uint32 init_range_start = 0;
uint32 init_range_end = 0; uint32 init_range_end = 0;
const bool has_init_range = const bool has_init_range =
@ -269,16 +267,14 @@ void MP4Muxer::FireOnMediaEndEvent() {
return; return;
} }
muxer_listener()->OnMediaEnd(stream_info_vec, muxer_listener()->OnMediaEnd(has_init_range,
has_init_range,
init_range_start, init_range_start,
init_range_end, init_range_end,
has_index_range, has_index_range,
index_range_start, index_range_start,
index_range_end, index_range_end,
duration_seconds, duration_seconds,
file_size, file_size);
encryption_key_source());
} }
uint64 MP4Muxer::IsoTimeNow() { uint64 MP4Muxer::IsoTimeNow() {

View File

@ -17,11 +17,17 @@ namespace dash_packager {
class MediaInfo; class MediaInfo;
struct ContentProtectionElement; struct ContentProtectionElement;
enum DashProfile {
kUnknownProfile,
kOnDemandProfile,
kLiveProfile,
};
/// Interface for publish/subscribe publisher class which notifies MpdBuilder /// Interface for publish/subscribe publisher class which notifies MpdBuilder
/// of media-related events. /// of media-related events.
class MpdNotifier { class MpdNotifier {
public: public:
MpdNotifier() {}; MpdNotifier(DashProfile dash_profile) : dash_profile_(dash_profile) {};
virtual ~MpdNotifier() {}; virtual ~MpdNotifier() {};
/// Initializes the notifier. For example, if this notifier uses a network for /// Initializes the notifier. For example, if this notifier uses a network for
@ -62,6 +68,14 @@ class MpdNotifier {
virtual bool AddContentProtectionElement( virtual bool AddContentProtectionElement(
uint32 container_id, uint32 container_id,
const ContentProtectionElement& content_protection_element) = 0; const ContentProtectionElement& content_protection_element) = 0;
/// @return The dash profile for this object.
DashProfile dash_profile() const { return dash_profile_; }
private:
const DashProfile dash_profile_;
DISALLOW_COPY_AND_ASSIGN(MpdNotifier);
}; };
} // namespace dash_packager } // namespace dash_packager

View File

@ -25,9 +25,17 @@ bool AtLeastOneTrue(bool b1, bool b2, bool b3) {
namespace dash_packager { namespace dash_packager {
SimpleMpdNotifier::SimpleMpdNotifier(const std::vector<std::string>& base_urls, SimpleMpdNotifier::SimpleMpdNotifier(DashProfile dash_profile,
const std::vector<std::string>& base_urls,
const std::string& output_path) const std::string& output_path)
: base_urls_(base_urls), output_path_(output_path) { : MpdNotifier(dash_profile),
output_path_(output_path),
mpd_builder_(new MpdBuilder(dash_profile == kLiveProfile
? MpdBuilder::kDynamic
: MpdBuilder::kStatic)) {
DCHECK(dash_profile == kLiveProfile || dash_profile == kOnDemandProfile);
for (size_t i = 0; i < base_urls.size(); ++i)
mpd_builder_->AddBaseUrl(base_urls[i]);
} }
SimpleMpdNotifier::~SimpleMpdNotifier() { SimpleMpdNotifier::~SimpleMpdNotifier() {
@ -45,35 +53,9 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
if (content_type == kUnknown) if (content_type == kUnknown)
return false; return false;
// Determine whether the media_info is for VOD or live.
bool has_vod_only_fields = HasVODOnlyFields(media_info);
bool has_live_only_fields = HasLiveOnlyFields(media_info);
if (has_vod_only_fields && has_live_only_fields) {
LOG(ERROR) << "MediaInfo with both VOD fields and Live fields is invalid.";
return false;
}
if (!has_vod_only_fields && !has_live_only_fields) {
LOG(ERROR) << "MediaInfo should contain either VOD fields or Live fields.";
return false;
}
MpdBuilder::MpdType mpd_type =
has_vod_only_fields ? MpdBuilder::kStatic : MpdBuilder::kDynamic;
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
// 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.
if (!mpd_builder_) {
mpd_builder_.reset(new MpdBuilder(mpd_type));
for (size_t i = 0; i < base_urls_.size(); ++i)
mpd_builder_->AddBaseUrl(base_urls_[i]);
} else {
if (mpd_builder_->type() != mpd_type) {
LOG(ERROR) << "Expecting MediaInfo with '"
<< (has_vod_only_fields ? "Live" : "VOD") << "' fields.";
return false;
}
}
AdaptationSet** adaptation_set = &adaptation_set_map_[content_type]; AdaptationSet** adaptation_set = &adaptation_set_map_[content_type];
if (*adaptation_set == NULL) if (*adaptation_set == NULL)
*adaptation_set = mpd_builder_->AddAdaptationSet(); *adaptation_set = mpd_builder_->AddAdaptationSet();
@ -86,7 +68,7 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
*container_id = representation->id(); *container_id = representation->id();
if (has_vod_only_fields) if (mpd_builder_->type() == MpdBuilder::kStatic)
return WriteMpdToFile(); return WriteMpdToFile();
DCHECK(!ContainsKey(representation_map_, representation->id())); DCHECK(!ContainsKey(representation_map_, representation->id()));

View File

@ -25,7 +25,8 @@ class Representation;
/// generates an Mpd file. /// generates an Mpd file.
class SimpleMpdNotifier : public MpdNotifier { class SimpleMpdNotifier : public MpdNotifier {
public: public:
SimpleMpdNotifier(const std::vector<std::string>& base_urls, SimpleMpdNotifier(DashProfile dash_profile,
const std::vector<std::string>& base_urls,
const std::string& output_path); const std::string& output_path);
virtual ~SimpleMpdNotifier(); virtual ~SimpleMpdNotifier();
@ -52,7 +53,6 @@ class SimpleMpdNotifier : public MpdNotifier {
ContentType GetContentType(const MediaInfo& media_info); ContentType GetContentType(const MediaInfo& media_info);
bool WriteMpdToFile(); bool WriteMpdToFile();
std::vector<std::string> base_urls_;
std::string output_path_; std::string output_path_;
scoped_ptr<MpdBuilder> mpd_builder_; scoped_ptr<MpdBuilder> mpd_builder_;