1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
media / filters / decrypting_demuxer_stream.h [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_FILTERS_DECRYPTING_DEMUXER_STREAM_H_
#define MEDIA_FILTERS_DECRYPTING_DEMUXER_STREAM_H_
#include <optional>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/callback_registry.h"
#include "media/base/cdm_context.h"
#include "media/base/decryptor.h"
#include "media/base/demuxer_stream.h"
#include "media/base/pipeline_status.h"
#include "media/base/video_decoder_config.h"
#include "media/base/waiting.h"
namespace base {
class SequencedTaskRunner;
}
namespace media {
class CdmContext;
class DecoderBuffer;
class MediaLog;
// Decryptor-based DemuxerStream implementation that converts a potentially
// encrypted demuxer stream to a clear demuxer stream.
// All public APIs and callbacks are trampolined to the |task_runner_| so
// that no locks are required for thread safety.
class MEDIA_EXPORT DecryptingDemuxerStream : public DemuxerStream {
public:
DecryptingDemuxerStream(
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
MediaLog* media_log,
const WaitingCB& waiting_cb);
DecryptingDemuxerStream(const DecryptingDemuxerStream&) = delete;
DecryptingDemuxerStream& operator=(const DecryptingDemuxerStream&) = delete;
// Cancels all pending operations immediately and fires all pending callbacks.
~DecryptingDemuxerStream() override;
// |stream| must be encrypted and |cdm_context| must be non-null.
void Initialize(DemuxerStream* stream,
CdmContext* cdm_context,
PipelineStatusCallback status_cb);
// Cancels all pending operations and fires all pending callbacks. If in
// kPendingDemuxerRead or kPendingDecrypt state, waits for the pending
// operation to finish before satisfying |closure|. Sets the state to
// kUninitialized if |this| hasn't been initialized, or to kIdle otherwise.
void Reset(base::OnceClosure closure);
// Returns the name of this class for logging purpose.
std::string GetDisplayName() const;
// DemuxerStream implementation.
void Read(uint32_t count, ReadCB read_cb) override;
AudioDecoderConfig audio_decoder_config() override;
VideoDecoderConfig video_decoder_config() override;
Type type() const override;
StreamLiveness liveness() const override;
void EnableBitstreamConverter() override;
bool SupportsConfigChanges() override;
// Returns whether the stream has clear lead.
bool HasClearLead() const;
private:
// See this link for a detailed state diagram: http://shortn/_1nXgoVIrps
// Each line has a number that corresponds to an action, status or function
// that results in a state change. These actions, etc are all listed below.
// NOTE: invoking Reset() will cause a transition from any state except
// kUninitialized to the kIdle state.
//
// +----------------+ +---------------------------------+
// | kUninitialized | | Any State Except kUninitialized |
// +----------------+ +---------------------------------+
// | |
// 0 7
// v v
// +-------+ +-------+
// | kIdle |<-------+-+ | kIdle |
// +-------+ | | +-------+
// | | |
// 1 4 5
// v | |
// +---------------------+ | |
// | kPendingDemuxerRead |-+ |
// +---------------------+ |
// | |
// 2 |
// v |
// +-----------------+ |
// +->| kPendingDecrypt |-----+
// | +-----------------+
// | |
// 6 3
// | v
// | +----------------+
// +---| kWaitingForKey |
// +----------------+
//
// 1) Read()
// 2) Has encrypted buffer
// 3) kNoKey
// 4) kConfigChanged, kAborted, has clear buffer or end of stream
// 5) kSuccess or kAborted
// 6) OnKeyAdded()
// 7) Reset()
enum State {
kUninitialized = 0,
kIdle,
kPendingDemuxerRead,
kPendingDecrypt,
kWaitingForKey
};
void OnBuffersReadFromDemuxerStream(
DemuxerStream::Status status,
DemuxerStream::DecoderBufferVector buffers);
// Callback for DemuxerStream::Read().
void OnBufferReadFromDemuxerStream(DemuxerStream::Status status,
scoped_refptr<DecoderBuffer> buffer);
void DecryptPendingBuffer();
// Callback for Decryptor::Decrypt().
void OnBufferDecrypted(Decryptor::Status status,
scoped_refptr<DecoderBuffer> decrypted_buffer);
// Callback for the CDM to notify |this|.
void OnCdmContextEvent(CdmContext::Event event);
// Resets decoder and calls |reset_cb_|.
void DoReset();
// Returns Decryptor::StreamType converted from |stream_type_|.
Decryptor::StreamType GetDecryptorStreamType() const;
// Creates and initializes either |audio_config_| or |video_config_| based on
// |demuxer_stream_|.
void InitializeDecoderConfig();
// Completes traces for various pending states.
void CompletePendingDecrypt(Decryptor::Status status);
void CompleteWaitingForDecryptionKey();
void LogMetadata();
scoped_refptr<base::SequencedTaskRunner> task_runner_;
SEQUENCE_CHECKER(sequence_checker_);
const raw_ptr<MediaLog> media_log_;
WaitingCB waiting_cb_;
State state_ = kUninitialized;
PipelineStatusCallback init_cb_;
ReadCB read_cb_;
base::OnceClosure reset_cb_;
// Pointer to the input demuxer stream that will feed us encrypted buffers.
raw_ptr<DemuxerStream> demuxer_stream_ = nullptr;
AudioDecoderConfig audio_config_;
VideoDecoderConfig video_config_;
raw_ptr<Decryptor> decryptor_ = nullptr;
std::optional<bool> has_clear_lead_;
bool switched_clear_to_encrypted_ = false;
// The buffer returned by the demuxer that needs to be decrypted.
scoped_refptr<media::DecoderBuffer> pending_buffer_to_decrypt_;
// Indicates the situation where new key is added during pending decryption
// (in other words, this variable can only be set in state kPendingDecrypt).
// If this variable is true and kNoKey is returned then we need to try
// decrypting again in case the newly added key is the correct decryption key.
bool key_added_while_decrypt_pending_ = false;
// To keep the CdmContext event callback registered.
std::unique_ptr<CallbackRegistration> event_cb_registration_;
base::WeakPtrFactory<DecryptingDemuxerStream> weak_factory_{this};
};
} // namespace media
#endif // MEDIA_FILTERS_DECRYPTING_DEMUXER_STREAM_H_