Shaka Packager SDK
text_muxer.cc
1 // Copyright 2020 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/base/text_muxer.h"
8 
9 #include "packager/media/base/muxer_util.h"
10 #include "packager/status_macros.h"
11 
12 namespace shaka {
13 namespace media {
14 
15 TextMuxer::TextMuxer(const MuxerOptions& options) : Muxer(options) {}
16 TextMuxer::~TextMuxer() {}
17 
18 Status TextMuxer::InitializeMuxer() {
19  if (streams().size() != 1 || streams()[0]->stream_type() != kStreamText) {
20  return Status(error::MUXER_FAILURE,
21  "Incorrect streams given to WebVTT muxer");
22  }
23 
24  auto copy = streams()[0]->Clone();
25  RETURN_IF_ERROR(InitializeStream(static_cast<TextStreamInfo*>(copy.get())));
26 
27  muxer_listener()->OnMediaStart(options(), *copy, copy->time_scale(),
28  MuxerListener::kContainerText);
29 
30  last_cue_ms_ = 0;
31  return Status::OK;
32 }
33 
34 Status TextMuxer::Finalize() {
35  const float duration_ms = static_cast<float>(total_duration_ms_);
36  float duration_seconds = duration_ms / 1000;
37 
38  // If we haven't seen any segments, this is a single-file. In this case,
39  // flush the single segment.
40  MuxerListener::MediaRanges ranges;
41  if (duration_seconds == 0 && last_cue_ms_ != 0) {
42  DCHECK(options().segment_template.empty());
43  duration_seconds = static_cast<float>(last_cue_ms_) / 1000;
44 
45  uint64_t size;
46  RETURN_IF_ERROR(WriteToFile(options().output_file_name, &size));
47  // Insert a dummy value so the HLS generator will generate a segment list.
48  ranges.subsegment_ranges.emplace_back();
49 
50  muxer_listener()->OnNewSegment(
51  options().output_file_name, 0,
52  duration_seconds * streams()[0]->time_scale(), size);
53  }
54 
55  muxer_listener()->OnMediaEnd(ranges, duration_seconds);
56 
57  return Status::OK;
58 }
59 
60 Status TextMuxer::AddTextSample(size_t stream_id, const TextSample& sample) {
61  // Ignore sync samples.
62  if (sample.body().is_empty()) {
63  return Status::OK;
64  }
65 
66  RETURN_IF_ERROR(AddTextSampleInternal(sample));
67 
68  last_cue_ms_ = sample.EndTime();
69  return Status::OK;
70 }
71 
72 Status TextMuxer::FinalizeSegment(size_t stream_id,
73  const SegmentInfo& segment_info) {
74  total_duration_ms_ += segment_info.duration;
75 
76  const std::string& segment_template = options().segment_template;
77  DCHECK(!segment_template.empty());
78  const uint32_t index = segment_index_++;
79  const uint64_t start = segment_info.start_timestamp;
80  const uint64_t duration = segment_info.duration;
81  const uint32_t bandwidth = options().bandwidth;
82 
83  const std::string filename =
84  GetSegmentName(segment_template, start, index, bandwidth);
85  uint64_t size;
86  RETURN_IF_ERROR(WriteToFile(filename, &size));
87 
88  muxer_listener()->OnNewSegment(filename, start, duration, size);
89  return Status::OK;
90 }
91 
92 } // namespace media
93 } // namespace shaka
All the methods that are virtual are virtual for mocking.