feat: port HLS module to CMake (#1238)

related to issue #1047
This commit is contained in:
Cosmin Stejerean 2023-08-21 18:41:18 -07:00 committed by GitHub
parent 682ac3c990
commit ab8485c5b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 296 additions and 298 deletions

View File

@ -20,6 +20,7 @@ Anders Hasselqvist <anders.hasselqvist@gmail.com>
Audible <*@audible.com> Audible <*@audible.com>
Chun-da Chen <capitalm.c@gmail.com> Chun-da Chen <capitalm.c@gmail.com>
Daniel Cantarín <canta@canta.com.ar> Daniel Cantarín <canta@canta.com.ar>
Dennis E. Mungai (Brainiarc7) <dmngaie@gmail.com>
Dolby Laboratories <*@dolby.com> Dolby Laboratories <*@dolby.com>
Evgeny Zajcev <zevlg@yandex.ru> Evgeny Zajcev <zevlg@yandex.ru>
Eyevinn Technology AB <*@eyevinn.se> Eyevinn Technology AB <*@eyevinn.se>
@ -27,13 +28,14 @@ Google LLC. <*@google.com>
Ivi.ru LLC <*@ivi.ru> Ivi.ru LLC <*@ivi.ru>
Leandro Moreira <leandro.ribeiro.moreira@gmail.com> Leandro Moreira <leandro.ribeiro.moreira@gmail.com>
Leo Law <leoltlaw.gh@gmail.com> Leo Law <leoltlaw.gh@gmail.com>
Meta Platforms, Inc. <*@meta.com>
More Screens Ltd. <*@morescreens.net> More Screens Ltd. <*@morescreens.net>
Ole Andre Birkedal <o.birkedal@sportradar.com> Ole Andre Birkedal <o.birkedal@sportradar.com>
Philo Inc. <*@philo.com> Philo Inc. <*@philo.com>
Piotr Srebrny <srebrny.piotr@gmail.com> Piotr Srebrny <srebrny.piotr@gmail.com>
Prakash Duggaraju <duggaraju@gmail.com>
Richard Eklycke <richard@eklycke.se> Richard Eklycke <richard@eklycke.se>
Sanil Raut <sr1990003@gmail.com> Sanil Raut <sr1990003@gmail.com>
Sergio Ammirata <sergio@ammirata.net> Sergio Ammirata <sergio@ammirata.net>
The Chromium Authors <*@chromium.org> The Chromium Authors <*@chromium.org>
Prakash Duggaraju <duggaraju@gmail.com>
Dennis E. Mungai (Brainiarc7) <dmngaie@gmail.com>

View File

@ -27,8 +27,10 @@ Anders Hasselqvist <anders.hasselqvist@gmail.com>
Andreas Motl <andreas.motl@elmyra.de> Andreas Motl <andreas.motl@elmyra.de>
Bei Li <beil@google.com> Bei Li <beil@google.com>
Chun-da Chen <capitalm.c@gmail.com> Chun-da Chen <capitalm.c@gmail.com>
Cosmin Stejerean <cstejerean@meta.com>
Daniel Cantarín <canta@canta.com.ar> Daniel Cantarín <canta@canta.com.ar>
David Cavar <pal3thorn@gmail.com> David Cavar <pal3thorn@gmail.com>
Dennis E. Mungai (Brainiarc7) <dmngaie@gmail.com>
Evgeny Zajcev <zevlg@yandex.ru> Evgeny Zajcev <zevlg@yandex.ru>
Gabe Kopley <gabe@philo.com> Gabe Kopley <gabe@philo.com>
Geoff Jukes <geoff@jukes.org> Geoff Jukes <geoff@jukes.org>
@ -42,6 +44,7 @@ Leo Law <leoltlaw.gh@gmail.com>
Marcus Spangenberg <marcus.spangenberg@eyevinn.se> Marcus Spangenberg <marcus.spangenberg@eyevinn.se>
Ole Andre Birkedal <o.birkedal@sportradar.com> Ole Andre Birkedal <o.birkedal@sportradar.com>
Piotr Srebrny <srebrny.piotr@gmail.com> Piotr Srebrny <srebrny.piotr@gmail.com>
Prakash Duggaraju <duggaraju@gmail.com>
Qingquan Wang <wangqq1103@gmail.com> Qingquan Wang <wangqq1103@gmail.com>
Richard Eklycke <richard@eklycke.se> Richard Eklycke <richard@eklycke.se>
Rintaro Kuroiwa <rkuroiwa@google.com> Rintaro Kuroiwa <rkuroiwa@google.com>
@ -52,5 +55,4 @@ Thomas Inskip <tinskip@google.com>
Tim Lansen <tim.lansen@gmail.com> Tim Lansen <tim.lansen@gmail.com>
Vincent Nguyen <nvincen@amazon.com> Vincent Nguyen <nvincen@amazon.com>
Weiguo Shao <weiguo.shao@dolby.com> Weiguo Shao <weiguo.shao@dolby.com>
Prakash Duggaraju <duggaraju@gmail.com>
Dennis E. Mungai (Brainiarc7) <dmngaie@gmail.com>

View File

@ -53,6 +53,7 @@ include("protobuf.cmake")
add_subdirectory(file) add_subdirectory(file)
add_subdirectory(kv_pairs) add_subdirectory(kv_pairs)
add_subdirectory(media) add_subdirectory(media)
add_subdirectory(hls)
add_subdirectory(mpd) add_subdirectory(mpd)
add_subdirectory(status) add_subdirectory(status)
add_subdirectory(third_party) add_subdirectory(third_party)

View File

@ -48,4 +48,15 @@ bool TempFilePath(const std::string& temp_dir, std::string* temp_file_path) {
return true; return true;
} }
std::string MakePathRelative(const std::filesystem::path& media_path,
const std::filesystem::path& parent_path) {
auto relative_path = std::filesystem::relative(media_path, parent_path);
if (relative_path.empty() || *relative_path.begin() == "..") {
// Not related.
relative_path = media_path;
}
return relative_path.lexically_normal().generic_string();
}
} // namespace shaka } // namespace shaka

View File

