Shaka Packager SDK
webm_muxer.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/webm_muxer.h>
8 
9 #include <absl/log/check.h>
10 
11 #include <packager/macros/logging.h>
12 #include <packager/media/base/fourccs.h>
13 #include <packager/media/base/media_sample.h>
14 #include <packager/media/base/stream_info.h>
15 #include <packager/media/formats/webm/mkv_writer.h>
16 #include <packager/media/formats/webm/multi_segment_segmenter.h>
17 #include <packager/media/formats/webm/single_segment_segmenter.h>
18 #include <packager/media/formats/webm/two_pass_single_segment_segmenter.h>
19 
20 namespace shaka {
21 namespace media {
22 namespace webm {
23 
24 WebMMuxer::WebMMuxer(const MuxerOptions& options) : Muxer(options) {}
25 WebMMuxer::~WebMMuxer() {}
26 
27 Status WebMMuxer::InitializeMuxer() {
28  CHECK_EQ(streams().size(), 1U);
29 
30  if (streams()[0]->is_encrypted() &&
31  streams()[0]->encryption_config().protection_scheme != FOURCC_cenc) {
32  LOG(ERROR) << "WebM does not support protection scheme other than 'cenc'.";
33  return Status(error::INVALID_ARGUMENT,
34  "WebM does not support protection scheme other than 'cenc'.");
35  }
36 
37  if (!options().segment_template.empty()) {
38  segmenter_.reset(new MultiSegmentSegmenter(options()));
39  } else {
40  segmenter_.reset(new TwoPassSingleSegmentSegmenter(options()));
41  }
42 
43  Status initialized = segmenter_->Initialize(
44  *streams()[0], progress_listener(), muxer_listener());
45  if (!initialized.ok())
46  return initialized;
47 
48  FireOnMediaStartEvent();
49  return Status::OK;
50 }
51 
52 Status WebMMuxer::Finalize() {
53  if (!segmenter_)
54  return Status::OK;
55  Status segmenter_finalized = segmenter_->Finalize();
56 
57  if (!segmenter_finalized.ok())
58  return segmenter_finalized;
59 
60  FireOnMediaEndEvent();
61  LOG(INFO) << "WEBM file '" << options().output_file_name << "' finalized.";
62  return Status::OK;
63 }
64 
65 Status WebMMuxer::AddMediaSample(size_t stream_id, const MediaSample& sample) {
66  DCHECK(segmenter_);
67  DCHECK_EQ(stream_id, 0u);
68  if (sample.pts() < 0) {
69  LOG(ERROR) << "Seeing negative timestamp " << sample.pts();
70  return Status(error::MUXER_FAILURE, "Unsupported negative timestamp.");
71  }
72  return segmenter_->AddSample(sample);
73 }
74 
75 Status WebMMuxer::FinalizeSegment(size_t stream_id,
76  const SegmentInfo& segment_info) {
77  DCHECK(segmenter_);
78  DCHECK_EQ(stream_id, 0u);
79 
80  if (segment_info.key_rotation_encryption_config) {
81  NOTIMPLEMENTED() << "Key rotation is not implemented for WebM.";
82  return Status(error::UNIMPLEMENTED,
83  "Key rotation is not implemented for WebM");
84  }
85  return segmenter_->FinalizeSegment(
86  segment_info.start_timestamp, segment_info.duration,
87  segment_info.is_subsegment, segment_info.segment_number);
88 }
89 
90 void WebMMuxer::FireOnMediaStartEvent() {
91  if (!muxer_listener())
92  return;
93 
94  DCHECK(!streams().empty()) << "Media started without a stream.";
95 
96  const int32_t timescale = streams().front()->time_scale();
97  muxer_listener()->OnMediaStart(options(), *streams().front(), timescale,
98  MuxerListener::kContainerWebM);
99 }
100 
101 void WebMMuxer::FireOnMediaEndEvent() {
102  if (!muxer_listener())
103  return;
104 
105  MuxerListener::MediaRanges media_range;
106 
107  uint64_t init_range_start = 0;
108  uint64_t init_range_end = 0;
109  const bool has_init_range =
110  segmenter_->GetInitRangeStartAndEnd(&init_range_start, &init_range_end);
111  if (has_init_range) {
112  Range r;
113  r.start = init_range_start;
114  r.end = init_range_end;
115  media_range.init_range = r;
116  }
117 
118  uint64_t index_range_start = 0;
119  uint64_t index_range_end = 0;
120  const bool has_index_range = segmenter_->GetIndexRangeStartAndEnd(
121  &index_range_start, &index_range_end);
122  if (has_index_range) {
123  Range r;
124  r.start = index_range_start;
125  r.end = index_range_end;
126  media_range.index_range = r;
127  }
128 
129  media_range.subsegment_ranges = segmenter_->GetSegmentRanges();
130 
131  const float duration_seconds = segmenter_->GetDurationInSeconds();
132  muxer_listener()->OnMediaEnd(media_range, duration_seconds);
133 }
134 
135 } // namespace webm
136 } // namespace media
137 } // namespace shaka
virtual void OnMediaEnd(const MediaRanges &media_ranges, float duration_seconds)=0
virtual void OnMediaStart(const MuxerOptions &muxer_options, const StreamInfo &stream_info, int32_t time_scale, ContainerType container_type)=0
WebMMuxer(const MuxerOptions &options)
Create a WebMMuxer object from MuxerOptions.
Definition: webm_muxer.cc:24
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66
This structure contains the list of configuration options for Muxer.
Definition: muxer_options.h:19