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 <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
18namespace shaka {
19namespace media {
20namespace {
21const bool kInitialEncryptionInfo = true;
22const int64_t kStartTime = 0;
23} // namespace
24
25Muxer::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
33Muxer::~Muxer() {}
34
35void Muxer::Cancel() {
36 cancelled_ = true;
37}
38
39void Muxer::SetMuxerListener(std::unique_ptr<MuxerListener> muxer_listener) {
40 muxer_listener_ = std::move(muxer_listener);
41}
42
43void Muxer::SetProgressListener(
44 std::unique_ptr<ProgressListener> progress_listener) {
45 progress_listener_ = std::move(progress_listener);
46}
47
48Status 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
106Status Muxer::OnFlushRequest(size_t input_stream_index) {
107 UNUSED(input_stream_index);
108 return Finalize();
109}
110
111Status Muxer::AddMediaSample(size_t stream_id, const MediaSample& sample) {
112 UNUSED(stream_id);
113 UNUSED(sample);
114 return Status::OK;
115}
116
117Status Muxer::AddTextSample(size_t stream_id, const TextSample& sample) {
118 UNUSED(stream_id);
119 UNUSED(sample);
120 return Status::OK;
121}
122
123Status 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.
All the methods that are virtual are virtual for mocking.