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>
Chun-da Chen <capitalm.c@gmail.com>
Daniel Cantarín <canta@canta.com.ar>
Dennis E. Mungai (Brainiarc7) <dmngaie@gmail.com>
Dolby Laboratories <*@dolby.com>
Evgeny Zajcev <zevlg@yandex.ru>
Eyevinn Technology AB <*@eyevinn.se>
@ -27,13 +28,14 @@ Google LLC. <*@google.com>
Ivi.ru LLC <*@ivi.ru>
Leandro Moreira <leandro.ribeiro.moreira@gmail.com>
Leo Law <leoltlaw.gh@gmail.com>
Meta Platforms, Inc. <*@meta.com>
More Screens Ltd. <*@morescreens.net>
Ole Andre Birkedal <o.birkedal@sportradar.com>
Philo Inc. <*@philo.com>
Piotr Srebrny <srebrny.piotr@gmail.com>
Prakash Duggaraju <duggaraju@gmail.com>
Richard Eklycke <richard@eklycke.se>
Sanil Raut <sr1990003@gmail.com>
Sergio Ammirata <sergio@ammirata.net>
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>
Bei Li <beil@google.com>
Chun-da Chen <capitalm.c@gmail.com>
Cosmin Stejerean <cstejerean@meta.com>
Daniel Cantarín <canta@canta.com.ar>
David Cavar <pal3thorn@gmail.com>
Dennis E. Mungai (Brainiarc7) <dmngaie@gmail.com>
Evgeny Zajcev <zevlg@yandex.ru>
Gabe Kopley <gabe@philo.com>
Geoff Jukes <geoff@jukes.org>
@ -42,6 +44,7 @@ Leo Law <leoltlaw.gh@gmail.com>
Marcus Spangenberg <marcus.spangenberg@eyevinn.se>
Ole Andre Birkedal <o.birkedal@sportradar.com>
Piotr Srebrny <srebrny.piotr@gmail.com>
Prakash Duggaraju <duggaraju@gmail.com>
Qingquan Wang <wangqq1103@gmail.com>
Richard Eklycke <richard@eklycke.se>
Rintaro Kuroiwa <rkuroiwa@google.com>
@ -52,5 +55,4 @@ Thomas Inskip <tinskip@google.com>
Tim Lansen <tim.lansen@gmail.com>
Vincent Nguyen <nvincen@amazon.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(kv_pairs)
add_subdirectory(media)
add_subdirectory(hls)
add_subdirectory(mpd)
add_subdirectory(status)
add_subdirectory(third_party)

View File

