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