7 #include "packager/media/base/muxer_util.h"
14 #include "packager/base/logging.h"
15 #include "packager/base/strings/string_number_conversions.h"
16 #include "packager/base/strings/string_split.h"
17 #include "packager/base/strings/stringprintf.h"
18 #include "packager/media/base/video_stream_info.h"
22 Status ValidateFormatTag(
const std::string& format_tag) {
23 if (format_tag.empty()) {
24 return Status(error::INVALID_ARGUMENT,
"Format tag should not be empty");
28 if (format_tag.size() > 3 && format_tag[0] ==
'%' && format_tag[1] ==
'0' &&
29 format_tag[format_tag.size() - 1] ==
'd') {
31 if (base::StringToUint(format_tag.substr(2, format_tag.size() - 3), &out)) {
37 error::INVALID_ARGUMENT,
38 "Format tag should follow this prototype: %0[width]d if exist.");
44 Status ValidateSegmentTemplate(
const std::string& segment_template) {
45 if (segment_template.empty()) {
46 return Status(error::INVALID_ARGUMENT,
47 "Segment template should not be empty.");
50 std::vector<std::string> splits = base::SplitString(
51 segment_template,
"$", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
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 uint64_t segment_start_time,
113 uint32_t segment_index,
114 uint32_t bandwidth) {
115 DCHECK_EQ(Status::OK, ValidateSegmentTemplate(segment_template));
117 std::vector<std::string> splits = base::SplitString(
118 segment_template,
"$", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
120 DCHECK_EQ(1u, splits.size() % 2);
122 std::string segment_name;
123 for (
size_t i = 0; i < splits.size(); ++i) {
127 segment_name += splits[i];
130 if (splits[i].empty()) {
135 size_t format_pos = splits[i].find(
'%');
136 std::string identifier = splits[i].substr(0, format_pos);
137 DCHECK(identifier ==
"Number" || identifier ==
"Time" ||
138 identifier ==
"Bandwidth");
140 std::string format_tag;
141 if (format_pos != std::string::npos) {
142 format_tag = splits[i].substr(format_pos);
143 DCHECK_EQ(Status::OK, ValidateFormatTag(format_tag));
145 format_tag = format_tag.substr(0, format_tag.size() - 1) + PRIu64;
148 format_tag =
"%01" PRIu64;
151 if (identifier ==
"Number") {
153 segment_name += base::StringPrintf(
154 format_tag.c_str(),
static_cast<uint64_t
>(segment_index + 1));
155 }
else if (identifier ==
"Time") {
157 base::StringPrintf(format_tag.c_str(), segment_start_time);
158 }
else if (identifier ==
"Bandwidth") {
159 segment_name += base::StringPrintf(format_tag.c_str(),
160 static_cast<uint64_t
>(bandwidth));