Shaka Packager SDK
text_chunker.cc
1 // Copyright 2017 Google Inc. 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/text_chunker.h"
8 
9 #include "packager/status_macros.h"
10 
11 namespace shaka {
12 namespace media {
13 namespace {
14 const size_t kStreamIndex = 0;
15 
16 std::shared_ptr<const SegmentInfo> MakeSegmentInfo(int64_t start_ms,
17  int64_t end_ms) {
18  DCHECK_LT(start_ms, end_ms);
19 
20  std::shared_ptr<SegmentInfo> info = std::make_shared<SegmentInfo>();
21  info->start_timestamp = start_ms;
22  info->duration = end_ms - start_ms;
23 
24  return info;
25 }
26 } // namespace
27 
28 TextChunker::TextChunker(int64_t segment_duration_ms)
29  : segment_duration_ms_(segment_duration_ms),
30  segment_start_ms_(0),
31  segment_expected_end_ms_(segment_duration_ms) {}
32 
33 Status TextChunker::InitializeInternal() {
34  return Status::OK;
35 }
36 
37 Status TextChunker::Process(std::unique_ptr<StreamData> data) {
38  switch (data->stream_data_type) {
39  case StreamDataType::kStreamInfo:
40  return OnStreamInfo(std::move(data->stream_info));
41  case StreamDataType::kTextSample:
42  return OnTextSample(data->text_sample);
43  case StreamDataType::kCueEvent:
44  return OnCueEvent(data->cue_event);
45  default:
46  return Status(error::INTERNAL_ERROR,
47  "Invalid stream data type for this handler");
48  }
49 }
50 
51 Status TextChunker::OnFlushRequest(size_t input_stream_index) {
52  // Keep outputting segments until all the samples leave the system.
53  while (segment_samples_.size()) {
54  RETURN_IF_ERROR(EndSegment(segment_expected_end_ms_));
55  }
56 
57  return FlushAllDownstreams();
58 }
59 
60 Status TextChunker::OnStreamInfo(std::shared_ptr<const StreamInfo> info) {
61  // There is no information we need from the stream info, so just pass it
62  // downstream.
63  return DispatchStreamInfo(kStreamIndex, std::move(info));
64 }
65 
66 Status TextChunker::OnCueEvent(std::shared_ptr<const CueEvent> event) {
67  // We are going to cut the current segment into two using the event's time as
68  // the division.
69  const int64_t cue_time_in_ms = event->time_in_seconds * 1000;
70 
71  // In the case that there is a gap with no samples between the last sample
72  // and the cue event, output all the segments until we get to the segment that
73  // the cue event interrupts.
74  while (segment_expected_end_ms_ < cue_time_in_ms) {
75  RETURN_IF_ERROR(EndSegment(segment_expected_end_ms_));
76  }
77 
78  RETURN_IF_ERROR(EndSegment(cue_time_in_ms));
79  RETURN_IF_ERROR(DispatchCueEvent(kStreamIndex, std::move(event)));
80 
81  return Status::OK;
82 }
83 
84 Status TextChunker::OnTextSample(std::shared_ptr<const TextSample> sample) {
85  // Output all segments that come before our new sample.
86  while (segment_expected_end_ms_ <= sample->start_time()) {
87  RETURN_IF_ERROR(EndSegment(segment_expected_end_ms_));
88  }
89 
90  segment_samples_.push_back(std::move(sample));
91 
92  return Status::OK;
93 }
94 
95 Status TextChunker::EndSegment(int64_t segment_actual_end_ms) {
96  // Output all the samples that are part of the segment.
97  for (const auto& sample : segment_samples_) {
98  RETURN_IF_ERROR(DispatchTextSample(kStreamIndex, sample));
99  }
100 
101  RETURN_IF_ERROR(DispatchSegmentInfo(
102  kStreamIndex, MakeSegmentInfo(segment_start_ms_, segment_actual_end_ms)));
103 
104  // Create a new segment that comes right after the old segment and remove all
105  // samples that don't cross over into the new segment.
106  StartNewSegment(segment_actual_end_ms);
107 
108  return Status::OK;
109 }
110 
111 void TextChunker::StartNewSegment(int64_t start_ms) {
112  segment_start_ms_ = start_ms;
113  segment_expected_end_ms_ = start_ms + segment_duration_ms_;
114 
115  // Remove all samples that no longer overlap with the new segment.
116  segment_samples_.remove_if(
117  [start_ms](const std::shared_ptr<const TextSample>& sample) {
118  return sample->EndTime() <= start_ms;
119  });
120 }
121 
122 } // namespace media
123 } // namespace shaka
All the methods that are virtual are virtual for mocking.