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

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

Issue 1932093002: Reland: Use actual audio channel count in Spitzer audio decoder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@bug607024
Patch Set: Fix the use of out.offset: decoded data size does not depend on it. Created 4 years, 7 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') | no next file » | 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 559ddfd3e4aceed2c04557be158d5b2a74e6ada6..c06cd44557e7fb634de7a903b5c0f0e9c1f0ae25 100644
--- a/media/filters/android/media_codec_audio_decoder.cc
+++ b/media/filters/android/media_codec_audio_decoder.cc
@@ -64,12 +64,36 @@ std::unique_ptr<MediaCodecBridge> CreateMediaCodec(
return std::move(audio_codec_bridge);
}
+// 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),
pending_input_buf_index_(kInvalidBufferIndex),
media_drm_bridge_cdm_context_(nullptr),
cdm_registration_id_(0),
@@ -596,15 +620,54 @@ void MediaCodecAudioDecoder::OnDecodedFrame(const OutputBufferInfo& out) {
DCHECK_NE(out.buf_index, kInvalidBufferIndex);
DCHECK(media_codec_);
- // Create AudioOutput buffer based on configuration.
- const int channel_count = GetChannelCount(config_);
- const int bytes_per_frame = kBytesPerOutputSample * channel_count;
+ // For proper |frame_count| calculation we need to use the actual number
+ // of channels which can be different from |config_| value.
+ 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(
- kSampleFormatS16, config_.channel_layout(), channel_count,
+ 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.buf_index, out.offset, audio_buffer->channel_data()[0], out.size);
+
+ // TODO(timav,watk): This CHECK maintains the behavior of this call before
+ // we started catching CodecException and returning it as MEDIA_CODEC_ERROR.
+ // It needs to be handled some other way. http://crbug.com/585978
+ CHECK_EQ(status, MEDIA_CODEC_OK);
+ } 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.buf_index, out.offset, &interleaved_data, &interleaved_capacity);
+
+ // TODO(timav): Handle wrong status properly, http://crbug.com/585978.
+ CHECK_EQ(status, MEDIA_CODEC_OK);
+
+ DCHECK_LE(out.size, interleaved_capacity);
+
+ 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());
+ }
+
+ // Release MediaCodec output buffer.
+ media_codec_->ReleaseOutputBuffer(out.buf_index, false);
+
// Calculate and set buffer timestamp.
const bool first_buffer =
@@ -617,20 +680,6 @@ void MediaCodecAudioDecoder::OnDecodedFrame(const OutputBufferInfo& out) {
audio_buffer->set_timestamp(timestamp_helper_->GetTimestamp());
timestamp_helper_->AddFrames(frame_count);
- // Copy data into AudioBuffer.
- CHECK_LE(out.size, audio_buffer->data_size());
-
- MediaCodecStatus status = media_codec_->CopyFromOutputBuffer(
- out.buf_index, out.offset, audio_buffer->channel_data()[0],
- audio_buffer->data_size());
- // TODO(timav,watk): This CHECK maintains the behavior of this call before
- // we started catching CodecException and returning it as MEDIA_CODEC_ERROR.
- // It needs to be handled some other way. http://crbug.com/585978
- CHECK_EQ(status, MEDIA_CODEC_OK);
-
- // Release MediaCodec output buffer.
- media_codec_->ReleaseOutputBuffer(out.buf_index, false);
-
// Call the |output_cb_|.
output_cb_.Run(audio_buffer);
}
@@ -638,18 +687,40 @@ void MediaCodecAudioDecoder::OnDecodedFrame(const OutputBufferInfo& out) {
void MediaCodecAudioDecoder::OnOutputFormatChanged() {
DVLOG(2) << __FUNCTION__;
- int new_sampling_rate;
+ int new_sampling_rate = 0;
MediaCodecStatus status =
media_codec_->GetOutputSamplingRate(&new_sampling_rate);
if (status != MEDIA_CODEC_OK) {
- DVLOG(0) << "GetOutputSamplingRate failed.";
+ DLOG(ERROR) << "GetOutputSamplingRate failed.";
SetState(STATE_ERROR);
- } else if (new_sampling_rate != config_.samples_per_second()) {
+ return;
+ }
+ if (new_sampling_rate != config_.samples_per_second()) {
// We do not support the change of sampling rate on the fly
- DVLOG(0) << "Sampling rate change is not supported by" << GetDisplayName()
- << " (detected change " << config_.samples_per_second() << "->"
- << new_sampling_rate << ")";
+ DLOG(ERROR) << "Sampling rate change is not supported by "
+ << GetDisplayName() << " (detected change "
+ << config_.samples_per_second() << "->" << new_sampling_rate
+ << ")";
+ SetState(STATE_ERROR);
+ return;
+ }
+
+ status = media_codec_->GetOutputChannelCount(&channel_count_);
+ if (status != MEDIA_CODEC_OK) {
+ DLOG(ERROR) << "GetOutputChannelCount failed.";
SetState(STATE_ERROR);
+ return;
+ }
+
+ 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;
+ SetState(STATE_ERROR);
+ return;
}
}
« no previous file with comments | « media/filters/android/media_codec_audio_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698