Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: media/filters/android_audio_decoder.cc

Issue 1651673002: Add MediaCodecAudioDecoder implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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/android_audio_decoder.h"
6
7 #include "base/android/build_info.h"
8 #include "base/bind.h"
9 #include "base/callback_helpers.h"
10 #include "base/logging.h"
11 #include "base/thread_task_runner_handle.h"
12
13 #include "media/base/android/sdk_media_codec_bridge.h"
14 #include "media/base/audio_buffer.h"
15 #include "media/base/bind_to_current_loop.h"
16
17 namespace media {
18
19 // Android MediaCodec can only output 16bit PCM audio.
20 const int kBytesPerOutputSample = 2;
21
22 inline const base::TimeDelta DecodePollDelay() {
23 return base::TimeDelta::FromMilliseconds(10);
24 }
25
26 inline const base::TimeDelta NoWaitTimeOut() {
27 return base::TimeDelta::FromMicroseconds(0);
28 }
29
30 inline const base::TimeDelta IdleTimerTimeOut() {
31 return base::TimeDelta::FromSeconds(1);
32 }
33
34 AndroidAudioDecoder::AndroidAudioDecoder()
35 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
36 state_(kStateUninitialized),
37 channel_count_(0),
38 bytes_per_frame_(0),
39 cdm_registration_id_(0),
40 pending_input_buf_index_(-1),
41 weak_factory_(this) {
42 DVLOG(1) << __FUNCTION__;
43 }
44
45 AndroidAudioDecoder::~AndroidAudioDecoder() {
46 DVLOG(1) << __FUNCTION__;
47
48 if (!set_cdm_ready_cb_.is_null())
49 base::ResetAndReturn(&set_cdm_ready_cb_).Run(CdmReadyCB());
50 if (!cdm_attached_cb_.is_null())
51 base::ResetAndReturn(&cdm_attached_cb_).Run(false);
52 if (!init_cb_.is_null())
53 base::ResetAndReturn(&init_cb_).Run(false);
54
55 media_codec_.reset();
56
57 // Report kAborted status for pending EOS and all frames in the input queue.
58 if (!eos_decode_cb_.is_null())
59 base::ResetAndReturn(&eos_decode_cb_).Run(kAborted);
60
61 for (const auto& entry : input_queue_) {
62 entry.second.Run(kAborted);
63 }
64 }
65
66 std::string AndroidAudioDecoder::GetDisplayName() const {
67 return "AndroidAudioDecoder";
68 }
69
70 void AndroidAudioDecoder::Initialize(const AudioDecoderConfig& config,
71 const SetCdmReadyCB& set_cdm_ready_cb,
72 const InitCB& init_cb,
73 const OutputCB& output_cb) {
74 DVLOG(1) << __FUNCTION__ << ": " << config.AsHumanReadableString();
75
76 InitCB bound_init_cb = BindToCurrentLoop(init_cb);
77
78 // Keep this consistent with AudioCodecBridge.
79 const bool is_codec_supported = config.codec() == kCodecVorbis ||
80 config.codec() == kCodecAAC ||
81 config.codec() == kCodecOpus;
82 if (!is_codec_supported) {
83 DVLOG(1) << "Unsuported codec " << GetCodecName(config.codec());
84 bound_init_cb.Run(false);
85 return;
86 }
87
88 config_ = config;
89 init_cb_ = bound_init_cb;
90 output_cb_ = BindToCurrentLoop(output_cb);
91
92 // The following derived parameters are frequently used.
93 channel_count_ = ChannelLayoutToChannelCount(config_.channel_layout());
94 bytes_per_frame_ = kBytesPerOutputSample * channel_count_;
95
96 if (config.is_encrypted()) {
97 // Delay configuration until we get MediaCrypto object.
98 set_cdm_ready_cb_ = set_cdm_ready_cb;
99 set_cdm_ready_cb_.Run(BindToCurrentLoop(
100 base::Bind(&AndroidAudioDecoder::SetCdm, weak_factory_.GetWeakPtr())));
101 SetState(kStateWaitingForCDM);
102 return;
103 }
104
105 const bool success = ConfigureMediaCodec();
106
107 SetState(success ? kStateReady : kStateUninitialized);
108 base::ResetAndReturn(&init_cb_).Run(success);
109 }
110
111 void AndroidAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
112 const DecodeCB& decode_cb) {
113 DecodeCB bound_decode_cb = BindToCurrentLoop(decode_cb);
114
115 if (state_ == kStateError) {
116 DVLOG(2) << __FUNCTION__ << " " << buffer->AsShortString()
117 << ": Error state, dropping buffer";
118 bound_decode_cb.Run(kDecodeError);
119 return;
120 }
121
122 DVLOG(2) << __FUNCTION__ << " " << buffer->AsShortString();
123
124 input_queue_.push_back(std::make_pair(buffer, bound_decode_cb));
125
126 DoIOTask();
127 }
128
129 void AndroidAudioDecoder::Reset(const base::Closure& closure) {
130 DVLOG(1) << __FUNCTION__;
131
132 io_timer_.Stop();
133
134 if (!eos_decode_cb_.is_null())
135 base::ResetAndReturn(&eos_decode_cb_).Run(kAborted);
136
137 // Report kAborted status for all frames in the input queue.
138 for (const auto& entry : input_queue_) {
139 entry.second.Run(kAborted);
140 }
141 input_queue_.clear();
142
143 // Flush if we can, otherwise completely recreate and reconfigure the codec.
144 // Prior to JB-MR2, flush() had several bugs (b/8125974, b/8347958).
145 bool success = false;
146 if (state_ != kStateError && state_ != kStateDrained &&
147 base::android::BuildInfo::GetInstance()->sdk_int() < 18) {
148 // media_codec_->Reset() calls MediaCodec.flush().
149 success = (media_codec_->Reset() == MEDIA_CODEC_OK);
150 }
151
152 if (!success) {
153 media_codec_.reset();
154 success = ConfigureMediaCodec();
155 }
156
157 SetState(success ? kStateReady : kStateError);
158
159 task_runner_->PostTask(FROM_HERE, closure);
160 }
161
162 void AndroidAudioDecoder::SetCdm(CdmContext* cdm_context,
163 const CdmAttachedCB& cdm_attached_cb) {
164 DVLOG(1) << __FUNCTION__;
165
166 DCHECK(!init_cb_.is_null());
167 DCHECK(!set_cdm_ready_cb_.is_null());
168 set_cdm_ready_cb_.Reset();
169
170 if (!cdm_context || cdm_context->GetCdmId() == CdmContext::kInvalidCdmId) {
171 DVLOG(1) << __FUNCTION__ << ": CDM ID not available.";
172 cdm_attached_cb.Run(false);
173 base::ResetAndReturn(&init_cb_).Run(false);
174 SetState(kStateUninitialized);
175 return;
176 }
177
178 if (cdm_) {
179 NOTREACHED() << "We do not support resetting CDM.";
180 cdm_attached_cb.Run(false);
181 base::ResetAndReturn(&init_cb_).Run(false);
182 SetState(kStateUninitialized);
183 return;
184 }
185
186 // TODO(timav): get |cdm_| from cdm_context->GetCdmId().
187
188 // #define CDM_IN_ANDROID_AUDIO_DECODE
189 #if !defined(CDM_IN_ANDROID_AUDIO_DECODER)
190 NOTIMPLEMENTED();
191 cdm_attached_cb.Run(false);
192 base::ResetAndReturn(&init_cb_).Run(false);
193 SetState(kStateUninitialized);
194 #else
195 // cdm_ = media::MojoCdmService::GetCdm(cdm_id);
196 // DCHECK(cdm_);
197
198 // On Android platform the MediaKeys will be its subclass MediaDrmBridge.
199 MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get());
200
201 // Register CDM callbacks. The callbacks registered will be posted back to
202 // this thread via BindToCurrentLoop.
203
204 // Since |this| holds a reference to the |cdm_|, by the time the CDM is
205 // destructed, UnregisterPlayer() must have been called and |this| has been
206 // destructed as well. So the |cdm_unset_cb| will never have a chance to be
207 // called.
208 // TODO(xhwang): Remove |cdm_unset_cb| after it's not used on all platforms.
209 cdm_registration_id_ = drm_bridge->RegisterPlayer(
210 BindToCurrentLoop(base::Bind(&AndroidAudioDecoder::OnKeyAdded,
211 weak_factory_.GetWeakPtr())),
212 base::Bind(&base::DoNothing));
213
214 drm_bridge->SetMediaCryptoReadyCB(BindToCurrentLoop(base::Bind(
215 &AndroidAudioDecoder::OnMediaCryptoReady, weak_factory_.GetWeakPtr())));
216
217 // Postpone cdm_attached_cb.Run() call till CreateMediaCodec() which we can do
218 // after OnMediaCryptoReady().
219 cdm_attached_cb_ = cdm_attached_cb;
220 SetState(kStateWaitingForCrypto);
221 #endif
222 }
223
224 void AndroidAudioDecoder::OnMediaCryptoReady(
225 media::MediaDrmBridge::JavaObjectPtr media_crypto) {
226 DVLOG(1) << __FUNCTION__;
227
228 if (!media_crypto) {
229 LOG(ERROR) << "MediaCrypto is not available, can't play encrypted stream.";
230 base::ResetAndReturn(&cdm_attached_cb_).Run(false);
231 base::ResetAndReturn(&init_cb_).Run(false);
232 SetState(kStateUninitialized);
233 return;
234 }
235
236 DCHECK(!media_crypto->is_null());
237
238 // We assume this is a part of the initialization process, thus MediaCodec
239 // is not created yet.
240 DCHECK(!media_codec_);
241
242 media_crypto_ = std::move(media_crypto);
243
244 // After receiving |media_crypto_| we can configure MediaCodec.
245 const bool success = ConfigureMediaCodec();
246
247 SetState(success ? kStateReady : kStateUninitialized);
248
249 base::ResetAndReturn(&cdm_attached_cb_).Run(success);
250 base::ResetAndReturn(&init_cb_).Run(success);
251 }
252
253 void AndroidAudioDecoder::OnKeyAdded() {
254 DVLOG(1) << __FUNCTION__;
255
256 if (state_ == kStateWaitingForKey)
257 SetState(kStateReady);
258
259 DoIOTask();
260 }
261
262 void AndroidAudioDecoder::DoIOTask() {
263 if (state_ == kStateError)
264 return;
265
266 const bool did_input = QueueInput();
267 const bool did_output = DequeueOutput();
268
269 ManageTimer(did_input || did_output);
270 }
271
272 bool AndroidAudioDecoder::QueueInput() {
273 DVLOG(2) << __FUNCTION__;
274
275 if (input_queue_.empty())
276 return false;
277
278 if (state_ == kStateWaitingForKey)
279 return false;
280
281 if (state_ == kStateDraining)
282 return false;
283
284 scoped_refptr<DecoderBuffer> decoder_buffer = input_queue_.front().first;
285 const DecodeCB& decode_cb = input_queue_.front().second;
286
287 int input_buf_index = pending_input_buf_index_;
288
289 // Do not dequeue a new input buffer if we failed with MEDIA_CODEC_NO_KEY.
290 // That status does not return the input buffer back to the pool of
291 // available input buffers. We have to reuse it in QueueSecureInputBuffer().
292 if (input_buf_index == -1) {
293 media::MediaCodecStatus status =
294 media_codec_->DequeueInputBuffer(NoWaitTimeOut(), &input_buf_index);
295 switch (status) {
296 case media::MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER:
297 return false;
298 case media::MEDIA_CODEC_ERROR:
299 DVLOG(1) << __FUNCTION__ << ": MEDIA_CODEC_ERROR";
300 SetState(kStateError);
301
302 // Report an error to the pipeline.
303 decode_cb.Run(kDecodeError);
304 return false;
305 case media::MEDIA_CODEC_OK:
306 break;
307 default:
308 NOTREACHED() << "Unknown DequeueInputBuffer status " << status;
309 return false;
310 }
311 }
312
313 DCHECK_NE(input_buf_index, -1);
314
315 if (decoder_buffer->end_of_stream()) {
316 media_codec_->QueueEOS(input_buf_index);
317
318 // After queueing EOS we need to flush decoder, i.e. receive this EOS at
319 // the output, and then call corresponding decoder_cb.
320 eos_decode_cb_ = decode_cb;
321 input_queue_.pop_front();
322 SetState(kStateDraining);
323 return true;
324 }
325
326 // Make sure our DecoderBuffer is not EOS, otherwise we can't call any method.
327 DCHECK(!decoder_buffer->end_of_stream());
328
329 media::MediaCodecStatus status;
330 const DecryptConfig* decrypt_config = decoder_buffer->decrypt_config();
331 if (decrypt_config) {
332 // If pending_input_buf_index_ != -1 the input buffer is already filled up,
333 // no need to copy it again.
334 const uint8_t* memory =
335 (pending_input_buf_index_ == -1) ? decoder_buffer->data() : nullptr;
336
337 status = media_codec_->QueueSecureInputBuffer(
338 input_buf_index, memory, decoder_buffer->data_size(),
339 decrypt_config->key_id(), decrypt_config->iv(),
340 decrypt_config->subsamples(), decoder_buffer->timestamp());
341
342 DVLOG(2) << __FUNCTION__
343 << ": QueueInputBuffer: pts:" << decoder_buffer->timestamp()
344 << " status:" << status;
345 } else {
346 status = media_codec_->QueueInputBuffer(
347 input_buf_index, decoder_buffer->data(), decoder_buffer->data_size(),
348 decoder_buffer->timestamp());
349 DVLOG(2) << __FUNCTION__
350 << ": QueueSecureInputBuffer: pts:" << decoder_buffer->timestamp()
351 << " status:" << status;
352 }
353
354 if (status == media::MEDIA_CODEC_NO_KEY) {
355 // Keep trying to enqueue the same input buffer.
356 // The buffer is owned by us (not the MediaCodec) and is filled with data.
357 DVLOG(1) << "QueueSecureInputBuffer failed: MEDIA_CODEC_NO_KEY";
358 pending_input_buf_index_ = input_buf_index;
359 SetState(kStateWaitingForKey);
360 return false;
361 }
362
363 pending_input_buf_index_ = -1;
364
365 // Although audio_decoder.h says "Once the buffer is decoded the decoder calls
366 // |decode_cb|", we call |decode_cb| when the buffer is accepted by
367 // MediaCodec, not when it is completely decoded. It seems consistent to what
368 // other decoders do.
369 decode_cb.Run(kOk);
370 input_queue_.pop_front();
371 return true;
372 }
373
374 bool AndroidAudioDecoder::DequeueOutput() {
liberato (no reviews please) 2016/02/01 15:18:06 DequeueOutput looks like it's an improvement over
375 DVLOG(2) << __FUNCTION__;
376
377 DCHECK(media_codec_);
378
379 MediaCodecStatus status;
380 OutputBufferInfo out;
liberato (no reviews please) 2016/02/01 15:18:06 OutputBufferInfo: good idea for avda.
381 bool work_done = false;
382 do {
383 status = media_codec_->DequeueOutputBuffer(NoWaitTimeOut(), &out.buf_index,
384 &out.offset, &out.size, &out.pts,
385 &out.is_eos, &out.is_key_frame);
386
387 switch (status) {
388 case MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED:
389 // Output buffers are replaced in MediaCodecBridge, nothing to do.
390 DVLOG(2) << __FUNCTION__ << " MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED";
391 work_done = true;
392 break;
393
394 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
395 DVLOG(2) << __FUNCTION__ << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED";
396 OnOutputFormatChanged();
397 work_done = true;
398 break;
399
400 case MEDIA_CODEC_OK:
401 // We got the decoded frame.
402 if (out.is_eos) {
403 media_codec_->ReleaseOutputBuffer(out.buf_index, false);
404
405 DCHECK_EQ(state_, kStateDraining);
406 DCHECK(!eos_decode_cb_.is_null());
407
408 // Report the end of decoding for EOS DecoderBuffer.
409 base::ResetAndReturn(&eos_decode_cb_).Run(kOk);
410
411 // media_decoder_job.cc says: once output EOS has occurred, we should
412 // not be asked to decode again.
413 // Have a separate state for this case.
414 SetState(kStateDrained);
415 } else {
416 // Process the real decoded frame.
417 OnDecodedFrame(&out);
418 }
419
420 work_done = true;
421 break;
422
423 case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
424 // Nothing to do.
425 DVLOG(2) << __FUNCTION__ << " MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER";
426 break;
427
428 case MEDIA_CODEC_ERROR:
429 DVLOG(0) << __FUNCTION__
430 << ": MEDIA_CODEC_ERROR from DequeueOutputBuffer";
431
432 // Next Decode() will report the error to the pipeline.
433 SetState(kStateError);
434 break;
435
436 default:
437 NOTREACHED();
438 break;
439 }
440 } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER &&
441 status != MEDIA_CODEC_ERROR && !out.is_eos);
442
443 return work_done;
444 }
445
446 void AndroidAudioDecoder::ManageTimer(bool did_work) {
447 bool should_be_running = true;
448
449 base::TimeTicks now = base::TimeTicks::Now();
450 if (!did_work) {
451 // Make sure that we have done work recently enough, else stop the timer.
452 if (now - most_recent_work_ > IdleTimerTimeOut())
453 should_be_running = false;
454 } else {
455 most_recent_work_ = now;
456 }
457
458 if (should_be_running && !io_timer_.IsRunning()) {
459 io_timer_.Start(FROM_HERE, DecodePollDelay(), this,
460 &AndroidAudioDecoder::DoIOTask);
461 } else if (!should_be_running && io_timer_.IsRunning()) {
462 io_timer_.Stop();
463 }
464 }
465
466 void AndroidAudioDecoder::SetState(State new_state) {
liberato (no reviews please) 2016/02/01 15:18:06 this is an improvement over avda.
467 DVLOG(1) << __FUNCTION__ << ": " << AsString(state_) << "->"
468 << AsString(new_state);
469 state_ = new_state;
470 }
471
472 bool AndroidAudioDecoder::ConfigureMediaCodec() {
473 DVLOG(1) << __FUNCTION__;
474
475 media_codec_.reset(AudioCodecBridge::Create(config_.codec()));
476 if (!media_codec_) {
477 DVLOG(0) << __FUNCTION__ << " failed: cannot create AudioCodecBridge";
478 return false;
479 }
480
481 AudioCodecBridge* audio_codec_bridge =
482 static_cast<AudioCodecBridge*>(media_codec_.get());
483 DCHECK(audio_codec_bridge);
484
485 jobject media_crypto = media_crypto_ ? media_crypto_->obj() : nullptr;
486
487 const bool play_audio = false; // Do not create AudioTrack object.
488 if (!audio_codec_bridge->ConfigureAndStart(
489 config_.codec(), config_.samples_per_second(), channel_count_,
490 &config_.extra_data()[0], config_.extra_data().size(),
491 config_.codec_delay(), config_.seek_preroll().InMicroseconds() * 1000,
492 play_audio, media_crypto)) {
493 DVLOG(0) << __FUNCTION__ << " failed: cannot start audio codec";
494 media_codec_.reset();
495 return false;
496 }
497
498 return true;
499 }
500
501 void AndroidAudioDecoder::OnDecodedFrame(const OutputBufferInfo* out) {
502 DCHECK(out);
503 DCHECK_NE(out->size, 0U);
504 DCHECK(media_codec_);
505
506 DVLOG(2) << __FUNCTION__ << " pts:" << out->pts;
507
508 // Create AudioOutput buffer based on configuration.
509 const size_t frame_count = out->size / bytes_per_frame_;
510
511 scoped_refptr<AudioBuffer> audio_buffer = AudioBuffer::CreateBuffer(
512 kSampleFormatS16, config_.channel_layout(), channel_count_,
513 config_.samples_per_second(), frame_count);
514
515 // Copy data into AudioBuffer.
516 media_codec_->CopyFromOutputBuffer(out->buf_index, out->offset,
517 audio_buffer->interleaved_data(),
518 audio_buffer->interleaved_data_size());
519
520 // Release MediaCodec output buffer.
521 media_codec_->ReleaseOutputBuffer(out->buf_index, false);
522
523 // Call the output_cb_.
524 output_cb_.Run(audio_buffer);
525 }
526
527 void AndroidAudioDecoder::OnOutputFormatChanged() {
528 DVLOG(0) << __FUNCTION__ << ": not implemented, going to error state";
529
530 SetState(kStateError);
531 }
532
533 #undef RETURN_STRING
534 #define RETURN_STRING(x) \
535 case x: \
536 return #x;
537
538 // static
539 const char* AndroidAudioDecoder::AsString(State state) {
540 switch (state) {
541 RETURN_STRING(kStateUninitialized);
542 RETURN_STRING(kStateWaitingForCDM);
543 RETURN_STRING(kStateWaitingForCrypto);
544 RETURN_STRING(kStateReady);
545 RETURN_STRING(kStateWaitingForKey);
546 RETURN_STRING(kStateDraining);
547 RETURN_STRING(kStateDrained);
548 RETURN_STRING(kStateError);
549 }
550 return nullptr; // crash early
551 }
552
553 #undef RETURN_STRING
554
555 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698