@ -4,6 +4,7 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // https://developers.google.com/open-source/licenses/bsd
#include <filesystem>
#include <string> #include <string>
namespace shaka { namespace shaka {
@ -15,4 +16,7 @@ namespace shaka {
/// @returns true on success, false otherwise. /// @returns true on success, false otherwise.
bool TempFilePath(const std::string& temp_dir, std::string* temp_file_path); bool TempFilePath(const std::string& temp_dir, std::string* temp_file_path);
std::string MakePathRelative(const std::filesystem::path& media_path,
const std::filesystem::path& parent_path);
} // namespace shaka } // namespace shaka

View File

@ -0,0 +1,52 @@
# Copyright 2016 Google LLC. All rights reserved.
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
add_library(hls_builder
base/hls_notifier.h
base/master_playlist.cc
base/master_playlist.h
base/media_playlist.cc
base/media_playlist.h
base/simple_hls_notifier.cc
base/simple_hls_notifier.h
base/tag.cc
base/tag.h
public/hls_params.h
)
target_link_libraries(hls_builder
file
media_base
widevine_protos
manifest_base
mpd_media_info_proto
absl::flags
absl::strings
absl::str_format
glog
)
add_executable(hls_unittest
base/master_playlist_unittest.cc
base/media_playlist_unittest.cc
base/mock_media_playlist.cc
base/mock_media_playlist.h
base/simple_hls_notifier_unittest.cc
)
target_link_libraries(hls_unittest
file
file_test_util
test_data_util
absl::flags
hls_builder
gmock
gtest
gtest_main)
add_test(NAME hls_unittest COMMAND hls_unittest)

View File

@ -10,10 +10,11 @@
#include <inttypes.h> #include <inttypes.h>
#include "packager/base/files/file_path.h" #include <absl/strings/numbers.h>
#include "packager/base/strings/string_number_conversions.h" #include <absl/strings/str_format.h>
#include "packager/base/strings/string_util.h" #include <absl/strings/str_join.h>
#include "packager/base/strings/stringprintf.h" #include <glog/logging.h>
#include <filesystem>
#include "packager/file/file.h" #include "packager/file/file.h"
#include "packager/hls/base/media_playlist.h" #include "packager/hls/base/media_playlist.h"
#include "packager/hls/base/tag.h" #include "packager/hls/base/tag.h"
@ -30,7 +31,7 @@ void AppendVersionString(std::string* content) {
const std::string version = GetPackagerVersion(); const std::string version = GetPackagerVersion();
if (version.empty()) if (version.empty())
return; return;
base::StringAppendF(content, "## Generated with %s version %s\n", absl::StrAppendFormat(content, "## Generated with %s version %s\n",
GetPackagerProjectUrl().c_str(), version.c_str()); GetPackagerProjectUrl().c_str(), version.c_str());
} }
@ -207,7 +208,7 @@ void BuildStreamInfTag(const MediaPlaylist& playlist,
tag_name = "#EXT-X-I-FRAME-STREAM-INF"; tag_name = "#EXT-X-I-FRAME-STREAM-INF";
break; break;
default: default:
NOTREACHED() << "Cannot build STREAM-INFO tag for type " NOTIMPLEMENTED() << "Cannot build STREAM-INFO tag for type "
<< static_cast<int>(playlist.stream_type()); << static_cast<int>(playlist.stream_type());
break; break;
} }
@ -223,7 +224,7 @@ void BuildStreamInfTag(const MediaPlaylist& playlist,
variant.audio_codecs.end()); variant.audio_codecs.end());
all_codecs.insert(all_codecs.end(), variant.text_codecs.begin(), all_codecs.insert(all_codecs.end(), variant.text_codecs.begin(),
variant.text_codecs.end()); variant.text_codecs.end());
tag.AddQuotedString("CODECS", base::JoinString(all_codecs, ",")); tag.AddQuotedString("CODECS", absl::StrJoin(all_codecs, ","));
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
@ -266,7 +267,7 @@ void BuildStreamInfTag(const MediaPlaylist& playlist,
tag.AddQuotedString("URI", base_url + playlist.file_name()); tag.AddQuotedString("URI", base_url + playlist.file_name());
out->append("\n"); out->append("\n");
} else { } else {
base::StringAppendF(out, "\n%s%s\n", base_url.c_str(), absl::StrAppendFormat(out, "\n%s%s\n", base_url.c_str(),
playlist.file_name().c_str()); playlist.file_name().c_str());
} }
} }
@ -295,7 +296,7 @@ void BuildMediaTag(const MediaPlaylist& playlist,
break; break;
default: default:
NOTREACHED() << "Cannot build media tag for type " NOTIMPLEMENTED() << "Cannot build media tag for type "
<< static_cast<int>(playlist.stream_type()); << static_cast<int>(playlist.stream_type());
break; break;
} }
@ -322,8 +323,7 @@ void BuildMediaTag(const MediaPlaylist& playlist,
const std::vector<std::string>& characteristics = playlist.characteristics(); const std::vector<std::string>& characteristics = playlist.characteristics();
if (!characteristics.empty()) { if (!characteristics.empty()) {
tag.AddQuotedString("CHARACTERISTICS", tag.AddQuotedString("CHARACTERISTICS", absl::StrJoin(characteristics, ","));
base::JoinString(characteristics, ","));
} }
const MediaPlaylist::MediaPlaylistStreamType kAudio = const MediaPlaylist::MediaPlaylistStreamType kAudio =
@ -486,7 +486,7 @@ void AppendPlaylists(const std::string& default_audio_language,
} // namespace } // namespace
MasterPlaylist::MasterPlaylist(const std::string& file_name, MasterPlaylist::MasterPlaylist(const std::filesystem::path& file_name,
const std::string& default_audio_language, const std::string& default_audio_language,
const std::string& default_text_language, const std::string& default_text_language,
bool is_independent_segments) bool is_independent_segments)
@ -514,12 +514,9 @@ bool MasterPlaylist::WriteMasterPlaylist(
if (content == written_playlist_) if (content == written_playlist_)
return true; return true;
std::string file_path = auto file_path = std::filesystem::u8path(output_dir) / file_name_;
base::FilePath::FromUTF8Unsafe(output_dir) if (!File::WriteFileAtomically(file_path.string().c_str(), content)) {
.Append(base::FilePath::FromUTF8Unsafe(file_name_)) LOG(ERROR) << "Failed to write master playlist to: " << file_path.string();
.AsUTF8Unsafe();
if (!File::WriteFileAtomically(file_path.c_str(), content)) {
LOG(ERROR) << "Failed to write master playlist to: " << file_path;
return false; return false;
} }
written_playlist_ = content; written_playlist_ = content;

View File

@ -7,6 +7,7 @@
#ifndef PACKAGER_HLS_BASE_MASTER_PLAYLIST_H_ #ifndef PACKAGER_HLS_BASE_MASTER_PLAYLIST_H_
#define PACKAGER_HLS_BASE_MASTER_PLAYLIST_H_ #define PACKAGER_HLS_BASE_MASTER_PLAYLIST_H_
#include <filesystem>
#include <list> #include <list>
#include <string> #include <string>
@ -24,7 +25,7 @@ class MasterPlaylist {
/// be tagged with 'DEFAULT'. /// be tagged with 'DEFAULT'.
/// @param default_text_language determines the text rendition that should be /// @param default_text_language determines the text rendition that should be
/// tagged with 'DEFAULT'. /// tagged with 'DEFAULT'.
MasterPlaylist(const std::string& file_name, MasterPlaylist(const std::filesystem::path& file_name,
const std::string& default_audio_language, const std::string& default_audio_language,
const std::string& default_text_language, const std::string& default_text_language,
const bool is_independent_segments); const bool is_independent_segments);
@ -48,7 +49,7 @@ class MasterPlaylist {
MasterPlaylist& operator=(const MasterPlaylist&) = delete; MasterPlaylist& operator=(const MasterPlaylist&) = delete;
std::string written_playlist_; std::string written_playlist_;
const std::string file_name_; const std::filesystem::path file_name_;
const std::string default_audio_language_; const std::string default_audio_language_;
const std::string default_text_language_; const std::string default_text_language_;
bool is_independent_segments_; bool is_independent_segments_;

View File

@ -7,7 +7,7 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "packager/base/files/file_path.h" #include <filesystem>
#include "packager/file/file.h" #include "packager/file/file.h"
#include "packager/hls/base/master_playlist.h" #include "packager/hls/base/master_playlist.h"
#include "packager/hls/base/media_playlist.h" #include "packager/hls/base/media_playlist.h"
@ -17,9 +17,9 @@
namespace shaka { namespace shaka {
namespace hls { namespace hls {
using base::FilePath;
using ::testing::_; using ::testing::_;
using ::testing::AtLeast; using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::NotNull; using ::testing::NotNull;
using ::testing::Return; using ::testing::Return;
using ::testing::ReturnRef; using ::testing::ReturnRef;
@ -142,16 +142,14 @@ class MasterPlaylistTest : public ::testing::Test {
kDefaultTextLanguage, kDefaultTextLanguage,
!kIsIndependentSegments)), !kIsIndependentSegments)),
test_output_dir_("memory://test_dir"), test_output_dir_("memory://test_dir"),
master_playlist_path_( master_playlist_path_(std::filesystem::u8path(test_output_dir_) /
FilePath::FromUTF8Unsafe(test_output_dir_) kDefaultMasterPlaylistName) {}
.Append(FilePath::FromUTF8Unsafe(kDefaultMasterPlaylistName))
.AsUTF8Unsafe()) {}
void SetUp() override { SetPackagerVersionForTesting("test"); } void SetUp() override { SetPackagerVersionForTesting("test"); }
std::unique_ptr<MasterPlaylist> master_playlist_; std::unique_ptr<MasterPlaylist> master_playlist_;
std::string test_output_dir_; std::string test_output_dir_;
std::string master_playlist_path_; std::filesystem::path master_playlist_path_;
}; };
TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneVideo) { TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneVideo) {
@ -166,7 +164,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneVideo) {
{mock_playlist.get()})); {mock_playlist.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -200,7 +199,8 @@ TEST_F(MasterPlaylistTest,
{mock_playlist.get()})); {mock_playlist.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -229,7 +229,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneVideoWithFrameRate) {
{mock_playlist.get()})); {mock_playlist.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -257,7 +258,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistOneIframePlaylist) {
{mock_playlist.get()})); {mock_playlist.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -312,7 +314,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudio) {
spanish_playlist.get()})); spanish_playlist.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -372,7 +375,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMultipleAudioGroups) {
{video_playlist.get(), eng_lo_playlist.get(), eng_hi_playlist.get()})); {video_playlist.get(), eng_lo_playlist.get(), eng_hi_playlist.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -419,7 +423,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistSameAudioGroupSameLanguage) {
{video_playlist.get(), eng_lo_playlist.get(), eng_hi_playlist.get()})); {video_playlist.get(), eng_lo_playlist.get(), eng_hi_playlist.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -464,7 +469,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideosAndTexts) {
{video1.get(), video2.get(), text_eng.get(), text_fr.get()})); {video1.get(), video2.get(), text_eng.get(), text_fr.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -506,7 +512,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextWithCharacteritics) {
{video.get(), text.get()})); {video.get(), text.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -548,7 +555,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndDvsAudio) {
kBaseUrl, test_output_dir_, {video.get(), dvs_audio.get(), audio.get()})); kBaseUrl, test_output_dir_, {video.get(), dvs_audio.get(), audio.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -590,7 +598,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndTextGroups) {
{video.get(), text_eng.get(), text_fr.get()})); {video.get(), text_eng.get(), text_fr.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -636,7 +645,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistVideoAndAudioAndText) {
kBaseUrl, test_output_dir_, {video.get(), audio.get(), text.get()})); kBaseUrl, test_output_dir_, {video.get(), audio.get(), text.get()}));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -709,7 +719,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistMixedPlaylistsDifferentGroups) {
media_playlist_list)); media_playlist_list));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -812,7 +823,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistAudioOnly) {
media_playlist_list)); media_playlist_list));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -864,7 +876,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistAudioOnlyJOC) {
media_playlist_list)); media_playlist_list));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -916,7 +929,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistAudioOnlyAC4IMS) {
media_playlist_list)); media_playlist_list));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"
@ -969,7 +983,8 @@ TEST_F(MasterPlaylistTest, WriteMasterPlaylistAudioOnlyAC4CBI) {
media_playlist_list)); media_playlist_list));
std::string actual; std::string actual;
ASSERT_TRUE(File::ReadFileToString(master_playlist_path_.c_str(), &actual)); ASSERT_TRUE(
File::ReadFileToString(master_playlist_path_.string().c_str(), &actual));
const std::string expected = const std::string expected =
"#EXTM3U\n" "#EXTM3U\n"

View File

