decrypting_video_decoder.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
1// Copyright (c) 2012 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/filters/decrypting_video_decoder.h"
6
7#include "base/bind.h"
8#include "base/callback_helpers.h"
9#include "base/debug/trace_event.h"
10#include "base/location.h"
11#include "base/logging.h"
12#include "base/message_loop/message_loop_proxy.h"
13#include "media/base/bind_to_loop.h"
14#include "media/base/decoder_buffer.h"
15#include "media/base/decryptor.h"
16#include "media/base/pipeline.h"
17#include "media/base/video_decoder_config.h"
18#include "media/base/video_frame.h"
19
20namespace media {
21
22DecryptingVideoDecoder::DecryptingVideoDecoder(
23    const scoped_refptr<base::MessageLoopProxy>& message_loop,
24    const SetDecryptorReadyCB& set_decryptor_ready_cb)
25    : message_loop_(message_loop),
26      weak_factory_(this),
27      state_(kUninitialized),
28      set_decryptor_ready_cb_(set_decryptor_ready_cb),
29      decryptor_(NULL),
30      key_added_while_decode_pending_(false),
31      trace_id_(0) {
32}
33
34void DecryptingVideoDecoder::Initialize(const VideoDecoderConfig& config,
35                                        const PipelineStatusCB& status_cb) {
36  DVLOG(2) << "Initialize()";
37  DCHECK(message_loop_->BelongsToCurrentThread());
38  DCHECK(state_ == kUninitialized ||
39         state_ == kIdle ||
40         state_ == kDecodeFinished) << state_;
41  DCHECK(read_cb_.is_null());
42  DCHECK(reset_cb_.is_null());
43  DCHECK(config.IsValidConfig());
44  DCHECK(config.is_encrypted());
45
46  init_cb_ = BindToCurrentLoop(status_cb);
47  weak_this_ = weak_factory_.GetWeakPtr();
48  config_ = config;
49
50  if (state_ == kUninitialized) {
51    state_ = kDecryptorRequested;
52    set_decryptor_ready_cb_.Run(BindToCurrentLoop(base::Bind(
53        &DecryptingVideoDecoder::SetDecryptor, weak_this_)));
54    return;
55  }
56
57  // Reinitialization.
58  decryptor_->DeinitializeDecoder(Decryptor::kVideo);
59  state_ = kPendingDecoderInit;
60  decryptor_->InitializeVideoDecoder(config, BindToCurrentLoop(base::Bind(
61      &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
62}
63
64void DecryptingVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
65                                    const ReadCB& read_cb) {
66  DVLOG(3) << "Decode()";
67  DCHECK(message_loop_->BelongsToCurrentThread());
68  DCHECK(state_ == kIdle ||
69         state_ == kDecodeFinished ||
70         state_ == kError) << state_;
71  DCHECK(!read_cb.is_null());
72  CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
73
74  read_cb_ = BindToCurrentLoop(read_cb);
75
76  if (state_ == kError) {
77    base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
78    return;
79  }
80
81  // Return empty frames if decoding has finished.
82  if (state_ == kDecodeFinished) {
83    base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame());
84    return;
85  }
86
87  pending_buffer_to_decode_ = buffer;
88  state_ = kPendingDecode;
89  DecodePendingBuffer();
90}
91
92void DecryptingVideoDecoder::Reset(const base::Closure& closure) {
93  DVLOG(2) << "Reset() - state: " << state_;
94  DCHECK(message_loop_->BelongsToCurrentThread());
95  DCHECK(state_ == kIdle ||
96         state_ == kPendingDecode ||
97         state_ == kWaitingForKey ||
98         state_ == kDecodeFinished ||
99         state_ == kError) << state_;
100  DCHECK(init_cb_.is_null());  // No Reset() during pending initialization.
101  DCHECK(reset_cb_.is_null());
102
103  reset_cb_ = BindToCurrentLoop(closure);
104
105  decryptor_->ResetDecoder(Decryptor::kVideo);
106
107  // Reset() cannot complete if the read callback is still pending.
108  // Defer the resetting process in this case. The |reset_cb_| will be fired
109  // after the read callback is fired - see DecryptAndDecodeBuffer() and
110  // DeliverFrame().
111  if (state_ == kPendingDecode) {
112    DCHECK(!read_cb_.is_null());
113    return;
114  }
115
116  if (state_ == kWaitingForKey) {
117    DCHECK(!read_cb_.is_null());
118    pending_buffer_to_decode_ = NULL;
119    base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
120  }
121
122  DCHECK(read_cb_.is_null());
123  DoReset();
124}
125
126void DecryptingVideoDecoder::Stop(const base::Closure& closure) {
127  DCHECK(message_loop_->BelongsToCurrentThread());
128  DVLOG(2) << "Stop() - state: " << state_;
129
130  // At this point the render thread is likely paused (in WebMediaPlayerImpl's
131  // Destroy()), so running |closure| can't wait for anything that requires the
132  // render thread to be processing messages to complete (such as PPAPI
133  // callbacks).
134  if (decryptor_) {
135    decryptor_->RegisterNewKeyCB(Decryptor::kVideo, Decryptor::NewKeyCB());
136    decryptor_->DeinitializeDecoder(Decryptor::kVideo);
137    decryptor_ = NULL;
138  }
139  if (!set_decryptor_ready_cb_.is_null())
140    base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
141  pending_buffer_to_decode_ = NULL;
142  if (!init_cb_.is_null())
143    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
144  if (!read_cb_.is_null())
145    base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
146  if (!reset_cb_.is_null())
147    base::ResetAndReturn(&reset_cb_).Run();
148  state_ = kStopped;
149  BindToCurrentLoop(closure).Run();
150}
151
152DecryptingVideoDecoder::~DecryptingVideoDecoder() {
153  DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
154}
155
156void DecryptingVideoDecoder::SetDecryptor(Decryptor* decryptor) {
157  DVLOG(2) << "SetDecryptor()";
158  DCHECK(message_loop_->BelongsToCurrentThread());
159
160  if (state_ == kStopped)
161    return;
162
163  DCHECK_EQ(state_, kDecryptorRequested) << state_;
164  DCHECK(!init_cb_.is_null());
165  DCHECK(!set_decryptor_ready_cb_.is_null());
166  set_decryptor_ready_cb_.Reset();
167
168  if (!decryptor) {
169    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
170    state_ = kStopped;
171    return;
172  }
173
174  decryptor_ = decryptor;
175
176  state_ = kPendingDecoderInit;
177  decryptor_->InitializeVideoDecoder(
178      config_,
179      BindToCurrentLoop(base::Bind(
180          &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
181}
182
183void DecryptingVideoDecoder::FinishInitialization(bool success) {
184  DVLOG(2) << "FinishInitialization()";
185  DCHECK(message_loop_->BelongsToCurrentThread());
186
187  if (state_ == kStopped)
188    return;
189
190  DCHECK_EQ(state_, kPendingDecoderInit) << state_;
191  DCHECK(!init_cb_.is_null());
192  DCHECK(reset_cb_.is_null());  // No Reset() before initialization finished.
193  DCHECK(read_cb_.is_null());  // No Read() before initialization finished.
194
195  if (!success) {
196    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
197    state_ = kStopped;
198    return;
199  }
200
201  decryptor_->RegisterNewKeyCB(Decryptor::kVideo, BindToCurrentLoop(
202      base::Bind(&DecryptingVideoDecoder::OnKeyAdded, weak_this_)));
203
204  // Success!
205  state_ = kIdle;
206  base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
207}
208
209
210void DecryptingVideoDecoder::DecodePendingBuffer() {
211  DCHECK(message_loop_->BelongsToCurrentThread());
212  DCHECK_EQ(state_, kPendingDecode) << state_;
213  TRACE_EVENT_ASYNC_BEGIN0(
214      "eme", "DecryptingVideoDecoder::DecodePendingBuffer", ++trace_id_);
215
216  int buffer_size = 0;
217  if (!pending_buffer_to_decode_->end_of_stream()) {
218    buffer_size = pending_buffer_to_decode_->data_size();
219  }
220
221  decryptor_->DecryptAndDecodeVideo(
222      pending_buffer_to_decode_, BindToCurrentLoop(base::Bind(
223          &DecryptingVideoDecoder::DeliverFrame, weak_this_, buffer_size)));
224}
225
226void DecryptingVideoDecoder::DeliverFrame(
227    int buffer_size,
228    Decryptor::Status status,
229    const scoped_refptr<VideoFrame>& frame) {
230  DVLOG(3) << "DeliverFrame() - status: " << status;
231  DCHECK(message_loop_->BelongsToCurrentThread());
232  TRACE_EVENT_ASYNC_END0(
233      "eme", "DecryptingVideoDecoder::DecodePendingBuffer", trace_id_);
234
235  if (state_ == kStopped)
236    return;
237
238  DCHECK_EQ(state_, kPendingDecode) << state_;
239  DCHECK(!read_cb_.is_null());
240  DCHECK(pending_buffer_to_decode_.get());
241
242  bool need_to_try_again_if_nokey_is_returned = key_added_while_decode_pending_;
243  key_added_while_decode_pending_ = false;
244
245  scoped_refptr<DecoderBuffer> scoped_pending_buffer_to_decode =
246      pending_buffer_to_decode_;
247  pending_buffer_to_decode_ = NULL;
248
249  if (!reset_cb_.is_null()) {
250    base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
251    DoReset();
252    return;
253  }
254
255  DCHECK_EQ(status == Decryptor::kSuccess, frame.get() != NULL);
256
257  if (status == Decryptor::kError) {
258    DVLOG(2) << "DeliverFrame() - kError";
259    state_ = kError;
260    base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
261    return;
262  }
263
264  if (status == Decryptor::kNoKey) {
265    DVLOG(2) << "DeliverFrame() - kNoKey";
266    // Set |pending_buffer_to_decode_| back as we need to try decoding the
267    // pending buffer again when new key is added to the decryptor.
268    pending_buffer_to_decode_ = scoped_pending_buffer_to_decode;
269
270    if (need_to_try_again_if_nokey_is_returned) {
271      // The |state_| is still kPendingDecode.
272      DecodePendingBuffer();
273      return;
274    }
275
276    state_ = kWaitingForKey;
277    return;
278  }
279
280  if (status == Decryptor::kNeedMoreData) {
281    DVLOG(2) << "DeliverFrame() - kNeedMoreData";
282    if (scoped_pending_buffer_to_decode->end_of_stream()) {
283      state_ = kDecodeFinished;
284      base::ResetAndReturn(&read_cb_).Run(
285          kOk, media::VideoFrame::CreateEmptyFrame());
286      return;
287    }
288
289    state_ = kIdle;
290    base::ResetAndReturn(&read_cb_).Run(kNotEnoughData, NULL);
291    return;
292  }
293
294  DCHECK_EQ(status, Decryptor::kSuccess);
295  // No frame returned with kSuccess should be end-of-stream frame.
296  DCHECK(!frame->IsEndOfStream());
297  state_ = kIdle;
298  base::ResetAndReturn(&read_cb_).Run(kOk, frame);
299}
300
301void DecryptingVideoDecoder::OnKeyAdded() {
302  DVLOG(2) << "OnKeyAdded()";
303  DCHECK(message_loop_->BelongsToCurrentThread());
304
305  if (state_ == kPendingDecode) {
306    key_added_while_decode_pending_ = true;
307    return;
308  }
309
310  if (state_ == kWaitingForKey) {
311    state_ = kPendingDecode;
312    DecodePendingBuffer();
313  }
314}
315
316void DecryptingVideoDecoder::DoReset() {
317  DCHECK(init_cb_.is_null());
318  DCHECK(read_cb_.is_null());
319  state_ = kIdle;
320  base::ResetAndReturn(&reset_cb_).Run();
321}
322
323}  // namespace media
324