summaryrefslogtreecommitdiff
path: root/chromium/media
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media')
-rw-r--r--chromium/media/audio/BUILD.gn2
-rw-r--r--chromium/media/audio/android/audio_manager_android.cc11
-rw-r--r--chromium/media/audio/android/opensles_input.cc7
-rw-r--r--chromium/media/audio/android/opensles_output.cc7
-rw-r--r--chromium/media/audio/android/opensles_util.cc50
-rw-r--r--chromium/media/audio/android/opensles_util.h6
-rw-r--r--chromium/media/base/android/audio_decoder_job.cc71
-rw-r--r--chromium/media/base/android/audio_decoder_job.h12
-rw-r--r--chromium/media/base/android/audio_media_codec_decoder.cc47
-rw-r--r--chromium/media/base/android/audio_media_codec_decoder.h9
-rw-r--r--chromium/media/base/android/media_codec_bridge.cc15
-rw-r--r--chromium/media/base/android/media_codec_bridge.h24
-rw-r--r--chromium/media/base/android/media_codec_decoder.cc7
-rw-r--r--chromium/media/base/android/media_codec_decoder.h3
-rw-r--r--chromium/media/base/android/media_decoder_job.cc10
-rw-r--r--chromium/media/base/android/media_decoder_job.h4
-rw-r--r--chromium/media/base/android/ndk_media_codec_bridge.cc28
-rw-r--r--chromium/media/base/android/ndk_media_codec_bridge.h9
-rw-r--r--chromium/media/base/android/ndk_media_codec_wrapper.cc8
-rw-r--r--chromium/media/base/android/sdk_media_codec_bridge.cc58
-rw-r--r--chromium/media/base/android/sdk_media_codec_bridge.h24
-rw-r--r--chromium/media/base/android/video_media_codec_decoder.cc3
-rw-r--r--chromium/media/base/android/video_media_codec_decoder.h2
-rw-r--r--chromium/media/base/video_decoder.h11
-rw-r--r--chromium/media/blink/webmediaplayer_impl.cc8
-rw-r--r--chromium/media/blink/webmediaplayer_impl.h1
-rw-r--r--chromium/media/filters/android/media_codec_audio_decoder.cc119
-rw-r--r--chromium/media/filters/android/media_codec_audio_decoder.h4
-rw-r--r--chromium/media/filters/ffmpeg_video_decoder.cc2
-rw-r--r--chromium/media/filters/gpu_video_decoder.cc23
-rw-r--r--chromium/media/filters/vpx_video_decoder.cc2
-rw-r--r--chromium/media/media.gyp2
32 files changed, 428 insertions, 161 deletions
diff --git a/chromium/media/audio/BUILD.gn b/chromium/media/audio/BUILD.gn
index e69dc42dd6c..aa8ddfc5c51 100644
--- a/chromium/media/audio/BUILD.gn
+++ b/chromium/media/audio/BUILD.gn
@@ -188,6 +188,8 @@ source_set("audio") {
"android/opensles_input.h",
"android/opensles_output.cc",
"android/opensles_output.h",
+ "android/opensles_util.cc",
+ "android/opensles_util.h",
"android/opensles_wrapper.cc",
]
deps += [ "//media/base/android:media_jni_headers" ]
diff --git a/chromium/media/audio/android/audio_manager_android.cc b/chromium/media/audio/android/audio_manager_android.cc
index 96a7c78c29c..0df73188b62 100644
--- a/chromium/media/audio/android/audio_manager_android.cc
+++ b/chromium/media/audio/android/audio_manager_android.cc
@@ -302,7 +302,16 @@ AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
// Use the client's input parameters if they are valid.
sample_rate = input_params.sample_rate();
bits_per_sample = input_params.bits_per_sample();
- channel_layout = input_params.channel_layout();
+
+ // Pre-Lollipop devices don't support > stereo OpenSLES output and the
+ // AudioManager APIs for GetOptimalOutputFrameSize() don't support channel
+ // layouts greater than stereo unless low latency audio is supported.
+ if (input_params.channels() <= 2 ||
+ (base::android::BuildInfo::GetInstance()->sdk_int() >= 21 &&
+ IsAudioLowLatencySupported())) {
+ channel_layout = input_params.channel_layout();
+ }
+
buffer_size = GetOptimalOutputFrameSize(
sample_rate, ChannelLayoutToChannelCount(channel_layout));
}
diff --git a/chromium/media/audio/android/opensles_input.cc b/chromium/media/audio/android/opensles_input.cc
index afbe02e5566..748a9cca802 100644
--- a/chromium/media/audio/android/opensles_input.cc
+++ b/chromium/media/audio/android/opensles_input.cc
@@ -39,12 +39,7 @@ OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager,
format_.bitsPerSample = params.bits_per_sample();
format_.containerSize = params.bits_per_sample();
format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
- if (format_.numChannels == 1)
- format_.channelMask = SL_SPEAKER_FRONT_CENTER;
- else if (format_.numChannels == 2)
- format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
- else
- NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
+ format_.channelMask = ChannelCountToSLESChannelMask(params.channels());
buffer_size_bytes_ = params.GetBytesPerBuffer();
diff --git a/chromium/media/audio/android/opensles_output.cc b/chromium/media/audio/android/opensles_output.cc
index 005b0e70718..bf1957f7829 100644
--- a/chromium/media/audio/android/opensles_output.cc
+++ b/chromium/media/audio/android/opensles_output.cc
@@ -42,12 +42,7 @@ OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
format_.bitsPerSample = params.bits_per_sample();
format_.containerSize = params.bits_per_sample();
format_.endianness = SL_BYTEORDER_LITTLEENDIAN;
- if (format_.numChannels == 1)
- format_.channelMask = SL_SPEAKER_FRONT_CENTER;
- else if (format_.numChannels == 2)
- format_.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
- else
- NOTREACHED() << "Unsupported number of channels: " << format_.numChannels;
+ format_.channelMask = ChannelCountToSLESChannelMask(params.channels());
buffer_size_bytes_ = params.GetBytesPerBuffer();
audio_bus_ = AudioBus::Create(params);
diff --git a/chromium/media/audio/android/opensles_util.cc b/chromium/media/audio/android/opensles_util.cc
new file mode 100644
index 00000000000..cf5ea3b98d8
--- /dev/null
+++ b/chromium/media/audio/android/opensles_util.cc
@@ -0,0 +1,50 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/audio/android/opensles_util.h"
+
+namespace media {
+
+#define SL_ANDROID_SPEAKER_QUAD \
+ (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT | \
+ SL_SPEAKER_BACK_RIGHT)
+#define SL_ANDROID_SPEAKER_5DOT1 \
+ (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | \
+ SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
+#define SL_ANDROID_SPEAKER_7DOT1 \
+ (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
+
+// Ported from:
+// https://android.googlesource.com/platform/frameworks/wilhelm/+/refs/heads/master/src/android/channels.h
+// https://android.googlesource.com/platform/frameworks/wilhelm/+/refs/heads/master/src/android/channels.c
+SLuint32 ChannelCountToSLESChannelMask(int channel_count) {
+ if (channel_count > 2) {
+ LOG(WARNING) << "Guessing channel layout for " << channel_count
+ << " channels; speaker order may be incorrect.";
+ }
+
+ switch (channel_count) {
+ case 1:
+ return SL_SPEAKER_FRONT_LEFT;
+ case 2:
+ return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
+ case 3:
+ return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
+ SL_SPEAKER_FRONT_CENTER;
+ case 4:
+ return SL_ANDROID_SPEAKER_QUAD;
+ case 5:
+ return SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER;
+ case 6:
+ return SL_ANDROID_SPEAKER_5DOT1;
+ case 7:
+ return SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_BACK_CENTER;
+ case 8:
+ return SL_ANDROID_SPEAKER_7DOT1;
+ }
+
+ return 0;
+}
+
+} // namespace media
diff --git a/chromium/media/audio/android/opensles_util.h b/chromium/media/audio/android/opensles_util.h
index bc6d0410af9..2673d14f3b6 100644
--- a/chromium/media/audio/android/opensles_util.h
+++ b/chromium/media/audio/android/opensles_util.h
@@ -8,6 +8,7 @@
#include <SLES/OpenSLES.h>
#include "base/logging.h"
+#include "media/base/media_export.h"
namespace media {
@@ -40,6 +41,11 @@ class ScopedSLObject {
typedef ScopedSLObject<SLObjectItf, const SLObjectItf_*> ScopedSLObjectItf;
+// Guesses the channel mask for a given channel count. Android does not offer a
+// way to configure the layout, so this will be incorrect for less common
+// channel layouts.
+MEDIA_EXPORT SLuint32 ChannelCountToSLESChannelMask(int channel_count);
+
} // namespace media
#endif // MEDIA_AUDIO_ANDROID_OPENSLES_UTIL_H_
diff --git a/chromium/media/base/android/audio_decoder_job.cc b/chromium/media/base/android/audio_decoder_job.cc
index f0baca4e949..9b237b8ec67 100644
--- a/chromium/media/base/android/audio_decoder_job.cc
+++ b/chromium/media/base/android/audio_decoder_job.cc
@@ -40,13 +40,12 @@ AudioDecoderJob::AudioDecoderJob(
request_data_cb,
on_demuxer_config_changed_cb),
audio_codec_(kUnknownAudioCodec),
- num_channels_(0),
+ config_num_channels_(0),
config_sampling_rate_(0),
volume_(-1.0),
- bytes_per_frame_(0),
output_sampling_rate_(0),
- frame_count_(0) {
-}
+ output_num_channels_(0),
+ frame_count_(0) {}
AudioDecoderJob::~AudioDecoderJob() {}
@@ -63,15 +62,17 @@ void AudioDecoderJob::SetDemuxerConfigs(const DemuxerConfigs& configs) {
// TODO(qinmin): split DemuxerConfig for audio and video separately so we
// can simply store the stucture here.
audio_codec_ = configs.audio_codec;
- num_channels_ = configs.audio_channels;
+ config_num_channels_ = configs.audio_channels;
config_sampling_rate_ = configs.audio_sampling_rate;
set_is_content_encrypted(configs.is_audio_encrypted);
audio_extra_data_ = configs.audio_extra_data;
audio_codec_delay_ns_ = configs.audio_codec_delay_ns;
audio_seek_preroll_ns_ = configs.audio_seek_preroll_ns;
- bytes_per_frame_ = kBytesPerAudioOutputSample * num_channels_;
- if (!media_codec_bridge_)
+
+ if (!media_codec_bridge_) {
output_sampling_rate_ = config_sampling_rate_;
+ output_num_channels_ = config_num_channels_;
+ }
}
void AudioDecoderJob::SetVolume(double volume) {
@@ -118,7 +119,8 @@ void AudioDecoderJob::ReleaseOutputBuffer(
base::TimeTicks current_time = base::TimeTicks::Now();
- size_t new_frames_count = size / bytes_per_frame_;
+ size_t bytes_per_frame = kBytesPerAudioOutputSample * output_num_channels_;
+ size_t new_frames_count = size / bytes_per_frame;
frame_count_ += new_frames_count;
audio_timestamp_helper_->AddFrames(new_frames_count);
int64_t frames_to_play = frame_count_ - head_position;
@@ -153,13 +155,12 @@ bool AudioDecoderJob::ComputeTimeToRender() const {
bool AudioDecoderJob::AreDemuxerConfigsChanged(
const DemuxerConfigs& configs) const {
return audio_codec_ != configs.audio_codec ||
- num_channels_ != configs.audio_channels ||
- config_sampling_rate_ != configs.audio_sampling_rate ||
- is_content_encrypted() != configs.is_audio_encrypted ||
- audio_extra_data_.size() != configs.audio_extra_data.size() ||
- !std::equal(audio_extra_data_.begin(),
- audio_extra_data_.end(),
- configs.audio_extra_data.begin());
+ config_num_channels_ != configs.audio_channels ||
+ config_sampling_rate_ != configs.audio_sampling_rate ||
+ is_content_encrypted() != configs.is_audio_encrypted ||
+ audio_extra_data_.size() != configs.audio_extra_data.size() ||
+ !std::equal(audio_extra_data_.begin(), audio_extra_data_.end(),
+ configs.audio_extra_data.begin());
}
MediaDecoderJob::MediaDecoderJobStatus
@@ -170,7 +171,7 @@ MediaDecoderJob::MediaDecoderJobStatus
if (!(static_cast<AudioCodecBridge*>(media_codec_bridge_.get()))
->ConfigureAndStart(audio_codec_, config_sampling_rate_,
- num_channels_, &audio_extra_data_[0],
+ config_num_channels_, &audio_extra_data_[0],
audio_extra_data_.size(), audio_codec_delay_ns_,
audio_seek_preroll_ns_, true,
GetMediaCrypto())) {
@@ -194,18 +195,42 @@ void AudioDecoderJob::SetVolumeInternal() {
}
}
-void AudioDecoderJob::OnOutputFormatChanged() {
+bool AudioDecoderJob::OnOutputFormatChanged() {
DCHECK(media_codec_bridge_);
- int old_sampling_rate = output_sampling_rate_;
+ // Recreate AudioTrack if either sample rate or output channel count changed.
+ // If we cannot obtain these values we assume they did not change.
+ bool needs_recreate_audio_track = false;
+
+ const int old_sampling_rate = output_sampling_rate_;
MediaCodecStatus status =
media_codec_bridge_->GetOutputSamplingRate(&output_sampling_rate_);
- // 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);
- if (output_sampling_rate_ != old_sampling_rate)
+
+ if (status == MEDIA_CODEC_OK && old_sampling_rate != output_sampling_rate_) {
+ DCHECK_GT(output_sampling_rate_, 0);
+ DVLOG(2) << __FUNCTION__ << ": new sampling rate " << output_sampling_rate_;
+ needs_recreate_audio_track = true;
+
ResetTimestampHelper();
+ }
+
+ const int old_num_channels = output_num_channels_;
+ status = media_codec_bridge_->GetOutputChannelCount(&output_num_channels_);
+
+ if (status == MEDIA_CODEC_OK && old_num_channels != output_num_channels_) {
+ DCHECK_GT(output_sampling_rate_, 0);
+ DVLOG(2) << __FUNCTION__ << ": new channel count " << output_num_channels_;
+ needs_recreate_audio_track = true;
+ }
+
+ if (needs_recreate_audio_track &&
+ !static_cast<AudioCodecBridge*>(media_codec_bridge_.get())
+ ->CreateAudioTrack(output_sampling_rate_, output_num_channels_)) {
+ DLOG(ERROR) << __FUNCTION__ << ": cannot create AudioTrack";
+ return false;
+ }
+
+ return true;
}
} // namespace media
diff --git a/chromium/media/base/android/audio_decoder_job.h b/chromium/media/base/android/audio_decoder_job.h
index 8b1b4e9c51f..1583185e497 100644
--- a/chromium/media/base/android/audio_decoder_job.h
+++ b/chromium/media/base/android/audio_decoder_job.h
@@ -54,7 +54,7 @@ class AudioDecoderJob : public MediaDecoderJob {
bool ComputeTimeToRender() const override;
bool AreDemuxerConfigsChanged(const DemuxerConfigs& configs) const override;
MediaDecoderJobStatus CreateMediaCodecBridgeInternal() override;
- void OnOutputFormatChanged() override;
+ bool OnOutputFormatChanged() override;
// Helper method to set the audio output volume.
void SetVolumeInternal();
@@ -63,18 +63,20 @@ class AudioDecoderJob : public MediaDecoderJob {
// Audio configs from the demuxer.
AudioCodec audio_codec_;
- int num_channels_;
+ int config_num_channels_;
int config_sampling_rate_;
std::vector<uint8_t> audio_extra_data_;
int64_t audio_codec_delay_ns_;
int64_t audio_seek_preroll_ns_;
double volume_;
- int bytes_per_frame_;
- // Audio output sample rate
+ // Audio output sample rate.
int output_sampling_rate_;
- // Frame count to sync with audio codec output
+ // Number of output audio channels.
+ int output_num_channels_;
+
+ // Frame count to sync with audio codec output.
int64_t frame_count_;
// Base timestamp for the |audio_timestamp_helper_|.
diff --git a/chromium/media/base/android/audio_media_codec_decoder.cc b/chromium/media/base/android/audio_media_codec_decoder.cc
index 5654e7ca4a0..bf9939de1e5 100644
--- a/chromium/media/base/android/audio_media_codec_decoder.cc
+++ b/chromium/media/base/android/audio_media_codec_decoder.cc
@@ -40,8 +40,8 @@ AudioMediaCodecDecoder::AudioMediaCodecDecoder(
waiting_for_decryption_key_cb,
error_cb),
volume_(-1.0),
- bytes_per_frame_(0),
output_sampling_rate_(0),
+ output_num_channels_(0),
frame_count_(0),
update_current_time_cb_(update_current_time_cb) {}
@@ -65,8 +65,10 @@ void AudioMediaCodecDecoder::SetDemuxerConfigs(const DemuxerConfigs& configs) {
DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << configs;
configs_ = configs;
- if (!media_codec_bridge_)
+ if (!media_codec_bridge_) {
output_sampling_rate_ = configs.audio_sampling_rate;
+ output_num_channels_ = configs.audio_channels;
+ }
}
bool AudioMediaCodecDecoder::IsContentEncrypted() const {
@@ -159,7 +161,6 @@ MediaCodecDecoder::ConfigStatus AudioMediaCodecDecoder::ConfigureInternal(
SetVolumeInternal();
- bytes_per_frame_ = kBytesPerAudioOutputSample * configs_.audio_channels;
frame_count_ = 0;
ResetTimestampHelper();
@@ -169,16 +170,44 @@ MediaCodecDecoder::ConfigStatus AudioMediaCodecDecoder::ConfigureInternal(
return kConfigOk;
}
-void AudioMediaCodecDecoder::OnOutputFormatChanged() {
+bool AudioMediaCodecDecoder::OnOutputFormatChanged() {
DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
DCHECK(media_codec_bridge_);
- int old_sampling_rate = output_sampling_rate_;
+ // Recreate AudioTrack if either sample rate or output channel count changed.
+ // If we cannot obtain these values we assume they did not change.
+ bool needs_recreate_audio_track = false;
+
+ const int old_sampling_rate = output_sampling_rate_;
MediaCodecStatus status =
media_codec_bridge_->GetOutputSamplingRate(&output_sampling_rate_);
- if (status != MEDIA_CODEC_OK || output_sampling_rate_ != old_sampling_rate)
+
+ if (status == MEDIA_CODEC_OK && old_sampling_rate != output_sampling_rate_) {
+ DCHECK_GT(output_sampling_rate_, 0);
+ DVLOG(2) << __FUNCTION__ << ": new sampling rate " << output_sampling_rate_;
+ needs_recreate_audio_track = true;
+
ResetTimestampHelper();
+ }
+
+ const int old_num_channels = output_num_channels_;
+ status = media_codec_bridge_->GetOutputChannelCount(&output_num_channels_);
+
+ if (status == MEDIA_CODEC_OK && old_num_channels != output_num_channels_) {
+ DCHECK_GT(output_sampling_rate_, 0);
+ DVLOG(2) << __FUNCTION__ << ": new channel count " << output_num_channels_;
+ needs_recreate_audio_track = true;
+ }
+
+ if (needs_recreate_audio_track &&
+ !static_cast<AudioCodecBridge*>(media_codec_bridge_.get())
+ ->CreateAudioTrack(output_sampling_rate_, output_num_channels_)) {
+ DLOG(ERROR) << __FUNCTION__ << ": cannot create AudioTrack";
+ return false;
+ }
+
+ return true;
}
void AudioMediaCodecDecoder::Render(int buffer_index,
@@ -220,7 +249,9 @@ void AudioMediaCodecDecoder::Render(int buffer_index,
if (postpone && !frame_count_)
SetBaseTimestamp(pts);
- size_t new_frames_count = size / bytes_per_frame_;
+ const size_t bytes_per_frame =
+ kBytesPerAudioOutputSample * output_num_channels_;
+ const size_t new_frames_count = size / bytes_per_frame;
frame_count_ += new_frames_count;
audio_timestamp_helper_->AddFrames(new_frames_count);
@@ -286,7 +317,7 @@ void AudioMediaCodecDecoder::ResetTimestampHelper() {
base_timestamp_ = audio_timestamp_helper_->GetTimestamp();
audio_timestamp_helper_.reset(
- new AudioTimestampHelper(configs_.audio_sampling_rate));
+ new AudioTimestampHelper(output_sampling_rate_));
audio_timestamp_helper_->SetBaseTimestamp(base_timestamp_);
}
diff --git a/chromium/media/base/android/audio_media_codec_decoder.h b/chromium/media/base/android/audio_media_codec_decoder.h
index ce264b60ee6..d82322c96f9 100644
--- a/chromium/media/base/android/audio_media_codec_decoder.h
+++ b/chromium/media/base/android/audio_media_codec_decoder.h
@@ -50,7 +50,7 @@ class AudioMediaCodecDecoder : public MediaCodecDecoder {
protected:
bool IsCodecReconfigureNeeded(const DemuxerConfigs& next) const override;
ConfigStatus ConfigureInternal(jobject media_crypto) override;
- void OnOutputFormatChanged() override;
+ bool OnOutputFormatChanged() override;
void Render(int buffer_index,
size_t offset,
size_t size,
@@ -73,13 +73,12 @@ class AudioMediaCodecDecoder : public MediaCodecDecoder {
// Requested volume
double volume_;
- // Number of bytes per audio frame. Depends on the output format and the
- // number of channels.
- int bytes_per_frame_;
-
// The sampling rate received from decoder.
int output_sampling_rate_;
+ // The number of audio channels received from decoder.
+ int output_num_channels_;
+
// Frame count to sync with audio codec output.
int64_t frame_count_;
diff --git a/chromium/media/base/android/media_codec_bridge.cc b/chromium/media/base/android/media_codec_bridge.cc
index 833d51ef890..8beb1a2c803 100644
--- a/chromium/media/base/android/media_codec_bridge.cc
+++ b/chromium/media/base/android/media_codec_bridge.cc
@@ -42,6 +42,21 @@ MediaCodecStatus MediaCodecBridge::QueueSecureInputBuffer(
subsamples.size(), presentation_time);
}
+MediaCodecStatus MediaCodecBridge::CopyFromOutputBuffer(int index,
+ size_t offset,
+ void* dst,
+ size_t num) {
+ const uint8_t* src_data = nullptr;
+ size_t src_capacity = 0;
+ MediaCodecStatus status =
+ GetOutputBufferAddress(index, offset, &src_data, &src_capacity);
+ if (status == MEDIA_CODEC_OK) {
+ CHECK_GE(src_capacity, num);
+ memcpy(dst, src_data, num);
+ }
+ return status;
+}
+
bool MediaCodecBridge::FillInputBuffer(int index,
const uint8_t* data,
size_t size) {
diff --git a/chromium/media/base/android/media_codec_bridge.h b/chromium/media/base/android/media_codec_bridge.h
index 25d61f97cc3..434f1806761 100644
--- a/chromium/media/base/android/media_codec_bridge.h
+++ b/chromium/media/base/android/media_codec_bridge.h
@@ -75,6 +75,11 @@ class MEDIA_EXPORT MediaCodecBridge {
// Returns MEDIA_CODEC_ERROR if an error occurs, or MEDIA_CODEC_OK otherwise.
virtual MediaCodecStatus GetOutputSamplingRate(int* sampling_rate) = 0;
+ // Fills |channel_count| with the number of audio channels. Useful after
+ // INFO_OUTPUT_FORMAT_CHANGED.
+ // Returns MEDIA_CODEC_ERROR if an error occurs, or MEDIA_CODEC_OK otherwise.
+ virtual MediaCodecStatus GetOutputChannelCount(int* channel_count) = 0;
+
// Submits a byte array to the given input buffer. Call this after getting an
// available buffer from DequeueInputBuffer(). If |data| is NULL, assume the
// input buffer has already been populated (but still obey |size|).
@@ -151,14 +156,23 @@ class MEDIA_EXPORT MediaCodecBridge {
uint8_t** data,
size_t* capacity) = 0;
- // Copy |num| bytes from output buffer |index|'s |offset| into the memory
+ // Gives the access to buffer's data which is referenced by |index| and
+ // |offset|. The size of available data for reading is written to |*capacity|
+ // and the address is written to |*addr|.
+ // Returns MEDIA_CODEC_ERROR if a error occurs, or MEDIA_CODEC_OK otherwise.
+ virtual MediaCodecStatus GetOutputBufferAddress(int index,
+ size_t offset,
+ const uint8_t** addr,
+ size_t* capacity) = 0;
+
+ // Copies |num| bytes from output buffer |index|'s |offset| into the memory
// region pointed to by |dst|. To avoid overflows, the size of both source
// and destination must be at least |num| bytes, and should not overlap.
// Returns MEDIA_CODEC_ERROR if an error occurs, or MEDIA_CODEC_OK otherwise.
- virtual MediaCodecStatus CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- size_t num) = 0;
+ MediaCodecStatus CopyFromOutputBuffer(int index,
+ size_t offset,
+ void* dst,
+ size_t num);
protected:
MediaCodecBridge();
diff --git a/chromium/media/base/android/media_codec_decoder.cc b/chromium/media/base/android/media_codec_decoder.cc
index bf3c8a31591..942cd6351c3 100644
--- a/chromium/media/base/android/media_codec_decoder.cc
+++ b/chromium/media/base/android/media_codec_decoder.cc
@@ -891,7 +891,12 @@ bool MediaCodecDecoder::DepleteOutputBufferQueue() {
case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
DVLOG(2) << class_name() << "::" << __FUNCTION__
<< " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED";
- OnOutputFormatChanged();
+ if (!OnOutputFormatChanged()) {
+ DVLOG(0) << class_name() << "::" << __FUNCTION__
+ << ": OnOutputFormatChanged failed";
+ status = MEDIA_CODEC_ERROR;
+ media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
+ }
break;
case MEDIA_CODEC_OK:
diff --git a/chromium/media/base/android/media_codec_decoder.h b/chromium/media/base/android/media_codec_decoder.h
index 4135d27fb01..e9d281ff58b 100644
--- a/chromium/media/base/android/media_codec_decoder.h
+++ b/chromium/media/base/android/media_codec_decoder.h
@@ -281,7 +281,8 @@ class MediaCodecDecoder {
virtual void DissociatePTSFromTime() {}
// Processes the change of the output format, varies by stream.
- virtual void OnOutputFormatChanged() = 0;
+ // Returns true if this processing succeeded.
+ virtual bool OnOutputFormatChanged() = 0;
// Renders the decoded frame and releases output buffer, or posts
// a delayed task to do it at a later time,
diff --git a/chromium/media/base/android/media_decoder_job.cc b/chromium/media/base/android/media_decoder_job.cc
index 9e0a2168adb..0e036870bb9 100644
--- a/chromium/media/base/android/media_decoder_job.cc
+++ b/chromium/media/base/android/media_decoder_job.cc
@@ -457,8 +457,10 @@ void MediaDecoderJob::DecodeInternal(
if (status == MEDIA_CODEC_OUTPUT_FORMAT_CHANGED) {
// TODO(qinmin): instead of waiting for the next output buffer to be
// dequeued, post a task on the UI thread to signal the format change.
- OnOutputFormatChanged();
- has_format_change = true;
+ if (OnOutputFormatChanged())
+ has_format_change = true;
+ else
+ status = MEDIA_CODEC_ERROR;
}
} while (status != MEDIA_CODEC_OK && status != MEDIA_CODEC_ERROR &&
status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER);
@@ -675,7 +677,9 @@ bool MediaDecoderJob::IsCodecReconfigureNeeded(
return true;
}
-void MediaDecoderJob::OnOutputFormatChanged() {}
+bool MediaDecoderJob::OnOutputFormatChanged() {
+ return true;
+}
bool MediaDecoderJob::UpdateOutputFormat() {
return false;
diff --git a/chromium/media/base/android/media_decoder_job.h b/chromium/media/base/android/media_decoder_job.h
index b0136aa8191..ce3cd767120 100644
--- a/chromium/media/base/android/media_decoder_job.h
+++ b/chromium/media/base/android/media_decoder_job.h
@@ -253,8 +253,8 @@ class MediaDecoderJob {
// Signals to decoder job that decoder has updated output format. Decoder job
// may need to do internal reconfiguration in order to correctly interpret
- // incoming buffers
- virtual void OnOutputFormatChanged();
+ // incoming buffers. Returns true if this internal configuration succeeded.
+ virtual bool OnOutputFormatChanged();
// Update the output format from the decoder, returns true if the output
// format changes, or false otherwise.
diff --git a/chromium/media/base/android/ndk_media_codec_bridge.cc b/chromium/media/base/android/ndk_media_codec_bridge.cc
index 3a66db675c9..c39e0f9ca3e 100644
--- a/chromium/media/base/android/ndk_media_codec_bridge.cc
+++ b/chromium/media/base/android/ndk_media_codec_bridge.cc
@@ -85,6 +85,7 @@ MediaCodecStatus NdkMediaCodecBridge::GetOutputSize(gfx::Size* size) {
AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
}
+ AMediaFormat_delete(format);
size->SetSize(width, height);
return MEDIA_CODEC_OK;
}
@@ -94,10 +95,21 @@ MediaCodecStatus NdkMediaCodecBridge::GetOutputSamplingRate(
AMediaFormat* format = AMediaCodec_getOutputFormat(media_codec_.get());
*sampling_rate = 0;
AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampling_rate);
+ AMediaFormat_delete(format);
DCHECK_NE(*sampling_rate, 0);
return MEDIA_CODEC_OK;
}
+MediaCodecStatus NdkMediaCodecBridge::GetOutputChannelCount(
+ int* channel_count) {
+ AMediaFormat* format = AMediaCodec_getOutputFormat(media_codec_.get());
+ *channel_count = 0;
+ AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channel_count);
+ AMediaFormat_delete(format);
+ DCHECK_NE(*channel_count, 0);
+ return MEDIA_CODEC_OK;
+}
+
MediaCodecStatus NdkMediaCodecBridge::QueueInputBuffer(
int index,
const uint8_t* data,
@@ -225,15 +237,15 @@ MediaCodecStatus NdkMediaCodecBridge::GetInputBuffer(int input_buffer_index,
return MEDIA_CODEC_OK;
}
-MediaCodecStatus NdkMediaCodecBridge::CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- size_t num) {
- size_t capacity;
+MediaCodecStatus NdkMediaCodecBridge::GetOutputBufferAddress(
+ int index,
+ size_t offset,
+ const uint8_t** addr,
+ size_t* capacity) {
const uint8_t* src_data =
- AMediaCodec_getOutputBuffer(media_codec_.get(), index, &capacity);
- CHECK_GE(capacity, offset + num);
- memcpy(dst, src_data + offset, num);
+ AMediaCodec_getOutputBuffer(media_codec_.get(), index, capacity);
+ *addr = src_data + offset;
+ *capacity -= offset;
return MEDIA_CODEC_OK;
}
diff --git a/chromium/media/base/android/ndk_media_codec_bridge.h b/chromium/media/base/android/ndk_media_codec_bridge.h
index d7f2b108a1a..d247d9f1e12 100644
--- a/chromium/media/base/android/ndk_media_codec_bridge.h
+++ b/chromium/media/base/android/ndk_media_codec_bridge.h
@@ -28,6 +28,7 @@ class MEDIA_EXPORT NdkMediaCodecBridge : public MediaCodecBridge {
void Stop() override;
MediaCodecStatus GetOutputSize(gfx::Size* size) override;
MediaCodecStatus GetOutputSamplingRate(int* sampling_rate) override;
+ MediaCodecStatus GetOutputChannelCount(int* channel_count) override;
MediaCodecStatus QueueInputBuffer(
int index,
const uint8_t* data,
@@ -57,10 +58,10 @@ class MEDIA_EXPORT NdkMediaCodecBridge : public MediaCodecBridge {
MediaCodecStatus GetInputBuffer(int input_buffer_index,
uint8_t** data,
size_t* capacity) override;
- MediaCodecStatus CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- size_t num) override;
+ MediaCodecStatus GetOutputBufferAddress(int index,
+ size_t offset,
+ const uint8_t** addr,
+ size_t* capacity) override;
protected:
NdkMediaCodecBridge(const std::string& mime,
diff --git a/chromium/media/base/android/ndk_media_codec_wrapper.cc b/chromium/media/base/android/ndk_media_codec_wrapper.cc
index e4709a63a52..ba8a250c9ee 100644
--- a/chromium/media/base/android/ndk_media_codec_wrapper.cc
+++ b/chromium/media/base/android/ndk_media_codec_wrapper.cc
@@ -26,6 +26,7 @@
// The constants used in chromium. Those symbols are defined as extern symbols
// in the NdkMediaFormat headers. They will be initialized to their correct
// values when the library is loaded.
+const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT;
const char* AMEDIAFORMAT_KEY_HEIGHT;
const char* AMEDIAFORMAT_KEY_SAMPLE_RATE;
const char* AMEDIAFORMAT_KEY_WIDTH;
@@ -50,9 +51,10 @@ base::NativeLibrary IntializeLibraryHandle() {
// The list of defined symbols.
const SymbolDefinition kSymbols[] = {
+ {"AMEDIAFORMAT_KEY_CHANNEL_COUNT", &AMEDIAFORMAT_KEY_CHANNEL_COUNT},
{"AMEDIAFORMAT_KEY_HEIGHT", &AMEDIAFORMAT_KEY_HEIGHT},
{"AMEDIAFORMAT_KEY_SAMPLE_RATE", &AMEDIAFORMAT_KEY_SAMPLE_RATE},
- {"AMEDIAFORMAT_KEY_SAMPLE_RATE", &AMEDIAFORMAT_KEY_SAMPLE_RATE},
+ {"AMEDIAFORMAT_KEY_WIDTH", &AMEDIAFORMAT_KEY_WIDTH},
};
for (size_t i = 0; i < sizeof(kSymbols) / sizeof(kSymbols[0]); ++i) {
@@ -158,6 +160,10 @@ LOOKUP_FUNC(AMediaCodecCryptoInfo_delete,
media_status_t,
(AMediaCodecCryptoInfo * info),
(info));
+LOOKUP_FUNC(AMediaFormat_delete,
+ media_status_t,
+ (AMediaFormat * format),
+ (format));
LOOKUP_FUNC(AMediaFormat_getInt32,
bool,
(AMediaFormat * format, const char* name, int32_t* out),
diff --git a/chromium/media/base/android/sdk_media_codec_bridge.cc b/chromium/media/base/android/sdk_media_codec_bridge.cc
index 226a90a6cbf..e35fd4b7a8d 100644
--- a/chromium/media/base/android/sdk_media_codec_bridge.cc
+++ b/chromium/media/base/android/sdk_media_codec_bridge.cc
@@ -137,6 +137,18 @@ MediaCodecStatus SdkMediaCodecBridge::GetOutputSamplingRate(
return status;
}
+MediaCodecStatus SdkMediaCodecBridge::GetOutputChannelCount(
+ int* channel_count) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> result =
+ Java_MediaCodecBridge_getOutputFormat(env, j_media_codec_.obj());
+ MediaCodecStatus status = static_cast<MediaCodecStatus>(
+ Java_GetOutputFormatResult_status(env, result.obj()));
+ if (status == MEDIA_CODEC_OK)
+ *channel_count = Java_GetOutputFormatResult_channelCount(env, result.obj());
+ return status;
+}
+
MediaCodecStatus SdkMediaCodecBridge::QueueInputBuffer(
int index,
const uint8_t* data,
@@ -301,25 +313,11 @@ MediaCodecStatus SdkMediaCodecBridge::GetInputBuffer(int input_buffer_index,
return MEDIA_CODEC_OK;
}
-MediaCodecStatus SdkMediaCodecBridge::CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- size_t num) {
- void* src_data = nullptr;
- size_t src_capacity = 0;
- MediaCodecStatus status =
- GetOutputBufferAddress(index, offset, &src_data, &src_capacity);
- if (status == MEDIA_CODEC_OK) {
- CHECK_GE(src_capacity, num);
- memcpy(dst, src_data, num);
- }
- return status;
-}
-
-MediaCodecStatus SdkMediaCodecBridge::GetOutputBufferAddress(int index,
- size_t offset,
- void** addr,
- size_t* capacity) {
+MediaCodecStatus SdkMediaCodecBridge::GetOutputBufferAddress(
+ int index,
+ size_t offset,
+ const uint8_t** addr,
+ size_t* capacity) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> j_buffer(
Java_MediaCodecBridge_getOutputBuffer(env, j_media_codec_.obj(), index));
@@ -327,9 +325,9 @@ MediaCodecStatus SdkMediaCodecBridge::GetOutputBufferAddress(int index,
return MEDIA_CODEC_ERROR;
const size_t total_capacity = env->GetDirectBufferCapacity(j_buffer.obj());
CHECK_GE(total_capacity, offset);
- *addr =
- reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(j_buffer.obj())) +
- offset;
+ *addr = reinterpret_cast<const uint8_t*>(
+ env->GetDirectBufferAddress(j_buffer.obj())) +
+ offset;
*capacity = total_capacity - offset;
return MEDIA_CODEC_OK;
}
@@ -511,6 +509,7 @@ bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format,
LOG(ERROR) << "Invalid AAC header";
return false;
}
+
const size_t kCsdLength = 2;
uint8_t csd[kCsdLength];
csd[0] = profile << 3 | frequency_index >> 1;
@@ -558,6 +557,15 @@ bool AudioCodecBridge::ConfigureMediaFormat(jobject j_format,
return true;
}
+bool AudioCodecBridge::CreateAudioTrack(int sampling_rate, int channel_count) {
+ DVLOG(2) << __FUNCTION__ << ": samping_rate:" << sampling_rate
+ << " channel_count:" << channel_count;
+
+ JNIEnv* env = AttachCurrentThread();
+ return Java_MediaCodecBridge_createAudioTrack(env, media_codec(),
+ sampling_rate, channel_count);
+}
+
MediaCodecStatus AudioCodecBridge::PlayOutputBuffer(int index,
size_t size,
size_t offset,
@@ -566,7 +574,7 @@ MediaCodecStatus AudioCodecBridge::PlayOutputBuffer(int index,
DCHECK_LE(0, index);
int numBytes = base::checked_cast<int>(size);
- void* buffer = nullptr;
+ const uint8_t* buffer = nullptr;
size_t capacity = 0;
MediaCodecStatus status =
GetOutputBufferAddress(index, offset, &buffer, &capacity);
@@ -577,8 +585,8 @@ MediaCodecStatus AudioCodecBridge::PlayOutputBuffer(int index,
CHECK_GE(numBytes, 0);
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jbyteArray> byte_array = base::android::ToJavaByteArray(
- env, static_cast<uint8_t*>(buffer), numBytes);
+ ScopedJavaLocalRef<jbyteArray> byte_array =
+ base::android::ToJavaByteArray(env, buffer, numBytes);
*playback_pos = Java_MediaCodecBridge_playOutputBuffer(
env, media_codec(), byte_array.obj(), postpone);
return status;
diff --git a/chromium/media/base/android/sdk_media_codec_bridge.h b/chromium/media/base/android/sdk_media_codec_bridge.h
index e23400df319..2c52ede9060 100644
--- a/chromium/media/base/android/sdk_media_codec_bridge.h
+++ b/chromium/media/base/android/sdk_media_codec_bridge.h
@@ -34,6 +34,7 @@ class MEDIA_EXPORT SdkMediaCodecBridge : public MediaCodecBridge {
void Stop() override;
MediaCodecStatus GetOutputSize(gfx::Size* size) override;
MediaCodecStatus GetOutputSamplingRate(int* sampling_rate) override;
+ MediaCodecStatus GetOutputChannelCount(int* channel_count) override;
MediaCodecStatus QueueInputBuffer(
int index,
const uint8_t* data,
@@ -63,10 +64,10 @@ class MEDIA_EXPORT SdkMediaCodecBridge : public MediaCodecBridge {
MediaCodecStatus GetInputBuffer(int input_buffer_index,
uint8_t** data,
size_t* capacity) override;
- MediaCodecStatus CopyFromOutputBuffer(int index,
- size_t offset,
- void* dst,
- size_t num) override;
+ MediaCodecStatus GetOutputBufferAddress(int index,
+ size_t offset,
+ const uint8_t** addr,
+ size_t* capacity) override;
static bool RegisterSdkMediaCodecBridge(JNIEnv* env);
@@ -75,14 +76,6 @@ class MEDIA_EXPORT SdkMediaCodecBridge : public MediaCodecBridge {
bool is_secure,
MediaCodecDirection direction);
- // Called to get the buffer address given the output buffer index and offset.
- // The size of available data to read is written to |*capacity| and the
- // address to read from is written to |*addr|.
- // Returns MEDIA_CODEC_ERROR if a error occurs, or MEDIA_CODEC_OK otherwise.
- MediaCodecStatus GetOutputBufferAddress(int index,
- size_t offset,
- void** addr,
- size_t* capacity);
jobject media_codec() { return j_media_codec_.obj(); }
MediaCodecDirection direction_;
@@ -106,7 +99,7 @@ class MEDIA_EXPORT AudioCodecBridge : public SdkMediaCodecBridge {
// See MediaCodecUtil::IsKnownUnaccelerated().
static bool IsKnownUnaccelerated(const AudioCodec& codec);
- // Start the audio codec bridge. If |play_audio| is true this method creates
+ // Starts the audio codec bridge. If |play_audio| is true this method creates
// Android AudioTrack object for the actual audio playback
// (http://developer.android.com/reference/android/media/AudioTrack.html).
bool ConfigureAndStart(const AudioDecoderConfig& config,
@@ -126,6 +119,11 @@ class MEDIA_EXPORT AudioCodecBridge : public SdkMediaCodecBridge {
bool play_audio,
jobject media_crypto) WARN_UNUSED_RESULT;
+ // Creates AudioTrack object for |sampling_rate| and |channel_count|
+ // (http://developer.android.com/reference/android/media/AudioTrack.html).
+ // Returns true in the case of success, false otherwise.
+ bool CreateAudioTrack(int sampling_rate, int channel_count);
+
// Plays the output buffer right away or save for later playback if |postpone|
// is set to true. This call must be called after DequeueOutputBuffer() and
// before ReleaseOutputBuffer. The data is extracted from the output buffers
diff --git a/chromium/media/base/android/video_media_codec_decoder.cc b/chromium/media/base/android/video_media_codec_decoder.cc
index e9a305830a4..e43dfbe51f4 100644
--- a/chromium/media/base/android/video_media_codec_decoder.cc
+++ b/chromium/media/base/android/video_media_codec_decoder.cc
@@ -205,7 +205,7 @@ void VideoMediaCodecDecoder::DissociatePTSFromTime() {
start_pts_ = last_seen_pts_ = kNoTimestamp();
}
-void VideoMediaCodecDecoder::OnOutputFormatChanged() {
+bool VideoMediaCodecDecoder::OnOutputFormatChanged() {
DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
gfx::Size prev_size = video_size_;
@@ -218,6 +218,7 @@ void VideoMediaCodecDecoder::OnOutputFormatChanged() {
media_task_runner_->PostTask(
FROM_HERE, base::Bind(video_size_changed_cb_, video_size_));
}
+ return true;
}
void VideoMediaCodecDecoder::Render(int buffer_index,
diff --git a/chromium/media/base/android/video_media_codec_decoder.h b/chromium/media/base/android/video_media_codec_decoder.h
index 03497269ba1..9aab5e30f80 100644
--- a/chromium/media/base/android/video_media_codec_decoder.h
+++ b/chromium/media/base/android/video_media_codec_decoder.h
@@ -67,7 +67,7 @@ class VideoMediaCodecDecoder : public MediaCodecDecoder {
ConfigStatus ConfigureInternal(jobject media_crypto) override;
void AssociateCurrentTimeWithPTS(base::TimeDelta pts) override;
void DissociatePTSFromTime() override;
- void OnOutputFormatChanged() override;
+ bool OnOutputFormatChanged() override;
void Render(int buffer_index,
size_t offset,
size_t size,
diff --git a/chromium/media/base/video_decoder.h b/chromium/media/base/video_decoder.h
index d6abf03e175..5a474b56e21 100644
--- a/chromium/media/base/video_decoder.h
+++ b/chromium/media/base/video_decoder.h
@@ -65,6 +65,10 @@ class MEDIA_EXPORT VideoDecoder {
// Upon reinitialization, all internal buffered frames will be dropped.
// 2) This method should not be called during pending decode or reset.
// 3) No VideoDecoder calls should be made before |init_cb| is executed.
+ // 4) VideoDecoders should take care to run |output_cb| as soon as the frame
+ // is ready (i.e. w/o thread trampolining) since it can strongly affect frame
+ // delivery times with high-frame-rate material. See Decode() for additional
+ // notes.
virtual void Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* cdm_context,
@@ -84,9 +88,10 @@ class MEDIA_EXPORT VideoDecoder {
// called again).
//
// After decoding is finished the decoder calls |output_cb| specified in
- // Initialize() for each decoded frame. In general |output_cb| may be called
- // before or after |decode_cb|, but software decoders normally call
- // |output_cb| before calling |decode_cb|, i.e. while Decode() is pending.
+ // Initialize() for each decoded frame. |output_cb| is always called before
+ // |decode_cb|. However, |output_cb| may be called before Decode() returns, if
+ // other behavior is desired callers should ensure that |output_cb| will
+ // trampoline as necessary.
//
// If |buffer| is an EOS buffer then the decoder must be flushed, i.e.
// |output_cb| must be called for each frame pending in the queue and
diff --git a/chromium/media/blink/webmediaplayer_impl.cc b/chromium/media/blink/webmediaplayer_impl.cc
index 326522931d4..0b02e112ab6 100644
--- a/chromium/media/blink/webmediaplayer_impl.cc
+++ b/chromium/media/blink/webmediaplayer_impl.cc
@@ -281,14 +281,6 @@ void WebMediaPlayerImpl::load(LoadType load_type, const blink::WebURL& url,
DoLoad(load_type, url, cors_mode);
}
-bool WebMediaPlayerImpl::supportsOverlayFullscreenVideo() {
-#if defined(OS_ANDROID)
- return true;
-#else
- return false;
-#endif
-}
-
void WebMediaPlayerImpl::enteredFullscreen() {
fullscreen_ = true;
if (decoder_requires_restart_for_fullscreen_)
diff --git a/chromium/media/blink/webmediaplayer_impl.h b/chromium/media/blink/webmediaplayer_impl.h
index 8ae217b806b..1af8a5209f3 100644
--- a/chromium/media/blink/webmediaplayer_impl.h
+++ b/chromium/media/blink/webmediaplayer_impl.h
@@ -169,7 +169,6 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl
blink::WebContentDecryptionModule* cdm,
blink::WebContentDecryptionModuleResult result) override;
- bool supportsOverlayFullscreenVideo() override;
void enteredFullscreen() override;
void exitedFullscreen() override;
diff --git a/chromium/media/filters/android/media_codec_audio_decoder.cc b/chromium/media/filters/android/media_codec_audio_decoder.cc
index dbcd801a0fc..cb98232982a 100644
--- a/chromium/media/filters/android/media_codec_audio_decoder.cc
+++ b/chromium/media/filters/android/media_codec_audio_decoder.cc
@@ -63,12 +63,36 @@ scoped_ptr<MediaCodecBridge> CreateMediaCodec(const AudioDecoderConfig& config,
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),
@@ -595,15 +619,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 =
@@ -616,20 +679,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);
}
@@ -637,18 +686,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;
}
}
diff --git a/chromium/media/filters/android/media_codec_audio_decoder.h b/chromium/media/filters/android/media_codec_audio_decoder.h
index 3e68ba4e2d0..bccbd3fc3dc 100644
--- a/chromium/media/filters/android/media_codec_audio_decoder.h
+++ b/chromium/media/filters/android/media_codec_audio_decoder.h
@@ -7,6 +7,7 @@
#include <deque>
#include <utility>
+#include <vector>
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
@@ -237,6 +238,9 @@ class MEDIA_EXPORT MediaCodecAudioDecoder : public AudioDecoder {
// Cached decoder config.
AudioDecoderConfig config_;
+ // Actual channel count that comes from decoder may be different than config.
+ int channel_count_;
+
// Callback that delivers output frames.
OutputCB output_cb_;
diff --git a/chromium/media/filters/ffmpeg_video_decoder.cc b/chromium/media/filters/ffmpeg_video_decoder.cc
index 92028dce636..2ca570890f6 100644
--- a/chromium/media/filters/ffmpeg_video_decoder.cc
+++ b/chromium/media/filters/ffmpeg_video_decoder.cc
@@ -194,7 +194,7 @@ void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config,
return;
}
- output_cb_ = BindToCurrentLoop(output_cb);
+ output_cb_ = output_cb;
// Success!
state_ = kNormal;
diff --git a/chromium/media/filters/gpu_video_decoder.cc b/chromium/media/filters/gpu_video_decoder.cc
index 2e11d878686..84f70b4ca5d 100644
--- a/chromium/media/filters/gpu_video_decoder.cc
+++ b/chromium/media/filters/gpu_video_decoder.cc
@@ -130,6 +130,20 @@ static void ReportGpuVideoDecoderInitializeStatusToUMAAndRunCB(
cb.Run(success);
}
+// static
+void ReleaseMailboxTrampoline(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const VideoFrame::ReleaseMailboxCB& release_mailbox_cb,
+ const gpu::SyncToken& release_sync_token) {
+ if (task_runner->BelongsToCurrentThread()) {
+ release_mailbox_cb.Run(release_sync_token);
+ return;
+ }
+
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(release_mailbox_cb, release_sync_token));
+}
+
std::string GpuVideoDecoder::GetDisplayName() const {
return kDecoderName;
}
@@ -187,7 +201,7 @@ void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config,
supports_deferred_initialization_ = !!(
capabilities.flags &
VideoDecodeAccelerator::Capabilities::SUPPORTS_DEFERRED_INITIALIZATION);
- output_cb_ = BindToCurrentLoop(output_cb);
+ output_cb_ = output_cb;
if (config.is_encrypted() && !supports_deferred_initialization_) {
DVLOG(1) << __FUNCTION__
@@ -547,9 +561,10 @@ void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
opaque ? PIXEL_FORMAT_XRGB : PIXEL_FORMAT_ARGB,
gpu::MailboxHolder(pb.texture_mailbox(0), gpu::SyncToken(),
decoder_texture_target_),
- BindToCurrentLoop(base::Bind(
- &GpuVideoDecoder::ReleaseMailbox, weak_factory_.GetWeakPtr(),
- factories_, picture.picture_buffer_id(), pb.texture_ids())),
+ base::Bind(&ReleaseMailboxTrampoline, factories_->GetTaskRunner(),
+ base::Bind(&GpuVideoDecoder::ReleaseMailbox,
+ weak_factory_.GetWeakPtr(), factories_,
+ picture.picture_buffer_id(), pb.texture_ids())),
pb.size(), visible_rect, natural_size, timestamp));
if (!frame) {
DLOG(ERROR) << "Create frame failed for: " << picture.picture_buffer_id();
diff --git a/chromium/media/filters/vpx_video_decoder.cc b/chromium/media/filters/vpx_video_decoder.cc
index 2d60d917a43..e19e3a6be15 100644
--- a/chromium/media/filters/vpx_video_decoder.cc
+++ b/chromium/media/filters/vpx_video_decoder.cc
@@ -391,7 +391,7 @@ void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config,
// Success!
config_ = config;
state_ = kNormal;
- output_cb_ = BindToCurrentLoop(output_cb);
+ output_cb_ = offload_task_runner_ ? BindToCurrentLoop(output_cb) : output_cb;
bound_init_cb.Run(true);
}
diff --git a/chromium/media/media.gyp b/chromium/media/media.gyp
index ee32a6fe21b..9752856db3f 100644
--- a/chromium/media/media.gyp
+++ b/chromium/media/media.gyp
@@ -121,6 +121,8 @@
'audio/android/opensles_input.h',
'audio/android/opensles_output.cc',
'audio/android/opensles_output.h',
+ 'audio/android/opensles_util.cc',
+ 'audio/android/opensles_util.h',
'audio/android/opensles_wrapper.cc',
'audio/audio_device_name.cc',
'audio/audio_device_name.h',