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/media/base/container_names.h"
14 #include "packager/mpd/base/language_utils.h"
15 
16 namespace shaka {
17 namespace media {
18 
19 namespace {
20 
21 enum FieldType {
22  kUnknownField = 0,
23  kStreamSelectorField,
24  kInputField,
25  kOutputField,
26  kSegmentTemplateField,
27  kBandwidthField,
28  kLanguageField,
29  kOutputFormatField,
30  kHlsNameField,
31  kHlsGroupIdField,
32  kHlsPlaylistNameField,
33 };
34 
35 struct FieldNameToTypeMapping {
36  const char* field_name;
37  FieldType field_type;
38 };
39 
40 const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
41  {"stream_selector", kStreamSelectorField},
42  {"stream", kStreamSelectorField},
43  {"input", kInputField},
44  {"in", kInputField},
45  {"output", kOutputField},
46  {"out", kOutputField},
47  {"init_segment", kOutputField},
48  {"segment_template", kSegmentTemplateField},
49  {"template", kSegmentTemplateField},
50  {"bandwidth", kBandwidthField},
51  {"bw", kBandwidthField},
52  {"bitrate", kBandwidthField},
53  {"language", kLanguageField},
54  {"lang", kLanguageField},
55  {"output_format", kOutputFormatField},
56  {"format", kOutputFormatField},
57  {"hls_name", kHlsNameField},
58  {"hls_group_id", kHlsGroupIdField},
59  {"playlist_name", kHlsPlaylistNameField},
60 };
61 
62 FieldType GetFieldType(const std::string& field_name) {
63  for (size_t idx = 0; idx < arraysize(kFieldNameTypeMappings); ++idx) {
64  if (field_name == kFieldNameTypeMappings[idx].field_name)
65  return kFieldNameTypeMappings[idx].field_type;
66  }
67  return kUnknownField;
68 }
69 
70 } // anonymous namespace
71 
72 StreamDescriptor::StreamDescriptor()
73  : bandwidth(0), output_format(CONTAINER_UNKNOWN) {}
74 
75 StreamDescriptor::~StreamDescriptor() {}
76 
77 bool InsertStreamDescriptor(const std::string& descriptor_string,
78  StreamDescriptorList* descriptor_list) {
79  StreamDescriptor descriptor;
80 
81  // Split descriptor string into name/value pairs.
82  base::StringPairs pairs;
83  if (!base::SplitStringIntoKeyValuePairs(descriptor_string,
84  '=',
85  ',',
86  &pairs)) {
87  LOG(ERROR) << "Invalid stream descriptors name/value pairs.";
88  return false;
89  }
90  for (base::StringPairs::const_iterator iter = pairs.begin();
91  iter != pairs.end(); ++iter) {
92  switch (GetFieldType(iter->first)) {
93  case kStreamSelectorField:
94  descriptor.stream_selector = iter->second;
95  break;
96  case kInputField:
97  descriptor.input = iter->second;
98  break;
99  case kOutputField:
100  descriptor.output = iter->second;
101  break;
102  case kSegmentTemplateField:
103  descriptor.segment_template = iter->second;
104  break;
105  case kBandwidthField: {
106  unsigned bw;
107  if (!base::StringToUint(iter->second, &bw)) {
108  LOG(ERROR) << "Non-numeric bandwidth specified.";
109  return false;
110  }
111  descriptor.bandwidth = bw;
112  break;
113  }
114  case kLanguageField: {
115  std::string language = LanguageToISO_639_2(iter->second);
116  if (language == "und") {
117  LOG(ERROR) << "Unknown/invalid language specified: " << iter->second;
118  return false;
119  }
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  if (descriptor.output_format == CONTAINER_UNKNOWN) {
163  const std::string& output_name = descriptor.output.empty()
164  ? descriptor.segment_template
165  : descriptor.output;
166  if (!output_name.empty()) {
167  descriptor.output_format = DetermineContainerFromFileName(output_name);
168  if (descriptor.output_format == CONTAINER_UNKNOWN) {
169  LOG(ERROR) << "Unable to determine output format for file "
170  << output_name;
171  return false;
172  }
173  }
174  }
175 
176  if (descriptor.output_format == MediaContainerName::CONTAINER_MPEG2TS) {
177  if (descriptor.segment_template.empty()) {
178  LOG(ERROR) << "Please specify segment_template. Single file TS output is "
179  "not supported.";
180  return false;
181  }
182  // Note that MPEG2 TS doesn't need a separate initialization segment, so
183  // output field is not needed.
184  if (!descriptor.output.empty()) {
185  LOG(WARNING) << "TS output '" << descriptor.output
186  << "' ignored. TS muxer does not support initialization "
187  "segment generation.";
188  }
189  // For convenience, set descriptor.output to descriptor.segment_template. It
190  // is only used for flag checking in variuos places.
191  descriptor.output = descriptor.segment_template;
192  }
193 
194  if (!FLAGS_dump_stream_info && descriptor.output.empty()) {
195  LOG(ERROR) << "Stream output not specified.";
196  return false;
197  }
198  descriptor_list->insert(descriptor);
199  return true;
200 }
201 
202 } // namespace media
203 } // namespace shaka
std::string LanguageToISO_639_2(const std::string &language)