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