Shaka Packager SDK
adaptation_set.cc
1 // Copyright 2017 Google Inc. 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/adaptation_set.h"
8 
9 #include <cmath>
10 
11 #include "packager/base/logging.h"
12 #include "packager/base/strings/string_number_conversions.h"
13 #include "packager/mpd/base/media_info.pb.h"
14 #include "packager/mpd/base/mpd_options.h"
15 #include "packager/mpd/base/mpd_utils.h"
16 #include "packager/mpd/base/representation.h"
17 #include "packager/mpd/base/xml/xml_node.h"
18 
19 namespace shaka {
20 namespace {
21 
22 AdaptationSet::Role MediaInfoTextTypeToRole(
23  MediaInfo::TextInfo::TextType type) {
24  switch (type) {
25  case MediaInfo::TextInfo::UNKNOWN:
26  LOG(WARNING) << "Unknown text type, assuming subtitle.";
27  return AdaptationSet::kRoleSubtitle;
28  case MediaInfo::TextInfo::CAPTION:
29  return AdaptationSet::kRoleCaption;
30  case MediaInfo::TextInfo::SUBTITLE:
31  return AdaptationSet::kRoleSubtitle;
32  default:
33  NOTREACHED() << "Unknown MediaInfo TextType: " << type
34  << " assuming subtitle.";
35  return AdaptationSet::kRoleSubtitle;
36  }
37 }
38 
39 std::string RoleToText(AdaptationSet::Role role) {
40  // Using switch so that the compiler can detect whether there is a case that's
41  // not being handled.
42  switch (role) {
43  case AdaptationSet::kRoleCaption:
44  return "caption";
45  case AdaptationSet::kRoleSubtitle:
46  return "subtitle";
47  case AdaptationSet::kRoleMain:
48  return "main";
49  case AdaptationSet::kRoleAlternate:
50  return "alternate";
51  case AdaptationSet::kRoleSupplementary:
52  return "supplementary";
53  case AdaptationSet::kRoleCommentary:
54  return "commentary";
55  case AdaptationSet::kRoleDub:
56  return "dub";
57  default:
58  return "unknown";
59  }
60 }
61 
62 // Returns the picture aspect ratio string e.g. "16:9", "4:3".
63 // "Reducing the quotient to minimal form" does not work well in practice as
64 // there may be some rounding performed in the input, e.g. the resolution of
65 // 480p is 854:480 for 16:9 aspect ratio, can only be reduced to 427:240.
66 // The algorithm finds out the pair of integers, num and den, where num / den is
67 // the closest ratio to scaled_width / scaled_height, by looping den through
68 // common values.
69 std::string GetPictureAspectRatio(uint32_t width,
70  uint32_t height,
71  uint32_t pixel_width,
72  uint32_t pixel_height) {
73  const uint32_t scaled_width = pixel_width * width;
74  const uint32_t scaled_height = pixel_height * height;
75  const double par = static_cast<double>(scaled_width) / scaled_height;
76 
77  // Typical aspect ratios have par_y less than or equal to 19:
78  // https://en.wikipedia.org/wiki/List_of_common_resolutions
79  const uint32_t kLargestPossibleParY = 19;
80 
81  uint32_t par_num = 0;
82  uint32_t par_den = 0;
83  double min_error = 1.0;
84  for (uint32_t den = 1; den <= kLargestPossibleParY; ++den) {
85  uint32_t num = par * den + 0.5;
86  double error = fabs(par - static_cast<double>(num) / den);
87  if (error < min_error) {
88  min_error = error;
89  par_num = num;
90  par_den = den;
91  if (error == 0)
92  break;
93  }
94  }
95  VLOG(2) << "width*pix_width : height*pixel_height (" << scaled_width << ":"
96  << scaled_height << ") reduced to " << par_num << ":" << par_den
97  << " with error " << min_error << ".";
98 
99  return base::IntToString(par_num) + ":" + base::IntToString(par_den);
100 }
101 
102 // Adds an entry to picture_aspect_ratio if the size of picture_aspect_ratio is
103 // less than 2 and video_info has both pixel width and pixel height.
104 void AddPictureAspectRatio(const MediaInfo::VideoInfo& video_info,
105  std::set<std::string>* picture_aspect_ratio) {
106  // If there are more than one entries in picture_aspect_ratio, the @par
107  // attribute cannot be set, so skip.
108  if (picture_aspect_ratio->size() > 1)
109  return;
110 
111  if (video_info.width() == 0 || video_info.height() == 0 ||
112  video_info.pixel_width() == 0 || video_info.pixel_height() == 0) {
113  // If there is even one Representation without a @sar attribute, @par cannot
114  // be calculated.
115  // Just populate the set with at least 2 bogus strings so that further call
116  // to this function will bail out immediately.
117  picture_aspect_ratio->insert("bogus");
118  picture_aspect_ratio->insert("entries");
119  return;
120  }
121 
122  const std::string par = GetPictureAspectRatio(
123  video_info.width(), video_info.height(), video_info.pixel_width(),
124  video_info.pixel_height());
125  DVLOG(1) << "Setting par as: " << par
126  << " for video with width: " << video_info.width()
127  << " height: " << video_info.height()
128  << " pixel_width: " << video_info.pixel_width() << " pixel_height; "
129  << video_info.pixel_height();
130  picture_aspect_ratio->insert(par);
131 }
132 
133 class RepresentationStateChangeListenerImpl
134  : public RepresentationStateChangeListener {
135  public:
136  // |adaptation_set| is not owned by this class.
137  RepresentationStateChangeListenerImpl(uint32_t representation_id,
138  AdaptationSet* adaptation_set)
139  : representation_id_(representation_id), adaptation_set_(adaptation_set) {
140  DCHECK(adaptation_set_);
141  }
142  ~RepresentationStateChangeListenerImpl() override {}
143 
144  // RepresentationStateChangeListener implementation.
145  void OnNewSegmentForRepresentation(int64_t start_time,
146  int64_t duration) override {
147  adaptation_set_->OnNewSegmentForRepresentation(representation_id_,
148  start_time, duration);
149  }
150 
151  void OnSetFrameRateForRepresentation(uint32_t frame_duration,
152  uint32_t timescale) override {
153  adaptation_set_->OnSetFrameRateForRepresentation(representation_id_,
154  frame_duration, timescale);
155  }
156 
157  private:
158  const uint32_t representation_id_;
159  AdaptationSet* const adaptation_set_;
160 
161  DISALLOW_COPY_AND_ASSIGN(RepresentationStateChangeListenerImpl);
162 };
163 
164 } // namespace
165 
166 AdaptationSet::AdaptationSet(const std::string& language,
167  const MpdOptions& mpd_options,
168  uint32_t* counter)
169  : representation_counter_(counter),
170  language_(language),
171  mpd_options_(mpd_options),
172  segments_aligned_(kSegmentAlignmentUnknown),
173  force_set_segment_alignment_(false) {
174  DCHECK(counter);
175 }
176 
177 AdaptationSet::~AdaptationSet() {}
178 
179 Representation* AdaptationSet::AddRepresentation(const MediaInfo& media_info) {
180  const uint32_t representation_id = (*representation_counter_)++;
181  // Note that AdaptationSet outlive Representation, so this object
182  // will die before AdaptationSet.
183  std::unique_ptr<RepresentationStateChangeListener> listener(
184  new RepresentationStateChangeListenerImpl(representation_id, this));
185  std::unique_ptr<Representation> new_representation(new Representation(
186  media_info, mpd_options_, representation_id, std::move(listener)));
187 
188  if (!new_representation->Init()) {
189  LOG(ERROR) << "Failed to initialize Representation.";
190  return NULL;
191  }
192  UpdateFromMediaInfo(media_info);
193  Representation* representation_ptr = new_representation.get();
194  representation_map_[representation_ptr->id()] = std::move(new_representation);
195  return representation_ptr;
196 }
197 
199  const Representation& representation) {
200  // Note that AdaptationSet outlive Representation, so this object
201  // will die before AdaptationSet.
202  std::unique_ptr<RepresentationStateChangeListener> listener(
203  new RepresentationStateChangeListenerImpl(representation.id(), this));
204  std::unique_ptr<Representation> new_representation(
205  new Representation(representation, std::move(listener)));
206 
207  UpdateFromMediaInfo(new_representation->GetMediaInfo());
208  Representation* representation_ptr = new_representation.get();
209  representation_map_[representation_ptr->id()] = std::move(new_representation);
210  return representation_ptr;
211 }
212 
214  const ContentProtectionElement& content_protection_element) {
215  content_protection_elements_.push_back(content_protection_element);
216  RemoveDuplicateAttributes(&content_protection_elements_.back());
217 }
218 
219 void AdaptationSet::UpdateContentProtectionPssh(const std::string& drm_uuid,
220  const std::string& pssh) {
221  UpdateContentProtectionPsshHelper(drm_uuid, pssh,
222  &content_protection_elements_);
223 }
224 
225 void AdaptationSet::AddAccessibility(const std::string& scheme,
226  const std::string& value) {
227  accessibilities_.push_back(Accessibility{scheme, value});
228 }
229 
230 void AdaptationSet::AddRole(Role role) {
231  roles_.insert(role);
232 }
233 
234 // Creates a copy of <AdaptationSet> xml element, iterate thru all the
235 // <Representation> (child) elements and add them to the copy.
236 // Set all the attributes first and then add the children elements so that flags
237 // can be passed to Representation to avoid setting redundant attributes. For
238 // example, if AdaptationSet@width is set, then Representation@width is
239 // redundant and should not be set.
240 base::Optional<xml::XmlNode> AdaptationSet::GetXml() {
241  xml::AdaptationSetXmlNode adaptation_set;
242 
243  bool suppress_representation_width = false;
244  bool suppress_representation_height = false;
245  bool suppress_representation_frame_rate = false;
246 
247  if (id_ && !adaptation_set.SetId(id_.value()))
248  return base::nullopt;
249  if (!adaptation_set.SetStringAttribute("contentType", content_type_))
250  return base::nullopt;
251  if (!language_.empty() && language_ != "und" &&
252  !adaptation_set.SetStringAttribute("lang", language_)) {
253  return base::nullopt;
254  }
255 
256  // Note that std::{set,map} are ordered, so the last element is the max value.
257  if (video_widths_.size() == 1) {
258  suppress_representation_width = true;
259  if (!adaptation_set.SetIntegerAttribute("width", *video_widths_.begin()))
260  return base::nullopt;
261  } else if (video_widths_.size() > 1) {
262  if (!adaptation_set.SetIntegerAttribute("maxWidth",
263  *video_widths_.rbegin())) {
264  return base::nullopt;
265  }
266  }
267  if (video_heights_.size() == 1) {
268  suppress_representation_height = true;
269  if (!adaptation_set.SetIntegerAttribute("height", *video_heights_.begin()))
270  return base::nullopt;
271  } else if (video_heights_.size() > 1) {
272  if (!adaptation_set.SetIntegerAttribute("maxHeight",
273  *video_heights_.rbegin())) {
274  return base::nullopt;
275  }
276  }
277 
278  if (video_frame_rates_.size() == 1) {
279  suppress_representation_frame_rate = true;
280  if (!adaptation_set.SetStringAttribute(
281  "frameRate", video_frame_rates_.begin()->second)) {
282  return base::nullopt;
283  }
284  } else if (video_frame_rates_.size() > 1) {
285  if (!adaptation_set.SetStringAttribute(
286  "maxFrameRate", video_frame_rates_.rbegin()->second)) {
287  return base::nullopt;
288  }
289  }
290 
291  // Note: must be checked before checking segments_aligned_ (below). So that
292  // segments_aligned_ is set before checking below.
293  if (mpd_options_.mpd_type == MpdType::kStatic) {
294  CheckStaticSegmentAlignment();
295  }
296 
297  if (segments_aligned_ == kSegmentAlignmentTrue) {
298  if (!adaptation_set.SetStringAttribute(
299  mpd_options_.dash_profile == DashProfile::kOnDemand
300  ? "subsegmentAlignment"
301  : "segmentAlignment",
302  "true")) {
303  return base::nullopt;
304  }
305  }
306 
307  if (picture_aspect_ratio_.size() == 1 &&
308  !adaptation_set.SetStringAttribute("par",
309  *picture_aspect_ratio_.begin())) {
310  return base::nullopt;
311  }
312 
313  if (!adaptation_set.AddContentProtectionElements(
314  content_protection_elements_)) {
315  return base::nullopt;
316  }
317 
318  std::string trick_play_reference_ids;
319  for (const AdaptationSet* adaptation_set : trick_play_references_) {
320  // Should be a whitespace-separated list, see DASH-IOP 3.2.9.
321  if (!trick_play_reference_ids.empty())
322  trick_play_reference_ids += ' ';
323  CHECK(adaptation_set->has_id());
324  trick_play_reference_ids += std::to_string(adaptation_set->id());
325  }
326  if (!trick_play_reference_ids.empty() &&
327  !adaptation_set.AddEssentialProperty(
328  "http://dashif.org/guidelines/trickmode", trick_play_reference_ids)) {
329  return base::nullopt;
330  }
331 
332  std::string switching_ids;
333  for (const AdaptationSet* adaptation_set : switchable_adaptation_sets_) {
334  // Should be a comma-separated list, see DASH-IOP 3.8.
335  if (!switching_ids.empty())
336  switching_ids += ',';
337  CHECK(adaptation_set->has_id());
338  switching_ids += std::to_string(adaptation_set->id());
339  }
340  if (!switching_ids.empty() &&
341  !adaptation_set.AddSupplementalProperty(
342  "urn:mpeg:dash:adaptation-set-switching:2016", switching_ids)) {
343  return base::nullopt;
344  }
345 
346  for (const AdaptationSet::Accessibility& accessibility : accessibilities_) {
347  if (!adaptation_set.AddAccessibilityElement(accessibility.scheme,
348  accessibility.value)) {
349  return base::nullopt;
350  }
351  }
352 
353  for (AdaptationSet::Role role : roles_) {
354  if (!adaptation_set.AddRoleElement("urn:mpeg:dash:role:2011",
355  RoleToText(role))) {
356  return base::nullopt;
357  }
358  }
359 
360  for (const auto& representation_pair : representation_map_) {
361  const auto& representation = representation_pair.second;
362  if (suppress_representation_width)
363  representation->SuppressOnce(Representation::kSuppressWidth);
364  if (suppress_representation_height)
365  representation->SuppressOnce(Representation::kSuppressHeight);
366  if (suppress_representation_frame_rate)
367  representation->SuppressOnce(Representation::kSuppressFrameRate);
368  auto child = representation->GetXml();
369  if (!child || !adaptation_set.AddChild(std::move(*child)))
370  return base::nullopt;
371  }
372 
373  return std::move(adaptation_set);
374 }
375 
376 void AdaptationSet::ForceSetSegmentAlignment(bool segment_alignment) {
377  segments_aligned_ =
378  segment_alignment ? kSegmentAlignmentTrue : kSegmentAlignmentFalse;
379  force_set_segment_alignment_ = true;
380 }
381 
383  const AdaptationSet* adaptation_set) {
384  switchable_adaptation_sets_.push_back(adaptation_set);
385 }
386 
387 // For dynamic MPD, storing all start_time and duration will out-of-memory
388 // because there's no way of knowing when it will end. Static MPD
389 // subsegmentAlignment check is *not* done here because it is possible that some
390 // Representations might not have been added yet (e.g. a thread is assigned per
391 // muxer so one might run faster than others). To be clear, for dynamic MPD, all
392 // Representations should be added before a segment is added.
393 void AdaptationSet::OnNewSegmentForRepresentation(uint32_t representation_id,
394  uint64_t start_time,
395  uint64_t duration) {
396  if (mpd_options_.mpd_type == MpdType::kDynamic) {
397  CheckDynamicSegmentAlignment(representation_id, start_time, duration);
398  } else {
399  representation_segment_start_times_[representation_id].push_back(
400  start_time);
401  }
402 }
403 
404 void AdaptationSet::OnSetFrameRateForRepresentation(uint32_t representation_id,
405  uint32_t frame_duration,
406  uint32_t timescale) {
407  RecordFrameRate(frame_duration, timescale);
408 }
409 
411  trick_play_references_.push_back(adaptation_set);
412 }
413 
414 const std::list<Representation*> AdaptationSet::GetRepresentations() const {
415  std::list<Representation*> representations;
416  for (const auto& representation_pair : representation_map_) {
417  representations.push_back(representation_pair.second.get());
418  }
419  return representations;
420 }
421 
423  return content_type_ == "video";
424 }
425 
426 void AdaptationSet::UpdateFromMediaInfo(const MediaInfo& media_info) {
427  // For videos, record the width, height, and the frame rate to calculate the
428  // max {width,height,framerate} required for DASH IOP.
429  if (media_info.has_video_info()) {
430  const MediaInfo::VideoInfo& video_info = media_info.video_info();
431  DCHECK(video_info.has_width());
432  DCHECK(video_info.has_height());
433  video_widths_.insert(video_info.width());
434  video_heights_.insert(video_info.height());
435 
436  if (video_info.has_time_scale() && video_info.has_frame_duration())
437  RecordFrameRate(video_info.frame_duration(), video_info.time_scale());
438 
439  AddPictureAspectRatio(video_info, &picture_aspect_ratio_);
440  }
441 
442  if (media_info.has_video_info()) {
443  content_type_ = "video";
444  } else if (media_info.has_audio_info()) {
445  content_type_ = "audio";
446  } else if (media_info.has_text_info()) {
447  content_type_ = "text";
448 
449  if (media_info.text_info().has_type() &&
450  (media_info.text_info().type() != MediaInfo::TextInfo::UNKNOWN)) {
451  roles_.insert(MediaInfoTextTypeToRole(media_info.text_info().type()));
452  }
453  }
454 }
455 
456 // This implementation assumes that each representations' segments' are
457 // contiguous.
458 // Also assumes that all Representations are added before this is called.
459 // This checks whether the first elements of the lists in
460 // representation_segment_start_times_ are aligned.
461 // For example, suppose this method was just called with args rep_id=2
462 // start_time=1.
463 // 1 -> [1, 100, 200]
464 // 2 -> [1]
465 // The timestamps of the first elements match, so this flags
466 // segments_aligned_=true.
467 // Also since the first segment start times match, the first element of all the
468 // lists are removed, so the map of lists becomes:
469 // 1 -> [100, 200]
470 // 2 -> []
471 // Note that there could be false positives.
472 // e.g. just got rep_id=3 start_time=1 duration=300, and the duration of the
473 // whole AdaptationSet is 300.
474 // 1 -> [1, 100, 200]
475 // 2 -> [1, 90, 100]
476 // 3 -> [1]
477 // They are not aligned but this will be marked as aligned.
478 // But since this is unlikely to happen in the packager (and to save
479 // computation), this isn't handled at the moment.
480 void AdaptationSet::CheckDynamicSegmentAlignment(uint32_t representation_id,
481  uint64_t start_time,
482  uint64_t /* duration */) {
483  if (segments_aligned_ == kSegmentAlignmentFalse ||
484  force_set_segment_alignment_) {
485  return;
486  }
487 
488  std::list<uint64_t>& current_representation_start_times =
489  representation_segment_start_times_[representation_id];
490  current_representation_start_times.push_back(start_time);
491  // There's no way to detemine whether the segments are aligned if some
492  // representations do not have any segments.
493  if (representation_segment_start_times_.size() != representation_map_.size())
494  return;
495 
496  DCHECK(!current_representation_start_times.empty());
497  const uint64_t expected_start_time =
498  current_representation_start_times.front();
499  for (const auto& key_value : representation_segment_start_times_) {
500  const std::list<uint64_t>& representation_start_time = key_value.second;
501  // If there are no entries in a list, then there is no way for the
502  // segment alignment status to change.
503  // Note that it can be empty because entries get deleted below.
504  if (representation_start_time.empty())
505  return;
506 
507  if (expected_start_time != representation_start_time.front()) {
508  VLOG(1) << "Seeing Misaligned segments with different start_times: "
509  << expected_start_time << " vs "
510  << representation_start_time.front();
511  // Flag as false and clear the start times data, no need to keep it
512  // around.
513  segments_aligned_ = kSegmentAlignmentFalse;
514  representation_segment_start_times_.clear();
515  return;
516  }
517  }
518  segments_aligned_ = kSegmentAlignmentTrue;
519 
520  for (auto& key_value : representation_segment_start_times_) {
521  std::list<uint64_t>& representation_start_time = key_value.second;
522  representation_start_time.pop_front();
523  }
524 }
525 
526 // Make sure all segements start times match for all Representations.
527 // This assumes that the segments are contiguous.
528 void AdaptationSet::CheckStaticSegmentAlignment() {
529  if (segments_aligned_ == kSegmentAlignmentFalse ||
530  force_set_segment_alignment_) {
531  return;
532  }
533  if (representation_segment_start_times_.empty())
534  return;
535  if (representation_segment_start_times_.size() == 1) {
536  segments_aligned_ = kSegmentAlignmentTrue;
537  return;
538  }
539 
540  // This is not the most efficient implementation to compare the values
541  // because expected_time_line is compared against all other time lines, but
542  // probably the most readable.
543  const std::list<uint64_t>& expected_time_line =
544  representation_segment_start_times_.begin()->second;
545 
546  bool all_segment_time_line_same_length = true;
547  // Note that the first entry is skipped because it is expected_time_line.
548  RepresentationTimeline::const_iterator it =
549  representation_segment_start_times_.begin();
550  for (++it; it != representation_segment_start_times_.end(); ++it) {
551  const std::list<uint64_t>& other_time_line = it->second;
552  if (expected_time_line.size() != other_time_line.size()) {
553  all_segment_time_line_same_length = false;
554  }
555 
556  const std::list<uint64_t>* longer_list = &other_time_line;
557  const std::list<uint64_t>* shorter_list = &expected_time_line;
558  if (expected_time_line.size() > other_time_line.size()) {
559  shorter_list = &other_time_line;
560  longer_list = &expected_time_line;
561  }
562 
563  if (!std::equal(shorter_list->begin(), shorter_list->end(),
564  longer_list->begin())) {
565  // Some segments are definitely unaligned.
566  segments_aligned_ = kSegmentAlignmentFalse;
567  representation_segment_start_times_.clear();
568  return;
569  }
570  }
571 
572  // TODO(rkuroiwa): The right way to do this is to also check the durations.
573  // For example:
574  // (a) 3 4 5
575  // (b) 3 4 5 6
576  // could be true or false depending on the length of the third segment of (a).
577  // i.e. if length of the third segment is 2, then this is not aligned.
578  if (!all_segment_time_line_same_length) {
579  segments_aligned_ = kSegmentAlignmentUnknown;
580  return;
581  }
582 
583  segments_aligned_ = kSegmentAlignmentTrue;
584 }
585 
586 // Since all AdaptationSet cares about is the maxFrameRate, representation_id
587 // is not passed to this method.
588 void AdaptationSet::RecordFrameRate(uint32_t frame_duration,
589  uint32_t timescale) {
590  if (frame_duration == 0) {
591  LOG(ERROR) << "Frame duration is 0 and cannot be set.";
592  return;
593  }
594  video_frame_rates_[static_cast<double>(timescale) / frame_duration] =
595  base::IntToString(timescale) + "/" + base::IntToString(frame_duration);
596 }
597 
598 } // namespace shaka
shaka::MpdOptions
Defines Mpd Options.
Definition: mpd_options.h:25
shaka::AdaptationSet::OnSetFrameRateForRepresentation
void OnSetFrameRateForRepresentation(uint32_t representation_id, uint32_t frame_duration, uint32_t timescale)
Definition: adaptation_set.cc:404
shaka::AdaptationSet::ForceSetSegmentAlignment
virtual void ForceSetSegmentAlignment(bool segment_alignment)
Definition: adaptation_set.cc:376
shaka::AdaptationSet::IsVideo
bool IsVideo() const
Definition: adaptation_set.cc:422
shaka::AdaptationSet
Definition: adaptation_set.h:33
shaka::AdaptationSet::OnNewSegmentForRepresentation
void OnNewSegmentForRepresentation(uint32_t representation_id, uint64_t start_time, uint64_t duration)
Definition: adaptation_set.cc:393
shaka
All the methods that are virtual are virtual for mocking.
Definition: gflags_hex_bytes.cc:11
shaka::xml::XmlNode::SetIntegerAttribute
bool SetIntegerAttribute(const std::string &attribute_name, uint64_t number) WARN_UNUSED_RESULT
Definition: xml_node.cc:191
shaka::Representation::id
uint32_t id() const
Definition: representation.h:142
shaka::AdaptationSet::AdaptationSet
AdaptationSet(const std::string &language, const MpdOptions &mpd_options, uint32_t *representation_counter)
Definition: adaptation_set.cc:166
shaka::xml::XmlNode::SetId
bool SetId(uint32_t id) WARN_UNUSED_RESULT
Definition: xml_node.cc:205
shaka::AdaptationSet::GetXml
base::Optional< xml::XmlNode > GetXml()
Definition: adaptation_set.cc:240
shaka::AdaptationSet::UpdateContentProtectionPssh
virtual void UpdateContentProtectionPssh(const std::string &drm_uuid, const std::string &pssh)
Definition: adaptation_set.cc:219
shaka::xml::AdaptationSetXmlNode::AddRoleElement
bool AddRoleElement(const std::string &scheme_id_uri, const std::string &value) WARN_UNUSED_RESULT
Definition: xml_node.cc:329
shaka::Representation
Definition: representation.h:50
shaka::AdaptationSet::AddAccessibility
virtual void AddAccessibility(const std::string &scheme, const std::string &value)
Definition: adaptation_set.cc:225
shaka::AdaptationSet::AddRepresentation
virtual Representation * AddRepresentation(const MediaInfo &media_info)
Definition: adaptation_set.cc:179
shaka::AdaptationSet::AddContentProtectionElement
virtual void AddContentProtectionElement(const ContentProtectionElement &element)
Definition: adaptation_set.cc:213
shaka::AdaptationSet::CopyRepresentation
virtual Representation * CopyRepresentation(const Representation &representation)
Definition: adaptation_set.cc:198
shaka::xml::XmlNode::AddChild
bool AddChild(XmlNode child) WARN_UNUSED_RESULT
Definition: xml_node.cc:141
shaka::xml::AdaptationSetXmlNode
AdaptationSetType specified in MPD.
Definition: xml_node.h:162
shaka::xml::XmlNode::SetStringAttribute
bool SetStringAttribute(const std::string &attribute_name, const std::string &attribute) WARN_UNUSED_RESULT
Definition: xml_node.cc:184
shaka::AdaptationSet::AddAdaptationSetSwitching
virtual void AddAdaptationSetSwitching(const AdaptationSet *adaptation_set)
Definition: adaptation_set.cc:382
shaka::AdaptationSet::AddRole
virtual void AddRole(Role role)
Definition: adaptation_set.cc:230
shaka::xml::RepresentationBaseXmlNode::AddSupplementalProperty
bool AddSupplementalProperty(const std::string &scheme_id_uri, const std::string &value) WARN_UNUSED_RESULT
Definition: xml_node.cc:275
shaka::xml::RepresentationBaseXmlNode::AddEssentialProperty
bool AddEssentialProperty(const std::string &scheme_id_uri, const std::string &value) WARN_UNUSED_RESULT
Definition: xml_node.cc:281
shaka::xml::AdaptationSetXmlNode::AddAccessibilityElement
bool AddAccessibilityElement(const std::string &scheme_id_uri, const std::string &value) WARN_UNUSED_RESULT
Definition: xml_node.cc:323
shaka::AdaptationSet::AddTrickPlayReference
virtual void AddTrickPlayReference(const AdaptationSet *adaptation_set)
Definition: adaptation_set.cc:410
shaka::ContentProtectionElement
Definition: content_protection_element.h:36