Implement SimpleMpdNotifier
SimpleMpdNotifier listens to muxer events and generates MPD file. Change-Id: I19304cdb9eba65fd01328aa0fd5e6d280cc5714e
This commit is contained in:
parent
f6a54c289f
commit
b0e26ff297
|
@ -60,6 +60,9 @@ class MpdBuilder {
|
|||
/// @return true on success, false otherwise.
|
||||
bool ToString(std::string* output);
|
||||
|
||||
/// @return The mpd type.
|
||||
MpdType type() { return type_; }
|
||||
|
||||
private:
|
||||
bool ToStringImpl(std::string* output);
|
||||
|
||||
|
|
|
@ -11,12 +11,11 @@
|
|||
#define MPD_BASE_MPD_NOTIFIER_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "mpd/base/media_info.pb.h"
|
||||
|
||||
namespace dash_packager {
|
||||
|
||||
class ContentProtectionElement;
|
||||
class MediaInfo;
|
||||
struct ContentProtectionElement;
|
||||
|
||||
/// Interface for publish/subscribe publisher class which notifies MpdBuilder
|
||||
/// of media-related events.
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "mpd/base/simple_mpd_notifier.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "media/file/file.h"
|
||||
#include "mpd/base/mpd_builder.h"
|
||||
#include "mpd/base/mpd_utils.h"
|
||||
|
||||
using media::File;
|
||||
|
||||
namespace {
|
||||
bool MoreThanOneTrue(bool b1, bool b2, bool b3) {
|
||||
return (b1 && b2) || (b2 && b3) || (b3 && b1);
|
||||
}
|
||||
|
||||
bool AtLeastOneTrue(bool b1, bool b2, bool b3) {
|
||||
return (b1 || b2 || b3);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace dash_packager {
|
||||
|
||||
SimpleMpdNotifier::SimpleMpdNotifier(const std::vector<std::string>& base_urls,
|
||||
const std::string& output_path)
|
||||
: base_urls_(base_urls), output_path_(output_path) {
|
||||
}
|
||||
|
||||
SimpleMpdNotifier::~SimpleMpdNotifier() {
|
||||
}
|
||||
|
||||
bool SimpleMpdNotifier::Init() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
|
||||
uint32* container_id) {
|
||||
DCHECK(container_id);
|
||||
|
||||
ContentType content_type = GetContentType(media_info);
|
||||
if (content_type == kUnknown)
|
||||
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_);
|
||||
// TODO(kqyang): Consider adding a new method MpdBuilder::AddRepresentation.
|
||||
// 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];
|
||||
if (*adaptation_set == NULL)
|
||||
*adaptation_set = mpd_builder_->AddAdaptationSet();
|
||||
|
||||
DCHECK(*adaptation_set);
|
||||
Representation* representation =
|
||||
(*adaptation_set)->AddRepresentation(media_info);
|
||||
if (representation == NULL)
|
||||
return false;
|
||||
|
||||
*container_id = representation->id();
|
||||
|
||||
if (has_vod_only_fields)
|
||||
return WriteMpdToFile();
|
||||
|
||||
DCHECK(!ContainsKey(representation_map_, representation->id()));
|
||||
representation_map_[representation->id()] = representation;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimpleMpdNotifier::NotifyNewSegment(uint32 container_id,
|
||||
uint64 start_time,
|
||||
uint64 duration) {
|
||||
base::AutoLock auto_lock(lock_);
|
||||
|
||||
RepresentationMap::iterator it = representation_map_.find(container_id);
|
||||
if (it == representation_map_.end()) {
|
||||
LOG(ERROR) << "Unexpected container_id: " << container_id;
|
||||
return false;
|
||||
}
|
||||
if (!it->second->AddNewSegment(start_time, duration))
|
||||
return false;
|
||||
return WriteMpdToFile();
|
||||
}
|
||||
|
||||
bool SimpleMpdNotifier::AddContentProtectionElement(
|
||||
uint32 container_id,
|
||||
const ContentProtectionElement& content_protection_element) {
|
||||
NOTIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (MoreThanOneTrue(has_video, has_audio, has_text)) {
|
||||
NOTIMPLEMENTED() << "MediaInfo with more than one stream is not supported.";
|
||||
return kUnknown;
|
||||
}
|
||||
if (!AtLeastOneTrue(has_video, has_audio, has_text)) {
|
||||
LOG(ERROR) << "MediaInfo should contain one audio, video, or text stream.";
|
||||
return kUnknown;
|
||||
}
|
||||
return has_video ? kVideo : (has_audio ? kAudio : kText);
|
||||
}
|
||||
|
||||
bool SimpleMpdNotifier::WriteMpdToFile() {
|
||||
CHECK(!output_path_.empty());
|
||||
|
||||
std::string mpd;
|
||||
if (!mpd_builder_->ToString(&mpd)) {
|
||||
LOG(ERROR) << "Failed to write MPD to string.";
|
||||
return false;
|
||||
}
|
||||
|
||||
File* file = File::Open(output_path_.c_str(), "w");
|
||||
if (!file) {
|
||||
LOG(ERROR) << "Failed to open file for writing: " << output_path_;
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* mpd_char_ptr = mpd.data();
|
||||
size_t mpd_bytes_left = mpd.size();
|
||||
while (mpd_bytes_left > 0) {
|
||||
int64 length = file->Write(mpd_char_ptr, mpd_bytes_left);
|
||||
if (length <= 0) {
|
||||
LOG(ERROR) << "Failed to write to file '" << output_path_ << "' ("
|
||||
<< length << ").";
|
||||
return false;
|
||||
}
|
||||
mpd_char_ptr += length;
|
||||
mpd_bytes_left -= length;
|
||||
}
|
||||
return file->Close();
|
||||
}
|
||||
|
||||
} // namespace dash_packager
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef MPD_BASE_SIMPLE_MPD_NOTIFIER_H_
|
||||
#define MPD_BASE_SIMPLE_MPD_NOTIFIER_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "mpd/base/mpd_notifier.h"
|
||||
|
||||
namespace dash_packager {
|
||||
|
||||
class AdaptationSet;
|
||||
class MpdBuilder;
|
||||
class Representation;
|
||||
|
||||
/// A simple MpdNotifier implementation which receives muxer listener event and
|
||||
/// generates an Mpd file.
|
||||
class SimpleMpdNotifier : public MpdNotifier {
|
||||
public:
|
||||
SimpleMpdNotifier(const std::vector<std::string>& base_urls,
|
||||
const std::string& output_path);
|
||||
virtual ~SimpleMpdNotifier();
|
||||
|
||||
/// @name MpdNotifier implemetation overrides.
|
||||
/// @{
|
||||
virtual bool Init() OVERRIDE;
|
||||
virtual bool NotifyNewContainer(const MediaInfo& media_info,
|
||||
uint32* id) OVERRIDE;
|
||||
virtual bool NotifyNewSegment(uint32 id,
|
||||
uint64 start_time,
|
||||
uint64 duration) OVERRIDE;
|
||||
virtual bool AddContentProtectionElement(
|
||||
uint32 id,
|
||||
const ContentProtectionElement& content_protection_element) OVERRIDE;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
enum ContentType {
|
||||
kUnknown,
|
||||
kVideo,
|
||||
kAudio,
|
||||
kText
|
||||
};
|
||||
ContentType GetContentType(const MediaInfo& media_info);
|
||||
bool WriteMpdToFile();
|
||||
|
||||
std::vector<std::string> base_urls_;
|
||||
std::string output_path_;
|
||||
|
||||
scoped_ptr<MpdBuilder> mpd_builder_;
|
||||
|
||||
base::Lock lock_;
|
||||
|
||||
typedef std::map<ContentType, AdaptationSet*> AdaptationSetMap;
|
||||
AdaptationSetMap adaptation_set_map_;
|
||||
|
||||
typedef std::map<uint32, Representation*> RepresentationMap;
|
||||
RepresentationMap representation_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SimpleMpdNotifier);
|
||||
};
|
||||
|
||||
} // namespace dash_packager
|
||||
|
||||
#endif // MPD_BASE_SIMPLE_MPD_NOTIFIER_H_
|
|
@ -44,8 +44,11 @@
|
|||
'base/content_protection_element.h',
|
||||
'base/mpd_builder.cc',
|
||||
'base/mpd_builder.h',
|
||||
'base/mpd_notifier.h',
|
||||
'base/mpd_utils.cc',
|
||||
'base/mpd_utils.h',
|
||||
'base/simple_mpd_notifier.cc',
|
||||
'base/simple_mpd_notifier.h',
|
||||
'base/xml/scoped_xml_ptr.h',
|
||||
'base/xml/xml_node.cc',
|
||||
'base/xml/xml_node.h',
|
||||
|
|
Loading…
Reference in New Issue