Shaka Packager SDK
Loading...
Searching...
No Matches
segment_coordinator.cc
1// Copyright 2025 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/media/chunking/segment_coordinator.h>
8
9#include <cstddef>
10#include <memory>
11#include <utility>
12
13#include <absl/log/log.h>
14
15#include <packager/macros/status.h>
16#include <packager/media/base/media_handler.h>
17#include <packager/status.h>
18
19namespace shaka {
20namespace media {
21
22SegmentCoordinator::SegmentCoordinator() = default;
23
24void SegmentCoordinator::MarkAsTeletextStream(size_t input_stream_index) {
25 DVLOG(2) << "SegmentCoordinator: Marking stream " << input_stream_index
26 << " as teletext";
27 teletext_stream_indices_.insert(input_stream_index);
28}
29
31 // This handler accepts all stream types and passes them through.
32 // The number of output streams equals the number of input streams.
33 return Status::OK;
34}
35
36Status SegmentCoordinator::Process(std::unique_ptr<StreamData> stream_data) {
37 const size_t input_stream_index = stream_data->stream_index;
38 const StreamDataType stream_data_type = stream_data->stream_data_type;
39
40 DVLOG(3) << "SegmentCoordinator::Process stream_index=" << input_stream_index
41 << " type=" << StreamDataTypeToString(stream_data_type);
42
43 // Handle SegmentInfo specially - replicate to teletext streams
44 if (stream_data_type == StreamDataType::kSegmentInfo) {
45 auto info = std::move(stream_data->segment_info);
46
47 // First, dispatch to the same output stream (pass through)
48 RETURN_IF_ERROR(DispatchSegmentInfo(input_stream_index, info));
49
50 // If this is from a video/audio stream (not teletext), replicate to
51 // teletext streams
52 if (!IsTeletextStream(input_stream_index)) {
53 RETURN_IF_ERROR(OnSegmentInfo(input_stream_index, std::move(info)));
54 }
55
56 return Status::OK;
57 }
58
59 // For all other data types, pass through unchanged
60 return Dispatch(std::move(stream_data));
61}
62
63Status SegmentCoordinator::OnSegmentInfo(
64 size_t input_stream_index,
65 std::shared_ptr<const SegmentInfo> info) {
66 // Only replicate full segments, not subsegments
67 if (info->is_subsegment) {
68 DVLOG(3) << "SegmentCoordinator: Skipping subsegment replication";
69 return Status::OK;
70 }
71
72 // Replicate to all teletext streams
73 if (teletext_stream_indices_.empty()) {
74 DVLOG(3) << "SegmentCoordinator: No teletext streams registered, "
75 << "skipping replication";
76 return Status::OK;
77 }
78
79 // Set the sync source to the first non-teletext stream that sends
80 // SegmentInfo. This ensures we only use one stream (typically video) for
81 // alignment, avoiding issues when video and audio have different segment
82 // boundaries.
83 if (!sync_source_stream_index_.has_value()) {
84 sync_source_stream_index_ = input_stream_index;
85 DVLOG(2) << "SegmentCoordinator: Set sync source to stream "
86 << input_stream_index;
87 }
88
89 // Only replicate from the sync source stream
90 if (input_stream_index != sync_source_stream_index_.value()) {
91 DVLOG(3) << "SegmentCoordinator: Ignoring SegmentInfo from stream "
92 << input_stream_index << " (sync source is stream "
93 << sync_source_stream_index_.value() << ")";
94 return Status::OK;
95 }
96
97 // Update latest boundary for logging
98 latest_segment_boundary_ = info->start_timestamp;
99
100 DVLOG(2)
101 << "SegmentCoordinator: Received SegmentInfo from sync source stream "
102 << input_stream_index << " boundary=" << info->start_timestamp
103 << " duration=" << info->duration
104 << " segment_number=" << info->segment_number;
105
106 DVLOG(2) << "SegmentCoordinator: Replicating segment boundary "
107 << info->start_timestamp << " to " << teletext_stream_indices_.size()
108 << " teletext stream(s)";
109
110 // Replicate SegmentInfo to all teletext stream indices
111 for (size_t teletext_stream_index : teletext_stream_indices_) {
112 DVLOG(3) << "SegmentCoordinator: Replicating to teletext stream "
113 << teletext_stream_index;
114 RETURN_IF_ERROR(DispatchSegmentInfo(teletext_stream_index, info));
115 }
116
117 return Status::OK;
118}
119
120bool SegmentCoordinator::IsTeletextStream(size_t input_stream_index) const {
121 return teletext_stream_indices_.count(input_stream_index) > 0;
122}
123
124} // namespace media
125} // namespace shaka
Status DispatchSegmentInfo(size_t stream_index, std::shared_ptr< const SegmentInfo > segment_info) const
Dispatch the segment info to downstream handlers.
Status Dispatch(std::unique_ptr< StreamData > stream_data) const
Status Process(std::unique_ptr< StreamData > stream_data) override
void MarkAsTeletextStream(size_t input_stream_index)
All the methods that are virtual are virtual for mocking.