7 #include <packager/app/stream_descriptor.h>
9 #include <absl/log/log.h>
10 #include <absl/strings/numbers.h>
11 #include <absl/strings/str_split.h>
13 #include <packager/kv_pairs/kv_pairs.h>
14 #include <packager/utils/string_trim_split.h>
25 kSegmentTemplateField,
32 kHlsPlaylistNameField,
33 kHlsIframePlaylistNameField,
34 kTrickPlayFactorField,
37 kHlsCharacteristicsField,
38 kDashAccessiblitiesField,
47 struct FieldNameToTypeMapping {
48 const char* field_name;
52 const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
53 {
"stream_selector", kStreamSelectorField},
54 {
"stream", kStreamSelectorField},
55 {
"input", kInputField},
57 {
"output", kOutputField},
58 {
"out", kOutputField},
59 {
"init_segment", kOutputField},
60 {
"segment_template", kSegmentTemplateField},
61 {
"template", kSegmentTemplateField},
62 {
"bandwidth", kBandwidthField},
63 {
"bw", kBandwidthField},
64 {
"bitrate", kBandwidthField},
65 {
"language", kLanguageField},
66 {
"lang", kLanguageField},
67 {
"cc_index", kCcIndexField},
68 {
"output_format", kOutputFormatField},
69 {
"format", kOutputFormatField},
70 {
"hls_name", kHlsNameField},
71 {
"hls_group_id", kHlsGroupIdField},
72 {
"playlist_name", kHlsPlaylistNameField},
73 {
"iframe_playlist_name", kHlsIframePlaylistNameField},
74 {
"trick_play_factor", kTrickPlayFactorField},
75 {
"tpf", kTrickPlayFactorField},
76 {
"skip_encryption", kSkipEncryptionField},
77 {
"drm_stream_label", kDrmStreamLabelField},
78 {
"drm_label", kDrmStreamLabelField},
79 {
"hls_characteristics", kHlsCharacteristicsField},
80 {
"characteristics", kHlsCharacteristicsField},
81 {
"charcs", kHlsCharacteristicsField},
82 {
"dash_accessibilities", kDashAccessiblitiesField},
83 {
"dash_accessibility", kDashAccessiblitiesField},
84 {
"accessibilities", kDashAccessiblitiesField},
85 {
"accessibility", kDashAccessiblitiesField},
86 {
"dash_roles", kDashRolesField},
87 {
"dash_role", kDashRolesField},
88 {
"roles", kDashRolesField},
89 {
"role", kDashRolesField},
90 {
"dash_only", kDashOnlyField},
91 {
"hls_only", kHlsOnlyField},
92 {
"dash_label", kDashLabelField},
93 {
"forced_subtitle", kForcedSubtitleField},
94 {
"input_format", kInputFormatField},
97 FieldType GetFieldType(
const std::string& field_name) {
98 for (
size_t idx = 0; idx < std::size(kFieldNameTypeMappings); ++idx) {
99 if (field_name == kFieldNameTypeMappings[idx].field_name)
100 return kFieldNameTypeMappings[idx].field_type;
102 return kUnknownField;
108 const std::string& descriptor_string) {
109 StreamDescriptor descriptor;
112 std::vector<KVPair> kv_pairs =
113 SplitStringIntoKeyValuePairs(descriptor_string,
'=',
',');
114 if (kv_pairs.empty()) {
115 LOG(ERROR) <<
"Invalid stream descriptors name/value pairs: "
116 << descriptor_string;
119 std::vector<absl::string_view> tokens;
121 for (
const auto& pair : kv_pairs) {
122 switch (GetFieldType(pair.first)) {
123 case kStreamSelectorField:
124 descriptor.stream_selector = pair.second;
127 descriptor.input = pair.second;
130 descriptor.output = pair.second;
132 case kSegmentTemplateField:
133 descriptor.segment_template = pair.second;
135 case kBandwidthField: {
137 if (!absl::SimpleAtoi(pair.second, &bw)) {
138 LOG(ERROR) <<
"Non-numeric bandwidth specified.";
141 descriptor.bandwidth = bw;
144 case kLanguageField: {
145 descriptor.language = pair.second;
148 case kCcIndexField: {
150 if (!absl::SimpleAtoi(pair.second, &index)) {
151 LOG(ERROR) <<
"Non-numeric cc_index specified.";
154 descriptor.cc_index = index;
157 case kOutputFormatField: {
158 descriptor.output_format = pair.second;
161 case kHlsNameField: {
162 descriptor.hls_name = pair.second;
165 case kHlsGroupIdField: {
166 descriptor.hls_group_id = pair.second;
169 case kHlsPlaylistNameField: {
170 descriptor.hls_playlist_name = pair.second;
173 case kHlsIframePlaylistNameField: {
174 descriptor.hls_iframe_playlist_name = pair.second;
177 case kTrickPlayFactorField: {
179 if (!absl::SimpleAtoi(pair.second, &factor)) {
180 LOG(ERROR) <<
"Non-numeric trick play factor " << pair.second
185 LOG(ERROR) <<
"Stream trick_play_factor should be > 0.";
188 descriptor.trick_play_factor = factor;
191 case kSkipEncryptionField: {
192 unsigned skip_encryption_value;
193 if (!absl::SimpleAtoi(pair.second, &skip_encryption_value)) {
194 LOG(ERROR) <<
"Non-numeric option for skip encryption field "
196 << pair.second <<
").";
199 if (skip_encryption_value > 1) {
200 LOG(ERROR) <<
"skip_encryption should be either 0 or 1.";
204 descriptor.skip_encryption = skip_encryption_value > 0;
207 case kDrmStreamLabelField:
208 descriptor.drm_label = pair.second;
210 case kHlsCharacteristicsField:
211 descriptor.hls_characteristics =
212 SplitAndTrimSkipEmpty(pair.second,
';');
214 case kDashAccessiblitiesField: {
215 descriptor.dash_accessiblities =
216 SplitAndTrimSkipEmpty(pair.second,
';');
217 for (
const std::string& accessibility :
218 descriptor.dash_accessiblities) {
219 size_t pos = accessibility.find(
'=');
220 if (pos == std::string::npos) {
221 LOG(ERROR) <<
"Accessibility should be in scheme=value format, "
228 case kDashRolesField:
229 descriptor.dash_roles = SplitAndTrimSkipEmpty(pair.second,
';');
232 unsigned dash_only_value;
233 if (!absl::SimpleAtoi(pair.second, &dash_only_value)) {
234 LOG(ERROR) <<
"Non-numeric option for dash_only field "
236 << pair.second <<
").";
239 if (dash_only_value > 1) {
240 LOG(ERROR) <<
"dash_only should be either 0 or 1.";
243 descriptor.dash_only = dash_only_value > 0;
246 unsigned hls_only_value;
247 if (!absl::SimpleAtoi(pair.second, &hls_only_value)) {
248 LOG(ERROR) <<
"Non-numeric option for hls_only field "
250 << pair.second <<
").";
253 if (hls_only_value > 1) {
254 LOG(ERROR) <<
"hls_only should be either 0 or 1.";
257 descriptor.hls_only = hls_only_value > 0;
259 case kDashLabelField:
260 descriptor.dash_label = pair.second;
262 case kForcedSubtitleField:
263 unsigned forced_subtitle_value;
264 if (!absl::SimpleAtoi(pair.second, &forced_subtitle_value)) {
265 LOG(ERROR) <<
"Non-numeric option for forced field "
267 << pair.second <<
").";
270 if (forced_subtitle_value > 1) {
271 LOG(ERROR) <<
"forced should be either 0 or 1.";
274 descriptor.forced_subtitle = forced_subtitle_value > 0;
276 case kInputFormatField: {
277 descriptor.input_format = pair.second;
281 LOG(ERROR) <<
"Unknown field in stream descriptor (\"" << pair.first
287 if (descriptor.forced_subtitle) {
288 auto itr = std::find(descriptor.dash_roles.begin(),
289 descriptor.dash_roles.end(),
"forced-subtitle");
290 if (itr == descriptor.dash_roles.end()) {
291 descriptor.dash_roles.push_back(
"forced-subtitle");
All the methods that are virtual are virtual for mocking.
std::optional< StreamDescriptor > ParseStreamDescriptor(const std::string &descriptor_string)