From d36091cf65a311baea8a129d4b9fd1fbe2a3b455 Mon Sep 17 00:00:00 2001 From: Rintaro Kuroiwa Date: Thu, 5 Dec 2013 15:13:35 -0800 Subject: [PATCH] MpdNotifier and simple MpdNotifier implementation for VOD This is the MPD side of the bridge between MpdBuilder and Muxer. Change-Id: I4ca7436914e008b3c65399cced1f689abd82d085 --- mpd/base/mpd_notifier.h | 49 ++++++++++++++ mpd/base/simple_vod_mpd_notifier.cc | 100 ++++++++++++++++++++++++++++ mpd/base/simple_vod_mpd_notifier.h | 73 ++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 mpd/base/mpd_notifier.h create mode 100644 mpd/base/simple_vod_mpd_notifier.cc create mode 100644 mpd/base/simple_vod_mpd_notifier.h diff --git a/mpd/base/mpd_notifier.h b/mpd/base/mpd_notifier.h new file mode 100644 index 0000000000..ae93d3e554 --- /dev/null +++ b/mpd/base/mpd_notifier.h @@ -0,0 +1,49 @@ +// MpdNotifier is responsible for notifying the MpdBuilder class to generate an +// MPD file. +#ifndef MPD_BASE_MPD_NOTIFIER_H_ +#define MPD_BASE_MPD_NOTIFIER_H_ + +#include "base/basictypes.h" +#include "mpd/base/media_info.pb.h" + +namespace dash_packager { + +class ContentProtectionElement; +class MediaInfo; + +class MpdNotifier { + public: + MpdNotifier() {}; + virtual ~MpdNotifier() {}; + + // Initializes the notifier. For example, if this notifier uses a network for + // notification, then this would setup connection with the remote host. + virtual bool Init() = 0; + + // Notifies the MpdBuilder that there is a new container along with + // |media_info|. Live may have multiple "files" but those should be notified + // via NotifyNewSegment(). + // On success this populates |container_id| for the container and returns true, + // otherwise returns false. + virtual bool NotifyNewContainer(const MediaInfo& media_info, + uint32* container_id) = 0; + + // Only for Live. Notifies MpdBuilder that there is a new segment ready that + // starts from |start_time| for |duration|. + // |container_id| must be an ID number populated by calling + // NotifyNewContainer(). + virtual bool NotifyNewSegment(uint32 container_id, + uint64 start_time, + uint64 duration) = 0; + + // Adds content protection information to the MPD. + // |container_id| must be an ID number populated by calling + // NotifyNewContainer(). + virtual bool AddContentProtectionElement( + uint32 container_id, + const ContentProtectionElement& content_protection_element) = 0; +}; + +} // namespace dash_packager + +#endif // MPD_BASE_MPD_NOTIFIER_H_ diff --git a/mpd/base/simple_vod_mpd_notifier.cc b/mpd/base/simple_vod_mpd_notifier.cc new file mode 100644 index 0000000000..2b82e6037c --- /dev/null +++ b/mpd/base/simple_vod_mpd_notifier.cc @@ -0,0 +1,100 @@ +#include "mpd/base/simple_vod_mpd_notifier.h" + +#include "base/stl_util.h" +#include "mpd/base/content_protection_element.h" +#include "mpd/base/media_info.pb.h" + +namespace dash_packager { + +SimpleVodMpdNotifier::SimpleVodMpdNotifier(MpdBuilder* mpd_builder) + : mpd_builder_(mpd_builder), + video_adaptation_set_(NULL), + audio_adaptation_set_(NULL), + representation_(NULL) { + DCHECK(mpd_builder); +} + +SimpleVodMpdNotifier::~SimpleVodMpdNotifier() {} + +bool SimpleVodMpdNotifier::Init() { + return true; +} + +bool SimpleVodMpdNotifier::NotifyNewContainer(const MediaInfo& media_info, + uint32* container_id) { + DCHECK(container_id); + + if (media_info.video_info_size() > 0 && media_info.audio_info_size() > 0) { + LOG(ERROR) << "SimpleVodMpdNotifier cannot handle media container with " + "both video and audio"; + return false; + } + + ContainerType container_type = kVideo; + if (media_info.video_info_size() > 0) { + container_type = kVideo; + } else if (media_info.audio_info_size() > 0) { + container_type = kAudio; + } else { + LOG(ERROR) << "Either video_info or audio_info must be populated."; + return false; + } + + if (!AddNewRepresentation(container_type, media_info, container_id)) + return false; + + return mpd_builder_->WriteMpd(); +} + +bool SimpleVodMpdNotifier::NotifyNewSegment(uint32 container_id, + uint64 start_time, + uint64 duration) { + DLOG(INFO) << "VOD does not support this operation."; + return false; +} + +bool SimpleVodMpdNotifier::AddContentProtectionElement( + uint32 container_id, + const ContentProtectionElement& content_protection_element) { + if (!ContainsKey(id_to_representation_, container_id)) + return false; + + Representation* representation = id_to_representation_[container_id]; + + DCHECK(representation); + representation->AddContentProtectionElement(content_protection_element); + return mpd_builder_->WriteMpd(); +} + +bool SimpleVodMpdNotifier::AddNewRepresentation(ContainerType type, + const MediaInfo& media_info, + uint32* container_id) { + // Use pointer-pointer to set {video,audio}_adaptation_set_. + AdaptationSet** adaptation_set_pp = NULL; + if (type == kVideo) { + adaptation_set_pp = &video_adaptation_set_; + } else if (type == kAudio){ + adaptation_set_pp = &audio_adaptation_set_; + } else { + NOTREACHED() << "Unknown container type: " << type; + return false; + } + + if (!*adaptation_set_pp) + *adaptation_set_pp = mpd_builder_->AddAdaptationSet(); + + AdaptationSet* const adaptation_set = *adaptation_set_pp; + Representation* new_representation = + adaptation_set->AddRepresentation(media_info); + + if (!new_representation) + return false; + + const uint32 representation_id = new_representation->id(); + id_to_representation_[representation_id] = new_representation; + *container_id = representation_id; + + return true; +} + +} // namespace dash_packager diff --git a/mpd/base/simple_vod_mpd_notifier.h b/mpd/base/simple_vod_mpd_notifier.h new file mode 100644 index 0000000000..24bae8b690 --- /dev/null +++ b/mpd/base/simple_vod_mpd_notifier.h @@ -0,0 +1,73 @@ +// Very simple implementation of MpdNotifier. Holds an instance of MpdBuilder +// and calls methods on the object directly. +#ifndef MPD_BASE_SIMPLE_MPD_NOTIFIER_H_ +#define MPD_BASE_SIMPLE_MPD_NOTIFIER_H_ + +#include "mpd/base/mpd_notifier.h" + +#include "mpd/base/mpd_builder.h" + +namespace dash_packager { + +// This assumes that MpdBuilder is for VOD. This class also assumes that all the +// container is for an AdaptationSet. +class SimpleVodMpdNotifier : public MpdNotifier { + public: + // TODO(rkuroiwa): Take File pointer for MPD output. + // MpdBuilder must be initialized before passing a pointer to this object. + // The ownership of |mpd_builder| does not transfer to this object and it must + // be non-NULL. + explicit SimpleVodMpdNotifier(MpdBuilder* mpd_builder); + virtual ~SimpleVodMpdNotifier(); + + // MpdNotifier implementation. + // This should be called only once. + virtual bool Init() OVERRIDE; + + // Notifies MpdBuilder to add a container. The container must have audio + // (logical exclusive) or video, IOW it cannot have both audio and video nor + // can both audio and video be empty. + // On success this writes out MPD and returns true, otherwise returns false. + virtual bool NotifyNewContainer(const MediaInfo& media_info, + uint32* id) OVERRIDE; + + // As documented in MpdNotifier. This is Live only feature. This will return + // false. + virtual bool NotifyNewSegment(uint32 id, + uint64 start_time, + uint64 duration) OVERRIDE; + + // Adds content protection information to the container added via + // NotifyNewContainer(). This will fail if |id| is not a value populated by + // calling NotifyNewContainer(). + // On success this writes out MPD and returns true, otherwise returns false. + virtual bool AddContentProtectionElement( + uint32 id, + const ContentProtectionElement& content_protection_element) OVERRIDE; + + private: + enum ContainerType { + kVideo, + kAudio + }; + + // Adds new Representation to mpd_builder_ on success. + // Sets {audio,video}_adaptation_set_ depending on |type|, if it is NULL. + bool AddNewRepresentation(ContainerType type, + const MediaInfo& media_info, + uint32* id); + + // None of these are owned by this object. + MpdBuilder* const mpd_builder_; + AdaptationSet* audio_adaptation_set_; + AdaptationSet* video_adaptation_set_; + Representation* representation_; + + std::map id_to_representation_; + + DISALLOW_COPY_AND_ASSIGN(SimpleVodMpdNotifier); +}; + +} // namespace dash_packager + +#endif // MPD_BASE_SIMPLE_MPD_NOTIFIER_H_