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 <absl/log/log.h>
10
11#include <packager/macros/status.h>
12
13namespace shaka {
14namespace media {
15
16SegmentCoordinator::SegmentCoordinator() = default;
17
18void SegmentCoordinator::MarkAsTeletextStream(size_t input_stream_index) {
19 DVLOG(2) << "SegmentCoordinator: Marking stream " << input_stream_index
20 << " as teletext";
21 teletext_stream_indices_.insert(input_stream_index);
22}
23
25 // This handler accepts all stream types and passes them through.
26 // The number of output streams equals the number of input streams.
27 return Status::OK;
28}
29
30Status SegmentCoordinator::Process(std::unique_ptr<StreamData> stream_data) {
31 const size_t input_stream_index = stream_data->stream_index;
32 const StreamDataType stream_data_type = stream_data->stream_data_type;
33
34 DVLOG(3) << "SegmentCoordinator::Process stream_index=" << input_stream_index
35 << " type=" << StreamDataTypeToString(stream_data_type);
36
37 // Handle SegmentInfo specially - replicate to teletext streams
38 if (stream_data_type == StreamDataType::kSegmentInfo) {
39 auto info = std::move(stream_data->segment_info);
40
41 // First, dispatch to the same output stream (pass through)
42 RETURN_IF_ERROR(DispatchSegmentInfo(input_stream_index, info));
43
44 // If this is from a video/audio stream (not teletext), replicate to
45 // teletext streams
46 if (!IsTeletextStream(input_stream_index)) {
47 RETURN_IF_ERROR(OnSegmentInfo(input_stream_index, std::move(info)));
48 }
49
50 return Status::OK;
51 }
52
53 // For all other data types, pass through unchanged
54 return Dispatch(std::move(stream_data));
55}
56
57Status SegmentCoordinator::OnSegmentInfo(
58 size_t input_stream_index,
59 std::shared_ptr<const SegmentInfo> info) {
60 // Only replicate full segments, not subsegments
61 if (info->is_subsegment) {
62 DVLOG(3) << "SegmentCoordinator: Skipping subsegment replication";
63 return Status::OK;
64 }
65
66 // Replicate to all teletext streams
67 if (teletext_stream_indices_.empty()) {
68 DVLOG(3) << "SegmentCoordinator: No teletext streams registered, "
69 << "skipping replication";
70 return Status::OK;
71 }
72
73 // Set the sync source to the first non-teletext stream that sends
74 // SegmentInfo. This ensures we only use one stream (typically video) for
75 // alignment, avoiding issues when video and audio have different segment
76 // boundaries.
77 if (!sync_source_stream_index_.has_value()) {
78 sync_source_stream_index_ = input_stream_index;
79 DVLOG(2) << "SegmentCoordinator: Set sync source to stream "
80 << input_stream_index;
81 }
82
83 // Only replicate from the sync source stream
84 if (input_stream_index != sync_source_stream_index_.value()) {
85 DVLOG(3) << "SegmentCoordinator: Ignoring SegmentInfo from stream "
86 << input_stream_index << " (sync source is stream "
87 << sync_source_stream_index_.value() << ")";
88 return Status::OK;
89 }
90
91 // Update latest boundary for logging
92 latest_segment_boundary_ = info->start_timestamp;
93
94 DVLOG(2)
95 << "SegmentCoordinator: Received SegmentInfo from sync source stream "
96 << input_stream_index << " boundary=" << info->start_timestamp
97 << " duration=" << info->duration
98 << " segment_number=" << info->segment_number;
99
100 DVLOG(2) << "SegmentCoordinator: Replicating segment boundary "
101 << info->start_timestamp << " to " << teletext_stream_indices_.size()
102 << " teletext stream(s)";
103
104 // Replicate SegmentInfo to all teletext stream indices
105 for (size_t teletext_stream_index : teletext_stream_indices_) {
106 DVLOG(3) << "SegmentCoordinator: Replicating to teletext stream "
107 << teletext_stream_index;
108 RETURN_IF_ERROR(DispatchSegmentInfo(teletext_stream_index, info));
109 }
110
111 return Status::OK;
112}
113
114bool SegmentCoordinator::IsTeletextStream(size_t input_stream_index) const {
115 return teletext_stream_indices_.count(input_stream_index) > 0;
116}
117
118} // namespace media
119} // 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.