Shaka Packager SDK
simple_mpd_notifier.cc
1 // Copyright 2015 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/mpd/base/simple_mpd_notifier.h>
8 
9 #include <absl/log/check.h>
10 #include <absl/log/log.h>
11 
12 #include <packager/mpd/base/adaptation_set.h>
13 #include <packager/mpd/base/mpd_builder.h>
14 #include <packager/mpd/base/mpd_notifier_util.h>
15 #include <packager/mpd/base/mpd_utils.h>
16 #include <packager/mpd/base/period.h>
17 #include <packager/mpd/base/representation.h>
18 
19 namespace shaka {
20 
21 SimpleMpdNotifier::SimpleMpdNotifier(const MpdOptions& mpd_options)
22  : MpdNotifier(mpd_options),
23  output_path_(mpd_options.mpd_params.mpd_output),
24  mpd_builder_(new MpdBuilder(mpd_options)),
25  content_protection_in_adaptation_set_(
26  mpd_options.mpd_params.generate_dash_if_iop_compliant_mpd) {
27  for (const std::string& base_url : mpd_options.mpd_params.base_urls)
28  mpd_builder_->AddBaseUrl(base_url);
29 }
30 
31 SimpleMpdNotifier::~SimpleMpdNotifier() {}
32 
33 bool SimpleMpdNotifier::Init() {
34  return true;
35 }
36 
37 bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info,
38  uint32_t* container_id) {
39  DCHECK(container_id);
40 
41  ContentType content_type = GetContentType(media_info);
42  if (content_type == kContentTypeUnknown)
43  return false;
44 
45  MediaInfo adjusted_media_info(media_info);
46  MpdBuilder::MakePathsRelativeToMpd(output_path_, &adjusted_media_info);
47 
48  absl::MutexLock auto_lock(&lock_);
49  const double kPeriodStartTimeSeconds = 0.0;
50  Period* period = mpd_builder_->GetOrCreatePeriod(kPeriodStartTimeSeconds);
51  DCHECK(period);
52  AdaptationSet* adaptation_set = period->GetOrCreateAdaptationSet(
53  media_info, content_protection_in_adaptation_set_);
54  DCHECK(adaptation_set);
55  if (!adaptation_set->has_id())
56  adaptation_set->set_id(next_adaptation_set_id_++);
57  Representation* representation =
58  adaptation_set->AddRepresentation(adjusted_media_info);
59  if (!representation)
60  return false;
61 
62  *container_id = representation->id();
63  if (content_protection_in_adaptation_set_) {
64  // ContentProtection elements are already added to AdaptationSet above.
65  // Use RepresentationId to AdaptationSet map to update ContentProtection
66  // in AdaptationSet in NotifyEncryptionUpdate.
67  representation_id_to_adaptation_set_[representation->id()] = adaptation_set;
68  } else {
69  AddContentProtectionElements(media_info, representation);
70  }
71  representation_map_[representation->id()] = representation;
72  return true;
73 }
74 
75 bool SimpleMpdNotifier::NotifyAvailabilityTimeOffset(uint32_t container_id) {
76  absl::MutexLock lock(&lock_);
77  auto it = representation_map_.find(container_id);
78  if (it == representation_map_.end()) {
79  LOG(ERROR) << "Unexpected container_id: " << container_id;
80  return false;
81  }
82  it->second->SetAvailabilityTimeOffset();
83  return true;
84 }
85 
86 bool SimpleMpdNotifier::NotifySampleDuration(uint32_t container_id,
87  int32_t sample_duration) {
88  absl::MutexLock lock(&lock_);
89  auto it = representation_map_.find(container_id);
90  if (it == representation_map_.end()) {
91  LOG(ERROR) << "Unexpected container_id: " << container_id;
92  return false;
93  }
94  it->second->SetSampleDuration(sample_duration);
95  return true;
96 }
97 
98 bool SimpleMpdNotifier::NotifySegmentDuration(uint32_t container_id) {
99  absl::MutexLock lock(&lock_);
100  auto it = representation_map_.find(container_id);
101  if (it == representation_map_.end()) {
102  LOG(ERROR) << "Unexpected container_id: " << container_id;
103  return false;
104  }
105  it->second->SetSegmentDuration();
106  return true;
107 }
108 
109 bool SimpleMpdNotifier::NotifyNewSegment(uint32_t container_id,
110  int64_t start_time,
111  int64_t duration,
112  uint64_t size,
113  int64_t segment_number) {
114  absl::MutexLock lock(&lock_);
115  auto it = representation_map_.find(container_id);
116  if (it == representation_map_.end()) {
117  LOG(ERROR) << "Unexpected container_id: " << container_id;
118  return false;
119  }
120  it->second->AddNewSegment(start_time, duration, size, segment_number);
121  return true;
122 }
123 
124 bool SimpleMpdNotifier::NotifyCompletedSegment(uint32_t container_id,
125  int64_t duration,
126  uint64_t size) {
127  absl::MutexLock lock(&lock_);
128  auto it = representation_map_.find(container_id);
129  if (it == representation_map_.end()) {
130  LOG(ERROR) << "Unexpected container_id: " << container_id;
131  return false;
132  }
133  it->second->UpdateCompletedSegment(duration, size);
134  return true;
135 }
136 
137 bool SimpleMpdNotifier::NotifyCueEvent(uint32_t container_id,
138  int64_t timestamp) {
139  absl::MutexLock lock(&lock_);
140  auto it = representation_map_.find(container_id);
141  if (it == representation_map_.end()) {
142  LOG(ERROR) << "Unexpected container_id: " << container_id;
143  return false;
144  }
145  Representation* original_representation = it->second;
146  AdaptationSet* original_adaptation_set =
147  representation_id_to_adaptation_set_[container_id];
148 
149  const MediaInfo& media_info = original_representation->GetMediaInfo();
150  const double period_start_time_seconds =
151  static_cast<double>(timestamp) / media_info.reference_time_scale();
152 
153  Period* period = mpd_builder_->GetOrCreatePeriod(period_start_time_seconds);
154  DCHECK(period);
155  AdaptationSet* adaptation_set = period->GetOrCreateAdaptationSet(
156  media_info, content_protection_in_adaptation_set_);
157  DCHECK(adaptation_set);
158  if (!adaptation_set->has_id()) {
159  adaptation_set->set_id(original_adaptation_set->id());
160  } else {
161  DCHECK_EQ(adaptation_set->id(), original_adaptation_set->id());
162  }
163 
164  Representation* representation =
165  adaptation_set->CopyRepresentation(*original_representation);
166  if (!representation)
167  return false;
168 
169  if (content_protection_in_adaptation_set_) {
170  // ContentProtection elements are already added to AdaptationSet above.
171  // Use RepresentationId to AdaptationSet map to update ContentProtection
172  // in AdaptationSet in NotifyEncryptionUpdate.
173  representation_id_to_adaptation_set_[representation->id()] = adaptation_set;
174  } else {
175  AddContentProtectionElements(media_info, representation);
176  }
177  representation_map_[representation->id()] = representation;
178  return true;
179 }
180 
181 bool SimpleMpdNotifier::NotifyEncryptionUpdate(
182  uint32_t container_id,
183  const std::string& drm_uuid,
184  const std::vector<uint8_t>& new_key_id,
185  const std::vector<uint8_t>& new_pssh) {
186  absl::MutexLock lock(&lock_);
187  auto it = representation_map_.find(container_id);
188  if (it == representation_map_.end()) {
189  LOG(ERROR) << "Unexpected container_id: " << container_id;
190  return false;
191  }
192 
193  if (content_protection_in_adaptation_set_) {
194  AdaptationSet* adaptation_set_for_representation =
195  representation_id_to_adaptation_set_[it->second->id()];
196  adaptation_set_for_representation->UpdateContentProtectionPssh(
197  drm_uuid, Uint8VectorToBase64(new_pssh));
198  } else {
199  it->second->UpdateContentProtectionPssh(drm_uuid,
200  Uint8VectorToBase64(new_pssh));
201  }
202  return true;
203 }
204 
205 bool SimpleMpdNotifier::NotifyMediaInfoUpdate(uint32_t container_id,
206  const MediaInfo& media_info) {
207  absl::MutexLock lock(&lock_);
208  auto it = representation_map_.find(container_id);
209  if (it == representation_map_.end()) {
210  LOG(ERROR) << "Unexpected container_id: " << container_id;
211  return false;
212  }
213 
214  MediaInfo adjusted_media_info(media_info);
215  MpdBuilder::MakePathsRelativeToMpd(output_path_, &adjusted_media_info);
216 
217  it->second->set_media_info(adjusted_media_info);
218  return true;
219 }
220 
221 bool SimpleMpdNotifier::Flush() {
222  absl::MutexLock lock(&lock_);
223  return WriteMpdToFile(output_path_, mpd_builder_.get());
224 }
225 
226 } // namespace shaka
virtual Representation * AddRepresentation(const MediaInfo &media_info)
virtual Representation * CopyRepresentation(const Representation &representation)
virtual void UpdateContentProtectionPssh(const std::string &drm_uuid, const std::string &pssh)
void set_id(uint32_t id)
virtual AdaptationSet * GetOrCreateAdaptationSet(const MediaInfo &media_info, bool content_protection_in_adaptation_set)
Definition: period.cc:75
virtual const MediaInfo & GetMediaInfo() const
uint32_t id() const
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66
std::string Uint8VectorToBase64(const std::vector< uint8_t > &input)
Converts uint8 vector into base64 encoded string.
ContentType GetContentType(const MediaInfo &media_info)
bool WriteMpdToFile(const std::string &output_path, MpdBuilder *mpd_builder)
void AddContentProtectionElements(const MediaInfo &media_info, Representation *parent)
Definition: mpd_utils.cc:523