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

Unified Diff: media/filters/android/media_codec_audio_decoder.cc

Issue 2376513002: Fix implicit configuration changes in MediaCodecAudioDecoder. (Closed)
Patch Set: Cleanup code a bit. Created 4 years, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/android/media_codec_audio_decoder.h ('k') | media/filters/audio_decoder_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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: \
« no previous file with comments | « media/filters/android/media_codec_audio_decoder.h ('k') | media/filters/audio_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698