@ -12,9 +12,9 @@
#include <cmath> #include <cmath>
#include <memory> #include <memory>
#include "packager/base/logging.h" #include <absl/strings/numbers.h>
#include "packager/base/strings/string_number_conversions.h" #include <absl/strings/str_format.h>
#include "packager/base/strings/stringprintf.h" #include <glog/logging.h>
#include "packager/file/file.h" #include "packager/file/file.h"
#include "packager/hls/base/tag.h" #include "packager/hls/base/tag.h"
#include "packager/media/base/language_utils.h" #include "packager/media/base/language_utils.h"
@ -112,12 +112,12 @@ std::string CreatePlaylistHeader(
std::string version_line; std::string version_line;
if (!version.empty()) { if (!version.empty()) {
version_line = version_line =
base::StringPrintf("## Generated with %s version %s\n", absl::StrFormat("## Generated with %s version %s\n",
GetPackagerProjectUrl().c_str(), version.c_str()); GetPackagerProjectUrl().c_str(), version.c_str());
} }
// 6 is required for EXT-X-MAP without EXT-X-I-FRAMES-ONLY. // 6 is required for EXT-X-MAP without EXT-X-I-FRAMES-ONLY.
std::string header = base::StringPrintf( std::string header = absl::StrFormat(
"#EXTM3U\n" "#EXTM3U\n"
"#EXT-X-VERSION:6\n" "#EXT-X-VERSION:6\n"
"%s" "%s"
@ -133,20 +133,21 @@ std::string CreatePlaylistHeader(
break; break;
case HlsPlaylistType::kLive: case HlsPlaylistType::kLive:
if (media_sequence_number > 0) { if (media_sequence_number > 0) {
base::StringAppendF(&header, "#EXT-X-MEDIA-SEQUENCE:%d\n", absl::StrAppendFormat(&header, "#EXT-X-MEDIA-SEQUENCE:%d\n",
media_sequence_number); media_sequence_number);
} }
if (discontinuity_sequence_number > 0) { if (discontinuity_sequence_number > 0) {
base::StringAppendF(&header, "#EXT-X-DISCONTINUITY-SEQUENCE:%d\n", absl::StrAppendFormat(&header, "#EXT-X-DISCONTINUITY-SEQUENCE:%d\n",
discontinuity_sequence_number); discontinuity_sequence_number);
} }
break; break;
default: default:
NOTREACHED() << "Unexpected MediaPlaylistType " << static_cast<int>(type); NOTIMPLEMENTED() << "Unexpected MediaPlaylistType "
<< static_cast<int>(type);
} }
if (stream_type == if (stream_type ==
MediaPlaylist::MediaPlaylistStreamType::kVideoIFramesOnly) { MediaPlaylist::MediaPlaylistStreamType::kVideoIFramesOnly) {
base::StringAppendF(&header, "#EXT-X-I-FRAMES-ONLY\n"); absl::StrAppendFormat(&header, "#EXT-X-I-FRAMES-ONLY\n");
} }
// Put EXT-X-MAP at the end since the rest of the playlist is about the // Put EXT-X-MAP at the end since the rest of the playlist is about the
@ -209,17 +210,17 @@ SegmentInfoEntry::SegmentInfoEntry(const std::string& file_name,
previous_segment_end_offset_(previous_segment_end_offset) {} previous_segment_end_offset_(previous_segment_end_offset) {}
std::string SegmentInfoEntry::ToString() { std::string SegmentInfoEntry::ToString() {
std::string result = base::StringPrintf("#EXTINF:%.3f,", duration_seconds_); std::string result = absl::StrFormat("#EXTINF:%.3f,", duration_seconds_);
if (use_byte_range_) { if (use_byte_range_) {
base::StringAppendF(&result, "\n#EXT-X-BYTERANGE:%" PRIu64, absl::StrAppendFormat(&result, "\n#EXT-X-BYTERANGE:%" PRIu64,
segment_file_size_); segment_file_size_);
if (previous_segment_end_offset_ + 1 != start_byte_offset_) { if (previous_segment_end_offset_ + 1 != start_byte_offset_) {
base::StringAppendF(&result, "@%" PRIu64, start_byte_offset_); absl::StrAppendFormat(&result, "@%" PRIu64, start_byte_offset_);
} }
} }
base::StringAppendF(&result, "\n%s", file_name_.c_str()); absl::StrAppendFormat(&result, "\n%s", file_name_.c_str());
return result; return result;
} }
@ -445,7 +446,7 @@ void MediaPlaylist::AddKeyFrame(int64_t timestamp,
stream_type_ = MediaPlaylistStreamType::kVideoIFramesOnly; stream_type_ = MediaPlaylistStreamType::kVideoIFramesOnly;
use_byte_range_ = true; use_byte_range_ = true;
} }
key_frames_.push_back({timestamp, start_byte_offset, size}); key_frames_.push_back({timestamp, start_byte_offset, size, std::string("")});
} }
void MediaPlaylist::AddEncryptionInfo(MediaPlaylist::EncryptionMethod method, void MediaPlaylist::AddEncryptionInfo(MediaPlaylist::EncryptionMethod method,
@ -469,7 +470,7 @@ void MediaPlaylist::AddPlacementOpportunity() {
entries_.emplace_back(new PlacementOpportunityEntry()); entries_.emplace_back(new PlacementOpportunityEntry());
} }
bool MediaPlaylist::WriteToFile(const std::string& file_path) { bool MediaPlaylist::WriteToFile(const std::filesystem::path& file_path) {
if (!target_duration_set_) { if (!target_duration_set_) {
SetTargetDuration(ceil(GetLongestSegmentDuration())); SetTargetDuration(ceil(GetLongestSegmentDuration()));
} }
@ -479,14 +480,14 @@ bool MediaPlaylist::WriteToFile(const std::string& file_path) {
media_sequence_number_, discontinuity_sequence_number_); media_sequence_number_, discontinuity_sequence_number_);
for (const auto& entry : entries_) for (const auto& entry : entries_)
base::StringAppendF(&content, "%s\n", entry->ToString().c_str()); absl::StrAppendFormat(&content, "%s\n", entry->ToString().c_str());
if (hls_params_.playlist_type == HlsPlaylistType::kVod) { if (hls_params_.playlist_type == HlsPlaylistType::kVod) {
content += "#EXT-X-ENDLIST\n"; content += "#EXT-X-ENDLIST\n";
} }
if (!File::WriteFileAtomically(file_path.c_str(), content)) { if (!File::WriteFileAtomically(file_path.string().c_str(), content)) {
LOG(ERROR) << "Failed to write playlist to: " << file_path; LOG(ERROR) << "Failed to write playlist to: " << file_path.string();
return false; return false;
} }
return true; return true;
@ -691,7 +692,8 @@ void MediaPlaylist::SlideWindow() {
} else if (entry_type == HlsEntry::EntryType::kExtDiscontinuity) { } else if (entry_type == HlsEntry::EntryType::kExtDiscontinuity) {
++discontinuity_sequence_number_; ++discontinuity_sequence_number_;
} else { } else {
DCHECK_EQ(entry_type, HlsEntry::EntryType::kExtInf); DCHECK_EQ(static_cast<int>(entry_type),
static_cast<int>(HlsEntry::EntryType::kExtInf));
const SegmentInfoEntry& segment_info = const SegmentInfoEntry& segment_info =
*reinterpret_cast<SegmentInfoEntry*>(last->get()); *reinterpret_cast<SegmentInfoEntry*>(last->get());

View File

@ -7,13 +7,14 @@
#ifndef PACKAGER_HLS_BASE_MEDIA_PLAYLIST_H_ #ifndef PACKAGER_HLS_BASE_MEDIA_PLAYLIST_H_
#define PACKAGER_HLS_BASE_MEDIA_PLAYLIST_H_ #define PACKAGER_HLS_BASE_MEDIA_PLAYLIST_H_
#include <filesystem>
#include <list> #include <list>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "packager/base/macros.h"
#include "packager/hls/public/hls_params.h" #include "packager/hls/public/hls_params.h"
#include "packager/macros.h"
#include "packager/mpd/base/bandwidth_estimator.h" #include "packager/mpd/base/bandwidth_estimator.h"
#include "packager/mpd/base/media_info.pb.h" #include "packager/mpd/base/media_info.pb.h"
@ -160,7 +161,7 @@ class MediaPlaylist {
/// @param file_path is the output file path accepted by the File /// @param file_path is the output file path accepted by the File
/// implementation. /// implementation.
/// @return true on success, false otherwise. /// @return true on success, false otherwise.
virtual bool WriteToFile(const std::string& file_path); virtual bool WriteToFile(const std::filesystem::path& file_path);
/// If bitrate is specified in MediaInfo then it will use that value. /// If bitrate is specified in MediaInfo then it will use that value.
/// Otherwise, returns the max bitrate. /// Otherwise, returns the max bitrate.

View File

@ -7,7 +7,7 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "packager/base/strings/stringprintf.h" #include <absl/strings/str_format.h>
#include "packager/file/file.h" #include "packager/file/file.h"
#include "packager/file/file_closer.h" #include "packager/file/file_closer.h"
#include "packager/file/file_test_util.h" #include "packager/file/file_test_util.h"
@ -1032,8 +1032,8 @@ class MediaPlaylistDeleteSegmentsTest
std::string GetSegmentName(int index) { std::string GetSegmentName(int index) {
if (segment_template_.find("$Time$") != std::string::npos) if (segment_template_.find("$Time$") != std::string::npos)
return base::StringPrintf(kStringPrintTemplate, GetTime(index)); return absl::StrFormat(kStringPrintTemplate, GetTime(index));
return base::StringPrintf(kStringPrintTemplate, index + 1); return absl::StrFormat(kStringPrintTemplate, index + 1);
} }
bool SegmentDeleted(const std::string& segment_name) { bool SegmentDeleted(const std::string& segment_name) {

View File

@ -42,7 +42,7 @@ class MockMediaPlaylist : public MediaPlaylist {
const std::string& key_format, const std::string& key_format,
const std::string& key_format_versions)); const std::string& key_format_versions));
MOCK_METHOD0(AddPlacementOpportunity, void()); MOCK_METHOD0(AddPlacementOpportunity, void());
MOCK_METHOD1(WriteToFile, bool(const std::string& file_path)); MOCK_METHOD1(WriteToFile, bool(const std::filesystem::path& file_path));
MOCK_CONST_METHOD0(MaxBitrate, uint64_t()); MOCK_CONST_METHOD0(MaxBitrate, uint64_t());
MOCK_CONST_METHOD0(AvgBitrate, uint64_t()); MOCK_CONST_METHOD0(AvgBitrate, uint64_t());
MOCK_CONST_METHOD0(GetLongestSegmentDuration, double()); MOCK_CONST_METHOD0(GetLongestSegmentDuration, double());

View File

@ -6,22 +6,22 @@
#include "packager/hls/base/simple_hls_notifier.h" #include "packager/hls/base/simple_hls_notifier.h"
#include <gflags/gflags.h> #include <absl/flags/flag.h>
#include <cmath> #include <cmath>
#include "packager/base/base64.h" #include <absl/strings/escaping.h>
#include "packager/base/files/file_path.h" #include <absl/strings/numbers.h>
#include "packager/base/logging.h" #include <glog/logging.h>
#include "packager/base/optional.h" #include <filesystem>
#include "packager/base/strings/string_number_conversions.h" #include <optional>
#include "packager/base/strings/stringprintf.h" #include "packager/file/file_util.h"
#include "packager/hls/base/media_playlist.h"
#include "packager/media/base/protection_system_ids.h" #include "packager/media/base/protection_system_ids.h"
#include "packager/media/base/protection_system_specific_info.h" #include "packager/media/base/protection_system_specific_info.h"
#include "packager/media/base/proto_json_util.h" #include "packager/media/base/proto_json_util.h"
#include "packager/media/base/widevine_pssh_data.pb.h" #include "packager/media/base/widevine_pssh_data.pb.h"
DEFINE_bool(enable_legacy_widevine_hls_signaling, ABSL_FLAG(bool,
enable_legacy_widevine_hls_signaling,
false, false,
"Specifies whether Legacy Widevine HLS, i.e. v1 is signalled in " "Specifies whether Legacy Widevine HLS, i.e. v1 is signalled in "
"the media playlist. Applies to Widevine protection system in HLS " "the media playlist. Applies to Widevine protection system in HLS "
@ -29,8 +29,6 @@ DEFINE_bool(enable_legacy_widevine_hls_signaling,
namespace shaka { namespace shaka {
using base::FilePath;
namespace hls { namespace hls {
namespace { namespace {
@ -41,18 +39,18 @@ const char kWidevineDashIfIopUUID[] =
"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"; "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";
bool IsWidevineSystemId(const std::vector<uint8_t>& system_id) { bool IsWidevineSystemId(const std::vector<uint8_t>& system_id) {
return system_id.size() == arraysize(media::kWidevineSystemId) && return system_id.size() == std::size(media::kWidevineSystemId) &&
std::equal(system_id.begin(), system_id.end(), std::equal(system_id.begin(), system_id.end(),
media::kWidevineSystemId); media::kWidevineSystemId);
} }
bool IsCommonSystemId(const std::vector<uint8_t>& system_id) { bool IsCommonSystemId(const std::vector<uint8_t>& system_id) {
return system_id.size() == arraysize(media::kCommonSystemId) && return system_id.size() == std::size(media::kCommonSystemId) &&
std::equal(system_id.begin(), system_id.end(), media::kCommonSystemId); std::equal(system_id.begin(), system_id.end(), media::kCommonSystemId);
} }
bool IsFairPlaySystemId(const std::vector<uint8_t>& system_id) { bool IsFairPlaySystemId(const std::vector<uint8_t>& system_id) {
return system_id.size() == arraysize(media::kFairPlaySystemId) && return system_id.size() == std::size(media::kFairPlaySystemId) &&
std::equal(system_id.begin(), system_id.end(), std::equal(system_id.begin(), system_id.end(),
media::kFairPlaySystemId); media::kFairPlaySystemId);
} }
@ -60,7 +58,7 @@ bool IsFairPlaySystemId(const std::vector<uint8_t>& system_id) {
std::string Base64EncodeData(const std::string& prefix, std::string Base64EncodeData(const std::string& prefix,
const std::string& data) { const std::string& data) {
std::string data_base64; std::string data_base64;
base::Base64Encode(data, &data_base64); absl::Base64Escape(data, &data_base64);
return prefix + data_base64; return prefix + data_base64;
} }
@ -68,33 +66,13 @@ std::string VectorToString(const std::vector<uint8_t>& v) {
return std::string(v.begin(), v.end()); return std::string(v.begin(), v.end());
} }
// TODO(rkuroiwa): Dedup these with the functions in MpdBuilder.
// If |media_path| is contained in |parent_path|, then
// Strips the common path and keep only the relative part of |media_path|.
// e.g. if |parent_path| is /some/parent/ and
// |media_path| is /some/parent/abc/child/item.ext,
// abc/child/item.ext is returned.
// else
// Returns |media_path|.
// The path separator of the output is also changed to "/" if it is not.
std::string MakePathRelative(const std::string& media_path,
const FilePath& parent_path) {
FilePath relative_path;
const FilePath child_path = FilePath::FromUTF8Unsafe(media_path);
const bool is_child =
parent_path.AppendRelativePath(child_path, &relative_path);
if (!is_child)
relative_path = child_path;
return relative_path.NormalizePathSeparatorsTo('/').AsUTF8Unsafe();
}
// Segment URL is relative to either output directory or the directory // Segment URL is relative to either output directory or the directory
// containing the media playlist depends on whether base_url is set. // containing the media playlist depends on whether base_url is set.
std::string GenerateSegmentUrl(const std::string& segment_name, std::string GenerateSegmentUrl(const std::string& segment_name,
const std::string& base_url, const std::string& base_url,
const std::string& output_dir, const std::string& output_dir,
const std::string& playlist_file_name) { const std::string& playlist_file_name) {
FilePath output_path = FilePath::FromUTF8Unsafe(output_dir); auto output_path = std::filesystem::u8path(output_dir);
if (!base_url.empty()) { if (!base_url.empty()) {
// Media segment URL is base_url + segment path relative to output // Media segment URL is base_url + segment path relative to output
// directory. // directory.
@ -102,10 +80,8 @@ std::string GenerateSegmentUrl(const std::string& segment_name,
} }
// Media segment URL is segment path relative to the directory containing the // Media segment URL is segment path relative to the directory containing the
// playlist. // playlist.
const FilePath playlist_dir = const std::filesystem::path playlist_dir =
output_path.Append(FilePath::FromUTF8Unsafe(playlist_file_name)) (output_path / playlist_file_name).parent_path() / "";
.DirName()
.AsEndingWithSeparator();
return MakePathRelative(segment_name, playlist_dir); return MakePathRelative(segment_name, playlist_dir);
} }
@ -168,10 +144,12 @@ bool WidevinePsshToJson(const std::vector<uint8_t>& pssh_box,
// Place the current |key_id| to the front and converts all key_id to hex // Place the current |key_id| to the front and converts all key_id to hex
// format. // format.
widevine_header.add_key_ids(base::HexEncode(key_id.data(), key_id.size())); widevine_header.add_key_ids(absl::BytesToHexString(absl::string_view(
reinterpret_cast<const char*>(key_id.data()), key_id.size())));
for (const std::string& key_id_in_pssh : pssh_proto.key_id()) { for (const std::string& key_id_in_pssh : pssh_proto.key_id()) {
const std::string key_id_hex = const std::string key_id_hex = absl::BytesToHexString(
base::HexEncode(key_id_in_pssh.data(), key_id_in_pssh.size()); absl::string_view(reinterpret_cast<const char*>(key_id_in_pssh.data()),
key_id_in_pssh.size()));
if (widevine_header.key_ids(0) != key_id_hex) if (widevine_header.key_ids(0) != key_id_hex)
widevine_header.add_key_ids(key_id_hex); widevine_header.add_key_ids(key_id_hex);
} }
@ -180,7 +158,7 @@ bool WidevinePsshToJson(const std::vector<uint8_t>& pssh_box,
return true; return true;
} }
base::Optional<MediaPlaylist::EncryptionMethod> StringToEncryptionMethod( std::optional<MediaPlaylist::EncryptionMethod> StringToEncryptionMethod(
const std::string& method) { const std::string& method) {
if (method == "cenc") { if (method == "cenc") {
return MediaPlaylist::EncryptionMethod::kSampleAesCenc; return MediaPlaylist::EncryptionMethod::kSampleAesCenc;
@ -192,7 +170,7 @@ base::Optional<MediaPlaylist::EncryptionMethod> StringToEncryptionMethod(
// cbca is a place holder for sample aes. // cbca is a place holder for sample aes.
return MediaPlaylist::EncryptionMethod::kSampleAes; return MediaPlaylist::EncryptionMethod::kSampleAes;
} }
return base::nullopt; return std::nullopt;
} }
void NotifyEncryptionToMediaPlaylist( void NotifyEncryptionToMediaPlaylist(
@ -205,11 +183,15 @@ void NotifyEncryptionToMediaPlaylist(
MediaPlaylist* media_playlist) { MediaPlaylist* media_playlist) {
std::string iv_string; std::string iv_string;
if (!iv.empty()) { if (!iv.empty()) {
iv_string = "0x" + base::HexEncode(iv.data(), iv.size()); iv_string =
"0x" + absl::BytesToHexString(absl::string_view(
reinterpret_cast<const char*>(iv.data()), iv.size()));
} }
std::string key_id_string; std::string key_id_string;
if (!key_id.empty()) { if (!key_id.empty()) {
key_id_string = "0x" + base::HexEncode(key_id.data(), key_id.size()); key_id_string = "0x" + absl::BytesToHexString(absl::string_view(
reinterpret_cast<const char*>(key_id.data()),
key_id.size()));
} }
media_playlist->AddEncryptionInfo( media_playlist->AddEncryptionInfo(
@ -225,7 +207,7 @@ bool HandleWidevineKeyFormats(
const std::vector<uint8_t>& iv, const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& protection_system_specific_data, const std::vector<uint8_t>& protection_system_specific_data,
MediaPlaylist* media_playlist) { MediaPlaylist* media_playlist) {
if (FLAGS_enable_legacy_widevine_hls_signaling && if (absl::GetFlag(FLAGS_enable_legacy_widevine_hls_signaling) &&
encryption_method == MediaPlaylist::EncryptionMethod::kSampleAes) { encryption_method == MediaPlaylist::EncryptionMethod::kSampleAes) {
// This format allows SAMPLE-AES only. // This format allows SAMPLE-AES only.
std::string key_uri_data; std::string key_uri_data;
@ -253,12 +235,9 @@ bool HandleWidevineKeyFormats(
bool WriteMediaPlaylist(const std::string& output_dir, bool WriteMediaPlaylist(const std::string& output_dir,
MediaPlaylist* playlist) { MediaPlaylist* playlist) {
std::string file_path = auto file_path = std::filesystem::u8path(output_dir) / playlist->file_name();
FilePath::FromUTF8Unsafe(output_dir)
.Append(FilePath::FromUTF8Unsafe(playlist->file_name()))
.AsUTF8Unsafe();
if (!playlist->WriteToFile(file_path)) { if (!playlist->WriteToFile(file_path)) {
LOG(ERROR) << "Failed to write playlist " << file_path; LOG(ERROR) << "Failed to write playlist " << file_path.string();
return false; return false;
} }
return true; return true;
@ -280,18 +259,17 @@ std::unique_ptr<MediaPlaylist> MediaPlaylistFactory::Create(
SimpleHlsNotifier::SimpleHlsNotifier(const HlsParams& hls_params) SimpleHlsNotifier::SimpleHlsNotifier(const HlsParams& hls_params)
: HlsNotifier(hls_params), : HlsNotifier(hls_params),
media_playlist_factory_(new MediaPlaylistFactory()) { media_playlist_factory_(new MediaPlaylistFactory()) {
const base::FilePath master_playlist_path( const auto master_playlist_path =
base::FilePath::FromUTF8Unsafe(hls_params.master_playlist_output)); std::filesystem::u8path(hls_params.master_playlist_output);
master_playlist_dir_ = master_playlist_path.DirName().AsUTF8Unsafe(); master_playlist_dir_ = master_playlist_path.parent_path().string();
const std::string& default_audio_langauge = hls_params.default_language; const std::string& default_audio_langauge = hls_params.default_language;
const std::string& default_text_language = const std::string& default_text_language =
hls_params.default_text_language.empty() hls_params.default_text_language.empty()
? hls_params.default_language ? hls_params.default_language
: hls_params.default_text_language; : hls_params.default_text_language;
master_playlist_.reset( master_playlist_.reset(new MasterPlaylist(
new MasterPlaylist(master_playlist_path.BaseName().AsUTF8Unsafe(), master_playlist_path.filename(), default_audio_langauge,
default_audio_langauge, default_text_language, default_text_language, hls_params.is_independent_segments));
hls_params.is_independent_segments));
} }
SimpleHlsNotifier::~SimpleHlsNotifier() {} SimpleHlsNotifier::~SimpleHlsNotifier() {}
@ -308,7 +286,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
DCHECK(stream_id); DCHECK(stream_id);
const std::string relative_playlist_path = MakePathRelative( const std::string relative_playlist_path = MakePathRelative(
playlist_name, FilePath::FromUTF8Unsafe(master_playlist_dir_)); playlist_name, std::filesystem::u8path(master_playlist_dir_));
std::unique_ptr<MediaPlaylist> media_playlist = std::unique_ptr<MediaPlaylist> media_playlist =
media_playlist_factory_->Create(hls_params(), relative_playlist_path, media_playlist_factory_->Create(hls_params(), relative_playlist_path,
@ -326,7 +304,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
if (media_info.protected_content().has_protection_scheme()) { if (media_info.protected_content().has_protection_scheme()) {
const std::string& protection_scheme = const std::string& protection_scheme =
media_info.protected_content().protection_scheme(); media_info.protected_content().protection_scheme();
base::Optional<MediaPlaylist::EncryptionMethod> enc_method = std::optional<MediaPlaylist::EncryptionMethod> enc_method =
StringToEncryptionMethod(protection_scheme); StringToEncryptionMethod(protection_scheme);
if (!enc_method) { if (!enc_method) {
LOG(ERROR) << "Failed to recognize protection scheme " LOG(ERROR) << "Failed to recognize protection scheme "
@ -336,7 +314,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
encryption_method = enc_method.value(); encryption_method = enc_method.value();
} }
base::AutoLock auto_lock(lock_); absl::MutexLock lock(&lock_);
*stream_id = sequence_number_++; *stream_id = sequence_number_++;
media_playlists_.push_back(media_playlist.get()); media_playlists_.push_back(media_playlist.get());
stream_map_[*stream_id].reset( stream_map_[*stream_id].reset(
@ -346,7 +324,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
bool SimpleHlsNotifier::NotifySampleDuration(uint32_t stream_id, bool SimpleHlsNotifier::NotifySampleDuration(uint32_t stream_id,
int32_t sample_duration) { int32_t sample_duration) {
base::AutoLock auto_lock(lock_); absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id); auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) { if (stream_iterator == stream_map_.end()) {
LOG(ERROR) << "Cannot find stream with ID: " << stream_id; LOG(ERROR) << "Cannot find stream with ID: " << stream_id;
@ -363,7 +341,7 @@ bool SimpleHlsNotifier::NotifyNewSegment(uint32_t stream_id,
int64_t duration, int64_t duration,
uint64_t start_byte_offset, uint64_t start_byte_offset,
uint64_t size) { uint64_t size) {
base::AutoLock auto_lock(lock_); absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id); auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) { if (stream_iterator == stream_map_.end()) {
LOG(ERROR) << "Cannot find stream with ID: " << stream_id; LOG(ERROR) << "Cannot find stream with ID: " << stream_id;
@ -412,7 +390,7 @@ bool SimpleHlsNotifier::NotifyKeyFrame(uint32_t stream_id,
int64_t timestamp, int64_t timestamp,
uint64_t start_byte_offset, uint64_t start_byte_offset,
uint64_t size) { uint64_t size) {
base::AutoLock auto_lock(lock_); absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id); auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) { if (stream_iterator == stream_map_.end()) {
LOG(ERROR) << "Cannot find stream with ID: " << stream_id; LOG(ERROR) << "Cannot find stream with ID: " << stream_id;
@ -424,7 +402,7 @@ bool SimpleHlsNotifier::NotifyKeyFrame(uint32_t stream_id,
} }
bool SimpleHlsNotifier::NotifyCueEvent(uint32_t stream_id, int64_t timestamp) { bool SimpleHlsNotifier::NotifyCueEvent(uint32_t stream_id, int64_t timestamp) {
base::AutoLock auto_lock(lock_); absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id); auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) { if (stream_iterator == stream_map_.end()) {
LOG(ERROR) << "Cannot find stream with ID: " << stream_id; LOG(ERROR) << "Cannot find stream with ID: " << stream_id;
@ -441,7 +419,7 @@ bool SimpleHlsNotifier::NotifyEncryptionUpdate(
const std::vector<uint8_t>& system_id, const std::vector<uint8_t>& system_id,
const std::vector<uint8_t>& iv, const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& protection_system_specific_data) { const std::vector<uint8_t>& protection_system_specific_data) {
base::AutoLock auto_lock(lock_); absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id); auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) { if (stream_iterator == stream_map_.end()) {
LOG(ERROR) << "Cannot find stream with ID: " << stream_id; LOG(ERROR) << "Cannot find stream with ID: " << stream_id;
@ -493,12 +471,14 @@ bool SimpleHlsNotifier::NotifyEncryptionUpdate(
} }
LOG(WARNING) << "HLS: Ignore unknown or unsupported system ID: " LOG(WARNING) << "HLS: Ignore unknown or unsupported system ID: "
<< base::HexEncode(system_id.data(), system_id.size()); << absl::BytesToHexString(absl::string_view(
reinterpret_cast<const char*>(system_id.data()),
system_id.size()));
return true; return true;
} }
bool SimpleHlsNotifier::Flush() { bool SimpleHlsNotifier::Flush() {
base::AutoLock auto_lock(lock_); absl::MutexLock lock(&lock_);
for (MediaPlaylist* playlist : media_playlists_) { for (MediaPlaylist* playlist : media_playlists_) {
playlist->SetTargetDuration(target_duration_); playlist->SetTargetDuration(target_duration_);
if (!WriteMediaPlaylist(master_playlist_dir_, playlist)) if (!WriteMediaPlaylist(master_playlist_dir_, playlist))

View File

@ -13,12 +13,13 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "packager/base/macros.h" #include <absl/synchronization/mutex.h>
#include "packager/base/synchronization/lock.h"
#include "packager/hls/base/hls_notifier.h" #include "packager/hls/base/hls_notifier.h"
#include "packager/hls/base/master_playlist.h" #include "packager/hls/base/master_playlist.h"
#include "packager/hls/base/media_playlist.h" #include "packager/hls/base/media_playlist.h"
#include "packager/hls/public/hls_params.h" #include "packager/hls/public/hls_params.h"
#include "packager/macros.h"
namespace shaka { namespace shaka {
namespace hls { namespace hls {
@ -91,7 +92,7 @@ class SimpleHlsNotifier : public HlsNotifier {
uint32_t sequence_number_ = 0; uint32_t sequence_number_ = 0;
base::Lock lock_; absl::Mutex lock_;
DISALLOW_COPY_AND_ASSIGN(SimpleHlsNotifier); DISALLOW_COPY_AND_ASSIGN(SimpleHlsNotifier);
}; };

View File

@ -7,23 +7,26 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gflags/gflags.h> #include <absl/flags/declare.h>
#include <absl/flags/flag.h>
#include <memory> #include <memory>
#include "packager/base/base64.h" #include <absl/strings/escaping.h>
#include "packager/base/files/file_path.h" #include <filesystem>
#include "packager/flag_saver.h"
#include "packager/hls/base/mock_media_playlist.h" #include "packager/hls/base/mock_media_playlist.h"
#include "packager/hls/base/simple_hls_notifier.h" #include "packager/hls/base/simple_hls_notifier.h"
#include "packager/media/base/protection_system_ids.h" #include "packager/media/base/protection_system_ids.h"
#include "packager/media/base/protection_system_specific_info.h" #include "packager/media/base/protection_system_specific_info.h"
#include "packager/media/base/widevine_pssh_data.pb.h" #include "packager/media/base/widevine_pssh_data.pb.h"
DECLARE_bool(enable_legacy_widevine_hls_signaling); ABSL_DECLARE_FLAG(bool, enable_legacy_widevine_hls_signaling);
namespace shaka { namespace shaka {
namespace hls { namespace hls {
using ::testing::_; using ::testing::_;
using ::testing::DoAll;
using ::testing::ElementsAre; using ::testing::ElementsAre;
using ::testing::Eq; using ::testing::Eq;
using ::testing::InSequence; using ::testing::InSequence;
@ -245,10 +248,8 @@ TEST_F(SimpleHlsNotifierTest, NotifyNewSegment) {
EXPECT_CALL(*mock_media_playlist, SetTargetDuration(kTargetDuration)) EXPECT_CALL(*mock_media_playlist, SetTargetDuration(kTargetDuration))
.Times(1); .Times(1);
EXPECT_CALL(*mock_media_playlist, EXPECT_CALL(*mock_media_playlist,
WriteToFile(StrEq( WriteToFile(Eq(
base::FilePath::FromUTF8Unsafe(kAnyOutputDir) (std::filesystem::u8path(kAnyOutputDir) / "playlist.m3u8"))))
.Append(base::FilePath::FromUTF8Unsafe("playlist.m3u8"))
.AsUTF8Unsafe())))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_TRUE(notifier.Flush()); EXPECT_TRUE(notifier.Flush());
} }
@ -289,7 +290,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateIdentityKey) {
const std::vector<uint8_t> dummy_pssh_data(10, 'p'); const std::vector<uint8_t> dummy_pssh_data(10, 'p');
std::string expected_key_uri_base64; std::string expected_key_uri_base64;
base::Base64Encode(std::string(key_id.begin(), key_id.end()), absl::Base64Escape(std::string(key_id.begin(), key_id.end()),
&expected_key_uri_base64); &expected_key_uri_base64);
EXPECT_CALL(*mock_media_playlist, EXPECT_CALL(*mock_media_playlist,
@ -557,10 +558,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegment) {
EXPECT_CALL(*mock_media_playlist, SetTargetDuration(kTargetDuration)) EXPECT_CALL(*mock_media_playlist, SetTargetDuration(kTargetDuration))
.Times(1); .Times(1);
EXPECT_CALL(*mock_media_playlist, EXPECT_CALL(*mock_media_playlist,
WriteToFile(StrEq( WriteToFile(Eq(
base::FilePath::FromUTF8Unsafe(kAnyOutputDir) (std::filesystem::u8path(kAnyOutputDir) / "playlist.m3u8"))))
.Append(base::FilePath::FromUTF8Unsafe("playlist.m3u8"))
.AsUTF8Unsafe())))
.WillOnce(Return(true)); .WillOnce(Return(true));
hls_params_.playlist_type = GetParam(); hls_params_.playlist_type = GetParam();
@ -627,18 +626,14 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) {
EXPECT_CALL(*mock_media_playlist1, SetTargetDuration(kTargetDuration)) EXPECT_CALL(*mock_media_playlist1, SetTargetDuration(kTargetDuration))
.Times(1); .Times(1);
EXPECT_CALL(*mock_media_playlist1, EXPECT_CALL(*mock_media_playlist1,
WriteToFile(StrEq( WriteToFile(Eq(
base::FilePath::FromUTF8Unsafe(kAnyOutputDir) (std::filesystem::u8path(kAnyOutputDir) / "playlist1.m3u8"))))
.Append(base::FilePath::FromUTF8Unsafe("playlist1.m3u8"))
.AsUTF8Unsafe())))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL(*mock_media_playlist2, SetTargetDuration(kTargetDuration)) EXPECT_CALL(*mock_media_playlist2, SetTargetDuration(kTargetDuration))
.Times(1); .Times(1);
EXPECT_CALL(*mock_media_playlist2, EXPECT_CALL(*mock_media_playlist2,
WriteToFile(StrEq( WriteToFile(Eq(
base::FilePath::FromUTF8Unsafe(kAnyOutputDir) (std::filesystem::u8path(kAnyOutputDir) / "playlist2.m3u8"))))
.Append(base::FilePath::FromUTF8Unsafe("playlist2.m3u8"))
.AsUTF8Unsafe())))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL( EXPECT_CALL(
*mock_master_playlist_ptr, *mock_master_playlist_ptr,
@ -653,10 +648,8 @@ TEST_P(LiveOrEventSimpleHlsNotifierTest, NotifyNewSegmentsWithMultipleStreams) {
.WillOnce(Return(kLongestSegmentDuration)); .WillOnce(Return(kLongestSegmentDuration));
// Not updating other playlists as target duration does not change. // Not updating other playlists as target duration does not change.
EXPECT_CALL(*mock_media_playlist2, EXPECT_CALL(*mock_media_playlist2,
WriteToFile(StrEq( WriteToFile(Eq(
base::FilePath::FromUTF8Unsafe(kAnyOutputDir) (std::filesystem::u8path(kAnyOutputDir) / "playlist2.m3u8"))))
.Append(base::FilePath::FromUTF8Unsafe("playlist2.m3u8"))
.AsUTF8Unsafe())))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL(*mock_master_playlist_ptr, WriteMasterPlaylist(_, _, _)) EXPECT_CALL(*mock_master_playlist_ptr, WriteMasterPlaylist(_, _, _))
.WillOnce(Return(true)); .WillOnce(Return(true));
@ -673,12 +666,16 @@ class WidevineSimpleHlsNotifierTest : public SimpleHlsNotifierTest,
public WithParamInterface<bool> { public WithParamInterface<bool> {
protected: protected:
WidevineSimpleHlsNotifierTest() WidevineSimpleHlsNotifierTest()
: enable_legacy_widevine_hls_signaling_(GetParam()) { : enable_legacy_widevine_hls_signaling_(GetParam()),
FLAGS_enable_legacy_widevine_hls_signaling = saver(&FLAGS_enable_legacy_widevine_hls_signaling) {
enable_legacy_widevine_hls_signaling_; absl::SetFlag(&FLAGS_enable_legacy_widevine_hls_signaling,
enable_legacy_widevine_hls_signaling_);
} }
bool enable_legacy_widevine_hls_signaling_ = false; bool enable_legacy_widevine_hls_signaling_ = false;
private:
FlagSaver<bool> saver;
}; };
TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdate) { TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdate) {
@ -698,9 +695,9 @@ TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdate) {
0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44,
0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44,
}; };
std::vector<uint8_t> any_key_id(kAnyKeyId, kAnyKeyId + arraysize(kAnyKeyId)); std::vector<uint8_t> any_key_id(kAnyKeyId, kAnyKeyId + std::size(kAnyKeyId));
widevine_pssh_data.add_key_id()->assign(kAnyKeyId, widevine_pssh_data.add_key_id()->assign(kAnyKeyId,
kAnyKeyId + arraysize(kAnyKeyId)); kAnyKeyId + std::size(kAnyKeyId));
std::string widevine_pssh_data_str = widevine_pssh_data.SerializeAsString(); std::string widevine_pssh_data_str = widevine_pssh_data.SerializeAsString();
EXPECT_TRUE(!widevine_pssh_data_str.empty()); EXPECT_TRUE(!widevine_pssh_data_str.empty());
@ -717,11 +714,11 @@ TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdate) {
R"({"key_ids":["11223344112233441122334411223344"],)" R"({"key_ids":["11223344112233441122334411223344"],)"
R"("provider":"someprovider","content_id":"Y29udGVudGlk"})"; R"("provider":"someprovider","content_id":"Y29udGVudGlk"})";
std::string expected_json_base64; std::string expected_json_base64;
base::Base64Encode(kExpectedJson, &expected_json_base64); absl::Base64Escape(kExpectedJson, &expected_json_base64);
std::string expected_pssh_base64; std::string expected_pssh_base64;
const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox(); const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox();
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()), absl::Base64Escape(std::string(pssh_box.begin(), pssh_box.end()),
&expected_pssh_base64); &expected_pssh_base64);
EXPECT_CALL(*mock_media_playlist, EXPECT_CALL(*mock_media_playlist,
@ -763,7 +760,7 @@ TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdateNoKeyidsInPssh) {
R"({"key_ids":["11223344112233441122334411223344"],)" R"({"key_ids":["11223344112233441122334411223344"],)"
R"("provider":"someprovider","content_id":"Y29udGVudGlk"})"; R"("provider":"someprovider","content_id":"Y29udGVudGlk"})";
std::string expected_json_base64; std::string expected_json_base64;
base::Base64Encode(kExpectedJson, &expected_json_base64); absl::Base64Escape(kExpectedJson, &expected_json_base64);
media::PsshBoxBuilder pssh_builder; media::PsshBoxBuilder pssh_builder;
pssh_builder.set_pssh_data(pssh_data); pssh_builder.set_pssh_data(pssh_data);
@ -772,7 +769,7 @@ TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdateNoKeyidsInPssh) {
std::string expected_pssh_base64; std::string expected_pssh_base64;
const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox(); const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox();
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()), absl::Base64Escape(std::string(pssh_box.begin(), pssh_box.end()),
&expected_pssh_base64); &expected_pssh_base64);
EXPECT_CALL(*mock_media_playlist, EXPECT_CALL(*mock_media_playlist,
@ -793,7 +790,7 @@ TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdateNoKeyidsInPssh) {
}; };
EXPECT_TRUE(notifier.NotifyEncryptionUpdate( EXPECT_TRUE(notifier.NotifyEncryptionUpdate(
stream_id, stream_id,
std::vector<uint8_t>(kAnyKeyId, kAnyKeyId + arraysize(kAnyKeyId)), std::vector<uint8_t>(kAnyKeyId, kAnyKeyId + std::size(kAnyKeyId)),
widevine_system_id_, iv, pssh_box)); widevine_system_id_, iv, pssh_box));
} }
@ -821,14 +818,14 @@ TEST_P(WidevineSimpleHlsNotifierTest, MultipleKeyIdsNoContentIdInPssh) {
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
}; };
std::vector<uint8_t> first_keyid(kFirstKeyId, std::vector<uint8_t> first_keyid(kFirstKeyId,
kFirstKeyId + arraysize(kFirstKeyId)); kFirstKeyId + std::size(kFirstKeyId));
std::vector<uint8_t> second_keyid(kSecondKeyId, std::vector<uint8_t> second_keyid(kSecondKeyId,
kSecondKeyId + arraysize(kSecondKeyId)); kSecondKeyId + std::size(kSecondKeyId));
widevine_pssh_data.add_key_id()->assign(kFirstKeyId, widevine_pssh_data.add_key_id()->assign(kFirstKeyId,
kFirstKeyId + arraysize(kFirstKeyId)); kFirstKeyId + std::size(kFirstKeyId));
widevine_pssh_data.add_key_id()->assign( widevine_pssh_data.add_key_id()->assign(
kSecondKeyId, kSecondKeyId + arraysize(kSecondKeyId)); kSecondKeyId, kSecondKeyId + std::size(kSecondKeyId));
std::string widevine_pssh_data_str = widevine_pssh_data.SerializeAsString(); std::string widevine_pssh_data_str = widevine_pssh_data.SerializeAsString();
EXPECT_TRUE(!widevine_pssh_data_str.empty()); EXPECT_TRUE(!widevine_pssh_data_str.empty());
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(), std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
@ -847,11 +844,11 @@ TEST_P(WidevineSimpleHlsNotifierTest, MultipleKeyIdsNoContentIdInPssh) {
R"("11111111111111111111111111111111"],)" R"("11111111111111111111111111111111"],)"
R"("provider":"someprovider"})"; R"("provider":"someprovider"})";
std::string expected_json_base64; std::string expected_json_base64;
base::Base64Encode(kExpectedJson, &expected_json_base64); absl::Base64Escape(kExpectedJson, &expected_json_base64);
std::string expected_pssh_base64; std::string expected_pssh_base64;
const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox(); const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox();
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()), absl::Base64Escape(std::string(pssh_box.begin(), pssh_box.end()),
&expected_pssh_base64); &expected_pssh_base64);
EXPECT_CALL(*mock_media_playlist, EXPECT_CALL(*mock_media_playlist,
@ -893,9 +890,9 @@ TEST_P(WidevineSimpleHlsNotifierTest, CencEncryptionScheme) {
0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44,
0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44,
}; };
std::vector<uint8_t> any_key_id(kAnyKeyId, kAnyKeyId + arraysize(kAnyKeyId)); std::vector<uint8_t> any_key_id(kAnyKeyId, kAnyKeyId + std::size(kAnyKeyId));
widevine_pssh_data.add_key_id()->assign(kAnyKeyId, widevine_pssh_data.add_key_id()->assign(kAnyKeyId,
kAnyKeyId + arraysize(kAnyKeyId)); kAnyKeyId + std::size(kAnyKeyId));
std::string widevine_pssh_data_str = widevine_pssh_data.SerializeAsString(); std::string widevine_pssh_data_str = widevine_pssh_data.SerializeAsString();
EXPECT_TRUE(!widevine_pssh_data_str.empty()); EXPECT_TRUE(!widevine_pssh_data_str.empty());
@ -904,7 +901,7 @@ TEST_P(WidevineSimpleHlsNotifierTest, CencEncryptionScheme) {
std::string expected_pssh_base64; std::string expected_pssh_base64;
const std::vector<uint8_t> pssh_box = {'p', 's', 's', 'h'}; const std::vector<uint8_t> pssh_box = {'p', 's', 's', 'h'};
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()), absl::Base64Escape(std::string(pssh_box.begin(), pssh_box.end()),
&expected_pssh_base64); &expected_pssh_base64);
EXPECT_CALL(*mock_media_playlist, EXPECT_CALL(*mock_media_playlist,
@ -932,9 +929,9 @@ TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdateEmptyIv) {
0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44,
0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44, 0x11, 0x22, 0x33, 0x44,
}; };
std::vector<uint8_t> any_key_id(kAnyKeyId, kAnyKeyId + arraysize(kAnyKeyId)); std::vector<uint8_t> any_key_id(kAnyKeyId, kAnyKeyId + std::size(kAnyKeyId));
widevine_pssh_data.add_key_id()->assign(kAnyKeyId, widevine_pssh_data.add_key_id()->assign(kAnyKeyId,
kAnyKeyId + arraysize(kAnyKeyId)); kAnyKeyId + std::size(kAnyKeyId));
std::string widevine_pssh_data_str = widevine_pssh_data.SerializeAsString(); std::string widevine_pssh_data_str = widevine_pssh_data.SerializeAsString();
EXPECT_TRUE(!widevine_pssh_data_str.empty()); EXPECT_TRUE(!widevine_pssh_data_str.empty());
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(), std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
@ -944,7 +941,7 @@ TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdateEmptyIv) {
R"({"key_ids":["11223344112233441122334411223344"],)" R"({"key_ids":["11223344112233441122334411223344"],)"
R"("provider":"someprovider","content_id":"Y29udGVudGlk"})"; R"("provider":"someprovider","content_id":"Y29udGVudGlk"})";
std::string expected_json_base64; std::string expected_json_base64;
base::Base64Encode(kExpectedJson, &expected_json_base64); absl::Base64Escape(kExpectedJson, &expected_json_base64);
media::PsshBoxBuilder pssh_builder; media::PsshBoxBuilder pssh_builder;
pssh_builder.set_pssh_data(pssh_data); pssh_builder.set_pssh_data(pssh_data);
@ -971,13 +968,13 @@ TEST_P(WidevineSimpleHlsNotifierTest, NotifyEncryptionUpdateEmptyIv) {
std::vector<uint8_t> pssh_as_vec = pssh_builder.CreateBox(); std::vector<uint8_t> pssh_as_vec = pssh_builder.CreateBox();
std::string pssh_in_string(pssh_as_vec.begin(), pssh_as_vec.end()); std::string pssh_in_string(pssh_as_vec.begin(), pssh_as_vec.end());
std::string base_64_encoded_pssh; std::string base_64_encoded_pssh;
base::Base64Encode(pssh_in_string, &base_64_encoded_pssh); absl::Base64Escape(pssh_in_string, &base_64_encoded_pssh);
LOG(INFO) << base_64_encoded_pssh; LOG(INFO) << base_64_encoded_pssh;
std::vector<uint8_t> empty_iv; std::vector<uint8_t> empty_iv;
EXPECT_TRUE(notifier.NotifyEncryptionUpdate( EXPECT_TRUE(notifier.NotifyEncryptionUpdate(
stream_id, stream_id,
std::vector<uint8_t>(kAnyKeyId, kAnyKeyId + arraysize(kAnyKeyId)), std::vector<uint8_t>(kAnyKeyId, kAnyKeyId + std::size(kAnyKeyId)),
widevine_system_id_, empty_iv, pssh_builder.CreateBox())); widevine_system_id_, empty_iv, pssh_builder.CreateBox()));
} }

View File

@ -6,35 +6,34 @@
#include "packager/hls/base/tag.h" #include "packager/hls/base/tag.h"
#include <absl/strings/str_format.h>
#include <inttypes.h> #include <inttypes.h>
#include "packager/base/strings/stringprintf.h"
namespace shaka { namespace shaka {
namespace hls { namespace hls {
Tag::Tag(const std::string& name, std::string* buffer) : buffer_(buffer) { Tag::Tag(const std::string& name, std::string* buffer) : buffer_(buffer) {
base::StringAppendF(buffer_, "%s:", name.c_str()); absl::StrAppendFormat(buffer_, "%s:", name.c_str());
} }
void Tag::AddString(const std::string& key, const std::string& value) { void Tag::AddString(const std::string& key, const std::string& value) {
NextField(); NextField();
base::StringAppendF(buffer_, "%s=%s", key.c_str(), value.c_str()); absl::StrAppendFormat(buffer_, "%s=%s", key.c_str(), value.c_str());
} }
void Tag::AddQuotedString(const std::string& key, const std::string& value) { void Tag::AddQuotedString(const std::string& key, const std::string& value) {
NextField(); NextField();
base::StringAppendF(buffer_, "%s=\"%s\"", key.c_str(), value.c_str()); absl::StrAppendFormat(buffer_, "%s=\"%s\"", key.c_str(), value.c_str());
} }
void Tag::AddNumber(const std::string& key, uint64_t value) { void Tag::AddNumber(const std::string& key, uint64_t value) {
NextField(); NextField();
base::StringAppendF(buffer_, "%s=%" PRIu64, key.c_str(), value); absl::StrAppendFormat(buffer_, "%s=%" PRIu64, key.c_str(), value);
} }
void Tag::AddFloat(const std::string& key, float value) { void Tag::AddFloat(const std::string& key, float value) {
NextField(); NextField();
base::StringAppendF(buffer_, "%s=%.3f", key.c_str(), value); absl::StrAppendFormat(buffer_, "%s=%.3f", key.c_str(), value);
} }
void Tag::AddNumberPair(const std::string& key, void Tag::AddNumberPair(const std::string& key,
@ -42,8 +41,8 @@ void Tag::AddNumberPair(const std::string& key,
char separator, char separator,
uint64_t number2) { uint64_t number2) {
NextField(); NextField();
base::StringAppendF(buffer_, "%s=%" PRIu64 "%c%" PRIu64, key.c_str(), number1, absl::StrAppendFormat(buffer_, "%s=%" PRIu64 "%c%" PRIu64, key.c_str(),
separator, number2); number1, separator, number2);
} }
void Tag::AddQuotedNumberPair(const std::string& key, void Tag::AddQuotedNumberPair(const std::string& key,
@ -51,7 +50,7 @@ void Tag::AddQuotedNumberPair(const std::string& key,
char separator, char separator,
uint64_t number2) { uint64_t number2) {
NextField(); NextField();
base::StringAppendF(buffer_, "%s=\"%" PRIu64 "%c%" PRIu64 "\"", key.c_str(), absl::StrAppendFormat(buffer_, "%s=\"%" PRIu64 "%c%" PRIu64 "\"", key.c_str(),
number1, separator, number2); number1, separator, number2);
} }

View File

@ -7,6 +7,7 @@
#ifndef PACKAGER_HLS_BASE_TAG_H_ #ifndef PACKAGER_HLS_BASE_TAG_H_
#define PACKAGER_HLS_BASE_TAG_H_ #define PACKAGER_HLS_BASE_TAG_H_
#include <cstdint>
#include <string> #include <string>
namespace shaka { namespace shaka {

View File

@ -1,58 +0,0 @@
# Copyright 2016 Google LLC. All rights reserved.
#
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
{
'variables': {
'shaka_code': 1,
},
'targets': [
{
'target_name': 'hls_builder',
'type': '<(component)',
'sources': [
'base/hls_notifier.h',
'base/master_playlist.cc',
'base/master_playlist.h',
'base/media_playlist.cc',
'base/media_playlist.h',
'base/simple_hls_notifier.cc',
'base/simple_hls_notifier.h',
'base/tag.cc',
'base/tag.h',
'public/hls_params.h',
],
'dependencies': [
'../base/base.gyp:base',
'../file/file.gyp:file',
'../media/base/media_base.gyp:media_base',
'../media/base/media_base.gyp:widevine_pssh_data_proto',
'../mpd/mpd.gyp:manifest_base',
'../mpd/mpd.gyp:media_info_proto',
'../third_party/gflags/gflags.gyp:gflags',
],
},
{
'target_name': 'hls_unittest',
'type': '<(gtest_target_type)',
'sources': [
'base/master_playlist_unittest.cc',
'base/media_playlist_unittest.cc',
'base/mock_media_playlist.cc',
'base/mock_media_playlist.h',
'base/simple_hls_notifier_unittest.cc',
],
'dependencies': [
'../base/base.gyp:base',
'../media/test/media_test.gyp:run_tests_with_atexit_manager',
'../mpd/mpd.gyp:media_info_proto',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'../third_party/gflags/gflags.gyp:gflags',
'hls_builder',
],
},
],
}

View File

@ -31,8 +31,7 @@ target_link_libraries(mock_muxer_listener
add_executable(media_event_unittest add_executable(media_event_unittest
hls_notify_muxer_listener_unittest.cc hls_notify_muxer_listener_unittest.cc
muxer_listener_internal_unittest.cc muxer_listener_internal_unittest.cc
# TODO(cmake): Re-enable when mpd/base is ported (needs MockMpdNotifier) mpd_notify_muxer_listener_unittest.cc
# mpd_notify_muxer_listener_unittest.cc
multi_codec_muxer_listener_unittest.cc multi_codec_muxer_listener_unittest.cc
muxer_listener_test_helper.cc muxer_listener_test_helper.cc
vod_media_info_dump_muxer_listener_unittest.cc vod_media_info_dump_muxer_listener_unittest.cc
@ -40,6 +39,7 @@ add_executable(media_event_unittest
target_link_libraries(media_event_unittest target_link_libraries(media_event_unittest
file file
file_test_util file_test_util
mpd_mocks
mpd_media_info_proto mpd_media_info_proto
gmock gmock
gtest gtest

View File

@ -15,6 +15,7 @@
#include <filesystem> #include <filesystem>
#include <optional> #include <optional>
#include "packager/file/file_util.h"
#include "packager/media/base/rcheck.h" #include "packager/media/base/rcheck.h"
#include "packager/mpd/base/adaptation_set.h" #include "packager/mpd/base/adaptation_set.h"
#include "packager/mpd/base/mpd_utils.h" #include "packager/mpd/base/mpd_utils.h"
@ -88,17 +89,6 @@ bool SetIfPositive(const char* attr_name, double value, XmlNode* mpd) {
mpd->SetStringAttribute(attr_name, SecondsToXmlDuration(value)); mpd->SetStringAttribute(attr_name, SecondsToXmlDuration(value));
} }
std::string MakePathRelative(const std::filesystem::path& media_path,
const std::filesystem::path& parent_path) {
auto relative_path = std::filesystem::relative(media_path, parent_path);
if (relative_path.empty() || *relative_path.begin() == "..") {
// Not related.
relative_path = media_path;
}
return relative_path.lexically_normal().generic_string();
}
// Spooky static initialization/cleanup of libxml. // Spooky static initialization/cleanup of libxml.
class LibXmlInitializer { class LibXmlInitializer {
public: public:

View File

@ -19,12 +19,12 @@
namespace shaka { namespace shaka {
std::filesystem::path GetTestDataFilePath(const std::string& name) { std::filesystem::path GetTestDataFilePath(const std::string& name) {
auto data_dir = std::filesystem::path(TEST_DATA_DIR); auto data_dir = std::filesystem::u8path(TEST_DATA_DIR);
return data_dir / name; return data_dir / name;
} }
std::filesystem::path GetSchemaPath() { std::filesystem::path GetSchemaPath() {
auto schema_dir = std::filesystem::path(TEST_SCHEMA_DIR); auto schema_dir = std::filesystem::u8path(TEST_SCHEMA_DIR);
return schema_dir / "DASH-MPD.xsd"; return schema_dir / "DASH-MPD.xsd";
} }

View File

@ -1,7 +1,7 @@
FROM archlinux:latest FROM archlinux:latest
# Install utilities, libraries, and dev tools. # Install utilities, libraries, and dev tools.
RUN pacman -Sy --needed --noconfirm \ RUN pacman -Suy --needed --noconfirm \
core/which \ core/which \
c-ares \ c-ares \
cmake gcc git ninja python3 cmake gcc git ninja python3

View File

@ -2,7 +2,7 @@ FROM tgagor/centos:stream9
# For CentOS, Ninja is only available from the "CRB" ("Code Ready Builder") # For CentOS, Ninja is only available from the "CRB" ("Code Ready Builder")
# repo. Enable that first. # repo. Enable that first.
RUN dnf update RUN dnf update -y
RUN dnf install -y yum-utils RUN dnf install -y yum-utils
RUN dnf config-manager --set-enabled crb RUN dnf config-manager --set-enabled crb