Index: media/filters/android/media_codec_audio_decoder.cc |
diff --git a/media/filters/android/media_codec_audio_decoder.cc b/media/filters/android/media_codec_audio_decoder.cc |
index c1db1d97a7fd3f2efb0282008c0ea64c161caddb..f002dffad86140645a884321e069fd135b487de6 100644 |
--- a/media/filters/android/media_codec_audio_decoder.cc |
+++ b/media/filters/android/media_codec_audio_decoder.cc |
@@ -17,45 +17,13 @@ |
namespace media { |
-namespace { |
- |
-// Android MediaCodec can only output 16bit PCM audio. |
-const int kBytesPerOutputSample = 2; |
- |
-inline int GetChannelCount(const AudioDecoderConfig& config) { |
- return ChannelLayoutToChannelCount(config.channel_layout()); |
-} |
- |
-// Converts interleaved data into planar data and writes it to |planes|. |
-// The planes are populated in the order of channels in the interleaved frame. |
-// If |channel_count| is less than the number of available planes the extra |
-// destination planes will not be touched. |
-void SeparatePlanes(const uint8_t* interleaved_data, |
- size_t frame_count, |
- size_t bytes_per_frame, |
- size_t channel_count, |
- const std::vector<uint8_t*>& planes) { |
- DCHECK(interleaved_data); |
- DCHECK_LE(channel_count, planes.size()); |
- |
- const uint8_t* src_frame = interleaved_data; |
- for (size_t i = 0; i < frame_count; ++i, src_frame += bytes_per_frame) { |
- for (size_t ch = 0; ch < channel_count; ++ch) { |
- const int16_t* src_sample = |
- reinterpret_cast<const int16_t*>(src_frame) + ch; |
- int16_t* dst_sample = reinterpret_cast<int16_t*>(planes[ch]) + i; |
- *dst_sample = *src_sample; |
- } |
- } |
-} |
- |
-} // namespace (anonymous) |
- |
MediaCodecAudioDecoder::MediaCodecAudioDecoder( |
scoped_refptr<base::SingleThreadTaskRunner> task_runner) |
: task_runner_(task_runner), |
state_(STATE_UNINITIALIZED), |
channel_count_(0), |
+ channel_layout_(CHANNEL_LAYOUT_NONE), |
+ sample_rate_(0), |
media_drm_bridge_cdm_context_(nullptr), |
cdm_registration_id_(0), |
weak_factory_(this) { |
@@ -110,8 +78,6 @@ void MediaCodecAudioDecoder::Initialize(const AudioDecoderConfig& config, |
} |
config_ = config; |
- timestamp_helper_.reset( |
- new AudioTimestampHelper(config_.samples_per_second())); |
output_cb_ = BindToCurrentLoop(output_cb); |
if (config_.is_encrypted()) { |
@@ -127,12 +93,7 @@ void MediaCodecAudioDecoder::Initialize(const AudioDecoderConfig& config, |
return; |
} |
- // Guess the channel count from |config_| in case OnOutputFormatChanged |
- // that delivers the true count is not called before the first data arrives. |
- // It seems upon certain input errors a codec may substitute silence and |
- // not call OnOutputFormatChanged in this case. |
- channel_count_ = GetChannelCount(config_); |
- |
+ ResetTimestampState(); |
AndyWu
2016/09/28 18:28:48
We should move this line before line 83. Sorry I d
AndyWu
2016/09/28 19:15:59
Sorry, this is not the root cause, just a workarou
|
SetState(STATE_READY); |
bound_init_cb.Run(true); |
} |
@@ -213,9 +174,7 @@ void MediaCodecAudioDecoder::Reset(const base::Closure& closure) { |
if (!success) |
success = CreateMediaCodecLoop(); |
- // Reset AudioTimestampHelper. |
- timestamp_helper_->SetBaseTimestamp(kNoTimestamp); |
- |
+ ResetTimestampState(); |
SetState(success ? STATE_READY : STATE_ERROR); |
task_runner_->PostTask(FROM_HERE, closure); |
@@ -392,54 +351,28 @@ bool MediaCodecAudioDecoder::OnDecodedFrame( |
// For proper |frame_count| calculation we need to use the actual number |
// of channels which can be different from |config_| value. |
DCHECK_GT(channel_count_, 0); |
- const int bytes_per_frame = kBytesPerOutputSample * channel_count_; |
- const size_t frame_count = out.size / bytes_per_frame; |
- |
- // Create AudioOutput buffer based on configuration. |
- const int config_channel_count = GetChannelCount(config_); |
- const SampleFormat sample_format = config_channel_count == channel_count_ |
- ? kSampleFormatS16 // can copy |
- : kSampleFormatPlanarS16; // upsample |
- |
- scoped_refptr<AudioBuffer> audio_buffer = AudioBuffer::CreateBuffer( |
- sample_format, config_.channel_layout(), config_channel_count, |
- config_.samples_per_second(), frame_count); |
- |
- if (config_channel_count == channel_count_) { |
- // Copy data into AudioBuffer. |
- CHECK_LE(out.size, audio_buffer->data_size()); |
- |
- MediaCodecStatus status = media_codec->CopyFromOutputBuffer( |
- out.index, out.offset, audio_buffer->channel_data()[0], out.size); |
- if (status != MEDIA_CODEC_OK) { |
- media_codec->ReleaseOutputBuffer(out.index, false); |
- return false; |
- } |
- } else { |
- // Separate the planes while copying MediaCodec buffer into AudioBuffer. |
- DCHECK_LT(channel_count_, config_channel_count); |
- |
- const uint8_t* interleaved_data = nullptr; |
- size_t interleaved_capacity = 0; |
- MediaCodecStatus status = media_codec->GetOutputBufferAddress( |
- out.index, out.offset, &interleaved_data, &interleaved_capacity); |
+ // Android MediaCodec can only output 16bit PCM audio. |
+ const int bytes_per_frame = sizeof(uint16_t) * channel_count_; |
+ const size_t frame_count = out.size / bytes_per_frame; |
- if (status != MEDIA_CODEC_OK) { |
- media_codec->ReleaseOutputBuffer(out.index, false); |
- return false; |
- } |
+ // Create AudioOutput buffer based on current parameters. |
+ scoped_refptr<AudioBuffer> audio_buffer = |
+ AudioBuffer::CreateBuffer(kSampleFormatS16, channel_layout_, |
+ channel_count_, sample_rate_, frame_count); |
- DCHECK_LE(out.size, interleaved_capacity); |
+ // Copy data into AudioBuffer. |
+ CHECK_LE(out.size, audio_buffer->data_size()); |
- memset(audio_buffer->channel_data()[0], 0, audio_buffer->data_size()); |
- SeparatePlanes(interleaved_data, frame_count, bytes_per_frame, |
- channel_count_, audio_buffer->channel_data()); |
- } |
+ MediaCodecStatus status = media_codec->CopyFromOutputBuffer( |
+ out.index, out.offset, audio_buffer->channel_data()[0], out.size); |
// Release MediaCodec output buffer. |
media_codec->ReleaseOutputBuffer(out.index, false); |
+ if (status != MEDIA_CODEC_OK) |
+ return false; |
+ |
// Calculate and set buffer timestamp. |
const bool first_buffer = timestamp_helper_->base_timestamp() == kNoTimestamp; |
@@ -471,34 +404,51 @@ bool MediaCodecAudioDecoder::OnOutputFormatChanged() { |
DLOG(ERROR) << "GetOutputSamplingRate failed."; |
return false; |
} |
- if (new_sampling_rate != config_.samples_per_second()) { |
- // We do not support the change of sampling rate on the fly |
- DLOG(ERROR) << "Sampling rate change is not supported by " |
- << GetDisplayName() << " (detected change " |
- << config_.samples_per_second() << "->" << new_sampling_rate |
- << ")"; |
- return false; |
+ if (new_sampling_rate != sample_rate_) { |
+ DVLOG(1) << __FUNCTION__ |
+ << ": detected sample rate change: " << sample_rate_ << " -> " |
+ << new_sampling_rate; |
+ |
+ sample_rate_ = new_sampling_rate; |
+ const base::TimeDelta base_timestamp = |
+ timestamp_helper_->base_timestamp() == kNoTimestamp |
AndyWu
2016/09/28 19:15:59
We should check |timestamp_helper_| is null or not
|
+ ? kNoTimestamp |
+ : timestamp_helper_->GetTimestamp(); |
+ timestamp_helper_.reset(new AudioTimestampHelper(sample_rate_)); |
+ if (base_timestamp != kNoTimestamp) |
+ timestamp_helper_->SetBaseTimestamp(base_timestamp); |
} |
- status = media_codec->GetOutputChannelCount(&channel_count_); |
- if (status != MEDIA_CODEC_OK) { |
+ int new_channel_count = 0; |
+ status = media_codec->GetOutputChannelCount(&new_channel_count); |
+ if (status != MEDIA_CODEC_OK || !new_channel_count) { |
DLOG(ERROR) << "GetOutputChannelCount failed."; |
return false; |
} |
- const int config_channel_count = GetChannelCount(config_); |
- DVLOG(1) << __FUNCTION__ << ": new channel count:" << channel_count_ |
- << " (configured for " << config_channel_count << ")"; |
- |
- if (channel_count_ > config_channel_count) { |
- DLOG(ERROR) << "Actual channel count " << channel_count_ |
- << " is greater than configured " << config_channel_count; |
- return false; |
+ if (new_channel_count != channel_count_) { |
+ DVLOG(1) << __FUNCTION__ |
+ << ": detected channel count change: " << channel_count_ << " -> " |
+ << new_channel_count; |
+ channel_count_ = new_channel_count; |
+ channel_layout_ = GuessChannelLayout(channel_count_); |
} |
return true; |
} |
+void MediaCodecAudioDecoder::ResetTimestampState() { |
Tima Vaisburd
2016/09/27 00:14:57
nit: s/ResetTimestampState/GuessParamsFromConfig/
DaleCurtis
2016/09/27 18:13:21
Hmm, don't like GuessParamsFromConfig and can't th
|
+ // Guess the channel count from |config_| in case OnOutputFormatChanged |
+ // that delivers the true count is not called before the first data arrives. |
+ // It seems upon certain input errors a codec may substitute silence and |
+ // not call OnOutputFormatChanged in this case. |
+ channel_layout_ = config_.channel_layout(); |
+ channel_count_ = ChannelLayoutToChannelCount(channel_layout_); |
+ |
+ sample_rate_ = config_.samples_per_second(); |
+ timestamp_helper_.reset(new AudioTimestampHelper(sample_rate_)); |
+} |
+ |
#undef RETURN_STRING |
#define RETURN_STRING(x) \ |
case x: \ |