diff options
Diffstat (limited to 'chromium/media/base')
18 files changed, 236 insertions, 109 deletions
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 |