Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |