Shaka Packager SDK
muxer.cc
1 // Copyright 2014 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/muxer.h>
8 
9 #include <algorithm>
10 #include <chrono>
11 
12 #include <packager/macros/compiler.h>
13 #include <packager/macros/logging.h>
14 #include <packager/macros/status.h>
15 #include <packager/media/base/media_sample.h>
16 #include <packager/media/base/muxer_util.h>
17 
18 namespace shaka {
19 namespace media {
20 namespace {
21 const bool kInitialEncryptionInfo = true;
22 const int64_t kStartTime = 0;
23 } // namespace
24 
25 Muxer::Muxer(const MuxerOptions& options)
26  : options_(options), clock_(new Clock) {
27  // "$" is only allowed if the output file name is a template, which is used to
28  // support one file per Representation per Period when there are Ad Cues.
29  if (options_.output_file_name.find("$") != std::string::npos)
30  output_file_template_ = options_.output_file_name;
31 }
32 
33 Muxer::~Muxer() {}
34 
35 void Muxer::Cancel() {
36  cancelled_ = true;
37 }
38 
39 void Muxer::SetMuxerListener(std::unique_ptr<MuxerListener> muxer_listener) {
40  muxer_listener_ = std::move(muxer_listener);
41 }
42 
43 void Muxer::SetProgressListener(
44  std::unique_ptr<ProgressListener> progress_listener) {
45  progress_listener_ = std::move(progress_listener);
46 }
47 
48 Status Muxer::Process(std::unique_ptr<StreamData> stream_data) {
49  Status status;
50  switch (stream_data->stream_data_type) {
51  case StreamDataType::kStreamInfo:
52  streams_.push_back(std::move(stream_data->stream_info));
53  return ReinitializeMuxer(kStartTime);
54  case StreamDataType::kSegmentInfo: {
55  const auto& segment_info = *stream_data->segment_info;
56  if (muxer_listener_ && segment_info.is_encrypted) {
57  const EncryptionConfig* encryption_config =
58  segment_info.key_rotation_encryption_config.get();
59  // Only call OnEncryptionInfoReady again when key updates.
60  if (encryption_config && encryption_config->key_id != current_key_id_) {
61  muxer_listener_->OnEncryptionInfoReady(
62  !kInitialEncryptionInfo, encryption_config->protection_scheme,
63  encryption_config->key_id, encryption_config->constant_iv,
64  encryption_config->key_system_info);
65  current_key_id_ = encryption_config->key_id;
66  }
67  if (!encryption_started_) {
68  encryption_started_ = true;
69  muxer_listener_->OnEncryptionStart();
70  }
71  }
72  return FinalizeSegment(stream_data->stream_index, segment_info);
73  }
74  case StreamDataType::kMediaSample:
75  return AddMediaSample(stream_data->stream_index,
76  *stream_data->media_sample);
77  case StreamDataType::kTextSample:
78  return AddTextSample(stream_data->stream_index,
79  *stream_data->text_sample);
80  case StreamDataType::kCueEvent:
81  if (muxer_listener_) {
82  const int64_t time_scale =
83  streams_[stream_data->stream_index]->time_scale();
84  const double time_in_seconds = stream_data->cue_event->time_in_seconds;
85  const int64_t scaled_time =
86  static_cast<int64_t>(time_in_seconds * time_scale);
87  muxer_listener_->OnCueEvent(scaled_time,
88  stream_data->cue_event->cue_data);
89 
90  // Finalize and re-initialize Muxer to generate different content files.
91  if (!output_file_template_.empty()) {
92  RETURN_IF_ERROR(Finalize());
93  RETURN_IF_ERROR(ReinitializeMuxer(scaled_time));
94  }
95  }
96  break;
97  default:
98  VLOG(3) << "Stream data type "
99  << static_cast<int>(stream_data->stream_data_type) << " ignored.";
100  break;
101  }
102  // No dispatch for muxer.
103  return Status::OK;
104 }
105 
106 Status Muxer::OnFlushRequest(size_t input_stream_index) {
107  UNUSED(input_stream_index);
108  return Finalize();
109 }
110 
111 Status Muxer::AddMediaSample(size_t stream_id, const MediaSample& sample) {
112  UNUSED(stream_id);
113  UNUSED(sample);
114  return Status::OK;
115 }
116 
117 Status Muxer::AddTextSample(size_t stream_id, const TextSample& sample) {
118  UNUSED(stream_id);
119  UNUSED(sample);
120  return Status::OK;
121 }
122 
123 Status Muxer::ReinitializeMuxer(int64_t timestamp) {
124  if (muxer_listener_ && streams_.back()->is_encrypted()) {
125  const EncryptionConfig& encryption_config =
126  streams_.back()->encryption_config();
127  muxer_listener_->OnEncryptionInfoReady(
128  kInitialEncryptionInfo, encryption_config.protection_scheme,
129  encryption_config.key_id, encryption_config.constant_iv,
130  encryption_config.key_system_info);
131  current_key_id_ = encryption_config.key_id;
132  }
133  if (!output_file_template_.empty()) {
134  // Update |output_file_name| with an actual file name, which will be used by
135  // the subclasses.
136  options_.output_file_name =
137  GetSegmentName(output_file_template_, timestamp, output_file_index_++,
138  options_.bandwidth);
139  }
140  return InitializeMuxer();
141 }
142 
143 } // namespace media
144 } // namespace shaka
Class to hold a media sample.
Definition: media_sample.h:25
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66