Shaka Player Embedded
media_utils.cc
Go to the documentation of this file.
1 // Copyright 2017 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/media/media_utils.h"
16 
17 #include <algorithm>
18 #include <cstdlib>
19 #include <type_traits>
20 #include <utility>
21 
22 #include "src/util/macros.h"
23 
24 namespace shaka {
25 namespace media {
26 
27 namespace {
28 
29 struct StringMapping {
30  const char* source;
31  const char* dest;
32 };
33 
34 const StringMapping kContainerMap[] = {
35  {"mp4", "mov"},
36  {"webm", "matroska"},
37 };
38 const StringMapping kCodecMap[] = {
39  {"avc1", "h264"}, {"avc3", "h264"}, {"hev1", "hevc"},
40  {"hvc1", "hevc"}, {"vp09", "vp9"}, {"mp4a", "aac"},
41 };
42 
43 constexpr const char* kWhitespaceCharacters = " \f\n\r\t\v";
44 
46 bool IsToken(const std::string& token) {
47  return !token.empty() &&
48  token.find_first_of(R"(()<>@,;:\"/[]?=)") == std::string::npos &&
49  token.find_first_of(kWhitespaceCharacters) == std::string::npos;
50 }
51 
52 std::string substr_end(const std::string& source, std::string::size_type start,
53  std::string::size_type end) {
54  if (end == std::string::npos)
55  return source.substr(start);
56 
57  return source.substr(start, end - start);
58 }
59 
60 } // namespace
61 
62 bool ParseMimeType(const std::string& source, std::string* type,
63  std::string* subtype,
64  std::unordered_map<std::string, std::string>* params) {
65  // Extract type.
66  const auto type_end = source.find('/');
67  if (type_end == std::string::npos)
68  return false;
69  std::string type_tmp =
70  util::TrimAsciiWhitespace(substr_end(source, 0, type_end));
71  if (!IsToken(type_tmp))
72  return false;
73  if (type)
74  *type = std::move(type_tmp);
75 
76  // Extract subtype.
77  const auto subtype_end = source.find(';', type_end);
78  std::string subtype_tmp =
79  util::TrimAsciiWhitespace(substr_end(source, type_end + 1, subtype_end));
80  if (!IsToken(subtype_tmp))
81  return false;
82  if (subtype)
83  *subtype = std::move(subtype_tmp);
84 
85  // Extract parameters.
86  auto param_end = subtype_end;
87  while (param_end != std::string::npos) {
88  const auto name_end = source.find('=', param_end);
89  if (name_end == std::string::npos)
90  return false;
91 
92  const std::string param_name =
93  util::TrimAsciiWhitespace(substr_end(source, param_end + 1, name_end));
94  if (!IsToken(param_name))
95  return false;
96 
97  const auto value_start =
98  source.find_first_not_of(kWhitespaceCharacters, name_end + 1);
99  std::string value;
100  if (value_start == std::string::npos) {
101  param_end = std::string::npos;
102  value = "";
103  } else if (source[value_start] == '"') {
104  const auto str_end = source.find('"', value_start + 1);
105  if (str_end == std::string::npos)
106  return false;
107  value = substr_end(source, value_start + 1, str_end);
108  param_end = source.find(';', str_end);
109 
110  const std::string extra =
111  util::TrimAsciiWhitespace(substr_end(source, str_end + 1, param_end));
112  if (!extra.empty())
113  return false;
114  } else {
115  param_end = source.find(';', name_end);
117  substr_end(source, name_end + 1, param_end));
118  if (!IsToken(value))
119  return false;
120  }
121  if (params)
122  params->emplace(util::ToAsciiLower(param_name), value);
123  }
124 
125  return true;
126 }
127 
128 std::string NormalizeContainer(const std::string& container) {
129  for (const auto& entry : kContainerMap)
130  if (container == entry.source)
131  return entry.dest;
132  return container;
133 }
134 
135 std::string NormalizeCodec(const std::string& codec) {
136  const std::string simple_codec = codec.substr(0, codec.find('.'));
137  for (const auto& entry : kCodecMap)
138  if (simple_codec == entry.source)
139  return entry.dest;
140  return simple_codec;
141 }
142 
143 
145  const std::vector<BufferedRanges>& sources) {
146  if (sources.empty())
147  return BufferedRanges();
148 
149  BufferedRanges accumulated = sources[0];
150  for (auto& source : sources) {
151  BufferedRanges temp;
152  size_t acc_i = 0, source_i = 0;
153 
154  while (acc_i < accumulated.size() && source_i < source.size()) {
155  const double start =
156  std::max(accumulated[acc_i].start, source[source_i].start);
157  const double end = std::min(accumulated[acc_i].end, source[source_i].end);
158  if (end > start)
159  temp.emplace_back(start, end);
160 
161  if (accumulated[acc_i].end < source[source_i].end)
162  acc_i++;
163  else
164  source_i++;
165  }
166 
167  accumulated.swap(temp);
168  }
169 
170  return accumulated;
171 }
172 
174  const std::string& mime_type, MediaDecodingType type) {
176  info.type = type;
177  info.audio.content_type = info.video.content_type = mime_type;
178 
179  std::unordered_map<std::string, std::string> params;
180  if (ParseMimeType(mime_type, nullptr, nullptr, &params)) {
181  info.video.width = std::atol(params["width"].c_str());
182  info.video.height = std::atol(params["height"].c_str());
183  info.video.framerate = std::atof(params["framerate"].c_str());
184 
185  info.audio.channels =
186  static_cast<uint16_t>(std::atoi(params["channels"].c_str()));
187 
188  info.audio.bitrate = info.video.bitrate =
189  std::atoll(params["bitrate"].c_str());
190  }
191 
192  return info;
193 }
194 
195 #ifndef OS_IOS
196 std::pair<uint32_t, uint32_t> GetScreenResolution() {
197  return {UINT32_MAX, UINT32_MAX};
198 }
199 #endif
200 
201 } // namespace media
202 } // namespace shaka
std::string ToAsciiLower(const std::string &source)
Definition: utils.cc:76
bool ParseMimeType(const std::string &source, std::string *type, std::string *subtype, std::unordered_map< std::string, std::string > *params)
Definition: media_utils.cc:62
const char * dest
Definition: media_utils.cc:31
std::string NormalizeCodec(const std::string &codec)
Definition: media_utils.cc:135
const char * source
Definition: media_utils.cc:30
std::string NormalizeContainer(const std::string &container)
Definition: media_utils.cc:128
ExceptionCode type
MediaDecodingConfiguration ConvertMimeToDecodingConfiguration(const std::string &mime_type, MediaDecodingType type)
Definition: media_utils.cc:173
std::vector< BufferedRange > BufferedRanges
Definition: types.h:26
std::string TrimAsciiWhitespace(const std::string &source)
Definition: utils.cc:82
BufferedRanges IntersectionOfBufferedRanges(const std::vector< BufferedRanges > &sources)
Definition: media_utils.cc:144
std::pair< uint32_t, uint32_t > GetScreenResolution()
Definition: media_utils.cc:196