From ec83d8a73ae64cc694c52d1b63d4135f76a86cb9 Mon Sep 17 00:00:00 2001 From: Aaron Vaage Date: Thu, 17 Aug 2017 11:09:34 -0700 Subject: [PATCH] Implement MsToWebVTTTimestamp Implemented the other end of the webvtt timestamp parsing as it will be needed when we write out WebVtt files. Also changed the name of the parse function to be more inline with the writing function. Change-Id: I1f36ddbbf80028732b4cb1b15e871dec17767f63 --- .../formats/webvtt/webvtt_media_parser.cc | 4 +- .../media/formats/webvtt/webvtt_timestamp.cc | 42 +++++++----- .../media/formats/webvtt/webvtt_timestamp.h | 5 +- .../webvtt/webvtt_timestamp_unittest.cc | 65 ++++++++++++++----- 4 files changed, 83 insertions(+), 33 deletions(-) diff --git a/packager/media/formats/webvtt/webvtt_media_parser.cc b/packager/media/formats/webvtt/webvtt_media_parser.cc index a18b6c12e3..615f03036a 100644 --- a/packager/media/formats/webvtt/webvtt_media_parser.cc +++ b/packager/media/formats/webvtt/webvtt_media_parser.cc @@ -93,14 +93,14 @@ bool ParseTimingAndSettingsLine(const std::string& line, } const std::string& start_time_str = entries[0]; - if (!WebVttTimestampParse(start_time_str, start_time)) { + if (!WebVttTimestampToMs(start_time_str, start_time)) { LOG(ERROR) << "Failed to parse " << start_time_str << " in " << line; return false; } const std::string& end_time_str = entries[2]; uint64_t end_time = 0; - if (!WebVttTimestampParse(end_time_str, &end_time)) { + if (!WebVttTimestampToMs(end_time_str, &end_time)) { LOG(ERROR) << "Failed to parse " << end_time_str << " in " << line; return false; } diff --git a/packager/media/formats/webvtt/webvtt_timestamp.cc b/packager/media/formats/webvtt/webvtt_timestamp.cc index 2f2810e2cf..0ef67aa2e8 100644 --- a/packager/media/formats/webvtt/webvtt_timestamp.cc +++ b/packager/media/formats/webvtt/webvtt_timestamp.cc @@ -7,9 +7,11 @@ #include "packager/media/formats/webvtt/webvtt_timestamp.h" #include +#include #include "packager/base/logging.h" #include "packager/base/strings/string_number_conversions.h" +#include "packager/base/strings/stringprintf.h" namespace shaka { namespace media { @@ -22,22 +24,17 @@ bool GetTotalMilliseconds(uint64_t hours, uint64_t* out) { DCHECK(out); if (minutes > 59 || seconds > 59 || ms > 999) { - VLOG(1) << "Hours:" << hours - << " Minutes:" << minutes - << " Seconds:" << seconds - << " MS:" << ms + VLOG(1) << "Hours:" << hours << " Minutes:" << minutes + << " Seconds:" << seconds << " MS:" << ms << " shoud have never made it to GetTotalMilliseconds"; return false; } - *out = 60 * 60 * 1000 * hours + - 60 * 1000 * minutes + - 1000 * seconds + - ms; + *out = 60 * 60 * 1000 * hours + 60 * 1000 * minutes + 1000 * seconds + ms; return true; } } // namespace -bool WebVttTimestampParse(const base::StringPiece& source, uint64_t* out) { +bool WebVttTimestampToMs(const base::StringPiece& source, uint64_t* out) { DCHECK(out); if (source.length() < 9) { @@ -54,13 +51,12 @@ bool WebVttTimestampParse(const base::StringPiece& source, uint64_t* out) { uint64_t seconds = 0; uint64_t ms = 0; - const bool has_hours = minutes_begin >= 3 && - source[minutes_begin-1] == ':' && - base::StringToUint64(source.substr(0, minutes_begin-1), &hours); + const bool has_hours = + minutes_begin >= 3 && source[minutes_begin - 1] == ':' && + base::StringToUint64(source.substr(0, minutes_begin - 1), &hours); - if ((minutes_begin == 0 || has_hours) && - source[seconds_begin-1] == ':' && - source[milliseconds_begin-1] == '.' && + if ((minutes_begin == 0 || has_hours) && source[seconds_begin - 1] == ':' && + source[milliseconds_begin - 1] == '.' && base::StringToUint64(source.substr(minutes_begin, 2), &minutes) && base::StringToUint64(source.substr(seconds_begin, 2), &seconds) && base::StringToUint64(source.substr(milliseconds_begin, 3), &ms)) { @@ -70,5 +66,21 @@ bool WebVttTimestampParse(const base::StringPiece& source, uint64_t* out) { LOG(WARNING) << "Timestamp '" << source << "' is mal-formed"; return false; } + +std::string MsToWebVttTimestamp(uint64_t ms) { + uint64_t remaining = ms; + + uint64_t only_ms = remaining % 1000; + remaining /= 1000; + uint64_t only_seconds = remaining % 60; + remaining /= 60; + uint64_t only_minutes = remaining % 60; + remaining /= 60; + uint64_t only_hours = remaining; + + return base::StringPrintf("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 + ".%03" PRIu64, + only_hours, only_minutes, only_seconds, only_ms); +} } // namespace media } // namespace shaka diff --git a/packager/media/formats/webvtt/webvtt_timestamp.h b/packager/media/formats/webvtt/webvtt_timestamp.h index 3bdc65f434..088ab290a5 100644 --- a/packager/media/formats/webvtt/webvtt_timestamp.h +++ b/packager/media/formats/webvtt/webvtt_timestamp.h @@ -18,7 +18,10 @@ namespace media { // Parse a timestamp into milliseconds using the two patterns defined by WebVtt: // LONG : ##:##:##.### (long can have 2 or more hour digits) // SHORT : ##:##:### -bool WebVttTimestampParse(const base::StringPiece& source, uint64_t* out); +bool WebVttTimestampToMs(const base::StringPiece& source, uint64_t* out); + +// Create a long form timestamp encoded as a string. +std::string MsToWebVttTimestamp(uint64_t ms); } // namespace media } // namespace shaka diff --git a/packager/media/formats/webvtt/webvtt_timestamp_unittest.cc b/packager/media/formats/webvtt/webvtt_timestamp_unittest.cc index 5cb855df51..9f5ab09075 100644 --- a/packager/media/formats/webvtt/webvtt_timestamp_unittest.cc +++ b/packager/media/formats/webvtt/webvtt_timestamp_unittest.cc @@ -13,84 +13,119 @@ namespace media { TEST(WebVttTimestampTest, TooShort) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("00.000", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("00.000", &ms)); } TEST(WebVttTimestampTest, RightLengthButMeaningless) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("ABCDEFGHI", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("ABCDEFGHI", &ms)); } TEST(WebVttTimestampTest, ParseHours) { uint64_t ms; - EXPECT_TRUE(WebVttTimestampParse("12:00:00.000", &ms)); + EXPECT_TRUE(WebVttTimestampToMs("12:00:00.000", &ms)); EXPECT_EQ(43200000u, ms); } TEST(WebVttTimestampTest, ParseLongHours) { uint64_t ms; - EXPECT_TRUE(WebVttTimestampParse("120:00:00.000", &ms)); + EXPECT_TRUE(WebVttTimestampToMs("120:00:00.000", &ms)); EXPECT_EQ(432000000u, ms); } TEST(WebVttTimestampTest, ParseMinutes) { uint64_t ms; - EXPECT_TRUE(WebVttTimestampParse("00:12:00.000", &ms)); + EXPECT_TRUE(WebVttTimestampToMs("00:12:00.000", &ms)); EXPECT_EQ(720000u, ms); } TEST(WebVttTimestampTest, ParseSeconds) { uint64_t ms; - EXPECT_TRUE(WebVttTimestampParse("00:00:12.000", &ms)); + EXPECT_TRUE(WebVttTimestampToMs("00:00:12.000", &ms)); EXPECT_EQ(12000u, ms); } TEST(WebVttTimestampTest, ParseMs) { uint64_t ms; - EXPECT_TRUE(WebVttTimestampParse("00:00:00.123", &ms)); + EXPECT_TRUE(WebVttTimestampToMs("00:00:00.123", &ms)); EXPECT_EQ(123u, ms); } TEST(WebVttTimestampTest, ParseNoHours) { uint64_t ms; - EXPECT_TRUE(WebVttTimestampParse("12:00.000", &ms)); + EXPECT_TRUE(WebVttTimestampToMs("12:00.000", &ms)); EXPECT_EQ(720000u, ms); } TEST(WebVttTimestampTest, FailWithShortHours) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("1:00:00.000", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("1:00:00.000", &ms)); } TEST(WebVttTimestampTest, FailWithShortMinutes) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("00:1:00.000", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("00:1:00.000", &ms)); } TEST(WebVttTimestampTest, FailWithShortSeconds) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("00:1.000", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("00:1.000", &ms)); } TEST(WebVttTimestampTest, FailWithShortMs) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("00:00.01", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("00:00.01", &ms)); } TEST(WebVttTimestampTest, FailWithNonDigit) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("00:0A:00.000", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("00:0A:00.000", &ms)); } TEST(WebVttTimestampTest, FailWithInvalidMinutes) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("00:79:00.000", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("00:79:00.000", &ms)); } TEST(WebVttTimestampTest, FailWithInvalidSeconds) { uint64_t ms; - EXPECT_FALSE(WebVttTimestampParse("00:00:79.000", &ms)); + EXPECT_FALSE(WebVttTimestampToMs("00:00:79.000", &ms)); } +TEST(WebVttTimestampTest, CreatesMilliseconds) { + EXPECT_EQ("00:00:00.123", MsToWebVttTimestamp(123)); +} + +TEST(WebVttTimestampTest, CreatesMillisecondsShort) { + EXPECT_EQ("00:00:00.012", MsToWebVttTimestamp(12)); +} + +TEST(WebVttTimestampTest, CreateSeconds) { + EXPECT_EQ("00:00:12.000", MsToWebVttTimestamp(12000)); +} + +TEST(WebVttTimestampTest, CreateSecondsShort) { + EXPECT_EQ("00:00:01.000", MsToWebVttTimestamp(1000)); +} + +TEST(WebVttTimestampTest, CreateMinutes) { + EXPECT_EQ("00:12:00.000", MsToWebVttTimestamp(720000)); +} + +TEST(WebVttTimestampTest, CreateMinutesShort) { + EXPECT_EQ("00:01:00.000", MsToWebVttTimestamp(60000)); +} + +TEST(WebVttTimestampTest, CreateHours) { + EXPECT_EQ("12:00:00.000", MsToWebVttTimestamp(43200000)); +} + +TEST(WebVttTimestampTest, CreateHoursShort) { + EXPECT_EQ("01:00:00.000", MsToWebVttTimestamp(3600000)); +} + +TEST(WebVttTimestampTest, CreateHoursLong) { + EXPECT_EQ("123:00:00.000", MsToWebVttTimestamp(442800000)); +} } // namespace media } // namespace shaka