1
0
Fork 0
mirror of https://github.com/fastogt/fastocloud.git synced 2025-03-09 23:18:50 +00:00

Init FastoCloud on Github

This commit is contained in:
topilski 2023-01-21 05:21:27 +03:00
parent d0d234101d
commit d0d6551903
359 changed files with 32676 additions and 23 deletions

70
src/utils/CMakeLists.txt Normal file
View file

@ -0,0 +1,70 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR)
PROJECT(utils)
IF(OS_WINDOWS)
SET(PLATFORM_HEADER)
SET(PLATFORM_SOURCES)
SET(PLATFORM_LIBRARIES)
ELSEIF(OS_LINUX)
SET(PLATFORM_HEADER)
SET(PLATFORM_SOURCES)
SET(PLATFORM_LIBRARIES)
ELSEIF(OS_POSIX)
SET(PLATFORM_HEADER)
SET(PLATFORM_SOURCES)
SET(PLATFORM_LIBRARIES)
ENDIF(OS_WINDOWS)
IF(USE_PTHREAD)
IF(NOT OS_ANDROID)
SET(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} pthread)
ENDIF(NOT OS_ANDROID)
ENDIF(USE_PTHREAD)
SET(HEADERS
${CMAKE_SOURCE_DIR}/src/utils/chunk_info.h
${CMAKE_SOURCE_DIR}/src/utils/m3u8_reader.h
${CMAKE_SOURCE_DIR}/src/utils/m3u8_writer.h
)
SET(SOURCES
${CMAKE_SOURCE_DIR}/src/utils/chunk_info.cpp
${CMAKE_SOURCE_DIR}/src/utils/m3u8_reader.cpp
${CMAKE_SOURCE_DIR}/src/utils/m3u8_writer.cpp
)
SET(UTILS_SOURCES ${HEADERS} ${SOURCES})
SET(UTILS_LIBRARIES ${COMMON_BASE_LIBRARY})
SET(INCLUDE_DIRECTORIES_UTILS
${INCLUDE_DIRECTORIES_UTILS}
${CMAKE_SOURCE_DIR}/src
${COMMON_INCLUDE_DIRS}
)
ADD_LIBRARY(${PROJECT_NAME} STATIC ${UTILS_SOURCES})
TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PRIVATE ${INCLUDE_DIRECTORIES_UTILS})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${UTILS_LIBRARIES})
IF (DEVELOPER_CHECK_STYLE)
SET(CHECK_SOURCES ${UTILS_SOURCES})
REGISTER_CHECK_STYLE_TARGET(check_style_utils "${CHECK_SOURCES}")
REGISTER_CHECK_INCLUDES_TARGET(${PROJECT_NAME})
ENDIF(DEVELOPER_CHECK_STYLE)
IF(DEVELOPER_ENABLE_TESTS)
FIND_PACKAGE(GTest REQUIRED)
SET(UTILS_UNIT_TEST "utils_unit_tests")
SET(PRIVATE_INCLUDE_DIRECTORIES_UTILS_TESTS
${PRIVATE_INCLUDE_DIRECTORIES_UTILS_TESTS}
${CMAKE_SOURCE_DIR}/src
)
SET(UTILS_TESTS_LIBS ${PROJECT_NAME} ${GTEST_BOTH_LIBRARIES} ${PLATFORM_LIBRARIES})
ADD_EXECUTABLE(${UTILS_UNIT_TEST}
${CMAKE_SOURCE_DIR}/tests/utils/unit_test_utils.cpp
)
TARGET_INCLUDE_DIRECTORIES(${UTILS_UNIT_TEST} PRIVATE ${PRIVATE_INCLUDE_DIRECTORIES_UTILS_TESTS})
TARGET_COMPILE_DEFINITIONS(${UTILS_UNIT_TEST} PRIVATE -DPROJECT_TEST_SOURCES_DIR="${CMAKE_SOURCE_DIR}/tests")
TARGET_LINK_LIBRARIES(${UTILS_UNIT_TEST} ${UTILS_TESTS_LIBS})
ADD_TEST_TARGET(${UTILS_UNIT_TEST})
SET_PROPERTY(TARGET ${UTILS_UNIT_TEST} PROPERTY FOLDER "Utils unit tests")
ENDIF(DEVELOPER_ENABLE_TESTS)

