Shaka Packager SDK
webvtt_segmenter.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/formats/webvtt/webvtt_segmenter.h"
8 
9 namespace shaka {
10 namespace media {
11 namespace {
12 const size_t kStreamIndex = 0;
13 } // namespace
14 
15 WebVttSegmenter::WebVttSegmenter(uint64_t segment_duration_ms)
16  : segment_duration_ms_(segment_duration_ms) {}
17 
18 Status WebVttSegmenter::InitializeInternal() {
19  return Status::OK;
20 }
21 
22 Status WebVttSegmenter::Process(std::unique_ptr<StreamData> stream_data) {
23  switch (stream_data->stream_data_type) {
24  case StreamDataType::kStreamInfo:
25  return DispatchStreamInfo(kStreamIndex,
26  std::move(stream_data->stream_info));
27  case StreamDataType::kTextSample:
28  return OnTextSample(stream_data->text_sample);
29  default:
30  return Status(error::INTERNAL_ERROR,
31  "Invalid stream data type for this handler");
32  }
33 }
34 
35 Status WebVttSegmenter::OnFlushRequest(size_t input_stream_index) {
36  // At this point we know that there is a single series of consecutive
37  // segments, all we need to do is run through all of them.
38  for (const auto& pair : segment_map_) {
39  Status status = DispatchSegmentWithSamples(pair.first, pair.second);
40 
41  if (!status.ok()) {
42  return status;
43  }
44  }
45 
46  segment_map_.clear();
47 
48  return FlushAllDownstreams();
49 }
50 
51 Status WebVttSegmenter::OnTextSample(std::shared_ptr<const TextSample> sample) {
52  const uint64_t start_segment = sample->start_time() / segment_duration_ms_;
53 
54  // Find the last segment that overlaps the sample. Adjust the sample by one
55  // ms (smallest time unit) in case |EndTime| falls on the segment boundary.
56  DCHECK_GT(sample->duration(), 0u);
57  const uint64_t ending_segment =
58  (sample->EndTime() - 1) / segment_duration_ms_;
59 
60  DCHECK_GE(ending_segment, start_segment);
61 
62  // Samples must always be advancing. If a sample comes in out of order,
63  // skip the sample.
64  if (head_segment_ > start_segment) {
65  LOG(WARNING) << "New sample has arrived out of order. Skipping sample "
66  << "as segment start is " << start_segment << " and segment "
67  << "head is " << head_segment_ << ".";
68  return Status::OK;
69  }
70 
71  // Add the sample to each segment it spans.
72  for (uint64_t segment = start_segment; segment <= ending_segment; segment++) {
73  segment_map_[segment].push_back(sample);
74  }
75 
76  // Move forward segment-by-segment so that we output empty segments to fill
77  // any segments with no cues.
78  for (uint64_t segment = head_segment_; segment < start_segment; segment++) {
79  auto it = segment_map_.find(segment);
80 
81  Status status;
82  if (it == segment_map_.end()) {
83  const WebVttSegmentSamples kNoSamples;
84  status.Update(DispatchSegmentWithSamples(segment, kNoSamples));
85  } else {
86  // We found a segment, output all the samples. Remove it from the map as
87  // we should never need to write to it again.
88  status.Update(DispatchSegmentWithSamples(segment, it->second));
89  segment_map_.erase(it);
90  }
91 
92  // If we fail to output a single sample, just stop.
93  if (!status.ok()) {
94  return status;
95  }
96  }
97 
98  // Jump ahead to the start of this segment as we should never have any samples
99  // start before |start_segment|.
100  head_segment_ = start_segment;
101 
102  return Status::OK;
103 }
104 
105 Status WebVttSegmenter::DispatchSegmentWithSamples(
106  uint64_t segment,
107  const WebVttSegmentSamples& samples) {
108  Status status;
109  for (const auto& sample : samples) {
110  status.Update(DispatchTextSample(kStreamIndex, sample));
111  }
112 
113  // Only send the segment info if all the samples were successful.
114  if (!status.ok()) {
115  return status;
116  }
117 
118  std::shared_ptr<SegmentInfo> info = std::make_shared<SegmentInfo>();
119  info->start_timestamp = segment * segment_duration_ms_;
120  info->duration = segment_duration_ms_;
121 
122  return DispatchSegmentInfo(kStreamIndex, std::move(info));
123 }
124 } // namespace media
125 } // namespace shaka
Status Process(std::unique_ptr< StreamData > stream_data) override
All the methods that are virtual are virtual for mocking.
void Update(Status new_status)
Definition: status.cc:76
Status OnFlushRequest(size_t input_stream_index) override
Event handler for flush request at the specific input stream index.