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