7 #include <packager/media/chunking/text_chunker.h>
9 #include <absl/log/check.h>
11 #include <packager/macros/status.h>
16 const size_t kStreamIndex = 0;
19 TextChunker::TextChunker(
double segment_duration_in_seconds,
20 int64_t start_segment_number)
21 : segment_duration_in_seconds_(segment_duration_in_seconds),
22 segment_number_(start_segment_number){};
24 Status TextChunker::Process(std::unique_ptr<StreamData> data) {
25 switch (data->stream_data_type) {
26 case StreamDataType::kStreamInfo:
27 return OnStreamInfo(std::move(data->stream_info));
28 case StreamDataType::kTextSample:
29 return OnTextSample(data->text_sample);
30 case StreamDataType::kCueEvent:
31 return OnCueEvent(data->cue_event);
33 return Status(error::INTERNAL_ERROR,
34 "Invalid stream data type for this handler");
38 Status TextChunker::OnFlushRequest(
size_t ) {
41 while (samples_in_current_segment_.size()) {
42 RETURN_IF_ERROR(DispatchSegment(segment_duration_));
45 return FlushAllDownstreams();
48 Status TextChunker::OnStreamInfo(std::shared_ptr<const StreamInfo> info) {
49 time_scale_ = info->time_scale();
50 segment_duration_ = ScaleTime(segment_duration_in_seconds_);
52 return DispatchStreamInfo(kStreamIndex, std::move(info));
55 Status TextChunker::OnCueEvent(std::shared_ptr<const CueEvent> event) {
64 const int64_t event_time = ScaleTime(event->time_in_seconds);
66 while (segment_start_ + segment_duration_ < event_time) {
67 RETURN_IF_ERROR(DispatchSegment(segment_duration_));
70 const int64_t shorten_duration = event_time - segment_start_;
71 RETURN_IF_ERROR(DispatchSegment(shorten_duration));
72 return DispatchCueEvent(kStreamIndex, std::move(event));
75 Status TextChunker::OnTextSample(std::shared_ptr<const TextSample> sample) {
77 const int64_t sample_start = sample->start_time();
81 if (segment_start_ < 0) {
85 segment_start_ = (sample_start / segment_duration_) * segment_duration_;
90 while (sample_start >= segment_start_ + segment_duration_) {
92 RETURN_IF_ERROR(DispatchSegment(segment_duration_));
95 samples_in_current_segment_.push_back(std::move(sample));
100 Status TextChunker::DispatchSegment(int64_t duration) {
101 DCHECK_GT(duration, 0) <<
"Segment duration should always be positive";
104 for (
const auto& sample : samples_in_current_segment_) {
105 RETURN_IF_ERROR(DispatchTextSample(kStreamIndex, sample));
109 std::shared_ptr<SegmentInfo> info = std::make_shared<SegmentInfo>();
110 info->start_timestamp = segment_start_;
111 info->duration = duration;
112 info->segment_number = segment_number_++;
114 RETURN_IF_ERROR(DispatchSegmentInfo(kStreamIndex, std::move(info)));
117 const int64_t new_segment_start = segment_start_ + duration;
118 segment_start_ = new_segment_start;
121 samples_in_current_segment_.remove_if(
122 [new_segment_start](
const std::shared_ptr<const TextSample>& sample) {
125 DCHECK_LT(sample->start_time(), new_segment_start);
126 return sample->EndTime() <= new_segment_start;
132 int64_t TextChunker::ScaleTime(
double seconds)
const {
133 DCHECK_GT(time_scale_, 0) <<
"Need positive time scale to scale time.";
134 return static_cast<int64_t
>(seconds * time_scale_);
All the methods that are virtual are virtual for mocking.