From a05050e100607746a28b77de6398d1a52edba3ca Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 14 Mar 2024 00:07:04 +0200 Subject: [PATCH 01/29] Add C interface --- include/packager/live_packager_export.h | 67 +++++++++++++++++++++++++ packager/CMakeLists.txt | 3 ++ packager/live_packager.cc | 60 ++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 include/packager/live_packager_export.h diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h new file mode 100644 index 00000000000..5ce6b53cd95 --- /dev/null +++ b/include/packager/live_packager_export.h @@ -0,0 +1,67 @@ +// +// Created by Oleksandr Khodos on 13.03.2024. +// + +#ifndef PACKAGER_LIVE_PACKAGER_EXPORT_H +#define PACKAGER_LIVE_PACKAGER_EXPORT_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +typedef enum OutputFormat { + OUTPUT_FORMAT_FMP4, + OUTPUT_FORMAT_TS, + OUTPUT_FORMAT_VTTMP4, + OUTPUT_FORMAT_TTMLMP4, + OUTPUT_FORMAT_TTML, +} OutputFormat_t; + +typedef enum TrackType { + TRACK_TYPE_AUDIO, + TRACK_TYPE_VIDEO, + TRACK_TYPE_TEXT, +} TrackType_t; + +typedef enum EncryptionScheme { + ENCRYPTION_SCHEME_NONE, + ENCRYPTION_SCHEME_SAMPLE_AES, + ENCRYPTION_SCHEME_AES_128, + ENCRYPTION_SCHEME_CBCS, + ENCRYPTION_SCHEME_CENC, +} EncryptionScheme_t; + +#define KEY_IV_LEN 16 + +typedef struct LivePackagerConfig { + OutputFormat_t format; + TrackType_t track_type; + + uint8_t iv [KEY_IV_LEN]; + uint8_t key [KEY_IV_LEN]; + uint8_t key_id[KEY_IV_LEN]; + EncryptionScheme_t protection_scheme; + + uint32_t segment_number; + int32_t m2ts_offset_ms; + int64_t timed_text_decode_time; +} LivePackagerConfig_t; + +typedef struct LivePackager_instance_s* LivePackager_t; + +LivePackager_t livepackager_new(LivePackagerConfig_t cfg); +void livepackager_free(LivePackager_t lp); + +size_t livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* dest); +size_t livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* seg, size_t seg_len, uint8_t* dest); +size_t livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, uint8_t* dest); + +#ifdef __cplusplus +} +#endif + + +#endif //PACKAGER_LIVE_PACKAGER_EXPORT_H diff --git a/packager/CMakeLists.txt b/packager/CMakeLists.txt index 53ebfbf1a45..50e63d6fca8 100644 --- a/packager/CMakeLists.txt +++ b/packager/CMakeLists.txt @@ -9,6 +9,8 @@ # Include a module to define standard install directories. include(GNUInstallDirs) +set(BUILD_SHARED_LIBS ON) + # Build static libs by default, or shared if BUILD_SHARED_LIBS is on. if(BUILD_SHARED_LIBS) add_definitions(-DSHARED_LIBRARY_BUILD) @@ -92,6 +94,7 @@ set(libpackager_sources live_packager.cc ../include/packager/packager.h ../include/packager/live_packager.h + ../include/packager/live_packager_export.h ) set(libpackager_deps diff --git a/packager/live_packager.cc b/packager/live_packager.cc index bf666b0645e..bd6c40fd147 100644 --- a/packager/live_packager.cc +++ b/packager/live_packager.cc @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -647,3 +648,62 @@ Status GeneratePSSHData(const PSSHGeneratorInput& in, PSSHData* out) { return Status::OK; } } // namespace shaka + +struct LivePackager_instance_s { + std::unique_ptr inner; +}; + +LivePackager_t livepackager_new(LivePackagerConfig_t cfg) { + return new LivePackager_instance_s{std::make_unique(shaka::LiveConfig{ + .format = shaka::LiveConfig::OutputFormat(cfg.format), + .track_type = shaka::LiveConfig::TrackType(cfg.track_type), + .iv=std::vector(cfg.iv, cfg.iv+sizeof(cfg.iv)), + .key=std::vector(cfg.key, cfg.key+sizeof(cfg.key)), + .key_id=std::vector(cfg.key_id, cfg.key_id+sizeof(cfg.key_id)), + .protection_scheme=shaka::LiveConfig::EncryptionScheme(cfg.protection_scheme), + .segment_number = cfg.segment_number, + .m2ts_offset_ms = cfg.m2ts_offset_ms, + .timed_text_decode_time = cfg.timed_text_decode_time, + })}; +} + +void livepackager_free(LivePackager_t lp) { + delete lp; +} + +size_t livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* dest) { + shaka::SegmentData input(init, init_len); + shaka::FullSegmentBuffer output; + shaka::Status status = lp->inner->PackageInit(input, output); + if (!status.ok()) { + return -1; + } + + std::memcpy(dest, output.InitSegmentData(), output.InitSegmentSize()); + return output.InitSegmentSize(); +} + +size_t livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* seg, size_t seg_len, uint8_t* dest) { + shaka::SegmentData input_init(init, init_len); + shaka::SegmentData input_seg(seg, seg_len); + shaka::FullSegmentBuffer output; + shaka::Status status = lp->inner->Package(input_init, input_seg, output); + if (!status.ok()) { + return -1; + } + + std::memcpy(dest, output.SegmentData(), output.SegmentSize()); + return output.SegmentSize(); +} + +size_t livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, uint8_t* dest) { + shaka::SegmentData input_seg(seg, seg_len); + shaka::FullSegmentBuffer output; + shaka::Status status = lp->inner->PackageTimedText(input_seg, output); + if (!status.ok()) { + return -1; + } + + std::memcpy(dest, output.SegmentData(), output.SegmentSize()); + return output.SegmentSize(); +} From 2b599cb771c8f1b71413eb3f74d3accbc9809793 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 14 Mar 2024 10:24:59 +0200 Subject: [PATCH 02/29] update action --- .github/workflows/github-dev-snap.yaml | 44 +++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/.github/workflows/github-dev-snap.yaml b/.github/workflows/github-dev-snap.yaml index 5a273e3ccc8..79cb47600b4 100644 --- a/.github/workflows/github-dev-snap.yaml +++ b/.github/workflows/github-dev-snap.yaml @@ -12,6 +12,7 @@ on: env: ARTIFACT_NAME: "artifact" + ARTIFACT_NAME_2: "artifact_arm64" jobs: build_linux: @@ -54,6 +55,40 @@ jobs: name: ${{ env.ARTIFACT_NAME }} path: build/packager/libpackager.so + build_macos_arm64: + name: MacOS M1 build + runs-on: macos-14 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag }} + submodules: recursive + + - name: Generate build files + run: | + mkdir -p build/ + + cmake \ + -DCMAKE_BUILD_TYPE="Release" \ + -DBUILD_SHARED_LIBS=1 \ + -DUSE_WORKAROUND_FOR_TRUN_VERSION_0=1 \ + -S . \ + -B build/ + + - name: Build + run: cmake --build build/ --parallel $(getconf _NPROCESSORS_ONLN) + + # Debug + - name: Display structure of built files + run: ls -la build/packager + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ env.ARTIFACT_NAME_2 }} + path: build/packager/libpackager.dylib + update_release: needs: [build_linux] name: Update release @@ -67,6 +102,11 @@ jobs: with: name: ${{ env.ARTIFACT_NAME }} + - name: Download artifact 2 + uses: actions/download-artifact@v3 + with: + name: ${{ env.ARTIFACT_NAME_2 }} + # Debug - name: Display structure of downloaded files run: ls -la @@ -77,7 +117,9 @@ jobs: with: allowUpdates: true replacesArtifacts: true - artifacts: libpackager.so + artifacts: | + libpackager.so + libpackager.dylib token: ${{ secrets.GITHUB_TOKEN }} omitBodyDuringUpdate: true omitNameDuringUpdate: true From 3d13ca888cc846df2592a5557b8bb4649072b964 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 14 Mar 2024 10:29:17 +0200 Subject: [PATCH 03/29] update action --- .github/workflows/github-dev-snap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-dev-snap.yaml b/.github/workflows/github-dev-snap.yaml index 79cb47600b4..96903aaa148 100644 --- a/.github/workflows/github-dev-snap.yaml +++ b/.github/workflows/github-dev-snap.yaml @@ -90,7 +90,7 @@ jobs: path: build/packager/libpackager.dylib update_release: - needs: [build_linux] + needs: [build_linux, build_macos_arm64] name: Update release runs-on: ubuntu-latest steps: From fc06fa03adef174f7e60dd29b1ea30b1026a730b Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 14 Mar 2024 12:12:41 +0200 Subject: [PATCH 04/29] Add MacOS Intel --- .github/workflows/github-dev-snap.yaml | 50 ++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/.github/workflows/github-dev-snap.yaml b/.github/workflows/github-dev-snap.yaml index 96903aaa148..8579eaa0a9e 100644 --- a/.github/workflows/github-dev-snap.yaml +++ b/.github/workflows/github-dev-snap.yaml @@ -13,6 +13,7 @@ on: env: ARTIFACT_NAME: "artifact" ARTIFACT_NAME_2: "artifact_arm64" + ARTIFACT_NAME_3: "artifact_macos_intel" jobs: build_linux: @@ -30,13 +31,8 @@ jobs: ref: ${{ inputs.tag }} submodules: recursive - - name: Apply ccache - uses: hendrikmuhs/ccache-action@v1.2 - - name: Generate build files run: | - export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" - mkdir -p build/ cmake \ @@ -89,8 +85,44 @@ jobs: name: ${{ env.ARTIFACT_NAME_2 }} path: build/packager/libpackager.dylib + build_macos_intel: + name: MacOS Intel Build + runs-on: macos-13 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag }} + submodules: recursive + + - name: Generate build files + run: | + mkdir -p build/ + + cmake \ + -DCMAKE_BUILD_TYPE="Release" \ + -DBUILD_SHARED_LIBS=1 \ + -DUSE_WORKAROUND_FOR_TRUN_VERSION_0=1 \ + -S . \ + -B build/ + + - name: Build + run: cmake --build build/ --parallel $(getconf _NPROCESSORS_ONLN) + + # Debug + - name: Display structure of built files + run: | + ls -la build/packager + cp build/packager/libpackager.dylib build/packager/libpackager-intel.dylib + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ env.ARTIFACT_NAME_3 }} + path: build/packager/libpackager-intel.dylib + update_release: - needs: [build_linux, build_macos_arm64] + needs: [build_linux, build_macos_arm64, build_macos_intel] name: Update release runs-on: ubuntu-latest steps: @@ -107,6 +139,11 @@ jobs: with: name: ${{ env.ARTIFACT_NAME_2 }} + - name: Download artifact 3 + uses: actions/download-artifact@v3 + with: + name: ${{ env.ARTIFACT_NAME_3 }} + # Debug - name: Display structure of downloaded files run: ls -la @@ -120,6 +157,7 @@ jobs: artifacts: | libpackager.so libpackager.dylib + libpackager-intel.dylib token: ${{ secrets.GITHUB_TOKEN }} omitBodyDuringUpdate: true omitNameDuringUpdate: true From 45c8d21b473571d5444b90206cf3d4e5d1e1b5c6 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 14 Mar 2024 15:21:28 +0200 Subject: [PATCH 05/29] Use older runner for linux --- .github/workflows/github-dev-snap.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-dev-snap.yaml b/.github/workflows/github-dev-snap.yaml index 8579eaa0a9e..2581e67dd86 100644 --- a/.github/workflows/github-dev-snap.yaml +++ b/.github/workflows/github-dev-snap.yaml @@ -18,7 +18,7 @@ env: jobs: build_linux: name: Build artifact and upload - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - name: Install build tools run: | From c31d4055e4001f1efbf22da5ecadff4c230ed153 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Fri, 15 Mar 2024 15:31:52 +0200 Subject: [PATCH 06/29] Add segment buffer --- include/packager/live_packager.h | 20 ++++- include/packager/live_packager_export.h | 17 +++- packager/live_packager.cc | 105 +++++++++++++----------- 3 files changed, 89 insertions(+), 53 deletions(-) diff --git a/include/packager/live_packager.h b/include/packager/live_packager.h index e17d3f692f8..934edf55a54 100644 --- a/include/packager/live_packager.h +++ b/include/packager/live_packager.h @@ -32,6 +32,20 @@ class SegmentData final : public Segment { const size_t size_ = 0; }; +class SegmentBuffer final : public Segment { +public: + SegmentBuffer() = default; + ~SegmentBuffer() = default; + + void AppendData(const uint8_t* data, size_t size); + + virtual const uint8_t* Data() const override; + virtual size_t Size() const override; + +private: + std::vector buffer_; +}; + class FullSegmentBuffer final : public Segment { public: FullSegmentBuffer() = default; @@ -115,7 +129,7 @@ class LivePackager { /// @param init_segment contains the init segment data. /// @param output contains the packaged init segment data. /// @return OK on success, an appropriate error code on failure. - Status PackageInit(const Segment& init_segment, FullSegmentBuffer& output); + Status PackageInit(const Segment& init_segment, SegmentBuffer& output); /// Performs packaging of segment data. /// @param init_segment contains the init segment data. @@ -124,10 +138,10 @@ class LivePackager { /// @return OK on success, an appropriate error code on failure. Status Package(const Segment& init_segment, const Segment& media_segment, - FullSegmentBuffer& output); + SegmentBuffer& output); Status PackageTimedText(const Segment& media_segment, - FullSegmentBuffer& output); + SegmentBuffer& output); LivePackager(const LivePackager&) = delete; LivePackager& operator=(const LivePackager&) = delete; diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h index 5ce6b53cd95..23ac67d8649 100644 --- a/include/packager/live_packager_export.h +++ b/include/packager/live_packager_export.h @@ -10,6 +10,7 @@ extern "C" { #endif +#include #include typedef enum OutputFormat { @@ -50,14 +51,24 @@ typedef struct LivePackagerConfig { int64_t timed_text_decode_time; } LivePackagerConfig_t; + +typedef struct LivePackager_buffer_s* LivePackagerBuffer_t; + +LivePackagerBuffer_t livepackager_buf_new(); +void livepackager_buf_free(LivePackagerBuffer_t buf); + +const uint8_t* livepackager_buf_data(LivePackagerBuffer_t buf); +size_t livepackager_buf_size(LivePackagerBuffer_t buf); + + typedef struct LivePackager_instance_s* LivePackager_t; LivePackager_t livepackager_new(LivePackagerConfig_t cfg); void livepackager_free(LivePackager_t lp); -size_t livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* dest); -size_t livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* seg, size_t seg_len, uint8_t* dest); -size_t livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, uint8_t* dest); +bool livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, LivePackagerBuffer_t dest); +bool livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* media, size_t media_len, LivePackagerBuffer_t dest); +bool livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest); #ifdef __cplusplus } diff --git a/packager/live_packager.cc b/packager/live_packager.cc index bd6c40fd147..865e8250ec6 100644 --- a/packager/live_packager.cc +++ b/packager/live_packager.cc @@ -181,7 +181,7 @@ class SegmentManager { virtual int64_t OnSegmentWrite(const std::string& name, const void* buffer, uint64_t size, - FullSegmentBuffer& out); + SegmentBuffer& out); virtual Status InitializeEncryption(const LiveConfig& config, EncryptionParams& encryption_params); @@ -202,7 +202,7 @@ class Aes128EncryptedSegmentManager : public SegmentManager { int64_t OnSegmentWrite(const std::string& name, const void* buffer, uint64_t size, - FullSegmentBuffer& out) override; + SegmentBuffer& out) override; Status InitializeEncryption(const LiveConfig& config, EncryptionParams& encryption_params) override; @@ -226,6 +226,18 @@ size_t SegmentData::Size() const { return size_; } +void SegmentBuffer::AppendData(const uint8_t* data, size_t size) { + std::copy(data, data + size, std::back_inserter(buffer_)); +} + +size_t SegmentBuffer::Size() const { + return buffer_.size(); +} + +const uint8_t* SegmentBuffer::Data() const { + return buffer_.data(); +} + void FullSegmentBuffer::SetInitSegment(const uint8_t* data, size_t size) { buffer_.clear(); std::copy(data, data + size, std::back_inserter(buffer_)); @@ -280,7 +292,7 @@ LivePackager::LivePackager(const LiveConfig& config) LivePackager::~LivePackager() = default; Status LivePackager::PackageInit(const Segment& init_segment, - FullSegmentBuffer& output) { + SegmentBuffer& output) { SegmentDataReader reader(init_segment); shaka::BufferCallbackParams callback_params; @@ -289,18 +301,18 @@ Status LivePackager::PackageInit(const Segment& init_segment, return reader.Read(buffer, size); }; - callback_params.write_func = [&output](const std::string& name, + callback_params.write_func = [](const std::string& name, const void* data, uint64_t size) { - output.AppendData(reinterpret_cast(data), size); + // output.AppendData(reinterpret_cast(data), size); return size; }; shaka::BufferCallbackParams init_callback_params; init_callback_params.write_func = [&output](const std::string& name, const void* data, uint64_t size) { - if (output.InitSegmentSize() == 0) { + if (output.Size() == 0) { LOG(INFO) << "init segment callback, name: " << name << " size: " << size; - output.SetInitSegment(reinterpret_cast(data), size); + output.AppendData(reinterpret_cast(data), size); } return size; }; @@ -340,7 +352,7 @@ Status LivePackager::PackageInit(const Segment& init_segment, Status LivePackager::Package(const Segment& init_segment, const Segment& media_segment, - FullSegmentBuffer& out) { + SegmentBuffer& out) { MultiSegmentDataReader reader(init_segment, media_segment); shaka::BufferCallbackParams callback_params; callback_params.read_func = [&reader](const std::string& name, void* buffer, @@ -354,7 +366,7 @@ Status LivePackager::Package(const Segment& init_segment, }; shaka::BufferCallbackParams init_callback_params; - init_callback_params.write_func = [&out](const std::string& name, + init_callback_params.write_func = [](const std::string& name, const void* data, uint64_t size) { // For live packaging it is observed that the init segment callback is // invoked more than once. The initial callback does not contain the MEHD @@ -362,9 +374,9 @@ Status LivePackager::Package(const Segment& init_segment, // If an MP4 file is created in real-time, such as used in live-streaming, // it is not likely that the fragment_duration is known in advance and this // box may be omitted. - if (out.InitSegmentSize() == 0) { - out.SetInitSegment(reinterpret_cast(data), size); - } + //if (out.InitSegmentSize() == 0) { + // out.SetInitSegment(reinterpret_cast(data), size); + //} return size; }; @@ -403,7 +415,7 @@ Status LivePackager::Package(const Segment& init_segment, } Status LivePackager::PackageTimedText(const Segment& in, - FullSegmentBuffer& out) { + SegmentBuffer& out) { SegmentDataReader reader(in); shaka::BufferCallbackParams callback_params; callback_params.read_func = [&reader](const std::string& name, void* buffer, @@ -418,11 +430,11 @@ Status LivePackager::PackageTimedText(const Segment& in, }; shaka::BufferCallbackParams init_callback_params; - init_callback_params.write_func = [&out](const std::string& name, + init_callback_params.write_func = [](const std::string& name, const void* data, uint64_t size) { - if (out.InitSegmentSize() == 0) { - out.SetInitSegment(reinterpret_cast(data), size); - } + //if (out.InitSegmentSize() == 0) { + // out.SetInitSegment(reinterpret_cast(data), size); + //} return size; }; @@ -453,7 +465,7 @@ SegmentManager::SegmentManager() = default; int64_t SegmentManager::OnSegmentWrite(const std::string& name, const void* buffer, uint64_t size, - FullSegmentBuffer& out) { + SegmentBuffer& out) { out.AppendData(reinterpret_cast(buffer), size); return size; } @@ -506,7 +518,7 @@ Aes128EncryptedSegmentManager::~Aes128EncryptedSegmentManager() = default; int64_t Aes128EncryptedSegmentManager::OnSegmentWrite(const std::string& name, const void* buffer, uint64_t size, - FullSegmentBuffer& out) { + SegmentBuffer& out) { // if (!encryptor_->InitializeWithIv(key_, iv_)) { // LOG(WARNING) << "failed to initialize encryptor with key and iv"; // // Negative size will trigger a status error within the packager @@ -671,39 +683,38 @@ void livepackager_free(LivePackager_t lp) { delete lp; } -size_t livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* dest) { - shaka::SegmentData input(init, init_len); - shaka::FullSegmentBuffer output; - shaka::Status status = lp->inner->PackageInit(input, output); - if (!status.ok()) { - return -1; - } +struct LivePackager_buffer_s { + std::unique_ptr inner; +}; - std::memcpy(dest, output.InitSegmentData(), output.InitSegmentSize()); - return output.InitSegmentSize(); +LivePackagerBuffer_t livepackager_buf_new() { + return new LivePackager_buffer_s{std::make_unique()}; } -size_t livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* seg, size_t seg_len, uint8_t* dest) { - shaka::SegmentData input_init(init, init_len); - shaka::SegmentData input_seg(seg, seg_len); - shaka::FullSegmentBuffer output; - shaka::Status status = lp->inner->Package(input_init, input_seg, output); - if (!status.ok()) { - return -1; - } +void livepackager_buf_free(LivePackagerBuffer_t buf) { + delete buf; +} - std::memcpy(dest, output.SegmentData(), output.SegmentSize()); - return output.SegmentSize(); +const uint8_t* livepackager_buf_data(LivePackagerBuffer_t buf) { + return buf->inner->Data(); } -size_t livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, uint8_t* dest) { - shaka::SegmentData input_seg(seg, seg_len); - shaka::FullSegmentBuffer output; - shaka::Status status = lp->inner->PackageTimedText(input_seg, output); - if (!status.ok()) { - return -1; - } +size_t livepackager_buf_size(LivePackagerBuffer_t buf) { + return buf->inner->Size(); +} - std::memcpy(dest, output.SegmentData(), output.SegmentSize()); - return output.SegmentSize(); +bool livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, LivePackagerBuffer_t dest) { + shaka::SegmentData input(init, init_len); + return lp->inner->PackageInit(input, *dest->inner).ok(); +} + +bool livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* media, size_t media_len, LivePackagerBuffer_t dest) { + shaka::SegmentData input_init(init, init_len); + shaka::SegmentData input_media(media, media_len); + return lp->inner->Package(input_init, input_media, *dest->inner).ok(); +} + +bool livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest) { + shaka::SegmentData input_seg(seg, seg_len); + return lp->inner->PackageTimedText(input_seg, *dest->inner).ok(); } From 1be39ac3353c4694b47405c61bf763ae8098fa41 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Mon, 18 Mar 2024 14:29:49 +0200 Subject: [PATCH 07/29] Add variable length IV --- include/packager/live_packager_export.h | 12 ++++++++---- packager/live_packager.cc | 15 ++++++++++----- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h index 23ac67d8649..e1678b9e191 100644 --- a/include/packager/live_packager_export.h +++ b/include/packager/live_packager_export.h @@ -35,15 +35,19 @@ typedef enum EncryptionScheme { ENCRYPTION_SCHEME_CENC, } EncryptionScheme_t; -#define KEY_IV_LEN 16 +enum KeySize { + KEY_SIZE = 16, + KEY_ID_SIZE = 16, +}; typedef struct LivePackagerConfig { OutputFormat_t format; TrackType_t track_type; - uint8_t iv [KEY_IV_LEN]; - uint8_t key [KEY_IV_LEN]; - uint8_t key_id[KEY_IV_LEN]; + size_t iv_size; + uint8_t* iv; + uint8_t key[KEY_SIZE]; + uint8_t key_id[KEY_ID_SIZE]; EncryptionScheme_t protection_scheme; uint32_t segment_number; diff --git a/packager/live_packager.cc b/packager/live_packager.cc index 865e8250ec6..506e4f886f2 100644 --- a/packager/live_packager.cc +++ b/packager/live_packager.cc @@ -666,17 +666,22 @@ struct LivePackager_instance_s { }; LivePackager_t livepackager_new(LivePackagerConfig_t cfg) { - return new LivePackager_instance_s{std::make_unique(shaka::LiveConfig{ + shaka::LiveConfig converted{ .format = shaka::LiveConfig::OutputFormat(cfg.format), .track_type = shaka::LiveConfig::TrackType(cfg.track_type), - .iv=std::vector(cfg.iv, cfg.iv+sizeof(cfg.iv)), - .key=std::vector(cfg.key, cfg.key+sizeof(cfg.key)), - .key_id=std::vector(cfg.key_id, cfg.key_id+sizeof(cfg.key_id)), .protection_scheme=shaka::LiveConfig::EncryptionScheme(cfg.protection_scheme), .segment_number = cfg.segment_number, .m2ts_offset_ms = cfg.m2ts_offset_ms, .timed_text_decode_time = cfg.timed_text_decode_time, - })}; + }; + + if (cfg.protection_scheme != ENCRYPTION_SCHEME_NONE) { + converted.iv=std::vector(cfg.iv, cfg.iv+cfg.iv_size); + converted.key=std::vector(cfg.key, cfg.key+KEY_SIZE); + converted.key_id=std::vector(cfg.key_id, cfg.key_id+KEY_ID_SIZE); + } + + return new LivePackager_instance_s{std::make_unique(converted)}; } void livepackager_free(LivePackager_t lp) { From 701647d9985b83332cc212dd307ec481171f5540 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Mon, 18 Mar 2024 14:44:41 +0200 Subject: [PATCH 08/29] Initialize key vectors --- packager/live_packager.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packager/live_packager.cc b/packager/live_packager.cc index 506e4f886f2..ecd54c79f2e 100644 --- a/packager/live_packager.cc +++ b/packager/live_packager.cc @@ -669,6 +669,9 @@ LivePackager_t livepackager_new(LivePackagerConfig_t cfg) { shaka::LiveConfig converted{ .format = shaka::LiveConfig::OutputFormat(cfg.format), .track_type = shaka::LiveConfig::TrackType(cfg.track_type), + .iv={}, + .key={}, + .key_id={}, .protection_scheme=shaka::LiveConfig::EncryptionScheme(cfg.protection_scheme), .segment_number = cfg.segment_number, .m2ts_offset_ms = cfg.m2ts_offset_ms, From f8eda81312c3d26ca348ddc169be5cd337712126 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 20 Mar 2024 14:02:59 +0200 Subject: [PATCH 09/29] Update actions --- .github/workflows/build-attach-artifacts.yaml | 152 ++++++++++++++++ .github/workflows/build-matrix.json | 32 ++-- .github/workflows/github-dev-snap.yaml | 165 ------------------ 3 files changed, 163 insertions(+), 186 deletions(-) create mode 100644 .github/workflows/build-attach-artifacts.yaml delete mode 100644 .github/workflows/github-dev-snap.yaml diff --git a/.github/workflows/build-attach-artifacts.yaml b/.github/workflows/build-attach-artifacts.yaml new file mode 100644 index 00000000000..6ce4a0caf1d --- /dev/null +++ b/.github/workflows/build-attach-artifacts.yaml @@ -0,0 +1,152 @@ +# Copyright 2023 Pluto TV + +name: Build and attach release artifacts + +on: + workflow_dispatch: + inputs: + tag: + description: 'Tag of the release' + required: true + type: string + +# By default, run all commands in a bash shell. On Windows, the default would +# otherwise be powershell. +defaults: + run: + shell: bash + +env: + ARTIFACT_NAME: "artifact" + ARTIFACT_NAME_2: "artifact_arm64" + ARTIFACT_NAME_3: "artifact_macos_intel" + +jobs: + build_matrix_config: + name: Matrix configuration + runs-on: ubuntu-latest + outputs: + INCLUDE: ${{ steps.configure.outputs.INCLUDE }} + OS: ${{ steps.configure.outputs.OS }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + + - name: Configure Build Matrix + id: configure + shell: node {0} + run: | + const enableSelfHosted = ${{ inputs.self_hosted }}; + + // Use enableSelfHosted to decide what the build matrix below should + // include. + const {hosted, selfHosted} = require("${{ github.workspace }}/.github/workflows/build-matrix.json"); + const include = enableSelfHosted ? hosted.concat(selfHosted) : hosted; + const os = include.map((config) => config.os); + + // Output JSON objects consumed by the build matrix below. + const fs = require('fs'); + fs.writeFileSync(process.env.GITHUB_OUTPUT, + [ + `INCLUDE=${ JSON.stringify(include) }`, + `OS=${ JSON.stringify(os) }`, + ].join('\n'), + {flag: 'a'}); + + // Log the outputs, for the sake of debugging this script. + console.log({enableSelfHosted, include, os}); + + build: + needs: build_matrix_config + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(needs.build_matrix_config.outputs.INCLUDE) }} + os: ${{ fromJSON(needs.build_matrix_config.outputs.OS) }} + build_type: ["Debug", "Release"] + lib_type: ["static", "shared"] + + name: ${{ matrix.os_name }} ${{ matrix.target_arch }} ${{ matrix.build_type }} ${{ matrix.lib_type }} + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag }} + submodules: recursive + + - name: Generate build files + run: | + mkdir -p build/ + + cmake \ + -DCMAKE_BUILD_TYPE="Release" \ + -DBUILD_SHARED_LIBS=1 \ + -DUSE_WORKAROUND_FOR_TRUN_VERSION_0=1 \ + -S . \ + -B build/ + + - name: Build + run: cmake --build build/ --parallel $(getconf _NPROCESSORS_ONLN) + + - name: Prepare artifacts + run: | + echo "::group::Prepare artifacts folder" + mkdir artifacts + ARTIFACTS="$GITHUB_WORKSPACE/artifacts" + if [[ "${{ runner.os }}" == "Windows" ]]; then + cd build/packager/Release + else + cd build/packager + fi + echo "::endgroup::" + + SUFFIX="-${{ matrix.os_name }}-${{ matrix.target_arch }}" + EXE_SUFFIX="$SUFFIX${{ matrix.exe_ext}}" + + echo "::group::Copy libpackager" + cp libpackager${{ matrix.exe_ext }} $ARTIFACTS/libpackager$EXE_SUFFIX + echo "::endgroup::" + + - name: Upload release build artifacts + uses: actions/upload-artifact@v4 + with: + name: artifacts-${{ matrix.os_name }}-${{ matrix.target_arch }} + path: artifacts/* + if-no-files-found: error + retention-days: 5 + + update_release: + needs: [build] + name: Update release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true + + # Debug + - name: Display structure of downloaded files + run: ls -la + + - name: Attach artifact + id: attach_artifact + uses: ncipollo/release-action@v1.13.0 + with: + allowUpdates: true + replacesArtifacts: true + artifacts: | + artifacts/* + include/packager/live_packager_export.h + token: ${{ secrets.GITHUB_TOKEN }} + omitBodyDuringUpdate: true + omitNameDuringUpdate: true + tag: ${{ inputs.tag }} + draft: false diff --git a/.github/workflows/build-matrix.json b/.github/workflows/build-matrix.json index 71c87f18339..a5d08e0217d 100644 --- a/.github/workflows/build-matrix.json +++ b/.github/workflows/build-matrix.json @@ -2,37 +2,27 @@ "comment1": "runners hosted by GitHub, always enabled", "hosted": [ { - "os": "ubuntu-latest", + "os": "ubuntu-20.04", "os_name": "linux", "target_arch": "x64", - "exe_ext": "", + "exe_ext": ".so", "generator": "Ninja" }, { - "os": "macos-latest", + "comment": "Explicit macOS version 13 is required for explicit x64 CPU.", + "os": "macos-13", "os_name": "osx", "target_arch": "x64", - "exe_ext": "", + "exe_ext": ".dylib", "generator": "Ninja" }, { - "os": "windows-latest", - "os_name": "win", - "target_arch": "x64", - "exe_ext": ".exe", - "generator": "" - } - ], - - "comment2": "runners hosted by the owner, enabled by the 'self_hosted' environment being created on the repo", - "selfHosted": [ - { - "os": "self-hosted-linux-arm64", - "os_name": "linux", + "comment": "Explicit macOS version 14 is required for explicit arm64 CPU.", + "os": "macos-14", + "os_name": "osx", "target_arch": "arm64", - "exe_ext": "", - "generator": "Ninja", - "low_mem": "yes" + "exe_ext": ".dylib", + "generator": "Ninja" } ] -} +} \ No newline at end of file diff --git a/.github/workflows/github-dev-snap.yaml b/.github/workflows/github-dev-snap.yaml deleted file mode 100644 index 2581e67dd86..00000000000 --- a/.github/workflows/github-dev-snap.yaml +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright 2023 Pluto TV - -name: Attach release artifacts - -on: - workflow_dispatch: - inputs: - tag: - description: 'Tag of the release' - required: true - type: string - -env: - ARTIFACT_NAME: "artifact" - ARTIFACT_NAME_2: "artifact_arm64" - ARTIFACT_NAME_3: "artifact_macos_intel" - -jobs: - build_linux: - name: Build artifact and upload - runs-on: ubuntu-20.04 - steps: - - name: Install build tools - run: | - sudo apt update && sudo apt install -y \ - cmake - - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.tag }} - submodules: recursive - - - name: Generate build files - run: | - mkdir -p build/ - - cmake \ - -DCMAKE_BUILD_TYPE="Release" \ - -DBUILD_SHARED_LIBS=1 \ - -DUSE_WORKAROUND_FOR_TRUN_VERSION_0=1 \ - -S . \ - -B build/ - - - name: Build - run: cmake --build build/ --parallel $(getconf _NPROCESSORS_ONLN) - - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: ${{ env.ARTIFACT_NAME }} - path: build/packager/libpackager.so - - build_macos_arm64: - name: MacOS M1 build - runs-on: macos-14 - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.tag }} - submodules: recursive - - - name: Generate build files - run: | - mkdir -p build/ - - cmake \ - -DCMAKE_BUILD_TYPE="Release" \ - -DBUILD_SHARED_LIBS=1 \ - -DUSE_WORKAROUND_FOR_TRUN_VERSION_0=1 \ - -S . \ - -B build/ - - - name: Build - run: cmake --build build/ --parallel $(getconf _NPROCESSORS_ONLN) - - # Debug - - name: Display structure of built files - run: ls -la build/packager - - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: ${{ env.ARTIFACT_NAME_2 }} - path: build/packager/libpackager.dylib - - build_macos_intel: - name: MacOS Intel Build - runs-on: macos-13 - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.tag }} - submodules: recursive - - - name: Generate build files - run: | - mkdir -p build/ - - cmake \ - -DCMAKE_BUILD_TYPE="Release" \ - -DBUILD_SHARED_LIBS=1 \ - -DUSE_WORKAROUND_FOR_TRUN_VERSION_0=1 \ - -S . \ - -B build/ - - - name: Build - run: cmake --build build/ --parallel $(getconf _NPROCESSORS_ONLN) - - # Debug - - name: Display structure of built files - run: | - ls -la build/packager - cp build/packager/libpackager.dylib build/packager/libpackager-intel.dylib - - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: ${{ env.ARTIFACT_NAME_3 }} - path: build/packager/libpackager-intel.dylib - - update_release: - needs: [build_linux, build_macos_arm64, build_macos_intel] - name: Update release - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Download artifact - uses: actions/download-artifact@v3 - with: - name: ${{ env.ARTIFACT_NAME }} - - - name: Download artifact 2 - uses: actions/download-artifact@v3 - with: - name: ${{ env.ARTIFACT_NAME_2 }} - - - name: Download artifact 3 - uses: actions/download-artifact@v3 - with: - name: ${{ env.ARTIFACT_NAME_3 }} - - # Debug - - name: Display structure of downloaded files - run: ls -la - - - name: Attach artifact - id: attach_artifact - uses: ncipollo/release-action@v1.13.0 - with: - allowUpdates: true - replacesArtifacts: true - artifacts: | - libpackager.so - libpackager.dylib - libpackager-intel.dylib - token: ${{ secrets.GITHUB_TOKEN }} - omitBodyDuringUpdate: true - omitNameDuringUpdate: true - tag: ${{ inputs.tag }} - draft: false From 935a3f02212f55e1cbe3ec481e46b5b5b89cbbad Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 20 Mar 2024 14:06:40 +0200 Subject: [PATCH 10/29] Update actions --- .github/workflows/build-attach-artifacts.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-attach-artifacts.yaml b/.github/workflows/build-attach-artifacts.yaml index 6ce4a0caf1d..f33d7594227 100644 --- a/.github/workflows/build-attach-artifacts.yaml +++ b/.github/workflows/build-attach-artifacts.yaml @@ -9,6 +9,9 @@ on: description: 'Tag of the release' required: true type: string + push: + branches: + - feature/c # By default, run all commands in a bash shell. On Windows, the default would # otherwise be powershell. @@ -16,11 +19,6 @@ defaults: run: shell: bash -env: - ARTIFACT_NAME: "artifact" - ARTIFACT_NAME_2: "artifact_arm64" - ARTIFACT_NAME_3: "artifact_macos_intel" - jobs: build_matrix_config: name: Matrix configuration @@ -148,5 +146,5 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} omitBodyDuringUpdate: true omitNameDuringUpdate: true - tag: ${{ inputs.tag }} + tag: dev-arm64-buf draft: false From c38591b811e8959fea055fc251ad2df51e0b953b Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 20 Mar 2024 15:05:04 +0200 Subject: [PATCH 11/29] Update actions --- .github/workflows/build-attach-artifacts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-attach-artifacts.yaml b/.github/workflows/build-attach-artifacts.yaml index f33d7594227..09188ff3831 100644 --- a/.github/workflows/build-attach-artifacts.yaml +++ b/.github/workflows/build-attach-artifacts.yaml @@ -35,7 +35,7 @@ jobs: id: configure shell: node {0} run: | - const enableSelfHosted = ${{ inputs.self_hosted }}; + const enableSelfHosted = false; // Use enableSelfHosted to decide what the build matrix below should // include. From d8363488b68561f610f4b23c13f1ac17d4e6f711 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 20 Mar 2024 15:57:30 +0200 Subject: [PATCH 12/29] Update actions --- .github/workflows/build-attach-artifacts.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-attach-artifacts.yaml b/.github/workflows/build-attach-artifacts.yaml index 09188ff3831..9c4bb860b9e 100644 --- a/.github/workflows/build-attach-artifacts.yaml +++ b/.github/workflows/build-attach-artifacts.yaml @@ -62,8 +62,8 @@ jobs: matrix: include: ${{ fromJSON(needs.build_matrix_config.outputs.INCLUDE) }} os: ${{ fromJSON(needs.build_matrix_config.outputs.OS) }} - build_type: ["Debug", "Release"] - lib_type: ["static", "shared"] + build_type: ["Release"] + lib_type: ["shared"] name: ${{ matrix.os_name }} ${{ matrix.target_arch }} ${{ matrix.build_type }} ${{ matrix.lib_type }} runs-on: ${{ matrix.os }} From dd40ae8197fb4a7f02b93f4cc5e66eda87b7f1f5 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 21 Mar 2024 12:03:17 +0200 Subject: [PATCH 13/29] Update actions --- .github/workflows/build-attach-artifacts.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build-attach-artifacts.yaml b/.github/workflows/build-attach-artifacts.yaml index 9c4bb860b9e..9b5c2907d93 100644 --- a/.github/workflows/build-attach-artifacts.yaml +++ b/.github/workflows/build-attach-artifacts.yaml @@ -9,9 +9,6 @@ on: description: 'Tag of the release' required: true type: string - push: - branches: - - feature/c # By default, run all commands in a bash shell. On Windows, the default would # otherwise be powershell. @@ -146,5 +143,5 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} omitBodyDuringUpdate: true omitNameDuringUpdate: true - tag: dev-arm64-buf + tag: ${{ inputs.tag }} draft: false From 2907b0820b5e5249fda6f03440939310155f07b1 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 21 Mar 2024 12:08:48 +0200 Subject: [PATCH 14/29] Update actions --- .github/workflows/build-attach-artifacts.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-attach-artifacts.yaml b/.github/workflows/build-attach-artifacts.yaml index 9b5c2907d93..a7c3f2b0e04 100644 --- a/.github/workflows/build-attach-artifacts.yaml +++ b/.github/workflows/build-attach-artifacts.yaml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ inputs.ref }} + ref: ${{ inputs.tag }} - name: Configure Build Matrix id: configure @@ -120,6 +120,9 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag }} + submodules: recursive - name: Download artifacts uses: actions/download-artifact@v4 From 9ec8745133b38612d0518109cc181fd3c4e3a1db Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Tue, 26 Mar 2024 16:06:00 +0200 Subject: [PATCH 15/29] Update header --- .github/workflows/build-attach-artifacts.yaml | 6 +++++- include/packager/live_packager_export.h | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-attach-artifacts.yaml b/.github/workflows/build-attach-artifacts.yaml index a7c3f2b0e04..9dfddb00825 100644 --- a/.github/workflows/build-attach-artifacts.yaml +++ b/.github/workflows/build-attach-artifacts.yaml @@ -9,6 +9,10 @@ on: description: 'Tag of the release' required: true type: string + push: + branches: + - feature/c + # By default, run all commands in a bash shell. On Windows, the default would # otherwise be powershell. @@ -146,5 +150,5 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} omitBodyDuringUpdate: true omitNameDuringUpdate: true - tag: ${{ inputs.tag }} + tag: dev-arm64-test draft: false diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h index e1678b9e191..950593416d6 100644 --- a/include/packager/live_packager_export.h +++ b/include/packager/live_packager_export.h @@ -36,6 +36,7 @@ typedef enum EncryptionScheme { } EncryptionScheme_t; enum KeySize { + IV_MAX_SIZE = 16, KEY_SIZE = 16, KEY_ID_SIZE = 16, }; @@ -45,13 +46,25 @@ typedef struct LivePackagerConfig { TrackType_t track_type; size_t iv_size; - uint8_t* iv; + uint8_t iv[IV_MAX_SIZE]; uint8_t key[KEY_SIZE]; uint8_t key_id[KEY_ID_SIZE]; EncryptionScheme_t protection_scheme; + /// User-specified segment number. + /// For FMP4 output: + /// It can be used to set the moof header sequence number if > 0. + /// For M2TS output: + /// It is be used to set the continuity counter. uint32_t segment_number; + + /// The offset to be applied to transport stream (e.g. MPEG2-TS, HLS packed + /// audio) timestamps to compensate for possible negative timestamps in the + /// input. int32_t m2ts_offset_ms; + + /// Used for timed text packaging to set the fragment decode time when the + /// output format is either VTT in MP4 or TTML in MP4. int64_t timed_text_decode_time; } LivePackagerConfig_t; From f0296736d1db00d254bac62a7510b5363cd3a5a2 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Tue, 26 Mar 2024 16:15:07 +0200 Subject: [PATCH 16/29] Separate implementation --- packager/CMakeLists.txt | 1 + packager/live_packager.cc | 66 ------------------------------- packager/live_packager_export.cc | 68 ++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 66 deletions(-) create mode 100644 packager/live_packager_export.cc diff --git a/packager/CMakeLists.txt b/packager/CMakeLists.txt index 50e63d6fca8..926909ef0f9 100644 --- a/packager/CMakeLists.txt +++ b/packager/CMakeLists.txt @@ -92,6 +92,7 @@ set(libpackager_sources app/single_thread_job_manager.h packager.cc live_packager.cc + live_packager_export.cc ../include/packager/packager.h ../include/packager/live_packager.h ../include/packager/live_packager_export.h diff --git a/packager/live_packager.cc b/packager/live_packager.cc index ecd54c79f2e..d96d01dd0f2 100644 --- a/packager/live_packager.cc +++ b/packager/live_packager.cc @@ -660,69 +660,3 @@ Status GeneratePSSHData(const PSSHGeneratorInput& in, PSSHData* out) { return Status::OK; } } // namespace shaka - -struct LivePackager_instance_s { - std::unique_ptr inner; -}; - -LivePackager_t livepackager_new(LivePackagerConfig_t cfg) { - shaka::LiveConfig converted{ - .format = shaka::LiveConfig::OutputFormat(cfg.format), - .track_type = shaka::LiveConfig::TrackType(cfg.track_type), - .iv={}, - .key={}, - .key_id={}, - .protection_scheme=shaka::LiveConfig::EncryptionScheme(cfg.protection_scheme), - .segment_number = cfg.segment_number, - .m2ts_offset_ms = cfg.m2ts_offset_ms, - .timed_text_decode_time = cfg.timed_text_decode_time, - }; - - if (cfg.protection_scheme != ENCRYPTION_SCHEME_NONE) { - converted.iv=std::vector(cfg.iv, cfg.iv+cfg.iv_size); - converted.key=std::vector(cfg.key, cfg.key+KEY_SIZE); - converted.key_id=std::vector(cfg.key_id, cfg.key_id+KEY_ID_SIZE); - } - - return new LivePackager_instance_s{std::make_unique(converted)}; -} - -void livepackager_free(LivePackager_t lp) { - delete lp; -} - -struct LivePackager_buffer_s { - std::unique_ptr inner; -}; - -LivePackagerBuffer_t livepackager_buf_new() { - return new LivePackager_buffer_s{std::make_unique()}; -} - -void livepackager_buf_free(LivePackagerBuffer_t buf) { - delete buf; -} - -const uint8_t* livepackager_buf_data(LivePackagerBuffer_t buf) { - return buf->inner->Data(); -} - -size_t livepackager_buf_size(LivePackagerBuffer_t buf) { - return buf->inner->Size(); -} - -bool livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, LivePackagerBuffer_t dest) { - shaka::SegmentData input(init, init_len); - return lp->inner->PackageInit(input, *dest->inner).ok(); -} - -bool livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* media, size_t media_len, LivePackagerBuffer_t dest) { - shaka::SegmentData input_init(init, init_len); - shaka::SegmentData input_media(media, media_len); - return lp->inner->Package(input_init, input_media, *dest->inner).ok(); -} - -bool livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest) { - shaka::SegmentData input_seg(seg, seg_len); - return lp->inner->PackageTimedText(input_seg, *dest->inner).ok(); -} diff --git a/packager/live_packager_export.cc b/packager/live_packager_export.cc new file mode 100644 index 00000000000..4de45d68bd4 --- /dev/null +++ b/packager/live_packager_export.cc @@ -0,0 +1,68 @@ +#include +#include + +struct LivePackager_instance_s { + std::unique_ptr inner; +}; + +LivePackager_t livepackager_new(LivePackagerConfig_t cfg) { + shaka::LiveConfig converted{ + .format = shaka::LiveConfig::OutputFormat(cfg.format), + .track_type = shaka::LiveConfig::TrackType(cfg.track_type), + .iv={}, + .key={}, + .key_id={}, + .protection_scheme=shaka::LiveConfig::EncryptionScheme(cfg.protection_scheme), + .segment_number = cfg.segment_number, + .m2ts_offset_ms = cfg.m2ts_offset_ms, + .timed_text_decode_time = cfg.timed_text_decode_time, + }; + + if (cfg.protection_scheme != ENCRYPTION_SCHEME_NONE) { + converted.iv=std::vector(cfg.iv, cfg.iv+cfg.iv_size); + converted.key=std::vector(cfg.key, cfg.key+KEY_SIZE); + converted.key_id=std::vector(cfg.key_id, cfg.key_id+KEY_ID_SIZE); + } + + return new LivePackager_instance_s{std::make_unique(converted)}; +} + +void livepackager_free(LivePackager_t lp) { + delete lp; +} + +struct LivePackager_buffer_s { + std::unique_ptr inner; +}; + +LivePackagerBuffer_t livepackager_buf_new() { + return new LivePackager_buffer_s{std::make_unique()}; +} + +void livepackager_buf_free(LivePackagerBuffer_t buf) { + delete buf; +} + +const uint8_t* livepackager_buf_data(LivePackagerBuffer_t buf) { + return buf->inner->Data(); +} + +size_t livepackager_buf_size(LivePackagerBuffer_t buf) { + return buf->inner->Size(); +} + +bool livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, LivePackagerBuffer_t dest) { + shaka::SegmentData input(init, init_len); + return lp->inner->PackageInit(input, *dest->inner).ok(); +} + +bool livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* media, size_t media_len, LivePackagerBuffer_t dest) { + shaka::SegmentData input_init(init, init_len); + shaka::SegmentData input_media(media, media_len); + return lp->inner->Package(input_init, input_media, *dest->inner).ok(); +} + +bool livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest) { + shaka::SegmentData input_seg(seg, seg_len); + return lp->inner->PackageTimedText(input_seg, *dest->inner).ok(); +} \ No newline at end of file From 2da278c526bf12336f353469d9f150d6b34434c9 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 14:24:00 +0200 Subject: [PATCH 17/29] Fix tests --- packager/live_packager_test.cc | 73 ++++++++++++++++------------------ 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/packager/live_packager_test.cc b/packager/live_packager_test.cc index 54f91a53968..78b4adf8721 100644 --- a/packager/live_packager_test.cc +++ b/packager/live_packager_test.cc @@ -251,11 +251,11 @@ class MP4MediaParserTest { std::vector> samples_; }; -void CheckVideoInitSegment(const FullSegmentBuffer& buffer, +void CheckVideoInitSegment(const SegmentBuffer& buffer, media::FourCC format) { bool err(true); - size_t bytes_to_read(buffer.InitSegmentSize()); - const uint8_t* data(buffer.InitSegmentData()); + size_t bytes_to_read(buffer.Size()); + const uint8_t* data(buffer.Data()); { std::unique_ptr reader( @@ -293,12 +293,12 @@ void CheckVideoInitSegment(const FullSegmentBuffer& buffer, } void CheckSegment(const LiveConfig& config, - const FullSegmentBuffer& buffer, + const SegmentBuffer& buffer, const uint32_t expected_timescale, const bool check_decode_time) { bool err(true); - size_t bytes_to_read(buffer.SegmentSize()); - const uint8_t* data(buffer.SegmentData()); + size_t bytes_to_read(buffer.Size()); + const uint8_t* data(buffer.Data()); { std::unique_ptr reader( @@ -547,7 +547,7 @@ TEST_F(LivePackagerBaseTest, InitSegmentOnly) { FullSegmentBuffer in; in.SetInitSegment(init_segment_buffer.data(), init_segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.format = LiveConfig::OutputFormat::FMP4; @@ -555,8 +555,7 @@ TEST_F(LivePackagerBaseTest, InitSegmentOnly) { SetupLivePackagerConfig(live_config); ASSERT_EQ(Status::OK, live_packager_->PackageInit(in, out)); - ASSERT_GT(out.InitSegmentSize(), 0); - ASSERT_EQ(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); CheckVideoInitSegment(out, media::FourCC::FOURCC_avc1); } @@ -568,7 +567,7 @@ TEST_F(LivePackagerBaseTest, InitSegmentOnlyWithCBCS) { FullSegmentBuffer in; in.SetInitSegment(init_segment_buffer.data(), init_segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.format = LiveConfig::OutputFormat::FMP4; @@ -577,8 +576,7 @@ TEST_F(LivePackagerBaseTest, InitSegmentOnlyWithCBCS) { SetupLivePackagerConfig(live_config); ASSERT_EQ(Status::OK, live_packager_->PackageInit(in, out)); - ASSERT_GT(out.InitSegmentSize(), 0); - ASSERT_EQ(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); CheckVideoInitSegment(out, media::FourCC::FOURCC_encv); } @@ -590,7 +588,7 @@ TEST_F(LivePackagerBaseTest, InitSegmentOnlyWithCENC) { FullSegmentBuffer in; in.SetInitSegment(init_segment_buffer.data(), init_segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.format = LiveConfig::OutputFormat::FMP4; @@ -599,8 +597,7 @@ TEST_F(LivePackagerBaseTest, InitSegmentOnlyWithCENC) { SetupLivePackagerConfig(live_config); ASSERT_EQ(Status::OK, live_packager_->PackageInit(in, out)); - ASSERT_GT(out.InitSegmentSize(), 0); - ASSERT_EQ(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); CheckVideoInitSegment(out, media::FourCC::FOURCC_encv); } @@ -623,7 +620,7 @@ TEST_F(LivePackagerBaseTest, VerifyAes128WithDecryption) { init_segment_buffer.size()); SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.format = LiveConfig::OutputFormat::TS; @@ -633,7 +630,7 @@ TEST_F(LivePackagerBaseTest, VerifyAes128WithDecryption) { SetupLivePackagerConfig(live_config); ASSERT_EQ(Status::OK, live_packager_->Package(init_seg, media_seg, out)); - ASSERT_GT(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); std::string exp_segment_num = absl::StrFormat("expected/stuffing_ts/%04d.ts", i + 1); @@ -641,8 +638,8 @@ TEST_F(LivePackagerBaseTest, VerifyAes128WithDecryption) { ASSERT_FALSE(exp_segment_buffer.empty()); std::vector decrypted; - std::vector buffer(out.SegmentData(), - out.SegmentData() + out.SegmentSize()); + std::vector buffer(out.Data(), + out.Data() + out.Size()); ASSERT_TRUE(decryptor.Crypt(buffer, &decrypted)); ASSERT_EQ(decrypted, exp_segment_buffer); @@ -666,7 +663,7 @@ TEST_F(LivePackagerBaseTest, EncryptionFailure) { init_segment_buffer.size()); SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.format = LiveConfig::OutputFormat::TS; @@ -696,7 +693,7 @@ TEST_F(LivePackagerBaseTest, CheckContinutityCounter) { init_segment_buffer.size()); SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.format = LiveConfig::OutputFormat::TS; @@ -706,9 +703,9 @@ TEST_F(LivePackagerBaseTest, CheckContinutityCounter) { SetupLivePackagerConfig(live_config); ASSERT_EQ(Status::OK, live_packager_->Package(init_seg, media_seg, out)); - ASSERT_GT(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); - ts_byte_queue.Push(out.SegmentData(), static_cast(out.SegmentSize())); + ts_byte_queue.Push(out.Data(), static_cast(out.Size())); while (true) { const uint8_t* ts_buffer; int ts_buffer_size; @@ -764,7 +761,7 @@ TEST_F(LivePackagerMp2tTest, Mp2TSNegativeCTS) { init_segment_buffer.size()); SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.format = LiveConfig::OutputFormat::TS; @@ -774,8 +771,8 @@ TEST_F(LivePackagerMp2tTest, Mp2TSNegativeCTS) { SetupLivePackagerConfig(live_config); ASSERT_EQ(Status::OK, live_packager_->Package(init_seg, media_seg, out)); - ASSERT_GT(out.SegmentSize(), 0); - actual_buf.AppendData(out.SegmentData(), out.SegmentSize()); + ASSERT_GT(out.Size(), 0); + actual_buf.AppendData(out.Data(), out.Size()); } ASSERT_TRUE( @@ -801,11 +798,11 @@ TEST_F(LivePackagerBaseTest, CustomMoofSequenceNumber) { init_segment_buffer.size()); SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LivePackager packager(live_config); ASSERT_EQ(Status::OK, packager.Package(init_seg, media_seg, out)); - ASSERT_GT(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); CheckSegment(live_config, out, 10000000, false); } @@ -874,7 +871,7 @@ TEST_P(LivePackagerEncryptionTest, VerifyWithEncryption) { SegmentData init_seg(init_segment_buffer.data(), init_segment_buffer.size()); - FullSegmentBuffer actual_buf; + SegmentBuffer actual_buf; live_packager_->PackageInit(init_seg, actual_buf); for (unsigned int i = 0; i < GetParam().num_segments; i++) { @@ -888,12 +885,12 @@ TEST_P(LivePackagerEncryptionTest, VerifyWithEncryption) { std::vector segment_buffer = ReadTestDataFile(format_output); ASSERT_FALSE(segment_buffer.empty()); - FullSegmentBuffer out; + SegmentBuffer out; SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); ASSERT_EQ(Status::OK, live_packager_->Package(init_seg, media_seg, out)); - ASSERT_GT(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); - actual_buf.AppendData(out.SegmentData(), out.SegmentSize()); + actual_buf.AppendData(out.Data(), out.Size()); } if (GetParam().compare_samples) { @@ -959,7 +956,7 @@ TEST_F(LivePackagerBaseTest, TestPackageTimedTextHybrikComp) { SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.format = LiveConfig::OutputFormat::VTTMP4; @@ -970,7 +967,7 @@ TEST_F(LivePackagerBaseTest, TestPackageTimedTextHybrikComp) { SetupLivePackagerConfig(live_config); ASSERT_EQ(Status::OK, live_packager_->PackageTimedText(media_seg, out)); - ASSERT_GT(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); CheckSegment(live_config, out, 1000, true); @@ -978,8 +975,8 @@ TEST_F(LivePackagerBaseTest, TestPackageTimedTextHybrikComp) { absl::StrFormat("timed_text/expected/%05d.m4s", i + 1)); ASSERT_FALSE(exp_seg_buf.empty()); - std::vector buffer(out.SegmentData(), - out.SegmentData() + out.SegmentSize()); + std::vector buffer(out.Data(), + out.Data() + out.Size()); ASSERT_EQ(exp_seg_buf, buffer); } } @@ -1009,7 +1006,7 @@ TEST_P(TimedTextParameterizedTest, VerifyTimedText) { ASSERT_FALSE(segment_buffer.empty()); SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); - FullSegmentBuffer out; + SegmentBuffer out; LiveConfig live_config; live_config.protection_scheme = LiveConfig::EncryptionScheme::NONE; @@ -1026,7 +1023,7 @@ TEST_P(TimedTextParameterizedTest, VerifyTimedText) { ASSERT_EQ(GetParam().expected_status, live_packager_->PackageTimedText(media_seg, out)); if (GetParam().expected_status == Status::OK) { - ASSERT_GT(out.SegmentSize(), 0); + ASSERT_GT(out.Size(), 0); if (live_config.format == LiveConfig::OutputFormat::VTTMP4 || live_config.format == LiveConfig::OutputFormat::TTMLMP4) { CheckSegment(live_config, out, 1000, true); From f333da9f86e8905d468961e74e25635b036b4ba5 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 14:54:53 +0200 Subject: [PATCH 18/29] Fix tests --- packager/live_packager_test.cc | 79 +++++++++++++++++----------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/packager/live_packager_test.cc b/packager/live_packager_test.cc index fc901e3be24..592cce09de6 100644 --- a/packager/live_packager_test.cc +++ b/packager/live_packager_test.cc @@ -314,45 +314,46 @@ void CheckVideoInitSegment(const SegmentBuffer& buffer, } } -void CheckTextInitSegment(const FullSegmentBuffer& buffer, - media::FourCC handler, - media::FourCC format) { - bool err(true); - size_t bytes_to_read(buffer.InitSegmentSize()); - const uint8_t* data(buffer.InitSegmentData()); - - { - std::unique_ptr reader( - media::mp4::BoxReader::ReadBox(data, bytes_to_read, &err)); - EXPECT_FALSE(err); - - FileTypeBoxChecker checker; - checker.Check(reader.get()); - - data += reader->size(); - bytes_to_read -= reader->size(); - } - - { - std::unique_ptr reader( - media::mp4::BoxReader::ReadBox(data, bytes_to_read, &err)); - EXPECT_FALSE(err); - - media::mp4::TextSampleEntry entry; - entry.format = format; - - media::mp4::Track track; - track.media.handler.handler_type = handler; - track.media.information.sample_table.description.text_entries.push_back( - entry); - - media::mp4::Movie expected; - expected.tracks.push_back(track); - - MovieBoxChecker checker(expected); - checker.Check(reader.get()); - } -} +// TODO(sasha): must be used when PackageTimedTextInit is added. +// void CheckTextInitSegment(const FullSegmentBuffer& buffer, +// media::FourCC handler, +// media::FourCC format) { +// bool err(true); +// size_t bytes_to_read(buffer.InitSegmentSize()); +// const uint8_t* data(buffer.InitSegmentData()); +// +// { +// std::unique_ptr reader( +// media::mp4::BoxReader::ReadBox(data, bytes_to_read, &err)); +// EXPECT_FALSE(err); +// +// FileTypeBoxChecker checker; +// checker.Check(reader.get()); +// +// data += reader->size(); +// bytes_to_read -= reader->size(); +// } +// +// { +// std::unique_ptr reader( +// media::mp4::BoxReader::ReadBox(data, bytes_to_read, &err)); +// EXPECT_FALSE(err); +// +// media::mp4::TextSampleEntry entry; +// entry.format = format; +// +// media::mp4::Track track; +// track.media.handler.handler_type = handler; +// track.media.information.sample_table.description.text_entries.push_back( +// entry); +// +// media::mp4::Movie expected; +// expected.tracks.push_back(track); +// +// MovieBoxChecker checker(expected); +// checker.Check(reader.get()); +// } +// } void CheckSegment(const LiveConfig& config, const SegmentBuffer& buffer, From 0bc0a653b57873d6090f1a72a61d3b93a8b70c0f Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 15:10:22 +0200 Subject: [PATCH 19/29] Remove enum for constants --- include/packager/live_packager_export.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h index 950593416d6..a4deb59577c 100644 --- a/include/packager/live_packager_export.h +++ b/include/packager/live_packager_export.h @@ -35,20 +35,18 @@ typedef enum EncryptionScheme { ENCRYPTION_SCHEME_CENC, } EncryptionScheme_t; -enum KeySize { - IV_MAX_SIZE = 16, - KEY_SIZE = 16, - KEY_ID_SIZE = 16, -}; +static const size_t kIvMaxSize = 16; +static const size_t kKeySize = 16; +static const size_t kKeyIdSize = 16; typedef struct LivePackagerConfig { OutputFormat_t format; TrackType_t track_type; size_t iv_size; - uint8_t iv[IV_MAX_SIZE]; - uint8_t key[KEY_SIZE]; - uint8_t key_id[KEY_ID_SIZE]; + uint8_t iv[kIvMaxSize]; + uint8_t key[kKeySize]; + uint8_t key_id[kKeyIdSize]; EncryptionScheme_t protection_scheme; /// User-specified segment number. From 80d7c56f4099ea6420af4770ab308b111fc07bb6 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 15:14:16 +0200 Subject: [PATCH 20/29] Appease linter --- include/packager/live_packager_export.h | 71 ++++++++++++++----------- packager/live_packager.cc | 19 ++++--- packager/live_packager_export.cc | 45 ++++++++++------ packager/live_packager_test.cc | 14 +++-- 4 files changed, 83 insertions(+), 66 deletions(-) diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h index a4deb59577c..ee0ac92f184 100644 --- a/include/packager/live_packager_export.h +++ b/include/packager/live_packager_export.h @@ -6,33 +6,32 @@ #define PACKAGER_LIVE_PACKAGER_EXPORT_H #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #include #include typedef enum OutputFormat { - OUTPUT_FORMAT_FMP4, - OUTPUT_FORMAT_TS, - OUTPUT_FORMAT_VTTMP4, - OUTPUT_FORMAT_TTMLMP4, - OUTPUT_FORMAT_TTML, + OUTPUT_FORMAT_FMP4, + OUTPUT_FORMAT_TS, + OUTPUT_FORMAT_VTTMP4, + OUTPUT_FORMAT_TTMLMP4, + OUTPUT_FORMAT_TTML, } OutputFormat_t; typedef enum TrackType { - TRACK_TYPE_AUDIO, - TRACK_TYPE_VIDEO, - TRACK_TYPE_TEXT, + TRACK_TYPE_AUDIO, + TRACK_TYPE_VIDEO, + TRACK_TYPE_TEXT, } TrackType_t; typedef enum EncryptionScheme { - ENCRYPTION_SCHEME_NONE, - ENCRYPTION_SCHEME_SAMPLE_AES, - ENCRYPTION_SCHEME_AES_128, - ENCRYPTION_SCHEME_CBCS, - ENCRYPTION_SCHEME_CENC, + ENCRYPTION_SCHEME_NONE, + ENCRYPTION_SCHEME_SAMPLE_AES, + ENCRYPTION_SCHEME_AES_128, + ENCRYPTION_SCHEME_CBCS, + ENCRYPTION_SCHEME_CENC, } EncryptionScheme_t; static const size_t kIvMaxSize = 16; @@ -40,33 +39,32 @@ static const size_t kKeySize = 16; static const size_t kKeyIdSize = 16; typedef struct LivePackagerConfig { - OutputFormat_t format; - TrackType_t track_type; + OutputFormat_t format; + TrackType_t track_type; - size_t iv_size; - uint8_t iv[kIvMaxSize]; - uint8_t key[kKeySize]; - uint8_t key_id[kKeyIdSize]; - EncryptionScheme_t protection_scheme; + size_t iv_size; + uint8_t iv[kIvMaxSize]; + uint8_t key[kKeySize]; + uint8_t key_id[kKeyIdSize]; + EncryptionScheme_t protection_scheme; /// User-specified segment number. /// For FMP4 output: /// It can be used to set the moof header sequence number if > 0. /// For M2TS output: /// It is be used to set the continuity counter. - uint32_t segment_number; + uint32_t segment_number; /// The offset to be applied to transport stream (e.g. MPEG2-TS, HLS packed /// audio) timestamps to compensate for possible negative timestamps in the /// input. - int32_t m2ts_offset_ms; + int32_t m2ts_offset_ms; /// Used for timed text packaging to set the fragment decode time when the /// output format is either VTT in MP4 or TTML in MP4. - int64_t timed_text_decode_time; + int64_t timed_text_decode_time; } LivePackagerConfig_t; - typedef struct LivePackager_buffer_s* LivePackagerBuffer_t; LivePackagerBuffer_t livepackager_buf_new(); @@ -75,19 +73,28 @@ void livepackager_buf_free(LivePackagerBuffer_t buf); const uint8_t* livepackager_buf_data(LivePackagerBuffer_t buf); size_t livepackager_buf_size(LivePackagerBuffer_t buf); - typedef struct LivePackager_instance_s* LivePackager_t; LivePackager_t livepackager_new(LivePackagerConfig_t cfg); void livepackager_free(LivePackager_t lp); -bool livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, LivePackagerBuffer_t dest); -bool livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* media, size_t media_len, LivePackagerBuffer_t dest); -bool livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest); +bool livepackager_package_init(LivePackager_t lp, + uint8_t* init, + size_t init_len, + LivePackagerBuffer_t dest); +bool livepackager_package(LivePackager_t lp, + uint8_t* init, + size_t init_len, + uint8_t* media, + size_t media_len, + LivePackagerBuffer_t dest); +bool livepackager_package_timedtext(LivePackager_t lp, + uint8_t* seg, + size_t seg_len, + LivePackagerBuffer_t dest); #ifdef __cplusplus } #endif - -#endif //PACKAGER_LIVE_PACKAGER_EXPORT_H +#endif // PACKAGER_LIVE_PACKAGER_EXPORT_H diff --git a/packager/live_packager.cc b/packager/live_packager.cc index d96d01dd0f2..64d1889d9c0 100644 --- a/packager/live_packager.cc +++ b/packager/live_packager.cc @@ -301,8 +301,8 @@ Status LivePackager::PackageInit(const Segment& init_segment, return reader.Read(buffer, size); }; - callback_params.write_func = [](const std::string& name, - const void* data, uint64_t size) { + callback_params.write_func = [](const std::string& name, const void* data, + uint64_t size) { // output.AppendData(reinterpret_cast(data), size); return size; }; @@ -367,14 +367,14 @@ Status LivePackager::Package(const Segment& init_segment, shaka::BufferCallbackParams init_callback_params; init_callback_params.write_func = [](const std::string& name, - const void* data, uint64_t size) { + const void* data, uint64_t size) { // For live packaging it is observed that the init segment callback is // invoked more than once. The initial callback does not contain the MEHD // box data and furthermore does not contain fragment duration. // If an MP4 file is created in real-time, such as used in live-streaming, // it is not likely that the fragment_duration is known in advance and this // box may be omitted. - //if (out.InitSegmentSize() == 0) { + // if (out.InitSegmentSize() == 0) { // out.SetInitSegment(reinterpret_cast(data), size); //} return size; @@ -414,8 +414,7 @@ Status LivePackager::Package(const Segment& init_segment, return packager.Run(); } -Status LivePackager::PackageTimedText(const Segment& in, - SegmentBuffer& out) { +Status LivePackager::PackageTimedText(const Segment& in, SegmentBuffer& out) { SegmentDataReader reader(in); shaka::BufferCallbackParams callback_params; callback_params.read_func = [&reader](const std::string& name, void* buffer, @@ -431,10 +430,10 @@ Status LivePackager::PackageTimedText(const Segment& in, shaka::BufferCallbackParams init_callback_params; init_callback_params.write_func = [](const std::string& name, - const void* data, uint64_t size) { - //if (out.InitSegmentSize() == 0) { - // out.SetInitSegment(reinterpret_cast(data), size); - //} + const void* data, uint64_t size) { + // if (out.InitSegmentSize() == 0) { + // out.SetInitSegment(reinterpret_cast(data), size); + // } return size; }; diff --git a/packager/live_packager_export.cc b/packager/live_packager_export.cc index 4de45d68bd4..301bbeb2fe0 100644 --- a/packager/live_packager_export.cc +++ b/packager/live_packager_export.cc @@ -7,24 +7,26 @@ struct LivePackager_instance_s { LivePackager_t livepackager_new(LivePackagerConfig_t cfg) { shaka::LiveConfig converted{ - .format = shaka::LiveConfig::OutputFormat(cfg.format), - .track_type = shaka::LiveConfig::TrackType(cfg.track_type), - .iv={}, - .key={}, - .key_id={}, - .protection_scheme=shaka::LiveConfig::EncryptionScheme(cfg.protection_scheme), - .segment_number = cfg.segment_number, - .m2ts_offset_ms = cfg.m2ts_offset_ms, - .timed_text_decode_time = cfg.timed_text_decode_time, + .format = shaka::LiveConfig::OutputFormat(cfg.format), + .track_type = shaka::LiveConfig::TrackType(cfg.track_type), + .iv = {}, + .key = {}, + .key_id = {}, + .protection_scheme = + shaka::LiveConfig::EncryptionScheme(cfg.protection_scheme), + .segment_number = cfg.segment_number, + .m2ts_offset_ms = cfg.m2ts_offset_ms, + .timed_text_decode_time = cfg.timed_text_decode_time, }; if (cfg.protection_scheme != ENCRYPTION_SCHEME_NONE) { - converted.iv=std::vector(cfg.iv, cfg.iv+cfg.iv_size); - converted.key=std::vector(cfg.key, cfg.key+KEY_SIZE); - converted.key_id=std::vector(cfg.key_id, cfg.key_id+KEY_ID_SIZE); + converted.iv = std::vector(cfg.iv, cfg.iv + cfg.iv_size); + converted.key = std::vector(cfg.key, cfg.key + kKeySize); + converted.key_id = std::vector(cfg.key_id, cfg.key_id + kKeyIdSize); } - return new LivePackager_instance_s{std::make_unique(converted)}; + return new LivePackager_instance_s{ + std::make_unique(converted)}; } void livepackager_free(LivePackager_t lp) { @@ -51,18 +53,29 @@ size_t livepackager_buf_size(LivePackagerBuffer_t buf) { return buf->inner->Size(); } -bool livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, LivePackagerBuffer_t dest) { +bool livepackager_package_init(LivePackager_t lp, + uint8_t* init, + size_t init_len, + LivePackagerBuffer_t dest) { shaka::SegmentData input(init, init_len); return lp->inner->PackageInit(input, *dest->inner).ok(); } -bool livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* media, size_t media_len, LivePackagerBuffer_t dest) { +bool livepackager_package(LivePackager_t lp, + uint8_t* init, + size_t init_len, + uint8_t* media, + size_t media_len, + LivePackagerBuffer_t dest) { shaka::SegmentData input_init(init, init_len); shaka::SegmentData input_media(media, media_len); return lp->inner->Package(input_init, input_media, *dest->inner).ok(); } -bool livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest) { +bool livepackager_package_timedtext(LivePackager_t lp, + uint8_t* seg, + size_t seg_len, + LivePackagerBuffer_t dest) { shaka::SegmentData input_seg(seg, seg_len); return lp->inner->PackageTimedText(input_seg, *dest->inner).ok(); } \ No newline at end of file diff --git a/packager/live_packager_test.cc b/packager/live_packager_test.cc index 592cce09de6..e049348111b 100644 --- a/packager/live_packager_test.cc +++ b/packager/live_packager_test.cc @@ -273,8 +273,7 @@ class MP4MediaParserTest { std::vector> samples_; }; -void CheckVideoInitSegment(const SegmentBuffer& buffer, - media::FourCC format) { +void CheckVideoInitSegment(const SegmentBuffer& buffer, media::FourCC format) { bool err(true); size_t bytes_to_read(buffer.Size()); const uint8_t* data(buffer.Data()); @@ -701,8 +700,7 @@ TEST_F(LivePackagerBaseTest, VerifyAes128WithDecryption) { ASSERT_FALSE(exp_segment_buffer.empty()); std::vector decrypted; - std::vector buffer(out.Data(), - out.Data() + out.Size()); + std::vector buffer(out.Data(), out.Data() + out.Size()); ASSERT_TRUE(decryptor.Crypt(buffer, &decrypted)); ASSERT_EQ(decrypted, exp_segment_buffer); @@ -1056,8 +1054,9 @@ TEST_P(TimedTextParameterizedTest, VerifyTimedText) { // TODO(sasha): must be checked separately when PackageTimedTextInit is // added. - //if (i == 0) { - // CheckTextInitSegment(out, GetParam().handler_type, GetParam().format); + // if (i == 0) { + // CheckTextInitSegment(out, GetParam().handler_type, + // GetParam().format); //} std::string expected_fname; @@ -1067,8 +1066,7 @@ TEST_P(TimedTextParameterizedTest, VerifyTimedText) { std::vector expected_buf(ReadTestDataFile(expected_fname)); ASSERT_FALSE(expected_buf.empty()); - std::vector actual_buf(out.Data(), - out.Data() + out.Size()); + std::vector actual_buf(out.Data(), out.Data() + out.Size()); ASSERT_EQ(expected_buf, actual_buf); } } From 9394604a2dac5bcbc8799d0dc10b3528cbc60f88 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 15:16:56 +0200 Subject: [PATCH 21/29] Appease linter --- include/packager/live_packager.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/packager/live_packager.h b/include/packager/live_packager.h index 934edf55a54..4ebf2a6651a 100644 --- a/include/packager/live_packager.h +++ b/include/packager/live_packager.h @@ -33,7 +33,7 @@ class SegmentData final : public Segment { }; class SegmentBuffer final : public Segment { -public: + public: SegmentBuffer() = default; ~SegmentBuffer() = default; @@ -42,7 +42,7 @@ class SegmentBuffer final : public Segment { virtual const uint8_t* Data() const override; virtual size_t Size() const override; -private: + private: std::vector buffer_; }; @@ -140,8 +140,7 @@ class LivePackager { const Segment& media_segment, SegmentBuffer& output); - Status PackageTimedText(const Segment& media_segment, - SegmentBuffer& output); + Status PackageTimedText(const Segment& media_segment, SegmentBuffer& output); LivePackager(const LivePackager&) = delete; LivePackager& operator=(const LivePackager&) = delete; From 226c45a9620827993f6161a498e36d7bbe60e8e1 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 16:21:46 +0200 Subject: [PATCH 22/29] Add nothrow --- packager/live_packager_export.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packager/live_packager_export.cc b/packager/live_packager_export.cc index 301bbeb2fe0..3563da175de 100644 --- a/packager/live_packager_export.cc +++ b/packager/live_packager_export.cc @@ -25,8 +25,8 @@ LivePackager_t livepackager_new(LivePackagerConfig_t cfg) { converted.key_id = std::vector(cfg.key_id, cfg.key_id + kKeyIdSize); } - return new LivePackager_instance_s{ - std::make_unique(converted)}; + return new (std::nothrow) + LivePackager_instance_s{std::make_unique(converted)}; } void livepackager_free(LivePackager_t lp) { @@ -38,7 +38,8 @@ struct LivePackager_buffer_s { }; LivePackagerBuffer_t livepackager_buf_new() { - return new LivePackager_buffer_s{std::make_unique()}; + return new (std::nothrow) + LivePackager_buffer_s{std::make_unique()}; } void livepackager_buf_free(LivePackagerBuffer_t buf) { From 1fcd4362006c01f59e35d8cbcb53acdd08cdeea1 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 17:18:21 +0200 Subject: [PATCH 23/29] Use defines --- include/packager/live_packager_export.h | 12 ++++++------ packager/live_packager_export.cc | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h index ee0ac92f184..611cff0e991 100644 --- a/include/packager/live_packager_export.h +++ b/include/packager/live_packager_export.h @@ -34,18 +34,18 @@ typedef enum EncryptionScheme { ENCRYPTION_SCHEME_CENC, } EncryptionScheme_t; -static const size_t kIvMaxSize = 16; -static const size_t kKeySize = 16; -static const size_t kKeyIdSize = 16; +#define IV_MAX_SIZE 16 +#define KEY_SIZE 16 +#define KEY_ID_SIZE 16 typedef struct LivePackagerConfig { OutputFormat_t format; TrackType_t track_type; size_t iv_size; - uint8_t iv[kIvMaxSize]; - uint8_t key[kKeySize]; - uint8_t key_id[kKeyIdSize]; + uint8_t iv[IV_MAX_SIZE]; + uint8_t key[KEY_SIZE]; + uint8_t key_id[KEY_ID_SIZE]; EncryptionScheme_t protection_scheme; /// User-specified segment number. diff --git a/packager/live_packager_export.cc b/packager/live_packager_export.cc index 3563da175de..b3bcf6be50f 100644 --- a/packager/live_packager_export.cc +++ b/packager/live_packager_export.cc @@ -21,8 +21,8 @@ LivePackager_t livepackager_new(LivePackagerConfig_t cfg) { if (cfg.protection_scheme != ENCRYPTION_SCHEME_NONE) { converted.iv = std::vector(cfg.iv, cfg.iv + cfg.iv_size); - converted.key = std::vector(cfg.key, cfg.key + kKeySize); - converted.key_id = std::vector(cfg.key_id, cfg.key_id + kKeyIdSize); + converted.key = std::vector(cfg.key, cfg.key + KEY_SIZE); + converted.key_id = std::vector(cfg.key_id, cfg.key_id + KEY_ID_SIZE); } return new (std::nothrow) From 8472b2462f858fcaf361d85f086eeda35c5eda0e Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 18:17:26 +0200 Subject: [PATCH 24/29] Remove build flags --- packager/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/packager/CMakeLists.txt b/packager/CMakeLists.txt index 926909ef0f9..a0dec369edf 100644 --- a/packager/CMakeLists.txt +++ b/packager/CMakeLists.txt @@ -9,8 +9,6 @@ # Include a module to define standard install directories. include(GNUInstallDirs) -set(BUILD_SHARED_LIBS ON) - # Build static libs by default, or shared if BUILD_SHARED_LIBS is on. if(BUILD_SHARED_LIBS) add_definitions(-DSHARED_LIBRARY_BUILD) From ce5531cbf81159634ac811baaa3eb2d8efd221e4 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 20:55:14 +0200 Subject: [PATCH 25/29] Add timed text init packaging --- include/packager/live_packager.h | 3 +- include/packager/live_packager_export.h | 7 ++ packager/live_packager.cc | 16 ++-- packager/live_packager_export.cc | 26 ++++++- packager/live_packager_test.cc | 98 ++++++++++++------------- 5 files changed, 92 insertions(+), 58 deletions(-) diff --git a/include/packager/live_packager.h b/include/packager/live_packager.h index 4ebf2a6651a..bf062f19847 100644 --- a/include/packager/live_packager.h +++ b/include/packager/live_packager.h @@ -35,6 +35,7 @@ class SegmentData final : public Segment { class SegmentBuffer final : public Segment { public: SegmentBuffer() = default; + SegmentBuffer(const uint8_t* data, size_t size); ~SegmentBuffer() = default; void AppendData(const uint8_t* data, size_t size); @@ -140,7 +141,7 @@ class LivePackager { const Segment& media_segment, SegmentBuffer& output); - Status PackageTimedText(const Segment& media_segment, SegmentBuffer& output); + Status PackageTimedText(const Segment& media_segment, FullSegmentBuffer& output); LivePackager(const LivePackager&) = delete; LivePackager& operator=(const LivePackager&) = delete; diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h index 611cff0e991..17e31dec25a 100644 --- a/include/packager/live_packager_export.h +++ b/include/packager/live_packager_export.h @@ -82,12 +82,19 @@ bool livepackager_package_init(LivePackager_t lp, uint8_t* init, size_t init_len, LivePackagerBuffer_t dest); + bool livepackager_package(LivePackager_t lp, uint8_t* init, size_t init_len, uint8_t* media, size_t media_len, LivePackagerBuffer_t dest); + +bool livepackager_package_timedtext_init(LivePackager_t lp, + uint8_t* seg, + size_t seg_len, + LivePackagerBuffer_t dest); + bool livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, diff --git a/packager/live_packager.cc b/packager/live_packager.cc index 64d1889d9c0..781a8621443 100644 --- a/packager/live_packager.cc +++ b/packager/live_packager.cc @@ -226,6 +226,9 @@ size_t SegmentData::Size() const { return size_; } +SegmentBuffer::SegmentBuffer(const uint8_t* data, size_t size) + : buffer_(data, data + size) {} + void SegmentBuffer::AppendData(const uint8_t* data, size_t size) { std::copy(data, data + size, std::back_inserter(buffer_)); } @@ -414,7 +417,8 @@ Status LivePackager::Package(const Segment& init_segment, return packager.Run(); } -Status LivePackager::PackageTimedText(const Segment& in, SegmentBuffer& out) { +Status LivePackager::PackageTimedText(const Segment& in, + FullSegmentBuffer& out) { SegmentDataReader reader(in); shaka::BufferCallbackParams callback_params; callback_params.read_func = [&reader](const std::string& name, void* buffer, @@ -429,11 +433,11 @@ Status LivePackager::PackageTimedText(const Segment& in, SegmentBuffer& out) { }; shaka::BufferCallbackParams init_callback_params; - init_callback_params.write_func = [](const std::string& name, - const void* data, uint64_t size) { - // if (out.InitSegmentSize() == 0) { - // out.SetInitSegment(reinterpret_cast(data), size); - // } + init_callback_params.write_func = [&out](const std::string& name, + const void* data, uint64_t size) { + if (out.InitSegmentSize() == 0) { + out.SetInitSegment(reinterpret_cast(data), size); + } return size; }; diff --git a/packager/live_packager_export.cc b/packager/live_packager_export.cc index b3bcf6be50f..a25da0acd90 100644 --- a/packager/live_packager_export.cc +++ b/packager/live_packager_export.cc @@ -1,6 +1,8 @@ #include #include +#include + struct LivePackager_instance_s { std::unique_ptr inner; }; @@ -73,10 +75,32 @@ bool livepackager_package(LivePackager_t lp, return lp->inner->Package(input_init, input_media, *dest->inner).ok(); } +bool livepackager_package_timedtext_init(LivePackager_t lp, + uint8_t* seg, + size_t seg_len, + LivePackagerBuffer_t dest) { + shaka::SegmentData input_seg(seg, seg_len); + shaka::FullSegmentBuffer out; + if (!lp->inner->PackageTimedText(input_seg, out).ok()) { + return false; + } + + dest->inner = std::make_unique(out.InitSegmentData(), + out.InitSegmentSize()); + return true; +} + bool livepackager_package_timedtext(LivePackager_t lp, uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest) { shaka::SegmentData input_seg(seg, seg_len); - return lp->inner->PackageTimedText(input_seg, *dest->inner).ok(); + shaka::FullSegmentBuffer out; + if (!lp->inner->PackageTimedText(input_seg, out).ok()) { + return false; + } + + dest->inner = std::make_unique(out.SegmentData(), + out.SegmentSize()); + return true; } \ No newline at end of file diff --git a/packager/live_packager_test.cc b/packager/live_packager_test.cc index e049348111b..e8ad4295a31 100644 --- a/packager/live_packager_test.cc +++ b/packager/live_packager_test.cc @@ -313,46 +313,45 @@ void CheckVideoInitSegment(const SegmentBuffer& buffer, media::FourCC format) { } } -// TODO(sasha): must be used when PackageTimedTextInit is added. -// void CheckTextInitSegment(const FullSegmentBuffer& buffer, -// media::FourCC handler, -// media::FourCC format) { -// bool err(true); -// size_t bytes_to_read(buffer.InitSegmentSize()); -// const uint8_t* data(buffer.InitSegmentData()); -// -// { -// std::unique_ptr reader( -// media::mp4::BoxReader::ReadBox(data, bytes_to_read, &err)); -// EXPECT_FALSE(err); -// -// FileTypeBoxChecker checker; -// checker.Check(reader.get()); -// -// data += reader->size(); -// bytes_to_read -= reader->size(); -// } -// -// { -// std::unique_ptr reader( -// media::mp4::BoxReader::ReadBox(data, bytes_to_read, &err)); -// EXPECT_FALSE(err); -// -// media::mp4::TextSampleEntry entry; -// entry.format = format; -// -// media::mp4::Track track; -// track.media.handler.handler_type = handler; -// track.media.information.sample_table.description.text_entries.push_back( -// entry); -// -// media::mp4::Movie expected; -// expected.tracks.push_back(track); -// -// MovieBoxChecker checker(expected); -// checker.Check(reader.get()); -// } -// } +void CheckTextInitSegment(const FullSegmentBuffer& buffer, + media::FourCC handler, + media::FourCC format) { + bool err(true); + size_t bytes_to_read(buffer.InitSegmentSize()); + const uint8_t* data(buffer.InitSegmentData()); + + { + std::unique_ptr reader( + media::mp4::BoxReader::ReadBox(data, bytes_to_read, &err)); + EXPECT_FALSE(err); + + FileTypeBoxChecker checker; + checker.Check(reader.get()); + + data += reader->size(); + bytes_to_read -= reader->size(); + } + + { + std::unique_ptr reader( + media::mp4::BoxReader::ReadBox(data, bytes_to_read, &err)); + EXPECT_FALSE(err); + + media::mp4::TextSampleEntry entry; + entry.format = format; + + media::mp4::Track track; + track.media.handler.handler_type = handler; + track.media.information.sample_table.description.text_entries.push_back( + entry); + + media::mp4::Movie expected; + expected.tracks.push_back(track); + + MovieBoxChecker checker(expected); + checker.Check(reader.get()); + } +} void CheckSegment(const LiveConfig& config, const SegmentBuffer& buffer, @@ -1030,7 +1029,7 @@ TEST_P(TimedTextParameterizedTest, VerifyTimedText) { ASSERT_FALSE(segment_buffer.empty()); SegmentData media_seg(segment_buffer.data(), segment_buffer.size()); - SegmentBuffer out; + FullSegmentBuffer out; LiveConfig live_config; live_config.protection_scheme = LiveConfig::EncryptionScheme::NONE; @@ -1047,17 +1046,15 @@ TEST_P(TimedTextParameterizedTest, VerifyTimedText) { ASSERT_EQ(GetParam().expected_status, live_packager_->PackageTimedText(media_seg, out)); if (GetParam().expected_status == Status::OK) { - ASSERT_GT(out.Size(), 0); + ASSERT_GT(out.SegmentSize(), 0); if (live_config.format == LiveConfig::OutputFormat::VTTMP4 || live_config.format == LiveConfig::OutputFormat::TTMLMP4) { - CheckSegment(live_config, out, 1000, true); + SegmentBuffer seg(out.SegmentData(), out.SegmentSize()); + CheckSegment(live_config, seg, 1000, true); - // TODO(sasha): must be checked separately when PackageTimedTextInit is - // added. - // if (i == 0) { - // CheckTextInitSegment(out, GetParam().handler_type, - // GetParam().format); - //} + if (i == 0) { + CheckTextInitSegment(out, GetParam().handler_type, GetParam().format); + } std::string expected_fname; ASSERT_TRUE(FormatWithIndex(GetParam().expected_segment_format, i + 1, @@ -1066,7 +1063,8 @@ TEST_P(TimedTextParameterizedTest, VerifyTimedText) { std::vector expected_buf(ReadTestDataFile(expected_fname)); ASSERT_FALSE(expected_buf.empty()); - std::vector actual_buf(out.Data(), out.Data() + out.Size()); + std::vector actual_buf(out.SegmentData(), + out.SegmentData() + out.SegmentSize()); ASSERT_EQ(expected_buf, actual_buf); } } From aadf9be00d8d1ca94e8ea0f5143c690ba1ffa0de Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Wed, 27 Mar 2024 20:58:37 +0200 Subject: [PATCH 26/29] Appease linter --- include/packager/live_packager.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/packager/live_packager.h b/include/packager/live_packager.h index bf062f19847..7b52ba6fe1d 100644 --- a/include/packager/live_packager.h +++ b/include/packager/live_packager.h @@ -141,7 +141,8 @@ class LivePackager { const Segment& media_segment, SegmentBuffer& output); - Status PackageTimedText(const Segment& media_segment, FullSegmentBuffer& output); + Status PackageTimedText(const Segment& media_segment, + FullSegmentBuffer& output); LivePackager(const LivePackager&) = delete; LivePackager& operator=(const LivePackager&) = delete; From b277b8787c2a5ea1903fdf57349c03024f121733 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 28 Mar 2024 15:48:52 +0200 Subject: [PATCH 27/29] Cleanup code --- include/packager/live_packager.h | 1 - include/packager/live_packager_export.h | 10 +++++----- packager/live_packager.cc | 21 ++++++++------------- packager/live_packager_export.cc | 16 +++++++--------- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/include/packager/live_packager.h b/include/packager/live_packager.h index 7b52ba6fe1d..4f71cf15826 100644 --- a/include/packager/live_packager.h +++ b/include/packager/live_packager.h @@ -35,7 +35,6 @@ class SegmentData final : public Segment { class SegmentBuffer final : public Segment { public: SegmentBuffer() = default; - SegmentBuffer(const uint8_t* data, size_t size); ~SegmentBuffer() = default; void AppendData(const uint8_t* data, size_t size); diff --git a/include/packager/live_packager_export.h b/include/packager/live_packager_export.h index 17e31dec25a..bf238949a1f 100644 --- a/include/packager/live_packager_export.h +++ b/include/packager/live_packager_export.h @@ -79,24 +79,24 @@ LivePackager_t livepackager_new(LivePackagerConfig_t cfg); void livepackager_free(LivePackager_t lp); bool livepackager_package_init(LivePackager_t lp, - uint8_t* init, + const uint8_t* init, size_t init_len, LivePackagerBuffer_t dest); bool livepackager_package(LivePackager_t lp, - uint8_t* init, + const uint8_t* init, size_t init_len, - uint8_t* media, + const uint8_t* media, size_t media_len, LivePackagerBuffer_t dest); bool livepackager_package_timedtext_init(LivePackager_t lp, - uint8_t* seg, + const uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest); bool livepackager_package_timedtext(LivePackager_t lp, - uint8_t* seg, + const uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest); diff --git a/packager/live_packager.cc b/packager/live_packager.cc index 781a8621443..e28f8b2d271 100644 --- a/packager/live_packager.cc +++ b/packager/live_packager.cc @@ -226,9 +226,6 @@ size_t SegmentData::Size() const { return size_; } -SegmentBuffer::SegmentBuffer(const uint8_t* data, size_t size) - : buffer_(data, data + size) {} - void SegmentBuffer::AppendData(const uint8_t* data, size_t size) { std::copy(data, data + size, std::back_inserter(buffer_)); } @@ -306,13 +303,19 @@ Status LivePackager::PackageInit(const Segment& init_segment, callback_params.write_func = [](const std::string& name, const void* data, uint64_t size) { - // output.AppendData(reinterpret_cast(data), size); + // skip writing any media segment data return size; }; shaka::BufferCallbackParams init_callback_params; init_callback_params.write_func = [&output](const std::string& name, const void* data, uint64_t size) { + // For live packaging it is observed that the init segment callback is + // invoked more than once. The initial callback does not contain the MEHD + // box data and furthermore does not contain fragment duration. + // If an MP4 file is created in real-time, such as used in live-streaming, + // it is not likely that the fragment_duration is known in advance and this + // box may be omitted. if (output.Size() == 0) { LOG(INFO) << "init segment callback, name: " << name << " size: " << size; output.AppendData(reinterpret_cast(data), size); @@ -371,15 +374,7 @@ Status LivePackager::Package(const Segment& init_segment, shaka::BufferCallbackParams init_callback_params; init_callback_params.write_func = [](const std::string& name, const void* data, uint64_t size) { - // For live packaging it is observed that the init segment callback is - // invoked more than once. The initial callback does not contain the MEHD - // box data and furthermore does not contain fragment duration. - // If an MP4 file is created in real-time, such as used in live-streaming, - // it is not likely that the fragment_duration is known in advance and this - // box may be omitted. - // if (out.InitSegmentSize() == 0) { - // out.SetInitSegment(reinterpret_cast(data), size); - //} + // skip writing any init segment data return size; }; diff --git a/packager/live_packager_export.cc b/packager/live_packager_export.cc index a25da0acd90..a5fe5fb15a0 100644 --- a/packager/live_packager_export.cc +++ b/packager/live_packager_export.cc @@ -57,7 +57,7 @@ size_t livepackager_buf_size(LivePackagerBuffer_t buf) { } bool livepackager_package_init(LivePackager_t lp, - uint8_t* init, + const uint8_t* init, size_t init_len, LivePackagerBuffer_t dest) { shaka::SegmentData input(init, init_len); @@ -65,9 +65,9 @@ bool livepackager_package_init(LivePackager_t lp, } bool livepackager_package(LivePackager_t lp, - uint8_t* init, + const uint8_t* init, size_t init_len, - uint8_t* media, + const uint8_t* media, size_t media_len, LivePackagerBuffer_t dest) { shaka::SegmentData input_init(init, init_len); @@ -76,7 +76,7 @@ bool livepackager_package(LivePackager_t lp, } bool livepackager_package_timedtext_init(LivePackager_t lp, - uint8_t* seg, + const uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest) { shaka::SegmentData input_seg(seg, seg_len); @@ -85,13 +85,12 @@ bool livepackager_package_timedtext_init(LivePackager_t lp, return false; } - dest->inner = std::make_unique(out.InitSegmentData(), - out.InitSegmentSize()); + dest->inner->AppendData(out.InitSegmentData(), out.InitSegmentSize()); return true; } bool livepackager_package_timedtext(LivePackager_t lp, - uint8_t* seg, + const uint8_t* seg, size_t seg_len, LivePackagerBuffer_t dest) { shaka::SegmentData input_seg(seg, seg_len); @@ -100,7 +99,6 @@ bool livepackager_package_timedtext(LivePackager_t lp, return false; } - dest->inner = std::make_unique(out.SegmentData(), - out.SegmentSize()); + dest->inner->AppendData(out.SegmentData(), out.SegmentSize()); return true; } \ No newline at end of file From a4f1ffe0f3481caaf37b9562cd04e652007cf68d Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 28 Mar 2024 16:10:59 +0200 Subject: [PATCH 28/29] Fix test --- packager/live_packager_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packager/live_packager_test.cc b/packager/live_packager_test.cc index e8ad4295a31..7b23cd97a05 100644 --- a/packager/live_packager_test.cc +++ b/packager/live_packager_test.cc @@ -1049,7 +1049,8 @@ TEST_P(TimedTextParameterizedTest, VerifyTimedText) { ASSERT_GT(out.SegmentSize(), 0); if (live_config.format == LiveConfig::OutputFormat::VTTMP4 || live_config.format == LiveConfig::OutputFormat::TTMLMP4) { - SegmentBuffer seg(out.SegmentData(), out.SegmentSize()); + SegmentBuffer seg; + seg.AppendData(out.SegmentData(), out.SegmentSize()); CheckSegment(live_config, seg, 1000, true); if (i == 0) { From b9f8727bc253c7a970220a970671317476e49154 Mon Sep 17 00:00:00 2001 From: Oleksandr Khodos Date: Thu, 11 Apr 2024 16:58:43 +0300 Subject: [PATCH 29/29] Remove on push trigger --- .github/workflows/build-attach-artifacts.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/build-attach-artifacts.yaml b/.github/workflows/build-attach-artifacts.yaml index 9dfddb00825..a7c3f2b0e04 100644 --- a/.github/workflows/build-attach-artifacts.yaml +++ b/.github/workflows/build-attach-artifacts.yaml @@ -9,10 +9,6 @@ on: description: 'Tag of the release' required: true type: string - push: - branches: - - feature/c - # By default, run all commands in a bash shell. On Windows, the default would # otherwise be powershell. @@ -150,5 +146,5 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} omitBodyDuringUpdate: true omitNameDuringUpdate: true - tag: dev-arm64-test + tag: ${{ inputs.tag }} draft: false