DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
muxer_util.cc
1 // Copyright 2014 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/media/base/muxer_util.h"
8 
9 #include <inttypes.h>
10 
11 #include <string>
12 #include <vector>
13 
14 #include "packager/base/logging.h"
15 #include "packager/base/strings/string_number_conversions.h"
16 #include "packager/base/strings/string_split.h"
17 #include "packager/base/strings/stringprintf.h"
18 #include "packager/media/base/video_stream_info.h"
19 
20 namespace edash_packager {
21 namespace {
22 bool ValidateFormatTag(const std::string& format_tag) {
23  DCHECK(!format_tag.empty());
24  // Format tag should follow this prototype: %0[width]d.
25  if (format_tag.size() > 3 && format_tag[0] == '%' && format_tag[1] == '0' &&
26  format_tag[format_tag.size() - 1] == 'd') {
27  unsigned out;
28  if (base::StringToUint(format_tag.substr(2, format_tag.size() - 3), &out))
29  return true;
30  }
31  LOG(ERROR) << "SegmentTemplate: Format tag should follow this prototype: "
32  << "%0[width]d if exist.";
33  return false;
34 }
35 } // namespace
36 
37 namespace media {
38 
39 bool ValidateSegmentTemplate(const std::string& segment_template) {
40  if (segment_template.empty())
41  return false;
42 
43  std::vector<std::string> splits;
44  base::SplitString(segment_template, '$', &splits);
45 
46  // ISO/IEC 23009-1:2012 5.3.9.4.4 Template-based Segment URL construction.
47  // Allowed identifiers: $$, $RepresentationID$, $Number$, $Bandwidth$, $Time$.
48  // "$" always appears in pairs, so there should be odd number of splits.
49  if (splits.size() % 2 == 0) {
50  LOG(ERROR) << "SegmentTemplate: '$' should appear in pairs.";
51  return false;
52  }
53 
54  bool has_number = false;
55  bool has_time = false;
56  // Every second substring in split output should be an identifier.
57  for (size_t i = 1; i < splits.size(); i += 2) {
58  // Each identifier may be suffixed, within the enclosing ‘$’ characters,
59  // with an additional format tag aligned with the printf format tag as
60  // defined in IEEE 1003.1-2008 [10] following this prototype: %0[width]d.
61  size_t format_pos = splits[i].find('%');
62  std::string identifier = splits[i].substr(0, format_pos);
63  if (format_pos != std::string::npos) {
64  if (!ValidateFormatTag(splits[i].substr(format_pos)))
65  return false;
66  }
67 
68  // TODO(kqyang): Support "RepresentationID".
69  if (identifier == "RepresentationID") {
70  NOTIMPLEMENTED() << "SegmentTemplate: $RepresentationID$ is not supported "
71  "yet.";
72  return false;
73  } else if (identifier == "Number") {
74  has_number = true;
75  } else if (identifier == "Time") {
76  has_time = true;
77  } else if (identifier == "") {
78  if (format_pos != std::string::npos) {
79  LOG(ERROR) << "SegmentTemplate: $$ should not have any format tags.";
80  return false;
81  }
82  } else if (identifier != "Bandwidth") {
83  LOG(ERROR) << "SegmentTemplate: '$" << splits[i]
84  << "$' is not a valid identifier.";
85  return false;
86  }
87  }
88  if (has_number && has_time) {
89  LOG(ERROR) << "SegmentTemplate: $Number$ and $Time$ should not co-exist.";
90  return false;
91  }
92  if (!has_number && !has_time) {
93  LOG(ERROR) << "SegmentTemplate: $Number$ or $Time$ should exist.";
94  return false;
95  }
96  // Note: The below check is skipped.
97  // Strings outside identifiers shall only contain characters that are
98  // permitted within URLs according to RFC 1738.
99  return true;
100 }
101 
102 std::string GetSegmentName(const std::string& segment_template,
103  uint64_t segment_start_time,
104  uint32_t segment_index,
105  uint32_t bandwidth) {
106  DCHECK(ValidateSegmentTemplate(segment_template));
107 
108  std::vector<std::string> splits;
109  base::SplitString(segment_template, '$', &splits);
110  // "$" always appears in pairs, so there should be odd number of splits.
111  DCHECK_EQ(1u, splits.size() % 2);
112 
113  std::string segment_name;
114  for (size_t i = 0; i < splits.size(); ++i) {
115  // Every second substring in split output should be an identifier.
116  // Simply copy the non-identifier part.
117  if (i % 2 == 0) {
118  segment_name += splits[i];
119  continue;
120  }
121  if (splits[i].empty()) {
122  // "$$" is an escape sequence, replaced with a single "$".
123  segment_name += "$";
124  continue;
125  }
126  size_t format_pos = splits[i].find('%');
127  std::string identifier = splits[i].substr(0, format_pos);
128  DCHECK(identifier == "Number" || identifier == "Time" ||
129  identifier == "Bandwidth");
130 
131  std::string format_tag;
132  if (format_pos != std::string::npos) {
133  format_tag = splits[i].substr(format_pos);
134  DCHECK(ValidateFormatTag(format_tag));
135  // Replace %d formatting to correctly format uint64_t.
136  format_tag = format_tag.substr(0, format_tag.size() - 1) + PRIu64;
137  } else {
138  // Default format tag "%01d", modified to format uint64_t correctly.
139  format_tag = "%01" PRIu64;
140  }
141 
142  if (identifier == "Number") {
143  // SegmentNumber starts from 1.
144  segment_name += base::StringPrintf(
145  format_tag.c_str(), static_cast<uint64_t>(segment_index + 1));
146  } else if (identifier == "Time") {
147  segment_name +=
148  base::StringPrintf(format_tag.c_str(), segment_start_time);
149  } else if (identifier == "Bandwidth") {
150  segment_name += base::StringPrintf(format_tag.c_str(),
151  static_cast<uint64_t>(bandwidth));
152  }
153  }
154  return segment_name;
155 }
156 
157 KeySource::TrackType GetTrackTypeForEncryption(const StreamInfo& stream_info,
158  uint32_t max_sd_pixels) {
159  if (stream_info.stream_type() == kStreamAudio)
160  return KeySource::TRACK_TYPE_AUDIO;
161 
162  if (stream_info.stream_type() != kStreamVideo)
163  return KeySource::TRACK_TYPE_UNKNOWN;
164 
165  DCHECK_EQ(kStreamVideo, stream_info.stream_type());
166  const VideoStreamInfo& video_stream_info =
167  static_cast<const VideoStreamInfo&>(stream_info);
168  uint32_t pixels = video_stream_info.width() * video_stream_info.height();
169  return (pixels > max_sd_pixels) ? KeySource::TRACK_TYPE_HD
170  : KeySource::TRACK_TYPE_SD;
171 }
172 
173 } // namespace media
174 } // namespace edash_packager