78
src/utils/chunk_info.cpp Normal file
View file

@ -0,0 +1,78 @@
/* Copyright (C) 2014-2022 FastoGT. All right reserved.
This file is part of fastocloud.
fastocloud is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fastocloud is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fastocloud. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utils/chunk_info.h"
#include <common/convert2string.h>
#include <common/sprintf.h>
namespace fastocloud {
namespace utils {
ChunkInfo::ChunkInfo() : path(), duration(0), index(0) {}
ChunkInfo::ChunkInfo(const std::string& path, uint64_t duration, uint64_t index)
: path(path), duration(duration), index(index) {}
double ChunkInfo::GetDurationInSecconds() const {
return duration / static_cast<double>(SECOND);
}
} // namespace utils
} // namespace fastocloud
namespace common {
std::string ConvertToString(const fastocloud::utils::ChunkInfo& value) {
return MemSPrintf("%s:%llu:%llu", value.path, value.index, value.duration);
}
bool ConvertFromString(const std::string& from, fastocloud::utils::ChunkInfo* out) {
if (from.empty() || !out) {
return false;
}
fastocloud::utils::ChunkInfo res;
std::string line;
line.reserve(64);
size_t pos = 0;
for (size_t i = 0; i < from.size(); ++i) {
char c = from[i];
if (c == ':') {
if (pos == 0) {
res.path = line;
} else {
uint64_t ind;
if (ConvertFromString(line, &ind)) {
res.index = ind;
}
std::string lts_str = from.substr(i + 1);
uint64_t lts;
if (ConvertFromString(lts_str, &lts)) {
res.duration = lts;
}
break;
}
line.clear();
pos++;
} else {
line += c;
}
}
*out = res;
return true;
}
} // namespace common

57
src/utils/chunk_info.h Normal file
View file

@ -0,0 +1,57 @@
/* Copyright (C) 2014-2022 FastoGT. All right reserved.
This file is part of fastocloud.
fastocloud is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fastocloud is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fastocloud. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
namespace fastocloud {
namespace utils {
struct ChunkInfo {
enum { SECOND = 1000000000 };
ChunkInfo();
ChunkInfo(const std::string& path, uint64_t duration, uint64_t index);
double GetDurationInSecconds() const;
std::string path;
uint64_t duration; // in nanoseconds
size_t index;
};
inline bool operator<(const ChunkInfo& left, const ChunkInfo& right) {
if (left.duration != right.duration) {
return left.duration < right.duration;
}
return left.index < right.index;
}
inline bool operator>(const ChunkInfo& left, const ChunkInfo& right) {
if (left.duration != right.duration) {
return left.duration > right.duration;
}
return left.index > right.index;
}
} // namespace utils
} // namespace fastocloud
namespace common {
std::string ConvertToString(const fastocloud::utils::ChunkInfo& value);
bool ConvertFromString(const std::string& from, fastocloud::utils::ChunkInfo* out);
} // namespace common

215
src/utils/m3u8_reader.cpp Normal file
View file

@ -0,0 +1,215 @@
/* Copyright (C) 2014-2022 FastoGT. All right reserved.
This file is part of fastocloud.
fastocloud is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fastocloud is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fastocloud. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utils/m3u8_reader.h"
#include <regex>
#include <string>
#include <common/convert2string.h>
#define CHUNK_EXT ".ts"
#define CHUNK_EXT_RE "\\" CHUNK_EXT
#define M3U8_HEADER "#EXTM3U"
#define M3U8_VERSION "#EXT-X-VERSION:%d"
#define M3U8_ALLOW_CACHE "#EXT-X-ALLOW-CACHE:%s"
#define M3U8_MEDIA_SEQUENCE "#EXT-X-MEDIA-SEQUENCE:%d"
#define M3U8_TARGET_DURATION "#EXT-X-TARGETDURATION:%d"
#define M3U8_CHUNK_HEADER "#EXTINF:%lf"
#define M3U8_FOOTER "#EXT-X-ENDLIST"
#define SECOND 1000000000
#define MAX_LINE 255
namespace {
bool GetNonEmptyLine(FILE* file, std::string* line) {
if (!line) {
return false;
}
char t[MAX_LINE] = {0};
while (true) {
if (!fgets(t, MAX_LINE, file)) {
return false;
}
auto it = std::find_if(std::begin(t), std::end(t), [](char c) { return !std::isspace(c); });
if (it != std::end(t) && *it != 0) {
*line = t;
return true;
}
}
}
void RemoveTrailingSpaces(std::string* str) {
if (!str || str->empty()) {
return;
}
while (std::isspace(str->back())) {
str->pop_back();
}
}
} // namespace
namespace fastocloud {
namespace utils {
M3u8Reader::M3u8Reader() : version_(-1), allow_cache_(false), media_sequence_(-1), target_duration_(-1), chunks_() {}
bool M3u8Reader::Parse(const std::string& path) {
FILE* file = fopen(path.c_str(), "r");
return ParseFile(file);
}
bool M3u8Reader::Parse(const common::file_system::ascii_file_string_path& path) {
const std::string filepath = path.GetPath();
FILE* file = fopen(filepath.c_str(), "r");
return ParseFile(file);
}
bool M3u8Reader::ParseFile(FILE* file) {
static const std::regex m3u8_version("^#EXT-X-VERSION:([0-9]+)$");
static const std::regex m3u8_allow_cache("^#EXT-X-ALLOW-CACHE:([A-Z]+)$");
static const std::regex m3u8_media_sequence("^#EXT-X-MEDIA-SEQUENCE:([0-9]+)$");
static const std::regex m3u8_target_duration("^#EXT-X-TARGETDURATION:([0-9]+)$");
Clear();
if (!file) {
return false;
}
std::string line;
std::smatch match;
while (GetNonEmptyLine(file, &line)) {
RemoveTrailingSpaces(&line);
if (line == M3U8_HEADER) {
continue;
} else if (std::regex_match(line, match, m3u8_version)) {
int version;
if (!common::ConvertFromString(match.str(1), &version)) {
return false;
}
version_ = version;
} else if (std::regex_match(line, match, m3u8_allow_cache)) {
const std::string allow_cache = match.str(1);
if (allow_cache == "YES") {
allow_cache_ = true;
} else if (allow_cache == "NO") {
allow_cache_ = false;
} else {
return false;
}
continue;
} else if (std::regex_match(line, match, m3u8_media_sequence)) {
int media_sequence;
if (!common::ConvertFromString(match.str(1), &media_sequence)) {
return false;
}
media_sequence_ = media_sequence;
} else if (std::regex_match(line, match, m3u8_target_duration)) {
int target_duration;
if (!common::ConvertFromString(match.str(1), &target_duration)) {
return false;
}
target_duration_ = target_duration;
} else {
long off = ftell(file);
fseek(file, off - line.length() - 1, SEEK_SET);
return ParseChunks(file);
}
}
return false;
}
bool M3u8Reader::ParseChunks(FILE* file) {
if (!file) {
return false;
}
std::string header_line, chunk_line;
while (true) {
if (!GetNonEmptyLine(file, &header_line)) {
return !chunks_.empty();
}
RemoveTrailingSpaces(&header_line);
if (header_line == M3U8_FOOTER) {
return true;
}
if (!GetNonEmptyLine(file, &chunk_line)) {
return false;
}
RemoveTrailingSpaces(&chunk_line);
double duration = 0;
uint64_t index = 0;
static const std::regex m3u8_chunk_header_re("^#EXTINF:([0-9.]+),$");
static const std::regex m3u8_chunk_re("^[A-Za-z0-9_]*?([0-9]+)" CHUNK_EXT_RE "$");
std::smatch header_match;
if (!std::regex_match(header_line, header_match, m3u8_chunk_header_re)) {
return false;
}
if (!common::ConvertFromString(header_match.str(1), &duration)) {
return false;
}
std::smatch chunk_match;
if (!std::regex_match(chunk_line, chunk_match, m3u8_chunk_re)) {
return false;
}
if (!common::ConvertFromString(chunk_match.str(1), &index)) {
return false;
}
ChunkInfo chunk(chunk_line, static_cast<uint64_t>(duration * SECOND), index);
chunks_.push_back(chunk);
}
}
int M3u8Reader::GetVersion() const {
return version_;
}
bool M3u8Reader::IsAllowCache() const {
return allow_cache_;
}
int M3u8Reader::GetMediaSequence() const {
return media_sequence_;
}
int M3u8Reader::GetTargetDuration() const {
return target_duration_;
}
std::vector<ChunkInfo> M3u8Reader::GetChunks() const {
return chunks_;
}
void M3u8Reader::Clear() {
version_ = -1;
allow_cache_ = false;
media_sequence_ = -1;
target_duration_ = -1;
chunks_.clear();
}
} // namespace utils
} // namespace fastocloud

55
src/utils/m3u8_reader.h Normal file
View file

@ -0,0 +1,55 @@
/* Copyright (C) 2014-2022 FastoGT. All right reserved.
This file is part of fastocloud.
fastocloud is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fastocloud is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fastocloud. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <vector>
#include <common/file_system/path.h>
#include "utils/chunk_info.h"
namespace fastocloud {
namespace utils {
class M3u8Reader {
public:
M3u8Reader();
bool Parse(const std::string& path);
bool Parse(const common::file_system::ascii_file_string_path& path);
int GetVersion() const;
bool IsAllowCache() const;
int GetMediaSequence() const;
int GetTargetDuration() const;
std::vector<ChunkInfo> GetChunks() const;
private:
void Clear();
bool ParseFile(FILE* file);
bool ParseChunks(FILE* file);
int version_;
bool allow_cache_;
int media_sequence_;
int target_duration_;
std::vector<ChunkInfo> chunks_;
};
} // namespace utils
} // namespace fastocloud

53
src/utils/m3u8_writer.cpp Normal file
View file

@ -0,0 +1,53 @@
/* Copyright (C) 2014-2022 FastoGT. All right reserved.
This file is part of fastocloud.
fastocloud is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fastocloud is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fastocloud. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utils/m3u8_writer.h"
#include "utils/chunk_info.h"
namespace fastocloud {
namespace utils {
M3u8Writer::M3u8Writer() : file_() {}
common::ErrnoError M3u8Writer::Open(const common::file_system::ascii_file_string_path& file_path, uint32_t flags) {
return file_.Open(file_path, flags);
}
common::ErrnoError M3u8Writer::WriteHeader(uint64_t first_index, size_t target_duration) {
size_t writed;
return file_.WriteBuffer(common::MemSPrintf("#EXTM3U\n#EXT-X-MEDIA-SEQUENCE:%llu\n#EXT-X-ALLOW-"
"CACHE:YES\n#EXT-X-VERSION:3\n#EXT-X-"
"TARGETDURATION:%llu\n",
first_index, target_duration),
&writed);
}
common::ErrnoError M3u8Writer::WriteLine(const ChunkInfo& chunk) {
double ftime = chunk.GetDurationInSecconds();
size_t writed;
return file_.WriteBuffer(common::MemSPrintf("#EXTINF:%.2f,\n%s\n", ftime, chunk.path), &writed);
}
common::ErrnoError M3u8Writer::WriteFooter() {
size_t writed;
return file_.WriteBuffer("#EXT-X-ENDLIST", &writed);
}
common::ErrnoError M3u8Writer::Close() {
return file_.Close();
}
} // namespace utils
} // namespace fastocloud

41
src/utils/m3u8_writer.h Normal file
View file

@ -0,0 +1,41 @@
/* Copyright (C) 2014-2022 FastoGT. All right reserved.
This file is part of fastocloud.
fastocloud is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fastocloud is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fastocloud. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <common/file_system/file.h>
namespace fastocloud {
namespace utils {
struct ChunkInfo;
class M3u8Writer {
public:
M3u8Writer();
common::ErrnoError Open(const common::file_system::ascii_file_string_path& file_path,
uint32_t flags) WARN_UNUSED_RESULT;
common::ErrnoError WriteHeader(uint64_t first_index, size_t target_duration) WARN_UNUSED_RESULT;
common::ErrnoError WriteLine(const ChunkInfo& chunks) WARN_UNUSED_RESULT;
common::ErrnoError WriteFooter() WARN_UNUSED_RESULT;
common::ErrnoError Close() WARN_UNUSED_RESULT;
private:
common::file_system::File file_;
};
} // namespace utils
} // namespace fastocloud