Shaka Packager SDK
Loading...
Searching...
No Matches
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 <cstddef>
10#include <cstdint>
11#include <string>
12
13#include <absl/log/check.h>
14
15#include <packager/macros/compiler.h>
16#include <packager/macros/status.h>
17#include <packager/media/base/media_handler.h>
18#include <packager/media/base/muxer.h>
19#include <packager/media/base/muxer_options.h>
20#include <packager/media/base/muxer_util.h>
21#include <packager/media/base/stream_info.h>
22#include <packager/media/base/text_sample.h>
23#include <packager/media/base/text_stream_info.h>
24#include <packager/media/event/muxer_listener.h>
25#include <packager/status.h>
26
27namespace shaka {
28namespace media {
29
30TextMuxer::TextMuxer(const MuxerOptions& options) : Muxer(options) {}
31TextMuxer::~TextMuxer() {}
32
33Status TextMuxer::InitializeMuxer() {
34 if (streams().size() != 1 || streams()[0]->stream_type() != kStreamText) {
35 return Status(error::MUXER_FAILURE,
36 "Incorrect streams given to WebVTT muxer");
37 }
38
39 auto copy = streams()[0]->Clone();
40 RETURN_IF_ERROR(InitializeStream(static_cast<TextStreamInfo*>(copy.get())));
41
42 muxer_listener()->OnMediaStart(options(), *copy, copy->time_scale(),
43 MuxerListener::kContainerText);
44
45 last_cue_ms_ = 0;
46 return Status::OK;
47}
48
49Status TextMuxer::Finalize() {
50 const float duration_ms = static_cast<float>(total_duration_ms_);
51 float duration_seconds = duration_ms / 1000;
52
53 // If we haven't seen any segments, this is a single-file. In this case,
54 // flush the single segment.
55 MuxerListener::MediaRanges ranges;
56 if (duration_seconds == 0 && last_cue_ms_ != 0) {
57 DCHECK(options().segment_template.empty());
58 duration_seconds = static_cast<float>(last_cue_ms_) / 1000;
59
60 uint64_t size;
61 RETURN_IF_ERROR(WriteToFile(options().output_file_name, &size));
62 // Insert a dummy value so the HLS generator will generate a segment list.
63 ranges.subsegment_ranges.emplace_back();
64
65 // The segment number does not matter for single segment output.
66 const uint32_t kArbitrarySegmentNumber = 0;
67
68 muxer_listener()->OnNewSegment(
69 options().output_file_name, 0,
70 duration_seconds * streams()[0]->time_scale(), size,
71 kArbitrarySegmentNumber);
72 }
73
74 muxer_listener()->OnMediaEnd(ranges, duration_seconds);
75
76 return Status::OK;
77}
78
79Status TextMuxer::AddTextSample(size_t stream_id, const TextSample& sample) {
80 UNUSED(stream_id);
81
82 // Ignore sync samples.
83 if (sample.body().is_empty()) {
84 return Status::OK;
85 }
86
87 RETURN_IF_ERROR(AddTextSampleInternal(sample));
88
89 last_cue_ms_ = sample.EndTime();
90 return Status::OK;
91}
92
93Status TextMuxer::FinalizeSegment(size_t stream_id,
94 const SegmentInfo& segment_info) {
95 UNUSED(stream_id);
96
97 total_duration_ms_ += segment_info.duration;
98
99 const std::string& segment_template = options().segment_template;
100 DCHECK(!segment_template.empty());
101
102 const int64_t start = segment_info.start_timestamp;
103 const int64_t duration = segment_info.duration;
104 const uint32_t segment_number = segment_info.segment_number;
105
106 const uint32_t bandwidth = options().bandwidth;
107
108 const std::string filename =
109 GetSegmentName(segment_template, start, segment_number, bandwidth);
110 uint64_t size;
111 RETURN_IF_ERROR(WriteToFile(filename, &size));
112
113 muxer_listener()->OnNewSegment(filename, start, duration, size,
114 segment_number);
115 return Status::OK;
116}
117
118} // namespace media
119} // namespace shaka
All the methods that are virtual are virtual for mocking.