DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
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/app/packager_util.h"
10 #include "packager/base/logging.h"
11 #include "packager/base/strings/string_number_conversions.h"
12 #include "packager/base/strings/string_split.h"
13 #include "packager/mpd/base/language_utils.h"
14 
15 namespace shaka {
16 namespace media {
17 
18 namespace {
19 
20 enum FieldType {
21  kUnknownField = 0,
22  kStreamSelectorField,
23  kInputField,
24  kOutputField,
25  kSegmentTemplateField,
26  kBandwidthField,
27  kLanguageField,
28  kOutputFormatField,
29  kHlsNameField,
30  kHlsGroupIdField,
31  kHlsPlaylistNameField,
32 };
33 
34 struct FieldNameToTypeMapping {
35  const char* field_name;
36  FieldType field_type;
37 };
38 
39 const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
40  {"stream_selector", kStreamSelectorField},
41  {"stream", kStreamSelectorField},
42  {"input", kInputField},
43  {"in", kInputField},
44  {"output", kOutputField},
45  {"out", kOutputField},
46  {"init_segment", kOutputField},
47  {"segment_template", kSegmentTemplateField},
48  {"template", kSegmentTemplateField},
49  {"bandwidth", kBandwidthField},
50  {"bw", kBandwidthField},
51  {"bitrate", kBandwidthField},
52  {"language", kLanguageField},
53  {"lang", kLanguageField},
54  {"output_format", kOutputFormatField},
55  {"format", kOutputFormatField},
56  {"hls_name", kHlsNameField},
57  {"hls_group_id", kHlsGroupIdField},
58  {"playlist_name", kHlsPlaylistNameField},
59 };
60 
61 FieldType GetFieldType(const std::string& field_name) {
62  for (size_t idx = 0; idx < arraysize(kFieldNameTypeMappings); ++idx) {
63  if (field_name == kFieldNameTypeMappings[idx].field_name)
64  return kFieldNameTypeMappings[idx].field_type;
65  }
66  return kUnknownField;
67 }
68 
69 } // anonymous namespace
70 
71 StreamDescriptor::StreamDescriptor()
72  : bandwidth(0), output_format(CONTAINER_UNKNOWN) {}
73 
74 StreamDescriptor::~StreamDescriptor() {}
75 
76 bool InsertStreamDescriptor(const std::string& descriptor_string,
77  StreamDescriptorList* descriptor_list) {
78  StreamDescriptor descriptor;
79 
80  // Split descriptor string into name/value pairs.
81  base::StringPairs pairs;
82  if (!base::SplitStringIntoKeyValuePairs(descriptor_string,
83  '=',
84  ',',
85  &pairs)) {
86  LOG(ERROR) << "Invalid stream descriptors name/value pairs.";
87  return false;
88  }
89  for (base::StringPairs::const_iterator iter = pairs.begin();
90  iter != pairs.end(); ++iter) {
91  switch (GetFieldType(iter->first)) {
92  case kStreamSelectorField:
93  descriptor.stream_selector = iter->second;
94  break;
95  case kInputField:
96  descriptor.input = iter->second;
97  break;
98  case kOutputField:
99  descriptor.output = iter->second;
100  break;
101  case kSegmentTemplateField:
102  descriptor.segment_template = iter->second;
103  break;
104  case kBandwidthField: {
105  unsigned bw;
106  if (!base::StringToUint(iter->second, &bw)) {
107  LOG(ERROR) << "Non-numeric bandwidth specified.";
108  return false;
109  }
110  descriptor.bandwidth = bw;
111  break;
112  }
113  case kLanguageField: {
114  std::string language = LanguageToISO_639_2(iter->second);
115  if (language == "und") {
116  LOG(ERROR) << "Unknown/invalid language specified: " << iter->second;
117  return false;
118  }
119  DCHECK_EQ(3u, language.size());
120  descriptor.language = language;
121  break;
122  }
123  case kOutputFormatField: {
124  MediaContainerName output_format =
125  DetermineContainerFromFormatName(iter->second);
126  if (output_format == CONTAINER_UNKNOWN) {
127  LOG(ERROR) << "Unrecognized output format " << iter->second;
128  return false;
129  }
130  descriptor.output_format = output_format;
131  break;
132  }
133  case kHlsNameField: {
134  descriptor.hls_name = iter->second;
135  break;
136  }
137  case kHlsGroupIdField: {
138  descriptor.hls_group_id = iter->second;
139  break;
140  }
141  case kHlsPlaylistNameField: {
142  descriptor.hls_playlist_name = iter->second;
143  break;
144  }
145  default:
146  LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first
147  << "\").";
148  return false;
149  break;
150  }
151  }
152  // Validate and insert the descriptor
153  if (descriptor.input.empty()) {
154  LOG(ERROR) << "Stream input not specified.";
155  return false;
156  }
157  if (!FLAGS_dump_stream_info && descriptor.stream_selector.empty()) {
158  LOG(ERROR) << "Stream stream_selector not specified.";
159  return false;
160  }
161 
162  // Note that MPEG2 TS doesn't need a separate initialization segment, so
163  // output field is ignored.
164  const bool is_mpeg2ts_with_segment_template =
165  descriptor.output_format == MediaContainerName::CONTAINER_MPEG2TS &&
166  !descriptor.segment_template.empty();
167  if (!FLAGS_dump_stream_info && descriptor.output.empty() &&
168  !is_mpeg2ts_with_segment_template) {
169  LOG(ERROR) << "Stream output not specified.";
170  return false;
171  }
172  descriptor_list->insert(descriptor);
173  return true;
174 }
175 
176 } // namespace media
177 } // namespace shaka
std::string LanguageToISO_639_2(const std::string &language)