Shaka Packager SDK
stream_descriptor.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/app/stream_descriptor.h"
8 
9 #include "packager/base/logging.h"
10 #include "packager/base/strings/string_number_conversions.h"
11 #include "packager/base/strings/string_split.h"
12 
13 namespace shaka {
14 
15 namespace {
16 
17 enum FieldType {
18  kUnknownField = 0,
19  kStreamSelectorField,
20  kInputField,
21  kOutputField,
22  kSegmentTemplateField,
23  kBandwidthField,
24  kLanguageField,
25  kCcIndexField,
26  kOutputFormatField,
27  kHlsNameField,
28  kHlsGroupIdField,
29  kHlsPlaylistNameField,
30  kHlsIframePlaylistNameField,
31  kTrickPlayFactorField,
32  kSkipEncryptionField,
33  kDrmStreamLabelField,
34  kHlsCharacteristicsField,
35  kDashAccessiblitiesField,
36  kDashRolesField,
37  kDashOnlyField,
38  kHlsOnlyField,
39 };
40 
41 struct FieldNameToTypeMapping {
42  const char* field_name;
43  FieldType field_type;
44 };
45 
46 const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
47  {"stream_selector", kStreamSelectorField},
48  {"stream", kStreamSelectorField},
49  {"input", kInputField},
50  {"in", kInputField},
51  {"output", kOutputField},
52  {"out", kOutputField},
53  {"init_segment", kOutputField},
54  {"segment_template", kSegmentTemplateField},
55  {"template", kSegmentTemplateField},
56  {"bandwidth", kBandwidthField},
57  {"bw", kBandwidthField},
58  {"bitrate", kBandwidthField},
59  {"language", kLanguageField},
60  {"lang", kLanguageField},
61  {"cc_index", kCcIndexField},
62  {"output_format", kOutputFormatField},
63  {"format", kOutputFormatField},
64  {"hls_name", kHlsNameField},
65  {"hls_group_id", kHlsGroupIdField},
66  {"playlist_name", kHlsPlaylistNameField},
67  {"iframe_playlist_name", kHlsIframePlaylistNameField},
68  {"trick_play_factor", kTrickPlayFactorField},
69  {"tpf", kTrickPlayFactorField},
70  {"skip_encryption", kSkipEncryptionField},
71  {"drm_stream_label", kDrmStreamLabelField},
72  {"drm_label", kDrmStreamLabelField},
73  {"hls_characteristics", kHlsCharacteristicsField},
74  {"characteristics", kHlsCharacteristicsField},
75  {"charcs", kHlsCharacteristicsField},
76  {"dash_accessibilities", kDashAccessiblitiesField},
77  {"dash_accessibility", kDashAccessiblitiesField},
78  {"accessibilities", kDashAccessiblitiesField},
79  {"accessibility", kDashAccessiblitiesField},
80  {"dash_roles", kDashRolesField},
81  {"dash_role", kDashRolesField},
82  {"roles", kDashRolesField},
83  {"role", kDashRolesField},
84  {"dash_only", kDashOnlyField},
85  {"hls_only", kHlsOnlyField},
86 };
87 
88 FieldType GetFieldType(const std::string& field_name) {
89  for (size_t idx = 0; idx < arraysize(kFieldNameTypeMappings); ++idx) {
90  if (field_name == kFieldNameTypeMappings[idx].field_name)
91  return kFieldNameTypeMappings[idx].field_type;
92  }
93  return kUnknownField;
94 }
95 
96 } // anonymous namespace
97 
98 base::Optional<StreamDescriptor> ParseStreamDescriptor(
99  const std::string& descriptor_string) {
100  StreamDescriptor descriptor;
101 
102  // Split descriptor string into name/value pairs.
103  base::StringPairs pairs;
104  if (!base::SplitStringIntoKeyValuePairs(descriptor_string, '=', ',',
105  &pairs)) {
106  LOG(ERROR) << "Invalid stream descriptors name/value pairs: "
107  << descriptor_string;
108  return base::nullopt;
109  }
110  for (base::StringPairs::const_iterator iter = pairs.begin();
111  iter != pairs.end(); ++iter) {
112  switch (GetFieldType(iter->first)) {
113  case kStreamSelectorField:
114  descriptor.stream_selector = iter->second;
115  break;
116  case kInputField:
117  descriptor.input = iter->second;
118  break;
119  case kOutputField:
120  descriptor.output = iter->second;
121  break;
122  case kSegmentTemplateField:
123  descriptor.segment_template = iter->second;
124  break;
125  case kBandwidthField: {
126  unsigned bw;
127  if (!base::StringToUint(iter->second, &bw)) {
128  LOG(ERROR) << "Non-numeric bandwidth specified.";
129  return base::nullopt;
130  }
131  descriptor.bandwidth = bw;
132  break;
133  }
134  case kLanguageField: {
135  descriptor.language = iter->second;
136  break;
137  }
138  case kCcIndexField: {
139  unsigned index;
140  if (!base::StringToUint(iter->second, &index)) {
141  LOG(ERROR) << "Non-numeric cc_index specified.";
142  return base::nullopt;
143  }
144  descriptor.cc_index = index;
145  break;
146  }
147  case kOutputFormatField: {
148  descriptor.output_format = iter->second;
149  break;
150  }
151  case kHlsNameField: {
152  descriptor.hls_name = iter->second;
153  break;
154  }
155  case kHlsGroupIdField: {
156  descriptor.hls_group_id = iter->second;
157  break;
158  }
159  case kHlsPlaylistNameField: {
160  descriptor.hls_playlist_name = iter->second;
161  break;
162  }
163  case kHlsIframePlaylistNameField: {
164  descriptor.hls_iframe_playlist_name = iter->second;
165  break;
166  }
167  case kTrickPlayFactorField: {
168  unsigned factor;
169  if (!base::StringToUint(iter->second, &factor)) {
170  LOG(ERROR) << "Non-numeric trick play factor " << iter->second
171  << " specified.";
172  return base::nullopt;
173  }
174  if (factor == 0) {
175  LOG(ERROR) << "Stream trick_play_factor should be > 0.";
176  return base::nullopt;
177  }
178  descriptor.trick_play_factor = factor;
179  break;
180  }
181  case kSkipEncryptionField: {
182  unsigned skip_encryption_value;
183  if (!base::StringToUint(iter->second, &skip_encryption_value)) {
184  LOG(ERROR) << "Non-numeric option for skip encryption field "
185  "specified (" << iter->second << ").";
186  return base::nullopt;
187  }
188  if (skip_encryption_value > 1) {
189  LOG(ERROR) << "skip_encryption should be either 0 or 1.";
190  return base::nullopt;
191  }
192 
193  descriptor.skip_encryption = skip_encryption_value > 0;
194  break;
195  }
196  case kDrmStreamLabelField:
197  descriptor.drm_label = iter->second;
198  break;
199  case kHlsCharacteristicsField:
200  descriptor.hls_characteristics =
201  base::SplitString(iter->second, ";:", base::TRIM_WHITESPACE,
202  base::SPLIT_WANT_NONEMPTY);
203  break;
204  case kDashAccessiblitiesField:
205  descriptor.dash_accessiblities =
206  base::SplitString(iter->second, ";", base::TRIM_WHITESPACE,
207  base::SPLIT_WANT_NONEMPTY);
208  for (const std::string& accessibility :
209  descriptor.dash_accessiblities) {
210  size_t pos = accessibility.find('=');
211  if (pos == std::string::npos) {
212  LOG(ERROR)
213  << "Accessibility should be in scheme=value format, but seeing "
214  << accessibility;
215  return base::nullopt;
216  }
217  }
218  break;
219  case kDashRolesField:
220  descriptor.dash_roles =
221  base::SplitString(iter->second, ";", base::TRIM_WHITESPACE,
222  base::SPLIT_WANT_NONEMPTY);
223  break;
224  case kDashOnlyField:
225  unsigned dash_only_value;
226  if (!base::StringToUint(iter->second, &dash_only_value)) {
227  LOG(ERROR) << "Non-numeric option for dash_only field "
228  "specified (" << iter->second << ").";
229  return base::nullopt;
230  }
231  if (dash_only_value > 1) {
232  LOG(ERROR) << "dash_only should be either 0 or 1.";
233  return base::nullopt;
234  }
235  descriptor.dash_only = dash_only_value > 0;
236  break;
237  case kHlsOnlyField:
238  unsigned hls_only_value;
239  if (!base::StringToUint(iter->second, &hls_only_value)) {
240  LOG(ERROR) << "Non-numeric option for hls_only field "
241  "specified (" << iter->second << ").";
242  return base::nullopt;
243  }
244  if (hls_only_value > 1) {
245  LOG(ERROR) << "hls_only should be either 0 or 1.";
246  return base::nullopt;
247  }
248  descriptor.hls_only = hls_only_value > 0;
249  break;
250  default:
251  LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first
252  << "\").";
253  return base::nullopt;
254  }
255  }
256  return descriptor;
257 }
258 
259 } // namespace shaka
All the methods that are virtual are virtual for mocking.
base::Optional< StreamDescriptor > ParseStreamDescriptor(const std::string &descriptor_string)
Defines a single input/output stream.
Definition: packager.h:76
std::string output_format
Definition: packager.h:92
std::vector< std::string > dash_accessiblities
Optional for DASH output. It defines Accessibility elements of the stream.
Definition: packager.h:135
std::string hls_iframe_playlist_name
Definition: packager.h:129
std::string output
Definition: packager.h:86
std::vector< std::string > dash_roles
Optional for DASH output. It defines Role elements of the stream.
Definition: packager.h:137
std::string hls_group_id
Definition: packager.h:123
bool dash_only
Set to true to indicate that the stream is for dash only.
Definition: packager.h:140
std::string stream_selector
Definition: packager.h:82
uint32_t trick_play_factor
Definition: packager.h:104
bool hls_only
Set to true to indicate that the stream is for hls only.
Definition: packager.h:142
std::string drm_label
Definition: packager.h:100
std::string hls_name
Definition: packager.h:120
std::string hls_playlist_name
Definition: packager.h:126
std::vector< std::string > hls_characteristics
Definition: packager.h:132
std::string input
Input/source media file path or network stream URL. Required.
Definition: packager.h:78
std::string language
Definition: packager.h:111
std::string segment_template
Specifies segment template. Can be empty.
Definition: packager.h:88