Shaka Packager SDK
Loading...
Searching...
No Matches
single_segment_segmenter.cc
1// Copyright 2015 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/formats/webm/single_segment_segmenter.h>
8
9#include <absl/log/check.h>
10#include <mkvmuxer/mkvmuxer.h>
11
12#include <packager/media/base/muxer_options.h>
13#include <packager/media/event/muxer_listener.h>
14
15namespace shaka {
16namespace media {
17namespace webm {
18
19SingleSegmentSegmenter::SingleSegmentSegmenter(const MuxerOptions& options)
20 : Segmenter(options), init_end_(0), index_start_(0) {}
21
22SingleSegmentSegmenter::~SingleSegmentSegmenter() {}
23
24Status SingleSegmentSegmenter::FinalizeSegment(int64_t start_timestamp,
25 int64_t duration_timestamp,
26 bool is_subsegment,
27 int64_t segment_number) {
28 Status status = Segmenter::FinalizeSegment(
29 start_timestamp, duration_timestamp, is_subsegment, segment_number);
30 if (!status.ok())
31 return status;
32 // No-op for subsegment in single segment mode.
33 if (is_subsegment)
34 return Status::OK;
35 CHECK(cluster());
36 if (!cluster()->Finalize())
37 return Status(error::FILE_FAILURE, "Error finalizing cluster.");
38 if (muxer_listener()) {
39 const uint64_t size = cluster()->Size();
40 muxer_listener()->OnNewSegment(options().output_file_name, start_timestamp,
41 duration_timestamp, size, segment_number);
42 }
43 return Status::OK;
44}
45
46bool SingleSegmentSegmenter::GetInitRangeStartAndEnd(uint64_t* start,
47 uint64_t* end) {
48 *start = 0;
49 *end = init_end_;
50 return true;
51}
52
53bool SingleSegmentSegmenter::GetIndexRangeStartAndEnd(uint64_t* start,
54 uint64_t* end) {
55 *start = index_start_;
56 *end = index_end_;
57 return true;
58}
59
60std::vector<Range> SingleSegmentSegmenter::GetSegmentRanges() {
61 std::vector<Range> ranges;
62 if (cues()->cue_entries_size() == 0) {
63 return ranges;
64 }
65 for (int32_t i = 0; i < cues()->cue_entries_size() - 1; ++i) {
66 const mkvmuxer::CuePoint* cue_point = cues()->GetCueByIndex(i);
67 Range r;
68 // Cue point cluster position is relative to segment payload pos.
69 r.start = segment_payload_pos() + cue_point->cluster_pos();
70 r.end =
71 segment_payload_pos() + cues()->GetCueByIndex(i + 1)->cluster_pos() - 1;
72 ranges.push_back(r);
73 }
74
75 Range last_range;
76 const mkvmuxer::CuePoint* last_cue_point =
77 cues()->GetCueByIndex(cues()->cue_entries_size() - 1);
78 last_range.start = segment_payload_pos() + last_cue_point->cluster_pos();
79 last_range.end = last_range.start + cluster()->Size() - 1;
80 ranges.push_back(last_range);
81 return ranges;
82}
83
84Status SingleSegmentSegmenter::DoInitialize() {
85 if (!writer_) {
86 std::unique_ptr<MkvWriter> writer(new MkvWriter);
87 Status status = writer->Open(options().output_file_name);
88 if (!status.ok())
89 return status;
90 writer_ = std::move(writer);
91 }
92
93 Status ret = WriteSegmentHeader(0, writer_.get());
94 init_end_ = writer_->Position() - 1;
95 seek_head()->set_cluster_pos(init_end_ + 1 - segment_payload_pos());
96 return ret;
97}
98
99Status SingleSegmentSegmenter::DoFinalize() {
100 // Write the Cues to the end of the file.
101 index_start_ = writer_->Position();
102 seek_head()->set_cues_pos(index_start_ - segment_payload_pos());
103 if (!cues()->Write(writer_.get()))
104 return Status(error::FILE_FAILURE, "Error writing Cues data.");
105
106 // The WebM index is at the end of the file.
107 index_end_ = writer_->Position() - 1;
108 writer_->Position(0);
109
110 Status status = WriteSegmentHeader(index_end_ + 1, writer_.get());
111 status.Update(writer_->Close());
112 return status;
113}
114
115Status SingleSegmentSegmenter::NewSegment(int64_t start_timestamp,
116 bool is_subsegment) {
117 // No-op for subsegment in single segment mode.
118 if (is_subsegment)
119 return Status::OK;
120 // Create a new Cue point.
121 uint64_t position = writer_->Position();
122 int64_t start_timecode = FromBmffTimestamp(start_timestamp);
123
124 mkvmuxer::CuePoint* cue_point = new mkvmuxer::CuePoint;
125 cue_point->set_time(start_timecode);
126 cue_point->set_track(track_id());
127 cue_point->set_cluster_pos(position - segment_payload_pos());
128 if (!cues()->AddCue(cue_point))
129 return Status(error::INTERNAL_ERROR, "Error adding CuePoint.");
130
131 return SetCluster(start_timecode, position, writer_.get());
132}
133
134} // namespace webm
135} // namespace media
136} // namespace shaka
All the methods that are virtual are virtual for mocking.