7 #include <packager/media/base/muxer_util.h>
13 #include <absl/log/check.h>
14 #include <absl/log/log.h>
15 #include <absl/strings/numbers.h>
16 #include <absl/strings/str_format.h>
17 #include <absl/strings/str_split.h>
19 #include <packager/media/base/video_stream_info.h>
23 Status ValidateFormatTag(
const std::string& format_tag) {
24 if (format_tag.empty()) {
25 return Status(error::INVALID_ARGUMENT,
"Format tag should not be empty");
29 if (format_tag.size() > 3 && format_tag[0] ==
'%' && format_tag[1] ==
'0' &&
30 format_tag[format_tag.size() - 1] ==
'd') {
32 if (absl::SimpleAtoi(format_tag.substr(2, format_tag.size() - 3), &out)) {
38 error::INVALID_ARGUMENT,
39 "Format tag should follow this prototype: %0[width]d if exist.");
45 Status ValidateSegmentTemplate(
const std::string& segment_template) {
46 if (segment_template.empty()) {
47 return Status(error::INVALID_ARGUMENT,
48 "Segment template should not be empty.");
51 std::vector<std::string> splits = absl::StrSplit(segment_template,
"$");
56 if (splits.size() % 2 == 0) {
57 return Status(error::INVALID_ARGUMENT,
58 "In segment templates, '$' should appear in pairs.");
61 bool has_number =
false;
62 bool has_time =
false;
64 for (
size_t i = 1; i < splits.size(); i += 2) {
68 size_t format_pos = splits[i].find(
'%');
69 std::string identifier = splits[i].substr(0, format_pos);
70 if (format_pos != std::string::npos) {
71 Status tag_check = ValidateFormatTag(splits[i].substr(format_pos));
72 if (!tag_check.ok()) {
78 if (identifier ==
"RepresentationID") {
81 "Segment template flag $RepresentationID$ is not supported yet.");
82 }
else if (identifier ==
"Number") {
84 }
else if (identifier ==
"Time") {
86 }
else if (identifier ==
"") {
87 if (format_pos != std::string::npos) {
88 return Status(error::INVALID_ARGUMENT,
89 "'$$' should not have any format tags.");
91 }
else if (identifier !=
"Bandwidth") {
92 return Status(error::INVALID_ARGUMENT,
93 "'$" + splits[i] +
"$' is not a valid identifier.");
96 if (has_number && has_time) {
98 error::INVALID_ARGUMENT,
99 "In segment templates $Number$ and $Time$ should not co-exist.");
101 if (!has_number && !has_time) {
102 return Status(error::INVALID_ARGUMENT,
103 "In segment templates $Number$ or $Time$ should exist.");
111 std::string GetSegmentName(
const std::string& segment_template,
112 int64_t segment_start_time,
113 uint32_t segment_number,
114 uint32_t bandwidth) {
115 DCHECK_EQ(Status::OK, ValidateSegmentTemplate(segment_template));
117 std::vector<std::string> splits = absl::StrSplit(segment_template,
"$");
119 DCHECK_EQ(1u, splits.size() % 2);
121 std::string segment_name;
122 for (
size_t i = 0; i < splits.size(); ++i) {
126 segment_name += splits[i];
129 if (splits[i].empty()) {
134 size_t format_pos = splits[i].find(
'%');
135 std::string identifier = splits[i].substr(0, format_pos);
136 DCHECK(identifier ==
"Number" || identifier ==
"Time" ||
137 identifier ==
"Bandwidth");
139 std::string format_tag;
140 if (format_pos != std::string::npos) {
141 format_tag = splits[i].substr(format_pos);
142 DCHECK_EQ(Status::OK, ValidateFormatTag(format_tag));
144 format_tag = format_tag.substr(0, format_tag.size() - 1) + PRIu64;
147 format_tag =
"%01" PRIu64;
153 std::vector<absl::FormatArg> format_args;
154 absl::UntypedFormatSpec format(format_tag);
155 if (identifier ==
"Number") {
157 format_args.emplace_back(
static_cast<uint64_t
>(segment_number));
158 }
else if (identifier ==
"Time") {
159 format_args.emplace_back(
static_cast<uint64_t
>(segment_start_time));
160 }
else if (identifier ==
"Bandwidth") {
161 format_args.emplace_back(
static_cast<uint64_t
>(bandwidth));
164 std::string format_output;
165 if (absl::FormatUntyped(&format_output, format, format_args)) {
166 segment_name += format_output;
All the methods that are virtual are virtual for mocking.