1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/mojo/services/mojo_decryptor_service.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "media/base/audio_decoder_config.h"
12 #include "media/base/cdm_context.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/decryptor.h"
15 #include "media/base/video_decoder_config.h"
16 #include "media/base/video_frame.h"
17 #include "media/mojo/common/media_type_converters.h"
18 #include "media/mojo/common/mojo_decoder_buffer_converter.h"
19 #include "media/mojo/common/mojo_shared_buffer_video_frame.h"
20 #include "media/mojo/mojom/demuxer_stream.mojom.h"
21 #include "media/mojo/services/mojo_cdm_service_context.h"
22 #include "mojo/public/cpp/bindings/pending_remote.h"
23 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
24
25 namespace media {
26
27 namespace {
28
29 // A mojom::FrameResourceReleaser implementation. This object is created when
30 // DecryptAndDecodeVideo() returns a shared memory video frame, and holds
31 // on to the local frame. When MojoDecryptor is done using the frame,
32 // the connection should be broken and this will free the shared resources
33 // associated with the frame.
34 class FrameResourceReleaserImpl final : public mojom::FrameResourceReleaser {
35 public:
FrameResourceReleaserImpl(scoped_refptr<VideoFrame> frame)36 explicit FrameResourceReleaserImpl(scoped_refptr<VideoFrame> frame)
37 : frame_(std::move(frame)) {
38 DVLOG(3) << __func__;
39 DCHECK_EQ(VideoFrame::STORAGE_MOJO_SHARED_BUFFER, frame_->storage_type());
40 }
~FrameResourceReleaserImpl()41 ~FrameResourceReleaserImpl() override { DVLOG(3) << __func__; }
42
43 private:
44 scoped_refptr<VideoFrame> frame_;
45
46 DISALLOW_COPY_AND_ASSIGN(FrameResourceReleaserImpl);
47 };
48
49 const char kInvalidStateMessage[] = "MojoDecryptorService - invalid state";
50
51 } // namespace
52
MojoDecryptorService(media::Decryptor * decryptor,std::unique_ptr<CdmContextRef> cdm_context_ref)53 MojoDecryptorService::MojoDecryptorService(
54 media::Decryptor* decryptor,
55 std::unique_ptr<CdmContextRef> cdm_context_ref)
56 : decryptor_(decryptor), cdm_context_ref_(std::move(cdm_context_ref)) {
57 DVLOG(1) << __func__;
58 DCHECK(decryptor_);
59 // |cdm_context_ref_| could be null, in which case the owner of |this| will
60 // make sure |decryptor_| is always valid.
61 weak_this_ = weak_factory_.GetWeakPtr();
62 }
63
~MojoDecryptorService()64 MojoDecryptorService::~MojoDecryptorService() {
65 DVLOG(1) << __func__;
66 }
67
Initialize(mojo::ScopedDataPipeConsumerHandle audio_pipe,mojo::ScopedDataPipeConsumerHandle video_pipe,mojo::ScopedDataPipeConsumerHandle decrypt_pipe,mojo::ScopedDataPipeProducerHandle decrypted_pipe)68 void MojoDecryptorService::Initialize(
69 mojo::ScopedDataPipeConsumerHandle audio_pipe,
70 mojo::ScopedDataPipeConsumerHandle video_pipe,
71 mojo::ScopedDataPipeConsumerHandle decrypt_pipe,
72 mojo::ScopedDataPipeProducerHandle decrypted_pipe) {
73 DVLOG(1) << __func__;
74
75 if (has_initialize_been_called_) {
76 mojo::ReportBadMessage(kInvalidStateMessage);
77 return;
78 }
79 has_initialize_been_called_ = true;
80
81 audio_buffer_reader_.reset(
82 new MojoDecoderBufferReader(std::move(audio_pipe)));
83 video_buffer_reader_.reset(
84 new MojoDecoderBufferReader(std::move(video_pipe)));
85 decrypt_buffer_reader_.reset(
86 new MojoDecoderBufferReader(std::move(decrypt_pipe)));
87 decrypted_buffer_writer_.reset(
88 new MojoDecoderBufferWriter(std::move(decrypted_pipe)));
89 }
90
Decrypt(StreamType stream_type,mojom::DecoderBufferPtr encrypted,DecryptCallback callback)91 void MojoDecryptorService::Decrypt(StreamType stream_type,
92 mojom::DecoderBufferPtr encrypted,
93 DecryptCallback callback) {
94 DVLOG(3) << __func__;
95
96 if (!decrypt_buffer_reader_) {
97 mojo::ReportBadMessage(kInvalidStateMessage);
98 return;
99 }
100
101 decrypt_buffer_reader_->ReadDecoderBuffer(
102 std::move(encrypted),
103 base::BindOnce(&MojoDecryptorService::OnReadDone, weak_this_, stream_type,
104 std::move(callback)));
105 }
106
CancelDecrypt(StreamType stream_type)107 void MojoDecryptorService::CancelDecrypt(StreamType stream_type) {
108 DVLOG(2) << __func__;
109 decryptor_->CancelDecrypt(stream_type);
110 }
111
InitializeAudioDecoder(const AudioDecoderConfig & config,InitializeAudioDecoderCallback callback)112 void MojoDecryptorService::InitializeAudioDecoder(
113 const AudioDecoderConfig& config,
114 InitializeAudioDecoderCallback callback) {
115 DVLOG(1) << __func__;
116 decryptor_->InitializeAudioDecoder(
117 config, base::BindOnce(&MojoDecryptorService::OnAudioDecoderInitialized,
118 weak_this_, std::move(callback)));
119 }
120
InitializeVideoDecoder(const VideoDecoderConfig & config,InitializeVideoDecoderCallback callback)121 void MojoDecryptorService::InitializeVideoDecoder(
122 const VideoDecoderConfig& config,
123 InitializeVideoDecoderCallback callback) {
124 DVLOG(2) << __func__;
125 decryptor_->InitializeVideoDecoder(
126 config, base::BindOnce(&MojoDecryptorService::OnVideoDecoderInitialized,
127 weak_this_, std::move(callback)));
128 }
129
DecryptAndDecodeAudio(mojom::DecoderBufferPtr encrypted,DecryptAndDecodeAudioCallback callback)130 void MojoDecryptorService::DecryptAndDecodeAudio(
131 mojom::DecoderBufferPtr encrypted,
132 DecryptAndDecodeAudioCallback callback) {
133 DVLOG(3) << __func__;
134
135 if (!audio_buffer_reader_) {
136 mojo::ReportBadMessage(kInvalidStateMessage);
137 return;
138 }
139
140 audio_buffer_reader_->ReadDecoderBuffer(
141 std::move(encrypted), base::BindOnce(&MojoDecryptorService::OnAudioRead,
142 weak_this_, std::move(callback)));
143 }
144
DecryptAndDecodeVideo(mojom::DecoderBufferPtr encrypted,DecryptAndDecodeVideoCallback callback)145 void MojoDecryptorService::DecryptAndDecodeVideo(
146 mojom::DecoderBufferPtr encrypted,
147 DecryptAndDecodeVideoCallback callback) {
148 DVLOG(3) << __func__;
149
150 if (!video_buffer_reader_) {
151 mojo::ReportBadMessage(kInvalidStateMessage);
152 return;
153 }
154
155 video_buffer_reader_->ReadDecoderBuffer(
156 std::move(encrypted), base::BindOnce(&MojoDecryptorService::OnVideoRead,
157 weak_this_, std::move(callback)));
158 }
159
ResetDecoder(StreamType stream_type)160 void MojoDecryptorService::ResetDecoder(StreamType stream_type) {
161 DVLOG(2) << __func__ << ": stream_type = " << stream_type;
162
163 // Reset the reader so that pending decodes will be dispatched first.
164 if (!GetBufferReader(stream_type))
165 return;
166
167 GetBufferReader(stream_type)
168 ->Flush(base::BindOnce(&MojoDecryptorService::OnReaderFlushDone,
169 weak_this_, stream_type));
170 }
171
DeinitializeDecoder(StreamType stream_type)172 void MojoDecryptorService::DeinitializeDecoder(StreamType stream_type) {
173 DVLOG(2) << __func__;
174 DCHECK(!GetBufferReader(stream_type)->HasPendingReads())
175 << "The decoder should be fully flushed before deinitialized.";
176
177 decryptor_->DeinitializeDecoder(stream_type);
178 }
179
OnReadDone(StreamType stream_type,DecryptCallback callback,scoped_refptr<DecoderBuffer> buffer)180 void MojoDecryptorService::OnReadDone(StreamType stream_type,
181 DecryptCallback callback,
182 scoped_refptr<DecoderBuffer> buffer) {
183 if (!buffer) {
184 std::move(callback).Run(Status::kError, nullptr);
185 return;
186 }
187
188 decryptor_->Decrypt(stream_type, std::move(buffer),
189 base::BindOnce(&MojoDecryptorService::OnDecryptDone,
190 weak_this_, std::move(callback)));
191 }
192
OnDecryptDone(DecryptCallback callback,Status status,scoped_refptr<DecoderBuffer> buffer)193 void MojoDecryptorService::OnDecryptDone(DecryptCallback callback,
194 Status status,
195 scoped_refptr<DecoderBuffer> buffer) {
196 DVLOG_IF(1, status != Status::kSuccess) << __func__ << "(" << status << ")";
197 DVLOG_IF(3, status == Status::kSuccess) << __func__;
198
199 if (!buffer) {
200 DCHECK_NE(status, Status::kSuccess);
201 std::move(callback).Run(status, nullptr);
202 return;
203 }
204
205 mojom::DecoderBufferPtr mojo_buffer =
206 decrypted_buffer_writer_->WriteDecoderBuffer(std::move(buffer));
207 if (!mojo_buffer) {
208 std::move(callback).Run(Status::kError, nullptr);
209 return;
210 }
211
212 std::move(callback).Run(status, std::move(mojo_buffer));
213 }
214
OnAudioDecoderInitialized(InitializeAudioDecoderCallback callback,bool success)215 void MojoDecryptorService::OnAudioDecoderInitialized(
216 InitializeAudioDecoderCallback callback,
217 bool success) {
218 DVLOG(2) << __func__ << "(" << success << ")";
219 std::move(callback).Run(success);
220 }
221
OnVideoDecoderInitialized(InitializeVideoDecoderCallback callback,bool success)222 void MojoDecryptorService::OnVideoDecoderInitialized(
223 InitializeVideoDecoderCallback callback,
224 bool success) {
225 DVLOG(2) << __func__ << "(" << success << ")";
226 std::move(callback).Run(success);
227 }
228
OnAudioRead(DecryptAndDecodeAudioCallback callback,scoped_refptr<DecoderBuffer> buffer)229 void MojoDecryptorService::OnAudioRead(DecryptAndDecodeAudioCallback callback,
230 scoped_refptr<DecoderBuffer> buffer) {
231 if (!buffer) {
232 std::move(callback).Run(Status::kError,
233 std::vector<mojom::AudioBufferPtr>());
234 return;
235 }
236
237 decryptor_->DecryptAndDecodeAudio(
238 std::move(buffer), base::Bind(&MojoDecryptorService::OnAudioDecoded,
239 weak_this_, base::Passed(&callback)));
240 }
241
OnVideoRead(DecryptAndDecodeVideoCallback callback,scoped_refptr<DecoderBuffer> buffer)242 void MojoDecryptorService::OnVideoRead(DecryptAndDecodeVideoCallback callback,
243 scoped_refptr<DecoderBuffer> buffer) {
244 if (!buffer) {
245 std::move(callback).Run(Status::kError, nullptr, mojo::NullRemote());
246 return;
247 }
248
249 decryptor_->DecryptAndDecodeVideo(
250 std::move(buffer), base::Bind(&MojoDecryptorService::OnVideoDecoded,
251 weak_this_, base::Passed(&callback)));
252 }
253
OnReaderFlushDone(StreamType stream_type)254 void MojoDecryptorService::OnReaderFlushDone(StreamType stream_type) {
255 DVLOG(2) << __func__ << ": stream_type = " << stream_type;
256 decryptor_->ResetDecoder(stream_type);
257 }
258
OnAudioDecoded(DecryptAndDecodeAudioCallback callback,Status status,const media::Decryptor::AudioFrames & frames)259 void MojoDecryptorService::OnAudioDecoded(
260 DecryptAndDecodeAudioCallback callback,
261 Status status,
262 const media::Decryptor::AudioFrames& frames) {
263 DVLOG_IF(1, status != Status::kSuccess) << __func__ << "(" << status << ")";
264 DVLOG_IF(3, status == Status::kSuccess) << __func__;
265
266 // Note that the audio data is sent over the mojo pipe. This could be
267 // improved to use shared memory (http://crbug.com/593896).
268 std::vector<mojom::AudioBufferPtr> audio_buffers;
269 for (const auto& frame : frames)
270 audio_buffers.push_back(mojom::AudioBuffer::From(*frame));
271
272 std::move(callback).Run(status, std::move(audio_buffers));
273 }
274
OnVideoDecoded(DecryptAndDecodeVideoCallback callback,Status status,scoped_refptr<VideoFrame> frame)275 void MojoDecryptorService::OnVideoDecoded(
276 DecryptAndDecodeVideoCallback callback,
277 Status status,
278 scoped_refptr<VideoFrame> frame) {
279 DVLOG_IF(1, status != Status::kSuccess)
280 << __func__ << ": status = " << status;
281 DVLOG_IF(3, status == Status::kSuccess) << __func__;
282
283 if (!frame) {
284 DCHECK_NE(status, Status::kSuccess);
285 std::move(callback).Run(status, nullptr, mojo::NullRemote());
286 return;
287 }
288
289 // If |frame| has shared memory that will be passed back, keep the reference
290 // to it until the other side is done with the memory.
291 mojo::PendingRemote<mojom::FrameResourceReleaser> releaser;
292 if (frame->storage_type() == VideoFrame::STORAGE_MOJO_SHARED_BUFFER) {
293 mojo::MakeSelfOwnedReceiver(
294 std::make_unique<FrameResourceReleaserImpl>(frame),
295 releaser.InitWithNewPipeAndPassReceiver());
296 }
297
298 std::move(callback).Run(status, std::move(frame), std::move(releaser));
299 }
300
GetBufferReader(StreamType stream_type) const301 MojoDecoderBufferReader* MojoDecryptorService::GetBufferReader(
302 StreamType stream_type) const {
303 switch (stream_type) {
304 case StreamType::kAudio:
305 return audio_buffer_reader_.get();
306 case StreamType::kVideo:
307 return video_buffer_reader_.get();
308 }
309
310 NOTREACHED() << "Unexpected stream_type: " << stream_type;
311 return nullptr;
312 }
313
314 } // namespace media
315