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