@ -48,4 +48,15 @@ bool TempFilePath(const std::string& temp_dir, std::string* temp_file_path) {
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

View File

@ -4,6 +4,7 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include <filesystem>
#include <string>
namespace shaka {
@ -15,4 +16,7 @@ namespace shaka {
/// @returns true on success, false otherwise.
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

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

View File

@ -7,6 +7,7 @@
#ifndef PACKAGER_HLS_BASE_MASTER_PLAYLIST_H_
#define PACKAGER_HLS_BASE_MASTER_PLAYLIST_H_
#include <filesystem>
#include <list>
#include <string>
@ -24,7 +25,7 @@ class MasterPlaylist {
/// be tagged with 'DEFAULT'.
/// @param default_text_language determines the text rendition that should be
/// 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_text_language,
const bool is_independent_segments);
@ -48,7 +49,7 @@ class MasterPlaylist {
MasterPlaylist& operator=(const MasterPlaylist&) = delete;
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_text_language_;
bool is_independent_segments_;

View File

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

View File

@ -12,9 +12,9 @@
#include <cmath>
#include <memory>
#include "packager/base/logging.h"
#include "packager/base/strings/string_number_conversions.h"
#include "packager/base/strings/stringprintf.h"
#include <absl/strings/numbers.h>
#include <absl/strings/str_format.h>
#include <glog/logging.h>
#include "packager/file/file.h"
#include "packager/hls/base/tag.h"
#include "packager/media/base/language_utils.h"
@ -112,12 +112,12 @@ std::string CreatePlaylistHeader(
std::string version_line;
if (!version.empty()) {
version_line =
base::StringPrintf("## Generated with %s version %s\n",
GetPackagerProjectUrl().c_str(), version.c_str());
absl::StrFormat("## Generated with %s version %s\n",
GetPackagerProjectUrl().c_str(), version.c_str());
}
// 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"
"#EXT-X-VERSION:6\n"
"%s"
@ -133,20 +133,21 @@ std::string CreatePlaylistHeader(
break;
case HlsPlaylistType::kLive:
if (media_sequence_number > 0) {
base::StringAppendF(&header, "#EXT-X-MEDIA-SEQUENCE:%d\n",
media_sequence_number);
absl::StrAppendFormat(&header, "#EXT-X-MEDIA-SEQUENCE:%d\n",
media_sequence_number);
}
if (discontinuity_sequence_number > 0) {
base::StringAppendF(&header, "#EXT-X-DISCONTINUITY-SEQUENCE:%d\n",
discontinuity_sequence_number);
absl::StrAppendFormat(&header, "#EXT-X-DISCONTINUITY-SEQUENCE:%d\n",
discontinuity_sequence_number);
}
break;
default:
NOTREACHED() << "Unexpected MediaPlaylistType " << static_cast<int>(type);
NOTIMPLEMENTED() << "Unexpected MediaPlaylistType "
<< static_cast<int>(type);
}
if (stream_type ==
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
@ -209,17 +210,17 @@ SegmentInfoEntry::SegmentInfoEntry(const std::string& file_name,
previous_segment_end_offset_(previous_segment_end_offset) {}
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_) {
base::StringAppendF(&result, "\n#EXT-X-BYTERANGE:%" PRIu64,
segment_file_size_);
absl::StrAppendFormat(&result, "\n#EXT-X-BYTERANGE:%" PRIu64,
segment_file_size_);
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;
}
@ -445,7 +446,7 @@ void MediaPlaylist::AddKeyFrame(int64_t timestamp,
stream_type_ = MediaPlaylistStreamType::kVideoIFramesOnly;
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,
@ -469,7 +470,7 @@ void MediaPlaylist::AddPlacementOpportunity() {
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_) {
SetTargetDuration(ceil(GetLongestSegmentDuration()));
}
@ -479,14 +480,14 @@ bool MediaPlaylist::WriteToFile(const std::string& file_path) {
media_sequence_number_, discontinuity_sequence_number_);
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) {
content += "#EXT-X-ENDLIST\n";
}
if (!File::WriteFileAtomically(file_path.c_str(), content)) {
LOG(ERROR) << "Failed to write playlist to: " << file_path;
if (!File::WriteFileAtomically(file_path.string().c_str(), content)) {
LOG(ERROR) << "Failed to write playlist to: " << file_path.string();
return false;
}
return true;
@ -691,7 +692,8 @@ void MediaPlaylist::SlideWindow() {
} else if (entry_type == HlsEntry::EntryType::kExtDiscontinuity) {
++discontinuity_sequence_number_;
} 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 =
*reinterpret_cast<SegmentInfoEntry*>(last->get());

View File

@ -7,13 +7,14 @@
#ifndef PACKAGER_HLS_BASE_MEDIA_PLAYLIST_H_
#define PACKAGER_HLS_BASE_MEDIA_PLAYLIST_H_
#include <filesystem>
#include <list>
#include <memory>
#include <string>
#include <vector>
#include "packager/base/macros.h"
#include "packager/hls/public/hls_params.h"
#include "packager/macros.h"
#include "packager/mpd/base/bandwidth_estimator.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
/// implementation.
/// @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.
/// Otherwise, returns the max bitrate.

View File

@ -7,7 +7,7 @@
#include <gmock/gmock.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_closer.h"
#include "packager/file/file_test_util.h"
@ -1032,8 +1032,8 @@ class MediaPlaylistDeleteSegmentsTest
std::string GetSegmentName(int index) {
if (segment_template_.find("$Time$") != std::string::npos)
return base::StringPrintf(kStringPrintTemplate, GetTime(index));
return base::StringPrintf(kStringPrintTemplate, index + 1);
return absl::StrFormat(kStringPrintTemplate, GetTime(index));
return absl::StrFormat(kStringPrintTemplate, index + 1);
}
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_versions));
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(AvgBitrate, uint64_t());
MOCK_CONST_METHOD0(GetLongestSegmentDuration, double());

View File

@ -6,31 +6,29 @@
#include "packager/hls/base/simple_hls_notifier.h"
#include <gflags/gflags.h>
#include <absl/flags/flag.h>
#include <cmath>
#include "packager/base/base64.h"
#include "packager/base/files/file_path.h"
#include "packager/base/logging.h"
#include "packager/base/optional.h"
#include "packager/base/strings/string_number_conversions.h"
#include "packager/base/strings/stringprintf.h"
#include "packager/hls/base/media_playlist.h"
#include <absl/strings/escaping.h>
#include <absl/strings/numbers.h>
#include <glog/logging.h>
#include <filesystem>
#include <optional>
#include "packager/file/file_util.h"
#include "packager/media/base/protection_system_ids.h"
#include "packager/media/base/protection_system_specific_info.h"
#include "packager/media/base/proto_json_util.h"
#include "packager/media/base/widevine_pssh_data.pb.h"
DEFINE_bool(enable_legacy_widevine_hls_signaling,
false,
"Specifies whether Legacy Widevine HLS, i.e. v1 is signalled in "
"the media playlist. Applies to Widevine protection system in HLS "
"with SAMPLE-AES only.");
ABSL_FLAG(bool,
enable_legacy_widevine_hls_signaling,
false,
"Specifies whether Legacy Widevine HLS, i.e. v1 is signalled in "
"the media playlist. Applies to Widevine protection system in HLS "
"with SAMPLE-AES only.");
namespace shaka {
using base::FilePath;
namespace hls {
namespace {
@ -41,18 +39,18 @@ const char kWidevineDashIfIopUUID[] =
"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";
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(),
media::kWidevineSystemId);
}
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);
}
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(),
media::kFairPlaySystemId);
}
@ -60,7 +58,7 @@ bool IsFairPlaySystemId(const std::vector<uint8_t>& system_id) {
std::string Base64EncodeData(const std::string& prefix,
const std::string& data) {
std::string data_base64;
base::Base64Encode(data, &data_base64);
absl::Base64Escape(data, &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());
}
// 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
// containing the media playlist depends on whether base_url is set.
std::string GenerateSegmentUrl(const std::string& segment_name,
const std::string& base_url,
const std::string& output_dir,
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()) {
// Media segment URL is base_url + segment path relative to output
// 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
// playlist.
const FilePath playlist_dir =
output_path.Append(FilePath::FromUTF8Unsafe(playlist_file_name))
.DirName()
.AsEndingWithSeparator();
const std::filesystem::path playlist_dir =
(output_path / playlist_file_name).parent_path() / "";
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
// 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()) {
const std::string key_id_hex =
base::HexEncode(key_id_in_pssh.data(), key_id_in_pssh.size());
const std::string key_id_hex = absl::BytesToHexString(
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)
widevine_header.add_key_ids(key_id_hex);
}
@ -180,7 +158,7 @@ bool WidevinePsshToJson(const std::vector<uint8_t>& pssh_box,
return true;
}
base::Optional<MediaPlaylist::EncryptionMethod> StringToEncryptionMethod(
std::optional<MediaPlaylist::EncryptionMethod> StringToEncryptionMethod(
const std::string& method) {
if (method == "cenc") {
return MediaPlaylist::EncryptionMethod::kSampleAesCenc;
@ -192,7 +170,7 @@ base::Optional<MediaPlaylist::EncryptionMethod> StringToEncryptionMethod(
// cbca is a place holder for sample aes.
return MediaPlaylist::EncryptionMethod::kSampleAes;
}
return base::nullopt;
return std::nullopt;
}
void NotifyEncryptionToMediaPlaylist(
@ -205,11 +183,15 @@ void NotifyEncryptionToMediaPlaylist(
MediaPlaylist* media_playlist) {
std::string iv_string;
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;
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(
@ -225,7 +207,7 @@ bool HandleWidevineKeyFormats(
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& protection_system_specific_data,
MediaPlaylist* media_playlist) {
if (FLAGS_enable_legacy_widevine_hls_signaling &&
if (absl::GetFlag(FLAGS_enable_legacy_widevine_hls_signaling) &&
encryption_method == MediaPlaylist::EncryptionMethod::kSampleAes) {
// This format allows SAMPLE-AES only.
std::string key_uri_data;
@ -253,12 +235,9 @@ bool HandleWidevineKeyFormats(
bool WriteMediaPlaylist(const std::string& output_dir,
MediaPlaylist* playlist) {
std::string file_path =
FilePath::FromUTF8Unsafe(output_dir)
.Append(FilePath::FromUTF8Unsafe(playlist->file_name()))
.AsUTF8Unsafe();
auto file_path = std::filesystem::u8path(output_dir) / playlist->file_name();
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 true;
@ -280,18 +259,17 @@ std::unique_ptr<MediaPlaylist> MediaPlaylistFactory::Create(
SimpleHlsNotifier::SimpleHlsNotifier(const HlsParams& hls_params)
: HlsNotifier(hls_params),
media_playlist_factory_(new MediaPlaylistFactory()) {
const base::FilePath master_playlist_path(
base::FilePath::FromUTF8Unsafe(hls_params.master_playlist_output));
master_playlist_dir_ = master_playlist_path.DirName().AsUTF8Unsafe();
const auto master_playlist_path =
std::filesystem::u8path(hls_params.master_playlist_output);
master_playlist_dir_ = master_playlist_path.parent_path().string();
const std::string& default_audio_langauge = hls_params.default_language;
const std::string& default_text_language =
hls_params.default_text_language.empty()
? hls_params.default_language
: hls_params.default_text_language;
master_playlist_.reset(
new MasterPlaylist(master_playlist_path.BaseName().AsUTF8Unsafe(),
default_audio_langauge, default_text_language,
hls_params.is_independent_segments));
master_playlist_.reset(new MasterPlaylist(
master_playlist_path.filename(), default_audio_langauge,
default_text_language, hls_params.is_independent_segments));
}
SimpleHlsNotifier::~SimpleHlsNotifier() {}
@ -308,7 +286,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
DCHECK(stream_id);
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 =
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()) {
const std::string& protection_scheme =
media_info.protected_content().protection_scheme();
base::Optional<MediaPlaylist::EncryptionMethod> enc_method =
std::optional<MediaPlaylist::EncryptionMethod> enc_method =
StringToEncryptionMethod(protection_scheme);
if (!enc_method) {
LOG(ERROR) << "Failed to recognize protection scheme "
@ -336,7 +314,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
encryption_method = enc_method.value();
}
base::AutoLock auto_lock(lock_);
absl::MutexLock lock(&lock_);
*stream_id = sequence_number_++;
media_playlists_.push_back(media_playlist.get());
stream_map_[*stream_id].reset(
@ -346,7 +324,7 @@ bool SimpleHlsNotifier::NotifyNewStream(const MediaInfo& media_info,
bool SimpleHlsNotifier::NotifySampleDuration(uint32_t stream_id,
int32_t sample_duration) {
base::AutoLock auto_lock(lock_);
absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) {
LOG(ERROR) << "Cannot find stream with ID: " << stream_id;
@ -363,7 +341,7 @@ bool SimpleHlsNotifier::NotifyNewSegment(uint32_t stream_id,
int64_t duration,
uint64_t start_byte_offset,
uint64_t size) {
base::AutoLock auto_lock(lock_);
absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) {
LOG(ERROR) << "Cannot find stream with ID: " << stream_id;
@ -412,7 +390,7 @@ bool SimpleHlsNotifier::NotifyKeyFrame(uint32_t stream_id,
int64_t timestamp,
uint64_t start_byte_offset,
uint64_t size) {
base::AutoLock auto_lock(lock_);
absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) {
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) {
base::AutoLock auto_lock(lock_);
absl::MutexLock lock(&lock_);
auto stream_iterator = stream_map_.find(stream_id);
if (stream_iterator == stream_map_.end()) {
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>& iv,
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);
if (stream_iterator == stream_map_.end()) {
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: "
<< 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;
}
bool SimpleHlsNotifier::Flush() {
base::AutoLock auto_lock(lock_);
absl::MutexLock lock(&lock_);
for (MediaPlaylist* playlist : media_playlists_) {
playlist->SetTargetDuration(target_duration_);
if (!WriteMediaPlaylist(master_playlist_dir_, playlist))

View File

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

View File

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

View File

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

View File

@ -7,6 +7,7 @@
#ifndef PACKAGER_HLS_BASE_TAG_H_
#define PACKAGER_HLS_BASE_TAG_H_
#include <cstdint>
#include <string>
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
hls_notify_muxer_listener_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
muxer_listener_test_helper.cc
vod_media_info_dump_muxer_listener_unittest.cc
@ -40,6 +39,7 @@ add_executable(media_event_unittest
target_link_libraries(media_event_unittest
file
file_test_util
mpd_mocks
mpd_media_info_proto
gmock
gtest

View File

@ -15,6 +15,7 @@
#include <filesystem>
#include <optional>
#include "packager/file/file_util.h"
#include "packager/media/base/rcheck.h"
#include "packager/mpd/base/adaptation_set.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));
}
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.
class LibXmlInitializer {
public:

View File

@ -19,12 +19,12 @@
namespace shaka {
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;
}
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";
}

View File

@ -1,7 +1,7 @@
FROM archlinux:latest
# Install utilities, libraries, and dev tools.
RUN pacman -Sy --needed --noconfirm \
RUN pacman -Suy --needed --noconfirm \
core/which \
c-ares \
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")
# repo. Enable that first.
RUN dnf update
RUN dnf update -y
RUN dnf install -y yum-utils
RUN dnf config-manager --set-enabled crb