diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-09-03 13:32:17 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-10-01 14:31:55 +0200 |
commit | 21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (patch) | |
tree | 91be119f694044dfc1ff9fdc054459e925de9df0 /chromium/media | |
parent | 03c549e0392f92c02536d3f86d5e1d8dfa3435ac (diff) | |
download | qtwebengine-chromium-21ba0c5d4bf8fba15dddd97cd693bad2358b77fd.tar.gz |
BASELINE: Update Chromium to 92.0.4515.166
Change-Id: I42a050486714e9e54fc271f2a8939223a02ae364
Diffstat (limited to 'chromium/media')
877 files changed, 10840 insertions, 12505 deletions
diff --git a/chromium/media/BUILD.gn b/chromium/media/BUILD.gn index 7e7271097d2..740789d1dcc 100644 --- a/chromium/media/BUILD.gn +++ b/chromium/media/BUILD.gn @@ -196,10 +196,17 @@ test("media_unittests") { } if (is_fuchsia) { + deps += [ + "//media/fuchsia/audio:unittests", + "//media/fuchsia/cdm/service:unittests", + ] + additional_manifest_fragments = [ "//build/config/fuchsia/test/audio_capabilities.test-cmx", - # TODO(crbug.com/1185811): Figure out why jit_capabilities is needed. + # TODO(crbug.com/1185811): Figure out why + # PaintCanvasVideoRendererWithGLTest.CopyVideoFrameYUVDataToGLTexture + # crashes without "deprecated-ambient-replace-as-executable". "//build/config/fuchsia/test/jit_capabilities.test-cmx", "//build/config/fuchsia/test/vulkan_capabilities.test-cmx", diff --git a/chromium/media/DIR_METADATA b/chromium/media/DIR_METADATA index 9f769ce7f98..2dc14a41ec9 100644 --- a/chromium/media/DIR_METADATA +++ b/chromium/media/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Media" diff --git a/chromium/media/audio/BUILD.gn b/chromium/media/audio/BUILD.gn index c68099d5baa..d7a46d050eb 100644 --- a/chromium/media/audio/BUILD.gn +++ b/chromium/media/audio/BUILD.gn @@ -201,6 +201,8 @@ source_set("audio") { "win/core_audio_util_win.h", "win/device_enumeration_win.cc", "win/device_enumeration_win.h", + "win/volume_range_util.cc", + "win/volume_range_util.h", "win/waveout_output_win.cc", "win/waveout_output_win.h", ] @@ -445,6 +447,7 @@ source_set("unit_tests") { if (use_cras) { sources += [ + "cras/audio_manager_chromeos_unittest.cc", "cras/cras_input_unittest.cc", "cras/cras_unified_unittest.cc", ] @@ -460,6 +463,7 @@ source_set("unit_tests") { "win/audio_session_event_listener_win_unittest.cc", "win/core_audio_util_win_unittest.cc", "win/device_enumeration_win_unittest.cc", + "win/volume_range_util_unittest.cc", ] } diff --git a/chromium/media/audio/DIR_METADATA b/chromium/media/audio/DIR_METADATA index 99031e09f7e..e80d793156b 100644 --- a/chromium/media/audio/DIR_METADATA +++ b/chromium/media/audio/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Media>Audio" diff --git a/chromium/media/audio/alsa/alsa_input.cc b/chromium/media/audio/alsa/alsa_input.cc index ee7c5d0305d..404516dcdcb 100644 --- a/chromium/media/audio/alsa/alsa_input.cc +++ b/chromium/media/audio/alsa/alsa_input.cc @@ -52,9 +52,9 @@ AlsaPcmInputStream::AlsaPcmInputStream(AudioManagerBase* audio_manager, AlsaPcmInputStream::~AlsaPcmInputStream() = default; -bool AlsaPcmInputStream::Open() { +AudioInputStream::OpenOutcome AlsaPcmInputStream::Open() { if (device_handle_) - return false; // Already open. + return OpenOutcome::kAlreadyOpen; uint32_t packet_us = buffer_duration_.InMicroseconds(); uint32_t buffer_us = packet_us * kNumPacketsInRingBuffer; @@ -91,7 +91,8 @@ bool AlsaPcmInputStream::Open() { } } - return device_handle_ != nullptr; + return device_handle_ != nullptr ? OpenOutcome::kSuccess + : OpenOutcome::kFailed; } void AlsaPcmInputStream::Start(AudioInputCallback* callback) { @@ -112,7 +113,7 @@ void AlsaPcmInputStream::Start(AudioInputCallback* callback) { } else { base::Thread::Options options; options.priority = base::ThreadPriority::REALTIME_AUDIO; - CHECK(capture_thread_.StartWithOptions(options)); + CHECK(capture_thread_.StartWithOptions(std::move(options))); // We start reading data half |buffer_duration_| later than when the // buffer might have got filled, to accommodate some delays in the audio diff --git a/chromium/media/audio/alsa/alsa_input.h b/chromium/media/audio/alsa/alsa_input.h index 09e525f826f..6301fba9afc 100644 --- a/chromium/media/audio/alsa/alsa_input.h +++ b/chromium/media/audio/alsa/alsa_input.h @@ -46,7 +46,7 @@ class MEDIA_EXPORT AlsaPcmInputStream ~AlsaPcmInputStream() override; // Implementation of AudioInputStream. - bool Open() override; + OpenOutcome Open() override; void Start(AudioInputCallback* callback) override; void Stop() override; void Close() override; diff --git a/chromium/media/audio/alsa/alsa_output.cc b/chromium/media/audio/alsa/alsa_output.cc index c2cc61d1d8c..c148f26b5ac 100644 --- a/chromium/media/audio/alsa/alsa_output.cc +++ b/chromium/media/audio/alsa/alsa_output.cc @@ -37,6 +37,7 @@ #include <stddef.h> #include <algorithm> +#include <memory> #include <utility> #include "base/bind.h" @@ -230,7 +231,7 @@ bool AlsaPcmOutputStream::Open() { channel_mixer_ ? mixed_audio_bus_->channels() * bytes_per_sample_ : bytes_per_frame_; uint32_t output_packet_size = frames_per_packet_ * bytes_per_output_frame_; - buffer_.reset(new SeekableBuffer(0, output_packet_size)); + buffer_ = std::make_unique<SeekableBuffer>(0, output_packet_size); // Get alsa buffer size. snd_pcm_uframes_t buffer_size; @@ -710,8 +711,8 @@ snd_pcm_t* AlsaPcmOutputStream::AutoSelectDevice(unsigned int latency) { // downmixing. uint32_t default_channels = channels_; if (default_channels > 2) { - channel_mixer_.reset( - new ChannelMixer(channel_layout_, kDefaultOutputChannelLayout)); + channel_mixer_ = std::make_unique<ChannelMixer>( + channel_layout_, kDefaultOutputChannelLayout); default_channels = 2; mixed_audio_bus_ = AudioBus::Create( default_channels, audio_bus_->frames()); diff --git a/chromium/media/audio/alsa/alsa_output_unittest.cc b/chromium/media/audio/alsa/alsa_output_unittest.cc index 9183721af1b..33fd1c5d0c8 100644 --- a/chromium/media/audio/alsa/alsa_output_unittest.cc +++ b/chromium/media/audio/alsa/alsa_output_unittest.cc @@ -80,7 +80,7 @@ class MockAudioManagerAlsa : public AudioManagerAlsa { class AlsaPcmOutputStreamTest : public testing::Test { protected: AlsaPcmOutputStreamTest() { - mock_manager_.reset(new StrictMock<MockAudioManagerAlsa>()); + mock_manager_ = std::make_unique<StrictMock<MockAudioManagerAlsa>>(); } ~AlsaPcmOutputStreamTest() override { mock_manager_->Shutdown(); } @@ -115,7 +115,7 @@ class AlsaPcmOutputStreamTest : public testing::Test { DCHECK(test_stream); packet_ = new DataBuffer(kTestPacketSize); packet_->set_data_size(kTestPacketSize); - test_stream->buffer_.reset(new SeekableBuffer(0, kTestPacketSize)); + test_stream->buffer_ = std::make_unique<SeekableBuffer>(0, kTestPacketSize); test_stream->buffer_->Append(packet_.get()); } diff --git a/chromium/media/audio/android/aaudio_output.cc b/chromium/media/audio/android/aaudio_output.cc index 9e9b53ab89b..c054f3910a2 100644 --- a/chromium/media/audio/android/aaudio_output.cc +++ b/chromium/media/audio/android/aaudio_output.cc @@ -4,7 +4,10 @@ #include "media/audio/android/aaudio_output.h" +#include "base/callback_helpers.h" #include "base/logging.h" +#include "base/thread_annotations.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "media/audio/android/aaudio_stubs.h" #include "media/audio/android/audio_manager_android.h" @@ -12,14 +15,58 @@ namespace media { +// Used to circumvent issues where the AAudio thread callbacks continue +// after AAudioStream_requestStop() completes. See crbug.com/1183255. +class LOCKABLE AAudioDestructionHelper { + public: + explicit AAudioDestructionHelper(AAudioOutputStream* stream) + : output_stream_(stream) {} + + ~AAudioDestructionHelper() { + DCHECK(is_closing_); + if (aaudio_stream_) + AAudioStream_close(aaudio_stream_); + } + + AAudioOutputStream* GetAndLockStream() EXCLUSIVE_LOCK_FUNCTION() { + lock_.Acquire(); + return is_closing_ ? nullptr : output_stream_; + } + + void UnlockStream() UNLOCK_FUNCTION() { lock_.Release(); } + + void DeferStreamClosure(AAudioStream* stream) { + base::AutoLock al(lock_); + DCHECK(!is_closing_); + + is_closing_ = true; + aaudio_stream_ = stream; + } + + private: + base::Lock lock_; + AAudioOutputStream* output_stream_ GUARDED_BY(lock_) = nullptr; + AAudioStream* aaudio_stream_ GUARDED_BY(lock_) = nullptr; + bool is_closing_ GUARDED_BY(lock_) = false; +}; + static aaudio_data_callback_result_t OnAudioDataRequestedCallback( AAudioStream* stream, void* user_data, void* audio_data, int32_t num_frames) { - AAudioOutputStream* output_stream = - reinterpret_cast<AAudioOutputStream*>(user_data); - return output_stream->OnAudioDataRequested(audio_data, num_frames); + AAudioDestructionHelper* destruction_helper = + reinterpret_cast<AAudioDestructionHelper*>(user_data); + + AAudioOutputStream* output_stream = destruction_helper->GetAndLockStream(); + + aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_STOP; + if (output_stream) + result = output_stream->OnAudioDataRequested(audio_data, num_frames); + + destruction_helper->UnlockStream(); + + return result; } static void OnStreamErrorCallback(AAudioStream* stream, @@ -38,7 +85,8 @@ AAudioOutputStream::AAudioOutputStream(AudioManagerAndroid* manager, usage_(usage), performance_mode_(AAUDIO_PERFORMANCE_MODE_NONE), ns_per_frame_(base::Time::kNanosecondsPerSecond / - static_cast<double>(params.sample_rate())) { + static_cast<double>(params.sample_rate())), + destruction_helper_(std::make_unique<AAudioDestructionHelper>(this)) { DCHECK(manager); DCHECK(params.IsValid()); @@ -66,6 +114,18 @@ AAudioOutputStream::AAudioOutputStream(AudioManagerAndroid* manager, AAudioOutputStream::~AAudioOutputStream() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // In R and earlier, it is possible for callbacks to still be running even + // after calling AAudioStream_close(). The code below is a mitigation to work + // around this issue. See crbug.com/1183255. + + // Keep |destruction_helper_| alive longer than |this|, so the |user_data| + // bound to the callback stays valid until the callbacks stop. + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce( + base::DoNothing::Once<std::unique_ptr<AAudioDestructionHelper>>(), + std::move(destruction_helper_)), + base::TimeDelta::FromMilliseconds(250)); } void AAudioOutputStream::Flush() {} @@ -90,7 +150,7 @@ bool AAudioOutputStream::Open() { // Callbacks AAudioStreamBuilder_setDataCallback(builder, OnAudioDataRequestedCallback, - this); + destruction_helper_.get()); AAudioStreamBuilder_setErrorCallback(builder, OnStreamErrorCallback, this); result = AAudioStreamBuilder_openStream(builder, &aaudio_stream_); @@ -120,13 +180,12 @@ void AAudioOutputStream::Close() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); Stop(); - if (aaudio_stream_) { - const auto result = AAudioStream_close(aaudio_stream_); - if (result != AAUDIO_OK) { - DLOG(ERROR) << "Failed to close audio stream, result: " - << AAudio_convertResultToText(result); - } - } + + // |destruction_helper_->GetStreamAndLock()| will return nullptr after this. + destruction_helper_->DeferStreamClosure(aaudio_stream_); + + // We shouldn't be acessing |aaudio_stream_| after it's stopped. + aaudio_stream_ = nullptr; // Note: This must be last, it will delete |this|. audio_manager_->ReleaseOutputStream(this); diff --git a/chromium/media/audio/android/aaudio_output.h b/chromium/media/audio/android/aaudio_output.h index 5c6b7b21de9..35343369e05 100644 --- a/chromium/media/audio/android/aaudio_output.h +++ b/chromium/media/audio/android/aaudio_output.h @@ -15,6 +15,7 @@ namespace media { +class AAudioDestructionHelper; class AudioManagerAndroid; class AAudioOutputStream : public MuteableAudioOutputStream { @@ -60,6 +61,10 @@ class AAudioOutputStream : public MuteableAudioOutputStream { AAudioStream* aaudio_stream_ = nullptr; + // Bound to the audio data callback. Outlives |this| in case the callbacks + // continue after |this| is destroyed. See crbug.com/1183255. + std::unique_ptr<AAudioDestructionHelper> destruction_helper_; + // Lock protects all members below which may be read concurrently from the // audio manager thread and the OS provided audio thread. base::Lock lock_; @@ -74,4 +79,4 @@ class AAudioOutputStream : public MuteableAudioOutputStream { } // namespace media -#endif // MEDIA_AUDIO_ANDROID_AAUDIO_OUTPUT_H_
\ No newline at end of file +#endif // MEDIA_AUDIO_ANDROID_AAUDIO_OUTPUT_H_ diff --git a/chromium/media/audio/android/audio_android_unittest.cc b/chromium/media/audio/android/audio_android_unittest.cc index 8dfff9017f1..20e696fc555 100644 --- a/chromium/media/audio/android/audio_android_unittest.cc +++ b/chromium/media/audio/android/audio_android_unittest.cc @@ -241,7 +241,7 @@ class FileAudioSink : public AudioInputStream::AudioInputCallback { // Allocate space for ~10 seconds of data. const int kMaxBufferSize = 10 * params.sample_rate() * params.GetBytesPerFrame(kSampleFormat); - buffer_.reset(new media::SeekableBuffer(0, kMaxBufferSize)); + buffer_ = std::make_unique<media::SeekableBuffer>(0, kMaxBufferSize); // Open up the binary file which will be written to in the destructor. base::FilePath file_path; @@ -314,7 +314,7 @@ class FullDuplexAudioSinkSource // Start with a reasonably small FIFO size. It will be increased // dynamically during the test if required. size_t buffer_size = params.GetBytesPerBuffer(kSampleFormat); - fifo_.reset(new media::SeekableBuffer(0, 2 * buffer_size)); + fifo_ = std::make_unique<media::SeekableBuffer>(0, 2 * buffer_size); buffer_.reset(new uint8_t[buffer_size]); } @@ -691,14 +691,16 @@ class AudioAndroidInputTest : public AudioAndroidOutputTest, void OpenAndClose() { DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread()); - EXPECT_TRUE(audio_input_stream_->Open()); + EXPECT_EQ(audio_input_stream_->Open(), + AudioInputStream::OpenOutcome::kSuccess); audio_input_stream_->Close(); audio_input_stream_ = nullptr; } void OpenAndStart(AudioInputStream::AudioInputCallback* sink) { DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread()); - EXPECT_TRUE(audio_input_stream_->Open()); + EXPECT_EQ(audio_input_stream_->Open(), + AudioInputStream::OpenOutcome::kSuccess); audio_input_stream_->Start(sink); } diff --git a/chromium/media/audio/android/audio_manager_android.h b/chromium/media/audio/android/audio_manager_android.h index 742c4bbf54c..a58a4e1ddf5 100644 --- a/chromium/media/audio/android/audio_manager_android.h +++ b/chromium/media/audio/android/audio_manager_android.h @@ -122,7 +122,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase { // input stream is destroyed. Also affects the stream type of output streams. bool communication_mode_is_on_; - base::Optional<bool> is_aaudio_available_; + absl::optional<bool> is_aaudio_available_; // If set, overrides volume level on output streams bool output_volume_override_set_; diff --git a/chromium/media/audio/android/muteable_audio_output_stream.h b/chromium/media/audio/android/muteable_audio_output_stream.h index 8ef13a640dd..db4f6b19cb5 100644 --- a/chromium/media/audio/android/muteable_audio_output_stream.h +++ b/chromium/media/audio/android/muteable_audio_output_stream.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_MUTEABLE_AUDIO_OUTPUT_STREAM_H_ -#define MEDIA_MUTEABLE_AUDIO_OUTPUT_STREAM_H_ +#ifndef MEDIA_AUDIO_ANDROID_MUTEABLE_AUDIO_OUTPUT_STREAM_H_ +#define MEDIA_AUDIO_ANDROID_MUTEABLE_AUDIO_OUTPUT_STREAM_H_ #include "media/audio/audio_io.h" @@ -20,4 +20,4 @@ class MEDIA_EXPORT MuteableAudioOutputStream : public AudioOutputStream { } // namespace media -#endif // MEDIA_MUTEABLE_AUDIO_OUTPUT_STREAM_H_ +#endif // MEDIA_AUDIO_ANDROID_MUTEABLE_AUDIO_OUTPUT_STREAM_H_ diff --git a/chromium/media/audio/android/opensles_input.cc b/chromium/media/audio/android/opensles_input.cc index 5949e7dee00..695277ed7f9 100644 --- a/chromium/media/audio/android/opensles_input.cc +++ b/chromium/media/audio/android/opensles_input.cc @@ -63,18 +63,17 @@ OpenSLESInputStream::~OpenSLESInputStream() { DCHECK(!audio_data_[0]); } -bool OpenSLESInputStream::Open() { +AudioInputStream::OpenOutcome OpenSLESInputStream::Open() { DVLOG(2) << __PRETTY_FUNCTION__; DCHECK(thread_checker_.CalledOnValidThread()); if (engine_object_.Get()) - return false; + return AudioInputStream::OpenOutcome::kFailed; if (!CreateRecorder()) - return false; + return AudioInputStream::OpenOutcome::kFailed; SetupAudioBuffer(); - - return true; + return AudioInputStream::OpenOutcome::kSuccess; } void OpenSLESInputStream::Start(AudioInputCallback* callback) { diff --git a/chromium/media/audio/android/opensles_input.h b/chromium/media/audio/android/opensles_input.h index a3afed0ed77..ee354f214ae 100644 --- a/chromium/media/audio/android/opensles_input.h +++ b/chromium/media/audio/android/opensles_input.h @@ -38,7 +38,7 @@ class OpenSLESInputStream : public AudioInputStream { ~OpenSLESInputStream() override; // Implementation of AudioInputStream. - bool Open() override; + OpenOutcome Open() override; void Start(AudioInputCallback* callback) override; void Stop() override; void Close() override; diff --git a/chromium/media/audio/audio_encoders_unittest.cc b/chromium/media/audio/audio_encoders_unittest.cc index c5fd70ceca1..d81a6729c5e 100644 --- a/chromium/media/audio/audio_encoders_unittest.cc +++ b/chromium/media/audio/audio_encoders_unittest.cc @@ -69,7 +69,7 @@ class AudioEncodersTest : public ::testing::TestWithParam<TestAudioParams> { AudioEncodersTest& operator=(const AudioEncodersTest&) = delete; ~AudioEncodersTest() override = default; - using MaybeDesc = base::Optional<AudioEncoder::CodecDescription>; + using MaybeDesc = absl::optional<AudioEncoder::CodecDescription>; AudioEncoder* encoder() const { return encoder_.get(); } diff --git a/chromium/media/audio/audio_features.cc b/chromium/media/audio/audio_features.cc index d231e8f0f29..dd1c1f30fac 100644 --- a/chromium/media/audio/audio_features.cc +++ b/chromium/media/audio/audio_features.cc @@ -33,10 +33,19 @@ const base::Feature kUseAAudioDriver{"UseAAudioDriver", #endif #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) -const base::Feature kCrOSSystemAEC{"CrOSSystemAEC", +const base::Feature kCrOSSystemAEC{"CrOSSystemAECWithBoardTuningsAllowed", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kCrOSSystemAECDeactivatedGroups{ "CrOSSystemAECDeactivatedGroups", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kCrOSEnforceSystemAecNsAgc{ + "CrOSEnforceSystemAecNsAgc", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kCrOSEnforceSystemAecNs{"CrOSEnforceSystemAecNs", + base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kCrOSEnforceSystemAecAgc{"CrOSEnforceSystemAecAgc", + base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kCrOSEnforceSystemAec{"CrOSEnforceSystemAec", + base::FEATURE_DISABLED_BY_DEFAULT}; + #endif #if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) diff --git a/chromium/media/audio/audio_features.h b/chromium/media/audio/audio_features.h index 0f3dcde21b0..38bcf40e464 100644 --- a/chromium/media/audio/audio_features.h +++ b/chromium/media/audio/audio_features.h @@ -22,6 +22,10 @@ MEDIA_EXPORT extern const base::Feature kUseAAudioDriver; #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS) MEDIA_EXPORT extern const base::Feature kCrOSSystemAEC; MEDIA_EXPORT extern const base::Feature kCrOSSystemAECDeactivatedGroups; +MEDIA_EXPORT extern const base::Feature kCrOSEnforceSystemAecNsAgc; +MEDIA_EXPORT extern const base::Feature kCrOSEnforceSystemAecNs; +MEDIA_EXPORT extern const base::Feature kCrOSEnforceSystemAecAgc; +MEDIA_EXPORT extern const base::Feature kCrOSEnforceSystemAec; #endif #if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) diff --git a/chromium/media/audio/audio_input_device.cc b/chromium/media/audio/audio_input_device.cc index 9e09e005df0..803c1430101 100644 --- a/chromium/media/audio/audio_input_device.cc +++ b/chromium/media/audio/audio_input_device.cc @@ -9,7 +9,6 @@ #include <vector> #include "base/bind.h" -#include "base/callback_forward.h" #include "base/callback_helpers.h" #include "base/format_macros.h" #include "base/logging.h" @@ -291,7 +290,7 @@ void AudioInputDevice::OnStreamCreated( alive_checker_->Start(); } -void AudioInputDevice::OnError() { +void AudioInputDevice::OnError(AudioCapturerSource::ErrorCode code) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); TRACE_EVENT0("audio", "AudioInputDevice::OnError"); @@ -299,7 +298,6 @@ void AudioInputDevice::OnError() { if (state_ < CREATING_STREAM) return; - if (state_ == CREATING_STREAM) { // At this point, we haven't attempted to start the audio thread. // Accessing the hardware might have failed or we may have reached @@ -309,7 +307,10 @@ void AudioInputDevice::OnError() { // a local audio source). had_error_ = kErrorDuringCreation; callback_->OnCaptureError( - "Maximum allowed input device limit reached or OS failure."); + code, code == AudioCapturerSource::ErrorCode::kSystemPermissions + ? "Unable to open due to failing an OS Permissions check." + : "Maximum allowed input device limit reached or an OS " + "failure occured."); } else { // Don't dereference the callback object if the audio thread // is stopped or stopping. That could mean that the callback @@ -319,7 +320,7 @@ void AudioInputDevice::OnError() { // a callback object via Start() and clear it in Stop(). had_error_ = kErrorDuringCapture; if (audio_thread_) - callback_->OnCaptureError("IPC delegate state error."); + callback_->OnCaptureError(code, "IPC delegate state error."); } } @@ -352,7 +353,8 @@ AudioInputDevice::~AudioInputDevice() { } void AudioInputDevice::DetectedDeadInputStream() { - callback_->OnCaptureError("No audio received from audio capture device."); + callback_->OnCaptureError(media::AudioCapturerSource::ErrorCode::kUnknown, + "No audio received from audio capture device."); } // AudioInputDevice::AudioThreadCallback @@ -432,14 +434,16 @@ void AudioInputDevice::AudioThreadCallback::Process(uint32_t pending_data) { "Incorrect buffer sequence. Expected = %u. Actual = %u.", last_buffer_id_ + 1, buffer->params.id); LOG(ERROR) << message; - capture_callback_->OnCaptureError(message); + capture_callback_->OnCaptureError( + media::AudioCapturerSource::ErrorCode::kUnknown, message); } if (current_segment_id_ != pending_data) { std::string message = base::StringPrintf( "Segment id not matching. Remote = %u. Local = %" PRIuS ".", pending_data, current_segment_id_); LOG(ERROR) << message; - capture_callback_->OnCaptureError(message); + capture_callback_->OnCaptureError( + media::AudioCapturerSource::ErrorCode::kUnknown, message); } last_buffer_id_ = buffer->params.id; diff --git a/chromium/media/audio/audio_input_device.h b/chromium/media/audio/audio_input_device.h index 219b79301d8..ab9d0991cf6 100644 --- a/chromium/media/audio/audio_input_device.h +++ b/chromium/media/audio/audio_input_device.h @@ -51,16 +51,15 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/read_only_shared_memory_region.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/threading/platform_thread.h" -#include "base/time/time.h" #include "media/audio/alive_checker.h" #include "media/audio/audio_device_thread.h" #include "media/audio/audio_input_ipc.h" #include "media/base/audio_capturer_source.h" #include "media/base/audio_parameters.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -117,7 +116,7 @@ class MEDIA_EXPORT AudioInputDevice : public AudioCapturerSource, void OnStreamCreated(base::ReadOnlySharedMemoryRegion shared_memory_region, base::SyncSocket::ScopedHandle socket_handle, bool initially_muted) override; - void OnError() override; + void OnError(AudioCapturerSource::ErrorCode code) override; void OnMuted(bool is_muted) override; void OnIPCClosed() override; @@ -161,7 +160,7 @@ class MEDIA_EXPORT AudioInputDevice : public AudioCapturerSource, // Cache the output device used for AEC in case it's called before the stream // is created. - base::Optional<std::string> output_device_id_for_aec_; + absl::optional<std::string> output_device_id_for_aec_; DISALLOW_IMPLICIT_CONSTRUCTORS(AudioInputDevice); }; diff --git a/chromium/media/audio/audio_input_device_unittest.cc b/chromium/media/audio/audio_input_device_unittest.cc index d951d344522..b0c1eba928a 100644 --- a/chromium/media/audio/audio_input_device_unittest.cc +++ b/chromium/media/audio/audio_input_device_unittest.cc @@ -57,7 +57,9 @@ class MockCaptureCallback : public AudioCapturerSource::CaptureCallback { double volume, bool key_pressed)); - MOCK_METHOD1(OnCaptureError, void(const std::string& message)); + MOCK_METHOD2(OnCaptureError, + void(AudioCapturerSource::ErrorCode code, + const std::string& message)); MOCK_METHOD1(OnCaptureMuted, void(bool is_muted)); }; @@ -77,7 +79,8 @@ TEST_P(AudioInputDeviceTest, Noop) { } ACTION_P(ReportStateChange, device) { - static_cast<AudioInputIPCDelegate*>(device)->OnError(); + static_cast<AudioInputIPCDelegate*>(device)->OnError( + media::AudioCapturerSource::ErrorCode::kUnknown); } // Verify that we get an OnCaptureError() callback if CreateStream fails. @@ -93,7 +96,8 @@ TEST_P(AudioInputDeviceTest, FailToCreateStream) { device->Initialize(params, &callback); EXPECT_CALL(*input_ipc, CreateStream(_, _, _, _)) .WillOnce(ReportStateChange(device.get())); - EXPECT_CALL(callback, OnCaptureError(_)); + EXPECT_CALL(callback, + OnCaptureError(AudioCapturerSource::ErrorCode::kUnknown, _)); EXPECT_CALL(*input_ipc, CloseStream()); device->Start(); device->Stop(); diff --git a/chromium/media/audio/audio_input_ipc.h b/chromium/media/audio/audio_input_ipc.h index 1f2192a3a6a..28663a98ab5 100644 --- a/chromium/media/audio/audio_input_ipc.h +++ b/chromium/media/audio/audio_input_ipc.h @@ -9,6 +9,7 @@ #include "base/memory/read_only_shared_memory_region.h" #include "base/sync_socket.h" +#include "media/base/audio_capturer_source.h" #include "media/base/audio_parameters.h" #include "media/base/media_export.h" @@ -30,7 +31,7 @@ class MEDIA_EXPORT AudioInputIPCDelegate { bool initially_muted) = 0; // Called when state of an audio stream has changed. - virtual void OnError() = 0; + virtual void OnError(AudioCapturerSource::ErrorCode code) = 0; // Called when an audio stream is muted or unmuted. virtual void OnMuted(bool is_muted) = 0; diff --git a/chromium/media/audio/audio_input_stream_data_interceptor.cc b/chromium/media/audio/audio_input_stream_data_interceptor.cc index b50303851f5..332b3aeaf79 100644 --- a/chromium/media/audio/audio_input_stream_data_interceptor.cc +++ b/chromium/media/audio/audio_input_stream_data_interceptor.cc @@ -24,13 +24,13 @@ AudioInputStreamDataInterceptor::~AudioInputStreamDataInterceptor() { } // Implementation of AudioInputStream. -bool AudioInputStreamDataInterceptor::Open() { +AudioInputStream::OpenOutcome AudioInputStreamDataInterceptor::Open() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return stream_->Open(); } void AudioInputStreamDataInterceptor::Start( - media::AudioInputStream::AudioInputCallback* callback) { + AudioInputStream::AudioInputCallback* callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); callback_ = callback; debug_recorder_ = create_debug_recorder_cb_.Run(); diff --git a/chromium/media/audio/audio_input_stream_data_interceptor.h b/chromium/media/audio/audio_input_stream_data_interceptor.h index 383a28b329e..6794267c840 100644 --- a/chromium/media/audio/audio_input_stream_data_interceptor.h +++ b/chromium/media/audio/audio_input_stream_data_interceptor.h @@ -36,7 +36,7 @@ class MEDIA_EXPORT AudioInputStreamDataInterceptor ~AudioInputStreamDataInterceptor() override; // Implementation of AudioInputStream. - bool Open() override; + OpenOutcome Open() override; void Start(AudioInputStream::AudioInputCallback* callback) override; void Stop() override; void Close() override; diff --git a/chromium/media/audio/audio_input_stream_data_interceptor_unittest.cc b/chromium/media/audio/audio_input_stream_data_interceptor_unittest.cc index 6e560003b04..3a2ec62f218 100644 --- a/chromium/media/audio/audio_input_stream_data_interceptor_unittest.cc +++ b/chromium/media/audio/audio_input_stream_data_interceptor_unittest.cc @@ -30,7 +30,7 @@ class MockStream : public AudioInputStream { public: MockStream() = default; ~MockStream() override = default; - MOCK_METHOD0(Open, bool()); + MOCK_METHOD0(Open, AudioInputStream::OpenOutcome()); MOCK_METHOD1(Start, void(AudioInputStream::AudioInputCallback*)); MOCK_METHOD0(Stop, void()); MOCK_METHOD0(Close, void()); diff --git a/chromium/media/audio/audio_input_unittest.cc b/chromium/media/audio/audio_input_unittest.cc index ddaba1dd45c..cd9195987c6 100644 --- a/chromium/media/audio/audio_input_unittest.cc +++ b/chromium/media/audio/audio_input_unittest.cc @@ -145,7 +145,8 @@ class AudioInputTest : public testing::Test { void OpenAndClose() { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); ASSERT_TRUE(audio_input_stream_); - EXPECT_TRUE(audio_input_stream_->Open()); + EXPECT_EQ(audio_input_stream_->Open(), + AudioInputStream::OpenOutcome::kSuccess); audio_input_stream_->Close(); audio_input_stream_ = nullptr; } @@ -153,14 +154,16 @@ class AudioInputTest : public testing::Test { void OpenAndStart(AudioInputStream::AudioInputCallback* sink) { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); ASSERT_TRUE(audio_input_stream_); - EXPECT_TRUE(audio_input_stream_->Open()); + EXPECT_EQ(audio_input_stream_->Open(), + AudioInputStream::OpenOutcome::kSuccess); audio_input_stream_->Start(sink); } void OpenStopAndClose() { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); ASSERT_TRUE(audio_input_stream_); - EXPECT_TRUE(audio_input_stream_->Open()); + EXPECT_EQ(audio_input_stream_->Open(), + AudioInputStream::OpenOutcome::kSuccess); audio_input_stream_->Stop(); audio_input_stream_->Close(); audio_input_stream_ = nullptr; diff --git a/chromium/media/audio/audio_io.h b/chromium/media/audio/audio_io.h index ae9111ab575..e574390d52e 100644 --- a/chromium/media/audio/audio_io.h +++ b/chromium/media/audio/audio_io.h @@ -39,7 +39,6 @@ // Specifically for this case we avoid supporting complex formats such as MP3 // or WMA. Complex format decoding should be done by the renderers. - // Models an audio stream that gets rendered to the audio hardware output. // Because we support more audio streams than physically available channels // a given AudioOutputStream might or might not talk directly to hardware. @@ -155,9 +154,18 @@ class MEDIA_EXPORT AudioInputStream { virtual ~AudioInputStream() {} + enum class OpenOutcome { + kSuccess, + kAlreadyOpen, + // Failed due to an unknown or unspecified reason. + kFailed, + // Failed to open due to OS-level System permissions. + kFailedSystemPermissions, + }; + // Open the stream and prepares it for recording. Call Start() to actually // begin recording. - virtual bool Open() = 0; + virtual OpenOutcome Open() = 0; // Starts recording audio and generating AudioInputCallback::OnData(). // The input stream does not take ownership of this callback. diff --git a/chromium/media/audio/audio_low_latency_input_output_unittest.cc b/chromium/media/audio/audio_low_latency_input_output_unittest.cc index 859181d3e33..eca3b36754d 100644 --- a/chromium/media/audio/audio_low_latency_input_output_unittest.cc +++ b/chromium/media/audio/audio_low_latency_input_output_unittest.cc @@ -119,11 +119,11 @@ class FullDuplexAudioSinkSource // Start with the smallest possible buffer size. It will be increased // dynamically during the test if required. - buffer_.reset( - new media::SeekableBuffer(0, samples_per_packet_ * frame_size_)); + buffer_ = std::make_unique<media::SeekableBuffer>( + 0, samples_per_packet_ * frame_size_); frames_to_ms_ = static_cast<double>(1000.0 / sample_rate_); - delay_states_.reset(new AudioDelayState[kMaxDelayMeasurements]); + delay_states_ = std::make_unique<AudioDelayState[]>(kMaxDelayMeasurements); } ~FullDuplexAudioSinkSource() override { @@ -378,7 +378,7 @@ TEST_F(AudioLowLatencyInputOutputTest, DISABLED_FullDuplexDelayMeasurement) { return; } - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); EXPECT_TRUE(aos->Open()); FullDuplexAudioSinkSource full_duplex( diff --git a/chromium/media/audio/audio_manager.cc b/chromium/media/audio/audio_manager.cc index ff94c386043..f04c67116c0 100644 --- a/chromium/media/audio/audio_manager.cc +++ b/chromium/media/audio/audio_manager.cc @@ -6,6 +6,7 @@ #include <stdint.h> +#include <memory> #include <utility> #include "base/bind.h" @@ -16,7 +17,6 @@ #include "base/metrics/histogram_macros.h" #include "base/power_monitor/power_monitor.h" #include "base/single_thread_task_runner.h" -#include "base/strings/stringprintf.h" #include "base/thread_annotations.h" #include "build/build_config.h" #include "media/audio/fake_audio_log_factory.h" @@ -44,7 +44,8 @@ class AudioManagerHelper { // This should be called before creating an AudioManager in tests to ensure // that the creating thread is COM initialized. void InitializeCOMForTesting() { - com_initializer_for_testing_.reset(new base::win::ScopedCOMInitializer()); + com_initializer_for_testing_ = + std::make_unique<base::win::ScopedCOMInitializer>(); } #endif diff --git a/chromium/media/audio/audio_manager_base.cc b/chromium/media/audio/audio_manager_base.cc index 2f97c51cbd4..f7d31c9c3ae 100644 --- a/chromium/media/audio/audio_manager_base.cc +++ b/chromium/media/audio/audio_manager_base.cc @@ -11,7 +11,6 @@ #include "base/command_line.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" @@ -25,6 +24,7 @@ #include "media/audio/fake_audio_input_stream.h" #include "media/audio/fake_audio_output_stream.h" #include "media/base/media_switches.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "base/logging.h" #include "build/chromeos_buildflags.h" @@ -332,7 +332,7 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( const std::string& device_id) { CHECK(GetTaskRunner()->BelongsToCurrentThread()); DCHECK(params.IsValid()); - base::Optional<StreamFormat> uma_stream_format; + absl::optional<StreamFormat> uma_stream_format; // If the caller supplied an empty device id to select the default device, // we fetch the actual device id of the default device so that the lookup diff --git a/chromium/media/audio/audio_manager_unittest.cc b/chromium/media/audio/audio_manager_unittest.cc index 85aba43cd33..c4ced09ce28 100644 --- a/chromium/media/audio/audio_manager_unittest.cc +++ b/chromium/media/audio/audio_manager_unittest.cc @@ -137,7 +137,8 @@ const AudioNode kInternalSpeaker(false, "Speaker", false, 0, - 2); + 2, + 0); const AudioNode kInternalMic(true, kInternalMicId, @@ -149,7 +150,8 @@ const AudioNode kInternalMic(true, "Internal Mic", false, 0, - 1); + 1, + 1); // EFFECT_TYPE_NOISE_CANCELLATION const AudioNode kJabraSpeaker1(false, kJabraSpeaker1Id, @@ -161,7 +163,8 @@ const AudioNode kJabraSpeaker1(false, "Jabra Speaker 1", false, 0, - 2); // expects CHANNEL_LAYOUT_STEREO + 2, // expects CHANNEL_LAYOUT_STEREO + 0); const AudioNode kJabraSpeaker2(false, kJabraSpeaker2Id, @@ -173,7 +176,8 @@ const AudioNode kJabraSpeaker2(false, "Jabra Speaker 2", false, 0, - 6); // expects CHANNEL_LAYOUT_5_1 + 6, // expects CHANNEL_LAYOUT_5_1 + 0); const AudioNode kHDMIOutput(false, kHDMIOutputId, @@ -185,7 +189,8 @@ const AudioNode kHDMIOutput(false, "HDA Intel MID", false, 0, - 8); // expects CHANNEL_LAYOUT_7_1 + 8, // expects CHANNEL_LAYOUT_7_1 + 0); const AudioNode kJabraMic1(true, kJabraMic1Id, @@ -197,7 +202,8 @@ const AudioNode kJabraMic1(true, "Jabra Mic 1", false, 0, - 1); + 1, + 0); const AudioNode kJabraMic2(true, kJabraMic2Id, @@ -209,7 +215,8 @@ const AudioNode kJabraMic2(true, "Jabra Mic 2", false, 0, - 1); + 1, + 0); const AudioNode kUSBCameraMic(true, kWebcamMicId, @@ -221,7 +228,8 @@ const AudioNode kUSBCameraMic(true, "Logitech Webcam", false, 0, - 1); + 1, + 0); #endif // defined(USE_CRAS) const char kRealDefaultInputDeviceID[] = "input2"; diff --git a/chromium/media/audio/audio_opus_encoder.cc b/chromium/media/audio/audio_opus_encoder.cc index 03bcef1993a..7a3a45100d3 100644 --- a/chromium/media/audio/audio_opus_encoder.cc +++ b/chromium/media/audio/audio_opus_encoder.cc @@ -275,7 +275,7 @@ void AudioOpusEncoder::OnFifoOutput(const AudioBus& output_bus, // If |result| in {0,1}, do nothing; the documentation says that a return // value of zero or one means the packet does not need to be transmitted. if (encoded_data_size > 1) { - base::Optional<CodecDescription> desc; + absl::optional<CodecDescription> desc; if (need_to_emit_extra_data_) { desc = PrepareExtraData(); need_to_emit_extra_data_ = false; diff --git a/chromium/media/audio/audio_opus_encoder.h b/chromium/media/audio/audio_opus_encoder.h index 0c1f45a413e..fcef6b60835 100644 --- a/chromium/media/audio/audio_opus_encoder.h +++ b/chromium/media/audio/audio_opus_encoder.h @@ -8,12 +8,12 @@ #include <memory> #include <vector> -#include "base/optional.h" #include "media/base/audio_bus.h" #include "media/base/audio_converter.h" #include "media/base/audio_encoder.h" #include "media/base/audio_push_fifo.h" #include "media/base/audio_timestamp_helper.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/opus/src/include/opus.h" namespace media { diff --git a/chromium/media/audio/audio_output_device.h b/chromium/media/audio/audio_output_device.h index c7686e01768..97704136e85 100644 --- a/chromium/media/audio/audio_output_device.h +++ b/chromium/media/audio/audio_output_device.h @@ -208,7 +208,7 @@ class MEDIA_EXPORT AudioOutputDevice : public AudioRendererSink, // received in OnDeviceAuthorized(). std::string matched_device_id_; - base::Optional<base::UnguessableToken> processing_id_; + absl::optional<base::UnguessableToken> processing_id_; // In order to avoid a race between OnStreamCreated and Stop(), we use this // guard to control stopping and starting the audio thread. diff --git a/chromium/media/audio/audio_output_device_thread_callback.h b/chromium/media/audio/audio_output_device_thread_callback.h index 84b80d9af78..ba3fac80fbc 100644 --- a/chromium/media/audio/audio_output_device_thread_callback.h +++ b/chromium/media/audio/audio_output_device_thread_callback.h @@ -8,9 +8,9 @@ #include <memory> #include "base/memory/unsafe_shared_memory_region.h" -#include "base/optional.h" #include "media/audio/audio_device_thread.h" #include "media/base/audio_renderer_sink.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { diff --git a/chromium/media/audio/audio_output_device_unittest.cc b/chromium/media/audio/audio_output_device_unittest.cc index ed5547fe088..768156d41ce 100644 --- a/chromium/media/audio/audio_output_device_unittest.cc +++ b/chromium/media/audio/audio_output_device_unittest.cc @@ -75,7 +75,7 @@ class MockAudioOutputIPC : public AudioOutputIPC { CreateStream, void(AudioOutputIPCDelegate* delegate, const AudioParameters& params, - const base::Optional<base::UnguessableToken>& processing_id)); + const absl::optional<base::UnguessableToken>& processing_id)); MOCK_METHOD0(PlayStream, void()); MOCK_METHOD0(PauseStream, void()); MOCK_METHOD0(FlushStream, void()); diff --git a/chromium/media/audio/audio_output_dispatcher_impl.cc b/chromium/media/audio/audio_output_dispatcher_impl.cc index 439331d5edd..a8c428caf51 100644 --- a/chromium/media/audio/audio_output_dispatcher_impl.cc +++ b/chromium/media/audio/audio_output_dispatcher_impl.cc @@ -9,8 +9,8 @@ #include "base/bind.h" #include "base/compiler_specific.h" +#include "base/containers/contains.h" #include "base/single_thread_task_runner.h" -#include "base/stl_util.h" #include "base/time/time.h" #include "media/audio/audio_logging.h" #include "media/audio/audio_manager.h" diff --git a/chromium/media/audio/audio_output_ipc.h b/chromium/media/audio/audio_output_ipc.h index 0b83581d93b..77198786b63 100644 --- a/chromium/media/audio/audio_output_ipc.h +++ b/chromium/media/audio/audio_output_ipc.h @@ -86,7 +86,7 @@ class MEDIA_EXPORT AudioOutputIPC { virtual void CreateStream( AudioOutputIPCDelegate* delegate, const AudioParameters& params, - const base::Optional<base::UnguessableToken>& processing_id) = 0; + const absl::optional<base::UnguessableToken>& processing_id) = 0; // Starts playing the stream. This should generate a call to // AudioOutputController::Play(). diff --git a/chromium/media/audio/audio_output_stream_sink.h b/chromium/media/audio/audio_output_stream_sink.h index 1c3eefe6741..fcc8bc14b3d 100644 --- a/chromium/media/audio/audio_output_stream_sink.h +++ b/chromium/media/audio/audio_output_stream_sink.h @@ -7,8 +7,6 @@ #include <stdint.h> -#include <string> - #include "base/compiler_specific.h" #include "base/macros.h" #include "base/single_thread_task_runner.h" diff --git a/chromium/media/audio/audio_sink_parameters.h b/chromium/media/audio/audio_sink_parameters.h index a51f1b82bc7..45b89b3127f 100644 --- a/chromium/media/audio/audio_sink_parameters.h +++ b/chromium/media/audio/audio_sink_parameters.h @@ -7,9 +7,9 @@ #include <string> -#include "base/optional.h" #include "base/unguessable_token.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -31,7 +31,7 @@ struct MEDIA_EXPORT AudioSinkParameters final { base::UnguessableToken session_id; std::string device_id; - base::Optional<base::UnguessableToken> processing_id; + absl::optional<base::UnguessableToken> processing_id; }; } // namespace media diff --git a/chromium/media/audio/audio_source_parameters.h b/chromium/media/audio/audio_source_parameters.h index 96e1c1960ab..efd2da31abd 100644 --- a/chromium/media/audio/audio_source_parameters.h +++ b/chromium/media/audio/audio_source_parameters.h @@ -5,12 +5,10 @@ #ifndef MEDIA_AUDIO_AUDIO_SOURCE_PARAMETERS_H_ #define MEDIA_AUDIO_AUDIO_SOURCE_PARAMETERS_H_ -#include <string> - -#include "base/optional.h" #include "base/unguessable_token.h" #include "media/base/audio_processing.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -33,7 +31,7 @@ struct MEDIA_EXPORT AudioSourceParameters final { AudioProcessingSettings settings; }; - base::Optional<ProcessingConfig> processing; + absl::optional<ProcessingConfig> processing; }; } // namespace media diff --git a/chromium/media/audio/audio_system.h b/chromium/media/audio/audio_system.h index c01f8d75e84..9701570bb73 100644 --- a/chromium/media/audio/audio_system.h +++ b/chromium/media/audio/audio_system.h @@ -8,10 +8,10 @@ #include <string> #include "base/callback.h" -#include "base/optional.h" #include "media/audio/audio_device_description.h" #include "media/base/audio_parameters.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -33,12 +33,12 @@ class MEDIA_EXPORT AudioSystem { // std::string. If optional matched output device id is empty, it means there // is no associated output device. using OnAudioParamsCallback = - base::OnceCallback<void(const base::Optional<AudioParameters>&)>; + base::OnceCallback<void(const absl::optional<AudioParameters>&)>; using OnDeviceIdCallback = - base::OnceCallback<void(const base::Optional<std::string>&)>; + base::OnceCallback<void(const absl::optional<std::string>&)>; using OnInputDeviceInfoCallback = - base::OnceCallback<void(const base::Optional<AudioParameters>&, - const base::Optional<std::string>&)>; + base::OnceCallback<void(const absl::optional<AudioParameters>&, + const absl::optional<std::string>&)>; using OnBoolCallback = base::OnceCallback<void(bool)>; using OnDeviceDescriptionsCallback = diff --git a/chromium/media/audio/audio_system_helper.cc b/chromium/media/audio/audio_system_helper.cc index e1a741726a5..ad026bc699c 100644 --- a/chromium/media/audio/audio_system_helper.cc +++ b/chromium/media/audio/audio_system_helper.cc @@ -12,7 +12,7 @@ namespace media { namespace { -base::Optional<AudioParameters> TryToFixChannels( +absl::optional<AudioParameters> TryToFixChannels( const AudioParameters& params) { DCHECK(!params.IsValid()); AudioParameters params_copy(params); @@ -26,7 +26,7 @@ base::Optional<AudioParameters> TryToFixChannels( } return params_copy.IsValid() ? params_copy - : base::Optional<AudioParameters>(); + : absl::optional<AudioParameters>(); } } // namespace @@ -83,7 +83,7 @@ void AudioSystemHelper::GetAssociatedOutputDeviceID( const std::string associated_output_device_id = audio_manager_->GetAssociatedOutputDeviceID(input_device_id); std::move(on_device_id_cb) - .Run(associated_output_device_id.empty() ? base::Optional<std::string>() + .Run(associated_output_device_id.empty() ? absl::optional<std::string>() : associated_output_device_id); } @@ -95,11 +95,11 @@ void AudioSystemHelper::GetInputDeviceInfo( audio_manager_->GetAssociatedOutputDeviceID(input_device_id); std::move(on_input_device_info_cb) .Run(ComputeInputParameters(input_device_id), - associated_output_device_id.empty() ? base::Optional<std::string>() + associated_output_device_id.empty() ? absl::optional<std::string>() : associated_output_device_id); } -base::Optional<AudioParameters> AudioSystemHelper::ComputeInputParameters( +absl::optional<AudioParameters> AudioSystemHelper::ComputeInputParameters( const std::string& device_id) { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); @@ -111,17 +111,17 @@ base::Optional<AudioParameters> AudioSystemHelper::ComputeInputParameters( // AudioManager::GetInputStreamParameters will check |device_id| and // query the correct device for audio parameters by itself. if (!audio_manager_->HasAudioOutputDevices()) - return base::Optional<AudioParameters>(); + return absl::optional<AudioParameters>(); } else { if (!audio_manager_->HasAudioInputDevices()) - return base::Optional<AudioParameters>(); + return absl::optional<AudioParameters>(); } AudioParameters params = audio_manager_->GetInputStreamParameters(device_id); return params.IsValid() ? params : TryToFixChannels(params); } -base::Optional<AudioParameters> AudioSystemHelper::ComputeOutputParameters( +absl::optional<AudioParameters> AudioSystemHelper::ComputeOutputParameters( const std::string& device_id) { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); @@ -129,7 +129,7 @@ base::Optional<AudioParameters> AudioSystemHelper::ComputeOutputParameters( // AudioManager::Get[Default]OutputStreamParameters() returns invalid // parameters if the device is not found. if (!audio_manager_->HasAudioOutputDevices()) - return base::Optional<AudioParameters>(); + return absl::optional<AudioParameters>(); AudioParameters params = AudioDeviceDescription::IsDefaultDevice(device_id) diff --git a/chromium/media/audio/audio_system_helper.h b/chromium/media/audio/audio_system_helper.h index e3e16428254..e630555651a 100644 --- a/chromium/media/audio/audio_system_helper.h +++ b/chromium/media/audio/audio_system_helper.h @@ -44,9 +44,9 @@ class MEDIA_EXPORT AudioSystemHelper { AudioSystem::OnInputDeviceInfoCallback on_input_device_info_cb); private: - base::Optional<AudioParameters> ComputeInputParameters( + absl::optional<AudioParameters> ComputeInputParameters( const std::string& device_id); - base::Optional<AudioParameters> ComputeOutputParameters( + absl::optional<AudioParameters> ComputeOutputParameters( const std::string& device_id); AudioManager* const audio_manager_; diff --git a/chromium/media/audio/audio_system_test_util.cc b/chromium/media/audio/audio_system_test_util.cc index dae244c0253..7e31a7fff0b 100644 --- a/chromium/media/audio/audio_system_test_util.cc +++ b/chromium/media/audio/audio_system_test_util.cc @@ -19,7 +19,7 @@ AudioSystem::OnAudioParamsCallback AudioSystemCallbackExpectations::GetAudioParamsCallback( const base::Location& location, base::OnceClosure on_cb_received, - const base::Optional<AudioParameters>& expected_params) { + const absl::optional<AudioParameters>& expected_params) { return base::BindOnce(&AudioSystemCallbackExpectations::OnAudioParams, base::Unretained(this), location.ToString(), std::move(on_cb_received), expected_params); @@ -48,8 +48,8 @@ AudioSystem::OnInputDeviceInfoCallback AudioSystemCallbackExpectations::GetInputDeviceInfoCallback( const base::Location& location, base::OnceClosure on_cb_received, - const base::Optional<AudioParameters>& expected_input, - const base::Optional<std::string>& expected_associated_device_id) { + const absl::optional<AudioParameters>& expected_input, + const absl::optional<std::string>& expected_associated_device_id) { return base::BindOnce(&AudioSystemCallbackExpectations::OnInputDeviceInfo, base::Unretained(this), location.ToString(), std::move(on_cb_received), expected_input, @@ -60,7 +60,7 @@ AudioSystem::OnDeviceIdCallback AudioSystemCallbackExpectations::GetDeviceIdCallback( const base::Location& location, base::OnceClosure on_cb_received, - const base::Optional<std::string>& expected_id) { + const absl::optional<std::string>& expected_id) { return base::BindOnce(&AudioSystemCallbackExpectations::OnDeviceId, base::Unretained(this), location.ToString(), std::move(on_cb_received), expected_id); @@ -69,8 +69,8 @@ AudioSystemCallbackExpectations::GetDeviceIdCallback( void AudioSystemCallbackExpectations::OnAudioParams( const std::string& from_here, base::OnceClosure on_cb_received, - const base::Optional<AudioParameters>& expected, - const base::Optional<AudioParameters>& received) { + const absl::optional<AudioParameters>& expected, + const absl::optional<AudioParameters>& received) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_, from_here); if (expected) { EXPECT_TRUE(received) << from_here; @@ -105,10 +105,10 @@ void AudioSystemCallbackExpectations::OnDeviceDescriptions( void AudioSystemCallbackExpectations::OnInputDeviceInfo( const std::string& from_here, base::OnceClosure on_cb_received, - const base::Optional<AudioParameters>& expected_input, - const base::Optional<std::string>& expected_associated_device_id, - const base::Optional<AudioParameters>& input, - const base::Optional<std::string>& associated_device_id) { + const absl::optional<AudioParameters>& expected_input, + const absl::optional<std::string>& expected_associated_device_id, + const absl::optional<AudioParameters>& input, + const absl::optional<std::string>& associated_device_id) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_, from_here); EXPECT_TRUE(!input || input->IsValid()); if (expected_input) { @@ -132,8 +132,8 @@ void AudioSystemCallbackExpectations::OnInputDeviceInfo( void AudioSystemCallbackExpectations::OnDeviceId( const std::string& from_here, base::OnceClosure on_cb_received, - const base::Optional<std::string>& expected_id, - const base::Optional<std::string>& result_id) { + const absl::optional<std::string>& expected_id, + const absl::optional<std::string>& result_id) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_, from_here); EXPECT_TRUE(!result_id || !result_id->empty()); if (expected_id) { diff --git a/chromium/media/audio/audio_system_test_util.h b/chromium/media/audio/audio_system_test_util.h index fa7133e1c92..20edd161fd4 100644 --- a/chromium/media/audio/audio_system_test_util.h +++ b/chromium/media/audio/audio_system_test_util.h @@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/location.h" #include "base/macros.h" -#include "base/optional.h" #include "base/run_loop.h" #include "base/threading/thread_checker.h" #include "media/audio/audio_device_description.h" @@ -16,6 +15,7 @@ #include "media/audio/mock_audio_manager.h" #include "media/base/audio_parameters.h" #include "testing/gmock/include/gmock/gmock.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -31,7 +31,7 @@ class AudioSystemCallbackExpectations { AudioSystem::OnAudioParamsCallback GetAudioParamsCallback( const base::Location& location, base::OnceClosure on_cb_received, - const base::Optional<AudioParameters>& expected_params); + const absl::optional<AudioParameters>& expected_params); AudioSystem::OnBoolCallback GetBoolCallback(const base::Location& location, base::OnceClosure on_cb_received, @@ -45,20 +45,20 @@ class AudioSystemCallbackExpectations { AudioSystem::OnInputDeviceInfoCallback GetInputDeviceInfoCallback( const base::Location& location, base::OnceClosure on_cb_received, - const base::Optional<AudioParameters>& expected_input, - const base::Optional<std::string>& expected_associated_device_id); + const absl::optional<AudioParameters>& expected_input, + const absl::optional<std::string>& expected_associated_device_id); AudioSystem::OnDeviceIdCallback GetDeviceIdCallback( const base::Location& location, base::OnceClosure on_cb_received, - const base::Optional<std::string>& expected_id); + const absl::optional<std::string>& expected_id); private: // Methods to verify correctness of received data. void OnAudioParams(const std::string& from_here, base::OnceClosure on_cb_received, - const base::Optional<AudioParameters>& expected, - const base::Optional<AudioParameters>& received); + const absl::optional<AudioParameters>& expected, + const absl::optional<AudioParameters>& received); void OnBool(const std::string& from_here, base::OnceClosure on_cb_received, @@ -74,15 +74,15 @@ class AudioSystemCallbackExpectations { void OnInputDeviceInfo( const std::string& from_here, base::OnceClosure on_cb_received, - const base::Optional<AudioParameters>& expected_input, - const base::Optional<std::string>& expected_associated_device_id, - const base::Optional<AudioParameters>& input, - const base::Optional<std::string>& associated_device_id); + const absl::optional<AudioParameters>& expected_input, + const absl::optional<std::string>& expected_associated_device_id, + const absl::optional<AudioParameters>& input, + const absl::optional<std::string>& associated_device_id); void OnDeviceId(const std::string& from_here, base::OnceClosure on_cb_received, - const base::Optional<std::string>& expected_id, - const base::Optional<std::string>& result_id); + const absl::optional<std::string>& expected_id, + const absl::optional<std::string>& result_id); THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(AudioSystemCallbackExpectations); @@ -160,7 +160,7 @@ TYPED_TEST_P(AudioSystemTestTemplate, GetInputStreamParametersNoDevice) { AudioDeviceDescription::kDefaultDeviceId, this->expectations_.GetAudioParamsCallback( FROM_HERE, wait_loop.QuitClosure(), - base::Optional<AudioParameters>())); + absl::optional<AudioParameters>())); wait_loop.Run(); } @@ -190,7 +190,7 @@ TYPED_TEST_P(AudioSystemTestTemplate, AudioDeviceDescription::kDefaultDeviceId, this->expectations_.GetAudioParamsCallback( FROM_HERE, wait_loop.QuitClosure(), - base::Optional<AudioParameters>())); + absl::optional<AudioParameters>())); wait_loop.Run(); } @@ -201,7 +201,7 @@ TYPED_TEST_P(AudioSystemTestTemplate, this->audio_system()->GetOutputStreamParameters( "non-default-device-id", this->expectations_.GetAudioParamsCallback( FROM_HERE, wait_loop.QuitClosure(), - base::Optional<AudioParameters>())); + absl::optional<AudioParameters>())); wait_loop.Run(); } @@ -321,7 +321,7 @@ TYPED_TEST_P(AudioSystemTestTemplate, GetInputDeviceInfoNoAssociation) { "non-default-device-id", this->expectations_.GetInputDeviceInfoCallback( FROM_HERE, wait_loop.QuitClosure(), this->input_params_, - base::Optional<std::string>())); + absl::optional<std::string>())); wait_loop.Run(); } diff --git a/chromium/media/audio/audio_thread_hang_monitor.cc b/chromium/media/audio/audio_thread_hang_monitor.cc index c26d3f59590..6131b53cb65 100644 --- a/chromium/media/audio/audio_thread_hang_monitor.cc +++ b/chromium/media/audio/audio_thread_hang_monitor.cc @@ -44,7 +44,7 @@ AudioThreadHangMonitor::SharedAtomicFlag::~SharedAtomicFlag() {} // static AudioThreadHangMonitor::Ptr AudioThreadHangMonitor::Create( HangAction hang_action, - base::Optional<base::TimeDelta> hang_deadline, + absl::optional<base::TimeDelta> hang_deadline, const base::TickClock* clock, scoped_refptr<base::SingleThreadTaskRunner> audio_thread_task_runner, scoped_refptr<base::SequencedTaskRunner> monitor_task_runner) { @@ -73,7 +73,7 @@ bool AudioThreadHangMonitor::IsAudioThreadHung() const { AudioThreadHangMonitor::AudioThreadHangMonitor( HangAction hang_action, - base::Optional<base::TimeDelta> hang_deadline, + absl::optional<base::TimeDelta> hang_deadline, const base::TickClock* clock, scoped_refptr<base::SingleThreadTaskRunner> audio_thread_task_runner) : clock_(clock), diff --git a/chromium/media/audio/audio_thread_hang_monitor.h b/chromium/media/audio/audio_thread_hang_monitor.h index 89a3758f718..014ac272b66 100644 --- a/chromium/media/audio/audio_thread_hang_monitor.h +++ b/chromium/media/audio/audio_thread_hang_monitor.h @@ -15,12 +15,12 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class TickClock; @@ -68,7 +68,7 @@ class MEDIA_EXPORT AudioThreadHangMonitor final { // zero, a default value is used. static Ptr Create( HangAction hang_action, - base::Optional<base::TimeDelta> hang_deadline, + absl::optional<base::TimeDelta> hang_deadline, const base::TickClock* clock, scoped_refptr<base::SingleThreadTaskRunner> audio_thread_task_runner, scoped_refptr<base::SequencedTaskRunner> monitor_task_runner = nullptr); @@ -95,7 +95,7 @@ class MEDIA_EXPORT AudioThreadHangMonitor final { AudioThreadHangMonitor( HangAction hang_action, - base::Optional<base::TimeDelta> hang_deadline, + absl::optional<base::TimeDelta> hang_deadline, const base::TickClock* clock, scoped_refptr<base::SingleThreadTaskRunner> audio_thread_task_runner); diff --git a/chromium/media/audio/audio_thread_hang_monitor_unittest.cc b/chromium/media/audio/audio_thread_hang_monitor_unittest.cc index a173c726d5a..5ed9585f2e9 100644 --- a/chromium/media/audio/audio_thread_hang_monitor_unittest.cc +++ b/chromium/media/audio/audio_thread_hang_monitor_unittest.cc @@ -6,7 +6,6 @@ #include "base/bind.h" #include "base/location.h" -#include "base/optional.h" #include "base/synchronization/waitable_event.h" #include "base/task/post_task.h" #include "base/test/metrics/histogram_tester.h" @@ -14,6 +13,7 @@ #include "base/threading/thread.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" using testing::ElementsAre; using testing::Test; @@ -47,7 +47,7 @@ class AudioThreadHangMonitorTest : public Test { // runner since TaskEnvironment::FastForwardBy only works for the main // thread. hang_monitor_ = AudioThreadHangMonitor::Create( - HangAction::kDoNothing, base::nullopt, task_env_.GetMockTickClock(), + HangAction::kDoNothing, absl::nullopt, task_env_.GetMockTickClock(), audio_thread_.task_runner(), task_env_.GetMainThreadTaskRunner()); } @@ -251,7 +251,7 @@ TEST_F(AudioThreadHangMonitorTest, NoHangActionWhenOk) { TEST_F(AudioThreadHangMonitorTest, DumpsWhenAudioThreadIsBlocked) { hang_monitor_ = AudioThreadHangMonitor::Create( - HangAction::kDump, base::nullopt, task_env_.GetMockTickClock(), + HangAction::kDump, absl::nullopt, task_env_.GetMockTickClock(), audio_thread_.task_runner(), task_env_.GetMainThreadTaskRunner()); SetHangActionCallbacksForTesting(); RunUntilIdle(); @@ -268,7 +268,7 @@ TEST_F(AudioThreadHangMonitorTest, DumpsWhenAudioThreadIsBlocked) { TEST_F(AudioThreadHangMonitorTest, TerminatesProcessWhenAudioThreadIsBlocked) { hang_monitor_ = AudioThreadHangMonitor::Create( - HangAction::kTerminateCurrentProcess, base::nullopt, + HangAction::kTerminateCurrentProcess, absl::nullopt, task_env_.GetMockTickClock(), audio_thread_.task_runner(), task_env_.GetMainThreadTaskRunner()); SetHangActionCallbacksForTesting(); @@ -287,7 +287,7 @@ TEST_F(AudioThreadHangMonitorTest, TerminatesProcessWhenAudioThreadIsBlocked) { TEST_F(AudioThreadHangMonitorTest, DumpsAndTerminatesProcessWhenAudioThreadIsBlocked) { hang_monitor_ = AudioThreadHangMonitor::Create( - HangAction::kDumpAndTerminateCurrentProcess, base::nullopt, + HangAction::kDumpAndTerminateCurrentProcess, absl::nullopt, task_env_.GetMockTickClock(), audio_thread_.task_runner(), task_env_.GetMainThreadTaskRunner()); SetHangActionCallbacksForTesting(); diff --git a/chromium/media/audio/audio_thread_impl.cc b/chromium/media/audio/audio_thread_impl.cc index db3d4e84b7b..f52e7aae934 100644 --- a/chromium/media/audio/audio_thread_impl.cc +++ b/chromium/media/audio/audio_thread_impl.cc @@ -5,11 +5,11 @@ #include "media/audio/audio_thread_impl.h" #include "base/message_loop/message_pump_type.h" -#include "base/optional.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/default_tick_clock.h" #include "build/build_config.h" #include "media/audio/audio_thread_hang_monitor.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -23,7 +23,7 @@ AudioThreadImpl::AudioThreadImpl() // FIDL-based APIs require async_t, which is initialized on IO thread. thread_options.message_pump_type = base::MessagePumpType::IO; #endif - CHECK(thread_.StartWithOptions(thread_options)); + CHECK(thread_.StartWithOptions(std::move(thread_options))); #if defined(OS_MAC) // On Mac, the audio task runner must belong to the main thread. @@ -39,7 +39,7 @@ AudioThreadImpl::AudioThreadImpl() // https://crbug.com/946968: The hang monitor possibly causes crashes on // Android hang_monitor_ = AudioThreadHangMonitor::Create( - AudioThreadHangMonitor::HangAction::kDoNothing, base::nullopt, + AudioThreadHangMonitor::HangAction::kDoNothing, absl::nullopt, base::DefaultTickClock::GetInstance(), task_runner_); #endif } diff --git a/chromium/media/audio/audio_thread_impl.h b/chromium/media/audio/audio_thread_impl.h index 77b0fcdd47b..70100352440 100644 --- a/chromium/media/audio/audio_thread_impl.h +++ b/chromium/media/audio/audio_thread_impl.h @@ -5,8 +5,6 @@ #ifndef MEDIA_AUDIO_AUDIO_THREAD_IMPL_H_ #define MEDIA_AUDIO_AUDIO_THREAD_IMPL_H_ -#include <memory> - #include "base/sequenced_task_runner.h" #include "base/threading/thread.h" #include "base/threading/thread_checker.h" diff --git a/chromium/media/audio/cras/audio_manager_chromeos.cc b/chromium/media/audio/cras/audio_manager_chromeos.cc index 15d36844128..9d1badafe52 100644 --- a/chromium/media/audio/cras/audio_manager_chromeos.cc +++ b/chromium/media/audio/cras/audio_manager_chromeos.cc @@ -100,6 +100,42 @@ void ProcessVirtualDeviceName(AudioDeviceNames* device_names, } } +// Collects flags values for whether, and in what way, the AEC, NS or AGC +// effects should be enforced in spite of them not being flagged as supported by +// the board. +void RetrieveSystemEffectFeatures(bool& enforce_system_aec, + bool& enforce_system_ns, + bool& enforce_system_agc, + bool& tuned_system_aec_allowed) { + const bool enforce_system_aec_ns_agc_feature = + base::FeatureList::IsEnabled(features::kCrOSEnforceSystemAecNsAgc); + const bool enforce_system_aec_ns_feature = + base::FeatureList::IsEnabled(features::kCrOSEnforceSystemAecNs); + const bool enforce_system_aec_agc_feature = + base::FeatureList::IsEnabled(features::kCrOSEnforceSystemAecAgc); + const bool enforce_system_aec_feature = + base::FeatureList::IsEnabled(features::kCrOSEnforceSystemAec); + + enforce_system_aec = + enforce_system_aec_feature || enforce_system_aec_ns_agc_feature || + enforce_system_aec_ns_feature || enforce_system_aec_agc_feature; + enforce_system_ns = + enforce_system_aec_ns_agc_feature || enforce_system_aec_ns_feature; + enforce_system_agc = + enforce_system_aec_ns_agc_feature || enforce_system_aec_agc_feature; + + tuned_system_aec_allowed = + base::FeatureList::IsEnabled(features::kCrOSSystemAEC); +} + +// Checks if a system AEC with a specific group ID is flagged to be deactivated +// by the field trial. +bool IsSystemAecDeactivated(int aec_group_id) { + return base::GetFieldTrialParamByFeatureAsBool( + features::kCrOSSystemAECDeactivatedGroups, std::to_string(aec_group_id), + false); +} + } // namespace bool AudioManagerChromeOS::HasAudioOutputDevices() { @@ -175,44 +211,24 @@ AudioParameters AudioManagerChromeOS::GetInputStreamParameters( const std::string& device_id) { DCHECK(GetTaskRunner()->BelongsToCurrentThread()); - int user_buffer_size = GetUserBufferSize(); - int buffer_size = - user_buffer_size ? user_buffer_size : kDefaultInputBufferSize; - - // TODO(hshi): Fine-tune audio parameters based on |device_id|. The optimal - // parameters for the loopback stream may differ from the default. - AudioParameters params( - AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, - kDefaultSampleRate, buffer_size, - AudioParameters::HardwareCapabilities(limits::kMinAudioBufferSize, - limits::kMaxAudioBufferSize)); + // Check if the device has keyboard. AudioDeviceList devices; GetAudioDevices(&devices); - if (HasKeyboardMic(devices)) - params.set_effects(AudioParameters::KEYBOARD_MIC); + const bool has_keyboard = HasKeyboardMic(devices); - // Allow experimentation with system echo cancellation with all devices, - // but enable it by default on devices that actually support it. - params.set_effects(params.effects() | - AudioParameters::EXPERIMENTAL_ECHO_CANCELLER); - if (base::FeatureList::IsEnabled(features::kCrOSSystemAEC)) { - if (GetSystemAecSupportedPerBoard()) { - const int32_t aec_group_id = GetSystemAecGroupIdPerBoard(); - - // Check if the system AEC has a group ID which is flagged to be - // deactivated by the field trial. - const bool system_aec_deactivated = - base::GetFieldTrialParamByFeatureAsBool( - features::kCrOSSystemAECDeactivatedGroups, - std::to_string(aec_group_id), false); - - if (!system_aec_deactivated) { - params.set_effects(params.effects() | AudioParameters::ECHO_CANCELLER); - } - } - } + // Retrieve buffer size. + int user_buffer_size = GetUserBufferSize(); + user_buffer_size = + user_buffer_size != 0 ? user_buffer_size : kDefaultInputBufferSize; - return params; + // Retrieve the board support in terms of APM effects and properties. + const SystemAudioProcessingInfo system_apm_info = + GetSystemApmEffectsSupportedPerBoard(); + + // TODO(hshi): Fine-tune audio parameters based on |device_id|. The optimal + // parameters for the loopback stream may differ from the default. + return GetStreamParametersForSystem(user_buffer_size, has_keyboard, + system_apm_info); } std::string AudioManagerChromeOS::GetAssociatedOutputDeviceID( @@ -295,46 +311,28 @@ int AudioManagerChromeOS::GetDefaultOutputBufferSizePerBoard() { return static_cast<int>(buffer_size); } -bool AudioManagerChromeOS::GetSystemAecSupportedPerBoard() { +AudioManagerChromeOS::SystemAudioProcessingInfo +AudioManagerChromeOS::GetSystemApmEffectsSupportedPerBoard() { DCHECK(GetTaskRunner()->BelongsToCurrentThread()); - bool system_aec_supported = false; base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); - if (main_task_runner_->BelongsToCurrentThread()) { - // Unittest may use the same thread for audio thread. - GetSystemAecSupportedOnMainThread(&system_aec_supported, &event); - } else { - // Using base::Unretained is safe here because we wait for callback be - // executed in main thread before local variables are destructed. - main_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&AudioManagerChromeOS::GetSystemAecSupportedOnMainThread, - weak_this_, base::Unretained(&system_aec_supported), - base::Unretained(&event))); - } - WaitEventOrShutdown(&event); - return system_aec_supported; -} -int32_t AudioManagerChromeOS::GetSystemAecGroupIdPerBoard() { - DCHECK(GetTaskRunner()->BelongsToCurrentThread()); - int32_t group_id = CrasAudioHandler::kSystemAecGroupIdNotAvailable; - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + SystemAudioProcessingInfo system_apm_info; if (main_task_runner_->BelongsToCurrentThread()) { // Unittest may use the same thread for audio thread. - GetSystemAecGroupIdOnMainThread(&group_id, &event); + GetSystemApmEffectsSupportedOnMainThread(&system_apm_info, &event); } else { // Using base::Unretained is safe here because we wait for callback be // executed in main thread before local variables are destructed. main_task_runner_->PostTask( FROM_HERE, - base::BindOnce(&AudioManagerChromeOS::GetSystemAecGroupIdOnMainThread, - weak_this_, base::Unretained(&group_id), - base::Unretained(&event))); + base::BindOnce( + &AudioManagerChromeOS::GetSystemApmEffectsSupportedOnMainThread, + weak_this_, base::Unretained(&system_apm_info), + base::Unretained(&event))); } WaitEventOrShutdown(&event); - return group_id; + return system_apm_info; } AudioParameters AudioManagerChromeOS::GetPreferredOutputStreamParameters( @@ -516,25 +514,23 @@ void AudioManagerChromeOS::GetDefaultOutputBufferSizeOnMainThread( event->Signal(); } -void AudioManagerChromeOS::GetSystemAecSupportedOnMainThread( - bool* system_aec_supported, +void AudioManagerChromeOS::GetSystemApmEffectsSupportedOnMainThread( + SystemAudioProcessingInfo* system_apm_info, base::WaitableEvent* event) { DCHECK(main_task_runner_->BelongsToCurrentThread()); if (CrasAudioHandler::Get()) { - *system_aec_supported = CrasAudioHandler::Get()->system_aec_supported(); + system_apm_info->aec_supported = + CrasAudioHandler::Get()->system_aec_supported(); + system_apm_info->aec_group_id = + CrasAudioHandler::Get()->system_aec_group_id(); + system_apm_info->ns_supported = + CrasAudioHandler::Get()->system_ns_supported(); + system_apm_info->agc_supported = + CrasAudioHandler::Get()->system_agc_supported(); } event->Signal(); } -void AudioManagerChromeOS::GetSystemAecGroupIdOnMainThread( - int32_t* group_id, - base::WaitableEvent* event) { - DCHECK(main_task_runner_->BelongsToCurrentThread()); - if (CrasAudioHandler::Get()) - *group_id = CrasAudioHandler::Get()->system_aec_group_id(); - event->Signal(); -} - void AudioManagerChromeOS::WaitEventOrShutdown(base::WaitableEvent* event) { base::WaitableEvent* waitables[] = {event, &on_shutdown_}; base::WaitableEvent::WaitMany(waitables, base::size(waitables)); @@ -544,4 +540,66 @@ enum CRAS_CLIENT_TYPE AudioManagerChromeOS::GetClientType() { return CRAS_CLIENT_TYPE_CHROME; } +AudioParameters AudioManagerChromeOS::GetStreamParametersForSystem( + int user_buffer_size, + bool has_keyboard, + const AudioManagerChromeOS::SystemAudioProcessingInfo& system_apm_info) { + AudioParameters params( + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + kDefaultSampleRate, user_buffer_size, + AudioParameters::HardwareCapabilities(limits::kMinAudioBufferSize, + limits::kMaxAudioBufferSize)); + if (has_keyboard) + params.set_effects(AudioParameters::KEYBOARD_MIC); + + bool enforce_system_aec; + bool enforce_system_ns; + bool enforce_system_agc; + bool tuned_system_aec_allowed; + RetrieveSystemEffectFeatures(enforce_system_aec, enforce_system_ns, + enforce_system_agc, tuned_system_aec_allowed); + + // Activation of the system AEC. Allow experimentation with system AEC with + // all devices, but enable it by default on devices that actually support it. + params.set_effects(params.effects() | + AudioParameters::EXPERIMENTAL_ECHO_CANCELLER); + + // Rephrase the field aec_supported to properly reflect its meaning in this + // context (since it currently signals whether an CrAS APM with tuned settings + // is available). + const bool tuned_system_apm_available = system_apm_info.aec_supported; + + // Don't use the system AEC if it is deactivated for this group ID. Also never + // activate NS nor AGC for this board if the AEC is not activated, since this + // will cause issues for the Browser AEC. + bool use_system_aec = + (tuned_system_apm_available && tuned_system_aec_allowed) || + enforce_system_aec; + + if (!use_system_aec || IsSystemAecDeactivated(system_apm_info.aec_group_id)) { + return params; + } + + // Activation of the system AEC. + params.set_effects(params.effects() | AudioParameters::ECHO_CANCELLER); + + // Don't use system NS or AGC if the AEC has board-specific tunings. + if (tuned_system_apm_available) { + return params; + } + + // Activation of the system NS. + if (system_apm_info.ns_supported || enforce_system_ns) { + params.set_effects(params.effects() | AudioParameters::NOISE_SUPPRESSION); + } + + // Activation of the system AGC. + if (system_apm_info.agc_supported || enforce_system_agc) { + params.set_effects(params.effects() | + AudioParameters::AUTOMATIC_GAIN_CONTROL); + } + + return params; +} + } // namespace media diff --git a/chromium/media/audio/cras/audio_manager_chromeos.h b/chromium/media/audio/cras/audio_manager_chromeos.h index 40da0ad6f82..3d38a3eb89f 100644 --- a/chromium/media/audio/cras/audio_manager_chromeos.h +++ b/chromium/media/audio/cras/audio_manager_chromeos.h @@ -12,6 +12,7 @@ #include <vector> #include "ash/components/audio/audio_device.h" +#include "ash/components/audio/cras_audio_handler.h" #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -45,6 +46,22 @@ class MEDIA_EXPORT AudioManagerChromeOS : public AudioManagerCrasBase { bool IsDefault(const std::string& device_id, bool is_input) override; enum CRAS_CLIENT_TYPE GetClientType() override; + // Stores information about the system audio processing effects and + // properties that are provided by the system audio processing module (APM). + struct SystemAudioProcessingInfo { + bool aec_supported = false; + int32_t aec_group_id = ash::CrasAudioHandler::kSystemAecGroupIdNotAvailable; + bool ns_supported = false; + bool agc_supported = false; + }; + + // Produces AudioParameters for the system, including audio processing + // capabilities tailored for the system, + static AudioParameters GetStreamParametersForSystem( + int user_buffer_size, + bool has_keyboard, + const AudioManagerChromeOS::SystemAudioProcessingInfo& system_apm_info); + protected: AudioParameters GetPreferredOutputStreamParameters( const std::string& output_device_id, @@ -54,11 +71,8 @@ class MEDIA_EXPORT AudioManagerChromeOS : public AudioManagerCrasBase { // Get default output buffer size for this board. int GetDefaultOutputBufferSizePerBoard(); - // Get if system AEC is supported or not for this board. - bool GetSystemAecSupportedPerBoard(); - - // Get what the system AEC group ID is for this board. - int32_t GetSystemAecGroupIdPerBoard(); + // Get any system APM effects that are supported for this board. + SystemAudioProcessingInfo GetSystemApmEffectsSupportedPerBoard(); void GetAudioDeviceNamesImpl(bool is_input, AudioDeviceNames* device_names); @@ -77,10 +91,9 @@ class MEDIA_EXPORT AudioManagerChromeOS : public AudioManagerCrasBase { base::WaitableEvent* event); void GetDefaultOutputBufferSizeOnMainThread(int32_t* buffer_size, base::WaitableEvent* event); - void GetSystemAecSupportedOnMainThread(bool* system_aec_supported, - base::WaitableEvent* event); - void GetSystemAecGroupIdOnMainThread(int32_t* group_id, - base::WaitableEvent* event); + void GetSystemApmEffectsSupportedOnMainThread( + SystemAudioProcessingInfo* system_apm_info, + base::WaitableEvent* event); void WaitEventOrShutdown(base::WaitableEvent* event); diff --git a/chromium/media/audio/cras/audio_manager_chromeos_unittest.cc b/chromium/media/audio/cras/audio_manager_chromeos_unittest.cc new file mode 100644 index 00000000000..db4517a4b3b --- /dev/null +++ b/chromium/media/audio/cras/audio_manager_chromeos_unittest.cc @@ -0,0 +1,217 @@ +// Copyright (c) 2021 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/cras/audio_manager_chromeos.h" + +#include "base/test/scoped_feature_list.h" +#include "media/audio/audio_features.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +namespace { +constexpr int kAecTestGroupId = 9; +constexpr int kNoAecFlaggedGroupId = 0; + +// Chosen to be the same as in `audio_manager_chromeos.cc`, but any size should +// work since this should not affect the testing done herein. +constexpr int kDefaultInputBufferSize = 1024; + +bool ExperimentalAecActive(const AudioParameters& params) { + return params.effects() & AudioParameters::EXPERIMENTAL_ECHO_CANCELLER; +} + +bool AecActive(const AudioParameters& params) { + return params.effects() & AudioParameters::ECHO_CANCELLER; +} + +bool NsActive(const AudioParameters& params) { + return params.effects() & AudioParameters::NOISE_SUPPRESSION; +} + +bool AgcActive(const AudioParameters& params) { + return params.effects() & AudioParameters::AUTOMATIC_GAIN_CONTROL; +} + +} // namespace + +class GetStreamParametersForSystem + : public ::testing::Test, + public ::testing::WithParamInterface< + std::tuple<bool, int, bool, int32_t, bool, bool>> { + protected: + // Retrieve test parameter values. + void GetTestParameters() { + has_keyboard_ = std::get<0>(GetParam()); + user_buffer_size_ = std::get<1>(GetParam()); + system_apm_info_.aec_supported = std::get<2>(GetParam()); + system_apm_info_.aec_group_id = std::get<3>(GetParam()); + system_apm_info_.ns_supported = std::get<4>(GetParam()); + system_apm_info_.agc_supported = std::get<5>(GetParam()); + } + + AudioManagerChromeOS::SystemAudioProcessingInfo system_apm_info_; + size_t has_keyboard_; + size_t user_buffer_size_; +}; + +INSTANTIATE_TEST_SUITE_P( + AllInputParameters, + GetStreamParametersForSystem, + ::testing::Combine(::testing::Values(false, true), + ::testing::Values(512, kDefaultInputBufferSize), + ::testing::Values(false, true), + ::testing::Values(kNoAecFlaggedGroupId, kAecTestGroupId), + ::testing::Values(false, true), + ::testing::Values(false, true))); + +TEST_P(GetStreamParametersForSystem, DefaultBehavior) { + GetTestParameters(); + AudioParameters params = AudioManagerChromeOS::GetStreamParametersForSystem( + user_buffer_size_, has_keyboard_, system_apm_info_); + + EXPECT_TRUE(ExperimentalAecActive(params)); + EXPECT_EQ(AecActive(params), system_apm_info_.aec_supported); + if (system_apm_info_.aec_supported) { + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); + } else { + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); + } +} + +TEST_P(GetStreamParametersForSystem, + BehaviorWithCrOSEnforceSystemAecDisallowed) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(features::kCrOSSystemAEC); + + GetTestParameters(); + AudioParameters params = AudioManagerChromeOS::GetStreamParametersForSystem( + user_buffer_size_, has_keyboard_, system_apm_info_); + + EXPECT_TRUE(ExperimentalAecActive(params)); + EXPECT_FALSE(AecActive(params)); + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); +} + +TEST_P(GetStreamParametersForSystem, BehaviorWithCrOSEnforceSystemAecNsAgc) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kCrOSEnforceSystemAecNsAgc); + + GetTestParameters(); + AudioParameters params = AudioManagerChromeOS::GetStreamParametersForSystem( + user_buffer_size_, has_keyboard_, system_apm_info_); + + EXPECT_TRUE(ExperimentalAecActive(params)); + EXPECT_TRUE(AecActive(params)); + if (system_apm_info_.aec_supported) { + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); + } else { + EXPECT_TRUE(NsActive(params)); + EXPECT_TRUE(AgcActive(params)); + } +} + +TEST_P(GetStreamParametersForSystem, + BehaviorWithCrOSEnforceSystemAecNsAndAecAgc) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kCrOSEnforceSystemAecNs); + feature_list.InitAndEnableFeature(features::kCrOSEnforceSystemAecAgc); + + GetTestParameters(); + AudioParameters params = AudioManagerChromeOS::GetStreamParametersForSystem( + user_buffer_size_, has_keyboard_, system_apm_info_); + + EXPECT_TRUE(ExperimentalAecActive(params)); + EXPECT_TRUE(AecActive(params)); + if (system_apm_info_.aec_supported) { + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); + } else { + EXPECT_TRUE(NsActive(params)); + EXPECT_TRUE(AgcActive(params)); + } +} + +TEST_P(GetStreamParametersForSystem, + BehaviorWithCrOSEnforceSystemAecNsAgcAndDisallowedSystemAec) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kCrOSEnforceSystemAecNsAgc); + feature_list.InitAndDisableFeature(features::kCrOSSystemAEC); + + GetTestParameters(); + AudioParameters params = AudioManagerChromeOS::GetStreamParametersForSystem( + user_buffer_size_, has_keyboard_, system_apm_info_); + + EXPECT_TRUE(ExperimentalAecActive(params)); + EXPECT_TRUE(AecActive(params)); + if (system_apm_info_.aec_supported) { + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); + } else { + EXPECT_TRUE(NsActive(params)); + EXPECT_TRUE(AgcActive(params)); + } +} + +TEST_P(GetStreamParametersForSystem, BehaviorWithCrOSEnforceSystemAecNs) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kCrOSEnforceSystemAecNs); + + GetTestParameters(); + AudioParameters params = AudioManagerChromeOS::GetStreamParametersForSystem( + user_buffer_size_, has_keyboard_, system_apm_info_); + + EXPECT_TRUE(ExperimentalAecActive(params)); + EXPECT_TRUE(AecActive(params)); + if (system_apm_info_.aec_supported) { + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); + } else { + EXPECT_TRUE(NsActive(params)); + EXPECT_EQ(AgcActive(params), system_apm_info_.agc_supported); + } +} + +TEST_P(GetStreamParametersForSystem, BehaviorWithCrOSEnforceSystemAecAgc) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kCrOSEnforceSystemAecAgc); + + GetTestParameters(); + AudioParameters params = AudioManagerChromeOS::GetStreamParametersForSystem( + user_buffer_size_, has_keyboard_, system_apm_info_); + + EXPECT_TRUE(ExperimentalAecActive(params)); + EXPECT_TRUE(AecActive(params)); + if (system_apm_info_.aec_supported) { + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); + } else { + EXPECT_EQ(NsActive(params), system_apm_info_.ns_supported); + EXPECT_TRUE(AgcActive(params)); + } +} + +TEST_P(GetStreamParametersForSystem, BehaviorWithCrOSEnforceSystemAec) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(features::kCrOSEnforceSystemAec); + + GetTestParameters(); + AudioParameters params = AudioManagerChromeOS::GetStreamParametersForSystem( + user_buffer_size_, has_keyboard_, system_apm_info_); + + EXPECT_TRUE(ExperimentalAecActive(params)); + EXPECT_TRUE(AecActive(params)); + if (system_apm_info_.aec_supported) { + EXPECT_FALSE(NsActive(params)); + EXPECT_FALSE(AgcActive(params)); + } else { + EXPECT_EQ(NsActive(params), system_apm_info_.ns_supported); + EXPECT_EQ(AgcActive(params), system_apm_info_.agc_supported); + } +} + +} // namespace media diff --git a/chromium/media/audio/cras/cras_input.cc b/chromium/media/audio/cras/cras_input.cc index dc91a84737f..ad4caaf5a17 100644 --- a/chromium/media/audio/cras/cras_input.cc +++ b/chromium/media/audio/cras/cras_input.cc @@ -45,22 +45,22 @@ CrasInputStream::~CrasInputStream() { DCHECK(!client_); } -bool CrasInputStream::Open() { +AudioInputStream::OpenOutcome CrasInputStream::Open() { if (client_) { NOTREACHED() << "CrasInputStream already open"; - return false; // Already open. + return OpenOutcome::kAlreadyOpen; } // Sanity check input values. if (params_.sample_rate() <= 0) { DLOG(WARNING) << "Unsupported audio frequency."; - return false; + return OpenOutcome::kFailed; } if (AudioParameters::AUDIO_PCM_LINEAR != params_.format() && AudioParameters::AUDIO_PCM_LOW_LATENCY != params_.format()) { DLOG(WARNING) << "Unsupported audio format."; - return false; + return OpenOutcome::kFailed; } // Create the client and connect to the CRAS server. @@ -68,14 +68,14 @@ bool CrasInputStream::Open() { if (!client_) { DLOG(WARNING) << "Couldn't create CRAS client.\n"; client_ = NULL; - return false; + return OpenOutcome::kFailed; } if (libcras_client_connect(client_)) { DLOG(WARNING) << "Couldn't connect CRAS client.\n"; libcras_client_destroy(client_); client_ = NULL; - return false; + return OpenOutcome::kFailed; } // Then start running the client. @@ -83,7 +83,7 @@ bool CrasInputStream::Open() { DLOG(WARNING) << "Couldn't run CRAS client.\n"; libcras_client_destroy(client_); client_ = NULL; - return false; + return OpenOutcome::kFailed; } if (is_loopback_) { @@ -93,7 +93,7 @@ bool CrasInputStream::Open() { // cleanup code. libcras_client_destroy(client_); client_ = NULL; - return false; + return OpenOutcome::kFailed; } int rc = libcras_client_get_loopback_dev_idx(client_, &pin_device_); @@ -101,11 +101,11 @@ bool CrasInputStream::Open() { DLOG(WARNING) << "Couldn't find CRAS loopback device."; libcras_client_destroy(client_); client_ = NULL; - return false; + return OpenOutcome::kFailed; } } - return true; + return OpenOutcome::kSuccess; } void CrasInputStream::Close() { @@ -126,6 +126,14 @@ inline bool CrasInputStream::UseCrasAec() const { return params_.effects() & AudioParameters::ECHO_CANCELLER; } +inline bool CrasInputStream::UseCrasNs() const { + return params_.effects() & AudioParameters::NOISE_SUPPRESSION; +} + +inline bool CrasInputStream::UseCrasAgc() const { + return params_.effects() & AudioParameters::AUTOMATIC_GAIN_CONTROL; +} + void CrasInputStream::Start(AudioInputCallback* callback) { DCHECK(client_); DCHECK(callback); @@ -212,6 +220,12 @@ void CrasInputStream::Start(AudioInputCallback* callback) { if (UseCrasAec()) libcras_stream_params_enable_aec(stream_params); + if (UseCrasNs()) + libcras_stream_params_enable_ns(stream_params); + + if (UseCrasAgc()) + libcras_stream_params_enable_agc(stream_params); + // Adding the stream will start the audio callbacks. if (libcras_client_add_pinned_stream(client_, pin_device_, &stream_id_, stream_params)) { diff --git a/chromium/media/audio/cras/cras_input.h b/chromium/media/audio/cras/cras_input.h index 17fa790e5ff..8efe59a35c8 100644 --- a/chromium/media/audio/cras/cras_input.h +++ b/chromium/media/audio/cras/cras_input.h @@ -39,7 +39,7 @@ class MEDIA_EXPORT CrasInputStream : public AgcAudioStream<AudioInputStream> { ~CrasInputStream() override; // Implementation of AudioInputStream. - bool Open() override; + AudioInputStream::OpenOutcome Open() override; void Start(AudioInputCallback* callback) override; void Stop() override; void Close() override; @@ -76,6 +76,12 @@ class MEDIA_EXPORT CrasInputStream : public AgcAudioStream<AudioInputStream> { // Return true to use AEC in CRAS for this input stream. inline bool UseCrasAec() const; + // Return true to use NS in CRAS for this input stream. + inline bool UseCrasNs() const; + + // Return true to use AGC in CRAS for this input stream. + inline bool UseCrasAgc() const; + // Non-refcounted pointer back to the audio manager. // The AudioManager indirectly holds on to stream objects, so we don't // want circular references. Additionally, stream objects live on the audio diff --git a/chromium/media/audio/cras/cras_input_unittest.cc b/chromium/media/audio/cras/cras_input_unittest.cc index 04d4deafe09..5bda316b07f 100644 --- a/chromium/media/audio/cras/cras_input_unittest.cc +++ b/chromium/media/audio/cras/cras_input_unittest.cc @@ -102,7 +102,7 @@ class CrasInputStreamTest : public testing::Test { CrasInputStream* test_stream = new CrasInputStream( params, mock_manager_.get(), AudioDeviceDescription::kDefaultDeviceId); - ASSERT_TRUE(test_stream->Open()); + EXPECT_EQ(test_stream->Open(), AudioInputStream::OpenOutcome::kSuccess); // Allow 8 frames variance for SRC in the callback. Different numbers of // samples can be provided when doing non-integer SRC. For example @@ -146,13 +146,13 @@ const int CrasInputStreamTest::kTestSampleRate = 44100; TEST_F(CrasInputStreamTest, OpenMono) { CrasInputStream* test_stream = CreateStream(CHANNEL_LAYOUT_MONO); - EXPECT_TRUE(test_stream->Open()); + EXPECT_EQ(test_stream->Open(), AudioInputStream::OpenOutcome::kSuccess); test_stream->Close(); } TEST_F(CrasInputStreamTest, OpenStereo) { CrasInputStream* test_stream = CreateStream(CHANNEL_LAYOUT_STEREO); - EXPECT_TRUE(test_stream->Open()); + EXPECT_EQ(test_stream->Open(), AudioInputStream::OpenOutcome::kSuccess); test_stream->Close(); } @@ -164,13 +164,13 @@ TEST_F(CrasInputStreamTest, BadSampleRate) { CrasInputStream* test_stream = new CrasInputStream(bad_rate_params, mock_manager_.get(), AudioDeviceDescription::kDefaultDeviceId); - EXPECT_FALSE(test_stream->Open()); + EXPECT_EQ(test_stream->Open(), AudioInputStream::OpenOutcome::kFailed); test_stream->Close(); } TEST_F(CrasInputStreamTest, SetGetVolume) { CrasInputStream* test_stream = CreateStream(CHANNEL_LAYOUT_MONO); - EXPECT_TRUE(test_stream->Open()); + EXPECT_EQ(test_stream->Open(), AudioInputStream::OpenOutcome::kSuccess); double max_volume = test_stream->GetMaxVolume(); EXPECT_GE(max_volume, 1.0); @@ -212,7 +212,7 @@ TEST_F(CrasInputStreamTest, CaptureLoopback) { CrasInputStream* test_stream = CreateStream(CHANNEL_LAYOUT_STEREO, kTestFramesPerPacket, AudioDeviceDescription::kLoopbackInputDeviceId); - EXPECT_TRUE(test_stream->Open()); + EXPECT_EQ(test_stream->Open(), AudioInputStream::OpenOutcome::kSuccess); test_stream->Close(); } diff --git a/chromium/media/audio/cras/cras_unified.h b/chromium/media/audio/cras/cras_unified.h index eb57e01c402..26055a726b2 100644 --- a/chromium/media/audio/cras/cras_unified.h +++ b/chromium/media/audio/cras/cras_unified.h @@ -18,7 +18,6 @@ #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/time/time.h" #include "media/audio/audio_io.h" #include "media/base/audio_parameters.h" diff --git a/chromium/media/audio/fake_audio_input_stream.cc b/chromium/media/audio/fake_audio_input_stream.cc index ca0ec900067..7d500303fc0 100644 --- a/chromium/media/audio/fake_audio_input_stream.cc +++ b/chromium/media/audio/fake_audio_input_stream.cc @@ -61,11 +61,11 @@ FakeAudioInputStream::~FakeAudioInputStream() { DCHECK(!fake_audio_worker_); } -bool FakeAudioInputStream::Open() { +AudioInputStream::OpenOutcome FakeAudioInputStream::Open() { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); audio_bus_->Zero(); - return true; + return OpenOutcome::kSuccess; } void FakeAudioInputStream::Start(AudioInputCallback* callback) { @@ -79,7 +79,7 @@ void FakeAudioInputStream::Start(AudioInputCallback* callback) { // REALTIME_AUDIO priority is needed to avoid audio playout delays. // See crbug.com/971265 options.priority = base::ThreadPriority::REALTIME_AUDIO; - CHECK(capture_thread_->StartWithOptions(options)); + CHECK(capture_thread_->StartWithOptions(std::move(options))); { base::AutoLock lock(callback_lock_); diff --git a/chromium/media/audio/fake_audio_input_stream.h b/chromium/media/audio/fake_audio_input_stream.h index b76f12fdde5..809edfb7b2f 100644 --- a/chromium/media/audio/fake_audio_input_stream.h +++ b/chromium/media/audio/fake_audio_input_stream.h @@ -28,13 +28,12 @@ class AudioManagerBase; // beeping sound unless --use-file-for-fake-audio-capture=<file> is specified, // in which case the indicated .wav file will be read and played into the // stream. -class MEDIA_EXPORT FakeAudioInputStream - : public AudioInputStream { +class MEDIA_EXPORT FakeAudioInputStream : public AudioInputStream { public: - static AudioInputStream* MakeFakeStream( - AudioManagerBase* manager, const AudioParameters& params); + static AudioInputStream* MakeFakeStream(AudioManagerBase* manager, + const AudioParameters& params); - bool Open() override; + OpenOutcome Open() override; void Start(AudioInputCallback* callback) override; void Stop() override; void Close() override; diff --git a/chromium/media/audio/fuchsia/DIR_METADATA b/chromium/media/audio/fuchsia/DIR_METADATA index e88f62328ca..abc57ac0fd5 100644 --- a/chromium/media/audio/fuchsia/DIR_METADATA +++ b/chromium/media/audio/fuchsia/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto team_email: "cr-fuchsia@chromium.org" os: FUCHSIA
\ No newline at end of file diff --git a/chromium/media/audio/fuchsia/OWNERS b/chromium/media/audio/fuchsia/OWNERS index 3ebcc4268bd..e7034eabb1e 100644 --- a/chromium/media/audio/fuchsia/OWNERS +++ b/chromium/media/audio/fuchsia/OWNERS @@ -1 +1 @@ -file://build/fuchsia/OWNERS
\ No newline at end of file +file://build/fuchsia/OWNERS diff --git a/chromium/media/audio/fuchsia/audio_output_stream_fuchsia.h b/chromium/media/audio/fuchsia/audio_output_stream_fuchsia.h index ff8fe2d62a0..5f5bfa89501 100644 --- a/chromium/media/audio/fuchsia/audio_output_stream_fuchsia.h +++ b/chromium/media/audio/fuchsia/audio_output_stream_fuchsia.h @@ -8,10 +8,10 @@ #include <fuchsia/media/cpp/fidl.h> #include "base/memory/shared_memory_mapping.h" -#include "base/optional.h" #include "base/timer/timer.h" #include "media/audio/audio_io.h" #include "media/base/audio_parameters.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -92,7 +92,7 @@ class AudioOutputStreamFuchsia : public AudioOutputStream { // Current min lead time for the stream. This value is not set until the first // AudioRenderer::OnMinLeadTimeChanged event. - base::Optional<base::TimeDelta> min_lead_time_; + absl::optional<base::TimeDelta> min_lead_time_; // Timer that's scheduled to call PumpSamples(). base::OneShotTimer timer_; diff --git a/chromium/media/audio/mac/audio_device_listener_mac.cc b/chromium/media/audio/mac/audio_device_listener_mac.cc index bccd5e64fb0..347608260fb 100644 --- a/chromium/media/audio/mac/audio_device_listener_mac.cc +++ b/chromium/media/audio/mac/audio_device_listener_mac.cc @@ -10,11 +10,11 @@ #include "base/files/file_path.h" #include "base/logging.h" #include "base/mac/mac_logging.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "media/audio/audio_manager.h" #include "media/audio/mac/core_audio_util_mac.h" #include "media/base/bind_to_current_loop.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { diff --git a/chromium/media/audio/mac/audio_input_mac.cc b/chromium/media/audio/mac/audio_input_mac.cc index 7cac52acea6..3151f4e687a 100644 --- a/chromium/media/audio/mac/audio_input_mac.cc +++ b/chromium/media/audio/mac/audio_input_mac.cc @@ -27,7 +27,7 @@ namespace { // should ideally be set to about the same value as in // audio_low_latency_input_mac.cc, to make comparing them reasonable. const int kInputCallbackStartTimeoutInSeconds = 8; -} +} // namespace PCMQueueInAudioInputStream::PCMQueueInAudioInputStream( AudioManagerMac* manager, @@ -66,7 +66,7 @@ PCMQueueInAudioInputStream::~PCMQueueInAudioInputStream() { DCHECK(!audio_queue_); } -bool PCMQueueInAudioInputStream::Open() { +AudioInputStream::OpenOutcome PCMQueueInAudioInputStream::Open() { OSStatus err = AudioQueueNewInput(&format_, &HandleInputBufferStatic, this, @@ -76,9 +76,10 @@ bool PCMQueueInAudioInputStream::Open() { &audio_queue_); if (err != noErr) { HandleError(err); - return false; + return AudioInputStream::OpenOutcome::kFailed; } - return SetupBuffers(); + return SetupBuffers() ? AudioInputStream::OpenOutcome::kSuccess + : AudioInputStream::OpenOutcome::kFailed; } void PCMQueueInAudioInputStream::Start(AudioInputCallback* callback) { diff --git a/chromium/media/audio/mac/audio_input_mac.h b/chromium/media/audio/mac/audio_input_mac.h index b96aadfa8eb..15da618e448 100644 --- a/chromium/media/audio/mac/audio_input_mac.h +++ b/chromium/media/audio/mac/audio_input_mac.h @@ -35,7 +35,7 @@ class PCMQueueInAudioInputStream : public AudioInputStream { ~PCMQueueInAudioInputStream() override; // Implementation of AudioInputStream. - bool Open() override; + AudioInputStream::OpenOutcome Open() override; void Start(AudioInputCallback* callback) override; void Stop() override; void Close() override; diff --git a/chromium/media/audio/mac/audio_low_latency_input_mac.cc b/chromium/media/audio/mac/audio_low_latency_input_mac.cc index e5fd2b351b4..eb39b38c308 100644 --- a/chromium/media/audio/mac/audio_low_latency_input_mac.cc +++ b/chromium/media/audio/mac/audio_low_latency_input_mac.cc @@ -286,7 +286,7 @@ AUAudioInputStream::~AUAudioInputStream() { } // Obtain and open the AUHAL AudioOutputUnit for recording. -bool AUAudioInputStream::Open() { +AudioInputStream::OpenOutcome AUAudioInputStream::Open() { DCHECK(thread_checker_.CalledOnValidThread()); DVLOG(1) << "Open"; DCHECK(!audio_unit_); @@ -296,7 +296,7 @@ bool AUAudioInputStream::Open() { if (input_device_id_ == kAudioObjectUnknown) { NOTREACHED() << "Device ID is unknown"; HandleError(kAudioUnitErr_InvalidElement); - return false; + return OpenOutcome::kFailed; } // The requested sample-rate must match the hardware sample-rate. @@ -311,7 +311,7 @@ bool AUAudioInputStream::Open() { use_voice_processing_ ? OpenVoiceProcessingAU() : OpenAUHAL(); if (!success) - return false; + return OpenOutcome::kFailed; // The hardware latency is fixed and will not change during the call. hardware_latency_ = AudioManagerMac::GetHardwareLatency( @@ -322,7 +322,7 @@ bool AUAudioInputStream::Open() { // And the master channel is not counted in |number_of_channels_in_frame_|. number_of_channels_in_frame_ = GetNumberOfChannelsFromStream(); - return true; + return OpenOutcome::kSuccess; } bool AUAudioInputStream::OpenAUHAL() { diff --git a/chromium/media/audio/mac/audio_low_latency_input_mac.h b/chromium/media/audio/mac/audio_low_latency_input_mac.h index da716271eab..1344ba83e3e 100644 --- a/chromium/media/audio/mac/audio_low_latency_input_mac.h +++ b/chromium/media/audio/mac/audio_low_latency_input_mac.h @@ -72,7 +72,7 @@ class MEDIA_EXPORT AUAudioInputStream ~AUAudioInputStream() override; // Implementation of AudioInputStream. - bool Open() override; + AudioInputStream::OpenOutcome Open() override; void Start(AudioInputCallback* callback) override; void Stop() override; void Close() override; diff --git a/chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc b/chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc index 341111d2e6b..96287c9515e 100644 --- a/chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc +++ b/chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc @@ -184,7 +184,7 @@ TEST_F(MacAudioInputTest, AUAudioInputStreamCreateAndClose) { TEST_F(MacAudioInputTest, AUAudioInputStreamOpenAndClose) { ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable()); AudioInputStream* ais = CreateDefaultAudioInputStream(); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); ais->Close(); } @@ -192,7 +192,7 @@ TEST_F(MacAudioInputTest, AUAudioInputStreamOpenAndClose) { TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartAndClose) { ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable()); AudioInputStream* ais = CreateDefaultAudioInputStream(); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); MockAudioInputCallback sink; ais->Start(&sink); ais->Close(); @@ -202,7 +202,7 @@ TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartAndClose) { TEST_F(MacAudioInputTest, AUAudioInputStreamOpenStartStopAndClose) { ABORT_AUDIO_TEST_IF_NOT(InputDevicesAvailable()); AudioInputStream* ais = CreateDefaultAudioInputStream(); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); MockAudioInputCallback sink; ais->Start(&sink); ais->Stop(); @@ -217,7 +217,7 @@ TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyMonoRecording) { // Create an audio input stream which records in mono. AudioInputStream* ais = CreateAudioInputStream(CHANNEL_LAYOUT_MONO); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); MockAudioInputCallback sink; @@ -246,7 +246,7 @@ TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyStereoRecording) { // Create an audio input stream which records in stereo. AudioInputStream* ais = CreateAudioInputStream(CHANNEL_LAYOUT_STEREO); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); MockAudioInputCallback sink; @@ -286,7 +286,7 @@ TEST_F(MacAudioInputTest, DISABLED_AUAudioInputStreamRecordToFile) { int fs = static_cast<int>(AUAudioInputStream::HardwareSampleRate()); AudioInputStream* ais = CreateDefaultAudioInputStream(); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); fprintf(stderr, " File name : %s\n", file_name); fprintf(stderr, " Sample rate: %d\n", fs); diff --git a/chromium/media/audio/mac/audio_manager_mac.cc b/chromium/media/audio/mac/audio_manager_mac.cc index 29f12e9928e..261596b9b74 100644 --- a/chromium/media/audio/mac/audio_manager_mac.cc +++ b/chromium/media/audio/mac/audio_manager_mac.cc @@ -17,7 +17,6 @@ #include "base/mac/scoped_cftyperef.h" #include "base/macros.h" #include "base/memory/free_deleter.h" -#include "base/optional.h" #include "base/power_monitor/power_monitor.h" #include "base/power_monitor/power_observer.h" #include "base/strings/sys_string_conversions.h" @@ -36,6 +35,7 @@ #include "media/base/limits.h" #include "media/base/mac/audio_latency_mac.h" #include "media/base/media_switches.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -139,12 +139,12 @@ static void GetAudioDeviceInfo(bool is_input, if (!is_valid_for_direction) continue; - base::Optional<std::string> unique_id = + absl::optional<std::string> unique_id = core_audio_mac::GetDeviceUniqueID(device_id); if (!unique_id) continue; - base::Optional<std::string> label = + absl::optional<std::string> label = core_audio_mac::GetDeviceLabel(device_id, is_input); if (!label) continue; @@ -680,7 +680,7 @@ std::string AudioManagerMac::GetAssociatedOutputDeviceID( // to detect if a device (e.g. a digital output device) is actually connected // to an endpoint, so we cannot randomly pick a device. if (related_output_device_ids.size() == 1) { - base::Optional<std::string> related_unique_id = + absl::optional<std::string> related_unique_id = core_audio_mac::GetDeviceUniqueID(related_output_device_ids[0]); if (related_unique_id) return std::move(*related_unique_id); diff --git a/chromium/media/audio/mac/core_audio_util_mac.cc b/chromium/media/audio/mac/core_audio_util_mac.cc index fa6dcf24539..8283c1abba6 100644 --- a/chromium/media/audio/mac/core_audio_util_mac.cc +++ b/chromium/media/audio/mac/core_audio_util_mac.cc @@ -23,7 +23,7 @@ AudioObjectPropertyScope InputOutputScope(bool is_input) { : kAudioObjectPropertyScopeOutput; } -base::Optional<std::string> GetDeviceStringProperty( +absl::optional<std::string> GetDeviceStringProperty( AudioObjectID device_id, AudioObjectPropertySelector property_selector) { CFStringRef property_value = nullptr; @@ -39,11 +39,11 @@ base::Optional<std::string> GetDeviceStringProperty( OSSTATUS_DLOG(WARNING, result) << "Failed to read string property " << property_selector << " for device " << device_id; - return base::nullopt; + return absl::nullopt; } if (!property_value) - return base::nullopt; + return absl::nullopt; std::string device_property = base::SysCFStringRefToUTF8(property_value); CFRelease(property_value); @@ -51,7 +51,7 @@ base::Optional<std::string> GetDeviceStringProperty( return device_property; } -base::Optional<uint32_t> GetDeviceUint32Property( +absl::optional<uint32_t> GetDeviceUint32Property( AudioObjectID device_id, AudioObjectPropertySelector property_selector, AudioObjectPropertyScope property_scope) { @@ -63,7 +63,7 @@ base::Optional<uint32_t> GetDeviceUint32Property( device_id, &property_address, 0 /* inQualifierDataSize */, nullptr /* inQualifierData */, &size, &property_value); if (result != noErr) - return base::nullopt; + return absl::nullopt; return property_value; } @@ -123,11 +123,11 @@ std::vector<AudioObjectID> GetAudioObjectIDs( return device_ids; } -base::Optional<std::string> GetDeviceName(AudioObjectID device_id) { +absl::optional<std::string> GetDeviceName(AudioObjectID device_id) { return GetDeviceStringProperty(device_id, kAudioObjectPropertyName); } -base::Optional<std::string> GetDeviceModel(AudioObjectID device_id) { +absl::optional<std::string> GetDeviceModel(AudioObjectID device_id) { return GetDeviceStringProperty(device_id, kAudioDevicePropertyModelUID); } @@ -178,7 +178,7 @@ std::string TransportTypeToString(uint32_t transport_type) { } } -base::Optional<std::string> TranslateDeviceSource(AudioObjectID device_id, +absl::optional<std::string> TranslateDeviceSource(AudioObjectID device_id, UInt32 source_id, bool is_input) { CFStringRef source_name = nullptr; @@ -197,7 +197,7 @@ base::Optional<std::string> TranslateDeviceSource(AudioObjectID device_id, device_id, &property_address, 0 /* inQualifierDataSize */, nullptr /* inQualifierData */, &translation_size, &translation); if (result) - return base::nullopt; + return absl::nullopt; std::string ret = base::SysCFStringRefToUTF8(source_name); CFRelease(source_name); @@ -216,14 +216,14 @@ std::vector<AudioObjectID> GetRelatedDeviceIDs(AudioObjectID device_id) { return GetAudioObjectIDs(device_id, kAudioDevicePropertyRelatedDevices); } -base::Optional<std::string> GetDeviceUniqueID(AudioObjectID device_id) { +absl::optional<std::string> GetDeviceUniqueID(AudioObjectID device_id) { return GetDeviceStringProperty(device_id, kAudioDevicePropertyDeviceUID); } -base::Optional<std::string> GetDeviceLabel(AudioObjectID device_id, +absl::optional<std::string> GetDeviceLabel(AudioObjectID device_id, bool is_input) { - base::Optional<std::string> device_label; - base::Optional<uint32_t> source = GetDeviceSource(device_id, is_input); + absl::optional<std::string> device_label; + absl::optional<uint32_t> source = GetDeviceSource(device_id, is_input); if (source) { device_label = TranslateDeviceSource(device_id, *source, is_input); } @@ -231,14 +231,14 @@ base::Optional<std::string> GetDeviceLabel(AudioObjectID device_id, if (!device_label) { device_label = GetDeviceName(device_id); if (!device_label) - return base::nullopt; + return absl::nullopt; } std::string suffix; - base::Optional<uint32_t> transport_type = GetDeviceTransportType(device_id); + absl::optional<uint32_t> transport_type = GetDeviceTransportType(device_id); if (transport_type) { if (*transport_type == kAudioDeviceTransportTypeUSB) { - base::Optional<std::string> model = GetDeviceModel(device_id); + absl::optional<std::string> model = GetDeviceModel(device_id); if (model) { suffix = UsbVidPidFromModel(*model); } @@ -259,13 +259,13 @@ uint32_t GetNumStreams(AudioObjectID device_id, bool is_input) { InputOutputScope(is_input)); } -base::Optional<uint32_t> GetDeviceSource(AudioObjectID device_id, +absl::optional<uint32_t> GetDeviceSource(AudioObjectID device_id, bool is_input) { return GetDeviceUint32Property(device_id, kAudioDevicePropertyDataSource, InputOutputScope(is_input)); } -base::Optional<uint32_t> GetDeviceTransportType(AudioObjectID device_id) { +absl::optional<uint32_t> GetDeviceTransportType(AudioObjectID device_id) { return GetDeviceUint32Property(device_id, kAudioDevicePropertyTransportType, kAudioObjectPropertyScopeGlobal); } diff --git a/chromium/media/audio/mac/core_audio_util_mac.h b/chromium/media/audio/mac/core_audio_util_mac.h index b8301be3ecc..b46243a5167 100644 --- a/chromium/media/audio/mac/core_audio_util_mac.h +++ b/chromium/media/audio/mac/core_audio_util_mac.h @@ -10,7 +10,7 @@ #include <string> #include <vector> -#include "base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace core_audio_mac { @@ -26,12 +26,12 @@ std::vector<AudioObjectID> GetRelatedDeviceIDs(AudioObjectID device_id); // Returns a string with a unique device ID for the given |device_id|, or no // value if there is an error. -base::Optional<std::string> GetDeviceUniqueID(AudioObjectID device_id); +absl::optional<std::string> GetDeviceUniqueID(AudioObjectID device_id); // Returns a string with a descriptive label for the given |device_id|, or no // value if there is an error. The returned label is based on several // characteristics of the device. -base::Optional<std::string> GetDeviceLabel(AudioObjectID device_id, +absl::optional<std::string> GetDeviceLabel(AudioObjectID device_id, bool is_input); // Returns the number of input or output streams associated with the given @@ -40,12 +40,12 @@ uint32_t GetNumStreams(AudioObjectID device_id, bool is_input); // Returns the source associated with the given |device_id|, or no value if // |device_id| has no source or if there is an error. -base::Optional<uint32_t> GetDeviceSource(AudioObjectID device_id, +absl::optional<uint32_t> GetDeviceSource(AudioObjectID device_id, bool is_input); // Returns the transport type of the given |device_id|, or no value if // |device_id| has no source or if there is an error. -base::Optional<uint32_t> GetDeviceTransportType(AudioObjectID device_id); +absl::optional<uint32_t> GetDeviceTransportType(AudioObjectID device_id); // Returns whether or not the |device_id| corresponds to a private, aggregate // device. Such a device gets created by instantiating a VoiceProcessingIO diff --git a/chromium/media/audio/pulse/pulse_input.cc b/chromium/media/audio/pulse/pulse_input.cc index 10bbd2d2af6..59b288eda69 100644 --- a/chromium/media/audio/pulse/pulse_input.cc +++ b/chromium/media/audio/pulse/pulse_input.cc @@ -56,25 +56,25 @@ PulseAudioInputStream::~PulseAudioInputStream() { DCHECK(!handle_); } -bool PulseAudioInputStream::Open() { +AudioInputStream::OpenOutcome PulseAudioInputStream::Open() { DCHECK(thread_checker_.CalledOnValidThread()); SendLogMessage("%s()", __func__); if (device_name_ == AudioDeviceDescription::kDefaultDeviceId && audio_manager_->DefaultSourceIsMonitor()) { SendLogMessage("%s => (ERROR: can't open monitor device)", __func__); - return false; + return OpenOutcome::kFailed; } AutoPulseLock auto_lock(pa_mainloop_); if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &handle_, params_, device_name_, &StreamNotifyCallback, this)) { SendLogMessage("%s => (ERROR: failed to open PA stream)", __func__); - return false; + return OpenOutcome::kFailed; } DCHECK(handle_); - return true; + return OpenOutcome::kSuccess; } void PulseAudioInputStream::Start(AudioInputCallback* callback) { diff --git a/chromium/media/audio/pulse/pulse_input.h b/chromium/media/audio/pulse/pulse_input.h index 2fe4b773fb2..b340bda07e9 100644 --- a/chromium/media/audio/pulse/pulse_input.h +++ b/chromium/media/audio/pulse/pulse_input.h @@ -34,7 +34,7 @@ class PulseAudioInputStream : public AgcAudioStream<AudioInputStream> { ~PulseAudioInputStream() override; // Implementation of AudioInputStream. - bool Open() override; + AudioInputStream::OpenOutcome Open() override; void Start(AudioInputCallback* callback) override; void Stop() override; void Close() override; diff --git a/chromium/media/audio/win/audio_low_latency_input_win.cc b/chromium/media/audio/win/audio_low_latency_input_win.cc index a5e5daf3ce7..f97f1e6eabe 100644 --- a/chromium/media/audio/win/audio_low_latency_input_win.cc +++ b/chromium/media/audio/win/audio_low_latency_input_win.cc @@ -30,12 +30,14 @@ #include "media/audio/audio_features.h" #include "media/audio/win/avrt_wrapper_win.h" #include "media/audio/win/core_audio_util_win.h" +#include "media/audio/win/volume_range_util.h" #include "media/base/audio_block_fifo.h" #include "media/base/audio_bus.h" #include "media/base/audio_timestamp_helper.h" #include "media/base/channel_layout.h" #include "media/base/limits.h" #include "media/base/media_switches.h" +#include "media/base/timestamp_constants.h" using ABI::Windows::Foundation::Collections::IVectorView; using ABI::Windows::Media::Devices::IMediaDeviceStatics; @@ -339,11 +341,11 @@ WASAPIAudioInputStream::~WASAPIAudioInputStream() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } -bool WASAPIAudioInputStream::Open() { +AudioInputStream::OpenOutcome WASAPIAudioInputStream::Open() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); SendLogMessage("%s([opened=%s])", __func__, opened_ ? "true" : "false"); if (opened_) { - return false; + return OpenOutcome::kAlreadyOpen; } // Obtain a reference to the IMMDevice interface of the capturing device with @@ -351,7 +353,7 @@ bool WASAPIAudioInputStream::Open() { HRESULT hr = SetCaptureDevice(); if (FAILED(hr)) { ReportOpenResult(hr); - return false; + return OpenOutcome::kFailed; } // Check if raw audio processing is supported for the selected capture device. @@ -382,7 +384,7 @@ bool WASAPIAudioInputStream::Open() { if (FAILED(hr)) { open_result_ = OPEN_RESULT_ACTIVATION_FAILED; ReportOpenResult(hr); - return false; + return OpenOutcome::kFailed; } #ifndef NDEBUG @@ -407,7 +409,7 @@ bool WASAPIAudioInputStream::Open() { if (!DesiredFormatIsSupported(&hr)) { open_result_ = OPEN_RESULT_FORMAT_NOT_SUPPORTED; ReportOpenResult(hr); - return false; + return OpenOutcome::kFailed; } // Initialize the audio stream between the client and the device using @@ -418,7 +420,12 @@ bool WASAPIAudioInputStream::Open() { ReportOpenResult(hr); // Report before we assign a value to |opened_|. opened_ = SUCCEEDED(hr); - return opened_; + if (opened_) { + return OpenOutcome::kSuccess; + } + + return (hr == E_ACCESSDENIED) ? OpenOutcome::kFailedSystemPermissions + : OpenOutcome::kFailed; } void WASAPIAudioInputStream::Start(AudioInputCallback* callback) { @@ -466,9 +473,9 @@ void WASAPIAudioInputStream::Start(AudioInputCallback* callback) { // Create and start the thread that will drive the capturing by waiting for // capture events. DCHECK(!capture_thread_.get()); - capture_thread_.reset(new base::DelegateSimpleThread( + capture_thread_ = std::make_unique<base::DelegateSimpleThread>( this, "wasapi_capture_thread", - base::SimpleThread::Options(base::ThreadPriority::REALTIME_AUDIO))); + base::SimpleThread::Options(base::ThreadPriority::REALTIME_AUDIO)); capture_thread_->Start(); // Start streaming data between the endpoint buffer and the audio engine. @@ -509,6 +516,23 @@ void WASAPIAudioInputStream::Stop() { } } + absl::optional<VolumeRange> volume_range; + if (add_uma_histogram && system_audio_volume_ && + !AudioDeviceDescription::IsLoopbackDevice(device_id_)) { + VolumeRange range; + HRESULT hr = system_audio_volume_->GetVolumeRange( + &range.min_volume_db, &range.max_volume_db, &range.volume_step_db); + if (FAILED(hr)) { + SendLogMessage("%s => (ERROR: IAudioEndpointVolume::GetVolumeRange=[%s])", + __func__, ErrorToString(hr).c_str()); + } else { + SendLogMessage("%s => (IAudioEndpointVolume::GetVolumeRange) %f %f %f", + __func__, range.min_volume_db, range.max_volume_db, + range.volume_step_db); + volume_range = range; + } + } + // Stops periodic AGC microphone measurements. StopAgc(); @@ -537,8 +561,21 @@ void WASAPIAudioInputStream::Stop() { base::UmaHistogramBoolean("Media.Audio.InputVolumeStartsAtZeroWin", audio_session_starts_at_zero_volume_); audio_session_starts_at_zero_volume_ = false; + LogVolumeRangeUmaHistograms(volume_range); } + SendLogMessage( + "%s => (timestamp(n)-timestamp(n-1)=[min: %.3f msec, max: %.3f msec])", + __func__, min_timestamp_diff_.InMillisecondsF(), + max_timestamp_diff_.InMillisecondsF()); + + const bool monotonic_timestamps = + min_timestamp_diff_ >= base::TimeDelta::FromMicroseconds(1); + base::UmaHistogramBoolean("Media.Audio.Capture.Win.MonotonicTimestamps", + monotonic_timestamps); + SendLogMessage("%s => (Media.Audio.Capture.Win.MonotonicTimestamps=%s)", + __func__, monotonic_timestamps ? "true" : "false"); + started_ = false; sink_ = nullptr; } @@ -706,8 +743,8 @@ void WASAPIAudioInputStream::Run() { ++buffers_required; DCHECK(!fifo_); - fifo_.reset(new AudioBlockFifo(input_format_.Format.nChannels, - packet_size_frames_, buffers_required)); + fifo_ = std::make_unique<AudioBlockFifo>( + input_format_.Format.nChannels, packet_size_frames_, buffers_required); DVLOG(1) << "AudioBlockFifo buffer count: " << buffers_required; bool recording = true; @@ -715,6 +752,11 @@ void WASAPIAudioInputStream::Run() { HANDLE wait_array[2] = {stop_capture_event_.Get(), audio_samples_ready_event_.Get()}; + record_start_time_ = base::TimeTicks::Now(); + last_capture_time_ = base::TimeTicks(); + max_timestamp_diff_ = base::TimeDelta::Min(); + min_timestamp_diff_ = base::TimeDelta::Max(); + while (recording && !error) { // Wait for a close-down event or a new capture event. DWORD wait_result = WaitForMultipleObjects(2, wait_array, FALSE, INFINITE); @@ -754,39 +796,81 @@ void WASAPIAudioInputStream::PullCaptureDataAndPushToSink() { "sample rate", input_format_.Format.nSamplesPerSec); UINT64 last_device_position = 0; + UINT32 num_frames_in_next_packet = 0; + + // Get the number of frames in the next data packet in the capture endpoint + // buffer. The count reported by GetNextPacketSize matches the count retrieved + // in the GetBuffer call that follows this call. + HRESULT hr = + audio_capture_client_->GetNextPacketSize(&num_frames_in_next_packet); + if (FAILED(hr)) { + LOG(ERROR) << "WAIS::" << __func__ + << " => (ERROR: 1-IAudioCaptureClient::GetNextPacketSize=[" + << ErrorToString(hr).c_str() << "])"; + return; + } // Pull data from the capture endpoint buffer until it's empty or an error - // occurs. - while (true) { + // occurs. Drains the WASAPI capture buffer fully. + while (num_frames_in_next_packet > 0) { BYTE* data_ptr = nullptr; UINT32 num_frames_to_read = 0; DWORD flags = 0; UINT64 device_position = 0; - - // Note: The units on this are 100ns intervals. Both GetBuffer() and - // GetPosition() will handle the translation from the QPC value, so we just - // need to convert from 100ns units into us. Which is just dividing by 10.0 - // since 10x100ns = 1us. UINT64 capture_time_100ns = 0; // Retrieve the amount of data in the capture endpoint buffer, replace it // with silence if required, create callbacks for each packet and store // non-delivered data for the next event. - HRESULT hr = + hr = audio_capture_client_->GetBuffer(&data_ptr, &num_frames_to_read, &flags, &device_position, &capture_time_100ns); - if (hr == AUDCLNT_S_BUFFER_EMPTY) - break; - - // TODO(grunell): Should we handle different errors explicitly? Perhaps exit - // by setting |error = true|. What are the assumptions here that makes us - // rely on the next WaitForMultipleObjects? Do we expect the next wait to be - // successful sometimes? + if (hr == AUDCLNT_S_BUFFER_EMPTY) { + DCHECK_EQ(num_frames_to_read, 0u); + return; + } + if (hr == AUDCLNT_E_OUT_OF_ORDER) { + // A previous IAudioCaptureClient::GetBuffer() call is still in effect. + // Release any acquired buffer to be able to try reading a buffer again. + audio_capture_client_->ReleaseBuffer(num_frames_to_read); + } if (FAILED(hr)) { LOG(ERROR) << "WAIS::" << __func__ << " => (ERROR: IAudioCaptureClient::GetBuffer=[" << ErrorToString(hr).c_str() << "])"; - break; + return; + } + + // The data in the packet is not correlated with the previous packet's + // device position; this is possibly due to a stream state transition or + // timing glitch. Note that, usage of this flag was added after the existing + // glitch detection in UpdateGlitchCount() and it will be used as a + // supplementary scheme initially. + // The behavior of the AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY flag is + // undefined on the application's first call to GetBuffer after Start and + // Windows 7 or later is required for support. + if (device_position > 0 && flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) { + LOG(WARNING) << "WAIS::" << __func__ + << " => (WARNING: AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY)"; + ++num_data_discontinuity_warnings_; + } + + // The time at which the device's stream position was recorded is uncertain. + // Thus, the client might be unable to accurately set a time stamp for the + // current data packet. + bool timestamp_error_was_detected = false; + if (flags & AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR) { + // TODO(https://crbug.com/825744): it might be possible to improve error + // handling here and avoid using the counter in |capture_time_100ns|. + LOG(WARNING) << "WAIS::" << __func__ + << " => (WARNING: AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR)"; + if (num_timestamp_errors_ == 0) { + // Measure the time it took until the first timestamp error was found. + time_until_first_timestamp_error_ = + base::TimeTicks::Now() - record_start_time_; + } + ++num_timestamp_errors_; + timestamp_error_was_detected = true; } // If the device position has changed, we assume this data belongs to a new @@ -802,41 +886,46 @@ void WASAPIAudioInputStream::PullCaptureDataAndPushToSink() { expected_next_device_position_ += num_frames_to_read; } - // TODO(dalecurtis, olka, grunell): Is this ever false? If it is, should we - // handle |flags & AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR|? - if (audio_clock_) { - // The reported timestamp from GetBuffer is not as reliable as the clock - // from the client. We've seen timestamps reported for USB audio devices, - // be off by several days. Furthermore we've seen them jump back in time - // every 2 seconds or so. - // TODO(grunell): Using the audio clock as capture time for the currently - // processed buffer seems incorrect. http://crbug.com/825744. - audio_clock_->GetPosition(&device_position, &capture_time_100ns); - } - base::TimeTicks capture_time; - if (capture_time_100ns) { - // See conversion notes on |capture_time_100ns|. + if (!timestamp_error_was_detected) { + // Use the latest |capture_time_100ns| since it is marked as valid. capture_time += base::TimeDelta::FromMicroseconds(capture_time_100ns / 10.0); - } else { - // We may not have an IAudioClock or GetPosition() may return zero. - capture_time = base::TimeTicks::Now(); + } + if (capture_time <= last_capture_time_) { + // Latest |capture_time_100ns| can't be trusted. Ensure a monotonic time- + // stamp sequence by adding one microsecond to the latest timestamp. + capture_time = last_capture_time_ + base::TimeDelta::FromMicroseconds(1); + } + + // Keep track of max and min time difference between two successive time- + // stamps. Results are used in Stop() to verify that the time-stamp sequence + // was monotonic. + if (!last_capture_time_.is_null()) { + const auto delta_ts = capture_time - last_capture_time_; + DCHECK_GT(device_position, 0u); + DCHECK_GT(delta_ts, base::TimeDelta::Min()); + if (delta_ts > max_timestamp_diff_) { + max_timestamp_diff_ = delta_ts; + } else if (delta_ts < min_timestamp_diff_) { + min_timestamp_diff_ = delta_ts; + } } + // Store the capture timestamp. Might be used as reference next time if + // a new valid timestamp can't be retrieved to always guarantee a monotonic + // sequence. + last_capture_time_ = capture_time; + // Adjust |capture_time| for the FIFO before pushing. capture_time -= AudioTimestampHelper::FramesToTime( fifo_->GetAvailableFrames(), input_format_.Format.nSamplesPerSec); - // TODO(grunell): Since we check |hr == AUDCLNT_S_BUFFER_EMPTY| above, - // should we instead assert that |num_frames_to_read != 0|? - if (num_frames_to_read != 0) { - if (flags & AUDCLNT_BUFFERFLAGS_SILENT) { - fifo_->PushSilence(num_frames_to_read); - } else { - fifo_->Push(data_ptr, num_frames_to_read, - input_format_.Format.wBitsPerSample / 8); - } + if (flags & AUDCLNT_BUFFERFLAGS_SILENT) { + fifo_->PushSilence(num_frames_to_read); + } else { + fifo_->Push(data_ptr, num_frames_to_read, + input_format_.Format.wBitsPerSample / 8); } hr = audio_capture_client_->ReleaseBuffer(num_frames_to_read); @@ -844,7 +933,7 @@ void WASAPIAudioInputStream::PullCaptureDataAndPushToSink() { LOG(ERROR) << "WAIS::" << __func__ << " => (ERROR: IAudioCaptureClient::ReleaseBuffer=[" << ErrorToString(hr).c_str() << "])"; - break; + return; } // Get a cached AGC volume level which is updated once every second on the @@ -862,7 +951,7 @@ void WASAPIAudioInputStream::PullCaptureDataAndPushToSink() { // Special case. We need to buffer up more audio before we can convert // or else we'll suffer an underrun. // TODO(grunell): Verify this is really true. - break; + return; } converter_->Convert(convert_bus_.get()); sink_->OnData(convert_bus_.get(), capture_time, volume); @@ -878,7 +967,17 @@ void WASAPIAudioInputStream::PullCaptureDataAndPushToSink() { packet_size_frames_, input_format_.Format.nSamplesPerSec); } } - } // while (true) + + // Get the number of frames in the next data packet in the capture endpoint + // buffer. Keep reading if more samples exist. + hr = audio_capture_client_->GetNextPacketSize(&num_frames_in_next_packet); + if (FAILED(hr)) { + LOG(ERROR) << "WAIS::" << __func__ + << " => (ERROR: 2-IAudioCaptureClient::GetNextPacketSize=[" + << ErrorToString(hr).c_str() << "])"; + return; + } + } // while (num_frames_in_next_packet > 0) } void WASAPIAudioInputStream::HandleError(HRESULT err) { @@ -926,15 +1025,15 @@ HRESULT WASAPIAudioInputStream::SetCaptureDevice() { return hr; } - // If loopback device with muted system audio is requested, get the volume - // interface for the endpoint. - if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId) { - hr = endpoint_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, - nullptr, &system_audio_volume_); - if (FAILED(hr)) { - open_result_ = OPEN_RESULT_ACTIVATION_FAILED; - return hr; - } + // Get the volume interface for the endpoint. Used in `Stop()` to query the + // volume range of the selected input device or to get/set mute state in + // `Start()` and `Stop()` if a loopback device with muted system audio is + // requested. + hr = endpoint_device_->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, + nullptr, &system_audio_volume_); + if (FAILED(hr)) { + open_result_ = OPEN_RESULT_ACTIVATION_FAILED; + return hr; } // Verify that the audio endpoint device is active, i.e., the audio @@ -1301,7 +1400,7 @@ void WASAPIAudioInputStream::SetupConverterAndStoreFormatInfo() { output_layout, output_format_.nSamplesPerSec, packet_size_frames_); - converter_.reset(new AudioConverter(input, output, false)); + converter_ = std::make_unique<AudioConverter>(input, output, false); converter_->AddInput(this); converter_->PrimeWithSilence(); convert_bus_ = AudioBus::Create(output); @@ -1463,14 +1562,6 @@ HRESULT WASAPIAudioInputStream::InitializeAudioEngine() { if (FAILED(hr)) open_result_ = OPEN_RESULT_NO_AUDIO_VOLUME; - audio_client_->GetService(IID_PPV_ARGS(&audio_clock_)); - if (!audio_clock_) { - SendLogMessage( - "%s => (WARNING: IAudioClock unavailable, capture times will be " - "inaccurate)", - __func__); - } - return hr; } @@ -1542,10 +1633,31 @@ void WASAPIAudioInputStream::ReportAndResetGlitchStats() { 50); } + // TODO(https://crbug.com/825744): It can be possible to replace + // "Media.Audio.Capture.Glitches" with this new (simplified) metric instead. + base::UmaHistogramCounts1M("Media.Audio.Capture.Win.Glitches", + num_data_discontinuity_warnings_); + SendLogMessage("%s => (discontinuity warnings=[%" PRIu64 "])", __func__, + num_data_discontinuity_warnings_); + base::UmaHistogramCounts1M("Media.Audio.Capture.Win.TimestampErrors", + num_timestamp_errors_); + SendLogMessage("%s => (timstamp errors=[%" PRIu64 "])", __func__, + num_timestamp_errors_); + if (num_timestamp_errors_ > 0) { + base::UmaHistogramLongTimes( + "Media.Audio.Capture.Win.TimeUntilFirstTimestampError", + time_until_first_timestamp_error_); + SendLogMessage("%s => (time until first timestamp error=[%" PRId64 " ms])", + __func__, + time_until_first_timestamp_error_.InMilliseconds()); + } + expected_next_device_position_ = 0; total_glitches_ = 0; total_lost_frames_ = 0; largest_glitch_frames_ = 0; + num_data_discontinuity_warnings_ = 0; + num_timestamp_errors_ = 0; } } // namespace media diff --git a/chromium/media/audio/win/audio_low_latency_input_win.h b/chromium/media/audio/win/audio_low_latency_input_win.h index f3e45d6343a..91b8fb19d3a 100644 --- a/chromium/media/audio/win/audio_low_latency_input_win.h +++ b/chromium/media/audio/win/audio_low_latency_input_win.h @@ -130,7 +130,7 @@ class MEDIA_EXPORT WASAPIAudioInputStream ~WASAPIAudioInputStream() override; // Implementation of AudioInputStream. - bool Open() override; + AudioInputStream::OpenOutcome Open() override; void Start(AudioInputCallback* callback) override; void Stop() override; void Close() override; @@ -266,11 +266,6 @@ class MEDIA_EXPORT WASAPIAudioInputStream // from a capture endpoint buffer. Microsoft::WRL::ComPtr<IAudioCaptureClient> audio_capture_client_; - // The IAudioClock interface is used to get the current timestamp, as the - // timestamp from IAudioCaptureClient::GetBuffer can be unreliable with some - // devices. - Microsoft::WRL::ComPtr<IAudioClock> audio_clock_; - // The ISimpleAudioVolume interface enables a client to control the // master volume level of an audio session. // The volume-level is a value in the range 0.0 to 1.0. @@ -312,6 +307,21 @@ class MEDIA_EXPORT WASAPIAudioInputStream UINT64 total_lost_frames_ = 0; UINT64 largest_glitch_frames_ = 0; + // Tracks error messages from IAudioCaptureClient::GetBuffer. + UINT64 num_data_discontinuity_warnings_ = 0; + UINT64 num_timestamp_errors_ = 0; + base::TimeTicks record_start_time_; + base::TimeDelta time_until_first_timestamp_error_; + + // Contains the last capture timestamp from IAudioCaptureClient::GetBuffer. + base::TimeTicks last_capture_time_; + + // Max and min of difference in time between two successive timestamps. + // |min_timestamp_diff_| should always be larger than or equal to one micro- + // second. + base::TimeDelta max_timestamp_diff_; + base::TimeDelta min_timestamp_diff_; + // Enabled if the volume level of the audio session is set to zero when the // session starts. Utilized in UMA histogram. bool audio_session_starts_at_zero_volume_ = false; diff --git a/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc b/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc index 2eed0cc87ea..a2cdbc2f2a1 100644 --- a/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc +++ b/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc @@ -19,6 +19,7 @@ #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/strings/stringprintf.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/test/test_timeouts.h" @@ -347,7 +348,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( CreateDefaultAudioInputStream(audio_manager_.get())); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); ais.Close(); } @@ -366,7 +367,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenAndCloseForAllDevices) { AudioInputStreamWrapper aisw(audio_manager_.get(), device.unique_id); { ScopedAudioInputStream ais(aisw.Create()); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); } } } @@ -376,7 +377,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( CreateDefaultAudioInputStream(audio_manager_.get())); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); MockAudioInputCallback sink; ais->Start(&sink); ais.Close(); @@ -393,13 +394,34 @@ TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { ScopedAudioInputStream ais( CreateDefaultAudioInputStream(audio_manager_.get())); EXPECT_TRUE(ais->SetAutomaticGainControl(true)); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); MockAudioInputCallback sink; ais->Start(&sink); ais->Stop(); ais.Close(); } +// Verify that histograms are created as expected. Only covers the latest +// histograms. +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamHistograms) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); + base::HistogramTester histogram_tester; + ScopedAudioInputStream ais( + CreateDefaultAudioInputStream(audio_manager_.get())); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); + FakeAudioInputCallback sink; + ais->Start(&sink); + sink.WaitForData(); + sink.WaitForData(); + ais->Stop(); + ais.Close(); + histogram_tester.ExpectTotalCount("Media.Audio.Capture.Win.Glitches", 1); + histogram_tester.ExpectTotalCount("Media.Audio.Capture.Win.TimestampErrors", + 1); + histogram_tester.ExpectTotalCount( + "Media.Audio.Capture.Win.TimeUntilFirstTimestampError", 0); +} + // Test some additional calling sequences. TEST_F(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); @@ -407,8 +429,8 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { CreateDefaultAudioInputStream(audio_manager_.get())); // Open(), Open() should fail the second time. - EXPECT_TRUE(ais->Open()); - EXPECT_FALSE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kAlreadyOpen); FakeAudioInputCallback sink; @@ -437,7 +459,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { // the shared mixing rate. The default buffer size is 10ms. AudioInputStreamWrapper aisw(audio_manager_.get()); ScopedAudioInputStream ais(aisw.Create()); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); MockAudioInputCallback sink; @@ -469,7 +491,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { count = 0; ais.Reset(aisw.Create(2 * frames_per_buffer_10ms)); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() * SampleFormatToBytesPerChannel(kSampleFormat); @@ -490,7 +512,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { count = 0; ais.Reset(aisw.Create(frames_per_buffer_10ms / 2)); - EXPECT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); bytes_per_packet = aisw.channels() * aisw.frames_per_buffer() * SampleFormatToBytesPerChannel(kSampleFormat); @@ -525,7 +547,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { ScopedAudioInputStream stream(audio_manager_->MakeAudioInputStream( params, AudioDeviceDescription::kLoopbackInputDeviceId, base::BindRepeating(&LogCallbackDummy))); - ASSERT_TRUE(stream->Open()); + EXPECT_EQ(stream->Open(), AudioInputStream::OpenOutcome::kSuccess); FakeAudioInputCallback sink; stream->Start(&sink); ASSERT_FALSE(sink.error()); @@ -553,7 +575,7 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { AudioInputStreamWrapper aisw(audio_manager_.get()); ScopedAudioInputStream ais(aisw.Create()); - ASSERT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); VLOG(0) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]"; WriteToFileAudioSink file_sink(file_name); @@ -580,7 +602,7 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFileRAW) { AudioInputStreamWrapper aisw(audio_manager_.get()); ScopedAudioInputStream ais(aisw.Create()); - ASSERT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); VLOG(0) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]"; WriteToFileAudioSink file_sink(file_name); @@ -634,7 +656,7 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) { AudioInputStreamWrapper aisw(audio_manager_.get(), params); ScopedAudioInputStream ais(aisw.Create()); - ASSERT_TRUE(ais->Open()); + EXPECT_EQ(ais->Open(), AudioInputStream::OpenOutcome::kSuccess); VLOG(0) << ">> Resampled rate will be: " << aisw.sample_rate() << " [Hz]"; VLOG(0) << ">> New layout will be: " diff --git a/chromium/media/audio/win/audio_low_latency_output_win.cc b/chromium/media/audio/win/audio_low_latency_output_win.cc index 5282739bb6c..1f7e1ec9461 100644 --- a/chromium/media/audio/win/audio_low_latency_output_win.cc +++ b/chromium/media/audio/win/audio_low_latency_output_win.cc @@ -10,11 +10,13 @@ #include <objbase.h> #include <climits> +#include <memory> #include "base/callback.h" #include "base/command_line.h" #include "base/logging.h" #include "base/metrics/histogram.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" @@ -32,13 +34,23 @@ #include "media/base/limits.h" #include "media/base/media_switches.h" -using base::win::ScopedCOMInitializer; using base::win::ScopedCoMem; +using base::win::ScopedCOMInitializer; namespace media { namespace { +constexpr char kOpenFailureHistogram[] = "Media.Audio.Output.Win.OpenError"; +constexpr char kStartFailureHistogram[] = "Media.Audio.Output.Win.StartError"; +constexpr char kStopFailureHistogram[] = "Media.Audio.Output.Win.StopError"; +constexpr char kRunFailureHistogram[] = "Media.Audio.Output.Win.RunError"; +constexpr char kRenderFailureHistogram[] = "Media.Audio.Output.Win.RenderError"; + +void RecordAudioFailure(const char* histogram, HRESULT hr) { + base::UmaHistogramSparse(histogram, hr); +} + // Converts a COM error into a human-readable string. std::string ErrorToString(HRESULT hresult) { return CoreAudioUtil::ErrorToString(hresult); @@ -180,6 +192,7 @@ bool WASAPIAudioOutputStream::Open() { Microsoft::WRL::ComPtr<IAudioClient> audio_client( CoreAudioUtil::CreateClient(device_id_, eRender, device_role_)); if (!audio_client.Get()) { + RecordAudioFailure(kOpenFailureHistogram, GetLastError()); SendLogMessage("%s => (ERROR: CAU::CreateClient failed)", __func__); return false; } @@ -187,6 +200,7 @@ bool WASAPIAudioOutputStream::Open() { // Extra sanity to ensure that the provided device format is still valid. if (!CoreAudioUtil::IsFormatSupported(audio_client.Get(), share_mode_, &format_)) { + RecordAudioFailure(kOpenFailureHistogram, GetLastError()); SendLogMessage("%s => (ERROR: CAU::IsFormatSupported failed)", __func__); return false; } @@ -200,6 +214,7 @@ bool WASAPIAudioOutputStream::Open() { requested_iaudioclient3_buffer_size_, &endpoint_buffer_size_frames_, communications_device ? &kCommunicationsSessionId : nullptr); if (FAILED(hr)) { + RecordAudioFailure(kOpenFailureHistogram, hr); SendLogMessage("%s => (ERROR: IAudioClient::SharedModeInitialize=[%s])", __func__, ErrorToString(hr).c_str()); return false; @@ -208,6 +223,7 @@ bool WASAPIAudioOutputStream::Open() { REFERENCE_TIME device_period = 0; if (FAILED(CoreAudioUtil::GetDevicePeriod( audio_client.Get(), AUDCLNT_SHAREMODE_SHARED, &device_period))) { + RecordAudioFailure(kOpenFailureHistogram, GetLastError()); return false; } @@ -270,6 +286,7 @@ bool WASAPIAudioOutputStream::Open() { Microsoft::WRL::ComPtr<IAudioRenderClient> audio_render_client = CoreAudioUtil::CreateRenderClient(audio_client.Get()); if (!audio_render_client.Get()) { + RecordAudioFailure(kOpenFailureHistogram, GetLastError()); SendLogMessage("%s => (ERROR: CAU::CreateRenderClient failed)", __func__); return false; } @@ -280,6 +297,7 @@ bool WASAPIAudioOutputStream::Open() { hr = audio_client_->GetService(IID_PPV_ARGS(&audio_clock_)); if (FAILED(hr)) { + RecordAudioFailure(kOpenFailureHistogram, hr); SendLogMessage("%s => (ERROR: IAudioClient::GetService(IAudioClock)=[%s])", __func__, ErrorToString(hr).c_str()); return false; @@ -336,6 +354,7 @@ void WASAPIAudioOutputStream::Start(AudioSourceCallback* callback) { audio_render_client_.Reset(); if (!Open() || !CoreAudioUtil::FillRenderEndpointBufferWithSilence( audio_client_.Get(), audio_render_client_.Get())) { + RecordAudioFailure(kStartFailureHistogram, GetLastError()); SendLogMessage("%s => (ERROR: Recovery attempt failed)", __func__); callback->OnError(AudioSourceCallback::ErrorType::kUnknown); return; @@ -350,11 +369,12 @@ void WASAPIAudioOutputStream::Start(AudioSourceCallback* callback) { // Create and start the thread that will drive the rendering by waiting for // render events. - render_thread_.reset(new base::DelegateSimpleThread( + render_thread_ = std::make_unique<base::DelegateSimpleThread>( this, "wasapi_render_thread", - base::SimpleThread::Options(base::ThreadPriority::REALTIME_AUDIO))); + base::SimpleThread::Options(base::ThreadPriority::REALTIME_AUDIO)); render_thread_->Start(); if (!render_thread_->HasBeenStarted()) { + RecordAudioFailure(kStartFailureHistogram, GetLastError()); SendLogMessage("%s => (ERROR: Failed to start \"wasapi_render_thread\")", __func__); StopThread(); @@ -365,6 +385,7 @@ void WASAPIAudioOutputStream::Start(AudioSourceCallback* callback) { // Start streaming data between the endpoint buffer and the audio engine. HRESULT hr = audio_client_->Start(); if (FAILED(hr)) { + RecordAudioFailure(kStartFailureHistogram, hr); SendLogMessage("%s => (ERROR: IAudioClient::Start=[%s])", __func__, ErrorToString(hr).c_str()); StopThread(); @@ -384,6 +405,7 @@ void WASAPIAudioOutputStream::Stop() { // Stop output audio streaming. HRESULT hr = audio_client_->Stop(); if (FAILED(hr)) { + RecordAudioFailure(kStopFailureHistogram, hr); SendLogMessage("%s => (ERROR: IAudioClient::Stop=[%s])", __func__, ErrorToString(hr).c_str()); source_->OnError(AudioSourceCallback::ErrorType::kUnknown); @@ -396,6 +418,7 @@ void WASAPIAudioOutputStream::Stop() { // Flush all pending data and reset the audio clock stream position to 0. hr = audio_client_->Reset(); if (FAILED(hr)) { + RecordAudioFailure(kStopFailureHistogram, hr); SendLogMessage("%s => (ERROR: IAudioClient::Reset=[%s])", __func__, ErrorToString(hr).c_str()); callback->OnError(AudioSourceCallback::ErrorType::kUnknown); @@ -494,6 +517,7 @@ void WASAPIAudioOutputStream::Run() { hr = audio_clock_->GetFrequency(&device_frequency); error = FAILED(hr); if (error) { + RecordAudioFailure(kRunFailureHistogram, hr); LOG(ERROR) << "WAOS::" << __func__ << " => (ERROR: IAudioClock::GetFrequency=[" << ErrorToString(hr).c_str() << "])"; @@ -522,6 +546,7 @@ void WASAPIAudioOutputStream::Run() { } if (playing && error) { + RecordAudioFailure(kRunFailureHistogram, GetLastError()); LOG(ERROR) << "WAOS::" << __func__ << " => (ERROR: WASAPI rendering failed)"; @@ -561,6 +586,7 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { num_available_frames = endpoint_buffer_size_frames_ - num_queued_frames; if (FAILED(hr)) { + RecordAudioFailure(kRenderFailureHistogram, hr); LOG(ERROR) << "WAOS::" << __func__ << " => (ERROR: IAudioClient::GetCurrentPadding=[" << ErrorToString(hr).c_str() << "])"; @@ -606,6 +632,7 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { hr = audio_render_client_->GetBuffer(packet_size_frames_, &audio_data); if (FAILED(hr)) { + RecordAudioFailure(kRenderFailureHistogram, hr); LOG(ERROR) << "WAOS::" << __func__ << " => (ERROR: IAudioRenderClient::GetBuffer=[" << ErrorToString(hr).c_str() << "])"; @@ -677,6 +704,7 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { // by 10.0 since 10x100ns = 1us. delay_timestamp += base::TimeDelta::FromMicroseconds(qpc_position * 0.1); } else { + RecordAudioFailure(kRenderFailureHistogram, hr); LOG(ERROR) << "WAOS::" << __func__ << " => (ERROR: IAudioClock::GetPosition=[" << ErrorToString(hr).c_str() << "])"; diff --git a/chromium/media/audio/win/volume_range_util.cc b/chromium/media/audio/win/volume_range_util.cc new file mode 100644 index 00000000000..086660309c9 --- /dev/null +++ b/chromium/media/audio/win/volume_range_util.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2021 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/win/volume_range_util.h" + +#include "base/logging.h" +#include "base/metrics/histogram_functions.h" + +namespace media { +namespace { + +constexpr int CountVolumeRangeIntervals(VolumeRange range) { + DCHECK_LT(range.min_volume_db, range.max_volume_db); + DCHECK_GT(range.volume_step_db, 0.0f); + return (range.max_volume_db - range.min_volume_db) / range.volume_step_db; +} + +} // namespace + +void LogVolumeRangeUmaHistograms(absl::optional<VolumeRange> range) { + base::UmaHistogramBoolean("Media.Audio.Capture.Win.VolumeRangeAvailable", + range.has_value()); + if (!range.has_value()) { + return; + } + // Count the number of steps before the range is modified. + constexpr int kMaxVolumeSteps = 2000; + const int num_steps = + std::min(CountVolumeRangeIntervals(*range), kMaxVolumeSteps); + // Approximate `range` to an integer interval since UMA histograms do not log + // floating point values. + range->min_volume_db = std::floor(range->min_volume_db); + range->max_volume_db = std::ceil(range->max_volume_db); + // `range` is expected to be fully included in [`kMinDb`, `kMaxDb`]. + constexpr int kMinDb = -60; + constexpr int kMaxDb = 60; + static_assert(kMinDb < kMaxDb, ""); + // UMA histograms only accept non-negative values; however, a volume range is + // expected to include negative values (if `kMinDb` is negative). Therefore, + // `max(0, -kMinDb)` is added as offset. + constexpr int kVolumeOffsetDb = kMinDb < 0 ? -kMinDb : 0; + range->min_volume_db += kVolumeOffsetDb; + range->max_volume_db += kVolumeOffsetDb; + // Log the modified volume range. + constexpr int kExclusiveMaxVolumeDb = kMaxDb + kVolumeOffsetDb + 1; + DCHECK_LE(range->min_volume_db, range->max_volume_db); + base::UmaHistogramExactLinear("Media.Audio.Capture.Win.VolumeRangeMin2", + static_cast<int>(range->min_volume_db), + kExclusiveMaxVolumeDb); + DCHECK_GE(range->max_volume_db, 0); + base::UmaHistogramExactLinear("Media.Audio.Capture.Win.VolumeRangeMax2", + static_cast<int>(range->max_volume_db), + kExclusiveMaxVolumeDb); + // Log the number of volume range steps. + DCHECK_GT(num_steps, 0); + constexpr int kStepsNumBuckets = 100; + base::UmaHistogramCustomCounts("Media.Audio.Capture.Win.VolumeRangeNumSteps", + /*sample=*/num_steps, + /*min=*/1, /*max=*/kMaxVolumeSteps, + kStepsNumBuckets); +} + +} // namespace media diff --git a/chromium/media/audio/win/volume_range_util.h b/chromium/media/audio/win/volume_range_util.h new file mode 100644 index 00000000000..29d0d62c1fa --- /dev/null +++ b/chromium/media/audio/win/volume_range_util.h @@ -0,0 +1,45 @@ +// Copyright (c) 2021 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. +// +// Volume range definition and UMA logging utilities for +// `IAudioEndpointVolume::GetVolumeRange()`. +// +// Implementation notes: +// - The minimum supported client is Windows Vista. + +#ifndef MEDIA_AUDIO_WIN_VOLUME_RANGE_UTIL_H_ +#define MEDIA_AUDIO_WIN_VOLUME_RANGE_UTIL_H_ + +#include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace media { + +// Microphone volume range in decibels. +struct VolumeRange { + float min_volume_db; // Range minimum. + float max_volume_db; // Range maximum. + // The range above is divided into N uniform intervals of size + // `volume_step_db`. + float volume_step_db; +}; + +// Logs `Media.Audio.Capture.Win.VolumeRange*` UMA histograms. +// `Media.Audio.Capture.Win.VolumeRangeAvailable` is always logged; the logged +// value reflects whether `range` is specified. When specified, the volume range +// and the number of steps are also logged as follows. `range.min_volume_db` and +// `range.max_volume_db` are logged as `Media.Audio.Capture.Win.VolumeRangeMin2` +// and `Media.Audio.Capture.Win.VolumeRangeMax2` respectively by casting the +// original values to an integer, by clamping in the [-60, 60] range, and by +// adding a 60 dB offset in order to log positive values - required by the UMA +// histograms framework. The value for +// `Media.Audio.Capture.Win.VolumeRangeNumSteps` is computed as +// (`range.max_volume_db` - `range.min_volume_db` / `volume_step_db`) and it is +// clamped to 2000. +MEDIA_EXPORT void LogVolumeRangeUmaHistograms( + absl::optional<VolumeRange> range); + +} // namespace media + +#endif // MEDIA_AUDIO_WIN_VOLUME_RANGE_UTIL_H_ diff --git a/chromium/media/audio/win/volume_range_util_unittest.cc b/chromium/media/audio/win/volume_range_util_unittest.cc new file mode 100644 index 00000000000..cc3098eb69f --- /dev/null +++ b/chromium/media/audio/win/volume_range_util_unittest.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2021 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/win/volume_range_util.h" + +#include "base/test/metrics/histogram_tester.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace media { +namespace { + +using base::Bucket; +using testing::ElementsAre; + +constexpr int kClampedMaxVolumeDb = 60; +constexpr int kVolumeOffsetDb = 60; +constexpr int kMaxNumSteps = 2000; + +constexpr VolumeRange kValidVolumeRange{.min_volume_db = -17.0f, + .max_volume_db = 20.0f, + .volume_step_db = 0.03125f}; + +constexpr int ComputeNumSteps(VolumeRange range) { + return (range.max_volume_db - range.min_volume_db) / range.volume_step_db; +} + +TEST(VolumeRangeUtilWin, LogUnavailableVolumeRange) { + base::HistogramTester tester; + LogVolumeRangeUmaHistograms(/*range=*/absl::nullopt); + EXPECT_THAT( + tester.GetAllSamples("Media.Audio.Capture.Win.VolumeRangeAvailable"), + ElementsAre(Bucket(false, 1))); +} + +TEST(VolumeRangeUtilWin, LogAvailableVolumeRange) { + base::HistogramTester tester; + LogVolumeRangeUmaHistograms(kValidVolumeRange); + EXPECT_THAT( + tester.GetAllSamples("Media.Audio.Capture.Win.VolumeRangeAvailable"), + ElementsAre(Bucket(true, 1))); +} + +TEST(VolumeRangeUtilWin, VolumeRangeMinMaxOffsetAdded) { + base::HistogramTester tester; + LogVolumeRangeUmaHistograms(kValidVolumeRange); + tester.ExpectUniqueSample( + "Media.Audio.Capture.Win.VolumeRangeMin2", + static_cast<int>(kValidVolumeRange.min_volume_db + kVolumeOffsetDb), 1); + tester.ExpectUniqueSample( + "Media.Audio.Capture.Win.VolumeRangeMax2", + static_cast<int>(kValidVolumeRange.max_volume_db + kVolumeOffsetDb), 1); +} + +TEST(VolumeRangeUtilWin, VolumeRangeMinMaxRoundedOff) { + base::HistogramTester tester; + constexpr VolumeRange kVolumeRange{.min_volume_db = -1.123f, + .max_volume_db = 1.123f, + .volume_step_db = 2.246}; + LogVolumeRangeUmaHistograms(kVolumeRange); + tester.ExpectUniqueSample("Media.Audio.Capture.Win.VolumeRangeMin2", + -2 + kVolumeOffsetDb, 1); + tester.ExpectUniqueSample("Media.Audio.Capture.Win.VolumeRangeMax2", + 2 + kVolumeOffsetDb, 1); +} + +// Checks that volume values outside of the expected range fall into the first +// and the last (a.k.a., overflow) buckets respectively. +TEST(VolumeRangeUtilWin, VolumeRangeMinMaxClamped) { + base::HistogramTester tester; + constexpr VolumeRange kVolumeRange{.min_volume_db = -10000.0f, + .max_volume_db = 10000.0f, + .volume_step_db = 1.0f}; + LogVolumeRangeUmaHistograms(kVolumeRange); + tester.ExpectUniqueSample("Media.Audio.Capture.Win.VolumeRangeMin2", 0, 1); + constexpr int kOverflowBucket = kClampedMaxVolumeDb + kVolumeOffsetDb + 1; + tester.ExpectUniqueSample("Media.Audio.Capture.Win.VolumeRangeMax2", + kOverflowBucket, 1); +} + +TEST(VolumeRangeUtilWin, VolumeRangeNumSteps) { + base::HistogramTester tester; + LogVolumeRangeUmaHistograms(kValidVolumeRange); + tester.ExpectUniqueSample("Media.Audio.Capture.Win.VolumeRangeNumSteps", + ComputeNumSteps(kValidVolumeRange), 1); +} + +TEST(VolumeRangeUtilWin, VolumeRangeNumStepsClamped) { + base::HistogramTester tester; + constexpr VolumeRange kVolumeRange{.min_volume_db = -17.0f, + .max_volume_db = 20.0f, + .volume_step_db = 0.00925f}; + LogVolumeRangeUmaHistograms(kVolumeRange); + constexpr int kNumSteps = ComputeNumSteps(kVolumeRange); + static_assert(kNumSteps > kMaxNumSteps, ""); + tester.ExpectUniqueSample("Media.Audio.Capture.Win.VolumeRangeNumSteps", + kMaxNumSteps, 1); +} + +} // namespace +} // namespace media diff --git a/chromium/media/base/BUILD.gn b/chromium/media/base/BUILD.gn index 54e6842abd4..eb2295b777f 100644 --- a/chromium/media/base/BUILD.gn +++ b/chromium/media/base/BUILD.gn @@ -374,6 +374,7 @@ source_set("base") { "//ui/display:display", "//ui/events:events", "//ui/events:events_base", + "//ui/events:keyboard_hook", "//url:url", ] @@ -394,6 +395,10 @@ source_set("base") { ] } + if (is_chromeos_ash) { + deps += [ "//ash/constants" ] + } + if (media_use_libvpx) { deps += [ "//third_party/libvpx" ] } diff --git a/chromium/media/base/DEPS b/chromium/media/base/DEPS new file mode 100644 index 00000000000..f51400454f2 --- /dev/null +++ b/chromium/media/base/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+ash/constants", +] diff --git a/chromium/media/base/android/media_codec_bridge.h b/chromium/media/base/android/media_codec_bridge.h index f9cb49f9cfe..4858127716e 100644 --- a/chromium/media/base/android/media_codec_bridge.h +++ b/chromium/media/base/android/media_codec_bridge.h @@ -14,11 +14,11 @@ #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" #include "base/macros.h" -#include "base/optional.h" #include "base/time/time.h" #include "media/base/encryption_pattern.h" #include "media/base/encryption_scheme.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { @@ -95,7 +95,7 @@ class MEDIA_EXPORT MediaCodecBridge { const std::string& iv, const std::vector<SubsampleEntry>& subsamples, EncryptionScheme encryption_scheme, - base::Optional<EncryptionPattern> encryption_pattern, + absl::optional<EncryptionPattern> encryption_pattern, base::TimeDelta presentation_time) = 0; // Submits an empty buffer with the END_OF_STREAM flag set. diff --git a/chromium/media/base/android/media_codec_bridge_impl.cc b/chromium/media/base/android/media_codec_bridge_impl.cc index 8bd73acadf1..68d6a8b0969 100644 --- a/chromium/media/base/android/media_codec_bridge_impl.cc +++ b/chromium/media/base/android/media_codec_bridge_impl.cc @@ -383,7 +383,7 @@ MediaCodecStatus MediaCodecBridgeImpl::QueueSecureInputBuffer( const std::string& iv, const std::vector<SubsampleEntry>& subsamples, EncryptionScheme encryption_scheme, - base::Optional<EncryptionPattern> encryption_pattern, + absl::optional<EncryptionPattern> encryption_pattern, base::TimeDelta presentation_time) { DVLOG(3) << __func__ << " " << index << ": " << data_size; if (data_size > diff --git a/chromium/media/base/android/media_codec_bridge_impl.h b/chromium/media/base/android/media_codec_bridge_impl.h index 1d4ce6da9d8..a1375a8ae10 100644 --- a/chromium/media/base/android/media_codec_bridge_impl.h +++ b/chromium/media/base/android/media_codec_bridge_impl.h @@ -54,7 +54,7 @@ class MEDIA_EXPORT VideoCodecConfig { // VP9 HDR metadata is only embedded in the container. HDR10 metadata is // embedded in the video stream. - base::Optional<gfx::HDRMetadata> hdr_metadata; + absl::optional<gfx::HDRMetadata> hdr_metadata; // Enables the async MediaCodec.Callback API. |on_buffers_available_cb| // will be called when input or output buffers are available. This will be @@ -122,7 +122,7 @@ class MEDIA_EXPORT MediaCodecBridgeImpl : public MediaCodecBridge { const std::string& iv, const std::vector<SubsampleEntry>& subsamples, EncryptionScheme encryption_scheme, - base::Optional<EncryptionPattern> encryption_pattern, + absl::optional<EncryptionPattern> encryption_pattern, base::TimeDelta presentation_time) override; void QueueEOS(int input_buffer_index) override; MediaCodecStatus DequeueInputBuffer(base::TimeDelta timeout, diff --git a/chromium/media/base/android/media_codec_loop.h b/chromium/media/base/android/media_codec_loop.h index 81651149a3c..a66c38cb265 100644 --- a/chromium/media/base/android/media_codec_loop.h +++ b/chromium/media/base/android/media_codec_loop.h @@ -124,7 +124,7 @@ class MEDIA_EXPORT MediaCodecLoop { bool is_eos = false; EncryptionScheme encryption_scheme = EncryptionScheme::kUnencrypted; - base::Optional<EncryptionPattern> encryption_pattern; + absl::optional<EncryptionPattern> encryption_pattern; }; // Handy enum for "no buffer". diff --git a/chromium/media/base/android/media_codec_loop_unittest.cc b/chromium/media/base/android/media_codec_loop_unittest.cc index b52a888f33e..f3ac9638026 100644 --- a/chromium/media/base/android/media_codec_loop_unittest.cc +++ b/chromium/media/base/android/media_codec_loop_unittest.cc @@ -92,8 +92,8 @@ class MediaCodecLoopTest : public testing::Test { std::unique_ptr<MediaCodecBridge> codec(new MockMediaCodecBridge()); // Since we're providing a codec, we do not expect an error. EXPECT_CALL(*client_, OnCodecLoopError()).Times(0); - codec_loop_.reset(new MediaCodecLoop(sdk_int, client_.get(), - std::move(codec), mock_task_runner_)); + codec_loop_ = std::make_unique<MediaCodecLoop>( + sdk_int, client_.get(), std::move(codec), mock_task_runner_); codec_loop_->SetTestTickClock(mock_task_runner_->GetMockTickClock()); Mock::VerifyAndClearExpectations(client_.get()); } @@ -199,9 +199,9 @@ TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) { std::unique_ptr<MediaCodecBridge> codec; EXPECT_CALL(*client_, OnCodecLoopError()).Times(1); const int sdk_int = base::android::SDK_VERSION_LOLLIPOP; - codec_loop_.reset( - new MediaCodecLoop(sdk_int, client_.get(), std::move(codec), - scoped_refptr<base::SingleThreadTaskRunner>())); + codec_loop_ = std::make_unique<MediaCodecLoop>( + sdk_int, client_.get(), std::move(codec), + scoped_refptr<base::SingleThreadTaskRunner>()); // Do not WaitUntilIdle() here, since that assumes that we have a codec. ASSERT_FALSE(codec_loop_->GetCodec()); diff --git a/chromium/media/base/android/media_crypto_context_impl.h b/chromium/media/base/android/media_crypto_context_impl.h index 435c96d953a..27e9eda77d6 100644 --- a/chromium/media/base/android/media_crypto_context_impl.h +++ b/chromium/media/base/android/media_crypto_context_impl.h @@ -7,8 +7,6 @@ #include <jni.h> -#include <memory> - #include "base/android/scoped_java_ref.h" #include "base/macros.h" #include "media/base/android/media_crypto_context.h" diff --git a/chromium/media/base/android/media_drm_bridge.cc b/chromium/media/base/android/media_drm_bridge.cc index 182dc13ad28..69356037f75 100644 --- a/chromium/media/base/android/media_drm_bridge.cc +++ b/chromium/media/base/android/media_drm_bridge.cc @@ -265,22 +265,6 @@ std::string GetSecurityLevelString( return ""; } -bool AreMediaDrmApisAvailable() { - if (base::android::BuildInfo::GetInstance()->sdk_int() < - base::android::SDK_VERSION_KITKAT) - return false; - - int32_t os_major_version = 0; - int32_t os_minor_version = 0; - int32_t os_bugfix_version = 0; - base::SysInfo::OperatingSystemVersionNumbers( - &os_major_version, &os_minor_version, &os_bugfix_version); - if (os_major_version == 4 && os_minor_version == 4 && os_bugfix_version == 0) - return false; - - return true; -} - int GetFirstApiLevel() { JNIEnv* env = AttachCurrentThread(); int first_api_level = Java_MediaDrmBridge_getFirstApiLevel(env); @@ -293,7 +277,7 @@ int GetFirstApiLevel() { // APIs and MediaCodec APIs must be enabled and not blocked. // static bool MediaDrmBridge::IsAvailable() { - return AreMediaDrmApisAvailable() && MediaCodecUtil::IsMediaCodecAvailable(); + return MediaCodecUtil::IsMediaCodecAvailable(); } // static @@ -375,7 +359,6 @@ scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateInternal( const SessionKeysChangeCB& session_keys_change_cb, const SessionExpirationUpdateCB& session_expiration_update_cb) { // All paths requires the MediaDrmApis. - DCHECK(AreMediaDrmApisAvailable()); DCHECK(!scheme_uuid.empty()); // TODO(crbug.com/917527): Check that |origin_id| is specified on devices @@ -400,10 +383,6 @@ scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateWithoutSessionSupport( CreateFetcherCB create_fetcher_cb) { DVLOG(1) << __func__; - // Sessions won't be used so decoding capability is not required. - if (!AreMediaDrmApisAvailable()) - return nullptr; - UUID scheme_uuid = GetKeySystemManager()->GetUUID(key_system); if (scheme_uuid.empty()) return nullptr; diff --git a/chromium/media/base/android/media_drm_bridge_unittest.cc b/chromium/media/base/android/media_drm_bridge_unittest.cc index 40c31575c49..06260327382 100644 --- a/chromium/media/base/android/media_drm_bridge_unittest.cc +++ b/chromium/media/base/android/media_drm_bridge_unittest.cc @@ -127,16 +127,11 @@ TEST_F(MediaDrmBridgeTest, IsKeySystemSupported_Widevine) { EXPECT_TRUE_IF_WIDEVINE_AVAILABLE( IsKeySystemSupportedWithType(kWidevineKeySystem, kVideoMp4)); - if (base::android::BuildInfo::GetInstance()->sdk_int() <= - base::android::SDK_VERSION_KITKAT) { - EXPECT_FALSE(IsKeySystemSupportedWithType(kWidevineKeySystem, kAudioWebM)); - EXPECT_FALSE(IsKeySystemSupportedWithType(kWidevineKeySystem, kVideoWebM)); - } else { - EXPECT_TRUE_IF_WIDEVINE_AVAILABLE( + + EXPECT_TRUE_IF_WIDEVINE_AVAILABLE( IsKeySystemSupportedWithType(kWidevineKeySystem, kAudioWebM)); - EXPECT_TRUE_IF_WIDEVINE_AVAILABLE( + EXPECT_TRUE_IF_WIDEVINE_AVAILABLE( IsKeySystemSupportedWithType(kWidevineKeySystem, kVideoWebM)); - } EXPECT_FALSE(IsKeySystemSupportedWithType(kWidevineKeySystem, "unknown")); EXPECT_FALSE(IsKeySystemSupportedWithType(kWidevineKeySystem, "video/avi")); diff --git a/chromium/media/base/android/mock_media_codec_bridge.h b/chromium/media/base/android/mock_media_codec_bridge.h index 85325f56cff..babe78a3064 100644 --- a/chromium/media/base/android/mock_media_codec_bridge.h +++ b/chromium/media/base/android/mock_media_codec_bridge.h @@ -44,7 +44,7 @@ class MockMediaCodecBridge : public MediaCodecBridge, const std::string& iv, const std::vector<SubsampleEntry>& subsamples, EncryptionScheme encryption_scheme, - base::Optional<EncryptionPattern> encryption_pattern, + absl::optional<EncryptionPattern> encryption_pattern, base::TimeDelta presentation_time)); MOCK_METHOD1(QueueEOS, void(int input_buffer_index)); MOCK_METHOD2(DequeueInputBuffer, diff --git a/chromium/media/base/android/mock_media_crypto_context.h b/chromium/media/base/android/mock_media_crypto_context.h index a113613545b..1cd64809cfd 100644 --- a/chromium/media/base/android/mock_media_crypto_context.h +++ b/chromium/media/base/android/mock_media_crypto_context.h @@ -5,8 +5,6 @@ #ifndef MEDIA_BASE_ANDROID_MOCK_MEDIA_CRYPTO_CONTEXT_H_ #define MEDIA_BASE_ANDROID_MOCK_MEDIA_CRYPTO_CONTEXT_H_ -#include <memory> - #include "base/macros.h" #include "media/base/android/media_crypto_context.h" #include "media/base/cdm_context.h" diff --git a/chromium/media/base/android/test_destruction_observable.h b/chromium/media/base/android/test_destruction_observable.h index 90dddfeec9e..d11b7ab9dda 100644 --- a/chromium/media/base/android/test_destruction_observable.h +++ b/chromium/media/base/android/test_destruction_observable.h @@ -7,7 +7,7 @@ #include "base/callback_helpers.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -55,7 +55,7 @@ class DestructionObserver { bool destructed_; // Whether to expect destruction. Unset if there is no expectation. - base::Optional<bool> expect_destruction_; + absl::optional<bool> expect_destruction_; base::WeakPtrFactory<DestructionObserver> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(DestructionObserver); diff --git a/chromium/media/base/android_overlay_mojo_factory.h b/chromium/media/base/android_overlay_mojo_factory.h index a7c0d06ed20..4a94579f27b 100644 --- a/chromium/media/base/android_overlay_mojo_factory.h +++ b/chromium/media/base/android_overlay_mojo_factory.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_BASE_ANDROID_OVERLAY_MOJO_FACTORY_CB_H_ -#define MEDIA_BASE_ANDROID_OVERLAY_MOJO_FACTORY_CB_H_ +#ifndef MEDIA_BASE_ANDROID_OVERLAY_MOJO_FACTORY_H_ +#define MEDIA_BASE_ANDROID_OVERLAY_MOJO_FACTORY_H_ #include "base/callback.h" #include "base/macros.h" @@ -20,4 +20,4 @@ using AndroidOverlayMojoFactoryCB = } // namespace media -#endif // MEDIA_BASE_ANDROID_OVERLAY_MOJO_FACTORY_CB_H_ +#endif // MEDIA_BASE_ANDROID_OVERLAY_MOJO_FACTORY_H_ diff --git a/chromium/media/base/audio_buffer.cc b/chromium/media/base/audio_buffer.cc index 99cbfb6af4c..56761fbe610 100644 --- a/chromium/media/base/audio_buffer.cc +++ b/chromium/media/base/audio_buffer.cc @@ -6,6 +6,7 @@ #include <cmath> +#include "base/callback_helpers.h" #include "base/logging.h" #include "base/notreached.h" #include "media/base/audio_bus.h" @@ -187,6 +188,26 @@ scoped_refptr<AudioBuffer> AudioBuffer::CopyFrom( } // static +scoped_refptr<AudioBuffer> AudioBuffer::CopyFrom( + int sample_rate, + const base::TimeDelta timestamp, + const AudioBus* audio_bus, + scoped_refptr<AudioBufferMemoryPool> pool) { + DCHECK(audio_bus->frames()); + + const int channel_count = audio_bus->channels(); + DCHECK(channel_count); + + std::vector<const uint8_t*> data(channel_count); + for (int ch = 0; ch < channel_count; ch++) + data[ch] = reinterpret_cast<const uint8_t*>(audio_bus->channel(ch)); + + return CopyFrom(kSampleFormatPlanarF32, GuessChannelLayout(channel_count), + channel_count, sample_rate, audio_bus->frames(), data.data(), + timestamp, std::move(pool)); +} + +// static scoped_refptr<AudioBuffer> AudioBuffer::CopyBitstreamFrom( SampleFormat sample_format, ChannelLayout channel_layout, @@ -255,6 +276,44 @@ scoped_refptr<AudioBuffer> AudioBuffer::CreateEOSBuffer() { nullptr, 0, kNoTimestamp, nullptr)); } +// static +std::unique_ptr<AudioBus> AudioBuffer::WrapOrCopyToAudioBus( + scoped_refptr<AudioBuffer> buffer) { + DCHECK(buffer); + + const int channels = buffer->channel_count(); + const int frames = buffer->frame_count(); + + DCHECK(channels); + DCHECK(frames); + + // |buffer| might already have the right memory layout. Prevent a data copy + // by wrapping it instead. + if (buffer->sample_format() == SampleFormat::kSampleFormatPlanarF32) { + auto audio_bus = AudioBus::CreateWrapper(channels); + + for (int ch = 0; ch < channels; ++ch) { + audio_bus->SetChannelData( + ch, reinterpret_cast<float*>(buffer->channel_data()[ch])); + } + + audio_bus->set_frames(frames); + + // Keep |buffer| alive as long as |audio_bus|. + audio_bus->SetWrappedDataDeleter( + base::BindOnce(base::DoNothing::Once<scoped_refptr<AudioBuffer>>(), + std::move(buffer))); + + return audio_bus; + } + + // |buffer|'s memory can't be wrapped directly. Convert and copy it instead. + auto audio_bus = AudioBus::Create(channels, frames); + buffer->ReadFrames(frames, 0, 0, audio_bus.get()); + + return audio_bus; +} + void AudioBuffer::AdjustSampleRate(int sample_rate) { DCHECK(!end_of_stream_); sample_rate_ = sample_rate; diff --git a/chromium/media/base/audio_buffer.h b/chromium/media/base/audio_buffer.h index 9a90ef1d88d..7042fab41b0 100644 --- a/chromium/media/base/audio_buffer.h +++ b/chromium/media/base/audio_buffer.h @@ -65,6 +65,15 @@ class MEDIA_EXPORT AudioBuffer const base::TimeDelta timestamp, scoped_refptr<AudioBufferMemoryPool> pool = nullptr); + // Create an AudioBuffer from a copy of the data in |audio_bus|. + // For optimal efficiency when many buffers are being created, a + // AudioBufferMemoryPool can be provided to avoid thrashing memory. + static scoped_refptr<AudioBuffer> CopyFrom( + int sample_rate, + const base::TimeDelta timestamp, + const AudioBus* audio_bus, + scoped_refptr<AudioBufferMemoryPool> pool = nullptr); + // Create an AudioBuffer for compressed bitstream. Its channel data is copied // from |data|, and the size is |data_size|. |data| must not be null and // |frame_count| must be >= 0. @@ -110,6 +119,13 @@ class MEDIA_EXPORT AudioBuffer int frame_count, const base::TimeDelta timestamp); + // Helper function that creates a new AudioBus which wraps |audio_buffer| and + // takes a reference on it, if the memory layout (e.g. |sample_format_|) is + // compatible with wrapping. Otherwise, this copies |audio_buffer| to a new + // AudioBus, using ReadFrames(). + static std::unique_ptr<AudioBus> WrapOrCopyToAudioBus( + scoped_refptr<AudioBuffer> audio_buffer); + // Create a AudioBuffer indicating we've reached end of stream. // Calling any method other than end_of_stream() on the resulting buffer // is disallowed. diff --git a/chromium/media/base/audio_buffer_converter.h b/chromium/media/base/audio_buffer_converter.h index 3a0320be67d..f59e8f23354 100644 --- a/chromium/media/base/audio_buffer_converter.h +++ b/chromium/media/base/audio_buffer_converter.h @@ -9,7 +9,6 @@ #include "base/containers/circular_deque.h" #include "base/memory/ref_counted.h" -#include "base/time/time.h" #include "media/base/audio_buffer.h" #include "media/base/audio_converter.h" #include "media/base/audio_parameters.h" diff --git a/chromium/media/base/audio_buffer_unittest.cc b/chromium/media/base/audio_buffer_unittest.cc index 3a30db21d2d..88ea630fc2a 100644 --- a/chromium/media/base/audio_buffer_unittest.cc +++ b/chromium/media/base/audio_buffer_unittest.cc @@ -174,6 +174,44 @@ TEST(AudioBufferTest, CopyFrom) { EXPECT_FALSE(original_buffer->end_of_stream()); } +TEST(AudioBufferTest, CopyFromAudioBus) { + const int kChannelCount = 2; + const int kFrameCount = kSampleRate / 100; + + // For convenience's sake, create an arbitrary |temp_buffer| and copy it to + // |audio_bus|, instead of generating data in |audio_bus| ourselves. + scoped_refptr<AudioBuffer> temp_buffer = MakeAudioBuffer<uint8_t>( + kSampleFormatU8, CHANNEL_LAYOUT_STEREO, kChannelCount, kSampleRate, 1, 1, + kFrameCount, base::TimeDelta()); + + auto audio_bus = media::AudioBus::Create(kChannelCount, kFrameCount); + temp_buffer->ReadFrames(kFrameCount, 0, 0, audio_bus.get()); + + const base::TimeDelta kTimestamp = base::TimeDelta::FromMilliseconds(123); + + auto audio_buffer_from_bus = + media::AudioBuffer::CopyFrom(kSampleRate, kTimestamp, audio_bus.get()); + + EXPECT_EQ(audio_buffer_from_bus->channel_count(), audio_bus->channels()); + EXPECT_EQ(audio_buffer_from_bus->channel_layout(), + GuessChannelLayout(kChannelCount)); + EXPECT_EQ(audio_buffer_from_bus->frame_count(), audio_bus->frames()); + EXPECT_EQ(audio_buffer_from_bus->timestamp(), kTimestamp); + EXPECT_EQ(audio_buffer_from_bus->sample_rate(), kSampleRate); + EXPECT_EQ(audio_buffer_from_bus->sample_format(), + SampleFormat::kSampleFormatPlanarF32); + EXPECT_FALSE(audio_buffer_from_bus->end_of_stream()); + + for (int ch = 0; ch < kChannelCount; ++ch) { + const float* bus_data = audio_bus->channel(ch); + const float* buffer_data = reinterpret_cast<const float*>( + audio_buffer_from_bus->channel_data()[ch]); + + for (int i = 0; i < kFrameCount; ++i) + EXPECT_EQ(buffer_data[i], bus_data[i]); + } +} + TEST(AudioBufferTest, CopyBitstreamFrom) { const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; const int kChannelCount = ChannelLayoutToChannelCount(kChannelLayout); @@ -456,6 +494,38 @@ TEST(AudioBufferTest, ReadF32Planar) { VerifyBus(bus.get(), frames, 1, 1, ValueType::kFloat); } +TEST(AudioBufferTest, WrapOrCopyToAudioBus) { + const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0; + const int channels = ChannelLayoutToChannelCount(channel_layout); + const int frames = 100; + const base::TimeDelta start_time; + scoped_refptr<AudioBuffer> buffer = + MakeAudioBuffer<float>(kSampleFormatPlanarF32, channel_layout, channels, + kSampleRate, 1.0f, 1.0f, frames, start_time); + + // With kSampleFormatPlanarF32, the memory layout should allow |bus| to + // directly wrap |buffer|'s data. + std::unique_ptr<AudioBus> bus = AudioBuffer::WrapOrCopyToAudioBus(buffer); + for (int ch = 0; ch < channels; ++ch) { + EXPECT_EQ(bus->channel(ch), + reinterpret_cast<float*>(buffer->channel_data()[ch])); + } + + // |bus| should have its own reference on |buffer|, so clearing it here should + // not free the underlying data. + buffer.reset(); + VerifyBus(bus.get(), frames, 1, 1, ValueType::kFloat); + + // Interleaved samples cannot be wrapped, and samples will be copied out. + buffer = MakeAudioBuffer<float>(kSampleFormatF32, channel_layout, channels, + kSampleRate, 1.0f, 1.0f, frames, start_time); + + bus = AudioBuffer::WrapOrCopyToAudioBus(buffer); + buffer.reset(); + + VerifyBus(bus.get(), frames, 1, 1, ValueType::kFloat); +} + TEST(AudioBufferTest, EmptyBuffer) { const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0; const int channels = ChannelLayoutToChannelCount(channel_layout); diff --git a/chromium/media/base/audio_bus.cc b/chromium/media/base/audio_bus.cc index 76ee5c24218..3115558f367 100644 --- a/chromium/media/base/audio_bus.cc +++ b/chromium/media/base/audio_bus.cc @@ -64,8 +64,7 @@ void AudioBus::CheckOverflow(int start_frame, int frames, int total_frames) { } AudioBus::AudioBus(int channels, int frames) - : frames_(frames), - can_set_channel_data_(false) { + : frames_(frames), is_wrapper_(false) { ValidateConfig(channels, frames_); int aligned_frames = 0; @@ -78,8 +77,7 @@ AudioBus::AudioBus(int channels, int frames) } AudioBus::AudioBus(int channels, int frames, float* data) - : frames_(frames), - can_set_channel_data_(false) { + : frames_(frames), is_wrapper_(false) { // Since |data| may have come from an external source, ensure it's valid. CHECK(data); ValidateConfig(channels, frames_); @@ -91,9 +89,7 @@ AudioBus::AudioBus(int channels, int frames, float* data) } AudioBus::AudioBus(int frames, const std::vector<float*>& channel_data) - : channel_data_(channel_data), - frames_(frames), - can_set_channel_data_(false) { + : channel_data_(channel_data), frames_(frames), is_wrapper_(false) { ValidateConfig( base::checked_cast<int>(channel_data_.size()), frames_); @@ -103,15 +99,16 @@ AudioBus::AudioBus(int frames, const std::vector<float*>& channel_data) } AudioBus::AudioBus(int channels) - : channel_data_(channels), - frames_(0), - can_set_channel_data_(true) { + : channel_data_(channels), frames_(0), is_wrapper_(true) { CHECK_GT(channels, 0); for (size_t i = 0; i < channel_data_.size(); ++i) channel_data_[i] = NULL; } -AudioBus::~AudioBus() = default; +AudioBus::~AudioBus() { + if (wrapped_data_deleter_cb_) + std::move(wrapped_data_deleter_cb_).Run(); +} std::unique_ptr<AudioBus> AudioBus::Create(int channels, int frames) { return base::WrapUnique(new AudioBus(channels, frames)); @@ -171,7 +168,7 @@ std::unique_ptr<const AudioBus> AudioBus::WrapReadOnlyMemory( } void AudioBus::SetChannelData(int channel, float* data) { - CHECK(can_set_channel_data_); + CHECK(is_wrapper_); CHECK(data); CHECK_GE(channel, 0); CHECK_LT(static_cast<size_t>(channel), channel_data_.size()); @@ -180,11 +177,17 @@ void AudioBus::SetChannelData(int channel, float* data) { } void AudioBus::set_frames(int frames) { - CHECK(can_set_channel_data_); + CHECK(is_wrapper_); ValidateConfig(static_cast<int>(channel_data_.size()), frames); frames_ = frames; } +void AudioBus::SetWrappedDataDeleter(base::OnceClosure deleter) { + CHECK(is_wrapper_); + DCHECK(!wrapped_data_deleter_cb_); + wrapped_data_deleter_cb_ = std::move(deleter); +} + size_t AudioBus::GetBitstreamDataSize() const { DCHECK(is_bitstream_format_); return bitstream_data_size_; diff --git a/chromium/media/base/audio_bus.h b/chromium/media/base/audio_bus.h index 1c520279146..75792baa9b8 100644 --- a/chromium/media/base/audio_bus.h +++ b/chromium/media/base/audio_bus.h @@ -10,6 +10,7 @@ #include <memory> #include <vector> +#include "base/callback.h" #include "base/macros.h" #include "base/memory/aligned_memory.h" #include "media/base/audio_sample_types.h" @@ -76,6 +77,13 @@ class MEDIA_SHMEM_EXPORT AudioBus { void SetChannelData(int channel, float* data); void set_frames(int frames); + // Method optionally called after AudioBus::CreateWrapper(). + // Runs |deleter| when on |this|' destruction, freeing external data + // referenced by SetChannelData(). + // Note: It is illegal to call this method when using a factory method other + // than CreateWrapper(). + void SetWrappedDataDeleter(base::OnceClosure deleter); + // Methods for compressed bitstream formats. The data size may not be equal to // the capacity of the AudioBus. Also, the frame count may not be equal to the // capacity of the AudioBus. Thus, we need extra methods to access the real @@ -220,8 +228,13 @@ class MEDIA_SHMEM_EXPORT AudioBus { std::vector<float*> channel_data_; int frames_; - // Protect SetChannelData() and set_frames() for use by CreateWrapper(). - bool can_set_channel_data_; + // Protect SetChannelData(), set_frames() and SetWrappedDataDeleter() for use + // by CreateWrapper(). + bool is_wrapper_; + + // Run on destruction. Frees memory to the data set via SetChannelData(). + // Only used with CreateWrapper(). + base::OnceClosure wrapped_data_deleter_cb_; DISALLOW_COPY_AND_ASSIGN(AudioBus); }; diff --git a/chromium/media/base/audio_bus_unittest.cc b/chromium/media/base/audio_bus_unittest.cc index 38d5cbd09da..e2cac3c8e29 100644 --- a/chromium/media/base/audio_bus_unittest.cc +++ b/chromium/media/base/audio_bus_unittest.cc @@ -11,6 +11,7 @@ #include "base/memory/aligned_memory.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" +#include "base/test/bind.h" #include "base/time/time.h" #include "build/build_config.h" #include "media/base/audio_bus.h" @@ -157,8 +158,16 @@ TEST_F(AudioBusTest, CreateWrapper) { for (int i = 0; i < bus->channels(); ++i) bus->SetChannelData(i, data_[i]); + bool deleted = false; + bus->SetWrappedDataDeleter( + base::BindLambdaForTesting([&]() { deleted = true; })); + VerifyChannelAndFrameCount(bus.get()); VerifyReadWriteAndAlignment(bus.get()); + + EXPECT_FALSE(deleted); + bus.reset(); + EXPECT_TRUE(deleted); } // Verify an AudioBus created via wrapping a vector works as advertised. diff --git a/chromium/media/base/audio_capturer_source.h b/chromium/media/base/audio_capturer_source.h index ca91a598c22..7ec2136eb5f 100644 --- a/chromium/media/base/audio_capturer_source.h +++ b/chromium/media/base/audio_capturer_source.h @@ -23,6 +23,11 @@ class AudioProcessorControls; class AudioCapturerSource : public base::RefCountedThreadSafe<media::AudioCapturerSource> { public: + enum class ErrorCode { + kUnknown = 0, + kSystemPermissions = 1, + }; + class CaptureCallback { public: // Signals that audio recording has been started. Called asynchronously @@ -40,7 +45,7 @@ class AudioCapturerSource bool key_pressed) = 0; // Signals an error has occurred. - virtual void OnCaptureError(const std::string& message) = 0; + virtual void OnCaptureError(ErrorCode code, const std::string& message) = 0; // Signals the muted state has changed. May be called before // OnCaptureStarted. diff --git a/chromium/media/base/audio_converter.h b/chromium/media/base/audio_converter.h index 5e1b609fabf..45b667b1fe8 100644 --- a/chromium/media/base/audio_converter.h +++ b/chromium/media/base/audio_converter.h @@ -23,7 +23,6 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/time/time.h" #include "media/base/audio_parameters.h" #include "media/base/media_export.h" diff --git a/chromium/media/base/audio_decoder.h b/chromium/media/base/audio_decoder.h index 245ac2979a0..961d570e561 100644 --- a/chromium/media/base/audio_decoder.h +++ b/chromium/media/base/audio_decoder.h @@ -5,8 +5,6 @@ #ifndef MEDIA_BASE_AUDIO_DECODER_H_ #define MEDIA_BASE_AUDIO_DECODER_H_ -#include <string> - #include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" diff --git a/chromium/media/base/audio_encoder.h b/chromium/media/base/audio_encoder.h index 2d3362bebca..d7979cca1e9 100644 --- a/chromium/media/base/audio_encoder.h +++ b/chromium/media/base/audio_encoder.h @@ -55,7 +55,7 @@ class MEDIA_EXPORT AudioEncoder { Options(const Options&); ~Options(); - base::Optional<int> bitrate; + absl::optional<int> bitrate; int channels; @@ -69,7 +69,7 @@ class MEDIA_EXPORT AudioEncoder { // invoked on the same sequence on which EncodeAudio() is called. using OutputCB = base::RepeatingCallback<void(EncodedAudioBuffer output, - base::Optional<CodecDescription>)>; + absl::optional<CodecDescription>)>; // Signature of the callback to report errors. using StatusCB = base::OnceCallback<void(Status error)>; diff --git a/chromium/media/base/audio_parameters.h b/chromium/media/base/audio_parameters.h index 9d571a3c6e2..fbebe23cf45 100644 --- a/chromium/media/base/audio_parameters.h +++ b/chromium/media/base/audio_parameters.h @@ -11,7 +11,6 @@ #include "base/compiler_specific.h" #include "base/numerics/checked_math.h" -#include "base/optional.h" #include "base/time/time.h" #include "build/build_config.h" #include "media/base/audio_bus.h" @@ -20,6 +19,7 @@ #include "media/base/channel_layout.h" #include "media/base/media_shmem_export.h" #include "media/base/sample_format.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -254,7 +254,7 @@ class MEDIA_SHMEM_EXPORT AudioParameters { } int frames_per_buffer() const { return frames_per_buffer_; } - base::Optional<HardwareCapabilities> hardware_capabilities() const { + absl::optional<HardwareCapabilities> hardware_capabilities() const { return hardware_capabilities_; } @@ -305,7 +305,7 @@ class MEDIA_SHMEM_EXPORT AudioParameters { // Audio hardware specific parameters, these are treated as read-only and // changing them has no effect. - base::Optional<HardwareCapabilities> hardware_capabilities_; + absl::optional<HardwareCapabilities> hardware_capabilities_; }; // Comparison is useful when AudioParameters is used with std structures. diff --git a/chromium/media/base/audio_processing.h b/chromium/media/base/audio_processing.h index 46428114847..52f32fbc6ef 100644 --- a/chromium/media/base/audio_processing.h +++ b/chromium/media/base/audio_processing.h @@ -8,7 +8,6 @@ #include <string> #include "base/files/file.h" -#include "base/time/time.h" #include "base/unguessable_token.h" #include "media/base/media_export.h" diff --git a/chromium/media/base/audio_renderer.h b/chromium/media/base/audio_renderer.h index 15701b34294..907d0fc7f82 100644 --- a/chromium/media/base/audio_renderer.h +++ b/chromium/media/base/audio_renderer.h @@ -7,11 +7,11 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/optional.h" #include "base/time/time.h" #include "media/base/buffering_state.h" #include "media/base/media_export.h" #include "media/base/pipeline_status.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -63,7 +63,7 @@ class MEDIA_EXPORT AudioRenderer { // Set a hint indicating target latency. See comment in renderer.h. // |latency_hint| may be nullopt to indicate the hint has been cleared // (restore UA default). - virtual void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) = 0; + virtual void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) = 0; // Sets a flag indicating that the AudioRenderer should use or avoid pitch // preservation when playing back at speeds other than 1.0. diff --git a/chromium/media/base/audio_renderer_mixer_input.h b/chromium/media/base/audio_renderer_mixer_input.h index c56e1f209c8..724cba483d5 100644 --- a/chromium/media/base/audio_renderer_mixer_input.h +++ b/chromium/media/base/audio_renderer_mixer_input.h @@ -83,7 +83,7 @@ class MEDIA_EXPORT AudioRendererMixerInput double volume_ GUARDED_BY(volume_lock_) = 1.0; scoped_refptr<AudioRendererSink> sink_; - base::Optional<OutputDeviceInfo> device_info_; + absl::optional<OutputDeviceInfo> device_info_; // AudioConverter::InputCallback implementation. double ProvideInput(AudioBus* audio_bus, uint32_t frames_delayed) override; diff --git a/chromium/media/base/cdm_context.cc b/chromium/media/base/cdm_context.cc index 9b30303dd4b..fc2901585bb 100644 --- a/chromium/media/base/cdm_context.cc +++ b/chromium/media/base/cdm_context.cc @@ -22,8 +22,8 @@ Decryptor* CdmContext::GetDecryptor() { return nullptr; } -base::Optional<base::UnguessableToken> CdmContext::GetCdmId() const { - return base::nullopt; +absl::optional<base::UnguessableToken> CdmContext::GetCdmId() const { + return absl::nullopt; } std::string CdmContext::CdmIdToString(const base::UnguessableToken* cdm_id) { diff --git a/chromium/media/base/cdm_context.h b/chromium/media/base/cdm_context.h index 9bb677217cc..f426dd3fd13 100644 --- a/chromium/media/base/cdm_context.h +++ b/chromium/media/base/cdm_context.h @@ -7,17 +7,13 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/optional.h" +#include "base/memory/scoped_refptr.h" #include "base/unguessable_token.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "media/base/media_export.h" #include "media/media_buildflags.h" - -#if defined(OS_WIN) -#include <wrl/client.h> -struct IMFCdmProxy; -#endif +#include "third_party/abseil-cpp/absl/types/optional.h" #if BUILDFLAG(IS_CHROMEOS_ASH) namespace chromeos { @@ -35,6 +31,10 @@ class MediaCryptoContext; class FuchsiaCdmContext; #endif +#if defined(OS_WIN) +class MediaFoundationCdmProxy; +#endif + // An interface representing the context that a media player needs from a // content decryption module (CDM) to decrypt (and decode) encrypted buffers. // Typically this will be passed to the media player (e.g. using SetCdm()). @@ -88,9 +88,9 @@ class MEDIA_EXPORT CdmContext { virtual Decryptor* GetDecryptor(); // Returns an ID that can be used to find a remote CDM, in which case this CDM - // serves as a proxy to the remote one. Returns base::nullopt when remote CDM + // serves as a proxy to the remote one. Returns absl::nullopt when remote CDM // is not supported (e.g. this CDM is a local CDM). - virtual base::Optional<base::UnguessableToken> GetCdmId() const; + virtual absl::optional<base::UnguessableToken> GetCdmId() const; static std::string CdmIdToString(const base::UnguessableToken* cdm_id); @@ -101,7 +101,7 @@ class MEDIA_EXPORT CdmContext { virtual bool RequiresMediaFoundationRenderer(); using GetMediaFoundationCdmProxyCB = - base::OnceCallback<void(Microsoft::WRL::ComPtr<IMFCdmProxy>)>; + base::OnceCallback<void(scoped_refptr<MediaFoundationCdmProxy>)>; // This allows a CdmContext to expose an IMFTrustedInput instance for use in // a Media Foundation rendering pipeline. This method is asynchronous because // the underlying MF-based CDM might not have a native session created yet. diff --git a/chromium/media/base/data_source.h b/chromium/media/base/data_source.h index 82dd76485fa..08c740c0fa0 100644 --- a/chromium/media/base/data_source.h +++ b/chromium/media/base/data_source.h @@ -9,7 +9,6 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/time/time.h" #include "media/base/media_export.h" namespace media { diff --git a/chromium/media/base/decoder_buffer.h b/chromium/media/base/decoder_buffer.h index ea64fa50d0b..9a305f3e77a 100644 --- a/chromium/media/base/decoder_buffer.h +++ b/chromium/media/base/decoder_buffer.h @@ -14,7 +14,6 @@ #include "base/check.h" #include "base/macros.h" -#include "base/memory/aligned_memory.h" #include "base/memory/read_only_shared_memory_region.h" #include "base/memory/ref_counted.h" #include "base/time/time.h" diff --git a/chromium/media/base/decrypt_config.cc b/chromium/media/base/decrypt_config.cc index 5b7c02c8f5e..ff3ed63f7a4 100644 --- a/chromium/media/base/decrypt_config.cc +++ b/chromium/media/base/decrypt_config.cc @@ -19,7 +19,7 @@ std::unique_ptr<DecryptConfig> DecryptConfig::CreateCencConfig( const std::string& iv, const std::vector<SubsampleEntry>& subsamples) { return std::make_unique<DecryptConfig>(EncryptionScheme::kCenc, key_id, iv, - subsamples, base::nullopt); + subsamples, absl::nullopt); } // static @@ -27,7 +27,7 @@ std::unique_ptr<DecryptConfig> DecryptConfig::CreateCbcsConfig( const std::string& key_id, const std::string& iv, const std::vector<SubsampleEntry>& subsamples, - base::Optional<EncryptionPattern> encryption_pattern) { + absl::optional<EncryptionPattern> encryption_pattern) { return std::make_unique<DecryptConfig>(EncryptionScheme::kCbcs, key_id, iv, subsamples, std::move(encryption_pattern)); @@ -38,7 +38,7 @@ DecryptConfig::DecryptConfig( const std::string& key_id, const std::string& iv, const std::vector<SubsampleEntry>& subsamples, - base::Optional<EncryptionPattern> encryption_pattern) + absl::optional<EncryptionPattern> encryption_pattern) : encryption_scheme_(encryption_scheme), key_id_(key_id), iv_(iv), diff --git a/chromium/media/base/decrypt_config.h b/chromium/media/base/decrypt_config.h index 79905419bdd..a9c55064566 100644 --- a/chromium/media/base/decrypt_config.h +++ b/chromium/media/base/decrypt_config.h @@ -13,11 +13,11 @@ #include <vector> #include "base/macros.h" -#include "base/optional.h" #include "media/base/encryption_pattern.h" #include "media/base/encryption_scheme.h" #include "media/base/media_export.h" #include "media/base/subsample_entry.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -47,20 +47,20 @@ class MEDIA_EXPORT DecryptConfig { const std::string& key_id, const std::string& iv, const std::vector<SubsampleEntry>& subsamples, - base::Optional<EncryptionPattern> encryption_pattern); + absl::optional<EncryptionPattern> encryption_pattern); DecryptConfig(EncryptionScheme encryption_scheme, const std::string& key_id, const std::string& iv, const std::vector<SubsampleEntry>& subsamples, - base::Optional<EncryptionPattern> encryption_pattern); + absl::optional<EncryptionPattern> encryption_pattern); ~DecryptConfig(); const std::string& key_id() const { return key_id_; } const std::string& iv() const { return iv_; } const std::vector<SubsampleEntry>& subsamples() const { return subsamples_; } EncryptionScheme encryption_scheme() const { return encryption_scheme_; } - const base::Optional<EncryptionPattern>& encryption_pattern() const { + const absl::optional<EncryptionPattern>& encryption_pattern() const { return encryption_pattern_; } @@ -95,7 +95,7 @@ class MEDIA_EXPORT DecryptConfig { const std::vector<SubsampleEntry> subsamples_; // Only specified if |encryption_mode_| requires a pattern. - base::Optional<EncryptionPattern> encryption_pattern_; + absl::optional<EncryptionPattern> encryption_pattern_; DISALLOW_ASSIGN(DecryptConfig); }; diff --git a/chromium/media/base/decrypt_config_unittest.cc b/chromium/media/base/decrypt_config_unittest.cc index e39d7a79461..014ee6a4d23 100644 --- a/chromium/media/base/decrypt_config_unittest.cc +++ b/chromium/media/base/decrypt_config_unittest.cc @@ -78,7 +78,7 @@ TEST(DecryptConfigTest, CbcsConstruction) { // Now without pattern. config = DecryptConfig::CreateCbcsConfig(kAlternateKeyId, kDefaultIV, - {{1, 2}}, base::nullopt); + {{1, 2}}, absl::nullopt); EXPECT_EQ(config->key_id(), kAlternateKeyId); EXPECT_EQ(config->iv(), kDefaultIV); EXPECT_EQ(config->subsamples().size(), 1u); @@ -173,7 +173,7 @@ TEST(DecryptConfigTest, CbcsMatches) { // Without pattern. auto config6 = DecryptConfig::CreateCbcsConfig(kDefaultKeyId, kDefaultIV, {}, - base::nullopt); + absl::nullopt); EXPECT_FALSE(config1->Matches(*config6)); EXPECT_FALSE(config5->Matches(*config6)); EXPECT_FALSE(config6->Matches(*config1)); @@ -192,7 +192,7 @@ TEST(DecryptConfigTest, Output) { // Simple 'cbcs' config. stream << *DecryptConfig::CreateCbcsConfig(kDefaultKeyId, kDefaultIV, {}, - base::nullopt); + absl::nullopt); // 'cbcs' config with subsamples and pattern. stream << *DecryptConfig::CreateCbcsConfig(kAlternateKeyId, kAlternateIV, diff --git a/chromium/media/base/demuxer.h b/chromium/media/base/demuxer.h index c9a4ebbd6b8..e048fca2d9c 100644 --- a/chromium/media/base/demuxer.h +++ b/chromium/media/base/demuxer.h @@ -11,7 +11,6 @@ #include <vector> #include "base/macros.h" -#include "base/optional.h" #include "base/time/time.h" #include "media/base/container_names.h" #include "media/base/data_source.h" @@ -22,6 +21,7 @@ #include "media/base/media_track.h" #include "media/base/pipeline_status.h" #include "media/base/ranges.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -149,7 +149,7 @@ class MEDIA_EXPORT Demuxer : public MediaResource { // Implementations where this is not meaningful will return an empty value. // Implementations that do provide values should always provide a value, // returning CONTAINER_UNKNOWN in cases where the container is not known. - virtual base::Optional<container_names::MediaContainerName> + virtual absl::optional<container_names::MediaContainerName> GetContainerForMetrics() const = 0; // The |track_ids| vector has either 1 track, or is empty, indicating that diff --git a/chromium/media/base/demuxer_memory_limit_cast_unittest.cc b/chromium/media/base/demuxer_memory_limit_cast_unittest.cc index 41b68a20aed..4dbe6d4308b 100644 --- a/chromium/media/base/demuxer_memory_limit_cast_unittest.cc +++ b/chromium/media/base/demuxer_memory_limit_cast_unittest.cc @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/optional.h" #include "media/base/audio_decoder_config.h" #include "media/base/demuxer.h" #include "media/base/demuxer_memory_limit.h" #include "media/base/media_util.h" #include "media/base/video_decoder_config.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { diff --git a/chromium/media/base/demuxer_stream.h b/chromium/media/base/demuxer_stream.h index 30236894215..3b10523f7fb 100644 --- a/chromium/media/base/demuxer_stream.h +++ b/chromium/media/base/demuxer_stream.h @@ -7,7 +7,6 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" -#include "base/time/time.h" #include "media/base/media_export.h" #include "media/base/video_transformation.h" diff --git a/chromium/media/base/eme_constants.h b/chromium/media/base/eme_constants.h index 11e7c1ed3ff..6e47c0ed18a 100644 --- a/chromium/media/base/eme_constants.h +++ b/chromium/media/base/eme_constants.h @@ -187,19 +187,20 @@ enum class EmeConfigRule { IDENTIFIER_AND_PERSISTENCE_REQUIRED, // The configuration option prevents use of hardware-secure codecs. - // This rule only has meaning on platforms that distinguish hardware-secure - // codecs (i.e. Android, Windows and ChromeOS). HW_SECURE_CODECS_NOT_ALLOWED, // The configuration option is supported if hardware-secure codecs are used. - // This rule only has meaning on platforms that distinguish hardware-secure - // codecs (i.e. Android, Windows and ChromeOS). HW_SECURE_CODECS_REQUIRED, // The configuration option is supported on platforms where hardware-secure // codecs are used and an identifier is also required (i.e. ChromeOS). IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED, + // The configuration option is supported on platforms where hardware-secure + // codecs are used and both identifier and persistent state are required (i.e. + // Windows). + IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED, + // The configuration option is supported without conditions. SUPPORTED, }; diff --git a/chromium/media/base/encryption_pattern.h b/chromium/media/base/encryption_pattern.h index 928c1dbadb9..89c3e28b115 100644 --- a/chromium/media/base/encryption_pattern.h +++ b/chromium/media/base/encryption_pattern.h @@ -20,7 +20,7 @@ namespace media { // encrypted, and the next nine are skipped. This pattern is applied // repeatedly until the end of the last 16-byte block in the subsample. // Any remaining bytes are left clear. -// TODO(jrummell): Use base::Optional<EncryptionPattern> everywhere. +// TODO(jrummell): Use absl::optional<EncryptionPattern> everywhere. class MEDIA_EXPORT EncryptionPattern { public: EncryptionPattern(); diff --git a/chromium/media/base/fake_audio_renderer_sink.h b/chromium/media/base/fake_audio_renderer_sink.h index 9918eabad63..63af4b5b987 100644 --- a/chromium/media/base/fake_audio_renderer_sink.h +++ b/chromium/media/base/fake_audio_renderer_sink.h @@ -7,8 +7,6 @@ #include <stdint.h> -#include <string> - #include "base/macros.h" #include "media/base/audio_parameters.h" #include "media/base/audio_renderer_sink.h" diff --git a/chromium/media/base/fake_text_track_stream.cc b/chromium/media/base/fake_text_track_stream.cc index 72a1655cfa8..5a9bd62f5ce 100644 --- a/chromium/media/base/fake_text_track_stream.cc +++ b/chromium/media/base/fake_text_track_stream.cc @@ -63,8 +63,8 @@ void FakeTextTrackStream::SatisfyPendingRead( const uint8_t* const sd_buf = &side_data[0]; const int sd_len = static_cast<int>(side_data.size()); - scoped_refptr<DecoderBuffer> buffer; - buffer = DecoderBuffer::CopyFrom(data_buf, data_len, sd_buf, sd_len); + scoped_refptr<DecoderBuffer> buffer = + DecoderBuffer::CopyFrom(data_buf, data_len, sd_buf, sd_len); buffer->set_timestamp(start); buffer->set_duration(duration); diff --git a/chromium/media/base/format_utils.cc b/chromium/media/base/format_utils.cc index be5a8b9c411..b9fc8143bd6 100644 --- a/chromium/media/base/format_utils.cc +++ b/chromium/media/base/format_utils.cc @@ -8,7 +8,7 @@ namespace media { -base::Optional<VideoPixelFormat> GfxBufferFormatToVideoPixelFormat( +absl::optional<VideoPixelFormat> GfxBufferFormatToVideoPixelFormat( gfx::BufferFormat format) { switch (format) { case gfx::BufferFormat::BGRX_8888: @@ -40,11 +40,11 @@ base::Optional<VideoPixelFormat> GfxBufferFormatToVideoPixelFormat( default: DLOG(WARNING) << "Unsupported BufferFormat: " << gfx::BufferFormatToString(format); - return base::nullopt; + return absl::nullopt; } } -base::Optional<gfx::BufferFormat> VideoPixelFormatToGfxBufferFormat( +absl::optional<gfx::BufferFormat> VideoPixelFormatToGfxBufferFormat( VideoPixelFormat pixel_format) { switch (pixel_format) { case PIXEL_FORMAT_ARGB: @@ -70,7 +70,7 @@ base::Optional<gfx::BufferFormat> VideoPixelFormatToGfxBufferFormat( default: DLOG(WARNING) << "Unsupported VideoPixelFormat: " << pixel_format; - return base::nullopt; + return absl::nullopt; } } diff --git a/chromium/media/base/format_utils.h b/chromium/media/base/format_utils.h index de7980c7034..eed468b553f 100644 --- a/chromium/media/base/format_utils.h +++ b/chromium/media/base/format_utils.h @@ -5,17 +5,17 @@ #ifndef MEDIA_BASE_FORMAT_UTILS_H_ #define MEDIA_BASE_FORMAT_UTILS_H_ -#include "base/optional.h" #include "media/base/media_export.h" #include "media/base/video_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/buffer_types.h" namespace media { -MEDIA_EXPORT base::Optional<VideoPixelFormat> GfxBufferFormatToVideoPixelFormat( +MEDIA_EXPORT absl::optional<VideoPixelFormat> GfxBufferFormatToVideoPixelFormat( gfx::BufferFormat format); -MEDIA_EXPORT base::Optional<gfx::BufferFormat> +MEDIA_EXPORT absl::optional<gfx::BufferFormat> VideoPixelFormatToGfxBufferFormat(VideoPixelFormat pixel_format); } // namespace media diff --git a/chromium/media/base/frame_rate_estimator.cc b/chromium/media/base/frame_rate_estimator.cc index 96a39b90707..48cf9f9a56d 100644 --- a/chromium/media/base/frame_rate_estimator.cc +++ b/chromium/media/base/frame_rate_estimator.cc @@ -62,7 +62,7 @@ void FrameRateEstimator::AddSample(base::TimeDelta frame_duration) { most_recent_bucket_ = bucketed_fps_min; } -base::Optional<int> FrameRateEstimator::ComputeFPS() { +absl::optional<int> FrameRateEstimator::ComputeFPS() { return most_recent_bucket_; } diff --git a/chromium/media/base/frame_rate_estimator.h b/chromium/media/base/frame_rate_estimator.h index 3a00f7bcd5e..38262abe4fc 100644 --- a/chromium/media/base/frame_rate_estimator.h +++ b/chromium/media/base/frame_rate_estimator.h @@ -6,9 +6,9 @@ #define MEDIA_BASE_FRAME_RATE_ESTIMATOR_H_ #include "base/macros.h" -#include "base/optional.h" #include "media/base/media_export.h" #include "media/base/moving_average.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -25,7 +25,7 @@ class MEDIA_EXPORT FrameRateEstimator { // Return the current (bucketed) frame rate (not duration), or nullopt if one // isn't available with suitable certainty. - base::Optional<int> ComputeFPS(); + absl::optional<int> ComputeFPS(); // Reset everything. void Reset(); @@ -43,7 +43,7 @@ class MEDIA_EXPORT FrameRateEstimator { uint64_t required_samples_; // Most recently computed bucketed FPS (not duration), if any. - base::Optional<int> most_recent_bucket_; + absl::optional<int> most_recent_bucket_; }; } // namespace media diff --git a/chromium/media/base/ipc/media_param_traits.cc b/chromium/media/base/ipc/media_param_traits.cc index 271754aff43..884ac079019 100644 --- a/chromium/media/base/ipc/media_param_traits.cc +++ b/chromium/media/base/ipc/media_param_traits.cc @@ -41,7 +41,7 @@ bool ParamTraits<AudioParameters>::Read(const base::Pickle* m, int sample_rate, frames_per_buffer, channels, effects; std::vector<media::Point> mic_positions; AudioLatency::LatencyType latency_tag; - base::Optional<media::AudioParameters::HardwareCapabilities> + absl::optional<media::AudioParameters::HardwareCapabilities> hardware_capabilities; if (!ReadParam(m, iter, &format) || !ReadParam(m, iter, &channel_layout) || diff --git a/chromium/media/base/key_system_names.cc b/chromium/media/base/key_system_names.cc index 6fdf44cac9e..6a8bc0a9f42 100644 --- a/chromium/media/base/key_system_names.cc +++ b/chromium/media/base/key_system_names.cc @@ -13,15 +13,14 @@ bool IsClearKey(const std::string& key_system) { return key_system == kClearKey; } -bool IsChildKeySystemOf(const std::string& key_system, - const std::string& base) { +bool IsSubKeySystemOf(const std::string& key_system, const std::string& base) { std::string prefix = base + '.'; return key_system.substr(0, prefix.size()) == prefix; } bool IsExternalClearKey(const std::string& key_system) { return key_system == kExternalClearKey || - IsChildKeySystemOf(key_system, kExternalClearKey); + IsSubKeySystemOf(key_system, kExternalClearKey); } } // namespace media diff --git a/chromium/media/base/key_system_names.h b/chromium/media/base/key_system_names.h index 0ba1934a275..e7ed8840b1e 100644 --- a/chromium/media/base/key_system_names.h +++ b/chromium/media/base/key_system_names.h @@ -18,8 +18,8 @@ namespace media { MEDIA_EXPORT bool IsClearKey(const std::string& key_system); // Returns true if |key_system| is (reverse) sub-domain of |base|. -MEDIA_EXPORT bool IsChildKeySystemOf(const std::string& key_system, - const std::string& base); +MEDIA_EXPORT bool IsSubKeySystemOf(const std::string& key_system, + const std::string& base); // Returns true if |key_system| is External Clear Key, false otherwise. MEDIA_EXPORT bool IsExternalClearKey(const std::string& key_system); diff --git a/chromium/media/base/key_system_properties.h b/chromium/media/base/key_system_properties.h index 032f745fd42..0cd832ff69a 100644 --- a/chromium/media/base/key_system_properties.h +++ b/chromium/media/base/key_system_properties.h @@ -40,9 +40,17 @@ class MEDIA_EXPORT KeySystemProperties { virtual SupportedCodecs GetSupportedHwSecureCodecs() const; // Returns the configuration rule for supporting a robustness requirement. + // If `hw_secure_requirement` is true, then the key system already has a HW + // secure requirement, if false then it already has a requirement to disallow + // HW secure; if null then there is no HW secure requirement to apply. This + // does not imply that `requested_robustness` should be ignored, both rules + // must be applied. + // TODO(crbug.com/1204284): Refactor this and remove the + // `hw_secure_requirement` argument. virtual EmeConfigRule GetRobustnessConfigRule( EmeMediaType media_type, - const std::string& requested_robustness) const = 0; + const std::string& requested_robustness, + const bool* hw_secure_requirement) const = 0; // Returns the support this key system provides for persistent-license // sessions. diff --git a/chromium/media/base/key_systems.cc b/chromium/media/base/key_systems.cc index c05c68495e6..03c1007bcd2 100644 --- a/chromium/media/base/key_systems.cc +++ b/chromium/media/base/key_systems.cc @@ -162,7 +162,8 @@ class ClearKeyProperties : public KeySystemProperties { EmeConfigRule GetRobustnessConfigRule( EmeMediaType media_type, - const std::string& requested_robustness) const override { + const std::string& requested_robustness, + const bool* /*hw_secure_requirement*/) const override { return requested_robustness.empty() ? EmeConfigRule::SUPPORTED : EmeConfigRule::NOT_SUPPORTED; } @@ -219,7 +220,7 @@ static bool IsPotentiallySupportedKeySystem(const std::string& key_system) { // Chromecast defines behaviors for Cast clients within its reverse domain. const char kChromecastRoot[] = "com.chromecast"; - if (IsChildKeySystemOf(key_system, kChromecastRoot)) + if (IsSubKeySystemOf(key_system, kChromecastRoot)) return true; // Implementations that do not have a specification or appropriate glue code @@ -264,7 +265,8 @@ class KeySystemsImpl : public KeySystems { EmeConfigRule GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, - const std::string& requested_robustness) const override; + const std::string& requested_robustness, + const bool* hw_secure_requirement) const override; EmeSessionTypeSupport GetPersistentLicenseSessionSupport( const std::string& key_system) const override; @@ -711,7 +713,8 @@ EmeConfigRule KeySystemsImpl::GetContentTypeConfigRule( EmeConfigRule KeySystemsImpl::GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, - const std::string& requested_robustness) const { + const std::string& requested_robustness, + const bool* hw_secure_requirement) const { DCHECK(thread_checker_.CalledOnValidThread()); auto key_system_iter = key_system_properties_map_.find(key_system); @@ -719,8 +722,8 @@ EmeConfigRule KeySystemsImpl::GetRobustnessConfigRule( NOTREACHED(); return EmeConfigRule::NOT_SUPPORTED; } - return key_system_iter->second->GetRobustnessConfigRule(media_type, - requested_robustness); + return key_system_iter->second->GetRobustnessConfigRule( + media_type, requested_robustness, hw_secure_requirement); } EmeSessionTypeSupport KeySystemsImpl::GetPersistentLicenseSessionSupport( diff --git a/chromium/media/base/key_systems.h b/chromium/media/base/key_systems.h index 34fd6a46602..9d2e2b7fc26 100644 --- a/chromium/media/base/key_systems.h +++ b/chromium/media/base/key_systems.h @@ -56,10 +56,18 @@ class MEDIA_EXPORT KeySystems { const std::vector<std::string>& codecs) const = 0; // Returns the configuration rule for supporting a robustness requirement. + // If `hw_secure_requirement` is true, then the key system already has a HW + // secure requirement, if false then it already has a requirement to disallow + // HW secure; if null then there is no HW secure requirement to apply. This + // does not imply that `requested_robustness` should be ignored, both rules + // must be applied. + // TODO(crbug.com/1204284): Refactor this and remove the + // `hw_secure_requirement` argument. virtual EmeConfigRule GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, - const std::string& requested_robustness) const = 0; + const std::string& requested_robustness, + const bool* hw_secure_requirement) const = 0; // Returns the support |key_system| provides for persistent-license sessions. virtual EmeSessionTypeSupport GetPersistentLicenseSessionSupport( diff --git a/chromium/media/base/key_systems_unittest.cc b/chromium/media/base/key_systems_unittest.cc index e38e2b33c2b..4a21bb67c4b 100644 --- a/chromium/media/base/key_systems_unittest.cc +++ b/chromium/media/base/key_systems_unittest.cc @@ -76,7 +76,8 @@ class TestKeySystemPropertiesBase : public KeySystemProperties { EmeConfigRule GetRobustnessConfigRule( EmeMediaType media_type, - const std::string& requested_robustness) const override { + const std::string& requested_robustness, + const bool* /*hw_secure_requirement*/) const override { return requested_robustness.empty() ? EmeConfigRule::SUPPORTED : EmeConfigRule::NOT_SUPPORTED; } @@ -140,7 +141,8 @@ class ExternalKeySystemProperties : public TestKeySystemPropertiesBase { EmeConfigRule GetRobustnessConfigRule( EmeMediaType media_type, - const std::string& requested_robustness) const override { + const std::string& requested_robustness, + const bool* /*hw_secure_requirement*/) const override { if (requested_robustness == kRobustnessSupported) return EmeConfigRule::SUPPORTED; else if (requested_robustness == kRobustnessSecureCodecsRequired) @@ -206,7 +208,7 @@ bool IsSupportedKeySystem(const std::string& key_system) { EmeConfigRule GetRobustnessConfigRule(const std::string& requested_robustness) { return KeySystems::GetInstance()->GetRobustnessConfigRule( - kExternal, EmeMediaType::VIDEO, requested_robustness); + kExternal, EmeMediaType::VIDEO, requested_robustness, nullptr); } // Adds test container and codec masks. @@ -268,7 +270,7 @@ class TestMediaClient : public MediaClient { // test the key system update case. void DisableExternalKeySystemSupport(); - base::Optional<::media::AudioRendererAlgorithmParameters> + absl::optional<::media::AudioRendererAlgorithmParameters> GetAudioRendererAlgorithmParameters(AudioParameters audio_parameters) final; private: @@ -317,10 +319,10 @@ void TestMediaClient::DisableExternalKeySystemSupport() { supports_external_key_system_ = false; } -base::Optional<::media::AudioRendererAlgorithmParameters> +absl::optional<::media::AudioRendererAlgorithmParameters> TestMediaClient::GetAudioRendererAlgorithmParameters( AudioParameters audio_parameters) { - return base::nullopt; + return absl::nullopt; } } // namespace diff --git a/chromium/media/base/limits.h b/chromium/media/base/limits.h index edc8fc6a39e..5430e09c1cb 100644 --- a/chromium/media/base/limits.h +++ b/chromium/media/base/limits.h @@ -32,6 +32,9 @@ enum { // restriction. // - Most PC audio hardware is limited to 192 kHz, some specialized DAC // devices will use 768 kHz though. + // + // kMaxSampleRate should be updated with + // blink::audio_utilities::MaxAudioBufferSampleRate() kMaxSampleRate = 768000, kMinSampleRate = 3000, kMaxChannels = 32, diff --git a/chromium/media/base/localized_strings.h b/chromium/media/base/localized_strings.h index 9ee50b18bb7..48779b0af56 100644 --- a/chromium/media/base/localized_strings.h +++ b/chromium/media/base/localized_strings.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_BASE_MEDIA_LOCALIZED_STRINGS_H_ -#define MEDIA_BASE_MEDIA_LOCALIZED_STRINGS_H_ +#ifndef MEDIA_BASE_LOCALIZED_STRINGS_H_ +#define MEDIA_BASE_LOCALIZED_STRINGS_H_ #include <string> @@ -46,4 +46,4 @@ std::u16string GetLocalizedStringUTF16(MessageId message_id); } // namespace media -#endif // MEDIA_BASE_MEDIA_LOCALIZED_STRINGS_H_ +#endif // MEDIA_BASE_LOCALIZED_STRINGS_H_ diff --git a/chromium/media/base/mac/videotoolbox_helpers.cc b/chromium/media/base/mac/videotoolbox_helpers.cc index 014cd2a05dd..25c7b864933 100644 --- a/chromium/media/base/mac/videotoolbox_helpers.cc +++ b/chromium/media/base/mac/videotoolbox_helpers.cc @@ -74,6 +74,10 @@ class RawAnnexBBuffer : public AnnexBBuffer { : annexb_buffer_(annexb_buffer), annexb_buffer_size_(annexb_buffer_size), annexb_buffer_offset_(0) {} + RawAnnexBBuffer() = delete; + RawAnnexBBuffer(const RawAnnexBBuffer&) = delete; + RawAnnexBBuffer& operator=(const RawAnnexBBuffer&) = delete; + bool Reserve(size_t size) override { reserved_size_ = size; return size <= annexb_buffer_size_; @@ -90,14 +94,16 @@ class RawAnnexBBuffer : public AnnexBBuffer { size_t annexb_buffer_size_; size_t annexb_buffer_offset_; size_t reserved_size_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(RawAnnexBBuffer); }; class StringAnnexBBuffer : public AnnexBBuffer { public: explicit StringAnnexBBuffer(std::string* str_annexb_buffer) : str_annexb_buffer_(str_annexb_buffer) {} + StringAnnexBBuffer() = delete; + StringAnnexBBuffer(const StringAnnexBBuffer&) = delete; + StringAnnexBBuffer& operator=(const StringAnnexBBuffer&) = delete; + bool Reserve(size_t size) override { str_annexb_buffer_->reserve(size); return true; @@ -109,7 +115,6 @@ class StringAnnexBBuffer : public AnnexBBuffer { private: std::string* str_annexb_buffer_; - DISALLOW_IMPLICIT_CONSTRUCTORS(StringAnnexBBuffer); }; template <typename NalSizeType> diff --git a/chromium/media/base/media_client.h b/chromium/media/base/media_client.h index 5c7d6c06c68..db1d3091990 100644 --- a/chromium/media/base/media_client.h +++ b/chromium/media/base/media_client.h @@ -9,7 +9,6 @@ #include <string> #include <vector> -#include "base/optional.h" #include "media/base/audio_codecs.h" #include "media/base/audio_parameters.h" #include "media/base/key_system_properties.h" @@ -17,6 +16,7 @@ #include "media/base/media_types.h" #include "media/base/video_codecs.h" #include "media/base/video_color_space.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/color_space.h" #include "url/gurl.h" @@ -61,7 +61,7 @@ class MEDIA_EXPORT MediaClient { virtual bool IsSupportedBitstreamAudioCodec(AudioCodec codec) = 0; // Optionally returns audio renderer algorithm parameters. - virtual base::Optional<::media::AudioRendererAlgorithmParameters> + virtual absl::optional<::media::AudioRendererAlgorithmParameters> GetAudioRendererAlgorithmParameters(AudioParameters audio_parameters) = 0; }; diff --git a/chromium/media/base/media_drm_storage.h b/chromium/media/base/media_drm_storage.h index ac17314bc3e..d691f232b60 100644 --- a/chromium/media/base/media_drm_storage.h +++ b/chromium/media/base/media_drm_storage.h @@ -14,9 +14,9 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "media/base/media_drm_key_type.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "url/origin.h" namespace base { @@ -32,7 +32,7 @@ class MEDIA_EXPORT MediaDrmStorage public: // When using per-origin provisioning, this is the ID for the origin. // If not specified, the device specific origin ID is to be used. - using MediaDrmOriginId = base::Optional<base::UnguessableToken>; + using MediaDrmOriginId = absl::optional<base::UnguessableToken>; struct MEDIA_EXPORT SessionData { SessionData(std::vector<uint8_t> key_set_id, diff --git a/chromium/media/base/media_log.h b/chromium/media/base/media_log.h index dc3ea25be66..46b52ae5587 100644 --- a/chromium/media/base/media_log.h +++ b/chromium/media/base/media_log.h @@ -214,8 +214,9 @@ class MEDIA_EXPORT LogHelper { // Provides a stringstream to collect a log entry to pass to the provided // MediaLog at the requested level. -#define MEDIA_LOG(level, media_log) \ - LogHelper((MediaLogMessageLevel::k##level), (media_log)).stream() +#define MEDIA_LOG(level, media_log) \ + media::LogHelper((media::MediaLogMessageLevel::k##level), (media_log)) \ + .stream() // Logs only while |count| < |max|, increments |count| for each log, and warns // in the log if |count| has just reached |max|. diff --git a/chromium/media/base/media_serializers.h b/chromium/media/base/media_serializers.h index 5dbff1ba7fb..a91f8bc2413 100644 --- a/chromium/media/base/media_serializers.h +++ b/chromium/media/base/media_serializers.h @@ -61,8 +61,8 @@ struct MediaSerializer<std::vector<VecType>> { // serialize optional types template <typename OptType> -struct MediaSerializer<base::Optional<OptType>> { - static base::Value Serialize(const base::Optional<OptType>& opt) { +struct MediaSerializer<absl::optional<OptType>> { + static base::Value Serialize(const absl::optional<OptType>& opt) { return opt ? MediaSerializer<OptType>::Serialize(opt.value()) : base::Value("unset"); // TODO(tmathmeyer) maybe empty string? } diff --git a/chromium/media/base/media_serializers_unittest.cc b/chromium/media/base/media_serializers_unittest.cc index e3f3a7bfc5c..466155569b8 100644 --- a/chromium/media/base/media_serializers_unittest.cc +++ b/chromium/media/base/media_serializers_unittest.cc @@ -41,7 +41,7 @@ TEST(MediaSerializersTest, BaseTypes) { } TEST(MediaSerializersTest, Optional) { - base::Optional<int> foo; + absl::optional<int> foo; ASSERT_EQ(ToString(MediaSerialize(foo)), "unset"); foo = 1; diff --git a/chromium/media/base/media_switches.cc b/chromium/media/base/media_switches.cc index 065ff8a0bd6..7c6ca90d52a 100644 --- a/chromium/media/base/media_switches.cc +++ b/chromium/media/base/media_switches.cc @@ -9,6 +9,14 @@ #include "build/chromeos_buildflags.h" #include "components/system_media_controls/linux/buildflags/buildflags.h" +#if defined(OS_LINUX) +#include "base/cpu.h" +#endif + +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "ash/constants/ash_features.h" +#endif + namespace switches { // Allow users to specify a custom buffer size for debugging purpose. @@ -91,8 +99,8 @@ const char kUseCras[] = "use-cras"; #endif // defined(USE_CRAS) // For automated testing of protected content, this switch allows specific -// domains (e.g. example.com) to skip asking the user for permission to share -// the protected media identifier. In this context, domain does not include the +// domains (e.g. example.com) to always allow the permission to share the +// protected media identifier. In this context, domain does not include the // port number. User's content settings will not be affected by enabling this // switch. // Reference: http://crbug.com/718608 @@ -178,7 +186,8 @@ const char kOverrideEnabledCdmInterfaceVersion[] = // Overrides hardware secure codecs support for testing. If specified, real // platform hardware secure codecs check will be skipped. Codecs are separated -// by comma. Valid codecs are "vp8", "vp9" and "avc1". For example: +// by comma. Valid video codecs are "vp8", "vp9" and "avc1", and the only valid +// audio codec is "vorbis". For example: // --override-hardware-secure-codecs-for-testing=vp8,vp9 // --override-hardware-secure-codecs-for-testing=avc1 // CENC encryption scheme is assumed to be supported for the specified codecs. @@ -331,7 +340,7 @@ const base::Feature kD3D11PrintCodecOnCrash{"D3D11PrintCodecOnCrash", // Enable The D3D11 Video decoder. const base::Feature kD3D11VideoDecoder{"D3D11VideoDecoder", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // Tell D3D11VideoDecoder to ignore workarounds for zero copy. Requires that // kD3D11VideoDecoder is enabled. @@ -452,7 +461,7 @@ const base::Feature kSuspendMutedAudio{"SuspendMutedAudio", // Enables using the media history store to store media engagement metrics. const base::Feature kUseMediaHistoryStore{"UseMediaHistoryStore", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // Use R16 texture for 9-16 bit channel instead of half-float conversion by CPU. const base::Feature kUseR16Texture{"use-r16-texture", @@ -517,17 +526,9 @@ const base::Feature kVideoBlitColorAccuracy{"video-blit-color-accuracy", const base::Feature kExternalClearKeyForTesting{ "ExternalClearKeyForTesting", base::FEATURE_DISABLED_BY_DEFAULT}; -// Enables the Live Caption feature. -const base::Feature kLiveCaption { - "LiveCaption", -#if defined(OS_CHROMEOS) - // TODO(crbug.com/1209058): Remove this special case after it's merged - // into M91. - base::FEATURE_DISABLED_BY_DEFAULT -#else - base::FEATURE_ENABLED_BY_DEFAULT -#endif -}; +// Enables the Live Caption feature on supported devices. +const base::Feature kLiveCaption{"LiveCaption", + base::FEATURE_ENABLED_BY_DEFAULT}; // Use the Speech On-Device API (SODA) to power the Live Caption feature instead // of the Cloud-based Open Speech API. @@ -631,11 +632,6 @@ const base::Feature kMediaDrmPreprovisioning{"MediaDrmPreprovisioning", const base::Feature kMediaDrmPreprovisioningAtStartup{ "MediaDrmPreprovisioningAtStartup", base::FEATURE_ENABLED_BY_DEFAULT}; -// Prevents using SurfaceLayer for videos. This is meant to be used by embedders -// that cannot support SurfaceLayer at the moment. -const base::Feature kDisableSurfaceLayerForVideo{ - "DisableSurfaceLayerForVideo", base::FEATURE_DISABLED_BY_DEFAULT}; - // Enable picture in picture web api for android. const base::Feature kPictureInPictureAPI{"PictureInPictureAPI", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -859,6 +855,10 @@ const base::Feature kUseFakeDeviceForMediaStream{ const base::Feature kBresenhamCadence{"BresenhamCadence", base::FEATURE_DISABLED_BY_DEFAULT}; +// Display the playback speed button on the media controls. +const base::Feature kPlaybackSpeedButton{"PlaybackSpeedButton", + base::FEATURE_DISABLED_BY_DEFAULT}; + bool IsVideoCaptureAcceleratedJpegDecodingEnabled() { if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableAcceleratedMjpegDecode)) { @@ -874,4 +874,35 @@ bool IsVideoCaptureAcceleratedJpegDecodingEnabled() { return false; } +bool IsLiveCaptionFeatureEnabled() { + if (!base::FeatureList::IsEnabled(media::kLiveCaption)) + return false; + +#if BUILDFLAG(IS_CHROMEOS_ASH) + // Some Chrome OS devices do not support on-device speech. + if (!base::FeatureList::IsEnabled(ash::features::kOnDeviceSpeechRecognition)) + return false; +#endif + +#if defined(OS_LINUX) + if (base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) { + // Check if the CPU has the required instruction set to run the Speech + // On-Device API (SODA) library. + static bool has_sse41 = base::CPU().has_sse41(); + if (!has_sse41) + return false; + } +#endif + +#if defined(OS_WIN) && defined(ARCH_CPU_ARM64) + if (base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) { + // The Speech On-Device API (SODA) component does not support Windows on + // arm64. + return false; + } +#endif + + return true; +} + } // namespace media diff --git a/chromium/media/base/media_switches.h b/chromium/media/base/media_switches.h index 57ae439f02b..69b9cfcc7b8 100644 --- a/chromium/media/base/media_switches.h +++ b/chromium/media/base/media_switches.h @@ -10,6 +10,7 @@ #include <string> #include "base/feature_list.h" +#include "base/metrics/field_trial_params.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "media/base/media_export.h" @@ -162,6 +163,7 @@ MEDIA_EXPORT extern const base::Feature kMediaSessionWebRTC; MEDIA_EXPORT extern const base::Feature kMemoryPressureBasedSourceBufferGC; MEDIA_EXPORT extern const base::Feature kOverlayFullscreenVideo; MEDIA_EXPORT extern const base::Feature kPictureInPicture; +MEDIA_EXPORT extern const base::Feature kPlaybackSpeedButton; MEDIA_EXPORT extern const base::Feature kPreloadMediaEngagementData; MEDIA_EXPORT extern const base::Feature kPreloadMetadataLazyLoad; MEDIA_EXPORT extern const base::Feature kPreloadMetadataSuspend; @@ -205,7 +207,6 @@ MEDIA_EXPORT extern const base::Feature kMediaControlsExpandGesture; MEDIA_EXPORT extern const base::Feature kMediaDrmPersistentLicense; MEDIA_EXPORT extern const base::Feature kMediaDrmPreprovisioning; MEDIA_EXPORT extern const base::Feature kMediaDrmPreprovisioningAtStartup; -MEDIA_EXPORT extern const base::Feature kDisableSurfaceLayerForVideo; MEDIA_EXPORT extern const base::Feature kCanPlayHls; MEDIA_EXPORT extern const base::Feature kPictureInPictureAPI; MEDIA_EXPORT extern const base::Feature kHlsPlayer; @@ -246,6 +247,8 @@ MEDIA_EXPORT std::string GetEffectiveAutoplayPolicy( MEDIA_EXPORT bool IsVideoCaptureAcceleratedJpegDecodingEnabled(); +MEDIA_EXPORT bool IsLiveCaptionFeatureEnabled(); + enum class kCrosGlobalMediaControlsPinOptions { kPin, kNotPin, diff --git a/chromium/media/base/media_url_demuxer.cc b/chromium/media/base/media_url_demuxer.cc index cff132e69e2..734604a4a7f 100644 --- a/chromium/media/base/media_url_demuxer.cc +++ b/chromium/media/base/media_url_demuxer.cc @@ -83,9 +83,9 @@ int64_t MediaUrlDemuxer::GetMemoryUsage() const { return 0; } -base::Optional<container_names::MediaContainerName> +absl::optional<container_names::MediaContainerName> MediaUrlDemuxer::GetContainerForMetrics() const { - return base::nullopt; + return absl::nullopt; } void MediaUrlDemuxer::OnEnabledAudioTracksChanged( diff --git a/chromium/media/base/media_url_demuxer.h b/chromium/media/base/media_url_demuxer.h index 638cc9b14a7..4d497ebacec 100644 --- a/chromium/media/base/media_url_demuxer.h +++ b/chromium/media/base/media_url_demuxer.h @@ -58,7 +58,7 @@ class MEDIA_EXPORT MediaUrlDemuxer : public Demuxer { base::TimeDelta GetStartTime() const override; base::Time GetTimelineOffset() const override; int64_t GetMemoryUsage() const override; - base::Optional<container_names::MediaContainerName> GetContainerForMetrics() + absl::optional<container_names::MediaContainerName> GetContainerForMetrics() const override; void OnEnabledAudioTracksChanged(const std::vector<MediaTrack::Id>& track_ids, base::TimeDelta curr_time, diff --git a/chromium/media/base/memory_dump_provider_proxy.h b/chromium/media/base/memory_dump_provider_proxy.h index 0473c79403d..0bdda75b7c5 100644 --- a/chromium/media/base/memory_dump_provider_proxy.h +++ b/chromium/media/base/memory_dump_provider_proxy.h @@ -8,10 +8,6 @@ #include <stddef.h> #include <stdint.h> -#include <memory> -#include <string> -#include <utility> - #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" diff --git a/chromium/media/base/mock_filters.cc b/chromium/media/base/mock_filters.cc index 4bf36edf546..981c4363d84 100644 --- a/chromium/media/base/mock_filters.cc +++ b/chromium/media/base/mock_filters.cc @@ -169,12 +169,12 @@ MockCdmContext::MockCdmContext() = default; MockCdmContext::~MockCdmContext() = default; -base::Optional<base::UnguessableToken> MockCdmContext::GetCdmId() const { +absl::optional<base::UnguessableToken> MockCdmContext::GetCdmId() const { return cdm_id_; } void MockCdmContext::set_cdm_id(const base::UnguessableToken& cdm_id) { - cdm_id_ = base::make_optional(cdm_id); + cdm_id_ = absl::make_optional(cdm_id); } MockCdmPromise::MockCdmPromise(bool expect_success) { diff --git a/chromium/media/base/mock_filters.h b/chromium/media/base/mock_filters.h index 281afd56335..e70cb8c6d9f 100644 --- a/chromium/media/base/mock_filters.h +++ b/chromium/media/base/mock_filters.h @@ -69,7 +69,7 @@ class MockPipelineClient : public Pipeline::Client { MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&)); MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&)); MOCK_METHOD1(OnVideoOpacityChange, void(bool)); - MOCK_METHOD1(OnVideoFrameRateChange, void(base::Optional<int>)); + MOCK_METHOD1(OnVideoFrameRateChange, void(absl::optional<int>)); MOCK_METHOD0(OnVideoAverageKeyframeDistanceUpdate, void()); MOCK_METHOD1(OnAudioDecoderChange, void(const AudioDecoderInfo&)); MOCK_METHOD1(OnVideoDecoderChange, void(const VideoDecoderInfo&)); @@ -103,7 +103,7 @@ class MockPipeline : public Pipeline { MOCK_METHOD2(OnEnabledAudioTracksChanged, void(const std::vector<MediaTrack::Id>&, base::OnceClosure)); MOCK_METHOD2(OnSelectedVideoTrackChanged, - void(base::Optional<MediaTrack::Id>, base::OnceClosure)); + void(absl::optional<MediaTrack::Id>, base::OnceClosure)); // TODO(sandersd): This should automatically return true between Start() and // Stop(). (Or better, remove it from the interface entirely.) @@ -116,7 +116,7 @@ class MockPipeline : public Pipeline { MOCK_METHOD1(SetPlaybackRate, void(double)); MOCK_CONST_METHOD0(GetVolume, float()); MOCK_METHOD1(SetVolume, void(float)); - MOCK_METHOD1(SetLatencyHint, void(base::Optional<base::TimeDelta>)); + MOCK_METHOD1(SetLatencyHint, void(absl::optional<base::TimeDelta>)); MOCK_METHOD1(SetPreservesPitch, void(bool)); MOCK_METHOD1(SetAutoplayInitiated, void(bool)); @@ -175,7 +175,7 @@ class MockDemuxer : public Demuxer { MOCK_CONST_METHOD0(GetTimelineOffset, base::Time()); MOCK_CONST_METHOD0(GetMemoryUsage, int64_t()); MOCK_CONST_METHOD0(GetContainerForMetrics, - base::Optional<container_names::MediaContainerName>()); + absl::optional<container_names::MediaContainerName>()); MOCK_METHOD3(OnEnabledAudioTracksChanged, void(const std::vector<MediaTrack::Id>&, base::TimeDelta, @@ -401,7 +401,7 @@ class MockRendererClient : public RendererClient { MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&)); MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&)); MOCK_METHOD1(OnVideoOpacityChange, void(bool)); - MOCK_METHOD1(OnVideoFrameRateChange, void(base::Optional<int>)); + MOCK_METHOD1(OnVideoFrameRateChange, void(absl::optional<int>)); MOCK_METHOD1(OnDurationChange, void(base::TimeDelta)); MOCK_METHOD1(OnRemotePlayStateChange, void(MediaStatus::State state)); MOCK_METHOD0(IsVideoStreamAvailable, bool()); @@ -431,7 +431,7 @@ class MockVideoRenderer : public VideoRenderer { MOCK_METHOD0(OnTimeProgressing, void()); MOCK_METHOD0(OnTimeStopped, void()); MOCK_METHOD1(SetLatencyHint, - void(base::Optional<base::TimeDelta> latency_hint)); + void(absl::optional<base::TimeDelta> latency_hint)); private: DISALLOW_COPY_AND_ASSIGN(MockVideoRenderer); @@ -459,7 +459,7 @@ class MockAudioRenderer : public AudioRenderer { MOCK_METHOD0(StartPlaying, void()); MOCK_METHOD1(SetVolume, void(float volume)); MOCK_METHOD1(SetLatencyHint, - void(base::Optional<base::TimeDelta> latency_hint)); + void(absl::optional<base::TimeDelta> latency_hint)); MOCK_METHOD1(SetPreservesPitch, void(bool)); MOCK_METHOD1(SetAutoplayInitiated, void(bool)); @@ -482,7 +482,7 @@ class MockRenderer : public Renderer { void(MediaResource* media_resource, RendererClient* client, PipelineStatusCallback& init_cb)); - MOCK_METHOD1(SetLatencyHint, void(base::Optional<base::TimeDelta>)); + MOCK_METHOD1(SetLatencyHint, void(absl::optional<base::TimeDelta>)); MOCK_METHOD1(SetPreservesPitch, void(bool)); MOCK_METHOD1(SetAutoplayInitiated, void(bool)); void Flush(base::OnceClosure flush_cb) override { OnFlush(flush_cb); } @@ -638,12 +638,12 @@ class MockCdmContext : public CdmContext { bool(GetMediaFoundationCdmProxyCB get_mf_cdm_proxy_cb)); #endif - base::Optional<base::UnguessableToken> GetCdmId() const override; + absl::optional<base::UnguessableToken> GetCdmId() const override; void set_cdm_id(const base::UnguessableToken& cdm_id); private: - base::Optional<base::UnguessableToken> cdm_id_; + absl::optional<base::UnguessableToken> cdm_id_; DISALLOW_COPY_AND_ASSIGN(MockCdmContext); }; @@ -830,7 +830,7 @@ class MockMediaClient : public media::MediaClient { MOCK_METHOD1(IsSupportedVideoType, bool(const media::VideoType& type)); MOCK_METHOD1(IsSupportedBitstreamAudioCodec, bool(media::AudioCodec codec)); MOCK_METHOD1(GetAudioRendererAlgorithmParameters, - base::Optional<::media::AudioRendererAlgorithmParameters>( + absl::optional<::media::AudioRendererAlgorithmParameters>( media::AudioParameters audio_parameters)); private: diff --git a/chromium/media/base/offloading_audio_encoder_unittest.cc b/chromium/media/base/offloading_audio_encoder_unittest.cc index b1377ae44c8..a3bbe6482f4 100644 --- a/chromium/media/base/offloading_audio_encoder_unittest.cc +++ b/chromium/media/base/offloading_audio_encoder_unittest.cc @@ -55,7 +55,7 @@ TEST_F(OffloadingAudioEncoderTest, Initialize) { bool called_output = false; AudioEncoder::Options options; AudioEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](EncodedAudioBuffer, base::Optional<AudioEncoder::CodecDescription>) { + [&](EncodedAudioBuffer, absl::optional<AudioEncoder::CodecDescription>) { EXPECT_TRUE(callback_runner_->RunsTasksInCurrentSequence()); called_output = true; }); diff --git a/chromium/media/base/offloading_video_encoder_unittest.cc b/chromium/media/base/offloading_video_encoder_unittest.cc index 8b2bc0a28b5..570c7dd98b6 100644 --- a/chromium/media/base/offloading_video_encoder_unittest.cc +++ b/chromium/media/base/offloading_video_encoder_unittest.cc @@ -57,7 +57,7 @@ TEST_F(OffloadingVideoEncoderTest, Initialize) { VideoEncoder::Options options; VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { EXPECT_TRUE(callback_runner_->RunsTasksInCurrentSequence()); called_output = true; }); @@ -111,7 +111,7 @@ TEST_F(OffloadingVideoEncoderTest, ChangeOptions) { }); VideoEncoder::OutputCB output_cb = base::BindRepeating( - [](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { }); EXPECT_CALL(*mock_video_encoder_, ChangeOptions(_, _, _)) diff --git a/chromium/media/base/overlay_info.h b/chromium/media/base/overlay_info.h index 603a2208f86..f0f1e6448ed 100644 --- a/chromium/media/base/overlay_info.h +++ b/chromium/media/base/overlay_info.h @@ -7,16 +7,16 @@ #include "base/callback.h" #include "base/macros.h" -#include "base/optional.h" #include "base/unguessable_token.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { struct MEDIA_EXPORT OverlayInfo { // An unset routing token indicates "do not use any routing token". A null // routing token isn't serializable, else we'd probably use that instead. - using RoutingToken = base::Optional<base::UnguessableToken>; + using RoutingToken = absl::optional<base::UnguessableToken>; OverlayInfo(); OverlayInfo(const OverlayInfo&); diff --git a/chromium/media/base/pipeline.h b/chromium/media/base/pipeline.h index 3e1180fb019..ffa8ad8a029 100644 --- a/chromium/media/base/pipeline.h +++ b/chromium/media/base/pipeline.h @@ -8,7 +8,6 @@ #include <memory> #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "base/time/time.h" #include "media/base/audio_decoder_config.h" #include "media/base/buffering_state.h" @@ -22,6 +21,7 @@ #include "media/base/video_decoder_config.h" #include "media/base/video_transformation.h" #include "media/base/waiting.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { @@ -85,7 +85,7 @@ class MEDIA_EXPORT Pipeline { // Executed whenever the video frame rate changes. |fps| will be unset if // the frame rate is unstable. The duration used for the frame rate is // based on wall clock time, not media time. - virtual void OnVideoFrameRateChange(base::Optional<int> fps) = 0; + virtual void OnVideoFrameRateChange(absl::optional<int> fps) = 0; }; virtual ~Pipeline() {} @@ -148,7 +148,7 @@ class MEDIA_EXPORT Pipeline { // |selected_track_id| is either empty, which means no video track is // selected, or contains the selected video track id. virtual void OnSelectedVideoTrackChanged( - base::Optional<MediaTrack::Id> selected_track_id, + absl::optional<MediaTrack::Id> selected_track_id, base::OnceClosure change_completed_cb) = 0; // Stops the pipeline. This is a blocking function. @@ -223,7 +223,7 @@ class MEDIA_EXPORT Pipeline { // post-decode buffering required to start playback or resume from // seek/underflow. A null option indicates the hint is unset and the pipeline // can choose its own default. - virtual void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) = 0; + virtual void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) = 0; // Sets whether pitch adjustment should be applied when the playback rate is // different than 1.0. diff --git a/chromium/media/base/pipeline_impl.cc b/chromium/media/base/pipeline_impl.cc index 9eeeb52b324..f29e529019c 100644 --- a/chromium/media/base/pipeline_impl.cc +++ b/chromium/media/base/pipeline_impl.cc @@ -71,7 +71,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost, void Resume(std::unique_ptr<Renderer> default_renderer, base::TimeDelta time); void SetPlaybackRate(double playback_rate); void SetVolume(float volume); - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint); + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint); void SetPreservesPitch(bool preserves_pitch); void SetAutoplayInitiated(bool autoplay_initiated); base::TimeDelta GetMediaTime() const; @@ -88,7 +88,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost, // |selected_track_id| is either empty, which means no video track is // selected, or contains the selected video track id. void OnSelectedVideoTrackChanged( - base::Optional<MediaTrack::Id> selected_track_id, + absl::optional<MediaTrack::Id> selected_track_id, base::OnceClosure change_completed_cb); private: @@ -150,7 +150,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost, void OnVideoConfigChange(const VideoDecoderConfig& config) final; void OnVideoNaturalSizeChange(const gfx::Size& size) final; void OnVideoOpacityChange(bool opaque) final; - void OnVideoFrameRateChange(base::Optional<int> fps) final; + void OnVideoFrameRateChange(absl::optional<int> fps) final; // Common handlers for notifications from renderers and demuxer. void OnPipelineError(PipelineStatus error); @@ -194,7 +194,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost, double playback_rate_; float volume_; - base::Optional<base::TimeDelta> latency_hint_; + absl::optional<base::TimeDelta> latency_hint_; CdmContext* cdm_context_; // By default, apply pitch adjustments. @@ -480,7 +480,7 @@ void PipelineImpl::RendererWrapper::SetVolume(float volume) { } void PipelineImpl::RendererWrapper::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { DCHECK(media_task_runner_->BelongsToCurrentThread()); if (latency_hint_ == latency_hint) @@ -580,16 +580,16 @@ void PipelineImpl::RendererWrapper::CreateRendererInternal( DCHECK(cdm_context_ || !HasEncryptedStream()) << "CDM should be available now if has encrypted stream"; - base::Optional<RendererFactoryType> factory_type; + absl::optional<RendererType> renderer_type; #if defined(OS_WIN) if (cdm_context_ && cdm_context_->RequiresMediaFoundationRenderer()) - factory_type = RendererFactoryType::kMediaFoundation; + renderer_type = RendererType::kMediaFoundation; #endif // defined(OS_WIN) // TODO(xhwang): During Resume(), the |default_renderer_| might already match - // the |factory_type|, in which case we shouldn't need to create a new one. - if (!default_renderer_ || factory_type) { + // the |renderer_type|, in which case we shouldn't need to create a new one. + if (!default_renderer_ || renderer_type) { // Create the Renderer asynchronously on the main task runner. Use // BindToCurrentLoop to call OnRendererCreated() on the media task runner. auto renderer_created_cb = BindToCurrentLoop( @@ -598,7 +598,7 @@ void PipelineImpl::RendererWrapper::CreateRendererInternal( main_task_runner_->PostTask( FROM_HERE, base::BindOnce(&PipelineImpl::AsyncCreateRenderer, weak_pipeline_, - factory_type, std::move(renderer_created_cb))); + renderer_type, std::move(renderer_created_cb))); return; } @@ -701,7 +701,7 @@ void PipelineImpl::RendererWrapper::OnEnabledAudioTracksChanged( } void PipelineImpl::OnSelectedVideoTrackChanged( - base::Optional<MediaTrack::Id> selected_track_id, + absl::optional<MediaTrack::Id> selected_track_id, base::OnceClosure change_completed_cb) { DCHECK(thread_checker_.CalledOnValidThread()); media_task_runner_->PostTask( @@ -713,7 +713,7 @@ void PipelineImpl::OnSelectedVideoTrackChanged( } void PipelineImpl::RendererWrapper::OnSelectedVideoTrackChanged( - base::Optional<MediaTrack::Id> selected_track_id, + absl::optional<MediaTrack::Id> selected_track_id, base::OnceClosure change_completed_cb) { DCHECK(media_task_runner_->BelongsToCurrentThread()); @@ -856,7 +856,7 @@ void PipelineImpl::RendererWrapper::OnVideoOpacityChange(bool opaque) { } void PipelineImpl::RendererWrapper::OnVideoFrameRateChange( - base::Optional<int> fps) { + absl::optional<int> fps) { DCHECK(media_task_runner_->BelongsToCurrentThread()); main_task_runner_->PostTask( @@ -1229,7 +1229,7 @@ void PipelineImpl::Start(StartType start_type, // play. In this case, not creating a default renderer to reduce memory usage. std::unique_ptr<Renderer> default_renderer; if (start_type != StartType::kSuspendAfterMetadata) - default_renderer = create_renderer_cb_.Run(base::nullopt); + default_renderer = create_renderer_cb_.Run(absl::nullopt); media_task_runner_->PostTask( FROM_HERE, @@ -1317,7 +1317,7 @@ void PipelineImpl::Resume(base::TimeDelta time, last_media_time_ = base::TimeDelta(); // Always create a default renderer for Resume(). - auto default_renderer = create_renderer_cb_.Run(base::nullopt); + auto default_renderer = create_renderer_cb_.Run(absl::nullopt); media_task_runner_->PostTask( FROM_HERE, base::BindOnce(&RendererWrapper::Resume, @@ -1383,7 +1383,7 @@ void PipelineImpl::SetVolume(float volume) { } void PipelineImpl::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { DVLOG(1) << __func__ << "(" << (latency_hint ? base::NumberToString(latency_hint->InMilliseconds()) + "ms" @@ -1507,12 +1507,12 @@ const char* PipelineImpl::GetStateString(State state) { #undef RETURN_STRING void PipelineImpl::AsyncCreateRenderer( - base::Optional<RendererFactoryType> factory_type, + absl::optional<RendererType> renderer_type, RendererCreatedCB renderer_created_cb) { DVLOG(2) << __func__; DCHECK(thread_checker_.CalledOnValidThread()); - std::move(renderer_created_cb).Run(create_renderer_cb_.Run(factory_type)); + std::move(renderer_created_cb).Run(create_renderer_cb_.Run(renderer_type)); } void PipelineImpl::OnError(PipelineStatus error) { @@ -1603,7 +1603,7 @@ void PipelineImpl::OnVideoOpacityChange(bool opaque) { client_->OnVideoOpacityChange(opaque); } -void PipelineImpl::OnVideoFrameRateChange(base::Optional<int> fps) { +void PipelineImpl::OnVideoFrameRateChange(absl::optional<int> fps) { DVLOG(2) << __func__; DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(IsRunning()); diff --git a/chromium/media/base/pipeline_impl.h b/chromium/media/base/pipeline_impl.h index beb88adb2b6..3edada0a981 100644 --- a/chromium/media/base/pipeline_impl.h +++ b/chromium/media/base/pipeline_impl.h @@ -10,12 +10,12 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/threading/thread_checker.h" #include "media/base/media_export.h" #include "media/base/pipeline.h" #include "media/base/renderer.h" #include "media/base/renderer_factory_selector.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class SingleThreadTaskRunner; @@ -25,13 +25,13 @@ namespace media { class MediaLog; -// Callbacks used for Renderer creation. When the FactoryType is nullopt, the +// Callbacks used for Renderer creation. When the RendererType is nullopt, the // current base one will be created. using CreateRendererCB = base::RepeatingCallback<std::unique_ptr<Renderer>( - base::Optional<RendererFactoryType>)>; + absl::optional<RendererType>)>; using RendererCreatedCB = base::OnceCallback<void(std::unique_ptr<Renderer>)>; using AsyncCreateRendererCB = - base::RepeatingCallback<void(base::Optional<RendererFactoryType>, + base::RepeatingCallback<void(absl::optional<RendererType>, RendererCreatedCB)>; // Pipeline runs the media pipeline. Filters are created and called on the @@ -103,7 +103,7 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline { void SetPlaybackRate(double playback_rate) override; float GetVolume() const override; void SetVolume(float volume) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void SetPreservesPitch(bool preserves_pitch) override; void SetAutoplayInitiated(bool autoplay_initiated) override; base::TimeDelta GetMediaTime() const override; @@ -121,7 +121,7 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline { // |selected_track_id| is either empty, which means no video track is // selected, or contains the selected video track id. void OnSelectedVideoTrackChanged( - base::Optional<MediaTrack::Id> selected_track_id, + absl::optional<MediaTrack::Id> selected_track_id, base::OnceClosure change_completed_cb) override; private: @@ -146,7 +146,7 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline { // Create a Renderer asynchronously. Must be called on the main task runner // and the callback will be called on the main task runner as well. - void AsyncCreateRenderer(base::Optional<RendererFactoryType> factory_type, + void AsyncCreateRenderer(absl::optional<RendererType> renderer_type, RendererCreatedCB renderer_created_cb); // Notifications from RendererWrapper. @@ -165,7 +165,7 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline { void OnAudioDecoderChange(const AudioDecoderInfo& info); void OnVideoDecoderChange(const VideoDecoderInfo& info); void OnRemotePlayStateChange(MediaStatus::State state); - void OnVideoFrameRateChange(base::Optional<int> fps); + void OnVideoFrameRateChange(absl::optional<int> fps); // Task completion callbacks from RendererWrapper. void OnSeekDone(bool is_suspended); diff --git a/chromium/media/base/pipeline_impl_unittest.cc b/chromium/media/base/pipeline_impl_unittest.cc index 8ff37cf90bc..69a0bed8c75 100644 --- a/chromium/media/base/pipeline_impl_unittest.cc +++ b/chromium/media/base/pipeline_impl_unittest.cc @@ -295,7 +295,7 @@ class PipelineImplTest : public ::testing::Test { } std::unique_ptr<Renderer> CreateRenderer( - base::Optional<RendererFactoryType> /* factory_type */) { + absl::optional<RendererType> /* renderer_type */) { return std::move(scoped_renderer_); } diff --git a/chromium/media/base/pipeline_status.cc b/chromium/media/base/pipeline_status.cc index ab7dfbee853..32c24f13563 100644 --- a/chromium/media/base/pipeline_status.cc +++ b/chromium/media/base/pipeline_status.cc @@ -8,7 +8,7 @@ namespace media { -base::Optional<PipelineStatus> StatusCodeToPipelineStatus(StatusCode status) { +absl::optional<PipelineStatus> StatusCodeToPipelineStatus(StatusCode status) { switch (status) { case StatusCode::kOk: return PIPELINE_OK; @@ -48,7 +48,7 @@ base::Optional<PipelineStatus> StatusCodeToPipelineStatus(StatusCode status) { return DEMUXER_ERROR_DETECTED_HLS; default: NOTREACHED(); - return base::nullopt; + return absl::nullopt; } } diff --git a/chromium/media/base/pipeline_status.h b/chromium/media/base/pipeline_status.h index a9e448040de..cab7506d68d 100644 --- a/chromium/media/base/pipeline_status.h +++ b/chromium/media/base/pipeline_status.h @@ -10,12 +10,12 @@ #include <string> #include "base/callback.h" -#include "base/optional.h" #include "base/time/time.h" #include "media/base/decoder.h" #include "media/base/media_export.h" #include "media/base/status.h" #include "media/base/timestamp_constants.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -62,7 +62,7 @@ enum PipelineStatus { PIPELINE_STATUS_MAX = DEMUXER_ERROR_DETECTED_HLS, }; -MEDIA_EXPORT base::Optional<PipelineStatus> StatusCodeToPipelineStatus( +MEDIA_EXPORT absl::optional<PipelineStatus> StatusCodeToPipelineStatus( StatusCode status); MEDIA_EXPORT StatusCode PipelineStatusToStatusCode(PipelineStatus status); diff --git a/chromium/media/base/renderer.h b/chromium/media/base/renderer.h index 9244948c287..09d775f0c99 100644 --- a/chromium/media/base/renderer.h +++ b/chromium/media/base/renderer.h @@ -8,12 +8,12 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "base/time/time.h" #include "media/base/buffering_state.h" #include "media/base/demuxer_stream.h" #include "media/base/media_export.h" #include "media/base/pipeline_status.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -49,7 +49,7 @@ class MEDIA_EXPORT Renderer { // of decoded data is buffered. A nullopt hint indicates the user is clearing // their preference and the renderer should restore its default buffering // thresholds. - virtual void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) = 0; + virtual void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) = 0; // Sets whether pitch adjustment should be applied when the playback rate is // different than 1.0. diff --git a/chromium/media/base/renderer_client.h b/chromium/media/base/renderer_client.h index f11f2132430..cb4c7131101 100644 --- a/chromium/media/base/renderer_client.h +++ b/chromium/media/base/renderer_client.h @@ -5,7 +5,6 @@ #ifndef MEDIA_BASE_RENDERER_CLIENT_H_ #define MEDIA_BASE_RENDERER_CLIENT_H_ -#include "base/time/time.h" #include "media/base/audio_decoder_config.h" #include "media/base/buffering_state.h" #include "media/base/media_status.h" @@ -58,7 +57,7 @@ class MEDIA_EXPORT RendererClient { // Called when the bucketed frames per second has changed. |fps| will be // unset if the frame rate is unstable. The duration used for the frame rate // is based on the wall clock time, not the media time. - virtual void OnVideoFrameRateChange(base::Optional<int> fps) = 0; + virtual void OnVideoFrameRateChange(absl::optional<int> fps) = 0; }; } // namespace media diff --git a/chromium/media/base/renderer_factory_selector.cc b/chromium/media/base/renderer_factory_selector.cc index 0e912d86a9b..c3d8fa5d371 100644 --- a/chromium/media/base/renderer_factory_selector.cc +++ b/chromium/media/base/renderer_factory_selector.cc @@ -13,30 +13,30 @@ RendererFactorySelector::RendererFactorySelector() = default; RendererFactorySelector::~RendererFactorySelector() = default; void RendererFactorySelector::AddBaseFactory( - RendererFactoryType type, + RendererType type, std::unique_ptr<RendererFactory> factory) { DVLOG(1) << __func__ << ": type=" << static_cast<int>(type); - DCHECK(!base_factory_type_) << "At most one base factory!"; + DCHECK(!base_renderer_type_) << "At most one base factory!"; AddFactory(type, std::move(factory)); - SetBaseFactoryType(type); + SetBaseRendererType(type); } void RendererFactorySelector::AddConditionalFactory( - RendererFactoryType type, + RendererType type, std::unique_ptr<RendererFactory> factory, ConditionalFactoryCB callback) { DCHECK(factory); DCHECK(callback); - DCHECK(!conditional_factory_types_.count(type)) + DCHECK(!conditional_factories_.count(type)) << "At most one conditional factory for a given type!"; - conditional_factory_types_.emplace(type, callback); + conditional_factories_.emplace(type, callback); AddFactory(type, std::move(factory)); } void RendererFactorySelector::AddFactory( - RendererFactoryType type, + RendererType type, std::unique_ptr<RendererFactory> factory) { DCHECK(factory); DCHECK(!factories_.count(type)); @@ -44,26 +44,26 @@ void RendererFactorySelector::AddFactory( factories_[type] = std::move(factory); } -void RendererFactorySelector::SetBaseFactoryType(RendererFactoryType type) { +void RendererFactorySelector::SetBaseRendererType(RendererType type) { DCHECK(factories_.count(type)); - base_factory_type_ = type; + base_renderer_type_ = type; } -RendererFactoryType RendererFactorySelector::GetCurrentFactoryType() { - for (const auto& entry : conditional_factory_types_) { +RendererType RendererFactorySelector::GetCurrentRendererType() { + for (const auto& entry : conditional_factories_) { if (entry.second.Run()) return entry.first; } - return base_factory_type_.value(); + return base_renderer_type_.value(); } RendererFactory* RendererFactorySelector::GetCurrentFactory() { - RendererFactoryType current_factory_type = GetCurrentFactoryType(); + RendererType current_renderer_type = GetCurrentRendererType(); DVLOG(1) << __func__ << " Selecting factory type: " - << static_cast<int>(current_factory_type); - auto* current_factory = factories_[current_factory_type].get(); + << static_cast<int>(current_renderer_type); + auto* current_factory = factories_[current_renderer_type].get(); DCHECK(current_factory); return current_factory; diff --git a/chromium/media/base/renderer_factory_selector.h b/chromium/media/base/renderer_factory_selector.h index c291fb35d20..a9599314b85 100644 --- a/chromium/media/base/renderer_factory_selector.h +++ b/chromium/media/base/renderer_factory_selector.h @@ -8,10 +8,10 @@ #include <map> #include "base/callback.h" -#include "base/optional.h" #include "build/build_config.h" #include "media/base/media_status.h" #include "media/base/renderer_factory.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -30,14 +30,14 @@ namespace media { // // Notes: // - One and at most one base factory must be set. -// - The base factory can be changed by calling SetBaseFactoryType(). +// - The base factory can be changed by calling SetBaseRendererType(). // - Multiple conditional factories are supported but there should be at most // one conditional factory for any factory type. If multiple conditions are // met, it's up to the implementation detail which factory will be returned. // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. -enum class RendererFactoryType { +enum class RendererType { kDefault = 0, // DefaultRendererFactory kMojo = 1, // MojoRendererFactory kMediaPlayer = 2, // MediaPlayerRendererClientFactory @@ -46,7 +46,7 @@ enum class RendererFactoryType { kCast = 5, // CastRendererClientFactory kMediaFoundation = 6, // MediaFoundationRendererClientFactory kFuchsia = 7, // FuchsiaRendererFactory - kRemoting = 8, // RemotingRendererFactory + kRemoting = 8, // RemotingRendererFactory for remoting::Receiver kMaxValue = kRemoting, }; @@ -58,27 +58,26 @@ class MEDIA_EXPORT RendererFactorySelector { ~RendererFactorySelector(); // See file level comments above. - void AddBaseFactory(RendererFactoryType type, + void AddBaseFactory(RendererType type, std::unique_ptr<RendererFactory> factory); - void AddConditionalFactory(RendererFactoryType type, + void AddConditionalFactory(RendererType type, std::unique_ptr<RendererFactory> factory, ConditionalFactoryCB callback); - void AddFactory(RendererFactoryType type, - std::unique_ptr<RendererFactory> factory); + void AddFactory(RendererType type, std::unique_ptr<RendererFactory> factory); // Sets the base factory to be returned, when there are no signals telling us // to select any specific factory. - // NOTE: |type| can be different than FactoryType::kDefault. kDefault is used + // NOTE: |type| can be different than RendererType::kDefault. kDefault is used // to identify the DefaultRendererFactory, not to indicate that a factory // should be used by default. - void SetBaseFactoryType(RendererFactoryType type); + void SetBaseRendererType(RendererType type); - // Returns the type of the factory that GetCurrentFactory() would return. - // NOTE: SetBaseFactoryType() must be called before calling this method. - RendererFactoryType GetCurrentFactoryType(); + // Returns the type of the Renderer for what GetCurrentFactory() would return. + // NOTE: SetBaseRendererType() must be called before calling this method. + RendererType GetCurrentRendererType(); // Updates |current_factory_| if necessary, and returns its value. - // NOTE: SetBaseFactoryType() must be called before calling this method. + // NOTE: SetBaseRendererType() must be called before calling this method. RendererFactory* GetCurrentFactory(); #if defined(OS_ANDROID) @@ -94,19 +93,18 @@ class MEDIA_EXPORT RendererFactorySelector { #endif private: - base::Optional<RendererFactoryType> base_factory_type_; + absl::optional<RendererType> base_renderer_type_; - // Use a map to avoid duplicate entires for the same FactoryType. - std::map<RendererFactoryType, ConditionalFactoryCB> - conditional_factory_types_; + // Use a map to avoid duplicate entries for the same RendererType. + std::map<RendererType, ConditionalFactoryCB> conditional_factories_; RequestRemotePlayStateChangeCB remote_play_state_change_cb_request_; - std::map<RendererFactoryType, std::unique_ptr<RendererFactory>> factories_; + std::map<RendererType, std::unique_ptr<RendererFactory>> factories_; DISALLOW_COPY_AND_ASSIGN(RendererFactorySelector); }; } // namespace media -#endif // MEDIA_BASE_RENDERER_FACTORY_H_ +#endif // MEDIA_BASE_RENDERER_FACTORY_SELECTOR_H_ diff --git a/chromium/media/base/renderer_factory_selector_unittest.cc b/chromium/media/base/renderer_factory_selector_unittest.cc index c4900ab51e8..468d49cf685 100644 --- a/chromium/media/base/renderer_factory_selector_unittest.cc +++ b/chromium/media/base/renderer_factory_selector_unittest.cc @@ -14,11 +14,9 @@ namespace media { class RendererFactorySelectorTest : public testing::Test { public: - using FactoryType = RendererFactoryType; - class FakeFactory : public RendererFactory { public: - explicit FakeFactory(FactoryType type) : type_(type) {} + explicit FakeFactory(RendererType type) : type_(type) {} std::unique_ptr<Renderer> CreateRenderer( const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, @@ -30,23 +28,23 @@ class RendererFactorySelectorTest : public testing::Test { return nullptr; } - FactoryType factory_type() { return type_; } + RendererType factory_type() { return type_; } private: - FactoryType type_; + RendererType type_; }; RendererFactorySelectorTest() = default; - void AddBaseFactory(FactoryType type) { + void AddBaseFactory(RendererType type) { selector_.AddBaseFactory(type, std::make_unique<FakeFactory>(type)); } - void AddFactory(FactoryType type) { + void AddFactory(RendererType type) { selector_.AddFactory(type, std::make_unique<FakeFactory>(type)); } - void AddConditionalFactory(FactoryType type) { + void AddConditionalFactory(RendererType type) { condition_met_map_[type] = false; selector_.AddConditionalFactory( type, std::make_unique<FakeFactory>(type), @@ -54,75 +52,75 @@ class RendererFactorySelectorTest : public testing::Test { base::Unretained(this), type)); } - FactoryType GetCurrentlySelectedFactoryType() { + RendererType GetCurrentlySelectedRendererType() { return reinterpret_cast<FakeFactory*>(selector_.GetCurrentFactory()) ->factory_type(); } - bool IsConditionMet(FactoryType type) { + bool IsConditionMet(RendererType type) { DCHECK(condition_met_map_.count(type)); return condition_met_map_[type]; } protected: RendererFactorySelector selector_; - std::map<FactoryType, bool> condition_met_map_; + std::map<RendererType, bool> condition_met_map_; DISALLOW_COPY_AND_ASSIGN(RendererFactorySelectorTest); }; TEST_F(RendererFactorySelectorTest, SingleFactory) { - AddBaseFactory(FactoryType::kDefault); - EXPECT_EQ(FactoryType::kDefault, GetCurrentlySelectedFactoryType()); + AddBaseFactory(RendererType::kDefault); + EXPECT_EQ(RendererType::kDefault, GetCurrentlySelectedRendererType()); } TEST_F(RendererFactorySelectorTest, MultipleFactory) { - AddBaseFactory(FactoryType::kDefault); - AddFactory(FactoryType::kMojo); + AddBaseFactory(RendererType::kDefault); + AddFactory(RendererType::kMojo); - EXPECT_EQ(FactoryType::kDefault, GetCurrentlySelectedFactoryType()); + EXPECT_EQ(RendererType::kDefault, GetCurrentlySelectedRendererType()); - selector_.SetBaseFactoryType(FactoryType::kMojo); - EXPECT_EQ(FactoryType::kMojo, GetCurrentlySelectedFactoryType()); + selector_.SetBaseRendererType(RendererType::kMojo); + EXPECT_EQ(RendererType::kMojo, GetCurrentlySelectedRendererType()); } TEST_F(RendererFactorySelectorTest, ConditionalFactory) { - AddBaseFactory(FactoryType::kDefault); - AddFactory(FactoryType::kMojo); - AddConditionalFactory(FactoryType::kCourier); + AddBaseFactory(RendererType::kDefault); + AddFactory(RendererType::kMojo); + AddConditionalFactory(RendererType::kCourier); - EXPECT_EQ(FactoryType::kDefault, GetCurrentlySelectedFactoryType()); + EXPECT_EQ(RendererType::kDefault, GetCurrentlySelectedRendererType()); - condition_met_map_[FactoryType::kCourier] = true; - EXPECT_EQ(FactoryType::kCourier, GetCurrentlySelectedFactoryType()); + condition_met_map_[RendererType::kCourier] = true; + EXPECT_EQ(RendererType::kCourier, GetCurrentlySelectedRendererType()); - selector_.SetBaseFactoryType(FactoryType::kMojo); - EXPECT_EQ(FactoryType::kCourier, GetCurrentlySelectedFactoryType()); + selector_.SetBaseRendererType(RendererType::kMojo); + EXPECT_EQ(RendererType::kCourier, GetCurrentlySelectedRendererType()); - condition_met_map_[FactoryType::kCourier] = false; - EXPECT_EQ(FactoryType::kMojo, GetCurrentlySelectedFactoryType()); + condition_met_map_[RendererType::kCourier] = false; + EXPECT_EQ(RendererType::kMojo, GetCurrentlySelectedRendererType()); } TEST_F(RendererFactorySelectorTest, MultipleConditionalFactories) { - AddBaseFactory(FactoryType::kDefault); - AddConditionalFactory(FactoryType::kFlinging); - AddConditionalFactory(FactoryType::kCourier); + AddBaseFactory(RendererType::kDefault); + AddConditionalFactory(RendererType::kFlinging); + AddConditionalFactory(RendererType::kCourier); - EXPECT_EQ(FactoryType::kDefault, GetCurrentlySelectedFactoryType()); + EXPECT_EQ(RendererType::kDefault, GetCurrentlySelectedRendererType()); - condition_met_map_[FactoryType::kFlinging] = false; - condition_met_map_[FactoryType::kCourier] = true; - EXPECT_EQ(FactoryType::kCourier, GetCurrentlySelectedFactoryType()); + condition_met_map_[RendererType::kFlinging] = false; + condition_met_map_[RendererType::kCourier] = true; + EXPECT_EQ(RendererType::kCourier, GetCurrentlySelectedRendererType()); - condition_met_map_[FactoryType::kFlinging] = true; - condition_met_map_[FactoryType::kCourier] = false; - EXPECT_EQ(FactoryType::kFlinging, GetCurrentlySelectedFactoryType()); + condition_met_map_[RendererType::kFlinging] = true; + condition_met_map_[RendererType::kCourier] = false; + EXPECT_EQ(RendererType::kFlinging, GetCurrentlySelectedRendererType()); // It's up to the implementation detail to decide which one to use. - condition_met_map_[FactoryType::kFlinging] = true; - condition_met_map_[FactoryType::kCourier] = true; - EXPECT_TRUE(GetCurrentlySelectedFactoryType() == FactoryType::kFlinging || - GetCurrentlySelectedFactoryType() == FactoryType::kCourier); + condition_met_map_[RendererType::kFlinging] = true; + condition_met_map_[RendererType::kCourier] = true; + EXPECT_TRUE(GetCurrentlySelectedRendererType() == RendererType::kFlinging || + GetCurrentlySelectedRendererType() == RendererType::kCourier); } } // namespace media diff --git a/chromium/media/base/routing_token_callback.h b/chromium/media/base/routing_token_callback.h index 9663c17f3f0..cecff0f6219 100644 --- a/chromium/media/base/routing_token_callback.h +++ b/chromium/media/base/routing_token_callback.h @@ -22,4 +22,4 @@ using RequestRoutingTokenCallback = } // namespace media -#endif // MEDIA_BASE_ANDROID_ROUTING_TOKEN_CALLBACK_H_ +#endif // MEDIA_BASE_ROUTING_TOKEN_CALLBACK_H_ diff --git a/chromium/media/base/sample_rates.h b/chromium/media/base/sample_rates.h index edba90ed2a6..80aa2ff5ca9 100644 --- a/chromium/media/base/sample_rates.h +++ b/chromium/media/base/sample_rates.h @@ -27,7 +27,7 @@ enum AudioSampleRate { k384000Hz = 12, k768000Hz = 13, // Must always equal the largest value ever reported: - kAudioSampleRateMax = k384000Hz, + kAudioSampleRateMax = k768000Hz, }; // Helper method to convert integral values to their respective enum values, diff --git a/chromium/media/base/sinc_resampler.cc b/chromium/media/base/sinc_resampler.cc index 06c85f9349b..118667ff83d 100644 --- a/chromium/media/base/sinc_resampler.cc +++ b/chromium/media/base/sinc_resampler.cc @@ -78,6 +78,7 @@ #include <limits> #include "base/check_op.h" +#include "base/cpu.h" #include "base/numerics/math_constants.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" diff --git a/chromium/media/base/sinc_resampler_perftest.cc b/chromium/media/base/sinc_resampler_perftest.cc index 9570e792bd7..4ac8c8a2941 100644 --- a/chromium/media/base/sinc_resampler_perftest.cc +++ b/chromium/media/base/sinc_resampler_perftest.cc @@ -4,6 +4,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/cpu.h" #include "base/time/time.h" #include "build/build_config.h" #include "media/base/sinc_resampler.h" diff --git a/chromium/media/base/status.cc b/chromium/media/base/status.cc index 1e30c223c4b..8bfa2f999b2 100644 --- a/chromium/media/base/status.cc +++ b/chromium/media/base/status.cc @@ -5,6 +5,7 @@ #include "media/base/status.h" #include <memory> +#include "base/strings/string_piece.h" #include "media/base/media_serializers.h" namespace media { @@ -19,7 +20,7 @@ Status::Status(StatusCode code, DCHECK(message.empty()); return; } - data_ = std::make_unique<StatusInternal>(code, message.as_string()); + data_ = std::make_unique<StatusInternal>(code, std::string(message)); AddFrame(location); } diff --git a/chromium/media/base/status.h b/chromium/media/base/status.h index 8a7b4e0b9c7..d8e74805bb9 100644 --- a/chromium/media/base/status.h +++ b/chromium/media/base/status.h @@ -257,10 +257,10 @@ class StatusOr { private: // Optional error. - base::Optional<Status> error_; + absl::optional<Status> error_; // We wrap |T| in a container so that windows COM wrappers work. They - // override operator& and similar, and won't compile in a base::Optional. - base::Optional<std::tuple<T>> value_; + // override operator& and similar, and won't compile in a absl::optional. + absl::optional<std::tuple<T>> value_; }; } // namespace media diff --git a/chromium/media/base/status_codes.h b/chromium/media/base/status_codes.h index 45eee6460fa..70078b05dcb 100644 --- a/chromium/media/base/status_codes.h +++ b/chromium/media/base/status_codes.h @@ -94,6 +94,7 @@ enum class StatusCode : StatusCodeType { kGetQuantBufferFailed = 0x00000328, kReleaseQuantBufferFailed = 0x00000329, kBitstreamBufferSliceTooBig = 0x00000330, + kCreateSharedImageFailed = 0x00000331, // MojoDecoder Errors: 0x04 kMojoDecoderNoWrappedDecoder = 0x00000401, diff --git a/chromium/media/base/tuneable.h b/chromium/media/base/tuneable.h index e1efc37458d..913fd3533c2 100644 --- a/chromium/media/base/tuneable.h +++ b/chromium/media/base/tuneable.h @@ -6,7 +6,6 @@ #define MEDIA_BASE_TUNEABLE_H_ #include "base/macros.h" -#include "base/time/time.h" #include "base/unguessable_token.h" #include "media/base/media_export.h" diff --git a/chromium/media/base/user_input_monitor_win.cc b/chromium/media/base/user_input_monitor_win.cc index 6082070ace0..327b28bb711 100644 --- a/chromium/media/base/user_input_monitor_win.cc +++ b/chromium/media/base/user_input_monitor_win.cc @@ -13,7 +13,6 @@ #include "base/logging.h" #include "base/macros.h" #include "base/single_thread_task_runner.h" -#include "base/strings/stringprintf.h" #include "base/synchronization/lock.h" #include "base/task/current_thread.h" #include "base/win/message_window.h" diff --git a/chromium/media/base/video_color_space.h b/chromium/media/base/video_color_space.h index ee639452198..72a7d73fcb5 100644 --- a/chromium/media/base/video_color_space.h +++ b/chromium/media/base/video_color_space.h @@ -107,4 +107,4 @@ class MEDIA_EXPORT VideoColorSpace { } // namespace media -#endif +#endif // MEDIA_BASE_VIDEO_COLOR_SPACE_H_ diff --git a/chromium/media/base/video_decoder.h b/chromium/media/base/video_decoder.h index 8c6cb290dc2..77772ab6b82 100644 --- a/chromium/media/base/video_decoder.h +++ b/chromium/media/base/video_decoder.h @@ -5,9 +5,6 @@ #ifndef MEDIA_BASE_VIDEO_DECODER_H_ #define MEDIA_BASE_VIDEO_DECODER_H_ -#include <string> - -#include "base/macros.h" #include "base/memory/ref_counted.h" #include "media/base/decode_status.h" #include "media/base/decoder.h" @@ -41,6 +38,8 @@ class MEDIA_EXPORT VideoDecoder : public Decoder { using DecodeCB = base::OnceCallback<void(Status)>; VideoDecoder(); + VideoDecoder(const VideoDecoder&) = delete; + VideoDecoder& operator=(const VideoDecoder&) = delete; ~VideoDecoder() override; // Initializes a VideoDecoder with the given |config|, executing the @@ -131,9 +130,6 @@ class MEDIA_EXPORT VideoDecoder : public Decoder { // this should return the underlying type, if it is known, otherwise return // its own type. virtual VideoDecoderType GetDecoderType() const = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(VideoDecoder); }; } // namespace media diff --git a/chromium/media/base/video_decoder_config.h b/chromium/media/base/video_decoder_config.h index 144f7d61a15..af04252500c 100644 --- a/chromium/media/base/video_decoder_config.h +++ b/chromium/media/base/video_decoder_config.h @@ -11,13 +11,13 @@ #include <vector> #include "base/macros.h" -#include "base/optional.h" #include "media/base/encryption_scheme.h" #include "media/base/media_export.h" #include "media/base/video_codecs.h" #include "media/base/video_color_space.h" #include "media/base/video_transformation.h" #include "media/base/video_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/hdr_metadata.h" @@ -155,7 +155,7 @@ class MEDIA_EXPORT VideoDecoderConfig { void set_hdr_metadata(const gfx::HDRMetadata& hdr_metadata) { hdr_metadata_ = hdr_metadata; } - const base::Optional<gfx::HDRMetadata>& hdr_metadata() const { + const absl::optional<gfx::HDRMetadata>& hdr_metadata() const { return hdr_metadata_; } @@ -194,7 +194,7 @@ class MEDIA_EXPORT VideoDecoderConfig { EncryptionScheme encryption_scheme_ = EncryptionScheme::kUnencrypted; VideoColorSpace color_space_info_; - base::Optional<gfx::HDRMetadata> hdr_metadata_; + absl::optional<gfx::HDRMetadata> hdr_metadata_; bool is_rtc_ = false; // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler diff --git a/chromium/media/base/video_encoder.h b/chromium/media/base/video_encoder.h index 4a5eb6bda79..2d80329c4f4 100644 --- a/chromium/media/base/video_encoder.h +++ b/chromium/media/base/video_encoder.h @@ -6,11 +6,10 @@ #define MEDIA_BASE_VIDEO_ENCODER_H_ #include "base/callback.h" -#include "base/macros.h" -#include "base/optional.h" #include "media/base/media_export.h" #include "media/base/status.h" #include "media/base/video_codecs.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { @@ -44,12 +43,12 @@ class MEDIA_EXPORT VideoEncoder { Options(); Options(const Options&); ~Options(); - base::Optional<uint64_t> bitrate; - base::Optional<double> framerate; + absl::optional<uint64_t> bitrate; + absl::optional<double> framerate; gfx::Size frame_size; - base::Optional<int> keyframe_interval = 10000; + absl::optional<int> keyframe_interval = 10000; // Requested number of SVC temporal layers. int temporal_layers = 1; @@ -67,12 +66,14 @@ class MEDIA_EXPORT VideoEncoder { // becomes available. using OutputCB = base::RepeatingCallback<void(VideoEncoderOutput output, - base::Optional<CodecDescription>)>; + absl::optional<CodecDescription>)>; // Callback to report success and errors in encoder calls. using StatusCB = base::OnceCallback<void(Status error)>; VideoEncoder(); + VideoEncoder(const VideoEncoder&) = delete; + VideoEncoder& operator=(const VideoEncoder&) = delete; virtual ~VideoEncoder(); // Initializes a VideoEncoder with the given |options|, executing the @@ -117,9 +118,6 @@ class MEDIA_EXPORT VideoEncoder { // Requests all outputs for already encoded frames to be // produced via |output_cb| and calls |dene_cb| after that. virtual void Flush(StatusCB done_cb) = 0; - - protected: - DISALLOW_COPY_AND_ASSIGN(VideoEncoder); }; } // namespace media diff --git a/chromium/media/base/video_frame.cc b/chromium/media/base/video_frame.cc index 452b1782164..d895ebf38a4 100644 --- a/chromium/media/base/video_frame.cc +++ b/chromium/media/base/video_frame.cc @@ -14,7 +14,7 @@ #include "base/bits.h" #include "base/callback_helpers.h" #include "base/logging.h" -#include "base/memory/aligned_memory.h" +#include "base/process/memory.h" #include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" @@ -210,7 +210,7 @@ static bool RequiresEvenSizeAllocation(VideoPixelFormat format) { } // Creates VideoFrameLayout for tightly packed frame. -static base::Optional<VideoFrameLayout> GetDefaultLayout( +static absl::optional<VideoFrameLayout> GetDefaultLayout( VideoPixelFormat format, const gfx::Size& coded_size) { std::vector<ColorPlaneLayout> planes; @@ -259,7 +259,7 @@ static base::Optional<VideoFrameLayout> GetDefaultLayout( // http://crbug.com/555909 . DLOG(ERROR) << "Unsupported pixel format" << VideoPixelFormatToString(format); - return base::nullopt; + return absl::nullopt; } return VideoFrameLayout::CreateWithPlanes(format, coded_size, planes); @@ -291,33 +291,8 @@ bool VideoFrame::IsValidConfig(VideoPixelFormat format, const gfx::Size& coded_size, const gfx::Rect& visible_rect, const gfx::Size& natural_size) { - // Check maximum limits for all formats. - int coded_size_area = coded_size.GetCheckedArea().ValueOrDefault(INT_MAX); - int natural_size_area = natural_size.GetCheckedArea().ValueOrDefault(INT_MAX); - static_assert(limits::kMaxCanvas < INT_MAX, ""); - if (coded_size_area > limits::kMaxCanvas || - coded_size.width() > limits::kMaxDimension || - coded_size.height() > limits::kMaxDimension || visible_rect.x() < 0 || - visible_rect.y() < 0 || visible_rect.right() > coded_size.width() || - visible_rect.bottom() > coded_size.height() || - natural_size_area > limits::kMaxCanvas || - natural_size.width() > limits::kMaxDimension || - natural_size.height() > limits::kMaxDimension) { - return false; - } - - // Make sure new formats are properly accounted for in the method. - static_assert(PIXEL_FORMAT_MAX == 33, - "Added pixel format, please review IsValidConfig()"); - - if (format == PIXEL_FORMAT_UNKNOWN) { - return coded_size.IsEmpty() && visible_rect.IsEmpty() && - natural_size.IsEmpty(); - } - - // Check that software-allocated buffer formats are not empty. - return !coded_size.IsEmpty() && !visible_rect.IsEmpty() && - !natural_size.IsEmpty(); + return IsValidConfigInternal(format, FrameControlType::kNone, coded_size, + visible_rect, natural_size); } // static @@ -336,9 +311,9 @@ scoped_refptr<VideoFrame> VideoFrame::CreateVideoHoleFrame( const gfx::Size& natural_size, base::TimeDelta timestamp) { auto layout = VideoFrameLayout::Create(PIXEL_FORMAT_UNKNOWN, natural_size); - scoped_refptr<VideoFrame> frame = - new VideoFrame(*layout, StorageType::STORAGE_OPAQUE, - gfx::Rect(natural_size), natural_size, timestamp); + scoped_refptr<VideoFrame> frame = new VideoFrame( + *layout, StorageType::STORAGE_OPAQUE, gfx::Rect(natural_size), + natural_size, timestamp, FrameControlType::kVideoHole); frame->metadata().overlay_plane_id = overlay_plane_id; return frame; } @@ -603,7 +578,7 @@ scoped_refptr<VideoFrame> VideoFrame::WrapExternalGpuMemoryBuffer( const gpu::MailboxHolder (&mailbox_holders)[kMaxPlanes], ReleaseMailboxCB mailbox_holder_release_cb, base::TimeDelta timestamp) { - const base::Optional<VideoPixelFormat> format = + const absl::optional<VideoPixelFormat> format = GfxBufferFormatToVideoPixelFormat(gpu_memory_buffer->GetFormat()); if (!format) return nullptr; @@ -740,7 +715,7 @@ scoped_refptr<VideoFrame> VideoFrame::WrapUnacceleratedIOSurface( std::vector<int32_t> strides; for (size_t i = 0; i < num_planes; ++i) strides.push_back(IOSurfaceGetBytesPerRowOfPlane(io_surface, i)); - base::Optional<VideoFrameLayout> layout = + absl::optional<VideoFrameLayout> layout = media::VideoFrameLayout::CreateWithStrides(pixel_format, size, strides); if (!layout) { DLOG(ERROR) << "Invalid layout."; @@ -857,7 +832,7 @@ scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame( } size_t new_plane_count = NumPlanes(format); - base::Optional<VideoFrameLayout> new_layout; + absl::optional<VideoFrameLayout> new_layout; if (format == frame->format()) { new_layout = frame->layout(); } else { @@ -913,8 +888,9 @@ scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() { DLOG(ERROR) << "Invalid layout."; return nullptr; } - scoped_refptr<VideoFrame> frame = new VideoFrame( - *layout, STORAGE_UNKNOWN, gfx::Rect(), gfx::Size(), kNoTimestamp); + scoped_refptr<VideoFrame> frame = + new VideoFrame(*layout, STORAGE_UNKNOWN, gfx::Rect(), gfx::Size(), + kNoTimestamp, FrameControlType::kEos); frame->metadata().end_of_stream = true; return frame; } @@ -1322,7 +1298,8 @@ VideoFrame::VideoFrame(const VideoFrameLayout& layout, StorageType storage_type, const gfx::Rect& visible_rect, const gfx::Size& natural_size, - base::TimeDelta timestamp) + base::TimeDelta timestamp, + FrameControlType frame_control_type) : layout_(layout), storage_type_(storage_type), visible_rect_(Intersection(visible_rect, gfx::Rect(layout.coded_size()))), @@ -1332,8 +1309,8 @@ VideoFrame::VideoFrame(const VideoFrameLayout& layout, #endif timestamp_(timestamp), unique_id_(g_unique_id_generator.GetNext()) { - DCHECK(IsValidConfig(format(), storage_type, coded_size(), visible_rect_, - natural_size_)); + DCHECK(IsValidConfigInternal(format(), frame_control_type, coded_size(), + visible_rect_, natural_size_)); DCHECK(visible_rect_ == visible_rect) << "visible_rect " << visible_rect.ToString() << " exceeds coded_size " << coded_size().ToString(); @@ -1383,6 +1360,46 @@ gfx::Size VideoFrame::DetermineAlignedSize(VideoPixelFormat format, } // static +bool VideoFrame::IsValidConfigInternal(VideoPixelFormat format, + FrameControlType frame_control_type, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size) { + // Check maximum limits for all formats. + int coded_size_area = coded_size.GetCheckedArea().ValueOrDefault(INT_MAX); + int natural_size_area = natural_size.GetCheckedArea().ValueOrDefault(INT_MAX); + static_assert(limits::kMaxCanvas < INT_MAX, ""); + if (coded_size_area > limits::kMaxCanvas || + coded_size.width() > limits::kMaxDimension || + coded_size.height() > limits::kMaxDimension || visible_rect.x() < 0 || + visible_rect.y() < 0 || visible_rect.right() > coded_size.width() || + visible_rect.bottom() > coded_size.height() || + natural_size_area > limits::kMaxCanvas || + natural_size.width() > limits::kMaxDimension || + natural_size.height() > limits::kMaxDimension) { + return false; + } + + // Make sure new formats are properly accounted for in the method. + static_assert(PIXEL_FORMAT_MAX == 33, + "Added pixel format, please review AreSizesValid()"); + switch (frame_control_type) { + case FrameControlType::kNone: + // Check that software-allocated buffer formats are not empty. + return !coded_size.IsEmpty() && !visible_rect.IsEmpty() && + !natural_size.IsEmpty(); + case FrameControlType::kEos: + DCHECK_EQ(format, PIXEL_FORMAT_UNKNOWN); + return coded_size.IsEmpty() && visible_rect.IsEmpty() && + natural_size.IsEmpty(); + case FrameControlType::kVideoHole: + DCHECK_EQ(format, PIXEL_FORMAT_UNKNOWN); + return !coded_size.IsEmpty() && !visible_rect.IsEmpty() && + !natural_size.IsEmpty(); + } +} + +// static scoped_refptr<VideoFrame> VideoFrame::CreateFrameInternal( VideoPixelFormat format, const gfx::Size& coded_size, @@ -1390,9 +1407,10 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrameInternal( const gfx::Size& natural_size, base::TimeDelta timestamp, bool zero_initialize_memory) { - // Since we're creating a new frame (and allocating memory for it ourselves), - // we can pad the requested |coded_size| if necessary if the request does not - // line up on sample boundaries. See discussion at http://crrev.com/1240833003 + // Since we're creating a new frame (and allocating memory for it + // ourselves), we can pad the requested |coded_size| if necessary if the + // request does not line up on sample boundaries. See discussion at + // http://crrev.com/1240833003 const gfx::Size new_coded_size = DetermineAlignedSize(format, coded_size); auto layout = VideoFrameLayout::CreateWithStrides( format, new_coded_size, ComputeStrides(format, new_coded_size)); @@ -1422,8 +1440,7 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrameWithLayout( scoped_refptr<VideoFrame> frame(new VideoFrame( std::move(layout), storage, visible_rect, natural_size, timestamp)); - frame->AllocateMemory(zero_initialize_memory); - return frame; + return frame->AllocateMemory(zero_initialize_memory) ? frame : nullptr; } // static @@ -1438,27 +1455,43 @@ gfx::Size VideoFrame::CommonAlignment(VideoPixelFormat format) { return gfx::Size(max_sample_width, max_sample_height); } -void VideoFrame::AllocateMemory(bool zero_initialize_memory) { +bool VideoFrame::AllocateMemory(bool zero_initialize_memory) { DCHECK_EQ(storage_type_, STORAGE_OWNED_MEMORY); static_assert(0 == kYPlane, "y plane data must be index 0"); std::vector<size_t> plane_size = CalculatePlaneSize(); - const size_t total_buffer_size = + const size_t buffer_size = std::accumulate(plane_size.begin(), plane_size.end(), 0u); + const size_t allocation_size = + buffer_size + (layout_.buffer_addr_align() - 1); - uint8_t* data = reinterpret_cast<uint8_t*>( - base::AlignedAlloc(total_buffer_size, layout_.buffer_addr_align())); + uint8_t* data = nullptr; if (zero_initialize_memory) { - memset(data, 0, total_buffer_size); + if (!base::UncheckedCalloc(1, allocation_size, + reinterpret_cast<void**>(&data)) || + !data) { + return false; + } + } else { + if (!base::UncheckedMalloc(allocation_size, + reinterpret_cast<void**>(&data)) || + !data) { + return false; + } } - AddDestructionObserver(base::BindOnce(&base::AlignedFree, data)); + private_data_.reset(data); + + data = base::bits::Align(data, layout_.buffer_addr_align()); + DCHECK_LE(data + buffer_size, private_data_.get() + allocation_size); - // Note that if layout.buffer_sizes is specified, color planes' layout is the - // same as buffers'. See CalculatePlaneSize() for detail. + // Note that if layout.buffer_sizes is specified, color planes' layout is + // the same as buffers'. See CalculatePlaneSize() for detail. for (size_t plane = 0, offset = 0; plane < NumPlanes(format()); ++plane) { data_[plane] = data + offset; offset += plane_size[plane]; } + + return true; } bool VideoFrame::IsValidSharedMemoryFrame() const { diff --git a/chromium/media/base/video_frame.h b/chromium/media/base/video_frame.h index cf10ff045c1..373d0268b67 100644 --- a/chromium/media/base/video_frame.h +++ b/chromium/media/base/video_frame.h @@ -16,11 +16,9 @@ #include "base/callback.h" #include "base/check_op.h" #include "base/hash/md5.h" -#include "base/macros.h" -#include "base/memory/aligned_memory.h" +#include "base/memory/free_deleter.h" #include "base/memory/ref_counted.h" #include "base/memory/unsafe_shared_memory_region.h" -#include "base/optional.h" #include "base/synchronization/lock.h" #include "base/thread_annotations.h" #include "base/unguessable_token.h" @@ -30,6 +28,7 @@ #include "media/base/video_frame_layout.h" #include "media/base/video_frame_metadata.h" #include "media/base/video_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/color_space.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -104,16 +103,21 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // the GPU Command Buffer and wait for it. class SyncTokenClient { public: - SyncTokenClient() {} + SyncTokenClient() = default; + SyncTokenClient(const SyncTokenClient&) = delete; + SyncTokenClient& operator=(const SyncTokenClient&) = delete; + virtual void GenerateSyncToken(gpu::SyncToken* sync_token) = 0; virtual void WaitSyncToken(const gpu::SyncToken& sync_token) = 0; protected: - virtual ~SyncTokenClient() {} - - DISALLOW_COPY_AND_ASSIGN(SyncTokenClient); + virtual ~SyncTokenClient() = default; }; + VideoFrame() = delete; + VideoFrame(const VideoFrame&) = delete; + VideoFrame& operator=(const VideoFrame&) = delete; + // Returns true if frame configuration is valid. static bool IsValidConfig(VideoPixelFormat format, StorageType storage_type, @@ -448,11 +452,11 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { color_space_ = color_space; } - const base::Optional<gfx::HDRMetadata>& hdr_metadata() const { + const absl::optional<gfx::HDRMetadata>& hdr_metadata() const { return hdr_metadata_; } - void set_hdr_metadata(const base::Optional<gfx::HDRMetadata>& hdr_metadata) { + void set_hdr_metadata(const absl::optional<gfx::HDRMetadata>& hdr_metadata) { hdr_metadata_ = hdr_metadata; } @@ -499,7 +503,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { return data_[plane]; } - const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info() const { + const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info() const { return wrapped_frame_ ? wrapped_frame_->ycbcr_info() : ycbcr_info_; } @@ -597,13 +601,19 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { size_t BitDepth() const; // Provide the sampler conversion information for the frame. - void set_ycbcr_info(const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info) { + void set_ycbcr_info(const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info) { ycbcr_info_ = ycbcr_info; } protected: friend class base::RefCountedThreadSafe<VideoFrame>; + enum class FrameControlType { + kNone, + kEos, + kVideoHole, + }; + // Clients must use the static factory/wrapping methods to create a new frame. // Derived classes should create their own factory/wrapping methods, and use // this constructor to do basic initialization. @@ -611,8 +621,8 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { StorageType storage_type, const gfx::Rect& visible_rect, const gfx::Size& natural_size, - base::TimeDelta timestamp); - + base::TimeDelta timestamp, + FrameControlType frame_control_type = FrameControlType::kNone); virtual ~VideoFrame(); // Creates a summary of the configuration settings provided as parameters. @@ -629,6 +639,15 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { } private: + // The constructor of VideoFrame should use IsValidConfigInternal() + // instead of the public IsValidConfig() to check the config, because we can + // create special video frames that won't pass the check by IsValidConfig(). + static bool IsValidConfigInternal(VideoPixelFormat format, + FrameControlType frame_control_type, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size); + static scoped_refptr<VideoFrame> CreateFrameInternal( VideoPixelFormat format, const gfx::Size& coded_size, @@ -641,7 +660,9 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { // alignment for each individual plane. static gfx::Size CommonAlignment(VideoPixelFormat format); - void AllocateMemory(bool zero_initialize_memory); + // Tries to allocate the requisite amount of memory for this frame. Returns + // false if this would cause an out of memory error. + WARN_UNUSED_RESULT bool AllocateMemory(bool zero_initialize_memory); // Calculates plane size. // It first considers buffer size layout_ object provides. If layout's @@ -729,12 +750,13 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> { const int unique_id_; gfx::ColorSpace color_space_; - base::Optional<gfx::HDRMetadata> hdr_metadata_; + absl::optional<gfx::HDRMetadata> hdr_metadata_; // Sampler conversion information which is used in vulkan context for android. - base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info_; + absl::optional<gpu::VulkanYCbCrInfo> ycbcr_info_; - DISALLOW_IMPLICIT_CONSTRUCTORS(VideoFrame); + // Allocation which makes up |data_| planes for self-allocated frames. + std::unique_ptr<uint8_t, base::FreeDeleter> private_data_; }; } // namespace media diff --git a/chromium/media/base/video_frame_layout.cc b/chromium/media/base/video_frame_layout.cc index dcf0dd23cc5..3eef408656d 100644 --- a/chromium/media/base/video_frame_layout.cc +++ b/chromium/media/base/video_frame_layout.cc @@ -87,7 +87,7 @@ size_t VideoFrameLayout::NumPlanes(VideoPixelFormat format) { } // static -base::Optional<VideoFrameLayout> VideoFrameLayout::Create( +absl::optional<VideoFrameLayout> VideoFrameLayout::Create( VideoPixelFormat format, const gfx::Size& coded_size) { return CreateWithStrides(format, coded_size, @@ -95,7 +95,7 @@ base::Optional<VideoFrameLayout> VideoFrameLayout::Create( } // static -base::Optional<VideoFrameLayout> VideoFrameLayout::CreateWithStrides( +absl::optional<VideoFrameLayout> VideoFrameLayout::CreateWithStrides( VideoPixelFormat format, const gfx::Size& coded_size, std::vector<int32_t> strides, @@ -106,32 +106,32 @@ base::Optional<VideoFrameLayout> VideoFrameLayout::CreateWithStrides( } // static -base::Optional<VideoFrameLayout> VideoFrameLayout::CreateWithPlanes( +absl::optional<VideoFrameLayout> VideoFrameLayout::CreateWithPlanes( VideoPixelFormat format, const gfx::Size& coded_size, std::vector<ColorPlaneLayout> planes, size_t buffer_addr_align, uint64_t modifier) { // NOTE: Even if format is UNKNOWN, it is valid if coded_sizes is not Empty(). - // TODO(crbug.com/896135): Return base::nullopt, + // TODO(crbug.com/896135): Return absl::nullopt, // if (format != PIXEL_FORMAT_UNKNOWN || !coded_sizes.IsEmpty()) - // TODO(crbug.com/896135): Return base::nullopt, + // TODO(crbug.com/896135): Return absl::nullopt, // if (planes.size() != NumPlanes(format)) return VideoFrameLayout(format, coded_size, std::move(planes), false /*is_multi_planar */, buffer_addr_align, modifier); } -base::Optional<VideoFrameLayout> VideoFrameLayout::CreateMultiPlanar( +absl::optional<VideoFrameLayout> VideoFrameLayout::CreateMultiPlanar( VideoPixelFormat format, const gfx::Size& coded_size, std::vector<ColorPlaneLayout> planes, size_t buffer_addr_align, uint64_t modifier) { // NOTE: Even if format is UNKNOWN, it is valid if coded_sizes is not Empty(). - // TODO(crbug.com/896135): Return base::nullopt, + // TODO(crbug.com/896135): Return absl::nullopt, // if (format != PIXEL_FORMAT_UNKNOWN || !coded_sizes.IsEmpty()) - // TODO(crbug.com/896135): Return base::nullopt, + // TODO(crbug.com/896135): Return absl::nullopt, // if (planes.size() != NumPlanes(format)) return VideoFrameLayout(format, coded_size, std::move(planes), true /*is_multi_planar */, buffer_addr_align, diff --git a/chromium/media/base/video_frame_layout.h b/chromium/media/base/video_frame_layout.h index 9d1f7c17437..73b106e0d4a 100644 --- a/chromium/media/base/video_frame_layout.h +++ b/chromium/media/base/video_frame_layout.h @@ -13,10 +13,10 @@ #include <utility> #include <vector> -#include "base/optional.h" #include "media/base/color_plane_layout.h" #include "media/base/media_export.h" #include "media/base/video_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_pixmap_handle.h" @@ -47,19 +47,19 @@ class MEDIA_EXPORT VideoFrameLayout { // |modifier| is the additional information of |format|. It will become some // value else than gfx::NativePixmapHandle::kNoModifier when the underlying // buffer format is different from a standard |format| due to tiling. - // The returned base::Optional will be base::nullopt if the configured values + // The returned absl::optional will be absl::nullopt if the configured values // are invalid. // Create a layout suitable for |format| at |coded_size|. The stride, offsets // and size of all planes are set to 0, since that information cannot reliably // be infered from the arguments. - static base::Optional<VideoFrameLayout> Create(VideoPixelFormat format, + static absl::optional<VideoFrameLayout> Create(VideoPixelFormat format, const gfx::Size& coded_size); // Create a layout suitable for |format| at |coded_size|, with the |strides| // for each plane specified. The offsets and size of all planes are set to 0. // The size of |strides| must be equal to NumPlanes(|format|). - static base::Optional<VideoFrameLayout> CreateWithStrides( + static absl::optional<VideoFrameLayout> CreateWithStrides( VideoPixelFormat format, const gfx::Size& coded_size, std::vector<int32_t> strides, @@ -69,7 +69,7 @@ class MEDIA_EXPORT VideoFrameLayout { // Create a layout suitable for |format| at |coded_size|, with the |planes| // fully provided. // The size of |planes| must be equal to NumPlanes(|format|). - static base::Optional<VideoFrameLayout> CreateWithPlanes( + static absl::optional<VideoFrameLayout> CreateWithPlanes( VideoPixelFormat format, const gfx::Size& coded_size, std::vector<ColorPlaneLayout> planes, @@ -79,7 +79,7 @@ class MEDIA_EXPORT VideoFrameLayout { // This constructor should be called for situations where the frames using // this format are backed by multiple physical buffers, instead of having each // plane at different offsets of the same buffer. Currently only used by V4L2. - static base::Optional<VideoFrameLayout> CreateMultiPlanar( + static absl::optional<VideoFrameLayout> CreateMultiPlanar( VideoPixelFormat format, const gfx::Size& coded_size, std::vector<ColorPlaneLayout> planes, diff --git a/chromium/media/base/video_frame_metadata.h b/chromium/media/base/video_frame_metadata.h index 3456e0703bd..844fde80b4d 100644 --- a/chromium/media/base/video_frame_metadata.h +++ b/chromium/media/base/video_frame_metadata.h @@ -5,9 +5,6 @@ #ifndef MEDIA_BASE_VIDEO_FRAME_METADATA_H_ #define MEDIA_BASE_VIDEO_FRAME_METADATA_H_ -#include <memory> -#include <string> - #include "base/compiler_specific.h" #include "base/macros.h" #include "base/time/time.h" @@ -55,8 +52,8 @@ struct MEDIA_EXPORT VideoFrameMetadata { // Video capture begin/end timestamps. Consumers can use these values for // dynamic optimizations, logging stats, etc. - base::Optional<base::TimeTicks> capture_begin_time; - base::Optional<base::TimeTicks> capture_end_time; + absl::optional<base::TimeTicks> capture_begin_time; + absl::optional<base::TimeTicks> capture_end_time; // A counter that is increased by the producer of video frames each time // it pushes out a new frame. By looking for gaps in this counter, clients @@ -64,7 +61,7 @@ struct MEDIA_EXPORT VideoFrameMetadata { // the producer between two consecutively received frames. Note that the // counter may start at arbitrary values, so the absolute value of it has no // meaning. - base::Optional<int> capture_counter; + absl::optional<int> capture_counter; // The rectangular region of the frame that has changed since the frame // with the directly preceding CAPTURE_COUNTER. If that frame was not @@ -73,11 +70,11 @@ struct MEDIA_EXPORT VideoFrameMetadata { // The rectangle is relative to the full frame data, i.e. [0, 0, // coded_size().width(), coded_size().height()]. It does not have to be // fully contained within visible_rect(). - base::Optional<gfx::Rect> capture_update_rect; + absl::optional<gfx::Rect> capture_update_rect; // If not null, it indicates how video frame mailbox should be copied to a // new mailbox. - base::Optional<CopyMode> copy_mode; + absl::optional<CopyMode> copy_mode; // Indicates if the current frame is the End of its current Stream. bool end_of_stream = false; @@ -88,12 +85,12 @@ struct MEDIA_EXPORT VideoFrameMetadata { // vary unpredictably for every frame. Consumers can use this to optimize // playback scheduling, make encoding quality decisions, and/or compute // frame-level resource utilization stats. - base::Optional<base::TimeDelta> frame_duration; + absl::optional<base::TimeDelta> frame_duration; // Represents either the fixed frame rate, or the maximum frame rate to // expect from a variable-rate source. This value generally remains the // same for all frames in the same session. - base::Optional<double> frame_rate; + absl::optional<double> frame_rate; // This is a boolean that signals that the video capture engine detects // interactive content. One possible optimization that this signal can help @@ -107,7 +104,7 @@ struct MEDIA_EXPORT VideoFrameMetadata { // a high-resolution timestamp, and so it should not be used as a // presentation time; but, instead, it should be used for buffering playback // and for A/V synchronization purposes. - base::Optional<base::TimeTicks> reference_time; + absl::optional<base::TimeTicks> reference_time; // Sources of VideoFrames use this marker to indicate that an instance of // VideoFrameExternalResources produced from the associated video frame @@ -115,7 +112,7 @@ struct MEDIA_EXPORT VideoFrameMetadata { bool read_lock_fences_enabled = false; // Indicates that the frame has a rotation and/or flip. - base::Optional<VideoTransformation> transformation; + absl::optional<VideoTransformation> transformation; // Android only: if set, then this frame is not suitable for overlay, even // if ALLOW_OVERLAY is set. However, it allows us to process the overlay @@ -140,7 +137,7 @@ struct MEDIA_EXPORT VideoFrameMetadata { // An UnguessableToken that identifies VideoOverlayFactory that created // this VideoFrame. It's used by Cast to help with video hole punch. - base::Optional<base::UnguessableToken> overlay_plane_id; + absl::optional<base::UnguessableToken> overlay_plane_id; // Whether this frame was decoded in a power efficient way. bool power_efficient = false; @@ -149,46 +146,46 @@ struct MEDIA_EXPORT VideoFrameMetadata { // remote debugging. // TODO(crbug.com/832220): Use a customized dictionary value instead of // using these keys directly. - base::Optional<double> device_scale_factor; - base::Optional<double> page_scale_factor; - base::Optional<double> root_scroll_offset_x; - base::Optional<double> root_scroll_offset_y; - base::Optional<double> top_controls_visible_height; + absl::optional<double> device_scale_factor; + absl::optional<double> page_scale_factor; + absl::optional<double> root_scroll_offset_x; + absl::optional<double> root_scroll_offset_y; + absl::optional<double> top_controls_visible_height; // If present, this field represents the local time at which the VideoFrame // was decoded from whichever format it was encoded in. Sometimes only // DECODE_END_TIME will be present. - base::Optional<base::TimeTicks> decode_begin_time; - base::Optional<base::TimeTicks> decode_end_time; + absl::optional<base::TimeTicks> decode_begin_time; + absl::optional<base::TimeTicks> decode_end_time; // If present, this field represents the elapsed time from the submission of // the encoded packet with the same PTS as this frame to the decoder until // the decoded frame was ready for presentation. - base::Optional<base::TimeDelta> processing_time; + absl::optional<base::TimeDelta> processing_time; // The RTP timestamp associated with this video frame. Stored as a double // since base::DictionaryValue doesn't have a uint32_t type. // // https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource-rtptimestamp - base::Optional<double> rtp_timestamp; + absl::optional<double> rtp_timestamp; // For video frames coming from a remote source, this is the time the // encoded frame was received by the platform, i.e., the time at // which the last packet belonging to this frame was received over the // network. - base::Optional<base::TimeTicks> receive_time; + absl::optional<base::TimeTicks> receive_time; // If present, this field represents the duration this frame is ideally // expected to spend on the screen during playback. Unlike FRAME_DURATION // this field takes into account current playback rate. - base::Optional<base::TimeDelta> wallclock_frame_duration; + absl::optional<base::TimeDelta> wallclock_frame_duration; // WebRTC streams only: if present, this field represents the maximum // composition delay that is allowed for this frame. This is respected // in a best effort manner. // This is an experimental feature, see crbug.com/1138888 for more // information. - base::Optional<int> maximum_composition_delay_in_frames; + absl::optional<int> maximum_composition_delay_in_frames; }; } // namespace media diff --git a/chromium/media/base/video_frame_pool.cc b/chromium/media/base/video_frame_pool.cc index 4541324af7b..b5db2c3fbab 100644 --- a/chromium/media/base/video_frame_pool.cc +++ b/chromium/media/base/video_frame_pool.cc @@ -7,7 +7,6 @@ #include "base/bind.h" #include "base/containers/circular_deque.h" #include "base/logging.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" #include "base/thread_annotations.h" @@ -19,6 +18,8 @@ class VideoFramePool::PoolImpl : public base::RefCountedThreadSafe<VideoFramePool::PoolImpl> { public: PoolImpl(); + PoolImpl(const PoolImpl&) = delete; + PoolImpl& operator=(const PoolImpl&) = delete; // See VideoFramePool::CreateFrame() for usage. Attempts to keep |frames_| in // LRU order by always pulling from the back of |frames_|. @@ -65,8 +66,6 @@ class VideoFramePool::PoolImpl // |tick_clock_| is always a DefaultTickClock outside of testing. const base::TickClock* tick_clock_; - - DISALLOW_COPY_AND_ASSIGN(PoolImpl); }; VideoFramePool::PoolImpl::PoolImpl() diff --git a/chromium/media/base/video_frame_pool.h b/chromium/media/base/video_frame_pool.h index e6532b4bf41..88cac326086 100644 --- a/chromium/media/base/video_frame_pool.h +++ b/chromium/media/base/video_frame_pool.h @@ -7,7 +7,6 @@ #include <stddef.h> -#include "base/macros.h" #include "media/base/media_export.h" #include "media/base/video_frame.h" @@ -28,6 +27,8 @@ namespace media { class MEDIA_EXPORT VideoFramePool { public: VideoFramePool(); + VideoFramePool(const VideoFramePool&) = delete; + VideoFramePool& operator=(const VideoFramePool&) = delete; ~VideoFramePool(); // Returns a frame from the pool that matches the specified @@ -53,8 +54,6 @@ class MEDIA_EXPORT VideoFramePool { private: class PoolImpl; scoped_refptr<PoolImpl> pool_; - - DISALLOW_COPY_AND_ASSIGN(VideoFramePool); }; } // namespace media diff --git a/chromium/media/base/video_frame_unittest.cc b/chromium/media/base/video_frame_unittest.cc index 50836987e0d..a16ecbcd3cf 100644 --- a/chromium/media/base/video_frame_unittest.cc +++ b/chromium/media/base/video_frame_unittest.cc @@ -291,6 +291,11 @@ TEST(VideoFrame, CreateFrame) { // Test an empty frame. frame = VideoFrame::CreateEOSFrame(); EXPECT_TRUE(frame->metadata().end_of_stream); + + // Test an video hole frame. + frame = VideoFrame::CreateVideoHoleFrame(base::UnguessableToken::Create(), + size, kTimestamp); + ASSERT_TRUE(frame); } TEST(VideoFrame, CreateZeroInitializedFrame) { diff --git a/chromium/media/base/video_renderer.h b/chromium/media/base/video_renderer.h index bfbc676c856..6e5611886f2 100644 --- a/chromium/media/base/video_renderer.h +++ b/chromium/media/base/video_renderer.h @@ -6,11 +6,10 @@ #define MEDIA_BASE_VIDEO_RENDERER_H_ #include "base/callback_forward.h" -#include "base/macros.h" -#include "base/optional.h" #include "media/base/media_export.h" #include "media/base/pipeline_status.h" #include "media/base/time_source.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -21,6 +20,8 @@ class RendererClient; class MEDIA_EXPORT VideoRenderer { public: VideoRenderer(); + VideoRenderer(const VideoRenderer&) = delete; + VideoRenderer& operator=(const VideoRenderer&) = delete; // Stops all operations and fires all pending callbacks. virtual ~VideoRenderer(); @@ -68,10 +69,7 @@ class MEDIA_EXPORT VideoRenderer { // media::Renderer::SetLatencyHint(). // |latency_hint| may be nullopt to indicate the hint has been cleared // (restore UA default). - virtual void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(VideoRenderer); + virtual void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) = 0; }; } // namespace media diff --git a/chromium/media/base/video_thumbnail_decoder.h b/chromium/media/base/video_thumbnail_decoder.h index 409ec23ab6a..af70aaf20dd 100644 --- a/chromium/media/base/video_thumbnail_decoder.h +++ b/chromium/media/base/video_thumbnail_decoder.h @@ -9,7 +9,6 @@ #include <vector> #include "base/callback.h" -#include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "media/base/media_export.h" @@ -32,6 +31,8 @@ class MEDIA_EXPORT VideoThumbnailDecoder { VideoThumbnailDecoder(std::unique_ptr<VideoDecoder> decoder, const VideoDecoderConfig& config, std::vector<uint8_t> encoded_data); + VideoThumbnailDecoder(const VideoThumbnailDecoder&) = delete; + VideoThumbnailDecoder& operator=(const VideoThumbnailDecoder&) = delete; ~VideoThumbnailDecoder(); // Starts to decode the video frame. @@ -56,8 +57,6 @@ class MEDIA_EXPORT VideoThumbnailDecoder { VideoFrameCallback video_frame_callback_; base::WeakPtrFactory<VideoThumbnailDecoder> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(VideoThumbnailDecoder); }; } // namespace media diff --git a/chromium/media/base/video_thumbnail_decoder_unittest.cc b/chromium/media/base/video_thumbnail_decoder_unittest.cc index 10aa6e34f6b..f070c07cce9 100644 --- a/chromium/media/base/video_thumbnail_decoder_unittest.cc +++ b/chromium/media/base/video_thumbnail_decoder_unittest.cc @@ -28,8 +28,11 @@ namespace { class VideoThumbnailDecoderTest : public testing::Test { public: - VideoThumbnailDecoderTest() {} - ~VideoThumbnailDecoderTest() override {} + VideoThumbnailDecoderTest() = default; + VideoThumbnailDecoderTest(const VideoThumbnailDecoderTest&) = delete; + VideoThumbnailDecoderTest& operator=(const VideoThumbnailDecoderTest&) = + delete; + ~VideoThumbnailDecoderTest() override = default; protected: void SetUp() override { @@ -76,8 +79,6 @@ class VideoThumbnailDecoderTest : public testing::Test { // The video frame returned from the thumbnail decoder. scoped_refptr<VideoFrame> frame_; - - DISALLOW_COPY_AND_ASSIGN(VideoThumbnailDecoderTest); }; // Verifies a video frame can be delivered when decoder successfully created diff --git a/chromium/media/base/video_util_unittest.cc b/chromium/media/base/video_util_unittest.cc index c6ae0616ddc..abaa9e25696 100644 --- a/chromium/media/base/video_util_unittest.cc +++ b/chromium/media/base/video_util_unittest.cc @@ -9,7 +9,6 @@ #include <cmath> #include <memory> -#include "base/macros.h" #include "media/base/video_frame.h" #include "testing/gtest/include/gtest/gtest.h" @@ -151,7 +150,8 @@ class VideoUtilTest : public testing::Test { u_stride_(0), v_stride_(0) { } - + VideoUtilTest(const VideoUtilTest&) = delete; + VideoUtilTest& operator=(const VideoUtilTest&) = delete; ~VideoUtilTest() override = default; void CreateSourceFrame(int width, int height, @@ -187,8 +187,6 @@ class VideoUtilTest : public testing::Test { int v_stride_; scoped_refptr<VideoFrame> destination_frame_; - - DISALLOW_COPY_AND_ASSIGN(VideoUtilTest); }; TEST_F(VideoUtilTest, GetPixelAspectRatio) { @@ -408,15 +406,14 @@ class VideoUtilRotationTest VideoUtilRotationTest() { dest_.reset(new uint8_t[GetParam().width * GetParam().height]); } - - virtual ~VideoUtilRotationTest() = default; + VideoUtilRotationTest(const VideoUtilRotationTest&) = delete; + VideoUtilRotationTest& operator=(const VideoUtilRotationTest&) = delete; + ~VideoUtilRotationTest() override = default; uint8_t* dest_plane() { return dest_.get(); } private: std::unique_ptr<uint8_t[]> dest_; - - DISALLOW_COPY_AND_ASSIGN(VideoUtilRotationTest); }; TEST_P(VideoUtilRotationTest, Rotate) { diff --git a/chromium/media/base/win/BUILD.gn b/chromium/media/base/win/BUILD.gn index b78090ac9c1..97dfcd06aa6 100644 --- a/chromium/media/base/win/BUILD.gn +++ b/chromium/media/base/win/BUILD.gn @@ -54,7 +54,7 @@ source_set("hresult_status_helper") { } source_set("mf_cdm_proxy") { - sources = [ "mf_cdm_proxy.h" ] + sources = [ "media_foundation_cdm_proxy.h" ] deps = [ "//base" ] } diff --git a/chromium/media/base/win/dxgi_device_manager.h b/chromium/media/base/win/dxgi_device_manager.h index d489b3160c2..98e830154f2 100644 --- a/chromium/media/base/win/dxgi_device_manager.h +++ b/chromium/media/base/win/dxgi_device_manager.h @@ -33,7 +33,7 @@ class MF_INITIALIZER_EXPORT DXGIDeviceScopedHandle { }; class MF_INITIALIZER_EXPORT DXGIDeviceManager - : public base::RefCounted<DXGIDeviceManager> { + : public base::RefCountedThreadSafe<DXGIDeviceManager> { public: DXGIDeviceManager(const DXGIDeviceManager&) = delete; DXGIDeviceManager& operator=(const DXGIDeviceManager&) = delete; @@ -61,7 +61,7 @@ class MF_INITIALIZER_EXPORT DXGIDeviceManager Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> GetMFDXGIDeviceManager(); protected: - friend class base::RefCounted<DXGIDeviceManager>; + friend class base::RefCountedThreadSafe<DXGIDeviceManager>; DXGIDeviceManager( Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> mf_dxgi_device_manager, UINT d3d_device_reset_token); diff --git a/chromium/media/base/win/mf_cdm_proxy.h b/chromium/media/base/win/media_foundation_cdm_proxy.h index fcbeff51a85..e7e7c51d9d2 100644 --- a/chromium/media/base/win/mf_cdm_proxy.h +++ b/chromium/media/base/win/media_foundation_cdm_proxy.h @@ -2,27 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_BASE_WIN_MF_CDM_PROXY_H_ -#define MEDIA_BASE_WIN_MF_CDM_PROXY_H_ +#ifndef MEDIA_BASE_WIN_MEDIA_FOUNDATION_CDM_PROXY_H_ +#define MEDIA_BASE_WIN_MEDIA_FOUNDATION_CDM_PROXY_H_ +#include <mfobjects.h> #include <stdint.h> #include <unknwn.h> +#include <windef.h> -// Interface for clients to get information from MediaFoundationCdm to -// implements COM interfaces. -// COM interface is used because we are working with Media Foundation which uses -// COM extensively for object lifetime management. -MIDL_INTERFACE("565ab5c2-9923-44e0-997a-f93ccba5dcbf") -IMFCdmProxy : public IUnknown { +#include "base/memory/ref_counted.h" + +namespace media { + +// Interface for the media pipeline to get information from MediaFoundationCdm. +// TODO(xhwang): Investigate whether this class needs to be ref-counted. +class MediaFoundationCdmProxy + : public base::RefCountedThreadSafe<MediaFoundationCdmProxy> { public: // Used by MediaFoundationProtectionManager to get // ABI::Windows::Media::Protection::IMediaProtectionPMPServer to implement - // ABI::Windows::Media::Protection::IMediaProtectionManager::get_Properties as - // in + // ABI::Windows::Media::Protection::IMediaProtectionManager::get_Properties // https://docs.microsoft.com/en-us/uwp/api/windows.media.protection.mediaprotectionmanager - virtual HRESULT STDMETHODCALLTYPE GetPMPServer( - /* [in] */ __RPC__in REFIID riid, - /* [iid_is][out] */ __RPC__deref_out_opt LPVOID * object_result) = 0; + virtual HRESULT GetPMPServer(REFIID riid, LPVOID* object_result) = 0; // Used by MediaFoundationSourceWrapper to implement // IMFTrustedInput::GetInputTrustAuthority as in @@ -30,30 +31,35 @@ IMFCdmProxy : public IUnknown { // // |content_init_data| is optional initialization data as in // https://www.w3.org/TR/encrypted-media/#initialization-data - virtual HRESULT STDMETHODCALLTYPE GetInputTrustAuthority( - _In_ uint32_t stream_id, _In_ uint32_t stream_count, - _In_reads_bytes_opt_(content_init_data_size) - const uint8_t* content_init_data, - _In_ uint32_t content_init_data_size, _In_ REFIID riid, - _COM_Outptr_ IUnknown** object_out) = 0; + virtual HRESULT GetInputTrustAuthority(uint32_t stream_id, + uint32_t stream_count, + const uint8_t* content_init_data, + uint32_t content_init_data_size, + REFIID riid, + IUnknown** object_out) = 0; // When the media Renderer is suspended, `MediaFoundationSourceWrapper` // provides its last set of key IDs using `SetLastKeyId()` when it is // destructed. Then during resume, the new `MediaFoundationSourceWrapper` // calls `RefreshTrustedInput()` to let the CDM use the key IDs information to // perform some optimization. - virtual HRESULT STDMETHODCALLTYPE SetLastKeyId(_In_ uint32_t stream_id, - _In_ REFGUID key_id) = 0; - virtual HRESULT STDMETHODCALLTYPE RefreshTrustedInput() = 0; + virtual HRESULT SetLastKeyId(uint32_t stream_id, REFGUID key_id) = 0; + virtual HRESULT RefreshTrustedInput() = 0; // Used by MediaFoundationProtectionManager to implement // IMFContentProtectionManager::BeginEnableContent as in // https://msdn.microsoft.com/en-us/windows/ms694217(v=vs.71) // - // |result| is used to obtain the result of an asynchronous operation as in + // `result` is used to obtain the result of an asynchronous operation as in // https://docs.microsoft.com/en-us/windows/win32/api/mfobjects/nn-mfobjects-imfasyncresult - virtual HRESULT STDMETHODCALLTYPE ProcessContentEnabler( - _In_ IUnknown * request, _In_ IMFAsyncResult * result) = 0; + virtual HRESULT ProcessContentEnabler(IUnknown* request, + IMFAsyncResult* result) = 0; + + protected: + friend base::RefCountedThreadSafe<MediaFoundationCdmProxy>; + virtual ~MediaFoundationCdmProxy() = default; }; -#endif // MEDIA_BASE_WIN_MF_CDM_PROXY_H_ +} // namespace media + +#endif // MEDIA_BASE_WIN_MEDIA_FOUNDATION_CDM_PROXY_H_ diff --git a/chromium/media/blink/BUILD.gn b/chromium/media/blink/BUILD.gn index 3537092d52b..f96c86f9430 100644 --- a/chromium/media/blink/BUILD.gn +++ b/chromium/media/blink/BUILD.gn @@ -35,6 +35,7 @@ component("blink") { "multibuffer_reader.h", "new_session_cdm_result_promise.cc", "new_session_cdm_result_promise.h", + "power_status_helper.cc", "power_status_helper.h", "remote_playback_client_wrapper_impl.cc", "remote_playback_client_wrapper_impl.h", @@ -82,6 +83,7 @@ component("blink") { "//media/learning/mojo/public/cpp:cpp", "//media/mojo/mojom", "//net", + "//services/device/public/mojom", "//services/network/public/cpp:cpp", "//services/service_manager/public/cpp:cpp", "//third_party/blink/public:blink", @@ -116,6 +118,7 @@ test("media_blink_unittests") { "//mojo/core/embedder", "//net", "//services/device:test_support", + "//services/device/public/mojom", "//testing/gmock", "//testing/gtest", "//third_party/blink/public:blink", @@ -149,6 +152,7 @@ test("media_blink_unittests") { "mock_webassociatedurlloader.h", "multibuffer_data_source_unittest.cc", "multibuffer_unittest.cc", + "power_status_helper_unittest.cc", "resource_multibuffer_data_provider_unittest.cc", "run_all_unittests.cc", "smoothness_helper_unittest.cc", diff --git a/chromium/media/blink/blink_platform_with_task_environment.h b/chromium/media/blink/blink_platform_with_task_environment.h index a279b2bc31c..4ebfff99e76 100644 --- a/chromium/media/blink/blink_platform_with_task_environment.h +++ b/chromium/media/blink/blink_platform_with_task_environment.h @@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/test/task_environment.h" +#include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h" #include "third_party/blink/public/web/blink.h" diff --git a/chromium/media/blink/cache_util.h b/chromium/media/blink/cache_util.h index 16e5c317c90..f354b9dc41e 100644 --- a/chromium/media/blink/cache_util.h +++ b/chromium/media/blink/cache_util.h @@ -7,8 +7,6 @@ #include <stdint.h> -#include <vector> - #include "base/time/time.h" #include "media/blink/media_blink_export.h" diff --git a/chromium/media/blink/cdm_result_promise_helper.h b/chromium/media/blink/cdm_result_promise_helper.h index a2a0fd7904a..80d9bf97859 100644 --- a/chromium/media/blink/cdm_result_promise_helper.h +++ b/chromium/media/blink/cdm_result_promise_helper.h @@ -7,7 +7,6 @@ #include <string> -#include "base/time/time.h" #include "media/base/cdm_key_information.h" #include "media/base/cdm_promise.h" #include "media/blink/media_blink_export.h" diff --git a/chromium/media/blink/cdm_session_adapter.cc b/chromium/media/blink/cdm_session_adapter.cc index ca046934c99..e378e62d575 100644 --- a/chromium/media/blink/cdm_session_adapter.cc +++ b/chromium/media/blink/cdm_session_adapter.cc @@ -8,10 +8,10 @@ #include <utility> #include "base/bind.h" +#include "base/containers/contains.h" #include "base/logging.h" #include "base/metrics/histogram.h" #include "base/metrics/histogram_functions.h" -#include "base/stl_util.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "media/base/cdm_factory.h" @@ -38,8 +38,8 @@ void CdmSessionAdapter::CreateCdm(CdmFactory* cdm_factory, const std::string& key_system, const CdmConfig& cdm_config, WebCdmCreatedCB web_cdm_created_cb) { - TRACE_EVENT_ASYNC_BEGIN0("media", "CdmSessionAdapter::CreateCdm", - ++trace_id_); + TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("media", "CdmSessionAdapter::CreateCdm", + ++trace_id_); base::TimeTicks start_time = base::TimeTicks::Now(); @@ -171,9 +171,9 @@ void CdmSessionAdapter::OnCdmCreated( << (cdm ? "success" : "failure (" + error_message + ")"); DCHECK(!cdm_); - TRACE_EVENT_ASYNC_END2("media", "CdmSessionAdapter::CreateCdm", trace_id_, - "success", (cdm ? "true" : "false"), "error_message", - error_message); + TRACE_EVENT_NESTABLE_ASYNC_END2( + "media", "CdmSessionAdapter::CreateCdm", trace_id_, "success", + (cdm ? "true" : "false"), "error_message", error_message); auto key_system_uma_prefix = kMediaEME + GetKeySystemNameForUMA(key_system) + kDot; diff --git a/chromium/media/blink/key_system_config_selector.cc b/chromium/media/blink/key_system_config_selector.cc index 0fb75ba185f..68c833ec965 100644 --- a/chromium/media/blink/key_system_config_selector.cc +++ b/chromium/media/blink/key_system_config_selector.cc @@ -20,15 +20,12 @@ #include "media/base/media_permission.h" #include "media/base/mime_util.h" #include "media/media_buildflags.h" -#include "third_party/blink/public/platform/url_conversion.h" #include "third_party/blink/public/platform/web_content_settings_client.h" #include "third_party/blink/public/platform/web_media_key_system_configuration.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/platform/web_vector.h" #include "third_party/blink/public/web/modules/media/webmediaplayer_util.h" #include "third_party/blink/public/web/web_local_frame.h" -#include "url/gurl.h" -#include "url/origin.h" namespace media { @@ -247,6 +244,10 @@ class KeySystemConfigSelector::ConfigState { return are_hw_secure_codecs_required_; } + bool AreHwSecureCodesNotAllowed() const { + return are_hw_secure_codecs_not_allowed_; + } + // Checks whether a rule is compatible with all previously added rules. bool IsRuleSupported(EmeConfigRule rule) const { switch (rule) { @@ -265,8 +266,8 @@ class KeySystemConfigSelector::ConfigState { case EmeConfigRule::PERSISTENCE_REQUIRED: return !is_persistence_not_allowed_; case EmeConfigRule::IDENTIFIER_AND_PERSISTENCE_REQUIRED: - return (!is_identifier_not_allowed_ && IsPermissionPossible() && - !is_persistence_not_allowed_); + return !is_identifier_not_allowed_ && IsPermissionPossible() && + !is_persistence_not_allowed_; case EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED: return !are_hw_secure_codecs_required_; case EmeConfigRule::HW_SECURE_CODECS_REQUIRED: @@ -274,6 +275,10 @@ class KeySystemConfigSelector::ConfigState { case EmeConfigRule::IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED: return !is_identifier_not_allowed_ && IsPermissionPossible() && !are_hw_secure_codecs_not_allowed_; + case EmeConfigRule::IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED: + return !is_identifier_not_allowed_ && IsPermissionPossible() && + !is_persistence_not_allowed_ && + !are_hw_secure_codecs_not_allowed_; case EmeConfigRule::SUPPORTED: return true; } @@ -317,6 +322,11 @@ class KeySystemConfigSelector::ConfigState { is_identifier_required_ = true; are_hw_secure_codecs_required_ = true; return; + case EmeConfigRule::IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED: + is_identifier_required_ = true; + is_persistence_required_ = true; + are_hw_secure_codecs_required_ = true; + return; case EmeConfigRule::SUPPORTED: return; } @@ -506,8 +516,20 @@ bool KeySystemConfigSelector::GetSupportedCapabilities( continue; requested_robustness_ascii = capability.robustness.Ascii(); } + // Both of these should not be true. + DCHECK(!(proposed_config_state.AreHwSecureCodecsRequired() && + proposed_config_state.AreHwSecureCodesNotAllowed())); + bool hw_secure_requirement; + bool* hw_secure_requirement_ptr = &hw_secure_requirement; + if (proposed_config_state.AreHwSecureCodecsRequired()) + hw_secure_requirement = true; + else if (proposed_config_state.AreHwSecureCodesNotAllowed()) + hw_secure_requirement = false; + else + hw_secure_requirement_ptr = nullptr; EmeConfigRule robustness_rule = key_systems_->GetRobustnessConfigRule( - key_system, media_type, requested_robustness_ascii); + key_system, media_type, requested_robustness_ascii, + hw_secure_requirement_ptr); // 3.13. If the user agent and implementation definitely support playback of // encrypted media data for the combination of container, media types, diff --git a/chromium/media/blink/key_system_config_selector_unittest.cc b/chromium/media/blink/key_system_config_selector_unittest.cc index a05a8f5bc13..3b6d68b8f44 100644 --- a/chromium/media/blink/key_system_config_selector_unittest.cc +++ b/chromium/media/blink/key_system_config_selector_unittest.cc @@ -45,8 +45,10 @@ const char kRecommendIdentifierRobustness[] = "recommend_identifier"; const char kRequireIdentifierRobustness[] = "require_identifier"; const char kDisallowHwSecureCodecRobustness[] = "disallow_hw_secure_codec"; const char kRequireHwSecureCodecRobustness[] = "require_hw_secure_codec"; -const char kRequireHwSecureCodecAndIdentifierRobustness[] = - "require_hw_secure_codec_and_identifier"; +const char kRequireIdentifierAndHwSecureCodecRobustness[] = + "require_identifier_and_hw_secure_codec"; +const char kRequireIdentifierPersistenceAndHwSecureCodecRobustness[] = + "require_identifier_persistence_and_hw_secure_codec"; const char kUnsupportedRobustness[] = "unsupported"; // Test container mime types. Supported types are prefixed with audio/video so @@ -284,7 +286,15 @@ class FakeKeySystems : public KeySystems { EmeConfigRule GetRobustnessConfigRule( const std::string& key_system, EmeMediaType media_type, - const std::string& requested_robustness) const override { + const std::string& requested_robustness, + const bool* hw_secure_requirement) const override { + // TODO(crbug.com/1204284): Remove the `hw_secure_requirement` parameter. + // This only exists as a temporary solution until a larger refactoring is + // done. We are only testing the explicit thing it is fixing here. + if (hw_secure_requirement && *hw_secure_requirement && + distinctive_identifier == EmeFeatureSupport::NOT_SUPPORTED) { + return EmeConfigRule::NOT_SUPPORTED; + } if (requested_robustness.empty()) return EmeConfigRule::SUPPORTED; if (requested_robustness == kSupportedRobustness) @@ -297,8 +307,13 @@ class FakeKeySystems : public KeySystems { return EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED; if (requested_robustness == kRequireHwSecureCodecRobustness) return EmeConfigRule::HW_SECURE_CODECS_REQUIRED; - if (requested_robustness == kRequireHwSecureCodecAndIdentifierRobustness) + if (requested_robustness == kRequireIdentifierAndHwSecureCodecRobustness) return EmeConfigRule::IDENTIFIER_AND_HW_SECURE_CODECS_REQUIRED; + if (requested_robustness == + kRequireIdentifierPersistenceAndHwSecureCodecRobustness) { + return EmeConfigRule:: + IDENTIFIER_PERSISTENCE_AND_HW_SECURE_CODECS_REQUIRED; + } if (requested_robustness == kUnsupportedRobustness) return EmeConfigRule::NOT_SUPPORTED; @@ -1503,10 +1518,10 @@ TEST_F(KeySystemConfigSelectorTest, SelectConfigReturnsError(); } -// --- HW Secure and Identifier Robustness --- +// --- Identifier and HW Secure Robustness --- TEST_F(KeySystemConfigSelectorTest, - HwSecureCodecAndIdentifier_IncompatibleCodecAndRobustness) { + IdentifierAndHwSecureCodec_IncompatibleCodecAndRobustness) { media_permission_->is_granted = true; key_systems_->distinctive_identifier = EmeFeatureSupport::REQUESTABLE; @@ -1515,7 +1530,7 @@ TEST_F(KeySystemConfigSelectorTest, video_capabilities[0].mime_type = kSupportedVideoContainer; video_capabilities[0].codecs = kDisallowHwSecureCodec; video_capabilities[0].robustness = - kRequireHwSecureCodecAndIdentifierRobustness; + kRequireIdentifierAndHwSecureCodecRobustness; auto config = EmptyConfiguration(); config.video_capabilities = video_capabilities; @@ -1525,7 +1540,7 @@ TEST_F(KeySystemConfigSelectorTest, } TEST_F(KeySystemConfigSelectorTest, - HwSecureCodecAndIdentifier_IncompatibleCapabilities) { + IdentifierAndHwSecureCodec_IncompatibleCapabilities) { media_permission_->is_granted = true; key_systems_->distinctive_identifier = EmeFeatureSupport::REQUESTABLE; @@ -1534,7 +1549,7 @@ TEST_F(KeySystemConfigSelectorTest, video_capabilities[0].mime_type = kSupportedVideoContainer; video_capabilities[0].codecs = kSupportedVideoCodec; video_capabilities[0].robustness = - kRequireHwSecureCodecAndIdentifierRobustness; + kRequireIdentifierAndHwSecureCodecRobustness; video_capabilities[1].content_type = "disallow_hw_secure_codec"; video_capabilities[1].mime_type = kSupportedVideoContainer; video_capabilities[1].codecs = kDisallowHwSecureCodec; @@ -1553,7 +1568,7 @@ TEST_F(KeySystemConfigSelectorTest, } TEST_F(KeySystemConfigSelectorTest, - HwSecureCodecAndIdentifier_UnsupportedCapabilityNotAffectingRules) { + IdentifierAndHwSecureCodec_UnsupportedCapabilityNotAffectingRules) { media_permission_->is_granted = true; key_systems_->distinctive_identifier = EmeFeatureSupport::REQUESTABLE; @@ -1566,7 +1581,7 @@ TEST_F(KeySystemConfigSelectorTest, video_capabilities[1].mime_type = kSupportedVideoContainer; video_capabilities[1].codecs = kRequireHwSecureCodec; video_capabilities[1].robustness = - kRequireHwSecureCodecAndIdentifierRobustness; + kRequireIdentifierAndHwSecureCodecRobustness; auto config = EmptyConfiguration(); config.video_capabilities = video_capabilities; @@ -1580,6 +1595,72 @@ TEST_F(KeySystemConfigSelectorTest, EXPECT_TRUE(cdm_config_.use_hw_secure_codecs); } +TEST_F(KeySystemConfigSelectorTest, + HwSecureCodecAndIdentifier_IdentifierAndHwSecureCodecsDisjoint) { + media_permission_->is_granted = false; + key_systems_->distinctive_identifier = EmeFeatureSupport::NOT_SUPPORTED; + + std::vector<WebMediaKeySystemMediaCapability> video_capabilities(2); + video_capabilities[0].content_type = "require_hw_secure_codec"; + video_capabilities[0].mime_type = kSupportedVideoContainer; + video_capabilities[0].codecs = kRequireHwSecureCodec; + video_capabilities[0].robustness = ""; + + auto config = EmptyConfiguration(); + config.video_capabilities = video_capabilities; + configs_.push_back(config); + + SelectConfigReturnsError(); +} + +// --- Identifier, Persistence and HW Secure Robustness --- + +TEST_F(KeySystemConfigSelectorTest, + IdentifierPersistenceAndHwSecureCodec_Supported) { + media_permission_->is_granted = true; + key_systems_->persistent_state = EmeFeatureSupport::REQUESTABLE; + key_systems_->distinctive_identifier = EmeFeatureSupport::REQUESTABLE; + + std::vector<WebMediaKeySystemMediaCapability> video_capabilities(1); + video_capabilities[0].content_type = "require_hw_secure_codec"; + video_capabilities[0].mime_type = kSupportedVideoContainer; + video_capabilities[0].codecs = kSupportedVideoCodec; + video_capabilities[0].robustness = + kRequireIdentifierPersistenceAndHwSecureCodecRobustness; + + auto config = EmptyConfiguration(); + config.video_capabilities = video_capabilities; + configs_.push_back(config); + + SelectConfigRequestsPermissionAndReturnsConfig(); + EXPECT_EQ(MediaKeysRequirement::kRequired, config_.distinctive_identifier); + EXPECT_EQ(MediaKeysRequirement::kRequired, config_.persistent_state); + ASSERT_EQ(1u, config_.video_capabilities.size()); + EXPECT_EQ("require_hw_secure_codec", + config_.video_capabilities[0].content_type); + EXPECT_TRUE(cdm_config_.use_hw_secure_codecs); +} + +TEST_F(KeySystemConfigSelectorTest, + IdentifierPersistenceAndHwSecureCodec_NotSupported) { + media_permission_->is_granted = true; + key_systems_->persistent_state = EmeFeatureSupport::NOT_SUPPORTED; + key_systems_->distinctive_identifier = EmeFeatureSupport::REQUESTABLE; + + std::vector<WebMediaKeySystemMediaCapability> video_capabilities(1); + video_capabilities[0].content_type = "require_hw_secure_codec"; + video_capabilities[0].mime_type = kSupportedVideoContainer; + video_capabilities[0].codecs = kSupportedVideoCodec; + video_capabilities[0].robustness = + kRequireIdentifierPersistenceAndHwSecureCodecRobustness; + + auto config = EmptyConfiguration(); + config.video_capabilities = video_capabilities; + configs_.push_back(config); + + SelectConfigReturnsError(); +} + // --- audioCapabilities --- // These are handled by the same code as |videoCapabilities|, so only minimal // additional testing is done. diff --git a/chromium/media/blink/learning_experiment_helper_unittest.cc b/chromium/media/blink/learning_experiment_helper_unittest.cc index 63926025760..36e3e0bec98 100644 --- a/chromium/media/blink/learning_experiment_helper_unittest.cc +++ b/chromium/media/blink/learning_experiment_helper_unittest.cc @@ -29,15 +29,15 @@ class MockLearningTaskController : public LearningTaskController { MOCK_METHOD4(BeginObservation, void(base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_value, - const base::Optional<ukm::SourceId>& source_id)); + const absl::optional<TargetValue>& default_value, + const absl::optional<ukm::SourceId>& source_id)); MOCK_METHOD2(CompleteObservation, void(base::UnguessableToken id, const ObservationCompletion& completion)); MOCK_METHOD1(CancelObservation, void(base::UnguessableToken id)); MOCK_METHOD2(UpdateDefaultTarget, void(base::UnguessableToken id, - const base::Optional<TargetValue>& default_target)); + const absl::optional<TargetValue>& default_target)); MOCK_METHOD2(PredictDistribution, void(const FeatureVector& features, PredictionCB callback)); diff --git a/chromium/media/blink/multibuffer_data_source.cc b/chromium/media/blink/multibuffer_data_source.cc index 1e5c85595c7..c157471b08e 100644 --- a/chromium/media/blink/multibuffer_data_source.cc +++ b/chromium/media/blink/multibuffer_data_source.cc @@ -17,6 +17,7 @@ #include "media/blink/buffered_data_source_host_impl.h" #include "media/blink/multibuffer_reader.h" #include "net/base/net_errors.h" +#include "url/gurl.h" namespace { diff --git a/chromium/media/blink/multibuffer_data_source.h b/chromium/media/blink/multibuffer_data_source.h index 8441d15ece8..2f35c43811e 100644 --- a/chromium/media/blink/multibuffer_data_source.h +++ b/chromium/media/blink/multibuffer_data_source.h @@ -20,7 +20,8 @@ #include "media/base/tuneable.h" #include "media/blink/media_blink_export.h" #include "media/blink/url_index.h" -#include "url/gurl.h" + +class GURL; namespace base { class SingleThreadTaskRunner; diff --git a/chromium/media/blink/multibuffer_data_source_unittest.cc b/chromium/media/blink/multibuffer_data_source_unittest.cc index 3bdce8224f9..bf7e74c1b90 100644 --- a/chromium/media/blink/multibuffer_data_source_unittest.cc +++ b/chromium/media/blink/multibuffer_data_source_unittest.cc @@ -22,6 +22,7 @@ #include "media/blink/multibuffer_reader.h" #include "media/blink/resource_multibuffer_data_provider.h" #include "media/blink/test_response_generator.h" +#include "services/network/public/mojom/fetch_api.mojom.h" #include "third_party/blink/public/platform/web_url.h" #include "third_party/blink/public/platform/web_url_response.h" @@ -1405,7 +1406,6 @@ TEST_F(MultibufferDataSourceTest, Http_RetryThenRedirect) { // Issue a pending read but trigger an error to force a retry. EXPECT_CALL(*this, ReadCallback(kDataSize - 10)); - EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2)); ReadAt(kDataSize + 10, kDataSize - 10); base::RunLoop run_loop; data_provider()->DidFail(response_generator_->GenerateError()); @@ -1417,9 +1417,11 @@ TEST_F(MultibufferDataSourceTest, Http_RetryThenRedirect) { blink::WebURLResponse response((GURL(kHttpUrl))); response.SetHttpStatusCode(307); data_provider()->WillFollowRedirect(url, response); + + EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2)); Respond(response_generator_->Generate206(kDataSize)); ReceiveData(kDataSize); - EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 3)); + FinishLoading(); EXPECT_FALSE(loading()); Stop(); diff --git a/chromium/media/blink/multibuffer_reader.h b/chromium/media/blink/multibuffer_reader.h index 137f3888be2..ae67ccae4ba 100644 --- a/chromium/media/blink/multibuffer_reader.h +++ b/chromium/media/blink/multibuffer_reader.h @@ -7,10 +7,6 @@ #include <stdint.h> -#include <limits> -#include <map> -#include <set> - #include "base/callback.h" #include "base/memory/weak_ptr.h" #include "media/blink/media_blink_export.h" diff --git a/chromium/media/blink/new_session_cdm_result_promise.cc b/chromium/media/blink/new_session_cdm_result_promise.cc index 4e718cac8f1..0f19f3a939a 100644 --- a/chromium/media/blink/new_session_cdm_result_promise.cc +++ b/chromium/media/blink/new_session_cdm_result_promise.cc @@ -4,9 +4,9 @@ #include "media/blink/new_session_cdm_result_promise.h" +#include "base/containers/contains.h" #include "base/logging.h" #include "base/metrics/histogram_functions.h" -#include "base/stl_util.h" #include "media/blink/cdm_result_promise_helper.h" #include "third_party/blink/public/platform/web_string.h" diff --git a/chromium/media/blink/power_status_helper.cc b/chromium/media/blink/power_status_helper.cc new file mode 100644 index 00000000000..aaed8fd3824 --- /dev/null +++ b/chromium/media/blink/power_status_helper.cc @@ -0,0 +1,310 @@ +// Copyright 2019 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/blink/power_status_helper.h" + +#include <utility> + +#include "base/check.h" +#include "base/check_op.h" +#include "base/metrics/histogram_macros.h" +#include "media/base/pipeline_metadata.h" +#include "services/device/public/mojom/battery_status.mojom.h" + +namespace media { +namespace { + +using ::device::mojom::BatteryStatusPtr; + +static constexpr const char* kBatteryDeltaHistogram = + "Media.PlaybackPower.BatteryDelta"; +static constexpr const char* kElapsedTimeHistogram = + "Media.PlaybackPower.ElapsedTime"; + +// Minimum enum value that we'll generate, inclusive. +static constexpr int kMinEnumValue = 0; + +// Maximum enum value that we'll generate, inclusive. +static constexpr int kMaxEnumValue = + PowerStatusHelper::Bits::kCodecBitsH264 | + PowerStatusHelper::Bits::kCodecBitsVP9Profile0 | + PowerStatusHelper::Bits::kCodecBitsVP9Profile2 | + + PowerStatusHelper::Bits::kResolution360p | + PowerStatusHelper::Bits::kResolution720p | + PowerStatusHelper::Bits::kResolution1080p | + + PowerStatusHelper::Bits::kFrameRate30 | + PowerStatusHelper::Bits::kFrameRate60 | + + PowerStatusHelper::Bits::kFullScreenNo | + PowerStatusHelper::Bits::kFullScreenYes; + +// UMA buckets are always [uma_min, uma_max). The first bucket is an implicit +// underflow bucket [0, uma_min), and the last is the overflow bucket +// [uma_max, infinity). The underflow bucket isn't counted, but the overflow +// bucket is. + +// Minimum bucket number. Since we always get an underflow bucket, we choose +// the minimum bucket to be one higher than the minimum enum value. That way. +// the minimum enum goes to the underflow bucket. +// //tools/metrics/histograms/README.md#count-histograms_choosing-min-and-max +// for details. +static constexpr int kMinUmaValue = kMinEnumValue + 1; + +// We want to avoid using the overflow bucket. See +// //tools/metrics/histograms/README.md#count-histograms_choosing-min-and-max +// and UMA_HISTOGRAM_EXACT_LINEAR for details. + +// Max value as reported to UMA, which is the lower bound of the overflow +// bucket. Add one, since we want the overflow bucket to be unused. +static constexpr int kMaxUmaValue = kMaxEnumValue + 1; + +// Number of buckets we want, which includes the overflow bucket but not the +// implicit underflow bucket. +// NOTE: We add two here, else we don't quite get enough buckets. This was +// emperically determined by checking Histogram::bucket_ranges(). It might +// be the case that we should subtract one here and from |kMaxUmaValue|, but +// either way, i think it works out. We just have one unused bucket at worst, +// which won't be renumbered even if we start using it later. +static constexpr int kNumUmaBuckets = kMaxUmaValue - kMinUmaValue + 2; + +// For example, if kMinEnum == 0 and kMaxEnum == 5 (inclusive), then: +// kMinUma = 1 (0 is implicit), kMaxUma = 6, and we'll want the implicit +// underflow bucket plus kNumUmaBuckets = 6 more. +// [0, 1) << implicit underflow bucket, kMinEnum goes here +// [1, 2) +// [2, 3) +// [3, 4) +// [4, 5) +// [5, 6) << kMaxEnum goes here +// [6, infinity) << unused overflow bucket. + +// We can have more, but shouldn't without talking to metrics folks. +static_assert(kNumUmaBuckets < 100, "Too many buckets"); + +} // namespace + +PowerStatusHelper::PowerStatusHelper( + CreateBatteryMonitorCB create_battery_monitor_cb) + : create_battery_monitor_cb_(std::move(create_battery_monitor_cb)) {} + +PowerStatusHelper::~PowerStatusHelper() = default; + +// static +absl::optional<int> PowerStatusHelper::BucketFor( + bool is_playing, + bool has_video, + media::VideoCodec codec, + media::VideoCodecProfile profile, + gfx::Size natural_size, + bool is_fullscreen, + absl::optional<int> average_fps) { + if (!is_playing) + return {}; + + if (!has_video) + return {}; + + int bucket = 0; + + if (codec == media::VideoCodec::kCodecH264) + bucket |= Bits::kCodecBitsH264; + else if (profile == media::VP9PROFILE_PROFILE0) + bucket |= Bits::kCodecBitsVP9Profile0; + else if (profile == media::VP9PROFILE_PROFILE2) + bucket |= Bits::kCodecBitsVP9Profile2; + else + return {}; + + // We could take into account rotation, but ignore it for now. + if (natural_size == gfx::Size(640, 360)) + bucket |= kResolution360p; + else if (natural_size == gfx::Size(1280, 720)) + bucket |= kResolution720p; + else if (natural_size == gfx::Size(1920, 1080)) + bucket |= kResolution1080p; + else + return {}; + + // Estimate the frame rate. Since 24 is popular, allow a wide range around + // 30fps, since it's likely the same for power. + if (!average_fps) + return {}; + else if (*average_fps == 60) + bucket |= kFrameRate60; + else if (*average_fps >= 24 && *average_fps <= 30) + bucket |= kFrameRate30; + else + return {}; + + bucket |= is_fullscreen ? kFullScreenYes : kFullScreenNo; + + return bucket; +} + +// static +const char* PowerStatusHelper::BatteryDeltaHistogram() { + return kBatteryDeltaHistogram; +} + +// static +const char* PowerStatusHelper::ElapsedTimeHistogram() { + return kElapsedTimeHistogram; +} + +void PowerStatusHelper::SetIsPlaying(bool is_playing) { + is_playing_ = is_playing; + OnAnyStateChange(); +} + +void PowerStatusHelper::SetMetadata(const media::PipelineMetadata& metadata) { + has_video_ = metadata.has_video; + codec_ = metadata.video_decoder_config.codec(); + profile_ = metadata.video_decoder_config.profile(); + natural_size_ = metadata.video_decoder_config.natural_size(); + OnAnyStateChange(); +} + +void PowerStatusHelper::SetIsFullscreen(bool is_fullscreen) { + is_fullscreen_ = is_fullscreen; + OnAnyStateChange(); +} + +void PowerStatusHelper::SetAverageFrameRate(absl::optional<int> average_fps) { + average_fps_ = average_fps; + OnAnyStateChange(); +} + +void PowerStatusHelper::UpdatePowerExperimentState(bool state) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + experiment_state_ = state; + OnAnyStateChange(); +} + +void PowerStatusHelper::OnAnyStateChange() { + absl::optional<int> old_bucket = current_bucket_; + current_bucket_.reset(); + + // If we're the power experiment, then we might have a bucket. Else, we + // definitely don't. + if (experiment_state_) { + current_bucket_ = BucketFor(is_playing_, has_video_, codec_, profile_, + natural_size_, is_fullscreen_, average_fps_); + } + + // If we're changing buckets, then request power updates with a new generation + // id. This lets us separate readings from the old bucket. + if (current_bucket_ && (!old_bucket || *current_bucket_ != *old_bucket)) { + // Also reset the baseline, in case we're changing buckets. We don't want + // to include any battery drain that should have been in the first bucket. + StartMonitoring(); + } else if (old_bucket && !current_bucket_) { + // We don't need power updates, but we had them before. + StopMonitoring(); + } +} + +void PowerStatusHelper::OnBatteryStatus( + device::mojom::BatteryStatusPtr battery_status) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + QueryNextStatus(); + + if (battery_status->charging) { + // If we're charging, then wait until we stop. Take a new baseline then. + battery_level_baseline_.reset(); + return; + } + + // Compute the amount of time since our last update. Note that, if this is + // the first status update since we (re)started monitoring, then the baseline + // should be unset, so |elapsed| will be ignored. That's good, since it could + // be quite far in the past since we've had an update. + const base::TimeTicks now = base::TimeTicks::Now(); + + // Convert to floating point 0-100 from 0-1. + const float current_level = battery_status->level * 100; + + // If we don't have a baseline, then use |current_level| and |now|. In the + // future, we might want to wait until the battery drain is reported twice, + // since we don't know how much of a fractional percent remains in this + // initial baseline. For now, just ignore that. + if (!battery_level_baseline_) { + battery_level_baseline_ = current_level; + last_update_ = now; + return; + } + + // Second or later update since we started monitoring / stopped charging. + // Compute the battery used. Note that positive numbers indicate that the + // battery has gone down. + const float delta = *battery_level_baseline_ - current_level; + + DCHECK(current_bucket_); + DCHECK_GE(delta, 0.); + + // See if we can record some nonzero battery drain and elapsed time, when + // converted to int. We can only record ints in UMA. + const int delta_int = static_cast<int>(delta); + const base::TimeDelta elapsed = now - last_update_; + const int elapsed_msec = elapsed.InMilliseconds(); + if (delta_int > 0 && elapsed_msec > 0) { + // Record that we consumed |delta_int| battery percent in |elapsed_msec|. + base::LinearHistogram::FactoryGet( + BatteryDeltaHistogram(), kMinUmaValue, kMaxUmaValue, kNumUmaBuckets, + base::HistogramBase::kUmaTargetedHistogramFlag) + ->AddCount(*current_bucket_, delta_int); + + base::LinearHistogram::FactoryGet( + ElapsedTimeHistogram(), kMinUmaValue, kMaxUmaValue, kNumUmaBuckets, + base::HistogramBase::kUmaTargetedHistogramFlag) + ->AddCount(*current_bucket_, elapsed_msec); + + // Update the baseline to |current_level|, but include any fractional + // unrecorded amount so that we can record it later. + battery_level_baseline_ = current_level + (delta - delta_int); + // Don't bother remembering any fractional msec. + last_update_ = now; + } +} + +void PowerStatusHelper::StartMonitoring() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!battery_monitor_.is_bound()) { + auto pending = create_battery_monitor_cb_.Run(); + if (!pending.is_valid()) + return; + battery_monitor_.Bind(std::move(pending)); + + // In case it's not available for some reason, do nothing. + if (!battery_monitor_.is_bound()) + return; + + // Start querying for status as long as we're connected. + QueryNextStatus(); + } + + // Any baseline that we had should be reset, since we're called to start or + // restart monitoring when our bucket changes. + battery_level_baseline_.reset(); +} + +void PowerStatusHelper::StopMonitoring() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + battery_monitor_.reset(); +} + +void PowerStatusHelper::QueryNextStatus() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(battery_monitor_.is_bound()); + + // Remember that overlapping calls are not allowed by BatteryMonitor, and are + // treated as a connection error. Unretained since we own |battery_monitor_|. + battery_monitor_->QueryNextStatus(base::BindOnce( + &PowerStatusHelper::OnBatteryStatus, base::Unretained(this))); +} + +} // namespace media diff --git a/chromium/media/blink/power_status_helper.h b/chromium/media/blink/power_status_helper.h index 828055afa21..d8381dd1d59 100644 --- a/chromium/media/blink/power_status_helper.h +++ b/chromium/media/blink/power_status_helper.h @@ -5,35 +5,142 @@ #ifndef MEDIA_BLINK_POWER_STATUS_HELPER_H_ #define MEDIA_BLINK_POWER_STATUS_HELPER_H_ -#include "base/macros.h" -#include "base/optional.h" +#include "base/callback.h" +#include "base/sequence_checker.h" #include "base/time/time.h" -#include "media/base/pipeline_metadata.h" #include "media/base/video_codecs.h" #include "media/blink/media_blink_export.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "services/device/public/mojom/battery_monitor.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/gfx/geometry/size.h" namespace media { +struct PipelineMetadata; -// Base class to monitor for power events during playback and record them to -// UMA / UKM. +// Class to monitor for power events during playback and record them to UMA/UKM. class MEDIA_BLINK_EXPORT PowerStatusHelper { public: - PowerStatusHelper() = default; - virtual ~PowerStatusHelper() = default; + using CreateBatteryMonitorCB = base::RepeatingCallback< + mojo::PendingRemote<device::mojom::BatteryMonitor>()>; + + // Bits used to construct UMA buckets. + // These values are persisted to logs. Entries should not be renumbered and + // numeric values should never be reused. + enum /* not class */ Bits { + // Bit layout is: [msb] xx f F RR CC [lsb] + // R == resolution + // C == codec + // F == frame rate + // f == full screen + // x == unused + // Remember that we can't use more than 6 bits, since we shouldn't go over + // 100 UMA buckets. + + // Codec bits, values 0x00 to 0x03 + // Named "CodecBits" to prevent a name collision with media::VideoCodec. + kCodecBitsH264 = (0x00) << 0, + kCodecBitsVP9Profile0 = (0x01) << 0, + // Ignore Profile1 + kCodecBitsVP9Profile2 = (0x02) << 0, + // TODO(liberato): add AV1 + + // Resolution bits, values 0x00 to 0x03 + kResolution360p = (0x00) << 2, + kResolution720p = (0x01) << 2, + kResolution1080p = (0x02) << 2, + + // Frame rate bits, values 0x00 to 0x01 + kFrameRate30 = (0x00) << 4, + kFrameRate60 = (0x01) << 4, + + // Fullscreen bits, values 0x00 to 0x01 + kFullScreenNo = (0x00) << 5, + kFullScreenYes = (0x01) << 5, + + // This is not a valid bit for, you know, testing. + kNotAValidBitForTesting = (0x01) << 10, + }; + + // If |stats_cb| is not provided, then we'll record to UMA. It's just for + // the tests. + explicit PowerStatusHelper(CreateBatteryMonitorCB create_battery_monitor_cb); + PowerStatusHelper(const PowerStatusHelper&) = delete; + PowerStatusHelper& operator=(const PowerStatusHelper&) = delete; + ~PowerStatusHelper(); // Notify us about changes to the player. - virtual void SetIsPlaying(bool is_playing) = 0; - virtual void SetMetadata(const PipelineMetadata& metadata) = 0; - virtual void SetIsFullscreen(bool is_fullscreen) = 0; - virtual void SetAverageFrameRate(base::Optional<int> average_fps) = 0; + void SetIsPlaying(bool is_playing); + void SetMetadata(const media::PipelineMetadata& metadata); + void SetIsFullscreen(bool is_fullscreen); + void SetAverageFrameRate(absl::optional<int> average_fps); // Handle notifications about the experiment state from the power experiment. // manager. |state| indicates whether our player is eligible to record power // experiments readings. - virtual void UpdatePowerExperimentState(bool state) = 0; + void UpdatePowerExperimentState(bool state); private: - DISALLOW_COPY_AND_ASSIGN(PowerStatusHelper); + friend class PowerStatusHelperTest; + friend class PowerStatusHelperBucketTest; + + // Return the UMA bucket for the given video configuration, or nullopt if we + // don't want to record it. + static absl::optional<int> BucketFor(bool is_playing, + bool has_video, + media::VideoCodec codec, + media::VideoCodecProfile profile, + gfx::Size natural_size, + bool is_fullscreen, + absl::optional<int> average_fps); + + // Return the histogram names. Here so that tests can find them too. + static const char* BatteryDeltaHistogram(); + static const char* ElapsedTimeHistogram(); + + // Recompute everything when playback state or power experiment state changes. + void OnAnyStateChange(); + + // Handle updates about the current battery status. + void OnBatteryStatus(device::mojom::BatteryStatusPtr battery_status); + + // Start monitoring if we haven't already. Any outstanding callbacks will be + // cancelled if monitoring was already in progress. + void StartMonitoring(); + void StopMonitoring(); + + // Register to receive a power update the next time it changes. + void QueryNextStatus(); + + CreateBatteryMonitorCB create_battery_monitor_cb_; + + // Most recent parameters we were given. + bool is_playing_ = false; + bool has_video_ = false; + media::VideoCodec codec_ = media::VideoCodec::kUnknownVideoCodec; + media::VideoCodecProfile profile_ = + media::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN; + gfx::Size natural_size_; + bool is_fullscreen_ = false; + // For estimating fps. Can be unset if we don't know. + absl::optional<int> average_fps_; + + // Current UMA bucket, if any. + absl::optional<int> current_bucket_; + + // If set, our previous battery level, from 0-100. + absl::optional<float> battery_level_baseline_; + // The time at which we last got an update from |battery_monitor_|. + base::TimeTicks last_update_; + + // Are we currently the player that should be recording power for the power + // experiment, according to the MediaPowerExperimentManager? + bool experiment_state_ = false; + + mojo::Remote<device::mojom::BatteryMonitor> battery_monitor_; + + SEQUENCE_CHECKER(sequence_checker_); }; } // namespace media diff --git a/chromium/media/blink/power_status_helper_unittest.cc b/chromium/media/blink/power_status_helper_unittest.cc new file mode 100644 index 00000000000..cdacbd7873a --- /dev/null +++ b/chromium/media/blink/power_status_helper_unittest.cc @@ -0,0 +1,445 @@ +// Copyright 2019 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/blink/power_status_helper.h" + +#include <memory> +#include <tuple> +#include <utility> +#include <vector> + +#include "base/run_loop.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/test/mock_callback.h" +#include "base/test/task_environment.h" +#include "media/base/pipeline_metadata.h" +#include "media/blink/blink_platform_with_task_environment.h" +#include "services/device/public/mojom/battery_status.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::Bool; +using ::testing::Combine; +using ::testing::Eq; +using ::testing::Gt; +using ::testing::Lt; +using ::testing::ResultOf; +using ::testing::Return; +using ::testing::Values; + +class PowerStatusHelperTest : public testing::Test { + public: + class MockBatteryMonitor : public device::mojom::BatteryMonitor { + public: + MOCK_METHOD0(DidGetBatteryMonitor, void()); + MOCK_METHOD0(DidQueryNextStatus, void()); + MOCK_METHOD0(DidDisconnect, void()); + + ~MockBatteryMonitor() { + // Mojo gets mad if we don't finish up outstanding callbacks. + if (callback_) + ProvidePowerUpdate(0, 0); + } + + // device::mojom::BatteryMonitor + void QueryNextStatus(QueryNextStatusCallback callback) override { + DidQueryNextStatus(); + callback_ = std::move(callback); + } + + // Would be nice to use a MockCallback for this, but a move-only return type + // doesn't seem to work. + mojo::PendingRemote<device::mojom::BatteryMonitor> GetBatteryMonitor() { + DidGetBatteryMonitor(); + switch (remote_type_) { + case RemoteType::kConnected: + case RemoteType::kDisconnected: { + auto pending = receiver_.BindNewPipeAndPassRemote(); + receiver_.set_disconnect_handler(base::BindOnce( + &MockBatteryMonitor::DidDisconnect, base::Unretained(this))); + if (remote_type_ == RemoteType::kDisconnected) + receiver_.reset(); + base::RunLoop().RunUntilIdle(); + return pending; + } + case RemoteType::kEmpty: + return mojo::PendingRemote<device::mojom::BatteryMonitor>(); + } + } + + // Would be nice if this were base::MockCallback, but move-only types don't + // seem to work. + PowerStatusHelper::CreateBatteryMonitorCB cb() { + return base::BindRepeating(&MockBatteryMonitor::GetBatteryMonitor, + base::Unretained(this)); + } + + // Provide a battery update via |callback_|. + void ProvidePowerUpdate(bool is_charging, float current_level) { + EXPECT_TRUE(callback_); + device::mojom::BatteryStatusPtr status = + device::mojom::BatteryStatus::New(is_charging, 0, /* charging time */ + 0, /* discharging time */ + current_level); + std::move(callback_).Run(std::move(status)); + base::RunLoop().RunUntilIdle(); + } + + mojo::Receiver<device::mojom::BatteryMonitor> receiver_{this}; + + // If false, then GetBatteryMonitor will not return a monitor. + enum class RemoteType { + // Provide a connected remote. + kConnected, + // Provide an empty PendingRemote + kEmpty, + // Provide a PendingRemote to a disconnected remote. + kDisconnected + }; + RemoteType remote_type_ = RemoteType::kConnected; + + // Most recently provided callback. + QueryNextStatusCallback callback_; + }; + + void SetUp() override { + helper_ = std::make_unique<PowerStatusHelper>(monitor_.cb()); + } + + // Set up |helper_| to be in a state that should record. Returns the bucket. + // |alternate| just causes us to create a different recordable bucket. + int MakeRecordable(bool alternate = false) { + helper_->SetIsPlaying(true); + media::PipelineMetadata metadata; + metadata.has_video = true; + metadata.video_decoder_config = media::VideoDecoderConfig( + media::kCodecH264, media::H264PROFILE_MAIN, + media::VideoDecoderConfig::AlphaMode::kIsOpaque, + media::VideoColorSpace(), media::VideoTransformation(), + gfx::Size(0, 0), /* coded_size */ + gfx::Rect(0, 0), /* visible rect */ + gfx::Size(640, 360), /* natural size */ + std::vector<uint8_t>(), /* extra_data */ + media::EncryptionScheme::kUnencrypted); + helper_->SetMetadata(metadata); + helper_->SetAverageFrameRate(60); + // Use |alternate| to set fullscreen state, since that should still be + // recordable but in a different bucket. + helper_->SetIsFullscreen(alternate); + base::RunLoop().RunUntilIdle(); + helper_->UpdatePowerExperimentState(true); + base::RunLoop().RunUntilIdle(); + + return PowerStatusHelper::kCodecBitsH264 | + PowerStatusHelper::kResolution360p | + PowerStatusHelper::kFrameRate60 | + (alternate ? PowerStatusHelper::kFullScreenYes + : PowerStatusHelper::kFullScreenNo); + } + + void FastForward(base::TimeDelta delta) { + BlinkPlatformWithTaskEnvironment::GetTaskEnvironment()->FastForwardBy( + delta); + } + + // Verify that we've added |battery_delta| and |time_delta| to |bucket| in + // both histograms. + void VerifyHistogramDelta(int bucket, + int battery_delta, + base::TimeDelta time_delta) { + // Since histograms are cumulative, include the new counts. + total_battery_delta += battery_delta; + total_time_delta += time_delta.InMilliseconds(); + histogram_tester_.ExpectBucketCount(helper_->BatteryDeltaHistogram(), + bucket, total_battery_delta); + histogram_tester_.ExpectBucketCount(helper_->ElapsedTimeHistogram(), bucket, + total_time_delta); + } + + // Previous total histogram counts. Note that we record the total in msec, + // rather than as a TimeDelta, so that we round the same way as the helper. + int total_battery_delta = 0; + int total_time_delta = 0; // msec + + MockBatteryMonitor monitor_; + + // Helper under test + std::unique_ptr<PowerStatusHelper> helper_; + + base::HistogramTester histogram_tester_; +}; + +TEST_F(PowerStatusHelperTest, EmptyPendingRemoteIsOkay) { + // Enable power monitoring, but have the callback fail to provide a remote. + // This should be handled gracefully. + + // Ask |monitor_| not to provide a remote, and expect that |helper_| asks. + monitor_.remote_type_ = MockBatteryMonitor::RemoteType::kEmpty; + EXPECT_CALL(monitor_, DidGetBatteryMonitor()).Times(1); + MakeRecordable(); +} + +TEST_F(PowerStatusHelperTest, UnboundPendingRemoteIsOkay) { + // TODO: this doesn't run the "is bound" part. maybe we should just delete + // the "is bound" part, or switch to a disconnection handler, etc. + monitor_.remote_type_ = MockBatteryMonitor::RemoteType::kDisconnected; + EXPECT_CALL(monitor_, DidGetBatteryMonitor()).Times(1); + MakeRecordable(); +} + +TEST_F(PowerStatusHelperTest, BasicReportingWithFractionalAmounts) { + // Send three power updates, and verify that an update is called for the + // last two. The update should be fractional, so that some of it is rolled + // over to the next call. + EXPECT_CALL(monitor_, DidGetBatteryMonitor()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + const int bucket = MakeRecordable(); + + const float baseline_level = 0.9; + // Will round to 10%. + const float second_level = baseline_level - 0.106; + // Will round to 11% (plus a little). + const float third_level = second_level - 0.106; + + // This should be the baseline. + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, baseline_level); + + // This should trigger recording. + base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1); + FastForward(time_delta); + + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, second_level); + VerifyHistogramDelta(bucket, 10, time_delta); + + // This should also record, and pick up the fractional percentage drop that + // wasn't included in the previous one. + FastForward(time_delta); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, third_level); + VerifyHistogramDelta(bucket, 11, time_delta); +} + +TEST_F(PowerStatusHelperTest, ChargingResetsBaseline) { + // Send some power updates, then send an update that's marked as 'charging'. + // Make sure that the baseline resets. + EXPECT_CALL(monitor_, DidGetBatteryMonitor()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + const int bucket = MakeRecordable(); + + const float fake_baseline_level = 0.95; + const float baseline_level = 0.9; + const float second_level = baseline_level - 0.10; + + // Send the fake baseline. + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, fake_baseline_level); + + // Send an update that's marked as charging. + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(true, second_level); + + // This should be the correct baseline. + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, baseline_level); + + // This should trigger recording. + base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1); + FastForward(time_delta); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, second_level); + VerifyHistogramDelta(bucket, 10, time_delta); +} + +TEST_F(PowerStatusHelperTest, ExperimentStateStopsRecording) { + // Verify that stopping the power experiment stops recording. + EXPECT_CALL(monitor_, DidGetBatteryMonitor()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + MakeRecordable(); + + EXPECT_CALL(monitor_, DidDisconnect()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(0); + helper_->UpdatePowerExperimentState(false); + base::RunLoop().RunUntilIdle(); + + // Call the callback to make sure nothing bad happens. It should be ignored, + // since it shouldn't use battery updates after the experiment stops. + monitor_.ProvidePowerUpdate(false, 1.0); +} + +TEST_F(PowerStatusHelperTest, ChangingBucketsWorks) { + // Switch buckets mid-recording, and make sure that we get a new bucket and + // use a new baseline. + EXPECT_CALL(monitor_, DidGetBatteryMonitor()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + auto first_bucket = MakeRecordable(false); + + const float fake_baseline_level = 0.95; + const float baseline_level = 0.9; + const float second_level = baseline_level - 0.10; + + // Send the fake baseline. + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, fake_baseline_level); + + // Switch buckets. + auto second_bucket = MakeRecordable(true); + ASSERT_NE(first_bucket, second_bucket); + + // This should be the correct baseline. + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, baseline_level); + + // This should trigger recording. + base::TimeDelta time_delta = base::TimeDelta::FromSeconds(1); + FastForward(time_delta); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + monitor_.ProvidePowerUpdate(false, second_level); + VerifyHistogramDelta(second_bucket, 10, time_delta); +} + +TEST_F(PowerStatusHelperTest, UnbucketedVideoStopsRecording) { + // If we switch to video that doesn't have a bucket, then recording should + // stop too. + EXPECT_CALL(monitor_, DidGetBatteryMonitor()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + MakeRecordable(); + + // Should disconnect when we send bad params. + EXPECT_CALL(monitor_, DidDisconnect()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(0); + helper_->SetIsPlaying(false); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(PowerStatusHelperTest, UnbucketedFrameRateStopsRecording) { + // If we switch to an unbucketed frame rate, then it should stop recording. + EXPECT_CALL(monitor_, DidGetBatteryMonitor()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(1); + MakeRecordable(); + + // Should disconnect when we send bad params. + EXPECT_CALL(monitor_, DidDisconnect()).Times(1); + EXPECT_CALL(monitor_, DidQueryNextStatus()).Times(0); + helper_->SetAverageFrameRate({}); + base::RunLoop().RunUntilIdle(); +} + +using PlaybackParamsTuple = std::tuple<bool, /* is_playing */ + bool, /* has_video */ + PowerStatusHelper::Bits, /* codec */ + PowerStatusHelper::Bits, /* resolution */ + PowerStatusHelper::Bits, /* frame rate */ + PowerStatusHelper::Bits /* full screen */ + >; + +class PowerStatusHelperBucketTest + : public testing::TestWithParam<PlaybackParamsTuple> { + public: + absl::optional<int> BucketFor(bool is_playing, + bool has_video, + media::VideoCodec codec, + media::VideoCodecProfile profile, + gfx::Size coded_size, + bool is_fullscreen, + absl::optional<int> average_fps) { + return PowerStatusHelper::BucketFor(is_playing, has_video, codec, profile, + coded_size, is_fullscreen, average_fps); + } +}; + +TEST_P(PowerStatusHelperBucketTest, TestBucket) { + // Construct a params that should end up in the bucket specified by the test + // parameter, if one exists. + bool expect_bucket = true; + + bool is_playing = std::get<0>(GetParam()); + bool has_video = std::get<1>(GetParam()); + + // We must be playing video to get a bucket. + if (!is_playing || !has_video) + expect_bucket = false; + + auto codec_bits = std::get<2>(GetParam()); + media::VideoCodec codec; + media::VideoCodecProfile profile; + if (codec_bits == PowerStatusHelper::Bits::kCodecBitsH264) { + codec = media::kCodecH264; + profile = media::H264PROFILE_MAIN; + } else if (codec_bits == PowerStatusHelper::Bits::kCodecBitsVP9Profile0) { + codec = media::kCodecVP9; + profile = media::VP9PROFILE_PROFILE0; + } else if (codec_bits == PowerStatusHelper::Bits::kCodecBitsVP9Profile2) { + codec = media::kCodecVP9; + profile = media::VP9PROFILE_PROFILE2; + } else { + // Some unsupported codec. + codec = media::kCodecVP8; + profile = media::VIDEO_CODEC_PROFILE_UNKNOWN; + expect_bucket = false; + } + + auto res = std::get<3>(GetParam()); + gfx::Size coded_size; + if (res == PowerStatusHelper::Bits::kResolution360p) { + coded_size = gfx::Size(640, 360); + } else if (res == PowerStatusHelper::Bits::kResolution720p) { + coded_size = gfx::Size(1280, 720); + } else if (res == PowerStatusHelper::Bits::kResolution1080p) { + coded_size = gfx::Size(1920, 1080); + } else { + coded_size = gfx::Size(1234, 5678); + expect_bucket = false; + } + + auto fps = std::get<4>(GetParam()); + absl::optional<int> average_fps; + if (fps == PowerStatusHelper::Bits::kFrameRate30) { + average_fps = 30; + } else if (fps == PowerStatusHelper::Bits::kFrameRate60) { + average_fps = 60; + } else { + average_fps = 90; + expect_bucket = false; + } + + bool is_fullscreen = + (std::get<5>(GetParam()) == PowerStatusHelper::Bits::kFullScreenYes); + + auto bucket = BucketFor(is_playing, has_video, codec, profile, coded_size, + is_fullscreen, average_fps); + if (!expect_bucket) { + EXPECT_FALSE(bucket); + } else { + EXPECT_EQ(*bucket, std::get<2>(GetParam()) | std::get<3>(GetParam()) | + std::get<4>(GetParam()) | std::get<5>(GetParam())); + } +} + +// Instantiate all valid combinations, plus some that aren't. +INSTANTIATE_TEST_SUITE_P( + All, + PowerStatusHelperBucketTest, + Combine(Bool(), + Bool(), + Values(PowerStatusHelper::Bits::kCodecBitsH264, + PowerStatusHelper::Bits::kCodecBitsVP9Profile0, + PowerStatusHelper::Bits::kCodecBitsVP9Profile2, + PowerStatusHelper::Bits::kNotAValidBitForTesting), + Values(PowerStatusHelper::Bits::kResolution360p, + PowerStatusHelper::Bits::kResolution720p, + PowerStatusHelper::Bits::kResolution1080p, + PowerStatusHelper::Bits::kNotAValidBitForTesting), + Values(PowerStatusHelper::Bits::kFrameRate30, + PowerStatusHelper::Bits::kFrameRate60, + PowerStatusHelper::Bits::kNotAValidBitForTesting), + Values(PowerStatusHelper::Bits::kFullScreenNo, + PowerStatusHelper::Bits::kFullScreenYes))); + +} // namespace media diff --git a/chromium/media/blink/resource_fetch_context.h b/chromium/media/blink/resource_fetch_context.h index e517811384d..588347c7760 100644 --- a/chromium/media/blink/resource_fetch_context.h +++ b/chromium/media/blink/resource_fetch_context.h @@ -8,7 +8,6 @@ #include <memory> #include "media/blink/media_blink_export.h" -#include "services/network/public/mojom/referrer_policy.mojom.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/web/web_associated_url_loader.h" #include "third_party/blink/public/web/web_associated_url_loader_options.h" diff --git a/chromium/media/blink/resource_multibuffer_data_provider.cc b/chromium/media/blink/resource_multibuffer_data_provider.cc index 3b9795f8d1a..3b369c0d924 100644 --- a/chromium/media/blink/resource_multibuffer_data_provider.cc +++ b/chromium/media/blink/resource_multibuffer_data_provider.cc @@ -17,7 +17,6 @@ #include "base/strings/string_util.h" #include "base/threading/thread_task_runner_handle.h" #include "media/blink/cache_util.h" -#include "media/blink/media_blink_export.h" #include "media/blink/resource_fetch_context.h" #include "media/blink/url_index.h" #include "net/http/http_byte_range.h" @@ -564,7 +563,7 @@ bool ResourceMultiBufferDataProvider::VerifyPartialResponse( return false; } - if (url_data_->length() == kPositionNotSpecified) { + if (url_data->length() == kPositionNotSpecified) { url_data->set_length(instance_size); } diff --git a/chromium/media/blink/resource_multibuffer_data_provider_unittest.cc b/chromium/media/blink/resource_multibuffer_data_provider_unittest.cc index 2a2958d0231..56df066b396 100644 --- a/chromium/media/blink/resource_multibuffer_data_provider_unittest.cc +++ b/chromium/media/blink/resource_multibuffer_data_provider_unittest.cc @@ -325,6 +325,16 @@ TEST_F(ResourceMultiBufferDataProviderTest, TestRedirects) { StopWhenLoad(); } +// Tests partial response after a redirect. +TEST_F(ResourceMultiBufferDataProviderTest, TestRedirectedPartialResponse) { + Initialize(kHttpUrl, 0); + Start(); + PartialResponse(0, 2048, 32000); + Redirect(kHttpRedirect); + PartialResponse(2048, 4096, 32000); + StopWhenLoad(); +} + TEST_F(ResourceMultiBufferDataProviderTest, TestSaveDataFRFRPreviewsState) { struct TestCase { std::string label; diff --git a/chromium/media/blink/smoothness_helper.cc b/chromium/media/blink/smoothness_helper.cc index 267697d4e5c..5c8e7b8e378 100644 --- a/chromium/media/blink/smoothness_helper.cc +++ b/chromium/media/blink/smoothness_helper.cc @@ -5,10 +5,10 @@ #include "media/blink/smoothness_helper.h" #include "base/bind.h" -#include "base/optional.h" #include "base/timer/timer.h" #include "base/unguessable_token.h" #include "media/learning/common/learning_task_controller.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace { static constexpr base::TimeDelta kSegmentSize = @@ -191,7 +191,7 @@ class SmoothnessHelperImpl : public SmoothnessHelper { private: // If an observation is in progress, then this is the id. - base::Optional<base::UnguessableToken> id_; + absl::optional<base::UnguessableToken> id_; std::unique_ptr<LearningTaskController> controller_; TargetValue target_value_; @@ -207,7 +207,7 @@ class SmoothnessHelperImpl : public SmoothnessHelper { struct Task consecutive_nnr_; // Time of the most recent nnr. - base::Optional<base::TimeTicks> most_recent_nnr_; + absl::optional<base::TimeTicks> most_recent_nnr_; // Number of NNRs that have occurred within |kMaxNNRDistance|. int num_consecutive_nnrs_ = 0; diff --git a/chromium/media/blink/smoothness_helper_unittest.cc b/chromium/media/blink/smoothness_helper_unittest.cc index 2162f5952f6..d706573e41c 100644 --- a/chromium/media/blink/smoothness_helper_unittest.cc +++ b/chromium/media/blink/smoothness_helper_unittest.cc @@ -30,11 +30,11 @@ using testing::Return; // Helper for EXPECT_CALL argument matching on Optional<TargetValue>. Applies // matcher |m| to the TargetValue as a double. For example: -// void Foo(base::Optional<TargetValue>); +// void Foo(absl::optional<TargetValue>); // EXPECT_CALL(..., Foo(OPT_TARGET(Gt(0.9)))) will expect that the value of the // Optional<TargetValue> passed to Foo() to be greather than 0.9 . #define OPT_TARGET(m) \ - ResultOf([](const base::Optional<TargetValue>& v) { return (*v).value(); }, m) + ResultOf([](const absl::optional<TargetValue>& v) { return (*v).value(); }, m) // Same as above, but expects an ObservationCompletion. #define COMPLETION_TARGET(m) \ @@ -48,8 +48,8 @@ class SmoothnessHelperTest : public testing::Test { MOCK_METHOD4(BeginObservation, void(base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target, - const base::Optional<ukm::SourceId>& source_id)); + const absl::optional<TargetValue>& default_target, + const absl::optional<ukm::SourceId>& source_id)); MOCK_METHOD2(CompleteObservation, void(base::UnguessableToken id, @@ -59,7 +59,7 @@ class SmoothnessHelperTest : public testing::Test { MOCK_METHOD2(UpdateDefaultTarget, void(base::UnguessableToken id, - const base::Optional<TargetValue>& default_target)); + const absl::optional<TargetValue>& default_target)); MOCK_METHOD0(GetLearningTask, const LearningTask&()); MOCK_METHOD2(PredictDistribution, @@ -87,8 +87,8 @@ class SmoothnessHelperTest : public testing::Test { } // Helper for EXPECT_CALL. - base::Optional<TargetValue> Opt(double x) { - return base::Optional<TargetValue>(TargetValue(x)); + absl::optional<TargetValue> Opt(double x) { + return absl::optional<TargetValue>(TargetValue(x)); } void FastForwardBy(base::TimeDelta amount) { diff --git a/chromium/media/blink/url_index.cc b/chromium/media/blink/url_index.cc index 701a0977457..af704d17757 100644 --- a/chromium/media/blink/url_index.cc +++ b/chromium/media/blink/url_index.cc @@ -59,12 +59,12 @@ UrlData::UrlData(const GURL& url, CorsMode cors_mode, UrlIndex* url_index) UrlData::~UrlData() = default; std::pair<GURL, UrlData::CorsMode> UrlData::key() const { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); return std::make_pair(url(), cors_mode()); } void UrlData::set_valid_until(base::Time valid_until) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); valid_until_ = valid_until; } @@ -73,7 +73,7 @@ void UrlData::MergeFrom(const scoped_refptr<UrlData>& other) { // resource, so when we merge the metadata, we can use the most // optimistic values. if (ValidateDataOrigin(other->data_origin_)) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); valid_until_ = std::max(valid_until_, other->valid_until_); // set_length() will not override the length if already known. set_length(other->length_); @@ -91,12 +91,12 @@ void UrlData::MergeFrom(const scoped_refptr<UrlData>& other) { } void UrlData::set_cacheable(bool cacheable) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); cacheable_ = cacheable; } void UrlData::set_length(int64_t length) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (length != kPositionNotSpecified) { length_ = length; } @@ -113,7 +113,7 @@ void UrlData::set_has_access_control() { } void UrlData::RedirectTo(const scoped_refptr<UrlData>& url_data) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Copy any cached data over to the new location. url_data->multibuffer()->MergeFrom(multibuffer()); @@ -125,7 +125,7 @@ void UrlData::RedirectTo(const scoped_refptr<UrlData>& url_data) { } void UrlData::Fail() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Handled similar to a redirect. std::vector<RedirectCB> redirect_callbacks; redirect_callbacks.swap(redirect_callbacks_); @@ -135,12 +135,12 @@ void UrlData::Fail() { } void UrlData::OnRedirect(RedirectCB cb) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); redirect_callbacks_.push_back(std::move(cb)); } void UrlData::Use() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); last_used_ = base::Time::Now(); } @@ -158,12 +158,12 @@ bool UrlData::ValidateDataOrigin(const GURL& origin) { } void UrlData::OnEmpty() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); url_index_->RemoveUrlData(this); } bool UrlData::FullyCached() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (length_ == kPositionNotSpecified) return false; // Check that the first unavailable block in the cache is after the @@ -172,7 +172,7 @@ bool UrlData::FullyCached() { } bool UrlData::Valid() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); base::Time now = base::Time::Now(); if (!range_supported_ && !FullyCached()) return false; @@ -186,27 +186,27 @@ bool UrlData::Valid() { } void UrlData::set_last_modified(base::Time last_modified) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); last_modified_ = last_modified; } void UrlData::set_etag(const std::string& etag) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); etag_ = etag; } void UrlData::set_range_supported() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); range_supported_ = true; } ResourceMultiBuffer* UrlData::multibuffer() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); return &multibuffer_; } size_t UrlData::CachedSize() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); return multibuffer()->map().size(); } diff --git a/chromium/media/blink/url_index.h b/chromium/media/blink/url_index.h index 80eef9a7e8a..88c595fc93d 100644 --- a/chromium/media/blink/url_index.h +++ b/chromium/media/blink/url_index.h @@ -16,10 +16,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" -#include "media/blink/lru.h" #include "media/blink/media_blink_export.h" #include "media/blink/multibuffer.h" -#include "services/network/public/mojom/fetch_api.mojom.h" #include "url/gurl.h" namespace media { @@ -216,7 +214,8 @@ class MEDIA_BLINK_EXPORT UrlData : public base::RefCounted<UrlData> { ResourceMultiBuffer multibuffer_; std::vector<RedirectCB> redirect_callbacks_; - base::ThreadChecker thread_checker_; + THREAD_CHECKER(thread_checker_); + DISALLOW_COPY_AND_ASSIGN(UrlData); }; diff --git a/chromium/media/blink/url_index_unittest.cc b/chromium/media/blink/url_index_unittest.cc index 0f3bcfa16fd..3933710f132 100644 --- a/chromium/media/blink/url_index_unittest.cc +++ b/chromium/media/blink/url_index_unittest.cc @@ -9,7 +9,6 @@ #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "media/base/media_switches.h" #include "media/blink/url_index.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chromium/media/blink/video_decode_stats_reporter.cc b/chromium/media/blink/video_decode_stats_reporter.cc index e78848d28c7..ba9d1f853f5 100644 --- a/chromium/media/blink/video_decode_stats_reporter.cc +++ b/chromium/media/blink/video_decode_stats_reporter.cc @@ -21,7 +21,7 @@ VideoDecodeStatsReporter::VideoDecodeStatsReporter( VideoCodecProfile codec_profile, const gfx::Size& natural_size, std::string key_system, - base::Optional<CdmConfig> cdm_config, + absl::optional<CdmConfig> cdm_config, scoped_refptr<base::SingleThreadTaskRunner> task_runner, const base::TickClock* tick_clock) : kRecordingInterval( diff --git a/chromium/media/blink/video_decode_stats_reporter.h b/chromium/media/blink/video_decode_stats_reporter.h index e430e7dda4b..cd641deb074 100644 --- a/chromium/media/blink/video_decode_stats_reporter.h +++ b/chromium/media/blink/video_decode_stats_reporter.h @@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "base/time/default_tick_clock.h" #include "base/time/tick_clock.h" @@ -23,6 +22,8 @@ #include "media/mojo/mojom/video_decode_stats_recorder.mojom.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/gfx/geometry/size.h" namespace media { @@ -40,7 +41,7 @@ class MEDIA_BLINK_EXPORT VideoDecodeStatsReporter { VideoCodecProfile codec_profile, const gfx::Size& natural_size, std::string key_system, - base::Optional<CdmConfig> cdm_config, + absl::optional<CdmConfig> cdm_config, scoped_refptr<base::SingleThreadTaskRunner> task_runner, const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance()); diff --git a/chromium/media/blink/video_decode_stats_reporter_unittest.cc b/chromium/media/blink/video_decode_stats_reporter_unittest.cc index 96a8f1e6a2d..4661354b5b0 100644 --- a/chromium/media/blink/video_decode_stats_reporter_unittest.cc +++ b/chromium/media/blink/video_decode_stats_reporter_unittest.cc @@ -7,7 +7,6 @@ #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "base/task/current_thread.h" #include "base/test/test_mock_time_task_runner.h" @@ -25,6 +24,7 @@ #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" using ::testing::Invoke; @@ -186,7 +186,7 @@ class VideoDecodeStatsReporterTest : public ::testing::Test { VideoCodecProfile profile = kDefaultProfile, const gfx::Size& natural_size = gfx::Size(kDefaultWidth, kDefaultHeight), const std::string key_system = kDefaultKeySystem, - const base::Optional<CdmConfig> cdm_config = kDefaultCdmConfig) { + const absl::optional<CdmConfig> cdm_config = kDefaultCdmConfig) { reporter_ = std::make_unique<VideoDecodeStatsReporter>( SetupRecordInterceptor(&interceptor_), base::BindRepeating(&VideoDecodeStatsReporterTest::GetPipelineStatsCB, @@ -875,7 +875,7 @@ TEST_F(VideoDecodeStatsReporterTest, VaryEmeProperties) { const char kFooKeySystem[] = "fookeysytem"; // Make reporter with no EME properties. - MakeReporter(kDefaultProfile, kDefaultSize, kEmptyKeySystem, base::nullopt); + MakeReporter(kDefaultProfile, kDefaultSize, kEmptyKeySystem, absl::nullopt); // Verify the empty key system and non-default hw_secure_codecs. StartPlayingAndStabilizeFramerate(kDefaultProfile, kDefaultSize, kDefaultFps, kEmptyKeySystem, kNonDefaultHwSecureCodecs); diff --git a/chromium/media/blink/video_frame_compositor.cc b/chromium/media/blink/video_frame_compositor.cc index 344d3c4a483..16e48bf22b0 100644 --- a/chromium/media/blink/video_frame_compositor.cc +++ b/chromium/media/blink/video_frame_compositor.cc @@ -15,7 +15,6 @@ #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "media/base/media_switches.h" #include "media/base/video_frame.h" -#include "media/blink/webmediaplayer_params.h" #include "third_party/blink/public/platform/web_video_frame_submitter.h" namespace media { diff --git a/chromium/media/blink/video_frame_compositor.h b/chromium/media/blink/video_frame_compositor.h index 8ee417924fe..2c7c535d558 100644 --- a/chromium/media/blink/video_frame_compositor.h +++ b/chromium/media/blink/video_frame_compositor.h @@ -21,9 +21,8 @@ #include "cc/layers/video_frame_provider.h" #include "media/base/video_renderer_sink.h" #include "media/blink/media_blink_export.h" -#include "media/blink/webmediaplayer_params.h" +#include "third_party/blink/public/platform/web_media_player.h" #include "third_party/blink/public/platform/web_video_frame_submitter.h" -#include "ui/gfx/geometry/size.h" namespace base { class WaitableEvent; diff --git a/chromium/media/blink/video_frame_compositor_unittest.cc b/chromium/media/blink/video_frame_compositor_unittest.cc index cd8ef477441..e1491b2d8ab 100644 --- a/chromium/media/blink/video_frame_compositor_unittest.cc +++ b/chromium/media/blink/video_frame_compositor_unittest.cc @@ -6,8 +6,10 @@ #include "base/bind.h" #include "base/macros.h" #include "base/run_loop.h" +#include "base/synchronization/waitable_event.h" #include "base/test/gmock_callback_support.h" #include "base/test/simple_test_tick_clock.h" +#include "base/threading/thread_task_runner_handle.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "media/base/video_frame.h" diff --git a/chromium/media/blink/webcontentdecryptionmodulesession_impl.cc b/chromium/media/blink/webcontentdecryptionmodulesession_impl.cc index 64e17e577eb..0be92465c3e 100644 --- a/chromium/media/blink/webcontentdecryptionmodulesession_impl.cc +++ b/chromium/media/blink/webcontentdecryptionmodulesession_impl.cc @@ -233,7 +233,7 @@ WebContentDecryptionModuleSessionImpl::WebContentDecryptionModuleSessionImpl( WebContentDecryptionModuleSessionImpl:: ~WebContentDecryptionModuleSessionImpl() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (!session_id_.empty()) { adapter_->UnregisterSession(session_id_); @@ -271,7 +271,7 @@ void WebContentDecryptionModuleSessionImpl::InitializeNewSession( blink::WebContentDecryptionModuleResult result) { DCHECK(init_data); DCHECK(session_id_.empty()); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // From https://w3c.github.io/encrypted-media/#generateRequest. // 6. If the Key System implementation represented by this object's cdm @@ -347,7 +347,7 @@ void WebContentDecryptionModuleSessionImpl::Load( blink::WebContentDecryptionModuleResult result) { DCHECK(!session_id.IsEmpty()); DCHECK(session_id_.empty()); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(session_type_ == CdmSessionType::kPersistentLicense); // From https://w3c.github.io/encrypted-media/#load. @@ -382,7 +382,7 @@ void WebContentDecryptionModuleSessionImpl::Update( blink::WebContentDecryptionModuleResult result) { DCHECK(response); DCHECK(!session_id_.empty()); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // From https://w3c.github.io/encrypted-media/#update. // 6.1 Let sanitized response be a validated and/or sanitized version of @@ -412,7 +412,7 @@ void WebContentDecryptionModuleSessionImpl::Update( void WebContentDecryptionModuleSessionImpl::Close( blink::WebContentDecryptionModuleResult result) { DCHECK(!session_id_.empty()); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // close() shouldn't be called if the session is already closed. Since the // operation is asynchronous, there is a window where close() was called @@ -434,7 +434,7 @@ void WebContentDecryptionModuleSessionImpl::Close( void WebContentDecryptionModuleSessionImpl::Remove( blink::WebContentDecryptionModuleResult result) { DCHECK(!session_id_.empty()); - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); adapter_->RemoveSession( session_id_, @@ -446,7 +446,7 @@ void WebContentDecryptionModuleSessionImpl::OnSessionMessage( CdmMessageType message_type, const std::vector<uint8_t>& message) { DCHECK(client_) << "Client not set before message event"; - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); client_->OnSessionMessage(convertMessageType(message_type), message.data(), message.size()); } @@ -454,7 +454,7 @@ void WebContentDecryptionModuleSessionImpl::OnSessionMessage( void WebContentDecryptionModuleSessionImpl::OnSessionKeysChange( bool has_additional_usable_key, CdmKeysInfo keys_info) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); blink::WebVector<blink::WebEncryptedMediaKeyInformation> keys( keys_info.size()); for (size_t i = 0; i < keys_info.size(); ++i) { @@ -475,7 +475,7 @@ void WebContentDecryptionModuleSessionImpl::OnSessionKeysChange( void WebContentDecryptionModuleSessionImpl::OnSessionExpirationUpdate( base::Time new_expiry_time) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // The check works around an issue in base::Time that converts null base::Time // to |1601-01-01 00:00:00 UTC| in ToJsTime(). See http://crbug.com/679079 client_->OnSessionExpirationUpdate( @@ -484,7 +484,7 @@ void WebContentDecryptionModuleSessionImpl::OnSessionExpirationUpdate( } void WebContentDecryptionModuleSessionImpl::OnSessionClosed() { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Only send one closed event to blink. if (is_closed_) @@ -497,7 +497,7 @@ void WebContentDecryptionModuleSessionImpl::OnSessionClosed() { void WebContentDecryptionModuleSessionImpl::OnSessionInitialized( const std::string& session_id, SessionInitStatus* status) { - DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // CDM will return NULL if the session to be loaded can't be found. if (session_id.empty()) { *status = SessionInitStatus::SESSION_NOT_FOUND; diff --git a/chromium/media/blink/webcontentdecryptionmodulesession_impl.h b/chromium/media/blink/webcontentdecryptionmodulesession_impl.h index b6c4572e96f..2bdb47aca03 100644 --- a/chromium/media/blink/webcontentdecryptionmodulesession_impl.h +++ b/chromium/media/blink/webcontentdecryptionmodulesession_impl.h @@ -88,7 +88,8 @@ class WebContentDecryptionModuleSessionImpl bool has_close_been_called_; bool is_closed_; - base::ThreadChecker thread_checker_; + THREAD_CHECKER(thread_checker_); + // Since promises will live until they are fired, use a weak reference when // creating a promise in case this class disappears before the promise // actually fires. diff --git a/chromium/media/blink/webencryptedmediaclient_impl.cc b/chromium/media/blink/webencryptedmediaclient_impl.cc index 9460a70ff04..125f22d3c48 100644 --- a/chromium/media/blink/webencryptedmediaclient_impl.cc +++ b/chromium/media/blink/webencryptedmediaclient_impl.cc @@ -15,14 +15,11 @@ #include "media/base/media_permission.h" #include "media/blink/webcontentdecryptionmodule_impl.h" #include "media/blink/webcontentdecryptionmoduleaccess_impl.h" -#include "third_party/blink/public/platform/url_conversion.h" #include "third_party/blink/public/platform/web_content_decryption_module_result.h" #include "third_party/blink/public/platform/web_encrypted_media_request.h" #include "third_party/blink/public/platform/web_media_key_system_configuration.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/public/platform/web_string.h" -#include "url/gurl.h" -#include "url/origin.h" namespace media { diff --git a/chromium/media/blink/webmediaplayer_impl.cc b/chromium/media/blink/webmediaplayer_impl.cc index 8fe58a83c76..ce5762369f3 100644 --- a/chromium/media/blink/webmediaplayer_impl.cc +++ b/chromium/media/blink/webmediaplayer_impl.cc @@ -23,6 +23,7 @@ #include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/task/post_task.h" #include "base/task/thread_pool.h" #include "base/task_runner_util.h" @@ -31,6 +32,7 @@ #include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "cc/layers/video_layer.h" +#include "components/viz/common/gpu/raster_context_provider.h" #include "media/audio/null_audio_sink.h" #include "media/base/bind_to_current_loop.h" #include "media/base/cdm_context.h" @@ -44,6 +46,7 @@ #include "media/base/text_renderer.h" #include "media/base/timestamp_constants.h" #include "media/base/video_frame.h" +#include "media/blink/power_status_helper.h" #include "media/blink/texttrack_impl.h" #include "media/blink/url_index.h" #include "media/blink/video_decode_stats_reporter.h" @@ -53,11 +56,15 @@ #include "media/filters/chunk_demuxer.h" #include "media/filters/ffmpeg_demuxer.h" #include "media/filters/memory_data_source.h" +#include "media/filters/pipeline_controller.h" +#include "media/learning/common/learning_task_controller.h" +#include "media/learning/common/media_learning_tasks.h" #include "media/learning/mojo/public/cpp/mojo_learning_task_controller.h" #include "media/media_buildflags.h" #include "media/remoting/remoting_constants.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "net/base/data_url.h" +#include "third_party/blink/public/common/media/display_type.h" #include "third_party/blink/public/common/media/watch_time_reporter.h" #include "third_party/blink/public/platform/web_encrypted_media_types.h" #include "third_party/blink/public/platform/web_fullscreen_video_status.h" @@ -78,6 +85,7 @@ #include "third_party/blink/public/web/web_frame.h" #include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/public/web/web_view.h" +#include "ui/gfx/geometry/size.h" #if defined(OS_ANDROID) #include "media/base/android/media_codec_util.h" @@ -97,7 +105,7 @@ namespace { const char kWatchTimeHistogram[] = "Media.WebMediaPlayerImpl.WatchTime"; -void RecordSimpleWatchTimeUMA(RendererFactoryType type) { +void RecordSimpleWatchTimeUMA(RendererType type) { UMA_HISTOGRAM_ENUMERATION(kWatchTimeHistogram, type); } @@ -1037,7 +1045,7 @@ void WebMediaPlayerImpl::SetVolume(double volume) { void WebMediaPlayerImpl::SetLatencyHint(double seconds) { DVLOG(1) << __func__ << "(" << seconds << ")"; DCHECK(main_task_runner_->BelongsToCurrentThread()); - base::Optional<base::TimeDelta> latency_hint; + absl::optional<base::TimeDelta> latency_hint; if (std::isfinite(seconds)) { DCHECK_GE(seconds, 0); latency_hint = base::TimeDelta::FromSecondsD(seconds); @@ -1124,7 +1132,7 @@ void WebMediaPlayerImpl::SelectedVideoTrackChanged( blink::WebMediaPlayer::TrackId* selectedTrackId) { DCHECK(main_task_runner_->BelongsToCurrentThread()); - base::Optional<MediaTrack::Id> selected_video_track_id; + absl::optional<MediaTrack::Id> selected_video_track_id; if (selectedTrackId && !video_track_disabled_) selected_video_track_id = MediaTrack::Id(selectedTrackId->Utf8().data()); MEDIA_LOG(INFO, media_log_.get()) @@ -1791,8 +1799,7 @@ void WebMediaPlayerImpl::OnError(PipelineStatus status) { "Media.WebMediaPlayerImpl.HLS.IsMixedContent", frame_url_is_cryptographic && !manifest_url_is_cryptographic); - renderer_factory_selector_->SetBaseFactoryType( - RendererFactoryType::kMediaPlayer); + renderer_factory_selector_->SetBaseRendererType(RendererType::kMediaPlayer); loaded_url_ = mb_data_source_->GetUrlAfterRedirects(); DCHECK(data_source_); @@ -2342,7 +2349,7 @@ void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) { bridge_->SetContentsOpaque(opaque_); } -void WebMediaPlayerImpl::OnVideoFrameRateChange(base::Optional<int> fps) { +void WebMediaPlayerImpl::OnVideoFrameRateChange(absl::optional<int> fps) { DCHECK(main_task_runner_->BelongsToCurrentThread()); if (power_status_helper_) power_status_helper_->SetAverageFrameRate(fps); @@ -2717,7 +2724,7 @@ void WebMediaPlayerImpl::MaybeSendOverlayInfoToDecoder() { } std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer( - base::Optional<RendererFactoryType> factory_type) { + absl::optional<RendererType> renderer_type) { DCHECK(main_task_runner_->BelongsToCurrentThread()); // Make sure that overlays are enabled if they're always allowed. @@ -2730,13 +2737,14 @@ std::unique_ptr<Renderer> WebMediaPlayerImpl::CreateRenderer( &WebMediaPlayerImpl::OnOverlayInfoRequested, weak_this_)); #endif - if (factory_type) { + if (renderer_type) { DVLOG(1) << __func__ - << ": factory_type=" << static_cast<int>(factory_type.value()); - renderer_factory_selector_->SetBaseFactoryType(factory_type.value()); + << ": renderer_type=" << static_cast<int>(renderer_type.value()); + renderer_factory_selector_->SetBaseRendererType(renderer_type.value()); } - reported_renderer_type_ = renderer_factory_selector_->GetCurrentFactoryType(); + reported_renderer_type_ = + renderer_factory_selector_->GetCurrentRendererType(); return renderer_factory_selector_->GetCurrentFactory()->CreateRenderer( media_task_runner_, worker_task_runner_, audio_source_provider_.get(), @@ -3077,7 +3085,7 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_flinging, // TODO(sandersd): Make the delegate suspend idle players immediately when // hidden. bool idle_suspended = can_auto_suspend && is_stale && paused_ && !seeking_ && - !overlay_enabled_ && !needs_first_frame_; + !overlay_info_.is_fullscreen && !needs_first_frame_; // If we're already suspended, see if we can wait for user interaction. Prior // to kReadyStateHaveMetadata, we require |is_stale| to remain suspended. @@ -3299,7 +3307,7 @@ void WebMediaPlayerImpl::ScheduleIdlePauseTimer() { // Idle timeout chosen arbitrarily. background_pause_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), client_, - &blink::WebMediaPlayerClient::ResumePlayback); + &blink::WebMediaPlayerClient::PausePlayback); } void WebMediaPlayerImpl::CreateWatchTimeReporter() { @@ -3423,9 +3431,9 @@ int WebMediaPlayerImpl::GetDelegateId() { return delegate_id_; } -base::Optional<viz::SurfaceId> WebMediaPlayerImpl::GetSurfaceId() { +absl::optional<viz::SurfaceId> WebMediaPlayerImpl::GetSurfaceId() { if (!surface_layer_for_video_enabled_) - return base::nullopt; + return absl::nullopt; return bridge_->GetSurfaceId(); } @@ -3615,7 +3623,7 @@ void WebMediaPlayerImpl::DisableVideoTrackIfNeeded() { void WebMediaPlayerImpl::SetPipelineStatisticsForTest( const PipelineStatistics& stats) { - pipeline_statistics_for_test_ = base::make_optional(stats); + pipeline_statistics_for_test_ = absl::make_optional(stats); } PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const { @@ -3627,7 +3635,7 @@ PipelineStatistics WebMediaPlayerImpl::GetPipelineStatistics() const { void WebMediaPlayerImpl::SetPipelineMediaDurationForTest( base::TimeDelta duration) { - pipeline_media_duration_for_test_ = base::make_optional(duration); + pipeline_media_duration_for_test_ = absl::make_optional(duration); } base::TimeDelta WebMediaPlayerImpl::GetPipelineMediaDuration() const { diff --git a/chromium/media/blink/webmediaplayer_impl.h b/chromium/media/blink/webmediaplayer_impl.h index 7eb775c291c..3c1069fd557 100644 --- a/chromium/media/blink/webmediaplayer_impl.h +++ b/chromium/media/blink/webmediaplayer_impl.h @@ -17,15 +17,12 @@ #include "base/memory/memory_pressure_listener.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/threading/thread.h" #include "base/time/default_tick_clock.h" #include "base/time/time.h" #include "base/timer/elapsed_timer.h" #include "base/timer/timer.h" #include "build/build_config.h" -#include "cc/layers/surface_layer.h" -#include "components/viz/common/gpu/raster_context_provider.h" #include "media/base/cdm_config.h" #include "media/base/encryption_scheme.h" #include "media/base/media_observer.h" @@ -39,17 +36,14 @@ #include "media/blink/learning_experiment_helper.h" #include "media/blink/media_blink_export.h" #include "media/blink/multibuffer_data_source.h" -#include "media/blink/power_status_helper.h" #include "media/blink/smoothness_helper.h" #include "media/blink/video_frame_compositor.h" #include "media/blink/webmediaplayer_params.h" -#include "media/filters/pipeline_controller.h" -#include "media/learning/common/media_learning_tasks.h" #include "media/mojo/mojom/playback_events_recorder.mojom.h" #include "media/renderers/paint_canvas_video_renderer.h" #include "mojo/public/cpp/bindings/remote.h" #include "services/media_session/public/cpp/media_position.h" -#include "third_party/blink/public/common/media/display_type.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/platform/media/webmediaplayer_delegate.h" #include "third_party/blink/public/platform/web_audio_source_provider.h" #include "third_party/blink/public/platform/web_content_decryption_module_result.h" @@ -75,12 +69,26 @@ namespace cc { class VideoLayer; } +namespace gfx { +class Size; +} + +namespace learning { +class LearningTaskController; +} + +namespace viz { +class RasterContextProvider; +} + namespace media { class CdmContextRef; class ChunkDemuxer; class VideoDecodeStatsReporter; class MediaLog; class MemoryDumpProviderProxy; +class PipelineController; +class PowerStatusHelper; class UrlIndex; class VideoFrameCompositor; @@ -256,7 +264,7 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl void OnBecameVisible() override; bool IsOpaque() const override; int GetDelegateId() override; - base::Optional<viz::SurfaceId> GetSurfaceId() override; + absl::optional<viz::SurfaceId> GetSurfaceId() override; GURL GetSrcAfterRedirects() override; void RequestVideoFrameCallback() override; std::unique_ptr<blink::WebMediaPlayer::VideoFramePresentationMetadata> @@ -327,7 +335,7 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl void OnVideoConfigChange(const VideoDecoderConfig& config) override; void OnVideoNaturalSizeChange(const gfx::Size& size) override; void OnVideoOpacityChange(bool opaque) override; - void OnVideoFrameRateChange(base::Optional<int> fps) override; + void OnVideoFrameRateChange(absl::optional<int> fps) override; void OnVideoAverageKeyframeDistanceUpdate() override; void OnAudioDecoderChange(const AudioDecoderInfo& info) override; void OnVideoDecoderChange(const VideoDecoderInfo& info) override; @@ -364,10 +372,10 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl ProvideOverlayInfoCB provide_overlay_info_cb); // Creates a Renderer via the |renderer_factory_selector_|. If the - // |factory_type| is base::nullopt, create the base Renderer. Otherwise, set - // the base type to be |factory_type| and create a Renderer of that type. + // |renderer_type| is absl::nullopt, create the base Renderer. Otherwise, set + // the base type to be |renderer_type| and create a Renderer of that type. std::unique_ptr<Renderer> CreateRenderer( - base::Optional<RendererFactoryType> factory_type); + absl::optional<RendererType> renderer_type); // Finishes starting the pipeline due to a call to load(). void StartPipeline(); @@ -708,11 +716,12 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl // WebMediaPlayer may also receive directives (play, pause) from the delegate // via the WebMediaPlayerDelegate::Observer interface after registration. // - // NOTE: HTMLMediaElement is a Blink::PausableObject, and will receive a - // call to contextDestroyed() when Blink::Document::shutdown() is called. - // Document::shutdown() is called before the frame detaches (and before the - // frame is destroyed). RenderFrameImpl owns |delegate_| and is guaranteed - // to outlive |this|; thus it is safe to store |delegate_| as a raw pointer. + // NOTE: HTMLMediaElement is a blink::ExecutionContextLifecycleObserver, and + // will receive a call to contextDestroyed() when blink::Document::shutdown() + // is called. Document::shutdown() is called before the frame detaches (and + // before the frame is destroyed). RenderFrameImpl owns |delegate_| and is + // guaranteed to outlive |this|; thus it is safe to store |delegate_| as a raw + // pointer. blink::WebMediaPlayerDelegate* delegate_; int delegate_id_ = 0; @@ -783,7 +792,7 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl // Captured once the cdm is provided to SetCdmInternal(). Used in creation of // |video_decode_stats_reporter_|. - base::Optional<CdmConfig> cdm_config_; + absl::optional<CdmConfig> cdm_config_; // String identifying the KeySystem described by |cdm_config_|. Empty until a // CDM has been attached. Used in creation |video_decode_stats_reporter_|. @@ -917,10 +926,10 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl bool disable_pipeline_auto_suspend_ = false; // Pipeline statistics overridden by tests. - base::Optional<PipelineStatistics> pipeline_statistics_for_test_; + absl::optional<PipelineStatistics> pipeline_statistics_for_test_; // Pipeline media duration overridden by tests. - base::Optional<base::TimeDelta> pipeline_media_duration_for_test_; + absl::optional<base::TimeDelta> pipeline_media_duration_for_test_; // Whether the video requires a user gesture to resume after it was paused in // the background. Affects the value of ShouldPausePlaybackWhenHidden(). @@ -974,7 +983,7 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl mojo::Remote<mojom::MediaMetricsProvider> media_metrics_provider_; mojo::Remote<mojom::PlaybackEventsRecorder> playback_events_recorder_; - base::Optional<ReadyState> stale_state_override_for_testing_; + absl::optional<ReadyState> stale_state_override_for_testing_; // True if we attempt to start the media pipeline in a suspended state for // preload=metadata. Cleared upon pipeline startup. @@ -1006,7 +1015,7 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl base::CancelableOnceClosure have_enough_after_lazy_load_cb_; // State for simplified watch time reporting. - RendererFactoryType reported_renderer_type_ = RendererFactoryType::kDefault; + RendererType reported_renderer_type_ = RendererType::kDefault; SimpleWatchTimer simple_watch_timer_; LearningExperimentHelper will_play_helper_; @@ -1018,7 +1027,7 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl // Created while playing, deleted otherwise. std::unique_ptr<SmoothnessHelper> smoothness_helper_; - base::Optional<int> last_reported_fps_; + absl::optional<int> last_reported_fps_; base::WeakPtr<WebMediaPlayerImpl> weak_this_; base::WeakPtrFactory<WebMediaPlayerImpl> weak_factory_{this}; diff --git a/chromium/media/blink/webmediaplayer_impl_unittest.cc b/chromium/media/blink/webmediaplayer_impl_unittest.cc index d9280ccdfb5..9cb9f9d0c22 100644 --- a/chromium/media/blink/webmediaplayer_impl_unittest.cc +++ b/chromium/media/blink/webmediaplayer_impl_unittest.cc @@ -15,6 +15,7 @@ #include "base/memory/weak_ptr.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/task_runner_util.h" #include "base/test/bind.h" @@ -44,6 +45,7 @@ #include "media/blink/video_decode_stats_reporter.h" #include "media/blink/webcontentdecryptionmodule_impl.h" #include "media/blink/webmediaplayer_params.h" +#include "media/filters/pipeline_controller.h" #include "media/mojo/services/media_metrics_provider.h" #include "media/mojo/services/video_decode_stats_recorder.h" #include "media/mojo/services/watch_time_recorder.h" @@ -318,6 +320,7 @@ class WebMediaPlayerImplTest /*is_hidden=*/false, /*is_inside_portal=*/false, /*compositing_enabled=*/false, + /*widgets_never_composited=*/false, /*opener=*/nullptr, mojo::NullAssociatedReceiver(), *agent_group_scheduler, @@ -387,14 +390,14 @@ class WebMediaPlayerImplTest decoder_factory_ = std::make_unique<media::DefaultDecoderFactory>(nullptr); #if defined(OS_ANDROID) factory_selector->AddBaseFactory( - RendererFactoryType::kDefault, + RendererType::kDefault, std::make_unique<DefaultRendererFactory>( media_log.get(), decoder_factory_.get(), DefaultRendererFactory::GetGpuFactoriesCB())); factory_selector->StartRequestRemotePlayStateCB(base::DoNothing()); #else factory_selector->AddBaseFactory( - RendererFactoryType::kDefault, + RendererType::kDefault, std::make_unique<DefaultRendererFactory>( media_log.get(), decoder_factory_.get(), DefaultRendererFactory::GetGpuFactoriesCB(), nullptr)); @@ -497,6 +500,7 @@ class WebMediaPlayerImplTest void SetFullscreen(bool is_fullscreen) { wmpi_->overlay_enabled_ = is_fullscreen; + wmpi_->overlay_info_.is_fullscreen = is_fullscreen; } void SetMetadata(bool has_audio, bool has_video) { @@ -617,6 +621,7 @@ class WebMediaPlayerImplTest void Pause() { wmpi_->Pause(); } void ScheduleIdlePauseTimer() { wmpi_->ScheduleIdlePauseTimer(); } + void FireIdlePauseTimer() { wmpi_->background_pause_timer_.FireNow(); } bool IsIdlePauseTimerRunning() { return wmpi_->background_pause_timer_.IsRunning(); @@ -787,7 +792,7 @@ class WebMediaPlayerImplTest void CreateCdm() { // Must use a supported key system on a secure context. - auto key_system = base::ASCIIToUTF16("org.w3.clearkey"); + std::u16string key_system = u"org.w3.clearkey"; auto test_origin = blink::WebSecurityOrigin::CreateFromString( blink::WebString::FromUTF8("https://test.origin")); @@ -1753,7 +1758,7 @@ TEST_F(WebMediaPlayerImplTest, FallbackToMediaFoundationRenderer) { return mock_renderer; }))); - renderer_factory_selector_->AddFactory(RendererFactoryType::kMediaFoundation, + renderer_factory_selector_->AddFactory(RendererType::kMediaFoundation, std::move(mock_renderer_factory)); // Create and set CDM. The CDM doesn't support a Decryptor and requires Media @@ -1935,6 +1940,10 @@ TEST_F(WebMediaPlayerImplTest, BackgroundIdlePauseTimerDependsOnAudio) { SetMetadata(true, true); ScheduleIdlePauseTimer(); EXPECT_TRUE(IsIdlePauseTimerRunning()); + + EXPECT_CALL(client_, PausePlayback()); + FireIdlePauseTimer(); + base::RunLoop().RunUntilIdle(); } // Verifies that an infinite duration doesn't muck up GetCurrentTimeInternal. diff --git a/chromium/media/blink/webmediaplayer_params.h b/chromium/media/blink/webmediaplayer_params.h index 70db6159b12..d7a2e42375f 100644 --- a/chromium/media/blink/webmediaplayer_params.h +++ b/chromium/media/blink/webmediaplayer_params.h @@ -12,7 +12,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/time/time.h" #include "cc/layers/surface_layer.h" #include "components/viz/common/gpu/raster_context_provider.h" #include "media/base/media_log.h" diff --git a/chromium/media/blink/websourcebuffer_impl.cc b/chromium/media/blink/websourcebuffer_impl.cc index 1ea1357f6b5..ff928eb5fc5 100644 --- a/chromium/media/blink/websourcebuffer_impl.cc +++ b/chromium/media/blink/websourcebuffer_impl.cc @@ -16,6 +16,7 @@ #include "media/base/media_tracks.h" #include "media/base/timestamp_constants.h" #include "media/filters/chunk_demuxer.h" +#include "media/filters/source_buffer_parse_warnings.h" #include "third_party/blink/public/platform/web_media_player.h" #include "third_party/blink/public/platform/web_source_buffer_client.h" @@ -49,14 +50,11 @@ static base::TimeDelta DoubleToTimeDelta(double time) { if (time == std::numeric_limits<double>::infinity()) return kInfiniteDuration; - // Don't use base::TimeDelta::Max() here, as we want the largest finite time - // delta. - base::TimeDelta max_time = base::TimeDelta::FromInternalValue( - std::numeric_limits<int64_t>::max() - 1); - double max_time_in_seconds = max_time.InSecondsF(); + constexpr double max_time_in_seconds = + base::TimeDelta::FiniteMax().InSecondsF(); if (time >= max_time_in_seconds) - return max_time; + return base::TimeDelta::FiniteMax(); return base::TimeDelta::FromMicroseconds( time * base::Time::kMicrosecondsPerSecond); diff --git a/chromium/media/blink/websourcebuffer_impl.h b/chromium/media/blink/websourcebuffer_impl.h index 0d79492d45b..284c792d130 100644 --- a/chromium/media/blink/websourcebuffer_impl.h +++ b/chromium/media/blink/websourcebuffer_impl.h @@ -13,12 +13,12 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/time/time.h" -#include "media/filters/source_buffer_parse_warnings.h" #include "third_party/blink/public/platform/web_source_buffer.h" namespace media { class ChunkDemuxer; class MediaTracks; +enum class SourceBufferParseWarning; class WebSourceBufferImpl : public blink::WebSourceBuffer { public: diff --git a/chromium/media/capabilities/bucket_utility.h b/chromium/media/capabilities/bucket_utility.h index 4bf05dbde7c..9d89b3d9da3 100644 --- a/chromium/media/capabilities/bucket_utility.h +++ b/chromium/media/capabilities/bucket_utility.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_CAPABILITIES_BUCKET_UTILITY -#define MEDIA_CAPABILITIES_BUCKET_UTILITY +#ifndef MEDIA_CAPABILITIES_BUCKET_UTILITY_H_ +#define MEDIA_CAPABILITIES_BUCKET_UTILITY_H_ #include "media/base/media_export.h" #include "ui/gfx/geometry/size.h" @@ -25,4 +25,4 @@ MEDIA_EXPORT int GetFpsBucket(double raw_fps); } // namespace media -#endif // MEDIA_CAPABILITIES_BUCKET_UTILITY
\ No newline at end of file +#endif // MEDIA_CAPABILITIES_BUCKET_UTILITY_H_ diff --git a/chromium/media/capabilities/in_memory_video_decode_stats_db_impl.cc b/chromium/media/capabilities/in_memory_video_decode_stats_db_impl.cc index c6901cd122d..dcee0b3a6b2 100644 --- a/chromium/media/capabilities/in_memory_video_decode_stats_db_impl.cc +++ b/chromium/media/capabilities/in_memory_video_decode_stats_db_impl.cc @@ -13,7 +13,6 @@ #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/sequence_checker.h" -#include "base/strings/stringprintf.h" #include "base/task/post_task.h" #include "media/base/bind_to_current_loop.h" #include "media/capabilities/video_decode_stats_db_provider.h" diff --git a/chromium/media/capabilities/in_memory_video_decode_stats_db_impl.h b/chromium/media/capabilities/in_memory_video_decode_stats_db_impl.h index c896534b987..7e3190878af 100644 --- a/chromium/media/capabilities/in_memory_video_decode_stats_db_impl.h +++ b/chromium/media/capabilities/in_memory_video_decode_stats_db_impl.h @@ -8,7 +8,6 @@ #include <map> #include <memory> -#include "base/files/file_path.h" #include "base/memory/weak_ptr.h" #include "components/leveldb_proto/public/proto_database.h" #include "media/base/media_export.h" diff --git a/chromium/media/capture/BUILD.gn b/chromium/media/capture/BUILD.gn index bd8a26a1dcc..e96ba09d212 100644 --- a/chromium/media/capture/BUILD.gn +++ b/chromium/media/capture/BUILD.gn @@ -256,10 +256,7 @@ component("capture_lib") { configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] } - # This includes the case of ChromeOS - # TODO: As we move to separately version Chrome from ChromeOS, we may need to split - # these sources into linux, chromeos, and common. - if (is_linux || is_chromeos) { + if (is_linux || is_chromeos_lacros) { sources += [ "video/linux/scoped_v4l2_device_fd.cc", "video/linux/scoped_v4l2_device_fd.h", @@ -327,15 +324,12 @@ component("capture_lib") { "video/chromeos/video_capture_jpeg_decoder.h", "video/chromeos/video_capture_jpeg_decoder_impl.cc", "video/chromeos/video_capture_jpeg_decoder_impl.h", - "video/linux/camera_config_chromeos.cc", - "video/linux/camera_config_chromeos.h", - "video/linux/video_capture_device_chromeos.cc", - "video/linux/video_capture_device_chromeos.h", ] public_deps += [ "//media/capture/video/chromeos/public" ] deps += [ "//ash/constants", "//build/config/linux/libdrm", + "//chromeos/components/sensors:sensors", "//chromeos/dbus/power", "//components/chromeos_camera:mojo_mjpeg_decode_accelerator", "//components/chromeos_camera/common", @@ -391,7 +385,7 @@ source_set("test_support") { "//ui/gfx:test_support", ] - if (is_linux || is_chromeos) { + if (is_linux || is_chromeos_lacros) { sources += [ "video/linux/fake_device_provider.cc", "video/linux/fake_device_provider.h", @@ -453,17 +447,13 @@ test("capture_unittests") { "//ui/gfx:test_support", ] - if (is_linux || is_chromeos) { + if (is_linux || is_chromeos_lacros) { sources += [ "video/linux/v4l2_capture_delegate_unittest.cc", "video/linux/video_capture_device_factory_linux_unittest.cc", ] } - if (is_chromeos_ash) { - sources += [ "video/linux/camera_config_chromeos_unittest.cc" ] - } - if (is_android) { deps += [ "//media/capture/video/android", diff --git a/chromium/media/capture/content/DIR_METADATA b/chromium/media/capture/content/DIR_METADATA index c46eabd56bc..f689e004f05 100644 --- a/chromium/media/capture/content/DIR_METADATA +++ b/chromium/media/capture/content/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Media>SurfaceCapture" diff --git a/chromium/media/capture/content/android/screen_capture_machine_android.h b/chromium/media/capture/content/android/screen_capture_machine_android.h index 4b118341f62..c1246e5a8f7 100644 --- a/chromium/media/capture/content/android/screen_capture_machine_android.h +++ b/chromium/media/capture/content/android/screen_capture_machine_android.h @@ -6,7 +6,6 @@ #define MEDIA_CAPTURE_CONTENT_ANDROID_SCREEN_CAPTURE_MACHINE_ANDROID_H_ #include <jni.h> -#include <memory> #include "base/android/scoped_java_ref.h" #include "base/memory/scoped_refptr.h" diff --git a/chromium/media/capture/content/video_capture_oracle_unittest.cc b/chromium/media/capture/content/video_capture_oracle_unittest.cc index 8f0c1d123da..aea1256f456 100644 --- a/chromium/media/capture/content/video_capture_oracle_unittest.cc +++ b/chromium/media/capture/content/video_capture_oracle_unittest.cc @@ -4,8 +4,8 @@ #include "media/capture/content/video_capture_oracle.h" -#include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -880,7 +880,7 @@ TEST(VideoCaptureOracleTest, RespectsMaxFrameRateFeedback) { int frame_number; // As if previous frame was captured at 30 fps. - base::Optional<base::TimeTicks> last_capture_time; + absl::optional<base::TimeTicks> last_capture_time; for (int i = 0; i < 100; ++i) { t += vsync_interval; if (oracle.ObserveEventAndDecideCapture( @@ -904,7 +904,7 @@ TEST(VideoCaptureOracleTest, RespectsMaxFrameRateFeedback) { frame_number, media::VideoCaptureFeedback(kNoResourceUtilization, k5Fps)); // Don't measure frame-rate across different target frame-rates. - last_capture_time = base::nullopt; + last_capture_time = absl::nullopt; // Continue capturing frames, observe that frame-rate limit is respected. for (int i = 0; i < 100; ++i) { t += vsync_interval; @@ -930,7 +930,7 @@ TEST(VideoCaptureOracleTest, RespectsMaxFrameRateFeedback) { media::VideoCaptureFeedback(kNoResourceUtilization, kNoFpsLimit)); // Don't measure frame-rate across different target frame-rates. - last_capture_time = base::nullopt; + last_capture_time = absl::nullopt; // Continue capturing frames, observe that original min capture period is // respected. for (int i = 0; i < 100; ++i) { diff --git a/chromium/media/capture/mojom/video_capture_buffer.mojom b/chromium/media/capture/mojom/video_capture_buffer.mojom index e8a70ee00a9..fa28c2eac09 100644 --- a/chromium/media/capture/mojom/video_capture_buffer.mojom +++ b/chromium/media/capture/mojom/video_capture_buffer.mojom @@ -19,6 +19,11 @@ struct VideoFrameInfo{ VideoCapturePixelFormat pixel_format; gfx.mojom.Size coded_size; gfx.mojom.Rect visible_rect; + // Some buffer types may be preemtively mapped in the capturer. + // In that case a shared memory region is passed to the consumer together + // with a GMB handle, and this flag here is passed to notify the consumer + // that the region has valid data. + bool is_premapped; // This field is only optional to work around the issue of native enums // not being usable for non-Chromium Mojo clients. // TODO(chfremer): Make this non-optional once gfx.mojom.ColorSpace has been diff --git a/chromium/media/capture/mojom/video_capture_types_mojom_traits.h b/chromium/media/capture/mojom/video_capture_types_mojom_traits.h index d47081e700f..aaaad37daa2 100644 --- a/chromium/media/capture/mojom/video_capture_types_mojom_traits.h +++ b/chromium/media/capture/mojom/video_capture_types_mojom_traits.h @@ -5,13 +5,13 @@ #ifndef MEDIA_CAPTURE_MOJOM_VIDEO_CAPTURE_TYPES_MOJOM_TRAITS_H_ #define MEDIA_CAPTURE_MOJOM_VIDEO_CAPTURE_TYPES_MOJOM_TRAITS_H_ -#include "base/optional.h" #include "media/base/video_facing.h" #include "media/capture/mojom/video_capture_types.mojom-shared.h" #include "media/capture/video/video_capture_device_descriptor.h" #include "media/capture/video/video_capture_device_info.h" #include "media/capture/video/video_capture_feedback.h" #include "media/capture/video_capture_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace mojo { diff --git a/chromium/media/capture/video/DIR_METADATA b/chromium/media/capture/video/DIR_METADATA index dc21b380384..ca45fdeb142 100644 --- a/chromium/media/capture/video/DIR_METADATA +++ b/chromium/media/capture/video/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Media>CameraCapture" diff --git a/chromium/media/capture/video/android/video_capture_device_factory_android.cc b/chromium/media/capture/video/android/video_capture_device_factory_android.cc index 157e2676c27..33e1b744ff1 100644 --- a/chromium/media/capture/video/android/video_capture_device_factory_android.cc +++ b/chromium/media/capture/video/android/video_capture_device_factory_android.cc @@ -10,7 +10,6 @@ #include "base/android/scoped_java_ref.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "media/capture/video/android/capture_jni_headers/VideoCaptureFactory_jni.h" #include "media/capture/video/android/video_capture_device_android.h" diff --git a/chromium/media/capture/video/chromeos/DEPS b/chromium/media/capture/video/chromeos/DEPS index db76c2a1b65..170ac6c6b6f 100644 --- a/chromium/media/capture/video/chromeos/DEPS +++ b/chromium/media/capture/video/chromeos/DEPS @@ -1,5 +1,6 @@ include_rules = [ "+ash/constants/ash_features.h", + "+chromeos/components/sensors", "+chromeos/dbus", "+components/chromeos_camera", "+third_party/libsync", diff --git a/chromium/media/capture/video/chromeos/camera_app_device_impl.cc b/chromium/media/capture/video/chromeos/camera_app_device_impl.cc index cf23b2aa7cb..8d0595ed820 100644 --- a/chromium/media/capture/video/chromeos/camera_app_device_impl.cc +++ b/chromium/media/capture/video/chromeos/camera_app_device_impl.cc @@ -125,7 +125,7 @@ void CameraAppDeviceImpl::ConsumeReprocessOptions( std::move(consumption_callback).Run(std::move(result_task_queue)); } -base::Optional<gfx::Range> CameraAppDeviceImpl::GetFpsRange() { +absl::optional<gfx::Range> CameraAppDeviceImpl::GetFpsRange() { base::AutoLock lock(fps_ranges_lock_); return specified_fps_range_; @@ -247,8 +247,15 @@ void CameraAppDeviceImpl::SetCaptureIntent( SetCaptureIntentCallback callback) { DCHECK(mojo_task_runner_->BelongsToCurrentThread()); - base::AutoLock lock(capture_intent_lock_); - capture_intent_ = capture_intent; + { + base::AutoLock lock(capture_intent_lock_); + capture_intent_ = capture_intent; + } + // Reset fps range for VCD to determine it if not explicitly set by app. + { + base::AutoLock lock(fps_ranges_lock_); + specified_fps_range_ = {}; + } std::move(callback).Run(); } diff --git a/chromium/media/capture/video/chromeos/camera_app_device_impl.h b/chromium/media/capture/video/chromeos/camera_app_device_impl.h index 9bb497ddd0b..42ca9fcd51c 100644 --- a/chromium/media/capture/video/chromeos/camera_app_device_impl.h +++ b/chromium/media/capture/video/chromeos/camera_app_device_impl.h @@ -11,6 +11,7 @@ #include <vector> #include "base/containers/flat_set.h" +#include "base/containers/queue.h" #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" @@ -87,7 +88,7 @@ class CAPTURE_EXPORT CameraAppDeviceImpl : public cros::mojom::CameraAppDevice { base::OnceCallback<void(ReprocessTaskQueue)> consumption_callback); // Retrieves the fps range if it is specified by the app. - base::Optional<gfx::Range> GetFpsRange(); + absl::optional<gfx::Range> GetFpsRange(); // Retrieves the corresponding capture resolution which is specified by the // app. @@ -168,7 +169,7 @@ class CAPTURE_EXPORT CameraAppDeviceImpl : public cros::mojom::CameraAppDevice { // It will be inserted and read from different threads. base::Lock fps_ranges_lock_; - base::Optional<gfx::Range> specified_fps_range_ GUARDED_BY(fps_ranges_lock_); + absl::optional<gfx::Range> specified_fps_range_ GUARDED_BY(fps_ranges_lock_); // It will be inserted and read from different threads. base::Lock still_capture_resolution_lock_; diff --git a/chromium/media/capture/video/chromeos/camera_app_device_provider_impl.cc b/chromium/media/capture/video/chromeos/camera_app_device_provider_impl.cc index 53defd23bee..66eb6cc1f39 100644 --- a/chromium/media/capture/video/chromeos/camera_app_device_provider_impl.cc +++ b/chromium/media/capture/video/chromeos/camera_app_device_provider_impl.cc @@ -39,7 +39,7 @@ void CameraAppDeviceProviderImpl::GetCameraAppDevice( void CameraAppDeviceProviderImpl::GetCameraAppDeviceWithDeviceId( GetCameraAppDeviceCallback callback, - const base::Optional<std::string>& device_id) { + const absl::optional<std::string>& device_id) { if (!device_id.has_value()) { std::move(callback).Run( cros::mojom::GetCameraAppDeviceStatus::ERROR_INVALID_ID, @@ -68,7 +68,7 @@ void CameraAppDeviceProviderImpl::SetMultipleStreamsEnabled( void CameraAppDeviceProviderImpl::SetMultipleStreamsEnabledWithDeviceId( bool enabled, SetMultipleStreamsEnabledCallback callback, - const base::Optional<std::string>& device_id) { + const absl::optional<std::string>& device_id) { if (!device_id.has_value()) { std::move(callback).Run(false); return; diff --git a/chromium/media/capture/video/chromeos/camera_app_device_provider_impl.h b/chromium/media/capture/video/chromeos/camera_app_device_provider_impl.h index 6bf036ef614..3fbb56257b6 100644 --- a/chromium/media/capture/video/chromeos/camera_app_device_provider_impl.h +++ b/chromium/media/capture/video/chromeos/camera_app_device_provider_impl.h @@ -17,7 +17,7 @@ class CAPTURE_EXPORT CameraAppDeviceProviderImpl : public cros::mojom::CameraAppDeviceProvider { public: using WithRealIdCallback = - base::OnceCallback<void(const base::Optional<std::string>&)>; + base::OnceCallback<void(const absl::optional<std::string>&)>; using DeviceIdMappingCallback = base::RepeatingCallback<void(const std::string&, WithRealIdCallback)>; @@ -40,12 +40,12 @@ class CAPTURE_EXPORT CameraAppDeviceProviderImpl private: void GetCameraAppDeviceWithDeviceId( GetCameraAppDeviceCallback callback, - const base::Optional<std::string>& device_id); + const absl::optional<std::string>& device_id); void SetMultipleStreamsEnabledWithDeviceId( bool enable, SetMultipleStreamsEnabledCallback callback, - const base::Optional<std::string>& device_id); + const absl::optional<std::string>& device_id); mojo::Remote<cros::mojom::CameraAppDeviceBridge> bridge_; diff --git a/chromium/media/capture/video/chromeos/camera_buffer_factory.cc b/chromium/media/capture/video/chromeos/camera_buffer_factory.cc index 345c9dcf27d..a4e3b5eb88f 100644 --- a/chromium/media/capture/video/chromeos/camera_buffer_factory.cc +++ b/chromium/media/capture/video/chromeos/camera_buffer_factory.cc @@ -4,7 +4,7 @@ #include "media/capture/video/chromeos/camera_buffer_factory.h" -#include "base/stl_util.h" +#include "base/containers/contains.h" #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h" namespace media { @@ -24,7 +24,7 @@ CameraBufferFactory::CreateGpuMemoryBuffer(const gfx::Size& size, return nullptr; } return buf_manager->CreateGpuMemoryBuffer(size, format, usage, - gpu::kNullSurfaceHandle); + gpu::kNullSurfaceHandle, nullptr); } // There's no good way to resolve the HAL pixel format to the platform-specific diff --git a/chromium/media/capture/video/chromeos/camera_device_context.h b/chromium/media/capture/video/chromeos/camera_device_context.h index 1d40dcc5cd1..a85d7f58243 100644 --- a/chromium/media/capture/video/chromeos/camera_device_context.h +++ b/chromium/media/capture/video/chromeos/camera_device_context.h @@ -203,4 +203,4 @@ class CAPTURE_EXPORT CameraDeviceContext { } // namespace media -#endif // MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_DEVICE_CONTEXT_CHROMEOS_H_ +#endif // MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_DEVICE_CONTEXT_H_ diff --git a/chromium/media/capture/video/chromeos/camera_device_delegate.cc b/chromium/media/capture/video/chromeos/camera_device_delegate.cc index b7d497c7a4d..490e828bab5 100644 --- a/chromium/media/capture/video/chromeos/camera_device_delegate.cc +++ b/chromium/media/capture/video/chromeos/camera_device_delegate.cc @@ -14,6 +14,7 @@ #include "ash/constants/ash_features.h" #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/containers/contains.h" #include "base/no_destructor.h" #include "base/numerics/ranges.h" #include "base/posix/safe_strerror.h" @@ -307,8 +308,11 @@ void CameraDeviceDelegate::AllocateAndStart( device_context_ = device_context; device_context_->SetState(CameraDeviceContext::State::kStarting); - if (camera_app_device_) { - camera_app_device_->SetCameraDeviceContext(device_context_); + auto camera_app_device = + CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice( + device_descriptor_.device_id); + if (camera_app_device) { + camera_app_device->SetCameraDeviceContext(device_context_); } auto camera_info = camera_hal_delegate_->GetCameraInfoFromDeviceId( @@ -320,6 +324,7 @@ void CameraDeviceDelegate::AllocateAndStart( return; } + device_api_version_ = camera_info->device_version; SortCameraMetadata(&camera_info->static_camera_characteristics); static_metadata_ = std::move(camera_info->static_camera_characteristics); @@ -369,8 +374,11 @@ void CameraDeviceDelegate::StopAndDeAllocate( // CameraDeviceContext::State::kStopping. DCHECK_NE(device_context_->GetState(), CameraDeviceContext::State::kStopping); - if (camera_app_device_) { - camera_app_device_->SetCameraDeviceContext(nullptr); + auto camera_app_device = + CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice( + device_descriptor_.device_id); + if (camera_app_device) { + camera_app_device->SetCameraDeviceContext(nullptr); } device_close_callback_ = std::move(device_close_callback); @@ -610,7 +618,7 @@ void CameraDeviceDelegate::ReconfigureStreams( // ReconfigureStreams is used for video recording. It does not require // photo. request_manager_->StopPreview(base::BindOnce( - &CameraDeviceDelegate::OnFlushed, GetWeakPtr(), false, base::nullopt)); + &CameraDeviceDelegate::OnFlushed, GetWeakPtr(), false, absl::nullopt)); } } @@ -645,7 +653,7 @@ bool CameraDeviceDelegate::MaybeReconfigureForPhotoStream( std::move(new_blob_resolution))); } else { request_manager_->StopPreview(base::BindOnce( - &CameraDeviceDelegate::OnFlushed, GetWeakPtr(), true, base::nullopt)); + &CameraDeviceDelegate::OnFlushed, GetWeakPtr(), true, absl::nullopt)); } return true; } @@ -666,7 +674,7 @@ void CameraDeviceDelegate::TakePhotoImpl() { // Trigger the reconfigure process if it not yet triggered. if (on_reconfigured_callbacks_.empty()) { request_manager_->StopPreview(base::BindOnce( - &CameraDeviceDelegate::OnFlushed, GetWeakPtr(), true, base::nullopt)); + &CameraDeviceDelegate::OnFlushed, GetWeakPtr(), true, absl::nullopt)); } auto on_reconfigured_callback = base::BindOnce( [](base::WeakPtr<Camera3AController> controller, @@ -703,7 +711,7 @@ void CameraDeviceDelegate::OnMojoConnectionError() { void CameraDeviceDelegate::OnFlushed( bool require_photo, - base::Optional<gfx::Size> new_blob_resolution, + absl::optional<gfx::Size> new_blob_resolution, int32_t result) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); if (result) { @@ -790,7 +798,8 @@ void CameraDeviceDelegate::Initialize() { device_context_, chrome_capture_params_[ClientType::kPreviewClient].buffer_type, std::make_unique<CameraBufferFactory>(), - base::BindRepeating(&RotateAndBlobify), ipc_task_runner_); + base::BindRepeating(&RotateAndBlobify), ipc_task_runner_, + device_api_version_); camera_3a_controller_ = std::make_unique<Camera3AController>( static_metadata_, request_manager_.get(), ipc_task_runner_); device_ops_->Initialize( @@ -837,12 +846,12 @@ void CameraDeviceDelegate::OnInitialized(int32_t result) { return false; } }(); - ConfigureStreams(require_photo, base::nullopt); + ConfigureStreams(require_photo, absl::nullopt); } void CameraDeviceDelegate::ConfigureStreams( bool require_photo, - base::Optional<gfx::Size> new_blob_resolution) { + absl::optional<gfx::Size> new_blob_resolution) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); DCHECK_EQ(device_context_->GetState(), CameraDeviceContext::State::kInitialized); @@ -871,6 +880,9 @@ void CameraDeviceDelegate::ConfigureStreams( stream->data_space = 0; stream->rotation = cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; + if (device_api_version_ >= cros::mojom::CAMERA_DEVICE_API_VERSION_3_5) { + stream->physical_camera_id = ""; + } stream_config->streams.push_back(std::move(stream)); } @@ -903,6 +915,9 @@ void CameraDeviceDelegate::ConfigureStreams( still_capture_stream->data_space = 0; still_capture_stream->rotation = cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; + if (device_api_version_ >= cros::mojom::CAMERA_DEVICE_API_VERSION_3_5) { + still_capture_stream->physical_camera_id = ""; + } stream_config->streams.push_back(std::move(still_capture_stream)); int32_t max_yuv_width = 0, max_yuv_height = 0; @@ -919,6 +934,9 @@ void CameraDeviceDelegate::ConfigureStreams( reprocessing_stream_input->data_space = 0; reprocessing_stream_input->rotation = cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; + if (device_api_version_ >= cros::mojom::CAMERA_DEVICE_API_VERSION_3_5) { + reprocessing_stream_input->physical_camera_id = ""; + } auto reprocessing_stream_output = cros::mojom::Camera3Stream::New(); reprocessing_stream_output->id = @@ -935,6 +953,9 @@ void CameraDeviceDelegate::ConfigureStreams( reprocessing_stream_output->data_space = 0; reprocessing_stream_output->rotation = cros::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0; + if (device_api_version_ >= cros::mojom::CAMERA_DEVICE_API_VERSION_3_5) { + reprocessing_stream_output->physical_camera_id = ""; + } stream_config->streams.push_back(std::move(reprocessing_stream_input)); stream_config->streams.push_back(std::move(reprocessing_stream_output)); @@ -943,6 +964,9 @@ void CameraDeviceDelegate::ConfigureStreams( stream_config->operation_mode = cros::mojom::Camera3StreamConfigurationMode:: CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE; + if (device_api_version_ >= cros::mojom::CAMERA_DEVICE_API_VERSION_3_5) { + stream_config->session_parameters = cros::mojom::CameraMetadata::New(); + } device_ops_->ConfigureStreams( std::move(stream_config), base::BindOnce(&CameraDeviceDelegate::OnConfiguredStreams, GetWeakPtr(), @@ -1125,7 +1149,7 @@ void CameraDeviceDelegate::OnConstructedDefaultPreviewRequestSettings( CameraAppDeviceBridgeImpl::GetInstance()->GetWeakCameraAppDevice( device_descriptor_.device_id); auto specified_fps_range = - camera_app_device ? camera_app_device->GetFpsRange() : base::nullopt; + camera_app_device ? camera_app_device->GetFpsRange() : absl::nullopt; if (specified_fps_range) { SetFpsRangeInMetadata(&settings, specified_fps_range->GetMin(), specified_fps_range->GetMax()); @@ -1152,16 +1176,15 @@ void CameraDeviceDelegate::OnConstructedDefaultPreviewRequestSettings( SetFpsRangeInMetadata(&settings, target_min, target_max); } - request_manager_->StartPreview(std::move(settings)); - - if (!take_photo_callbacks_.empty()) { - TakePhotoImpl(); - } - while (!on_reconfigured_callbacks_.empty()) { std::move(on_reconfigured_callbacks_.front()).Run(); on_reconfigured_callbacks_.pop(); } + + request_manager_->StartPreview(std::move(settings)); + if (!take_photo_callbacks_.empty()) { + TakePhotoImpl(); + } } void CameraDeviceDelegate::OnConstructedDefaultStillCaptureRequestSettings( @@ -1193,7 +1216,7 @@ void CameraDeviceDelegate::OnConstructedDefaultStillCaptureRequestSettings( } gfx::Size CameraDeviceDelegate::GetBlobResolution( - base::Optional<gfx::Size> new_blob_resolution) { + absl::optional<gfx::Size> new_blob_resolution) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); std::vector<gfx::Size> blob_resolutions; @@ -1304,7 +1327,7 @@ bool CameraDeviceDelegate::SetPointsOfInterest( mojom::RangePtr CameraDeviceDelegate::GetControlRangeByVendorTagName( const std::string& range_name, - const base::Optional<int32_t>& current) { + const absl::optional<int32_t>& current) { const VendorTagInfo* info = camera_hal_delegate_->GetVendorTagInfoByName(range_name); if (info == nullptr) { @@ -1338,7 +1361,7 @@ void CameraDeviceDelegate::OnResultMetadataAvailable( auto get_vendor_int = [&](const std::string& name, const cros::mojom::CameraMetadataPtr& result_metadata, - base::Optional<int32_t>* returned_value) { + absl::optional<int32_t>* returned_value) { returned_value->reset(); const VendorTagInfo* info = camera_hal_delegate_->GetVendorTagInfoByName(name); diff --git a/chromium/media/capture/video/chromeos/camera_device_delegate.h b/chromium/media/capture/video/chromeos/camera_device_delegate.h index 3f821f96b54..3f8c72cfb5e 100644 --- a/chromium/media/capture/video/chromeos/camera_device_delegate.h +++ b/chromium/media/capture/video/chromeos/camera_device_delegate.h @@ -11,7 +11,6 @@ #include "base/containers/flat_map.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "media/capture/video/chromeos/camera_device_context.h" #include "media/capture/video/chromeos/capture_metadata_dispatcher.h" @@ -20,13 +19,13 @@ #include "media/capture/video/video_capture_device.h" #include "media/capture/video_capture_types.h" #include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/range/range.h" namespace media { class Camera3AController; -class CameraAppDeviceImpl; class CameraHalDelegate; class RequestManager; @@ -56,21 +55,21 @@ struct ResultMetadata { ResultMetadata(); ~ResultMetadata(); - base::Optional<uint8_t> ae_mode; - base::Optional<int32_t> ae_compensation; - base::Optional<uint8_t> af_mode; - base::Optional<uint8_t> awb_mode; - base::Optional<int32_t> brightness; - base::Optional<int32_t> contrast; - base::Optional<int64_t> exposure_time; - base::Optional<float> focus_distance; - base::Optional<int32_t> pan; - base::Optional<int32_t> saturation; - base::Optional<int32_t> sensitivity; - base::Optional<int32_t> sharpness; - base::Optional<int32_t> tilt; - base::Optional<int32_t> zoom; - base::Optional<gfx::Rect> scaler_crop_region; + absl::optional<uint8_t> ae_mode; + absl::optional<int32_t> ae_compensation; + absl::optional<uint8_t> af_mode; + absl::optional<uint8_t> awb_mode; + absl::optional<int32_t> brightness; + absl::optional<int32_t> contrast; + absl::optional<int64_t> exposure_time; + absl::optional<float> focus_distance; + absl::optional<int32_t> pan; + absl::optional<int32_t> saturation; + absl::optional<int32_t> sensitivity; + absl::optional<int32_t> sharpness; + absl::optional<int32_t> tilt; + absl::optional<int32_t> zoom; + absl::optional<gfx::Rect> scaler_crop_region; }; // Returns true if the given stream type is an input stream. @@ -160,7 +159,7 @@ class CAPTURE_EXPORT CameraDeviceDelegate final // Reconfigure streams for picture taking and recording. void OnFlushed(bool require_photo, - base::Optional<gfx::Size> new_blob_resolution, + absl::optional<gfx::Size> new_blob_resolution, int32_t result); // Callback method for the Close Mojo IPC call. This method resets the Mojo @@ -186,7 +185,7 @@ class CAPTURE_EXPORT CameraDeviceDelegate final // |client_| the capture has started by calling OnStarted, and proceeds to // ConstructDefaultRequestSettings. void ConfigureStreams(bool require_photo, - base::Optional<gfx::Size> new_blob_resolution); + absl::optional<gfx::Size> new_blob_resolution); void OnConfiguredStreams( gfx::Size blob_resolution, int32_t result, @@ -214,7 +213,7 @@ class CAPTURE_EXPORT CameraDeviceDelegate final void OnConstructedDefaultStillCaptureRequestSettings( cros::mojom::CameraMetadataPtr settings); - gfx::Size GetBlobResolution(base::Optional<gfx::Size> new_blob_resolution); + gfx::Size GetBlobResolution(absl::optional<gfx::Size> new_blob_resolution); // StreamCaptureInterface implementations. These methods are called by // |stream_buffer_manager_| on |ipc_task_runner_|. @@ -229,7 +228,7 @@ class CAPTURE_EXPORT CameraDeviceDelegate final // metadata by |range_name| and current value of |current|. mojom::RangePtr GetControlRangeByVendorTagName( const std::string& range_name, - const base::Optional<int32_t>& current); + const absl::optional<int32_t>& current); // CaptureMetadataDispatcher::ResultMetadataObserver implementation. void OnResultMetadataAvailable( @@ -270,7 +269,7 @@ class CAPTURE_EXPORT CameraDeviceDelegate final std::queue<base::OnceClosure> on_reconfigured_callbacks_; - base::WeakPtr<CameraAppDeviceImpl> camera_app_device_; + uint32_t device_api_version_; // States of SetPhotoOptions bool is_set_awb_mode_; diff --git a/chromium/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/chromium/media/capture/video/chromeos/camera_device_delegate_unittest.cc index 1c1bb4ad006..9d47ddc1b62 100644 --- a/chromium/media/capture/video/chromeos/camera_device_delegate_unittest.cc +++ b/chromium/media/capture/video/chromeos/camera_device_delegate_unittest.cc @@ -396,7 +396,7 @@ class CameraDeviceDelegateTest : public ::testing::Test { CreateGpuMemoryBuffer( _, gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE, - gpu::kNullSurfaceHandle)) + gpu::kNullSurfaceHandle, nullptr)) .Times(1) .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager:: CreateFakeGpuMemoryBuffer)); @@ -404,7 +404,7 @@ class CameraDeviceDelegateTest : public ::testing::Test { mock_gpu_memory_buffer_manager_, CreateGpuMemoryBuffer(_, gfx::BufferFormat::R_8, gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE, - gpu::kNullSurfaceHandle)) + gpu::kNullSurfaceHandle, nullptr)) .Times(AtMost(1)) .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager:: CreateFakeGpuMemoryBuffer)); @@ -413,7 +413,7 @@ class CameraDeviceDelegateTest : public ::testing::Test { gfx::Size(kDefaultWidth, kDefaultHeight), gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE, - gpu::kNullSurfaceHandle)) + gpu::kNullSurfaceHandle, nullptr)) .Times(1) .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager:: CreateFakeGpuMemoryBuffer)); @@ -421,7 +421,7 @@ class CameraDeviceDelegateTest : public ::testing::Test { CreateGpuMemoryBuffer( gfx::Size(kJpegMaxBufferSize, 1), gfx::BufferFormat::R_8, gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE, - gpu::kNullSurfaceHandle)) + gpu::kNullSurfaceHandle, nullptr)) .Times(AtMost(1)) .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager:: CreateFakeGpuMemoryBuffer)); @@ -490,7 +490,7 @@ class CameraDeviceDelegateTest : public ::testing::Test { } void DoLoop() { - run_loop_.reset(new base::RunLoop()); + run_loop_ = std::make_unique<base::RunLoop>(); run_loop_->Run(); } diff --git a/chromium/media/capture/video/chromeos/camera_hal_delegate.cc b/chromium/media/capture/video/chromeos/camera_hal_delegate.cc index fcc92b23aed..9b83d4c0f9a 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_delegate.cc +++ b/chromium/media/capture/video/chromeos/camera_hal_delegate.cc @@ -264,7 +264,7 @@ void CameraHalDelegate::GetSupportedFormats( continue; } - CAMERA_LOG(EVENT) << "Supported format: " << width << "x" << height + CAMERA_LOG(DEBUG) << "Supported format: " << width << "x" << height << " fps=" << fps << " format=" << cr_format.video_format; supported_formats->emplace_back(gfx::Size(width, height), fps, diff --git a/chromium/media/capture/video/chromeos/camera_hal_delegate_unittest.cc b/chromium/media/capture/video/chromeos/camera_hal_delegate_unittest.cc index 3e1bf9b0d6e..a3cd9a46a27 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_delegate_unittest.cc +++ b/chromium/media/capture/video/chromeos/camera_hal_delegate_unittest.cc @@ -56,7 +56,7 @@ class CameraHalDelegateTest : public ::testing::Test { } void Wait() { - run_loop_.reset(new base::RunLoop()); + run_loop_ = std::make_unique<base::RunLoop>(); run_loop_->Run(); } @@ -232,7 +232,7 @@ TEST_F(CameraHalDelegateTest, GetBuiltinCameraInfo) { CreateGpuMemoryBuffer( _, gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE, - gpu::kNullSurfaceHandle)) + gpu::kNullSurfaceHandle, nullptr)) .Times(1) .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager:: CreateFakeGpuMemoryBuffer)); diff --git a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc index 18e810897d3..bdba7369c6f 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc +++ b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h" + #include <fcntl.h> #include <grp.h> #include <poll.h> @@ -22,10 +23,14 @@ #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/synchronization/waitable_event.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "base/trace_event/trace_event.h" +#include "chromeos/components/sensors/sensor_util.h" #include "components/device_event_log/device_event_log.h" #include "media/base/bind_to_current_loop.h" #include "media/capture/video/chromeos/mojom/camera_common.mojom.h" +#include "media/capture/video/chromeos/mojom/cros_camera_client.mojom.h" +#include "media/capture/video/chromeos/video_capture_features_chromeos.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/platform/named_platform_channel.h" #include "mojo/public/cpp/platform/platform_channel.h" @@ -37,8 +42,10 @@ namespace media { namespace { const base::FilePath::CharType kArcCamera3SocketPath[] = - "/var/run/camera/camera3.sock"; + "/run/camera/camera3.sock"; const char kArcCameraGroup[] = "arc-camera"; +const base::FilePath::CharType kForceEnableAePath[] = + "/run/camera/force_enable_ae"; std::string GenerateRandomToken() { char random_bytes[16]; @@ -164,6 +171,18 @@ bool CameraHalDispatcherImpl::Start( TRACE_EVENT0("camera", "CameraHalDispatcherImpl"); base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this); + base::FilePath file_path(kForceEnableAePath); + if (base::FeatureList::IsEnabled(media::features::kForceEnableFaceAe)) { + if (!base::PathExists(file_path)) { + base::File file(file_path, base::File::FLAG_CREATE_ALWAYS); + file.Close(); + } + } else { + if (base::PathExists(file_path)) { + base::DeleteFile(file_path); + } + } + jda_factory_ = std::move(jda_factory); jea_factory_ = std::move(jea_factory); base::WaitableEvent started(base::WaitableEvent::ResetPolicy::MANUAL, @@ -179,6 +198,11 @@ bool CameraHalDispatcherImpl::Start( LOG(ERROR) << "Failed to generate token for test client"; return false; } + if (!token_manager_.GenerateServerSensorClientToken()) { + LOG(ERROR) << "Failed to generate authentication token for server as a " + "sensor client"; + } + blocking_io_task_runner_->PostTask( FROM_HERE, base::BindOnce(&CameraHalDispatcherImpl::CreateSocket, @@ -250,6 +274,7 @@ void CameraHalDispatcherImpl::UnregisterPluginVmToken( CameraHalDispatcherImpl::CameraHalDispatcherImpl() : proxy_thread_("CameraProxyThread"), blocking_io_thread_("CameraBlockingIOThread"), + main_task_runner_(base::SequencedTaskRunnerHandle::Get()), camera_hal_server_callbacks_(this), active_client_observers_( new base::ObserverListThreadSafe<CameraActiveClientObserver>()), @@ -344,6 +369,20 @@ void CameraHalDispatcherImpl::GetJpegEncodeAccelerator( jea_factory_.Run(std::move(jea_receiver)); } +void CameraHalDispatcherImpl::RegisterSensorClientWithToken( + mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> client, + const base::UnguessableToken& auth_token, + RegisterSensorClientWithTokenCallback callback) { + DCHECK(proxy_task_runner_->BelongsToCurrentThread()); + + main_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + &CameraHalDispatcherImpl::RegisterSensorClientWithTokenOnUIThread, + weak_factory_.GetWeakPtr(), std::move(client), auth_token, + BindToCurrentLoop(std::move(callback)))); +} + void CameraHalDispatcherImpl::CameraDeviceActivityChange( int32_t camera_id, bool opened, @@ -395,6 +434,8 @@ void CameraHalDispatcherImpl::CameraPrivacySwitchStateChange( FROM_HERE, &CameraPrivacySwitchObserver::OnCameraPrivacySwitchStatusChanged, current_privacy_switch_state_); + CAMERA_LOG(EVENT) << "Camera privacy switch state changed: " + << current_privacy_switch_state_; } base::UnguessableToken CameraHalDispatcherImpl::GetTokenForTrustedClient( @@ -640,6 +681,26 @@ void CameraHalDispatcherImpl::OnCameraHalClientConnectionError( } } +void CameraHalDispatcherImpl::RegisterSensorClientWithTokenOnUIThread( + mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> client, + const base::UnguessableToken& auth_token, + RegisterSensorClientWithTokenCallback callback) { + DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); + + if (!token_manager_.AuthenticateServerSensorClient(auth_token)) { + std::move(callback).Run(-EPERM); + return; + } + + if (!chromeos::sensors::BindSensorHalClient(std::move(client))) { + LOG(ERROR) << "Failed to bind SensorHalClient to SensorHalDispatcher"; + std::move(callback).Run(-ENOSYS); + return; + } + + std::move(callback).Run(0); +} + void CameraHalDispatcherImpl::StopOnProxyThread() { DCHECK(proxy_task_runner_->BelongsToCurrentThread()); base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this); diff --git a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.h index 57ecc7118a8..e3422a83a84 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.h +++ b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl.h @@ -14,6 +14,7 @@ #include "base/files/scoped_file.h" #include "base/memory/scoped_refptr.h" #include "base/memory/singleton.h" +#include "base/memory/weak_ptr.h" #include "base/observer_list_threadsafe.h" #include "base/observer_list_types.h" #include "base/synchronization/lock.h" @@ -113,12 +114,18 @@ class CAPTURE_EXPORT CameraPrivacySwitchObserver // /var/run/camera3.sock. CameraHalServer and CameraHalClients connect to the // unix domain socket to create the initial Mojo connections with the // CameraHalDisptcherImpl, and CameraHalDispatcherImpl then creates and -// dispaches the Mojo channels between CameraHalServer and CameraHalClients to +// dispatches the Mojo channels between CameraHalServer and CameraHalClients to // establish direct Mojo connections between the CameraHalServer and the // CameraHalClients. // // For general documentation about the CameraHalDispater Mojo interface see the // comments in mojo/cros_camera_service.mojom. +// +// On ChromeOS the video capture service must run in the browser process, +// because parts of the code depend on global objects that are only available in +// the Browser process. Therefore, CameraHalDispatcherImpl must run in the +// browser process as well. +// See https://crbug.com/891961. class CAPTURE_EXPORT CameraHalDispatcherImpl final : public cros::mojom::CameraHalDispatcher, public cros::mojom::CameraHalServerCallbacks, @@ -177,6 +184,10 @@ class CAPTURE_EXPORT CameraHalDispatcherImpl final void GetJpegEncodeAccelerator( mojo::PendingReceiver<chromeos_camera::mojom::JpegEncodeAccelerator> jea_receiver) final; + void RegisterSensorClientWithToken( + mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> client, + const base::UnguessableToken& auth_token, + RegisterSensorClientWithTokenCallback callback) final; // CameraHalServerCallbacks implementations. void CameraDeviceActivityChange(int32_t camera_id, @@ -229,6 +240,11 @@ class CAPTURE_EXPORT CameraHalDispatcherImpl final void OnCameraHalServerConnectionError(); void OnCameraHalClientConnectionError(CameraClientObserver* client); + void RegisterSensorClientWithTokenOnUIThread( + mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> client, + const base::UnguessableToken& auth_token, + RegisterSensorClientWithTokenCallback callback); + void StopOnProxyThread(); void OnTraceLogEnabledOnProxyThread(); @@ -241,6 +257,7 @@ class CAPTURE_EXPORT CameraHalDispatcherImpl final base::Thread proxy_thread_; base::Thread blocking_io_thread_; + scoped_refptr<base::SequencedTaskRunner> main_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> blocking_io_task_runner_; @@ -275,6 +292,8 @@ class CAPTURE_EXPORT CameraHalDispatcherImpl final scoped_refptr<base::ObserverListThreadSafe<CameraPrivacySwitchObserver>> privacy_switch_observers_; + base::WeakPtrFactory<CameraHalDispatcherImpl> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(CameraHalDispatcherImpl); }; diff --git a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc index d5c6452a44a..f7b0265c2de 100644 --- a/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc +++ b/chromium/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc @@ -14,6 +14,7 @@ #include "base/synchronization/waitable_event.h" #include "base/test/task_environment.h" #include "media/capture/video/chromeos/mojom/camera_common.mojom.h" +#include "media/capture/video/chromeos/mojom/cros_camera_client.mojom.h" #include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -108,7 +109,7 @@ class CameraHalDispatcherImplTest : public ::testing::Test { } void DoLoop() { - run_loop_.reset(new base::RunLoop()); + run_loop_ = std::make_unique<base::RunLoop>(); run_loop_->Run(); } diff --git a/chromium/media/capture/video/chromeos/camera_metadata_utils.h b/chromium/media/capture/video/chromeos/camera_metadata_utils.h index 851b1fda550..d6b4a30b9f8 100644 --- a/chromium/media/capture/video/chromeos/camera_metadata_utils.h +++ b/chromium/media/capture/video/chromeos/camera_metadata_utils.h @@ -5,7 +5,7 @@ #ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_METADATA_UTILS_H_ #define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_METADATA_UTILS_H_ -#include "base/stl_util.h" +#include "base/containers/contains.h" #include "media/capture/capture_export.h" #include "media/capture/video/chromeos/mojom/camera_metadata.mojom.h" diff --git a/chromium/media/capture/video/chromeos/gpu_memory_buffer_tracker.cc b/chromium/media/capture/video/chromeos/gpu_memory_buffer_tracker.cc index 3a3f9a02a60..5b8c92838ea 100644 --- a/chromium/media/capture/video/chromeos/gpu_memory_buffer_tracker.cc +++ b/chromium/media/capture/video/chromeos/gpu_memory_buffer_tracker.cc @@ -19,7 +19,7 @@ GpuMemoryBufferTracker::~GpuMemoryBufferTracker() = default; bool GpuMemoryBufferTracker::Init(const gfx::Size& dimensions, VideoPixelFormat format, const mojom::PlaneStridesPtr& strides) { - base::Optional<gfx::BufferFormat> gfx_format = PixFormatVideoToGfx(format); + absl::optional<gfx::BufferFormat> gfx_format = PixFormatVideoToGfx(format); if (!gfx_format) { NOTREACHED() << "Unsupported VideoPixelFormat " << VideoPixelFormatToString(format); @@ -46,7 +46,7 @@ bool GpuMemoryBufferTracker::IsReusableForFormat( const gfx::Size& dimensions, VideoPixelFormat format, const mojom::PlaneStridesPtr& strides) { - base::Optional<gfx::BufferFormat> gfx_format = PixFormatVideoToGfx(format); + absl::optional<gfx::BufferFormat> gfx_format = PixFormatVideoToGfx(format); if (!gfx_format) { return false; } diff --git a/chromium/media/capture/video/chromeos/mock_vendor_tag_ops.h b/chromium/media/capture/video/chromeos/mock_vendor_tag_ops.h index d9bd4711941..8798e1c0c78 100644 --- a/chromium/media/capture/video/chromeos/mock_vendor_tag_ops.h +++ b/chromium/media/capture/video/chromeos/mock_vendor_tag_ops.h @@ -31,10 +31,10 @@ class MockVendorTagOps : public cros::mojom::VendorTagOps { MOCK_METHOD0(DoGetAllTags, std::vector<uint32_t>()); void GetAllTags(GetAllTagsCallback callback); - MOCK_METHOD1(DoGetSectionName, base::Optional<std::string>(uint32_t tag)); + MOCK_METHOD1(DoGetSectionName, absl::optional<std::string>(uint32_t tag)); void GetSectionName(uint32_t tag, GetSectionNameCallback callback); - MOCK_METHOD1(DoGetTagName, base::Optional<std::string>(uint32_t tag)); + MOCK_METHOD1(DoGetTagName, absl::optional<std::string>(uint32_t tag)); void GetTagName(uint32_t tag, GetTagNameCallback callback); MOCK_METHOD1(DoGetTagType, int32_t(uint32_t tag)); diff --git a/chromium/media/capture/video/chromeos/mojom/BUILD.gn b/chromium/media/capture/video/chromeos/mojom/BUILD.gn index cb72cea2f1b..4dfea8a0522 100644 --- a/chromium/media/capture/video/chromeos/mojom/BUILD.gn +++ b/chromium/media/capture/video/chromeos/mojom/BUILD.gn @@ -11,10 +11,12 @@ mojom("cros_camera") { "camera_common.mojom", "camera_metadata.mojom", "camera_metadata_tags.mojom", + "cros_camera_client.mojom", "cros_camera_service.mojom", ] deps = [ + "//chromeos/components/sensors/mojom", "//components/chromeos_camera/common", "//media/capture/mojom:image_capture", "//ui/gfx/geometry/mojom", diff --git a/chromium/media/capture/video/chromeos/mojom/camera3.mojom b/chromium/media/capture/video/chromeos/mojom/camera3.mojom index ce3e6506bc5..e0976bac90f 100644 --- a/chromium/media/capture/video/chromeos/mojom/camera3.mojom +++ b/chromium/media/capture/video/chromeos/mojom/camera3.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next min version: 4 +// Next min version: 5 module cros.mojom; @@ -86,11 +86,15 @@ struct Camera3Stream { uint32 data_space; Camera3StreamRotation rotation; [MinVersion=1] CropRotateScaleInfo? crop_rotate_scale_info; + // Required for camera HAL device API versions >= 3.5. + [MinVersion=4] string? physical_camera_id; }; struct Camera3StreamConfiguration { array<Camera3Stream> streams; Camera3StreamConfigurationMode operation_mode; + // Required for camera HAL device API versions >= 3.5. + [MinVersion=4] CameraMetadata? session_parameters; }; enum Camera3BufferStatus { @@ -167,11 +171,21 @@ enum Camera3RequestTemplate { CAMERA3_TEMPLATE_COUNT, }; +struct Camera3PhyscamMetadata { + // |id| is the camera ID of the physical camera, and comes from + // CameraCharacteristics.getPhysicalCameraIds(). All values are guaranteed to + // be integers. + int32 id; + CameraMetadata metadata; +}; + struct Camera3CaptureRequest { uint32 frame_number; CameraMetadata settings; Camera3StreamBuffer? input_buffer; array<Camera3StreamBuffer> output_buffers; + // Required for camera HAL device API versions >= 3.5. + [MinVersion=4] array<Camera3PhyscamMetadata>? physcam_settings; }; struct Camera3CaptureResult { @@ -180,6 +194,8 @@ struct Camera3CaptureResult { array<Camera3StreamBuffer>? output_buffers; Camera3StreamBuffer? input_buffer; uint32 partial_result; + // Required for camera HAL device API versions >= 3.5. + [MinVersion=4] array<Camera3PhyscamMetadata>? physcam_metadata; }; // Camera3CallbackOps is a translation of the camera3_callback_ops_t API diff --git a/chromium/media/capture/video/chromeos/mojom/camera_common.mojom b/chromium/media/capture/video/chromeos/mojom/camera_common.mojom index 15e2ab0e381..74263e98341 100644 --- a/chromium/media/capture/video/chromeos/mojom/camera_common.mojom +++ b/chromium/media/capture/video/chromeos/mojom/camera_common.mojom @@ -22,6 +22,13 @@ struct CameraResourceCost { uint32 resource_cost; }; +const uint32 CAMERA_DEVICE_API_VERSION_3_0 = 0x300; +const uint32 CAMERA_DEVICE_API_VERSION_3_1 = 0x301; +const uint32 CAMERA_DEVICE_API_VERSION_3_2 = 0x302; +const uint32 CAMERA_DEVICE_API_VERSION_3_3 = 0x303; +const uint32 CAMERA_DEVICE_API_VERSION_3_4 = 0x304; +const uint32 CAMERA_DEVICE_API_VERSION_3_5 = 0x305; + struct CameraInfo { CameraFacing facing; int32 orientation; diff --git a/chromium/media/capture/video/chromeos/mojom/cros_camera_client.mojom b/chromium/media/capture/video/chromeos/mojom/cros_camera_client.mojom new file mode 100644 index 00000000000..674b9bff613 --- /dev/null +++ b/chromium/media/capture/video/chromeos/mojom/cros_camera_client.mojom @@ -0,0 +1,23 @@ +// Copyright 2021 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. + +// Next min version: 1 + +module cros.mojom; + +import "media/capture/video/chromeos/mojom/camera_common.mojom"; + +// The CrOS camera HAL v3 Mojo client. +// +// Next method ID: 1 +interface CameraHalClient { + // A caller calls SetUpChannel to dispatch the established Mojo channel + // |camera_module| to the client. The CameraHalClient can create a Mojo + // channel to the camera HAL v3 adapter process with |camera_module|. + // SetUpChannel may be called multiple times. In cases such as the + // CameraHalServer which holds the original Mojo channel crashes, + // CameraHalDispatcher will call SetUpChannel again once a new CameraHalServer + // reconnects. + SetUpChannel@0(pending_remote<CameraModule> camera_module); +}; diff --git a/chromium/media/capture/video/chromeos/mojom/cros_camera_service.mojom b/chromium/media/capture/video/chromeos/mojom/cros_camera_service.mojom index b1a20076375..45c00de1e8e 100644 --- a/chromium/media/capture/video/chromeos/mojom/cros_camera_service.mojom +++ b/chromium/media/capture/video/chromeos/mojom/cros_camera_service.mojom @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next min version: 6 +// Next min version: 7 module cros.mojom; +import "chromeos/components/sensors/mojom/cros_sensor_service.mojom"; import "components/chromeos_camera/common/jpeg_encode_accelerator.mojom"; import "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom"; import "media/capture/video/chromeos/mojom/camera_common.mojom"; +import "media/capture/video/chromeos/mojom/cros_camera_client.mojom"; import "mojo/public/mojom/base/unguessable_token.mojom"; // CameraClientType indicates the type of a CameraHalClient. @@ -48,7 +50,7 @@ enum CameraPrivacySwitchState{ // channel to the server and pass the established Mojo channel to the client in // order to set up a Mojo channel between the client and the server. // -// Next method ID: 6 +// Next method ID: 7 interface CameraHalDispatcher { // [Deprecated in version 4] // A CameraHalServer calls RegisterServer to register itself with the @@ -88,6 +90,13 @@ interface CameraHalDispatcher { CameraClientType type, mojo_base.mojom.UnguessableToken auth_token) => (int32 result); + // A SensorHalClient calls RegisterSensorClient to register itself with + // SensorHalDispatcher through CameraHalDispatcher. |auth_token| is used to + // prove the caller has been granted permission to access SensorHalClient. + // CameraHalDispatcher will send back |result| as the errno. + [MinVersion=6] RegisterSensorClientWithToken@6( + pending_remote<chromeos.sensors.mojom.SensorHalClient> client, + mojo_base.mojom.UnguessableToken auth_token) => (int32 result); }; // The CrOS camera HAL v3 Mojo server. @@ -125,17 +134,3 @@ interface CameraHalServerCallbacks { [MinVersion=5] CameraPrivacySwitchStateChange@1(CameraPrivacySwitchState state); }; - -// The CrOS camera HAL v3 Mojo client. -// -// Next method ID: 1 -interface CameraHalClient { - // A caller calls SetUpChannel to dispatch the established Mojo channel - // |camera_module| to the client. The CameraHalClient can create a Mojo - // channel to the camera HAL v3 adapter process with |camera_module|. - // SetUpChannel may be called multiple times. In cases such as the - // CameraHalServer which holds the original Mojo channel crashes, - // CameraHalDispatcher will call SetUpChannel again once a new CameraHalServer - // reconnects. - SetUpChannel@0(pending_remote<CameraModule> camera_module); -}; diff --git a/chromium/media/capture/video/chromeos/pixel_format_utils.cc b/chromium/media/capture/video/chromeos/pixel_format_utils.cc index af5ded603ee..73237bc7569 100644 --- a/chromium/media/capture/video/chromeos/pixel_format_utils.cc +++ b/chromium/media/capture/video/chromeos/pixel_format_utils.cc @@ -62,7 +62,7 @@ uint32_t PixFormatVideoToDrm(VideoPixelFormat from) { } } -base::Optional<gfx::BufferFormat> PixFormatVideoToGfx( +absl::optional<gfx::BufferFormat> PixFormatVideoToGfx( VideoPixelFormat pixel_format) { switch (pixel_format) { case PIXEL_FORMAT_MJPEG: @@ -70,7 +70,7 @@ base::Optional<gfx::BufferFormat> PixFormatVideoToGfx( case PIXEL_FORMAT_NV12: return gfx::BufferFormat::YUV_420_BIPLANAR; default: - return base::nullopt; + return absl::nullopt; } } diff --git a/chromium/media/capture/video/chromeos/pixel_format_utils.h b/chromium/media/capture/video/chromeos/pixel_format_utils.h index be43491a9b4..f2ba1af221f 100644 --- a/chromium/media/capture/video/chromeos/pixel_format_utils.h +++ b/chromium/media/capture/video/chromeos/pixel_format_utils.h @@ -7,9 +7,9 @@ #include <vector> -#include "base/optional.h" #include "media/capture/video/chromeos/mojom/camera3.mojom.h" #include "media/capture/video_capture_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/buffer_types.h" namespace media { @@ -32,7 +32,7 @@ std::vector<ChromiumPixelFormat> PixFormatHalToChromium( uint32_t PixFormatVideoToDrm(VideoPixelFormat from); // Converts the video pixel format |pixel_format| to gfx::BufferFormat. -base::Optional<gfx::BufferFormat> PixFormatVideoToGfx( +absl::optional<gfx::BufferFormat> PixFormatVideoToGfx( VideoPixelFormat pixel_format); } // namespace media diff --git a/chromium/media/capture/video/chromeos/request_builder.cc b/chromium/media/capture/video/chromeos/request_builder.cc index c4fbbdf5310..b82fa2b60bd 100644 --- a/chromium/media/capture/video/chromeos/request_builder.cc +++ b/chromium/media/capture/video/chromeos/request_builder.cc @@ -23,10 +23,10 @@ RequestBuilder::~RequestBuilder() = default; cros::mojom::Camera3CaptureRequestPtr RequestBuilder::BuildRequest( std::set<StreamType> stream_types, cros::mojom::CameraMetadataPtr settings, - base::Optional<uint64_t> input_buffer_id) { + absl::optional<uint64_t> input_buffer_id) { auto capture_request = cros::mojom::Camera3CaptureRequest::New(); for (StreamType stream_type : stream_types) { - base::Optional<BufferInfo> buffer_info; + absl::optional<BufferInfo> buffer_info; if (IsInputStream(stream_type)) { DCHECK(input_buffer_id.has_value()); buffer_info = request_buffer_callback_.Run(stream_type, input_buffer_id); diff --git a/chromium/media/capture/video/chromeos/request_builder.h b/chromium/media/capture/video/chromeos/request_builder.h index 95f4d8e5b32..90d4207d526 100644 --- a/chromium/media/capture/video/chromeos/request_builder.h +++ b/chromium/media/capture/video/chromeos/request_builder.h @@ -9,10 +9,10 @@ #include <set> #include <vector> -#include "base/optional.h" #include "media/capture/video/chromeos/camera_device_delegate.h" #include "media/capture/video/chromeos/mojom/camera3.mojom.h" #include "media/capture/video_capture_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -33,7 +33,7 @@ struct BufferInfo { class CAPTURE_EXPORT RequestBuilder { public: using RequestBufferCallback = base::RepeatingCallback< - base::Optional<BufferInfo>(StreamType, base::Optional<uint64_t>)>; + absl::optional<BufferInfo>(StreamType, absl::optional<uint64_t>)>; RequestBuilder(CameraDeviceContext* device_context, // Callback to request buffer from StreamBufferManager. Having @@ -47,7 +47,7 @@ class CAPTURE_EXPORT RequestBuilder { cros::mojom::Camera3CaptureRequestPtr BuildRequest( std::set<StreamType> stream_types, cros::mojom::CameraMetadataPtr settings, - base::Optional<uint64_t> input_buffer_id); + absl::optional<uint64_t> input_buffer_id); private: cros::mojom::CameraBufferHandlePtr CreateCameraBufferHandle( diff --git a/chromium/media/capture/video/chromeos/request_manager.cc b/chromium/media/capture/video/chromeos/request_manager.cc index 14cfdaba413..2eab9764a32 100644 --- a/chromium/media/capture/video/chromeos/request_manager.cc +++ b/chromium/media/capture/video/chromeos/request_manager.cc @@ -14,6 +14,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/containers/contains.h" #include "base/posix/safe_strerror.h" #include "base/strings/string_number_conversions.h" #include "base/trace_event/trace_event.h" @@ -43,7 +44,8 @@ RequestManager::RequestManager( VideoCaptureBufferType buffer_type, std::unique_ptr<CameraBufferFactory> camera_buffer_factory, BlobifyCallback blobify_callback, - scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner) + scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner, + uint32_t device_api_version) : device_id_(device_id), callback_ops_(this, std::move(callback_ops_receiver)), capture_interface_(std::move(capture_interface)), @@ -58,7 +60,8 @@ RequestManager::RequestManager( ipc_task_runner_(std::move(ipc_task_runner)), capturing_(false), partial_result_count_(1), - first_frame_shutter_time_(base::TimeTicks()) { + first_frame_shutter_time_(base::TimeTicks()), + device_api_version_(device_api_version) { DCHECK(ipc_task_runner_->BelongsToCurrentThread()); DCHECK(callback_ops_.is_bound()); DCHECK(device_context_); @@ -287,7 +290,7 @@ void RequestManager::PrepareCaptureRequest() { std::set<StreamType> stream_types; cros::mojom::CameraMetadataPtr settings; TakePhotoCallback callback = base::NullCallback(); - base::Optional<uint64_t> input_buffer_id; + absl::optional<uint64_t> input_buffer_id; cros::mojom::Effect reprocess_effect = cros::mojom::Effect::NO_EFFECT; bool is_reprocess_request = false; @@ -369,6 +372,10 @@ void RequestManager::PrepareCaptureRequest() { if (!is_reprocess_request) { UpdateCaptureSettings(&capture_request->settings); } + if (device_api_version_ >= cros::mojom::CAMERA_DEVICE_API_VERSION_3_5) { + capture_request->physcam_settings = + std::vector<cros::mojom::Camera3PhyscamMetadataPtr>(); + } capture_interface_->ProcessCaptureRequest( std::move(capture_request), base::BindOnce(&RequestManager::OnProcessedCaptureRequest, GetWeakPtr())); @@ -378,7 +385,7 @@ bool RequestManager::TryPrepareReprocessRequest( std::set<StreamType>* stream_types, cros::mojom::CameraMetadataPtr* settings, TakePhotoCallback* callback, - base::Optional<uint64_t>* input_buffer_id, + absl::optional<uint64_t>* input_buffer_id, cros::mojom::Effect* reprocess_effect) { if (buffer_id_reprocess_job_info_map_.empty() || !stream_buffer_manager_->HasFreeBuffers(kYUVReprocessStreams)) { @@ -882,7 +889,7 @@ void RequestManager::SubmitCapturedPreviewRecordingBuffer( auto client_type = kStreamClientTypeMap[static_cast<int>(stream_type)]; if (video_capture_use_gmb_) { VideoCaptureFormat format; - base::Optional<VideoCaptureDevice::Client::Buffer> buffer = + absl::optional<VideoCaptureDevice::Client::Buffer> buffer = stream_buffer_manager_->AcquireBufferForClientById( stream_type, buffer_ipc_id, &format); CHECK(buffer); diff --git a/chromium/media/capture/video/chromeos/request_manager.h b/chromium/media/capture/video/chromeos/request_manager.h index 8739ceab41c..8b9fc55ad22 100644 --- a/chromium/media/capture/video/chromeos/request_manager.h +++ b/chromium/media/capture/video/chromeos/request_manager.h @@ -14,7 +14,6 @@ #include "base/containers/flat_map.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "media/capture/mojom/image_capture.mojom.h" #include "media/capture/video/chromeos/camera_app_device_impl.h" #include "media/capture/video/chromeos/camera_device_context.h" @@ -27,6 +26,7 @@ #include "media/capture/video_capture_types.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -93,7 +93,7 @@ class CAPTURE_EXPORT RequestManager final // NO_EFFECT if it is not a reprocess request. cros::mojom::Effect reprocess_effect; // The input buffer id for this capture request. - base::Optional<uint64_t> input_buffer_id; + absl::optional<uint64_t> input_buffer_id; // The orientation which is stored at the time the request is prepared. It // can be used to construct the reprocess job info when the result is back. int32_t orientation; @@ -107,7 +107,8 @@ class CAPTURE_EXPORT RequestManager final VideoCaptureBufferType buffer_type, std::unique_ptr<CameraBufferFactory> camera_buffer_factory, BlobifyCallback blobify_callback, - scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner); + scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner, + uint32_t device_api_version); ~RequestManager() override; // Sets up the stream context and allocate buffers according to the @@ -216,7 +217,7 @@ class CAPTURE_EXPORT RequestManager final bool TryPrepareReprocessRequest(std::set<StreamType>* stream_types, cros::mojom::CameraMetadataPtr* settings, TakePhotoCallback* callback, - base::Optional<uint64_t>* input_buffer_id, + absl::optional<uint64_t>* input_buffer_id, cros::mojom::Effect* reprocess_effect); bool TryPreparePreviewRequest(std::set<StreamType>* stream_types, @@ -371,6 +372,9 @@ class CAPTURE_EXPORT RequestManager final base::WeakPtr<CameraAppDeviceImpl> camera_app_device_; + // The API version of the camera device. + uint32_t device_api_version_; + base::WeakPtrFactory<RequestManager> weak_ptr_factory_{this}; DISALLOW_IMPLICIT_CONSTRUCTORS(RequestManager); diff --git a/chromium/media/capture/video/chromeos/request_manager_unittest.cc b/chromium/media/capture/video/chromeos/request_manager_unittest.cc index 90b9e83aafe..eb62aafc0f7 100644 --- a/chromium/media/capture/video/chromeos/request_manager_unittest.cc +++ b/chromium/media/capture/video/chromeos/request_manager_unittest.cc @@ -65,7 +65,8 @@ class FakeCameraBufferFactory : public CameraBufferFactory { gfx::BufferFormat format, gfx::BufferUsage usage) override { return unittest_internal::MockGpuMemoryBufferManager:: - CreateFakeGpuMemoryBuffer(size, format, usage, gpu::kNullSurfaceHandle); + CreateFakeGpuMemoryBuffer(size, format, usage, gpu::kNullSurfaceHandle, + nullptr); } ChromiumPixelFormat ResolveStreamBufferFormat( @@ -104,7 +105,8 @@ class RequestManagerTest : public ::testing::Test { [](const uint8_t* buffer, const uint32_t bytesused, const VideoCaptureFormat& capture_format, const int rotation) { return mojom::Blob::New(); }), - base::ThreadTaskRunnerHandle::Get()); + base::ThreadTaskRunnerHandle::Get(), + cros::mojom::CAMERA_DEVICE_API_VERSION_3_5); } } @@ -114,7 +116,7 @@ class RequestManagerTest : public ::testing::Test { } void DoLoop() { - run_loop_.reset(new base::RunLoop()); + run_loop_ = std::make_unique<base::RunLoop>(); run_loop_->Run(); } diff --git a/chromium/media/capture/video/chromeos/stream_buffer_manager.cc b/chromium/media/capture/video/chromeos/stream_buffer_manager.cc index 21bf391e673..2c107163365 100644 --- a/chromium/media/capture/video/chromeos/stream_buffer_manager.cc +++ b/chromium/media/capture/video/chromeos/stream_buffer_manager.cc @@ -63,7 +63,7 @@ gfx::GpuMemoryBuffer* StreamBufferManager::GetGpuMemoryBufferById( return it->second.gmb.get(); } -base::Optional<StreamBufferManager::Buffer> +absl::optional<StreamBufferManager::Buffer> StreamBufferManager::AcquireBufferForClientById(StreamType stream_type, uint64_t buffer_ipc_id, VideoCaptureFormat* format) { @@ -73,7 +73,7 @@ StreamBufferManager::AcquireBufferForClientById(StreamType stream_type, if (it == stream_context->buffers.end()) { LOG(ERROR) << "Invalid buffer: " << buffer_ipc_id << " for stream: " << stream_type; - return base::nullopt; + return absl::nullopt; } auto buffer_pair = std::move(it->second); stream_context->buffers.erase(it); @@ -92,7 +92,7 @@ StreamBufferManager::AcquireBufferForClientById(StreamType stream_type, gfx::Size(format->frame_size.height(), format->frame_size.width()); } - base::Optional<gfx::BufferFormat> gfx_format = + absl::optional<gfx::BufferFormat> gfx_format = PixFormatVideoToGfx(format->pixel_format); DCHECK(gfx_format); const auto& original_gmb = buffer_pair.gmb; @@ -154,7 +154,7 @@ StreamBufferManager::AcquireBufferForClientById(StreamType stream_type, return std::move(buffer_pair.vcd_buffer); } - base::Optional<gfx::BufferFormat> gfx_format = + absl::optional<gfx::BufferFormat> gfx_format = PixFormatVideoToGfx(format->pixel_format); DCHECK(gfx_format); auto rotated_gmb = gmb_support_->CreateGpuMemoryBufferImplFromHandle( @@ -320,9 +320,9 @@ cros::mojom::Camera3StreamPtr StreamBufferManager::GetStreamConfiguration( return stream_context_[stream_type]->stream.Clone(); } -base::Optional<BufferInfo> StreamBufferManager::RequestBufferForCaptureRequest( +absl::optional<BufferInfo> StreamBufferManager::RequestBufferForCaptureRequest( StreamType stream_type, - base::Optional<uint64_t> buffer_ipc_id) { + absl::optional<uint64_t> buffer_ipc_id) { VideoPixelFormat buffer_format = stream_context_[stream_type]->capture_format.pixel_format; uint32_t drm_format = PixFormatVideoToDrm(buffer_format); @@ -405,7 +405,7 @@ int StreamBufferManager::GetBufferKey(uint64_t buffer_ipc_id) { void StreamBufferManager::ReserveBufferFromFactory(StreamType stream_type) { auto& stream_context = stream_context_[stream_type]; - base::Optional<gfx::BufferFormat> gfx_format = + absl::optional<gfx::BufferFormat> gfx_format = PixFormatVideoToGfx(stream_context->capture_format.pixel_format); if (!gfx_format) { device_context_->SetErrorState( @@ -437,12 +437,12 @@ void StreamBufferManager::ReserveBufferFromFactory(StreamType stream_type) { int key = stream_context->buffers.size() + 1; stream_context->free_buffers.push(key); stream_context->buffers.insert( - std::make_pair(key, BufferPair(std::move(gmb), base::nullopt))); + std::make_pair(key, BufferPair(std::move(gmb), absl::nullopt))); } void StreamBufferManager::ReserveBufferFromPool(StreamType stream_type) { auto& stream_context = stream_context_[stream_type]; - base::Optional<gfx::BufferFormat> gfx_format = + absl::optional<gfx::BufferFormat> gfx_format = PixFormatVideoToGfx(stream_context->capture_format.pixel_format); if (!gfx_format) { device_context_->SetErrorState( @@ -489,7 +489,7 @@ void StreamBufferManager::DestroyCurrentStreamsAndBuffers() { StreamBufferManager::BufferPair::BufferPair( std::unique_ptr<gfx::GpuMemoryBuffer> input_gmb, - base::Optional<Buffer> input_vcd_buffer) + absl::optional<Buffer> input_vcd_buffer) : gmb(std::move(input_gmb)), vcd_buffer(std::move(input_vcd_buffer)) {} StreamBufferManager::BufferPair::BufferPair( diff --git a/chromium/media/capture/video/chromeos/stream_buffer_manager.h b/chromium/media/capture/video/chromeos/stream_buffer_manager.h index ba62fbe89f4..86ea140aa93 100644 --- a/chromium/media/capture/video/chromeos/stream_buffer_manager.h +++ b/chromium/media/capture/video/chromeos/stream_buffer_manager.h @@ -17,12 +17,12 @@ #include "base/containers/flat_map.h" #include "base/containers/queue.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "media/capture/video/chromeos/camera_device_context.h" #include "media/capture/video/chromeos/camera_device_delegate.h" #include "media/capture/video/chromeos/mojom/camera3.mojom.h" #include "media/capture/video_capture_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace gfx { @@ -68,7 +68,7 @@ class CAPTURE_EXPORT StreamBufferManager final { // // TODO(crbug.com/990682): Remove the |rotation| arg when we disable the // camera frame rotation for good. - base::Optional<Buffer> AcquireBufferForClientById(StreamType stream_type, + absl::optional<Buffer> AcquireBufferForClientById(StreamType stream_type, uint64_t buffer_ipc_id, VideoCaptureFormat* format); @@ -93,9 +93,9 @@ class CAPTURE_EXPORT StreamBufferManager final { // Requests buffer for specific stream type. If the |buffer_id| is provided, // it will use |buffer_id| as buffer id rather than using id from free // buffers. - base::Optional<BufferInfo> RequestBufferForCaptureRequest( + absl::optional<BufferInfo> RequestBufferForCaptureRequest( StreamType stream_type, - base::Optional<uint64_t> buffer_ipc_id); + absl::optional<uint64_t> buffer_ipc_id); // Releases buffer by marking it as free buffer. void ReleaseBufferFromCaptureResult(StreamType stream_type, @@ -113,7 +113,7 @@ class CAPTURE_EXPORT StreamBufferManager final { // BufferPair holding up to two types of handles of a stream buffer. struct BufferPair { BufferPair(std::unique_ptr<gfx::GpuMemoryBuffer> gmb, - base::Optional<Buffer> vcd_buffer); + absl::optional<Buffer> vcd_buffer); BufferPair(BufferPair&& other); ~BufferPair(); // The GpuMemoryBuffer interface of the stream buffer. @@ -124,7 +124,7 @@ class CAPTURE_EXPORT StreamBufferManager final { std::unique_ptr<gfx::GpuMemoryBuffer> gmb; // The VCD buffer reserved from the VCD buffer pool. This is only set when // the VCD runs GpuMemoryBuffer-based VideoCapture buffer. - base::Optional<Buffer> vcd_buffer; + absl::optional<Buffer> vcd_buffer; }; struct StreamContext { diff --git a/chromium/media/capture/video/chromeos/token_manager.cc b/chromium/media/capture/video/chromeos/token_manager.cc index 4e128d9348c..90e8f169d7a 100644 --- a/chromium/media/capture/video/chromeos/token_manager.cc +++ b/chromium/media/capture/video/chromeos/token_manager.cc @@ -13,6 +13,7 @@ #include "base/files/file_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "chromeos/components/sensors/ash/sensor_hal_dispatcher.h" namespace { @@ -66,6 +67,7 @@ bool WriteTokenToFile(const base::FilePath& token_path, namespace media { constexpr char TokenManager::kServerTokenPath[]; +constexpr char TokenManager::kServerSensorClientTokenPath[]; constexpr char TokenManager::kTestClientTokenPath[]; constexpr std::array<cros::mojom::CameraClientType, 3> TokenManager::kTrustedClientTypes; @@ -78,6 +80,16 @@ bool TokenManager::GenerateServerToken() { return WriteTokenToFile(base::FilePath(kServerTokenPath), server_token_); } +bool TokenManager::GenerateServerSensorClientToken() { + auto* sensor_hal_dispatcher = + chromeos::sensors::SensorHalDispatcher::GetInstance(); + if (!sensor_hal_dispatcher) + return false; + + return WriteTokenToFile(base::FilePath(kServerSensorClientTokenPath), + sensor_hal_dispatcher->GetTokenForTrustedClient()); +} + bool TokenManager::GenerateTestClientToken() { return WriteTokenToFile( base::FilePath(kTestClientTokenPath), @@ -122,7 +134,17 @@ bool TokenManager::AuthenticateServer(const base::UnguessableToken& token) { return server_token_ == token; } -base::Optional<cros::mojom::CameraClientType> TokenManager::AuthenticateClient( +bool TokenManager::AuthenticateServerSensorClient( + const base::UnguessableToken& token) { + auto* sensor_hal_dispatcher = + chromeos::sensors::SensorHalDispatcher::GetInstance(); + if (!sensor_hal_dispatcher) + return false; + + return sensor_hal_dispatcher->AuthenticateClient(token); +} + +absl::optional<cros::mojom::CameraClientType> TokenManager::AuthenticateClient( cros::mojom::CameraClientType type, const base::UnguessableToken& token) { base::AutoLock l(client_token_map_lock_); @@ -133,11 +155,11 @@ base::Optional<cros::mojom::CameraClientType> TokenManager::AuthenticateClient( return client_token_map_pair.first; } } - return base::nullopt; + return absl::nullopt; } auto& token_set = client_token_map_[type]; if (token_set.find(token) == token_set.end()) { - return base::nullopt; + return absl::nullopt; } return type; } diff --git a/chromium/media/capture/video/chromeos/token_manager.h b/chromium/media/capture/video/chromeos/token_manager.h index c4a75ad5f9f..0508aae905c 100644 --- a/chromium/media/capture/video/chromeos/token_manager.h +++ b/chromium/media/capture/video/chromeos/token_manager.h @@ -9,17 +9,19 @@ #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" -#include "base/optional.h" #include "base/thread_annotations.h" #include "base/unguessable_token.h" #include "media/capture/capture_export.h" #include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { class CAPTURE_EXPORT TokenManager { public: static constexpr char kServerTokenPath[] = "/run/camera_tokens/server/token"; + static constexpr char kServerSensorClientTokenPath[] = + "/run/camera_tokens/server/sensor_client_token"; static constexpr char kTestClientTokenPath[] = "/run/camera_tokens/testing/token"; static constexpr std::array<cros::mojom::CameraClientType, 3> @@ -31,6 +33,7 @@ class CAPTURE_EXPORT TokenManager { ~TokenManager(); bool GenerateServerToken(); + bool GenerateServerSensorClientToken(); bool GenerateTestClientToken(); @@ -41,13 +44,14 @@ class CAPTURE_EXPORT TokenManager { void UnregisterPluginVmToken(const base::UnguessableToken& token); bool AuthenticateServer(const base::UnguessableToken& token); + bool AuthenticateServerSensorClient(const base::UnguessableToken& token); // Authenticates client with the given |type| and |token|. When |type| is // cros::mojom::CameraClientType::UNKNOWN, it tries to figure out the actual // client type by the supplied |token|. If authentication succeeds, it returns // the authenticated type of the client. If authentication fails, - // base::nullopt is returned. - base::Optional<cros::mojom::CameraClientType> AuthenticateClient( + // absl::nullopt is returned. + absl::optional<cros::mojom::CameraClientType> AuthenticateClient( cros::mojom::CameraClientType type, const base::UnguessableToken& token); diff --git a/chromium/media/capture/video/chromeos/vendor_tag_ops_delegate.cc b/chromium/media/capture/video/chromeos/vendor_tag_ops_delegate.cc index 013b267fa77..0f36b69eb6c 100644 --- a/chromium/media/capture/video/chromeos/vendor_tag_ops_delegate.cc +++ b/chromium/media/capture/video/chromeos/vendor_tag_ops_delegate.cc @@ -96,7 +96,7 @@ void VendorTagOpsDelegate::OnGotAllTags(size_t tag_count, void VendorTagOpsDelegate::OnGotSectionName( uint32_t tag, - const base::Optional<std::string>& section_name) { + const absl::optional<std::string>& section_name) { DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); if (!section_name.has_value()) { LOG(ERROR) << "Failed to get section name of tag " << std::hex @@ -113,7 +113,7 @@ void VendorTagOpsDelegate::OnGotSectionName( void VendorTagOpsDelegate::OnGotTagName( uint32_t tag, - const base::Optional<std::string>& tag_name) { + const absl::optional<std::string>& tag_name) { DCHECK(ipc_task_runner_->RunsTasksInCurrentSequence()); if (!tag_name.has_value()) { LOG(ERROR) << "Failed to get tag name of tag " << std::hex << std::showbase diff --git a/chromium/media/capture/video/chromeos/vendor_tag_ops_delegate.h b/chromium/media/capture/video/chromeos/vendor_tag_ops_delegate.h index cd963e0cdd8..a5e3aa8e2dc 100644 --- a/chromium/media/capture/video/chromeos/vendor_tag_ops_delegate.h +++ b/chromium/media/capture/video/chromeos/vendor_tag_ops_delegate.h @@ -48,8 +48,8 @@ class VendorTagOpsDelegate { void OnGotTagCount(int32_t tag_count); void OnGotAllTags(size_t tag_count, const std::vector<uint32_t>& tags); void OnGotSectionName(uint32_t tag, - const base::Optional<std::string>& section_name); - void OnGotTagName(uint32_t tag, const base::Optional<std::string>& tag_name); + const absl::optional<std::string>& section_name); + void OnGotTagName(uint32_t tag, const absl::optional<std::string>& tag_name); void OnGotTagType(uint32_t tag, int32_t type); scoped_refptr<base::SequencedTaskRunner> ipc_task_runner_; diff --git a/chromium/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc b/chromium/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc index ebb424ceb25..a1e7cdf555b 100644 --- a/chromium/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc +++ b/chromium/media/capture/video/chromeos/video_capture_device_chromeos_delegate.cc @@ -265,6 +265,8 @@ void VideoCaptureDeviceChromeOSDelegate::CloseDevice( DCHECK(capture_task_runner_->BelongsToCurrentThread()); if (!camera_device_delegate_) { + if (!unblock_suspend_token.is_empty()) + power_manager_client_proxy_->UnblockSuspend(unblock_suspend_token); return; } // We do our best to allow the camera HAL cleanly shut down the device. In diff --git a/chromium/media/capture/video/chromeos/video_capture_features_chromeos.cc b/chromium/media/capture/video/chromeos/video_capture_features_chromeos.cc index 6e07d3913ad..81919624dac 100644 --- a/chromium/media/capture/video/chromeos/video_capture_features_chromeos.cc +++ b/chromium/media/capture/video/chromeos/video_capture_features_chromeos.cc @@ -12,5 +12,9 @@ namespace features { const base::Feature kDisableCameraFrameRotationAtSource{ "DisableCameraFrameRotationAtSource", base::FEATURE_DISABLED_BY_DEFAULT}; +// If enabled, will force enable face AE if the camera supports. +const base::Feature kForceEnableFaceAe{"ForceEnableFaceAe", + base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace media diff --git a/chromium/media/capture/video/chromeos/video_capture_features_chromeos.h b/chromium/media/capture/video/chromeos/video_capture_features_chromeos.h index f9d1705f366..04633a854b3 100644 --- a/chromium/media/capture/video/chromeos/video_capture_features_chromeos.h +++ b/chromium/media/capture/video/chromeos/video_capture_features_chromeos.h @@ -12,6 +12,7 @@ namespace media { namespace features { CAPTURE_EXPORT extern const base::Feature kDisableCameraFrameRotationAtSource; +CAPTURE_EXPORT extern const base::Feature kForceEnableFaceAe; } // namespace features } // namespace media diff --git a/chromium/media/capture/video/chromeos/video_capture_jpeg_decoder.h b/chromium/media/capture/video/chromeos/video_capture_jpeg_decoder.h index 59850884926..21a51d09df2 100644 --- a/chromium/media/capture/video/chromeos/video_capture_jpeg_decoder.h +++ b/chromium/media/capture/video/chromeos/video_capture_jpeg_decoder.h @@ -7,7 +7,6 @@ #include "base/callback.h" #include "media/capture/capture_export.h" -#include "media/capture/mojom/video_capture_types.mojom.h" #include "media/capture/video/video_capture_device.h" #include "media/capture/video/video_frame_receiver.h" diff --git a/chromium/media/capture/video/create_video_capture_device_factory.cc b/chromium/media/capture/video/create_video_capture_device_factory.cc index 435ede8bd3b..f234d6822f3 100644 --- a/chromium/media/capture/video/create_video_capture_device_factory.cc +++ b/chromium/media/capture/video/create_video_capture_device_factory.cc @@ -16,7 +16,6 @@ #elif BUILDFLAG(IS_CHROMEOS_ASH) #include "media/capture/video/chromeos/public/cros_features.h" #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h" -#include "media/capture/video/linux/video_capture_device_factory_linux.h" #elif defined(OS_WIN) #include "media/capture/video/win/video_capture_device_factory_win.h" #elif defined(OS_MAC) @@ -56,34 +55,13 @@ CreateFakeVideoCaptureDeviceFactory() { } } -#if BUILDFLAG(IS_CHROMEOS_ASH) -std::unique_ptr<VideoCaptureDeviceFactory> -CreateChromeOSVideoCaptureDeviceFactory( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { - // On Chrome OS we have to support two use cases: - // - // 1. For devices that have the camera HAL v3 service running on Chrome OS, - // we use the HAL v3 capture device which VideoCaptureDeviceFactoryChromeOS - // provides. - // 2. Existing devices that use UVC cameras need to use the V4L2 capture - // device which VideoCaptureDeviceFacotoryLinux provides; there are also - // some special devices that may never be able to implement a camera HAL - // v3. - if (ShouldUseCrosCameraService()) { - return std::make_unique<VideoCaptureDeviceFactoryChromeOS>(ui_task_runner); - } else { - return std::make_unique<VideoCaptureDeviceFactoryLinux>(ui_task_runner); - } -} -#endif // BUILDFLAG(IS_CHROMEOS_ASH) - std::unique_ptr<VideoCaptureDeviceFactory> CreatePlatformSpecificVideoCaptureDeviceFactory( scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { #if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) return std::make_unique<VideoCaptureDeviceFactoryLinux>(ui_task_runner); #elif BUILDFLAG(IS_CHROMEOS_ASH) - return CreateChromeOSVideoCaptureDeviceFactory(ui_task_runner); + return std::make_unique<VideoCaptureDeviceFactoryChromeOS>(ui_task_runner); #elif defined(OS_WIN) return std::make_unique<VideoCaptureDeviceFactoryWin>(); #elif defined(OS_MAC) diff --git a/chromium/media/capture/video/fake_video_capture_device_factory.cc b/chromium/media/capture/video/fake_video_capture_device_factory.cc index b96840f0a63..222e0ab1582 100644 --- a/chromium/media/capture/video/fake_video_capture_device_factory.cc +++ b/chromium/media/capture/video/fake_video_capture_device_factory.cc @@ -267,9 +267,9 @@ void FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString( FakeVideoCaptureDevice::DisplayMediaType::ANY; while (option_tokenizer.GetNext()) { - std::vector<std::string> param = - base::SplitString(option_tokenizer.token(), "=", base::TRIM_WHITESPACE, - base::SPLIT_WANT_NONEMPTY); + std::vector<base::StringPiece> param = base::SplitStringPiece( + option_tokenizer.token_piece(), "=", base::TRIM_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); if (param.size() != 2u) { LOG(WARNING) << "Forget a value '" << options_string diff --git a/chromium/media/capture/video/file_video_capture_device.cc b/chromium/media/capture/video/file_video_capture_device.cc index f70ee57eed8..295db70a9eb 100644 --- a/chromium/media/capture/video/file_video_capture_device.cc +++ b/chromium/media/capture/video/file_video_capture_device.cc @@ -13,6 +13,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" +#include "base/numerics/ranges.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" @@ -28,6 +29,23 @@ namespace media { +namespace { + +int gcd(int a, int b) { + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +} // namespace + static const int kY4MHeaderMaxSize = 200; static const char kY4MSimpleFrameDelimiter[] = "FRAME"; static const int kY4MSimpleFrameDelimiterSize = 6; @@ -307,6 +325,124 @@ std::unique_ptr<VideoFileParser> FileVideoCaptureDevice::GetVideoFileParser( return file_parser; } +std::unique_ptr<uint8_t[]> FileVideoCaptureDevice::CropPTZRegion( + const uint8_t* frame, + size_t frame_buffer_size) { + CHECK(frame); + + const gfx::Size& frame_size = capture_format_.frame_size; + uint32_t fourcc; + std::unique_ptr<uint8_t[]> jpeg_to_i420_buffer_; + switch (capture_format_.pixel_format) { + case PIXEL_FORMAT_MJPEG: + // |libyuv::ConvertToI420| don't support cropping MJPG into different + // width and thus require transform to i420 first. + if ([&frame, &frame_buffer_size, &frame_size, &jpeg_to_i420_buffer_]() { + const size_t i420_buffer_size = + VideoFrame::AllocationSize(PIXEL_FORMAT_I420, frame_size); + jpeg_to_i420_buffer_.reset(new uint8_t[i420_buffer_size]); + + uint8_t* dst_yp = jpeg_to_i420_buffer_.get(); + uint8_t* dst_up = + dst_yp + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 0, frame_size) + .GetArea(); + uint8_t* dst_vp = + dst_up + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 1, frame_size) + .GetArea(); + int dst_yp_stride = frame_size.width(); + int dst_up_stride = dst_yp_stride / 2; + int dst_vp_stride = dst_yp_stride / 2; + + return libyuv::ConvertToI420( + frame, frame_buffer_size, dst_yp, dst_yp_stride, dst_up, + dst_up_stride, dst_vp, dst_vp_stride, /* crop_x */ 0, + /* crop_y */ 0, + /* src_width */ frame_size.width(), + /* src_height */ frame_size.height(), + /* crop_width */ frame_size.width(), + /* crop_height */ frame_size.height(), + libyuv::RotationMode::kRotate0, libyuv::FOURCC_MJPG); + }()) { + LOG(ERROR) << "Failed to convert MJPEG to i420 for ptz transform"; + } + frame = jpeg_to_i420_buffer_.get(); + frame_buffer_size = + VideoFrame::AllocationSize(PIXEL_FORMAT_I420, frame_size); + ABSL_FALLTHROUGH_INTENDED; + case PIXEL_FORMAT_I420: + fourcc = libyuv::FOURCC_I420; + break; + default: + LOG(ERROR) << "Unsupported file format for ptz transform."; + return {}; + } + + // Crop zoomed region. + const int crop_width = (zoom_max_levels_ - zoom_) * aspect_ratio_numerator_; + const int crop_height = + (zoom_max_levels_ - zoom_) * aspect_ratio_denominator_; + const gfx::Size crop_size(crop_width, crop_height); + const int crop_x = + std::min(pan_ * aspect_ratio_numerator_, frame_size.width() - crop_width); + const int crop_y = + std::min((zoom_max_levels_ - 1 - tilt_) * aspect_ratio_denominator_, + frame_size.height() - crop_height); + const size_t crop_buffer_size = + VideoFrame::AllocationSize(PIXEL_FORMAT_I420, crop_size); + std::unique_ptr<uint8_t[]> crop_frame(new uint8_t[crop_buffer_size]); + + uint8_t* crop_yp = crop_frame.get(); + uint8_t* crop_up = + crop_yp + + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 0, crop_size).GetArea(); + uint8_t* crop_vp = + crop_up + + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 1, crop_size).GetArea(); + int crop_yp_stride = crop_width; + int crop_up_stride = crop_yp_stride / 2; + int crop_vp_stride = crop_yp_stride / 2; + + if (libyuv::ConvertToI420(frame, frame_buffer_size, crop_yp, crop_yp_stride, + crop_up, crop_up_stride, crop_vp, crop_vp_stride, + crop_x, crop_y, frame_size.width(), + frame_size.height(), crop_width, crop_height, + libyuv::RotationMode::kRotate0, fourcc)) { + LOG(ERROR) << "Failed to crop image for ptz transform."; + return {}; + } + + if (crop_size == frame_size) + return crop_frame; + + // Scale cropped region to original size. + const auto& scale_size = frame_size; + const size_t scale_buffer_size = + VideoFrame::AllocationSize(PIXEL_FORMAT_I420, scale_size); + std::unique_ptr<uint8_t[]> scale_frame(new uint8_t[scale_buffer_size]); + + uint8_t* scale_yp = scale_frame.get(); + uint8_t* scale_up = + scale_yp + + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 0, scale_size).GetArea(); + uint8_t* scale_vp = + scale_up + + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 1, scale_size).GetArea(); + int scale_yp_stride = scale_size.width(); + int scale_up_stride = scale_yp_stride / 2; + int scale_vp_stride = scale_yp_stride / 2; + + if (libyuv::I420Scale(crop_yp, crop_yp_stride, crop_up, crop_up_stride, + crop_vp, crop_vp_stride, crop_width, crop_height, + scale_yp, scale_yp_stride, scale_up, scale_up_stride, + scale_vp, scale_vp_stride, scale_size.width(), + scale_size.height(), + libyuv::FilterMode::kFilterBilinear)) { + LOG(ERROR) << "Failed to scale image for ptz transform."; + return {}; + } + return scale_frame; +} + FileVideoCaptureDevice::FileVideoCaptureDevice( const base::FilePath& file_path, std::unique_ptr<gpu::GpuMemoryBufferSupport> gmb_support) @@ -348,6 +484,15 @@ void FileVideoCaptureDevice::StopAndDeAllocate() { void FileVideoCaptureDevice::GetPhotoState(GetPhotoStateCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); + CHECK(capture_thread_.IsRunning()); + + capture_thread_.task_runner()->PostTask( + FROM_HERE, base::BindOnce(&FileVideoCaptureDevice::OnGetPhotoState, + base::Unretained(this), std::move(callback))); +} + +void FileVideoCaptureDevice::OnGetPhotoState(GetPhotoStateCallback callback) { + DCHECK(capture_thread_.task_runner()->BelongsToCurrentThread()); auto photo_capabilities = mojo::CreateEmptyPhotoState(); @@ -356,12 +501,44 @@ void FileVideoCaptureDevice::GetPhotoState(GetPhotoStateCallback callback) { int width = capture_format_.frame_size.width(); photo_capabilities->width = mojom::Range::New(width, width, width, 0); + if (zoom_max_levels_ > 0) { + photo_capabilities->pan = mojom::Range::New(); + photo_capabilities->pan->current = pan_; + photo_capabilities->pan->max = zoom_max_levels_ - 1; + photo_capabilities->pan->min = 0; + photo_capabilities->pan->step = 1; + + photo_capabilities->tilt = mojom::Range::New(); + photo_capabilities->tilt->current = tilt_; + photo_capabilities->tilt->max = zoom_max_levels_ - 1; + photo_capabilities->tilt->min = 0; + photo_capabilities->tilt->step = 1; + + photo_capabilities->zoom = mojom::Range::New(); + photo_capabilities->zoom->current = zoom_; + photo_capabilities->zoom->max = zoom_max_levels_ - 1; + photo_capabilities->zoom->min = 0; + photo_capabilities->zoom->step = 1; + } + std::move(callback).Run(std::move(photo_capabilities)); } void FileVideoCaptureDevice::SetPhotoOptions(mojom::PhotoSettingsPtr settings, SetPhotoOptionsCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); + CHECK(capture_thread_.IsRunning()); + + capture_thread_.task_runner()->PostTask( + FROM_HERE, base::BindOnce(&FileVideoCaptureDevice::OnSetPhotoOptions, + base::Unretained(this), std::move(settings), + std::move(callback))); +} + +void FileVideoCaptureDevice::OnSetPhotoOptions( + mojom::PhotoSettingsPtr settings, + SetPhotoOptionsCallback callback) { + DCHECK(capture_thread_.task_runner()->BelongsToCurrentThread()); if (settings->has_height && settings->height != capture_format_.frame_size.height()) { @@ -383,11 +560,21 @@ void FileVideoCaptureDevice::SetPhotoOptions(mojom::PhotoSettingsPtr settings, settings->has_color_temperature || settings->has_iso || settings->has_brightness || settings->has_contrast || settings->has_saturation || settings->has_sharpness || - settings->has_focus_distance || settings->has_pan || settings->has_tilt || - settings->has_zoom || settings->has_fill_light_mode) { + settings->has_focus_distance || settings->has_fill_light_mode) { return; } + if (settings->has_pan) { + pan_ = base::ClampToRange(int(settings->pan), 0, zoom_max_levels_); + } + + if (settings->has_tilt) { + tilt_ = base::ClampToRange(int(settings->tilt), 0, zoom_max_levels_); + } + if (settings->has_zoom) { + zoom_ = base::ClampToRange(int(settings->zoom), 0, zoom_max_levels_); + } + std::move(callback).Run(true); } @@ -417,6 +604,16 @@ void FileVideoCaptureDevice::OnAllocateAndStart( return; } + zoom_max_levels_ = gcd(capture_format_.frame_size.width(), + capture_format_.frame_size.height()); + aspect_ratio_numerator_ = + capture_format_.frame_size.width() / zoom_max_levels_; + aspect_ratio_denominator_ = + capture_format_.frame_size.height() / zoom_max_levels_; + zoom_ = 0; + pan_ = 0; + tilt_ = zoom_max_levels_ - 1; + DVLOG(1) << "Opened video file " << capture_format_.frame_size.ToString() << ", fps: " << capture_format_.frame_rate; client_->OnStarted(); @@ -442,8 +639,11 @@ void FileVideoCaptureDevice::OnCaptureTask() { // Give the captured frame to the client. int frame_size = 0; const uint8_t* frame_ptr = file_parser_->GetNextFrame(&frame_size); - DCHECK(frame_size); CHECK(frame_ptr); + + auto ptz_frame = CropPTZRegion(frame_ptr, frame_size); + CHECK(ptz_frame); + const base::TimeTicks current_time = base::TimeTicks::Now(); if (first_ref_time_.is_null()) first_ref_time_ = current_time; @@ -462,12 +662,12 @@ void FileVideoCaptureDevice::OnCaptureTask() { return; } ScopedNV12GpuMemoryBufferMapping scoped_mapping(std::move(gmb)); - const uint8_t* src_y_plane = frame_ptr; + const uint8_t* src_y_plane = ptz_frame.get(); const uint8_t* src_u_plane = - frame_ptr + + ptz_frame.get() + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 0, buffer_size).GetArea(); const uint8_t* src_v_plane = - frame_ptr + + ptz_frame.get() + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 0, buffer_size).GetArea() + VideoFrame::PlaneSize(PIXEL_FORMAT_I420, 1, buffer_size).GetArea(); libyuv::I420ToNV12( @@ -487,7 +687,7 @@ void FileVideoCaptureDevice::OnCaptureTask() { // Leave the color space unset for compatibility purposes but this // information should be retrieved from the container when possible. client_->OnIncomingCapturedData( - frame_ptr, frame_size, capture_format_, gfx::ColorSpace(), + ptz_frame.get(), frame_size, capture_format_, gfx::ColorSpace(), 0 /* clockwise_rotation */, false /* flip_y */, current_time, current_time - first_ref_time_); } @@ -498,7 +698,7 @@ void FileVideoCaptureDevice::OnCaptureTask() { take_photo_callbacks_.pop(); mojom::BlobPtr blob = - RotateAndBlobify(frame_ptr, frame_size, capture_format_, 0); + RotateAndBlobify(ptz_frame.get(), frame_size, capture_format_, 0); if (!blob) continue; diff --git a/chromium/media/capture/video/file_video_capture_device.h b/chromium/media/capture/video/file_video_capture_device.h index 796202cc778..a08187a58d0 100644 --- a/chromium/media/capture/video/file_video_capture_device.h +++ b/chromium/media/capture/video/file_video_capture_device.h @@ -10,6 +10,7 @@ #include <memory> #include <string> +#include "base/containers/queue.h" #include "base/files/file.h" #include "base/files/memory_mapped_file.h" #include "base/macros.h" @@ -67,9 +68,16 @@ class CAPTURE_EXPORT FileVideoCaptureDevice : public VideoCaptureDevice { const base::FilePath& file_path, VideoCaptureFormat* video_format); + // Crops frame with respect to PTZ settings. + std::unique_ptr<uint8_t[]> CropPTZRegion(const uint8_t* frame, + size_t frame_buffer_size); + // Called on the |capture_thread_|. void OnAllocateAndStart(const VideoCaptureParams& params, std::unique_ptr<Client> client); + void OnGetPhotoState(GetPhotoStateCallback callback); + void OnSetPhotoOptions(mojom::PhotoSettingsPtr settings, + SetPhotoOptionsCallback callback); void OnStopAndDeAllocate(); const uint8_t* GetNextFrame(); void OnCaptureTask(); @@ -86,6 +94,21 @@ class CAPTURE_EXPORT FileVideoCaptureDevice : public VideoCaptureDevice { const base::FilePath file_path_; std::unique_ptr<VideoFileParser> file_parser_; VideoCaptureFormat capture_format_; + + // The max zoom-able integer level that can be zoomed-in with respect to + // aspect ratio of original file. + int zoom_max_levels_; + // Numerator of file aspect ratio. + int aspect_ratio_numerator_; + // Denominator of file aspect ratio. + int aspect_ratio_denominator_; + // Current zoom values. + int zoom_; + // Current pan values. + int pan_; + // Current tilt values. + int tilt_; + // Target time for the next frame. base::TimeTicks next_frame_time_; // The system time when we receive the first frame. diff --git a/chromium/media/capture/video/file_video_capture_device_factory.cc b/chromium/media/capture/video/file_video_capture_device_factory.cc index 29fd7c77a0e..e318860c5cb 100644 --- a/chromium/media/capture/video/file_video_capture_device_factory.cc +++ b/chromium/media/capture/video/file_video_capture_device_factory.cc @@ -23,7 +23,6 @@ base::FilePath GetFilePathFromCommandLine() { base::FilePath command_line_file_path = base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( switches::kUseFileForFakeVideoCapture); - CHECK(!command_line_file_path.empty()); return command_line_file_path; } diff --git a/chromium/media/capture/video/file_video_capture_device_unittest.cc b/chromium/media/capture/video/file_video_capture_device_unittest.cc index 5f15cb60a95..a92f5729fb1 100644 --- a/chromium/media/capture/video/file_video_capture_device_unittest.cc +++ b/chromium/media/capture/video/file_video_capture_device_unittest.cc @@ -9,6 +9,7 @@ #include <utility> #include "base/bind.h" +#include "base/synchronization/waitable_event.h" #include "base/test/task_environment.h" #include "media/base/bind_to_current_loop.h" #include "media/base/test_data_util.h" @@ -25,16 +26,33 @@ namespace media { namespace { +const base::TimeDelta kWaitTimeoutSecs = base::TimeDelta::FromSeconds(3); + class MockImageCaptureClient { public: + MockImageCaptureClient() + : wait_get_photo_state_(base::WaitableEvent::ResetPolicy::AUTOMATIC), + wait_set_photo_state_(base::WaitableEvent::ResetPolicy::AUTOMATIC) {} + // GMock doesn't support move-only arguments, so we use this forward method. void DoOnGetPhotoState(mojom::PhotoStatePtr state) { state_ = std::move(state); + wait_get_photo_state_.Signal(); + } + + const mojom::PhotoState* State() { + EXPECT_TRUE(wait_get_photo_state_.TimedWait(kWaitTimeoutSecs)); + return state_.get(); } - const mojom::PhotoState* state() { return state_.get(); } + void DoOnSetPhotoOptions(bool success) { + EXPECT_TRUE(success); + wait_set_photo_state_.Signal(); + } - MOCK_METHOD1(OnCorrectSetPhotoOptions, void(bool)); + void WaitSetPhotoOptions() { + EXPECT_TRUE(wait_set_photo_state_.TimedWait(kWaitTimeoutSecs)); + } // GMock doesn't support move-only arguments, so we use this forward method. void DoOnPhotoTaken(mojom::BlobPtr blob) { @@ -44,7 +62,10 @@ class MockImageCaptureClient { MOCK_METHOD0(OnCorrectPhotoTaken, void(void)); private: + base::WaitableEvent wait_get_photo_state_; mojom::PhotoStatePtr state_; + + base::WaitableEvent wait_set_photo_state_; }; } // namespace @@ -82,6 +103,22 @@ class FileVideoCaptureDeviceTest : public ::testing::Test { run_loop_->Run(); } + void SetPhotoOptions(double pan, double tilt, double zoom) { + mojom::PhotoSettingsPtr photo_settings = mojom::PhotoSettings::New(); + photo_settings->has_pan = photo_settings->has_tilt = + photo_settings->has_zoom = true; + photo_settings->pan = pan; + photo_settings->tilt = tilt; + photo_settings->zoom = zoom; + + VideoCaptureDevice::SetPhotoOptionsCallback scoped_set_callback = + base::BindOnce(&MockImageCaptureClient::DoOnSetPhotoOptions, + base::Unretained(&image_capture_client_)); + device_->SetPhotoOptions(std::move(photo_settings), + std::move(scoped_set_callback)); + image_capture_client_.WaitSetPhotoOptions(); + } + std::unique_ptr<NiceMockVideoCaptureDeviceClient> client_; MockImageCaptureClient image_capture_client_; std::unique_ptr<VideoCaptureDevice> device_; @@ -97,21 +134,41 @@ TEST_F(FileVideoCaptureDeviceTest, GetPhotoState) { device_->GetPhotoState(std::move(scoped_get_callback)); - const mojom::PhotoState* state = image_capture_client_.state(); + const mojom::PhotoState* state = image_capture_client_.State(); EXPECT_TRUE(state); + + // From gcd of "bear.mjpeg" width=320, height=192. + const int kZoomMaxLevels = 64; + + const mojom::RangePtr& pan = state->pan; + EXPECT_TRUE(pan); + EXPECT_EQ(pan->current, 0); + EXPECT_EQ(pan->max, kZoomMaxLevels - 1); + EXPECT_EQ(pan->min, 0); + EXPECT_EQ(pan->step, 1); + + const mojom::RangePtr& tilt = state->tilt; + EXPECT_TRUE(tilt); + EXPECT_EQ(tilt->current, kZoomMaxLevels - 1); + EXPECT_EQ(tilt->max, kZoomMaxLevels - 1); + EXPECT_EQ(tilt->min, 0); + EXPECT_EQ(tilt->step, 1); + + const mojom::RangePtr& zoom = state->zoom; + EXPECT_TRUE(zoom); + EXPECT_EQ(zoom->current, 0); + EXPECT_EQ(zoom->max, kZoomMaxLevels - 1); + EXPECT_EQ(zoom->min, 0); + EXPECT_EQ(zoom->step, 1); } TEST_F(FileVideoCaptureDeviceTest, SetPhotoOptions) { - mojom::PhotoSettingsPtr photo_settings = mojom::PhotoSettings::New(); - VideoCaptureDevice::SetPhotoOptionsCallback scoped_set_callback = - base::BindOnce(&MockImageCaptureClient::OnCorrectSetPhotoOptions, - base::Unretained(&image_capture_client_)); - EXPECT_CALL(image_capture_client_, OnCorrectSetPhotoOptions(true)).Times(1); - device_->SetPhotoOptions(std::move(photo_settings), - std::move(scoped_set_callback)); + SetPhotoOptions(1.0, 1.0, 1.0); } TEST_F(FileVideoCaptureDeviceTest, TakePhoto) { + SetPhotoOptions(1.0, 1.0, 1.0); + VideoCaptureDevice::TakePhotoCallback scoped_callback = base::BindOnce(&MockImageCaptureClient::DoOnPhotoTaken, base::Unretained(&image_capture_client_)); diff --git a/chromium/media/capture/video/fuchsia/video_capture_device_factory_fuchsia.cc b/chromium/media/capture/video/fuchsia/video_capture_device_factory_fuchsia.cc index 1c42b270512..e87c3c8dbb3 100644 --- a/chromium/media/capture/video/fuchsia/video_capture_device_factory_fuchsia.cc +++ b/chromium/media/capture/video/fuchsia/video_capture_device_factory_fuchsia.cc @@ -99,8 +99,8 @@ class VideoCaptureDeviceFactoryFuchsia::DeviceConfigFetcher { uint64_t device_id_; fuchsia::camera3::DevicePtr device_; - base::Optional<std::string> description_; - base::Optional<VideoCaptureFormats> formats_; + absl::optional<std::string> description_; + absl::optional<VideoCaptureFormats> formats_; base::OnceClosure on_fetched_callback_; }; @@ -178,7 +178,7 @@ void VideoCaptureDeviceFactoryFuchsia::OnDeviceWatcherDisconnected( // Clear the list of devices, so we don't report any camera devices while // DeviceWatcher is disconnected. We will try connecting DeviceWatcher again // when GetDevicesInfo() is called. - devices_ = base::nullopt; + devices_ = absl::nullopt; num_pending_device_info_requests_ = 0; MaybeResolvePendingDeviceInfoCallbacks(); diff --git a/chromium/media/capture/video/fuchsia/video_capture_device_factory_fuchsia.h b/chromium/media/capture/video/fuchsia/video_capture_device_factory_fuchsia.h index 4afb3228c65..eeafa468882 100644 --- a/chromium/media/capture/video/fuchsia/video_capture_device_factory_fuchsia.h +++ b/chromium/media/capture/video/fuchsia/video_capture_device_factory_fuchsia.h @@ -10,8 +10,8 @@ #include <map> #include "base/containers/small_map.h" -#include "base/optional.h" #include "media/capture/video/video_capture_device_factory.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -52,7 +52,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryFuchsia // Current list of devices. Set to nullopt if the list hasn't been received // yet. - base::Optional< + absl::optional< base::small_map<std::map<uint64_t, std::unique_ptr<DeviceConfigFetcher>>>> devices_; diff --git a/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia.cc b/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia.cc index 2692ac2a3ca..33159564011 100644 --- a/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia.cc +++ b/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia.cc @@ -179,9 +179,8 @@ void VideoCaptureDeviceFuchsia::OnStreamError(zx_status_t status) { void VideoCaptureDeviceFuchsia::DisconnectStream() { stream_.Unbind(); - buffer_collection_creator_.reset(); buffer_collection_.reset(); - buffer_reader_.reset(); + buffers_.clear(); frame_size_.reset(); } @@ -246,70 +245,55 @@ void VideoCaptureDeviceFuchsia::InitializeBufferCollection( // Drop old buffers. buffer_collection_.reset(); - buffer_reader_.reset(); + buffers_.clear(); // Initialize the new collection. fuchsia::sysmem::BufferCollectionTokenPtr token; token.Bind(std::move(token_handle)); - buffer_collection_creator_ = - sysmem_allocator_.MakeBufferPoolCreatorFromToken(std::move(token)); // Request just one buffer in collection constraints: each frame is copied as // soon as it's received. const size_t kMaxUsedOutputFrames = 1; - // Sysmem calculates buffer size based on image constraints, so it doesn't - // need to specified explicitly. - fuchsia::sysmem::BufferCollectionConstraints constraints = - SysmemBufferReader::GetRecommendedConstraints( - kMaxUsedOutputFrames, - /*min_buffer_size=*/base::nullopt); // This is not an actual device driver, so the priority should be > 1. It's // also not a high-level system, so the name should be < 100. constexpr uint32_t kNamePriority = 10; - buffer_collection_creator_->SetName(kNamePriority, - "CrVideoCaptureDeviceFuchsia"); - buffer_collection_creator_->Create( - std::move(constraints), - base::BindOnce(&VideoCaptureDeviceFuchsia::OnBufferCollectionCreated, - base::Unretained(this))); -} - -void VideoCaptureDeviceFuchsia::OnBufferCollectionCreated( - std::unique_ptr<SysmemBufferPool> collection) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Buffer collection allocation has failed. This case is not treated as an - // error because the camera may create a new collection. - if (!collection) - return; - buffer_collection_ = std::move(collection); - buffer_collection_->CreateReader( - base::BindOnce(&VideoCaptureDeviceFuchsia::OnBufferReaderCreated, - base::Unretained(this))); + // Sysmem calculates buffer size based on image constraints, so it doesn't + // need to be specified explicitly. + fuchsia::sysmem::BufferCollectionConstraints constraints = + VmoBuffer::GetRecommendedConstraints(kMaxUsedOutputFrames, + /*min_buffer_size=*/absl::nullopt, + /*writable=*/false); + buffer_collection_ = sysmem_allocator_.BindSharedCollection(std::move(token)); + buffer_collection_->Initialize(std::move(constraints), "CrVideoCaptureDevice", + kNamePriority); + buffer_collection_->AcquireBuffers(base::BindOnce( + &VideoCaptureDeviceFuchsia::OnBuffersAcquired, base::Unretained(this))); } -void VideoCaptureDeviceFuchsia::OnBufferReaderCreated( - std::unique_ptr<SysmemBufferReader> reader) { +void VideoCaptureDeviceFuchsia::OnBuffersAcquired( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings& buffer_settings) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Buffer collection allocation has failed. This case is not treated as an // error because the camera may create a new collection. - if (!reader) { + if (buffers.empty()) { buffer_collection_.reset(); return; } - buffer_reader_ = std::move(reader); - if (!buffer_reader_->buffer_settings().has_image_format_constraints) { + buffers_ = std::move(buffers); + + if (!buffer_settings.has_image_format_constraints) { OnError(FROM_HERE, VideoCaptureError::kFuchsiaSysmemDidNotSetImageFormat, "Sysmem created buffer without image format constraints"); return; } - auto pixel_format = buffer_reader_->buffer_settings() - .image_format_constraints.pixel_format.type; + auto pixel_format = + buffer_settings.image_format_constraints.pixel_format.type; if (!IsSupportedPixelFormat(pixel_format)) { OnError(FROM_HERE, VideoCaptureError::kFuchsiaUnsupportedPixelFormat, base::StringPrintf("Unsupported video frame format: %d", @@ -317,6 +301,8 @@ void VideoCaptureDeviceFuchsia::OnBufferReaderCreated( return; } + buffers_format_ = buffer_settings.image_format_constraints; + if (!started_) { started_ = true; client_->OnStarted(); @@ -336,38 +322,35 @@ void VideoCaptureDeviceFuchsia::ProcessNewFrame( DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(client_); - if (!buffer_reader_) { + if (buffers_.empty()) { DLOG(WARNING) << "Dropping frame received before sysmem collection has " "been initialized."; return; } size_t index = frame_info.buffer_index; - if (index >= buffer_reader_->num_buffers()) { + if (index >= buffers_.size()) { OnError(FROM_HERE, VideoCaptureError::kFuchsiaSysmemInvalidBufferIndex, base::StringPrintf("Received frame with invalid buffer_index=%zu", index)); return; } - const fuchsia::sysmem::ImageFormatConstraints& sysmem_buffer_format = - buffer_reader_->buffer_settings().image_format_constraints; - // Calculate coded frame dimensions for the buffer collection based on the // sysmem collection constraints. This logic should match // LogicalBufferCollection::Allocate() in sysmem. size_t src_coded_width = - RoundUp(std::max(sysmem_buffer_format.min_coded_width, - sysmem_buffer_format.required_max_coded_width), - sysmem_buffer_format.coded_width_divisor); + RoundUp(std::max(buffers_format_.min_coded_width, + buffers_format_.required_max_coded_width), + buffers_format_.coded_width_divisor); size_t src_coded_height = - RoundUp(std::max(sysmem_buffer_format.min_coded_height, - sysmem_buffer_format.required_max_coded_height), - sysmem_buffer_format.coded_height_divisor); - size_t src_stride = RoundUp( - std::max(static_cast<size_t>(sysmem_buffer_format.min_bytes_per_row), - src_coded_width), - sysmem_buffer_format.bytes_per_row_divisor); + RoundUp(std::max(buffers_format_.min_coded_height, + buffers_format_.required_max_coded_height), + buffers_format_.coded_height_divisor); + size_t src_stride = + RoundUp(std::max(static_cast<size_t>(buffers_format_.min_bytes_per_row), + src_coded_width), + buffers_format_.bytes_per_row_divisor); gfx::Size visible_size = frame_size_.value_or(gfx::Size(src_coded_width, src_coded_height)); gfx::Size nonrotated_output_size((visible_size.width() + 1) & ~1, @@ -401,7 +384,7 @@ void VideoCaptureDeviceFuchsia::ProcessNewFrame( return; } - auto src_span = buffer_reader_->GetMappingForBuffer(index); + auto src_span = buffers_[index].GetMemory(); if (src_span.empty()) { OnError(FROM_HERE, VideoCaptureError::kFuchsiaFailedToMapSysmemBuffer, "Failed to map buffers allocated by sysmem"); @@ -440,9 +423,7 @@ void VideoCaptureDeviceFuchsia::ProcessNewFrame( if (flip_y) flipped_src_height = -flipped_src_height; - auto four_cc = - GetFourccForPixelFormat(buffer_reader_->buffer_settings() - .image_format_constraints.pixel_format.type); + auto four_cc = GetFourccForPixelFormat(buffers_format_.pixel_format.type); libyuv::ConvertToI420(src_span.data(), src_span.size(), dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, diff --git a/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia.h b/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia.h index 1d2e40ce55a..2df3beefda2 100644 --- a/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia.h +++ b/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia.h @@ -9,12 +9,12 @@ #include <memory> -#include "base/optional.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "media/capture/video/video_capture_device.h" -#include "media/fuchsia/common/sysmem_buffer_pool.h" -#include "media/fuchsia/common/sysmem_buffer_reader.h" +#include "media/fuchsia/common/sysmem_client.h" +#include "media/fuchsia/common/vmo_buffer.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -77,11 +77,10 @@ class CAPTURE_EXPORT VideoCaptureDeviceFuchsia : public VideoCaptureDevice { fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token_handle); - // Callback for SysmemBufferPool::Creator. - void OnBufferCollectionCreated(std::unique_ptr<SysmemBufferPool> collection); - - // Callback for SysmemBufferPool::CreateReader(). - void OnBufferReaderCreated(std::unique_ptr<SysmemBufferReader> reader); + // Callback for SysmemCollectionClient::AcquireBuffers(). + void OnBuffersAcquired( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings& buffer_settings); // Calls Stream::GetNextFrame() in a loop to receive incoming frames. void ReceiveNextFrame(); @@ -95,12 +94,12 @@ class CAPTURE_EXPORT VideoCaptureDeviceFuchsia : public VideoCaptureDevice { std::unique_ptr<Client> client_; - media::BufferAllocator sysmem_allocator_; - std::unique_ptr<SysmemBufferPool::Creator> buffer_collection_creator_; - std::unique_ptr<SysmemBufferPool> buffer_collection_; - std::unique_ptr<SysmemBufferReader> buffer_reader_; + SysmemAllocatorClient sysmem_allocator_; + std::unique_ptr<SysmemCollectionClient> buffer_collection_; + std::vector<VmoBuffer> buffers_; + fuchsia::sysmem::ImageFormatConstraints buffers_format_; - base::Optional<gfx::Size> frame_size_; + absl::optional<gfx::Size> frame_size_; fuchsia::camera3::Orientation orientation_ = fuchsia::camera3::Orientation::UP; diff --git a/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc b/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc index 321f11fe695..f6c8312867b 100644 --- a/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc +++ b/chromium/media/capture/video/fuchsia/video_capture_device_fuchsia_test.cc @@ -191,7 +191,7 @@ class TestVideoCaptureClient : public VideoCaptureDevice::Client { bool started_ = false; std::vector<ReceivedFrame> received_frames_; - base::Optional<base::RunLoop> wait_frame_run_loop_; + absl::optional<base::RunLoop> wait_frame_run_loop_; }; } // namespace diff --git a/chromium/media/capture/video/linux/camera_config_chromeos.cc b/chromium/media/capture/video/linux/camera_config_chromeos.cc deleted file mode 100644 index c2dbdd383ec..00000000000 --- a/chromium/media/capture/video/linux/camera_config_chromeos.cc +++ /dev/null @@ -1,221 +0,0 @@ -// 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/capture/video/linux/camera_config_chromeos.h" - -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" - -namespace media { - -namespace { - -// The value for each field in the enum matches the value in -// /etc/camera/camera_characteristics.conf. -enum LensFacing { FRONT = 0, BACK = 1 }; - -bool ParseCameraId(const base::StringPiece& sub_key, int* camera_id) { - const base::StringPiece camera_id_prefix = "camera"; - if (!base::StartsWith(sub_key, camera_id_prefix)) - return false; - return base::StringToInt(sub_key.substr(camera_id_prefix.size()), camera_id); -} -} - -// /etc/camera/camera_characteristics.conf contains camera information which -// driver cannot provide. -static const char kCameraCharacteristicsConfigFile[] = - "/etc/camera/camera_characteristics.conf"; -static const char kLensFacing[] = "lens_facing"; -static const char kSensorOrientation[] = "sensor_orientation"; -static const char kUsbVidPid[] = "usb_vid_pid"; -static const char kUsbPath[] = "usb_path"; -static const int kOrientationDefault = 0; -static const int kCameraIdNotFound = -1; - -CameraConfigChromeOS::CameraConfigChromeOS() { - InitializeDeviceInfo(std::string(kCameraCharacteristicsConfigFile)); -} - -CameraConfigChromeOS::CameraConfigChromeOS( - const std::string& config_file_path) { - InitializeDeviceInfo(config_file_path); -} - -CameraConfigChromeOS::~CameraConfigChromeOS() = default; - -VideoFacingMode CameraConfigChromeOS::GetCameraFacing( - const std::string& device_id, - const std::string& model_id) const { - int camera_id = GetCameraId(device_id, model_id); - const auto& camera_id_to_facing_const = camera_id_to_facing_; - const auto facing_found = camera_id_to_facing_const.find(camera_id); - if (facing_found == camera_id_to_facing_const.end()) { - DLOG(ERROR) << "Can't find lens_facing of camera ID " << camera_id - << " in config file"; - return kLensFacingDefault; - } - return facing_found->second; -} - -int CameraConfigChromeOS::GetOrientation(const std::string& device_id, - const std::string& model_id) const { - int camera_id = GetCameraId(device_id, model_id); - const auto& camera_id_to_orientation = camera_id_to_orientation_; - const auto orientation_found = camera_id_to_orientation.find(camera_id); - if (orientation_found == camera_id_to_orientation.end()) { - DLOG(ERROR) << "Can't find sensor_orientation of camera ID " << camera_id - << " in config file"; - return kOrientationDefault; - } - return orientation_found->second; -} - -int CameraConfigChromeOS::GetCameraId(const std::string& device_id, - const std::string& model_id) const { - std::string usb_id = GetUsbId(device_id); - const auto& usb_id_to_camera_id = usb_id_to_camera_id_; - const auto& model_id_to_camera_id = model_id_to_camera_id_; - - const auto usb_id_found = usb_id_to_camera_id.find(usb_id); - if (usb_id_found != usb_id_to_camera_id.end()) - return usb_id_found->second; - - // Can't find Usb ID. Fall back to use |model_id|. - const auto model_id_found = model_id_to_camera_id.find(model_id); - if (model_id_found != model_id_to_camera_id.end()) - return model_id_found->second; - - DLOG(ERROR) << "Can't find model ID in config file: " << model_id; - return kCameraIdNotFound; -} - -std::string CameraConfigChromeOS::GetUsbId(const std::string& device_id) const { - // |device_id| is of the form "/dev/video2". We want to retrieve "video2" - // into |file_name|. - const std::string device_dir = "/dev/"; - if (!base::StartsWith(device_id, device_dir)) { - DLOG(ERROR) << "device_id is invalid: " << device_id; - return std::string(); - } - const std::string file_name = device_id.substr(device_dir.length()); - - // Usb ID can be obtained by "readlink /sys/class/video4linux/video2/device". - const std::string symlink = - base::StringPrintf("/sys/class/video4linux/%s/device", file_name.c_str()); - base::FilePath symlinkTarget; - if (!base::ReadSymbolicLink(base::FilePath(symlink), &symlinkTarget)) { - DPLOG(ERROR) << "Failed to readlink: " << symlink; - return std::string(); - } - - // |symlinkTarget| is of the format "../../../A-B:C.D". Remove the path - // prefix. - base::StringPiece usb_part = symlinkTarget.BaseName().value(); - - // |usb_part| is of the format "A-B:C.D" or "A-B.C:D". We want everything - // before ":". - std::vector<base::StringPiece> usb_id_pieces = base::SplitStringPiece( - usb_part, ":", base::WhitespaceHandling::TRIM_WHITESPACE, - base::SplitResult::SPLIT_WANT_ALL); - - if (usb_id_pieces.empty()) { - DLOG(ERROR) << "Error after split: " << usb_part; - return std::string(); - } - return usb_id_pieces[0].as_string(); -} - -void CameraConfigChromeOS::InitializeDeviceInfo( - const std::string& config_file_path) { - const base::FilePath path(config_file_path); - std::string content; - if (!base::ReadFileToString(path, &content)) { - DPLOG(ERROR) << "ReadFileToString fails"; - return; - } - const std::vector<base::StringPiece> lines = base::SplitStringPiece( - content, "\n", base::WhitespaceHandling::TRIM_WHITESPACE, - base::SplitResult::SPLIT_WANT_NONEMPTY); - - for (const base::StringPiece& line : lines) { - // Ignore the comments that starts with "#". - if (base::StartsWith(line, "#")) - continue; - const std::vector<base::StringPiece> key_value = base::SplitStringPiece( - line, "=", base::WhitespaceHandling::TRIM_WHITESPACE, - base::SplitResult::SPLIT_WANT_ALL); - if (key_value.size() != 2) { - DLOG(ERROR) << "Invalid line in config file: " << line; - continue; - } - const auto& key = key_value[0]; - const auto& value = key_value[1]; - const std::vector<base::StringPiece> sub_keys = base::SplitStringPiece( - key, ".", base::WhitespaceHandling::TRIM_WHITESPACE, - base::SplitResult::SPLIT_WANT_ALL); - - if (sub_keys.size() < 1) { - DLOG(ERROR) << "No valid sub key exists. Line format is invalid: " - << line; - continue; - } - int camera_id = 0; - if (!ParseCameraId(sub_keys[0], &camera_id)) { - DLOG(ERROR) << "Invalid sub key for camera id: " << sub_keys[0]; - continue; - } - - if (sub_keys.size() == 2 && sub_keys[1] == kLensFacing) { - int lens_facing = -1; - if (!base::StringToInt(value, &lens_facing)) { - DLOG(ERROR) << "Invalid value for lens_facing: " << value; - continue; - } - switch (lens_facing) { - case LensFacing::FRONT: - camera_id_to_facing_[camera_id] = - VideoFacingMode::MEDIA_VIDEO_FACING_USER; - break; - case LensFacing::BACK: - camera_id_to_facing_[camera_id] = - VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT; - break; - default: - DLOG(ERROR) << "Invalid value for lens_facing: " << lens_facing; - continue; - } - } else if (sub_keys.size() == 2 && sub_keys[1] == kSensorOrientation) { - int orientation = 0; - if (!base::StringToInt(value, &orientation)) { - DLOG(ERROR) << "Invalid value for sensor_orientation: " << value; - continue; - } - camera_id_to_orientation_[camera_id] = orientation; - } else if (sub_keys.size() == 3 && sub_keys[2] == kUsbVidPid) { - if (value.empty()) { - DLOG(ERROR) << "model_id is empty"; - continue; - } - std::string model_id = value.as_string(); - std::transform(model_id.begin(), model_id.end(), model_id.begin(), - ::tolower); - model_id_to_camera_id_[model_id] = camera_id; - } else if (sub_keys.size() == 3 && sub_keys[2] == kUsbPath) { - if (value.empty()) { - DLOG(ERROR) << "usb_path is empty"; - continue; - } - usb_id_to_camera_id_[value.as_string()] = camera_id; - } - // Ignore unknown or unutilized attributes. - } -} - -} // namespace media diff --git a/chromium/media/capture/video/linux/camera_config_chromeos.h b/chromium/media/capture/video/linux/camera_config_chromeos.h deleted file mode 100644 index 3191eb0f22d..00000000000 --- a/chromium/media/capture/video/linux/camera_config_chromeos.h +++ /dev/null @@ -1,86 +0,0 @@ -// 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. - -#ifndef MEDIA_CAPTURE_VIDEO_LINUX_CAMERA_CONFIG_CHROMEOS_H_ -#define MEDIA_CAPTURE_VIDEO_LINUX_CAMERA_CONFIG_CHROMEOS_H_ - -#include <stddef.h> - -#include <string> -#include <unordered_map> - -#include "base/strings/string_piece.h" -#include "media/base/video_facing.h" -#include "media/capture/capture_export.h" - -namespace media { - -// CameraConfigChromeOS reads the file /etc/camera/camera_characteristics.conf -// and populates |camera_id_to_facing_|, |usb_id_to_camera_id_| and -// |model_id_to_camera_id_|. -// -// Each line in the config file can be: -// 1. Empty line -// 2. Line starts with '#': comments -// 3. Line follows the format: -// camera[camera_id].[root_level_attribute]=[value] OR -// camera[camera_id].module[module_id].[module_level_attribute]=[value] -// -// There are several assumptions of the config file: -// 1. One camera ID has exactly one lens_facing attribute, at root level. -// 2. usb_path is specified at module level. usb_path may not present at all, -// but if it presents, the same usb_path does not appear accross different -// camera IDs. -// 3. usb_vid_pid is specified at module level. If usb_path does not present, -// each module needs to have one unique usb_vid_pid. -// -// Example of the config file: -// camera0.lens_facing=0 -// camera0.sensor_orientation=0 -// camera0.module0.usb_vid_pid=0123:4567 -// camera0.module0.horizontal_view_angle=68.4 -// camera0.module0.lens_info_available_focal_lengths=1.64 -// camera0.module0.lens_info_minimum_focus_distance=0.22 -// camera0.module0.lens_info_optimal_focus_distance=0.5 -// camera0.module0.vertical_view_angle=41.6 -// camera0.module1.usb_vid_pid=89ab:cdef -// camera0.module1.lens_info_available_focal_lengths=1.69,2 -// camera1.lens_facing=1 -// camera1.sensor_orientation=180 -class CAPTURE_EXPORT CameraConfigChromeOS { - public: - CameraConfigChromeOS(); - CAPTURE_EXPORT CameraConfigChromeOS(const std::string& config_file_path); - CAPTURE_EXPORT ~CameraConfigChromeOS(); - - // Get camera facing by specifying USB vid and pid and device path. |model_id| - // should be formatted as "vid:pid". |device_id| is something like - // "/dev/video2". It first tries to match usb path, obtained from |device_id|. - // If fails, |model_id| is then used. - CAPTURE_EXPORT VideoFacingMode - GetCameraFacing(const std::string& device_id, - const std::string& model_id) const; - int GetOrientation(const std::string& device_id, - const std::string& model_id) const; - - static const VideoFacingMode kLensFacingDefault = - VideoFacingMode::MEDIA_VIDEO_FACING_NONE; - - private: - std::string GetUsbId(const std::string& device_id) const; - int GetCameraId(const std::string& device_id, - const std::string& model_id) const; - // Read file content and populate |camera_id_to_facing_|, - // |usb_id_to_camera_id_| and |model_id_to_camera_id_|. - void InitializeDeviceInfo(const std::string& config_file_path); - - std::unordered_map<int, VideoFacingMode> camera_id_to_facing_; - std::unordered_map<int, int> camera_id_to_orientation_; - std::unordered_map<std::string, int> usb_id_to_camera_id_; - std::unordered_map<std::string, int> model_id_to_camera_id_; -}; - -} // namespace media - -#endif // MEDIA_CAPTURE_VIDEO_LINUX_CAMERA_CONFIG_CHROMEOS_H_ diff --git a/chromium/media/capture/video/linux/camera_config_chromeos_unittest.cc b/chromium/media/capture/video/linux/camera_config_chromeos_unittest.cc deleted file mode 100644 index 9fa1d01141f..00000000000 --- a/chromium/media/capture/video/linux/camera_config_chromeos_unittest.cc +++ /dev/null @@ -1,43 +0,0 @@ -// 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 <string> - -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "media/capture/video/linux/camera_config_chromeos.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { - -namespace { - -const char kConfigFileContent[] = - "camera0.lens_facing=1\ncamera0.sensor_orientation=90\ncamera0.module0.usb_" - "vid_pid=04f2:b53a\n"; -} - -TEST(CameraConfigChromeOSTest, ParseSuccessfully) { - base::FilePath conf_path; - ASSERT_TRUE(base::CreateTemporaryFile(&conf_path)); - base::WriteFile(conf_path, kConfigFileContent, sizeof(kConfigFileContent)); - - CameraConfigChromeOS camera_config(conf_path.value()); - EXPECT_EQ(VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT, - camera_config.GetCameraFacing(std::string("/dev/video2"), - std::string("04f2:b53a"))); - EXPECT_EQ(90, camera_config.GetOrientation(std::string("/dev/video2"), - std::string("04f2:b53a"))); -} - -TEST(CameraConfigChromeOSTest, ConfigFileNotExist) { - CameraConfigChromeOS camera_config(std::string("file_not_exist")); - EXPECT_EQ(VideoFacingMode::MEDIA_VIDEO_FACING_NONE, - camera_config.GetCameraFacing(std::string("/dev/video2"), - std::string("04f2:b53a"))); - EXPECT_EQ(0, camera_config.GetOrientation(std::string("/dev/video2"), - std::string("04f2:b53a"))); -} - -} // namespace media diff --git a/chromium/media/capture/video/linux/fake_device_provider.cc b/chromium/media/capture/video/linux/fake_device_provider.cc index a8c79723c49..581c260a399 100644 --- a/chromium/media/capture/video/linux/fake_device_provider.cc +++ b/chromium/media/capture/video/linux/fake_device_provider.cc @@ -52,15 +52,4 @@ std::string FakeDeviceProvider::GetDeviceDisplayName( return iter->display_name(); } -VideoFacingMode FakeDeviceProvider::GetCameraFacing( - const std::string& device_id, - const std::string& model_id) { - return MEDIA_VIDEO_FACING_NONE; -} - -int FakeDeviceProvider::GetOrientation(const std::string& device_id, - const std::string& model_id) { - return 0; -} - } // namespace media diff --git a/chromium/media/capture/video/linux/fake_device_provider.h b/chromium/media/capture/video/linux/fake_device_provider.h index 15b95f59042..a98648eb356 100644 --- a/chromium/media/capture/video/linux/fake_device_provider.h +++ b/chromium/media/capture/video/linux/fake_device_provider.h @@ -25,10 +25,6 @@ class FakeDeviceProvider void GetDeviceIds(std::vector<std::string>* target_container) override; std::string GetDeviceModelId(const std::string& device_id) override; std::string GetDeviceDisplayName(const std::string& device_id) override; - VideoFacingMode GetCameraFacing(const std::string& device_id, - const std::string& model_id) override; - int GetOrientation(const std::string& device_id, - const std::string& model_id) override; private: std::vector<VideoCaptureDeviceDescriptor> descriptors_; diff --git a/chromium/media/capture/video/linux/fake_v4l2_impl.cc b/chromium/media/capture/video/linux/fake_v4l2_impl.cc index 4a976815d00..09647474bed 100644 --- a/chromium/media/capture/video/linux/fake_v4l2_impl.cc +++ b/chromium/media/capture/video/linux/fake_v4l2_impl.cc @@ -380,10 +380,16 @@ FakeV4L2Impl::~FakeV4L2Impl() = default; void FakeV4L2Impl::AddDevice(const std::string& device_name, const FakeV4L2DeviceConfig& config) { + base::AutoLock lock(lock_); device_configs_.emplace(device_name, config); } int FakeV4L2Impl::open(const char* device_name, int flags) { + if (!device_name) + return kInvalidId; + + base::AutoLock lock(lock_); + std::string device_name_as_string(device_name); auto device_configs_iter = device_configs_.find(device_name_as_string); if (device_configs_iter == device_configs_.end()) @@ -403,6 +409,7 @@ int FakeV4L2Impl::open(const char* device_name, int flags) { } int FakeV4L2Impl::close(int fd) { + base::AutoLock lock(lock_); auto device_iter = opened_devices_.find(fd); if (device_iter == opened_devices_.end()) return kErrorReturnValue; @@ -412,6 +419,7 @@ int FakeV4L2Impl::close(int fd) { } int FakeV4L2Impl::ioctl(int fd, int request, void* argp) { + base::AutoLock lock(lock_); auto device_iter = opened_devices_.find(fd); if (device_iter == opened_devices_.end()) return EBADF; @@ -518,6 +526,7 @@ void* FakeV4L2Impl::mmap(void* /*start*/, int flags, int fd, off_t offset) { + base::AutoLock lock(lock_); if (flags & MAP_FIXED) { errno = EINVAL; return MAP_FAILED; @@ -543,10 +552,12 @@ void* FakeV4L2Impl::mmap(void* /*start*/, } int FakeV4L2Impl::munmap(void* start, size_t length) { + base::AutoLock lock(lock_); return kSuccessReturnValue; } int FakeV4L2Impl::poll(struct pollfd* ufds, unsigned int nfds, int timeout) { + base::AutoLock lock(lock_); if (nfds != 1) { // We only support polling of a single device. errno = EINVAL; diff --git a/chromium/media/capture/video/linux/fake_v4l2_impl.h b/chromium/media/capture/video/linux/fake_v4l2_impl.h index 0a035a97dd8..ae7167f9516 100644 --- a/chromium/media/capture/video/linux/fake_v4l2_impl.h +++ b/chromium/media/capture/video/linux/fake_v4l2_impl.h @@ -10,6 +10,7 @@ #include <linux/videodev2.h> +#include "base/synchronization/lock.h" #include "media/capture/capture_export.h" #include "media/capture/video/linux/v4l2_capture_device.h" #include "media/capture/video/video_capture_device_descriptor.h" @@ -52,11 +53,13 @@ class CAPTURE_EXPORT FakeV4L2Impl : public V4L2CaptureDevice { private: class OpenedDevice; - int next_id_to_return_from_open_; - std::map<std::string, FakeV4L2DeviceConfig> device_configs_; - std::map<std::string, int> device_name_to_open_id_map_; + base::Lock lock_; + + int next_id_to_return_from_open_ GUARDED_BY(lock_); + std::map<std::string, FakeV4L2DeviceConfig> device_configs_ GUARDED_BY(lock_); + std::map<std::string, int> device_name_to_open_id_map_ GUARDED_BY(lock_); std::map<int /*value returned by open()*/, std::unique_ptr<OpenedDevice>> - opened_devices_; + opened_devices_ GUARDED_BY(lock_); }; } // namespace media diff --git a/chromium/media/capture/video/linux/v4l2_capture_delegate_unittest.cc b/chromium/media/capture/video/linux/v4l2_capture_delegate_unittest.cc index 88564367bee..710f5adf4ab 100644 --- a/chromium/media/capture/video/linux/v4l2_capture_delegate_unittest.cc +++ b/chromium/media/capture/video/linux/v4l2_capture_delegate_unittest.cc @@ -194,11 +194,12 @@ class V4L2CaptureDelegateTest : public ::testing::Test { } // anonymous namespace // Fails on Linux, see crbug/732355 -#if defined(OS_LINUX) || defined(OS_CHROMEOS) +#if defined(OS_LINUX) #define MAYBE_CreateAndDestroyAndVerifyControls \ DISABLED_CreateAndDestroyAndVerifyControls #else -#define MAYBE_CrashingTest CreateAndDestroyAndVerifyControls +#define MAYBE_CreateAndDestroyAndVerifyControls \ + CreateAndDestroyAndVerifyControls #endif TEST_F(V4L2CaptureDelegateTest, MAYBE_CreateAndDestroyAndVerifyControls) { // Check that there is at least a video device, otherwise bail. diff --git a/chromium/media/capture/video/linux/video_capture_device_chromeos.cc b/chromium/media/capture/video/linux/video_capture_device_chromeos.cc deleted file mode 100644 index 8fd1829805a..00000000000 --- a/chromium/media/capture/video/linux/video_capture_device_chromeos.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2014 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/capture/video/linux/video_capture_device_chromeos.h" - -#include <stdint.h> - -#include "base/bind.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "ui/display/display.h" -#include "ui/display/display_observer.h" -#include "ui/display/screen.h" - -namespace media { - -VideoCaptureDeviceChromeOS::VideoCaptureDeviceChromeOS( - const ChromeOSDeviceCameraConfig& camera_config, - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - scoped_refptr<V4L2CaptureDevice> v4l2, - const VideoCaptureDeviceDescriptor& device_descriptor) - : VideoCaptureDeviceLinux(std::move(v4l2), device_descriptor), - camera_config_(camera_config), - screen_observer_delegate_( - ScreenObserverDelegate::Create(this, ui_task_runner)) {} - -VideoCaptureDeviceChromeOS::~VideoCaptureDeviceChromeOS() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - screen_observer_delegate_->RemoveObserver(); -} - -void VideoCaptureDeviceChromeOS::SetRotation(int rotation) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!camera_config_.rotates_with_device) { - rotation = 0; - } else if (camera_config_.lens_facing == - VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT) { - // Original frame when |rotation| = 0 - // ----------------------- - // | * | - // | * * | - // | * * | - // | ******* | - // | * * | - // | * * | - // ----------------------- - // - // |rotation| = 90, this is what back camera sees - // ----------------------- - // | ******** | - // | * **** | - // | * *** | - // | * *** | - // | * **** | - // | ******** | - // ----------------------- - // - // |rotation| = 90, this is what front camera sees - // ----------------------- - // | ******** | - // | **** * | - // | *** * | - // | *** * | - // | **** * | - // | ******** | - // ----------------------- - // - // Therefore, for back camera, we need to rotate (360 - |rotation|). - rotation = (360 - rotation) % 360; - } - // Take into account camera orientation w.r.t. the display. External cameras - // would have camera_orientation_ as 0. - rotation = (rotation + camera_config_.camera_orientation) % 360; - VideoCaptureDeviceLinux::SetRotation(rotation); -} - -void VideoCaptureDeviceChromeOS::SetDisplayRotation( - const display::Display& display) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (display.IsInternal()) - SetRotation(display.rotation() * 90); -} - -} // namespace media diff --git a/chromium/media/capture/video/linux/video_capture_device_chromeos.h b/chromium/media/capture/video/linux/video_capture_device_chromeos.h deleted file mode 100644 index 13471667d53..00000000000 --- a/chromium/media/capture/video/linux/video_capture_device_chromeos.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2014 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. - -#ifndef MEDIA_CAPTURE_VIDEO_LINUX_VIDEO_CAPTURE_DEVICE_CHROMEOS_H_ -#define MEDIA_CAPTURE_VIDEO_LINUX_VIDEO_CAPTURE_DEVICE_CHROMEOS_H_ - -#include "base/macros.h" -#include "base/single_thread_task_runner.h" -#include "media/capture/video/chromeos/display_rotation_observer.h" -#include "media/capture/video/linux/video_capture_device_linux.h" - -namespace display { -class Display; -} // namespace display - -namespace media { - -struct ChromeOSDeviceCameraConfig { - ChromeOSDeviceCameraConfig(VideoFacingMode lens_facing, - int camera_orientation) - : lens_facing(lens_facing), - camera_orientation(camera_orientation), - // External cameras have lens_facing as MEDIA_VIDEO_FACING_NONE. - // We don't want to rotate the frame even if the device rotates. - rotates_with_device(lens_facing != - VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {} - - const VideoFacingMode lens_facing; - const int camera_orientation; - // Whether the incoming frames should rotate when the device rotates. - const bool rotates_with_device; -}; - -// This class is functionally the same as VideoCaptureDeviceLinux, with the -// exception that it is aware of the orientation of the internal Display. When -// the internal Display is rotated, the frames captured are rotated to match. -class VideoCaptureDeviceChromeOS : public VideoCaptureDeviceLinux, - public DisplayRotationObserver { - public: - VideoCaptureDeviceChromeOS( - const ChromeOSDeviceCameraConfig& camera_config, - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, - scoped_refptr<V4L2CaptureDevice> v4l2, - const VideoCaptureDeviceDescriptor& device_descriptor); - ~VideoCaptureDeviceChromeOS() override; - - protected: - void SetRotation(int rotation) override; - - private: - // DisplayRotationObserver implementation. - void SetDisplayRotation(const display::Display& display) override; - - const ChromeOSDeviceCameraConfig camera_config_; - scoped_refptr<ScreenObserverDelegate> screen_observer_delegate_; - - SEQUENCE_CHECKER(sequence_checker_); - - DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureDeviceChromeOS); -}; - -} // namespace media - -#endif // MEDIA_CAPTURE_VIDEO_LINUX_VIDEO_CAPTURE_DEVICE_CHROMEOS_H_ diff --git a/chromium/media/capture/video/linux/video_capture_device_factory_linux.cc b/chromium/media/capture/video/linux/video_capture_device_factory_linux.cc index 677d733460e..6724957d80a 100644 --- a/chromium/media/capture/video/linux/video_capture_device_factory_linux.cc +++ b/chromium/media/capture/video/linux/video_capture_device_factory_linux.cc @@ -12,13 +12,13 @@ #include <algorithm> #include <utility> +#include "base/containers/contains.h" #include "base/files/file_enumerator.h" #include "base/files/file_util.h" #include "base/posix/eintr_wrapper.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" -#include "build/chromeos_buildflags.h" #include "media/capture/video/linux/scoped_v4l2_device_fd.h" #include "media/capture/video/linux/video_capture_device_linux.h" @@ -28,11 +28,6 @@ #include <linux/videodev2.h> #endif -#if BUILDFLAG(IS_CHROMEOS_ASH) -#include "media/capture/video/linux/camera_config_chromeos.h" -#include "media/capture/video/linux/video_capture_device_chromeos.h" -#endif - namespace media { namespace { @@ -53,13 +48,6 @@ const char kPidPathTemplate[] = "/sys/class/video4linux/%s/device/../idProduct"; const char kInterfacePathTemplate[] = "/sys/class/video4linux/%s/device/interface"; -#if BUILDFLAG(IS_CHROMEOS_ASH) -static CameraConfigChromeOS* GetCameraConfig() { - static CameraConfigChromeOS* config = new CameraConfigChromeOS(); - return config; -} -#endif - bool ReadIdFile(const std::string& path, std::string* id) { char id_buf[kVidPidSize]; FILE* file = fopen(path.c_str(), "rb"); @@ -122,26 +110,6 @@ class DevVideoFilePathsDeviceProvider } return display_name; } - - VideoFacingMode GetCameraFacing(const std::string& device_id, - const std::string& model_id) override { -#if BUILDFLAG(IS_CHROMEOS_ASH) - return GetCameraConfig()->GetCameraFacing(device_id, model_id); -#else - NOTREACHED(); - return MEDIA_VIDEO_FACING_NONE; -#endif - } - - int GetOrientation(const std::string& device_id, - const std::string& model_id) override { -#if BUILDFLAG(IS_CHROMEOS_ASH) - return GetCameraConfig()->GetOrientation(device_id, model_id); -#else - NOTREACHED(); - return 0; -#endif - } }; } // namespace @@ -166,18 +134,8 @@ std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryLinux::CreateDevice( const VideoCaptureDeviceDescriptor& device_descriptor) { DCHECK(thread_checker_.CalledOnValidThread()); -#if BUILDFLAG(IS_CHROMEOS_ASH) - ChromeOSDeviceCameraConfig camera_config( - device_provider_->GetCameraFacing(device_descriptor.device_id, - device_descriptor.model_id), - device_provider_->GetOrientation(device_descriptor.device_id, - device_descriptor.model_id)); - auto self = std::make_unique<VideoCaptureDeviceChromeOS>( - camera_config, ui_task_runner_, v4l2_.get(), device_descriptor); -#else auto self = std::make_unique<VideoCaptureDeviceLinux>(v4l2_.get(), device_descriptor); -#endif // Test opening the device driver. This is to make sure it is available. // We will reopen it again in our worker thread when someone @@ -230,12 +188,7 @@ void VideoCaptureDeviceFactoryLinux::GetDevicesInfo( if (display_name.empty()) display_name = reinterpret_cast<char*>(cap.card); - VideoFacingMode facing_mode = -#if BUILDFLAG(IS_CHROMEOS_ASH) - device_provider_->GetCameraFacing(unique_id, model_id); -#else - VideoFacingMode::MEDIA_VIDEO_FACING_NONE; -#endif + VideoFacingMode facing_mode = VideoFacingMode::MEDIA_VIDEO_FACING_NONE; VideoCaptureFormats supported_formats; GetSupportedFormatsForV4L2BufferType(fd.get(), &supported_formats); diff --git a/chromium/media/capture/video/linux/video_capture_device_factory_linux.h b/chromium/media/capture/video/linux/video_capture_device_factory_linux.h index 9895d2129f9..63ffeef9e96 100644 --- a/chromium/media/capture/video/linux/video_capture_device_factory_linux.h +++ b/chromium/media/capture/video/linux/video_capture_device_factory_linux.h @@ -31,20 +31,6 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryLinux virtual void GetDeviceIds(std::vector<std::string>* target_container) = 0; virtual std::string GetDeviceModelId(const std::string& device_id) = 0; virtual std::string GetDeviceDisplayName(const std::string& device_id) = 0; - virtual VideoFacingMode GetCameraFacing(const std::string& device_id, - const std::string& model_id) = 0; - // Get the orientation of the camera. The value is the angle that the camera - // image needs to be rotated clockwise so it shows correctly on the display - // in its natural orientation. It should be 0, 90, 180, or 270. - // - // For example, suppose a device has a naturally tall screen. The - // back-facing camera sensor is mounted in landscape. You are looking at the - // screen. If the top side of the camera sensor is aligned with the right - // edge of the screen in natural orientation, the value should be 90. If the - // top side of a front-facing camera sensor is aligned with the right of the - // screen, the value should be 270. - virtual int GetOrientation(const std::string& device_id, - const std::string& model_id) = 0; }; explicit VideoCaptureDeviceFactoryLinux( diff --git a/chromium/media/capture/video/mac/pixel_buffer_pool_mac.cc b/chromium/media/capture/video/mac/pixel_buffer_pool_mac.cc index 4eae3d8f696..b25bb385da7 100644 --- a/chromium/media/capture/video/mac/pixel_buffer_pool_mac.cc +++ b/chromium/media/capture/video/mac/pixel_buffer_pool_mac.cc @@ -42,7 +42,7 @@ std::unique_ptr<PixelBufferPool> PixelBufferPool::Create( OSType format, int width, int height, - base::Optional<size_t> max_buffers) { + absl::optional<size_t> max_buffers) { // Pixel buffer attributes: The attributes of buffers created by the pool. CFStringRef pixel_buffer_attribute_keys[] = { kCVPixelBufferIOSurfacePropertiesKey, // We want IOSurfaces. @@ -91,7 +91,7 @@ std::unique_ptr<PixelBufferPool> PixelBufferPool::Create( PixelBufferPool::PixelBufferPool( base::ScopedCFTypeRef<CVPixelBufferPoolRef> buffer_pool, - base::Optional<size_t> max_buffers) + absl::optional<size_t> max_buffers) : buffer_pool_(std::move(buffer_pool)), max_buffers_(std::move(max_buffers)), num_consecutive_errors_(0) { diff --git a/chromium/media/capture/video/mac/pixel_buffer_pool_mac.h b/chromium/media/capture/video/mac/pixel_buffer_pool_mac.h index ed431d4699c..06c31a4f240 100644 --- a/chromium/media/capture/video/mac/pixel_buffer_pool_mac.h +++ b/chromium/media/capture/video/mac/pixel_buffer_pool_mac.h @@ -9,8 +9,8 @@ #include <memory> #include "base/mac/scoped_cftyperef.h" -#include "base/optional.h" #include "media/capture/capture_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -26,7 +26,7 @@ class CAPTURE_EXPORT PixelBufferPool { OSType format, int width, int height, - base::Optional<size_t> max_buffers); + absl::optional<size_t> max_buffers); ~PixelBufferPool(); // Creates a new buffer from the pool, if possible. The underlying buffers are @@ -55,13 +55,13 @@ class CAPTURE_EXPORT PixelBufferPool { private: friend std::unique_ptr<PixelBufferPool> std::make_unique<PixelBufferPool>( base::ScopedCFTypeRef<CVPixelBufferPoolRef>&& buffer_pool, - base::Optional<size_t>&& max_buffers); + absl::optional<size_t>&& max_buffers); PixelBufferPool(base::ScopedCFTypeRef<CVPixelBufferPoolRef> buffer_pool, - base::Optional<size_t> max_buffers); + absl::optional<size_t> max_buffers); base::ScopedCFTypeRef<CVPixelBufferPoolRef> buffer_pool_; - const base::Optional<size_t> max_buffers_; + const absl::optional<size_t> max_buffers_; size_t num_consecutive_errors_; }; diff --git a/chromium/media/capture/video/mac/pixel_buffer_pool_mac_unittest.mm b/chromium/media/capture/video/mac/pixel_buffer_pool_mac_unittest.mm index bf0b561b96c..9cad540d016 100644 --- a/chromium/media/capture/video/mac/pixel_buffer_pool_mac_unittest.mm +++ b/chromium/media/capture/video/mac/pixel_buffer_pool_mac_unittest.mm @@ -76,7 +76,7 @@ TEST(PixelBufferPoolTest, CannotExceedMaxBuffersWhenIOSurfaceIsInUse) { TEST(PixelBufferPoolTest, CanCreateBuffersIfMaxIsNull) { std::unique_ptr<PixelBufferPool> pool = PixelBufferPool::Create( - kPixelFormatNv12, kVgaWidth, kVgaHeight, base::nullopt); + kPixelFormatNv12, kVgaWidth, kVgaHeight, absl::nullopt); base::ScopedCFTypeRef<CVPixelBufferRef> first_buffer = pool->CreateBuffer(); EXPECT_TRUE(first_buffer); base::ScopedCFTypeRef<CVPixelBufferRef> second_buffer = pool->CreateBuffer(); @@ -180,7 +180,7 @@ TEST(PixelBufferPoolTest, BuffersCanOutliveThePool) { TEST(PixelBufferPoolTest, CanFlushWhileBufferIsInUse) { std::unique_ptr<PixelBufferPool> pool = PixelBufferPool::Create( - kPixelFormatNv12, kVgaWidth, kVgaHeight, base::nullopt); + kPixelFormatNv12, kVgaWidth, kVgaHeight, absl::nullopt); base::ScopedCFTypeRef<CVPixelBufferRef> retained_buffer = pool->CreateBuffer(); base::ScopedCFTypeRef<CVPixelBufferRef> released_buffer = diff --git a/chromium/media/capture/video/mac/sample_buffer_transformer_mac.cc b/chromium/media/capture/video/mac/sample_buffer_transformer_mac.cc index ed8a5293527..0d98d68189d 100644 --- a/chromium/media/capture/video/mac/sample_buffer_transformer_mac.cc +++ b/chromium/media/capture/video/mac/sample_buffer_transformer_mac.cc @@ -15,9 +15,6 @@ namespace media { -const base::Feature kInCaptureConvertToNv12{"InCaptureConvertToNv12", - base::FEATURE_ENABLED_BY_DEFAULT}; - namespace { // NV12 a.k.a. 420v @@ -479,7 +476,7 @@ void SampleBufferTransformer::Reconfigure( Transformer transformer, OSType destination_pixel_format, const gfx::Size& destination_size, - base::Optional<size_t> buffer_pool_size) { + absl::optional<size_t> buffer_pool_size) { DCHECK(transformer != Transformer::kLibyuv || destination_pixel_format == kPixelFormatI420 || destination_pixel_format == kPixelFormatNv12) diff --git a/chromium/media/capture/video/mac/sample_buffer_transformer_mac.h b/chromium/media/capture/video/mac/sample_buffer_transformer_mac.h index 24d42cff78d..d8b66605dcf 100644 --- a/chromium/media/capture/video/mac/sample_buffer_transformer_mac.h +++ b/chromium/media/capture/video/mac/sample_buffer_transformer_mac.h @@ -18,11 +18,6 @@ namespace media { -// This flag is used to decide whether or not to use the SampleBufferTransformer -// to convert captured images to NV12, see -// video_capture_device_avfoundation_mac.mm. -CAPTURE_EXPORT extern const base::Feature kInCaptureConvertToNv12; - // Capable of converting from any supported capture format (NV12, YUY2, UYVY and // MJPEG) to NV12 or I420 and doing rescaling. This class can be configured to // use VTPixelTransferSession (sometimes HW-accelerated) or third_party/libyuv @@ -60,7 +55,7 @@ class CAPTURE_EXPORT SampleBufferTransformer { void Reconfigure(Transformer transformer, OSType destination_pixel_format, const gfx::Size& destination_size, - base::Optional<size_t> buffer_pool_size = base::nullopt); + absl::optional<size_t> buffer_pool_size = absl::nullopt); // Converts the input buffer to an IOSurface-backed pixel buffer according to // current configurations. If no transformation is needed (input format is the diff --git a/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac.h b/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac.h index 2e2b3f65bac..68ee39aec62 100644 --- a/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac.h +++ b/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac.h @@ -142,7 +142,7 @@ CAPTURE_EXPORT // initialise an object of this class and register a |frameReceiver_|. This // initializes the instance and the underlying capture session and registers the // frame receiver. -- (id)initWithFrameReceiver: +- (instancetype)initWithFrameReceiver: (media::VideoCaptureDeviceAVFoundationFrameReceiver*)frameReceiver; // Frame receiver registration or removal can also happen via explicit call diff --git a/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac.mm b/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac.mm index 1cc1bdbcec2..e062332d85f 100644 --- a/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac.mm +++ b/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac.mm @@ -162,7 +162,7 @@ AVCaptureDeviceFormat* FindBestCaptureFormat( #pragma mark Public methods -- (id)initWithFrameReceiver: +- (instancetype)initWithFrameReceiver: (media::VideoCaptureDeviceAVFoundationFrameReceiver*)frameReceiver { if ((self = [super init])) { _mainThreadTaskRunner = base::ThreadTaskRunnerHandle::Get(); @@ -178,10 +178,7 @@ AVCaptureDeviceFormat* FindBestCaptureFormat( self); [self setFrameReceiver:frameReceiver]; _captureSession.reset([[AVCaptureSession alloc] init]); - if (base::FeatureList::IsEnabled(media::kInCaptureConvertToNv12)) { - _sampleBufferTransformer = media::SampleBufferTransformer::Create(); - VLOG(1) << "Capturing with SampleBufferTransformer enabled"; - } + _sampleBufferTransformer = media::SampleBufferTransformer::Create(); } return self; } @@ -227,8 +224,7 @@ AVCaptureDeviceFormat* FindBestCaptureFormat( _captureDevice.reset([AVCaptureDevice deviceWithUniqueID:deviceId], base::scoped_policy::RETAIN); if (!_captureDevice) { - *outMessage = - [NSString stringWithUTF8String:"Could not open video capture device."]; + *outMessage = @"Could not open video capture device."; return NO; } @@ -252,8 +248,7 @@ AVCaptureDeviceFormat* FindBestCaptureFormat( _captureVideoDataOutput.reset([[AVCaptureVideoDataOutput alloc] init]); if (!_captureVideoDataOutput) { [_captureSession removeInput:_captureDeviceInput]; - *outMessage = - [NSString stringWithUTF8String:"Could not create video data output."]; + *outMessage = @"Could not create video data output."; return NO; } [_captureVideoDataOutput setAlwaysDiscardsLateVideoFrames:true]; @@ -816,7 +811,10 @@ AVCaptureDeviceFormat* FindBestCaptureFormat( // https://crbug.com/959962 (ignoring color space) gfx::ColorSpace overriddenColorSpace = colorSpace; if (colorSpace == kColorSpaceRec709Apple) { - overriddenColorSpace = gfx::ColorSpace::CreateSRGB(); + overriddenColorSpace = gfx::ColorSpace( + gfx::ColorSpace::PrimaryID::BT709, + gfx::ColorSpace::TransferID::IEC61966_2_1, + gfx::ColorSpace::MatrixID::BT709, gfx::ColorSpace::RangeID::LIMITED); IOSurfaceSetValue(ioSurface, CFSTR("IOSurfaceColorSpace"), kCGColorSpaceSRGB); } @@ -906,7 +904,7 @@ AVCaptureDeviceFormat* FindBestCaptureFormat( // back on the M87 code path if this is the case. // TODO(https://crbug.com/1160315): When the SampleBufferTransformer is // patched to support non-MJPEG-and-non-pixel-buffer sample buffers, remove - // this workaround. + // this workaround and the fallback other code path. bool sampleHasPixelBufferOrIsMjpeg = CMSampleBufferGetImageBuffer(sampleBuffer) || CMFormatDescriptionGetMediaSubType(CMSampleBufferGetFormatDescription( @@ -916,9 +914,7 @@ AVCaptureDeviceFormat* FindBestCaptureFormat( // formats to an IOSurface-backed NV12 pixel buffer. // TODO(https://crbug.com/1175142): Refactor to not hijack the code paths // below the transformer code. - // TODO(hbos): When |_sampleBufferTransformer| gets shipped 100%, delete the - // other code paths. - if (_sampleBufferTransformer && sampleHasPixelBufferOrIsMjpeg) { + if (sampleHasPixelBufferOrIsMjpeg) { _sampleBufferTransformer->Reconfigure( media::SampleBufferTransformer::GetBestTransformerForNv12Output( sampleBuffer), @@ -1009,7 +1005,7 @@ AVCaptureDeviceFormat* FindBestCaptureFormat( - (void)onVideoError:(NSNotification*)errorNotification { NSError* error = base::mac::ObjCCast<NSError>( - [[errorNotification userInfo] objectForKey:AVCaptureSessionErrorKey]); + [errorNotification userInfo][AVCaptureSessionErrorKey]); [self sendErrorString:[NSString stringWithFormat:@"%@: %@", [error localizedDescription], diff --git a/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac_unittest.mm b/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac_unittest.mm index b51edef31da..2c6a3d55e72 100644 --- a/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac_unittest.mm +++ b/chromium/media/capture/video/mac/video_capture_device_avfoundation_mac_unittest.mm @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/mac/scoped_nsobject.h" #include "base/run_loop.h" +#include "base/strings/sys_string_conversions.h" #include "base/test/bind.h" #include "base/test/gmock_callback_support.h" #include "base/test/scoped_feature_list.h" @@ -29,8 +30,7 @@ namespace media { TEST(VideoCaptureDeviceAVFoundationMacTest, OutputsNv12WithoutScalingByDefault) { base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - {kInCaptureConvertToNv12, kInCapturerScaling}, {}); + scoped_feature_list.InitAndEnableFeature(kInCapturerScaling); RunTestCase(base::BindOnce([] { NSString* deviceId = GetFirstDeviceId(); @@ -76,7 +76,6 @@ TEST(VideoCaptureDeviceAVFoundationMacTest, TEST(VideoCaptureDeviceAVFoundationMacTest, SpecifiedScalingIsIgnoredWhenInCapturerScalingIsNotEnabled) { base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(kInCaptureConvertToNv12); // By default, kInCapturerScaling is false. EXPECT_FALSE(base::FeatureList::IsEnabled(kInCapturerScaling)); @@ -127,8 +126,7 @@ TEST(VideoCaptureDeviceAVFoundationMacTest, TEST(VideoCaptureDeviceAVFoundationMacTest, SpecifiedScalingOutputsNv12) { base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - {kInCaptureConvertToNv12, kInCapturerScaling}, {}); + scoped_feature_list.InitAndEnableFeature(kInCapturerScaling); RunTestCase(base::BindOnce([] { NSString* deviceId = GetFirstDeviceId(); @@ -183,8 +181,7 @@ TEST(VideoCaptureDeviceAVFoundationMacTest, SpecifiedScalingOutputsNv12) { TEST(VideoCaptureDeviceAVFoundationMacTest, SpecifiedScalingCanChangeDuringCapture) { base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - {kInCaptureConvertToNv12, kInCapturerScaling}, {}); + scoped_feature_list.InitAndEnableFeature(kInCapturerScaling); RunTestCase(base::BindOnce([] { NSString* deviceId = GetFirstDeviceId(); @@ -254,8 +251,7 @@ TEST(VideoCaptureDeviceAVFoundationMacTest, TEST(VideoCaptureDeviceAVFoundationMacTest, SpecifiedScalingUsesGoodSizesButNotBadSizes) { base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitWithFeatures( - {kInCaptureConvertToNv12, kInCapturerScaling}, {}); + scoped_feature_list.InitAndEnableFeature(kInCapturerScaling); RunTestCase(base::BindOnce([] { VideoCaptureDeviceFactoryMac video_capture_device_factory; @@ -266,8 +262,8 @@ TEST(VideoCaptureDeviceAVFoundationMacTest, return; } const auto& device_info = device_infos.front(); - NSString* deviceId = [NSString - stringWithUTF8String:device_info.descriptor.device_id.c_str()]; + NSString* deviceId = + base::SysUTF8ToNSString(device_info.descriptor.device_id); VideoCaptureFormat camera_format = device_info.supported_formats.front(); testing::NiceMock<MockVideoCaptureDeviceAVFoundationFrameReceiver> diff --git a/chromium/media/capture/video/mac/video_capture_device_avfoundation_utils_mac.mm b/chromium/media/capture/video/mac/video_capture_device_avfoundation_utils_mac.mm index f37ca493c1f..5268b2c1b2f 100644 --- a/chromium/media/capture/video/mac/video_capture_device_avfoundation_utils_mac.mm +++ b/chromium/media/capture/video/mac/video_capture_device_avfoundation_utils_mac.mm @@ -153,7 +153,7 @@ base::scoped_nsobject<NSDictionary> GetDeviceNames() { [[[DeviceNameAndTransportType alloc] initWithName:[device localizedName] transportType:[device transportType]] autorelease]; - [deviceNames setObject:nameAndTransportType forKey:[device uniqueID]]; + deviceNames[[device uniqueID]] = nameAndTransportType; } } MaybeWriteUma([deviceNames count], number_of_suspended_devices); diff --git a/chromium/media/capture/video/mac/video_capture_device_mac.h b/chromium/media/capture/video/mac/video_capture_device_mac.h index a4fde58694a..e1538917169 100644 --- a/chromium/media/capture/video/mac/video_capture_device_mac.h +++ b/chromium/media/capture/video/mac/video_capture_device_mac.h @@ -41,7 +41,8 @@ CAPTURE_EXPORT int32_t _transportType; } -- (id)initWithName:(NSString*)name transportType:(int32_t)transportType; +- (instancetype)initWithName:(NSString*)name + transportType:(int32_t)transportType; - (NSString*)deviceName; - (int32_t)transportType; diff --git a/chromium/media/capture/video/mac/video_capture_device_mac.mm b/chromium/media/capture/video/mac/video_capture_device_mac.mm index ed70ba8f991..83d4d0a18d1 100644 --- a/chromium/media/capture/video/mac/video_capture_device_mac.mm +++ b/chromium/media/capture/video/mac/video_capture_device_mac.mm @@ -37,7 +37,8 @@ using ScopedIOUSBInterfaceInterface = @implementation DeviceNameAndTransportType -- (id)initWithName:(NSString*)deviceName transportType:(int32_t)transportType { +- (instancetype)initWithName:(NSString*)deviceName + transportType:(int32_t)transportType { if (self = [super init]) { _deviceName.reset([deviceName copy]); _transportType = transportType; @@ -450,8 +451,8 @@ static void GetZoomControlRangeAndCurrent( static void SetPanTiltInUsbDevice( IOUSBInterfaceInterface220** control_interface, int unit_id, - base::Optional<int> pan, - base::Optional<int> tilt) { + absl::optional<int> pan, + absl::optional<int> tilt) { if (!pan.has_value() && !tilt.has_value()) return; @@ -620,8 +621,7 @@ void VideoCaptureDeviceMac::AllocateAndStart( LogMessage("Using AVFoundation for device: " + device_descriptor_.display_name()); - NSString* deviceId = - [NSString stringWithUTF8String:device_descriptor_.device_id.c_str()]; + NSString* deviceId = base::SysUTF8ToNSString(device_descriptor_.device_id); [capture_device_ setFrameReceiver:this]; @@ -750,10 +750,10 @@ void VideoCaptureDeviceMac::SetPhotoOptions(mojom::PhotoSettingsPtr settings, if (settings->has_pan || settings->has_tilt) { SetPanTiltInUsbDevice( control_interface, unit_id, - settings->has_pan ? base::make_optional(settings->pan) - : base::nullopt, - settings->has_tilt ? base::make_optional(settings->tilt) - : base::nullopt); + settings->has_pan ? absl::make_optional(settings->pan) + : absl::nullopt, + settings->has_tilt ? absl::make_optional(settings->tilt) + : absl::nullopt); } if (settings->has_zoom) { SetZoomInUsbDevice(control_interface, unit_id, settings->zoom); diff --git a/chromium/media/capture/video/mac/video_capture_device_mac_unittest.mm b/chromium/media/capture/video/mac/video_capture_device_mac_unittest.mm index f690264dbf7..d5ed43a2bbf 100644 --- a/chromium/media/capture/video/mac/video_capture_device_mac_unittest.mm +++ b/chromium/media/capture/video/mac/video_capture_device_mac_unittest.mm @@ -15,15 +15,15 @@ Float64 _minFrameRate; Float64 _maxFrameRate; } -- (id)initWithMinFrameRate:(Float64)minFrameRate - maxFrameRate:(Float64)maxFrameRate; +- (instancetype)initWithMinFrameRate:(Float64)minFrameRate + maxFrameRate:(Float64)maxFrameRate; @end @implementation FakeAVFrameRateRange #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-designated-initializers" -- (id)initWithMinFrameRate:(Float64)minFrameRate - maxFrameRate:(Float64)maxFrameRate { +- (instancetype)initWithMinFrameRate:(Float64)minFrameRate + maxFrameRate:(Float64)maxFrameRate { _minFrameRate = minFrameRate; _maxFrameRate = maxFrameRate; return self; @@ -46,20 +46,20 @@ base::scoped_nsobject<FakeAVFrameRateRange> _frameRateRange1; base::scoped_nsobject<FakeAVFrameRateRange> _frameRateRange2; }; -- (id)initWithWidth:(int)width - height:(int)height - fourCC:(FourCharCode)fourCC - frameRate:(Float64)frameRate; +- (instancetype)initWithWidth:(int)width + height:(int)height + fourCC:(FourCharCode)fourCC + frameRate:(Float64)frameRate; - (void)setSecondFrameRate:(Float64)frameRate; @end @implementation FakeAVCaptureDeviceFormat #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-designated-initializers" -- (id)initWithWidth:(int)width - height:(int)height - fourCC:(FourCharCode)fourCC - frameRate:(Float64)frameRate { +- (instancetype)initWithWidth:(int)width + height:(int)height + fourCC:(FourCharCode)fourCC + frameRate:(Float64)frameRate { CMVideoFormatDescriptionCreate(nullptr, fourCC, width, height, nullptr, _formatDescription.InitializeInto()); _frameRateRange1.reset([[FakeAVFrameRateRange alloc] diff --git a/chromium/media/capture/video/mock_gpu_memory_buffer_manager.cc b/chromium/media/capture/video/mock_gpu_memory_buffer_manager.cc index 0246f6cbe99..8d1e5f9d4c8 100644 --- a/chromium/media/capture/video/mock_gpu_memory_buffer_manager.cc +++ b/chromium/media/capture/video/mock_gpu_memory_buffer_manager.cc @@ -24,7 +24,8 @@ MockGpuMemoryBufferManager::CreateFakeGpuMemoryBuffer( const gfx::Size& size, gfx::BufferFormat format, gfx::BufferUsage usage, - gpu::SurfaceHandle surface_handle) { + gpu::SurfaceHandle surface_handle, + base::WaitableEvent* shutdown_event) { auto gmb = std::make_unique<FakeGpuMemoryBuffer>(size, format); #if BUILDFLAG(IS_CHROMEOS_ASH) // For faking a valid JPEG blob buffer. diff --git a/chromium/media/capture/video/mock_gpu_memory_buffer_manager.h b/chromium/media/capture/video/mock_gpu_memory_buffer_manager.h index 614cf8b8ac6..d617825ef3f 100644 --- a/chromium/media/capture/video/mock_gpu_memory_buffer_manager.h +++ b/chromium/media/capture/video/mock_gpu_memory_buffer_manager.h @@ -19,12 +19,13 @@ class MockGpuMemoryBufferManager : public gpu::GpuMemoryBufferManager { ~MockGpuMemoryBufferManager() override; - MOCK_METHOD4( - CreateGpuMemoryBuffer, - std::unique_ptr<gfx::GpuMemoryBuffer>(const gfx::Size& size, - gfx::BufferFormat format, - gfx::BufferUsage usage, - gpu::SurfaceHandle surface_handle)); + MOCK_METHOD5(CreateGpuMemoryBuffer, + std::unique_ptr<gfx::GpuMemoryBuffer>( + const gfx::Size& size, + gfx::BufferFormat format, + gfx::BufferUsage usage, + gpu::SurfaceHandle surface_handle, + base::WaitableEvent* shutdown_event)); MOCK_METHOD2(SetDestructionSyncToken, void(gfx::GpuMemoryBuffer* buffer, @@ -43,7 +44,8 @@ class MockGpuMemoryBufferManager : public gpu::GpuMemoryBufferManager { const gfx::Size& size, gfx::BufferFormat format, gfx::BufferUsage usage, - gpu::SurfaceHandle surface_handle); + gpu::SurfaceHandle surface_handle, + base::WaitableEvent* shutdown_event); private: DISALLOW_COPY_AND_ASSIGN(MockGpuMemoryBufferManager); diff --git a/chromium/media/capture/video/video_capture_device.h b/chromium/media/capture/video/video_capture_device.h index fdc1197c3a8..0ee1782bb83 100644 --- a/chromium/media/capture/video/video_capture_device.h +++ b/chromium/media/capture/video/video_capture_device.h @@ -137,6 +137,12 @@ class CAPTURE_EXPORT VideoCaptureDevice int frame_feedback_id; std::unique_ptr<HandleProvider> handle_provider; std::unique_ptr<ScopedAccessPermission> access_permission; + + // Some buffer types may be preemptively mapped in the capturer if + // requested by the consumer. + // This is used to notify the client that a shared memory region + // associated with the buffer is valid. + bool is_premapped = false; }; // Result code for calls to ReserveOutputBuffer() diff --git a/chromium/media/capture/video/video_capture_device_client.cc b/chromium/media/capture/video/video_capture_device_client.cc index 47ea404600e..a6771881497 100644 --- a/chromium/media/capture/video/video_capture_device_client.cc +++ b/chromium/media/capture/video/video_capture_device_client.cc @@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/containers/contains.h" #include "base/location.h" #include "base/strings/stringprintf.h" #include "base/trace_event/trace_event.h" @@ -628,6 +629,7 @@ void VideoCaptureDeviceClient::OnIncomingCapturedBufferExt( info->coded_size = format.frame_size; info->visible_rect = visible_rect; info->metadata = metadata; + info->is_premapped = buffer.is_premapped; buffer_pool_->HoldForConsumers(buffer.id, 1); receiver_->OnFrameReadyInBuffer( diff --git a/chromium/media/capture/video/video_capture_device_client.h b/chromium/media/capture/video/video_capture_device_client.h index 07d39c57cb5..3205586b357 100644 --- a/chromium/media/capture/video/video_capture_device_client.h +++ b/chromium/media/capture/video/video_capture_device_client.h @@ -16,7 +16,6 @@ #include "base/threading/thread_collision_warner.h" #include "build/chromeos_buildflags.h" #include "media/capture/capture_export.h" -#include "media/capture/mojom/video_capture_types.mojom.h" #include "media/capture/video/video_capture_device.h" #include "media/capture/video/video_frame_receiver.h" diff --git a/chromium/media/capture/video/video_capture_device_client_unittest.cc b/chromium/media/capture/video/video_capture_device_client_unittest.cc index 0d5f18b5ddc..c4a218f423e 100644 --- a/chromium/media/capture/video/video_capture_device_client_unittest.cc +++ b/chromium/media/capture/video/video_capture_device_client_unittest.cc @@ -112,7 +112,7 @@ TEST_F(VideoCaptureDeviceClientTest, Minimal) { gpu_memory_buffer_manager_->CreateFakeGpuMemoryBuffer( kBufferDimensions, gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE, - gpu::kNullSurfaceHandle); + gpu::kNullSurfaceHandle, nullptr); { InSequence s; const int expected_buffer_id = 0; @@ -152,7 +152,8 @@ TEST_F(VideoCaptureDeviceClientTest, FailsSilentlyGivenInvalidFrameFormat) { std::unique_ptr<gfx::GpuMemoryBuffer> buffer = gpu_memory_buffer_manager_->CreateFakeGpuMemoryBuffer( kBufferDimensions, gfx::BufferFormat::YUV_420_BIPLANAR, - gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, gpu::kNullSurfaceHandle); + gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, gpu::kNullSurfaceHandle, + nullptr); EXPECT_CALL(*receiver_, MockOnFrameReadyInBuffer(_, _, _)).Times(0); device_client_->OnIncomingCapturedGfxBuffer( buffer.get(), kFrameFormat, 0 /*clockwise rotation*/, base::TimeTicks(), @@ -311,7 +312,7 @@ TEST_F(VideoCaptureDeviceClientTest, CheckRotationsAndCrops) { size_and_rotation.input_resolution, gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE, - gpu::kNullSurfaceHandle); + gpu::kNullSurfaceHandle, nullptr); gfx::Size coded_size; EXPECT_CALL(*receiver_, MockOnFrameReadyInBuffer(_, _, _)) diff --git a/chromium/media/capture/video/video_capture_device_descriptor.h b/chromium/media/capture/video/video_capture_device_descriptor.h index f73d893e970..6318097be1d 100644 --- a/chromium/media/capture/video/video_capture_device_descriptor.h +++ b/chromium/media/capture/video/video_capture_device_descriptor.h @@ -8,9 +8,9 @@ #include <string> #include <vector> -#include "base/optional.h" #include "media/base/video_facing.h" #include "media/capture/capture_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { diff --git a/chromium/media/capture/video/video_capture_device_unittest.cc b/chromium/media/capture/video/video_capture_device_unittest.cc index 8ce31e46f7b..dcdb16d4c0b 100644 --- a/chromium/media/capture/video/video_capture_device_unittest.cc +++ b/chromium/media/capture/video/video_capture_device_unittest.cc @@ -109,13 +109,9 @@ #define MAYBE_UsingRealWebcam_AllocateBadSize \ DISABLED_UsingRealWebcam_AllocateBadSize #define MAYBE_UsingRealWebcam_CaptureMjpeg UsingRealWebcam_CaptureMjpeg -// Flaky: https://crbug.com/1096082 -#define MAYBE_UsingRealWebcam_TakePhoto DISABLED_UsingRealWebcam_TakePhoto -#define MAYBE_UsingRealWebcam_GetPhotoState \ - DISABLED_UsingRealWebcam_GetPhotoState -// Flaky crash: https://crbug.com/1069608 -#define MAYBE_UsingRealWebcam_CaptureWithSize \ - DISABLED_UsingRealWebcam_CaptureWithSize +#define MAYBE_UsingRealWebcam_TakePhoto UsingRealWebcam_TakePhoto +#define MAYBE_UsingRealWebcam_GetPhotoState UsingRealWebcam_GetPhotoState +#define MAYBE_UsingRealWebcam_CaptureWithSize UsingRealWebcam_CaptureWithSize #define MAYBE_UsingRealWebcam_CheckPhotoCallbackRelease \ UsingRealWebcam_CheckPhotoCallbackRelease #elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) @@ -374,7 +370,7 @@ class VideoCaptureDeviceTest run_loop_->Run(); } - base::Optional<VideoCaptureDeviceInfo> FindUsableDevice() { + absl::optional<VideoCaptureDeviceInfo> FindUsableDevice() { base::RunLoop run_loop; video_capture_device_factory_->GetDevicesInfo(base::BindLambdaForTesting( [this, &run_loop](std::vector<VideoCaptureDeviceInfo> devices_info) { @@ -385,7 +381,7 @@ class VideoCaptureDeviceTest if (devices_info_.empty()) { DLOG(WARNING) << "No camera found"; - return base::nullopt; + return absl::nullopt; } #if defined(OS_ANDROID) for (const auto& device : devices_info_) { @@ -400,7 +396,7 @@ class VideoCaptureDeviceTest } } DLOG(WARNING) << "No usable camera found"; - return base::nullopt; + return absl::nullopt; #else auto device = devices_info_.front(); DLOG(INFO) << "Using camera " << device.descriptor.GetNameAndModel(); @@ -410,10 +406,10 @@ class VideoCaptureDeviceTest const VideoCaptureFormat& last_format() const { return last_format_; } - base::Optional<VideoCaptureDeviceInfo> GetFirstDeviceSupportingPixelFormat( + absl::optional<VideoCaptureDeviceInfo> GetFirstDeviceSupportingPixelFormat( const VideoPixelFormat& pixel_format) { if (!FindUsableDevice()) - return base::nullopt; + return absl::nullopt; for (const auto& device : devices_info_) { for (const auto& format : device.supported_formats) { @@ -424,7 +420,7 @@ class VideoCaptureDeviceTest } DVLOG_IF(1, pixel_format != PIXEL_FORMAT_MAX) << VideoPixelFormatToString(pixel_format); - return base::nullopt; + return absl::nullopt; } bool IsCaptureSizeSupported(const VideoCaptureDeviceInfo& device_info, @@ -477,15 +473,17 @@ class VideoCaptureDeviceTest std::unique_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_; }; -// Causes a flaky crash on Chrome OS. https://crbug.com/1069608 // Cause hangs on Windows Debug. http://crbug.com/417824 -#if BUILDFLAG(IS_CHROMEOS_ASH) || (defined(OS_WIN) && !defined(NDEBUG)) -#define MAYBE_OpenInvalidDevice DISABLED_OpenInvalidDevice +#if (defined(OS_WIN) && !defined(NDEBUG)) +#define MAYBE_UsingRealWebcam_OpenInvalidDevice \ + DISABLED_UsingRealWebcam_OpenInvalidDevice #else -#define MAYBE_OpenInvalidDevice OpenInvalidDevice +#define MAYBE_UsingRealWebcam_OpenInvalidDevice \ + UsingRealWebcam_OpenInvalidDevice #endif // Tries to allocate an invalid device and verifies it doesn't work. -WRAPPED_TEST_P(VideoCaptureDeviceTest, MAYBE_OpenInvalidDevice) { +WRAPPED_TEST_P(VideoCaptureDeviceTest, + MAYBE_UsingRealWebcam_OpenInvalidDevice) { RunTestCase( base::BindOnce(&VideoCaptureDeviceTest::RunOpenInvalidDeviceTestCase, base::Unretained(this))); @@ -707,14 +705,10 @@ void VideoCaptureDeviceTest::RunCaptureMjpegTestCase() { device->StopAndDeAllocate(); } -// Flaky on ChromeOS. See https://crbug.com/1096082 -#if BUILDFLAG(IS_CHROMEOS_ASH) -#define MAYBE_NoCameraSupportsPixelFormatMax \ - DISABLED_NoCameraSupportsPixelFormatMax -#else -#define MAYBE_NoCameraSupportsPixelFormatMax NoCameraSupportsPixelFormatMax -#endif -WRAPPED_TEST_P(VideoCaptureDeviceTest, MAYBE_NoCameraSupportsPixelFormatMax) { +#define MAYBE_UsingRealWebcam_NoCameraSupportsPixelFormatMax \ + UsingRealWebcam_NoCameraSupportsPixelFormatMax +WRAPPED_TEST_P(VideoCaptureDeviceTest, + MAYBE_UsingRealWebcam_NoCameraSupportsPixelFormatMax) { RunTestCase(base::BindOnce( &VideoCaptureDeviceTest::RunNoCameraSupportsPixelFormatMaxTestCase, base::Unretained(this))); diff --git a/chromium/media/capture/video/win/capability_list_win.cc b/chromium/media/capture/video/win/capability_list_win.cc index 4ea9c690490..5ce95b17037 100644 --- a/chromium/media/capture/video/win/capability_list_win.cc +++ b/chromium/media/capture/video/win/capability_list_win.cc @@ -10,6 +10,7 @@ #include "base/check.h" #include "media/capture/video_capture_types.h" +#include "base/logging.h" namespace media { namespace { @@ -17,41 +18,79 @@ namespace { // Compares the priority of the capture formats. Returns true if |lhs| is the // preferred capture format in comparison with |rhs|. Returns false otherwise. bool CompareCapability(const VideoCaptureFormat& requested, - const VideoCaptureFormat& lhs, - const VideoCaptureFormat& rhs) { + const CapabilityWin& lhs, + const CapabilityWin& rhs) { // When 16-bit format or NV12 is requested and available, avoid other formats. // If both lhs and rhs are 16-bit, we still need to compare them based on // height, width and frame rate. const bool use_requested = (requested.pixel_format == media::PIXEL_FORMAT_Y16) || (requested.pixel_format == media::PIXEL_FORMAT_NV12); - if (use_requested && lhs.pixel_format != rhs.pixel_format) { - if (lhs.pixel_format == requested.pixel_format) + if (use_requested && + lhs.supported_format.pixel_format != rhs.supported_format.pixel_format) { + if (lhs.supported_format.pixel_format == requested.pixel_format) return true; - if (rhs.pixel_format == requested.pixel_format) + if (rhs.supported_format.pixel_format == requested.pixel_format) return false; } - const int diff_height_lhs = - std::abs(lhs.frame_size.height() - requested.frame_size.height()); - const int diff_height_rhs = - std::abs(rhs.frame_size.height() - requested.frame_size.height()); + const int diff_height_lhs = std::abs( + lhs.supported_format.frame_size.height() - requested.frame_size.height()); + const int diff_height_rhs = std::abs( + rhs.supported_format.frame_size.height() - requested.frame_size.height()); if (diff_height_lhs != diff_height_rhs) return diff_height_lhs < diff_height_rhs; - const int diff_width_lhs = - std::abs(lhs.frame_size.width() - requested.frame_size.width()); - const int diff_width_rhs = - std::abs(rhs.frame_size.width() - requested.frame_size.width()); + const int diff_width_lhs = std::abs(lhs.supported_format.frame_size.width() - + requested.frame_size.width()); + const int diff_width_rhs = std::abs(rhs.supported_format.frame_size.width() - + requested.frame_size.width()); if (diff_width_lhs != diff_width_rhs) return diff_width_lhs < diff_width_rhs; - const float diff_fps_lhs = std::fabs(lhs.frame_rate - requested.frame_rate); - const float diff_fps_rhs = std::fabs(rhs.frame_rate - requested.frame_rate); + const float diff_fps_lhs = + std::fabs(lhs.supported_format.frame_rate - requested.frame_rate); + const float diff_fps_rhs = + std::fabs(rhs.supported_format.frame_rate - requested.frame_rate); if (diff_fps_lhs != diff_fps_rhs) return diff_fps_lhs < diff_fps_rhs; - return VideoCaptureFormat::ComparePixelFormatPreference(lhs.pixel_format, - rhs.pixel_format); + // Compare by internal pixel format to avoid conversions when possible. + if (lhs.source_pixel_format != rhs.source_pixel_format) { + // Choose the format with no conversion if possible. + if (lhs.source_pixel_format == requested.pixel_format) + return true; + if (rhs.source_pixel_format == requested.pixel_format) + return false; + // Prefer I420<->NV12 conversion over all. + if ((lhs.source_pixel_format == PIXEL_FORMAT_NV12 && + requested.pixel_format == PIXEL_FORMAT_I420) || + (lhs.source_pixel_format == PIXEL_FORMAT_I420 && + requested.pixel_format == PIXEL_FORMAT_NV12)) { + return true; + } + if ((rhs.source_pixel_format == PIXEL_FORMAT_NV12 && + requested.pixel_format == PIXEL_FORMAT_I420) || + (rhs.source_pixel_format == PIXEL_FORMAT_I420 && + requested.pixel_format == PIXEL_FORMAT_NV12)) { + return false; + } + // YUY2<->NV12 is the next best. + if ((lhs.source_pixel_format == PIXEL_FORMAT_NV12 && + requested.pixel_format == PIXEL_FORMAT_YUY2) || + (lhs.source_pixel_format == PIXEL_FORMAT_YUY2 && + requested.pixel_format == PIXEL_FORMAT_NV12)) { + return true; + } + if ((rhs.source_pixel_format == PIXEL_FORMAT_NV12 && + requested.pixel_format == PIXEL_FORMAT_YUY2) || + (rhs.source_pixel_format == PIXEL_FORMAT_YUY2 && + requested.pixel_format == PIXEL_FORMAT_NV12)) { + return false; + } + } + + return VideoCaptureFormat::ComparePixelFormatPreference( + lhs.supported_format.pixel_format, rhs.supported_format.pixel_format); } } // namespace @@ -62,8 +101,7 @@ const CapabilityWin& GetBestMatchedCapability( DCHECK(!capabilities.empty()); const CapabilityWin* best_match = &(*capabilities.begin()); for (const CapabilityWin& capability : capabilities) { - if (CompareCapability(requested, capability.supported_format, - best_match->supported_format)) { + if (CompareCapability(requested, capability, *best_match)) { best_match = &capability; } } diff --git a/chromium/media/capture/video/win/capability_list_win.h b/chromium/media/capture/video/win/capability_list_win.h index f873251d6a6..2b77fbe98aa 100644 --- a/chromium/media/capture/video/win/capability_list_win.h +++ b/chromium/media/capture/video/win/capability_list_win.h @@ -21,7 +21,8 @@ struct CapabilityWin { : media_type_index(media_type_index), supported_format(format), info_header(), - stream_index(0) {} + stream_index(0), + source_pixel_format(format.pixel_format) {} // Used by VideoCaptureDeviceWin. CapabilityWin(int media_type_index, @@ -30,16 +31,19 @@ struct CapabilityWin { : media_type_index(media_type_index), supported_format(format), info_header(info_header), - stream_index(0) {} + stream_index(0), + source_pixel_format(format.pixel_format) {} // Used by VideoCaptureDeviceMFWin. CapabilityWin(int media_type_index, const VideoCaptureFormat& format, - int stream_index) + int stream_index, + VideoPixelFormat source_format) : media_type_index(media_type_index), supported_format(format), info_header(), - stream_index(stream_index) {} + stream_index(stream_index), + source_pixel_format(source_format) {} const int media_type_index; const VideoCaptureFormat supported_format; @@ -49,6 +53,10 @@ struct CapabilityWin { // |stream_index| is only valid if MediaFoundation is used. const int stream_index; + + // |source_pixel_format| may differ from |supported_format| + // if MediaFoundation is used. + VideoPixelFormat source_pixel_format; }; typedef std::list<CapabilityWin> CapabilityList; diff --git a/chromium/media/capture/video/win/gpu_memory_buffer_tracker.cc b/chromium/media/capture/video/win/gpu_memory_buffer_tracker.cc index e39f2db5f4f..8579ebcc295 100644 --- a/chromium/media/capture/video/win/gpu_memory_buffer_tracker.cc +++ b/chromium/media/capture/video/win/gpu_memory_buffer_tracker.cc @@ -101,6 +101,9 @@ bool GpuMemoryBufferTracker::CreateBufferInternal() { NOTREACHED() << "Failed to create GPU memory buffer"; return false; } + + region_ = base::UnsafeSharedMemoryRegion::Create(GetMemorySizeInBytes()); + return true; } @@ -137,10 +140,8 @@ GpuMemoryBufferTracker::DuplicateAsUnsafeRegion() { if (!buffer_) { return base::UnsafeSharedMemoryRegion(); } - const auto data_size = GetMemorySizeInBytes(); - if (!region_.IsValid() || region_.GetSize() < data_size) { - region_ = base::UnsafeSharedMemoryRegion::Create(data_size); - } + + CHECK(region_.IsValid()); if (!gpu::CopyDXGIBufferToShMem(buffer_->GetHandle(), region_.Duplicate(), d3d_device_.Get(), &staging_texture_)) { @@ -160,7 +161,9 @@ gfx::GpuMemoryBufferHandle GpuMemoryBufferTracker::GetGpuMemoryBufferHandle() { if (!EnsureD3DDevice()) { return gfx::GpuMemoryBufferHandle(); } - return buffer_->CloneHandle(); + auto handle = buffer_->CloneHandle(); + handle.region = region_.Duplicate(); + return handle; } uint32_t GpuMemoryBufferTracker::GetMemorySizeInBytes() { diff --git a/chromium/media/capture/video/win/video_capture_device_factory_win.cc b/chromium/media/capture/video/win/video_capture_device_factory_win.cc index 43e01991837..d7b56a063ac 100644 --- a/chromium/media/capture/video/win/video_capture_device_factory_win.cc +++ b/chromium/media/capture/video/win/video_capture_device_factory_win.cc @@ -17,6 +17,7 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/containers/contains.h" #include "base/feature_list.h" #include "base/metrics/histogram_macros.h" #include "base/no_destructor.h" @@ -975,11 +976,6 @@ VideoCaptureDeviceFactoryWin::GetSupportedFormatsMediaFoundation( ++stream_index; if (capture_format.pixel_format == PIXEL_FORMAT_UNKNOWN) continue; - // If we're using the hardware capture path, ignore non-NV12 pixel formats - // to prevent copies - if (dxgi_device_manager_available && - capture_format.pixel_format != PIXEL_FORMAT_NV12) - continue; formats.push_back(capture_format); DVLOG(1) << display_name << " " diff --git a/chromium/media/capture/video/win/video_capture_device_factory_win_unittest.cc b/chromium/media/capture/video/win/video_capture_device_factory_win_unittest.cc index 274bab4fdac..15bda062bd3 100644 --- a/chromium/media/capture/video/win/video_capture_device_factory_win_unittest.cc +++ b/chromium/media/capture/video/win/video_capture_device_factory_win_unittest.cc @@ -8,6 +8,7 @@ #include <ksmedia.h> #include <mfapi.h> #include <mferror.h> +#include <mfobjects.h> #include <stddef.h> #include <vidcap.h> #include <wrl.h> @@ -64,6 +65,11 @@ const wchar_t* kDirectShowDeviceName5 = L"Dazzle"; const wchar_t* kDirectShowDeviceId6 = L"\\\\?\\usb#vid_eb1a&pid_2860&mi_00"; const wchar_t* kDirectShowDeviceName6 = L"Empia Device"; +constexpr int kWidth = 1280; +constexpr int kHeight = 720; + +constexpr int kFps = 30; + using iterator = std::vector<VideoCaptureDeviceInfo>::const_iterator; iterator FindDeviceInRange(iterator begin, iterator end, @@ -385,6 +391,11 @@ class StubMFMediaSource final : public StubDeviceInterface<IMFMediaSourceEx> { *object = AddReference(static_cast<IMFMediaSource*>(this)); return S_OK; } + if (riid == _uuidof(IMFMediaEventGenerator)) { + *object = AddReference(static_cast<IMFMediaEventGenerator*>(this)); + return S_OK; + } + return StubDeviceInterface::QueryInterface(riid, object); } // IMFMediaEventGenerator @@ -436,6 +447,15 @@ class StubMFMediaSource final : public StubDeviceInterface<IMFMediaSourceEx> { if (FAILED(hr)) { return hr; } + hr = MFSetAttributeSize(media_type.Get(), MF_MT_FRAME_SIZE, kWidth, + kHeight); + if (FAILED(hr)) { + return hr; + } + hr = MFSetAttributeRatio(media_type.Get(), MF_MT_FRAME_RATE, kFps, 1); + if (FAILED(hr)) { + return hr; + } media_types.push_back(media_type); media_type_list.push_back(media_type.Get()); } @@ -1579,6 +1599,7 @@ TEST_P(VideoCaptureDeviceFactoryMFWinTest, base::SysWideToUTF8(kMFDeviceId0)); ASSERT_NE(it, devices_info.end()); EXPECT_EQ(it->descriptor.display_name(), base::SysWideToUTF8(kMFDeviceName0)); + EXPECT_FALSE(it->supported_formats.empty()); for (size_t i = 0; i < it->supported_formats.size(); i++) { SCOPED_TRACE(i); EXPECT_EQ(it->supported_formats[i].pixel_format, @@ -1589,9 +1610,11 @@ TEST_P(VideoCaptureDeviceFactoryMFWinTest, base::SysWideToUTF8(kMFDeviceId1)); ASSERT_NE(it, devices_info.end()); EXPECT_EQ(it->descriptor.display_name(), base::SysWideToUTF8(kMFDeviceName1)); + EXPECT_FALSE(it->supported_formats.empty()); for (size_t i = 0; i < it->supported_formats.size(); i++) { SCOPED_TRACE(i); - EXPECT_EQ(it->supported_formats[i].pixel_format, PIXEL_FORMAT_I420); + EXPECT_EQ(it->supported_formats[i].pixel_format, + expected_pixel_format_for_nv12); } } diff --git a/chromium/media/capture/video/win/video_capture_device_mf_win.cc b/chromium/media/capture/video/win/video_capture_device_mf_win.cc index 2f2b72f1e44..750a04d1dc4 100644 --- a/chromium/media/capture/video/win/video_capture_device_mf_win.cc +++ b/chromium/media/capture/video/win/video_capture_device_mf_win.cc @@ -10,6 +10,7 @@ #include <stddef.h> #include <wincodec.h> +#include <memory> #include <thread> #include <utility> @@ -226,10 +227,39 @@ bool GetFrameRateFromMediaType(IMFMediaType* type, float* frame_rate) { return true; } +struct PixelFormatMap { + GUID mf_source_media_subtype; + VideoPixelFormat pixel_format; +}; + +VideoPixelFormat MfSubTypeToSourcePixelFormat( + const GUID& mf_source_media_subtype) { + static const PixelFormatMap kPixelFormatMap[] = { + + {MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {MFVideoFormat_YUY2, PIXEL_FORMAT_YUY2}, + {MFVideoFormat_UYVY, PIXEL_FORMAT_UYVY}, + {MFVideoFormat_RGB24, PIXEL_FORMAT_RGB24}, + {MFVideoFormat_RGB32, PIXEL_FORMAT_XRGB}, + {MFVideoFormat_ARGB32, PIXEL_FORMAT_ARGB}, + {MFVideoFormat_MJPG, PIXEL_FORMAT_MJPEG}, + {MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {MFVideoFormat_YV12, PIXEL_FORMAT_YV12}, + {GUID_ContainerFormatJpeg, PIXEL_FORMAT_MJPEG}}; + + for (const auto& kEntry : kPixelFormatMap) { + if (kEntry.mf_source_media_subtype == mf_source_media_subtype) { + return kEntry.pixel_format; + } + } + return PIXEL_FORMAT_UNKNOWN; +} + bool GetFormatFromSourceMediaType(IMFMediaType* source_media_type, bool photo, bool use_hardware_format, - VideoCaptureFormat* format) { + VideoCaptureFormat* format, + VideoPixelFormat* source_pixel_format) { GUID major_type_guid; if (FAILED(source_media_type->GetGUID(MF_MT_MAJOR_TYPE, &major_type_guid)) || (major_type_guid != MFMediaType_Image && @@ -246,6 +276,7 @@ bool GetFormatFromSourceMediaType(IMFMediaType* source_media_type, return false; } + *source_pixel_format = MfSubTypeToSourcePixelFormat(sub_type_guid); return true; } @@ -264,6 +295,7 @@ HRESULT CopyAttribute(IMFAttributes* source_attributes, } struct MediaFormatConfiguration { + bool is_hardware_format; GUID mf_source_media_subtype; GUID mf_sink_media_subtype; VideoPixelFormat pixel_format; @@ -273,13 +305,6 @@ bool GetMediaFormatConfigurationFromMFSourceMediaSubtype( const GUID& mf_source_media_subtype, bool use_hardware_format, MediaFormatConfiguration* media_format_configuration) { - // Special case handling of the NV12 format when using hardware capture - // to ensure that captured buffers are passed through without copies - if (use_hardware_format && mf_source_media_subtype == MFVideoFormat_NV12) { - *media_format_configuration = {MFVideoFormat_NV12, MFVideoFormat_NV12, - PIXEL_FORMAT_NV12}; - return true; - } static const MediaFormatConfiguration kMediaFormatConfigurationMap[] = { // IMFCaptureEngine inevitably performs the video frame decoding itself. // This means that the sink must always be set to an uncompressed video @@ -287,30 +312,56 @@ bool GetMediaFormatConfigurationFromMFSourceMediaSubtype( // Since chromium uses I420 at the other end of the pipe, MF known video // output formats are always set to I420. - {MFVideoFormat_I420, MFVideoFormat_I420, PIXEL_FORMAT_I420}, - {MFVideoFormat_YUY2, MFVideoFormat_I420, PIXEL_FORMAT_I420}, - {MFVideoFormat_UYVY, MFVideoFormat_I420, PIXEL_FORMAT_I420}, - {MFVideoFormat_RGB24, MFVideoFormat_I420, PIXEL_FORMAT_I420}, - {MFVideoFormat_RGB32, MFVideoFormat_I420, PIXEL_FORMAT_I420}, - {MFVideoFormat_ARGB32, MFVideoFormat_I420, PIXEL_FORMAT_I420}, - {MFVideoFormat_MJPG, MFVideoFormat_I420, PIXEL_FORMAT_I420}, - {MFVideoFormat_NV12, MFVideoFormat_I420, PIXEL_FORMAT_I420}, - {MFVideoFormat_YV12, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_I420, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_YUY2, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_UYVY, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_RGB24, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_RGB32, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_ARGB32, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_MJPG, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_NV12, MFVideoFormat_I420, PIXEL_FORMAT_I420}, + {false, MFVideoFormat_YV12, MFVideoFormat_I420, PIXEL_FORMAT_I420}, // Depth cameras use 16-bit uncompressed video formats. // We ask IMFCaptureEngine to let the frame pass through, without // transcoding, since transcoding would lead to precision loss. - {kMediaSubTypeY16, kMediaSubTypeY16, PIXEL_FORMAT_Y16}, - {kMediaSubTypeZ16, kMediaSubTypeZ16, PIXEL_FORMAT_Y16}, - {kMediaSubTypeINVZ, kMediaSubTypeINVZ, PIXEL_FORMAT_Y16}, - {MFVideoFormat_D16, MFVideoFormat_D16, PIXEL_FORMAT_Y16}, + {false, kMediaSubTypeY16, kMediaSubTypeY16, PIXEL_FORMAT_Y16}, + {false, kMediaSubTypeZ16, kMediaSubTypeZ16, PIXEL_FORMAT_Y16}, + {false, kMediaSubTypeINVZ, kMediaSubTypeINVZ, PIXEL_FORMAT_Y16}, + {false, MFVideoFormat_D16, MFVideoFormat_D16, PIXEL_FORMAT_Y16}, // Photo type - {GUID_ContainerFormatJpeg, GUID_ContainerFormatJpeg, PIXEL_FORMAT_MJPEG}}; + {false, GUID_ContainerFormatJpeg, GUID_ContainerFormatJpeg, + PIXEL_FORMAT_MJPEG}, + + // For hardware path we always convert to NV12, since it's the only + // supported by GMBs format. + {true, MFVideoFormat_I420, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {true, MFVideoFormat_YUY2, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {true, MFVideoFormat_UYVY, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {true, MFVideoFormat_RGB24, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {true, MFVideoFormat_RGB32, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {true, MFVideoFormat_ARGB32, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {true, MFVideoFormat_MJPG, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {true, MFVideoFormat_NV12, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + {true, MFVideoFormat_YV12, MFVideoFormat_NV12, PIXEL_FORMAT_NV12}, + + // 16-bit formats can't be converted without loss of precision, + // so if leave an option to get Y16 pixel format even though the + // HW path won't be used for it. + {true, kMediaSubTypeY16, kMediaSubTypeY16, PIXEL_FORMAT_Y16}, + {true, kMediaSubTypeZ16, kMediaSubTypeZ16, PIXEL_FORMAT_Y16}, + {true, kMediaSubTypeINVZ, kMediaSubTypeINVZ, PIXEL_FORMAT_Y16}, + {true, MFVideoFormat_D16, MFVideoFormat_D16, PIXEL_FORMAT_Y16}, + + // Photo type + {true, GUID_ContainerFormatJpeg, GUID_ContainerFormatJpeg, + PIXEL_FORMAT_MJPEG}}; for (const auto& kMediaFormatConfiguration : kMediaFormatConfigurationMap) { - if (kMediaFormatConfiguration.mf_source_media_subtype == - mf_source_media_subtype) { + if (kMediaFormatConfiguration.is_hardware_format == use_hardware_format && + kMediaFormatConfiguration.mf_source_media_subtype == + mf_source_media_subtype) { *media_format_configuration = kMediaFormatConfiguration; return true; } @@ -789,12 +840,14 @@ HRESULT VideoCaptureDeviceMFWin::FillCapabilities( while (SUCCEEDED(hr = GetAvailableDeviceMediaType( source, stream_index, media_type_index, &type))) { VideoCaptureFormat format; + VideoPixelFormat source_pixel_format; if (GetFormatFromSourceMediaType( type.Get(), photo, /*use_hardware_format=*/!photo && static_cast<bool>(dxgi_device_manager_), - &format)) - capabilities->emplace_back(media_type_index, format, stream_index); + &format, &source_pixel_format)) + capabilities->emplace_back(media_type_index, format, stream_index, + source_pixel_format); type.Reset(); ++media_type_index; } @@ -947,8 +1000,8 @@ void VideoCaptureDeviceMFWin::AllocateAndStart( } if (!photo_capabilities_.empty()) { - selected_photo_capability_.reset( - new CapabilityWin(photo_capabilities_.front())); + selected_photo_capability_ = + std::make_unique<CapabilityWin>(photo_capabilities_.front()); } CapabilityList video_capabilities; @@ -1065,8 +1118,8 @@ void VideoCaptureDeviceMFWin::AllocateAndStart( return; } - selected_video_capability_.reset( - new CapabilityWin(best_match_video_capability)); + selected_video_capability_ = + std::make_unique<CapabilityWin>(best_match_video_capability); is_started_ = true; } @@ -1132,8 +1185,10 @@ void VideoCaptureDeviceMFWin::TakePhoto(TakePhotoCallback callback) { } VideoCaptureFormat format; + VideoPixelFormat source_format; hr = GetFormatFromSourceMediaType(sink_media_type.Get(), true, - /*use_hardware_format=*/false, &format) + /*use_hardware_format=*/false, &format, + &source_format) ? S_OK : E_FAIL; if (FAILED(hr)) { @@ -1309,7 +1364,7 @@ void VideoCaptureDeviceMFWin::SetPhotoOptions( const CapabilityWin best_match = GetBestMatchedPhotoCapability( current_source_media_type, requested_size, photo_capabilities_); - selected_photo_capability_.reset(new CapabilityWin(best_match)); + selected_photo_capability_ = std::make_unique<CapabilityWin>(best_match); } if (camera_control_ && video_control_) { @@ -1496,9 +1551,15 @@ HRESULT VideoCaptureDeviceMFWin::DeliverTextureToClient( auto gmb_handle = capture_buffer.handle_provider->GetGpuMemoryBufferHandle(); hr = CopyTextureToGpuMemoryBuffer(texture, gmb_handle.dxgi_handle.Get()); + capture_buffer.is_premapped = false; if (last_feedback_.require_mapped_frame) { - gmb_handle.region = - capture_buffer.handle_provider->DuplicateAsUnsafeRegion(); + // Only a flag on the Buffer is set here; the region itself isn't passed + // anywhere because it was passed when the buffer was created. + // Now the flag would tell the consumer that the region contains actual + // frame data. + if (capture_buffer.handle_provider->DuplicateAsUnsafeRegion().IsValid()) { + capture_buffer.is_premapped = true; + } } if (FAILED(hr)) { @@ -1563,7 +1624,11 @@ void VideoCaptureDeviceMFWin::OnIncomingCapturedDataInternal( camera_rotation_ = GetCameraRotation(facing_mode_); Microsoft::WRL::ComPtr<ID3D11Texture2D> texture; + // Use the hardware path only if it is enabled and the selected pixel format + // is NV12 (which is the only supported one). if (dxgi_device_manager_ && + selected_video_capability_->supported_format.pixel_format == + PIXEL_FORMAT_NV12 && SUCCEEDED(GetTextureFromMFBuffer(buffer, &texture))) { HRESULT hr = DeliverTextureToClient(texture.Get(), reference_time, timestamp); diff --git a/chromium/media/capture/video/win/video_capture_device_mf_win.h b/chromium/media/capture/video/win/video_capture_device_mf_win.h index beefdb9bec8..196ab92d0e2 100644 --- a/chromium/media/capture/video/win/video_capture_device_mf_win.h +++ b/chromium/media/capture/video/win/video_capture_device_mf_win.h @@ -19,14 +19,15 @@ #include <vector> #include "base/callback_forward.h" +#include "base/containers/queue.h" #include "base/macros.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "media/base/win/dxgi_device_manager.h" #include "media/capture/capture_export.h" #include "media/capture/video/video_capture_device.h" #include "media/capture/video/win/capability_list_win.h" #include "media/capture/video/win/metrics.h" +#include "third_party/abseil-cpp/absl/types/optional.h" interface IMFSourceReader; @@ -106,7 +107,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice { dxgi_device_manager_ = std::move(dxgi_device_manager); } - base::Optional<int> camera_rotation() const { return camera_rotation_; } + absl::optional<int> camera_rotation() const { return camera_rotation_; } private: HRESULT ExecuteHresultCallbackWithRetries( @@ -173,7 +174,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice { base::WaitableEvent capture_initialize_; base::WaitableEvent capture_error_; scoped_refptr<DXGIDeviceManager> dxgi_device_manager_; - base::Optional<int> camera_rotation_; + absl::optional<int> camera_rotation_; media::VideoCaptureFeedback last_feedback_; diff --git a/chromium/media/capture/video/win/video_capture_device_win.h b/chromium/media/capture/video/win/video_capture_device_win.h index 00775a5f60e..54bf57ed64a 100644 --- a/chromium/media/capture/video/win/video_capture_device_win.h +++ b/chromium/media/capture/video/win/video_capture_device_win.h @@ -20,13 +20,13 @@ #include "base/containers/queue.h" #include "base/macros.h" -#include "base/optional.h" #include "base/threading/thread_checker.h" #include "media/capture/video/video_capture_device.h" #include "media/capture/video/win/capability_list_win.h" #include "media/capture/video/win/sink_filter_win.h" #include "media/capture/video/win/sink_input_pin_win.h" #include "media/capture/video_capture_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class Location; @@ -156,7 +156,7 @@ class VideoCaptureDeviceWin : public VideoCaptureDevice, bool enable_get_photo_state_; - base::Optional<int> camera_rotation_; + absl::optional<int> camera_rotation_; DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureDeviceWin); }; diff --git a/chromium/media/capture/video_capture_types.h b/chromium/media/capture/video_capture_types.h index 051b9765f16..f3c2dfd0303 100644 --- a/chromium/media/capture/video_capture_types.h +++ b/chromium/media/capture/video_capture_types.h @@ -9,11 +9,11 @@ #include <vector> -#include "base/optional.h" #include "base/unguessable_token.h" #include "build/build_config.h" #include "media/base/video_types.h" #include "media/capture/capture_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { diff --git a/chromium/media/cast/BUILD.gn b/chromium/media/cast/BUILD.gn index 242ea4039d9..9a69682a21c 100644 --- a/chromium/media/cast/BUILD.gn +++ b/chromium/media/cast/BUILD.gn @@ -182,25 +182,25 @@ source_set("sender") { } } -source_set("receiver") { +source_set("test_receiver") { sources = [ - "cast_receiver.h", - "net/rtp/cast_message_builder.cc", - "net/rtp/cast_message_builder.h", - "net/rtp/frame_buffer.cc", - "net/rtp/frame_buffer.h", - "net/rtp/framer.cc", - "net/rtp/framer.h", - "net/rtp/receiver_stats.cc", - "net/rtp/receiver_stats.h", - "receiver/audio_decoder.cc", - "receiver/audio_decoder.h", - "receiver/cast_receiver_impl.cc", - "receiver/cast_receiver_impl.h", - "receiver/frame_receiver.cc", - "receiver/frame_receiver.h", - "receiver/video_decoder.cc", - "receiver/video_decoder.h", + "test/receiver/audio_decoder.cc", + "test/receiver/audio_decoder.h", + "test/receiver/cast_message_builder.cc", + "test/receiver/cast_message_builder.h", + "test/receiver/cast_receiver.h", + "test/receiver/cast_receiver_impl.cc", + "test/receiver/cast_receiver_impl.h", + "test/receiver/frame_buffer.cc", + "test/receiver/frame_buffer.h", + "test/receiver/frame_receiver.cc", + "test/receiver/frame_receiver.h", + "test/receiver/framer.cc", + "test/receiver/framer.h", + "test/receiver/receiver_stats.cc", + "test/receiver/receiver_stats.h", + "test/receiver/video_decoder.cc", + "test/receiver/video_decoder.h", ] deps = [ @@ -252,8 +252,8 @@ static_library("test_support") { deps = [ ":net", - ":receiver", ":sender", + ":test_receiver", "//base/test:test_support", "//media", "//net", @@ -301,22 +301,15 @@ test("cast_unittests") { # files. "net/rtcp/test_rtcp_packet_builder.cc", "net/rtcp/test_rtcp_packet_builder.h", - "net/rtp/cast_message_builder_unittest.cc", - "net/rtp/frame_buffer_unittest.cc", - "net/rtp/framer_unittest.cc", "net/rtp/mock_rtp_payload_feedback.cc", "net/rtp/mock_rtp_payload_feedback.h", "net/rtp/packet_storage_unittest.cc", - "net/rtp/receiver_stats_unittest.cc", "net/rtp/rtp_packet_builder.cc", "net/rtp/rtp_packet_builder.h", "net/rtp/rtp_packetizer_unittest.cc", "net/rtp/rtp_parser_unittest.cc", "net/udp_packet_pipe_unittest.cc", "net/udp_transport_unittest.cc", - "receiver/audio_decoder_unittest.cc", - "receiver/frame_receiver_unittest.cc", - "receiver/video_decoder_unittest.cc", "sender/audio_encoder_unittest.cc", "sender/audio_sender_unittest.cc", "sender/congestion_control_unittest.cc", @@ -327,6 +320,13 @@ test("cast_unittests") { "sender/video_sender_unittest.cc", "sender/vp8_quantizer_parser_unittest.cc", "test/end2end_unittest.cc", + "test/receiver/audio_decoder_unittest.cc", + "test/receiver/cast_message_builder_unittest.cc", + "test/receiver/frame_buffer_unittest.cc", + "test/receiver/frame_receiver_unittest.cc", + "test/receiver/framer_unittest.cc", + "test/receiver/receiver_stats_unittest.cc", + "test/receiver/video_decoder_unittest.cc", "test/utility/audio_utility_unittest.cc", "test/utility/barcode_unittest.cc", ] @@ -334,8 +334,8 @@ test("cast_unittests") { deps = [ ":common", ":net", - ":receiver", ":sender", + ":test_receiver", ":test_support", "//base", "//base:cfi_buildflags", @@ -386,8 +386,8 @@ if (is_win || is_mac || is_linux || is_chromeos_lacros) { deps = [ ":common", ":net", - ":receiver", ":sender", + ":test_receiver", ":test_support", "//base", "//base/test:test_support", @@ -424,8 +424,8 @@ if (is_win || is_mac || is_linux || is_chromeos_lacros) { ":common", ":net", ":network_simulation_model_proto", - ":receiver", ":sender", + ":test_receiver", ":test_support", "//base", "//base/test:test_support", @@ -499,5 +499,5 @@ static_library("cast_sender") { static_library("cast_receiver") { complete_static_lib = true configs -= [ "//build/config/compiler:thin_archive" ] - deps = [ ":receiver" ] + deps = [ ":test_receiver" ] } diff --git a/chromium/media/cast/DIR_METADATA b/chromium/media/cast/DIR_METADATA index 9e255559a4f..7c577c4a958 100644 --- a/chromium/media/cast/DIR_METADATA +++ b/chromium/media/cast/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Cast>Streaming" diff --git a/chromium/media/cast/OWNERS b/chromium/media/cast/OWNERS index 866a0313dc6..736f33990db 100644 --- a/chromium/media/cast/OWNERS +++ b/chromium/media/cast/OWNERS @@ -1,2 +1,3 @@ jophba@chromium.org mfoltz@chromium.org +rwkeane@google.com diff --git a/chromium/media/cast/README.md b/chromium/media/cast/README.md index 5d28612985f..679e0a2efdb 100644 --- a/chromium/media/cast/README.md +++ b/chromium/media/cast/README.md @@ -18,11 +18,11 @@ jophba@chromium.org for details. * net/ - Wire-level packetization and pacing. -* receiver/ - A minimal receiver implementation, used only for end-to-end - testing. - * sender/ - Encoder front-ends and frame-level sender implementation for audio/video. * test/ - A collection of end-to-end tests, experiments, benchmarks, and related utility code. + +* test/receiver/ - A minimal receiver implementation, used only for end-to-end + testing. diff --git a/chromium/media/cast/cast_config.h b/chromium/media/cast/cast_config.h index 67d156c604a..9a9f84c1f1c 100644 --- a/chromium/media/cast/cast_config.h +++ b/chromium/media/cast/cast_config.h @@ -245,7 +245,6 @@ struct FrameReceiverConfig { std::string aes_iv_mask; }; -// TODO(miu): Remove the CreateVEA callbacks. http://crbug.com/454029 typedef base::OnceCallback<void(scoped_refptr<base::SingleThreadTaskRunner>, std::unique_ptr<media::VideoEncodeAccelerator>)> ReceiveVideoEncodeAcceleratorCallback; @@ -253,10 +252,6 @@ typedef base::RepeatingCallback<void(ReceiveVideoEncodeAcceleratorCallback)> CreateVideoEncodeAcceleratorCallback; typedef base::OnceCallback<void(base::UnsafeSharedMemoryRegion)> ReceiveVideoEncodeMemoryCallback; -typedef base::RepeatingCallback<void(size_t size, - ReceiveVideoEncodeMemoryCallback)> - CreateVideoEncodeMemoryCallback; - } // namespace cast } // namespace media diff --git a/chromium/media/cast/cast_environment.h b/chromium/media/cast/cast_environment.h index bff6604efe7..7af484e17c0 100644 --- a/chromium/media/cast/cast_environment.h +++ b/chromium/media/cast/cast_environment.h @@ -5,8 +5,6 @@ #ifndef MEDIA_CAST_CAST_ENVIRONMENT_H_ #define MEDIA_CAST_CAST_ENVIRONMENT_H_ -#include <memory> - #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" diff --git a/chromium/media/cast/cast_receiver.h b/chromium/media/cast/cast_receiver.h deleted file mode 100644 index 659531b132c..00000000000 --- a/chromium/media/cast/cast_receiver.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2013 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. -// -// This is the main interface for the cast receiver. All configuration are done -// at creation. - -#ifndef MEDIA_CAST_CAST_RECEIVER_H_ -#define MEDIA_CAST_CAST_RECEIVER_H_ - -#include <memory> - -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/time/time.h" -#include "media/base/audio_bus.h" -#include "media/cast/cast_config.h" -#include "media/cast/cast_environment.h" -#include "media/cast/net/cast_transport.h" - -namespace media { -class VideoFrame; - -namespace cast { - -// The following callbacks are used to deliver decoded audio/video frame data, -// the frame's corresponding play-out time, and a continuity flag. -// |is_continuous| will be false to indicate the loss of data due to a loss of -// frames (or decoding errors). This allows the client to take steps to smooth -// discontinuities for playback. Note: A NULL pointer can be returned when data -// is not available (e.g., bad/missing packet). -using AudioFrameDecodedCallback = - base::RepeatingCallback<void(std::unique_ptr<AudioBus> audio_bus, - base::TimeTicks playout_time, - bool is_continuous)>; -// TODO(miu): |video_frame| includes a timestamp, so use that instead. -using VideoFrameDecodedCallback = - base::RepeatingCallback<void(scoped_refptr<media::VideoFrame> video_frame, - base::TimeTicks playout_time, - bool is_continuous)>; - -class CastReceiver { - public: - static std::unique_ptr<CastReceiver> Create( - scoped_refptr<CastEnvironment> cast_environment, - const FrameReceiverConfig& audio_config, - const FrameReceiverConfig& video_config, - CastTransport* const transport); - - // All received RTP and RTCP packets for the call should be sent to this - // PacketReceiver. Can be called from any thread. - virtual void ReceivePacket(std::unique_ptr<Packet> packet) = 0; - - // Polling interface to get audio and video frames from the CastReceiver. The - // the RequestDecodedXXXXXFrame() methods utilize internal software-based - // decoding. - // - // In all cases, the given |callback| is guaranteed to be run at some point in - // the future, except for those requests still enqueued at destruction time. - // - // These methods should all be called on the CastEnvironment's MAIN thread. - virtual void RequestDecodedAudioFrame( - const AudioFrameDecodedCallback& callback) = 0; - virtual void RequestDecodedVideoFrame( - const VideoFrameDecodedCallback& callback) = 0; - - virtual ~CastReceiver() {} -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_CAST_RECEIVER_H_ diff --git a/chromium/media/cast/cast_sender.h b/chromium/media/cast/cast_sender.h index 48b2d3d33d6..7784d60f42a 100644 --- a/chromium/media/cast/cast_sender.h +++ b/chromium/media/cast/cast_sender.h @@ -108,13 +108,10 @@ class CastSender { // Initialize the video stack. Must be called in order to send video frames. // |status_change_cb| will be run as operational status changes. - // - // TODO(miu): Remove the VEA-specific callbacks. http://crbug.com/454029 virtual void InitializeVideo( const FrameSenderConfig& video_config, const StatusChangeCallback& status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) = 0; + const CreateVideoEncodeAcceleratorCallback& create_vea_cb) = 0; // Change the target delay. This is only valid if the receiver // supports the "adaptive_target_delay" rtp extension. diff --git a/chromium/media/cast/cast_sender_impl.cc b/chromium/media/cast/cast_sender_impl.cc index 5882ea199c7..37a89f7e064 100644 --- a/chromium/media/cast/cast_sender_impl.cc +++ b/chromium/media/cast/cast_sender_impl.cc @@ -126,8 +126,7 @@ void CastSenderImpl::InitializeAudio( void CastSenderImpl::InitializeVideo( const FrameSenderConfig& video_config, const StatusChangeCallback& status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) { + const CreateVideoEncodeAcceleratorCallback& create_vea_cb) { DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); VLOG(1) << "CastSenderImpl@" << this << "::InitializeVideo()"; @@ -137,7 +136,7 @@ void CastSenderImpl::InitializeVideo( cast_environment_, video_config, base::BindRepeating(&CastSenderImpl::OnVideoStatusChange, weak_factory_.GetWeakPtr(), status_change_cb), - create_vea_cb, create_video_encode_mem_cb, transport_sender_, + create_vea_cb, transport_sender_, base::BindRepeating(&CastSenderImpl::SetTargetPlayoutDelay, weak_factory_.GetWeakPtr()), media::VideoCaptureFeedbackCB()); diff --git a/chromium/media/cast/cast_sender_impl.h b/chromium/media/cast/cast_sender_impl.h index cb8cbe98fa2..df50674851b 100644 --- a/chromium/media/cast/cast_sender_impl.h +++ b/chromium/media/cast/cast_sender_impl.h @@ -31,8 +31,7 @@ class CastSenderImpl final : public CastSender { void InitializeVideo( const FrameSenderConfig& video_config, const StatusChangeCallback& status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb) final; + const CreateVideoEncodeAcceleratorCallback& create_vea_cb) final; void SetTargetPlayoutDelay(base::TimeDelta new_target_playout_delay) final; diff --git a/chromium/media/cast/common/mod_util.h b/chromium/media/cast/common/mod_util.h index fc68c63f26f..2761df66d0b 100644 --- a/chromium/media/cast/common/mod_util.h +++ b/chromium/media/cast/common/mod_util.h @@ -5,7 +5,6 @@ #ifndef MEDIA_CAST_COMMON_MOD_UTIL_H_ #define MEDIA_CAST_COMMON_MOD_UTIL_H_ -#include <map> #include "base/check.h" namespace media { diff --git a/chromium/media/cast/logging/logging_defines.h b/chromium/media/cast/logging/logging_defines.h index 0199c45ae5a..c3a668cfa67 100644 --- a/chromium/media/cast/logging/logging_defines.h +++ b/chromium/media/cast/logging/logging_defines.h @@ -8,10 +8,6 @@ #include <stddef.h> #include <stdint.h> -#include <map> -#include <string> -#include <vector> - #include "base/time/time.h" #include "media/cast/common/frame_id.h" #include "media/cast/common/rtp_time.h" diff --git a/chromium/media/cast/logging/stats_event_subscriber.h b/chromium/media/cast/logging/stats_event_subscriber.h index 8c88c920f84..b2e2b410c54 100644 --- a/chromium/media/cast/logging/stats_event_subscriber.h +++ b/chromium/media/cast/logging/stats_event_subscriber.h @@ -8,7 +8,10 @@ #include <stddef.h> #include <stdint.h> +#include <map> #include <memory> +#include <utility> +#include <vector> #include "base/gtest_prod_util.h" #include "base/macros.h" diff --git a/chromium/media/cast/net/cast_transport_defines.h b/chromium/media/cast/net/cast_transport_defines.h index a9e0a407a25..7c11de2da03 100644 --- a/chromium/media/cast/net/cast_transport_defines.h +++ b/chromium/media/cast/net/cast_transport_defines.h @@ -15,7 +15,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/time/time.h" #include "media/cast/common/frame_id.h" namespace media { diff --git a/chromium/media/cast/net/rtcp/receiver_rtcp_session.h b/chromium/media/cast/net/rtcp/receiver_rtcp_session.h index 5b95a87973f..166f91b6304 100644 --- a/chromium/media/cast/net/rtcp/receiver_rtcp_session.h +++ b/chromium/media/cast/net/rtcp/receiver_rtcp_session.h @@ -9,7 +9,6 @@ #include "media/cast/common/clock_drift_smoother.h" #include "media/cast/net/pacing/paced_sender.h" #include "media/cast/net/rtcp/receiver_rtcp_event_subscriber.h" -#include "media/cast/net/rtcp/receiver_rtcp_session.h" #include "media/cast/net/rtcp/rtcp_defines.h" #include "media/cast/net/rtcp/rtcp_session.h" #include "media/cast/net/rtcp/rtcp_utility.h" diff --git a/chromium/media/cast/net/rtcp/rtcp_builder.h b/chromium/media/cast/net/rtcp/rtcp_builder.h index 7ff7050d0aa..10bd90475ff 100644 --- a/chromium/media/cast/net/rtcp/rtcp_builder.h +++ b/chromium/media/cast/net/rtcp/rtcp_builder.h @@ -8,9 +8,6 @@ #include <stddef.h> #include <stdint.h> -#include <list> -#include <string> - #include "base/big_endian.h" #include "base/macros.h" #include "media/cast/net/cast_transport_config.h" diff --git a/chromium/media/cast/net/rtcp/rtcp_defines.h b/chromium/media/cast/net/rtcp/rtcp_defines.h index 51f39259aae..d309149c05b 100644 --- a/chromium/media/cast/net/rtcp/rtcp_defines.h +++ b/chromium/media/cast/net/rtcp/rtcp_defines.h @@ -13,7 +13,6 @@ #include <utility> #include <vector> -#include "base/callback_forward.h" #include "base/macros.h" #include "media/cast/logging/logging_defines.h" #include "media/cast/net/cast_transport_defines.h" diff --git a/chromium/media/cast/net/rtp/cast_message_builder.cc b/chromium/media/cast/net/rtp/cast_message_builder.cc deleted file mode 100644 index 61a152b53a1..00000000000 --- a/chromium/media/cast/net/rtp/cast_message_builder.cc +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2014 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/cast/net/rtp/cast_message_builder.h" - -#include "base/logging.h" -#include "media/cast/constants.h" -#include "media/cast/net/rtp/framer.h" - -namespace media { -namespace cast { - -namespace { - -// TODO(miu): These should probably be dynamic and computed base on configured -// end-to-end latency and packet loss rates. http://crbug.com/563784 -enum { - // Number of milliseconds between sending of ACK/NACK Cast Message RTCP - // packets back to the sender. - kCastMessageUpdateIntervalMs = 33, - - // Number of milliseconds between repeating a NACK for packets in the same - // frame. - kNackRepeatIntervalMs = 30, -}; - -} // namespace - -CastMessageBuilder::CastMessageBuilder( - const base::TickClock* clock, - RtpPayloadFeedback* incoming_payload_feedback, - const Framer* framer, - uint32_t media_ssrc, - bool decoder_faster_than_max_frame_rate, - int max_unacked_frames) - : clock_(clock), - cast_feedback_(incoming_payload_feedback), - framer_(framer), - media_ssrc_(media_ssrc), - decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate), - max_unacked_frames_(max_unacked_frames), - cast_msg_(media_ssrc), - slowing_down_ack_(false), - acked_last_frame_(true) { - cast_msg_.ack_frame_id = FrameId::first() - 1; -} - -CastMessageBuilder::~CastMessageBuilder() = default; - -void CastMessageBuilder::CompleteFrameReceived(FrameId frame_id) { - DCHECK_GE(frame_id, last_acked_frame_id()); - VLOG(2) << "CompleteFrameReceived: " << frame_id; - if (last_update_time_.is_null()) { - // Our first update. - last_update_time_ = clock_->NowTicks(); - } - - if (!UpdateAckMessage(frame_id)) { - return; - } - BuildPacketList(); - - // Send cast message. - VLOG(2) << "Send cast message Ack:" << frame_id; - cast_feedback_->CastFeedback(cast_msg_); -} - -bool CastMessageBuilder::UpdateAckMessage(FrameId frame_id) { - if (!decoder_faster_than_max_frame_rate_) { - int complete_frame_count = framer_->NumberOfCompleteFrames(); - if (complete_frame_count > max_unacked_frames_) { - // We have too many frames pending in our framer; slow down ACK. - if (!slowing_down_ack_) { - slowing_down_ack_ = true; - ack_queue_.push_back(last_acked_frame_id()); - } - } else if (complete_frame_count <= 1) { - // We are down to one or less frames in our framer; ACK normally. - slowing_down_ack_ = false; - ack_queue_.clear(); - } - } - - if (slowing_down_ack_) { - // We are slowing down acknowledgment by acknowledging every other frame. - // Note: frame skipping and slowdown ACK is not supported at the same - // time; and it's not needed since we can skip frames to catch up. - if (!ack_queue_.empty() && ack_queue_.back() == frame_id) { - return false; - } - ack_queue_.push_back(frame_id); - if (!acked_last_frame_) { - ack_queue_.pop_front(); - } - frame_id = ack_queue_.front(); - } - - // Is it a new frame? - if (last_acked_frame_id() == frame_id) { - acked_last_frame_ = false; - return false; - } - acked_last_frame_ = true; - cast_msg_.ack_frame_id = frame_id; - cast_msg_.missing_frames_and_packets.clear(); - last_update_time_ = clock_->NowTicks(); - time_last_nacked_map_.erase( - time_last_nacked_map_.begin(), - time_last_nacked_map_.upper_bound(last_acked_frame_id())); - return true; -} - -bool CastMessageBuilder::TimeToSendNextCastMessage( - base::TimeTicks* time_to_send) { - // We haven't received any packets. - if (last_update_time_.is_null() && framer_->Empty()) - return false; - - *time_to_send = last_update_time_ + base::TimeDelta::FromMilliseconds( - kCastMessageUpdateIntervalMs); - return true; -} - -void CastMessageBuilder::UpdateCastMessage() { - RtcpCastMessage message(media_ssrc_); - if (!UpdateCastMessageInternal(&message)) - return; - - // Send cast message. - cast_feedback_->CastFeedback(message); -} - -bool CastMessageBuilder::UpdateCastMessageInternal(RtcpCastMessage* message) { - if (last_update_time_.is_null()) { - if (!framer_->Empty()) { - // We have received packets. - last_update_time_ = clock_->NowTicks(); - } - return false; - } - - // Is it time to update the cast message? - base::TimeTicks now = clock_->NowTicks(); - if (now - last_update_time_ < - base::TimeDelta::FromMilliseconds(kCastMessageUpdateIntervalMs)) { - return false; - } - last_update_time_ = now; - - // Needed to cover when a frame is skipped. - UpdateAckMessage(last_acked_frame_id()); - BuildPacketList(); - *message = cast_msg_; - return true; -} - -void CastMessageBuilder::BuildPacketList() { - base::TimeTicks now = clock_->NowTicks(); - - // Clear message NACK list. - cast_msg_.missing_frames_and_packets.clear(); - - // Are we missing packets? - if (framer_->Empty()) - return; - - const FrameId newest_frame_id = framer_->newest_frame_id(); - FrameId next_expected_frame_id = last_acked_frame_id() + 1; - - // Iterate over all frames. - for (; next_expected_frame_id <= newest_frame_id; ++next_expected_frame_id) { - const auto it = time_last_nacked_map_.find(next_expected_frame_id); - if (it != time_last_nacked_map_.end()) { - // We have sent a NACK in this frame before, make sure enough time have - // passed. - if (now - it->second < - base::TimeDelta::FromMilliseconds(kNackRepeatIntervalMs)) { - continue; - } - } - - PacketIdSet missing; - if (framer_->FrameExists(next_expected_frame_id)) { - bool last_frame = (newest_frame_id == next_expected_frame_id); - framer_->GetMissingPackets( - next_expected_frame_id, last_frame, &missing); - if (!missing.empty()) { - time_last_nacked_map_[next_expected_frame_id] = now; - cast_msg_.missing_frames_and_packets.insert( - std::make_pair(next_expected_frame_id, missing)); - } - } else { - time_last_nacked_map_[next_expected_frame_id] = now; - missing.insert(kRtcpCastAllPacketsLost); - cast_msg_.missing_frames_and_packets[next_expected_frame_id] = missing; - } - } -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/net/rtp/cast_message_builder.h b/chromium/media/cast/net/rtp/cast_message_builder.h deleted file mode 100644 index 9afd8c19752..00000000000 --- a/chromium/media/cast/net/rtp/cast_message_builder.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2014 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. - -// Handles NACK list and manages ACK. - -#ifndef MEDIA_CAST_NET_RTP_CAST_MESSAGE_BUILDER_H_ -#define MEDIA_CAST_NET_RTP_CAST_MESSAGE_BUILDER_H_ - -#include <stdint.h> - -#include <map> - -#include "base/containers/circular_deque.h" -#include "base/time/tick_clock.h" -#include "media/cast/net/rtp/rtp_defines.h" - -namespace media { -namespace cast { - -class Framer; -class RtpPayloadFeedback; - -class CastMessageBuilder { - public: - CastMessageBuilder(const base::TickClock* clock, - RtpPayloadFeedback* incoming_payload_feedback, - const Framer* framer, - uint32_t media_ssrc, - bool decoder_faster_than_max_frame_rate, - int max_unacked_frames); - ~CastMessageBuilder(); - - void CompleteFrameReceived(FrameId frame_id); - bool TimeToSendNextCastMessage(base::TimeTicks* time_to_send); - void UpdateCastMessage(); - - private: - bool UpdateAckMessage(FrameId frame_id); - void BuildPacketList(); - bool UpdateCastMessageInternal(RtcpCastMessage* message); - - FrameId last_acked_frame_id() const { return cast_msg_.ack_frame_id; } - - const base::TickClock* const clock_; // Not owned by this class. - RtpPayloadFeedback* const cast_feedback_; - - // CastMessageBuilder has only const access to the framer. - const Framer* const framer_; - const uint32_t media_ssrc_; - const bool decoder_faster_than_max_frame_rate_; - const int max_unacked_frames_; - - RtcpCastMessage cast_msg_; - base::TimeTicks last_update_time_; - - std::map<FrameId, base::TimeTicks> time_last_nacked_map_; - - bool slowing_down_ack_; - bool acked_last_frame_; - base::circular_deque<FrameId> ack_queue_; - - DISALLOW_COPY_AND_ASSIGN(CastMessageBuilder); -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_NET_RTP_CAST_MESSAGE_BUILDER_H_ diff --git a/chromium/media/cast/net/rtp/cast_message_builder_unittest.cc b/chromium/media/cast/net/rtp/cast_message_builder_unittest.cc deleted file mode 100644 index 370a5751cf4..00000000000 --- a/chromium/media/cast/net/rtp/cast_message_builder_unittest.cc +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright 2014 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/cast/net/rtp/cast_message_builder.h" - -#include <stddef.h> -#include <stdint.h> - -#include <memory> - -#include "base/macros.h" -#include "base/test/simple_test_tick_clock.h" -#include "media/cast/net/rtcp/rtcp_defines.h" -#include "media/cast/net/rtp/framer.h" -#include "media/cast/net/rtp/rtp_defines.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { -namespace cast { - -namespace { -static const uint32_t kSsrc = 0x1234; -static const uint32_t kShortTimeIncrementMs = 10; -static const uint32_t kLongTimeIncrementMs = 40; -static const int64_t kStartMillisecond = INT64_C(12345678900000); - -typedef std::map<FrameId, size_t> MissingPacketsMap; - -class NackFeedbackVerification : public RtpPayloadFeedback { - public: - NackFeedbackVerification() : triggered_(false) {} - - void CastFeedback(const RtcpCastMessage& cast_feedback) final { - EXPECT_EQ(kSsrc, cast_feedback.remote_ssrc); - - last_frame_acked_ = cast_feedback.ack_frame_id; - - auto frame_it = cast_feedback.missing_frames_and_packets.begin(); - - // Keep track of the number of missing packets per frame. - missing_packets_.clear(); - while (frame_it != cast_feedback.missing_frames_and_packets.end()) { - // Check for complete frame lost. - if ((frame_it->second.size() == 1) && - (*frame_it->second.begin() == kRtcpCastAllPacketsLost)) { - missing_packets_.insert( - std::make_pair(frame_it->first, kRtcpCastAllPacketsLost)); - } else { - missing_packets_.insert( - std::make_pair(frame_it->first, frame_it->second.size())); - } - ++frame_it; - } - triggered_ = true; - } - - size_t num_missing_packets(FrameId frame_id) { - MissingPacketsMap::iterator it; - it = missing_packets_.find(frame_id); - if (it == missing_packets_.end()) - return 0; - - return it->second; - } - - // Holds value for one call. - bool triggered() { - bool ret_val = triggered_; - triggered_ = false; - return ret_val; - } - - FrameId last_frame_acked() { return last_frame_acked_; } - - private: - bool triggered_; - MissingPacketsMap missing_packets_; // Missing packets per frame. - FrameId last_frame_acked_; - - DISALLOW_COPY_AND_ASSIGN(NackFeedbackVerification); -}; -} // namespace - -class CastMessageBuilderTest : public ::testing::Test { - protected: - CastMessageBuilderTest() - : framer_(&testing_clock_, - &feedback_, - kSsrc, - true, - 10), - cast_msg_builder_(new CastMessageBuilder(&testing_clock_, - &feedback_, - &framer_, - kSsrc, - true, - 0)) { - rtp_header_.sender_ssrc = kSsrc; - rtp_header_.is_key_frame = false; - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kStartMillisecond)); - } - - ~CastMessageBuilderTest() override = default; - - void SetFrameIds(FrameId frame_id, FrameId reference_frame_id) { - rtp_header_.frame_id = frame_id; - rtp_header_.reference_frame_id = reference_frame_id; - } - - void SetPacketId(uint16_t packet_id) { rtp_header_.packet_id = packet_id; } - - void SetMaxPacketId(uint16_t max_packet_id) { - rtp_header_.max_packet_id = max_packet_id; - } - - void SetKeyFrame(bool is_key) { rtp_header_.is_key_frame = is_key; } - - void InsertPacket() { - bool duplicate; - uint8_t payload = 0; - if (framer_.InsertPacket(&payload, 1, rtp_header_, &duplicate)) { - cast_msg_builder_->CompleteFrameReceived(rtp_header_.frame_id); - } - cast_msg_builder_->UpdateCastMessage(); - } - - void SetDecoderSlowerThanMaxFrameRate(int max_unacked_frames) { - cast_msg_builder_ = std::make_unique<CastMessageBuilder>( - &testing_clock_, &feedback_, &framer_, kSsrc, false, - max_unacked_frames); - } - - NackFeedbackVerification feedback_; - Framer framer_; - std::unique_ptr<CastMessageBuilder> cast_msg_builder_; - RtpCastHeader rtp_header_; - base::SimpleTestTickClock testing_clock_; - - private: - DISALLOW_COPY_AND_ASSIGN(CastMessageBuilderTest); -}; - -TEST_F(CastMessageBuilderTest, OneFrameNackList) { - SetFrameIds(FrameId::first(), FrameId::first()); - SetPacketId(4); - SetMaxPacketId(10); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - EXPECT_FALSE(feedback_.triggered()); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - SetPacketId(5); - InsertPacket(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(4u, feedback_.num_missing_packets(FrameId::first())); -} - -TEST_F(CastMessageBuilderTest, CompleteFrameMissing) { - SetFrameIds(FrameId::first(), FrameId::first()); - SetPacketId(2); - SetMaxPacketId(5); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - SetFrameIds(FrameId::first() + 2, FrameId::first() + 1); - SetPacketId(2); - SetMaxPacketId(5); - InsertPacket(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(kRtcpCastAllPacketsLost, - feedback_.num_missing_packets(FrameId::first() + 1)); -} - -TEST_F(CastMessageBuilderTest, ReleaseFrames) { - SetFrameIds(FrameId::first() + 1, FrameId::first()); - SetPacketId(0); - SetMaxPacketId(1); - InsertPacket(); - EXPECT_FALSE(feedback_.triggered()); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - SetFrameIds(FrameId::first() + 2, FrameId::first() + 1); - SetPacketId(0); - SetMaxPacketId(0); - InsertPacket(); - EXPECT_TRUE(feedback_.triggered()); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - SetFrameIds(FrameId::first() + 3, FrameId::first() + 2); - SetPacketId(0); - SetMaxPacketId(5); - InsertPacket(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(FrameId::first() + 2, feedback_.last_frame_acked()); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - SetFrameIds(FrameId::first() + 5, FrameId::first() + 5); - SetPacketId(0); - SetMaxPacketId(0); - SetKeyFrame(true); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - // Simulate 5 being pulled for rendering. - framer_.ReleaseFrame(FrameId::first() + 5); - cast_msg_builder_->UpdateCastMessage(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(FrameId::first() + 5, feedback_.last_frame_acked()); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - SetFrameIds(FrameId::first() + 1, FrameId::first()); - SetPacketId(1); - SetMaxPacketId(1); - InsertPacket(); - EXPECT_FALSE(feedback_.triggered()); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - InsertPacket(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(FrameId::first() + 5, feedback_.last_frame_acked()); -} - -TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacket) { - SetFrameIds(FrameId::first(), FrameId::first()); - SetPacketId(0); - SetMaxPacketId(20); - SetKeyFrame(true); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - SetPacketId(5); - InsertPacket(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(4u, feedback_.num_missing_packets(FrameId::first())); -} - -TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacketNextFrame) { - SetFrameIds(FrameId::first(), FrameId::first()); - SetPacketId(0); - SetMaxPacketId(20); - SetKeyFrame(true); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - SetPacketId(5); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(4u, feedback_.num_missing_packets(FrameId::first())); - SetFrameIds(FrameId::first() + 1, FrameId::first()); - SetMaxPacketId(2); - SetPacketId(0); - SetKeyFrame(false); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(19u, feedback_.num_missing_packets(FrameId::first())); -} - -TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacketNextKey) { - SetFrameIds(FrameId::first(), FrameId::first()); - SetPacketId(0); - SetMaxPacketId(20); - SetKeyFrame(true); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - SetPacketId(5); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(4u, feedback_.num_missing_packets(FrameId::first())); - SetFrameIds(FrameId::first() + 1, FrameId::first() + 1); - SetMaxPacketId(0); - SetPacketId(0); - SetKeyFrame(true); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(0u, feedback_.num_missing_packets(FrameId::first())); -} - -TEST_F(CastMessageBuilderTest, BasicRps) { - SetFrameIds(FrameId::first(), FrameId::first()); - SetPacketId(0); - SetMaxPacketId(0); - SetKeyFrame(true); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(FrameId::first(), feedback_.last_frame_acked()); - SetFrameIds(FrameId::first() + 3, FrameId::first()); - SetKeyFrame(false); - InsertPacket(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(FrameId::first() + 3, feedback_.last_frame_acked()); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); - // Simulate 3 being pulled for rendering. - framer_.ReleaseFrame(FrameId::first() + 3); - cast_msg_builder_->UpdateCastMessage(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(FrameId::first() + 3, feedback_.last_frame_acked()); -} - -TEST_F(CastMessageBuilderTest, InOrderRps) { - // Create a pattern - skip to rps, and don't look back. - SetFrameIds(FrameId::first(), FrameId::first()); - SetPacketId(0); - SetMaxPacketId(0); - SetKeyFrame(true); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(FrameId::first(), feedback_.last_frame_acked()); - SetFrameIds(FrameId::first() + 1, FrameId::first()); - SetPacketId(0); - SetMaxPacketId(1); - SetKeyFrame(false); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - EXPECT_FALSE(feedback_.triggered()); - SetFrameIds(FrameId::first() + 3, FrameId::first()); - SetPacketId(0); - SetMaxPacketId(0); - SetKeyFrame(false); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - // Simulate 3 being pulled for rendering. - framer_.ReleaseFrame(FrameId::first() + 3); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - cast_msg_builder_->UpdateCastMessage(); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(FrameId::first() + 3, feedback_.last_frame_acked()); - // Make an old frame complete - should not trigger an ack. - SetFrameIds(FrameId::first() + 1, FrameId::first()); - SetPacketId(1); - SetMaxPacketId(1); - SetKeyFrame(false); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - EXPECT_FALSE(feedback_.triggered()); - EXPECT_EQ(FrameId::first() + 3, feedback_.last_frame_acked()); -} - -TEST_F(CastMessageBuilderTest, SlowDownAck) { - SetDecoderSlowerThanMaxFrameRate(3); - SetFrameIds(FrameId::first(), FrameId::first()); - SetPacketId(0); - SetMaxPacketId(0); - SetKeyFrame(true); - InsertPacket(); - - FrameId frame_id; - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - SetKeyFrame(false); - for (frame_id = FrameId::first() + 1; frame_id < FrameId::first() + 3; - ++frame_id) { - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(frame_id - 1, feedback_.last_frame_acked()); - SetFrameIds(frame_id, frame_id - 1); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - } - // We should now have entered the slowdown ACK state. - FrameId expected_frame_id = FrameId::first() + 1; - for (; frame_id < FrameId::first() + 10; ++frame_id) { - if ((frame_id - FrameId::first()) % 2) { - ++expected_frame_id; - EXPECT_TRUE(feedback_.triggered()); - } else { - EXPECT_FALSE(feedback_.triggered()); - } - EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked()); - SetFrameIds(frame_id, frame_id - 1); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - } - EXPECT_FALSE(feedback_.triggered()); - EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked()); - - // Simulate frame_id being pulled for rendering. - framer_.ReleaseFrame(frame_id); - // We should now leave the slowdown ACK state. - ++frame_id; - SetFrameIds(frame_id, frame_id - 1); - InsertPacket(); - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); - EXPECT_TRUE(feedback_.triggered()); - EXPECT_EQ(frame_id, feedback_.last_frame_acked()); -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/net/rtp/frame_buffer.cc b/chromium/media/cast/net/rtp/frame_buffer.cc deleted file mode 100644 index 255b5067157..00000000000 --- a/chromium/media/cast/net/rtp/frame_buffer.cc +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2014 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/cast/net/rtp/frame_buffer.h" - -#include "base/check_op.h" - -namespace media { -namespace cast { - -FrameBuffer::FrameBuffer() - : max_packet_id_(0), - num_packets_received_(0), - max_seen_packet_id_(0), - new_playout_delay_ms_(0), - is_key_frame_(false), - total_data_size_(0), - packets_() {} - -FrameBuffer::~FrameBuffer() = default; - -bool FrameBuffer::InsertPacket(const uint8_t* payload_data, - size_t payload_size, - const RtpCastHeader& rtp_header) { - // Is this the first packet in the frame? - if (packets_.empty()) { - frame_id_ = rtp_header.frame_id; - max_packet_id_ = rtp_header.max_packet_id; - is_key_frame_ = rtp_header.is_key_frame; - new_playout_delay_ms_ = rtp_header.new_playout_delay_ms; - if (is_key_frame_) - DCHECK_EQ(rtp_header.frame_id, rtp_header.reference_frame_id); - last_referenced_frame_id_ = rtp_header.reference_frame_id; - rtp_timestamp_ = rtp_header.rtp_timestamp; - } - // Is this the correct frame? - if (rtp_header.frame_id != frame_id_) - return false; - - // Insert every packet only once. - if (packets_.find(rtp_header.packet_id) != packets_.end()) { - return false; - } - - std::vector<uint8_t> data; - std::pair<PacketMap::iterator, bool> retval = - packets_.insert(make_pair(rtp_header.packet_id, data)); - - // Insert the packet. - retval.first->second.resize(payload_size); - std::copy( - payload_data, payload_data + payload_size, retval.first->second.begin()); - - ++num_packets_received_; - max_seen_packet_id_ = std::max(max_seen_packet_id_, rtp_header.packet_id); - total_data_size_ += payload_size; - return true; -} - -bool FrameBuffer::Complete() const { - return num_packets_received_ - 1 == max_packet_id_; -} - -bool FrameBuffer::AssembleEncodedFrame(EncodedFrame* frame) const { - if (!Complete()) - return false; - - // Frame is complete -> construct. - if (is_key_frame_) - frame->dependency = EncodedFrame::KEY; - else if (frame_id_ == last_referenced_frame_id_) - frame->dependency = EncodedFrame::INDEPENDENT; - else - frame->dependency = EncodedFrame::DEPENDENT; - frame->frame_id = frame_id_; - frame->referenced_frame_id = last_referenced_frame_id_; - frame->rtp_timestamp = rtp_timestamp_; - frame->new_playout_delay_ms = new_playout_delay_ms_; - - // Build the data vector. - frame->data.clear(); - frame->data.reserve(total_data_size_); - PacketMap::const_iterator it; - for (it = packets_.begin(); it != packets_.end(); ++it) - frame->data.insert(frame->data.end(), it->second.begin(), it->second.end()); - return true; -} - -void FrameBuffer::GetMissingPackets(bool newest_frame, - PacketIdSet* missing_packets) const { - // Missing packets capped by max_seen_packet_id_. - // (Iff it's the latest frame) - int maximum = newest_frame ? max_seen_packet_id_ : max_packet_id_; - int packet = 0; - for (auto i = packets_.begin(); i != packets_.end() && packet <= maximum; - ++i) { - int end = std::min<int>(i->first, maximum + 1); - while (packet < end) { - missing_packets->insert(packet); - packet++; - } - packet++; - } - while (packet <= maximum) { - missing_packets->insert(packet); - packet++; - } -} - - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/net/rtp/frame_buffer.h b/chromium/media/cast/net/rtp/frame_buffer.h deleted file mode 100644 index 7f9b9859679..00000000000 --- a/chromium/media/cast/net/rtp/frame_buffer.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2014 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. - -#ifndef MEDIA_CAST_NET_RTP_FRAME_BUFFER_H_ -#define MEDIA_CAST_NET_RTP_FRAME_BUFFER_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <map> -#include <vector> - -#include "base/macros.h" -#include "media/cast/common/rtp_time.h" -#include "media/cast/net/cast_transport_config.h" -#include "media/cast/net/rtp/rtp_defines.h" - -namespace media { -namespace cast { - -typedef std::map<uint16_t, std::vector<uint8_t>> PacketMap; - -class FrameBuffer { - public: - FrameBuffer(); - ~FrameBuffer(); - bool InsertPacket(const uint8_t* payload_data, - size_t payload_size, - const RtpCastHeader& rtp_header); - bool Complete() const; - - void GetMissingPackets(bool newest_frame, PacketIdSet* missing_packets) const; - - // If a frame is complete, sets the frame IDs and RTP timestamp in |frame|, - // and also copies the data from all packets into the data field in |frame|. - // Returns true if the frame was complete; false if incomplete and |frame| - // remains unchanged. - bool AssembleEncodedFrame(EncodedFrame* frame) const; - - bool is_key_frame() const { return is_key_frame_; } - FrameId last_referenced_frame_id() const { return last_referenced_frame_id_; } - FrameId frame_id() const { return frame_id_; } - - private: - FrameId frame_id_; - uint16_t max_packet_id_; - uint16_t num_packets_received_; - uint16_t max_seen_packet_id_; - uint16_t new_playout_delay_ms_; - bool is_key_frame_; - size_t total_data_size_; - FrameId last_referenced_frame_id_; - RtpTimeTicks rtp_timestamp_; - PacketMap packets_; - - DISALLOW_COPY_AND_ASSIGN(FrameBuffer); -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_NET_RTP_FRAME_BUFFER_H_ diff --git a/chromium/media/cast/net/rtp/frame_buffer_unittest.cc b/chromium/media/cast/net/rtp/frame_buffer_unittest.cc deleted file mode 100644 index 60f35378988..00000000000 --- a/chromium/media/cast/net/rtp/frame_buffer_unittest.cc +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2014 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 <stdint.h> - -#include "base/macros.h" -#include "media/cast/net/cast_transport_defines.h" -#include "media/cast/net/rtp/frame_buffer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { -namespace cast { - -class FrameBufferTest : public ::testing::Test { - protected: - FrameBufferTest() { - payload_.assign(kMaxIpPacketSize, 0); - rtp_header_.frame_id = FrameId::first(); - rtp_header_.reference_frame_id = FrameId::first(); - } - - ~FrameBufferTest() override = default; - - FrameBuffer buffer_; - std::vector<uint8_t> payload_; - RtpCastHeader rtp_header_; - - DISALLOW_COPY_AND_ASSIGN(FrameBufferTest); -}; - -TEST_F(FrameBufferTest, OnePacketInsertSanity) { - rtp_header_.rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(3000)); - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = FrameId::first() + 5; - rtp_header_.reference_frame_id = FrameId::first() + 5; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - EncodedFrame frame; - EXPECT_TRUE(buffer_.AssembleEncodedFrame(&frame)); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first() + 5, frame.frame_id); - EXPECT_EQ(FrameId::first() + 5, frame.referenced_frame_id); - EXPECT_EQ(3000u, frame.rtp_timestamp.lower_32_bits()); -} - -TEST_F(FrameBufferTest, EmptyBuffer) { - EXPECT_FALSE(buffer_.Complete()); - EncodedFrame frame; - EXPECT_FALSE(buffer_.AssembleEncodedFrame(&frame)); -} - -TEST_F(FrameBufferTest, DefaultOnePacketFrame) { - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - EXPECT_TRUE(buffer_.Complete()); - EXPECT_FALSE(buffer_.is_key_frame()); - EncodedFrame frame; - EXPECT_TRUE(buffer_.AssembleEncodedFrame(&frame)); - EXPECT_EQ(payload_.size(), frame.data.size()); -} - -TEST_F(FrameBufferTest, MultiplePacketFrame) { - rtp_header_.is_key_frame = true; - rtp_header_.max_packet_id = 2; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - ++rtp_header_.packet_id; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - ++rtp_header_.packet_id; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - ++rtp_header_.packet_id; - EXPECT_TRUE(buffer_.Complete()); - EXPECT_TRUE(buffer_.is_key_frame()); - EncodedFrame frame; - EXPECT_TRUE(buffer_.AssembleEncodedFrame(&frame)); - EXPECT_EQ(3 * payload_.size(), frame.data.size()); -} - -TEST_F(FrameBufferTest, IncompleteFrame) { - rtp_header_.max_packet_id = 4; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - ++rtp_header_.packet_id; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - ++rtp_header_.packet_id; - // Increment again - skip packet #2. - ++rtp_header_.packet_id; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - ++rtp_header_.packet_id; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - EXPECT_FALSE(buffer_.Complete()); - // Insert missing packet. - rtp_header_.packet_id = 2; - buffer_.InsertPacket(&payload_[0], payload_.size(), rtp_header_); - EXPECT_TRUE(buffer_.Complete()); -} - -} // namespace media -} // namespace cast diff --git a/chromium/media/cast/net/rtp/framer.cc b/chromium/media/cast/net/rtp/framer.cc deleted file mode 100644 index 369c9db7a35..00000000000 --- a/chromium/media/cast/net/rtp/framer.cc +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2014 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/cast/net/rtp/framer.h" - -#include "base/logging.h" -#include "media/cast/constants.h" - -namespace media { -namespace cast { - -Framer::Framer(const base::TickClock* clock, - RtpPayloadFeedback* incoming_payload_feedback, - uint32_t ssrc, - bool decoder_faster_than_max_frame_rate, - int max_unacked_frames) - : decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate), - cast_msg_builder_(clock, - incoming_payload_feedback, - this, - ssrc, - decoder_faster_than_max_frame_rate, - max_unacked_frames), - waiting_for_key_(true), - last_released_frame_(FrameId::first() - 1), - newest_frame_id_(FrameId::first() - 1) { - DCHECK(incoming_payload_feedback) << "Invalid argument"; -} - -Framer::~Framer() = default; - -bool Framer::InsertPacket(const uint8_t* payload_data, - size_t payload_size, - const RtpCastHeader& rtp_header, - bool* duplicate) { - *duplicate = false; - - if (rtp_header.is_key_frame && waiting_for_key_) { - last_released_frame_ = rtp_header.frame_id - 1; - waiting_for_key_ = false; - } - - VLOG(1) << "InsertPacket frame:" << rtp_header.frame_id - << " packet:" << static_cast<int>(rtp_header.packet_id) - << " max packet:" << static_cast<int>(rtp_header.max_packet_id); - - if ((rtp_header.frame_id <= last_released_frame_) && !waiting_for_key_) { - // Packet is too old. - return false; - } - - // Update the last received frame id. - if (rtp_header.frame_id > newest_frame_id_) { - newest_frame_id_ = rtp_header.frame_id; - } - - // Insert packet. - const auto it = frames_.find(rtp_header.frame_id); - FrameBuffer* buffer; - if (it == frames_.end()) { - buffer = new FrameBuffer(); - frames_.insert(std::make_pair(rtp_header.frame_id, - std::unique_ptr<FrameBuffer>(buffer))); - } else { - buffer = it->second.get(); - } - if (!buffer->InsertPacket(payload_data, payload_size, rtp_header)) { - VLOG(3) << "Packet already received, ignored: frame " << rtp_header.frame_id - << ", packet " << rtp_header.packet_id; - *duplicate = true; - return false; - } - - return buffer->Complete(); -} - -// This does not release the frame. -bool Framer::GetEncodedFrame(EncodedFrame* frame, - bool* next_frame, - bool* have_multiple_decodable_frames) { - *have_multiple_decodable_frames = HaveMultipleDecodableFrames(); - - // Find frame id. - FrameBuffer* buffer = FindNextFrameForRelease(); - if (buffer) { - // We have our next frame. - *next_frame = true; - } else { - // Check if we can skip frames when our decoder is too slow. - if (!decoder_faster_than_max_frame_rate_) - return false; - - buffer = FindOldestDecodableFrame(); - if (!buffer) - return false; - *next_frame = false; - } - - return buffer->AssembleEncodedFrame(frame); -} - -void Framer::AckFrame(FrameId frame_id) { - VLOG(2) << "ACK frame " << frame_id; - cast_msg_builder_.CompleteFrameReceived(frame_id); -} - -void Framer::ReleaseFrame(FrameId frame_id) { - const auto it = frames_.begin(); - const bool skipped_old_frame = it->first < frame_id; - frames_.erase(it, frames_.upper_bound(frame_id)); - last_released_frame_ = frame_id; - if (skipped_old_frame) - cast_msg_builder_.UpdateCastMessage(); -} - -bool Framer::TimeToSendNextCastMessage(base::TimeTicks* time_to_send) { - return cast_msg_builder_.TimeToSendNextCastMessage(time_to_send); -} - -void Framer::SendCastMessage() { - cast_msg_builder_.UpdateCastMessage(); -} - -FrameBuffer* Framer::FindNextFrameForRelease() { - for (const auto& entry : frames_) { - if (entry.second->Complete() && IsNextFrameForRelease(*entry.second)) - return entry.second.get(); - } - return nullptr; -} - -FrameBuffer* Framer::FindOldestDecodableFrame() { - for (const auto& entry : frames_) { - if (entry.second->Complete() && IsDecodableFrame(*entry.second)) - return entry.second.get(); - } - return nullptr; -} - -bool Framer::HaveMultipleDecodableFrames() const { - bool found_one = false; - for (const auto& entry : frames_) { - if (entry.second->Complete() && IsDecodableFrame(*entry.second)) { - if (found_one) - return true; // Found another. - else - found_one = true; // Found first one. Continue search for another. - } - } - return false; -} - -bool Framer::Empty() const { return frames_.empty(); } - -int Framer::NumberOfCompleteFrames() const { - int count = 0; - for (const auto& entry : frames_) { - if (entry.second->Complete()) - ++count; - } - return count; -} - -bool Framer::FrameExists(FrameId frame_id) const { - return frames_.end() != frames_.find(frame_id); -} - -void Framer::GetMissingPackets(FrameId frame_id, - bool last_frame, - PacketIdSet* missing_packets) const { - const auto it = frames_.find(frame_id); - if (it == frames_.end()) - return; - - it->second->GetMissingPackets(last_frame, missing_packets); -} - -bool Framer::IsNextFrameForRelease(const FrameBuffer& buffer) const { - if (waiting_for_key_ && !buffer.is_key_frame()) - return false; - return (last_released_frame_ + 1) == buffer.frame_id(); -} - -bool Framer::IsDecodableFrame(const FrameBuffer& buffer) const { - if (buffer.is_key_frame()) - return true; - if (waiting_for_key_) - return false; - // Self-reference? - if (buffer.last_referenced_frame_id() == buffer.frame_id()) - return true; - - // Current frame is not necessarily referencing the last frame. - // Has the reference frame been released already? - return buffer.last_referenced_frame_id() <= last_released_frame_; -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/net/rtp/framer.h b/chromium/media/cast/net/rtp/framer.h deleted file mode 100644 index 1d0160a500b..00000000000 --- a/chromium/media/cast/net/rtp/framer.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2014 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. - -#ifndef MEDIA_CAST_NET_RTP_FRAMER_H_ -#define MEDIA_CAST_NET_RTP_FRAMER_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <map> -#include <memory> - -#include "base/macros.h" -#include "base/time/tick_clock.h" -#include "base/time/time.h" -#include "media/cast/net/rtp/cast_message_builder.h" -#include "media/cast/net/rtp/frame_buffer.h" -#include "media/cast/net/rtp/rtp_defines.h" - -namespace media { -namespace cast { - -class Framer { - public: - Framer(const base::TickClock* clock, - RtpPayloadFeedback* incoming_payload_feedback, - uint32_t ssrc, - bool decoder_faster_than_max_frame_rate, - int max_unacked_frames); - ~Framer(); - - // Return true when receiving the last packet in a frame, creating a - // complete frame. If a duplicate packet for an already complete frame is - // received, the function returns false but sets |duplicate| to true. - bool InsertPacket(const uint8_t* payload_data, - size_t payload_size, - const RtpCastHeader& rtp_header, - bool* duplicate); - - // Extracts a complete encoded frame - will only return a complete and - // decodable frame. Returns false if no such frames exist. - // |next_frame| will be set to true if the returned frame is the very - // next frame. |have_multiple_complete_frames| will be set to true - // if there are more decodadble frames available. - bool GetEncodedFrame(EncodedFrame* video_frame, - bool* next_frame, - bool* have_multiple_complete_frames); - - // TODO(hubbe): Move this elsewhere. - void AckFrame(FrameId frame_id); - - void ReleaseFrame(FrameId frame_id); - - bool TimeToSendNextCastMessage(base::TimeTicks* time_to_send); - void SendCastMessage(); - - // TODO(miu): These methods are called from CastMessageBuilder. We need to - // resolve these circular dependencies with some refactoring. - // http://crbug.com/530845 - FrameId newest_frame_id() const { return newest_frame_id_; } - bool Empty() const; - bool FrameExists(FrameId frame_id) const; - int NumberOfCompleteFrames() const; - void GetMissingPackets(FrameId frame_id, - bool last_frame, - PacketIdSet* missing_packets) const; - - private: - // Identifies the next frame to be released (rendered) and returns its - // associated buffer, or returns nullptr there is none. - FrameBuffer* FindNextFrameForRelease(); - - // Returns the buffer associated with the oldest decodable frame (i.e., where - // all dependencies are met), or nullptr if there is none. - FrameBuffer* FindOldestDecodableFrame(); - bool HaveMultipleDecodableFrames() const; - - // Helper for FindNextFrameForRelease(). - bool IsNextFrameForRelease(const FrameBuffer& frame) const; - - // Helper for FindOldestDecodableFrame() and HaveMultipleDecodableFrames(). - bool IsDecodableFrame(const FrameBuffer& frame) const; - - const bool decoder_faster_than_max_frame_rate_; - std::map<FrameId, std::unique_ptr<FrameBuffer>> frames_; - CastMessageBuilder cast_msg_builder_; - bool waiting_for_key_; - FrameId last_released_frame_; - FrameId newest_frame_id_; - - DISALLOW_COPY_AND_ASSIGN(Framer); -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_NET_RTP_FRAMER_H_ diff --git a/chromium/media/cast/net/rtp/framer_unittest.cc b/chromium/media/cast/net/rtp/framer_unittest.cc deleted file mode 100644 index cc6a05d7a84..00000000000 --- a/chromium/media/cast/net/rtp/framer_unittest.cc +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 2014 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 <stdint.h> - -#include "base/macros.h" -#include "base/test/simple_test_tick_clock.h" -#include "media/cast/net/cast_transport_defines.h" -#include "media/cast/net/rtp/framer.h" -#include "media/cast/net/rtp/mock_rtp_payload_feedback.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { -namespace cast { - -class FramerTest : public ::testing::Test { - protected: - FramerTest() - : mock_rtp_payload_feedback_(), - framer_(&testing_clock_, &mock_rtp_payload_feedback_, 0, true, 0) { - payload_.assign(kMaxIpPacketSize, 0); - - EXPECT_CALL(mock_rtp_payload_feedback_, CastFeedback(testing::_)) - .WillRepeatedly(testing::Return()); - } - - ~FramerTest() override = default; - - std::vector<uint8_t> payload_; - RtpCastHeader rtp_header_; - MockRtpPayloadFeedback mock_rtp_payload_feedback_; - Framer framer_; - base::SimpleTestTickClock testing_clock_; - - DISALLOW_COPY_AND_ASSIGN(FramerTest); -}; - -TEST_F(FramerTest, EmptyState) { - EncodedFrame frame; - bool next_frame = false; - bool multiple = false; - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); -} - -TEST_F(FramerTest, AlwaysStartWithKey) { - EncodedFrame frame; - bool next_frame = false; - bool complete = false; - bool multiple = false; - bool duplicate = false; - - // Insert non key first frame. - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(complete); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - rtp_header_.frame_id = FrameId::first() + 1; - rtp_header_.reference_frame_id = FrameId::first() + 1; - rtp_header_.is_key_frame = true; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(complete); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_TRUE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first() + 1, frame.frame_id); - EXPECT_EQ(FrameId::first() + 1, frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); -} - -TEST_F(FramerTest, CompleteFrame) { - EncodedFrame frame; - bool next_frame = false; - bool complete = false; - bool multiple = false; - bool duplicate = false; - - // Start with a complete key frame. - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = FrameId::first(); - rtp_header_.reference_frame_id = FrameId::first(); - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(complete); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_FALSE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first(), frame.frame_id); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - - // Incomplete delta. - ++rtp_header_.frame_id; - rtp_header_.reference_frame_id = rtp_header_.frame_id - 1; - rtp_header_.is_key_frame = false; - rtp_header_.max_packet_id = 2; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(complete); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - - // Complete delta - can't skip, as incomplete sequence. - ++rtp_header_.frame_id; - rtp_header_.reference_frame_id = rtp_header_.frame_id - 1; - rtp_header_.max_packet_id = 0; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(complete); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); -} - -TEST_F(FramerTest, DuplicatePackets) { - EncodedFrame frame; - bool next_frame = false; - bool complete = false; - bool multiple = false; - bool duplicate = false; - - // Start with an incomplete key frame. - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = FrameId::first(); - rtp_header_.reference_frame_id = FrameId::first(); - rtp_header_.max_packet_id = 1; - duplicate = true; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(complete); - EXPECT_FALSE(duplicate); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - - // Add same packet again in incomplete key frame. - duplicate = false; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(complete); - EXPECT_TRUE(duplicate); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - - // Complete key frame. - rtp_header_.packet_id = 1; - duplicate = true; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(complete); - EXPECT_FALSE(duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_FALSE(multiple); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - - // Add same packet again in complete key frame. - duplicate = false; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(complete); - EXPECT_TRUE(duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first(), frame.frame_id); - EXPECT_FALSE(multiple); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - - // Incomplete delta frame. - ++rtp_header_.frame_id; - rtp_header_.reference_frame_id = rtp_header_.frame_id - 1; - rtp_header_.packet_id = 0; - rtp_header_.is_key_frame = false; - duplicate = true; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(complete); - EXPECT_FALSE(duplicate); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - - // Add same packet again in incomplete delta frame. - duplicate = false; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(complete); - EXPECT_TRUE(duplicate); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - - // Complete delta frame. - rtp_header_.packet_id = 1; - duplicate = true; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(complete); - EXPECT_FALSE(duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_EQ(EncodedFrame::DEPENDENT, frame.dependency); - EXPECT_EQ(FrameId::first() + 1, frame.frame_id); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - EXPECT_FALSE(multiple); - - // Add same packet again in complete delta frame. - duplicate = false; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(complete); - EXPECT_TRUE(duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_EQ(EncodedFrame::DEPENDENT, frame.dependency); - EXPECT_EQ(FrameId::first() + 1, frame.frame_id); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - EXPECT_FALSE(multiple); -} - -TEST_F(FramerTest, ContinuousSequence) { - EncodedFrame frame; - bool next_frame = false; - bool complete = false; - bool multiple = false; - bool duplicate = false; - - // Start with a complete key frame. - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = FrameId::first(); - rtp_header_.reference_frame_id = FrameId::first(); - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(complete); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_FALSE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first(), frame.frame_id); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - - // Complete - not continuous. - rtp_header_.frame_id = FrameId::first() + 2; - rtp_header_.reference_frame_id = rtp_header_.frame_id - 1; - rtp_header_.is_key_frame = false; - complete = framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(complete); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); -} - -TEST_F(FramerTest, RequireKeyFrameForFirstFrame) { - EncodedFrame frame; - bool next_frame = false; - bool multiple = false; - bool duplicate = false; - - // Start with a complete key frame. - rtp_header_.is_key_frame = false; - rtp_header_.frame_id = FrameId::first(); - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - rtp_header_.frame_id = FrameId::first() + 1; - rtp_header_.reference_frame_id = FrameId::first() + 1; - rtp_header_.is_key_frame = true; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_TRUE(multiple); -} - -TEST_F(FramerTest, BasicNonLastReferenceId) { - EncodedFrame frame; - bool next_frame = false; - bool multiple = false; - bool duplicate = false; - - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = FrameId::first(); - rtp_header_.reference_frame_id = FrameId::first(); - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_FALSE(multiple); - framer_.ReleaseFrame(frame.frame_id); - - rtp_header_.is_key_frame = false; - rtp_header_.frame_id = FrameId::first() + 5; - rtp_header_.reference_frame_id = FrameId::first(); - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_FALSE(next_frame); - EXPECT_FALSE(multiple); -} - -TEST_F(FramerTest, InOrderReferenceFrameSelection) { - // Create pattern: 0, 1, 4, 5. - EncodedFrame frame; - bool next_frame = false; - bool multiple = false; - bool duplicate = false; - - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = FrameId::first(); - rtp_header_.reference_frame_id = FrameId::first(); - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - rtp_header_.is_key_frame = false; - rtp_header_.frame_id = FrameId::first() + 1; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - - // Insert frame #2 partially. - rtp_header_.frame_id = FrameId::first() + 2; - rtp_header_.max_packet_id = 1; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - rtp_header_.frame_id = FrameId::first() + 4; - rtp_header_.max_packet_id = 0; - rtp_header_.reference_frame_id = FrameId::first(); - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first(), frame.frame_id); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - EXPECT_FALSE(multiple); - framer_.ReleaseFrame(frame.frame_id); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_TRUE(multiple); - EXPECT_EQ(EncodedFrame::DEPENDENT, frame.dependency); - EXPECT_EQ(FrameId::first() + 1, frame.frame_id); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_FALSE(next_frame); - EXPECT_FALSE(multiple); - EXPECT_EQ(EncodedFrame::DEPENDENT, frame.dependency); - EXPECT_EQ(FrameId::first() + 4, frame.frame_id); - EXPECT_EQ(FrameId::first(), frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - // Insert remaining packet of frame #2 - should no be continuous. - rtp_header_.frame_id = FrameId::first() + 2; - rtp_header_.packet_id = 1; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_FALSE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - rtp_header_.frame_id = FrameId::first() + 5; - rtp_header_.reference_frame_id = rtp_header_.frame_id - 1; - rtp_header_.packet_id = 0; - rtp_header_.max_packet_id = 0; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_FALSE(multiple); - EXPECT_EQ(EncodedFrame::DEPENDENT, frame.dependency); - EXPECT_EQ(FrameId::first() + 5, frame.frame_id); - EXPECT_EQ(FrameId::first() + 4, frame.referenced_frame_id); -} - -TEST_F(FramerTest, ReleasesAllReceivedKeyFramesInContinuousSequence) { - EncodedFrame frame; - bool next_frame = false; - bool multiple = false; - bool duplicate = false; - - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = FrameId::first() + 254; - rtp_header_.reference_frame_id = FrameId::first() + 254; - - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_FALSE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first() + 254, frame.frame_id); - EXPECT_EQ(FrameId::first() + 254, frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - - rtp_header_.frame_id = FrameId::first() + 255; - rtp_header_.reference_frame_id = FrameId::first() + 255; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - - // Insert wrapped frame - should be continuous. - rtp_header_.frame_id = FrameId::first() + 256; - rtp_header_.reference_frame_id = FrameId::first() + 256; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_TRUE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first() + 255, frame.frame_id); - EXPECT_EQ(FrameId::first() + 255, frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_FALSE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first() + 256, frame.frame_id); - EXPECT_EQ(FrameId::first() + 256, frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); -} - -TEST_F(FramerTest, SkipsMissingFramesWhenLaterKeyFramesAreAvailable) { - EncodedFrame frame; - bool next_frame = false; - bool multiple = true; - bool duplicate = false; - - // Insert and get first frame's packet. - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = FrameId::first() + 253; - rtp_header_.reference_frame_id = FrameId::first() + 253; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_FALSE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first() + 253, frame.frame_id); - EXPECT_EQ(FrameId::first() + 253, frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - - // Insert third and fourth frames' packet. - rtp_header_.frame_id = FrameId::first() + 255; - rtp_header_.reference_frame_id = FrameId::first() + 255; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - rtp_header_.frame_id = FrameId::first() + 256; - rtp_header_.reference_frame_id = FrameId::first() + 256; - framer_.InsertPacket( - &payload_[0], payload_.size(), rtp_header_, &duplicate); - - // Get third and fourth frame. - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_FALSE(next_frame); - EXPECT_TRUE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first() + 255, frame.frame_id); - EXPECT_EQ(FrameId::first() + 255, frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); - EXPECT_TRUE(framer_.GetEncodedFrame(&frame, &next_frame, &multiple)); - EXPECT_TRUE(next_frame); - EXPECT_FALSE(multiple); - EXPECT_EQ(EncodedFrame::KEY, frame.dependency); - EXPECT_EQ(FrameId::first() + 256, frame.frame_id); - EXPECT_EQ(FrameId::first() + 256, frame.referenced_frame_id); - framer_.ReleaseFrame(frame.frame_id); -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/net/rtp/receiver_stats.cc b/chromium/media/cast/net/rtp/receiver_stats.cc deleted file mode 100644 index c9d3f68c203..00000000000 --- a/chromium/media/cast/net/rtp/receiver_stats.cc +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2014 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/cast/net/rtp/receiver_stats.h" - -#include "media/cast/net/rtp/rtp_defines.h" - -namespace media { -namespace cast { - -namespace { - -constexpr uint32_t kMaxSequenceNumber = 65536; - -// TODO(miu): Get rid of all the special 16-bit rounding detection and special -// handling throughout this file, and just use good 'ol int64_t. -// http://crbug.com/530839 -bool IsNewerSequenceNumber(uint16_t sequence_number, - uint16_t prev_sequence_number) { - return (sequence_number != prev_sequence_number) && - static_cast<uint16_t>(sequence_number - prev_sequence_number) < 0x8000; -} - -} // namespace - -ReceiverStats::ReceiverStats(const base::TickClock* clock) - : clock_(clock), - min_sequence_number_(0), - max_sequence_number_(0), - total_number_packets_(0), - sequence_number_cycles_(0), - interval_min_sequence_number_(0), - interval_number_packets_(0), - interval_wrap_count_(0) {} - -RtpReceiverStatistics ReceiverStats::GetStatistics() { - RtpReceiverStatistics ret; - // Compute losses. - if (interval_number_packets_ == 0) { - ret.fraction_lost = 0; - } else { - int diff = 0; - if (interval_wrap_count_ == 0) { - diff = max_sequence_number_ - interval_min_sequence_number_ + 1; - } else { - diff = kMaxSequenceNumber * (interval_wrap_count_ - 1) + - (max_sequence_number_ - interval_min_sequence_number_ + - kMaxSequenceNumber + 1); - } - - if (diff < 1) { - ret.fraction_lost = 0; - } else { - float tmp_ratio = - (1 - static_cast<float>(interval_number_packets_) / abs(diff)); - ret.fraction_lost = static_cast<uint8_t>(256 * tmp_ratio); - } - } - - int expected_packets_num = max_sequence_number_ - min_sequence_number_ + 1; - if (total_number_packets_ == 0) { - ret.cumulative_lost = 0; - } else if (sequence_number_cycles_ == 0) { - ret.cumulative_lost = expected_packets_num - total_number_packets_; - } else { - ret.cumulative_lost = - kMaxSequenceNumber * (sequence_number_cycles_ - 1) + - (expected_packets_num - total_number_packets_ + kMaxSequenceNumber); - } - - // Extended high sequence number consists of the highest seq number and the - // number of cycles (wrap). - ret.extended_high_sequence_number = - (sequence_number_cycles_ << 16) + max_sequence_number_; - - ret.jitter = - static_cast<uint32_t>(std::abs(jitter_.InMillisecondsRoundedUp())); - - // Reset interval values. - interval_min_sequence_number_ = 0; - interval_number_packets_ = 0; - interval_wrap_count_ = 0; - - return ret; -} - -void ReceiverStats::UpdateStatistics(const RtpCastHeader& header, - int rtp_timebase) { - const uint16_t new_seq_num = header.sequence_number; - - if (interval_number_packets_ == 0) { - // First packet in the interval. - interval_min_sequence_number_ = new_seq_num; - } - if (total_number_packets_ == 0) { - // First incoming packet. - min_sequence_number_ = new_seq_num; - max_sequence_number_ = new_seq_num; - } - - if (IsNewerSequenceNumber(new_seq_num, max_sequence_number_)) { - // Check wrap. - if (new_seq_num < max_sequence_number_) { - ++sequence_number_cycles_; - ++interval_wrap_count_; - } - max_sequence_number_ = new_seq_num; - } - - // Compute Jitter. - const base::TimeTicks now = clock_->NowTicks(); - if (total_number_packets_ > 0) { - const base::TimeDelta packet_time_difference = - now - last_received_packet_time_; - const base::TimeDelta media_time_differerence = - (header.rtp_timestamp - last_received_rtp_timestamp_) - .ToTimeDelta(rtp_timebase); - const base::TimeDelta delta = - packet_time_difference - media_time_differerence; - // Update jitter. - jitter_ += (delta - jitter_) / 16; - } - last_received_rtp_timestamp_ = header.rtp_timestamp; - last_received_packet_time_ = now; - - // Increment counters. - ++total_number_packets_; - ++interval_number_packets_; -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/net/rtp/receiver_stats.h b/chromium/media/cast/net/rtp/receiver_stats.h deleted file mode 100644 index a1cd9039714..00000000000 --- a/chromium/media/cast/net/rtp/receiver_stats.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2014 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. - -#ifndef MEDIA_CAST_NET_RTP_RECEIVER_STATS_H_ -#define MEDIA_CAST_NET_RTP_RECEIVER_STATS_H_ - -#include <stdint.h> - -#include "base/macros.h" -#include "base/time/tick_clock.h" -#include "base/time/time.h" -#include "media/cast/common/rtp_time.h" -#include "media/cast/net/rtp/rtp_defines.h" - -namespace media { -namespace cast { - -// TODO(miu): Document this class. -class ReceiverStats { - public: - explicit ReceiverStats(const base::TickClock* clock); - - RtpReceiverStatistics GetStatistics(); - void UpdateStatistics(const RtpCastHeader& header, int rtp_timebase); - - private: - const base::TickClock* const clock_; // Not owned by this class. - - // Global metrics. - uint16_t min_sequence_number_; - uint16_t max_sequence_number_; - uint32_t total_number_packets_; - uint16_t sequence_number_cycles_; - RtpTimeTicks last_received_rtp_timestamp_; - base::TimeTicks last_received_packet_time_; - base::TimeDelta jitter_; - - // Intermediate metrics - between RTCP reports. - int interval_min_sequence_number_; - int interval_number_packets_; - int interval_wrap_count_; - - DISALLOW_COPY_AND_ASSIGN(ReceiverStats); -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_NET_RTP_RECEIVER_STATS_H_ diff --git a/chromium/media/cast/net/rtp/receiver_stats_unittest.cc b/chromium/media/cast/net/rtp/receiver_stats_unittest.cc deleted file mode 100644 index ec132e4a7a2..00000000000 --- a/chromium/media/cast/net/rtp/receiver_stats_unittest.cc +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2014 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 <gtest/gtest.h> - -#include <stdint.h> - -#include "base/macros.h" -#include "base/test/simple_test_tick_clock.h" -#include "base/time/time.h" -#include "media/cast/constants.h" -#include "media/cast/net/rtp/receiver_stats.h" -#include "media/cast/net/rtp/rtp_defines.h" - -namespace media { -namespace cast { - -static const int64_t kStartMillisecond = INT64_C(12345678900000); -static const uint32_t kStdTimeIncrementMs = 33; - -class ReceiverStatsTest : public ::testing::Test { - protected: - ReceiverStatsTest() - : stats_(&testing_clock_) { - testing_clock_.Advance( - base::TimeDelta::FromMilliseconds(kStartMillisecond)); - start_time_ = testing_clock_.NowTicks(); - delta_increments_ = base::TimeDelta::FromMilliseconds(kStdTimeIncrementMs); - } - ~ReceiverStatsTest() override = default; - - uint32_t ExpectedJitter(uint32_t const_interval, int num_packets) { - float jitter = 0; - // Assume timestamps have a constant kStdTimeIncrementMs interval. - float float_interval = - static_cast<float>(const_interval - kStdTimeIncrementMs); - for (int i = 0; i < num_packets; ++i) { - jitter += (float_interval - jitter) / 16; - } - return static_cast<uint32_t>(jitter + 0.5f); - } - - ReceiverStats stats_; - RtpCastHeader rtp_header_; - base::SimpleTestTickClock testing_clock_; - base::TimeTicks start_time_; - base::TimeDelta delta_increments_; - - private: - DISALLOW_COPY_AND_ASSIGN(ReceiverStatsTest); -}; - -TEST_F(ReceiverStatsTest, ResetState) { - RtpReceiverStatistics s = stats_.GetStatistics(); - EXPECT_EQ(0u, s.fraction_lost); - EXPECT_EQ(0u, s.cumulative_lost); - EXPECT_EQ(0u, s.extended_high_sequence_number); - EXPECT_EQ(0u, s.jitter); -} - -TEST_F(ReceiverStatsTest, LossCount) { - for (int i = 0; i < 300; ++i) { - if (i % 4) - stats_.UpdateStatistics(rtp_header_, kVideoFrequency); - if (i % 3) { - rtp_header_.rtp_timestamp += RtpTimeDelta::FromTimeDelta( - base::TimeDelta::FromMilliseconds(33), kVideoFrequency); - } - ++rtp_header_.sequence_number; - testing_clock_.Advance(delta_increments_); - } - RtpReceiverStatistics s = stats_.GetStatistics(); - EXPECT_EQ(63u, s.fraction_lost); - EXPECT_EQ(74u, s.cumulative_lost); - // Build extended sequence number. - const uint32_t extended_seq_num = rtp_header_.sequence_number - 1; - EXPECT_EQ(extended_seq_num, s.extended_high_sequence_number); -} - -TEST_F(ReceiverStatsTest, NoLossWrap) { - rtp_header_.sequence_number = 65500; - for (int i = 0; i < 300; ++i) { - stats_.UpdateStatistics(rtp_header_, kVideoFrequency); - if (i % 3) { - rtp_header_.rtp_timestamp += RtpTimeDelta::FromTimeDelta( - base::TimeDelta::FromMilliseconds(33), kVideoFrequency); - } - ++rtp_header_.sequence_number; - testing_clock_.Advance(delta_increments_); - } - RtpReceiverStatistics s = stats_.GetStatistics(); - EXPECT_EQ(0u, s.fraction_lost); - EXPECT_EQ(0u, s.cumulative_lost); - // Build extended sequence number (one wrap cycle). - const uint32_t extended_seq_num = (1 << 16) + rtp_header_.sequence_number - 1; - EXPECT_EQ(extended_seq_num, s.extended_high_sequence_number); -} - -TEST_F(ReceiverStatsTest, LossCountWrap) { - const uint32_t kStartSequenceNumber = 65500; - rtp_header_.sequence_number = kStartSequenceNumber; - for (int i = 0; i < 300; ++i) { - if (i % 4) - stats_.UpdateStatistics(rtp_header_, kVideoFrequency); - if (i % 3) - rtp_header_.rtp_timestamp += RtpTimeDelta::FromTicks(1); - ++rtp_header_.sequence_number; - testing_clock_.Advance(delta_increments_); - } - RtpReceiverStatistics s = stats_.GetStatistics(); - EXPECT_EQ(63u, s.fraction_lost); - EXPECT_EQ(74u, s.cumulative_lost); - // Build extended sequence number (one wrap cycle). - const uint32_t extended_seq_num = (1 << 16) + rtp_header_.sequence_number - 1; - EXPECT_EQ(extended_seq_num, s.extended_high_sequence_number); -} - -TEST_F(ReceiverStatsTest, BasicJitter) { - for (int i = 0; i < 300; ++i) { - stats_.UpdateStatistics(rtp_header_, kVideoFrequency); - ++rtp_header_.sequence_number; - rtp_header_.rtp_timestamp += RtpTimeDelta::FromTimeDelta( - base::TimeDelta::FromMilliseconds(33), kVideoFrequency); - testing_clock_.Advance(delta_increments_); - } - RtpReceiverStatistics s = stats_.GetStatistics(); - EXPECT_FALSE(s.fraction_lost); - EXPECT_FALSE(s.cumulative_lost); - // Build extended sequence number (one wrap cycle). - const uint32_t extended_seq_num = rtp_header_.sequence_number - 1; - EXPECT_EQ(extended_seq_num, s.extended_high_sequence_number); - EXPECT_EQ(ExpectedJitter(kStdTimeIncrementMs, 300), s.jitter); -} - -TEST_F(ReceiverStatsTest, NonTrivialJitter) { - const int kAdditionalIncrement = 5; - for (int i = 0; i < 300; ++i) { - stats_.UpdateStatistics(rtp_header_, kVideoFrequency); - ++rtp_header_.sequence_number; - rtp_header_.rtp_timestamp += RtpTimeDelta::FromTimeDelta( - base::TimeDelta::FromMilliseconds(33), kVideoFrequency); - base::TimeDelta additional_delta = - base::TimeDelta::FromMilliseconds(kAdditionalIncrement); - testing_clock_.Advance(delta_increments_ + additional_delta); - } - RtpReceiverStatistics s = stats_.GetStatistics(); - EXPECT_FALSE(s.fraction_lost); - EXPECT_FALSE(s.cumulative_lost); - // Build extended sequence number (one wrap cycle). - const uint32_t extended_seq_num = rtp_header_.sequence_number - 1; - EXPECT_EQ(extended_seq_num, s.extended_high_sequence_number); - EXPECT_EQ(ExpectedJitter(kStdTimeIncrementMs + kAdditionalIncrement, 300), - s.jitter); -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/net/rtp/rtp_packetizer.h b/chromium/media/cast/net/rtp/rtp_packetizer.h index bb689541886..9bb6d61021a 100644 --- a/chromium/media/cast/net/rtp/rtp_packetizer.h +++ b/chromium/media/cast/net/rtp/rtp_packetizer.h @@ -9,10 +9,7 @@ #include <stdint.h> #include <cmath> -#include <list> -#include <map> -#include "base/time/time.h" #include "media/cast/common/rtp_time.h" #include "media/cast/net/rtp/packet_storage.h" diff --git a/chromium/media/cast/receiver/audio_decoder.cc b/chromium/media/cast/receiver/audio_decoder.cc deleted file mode 100644 index d3b760b81f2..00000000000 --- a/chromium/media/cast/receiver/audio_decoder.cc +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2014 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/cast/receiver/audio_decoder.h" - -#include <stdint.h> - -#include <utility> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/sys_byteorder.h" -#include "build/build_config.h" -#include "third_party/opus/src/include/opus.h" - -namespace media { -namespace cast { - -// Base class that handles the common problem of detecting dropped frames, and -// then invoking the Decode() method implemented by the subclasses to convert -// the encoded payload data into usable audio data. -class AudioDecoder::ImplBase - : public base::RefCountedThreadSafe<AudioDecoder::ImplBase> { - public: - ImplBase(const scoped_refptr<CastEnvironment>& cast_environment, - Codec codec, - int num_channels, - int sampling_rate) - : cast_environment_(cast_environment), - codec_(codec), - num_channels_(num_channels), - operational_status_(STATUS_UNINITIALIZED) { - if (num_channels_ <= 0 || sampling_rate <= 0 || sampling_rate % 100 != 0) { - operational_status_ = STATUS_INVALID_CONFIGURATION; - } - } - - OperationalStatus InitializationResult() const { - return operational_status_; - } - - void DecodeFrame(std::unique_ptr<EncodedFrame> encoded_frame, - DecodeFrameCallback callback) { - DCHECK_EQ(operational_status_, STATUS_INITIALIZED); - - bool is_continuous = true; - DCHECK(!encoded_frame->frame_id.is_null()); - if (!last_frame_id_.is_null()) { - if (encoded_frame->frame_id > (last_frame_id_ + 1)) { - RecoverBecauseFramesWereDropped(); - is_continuous = false; - } - } - last_frame_id_ = encoded_frame->frame_id; - - std::unique_ptr<AudioBus> decoded_audio = - Decode(encoded_frame->mutable_bytes(), - static_cast<int>(encoded_frame->data.size())); - if (!decoded_audio) { - VLOG(2) << "Decoding of frame " << encoded_frame->frame_id << " failed."; - cast_environment_->PostTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(std::move(callback), std::move(decoded_audio), false)); - return; - } - - std::unique_ptr<FrameEvent> event(new FrameEvent()); - event->timestamp = cast_environment_->Clock()->NowTicks(); - event->type = FRAME_DECODED; - event->media_type = AUDIO_EVENT; - event->rtp_timestamp = encoded_frame->rtp_timestamp; - event->frame_id = encoded_frame->frame_id; - cast_environment_->logger()->DispatchFrameEvent(std::move(event)); - - cast_environment_->PostTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(std::move(callback), std::move(decoded_audio), - is_continuous)); - } - - protected: - friend class base::RefCountedThreadSafe<ImplBase>; - virtual ~ImplBase() = default; - - virtual void RecoverBecauseFramesWereDropped() {} - - // Note: Implementation of Decode() is allowed to mutate |data|. - virtual std::unique_ptr<AudioBus> Decode(uint8_t* data, int len) = 0; - - const scoped_refptr<CastEnvironment> cast_environment_; - const Codec codec_; - const int num_channels_; - - // Subclass' ctor is expected to set this to STATUS_INITIALIZED. - OperationalStatus operational_status_; - - private: - FrameId last_frame_id_; - - DISALLOW_COPY_AND_ASSIGN(ImplBase); -}; - -class AudioDecoder::OpusImpl final : public AudioDecoder::ImplBase { - public: - OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, - int num_channels, - int sampling_rate) - : ImplBase(cast_environment, - CODEC_AUDIO_OPUS, - num_channels, - sampling_rate), - decoder_memory_(new uint8_t[opus_decoder_get_size(num_channels)]), - opus_decoder_(reinterpret_cast<OpusDecoder*>(decoder_memory_.get())), - max_samples_per_frame_(kOpusMaxFrameDurationMillis * sampling_rate / - 1000), - buffer_(new float[max_samples_per_frame_ * num_channels]) { - if (ImplBase::operational_status_ != STATUS_UNINITIALIZED) { - return; - } - if (opus_decoder_init(opus_decoder_, sampling_rate, num_channels) != - OPUS_OK) { - ImplBase::operational_status_ = STATUS_INVALID_CONFIGURATION; - return; - } - ImplBase::operational_status_ = STATUS_INITIALIZED; - } - - private: - ~OpusImpl() final = default; - - void RecoverBecauseFramesWereDropped() final { - // Passing nullptr for the input data notifies the decoder of frame loss. - const opus_int32 result = opus_decode_float( - opus_decoder_, nullptr, 0, buffer_.get(), max_samples_per_frame_, 0); - DCHECK_GE(result, 0); - } - - std::unique_ptr<AudioBus> Decode(uint8_t* data, int len) final { - std::unique_ptr<AudioBus> audio_bus; - const opus_int32 num_samples_decoded = opus_decode_float( - opus_decoder_, data, len, buffer_.get(), max_samples_per_frame_, 0); - if (num_samples_decoded <= 0) - return audio_bus; // Decode error. - - // Copy interleaved samples from |buffer_| into a new AudioBus (where - // samples are stored in planar format, for each channel). - audio_bus = AudioBus::Create(num_channels_, num_samples_decoded); - // TODO(miu): This should be moved into AudioBus::FromInterleaved(). - for (int ch = 0; ch < num_channels_; ++ch) { - const float* src = buffer_.get() + ch; - const float* const src_end = src + num_samples_decoded * num_channels_; - float* dest = audio_bus->channel(ch); - for (; src < src_end; src += num_channels_, ++dest) - *dest = *src; - } - return audio_bus; - } - - const std::unique_ptr<uint8_t[]> decoder_memory_; - OpusDecoder* const opus_decoder_; - const int max_samples_per_frame_; - const std::unique_ptr<float[]> buffer_; - - // According to documentation in third_party/opus/src/include/opus.h, we must - // provide enough space in |buffer_| to contain 120ms of samples. At 48 kHz, - // then, that means 5760 samples times the number of channels. - static const int kOpusMaxFrameDurationMillis = 120; - - DISALLOW_COPY_AND_ASSIGN(OpusImpl); -}; - -class AudioDecoder::Pcm16Impl final : public AudioDecoder::ImplBase { - public: - Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, - int num_channels, - int sampling_rate) - : ImplBase(cast_environment, - CODEC_AUDIO_PCM16, - num_channels, - sampling_rate) { - if (ImplBase::operational_status_ != STATUS_UNINITIALIZED) - return; - ImplBase::operational_status_ = STATUS_INITIALIZED; - } - - private: - ~Pcm16Impl() final = default; - - std::unique_ptr<AudioBus> Decode(uint8_t* data, int len) final { - std::unique_ptr<AudioBus> audio_bus; - const int num_samples = len / sizeof(int16_t) / num_channels_; - if (num_samples <= 0) - return audio_bus; - - int16_t* const pcm_data = reinterpret_cast<int16_t*>(data); -#if defined(ARCH_CPU_LITTLE_ENDIAN) - // Convert endianness. - const int num_elements = num_samples * num_channels_; - for (int i = 0; i < num_elements; ++i) - pcm_data[i] = static_cast<int16_t>(base::NetToHost16(pcm_data[i])); -#endif - audio_bus = AudioBus::Create(num_channels_, num_samples); - audio_bus->FromInterleaved<SignedInt16SampleTypeTraits>(pcm_data, - num_samples); - return audio_bus; - } - - DISALLOW_COPY_AND_ASSIGN(Pcm16Impl); -}; - -AudioDecoder::AudioDecoder( - const scoped_refptr<CastEnvironment>& cast_environment, - int channels, - int sampling_rate, - Codec codec) - : cast_environment_(cast_environment) { - switch (codec) { - case CODEC_AUDIO_OPUS: - impl_ = new OpusImpl(cast_environment, channels, sampling_rate); - break; - case CODEC_AUDIO_PCM16: - impl_ = new Pcm16Impl(cast_environment, channels, sampling_rate); - break; - default: - NOTREACHED() << "Unknown or unspecified codec."; - break; - } -} - -AudioDecoder::~AudioDecoder() = default; - -OperationalStatus AudioDecoder::InitializationResult() const { - if (impl_.get()) - return impl_->InitializationResult(); - return STATUS_UNSUPPORTED_CODEC; -} - -void AudioDecoder::DecodeFrame(std::unique_ptr<EncodedFrame> encoded_frame, - DecodeFrameCallback callback) { - DCHECK(encoded_frame.get()); - DCHECK(!callback.is_null()); - if (!impl_.get() || impl_->InitializationResult() != STATUS_INITIALIZED) { - std::move(callback).Run(base::WrapUnique<AudioBus>(nullptr), false); - return; - } - cast_environment_->PostTask( - CastEnvironment::AUDIO, FROM_HERE, - base::BindOnce(&AudioDecoder::ImplBase::DecodeFrame, impl_, - std::move(encoded_frame), std::move(callback))); -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/receiver/audio_decoder.h b/chromium/media/cast/receiver/audio_decoder.h deleted file mode 100644 index 608ff016e4e..00000000000 --- a/chromium/media/cast/receiver/audio_decoder.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 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. - -#ifndef MEDIA_CAST_RECEIVER_AUDIO_DECODER_H_ -#define MEDIA_CAST_RECEIVER_AUDIO_DECODER_H_ - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "media/base/audio_bus.h" -#include "media/cast/cast_environment.h" -#include "media/cast/constants.h" -#include "media/cast/net/cast_transport_config.h" - -namespace media { -namespace cast { - -class AudioDecoder { - public: - // Callback passed to DecodeFrame, to deliver decoded audio data from the - // decoder. The number of samples in |audio_bus| may vary, and |audio_bus| - // can be NULL when errors occur. |is_continuous| is normally true, but will - // be false if the decoder has detected a frame skip since the last decode - // operation; and the client should take steps to smooth audio discontinuities - // in this case. - using DecodeFrameCallback = - base::OnceCallback<void(std::unique_ptr<AudioBus> audio_bus, - bool is_continuous)>; - - AudioDecoder(const scoped_refptr<CastEnvironment>& cast_environment, - int channels, - int sampling_rate, - Codec codec); - virtual ~AudioDecoder(); - - // Returns STATUS_INITIALIZED if the decoder was successfully constructed. If - // this method returns any other value, calls to DecodeFrame() will not - // succeed. - OperationalStatus InitializationResult() const; - - // Decode the payload in |encoded_frame| asynchronously. |callback| will be - // invoked on the CastEnvironment::MAIN thread with the result. - // - // In the normal case, |encoded_frame->frame_id| will be - // monotonically-increasing by 1 for each successive call to this method. - // When it is not, the decoder will assume one or more frames have been - // dropped (e.g., due to packet loss), and will perform recovery actions. - void DecodeFrame(std::unique_ptr<EncodedFrame> encoded_frame, - DecodeFrameCallback callback); - - private: - class ImplBase; - class OpusImpl; - class Pcm16Impl; - - const scoped_refptr<CastEnvironment> cast_environment_; - scoped_refptr<ImplBase> impl_; - - DISALLOW_COPY_AND_ASSIGN(AudioDecoder); -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_RECEIVER_AUDIO_DECODER_H_ diff --git a/chromium/media/cast/receiver/audio_decoder_unittest.cc b/chromium/media/cast/receiver/audio_decoder_unittest.cc deleted file mode 100644 index 39268d66e5e..00000000000 --- a/chromium/media/cast/receiver/audio_decoder_unittest.cc +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright 2014 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 <stddef.h> -#include <stdint.h> - -#include <utility> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/stl_util.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/sys_byteorder.h" -#include "base/time/time.h" -#include "build/build_config.h" -#include "media/cast/cast_config.h" -#include "media/cast/receiver/audio_decoder.h" -#include "media/cast/test/utility/audio_utility.h" -#include "media/cast/test/utility/standalone_cast_environment.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/opus/src/include/opus.h" - -namespace media { -namespace cast { - -namespace { -struct TestScenario { - Codec codec; - int num_channels; - int sampling_rate; - - TestScenario(Codec c, int n, int s) - : codec(c), num_channels(n), sampling_rate(s) {} -}; -} // namespace - -class AudioDecoderTest : public ::testing::TestWithParam<TestScenario> { - public: - AudioDecoderTest() - : cast_environment_(new StandaloneCastEnvironment()), - cond_(&lock_) {} - - virtual ~AudioDecoderTest() { - // Make sure all threads have stopped before the environment goes away. - cast_environment_->Shutdown(); - } - - protected: - void SetUp() final { - audio_decoder_.reset(new AudioDecoder(cast_environment_, - GetParam().num_channels, - GetParam().sampling_rate, - GetParam().codec)); - CHECK_EQ(STATUS_INITIALIZED, audio_decoder_->InitializationResult()); - - audio_bus_factory_.reset( - new TestAudioBusFactory(GetParam().num_channels, - GetParam().sampling_rate, - TestAudioBusFactory::kMiddleANoteFreq, - 0.5f)); - last_frame_id_ = FrameId::first(); - decoded_frames_seen_ = 0; - - if (GetParam().codec == CODEC_AUDIO_OPUS) { - opus_encoder_memory_.reset( - new uint8_t[opus_encoder_get_size(GetParam().num_channels)]); - OpusEncoder* const opus_encoder = - reinterpret_cast<OpusEncoder*>(opus_encoder_memory_.get()); - CHECK_EQ(OPUS_OK, opus_encoder_init(opus_encoder, - GetParam().sampling_rate, - GetParam().num_channels, - OPUS_APPLICATION_AUDIO)); - CHECK_EQ(OPUS_OK, - opus_encoder_ctl(opus_encoder, OPUS_SET_BITRATE(OPUS_AUTO))); - } - - total_audio_feed_in_ = base::TimeDelta(); - total_audio_decoded_ = base::TimeDelta(); - } - - // Called from the unit test thread to create another EncodedFrame and push it - // into the decoding pipeline. - void FeedMoreAudio(const base::TimeDelta& duration, - int num_dropped_frames) { - // Prepare a simulated EncodedFrame to feed into the AudioDecoder. - std::unique_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); - encoded_frame->dependency = EncodedFrame::KEY; - encoded_frame->frame_id = last_frame_id_ + 1 + num_dropped_frames; - encoded_frame->referenced_frame_id = encoded_frame->frame_id; - last_frame_id_ = encoded_frame->frame_id; - - const std::unique_ptr<AudioBus> audio_bus( - audio_bus_factory_->NextAudioBus(duration)); - - // Encode |audio_bus| into |encoded_frame->data|. - const int num_elements = audio_bus->channels() * audio_bus->frames(); - std::vector<int16_t> interleaved(num_elements); - audio_bus->ToInterleaved<SignedInt16SampleTypeTraits>(audio_bus->frames(), - &interleaved.front()); - if (GetParam().codec == CODEC_AUDIO_PCM16) { - encoded_frame->data.resize(num_elements * sizeof(int16_t)); - int16_t* const pcm_data = - reinterpret_cast<int16_t*>(encoded_frame->mutable_bytes()); - for (size_t i = 0; i < interleaved.size(); ++i) - pcm_data[i] = static_cast<int16_t>(base::HostToNet16(interleaved[i])); - } else if (GetParam().codec == CODEC_AUDIO_OPUS) { - OpusEncoder* const opus_encoder = - reinterpret_cast<OpusEncoder*>(opus_encoder_memory_.get()); - const int kOpusEncodeBufferSize = 4000; - encoded_frame->data.resize(kOpusEncodeBufferSize); - const int payload_size = - opus_encode(opus_encoder, - &interleaved.front(), - audio_bus->frames(), - encoded_frame->mutable_bytes(), - encoded_frame->data.size()); - CHECK_GT(payload_size, 1); - encoded_frame->data.resize(payload_size); - } else { - ASSERT_TRUE(false); // Not reached. - } - - { - base::AutoLock auto_lock(lock_); - total_audio_feed_in_ += duration; - } - - cast_environment_->PostTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(&AudioDecoder::DecodeFrame, - base::Unretained(audio_decoder_.get()), - std::move(encoded_frame), - base::BindRepeating(&AudioDecoderTest::OnDecodedFrame, - base::Unretained(this), - num_dropped_frames == 0))); - } - - // Blocks the caller until all audio that has been feed in has been decoded. - void WaitForAllAudioToBeDecoded() { - DCHECK(!cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - base::AutoLock auto_lock(lock_); - while (total_audio_decoded_ < total_audio_feed_in_) - cond_.Wait(); - EXPECT_EQ(total_audio_feed_in_.InMicroseconds(), - total_audio_decoded_.InMicroseconds()); - } - - private: - // Called by |audio_decoder_| to deliver each frame of decoded audio. - void OnDecodedFrame(bool should_be_continuous, - std::unique_ptr<AudioBus> audio_bus, - bool is_continuous) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - - // A NULL |audio_bus| indicates a decode error, which we don't expect. - ASSERT_TRUE(audio_bus); - - // Did the decoder detect whether frames were dropped? - EXPECT_EQ(should_be_continuous, is_continuous); - - // Does the audio data seem to be intact? For Opus, we have to ignore the - // first two frames seen at the start (and immediately after dropped packet - // recovery) because it introduces a tiny, significant delay. - bool examine_signal = true; - if (GetParam().codec == CODEC_AUDIO_OPUS) { - decoded_frames_seen_ = should_be_continuous ? decoded_frames_seen_ + 1 : 1; - examine_signal = (decoded_frames_seen_ > 2) && should_be_continuous; - } - if (examine_signal) { - for (int ch = 0; ch < audio_bus->channels(); ++ch) { - EXPECT_NEAR( - TestAudioBusFactory::kMiddleANoteFreq * 2 * audio_bus->frames() / - GetParam().sampling_rate, - CountZeroCrossings(audio_bus->channel(ch), audio_bus->frames()), - 1); - } - } - - // Signal the main test thread that more audio was decoded. - base::AutoLock auto_lock(lock_); - total_audio_decoded_ += base::TimeDelta::FromSeconds(1) * - audio_bus->frames() / GetParam().sampling_rate; - cond_.Signal(); - } - - const scoped_refptr<StandaloneCastEnvironment> cast_environment_; - std::unique_ptr<AudioDecoder> audio_decoder_; - std::unique_ptr<TestAudioBusFactory> audio_bus_factory_; - FrameId last_frame_id_; - int decoded_frames_seen_; - std::unique_ptr<uint8_t[]> opus_encoder_memory_; - - base::Lock lock_; - base::ConditionVariable cond_; - base::TimeDelta total_audio_feed_in_; - base::TimeDelta total_audio_decoded_; - - DISALLOW_COPY_AND_ASSIGN(AudioDecoderTest); -}; - -TEST_P(AudioDecoderTest, DecodesFramesWithSameDuration) { - const base::TimeDelta kTenMilliseconds = - base::TimeDelta::FromMilliseconds(10); - const int kNumFrames = 10; - for (int i = 0; i < kNumFrames; ++i) - FeedMoreAudio(kTenMilliseconds, 0); - WaitForAllAudioToBeDecoded(); -} - -TEST_P(AudioDecoderTest, DecodesFramesWithVaryingDuration) { - // These are the set of frame durations supported by the Opus encoder. - const int kFrameDurationMs[] = { 5, 10, 20, 40, 60 }; - - const int kNumFrames = 10; - for (size_t i = 0; i < base::size(kFrameDurationMs); ++i) - for (int j = 0; j < kNumFrames; ++j) - FeedMoreAudio(base::TimeDelta::FromMilliseconds(kFrameDurationMs[i]), 0); - WaitForAllAudioToBeDecoded(); -} - -TEST_P(AudioDecoderTest, RecoversFromDroppedFrames) { - const base::TimeDelta kTenMilliseconds = - base::TimeDelta::FromMilliseconds(10); - const int kNumFrames = 100; - int next_drop_at = 3; - int next_num_dropped = 1; - for (int i = 0; i < kNumFrames; ++i) { - if (i == next_drop_at) { - const int num_dropped = next_num_dropped++; - next_drop_at *= 2; - i += num_dropped; - FeedMoreAudio(kTenMilliseconds, num_dropped); - } else { - FeedMoreAudio(kTenMilliseconds, 0); - } - } - WaitForAllAudioToBeDecoded(); -} - -INSTANTIATE_TEST_SUITE_P( - AudioDecoderTestScenarios, - AudioDecoderTest, - ::testing::Values(TestScenario(CODEC_AUDIO_PCM16, 1, 8000), - TestScenario(CODEC_AUDIO_PCM16, 2, 48000), - TestScenario(CODEC_AUDIO_OPUS, 1, 8000), - TestScenario(CODEC_AUDIO_OPUS, 2, 48000))); - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/receiver/cast_receiver_impl.cc b/chromium/media/cast/receiver/cast_receiver_impl.cc deleted file mode 100644 index 9e279fb4c6e..00000000000 --- a/chromium/media/cast/receiver/cast_receiver_impl.cc +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2014 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/cast/receiver/cast_receiver_impl.h" - -#include <stddef.h> - -#include <utility> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/callback_helpers.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/trace_event/trace_event.h" -#include "media/cast/net/rtcp/rtcp_utility.h" -#include "media/cast/receiver/audio_decoder.h" -#include "media/cast/receiver/video_decoder.h" - -namespace media { -namespace cast { - -std::unique_ptr<CastReceiver> CastReceiver::Create( - scoped_refptr<CastEnvironment> cast_environment, - const FrameReceiverConfig& audio_config, - const FrameReceiverConfig& video_config, - CastTransport* const transport) { - return std::unique_ptr<CastReceiver>(new CastReceiverImpl( - cast_environment, audio_config, video_config, transport)); -} - -CastReceiverImpl::CastReceiverImpl( - scoped_refptr<CastEnvironment> cast_environment, - const FrameReceiverConfig& audio_config, - const FrameReceiverConfig& video_config, - CastTransport* const transport) - : cast_environment_(cast_environment), - audio_receiver_(cast_environment, audio_config, AUDIO_EVENT, transport), - video_receiver_(cast_environment, video_config, VIDEO_EVENT, transport), - ssrc_of_audio_sender_(audio_config.sender_ssrc), - ssrc_of_video_sender_(video_config.sender_ssrc), - num_audio_channels_(audio_config.channels), - audio_sampling_rate_(audio_config.rtp_timebase), - audio_codec_(audio_config.codec), - video_codec_(video_config.codec) {} - -CastReceiverImpl::~CastReceiverImpl() = default; - -void CastReceiverImpl::ReceivePacket(std::unique_ptr<Packet> packet) { - const uint8_t* const data = &packet->front(); - const size_t length = packet->size(); - - uint32_t ssrc_of_sender; - if (IsRtcpPacket(data, length)) { - ssrc_of_sender = GetSsrcOfSender(data, length); - } else if (!RtpParser::ParseSsrc(data, length, &ssrc_of_sender)) { - VLOG(1) << "Invalid RTP packet."; - return; - } - - base::WeakPtr<FrameReceiver> target; - if (ssrc_of_sender == ssrc_of_video_sender_) { - target = video_receiver_.AsWeakPtr(); - } else if (ssrc_of_sender == ssrc_of_audio_sender_) { - target = audio_receiver_.AsWeakPtr(); - } else { - VLOG(1) << "Dropping packet with a non matching sender SSRC: " - << ssrc_of_sender; - return; - } - cast_environment_->PostTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(base::IgnoreResult(&FrameReceiver::ProcessPacket), target, - std::move(packet))); -} - -void CastReceiverImpl::RequestDecodedAudioFrame( - const AudioFrameDecodedCallback& callback) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - DCHECK(!callback.is_null()); - audio_receiver_.RequestEncodedFrame(base::BindOnce( - &CastReceiverImpl::DecodeEncodedAudioFrame, - // Note: Use of Unretained is safe since this Closure is guaranteed to be - // invoked or discarded by |audio_receiver_| before destruction of |this|. - base::Unretained(this), callback)); -} - -void CastReceiverImpl::RequestDecodedVideoFrame( - const VideoFrameDecodedCallback& callback) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - DCHECK(!callback.is_null()); - video_receiver_.RequestEncodedFrame(base::BindOnce( - &CastReceiverImpl::DecodeEncodedVideoFrame, - // Note: Use of Unretained is safe since this Closure is guaranteed to be - // invoked or discarded by |video_receiver_| before destruction of |this|. - base::Unretained(this), callback)); -} - -void CastReceiverImpl::DecodeEncodedAudioFrame( - const AudioFrameDecodedCallback& callback, - std::unique_ptr<EncodedFrame> encoded_frame) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - if (!encoded_frame) { - callback.Run(base::WrapUnique<AudioBus>(nullptr), base::TimeTicks(), false); - return; - } - - if (!audio_decoder_) { - audio_decoder_ = - std::make_unique<AudioDecoder>(cast_environment_, num_audio_channels_, - audio_sampling_rate_, audio_codec_); - } - const FrameId frame_id = encoded_frame->frame_id; - const RtpTimeTicks rtp_timestamp = encoded_frame->rtp_timestamp; - const base::TimeTicks playout_time = encoded_frame->reference_time; - audio_decoder_->DecodeFrame( - std::move(encoded_frame), - base::BindOnce(&CastReceiverImpl::EmitDecodedAudioFrame, - cast_environment_, callback, frame_id, rtp_timestamp, - playout_time)); -} - -void CastReceiverImpl::DecodeEncodedVideoFrame( - const VideoFrameDecodedCallback& callback, - std::unique_ptr<EncodedFrame> encoded_frame) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - if (!encoded_frame) { - callback.Run(base::WrapRefCounted<VideoFrame>(nullptr), base::TimeTicks(), - false); - return; - } - - // Used by chrome/browser/media/cast_mirroring_performance_browsertest.cc - TRACE_EVENT_INSTANT1("cast_perf_test", "PullEncodedVideoFrame", - TRACE_EVENT_SCOPE_THREAD, "rtp_timestamp", - encoded_frame->rtp_timestamp.lower_32_bits()); - - if (!video_decoder_) { - video_decoder_ = - std::make_unique<VideoDecoder>(cast_environment_, video_codec_); - } - const FrameId frame_id = encoded_frame->frame_id; - const RtpTimeTicks rtp_timestamp = encoded_frame->rtp_timestamp; - const base::TimeTicks playout_time = encoded_frame->reference_time; - video_decoder_->DecodeFrame( - std::move(encoded_frame), - base::BindRepeating(&CastReceiverImpl::EmitDecodedVideoFrame, - cast_environment_, callback, frame_id, rtp_timestamp, - playout_time)); -} - -// static -void CastReceiverImpl::EmitDecodedAudioFrame( - const scoped_refptr<CastEnvironment>& cast_environment, - const AudioFrameDecodedCallback& callback, - FrameId frame_id, - RtpTimeTicks rtp_timestamp, - const base::TimeTicks& playout_time, - std::unique_ptr<AudioBus> audio_bus, - bool is_continuous) { - DCHECK(cast_environment->CurrentlyOn(CastEnvironment::MAIN)); - - if (audio_bus.get()) { - // TODO(miu): This is reporting incorrect timestamp and delay. - // http://crbug.com/547251 - std::unique_ptr<FrameEvent> playout_event(new FrameEvent()); - playout_event->timestamp = cast_environment->Clock()->NowTicks(); - playout_event->type = FRAME_PLAYOUT; - playout_event->media_type = AUDIO_EVENT; - playout_event->rtp_timestamp = rtp_timestamp; - playout_event->frame_id = frame_id; - playout_event->delay_delta = playout_time - playout_event->timestamp; - cast_environment->logger()->DispatchFrameEvent(std::move(playout_event)); - } - - callback.Run(std::move(audio_bus), playout_time, is_continuous); -} - -// static -void CastReceiverImpl::EmitDecodedVideoFrame( - const scoped_refptr<CastEnvironment>& cast_environment, - const VideoFrameDecodedCallback& callback, - FrameId frame_id, - RtpTimeTicks rtp_timestamp, - const base::TimeTicks& playout_time, - scoped_refptr<VideoFrame> video_frame, - bool is_continuous) { - DCHECK(cast_environment->CurrentlyOn(CastEnvironment::MAIN)); - - if (video_frame) { - // TODO(miu): This is reporting incorrect timestamp and delay. - // http://crbug.com/547251 - std::unique_ptr<FrameEvent> playout_event(new FrameEvent()); - playout_event->timestamp = cast_environment->Clock()->NowTicks(); - playout_event->type = FRAME_PLAYOUT; - playout_event->media_type = VIDEO_EVENT; - playout_event->rtp_timestamp = rtp_timestamp; - playout_event->frame_id = frame_id; - playout_event->delay_delta = playout_time - playout_event->timestamp; - cast_environment->logger()->DispatchFrameEvent(std::move(playout_event)); - - // Used by chrome/browser/media/cast_mirroring_performance_browsertest.cc - TRACE_EVENT_INSTANT2("cast_perf_test", "VideoFrameDecoded", - TRACE_EVENT_SCOPE_THREAD, "rtp_timestamp", - rtp_timestamp.lower_32_bits(), "playout_time", - (playout_time - base::TimeTicks()).InMicroseconds()); - } - - callback.Run(std::move(video_frame), playout_time, is_continuous); -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/receiver/cast_receiver_impl.h b/chromium/media/cast/receiver/cast_receiver_impl.h deleted file mode 100644 index 81b8304a802..00000000000 --- a/chromium/media/cast/receiver/cast_receiver_impl.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2014 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. - -#ifndef MEDIA_CAST_RECEIVER_CAST_RECEIVER_IMPL_H_ -#define MEDIA_CAST_RECEIVER_CAST_RECEIVER_IMPL_H_ - -#include <stdint.h> - -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "media/cast/cast_environment.h" -#include "media/cast/cast_receiver.h" -#include "media/cast/common/rtp_time.h" -#include "media/cast/net/pacing/paced_sender.h" -#include "media/cast/receiver/frame_receiver.h" - -namespace media { -namespace cast { - -class AudioDecoder; -class VideoDecoder; - -// This is a pure owner class that groups all required receiver-related objects -// together, such as the paced packet sender, audio/video RTP frame receivers, -// and software decoders (created on-demand). -class CastReceiverImpl final : public CastReceiver { - public: - CastReceiverImpl(scoped_refptr<CastEnvironment> cast_environment, - const FrameReceiverConfig& audio_config, - const FrameReceiverConfig& video_config, - CastTransport* const transport); - - ~CastReceiverImpl() final; - - // CastReceiver implementation. - void ReceivePacket(std::unique_ptr<Packet> packet) final; - void RequestDecodedAudioFrame( - const AudioFrameDecodedCallback& callback) final; - void RequestDecodedVideoFrame( - const VideoFrameDecodedCallback& callback) final; - - private: - // Feeds an EncodedFrame into |audio_decoder_|. RequestDecodedAudioFrame() - // uses this as a callback for RequestEncodedAudioFrame(). - void DecodeEncodedAudioFrame(const AudioFrameDecodedCallback& callback, - std::unique_ptr<EncodedFrame> encoded_frame); - - // Feeds an EncodedFrame into |video_decoder_|. RequestDecodedVideoFrame() - // uses this as a callback for RequestEncodedVideoFrame(). - void DecodeEncodedVideoFrame(const VideoFrameDecodedCallback& callback, - std::unique_ptr<EncodedFrame> encoded_frame); - - // Receives an AudioBus from |audio_decoder_|, logs the event, and passes the - // data on by running the given |callback|. This method is static to ensure - // it can be called after a CastReceiverImpl instance is destroyed. - // DecodeEncodedAudioFrame() uses this as a callback for - // AudioDecoder::DecodeFrame(). - static void EmitDecodedAudioFrame( - const scoped_refptr<CastEnvironment>& cast_environment, - const AudioFrameDecodedCallback& callback, - FrameId frame_id, - RtpTimeTicks rtp_timestamp, - const base::TimeTicks& playout_time, - std::unique_ptr<AudioBus> audio_bus, - bool is_continuous); - - // Receives a VideoFrame from |video_decoder_|, logs the event, and passes the - // data on by running the given |callback|. This method is static to ensure - // it can be called after a CastReceiverImpl instance is destroyed. - // DecodeEncodedVideoFrame() uses this as a callback for - // VideoDecoder::DecodeFrame(). - static void EmitDecodedVideoFrame( - const scoped_refptr<CastEnvironment>& cast_environment, - const VideoFrameDecodedCallback& callback, - FrameId frame_id, - RtpTimeTicks rtp_timestamp, - const base::TimeTicks& playout_time, - scoped_refptr<VideoFrame> video_frame, - bool is_continuous); - - const scoped_refptr<CastEnvironment> cast_environment_; - FrameReceiver audio_receiver_; - FrameReceiver video_receiver_; - - // Used by DispatchReceivedPacket() to direct packets to the appropriate frame - // receiver. - const uint32_t ssrc_of_audio_sender_; - const uint32_t ssrc_of_video_sender_; - - // Parameters for the decoders that are created on-demand. The values here - // might be nonsense if the client of CastReceiverImpl never intends to use - // the internal software-based decoders. - const int num_audio_channels_; - const int audio_sampling_rate_; - const Codec audio_codec_; - const Codec video_codec_; - - // Created on-demand to decode frames from |audio_receiver_| into AudioBuses - // for playback. - std::unique_ptr<AudioDecoder> audio_decoder_; - - // Created on-demand to decode frames from |video_receiver_| into VideoFrame - // images for playback. - std::unique_ptr<VideoDecoder> video_decoder_; - - DISALLOW_COPY_AND_ASSIGN(CastReceiverImpl); -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_RECEIVER_CAST_RECEIVER_IMPL_H_ diff --git a/chromium/media/cast/receiver/frame_receiver.cc b/chromium/media/cast/receiver/frame_receiver.cc deleted file mode 100644 index 33a35833524..00000000000 --- a/chromium/media/cast/receiver/frame_receiver.cc +++ /dev/null @@ -1,403 +0,0 @@ -// Copyright 2014 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/cast/receiver/frame_receiver.h" - -#include <algorithm> -#include <string> -#include <utility> - -#include "base/big_endian.h" -#include "base/bind.h" -#include "base/logging.h" -#include "base/numerics/safe_conversions.h" -#include "media/cast/cast_config.h" -#include "media/cast/cast_environment.h" -#include "media/cast/constants.h" -#include "media/cast/net/rtcp/rtcp_utility.h" - -namespace { - -const int kMinSchedulingDelayMs = 1; - -media::cast::RtcpTimeData CreateRtcpTimeData(base::TimeTicks now) { - media::cast::RtcpTimeData ret; - ret.timestamp = now; - media::cast::ConvertTimeTicksToNtp(now, &ret.ntp_seconds, &ret.ntp_fraction); - return ret; -} - -} // namespace - -namespace media { -namespace cast { - -FrameReceiver::FrameReceiver( - const scoped_refptr<CastEnvironment>& cast_environment, - const FrameReceiverConfig& config, - EventMediaType event_media_type, - CastTransport* const transport) - : cast_environment_(cast_environment), - transport_(transport), - packet_parser_( - config.sender_ssrc, - config.rtp_payload_type <= RtpPayloadType::AUDIO_LAST ? 127 : 96), - stats_(cast_environment->Clock()), - event_media_type_(event_media_type), - event_subscriber_(kReceiverRtcpEventHistorySize, event_media_type), - rtp_timebase_(config.rtp_timebase), - target_playout_delay_( - base::TimeDelta::FromMilliseconds(config.rtp_max_delay_ms)), - expected_frame_duration_( - base::TimeDelta::FromSecondsD(1.0 / config.target_frame_rate)), - reports_are_scheduled_(false), - framer_(cast_environment->Clock(), - this, - config.sender_ssrc, - true, - static_cast<int>(config.rtp_max_delay_ms * - config.target_frame_rate / 1000)), - rtcp_(cast_environment_->Clock(), - config.receiver_ssrc, - config.sender_ssrc), - is_waiting_for_consecutive_frame_(false), - lip_sync_drift_(ClockDriftSmoother::GetDefaultTimeConstant()) { - transport_->AddValidRtpReceiver(config.sender_ssrc, config.receiver_ssrc); - DCHECK_GT(config.rtp_max_delay_ms, 0); - DCHECK_GT(config.target_frame_rate, 0); - decryptor_.Initialize(config.aes_key, config.aes_iv_mask); - cast_environment_->logger()->Subscribe(&event_subscriber_); -} - -FrameReceiver::~FrameReceiver() { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - cast_environment_->logger()->Unsubscribe(&event_subscriber_); -} - -void FrameReceiver::RequestEncodedFrame(ReceiveEncodedFrameCallback callback) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - frame_request_queue_.push_back(std::move(callback)); - EmitAvailableEncodedFrames(); -} - -bool FrameReceiver::ProcessPacket(std::unique_ptr<Packet> packet) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - - if (IsRtcpPacket(&packet->front(), packet->size())) { - rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); - } else { - RtpCastHeader rtp_header; - const uint8_t* payload_data; - size_t payload_size; - if (!packet_parser_.ParsePacket(&packet->front(), - packet->size(), - &rtp_header, - &payload_data, - &payload_size)) { - return false; - } - - ProcessParsedPacket(rtp_header, payload_data, payload_size); - stats_.UpdateStatistics(rtp_header, rtp_timebase_); - } - - if (!reports_are_scheduled_) { - ScheduleNextRtcpReport(); - ScheduleNextCastMessage(); - reports_are_scheduled_ = true; - } - - return true; -} - -base::WeakPtr<FrameReceiver> FrameReceiver::AsWeakPtr() { - return weak_factory_.GetWeakPtr(); -} - -void FrameReceiver::ProcessParsedPacket(const RtpCastHeader& rtp_header, - const uint8_t* payload_data, - size_t payload_size) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - - const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); - - frame_id_to_rtp_timestamp_[rtp_header.frame_id.lower_8_bits()] = - rtp_header.rtp_timestamp; - - std::unique_ptr<PacketEvent> receive_event(new PacketEvent()); - receive_event->timestamp = now; - receive_event->type = PACKET_RECEIVED; - receive_event->media_type = event_media_type_; - receive_event->rtp_timestamp = rtp_header.rtp_timestamp; - receive_event->frame_id = rtp_header.frame_id; - receive_event->packet_id = rtp_header.packet_id; - receive_event->max_packet_id = rtp_header.max_packet_id; - receive_event->size = base::checked_cast<uint32_t>(payload_size); - cast_environment_->logger()->DispatchPacketEvent(std::move(receive_event)); - - bool duplicate = false; - const bool complete = - framer_.InsertPacket(payload_data, payload_size, rtp_header, &duplicate); - - // Duplicate packets are ignored. - if (duplicate) - return; - - // Update lip-sync values upon receiving the first packet of each frame, or if - // they have never been set yet. - if (rtp_header.packet_id == 0 || lip_sync_reference_time_.is_null()) { - RtpTimeTicks fresh_sync_rtp; - base::TimeTicks fresh_sync_reference; - if (!rtcp_.GetLatestLipSyncTimes(&fresh_sync_rtp, &fresh_sync_reference)) { - // HACK: The sender should have provided Sender Reports before the first - // frame was sent. However, the spec does not currently require this. - // Therefore, when the data is missing, the local clock is used to - // generate reference timestamps. - VLOG(2) << "Lip sync info missing. Falling-back to local clock."; - fresh_sync_rtp = rtp_header.rtp_timestamp; - fresh_sync_reference = now; - } - // |lip_sync_reference_time_| is always incremented according to the time - // delta computed from the difference in RTP timestamps. Then, - // |lip_sync_drift_| accounts for clock drift and also smoothes-out any - // sudden/discontinuous shifts in the series of reference time values. - if (lip_sync_reference_time_.is_null()) { - lip_sync_reference_time_ = fresh_sync_reference; - } else { - // Note: It's okay for the conversion ToTimeDelta() to be approximate - // because |lip_sync_drift_| will account for accumulated errors. - lip_sync_reference_time_ += - (fresh_sync_rtp - lip_sync_rtp_timestamp_).ToTimeDelta(rtp_timebase_); - } - lip_sync_rtp_timestamp_ = fresh_sync_rtp; - lip_sync_drift_.Update( - now, fresh_sync_reference - lip_sync_reference_time_); - } - - // Another frame is complete from a non-duplicate packet. Attempt to emit - // more frames to satisfy enqueued requests. - if (complete) - EmitAvailableEncodedFrames(); -} - -void FrameReceiver::CastFeedback(const RtcpCastMessage& cast_message) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - - base::TimeTicks now = cast_environment_->Clock()->NowTicks(); - RtpTimeTicks rtp_timestamp = - frame_id_to_rtp_timestamp_[cast_message.ack_frame_id.lower_8_bits()]; - - std::unique_ptr<FrameEvent> ack_sent_event(new FrameEvent()); - ack_sent_event->timestamp = now; - ack_sent_event->type = FRAME_ACK_SENT; - ack_sent_event->media_type = event_media_type_; - ack_sent_event->rtp_timestamp = rtp_timestamp; - ack_sent_event->frame_id = cast_message.ack_frame_id; - cast_environment_->logger()->DispatchFrameEvent(std::move(ack_sent_event)); - - ReceiverRtcpEventSubscriber::RtcpEvents rtcp_events; - event_subscriber_.GetRtcpEventsWithRedundancy(&rtcp_events); - SendRtcpReport(rtcp_.local_ssrc(), rtcp_.remote_ssrc(), - CreateRtcpTimeData(now), &cast_message, nullptr, - target_playout_delay_, &rtcp_events, nullptr); -} - -void FrameReceiver::EmitAvailableEncodedFrames() { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - - while (!frame_request_queue_.empty()) { - // Attempt to peek at the next completed frame from the |framer_|. - // TODO(miu): We should only be peeking at the metadata, and not copying the - // payload yet! Or, at least, peek using a StringPiece instead of a copy. - std::unique_ptr<EncodedFrame> encoded_frame(new EncodedFrame()); - bool is_consecutively_next_frame = false; - bool have_multiple_complete_frames = false; - if (!framer_.GetEncodedFrame(encoded_frame.get(), - &is_consecutively_next_frame, - &have_multiple_complete_frames)) { - VLOG(1) << "Wait for more packets to produce a completed frame."; - return; // ProcessParsedPacket() will invoke this method in the future. - } - - const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); - const base::TimeTicks playout_time = GetPlayoutTime(*encoded_frame); - - // If we have multiple decodable frames, and the current frame is - // too old, then skip it and decode the next frame instead. - if (have_multiple_complete_frames && now > playout_time) { - framer_.ReleaseFrame(encoded_frame->frame_id); - continue; - } - - // If |framer_| has a frame ready that is out of sequence, examine the - // playout time to determine whether it's acceptable to continue, thereby - // skipping one or more frames. Skip if the missing frame wouldn't complete - // playing before the start of playback of the available frame. - if (!is_consecutively_next_frame) { - // This assumes that decoding takes as long as playing, which might - // not be true. - const base::TimeTicks earliest_possible_end_time_of_missing_frame = - now + expected_frame_duration_ * 2; - if (earliest_possible_end_time_of_missing_frame < playout_time) { - VLOG(1) << "Wait for next consecutive frame instead of skipping."; - if (!is_waiting_for_consecutive_frame_) { - is_waiting_for_consecutive_frame_ = true; - cast_environment_->PostDelayedTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce( - &FrameReceiver::EmitAvailableEncodedFramesAfterWaiting, - AsWeakPtr()), - playout_time - now); - } - return; - } - } - - // At this point, we have the complete next frame, or a decodable - // frame from somewhere later in the stream, AND we have given up - // on waiting for any frames in between, so now we can ACK the frame. - framer_.AckFrame(encoded_frame->frame_id); - - // Decrypt the payload data in the frame, if crypto is being used. - if (decryptor_.is_activated()) { - std::string decrypted_data; - if (!decryptor_.Decrypt(encoded_frame->frame_id, - encoded_frame->data, - &decrypted_data)) { - // Decryption failed. Give up on this frame. - framer_.ReleaseFrame(encoded_frame->frame_id); - continue; - } - encoded_frame->data.swap(decrypted_data); - } - - // At this point, we have a decrypted EncodedFrame ready to be emitted. - encoded_frame->reference_time = playout_time; - framer_.ReleaseFrame(encoded_frame->frame_id); - if (encoded_frame->new_playout_delay_ms) { - target_playout_delay_ = base::TimeDelta::FromMilliseconds( - encoded_frame->new_playout_delay_ms); - } - cast_environment_->PostTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(&FrameReceiver::EmitOneFrame, AsWeakPtr(), - std::move(*frame_request_queue_.begin()), - std::move(encoded_frame))); - frame_request_queue_.pop_front(); - } -} - -void FrameReceiver::EmitAvailableEncodedFramesAfterWaiting() { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - DCHECK(is_waiting_for_consecutive_frame_); - is_waiting_for_consecutive_frame_ = false; - EmitAvailableEncodedFrames(); -} - -void FrameReceiver::EmitOneFrame( - ReceiveEncodedFrameCallback callback, - std::unique_ptr<EncodedFrame> encoded_frame) const { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - if (!callback.is_null()) - std::move(callback).Run(std::move(encoded_frame)); -} - -base::TimeTicks FrameReceiver::GetPlayoutTime(const EncodedFrame& frame) const { - base::TimeDelta target_playout_delay = target_playout_delay_; - if (frame.new_playout_delay_ms) { - target_playout_delay = base::TimeDelta::FromMilliseconds( - frame.new_playout_delay_ms); - } - return lip_sync_reference_time_ + lip_sync_drift_.Current() + - (frame.rtp_timestamp - lip_sync_rtp_timestamp_) - .ToTimeDelta(rtp_timebase_) + - target_playout_delay; -} - -void FrameReceiver::ScheduleNextCastMessage() { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - base::TimeTicks send_time; - framer_.TimeToSendNextCastMessage(&send_time); - base::TimeDelta time_to_send = - send_time - cast_environment_->Clock()->NowTicks(); - time_to_send = std::max( - time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); - cast_environment_->PostDelayedTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(&FrameReceiver::SendNextCastMessage, AsWeakPtr()), - time_to_send); -} - -void FrameReceiver::SendNextCastMessage() { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - framer_.SendCastMessage(); // Will only send a message if it is time. - ScheduleNextCastMessage(); -} - -void FrameReceiver::ScheduleNextRtcpReport() { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - - cast_environment_->PostDelayedTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(&FrameReceiver::SendNextRtcpReport, AsWeakPtr()), - base::TimeDelta::FromMilliseconds(kRtcpReportIntervalMs)); -} - -void FrameReceiver::SendNextRtcpReport() { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); - RtpReceiverStatistics stats = stats_.GetStatistics(); - SendRtcpReport(rtcp_.local_ssrc(), rtcp_.remote_ssrc(), - CreateRtcpTimeData(now), nullptr, nullptr, base::TimeDelta(), - nullptr, &stats); - ScheduleNextRtcpReport(); -} - -void FrameReceiver::SendRtcpReport( - uint32_t rtp_receiver_ssrc, - uint32_t rtp_sender_ssrc, - const RtcpTimeData& time_data, - const RtcpCastMessage* cast_message, - const RtcpPliMessage* pli_message, - base::TimeDelta target_delay, - const ReceiverRtcpEventSubscriber::RtcpEvents* rtcp_events, - const RtpReceiverStatistics* rtp_receiver_statistics) { - transport_->InitializeRtpReceiverRtcpBuilder(rtp_receiver_ssrc, time_data); - RtcpReportBlock report_block; - if (rtp_receiver_statistics) { - report_block.remote_ssrc = 0; // Not needed to set send side. - report_block.media_ssrc = - rtp_sender_ssrc; // SSRC of the RTP packet sender. - report_block.fraction_lost = rtp_receiver_statistics->fraction_lost; - report_block.cumulative_lost = rtp_receiver_statistics->cumulative_lost; - report_block.extended_high_sequence_number = - rtp_receiver_statistics->extended_high_sequence_number; - report_block.jitter = rtp_receiver_statistics->jitter; - report_block.last_sr = rtcp_.last_report_truncated_ntp(); - base::TimeTicks last_report_received_time = - rtcp_.time_last_report_received(); - if (!last_report_received_time.is_null()) { - uint32_t delay_seconds = 0; - uint32_t delay_fraction = 0; - base::TimeDelta delta = time_data.timestamp - last_report_received_time; - ConvertTimeToFractions(delta.InMicroseconds(), &delay_seconds, - &delay_fraction); - report_block.delay_since_last_sr = - ConvertToNtpDiff(delay_seconds, delay_fraction); - } else { - report_block.delay_since_last_sr = 0; - } - transport_->AddRtpReceiverReport(report_block); - } - if (cast_message) - transport_->AddCastFeedback(*cast_message, target_delay); - if (pli_message) - transport_->AddPli(*pli_message); - if (rtcp_events) - transport_->AddRtcpEvents(*rtcp_events); - transport_->SendRtcpFromRtpReceiver(); -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/receiver/frame_receiver.h b/chromium/media/cast/receiver/frame_receiver.h deleted file mode 100644 index c5d2cb4f27e..00000000000 --- a/chromium/media/cast/receiver/frame_receiver.h +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2014 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. - -#ifndef MEDIA_CAST_RECEIVER_FRAME_RECEIVER_H_ -#define MEDIA_CAST_RECEIVER_FRAME_RECEIVER_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <list> -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" -#include "media/cast/cast_receiver.h" -#include "media/cast/common/clock_drift_smoother.h" -#include "media/cast/common/rtp_time.h" -#include "media/cast/common/transport_encryption_handler.h" -#include "media/cast/logging/logging_defines.h" -#include "media/cast/net/rtcp/receiver_rtcp_event_subscriber.h" -#include "media/cast/net/rtcp/receiver_rtcp_session.h" -#include "media/cast/net/rtp/framer.h" -#include "media/cast/net/rtp/receiver_stats.h" -#include "media/cast/net/rtp/rtp_defines.h" -#include "media/cast/net/rtp/rtp_parser.h" - -namespace media { -namespace cast { - -class CastEnvironment; - -// The following callback delivers encoded frame data and metadata. The client -// should examine the |frame_id| field to determine whether any frames have been -// dropped (i.e., frame_id should be incrementing by one each time). Note: A -// nullptr can be returned on error. -using ReceiveEncodedFrameCallback = - base::OnceCallback<void(std::unique_ptr<EncodedFrame>)>; - -// FrameReceiver receives packets out-of-order while clients make requests for -// complete frames in-order. (A frame consists of one or more packets.) -// -// FrameReceiver also includes logic for computing the playout time for each -// frame, accounting for a constant targeted playout delay. The purpose of the -// playout delay is to provide a fixed window of time between the capture event -// on the sender and the playout on the receiver. This is important because -// each step of the pipeline (i.e., encode frame, then transmit/retransmit from -// the sender, then receive and re-order packets on the receiver, then decode -// frame) can vary in duration and is typically very hard to predict. -// -// Each request for a frame includes a callback which FrameReceiver guarantees -// will be called at some point in the future unless the FrameReceiver is -// destroyed. Clients should generally limit the number of outstanding requests -// (perhaps to just one or two). -// -// This class is not thread safe. Should only be called from the Main cast -// thread. -class FrameReceiver final : public RtpPayloadFeedback { - public: - FrameReceiver(const scoped_refptr<CastEnvironment>& cast_environment, - const FrameReceiverConfig& config, - EventMediaType event_media_type, - CastTransport* const transport); - - ~FrameReceiver() final; - - // Request an encoded frame. - // - // The given |callback| is guaranteed to be run at some point in the future, - // except for those requests still enqueued at destruction time. - void RequestEncodedFrame(ReceiveEncodedFrameCallback callback); - - // Called to deliver another packet, possibly a duplicate, and possibly - // out-of-order. Returns true if the parsing of the packet succeeded. - bool ProcessPacket(std::unique_ptr<Packet> packet); - - base::WeakPtr<FrameReceiver> AsWeakPtr(); - - protected: - friend class FrameReceiverTest; // Invokes ProcessParsedPacket(). - - void ProcessParsedPacket(const RtpCastHeader& rtp_header, - const uint8_t* payload_data, - size_t payload_size); - - // RtpPayloadFeedback implementation. - void CastFeedback(const RtcpCastMessage& cast_message) final; - - private: - // Processes ready-to-consume packets from |framer_|, decrypting each packet's - // payload data, and then running the enqueued callbacks in order (one for - // each packet). This method may post a delayed task to re-invoke itself in - // the future to wait for missing/incomplete frames. - void EmitAvailableEncodedFrames(); - - // Clears the |is_waiting_for_consecutive_frame_| flag and invokes - // EmitAvailableEncodedFrames(). - void EmitAvailableEncodedFramesAfterWaiting(); - - // Helper that runs |callback|, passing ownership of |encoded_frame| to it. - // This method is used by EmitAvailableEncodedFrames() to return to the event - // loop, but make sure that FrameReceiver is still alive before the callback - // is run. - void EmitOneFrame(ReceiveEncodedFrameCallback callback, - std::unique_ptr<EncodedFrame> encoded_frame) const; - - // Computes the playout time for a frame with the given |rtp_timestamp|. - // Because lip-sync info is refreshed regularly, calling this method with the - // same argument may return different results. - base::TimeTicks GetPlayoutTime(const EncodedFrame& frame) const; - - // Schedule timing for the next cast message. - void ScheduleNextCastMessage(); - - // Schedule timing for the next RTCP report. - void ScheduleNextRtcpReport(); - - // Actually send the next cast message. - void SendNextCastMessage(); - - // Actually send the next RTCP report. - void SendNextRtcpReport(); - - // Interface to send RTCP reports. - // |cast_message|, |rtcp_events| and |rtp_receiver_statistics| are optional; - // if |cast_message| is provided the RTCP receiver report will contain a Cast - // ACK/NACK feedback message; |target_delay| is sent together with - // |cast_message|. If |rtcp_events| is provided the RTCP receiver report will - // include event log messages - void SendRtcpReport( - uint32_t rtp_receiver_ssrc, - uint32_t rtp_sender_ssrc, - const RtcpTimeData& time_data, - const RtcpCastMessage* cast_message, - const RtcpPliMessage* pli_message, - base::TimeDelta target_delay, - const ReceiverRtcpEventSubscriber::RtcpEvents* rtcp_events, - const RtpReceiverStatistics* rtp_receiver_statistics); - - const scoped_refptr<CastEnvironment> cast_environment_; - - // Transport used to send data back. - CastTransport* const transport_; - - // Deserializes a packet into a RtpHeader + payload bytes. - RtpParser packet_parser_; - - // Accumulates packet statistics, including packet loss, counts, and jitter. - ReceiverStats stats_; - - // Partitions logged events by the type of media passing through. - EventMediaType event_media_type_; - - // Subscribes to raw events. - // Processes raw events to be sent over to the cast sender via RTCP. - ReceiverRtcpEventSubscriber event_subscriber_; - - // RTP timebase: The number of RTP units advanced per one second. - const int rtp_timebase_; - - // The total amount of time between a frame's capture/recording on the sender - // and its playback on the receiver (i.e., shown to a user). This is fixed as - // a value large enough to give the system sufficient time to encode, - // transmit/retransmit, receive, decode, and render; given its run-time - // environment (sender/receiver hardware performance, network conditions, - // etc.). - base::TimeDelta target_playout_delay_; - - // Hack: This is used in logic that determines whether to skip frames. - // TODO(miu): Revisit this. Logic needs to also account for expected decode - // time. - const base::TimeDelta expected_frame_duration_; - - // Set to false initially, then set to true after scheduling the periodic - // sending of reports back to the sender. Reports are first scheduled just - // after receiving a first packet (since the first packet identifies the - // sender for the remainder of the session). - bool reports_are_scheduled_; - - // Assembles packets into frames, providing this receiver with complete, - // decodable EncodedFrames. - Framer framer_; - - // Manages sending/receiving of RTCP packets, including sender/receiver - // reports. - ReceiverRtcpSession rtcp_; - - // Decrypts encrypted frames. - TransportEncryptionHandler decryptor_; - - // Outstanding callbacks to run to deliver on client requests for frames. - std::list<ReceiveEncodedFrameCallback> frame_request_queue_; - - // True while there's an outstanding task to re-invoke - // EmitAvailableEncodedFrames(). - bool is_waiting_for_consecutive_frame_; - - // This mapping allows us to log FRAME_ACK_SENT as a frame event. In addition - // it allows the event to be transmitted via RTCP. The index into this ring - // buffer is the lower 8 bits of the FrameId. - RtpTimeTicks frame_id_to_rtp_timestamp_[256]; - - // Lip-sync values used to compute the playout time of each frame from its RTP - // timestamp. These are updated each time the first packet of a frame is - // received. - RtpTimeTicks lip_sync_rtp_timestamp_; - base::TimeTicks lip_sync_reference_time_; - ClockDriftSmoother lip_sync_drift_; - - // NOTE: Weak pointers must be invalidated before all other member variables. - base::WeakPtrFactory<FrameReceiver> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(FrameReceiver); -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_RECEIVER_FRAME_RECEIVER_H_ diff --git a/chromium/media/cast/receiver/frame_receiver_unittest.cc b/chromium/media/cast/receiver/frame_receiver_unittest.cc deleted file mode 100644 index 9e8bdbed4d7..00000000000 --- a/chromium/media/cast/receiver/frame_receiver_unittest.cc +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 2014 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/cast/receiver/frame_receiver.h" - -#include <stddef.h> -#include <stdint.h> - -#include <memory> -#include <utility> - -#include "base/bind.h" -#include "base/containers/circular_deque.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/test/simple_test_tick_clock.h" -#include "media/base/fake_single_thread_task_runner.h" -#include "media/cast/cast_environment.h" -#include "media/cast/logging/simple_event_subscriber.h" -#include "media/cast/net/cast_transport_impl.h" -#include "media/cast/net/rtcp/rtcp_utility.h" -#include "media/cast/net/rtcp/test_rtcp_packet_builder.h" -#include "media/cast/test/mock_cast_transport.h" -#include "media/cast/test/utility/default_config.h" -#include "testing/gmock/include/gmock/gmock.h" - -using ::testing::_; - -namespace media { -namespace cast { - -namespace { - -const int kPacketSize = 1500; -const int kPlayoutDelayMillis = 100; - -FrameId GetFirstTestFrameId() { - return FrameId::first() + 1234; -} - -class FakeFrameClient { - public: - FakeFrameClient() : num_called_(0) {} - virtual ~FakeFrameClient() = default; - - void AddExpectedResult(FrameId expected_frame_id, - const base::TimeTicks& expected_playout_time) { - expected_results_.push_back( - std::make_pair(expected_frame_id, expected_playout_time)); - } - - void DeliverEncodedFrame(std::unique_ptr<EncodedFrame> frame) { - SCOPED_TRACE(::testing::Message() << "num_called_ is " << num_called_); - ASSERT_TRUE(frame) - << "If at shutdown: There were unsatisfied requests enqueued."; - ASSERT_FALSE(expected_results_.empty()); - EXPECT_EQ(expected_results_.front().first, frame->frame_id); - EXPECT_EQ(expected_results_.front().second, frame->reference_time); - expected_results_.pop_front(); - ++num_called_; - } - - int number_times_called() const { return num_called_; } - - private: - base::circular_deque<std::pair<FrameId, base::TimeTicks>> expected_results_; - int num_called_; - - DISALLOW_COPY_AND_ASSIGN(FakeFrameClient); -}; -} // namespace - -class FrameReceiverTest : public ::testing::Test { - protected: - FrameReceiverTest() { - testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks()); - start_time_ = testing_clock_.NowTicks(); - task_runner_ = new FakeSingleThreadTaskRunner(&testing_clock_); - - cast_environment_ = new CastEnvironment(&testing_clock_, task_runner_, - task_runner_, task_runner_); - } - - ~FrameReceiverTest() override = default; - - void SetUp() final { - payload_.assign(kPacketSize, 0); - - // Always start with a key frame. - rtp_header_.is_key_frame = true; - rtp_header_.frame_id = GetFirstTestFrameId(); - rtp_header_.packet_id = 0; - rtp_header_.max_packet_id = 0; - rtp_header_.reference_frame_id = rtp_header_.frame_id; - rtp_header_.rtp_timestamp = RtpTimeTicks(); - } - - void CreateFrameReceiverOfAudio() { - config_ = GetDefaultAudioReceiverConfig(); - config_.rtp_max_delay_ms = kPlayoutDelayMillis; - - receiver_ = std::make_unique<FrameReceiver>(cast_environment_, config_, - AUDIO_EVENT, &mock_transport_); - } - - void CreateFrameReceiverOfVideo() { - config_ = GetDefaultVideoReceiverConfig(); - config_.rtp_max_delay_ms = kPlayoutDelayMillis; - // Note: Frame rate must divide 1000 without remainder so the test code - // doesn't have to account for rounding errors. - config_.target_frame_rate = 25; - - receiver_ = std::make_unique<FrameReceiver>(cast_environment_, config_, - VIDEO_EVENT, &mock_transport_); - } - - void FeedOneFrameIntoReceiver() { - // Note: For testing purposes, a frame consists of only a single packet. - receiver_->ProcessParsedPacket( - rtp_header_, &payload_[0], payload_.size()); - } - - void FeedLipSyncInfoIntoReceiver() { - const base::TimeTicks now = testing_clock_.NowTicks(); - const RtpTimeTicks rtp_timestamp = - RtpTimeTicks::FromTimeDelta(now - start_time_, config_.rtp_timebase); - CHECK_LE(RtpTimeTicks(), rtp_timestamp); - uint32_t ntp_seconds; - uint32_t ntp_fraction; - ConvertTimeTicksToNtp(now, &ntp_seconds, &ntp_fraction); - TestRtcpPacketBuilder rtcp_packet; - rtcp_packet.AddSrWithNtp(config_.sender_ssrc, ntp_seconds, ntp_fraction, - rtp_timestamp.lower_32_bits()); - ASSERT_TRUE(receiver_->ProcessPacket(rtcp_packet.GetPacket())); - } - - FrameReceiverConfig config_; - std::vector<uint8_t> payload_; - RtpCastHeader rtp_header_; - base::SimpleTestTickClock testing_clock_; - base::TimeTicks start_time_; - MockCastTransport mock_transport_; - scoped_refptr<FakeSingleThreadTaskRunner> task_runner_; - scoped_refptr<CastEnvironment> cast_environment_; - FakeFrameClient frame_client_; - - // Important for the FrameReceiver to be declared last, since its dependencies - // must remain alive until after its destruction. - std::unique_ptr<FrameReceiver> receiver_; - - private: - DISALLOW_COPY_AND_ASSIGN(FrameReceiverTest); -}; - -TEST_F(FrameReceiverTest, RejectsUnparsablePackets) { - EXPECT_CALL(mock_transport_, AddValidRtpReceiver(_, _)) - .WillRepeatedly(testing::Return()); - - CreateFrameReceiverOfVideo(); - - SimpleEventSubscriber event_subscriber; - cast_environment_->logger()->Subscribe(&event_subscriber); - - const bool success = - receiver_->ProcessPacket(std::make_unique<Packet>(kPacketSize, 0xff)); - EXPECT_FALSE(success); - - // Confirm no log events. - std::vector<FrameEvent> frame_events; - event_subscriber.GetFrameEventsAndReset(&frame_events); - EXPECT_TRUE(frame_events.empty()); - cast_environment_->logger()->Unsubscribe(&event_subscriber); -} - -TEST_F(FrameReceiverTest, ReceivesOneFrame) { - EXPECT_CALL(mock_transport_, AddValidRtpReceiver(_, _)) - .WillRepeatedly(testing::Return()); - - CreateFrameReceiverOfAudio(); - - SimpleEventSubscriber event_subscriber; - cast_environment_->logger()->Subscribe(&event_subscriber); - - EXPECT_CALL(mock_transport_, InitializeRtpReceiverRtcpBuilder(_, _)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddCastFeedback(_, _)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddPli(_)).WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddRtcpEvents(_)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, SendRtcpFromRtpReceiver()) - .WillRepeatedly(testing::Return()); - - FeedLipSyncInfoIntoReceiver(); - task_runner_->RunTasks(); - - // Enqueue a request for a frame. - receiver_->RequestEncodedFrame(base::BindOnce( - &FakeFrameClient::DeliverEncodedFrame, base::Unretained(&frame_client_))); - - // The request should not be satisfied since no packets have been received. - task_runner_->RunTasks(); - EXPECT_EQ(0, frame_client_.number_times_called()); - - // Deliver one frame to the receiver and expect to get one frame back. - const base::TimeDelta target_playout_delay = - base::TimeDelta::FromMilliseconds(kPlayoutDelayMillis); - frame_client_.AddExpectedResult( - GetFirstTestFrameId(), testing_clock_.NowTicks() + target_playout_delay); - FeedOneFrameIntoReceiver(); - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Was the frame logged? - std::vector<FrameEvent> frame_events; - event_subscriber.GetFrameEventsAndReset(&frame_events); - ASSERT_TRUE(!frame_events.empty()); - EXPECT_EQ(FRAME_ACK_SENT, frame_events.begin()->type); - EXPECT_EQ(AUDIO_EVENT, frame_events.begin()->media_type); - EXPECT_EQ(rtp_header_.frame_id, frame_events.begin()->frame_id); - EXPECT_EQ(rtp_header_.rtp_timestamp, frame_events.begin()->rtp_timestamp); - cast_environment_->logger()->Unsubscribe(&event_subscriber); -} - -TEST_F(FrameReceiverTest, ReceivesFramesSkippingWhenAppropriate) { - EXPECT_CALL(mock_transport_, AddValidRtpReceiver(_, _)) - .WillRepeatedly(testing::Return()); - - CreateFrameReceiverOfAudio(); - - SimpleEventSubscriber event_subscriber; - cast_environment_->logger()->Subscribe(&event_subscriber); - - EXPECT_CALL(mock_transport_, InitializeRtpReceiverRtcpBuilder(_, _)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddCastFeedback(_, _)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddPli(_)).WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddRtcpEvents(_)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, SendRtcpFromRtpReceiver()) - .WillRepeatedly(testing::Return()); - - const base::TimeDelta time_advance_per_frame = - base::TimeDelta::FromSeconds(1) / config_.target_frame_rate; - const RtpTimeDelta rtp_advance_per_frame = - RtpTimeDelta::FromTimeDelta(time_advance_per_frame, config_.rtp_timebase); - - // Feed and process lip sync in receiver. - FeedLipSyncInfoIntoReceiver(); - task_runner_->RunTasks(); - const base::TimeTicks first_frame_capture_time = testing_clock_.NowTicks(); - - // Enqueue a request for a frame. - receiver_->RequestEncodedFrame(base::BindOnce( - &FakeFrameClient::DeliverEncodedFrame, base::Unretained(&frame_client_))); - task_runner_->RunTasks(); - EXPECT_EQ(0, frame_client_.number_times_called()); - - // Receive one frame and expect to see the first request satisfied. - const base::TimeDelta target_playout_delay = - base::TimeDelta::FromMilliseconds(kPlayoutDelayMillis); - frame_client_.AddExpectedResult( - GetFirstTestFrameId(), first_frame_capture_time + target_playout_delay); - rtp_header_.rtp_timestamp = RtpTimeTicks(); - FeedOneFrameIntoReceiver(); // Frame 1 - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Enqueue a second request for a frame, but it should not be fulfilled yet. - receiver_->RequestEncodedFrame(base::BindOnce( - &FakeFrameClient::DeliverEncodedFrame, base::Unretained(&frame_client_))); - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Receive one frame out-of-order: Make sure that we are not continuous and - // that the RTP timestamp represents a time in the future. - rtp_header_.frame_id = GetFirstTestFrameId() + 2; // "Frame 3" - rtp_header_.reference_frame_id = rtp_header_.frame_id; - rtp_header_.rtp_timestamp += rtp_advance_per_frame * 2; - frame_client_.AddExpectedResult(rtp_header_.frame_id, - first_frame_capture_time + - 2 * time_advance_per_frame + - target_playout_delay); - FeedOneFrameIntoReceiver(); // Frame 3 - - // Frame 2 should not come out at this point in time. - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Enqueue a third request for a frame. - receiver_->RequestEncodedFrame(base::BindOnce( - &FakeFrameClient::DeliverEncodedFrame, base::Unretained(&frame_client_))); - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Now, advance time forward such that the receiver is convinced it should - // skip Frame 2. Frame 3 is emitted (to satisfy the second request) because a - // decision was made to skip over the no-show Frame 2. - testing_clock_.Advance(2 * time_advance_per_frame + target_playout_delay); - task_runner_->RunTasks(); - EXPECT_EQ(2, frame_client_.number_times_called()); - - // Receive Frame 4 and expect it to fulfill the third request immediately. - rtp_header_.frame_id = GetFirstTestFrameId() + 3; // "Frame 4" - rtp_header_.reference_frame_id = rtp_header_.frame_id; - rtp_header_.rtp_timestamp += rtp_advance_per_frame; - frame_client_.AddExpectedResult(rtp_header_.frame_id, - first_frame_capture_time + - 3 * time_advance_per_frame + - target_playout_delay); - FeedOneFrameIntoReceiver(); // Frame 4 - task_runner_->RunTasks(); - EXPECT_EQ(3, frame_client_.number_times_called()); - - // Move forward to the playout time of an unreceived Frame 5. Expect no - // additional frames were emitted. - testing_clock_.Advance(3 * time_advance_per_frame); - task_runner_->RunTasks(); - EXPECT_EQ(3, frame_client_.number_times_called()); - - // Were only non-skipped frames logged? - std::vector<FrameEvent> frame_events; - event_subscriber.GetFrameEventsAndReset(&frame_events); - ASSERT_TRUE(!frame_events.empty()); - for (size_t i = 0; i < frame_events.size(); ++i) { - EXPECT_EQ(FRAME_ACK_SENT, frame_events[i].type); - EXPECT_EQ(AUDIO_EVENT, frame_events[i].media_type); - EXPECT_LE(GetFirstTestFrameId(), frame_events[i].frame_id); - EXPECT_GE(GetFirstTestFrameId() + 4, frame_events[i].frame_id); - const int frame_offset = frame_events[i].frame_id - GetFirstTestFrameId(); - EXPECT_NE(frame_offset, 1); // Frame 2 never received. - EXPECT_EQ(RtpTimeTicks() + (rtp_advance_per_frame * frame_offset), - frame_events[i].rtp_timestamp); - } - cast_environment_->logger()->Unsubscribe(&event_subscriber); -} - -TEST_F(FrameReceiverTest, ReceivesFramesRefusingToSkipAny) { - EXPECT_CALL(mock_transport_, AddValidRtpReceiver(_, _)) - .WillRepeatedly(testing::Return()); - - CreateFrameReceiverOfVideo(); - - SimpleEventSubscriber event_subscriber; - cast_environment_->logger()->Subscribe(&event_subscriber); - - EXPECT_CALL(mock_transport_, InitializeRtpReceiverRtcpBuilder(_, _)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddCastFeedback(_, _)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddPli(_)).WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, AddRtcpEvents(_)) - .WillRepeatedly(testing::Return()); - EXPECT_CALL(mock_transport_, SendRtcpFromRtpReceiver()) - .WillRepeatedly(testing::Return()); - - const base::TimeDelta time_advance_per_frame = - base::TimeDelta::FromSeconds(1) / config_.target_frame_rate; - const RtpTimeDelta rtp_advance_per_frame = - RtpTimeDelta::FromTimeDelta(time_advance_per_frame, config_.rtp_timebase); - - // Feed and process lip sync in receiver. - FeedLipSyncInfoIntoReceiver(); - task_runner_->RunTasks(); - const base::TimeTicks first_frame_capture_time = testing_clock_.NowTicks(); - - // Enqueue a request for a frame. - receiver_->RequestEncodedFrame(base::BindOnce( - &FakeFrameClient::DeliverEncodedFrame, base::Unretained(&frame_client_))); - task_runner_->RunTasks(); - EXPECT_EQ(0, frame_client_.number_times_called()); - - // Receive one frame and expect to see the first request satisfied. - const base::TimeDelta target_playout_delay = - base::TimeDelta::FromMilliseconds(kPlayoutDelayMillis); - frame_client_.AddExpectedResult( - GetFirstTestFrameId(), first_frame_capture_time + target_playout_delay); - rtp_header_.rtp_timestamp = RtpTimeTicks(); - FeedOneFrameIntoReceiver(); // Frame 1 - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Enqueue a second request for a frame, but it should not be fulfilled yet. - receiver_->RequestEncodedFrame(base::BindOnce( - &FakeFrameClient::DeliverEncodedFrame, base::Unretained(&frame_client_))); - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Receive one frame out-of-order: Make sure that we are not continuous and - // that the RTP timestamp represents a time in the future. - rtp_header_.is_key_frame = false; - rtp_header_.frame_id = GetFirstTestFrameId() + 2; // "Frame 3" - rtp_header_.reference_frame_id = GetFirstTestFrameId() + 1; // "Frame 2" - rtp_header_.rtp_timestamp += rtp_advance_per_frame * 2; - FeedOneFrameIntoReceiver(); // Frame 3 - - // Frame 2 should not come out at this point in time. - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Enqueue a third request for a frame. - receiver_->RequestEncodedFrame(base::BindOnce( - &FakeFrameClient::DeliverEncodedFrame, base::Unretained(&frame_client_))); - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Now, advance time forward such that Frame 2 is now too late for playback. - // Regardless, the receiver must NOT emit Frame 3 yet because it is not - // allowed to skip frames when dependencies are not satisfied. In other - // words, Frame 3 is not decodable without Frame 2. - testing_clock_.Advance(2 * time_advance_per_frame + target_playout_delay); - task_runner_->RunTasks(); - EXPECT_EQ(1, frame_client_.number_times_called()); - - // Now receive Frame 2 and expect both the second and third requests to be - // fulfilled immediately. - frame_client_.AddExpectedResult(GetFirstTestFrameId() + 1, // "Frame 2" - first_frame_capture_time + - 1 * time_advance_per_frame + - target_playout_delay); - frame_client_.AddExpectedResult(GetFirstTestFrameId() + 2, // "Frame 3" - first_frame_capture_time + - 2 * time_advance_per_frame + - target_playout_delay); - --rtp_header_.frame_id; // "Frame 2" - --rtp_header_.reference_frame_id; // "Frame 1" - rtp_header_.rtp_timestamp -= rtp_advance_per_frame; - FeedOneFrameIntoReceiver(); // Frame 2 - task_runner_->RunTasks(); - EXPECT_EQ(3, frame_client_.number_times_called()); - - // Move forward to the playout time of an unreceived Frame 5. Expect no - // additional frames were emitted. - testing_clock_.Advance(3 * time_advance_per_frame); - task_runner_->RunTasks(); - EXPECT_EQ(3, frame_client_.number_times_called()); - - // Sanity-check logging results. - std::vector<FrameEvent> frame_events; - event_subscriber.GetFrameEventsAndReset(&frame_events); - ASSERT_TRUE(!frame_events.empty()); - for (size_t i = 0; i < frame_events.size(); ++i) { - EXPECT_EQ(FRAME_ACK_SENT, frame_events[i].type); - EXPECT_EQ(VIDEO_EVENT, frame_events[i].media_type); - EXPECT_LE(GetFirstTestFrameId(), frame_events[i].frame_id); - EXPECT_GE(GetFirstTestFrameId() + 3, frame_events[i].frame_id); - const int frame_offset = frame_events[i].frame_id - GetFirstTestFrameId(); - EXPECT_EQ(RtpTimeTicks() + (rtp_advance_per_frame * frame_offset), - frame_events[i].rtp_timestamp); - } - cast_environment_->logger()->Unsubscribe(&event_subscriber); -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/receiver/video_decoder.cc b/chromium/media/cast/receiver/video_decoder.cc deleted file mode 100644 index ecf20f40a04..00000000000 --- a/chromium/media/cast/receiver/video_decoder.cc +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2014 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/cast/receiver/video_decoder.h" - -#include <stdint.h> -#include <utility> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/json/json_reader.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/values.h" -#include "media/base/video_frame_pool.h" -#include "media/base/video_util.h" -#include "media/cast/cast_environment.h" -#include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" -#include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" -#include "third_party/libyuv/include/libyuv/convert.h" -#include "ui/gfx/geometry/size.h" - -namespace media { -namespace cast { - -// Base class that handles the common problem of detecting dropped frames, and -// then invoking the Decode() method implemented by the subclasses to convert -// the encoded payload data into a usable video frame. -class VideoDecoder::ImplBase - : public base::RefCountedThreadSafe<VideoDecoder::ImplBase> { - public: - ImplBase(const scoped_refptr<CastEnvironment>& cast_environment, Codec codec) - : cast_environment_(cast_environment), - codec_(codec), - operational_status_(STATUS_UNINITIALIZED) {} - - OperationalStatus InitializationResult() const { - return operational_status_; - } - - void DecodeFrame(std::unique_ptr<EncodedFrame> encoded_frame, - const DecodeFrameCallback& callback) { - DCHECK_EQ(operational_status_, STATUS_INITIALIZED); - - bool is_continuous = true; - DCHECK(!encoded_frame->frame_id.is_null()); - if (!last_frame_id_.is_null()) { - if (encoded_frame->frame_id > (last_frame_id_ + 1)) { - RecoverBecauseFramesWereDropped(); - is_continuous = false; - } - } - last_frame_id_ = encoded_frame->frame_id; - - const scoped_refptr<VideoFrame> decoded_frame = Decode( - encoded_frame->mutable_bytes(), - static_cast<int>(encoded_frame->data.size())); - if (!decoded_frame) { - VLOG(2) << "Decoding of frame " << encoded_frame->frame_id << " failed."; - cast_environment_->PostTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(callback, decoded_frame, false)); - return; - } - decoded_frame->set_timestamp( - encoded_frame->rtp_timestamp.ToTimeDelta(kVideoFrequency)); - - std::unique_ptr<FrameEvent> decode_event(new FrameEvent()); - decode_event->timestamp = cast_environment_->Clock()->NowTicks(); - decode_event->type = FRAME_DECODED; - decode_event->media_type = VIDEO_EVENT; - decode_event->rtp_timestamp = encoded_frame->rtp_timestamp; - decode_event->frame_id = encoded_frame->frame_id; - cast_environment_->logger()->DispatchFrameEvent(std::move(decode_event)); - - cast_environment_->PostTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(callback, decoded_frame, is_continuous)); - } - - protected: - friend class base::RefCountedThreadSafe<ImplBase>; - virtual ~ImplBase() = default; - - virtual void RecoverBecauseFramesWereDropped() {} - - // Note: Implementation of Decode() is allowed to mutate |data|. - virtual scoped_refptr<VideoFrame> Decode(uint8_t* data, int len) = 0; - - const scoped_refptr<CastEnvironment> cast_environment_; - const Codec codec_; - - // Subclass' ctor is expected to set this to STATUS_INITIALIZED. - OperationalStatus operational_status_; - - // Pool of VideoFrames to decode incoming frames into. - media::VideoFramePool video_frame_pool_; - - private: - FrameId last_frame_id_; - - DISALLOW_COPY_AND_ASSIGN(ImplBase); -}; - -class VideoDecoder::Vp8Impl final : public VideoDecoder::ImplBase { - public: - explicit Vp8Impl(const scoped_refptr<CastEnvironment>& cast_environment) - : ImplBase(cast_environment, CODEC_VIDEO_VP8) { - if (ImplBase::operational_status_ != STATUS_UNINITIALIZED) - return; - - vpx_codec_dec_cfg_t cfg = {0}; - // TODO(miu): Revisit this for typical multi-core desktop use case. This - // feels like it should be 4 or 8. - cfg.threads = 1; - - DCHECK(vpx_codec_get_caps(vpx_codec_vp8_dx()) & VPX_CODEC_CAP_POSTPROC); - if (vpx_codec_dec_init(&context_, - vpx_codec_vp8_dx(), - &cfg, - VPX_CODEC_USE_POSTPROC) != VPX_CODEC_OK) { - ImplBase::operational_status_ = STATUS_INVALID_CONFIGURATION; - return; - } - ImplBase::operational_status_ = STATUS_INITIALIZED; - } - - private: - ~Vp8Impl() final { - if (ImplBase::operational_status_ == STATUS_INITIALIZED) - CHECK_EQ(VPX_CODEC_OK, vpx_codec_destroy(&context_)); - } - - scoped_refptr<VideoFrame> Decode(uint8_t* data, int len) final { - if (len <= 0 || - vpx_codec_decode(&context_, data, static_cast<unsigned int>(len), - nullptr, 0) != VPX_CODEC_OK) { - return nullptr; - } - - vpx_codec_iter_t iter = nullptr; - vpx_image_t* const image = vpx_codec_get_frame(&context_, &iter); - if (!image) - return nullptr; - if (image->fmt != VPX_IMG_FMT_I420) { - NOTREACHED() << "Only pixel format supported is I420, got " << image->fmt; - return nullptr; - } - DCHECK(vpx_codec_get_frame(&context_, &iter) == nullptr) - << "Should have only decoded exactly one frame."; - - const gfx::Size frame_size(image->d_w, image->d_h); - // Note: Timestamp for the VideoFrame will be set in VideoReceiver. - // |decoded_frame| will be returned to |video_frame_pool_| on destruction to - // be reused. - const scoped_refptr<VideoFrame> decoded_frame = - video_frame_pool_.CreateFrame(PIXEL_FORMAT_I420, frame_size, - gfx::Rect(frame_size), frame_size, - base::TimeDelta()); - libyuv::I420Copy(image->planes[VPX_PLANE_Y], image->stride[VPX_PLANE_Y], - image->planes[VPX_PLANE_U], image->stride[VPX_PLANE_U], - image->planes[VPX_PLANE_V], image->stride[VPX_PLANE_V], - decoded_frame->visible_data(media::VideoFrame::kYPlane), - decoded_frame->stride(media::VideoFrame::kYPlane), - decoded_frame->visible_data(media::VideoFrame::kUPlane), - decoded_frame->stride(media::VideoFrame::kUPlane), - decoded_frame->visible_data(media::VideoFrame::kVPlane), - decoded_frame->stride(media::VideoFrame::kVPlane), - frame_size.width(), frame_size.height()); - return decoded_frame; - } - - // VPX decoder context (i.e., an instantiation). - vpx_codec_ctx_t context_; - - DISALLOW_COPY_AND_ASSIGN(Vp8Impl); -}; - -#ifndef OFFICIAL_BUILD -// A fake video decoder that always output 2x2 black frames. -class VideoDecoder::FakeImpl final : public VideoDecoder::ImplBase { - public: - explicit FakeImpl(const scoped_refptr<CastEnvironment>& cast_environment) - : ImplBase(cast_environment, CODEC_VIDEO_FAKE), - last_decoded_id_(-1) { - if (ImplBase::operational_status_ != STATUS_UNINITIALIZED) - return; - ImplBase::operational_status_ = STATUS_INITIALIZED; - } - - private: - ~FakeImpl() final = default; - - scoped_refptr<VideoFrame> Decode(uint8_t* data, int len) final { - // Make sure this is a JSON string. - if (!len || data[0] != '{') - return nullptr; - std::unique_ptr<base::Value> values(base::JSONReader::ReadDeprecated( - base::StringPiece(reinterpret_cast<char*>(data), len))); - if (!values) - return nullptr; - base::DictionaryValue* dict = nullptr; - values->GetAsDictionary(&dict); - - bool key = false; - int id = 0; - int ref = 0; - dict->GetBoolean("key", &key); - dict->GetInteger("id", &id); - dict->GetInteger("ref", &ref); - DCHECK(id == last_decoded_id_ + 1); - last_decoded_id_ = id; - return media::VideoFrame::CreateBlackFrame(gfx::Size(2, 2)); - } - - int last_decoded_id_; - - DISALLOW_COPY_AND_ASSIGN(FakeImpl); -}; -#endif - -VideoDecoder::VideoDecoder( - const scoped_refptr<CastEnvironment>& cast_environment, - Codec codec) - : cast_environment_(cast_environment) { - switch (codec) { -#ifndef OFFICIAL_BUILD - case CODEC_VIDEO_FAKE: - impl_ = new FakeImpl(cast_environment); - break; -#endif - case CODEC_VIDEO_VP8: - impl_ = new Vp8Impl(cast_environment); - break; - case CODEC_VIDEO_H264: - // TODO(miu): Need implementation. - NOTIMPLEMENTED(); - break; - default: - NOTREACHED() << "Unknown or unspecified codec."; - break; - } -} - -VideoDecoder::~VideoDecoder() = default; - -OperationalStatus VideoDecoder::InitializationResult() const { - if (impl_.get()) - return impl_->InitializationResult(); - return STATUS_UNSUPPORTED_CODEC; -} - -void VideoDecoder::DecodeFrame(std::unique_ptr<EncodedFrame> encoded_frame, - const DecodeFrameCallback& callback) { - DCHECK(encoded_frame.get()); - DCHECK(!callback.is_null()); - if (!impl_.get() || impl_->InitializationResult() != STATUS_INITIALIZED) { - callback.Run(base::WrapRefCounted<VideoFrame>(nullptr), false); - return; - } - cast_environment_->PostTask( - CastEnvironment::VIDEO, FROM_HERE, - base::BindOnce(&VideoDecoder::ImplBase::DecodeFrame, impl_, - std::move(encoded_frame), callback)); -} - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/receiver/video_decoder.h b/chromium/media/cast/receiver/video_decoder.h deleted file mode 100644 index 2116217cd53..00000000000 --- a/chromium/media/cast/receiver/video_decoder.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 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. - -#ifndef MEDIA_CAST_RECEIVER_VIDEO_DECODER_H_ -#define MEDIA_CAST_RECEIVER_VIDEO_DECODER_H_ - -#include <memory> - -#include "base/callback.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "media/base/video_frame.h" -#include "media/cast/constants.h" -#include "media/cast/net/cast_transport_config.h" - -namespace media { -namespace cast { - -class CastEnvironment; - -class VideoDecoder { - public: - // Callback passed to DecodeFrame, to deliver a decoded video frame from the - // decoder. |frame| can be NULL when errors occur. |is_continuous| is - // normally true, but will be false if the decoder has detected a frame skip - // since the last decode operation; and the client might choose to take steps - // to smooth/interpolate video discontinuities in this case. - typedef base::RepeatingCallback<void(scoped_refptr<VideoFrame> frame, - bool is_continuous)> - DecodeFrameCallback; - - VideoDecoder(const scoped_refptr<CastEnvironment>& cast_environment, - Codec codec); - virtual ~VideoDecoder(); - - // Returns STATUS_INITIALIZED if the decoder was successfully constructed. If - // this method returns any other value, calls to DecodeFrame() will not - // succeed. - OperationalStatus InitializationResult() const; - - // Decode the payload in |encoded_frame| asynchronously. |callback| will be - // invoked on the CastEnvironment::MAIN thread with the result. - // - // In the normal case, |encoded_frame->frame_id| will be - // monotonically-increasing by 1 for each successive call to this method. - // When it is not, the decoder will assume one or more frames have been - // dropped (e.g., due to packet loss), and will perform recovery actions. - void DecodeFrame(std::unique_ptr<EncodedFrame> encoded_frame, - const DecodeFrameCallback& callback); - - private: - class FakeImpl; - class ImplBase; - class Vp8Impl; - - const scoped_refptr<CastEnvironment> cast_environment_; - scoped_refptr<ImplBase> impl_; - - DISALLOW_COPY_AND_ASSIGN(VideoDecoder); -}; - -} // namespace cast -} // namespace media - -#endif // MEDIA_CAST_RECEIVER_VIDEO_DECODER_H_ diff --git a/chromium/media/cast/receiver/video_decoder_unittest.cc b/chromium/media/cast/receiver/video_decoder_unittest.cc deleted file mode 100644 index 496195648d3..00000000000 --- a/chromium/media/cast/receiver/video_decoder_unittest.cc +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2014 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 <stdint.h> - -#include <cstdlib> -#include <memory> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/macros.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/time/time.h" -#include "media/cast/cast_config.h" -#include "media/cast/receiver/video_decoder.h" -#include "media/cast/sender/sender_encoded_frame.h" -#include "media/cast/sender/vp8_encoder.h" -#include "media/cast/test/utility/default_config.h" -#include "media/cast/test/utility/standalone_cast_environment.h" -#include "media/cast/test/utility/video_utility.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { -namespace cast { - -namespace { - -const int kStartingWidth = 360; -const int kStartingHeight = 240; -const int kFrameRate = 10; - -FrameSenderConfig GetVideoSenderConfigForTest() { - FrameSenderConfig config = GetDefaultVideoSenderConfig(); - config.max_frame_rate = kFrameRate; - return config; -} - -} // namespace - -class VideoDecoderTest : public ::testing::TestWithParam<Codec> { - public: - VideoDecoderTest() - : cast_environment_(new StandaloneCastEnvironment()), - vp8_encoder_(GetVideoSenderConfigForTest()), - cond_(&lock_) { - vp8_encoder_.Initialize(); - } - - virtual ~VideoDecoderTest() { - // Make sure all threads have stopped before the environment goes away. - cast_environment_->Shutdown(); - } - - protected: - void SetUp() final { - video_decoder_ = - std::make_unique<VideoDecoder>(cast_environment_, GetParam()); - CHECK_EQ(STATUS_INITIALIZED, video_decoder_->InitializationResult()); - - next_frame_size_ = gfx::Size(kStartingWidth, kStartingHeight); - next_frame_timestamp_ = base::TimeDelta(); - last_frame_id_ = FrameId::first(); - seen_a_decoded_frame_ = false; - - total_video_frames_feed_in_ = 0; - total_video_frames_decoded_ = 0; - } - - void SetNextFrameSize(const gfx::Size& size) { - next_frame_size_ = size; - } - - // Called from the unit test thread to create another EncodedFrame and push it - // into the decoding pipeline. - void FeedMoreVideo(int num_dropped_frames) { - DCHECK(!cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - - // Prepare a simulated VideoFrame to feed into the VideoEncoder. - const scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame( - PIXEL_FORMAT_I420, next_frame_size_, gfx::Rect(next_frame_size_), - next_frame_size_, next_frame_timestamp_); - const base::TimeTicks reference_time = - base::TimeTicks::UnixEpoch() + next_frame_timestamp_; - next_frame_timestamp_ += base::TimeDelta::FromSeconds(1) / kFrameRate; - PopulateVideoFrame(video_frame.get(), 0); - - // Encode |frame| into |encoded_frame->data|. - std::unique_ptr<SenderEncodedFrame> encoded_frame(new SenderEncodedFrame()); - // Test only supports VP8, currently. - CHECK_EQ(CODEC_VIDEO_VP8, GetParam()); - vp8_encoder_.Encode(video_frame, reference_time, encoded_frame.get()); - // Rewrite frame IDs for testing purposes. - encoded_frame->frame_id = last_frame_id_ + 1 + num_dropped_frames; - if (encoded_frame->dependency == EncodedFrame::KEY) - encoded_frame->referenced_frame_id = encoded_frame->frame_id; - else - encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1; - last_frame_id_ = encoded_frame->frame_id; - ASSERT_EQ(reference_time, encoded_frame->reference_time); - - ++total_video_frames_feed_in_; - - // Post a task to decode the encoded frame. - cast_environment_->PostTask( - CastEnvironment::MAIN, FROM_HERE, - base::BindOnce(&VideoDecoder::DecodeFrame, - base::Unretained(video_decoder_.get()), - std::move(encoded_frame), - base::BindRepeating(&VideoDecoderTest::OnDecodedFrame, - base::Unretained(this), video_frame, - num_dropped_frames == 0))); - } - - // Blocks the caller until all video that has been feed in has been decoded. - void WaitForAllVideoToBeDecoded() { - DCHECK(!cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - base::AutoLock auto_lock(lock_); - while (total_video_frames_decoded_ < total_video_frames_feed_in_) - cond_.Wait(); - EXPECT_EQ(total_video_frames_feed_in_, total_video_frames_decoded_); - } - - private: - // Called by |vp8_decoder_| to deliver each frame of decoded video. - void OnDecodedFrame(scoped_refptr<VideoFrame> expected_video_frame, - bool should_be_continuous, - scoped_refptr<VideoFrame> video_frame, - bool is_continuous) { - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - - // A NULL |video_frame| indicates a decode error, which we don't expect. - ASSERT_TRUE(video_frame); - - // Did the decoder detect whether frames were dropped? - EXPECT_EQ(should_be_continuous, is_continuous); - - // Does the video data seem to be intact? - EXPECT_EQ(expected_video_frame->coded_size().width(), - video_frame->coded_size().width()); - EXPECT_EQ(expected_video_frame->coded_size().height(), - video_frame->coded_size().height()); - EXPECT_LT(40.0, I420PSNR(*expected_video_frame, *video_frame)); - // TODO(miu): Once we start using VideoFrame::timestamp_, check that here. - - // Signal the main test thread that more video was decoded. - base::AutoLock auto_lock(lock_); - ++total_video_frames_decoded_; - cond_.Signal(); - } - - const scoped_refptr<StandaloneCastEnvironment> cast_environment_; - std::unique_ptr<VideoDecoder> video_decoder_; - gfx::Size next_frame_size_; - base::TimeDelta next_frame_timestamp_; - FrameId last_frame_id_; - bool seen_a_decoded_frame_; - - Vp8Encoder vp8_encoder_; - - // Unlike |total_video_frames_decoded_|, this is only read/written on a single - // thread. - int total_video_frames_feed_in_; - - base::Lock lock_; - base::ConditionVariable cond_; - int total_video_frames_decoded_; // Protected by |lock_|. - - DISALLOW_COPY_AND_ASSIGN(VideoDecoderTest); -}; - -TEST_P(VideoDecoderTest, DecodesFrames) { - const int kNumFrames = 3; - for (int i = 0; i < kNumFrames; ++i) - FeedMoreVideo(0); - WaitForAllVideoToBeDecoded(); -} - -TEST_P(VideoDecoderTest, RecoversFromDroppedFrames) { - // Feed 20 frames and expect 20 to be decoded. At random points, drop one or - // more frames. - FeedMoreVideo(0); - FeedMoreVideo(2); // Two frames dropped. - FeedMoreVideo(0); - FeedMoreVideo(0); - FeedMoreVideo(1); // One frame dropped. - FeedMoreVideo(0); - FeedMoreVideo(0); - FeedMoreVideo(0); - FeedMoreVideo(1); // One frame dropped. - FeedMoreVideo(0); - FeedMoreVideo(0); - FeedMoreVideo(0); - FeedMoreVideo(0); - FeedMoreVideo(3); // Three frames dropped. - FeedMoreVideo(0); - FeedMoreVideo(0); - FeedMoreVideo(10); // Ten frames dropped. - FeedMoreVideo(0); - FeedMoreVideo(1); // One frame dropped. - FeedMoreVideo(0); - WaitForAllVideoToBeDecoded(); -} - -TEST_P(VideoDecoderTest, DecodesFramesOfVaryingSizes) { - std::vector<gfx::Size> frame_sizes; - frame_sizes.push_back(gfx::Size(128, 72)); - frame_sizes.push_back(gfx::Size(64, 36)); // Shrink both dimensions. - frame_sizes.push_back(gfx::Size(30, 20)); // Shrink both dimensions again. - frame_sizes.push_back(gfx::Size(20, 30)); // Same area. - frame_sizes.push_back(gfx::Size(60, 40)); // Grow both dimensions. - frame_sizes.push_back(gfx::Size(58, 40)); // Shrink only one dimension. - frame_sizes.push_back(gfx::Size(58, 38)); // Shrink the other dimension. - frame_sizes.push_back(gfx::Size(32, 18)); // Shrink both dimensions again. - frame_sizes.push_back(gfx::Size(34, 18)); // Grow only one dimension. - frame_sizes.push_back(gfx::Size(34, 20)); // Grow the other dimension. - frame_sizes.push_back(gfx::Size(192, 108)); // Grow both dimensions again. - - // Encode one frame at each size. - for (const auto& frame_size : frame_sizes) { - SetNextFrameSize(frame_size); - FeedMoreVideo(0); - } - - // Encode 3 frames at each size. - for (const auto& frame_size : frame_sizes) { - SetNextFrameSize(frame_size); - const int kNumFrames = 3; - for (int i = 0; i < kNumFrames; ++i) - FeedMoreVideo(0); - } - - WaitForAllVideoToBeDecoded(); -} - -INSTANTIATE_TEST_SUITE_P(All, - VideoDecoderTest, - ::testing::Values(CODEC_VIDEO_VP8)); - -} // namespace cast -} // namespace media diff --git a/chromium/media/cast/sender/external_video_encoder.cc b/chromium/media/cast/sender/external_video_encoder.cc index f9688c6ea85..3f5cc4631c9 100644 --- a/chromium/media/cast/sender/external_video_encoder.cc +++ b/chromium/media/cast/sender/external_video_encoder.cc @@ -4,7 +4,9 @@ #include "media/cast/sender/external_video_encoder.h" +#include <array> #include <cmath> +#include <sstream> #include <utility> #include "base/bind.h" @@ -31,7 +33,13 @@ namespace { -enum { MAX_H264_QUANTIZER = 51 }; +// The percentage of each frame to sample. This value is based on an +// analysis that showed sampling 10% of the rows of a frame generated +// reasonably accurate results. +constexpr int kFrameSamplingPercentage = 10; + +// QP for H.264 encoders ranges from [0, 51] (inclusive). +constexpr int kMaxH264Quantizer = 51; // Number of buffers for encoded bit stream. constexpr size_t kOutputBufferCount = 3; @@ -44,6 +52,10 @@ constexpr size_t kExtraInputBufferCount = 2; // assumed to be in full usage when the number of frames in progress reaches it. constexpr int kBacklogRedlineThreshold = 4; +// The number of histogram buckets for quantization estimation. These +// histograms must encompass the range [-255, 255] (inclusive). +constexpr int kQuantizationHistogramSize = 511; + } // namespace namespace media { @@ -93,13 +105,11 @@ class ExternalVideoEncoder::VEAClientImpl final const scoped_refptr<base::SingleThreadTaskRunner>& encoder_task_runner, std::unique_ptr<media::VideoEncodeAccelerator> vea, double max_frame_rate, - StatusChangeCallback status_change_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) + StatusChangeCallback status_change_cb) : cast_environment_(cast_environment), task_runner_(encoder_task_runner), max_frame_rate_(max_frame_rate), status_change_cb_(std::move(status_change_cb)), - create_video_encode_memory_cb_(create_video_encode_memory_cb), video_encode_accelerator_(std::move(vea)), encoder_active_(false), next_frame_id_(FrameId::first()), @@ -107,7 +117,6 @@ class ExternalVideoEncoder::VEAClientImpl final codec_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), key_frame_quantizer_parsable_(false), requested_bit_rate_(-1), - max_allowed_input_buffers_(0), allocate_input_buffer_in_progress_(false) {} base::SingleThreadTaskRunner* task_runner() const { @@ -179,10 +188,11 @@ class ExternalVideoEncoder::VEAClientImpl final if (!allocate_input_buffer_in_progress_ && input_buffers_.size() < max_allowed_input_buffers_) { allocate_input_buffer_in_progress_ = true; - create_video_encode_memory_cb_.Run( - media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420, - frame_coded_size_), - base::BindOnce(&VEAClientImpl::OnCreateInputSharedMemory, this)); + const size_t buffer_size = media::VideoFrame::AllocationSize( + media::PIXEL_FORMAT_I420, frame_coded_size_); + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&VEAClientImpl::AllocateInputBuffer, this, + buffer_size)); } AbortLatestEncodeAttemptDueToErrors(); return; @@ -241,25 +251,54 @@ class ExternalVideoEncoder::VEAClientImpl final CastEnvironment::MAIN, FROM_HERE, base::BindOnce(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR)); - // TODO(miu): Force-flush all |in_progress_frame_encodes_| immediately so - // pending frames do not become stuck, freezing VideoSender. + // TODO(crbug.com/1199930): Force-flush all |in_progress_frame_encodes_| + // immediately so pending frames do not become stuck, freezing VideoSender. + } + + void AllocateInputBuffer(size_t size) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + + auto memory = base::UnsafeSharedMemoryRegion::Create(size); + if (memory.IsValid()) { + base::WritableSharedMemoryMapping mapping = memory.Map(); + DCHECK(mapping.IsValid()); + input_buffers_.push_back( + std::make_unique<std::pair<base::UnsafeSharedMemoryRegion, + base::WritableSharedMemoryMapping>>( + std::move(memory), std::move(mapping))); + free_input_buffer_index_.push_back(input_buffers_.size() - 1); + } + allocate_input_buffer_in_progress_ = false; + } + + void AllocateOutputBuffers(size_t size) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + + for (size_t i = 0; i < kOutputBufferCount; ++i) { + auto memory = base::UnsafeSharedMemoryRegion::Create(size); + base::WritableSharedMemoryMapping mapping = memory.Map(); + DCHECK(mapping.IsValid()); + output_buffers_.push_back( + std::make_pair(std::move(memory), std::move(mapping))); + + video_encode_accelerator_->UseOutputBitstreamBuffer( + media::BitstreamBuffer(static_cast<int32_t>(i), + output_buffers_[i].first.Duplicate(), + output_buffers_[i].first.GetSize())); + } } - // Called to allocate the input and output buffers. + // Called by the VEA to indicate its buffer requirements. void RequireBitstreamBuffers(unsigned int input_count, const gfx::Size& input_coded_size, size_t output_buffer_size) final { DCHECK(task_runner_->RunsTasksInCurrentSequence()); frame_coded_size_ = input_coded_size; - max_allowed_input_buffers_ = input_count + kExtraInputBufferCount; - - for (size_t j = 0; j < kOutputBufferCount; ++j) { - create_video_encode_memory_cb_.Run( - output_buffer_size, - base::BindOnce(&VEAClientImpl::OnCreateSharedMemory, this)); - } + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&VEAClientImpl::AllocateOutputBuffers, this, + output_buffer_size)); } // Encoder has encoded a frame and it's available in one of the output @@ -294,10 +333,7 @@ class ExternalVideoEncoder::VEAClientImpl final // Do not send video until we have encountered the first key frame. // Save the bitstream buffer in |stream_header_| to be sent later along // with the first key frame. - // - // TODO(miu): Should |stream_header_| be an std::ostringstream for - // performance reasons? - stream_header_.append(output_buffer_memory, metadata.payload_size_bytes); + stream_header_.write(output_buffer_memory, metadata.payload_size_bytes); } else if (!in_progress_frame_encodes_.empty()) { InProgressExternalVideoFrameEncode& request = in_progress_frame_encodes_.front(); @@ -315,9 +351,11 @@ class ExternalVideoEncoder::VEAClientImpl final encoded_frame->rtp_timestamp = RtpTimeTicks::FromTimeDelta( request.video_frame->timestamp(), kVideoFrequency); encoded_frame->reference_time = request.reference_time; - if (!stream_header_.empty()) { - encoded_frame->data = stream_header_; - stream_header_.clear(); + + std::string header = stream_header_.str(); + if (!header.empty()) { + encoded_frame->data = std::move(header); + std::ostringstream().swap(stream_header_); } encoded_frame->data.append(output_buffer_memory, metadata.payload_size_bytes); @@ -389,7 +427,7 @@ class ExternalVideoEncoder::VEAClientImpl final const double max_quantizer = codec_profile_ == media::VP8PROFILE_ANY ? static_cast<int>(QuantizerEstimator::MAX_VP8_QUANTIZER) - : static_cast<int>(MAX_H264_QUANTIZER); + : static_cast<int>(kMaxH264Quantizer); encoded_frame->lossy_utilization = bitrate_utilization * (quantizer / max_quantizer); } @@ -436,55 +474,6 @@ class ExternalVideoEncoder::VEAClientImpl final } } - // Note: This method can be called on any thread. - void OnCreateSharedMemory(base::UnsafeSharedMemoryRegion memory) { - task_runner_->PostTask( - FROM_HERE, base::BindOnce(&VEAClientImpl::OnReceivedSharedMemory, this, - std::move(memory))); - } - - void OnCreateInputSharedMemory(base::UnsafeSharedMemoryRegion memory) { - task_runner_->PostTask( - FROM_HERE, base::BindOnce(&VEAClientImpl::OnReceivedInputSharedMemory, - this, std::move(memory))); - } - - void OnReceivedSharedMemory(base::UnsafeSharedMemoryRegion memory) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - - base::WritableSharedMemoryMapping mapping = memory.Map(); - DCHECK(mapping.IsValid()); - output_buffers_.push_back( - std::make_pair(std::move(memory), std::move(mapping))); - - // Wait until all requested buffers are received. - if (output_buffers_.size() < kOutputBufferCount) - return; - - // Immediately provide all output buffers to the VEA. - for (size_t i = 0; i < output_buffers_.size(); ++i) { - video_encode_accelerator_->UseOutputBitstreamBuffer( - media::BitstreamBuffer(static_cast<int32_t>(i), - output_buffers_[i].first.Duplicate(), - output_buffers_[i].first.GetSize())); - } - } - - void OnReceivedInputSharedMemory(base::UnsafeSharedMemoryRegion region) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - - if (region.IsValid()) { - base::WritableSharedMemoryMapping mapping = region.Map(); - DCHECK(mapping.IsValid()); - input_buffers_.push_back( - std::make_unique<std::pair<base::UnsafeSharedMemoryRegion, - base::WritableSharedMemoryMapping>>( - std::move(region), std::move(mapping))); - free_input_buffer_index_.push_back(input_buffers_.size() - 1); - } - allocate_input_buffer_in_progress_ = false; - } - // This is called when an error occurs while preparing a VideoFrame for // encode, or to abort a frame encode when shutting down. void AbortLatestEncodeAttemptDueToErrors() { @@ -540,7 +529,7 @@ class ExternalVideoEncoder::VEAClientImpl final ? pps->pic_init_qs_minus26 + slice_header.slice_qs_delta : pps->pic_init_qp_minus26 + slice_header.slice_qp_delta); DCHECK_GE(slice_quantizer, 0); - DCHECK_LE(slice_quantizer, MAX_H264_QUANTIZER); + DCHECK_LE(slice_quantizer, kMaxH264Quantizer); total_quantizer += slice_quantizer; break; } @@ -570,12 +559,11 @@ class ExternalVideoEncoder::VEAClientImpl final const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; const double max_frame_rate_; const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread. - const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; bool encoder_active_; FrameId next_frame_id_; bool key_frame_encountered_; - std::string stream_header_; + std::ostringstream stream_header_; VideoCodecProfile codec_profile_; bool key_frame_quantizer_parsable_; H264Parser h264_parser_; @@ -628,10 +616,7 @@ bool ExternalVideoEncoder::IsSupported(const FrameSenderConfig& video_config) { video_config.codec != CODEC_VIDEO_H264) return false; - // TODO(miu): "Layering hooks" are needed to be able to query outside of - // libmedia, to determine whether the system provides a hardware encoder. For - // now, assume that this was already checked by this point. - // http://crbug.com/454029 + // We assume that the system provides a hardware encoder at this point. return video_config.use_external_encoder; } @@ -641,19 +626,15 @@ ExternalVideoEncoder::ExternalVideoEncoder( const gfx::Size& frame_size, FrameId first_frame_id, StatusChangeCallback status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) + const CreateVideoEncodeAcceleratorCallback& create_vea_cb) : cast_environment_(cast_environment), - create_video_encode_memory_cb_(create_video_encode_memory_cb), frame_size_(frame_size), - bit_rate_(video_config.start_bitrate), - key_frame_requested_(false) { + bit_rate_(video_config.start_bitrate) { DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); DCHECK_GT(video_config.max_frame_rate, 0); DCHECK(!frame_size_.IsEmpty()); DCHECK(status_change_cb); DCHECK(create_vea_cb); - DCHECK(create_video_encode_memory_cb_); DCHECK_GT(bit_rate_, 0); create_vea_cb.Run( @@ -783,8 +764,7 @@ void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator( DCHECK(!client_); client_ = new VEAClientImpl(cast_environment_, encoder_task_runner, std::move(vea), video_config.max_frame_rate, - std::move(wrapped_status_change_cb), - create_video_encode_memory_cb_); + std::move(wrapped_status_change_cb)); client_->task_runner()->PostTask( FROM_HERE, base::BindOnce(&VEAClientImpl::Initialize, client_, frame_size_, @@ -795,13 +775,11 @@ SizeAdaptableExternalVideoEncoder::SizeAdaptableExternalVideoEncoder( const scoped_refptr<CastEnvironment>& cast_environment, const FrameSenderConfig& video_config, StatusChangeCallback status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) + const CreateVideoEncodeAcceleratorCallback& create_vea_cb) : SizeAdaptableVideoEncoderBase(cast_environment, video_config, std::move(status_change_cb)), - create_vea_cb_(create_vea_cb), - create_video_encode_memory_cb_(create_video_encode_memory_cb) {} + create_vea_cb_(create_vea_cb) {} SizeAdaptableExternalVideoEncoder::~SizeAdaptableExternalVideoEncoder() = default; @@ -810,8 +788,7 @@ std::unique_ptr<VideoEncoder> SizeAdaptableExternalVideoEncoder::CreateEncoder() { return std::make_unique<ExternalVideoEncoder>( cast_environment(), video_config(), frame_size(), next_frame_id(), - CreateEncoderStatusChangeCallback(), create_vea_cb_, - create_video_encode_memory_cb_); + CreateEncoderStatusChangeCallback(), create_vea_cb_); } QuantizerEstimator::QuantizerEstimator() = default; @@ -832,17 +809,15 @@ double QuantizerEstimator::EstimateForKeyFrame(const VideoFrame& frame) { // frame, since the entropy analysis only examines a subset of each frame. const gfx::Size size = frame.visible_rect().size(); const int rows_in_subset = - std::max(1, size.height() * FRAME_SAMPLING_PERCENT / 100); + std::max(1, size.height() * kFrameSamplingPercentage / 100); if (last_frame_size_ != size || !last_frame_pixel_buffer_) { last_frame_pixel_buffer_.reset(new uint8_t[size.width() * rows_in_subset]); last_frame_size_ = size; } // Compute a histogram where each bucket represents the number of times two - // neighboring pixels were different by a specific amount. 511 buckets are - // needed, one for each integer in the range [-255,255]. - int histogram[511]; - memset(histogram, 0, sizeof(histogram)); + // neighboring pixels were different by a specific amount. + std::array<int, kQuantizationHistogramSize> histogram{}; const int row_skip = size.height() / rows_in_subset; int y = 0; for (int i = 0; i < rows_in_subset; ++i, y += row_skip) { @@ -869,7 +844,7 @@ double QuantizerEstimator::EstimateForKeyFrame(const VideoFrame& frame) { // histogram and return it. const int num_samples = (size.width() - 1) * rows_in_subset; return ToQuantizerEstimate(ComputeEntropyFromHistogram( - histogram, base::size(histogram), num_samples)); + histogram.data(), histogram.size(), num_samples)); } double QuantizerEstimator::EstimateForDeltaFrame(const VideoFrame& frame) { @@ -879,19 +854,17 @@ double QuantizerEstimator::EstimateForDeltaFrame(const VideoFrame& frame) { // If the size of the |frame| has changed, no difference can be examined. // In this case, process this frame as if it were a key frame. - const gfx::Size size = frame.visible_rect().size(); + const gfx::Size& size = frame.visible_rect().size(); if (last_frame_size_ != size || !last_frame_pixel_buffer_) { return EstimateForKeyFrame(frame); } const int rows_in_subset = - std::max(1, size.height() * FRAME_SAMPLING_PERCENT / 100); + std::max(1, size.height() * (kFrameSamplingPercentage / 100)); // Compute a histogram where each bucket represents the number of times the // same pixel in this frame versus the last frame was different by a specific - // amount. 511 buckets are needed, one for each integer in the range - // [-255,255]. - int histogram[511]; - memset(histogram, 0, sizeof(histogram)); + // amount. + std::array<int, kQuantizationHistogramSize> histogram{}; const int row_skip = size.height() / rows_in_subset; int y = 0; for (int i = 0; i < rows_in_subset; ++i, y += row_skip) { @@ -916,7 +889,7 @@ double QuantizerEstimator::EstimateForDeltaFrame(const VideoFrame& frame) { // histogram and return it. const int num_samples = size.width() * rows_in_subset; return ToQuantizerEstimate(ComputeEntropyFromHistogram( - histogram, base::size(histogram), num_samples)); + histogram.data(), histogram.size(), num_samples)); } // static @@ -929,22 +902,14 @@ bool QuantizerEstimator::CanExamineFrame(const VideoFrame& frame) { // static double QuantizerEstimator::ComputeEntropyFromHistogram(const int* histogram, - size_t num_buckets, + size_t histogram_size, int num_samples) { -#if defined(OS_ANDROID) - // Android does not currently provide a log2() function in their C++ standard - // library. This is a substitute. - const auto log2 = [](double num) -> double { - return log(num) / 0.69314718055994528622676398299518041312694549560546875; - }; -#endif - DCHECK_LT(0, num_samples); double entropy = 0.0; - for (size_t i = 0; i < num_buckets; ++i) { + for (size_t i = 0; i < histogram_size; ++i) { const double probability = static_cast<double>(histogram[i]) / num_samples; if (probability > 0.0) { - entropy = entropy - probability * log2(probability); + entropy = entropy - probability * std::log2(probability); } } return entropy; @@ -961,14 +926,11 @@ double QuantizerEstimator::ToQuantizerEstimate(double shannon_entropy) { // running alongside. Based on an analysis of the data, the following linear // mapping seems to produce reasonable VP8 quantizer values from the // |shannon_entropy| values. - // - // TODO(miu): Confirm whether this model and value work well on other - // platforms. - const double kEntropyAtMaxQuantizer = 7.5; - const double slope = + constexpr double kEntropyAtMaxQuantizer = 7.5; + constexpr double kSlope = (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; const double quantizer = std::min<double>( - MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); + MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + kSlope * shannon_entropy); return quantizer; } diff --git a/chromium/media/cast/sender/external_video_encoder.h b/chromium/media/cast/sender/external_video_encoder.h index fbbfdb3c7d5..be6878aec8d 100644 --- a/chromium/media/cast/sender/external_video_encoder.h +++ b/chromium/media/cast/sender/external_video_encoder.h @@ -36,8 +36,7 @@ class ExternalVideoEncoder final : public VideoEncoder { const gfx::Size& frame_size, FrameId first_frame_id, StatusChangeCallback status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb); + const CreateVideoEncodeAcceleratorCallback& create_vea_cb); ~ExternalVideoEncoder() final; @@ -66,13 +65,12 @@ class ExternalVideoEncoder final : public VideoEncoder { std::unique_ptr<media::VideoEncodeAccelerator> vea); const scoped_refptr<CastEnvironment> cast_environment_; - const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; // The size of the visible region of the video frames to be encoded. const gfx::Size frame_size_; int bit_rate_; - bool key_frame_requested_; + bool key_frame_requested_ = false; scoped_refptr<VEAClientImpl> client_; @@ -92,8 +90,7 @@ class SizeAdaptableExternalVideoEncoder final const scoped_refptr<CastEnvironment>& cast_environment, const FrameSenderConfig& video_config, StatusChangeCallback status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb); + const CreateVideoEncodeAcceleratorCallback& create_vea_cb); ~SizeAdaptableExternalVideoEncoder() final; @@ -102,9 +99,7 @@ class SizeAdaptableExternalVideoEncoder final private: // Special callbacks needed by media::cast::ExternalVideoEncoder. - // TODO(miu): Remove these. http://crbug.com/454029 const CreateVideoEncodeAcceleratorCallback create_vea_cb_; - const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; DISALLOW_COPY_AND_ASSIGN(SizeAdaptableExternalVideoEncoder); }; @@ -135,13 +130,6 @@ class QuantizerEstimator { double EstimateForDeltaFrame(const VideoFrame& frame); private: - enum { - // The percentage of each frame to sample. This value is based on an - // analysis that showed sampling 10% of the rows of a frame generated - // reasonably accurate results. - FRAME_SAMPLING_PERCENT = 10, - }; - // Returns true if the frame is in planar YUV format. static bool CanExamineFrame(const VideoFrame& frame); @@ -149,7 +137,7 @@ class QuantizerEstimator { // based on the probabilities of values falling within each of the buckets of // the given |histogram|. static double ComputeEntropyFromHistogram(const int* histogram, - size_t num_buckets, + size_t histogram_size, int num_samples); // Map the |shannon_entropy| to its corresponding software VP8 quantizer. diff --git a/chromium/media/cast/sender/fake_video_encode_accelerator_factory.cc b/chromium/media/cast/sender/fake_video_encode_accelerator_factory.cc index b9c7ea280be..51d61d9d288 100644 --- a/chromium/media/cast/sender/fake_video_encode_accelerator_factory.cc +++ b/chromium/media/cast/sender/fake_video_encode_accelerator_factory.cc @@ -13,11 +13,7 @@ namespace cast { FakeVideoEncodeAcceleratorFactory::FakeVideoEncodeAcceleratorFactory( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) - : task_runner_(task_runner), - will_init_succeed_(true), - auto_respond_(false), - vea_response_count_(0), - shm_response_count_(0) {} + : task_runner_(task_runner) {} FakeVideoEncodeAcceleratorFactory::~FakeVideoEncodeAcceleratorFactory() = default; @@ -32,8 +28,6 @@ void FakeVideoEncodeAcceleratorFactory::SetAutoRespond(bool auto_respond) { if (auto_respond_) { if (!vea_response_callback_.is_null()) RespondWithVideoEncodeAccelerator(); - if (!shm_response_callback_.is_null()) - RespondWithSharedMemory(); } } @@ -51,18 +45,6 @@ void FakeVideoEncodeAcceleratorFactory::CreateVideoEncodeAccelerator( RespondWithVideoEncodeAccelerator(); } -void FakeVideoEncodeAcceleratorFactory::CreateSharedMemory( - size_t size, - ReceiveVideoEncodeMemoryCallback callback) { - DCHECK(!callback.is_null()); - DCHECK(!next_response_shm_.IsValid()); - - next_response_shm_ = base::UnsafeSharedMemoryRegion::Create(size); - shm_response_callback_ = std::move(callback); - if (auto_respond_) - RespondWithSharedMemory(); -} - void FakeVideoEncodeAcceleratorFactory::RespondWithVideoEncodeAccelerator() { DCHECK(next_response_vea_.get()); ++vea_response_count_; @@ -70,11 +52,5 @@ void FakeVideoEncodeAcceleratorFactory::RespondWithVideoEncodeAccelerator() { .Run(task_runner_, std::move(next_response_vea_)); } -void FakeVideoEncodeAcceleratorFactory::RespondWithSharedMemory() { - DCHECK(next_response_shm_.IsValid()); - ++shm_response_count_; - std::move(shm_response_callback_).Run(std::move(next_response_shm_)); -} - } // namespace cast } // namespace media diff --git a/chromium/media/cast/sender/fake_video_encode_accelerator_factory.h b/chromium/media/cast/sender/fake_video_encode_accelerator_factory.h index 81984145719..648ee27ed91 100644 --- a/chromium/media/cast/sender/fake_video_encode_accelerator_factory.h +++ b/chromium/media/cast/sender/fake_video_encode_accelerator_factory.h @@ -31,9 +31,6 @@ class FakeVideoEncodeAcceleratorFactory { int vea_response_count() const { return vea_response_count_; } - int shm_response_count() const { - return shm_response_count_; - } // Set whether the next created media::FakeVideoEncodeAccelerator will // initialize successfully. @@ -47,30 +44,18 @@ class FakeVideoEncodeAcceleratorFactory { void CreateVideoEncodeAccelerator( ReceiveVideoEncodeAcceleratorCallback callback); - // Creates shared memory of the requested |size|. If in auto-respond mode, - // |callback| is run synchronously (i.e., before this method returns). - void CreateSharedMemory(size_t size, - ReceiveVideoEncodeMemoryCallback callback); - // Runs the |callback| provided to the last call to // CreateVideoEncodeAccelerator() with the new VideoEncodeAccelerator // instance. void RespondWithVideoEncodeAccelerator(); - // Runs the |callback| provided to the last call to - // CreateSharedMemory() with the new base::UnsafeSharedMemoryRegion instance. - void RespondWithSharedMemory(); - private: const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - bool will_init_succeed_; - bool auto_respond_; + bool will_init_succeed_ = true; + bool auto_respond_ = false; std::unique_ptr<media::VideoEncodeAccelerator> next_response_vea_; ReceiveVideoEncodeAcceleratorCallback vea_response_callback_; - base::UnsafeSharedMemoryRegion next_response_shm_; - ReceiveVideoEncodeMemoryCallback shm_response_callback_; - int vea_response_count_; - int shm_response_count_; + int vea_response_count_ = 0; DISALLOW_COPY_AND_ASSIGN(FakeVideoEncodeAcceleratorFactory); }; diff --git a/chromium/media/cast/sender/h264_vt_encoder_unittest.cc b/chromium/media/cast/sender/h264_vt_encoder_unittest.cc index c43b40b4538..5f38a9980ba 100644 --- a/chromium/media/cast/sender/h264_vt_encoder_unittest.cc +++ b/chromium/media/cast/sender/h264_vt_encoder_unittest.cc @@ -12,7 +12,7 @@ #include "base/power_monitor/power_monitor.h" #include "base/run_loop.h" #include "base/test/launcher/unit_test_launcher.h" -#include "base/test/power_monitor_test_base.h" +#include "base/test/power_monitor_test.h" #include "base/test/simple_test_tick_clock.h" #include "base/test/task_environment.h" #include "base/test/test_suite.h" diff --git a/chromium/media/cast/sender/video_encoder.cc b/chromium/media/cast/sender/video_encoder.cc index 6e338fbabcd..bcd26be784c 100644 --- a/chromium/media/cast/sender/video_encoder.cc +++ b/chromium/media/cast/sender/video_encoder.cc @@ -20,8 +20,7 @@ std::unique_ptr<VideoEncoder> VideoEncoder::Create( const scoped_refptr<CastEnvironment>& cast_environment, const FrameSenderConfig& video_config, StatusChangeCallback status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) { + const CreateVideoEncodeAcceleratorCallback& create_vea_cb) { // On MacOS or IOS, attempt to use the system VideoToolbox library to // perform optimized H.264 encoding. #if defined(OS_MAC) @@ -36,7 +35,7 @@ std::unique_ptr<VideoEncoder> VideoEncoder::Create( if (ExternalVideoEncoder::IsSupported(video_config)) { return std::unique_ptr<VideoEncoder>(new SizeAdaptableExternalVideoEncoder( cast_environment, video_config, std::move(status_change_cb), - create_vea_cb, create_video_encode_memory_cb)); + create_vea_cb)); } // Attempt to use the software encoder implementation. diff --git a/chromium/media/cast/sender/video_encoder.h b/chromium/media/cast/sender/video_encoder.h index b9ef180eee7..1bcb401f5e6 100644 --- a/chromium/media/cast/sender/video_encoder.h +++ b/chromium/media/cast/sender/video_encoder.h @@ -34,14 +34,11 @@ class VideoEncoder { // // All VideoEncoder instances returned by this function support encoding // sequences of differently-size VideoFrames. - // - // TODO(miu): Remove the CreateVEA callbacks. http://crbug.com/454029 static std::unique_ptr<VideoEncoder> Create( const scoped_refptr<CastEnvironment>& cast_environment, const FrameSenderConfig& video_config, StatusChangeCallback status_change_cb, - const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb); + const CreateVideoEncodeAcceleratorCallback& create_vea_cb); virtual ~VideoEncoder() {} diff --git a/chromium/media/cast/sender/video_encoder_unittest.cc b/chromium/media/cast/sender/video_encoder_unittest.cc index eeaf2321014..a8c54b7dbbc 100644 --- a/chromium/media/cast/sender/video_encoder_unittest.cc +++ b/chromium/media/cast/sender/video_encoder_unittest.cc @@ -77,9 +77,6 @@ class VideoEncoderTest base::Unretained(this)), base::BindRepeating( &FakeVideoEncodeAcceleratorFactory::CreateVideoEncodeAccelerator, - base::Unretained(vea_factory_.get())), - base::BindRepeating( - &FakeVideoEncodeAcceleratorFactory::CreateSharedMemory, base::Unretained(vea_factory_.get()))); RunTasksAndAdvanceClock(); if (is_encoder_present()) @@ -164,13 +161,10 @@ class VideoEncoderTest // If the implementation of |video_encoder_| is ExternalVideoEncoder, check // that the VEA factory has responded (by running the callbacks) a specific // number of times. Otherwise, check that the VEA factory is inactive. - void ExpectVEAResponsesForExternalVideoEncoder( - int vea_response_count, - int shm_response_count) const { + void ExpectVEAResponseForExternalVideoEncoder(int vea_response_count) const { if (!vea_factory_) return; EXPECT_EQ(vea_response_count, vea_factory_->vea_response_count()); - EXPECT_EQ(shm_response_count, vea_factory_->shm_response_count()); } void SetVEAFactoryAutoRespond(bool auto_respond) { @@ -220,7 +214,7 @@ TEST_P(VideoEncoderTest, MAYBE_EncodesVariedFrameSizes) { CreateEncoder(); SetVEAFactoryAutoRespond(true); - ExpectVEAResponsesForExternalVideoEncoder(0, 0); + ExpectVEAResponseForExternalVideoEncoder(0); std::vector<gfx::Size> frame_sizes; frame_sizes.push_back(gfx::Size(128, 72)); @@ -350,14 +344,14 @@ TEST_P(VideoEncoderTest, MAYBE_CanBeDestroyedBeforeVEAIsCreated) { // Destroy the encoder, and confirm the VEA Factory did not respond yet. DestroyEncoder(); - ExpectVEAResponsesForExternalVideoEncoder(0, 0); + ExpectVEAResponseForExternalVideoEncoder(0); // Allow the VEA Factory to respond by running the creation callback. When // the task runs, it will be a no-op since the weak pointers to the // ExternalVideoEncoder were invalidated. SetVEAFactoryAutoRespond(true); RunTasksAndAdvanceClock(); - ExpectVEAResponsesForExternalVideoEncoder(1, 0); + ExpectVEAResponseForExternalVideoEncoder(1); } namespace { diff --git a/chromium/media/cast/sender/video_frame_factory.h b/chromium/media/cast/sender/video_frame_factory.h index 367f2265058..1db6ebecf2f 100644 --- a/chromium/media/cast/sender/video_frame_factory.h +++ b/chromium/media/cast/sender/video_frame_factory.h @@ -5,8 +5,6 @@ #ifndef MEDIA_CAST_SENDER_VIDEO_FRAME_FACTORY_H_ #define MEDIA_CAST_SENDER_VIDEO_FRAME_FACTORY_H_ -#include <memory> - #include "base/time/time.h" namespace gfx { diff --git a/chromium/media/cast/sender/video_sender.cc b/chromium/media/cast/sender/video_sender.cc index 5962cd92731..6e3949ee2bc 100644 --- a/chromium/media/cast/sender/video_sender.cc +++ b/chromium/media/cast/sender/video_sender.cc @@ -90,7 +90,6 @@ VideoSender::VideoSender( const FrameSenderConfig& video_config, StatusChangeCallback status_change_cb, const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, CastTransport* const transport_sender, PlayoutDelayChangeCB playout_delay_change_cb, media::VideoCaptureFeedbackCB feedback_callback) @@ -112,12 +111,8 @@ VideoSender::VideoSender( low_latency_mode_(false), last_reported_encoder_utilization_(-1.0), last_reported_lossy_utilization_(-1.0) { - video_encoder_ = VideoEncoder::Create( - cast_environment_, - video_config, - status_change_cb, - create_vea_cb, - create_video_encode_mem_cb); + video_encoder_ = VideoEncoder::Create(cast_environment_, video_config, + status_change_cb, create_vea_cb); if (!video_encoder_) { cast_environment_->PostTask( CastEnvironment::MAIN, FROM_HERE, diff --git a/chromium/media/cast/sender/video_sender.h b/chromium/media/cast/sender/video_sender.h index 33d38e7a4a0..053d0dda9d2 100644 --- a/chromium/media/cast/sender/video_sender.h +++ b/chromium/media/cast/sender/video_sender.h @@ -44,7 +44,6 @@ class VideoSender : public FrameSender { const FrameSenderConfig& video_config, StatusChangeCallback status_change_cb, const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, CastTransport* const transport_sender, PlayoutDelayChangeCB playout_delay_change_cb, media::VideoCaptureFeedbackCB feedback_callback); diff --git a/chromium/media/cast/sender/video_sender_unittest.cc b/chromium/media/cast/sender/video_sender_unittest.cc index 580f5482fce..05584fe0dac 100644 --- a/chromium/media/cast/sender/video_sender_unittest.cc +++ b/chromium/media/cast/sender/video_sender_unittest.cc @@ -112,13 +112,11 @@ class PeerVideoSender : public VideoSender { const FrameSenderConfig& video_config, const StatusChangeCallback& status_change_cb, const CreateVideoEncodeAcceleratorCallback& create_vea_cb, - const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb, CastTransport* const transport_sender) : VideoSender(cast_environment, video_config, status_change_cb, create_vea_cb, - create_video_encode_mem_cb, transport_sender, base::BindRepeating(&IgnorePlayoutDelayChanges), base::BindRepeating(&PeerVideoSender::ProcessFeedback, @@ -196,16 +194,12 @@ class VideoSenderTest : public ::testing::Test { base::BindRepeating( &FakeVideoEncodeAcceleratorFactory::CreateVideoEncodeAccelerator, base::Unretained(&vea_factory_)), - base::BindRepeating( - &FakeVideoEncodeAcceleratorFactory::CreateSharedMemory, - base::Unretained(&vea_factory_)), transport_sender_.get()); } else { video_sender_ = std::make_unique<PeerVideoSender>( cast_environment_, video_config, base::BindRepeating(&SaveOperationalStatus, &operational_status_), - CreateDefaultVideoEncodeAcceleratorCallback(), - CreateDefaultVideoEncodeMemoryCallback(), transport_sender_.get()); + base::DoNothing(), transport_sender_.get()); } task_runner_->RunTasks(); } @@ -286,7 +280,6 @@ TEST_F(VideoSenderTest, ExternalEncoder) { // VideoSender created an encoder for 1280x720 frames, in order to provide the // INITIALIZED status. EXPECT_EQ(1, vea_factory_.vea_response_count()); - EXPECT_LT(0, vea_factory_.shm_response_count()); scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame(); @@ -297,13 +290,11 @@ TEST_F(VideoSenderTest, ExternalEncoder) { // VideoSender re-created the encoder for the 320x240 frames we're // providing. EXPECT_EQ(1, vea_factory_.vea_response_count()); - EXPECT_LT(0, vea_factory_.shm_response_count()); } video_sender_.reset(NULL); task_runner_->RunTasks(); EXPECT_EQ(1, vea_factory_.vea_response_count()); - EXPECT_LT(0, vea_factory_.shm_response_count()); } TEST_F(VideoSenderTest, ExternalEncoderInitFails) { diff --git a/chromium/media/cast/sender/vp8_encoder.h b/chromium/media/cast/sender/vp8_encoder.h index a6080c41eec..00afbfdcb32 100644 --- a/chromium/media/cast/sender/vp8_encoder.h +++ b/chromium/media/cast/sender/vp8_encoder.h @@ -7,8 +7,6 @@ #include <stdint.h> -#include <memory> - #include "base/macros.h" #include "base/threading/thread_checker.h" #include "media/base/feedback_signal_accumulator.h" diff --git a/chromium/media/cast/sender/vp8_quantizer_parser_unittest.cc b/chromium/media/cast/sender/vp8_quantizer_parser_unittest.cc index d001777691c..3f42076715b 100644 --- a/chromium/media/cast/sender/vp8_quantizer_parser_unittest.cc +++ b/chromium/media/cast/sender/vp8_quantizer_parser_unittest.cc @@ -10,10 +10,10 @@ #include "base/macros.h" #include "base/time/time.h" #include "media/cast/cast_config.h" -#include "media/cast/receiver/video_decoder.h" #include "media/cast/sender/sender_encoded_frame.h" #include "media/cast/sender/vp8_encoder.h" #include "media/cast/sender/vp8_quantizer_parser.h" +#include "media/cast/test/receiver/video_decoder.h" #include "media/cast/test/utility/default_config.h" #include "media/cast/test/utility/video_utility.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chromium/media/cdm/BUILD.gn b/chromium/media/cdm/BUILD.gn index 49304dc271a..b166b77e8b0 100644 --- a/chromium/media/cdm/BUILD.gn +++ b/chromium/media/cdm/BUILD.gn @@ -9,7 +9,7 @@ source_set("cdm_api") { } source_set("cdm_type_conversion") { - if (enable_library_cdms) { + if (enable_library_cdms || is_win) { # This target is a subcomponent. visibility = [ "//media", @@ -51,6 +51,8 @@ source_set("cdm") { "aes_decryptor.h", "cbcs_decryptor.cc", "cbcs_decryptor.h", + "cdm_capability.cc", + "cdm_capability.h", "cdm_context_ref_impl.cc", "cdm_context_ref_impl.h", "cenc_decryptor.cc", @@ -61,6 +63,8 @@ source_set("cdm") { "default_cdm_factory.h", "json_web_key.cc", "json_web_key.h", + "supported_audio_codecs.cc", + "supported_audio_codecs.h", ] # TODO(crbug.com/167187): Fix size_t to int truncations. @@ -81,7 +85,6 @@ source_set("cdm") { deps += [ ":cdm_api", ":cdm_paths", - ":cdm_type_conversion", "//components/crash/core/common:crash_key", ] sources += [ @@ -89,12 +92,6 @@ source_set("cdm") { "cdm_adapter.h", "cdm_adapter_factory.cc", "cdm_adapter_factory.h", - "cdm_allocator.cc", - "cdm_allocator.h", - "cdm_auxiliary_helper.cc", - "cdm_auxiliary_helper.h", - "cdm_helpers.cc", - "cdm_helpers.h", "cdm_module.cc", "cdm_module.h", "cdm_wrapper.h", @@ -114,19 +111,39 @@ source_set("cdm") { } } + if (is_win || enable_library_cdms) { + sources += [ + "cdm_allocator.cc", + "cdm_allocator.h", + "cdm_auxiliary_helper.cc", + "cdm_auxiliary_helper.h", + "cdm_helpers.cc", + "cdm_helpers.h", + ] + deps += [ + ":cdm_api", + ":cdm_type_conversion", + ] + } + if (is_win) { sources += [ "win/media_foundation_cdm.cc", "win/media_foundation_cdm.h", "win/media_foundation_cdm_factory.cc", "win/media_foundation_cdm_factory.h", + "win/media_foundation_cdm_module.cc", + "win/media_foundation_cdm_module.h", "win/media_foundation_cdm_session.cc", "win/media_foundation_cdm_session.h", ] libs = [ "Propsys.lib" ] - deps += [ "//media/base/win:media_foundation_util" ] + deps += [ + ":cdm_paths", + "//media/base/win:media_foundation_util", + ] } } diff --git a/chromium/media/cdm/aes_cbc_crypto.h b/chromium/media/cdm/aes_cbc_crypto.h index b6e0ee5965f..a01ebc02d95 100644 --- a/chromium/media/cdm/aes_cbc_crypto.h +++ b/chromium/media/cdm/aes_cbc_crypto.h @@ -7,8 +7,6 @@ #include <stdint.h> -#include <string> - #include "base/containers/span.h" #include "base/macros.h" #include "media/base/media_export.h" diff --git a/chromium/media/cdm/aes_cbc_crypto_unittest.cc b/chromium/media/cdm/aes_cbc_crypto_unittest.cc index 4b996017215..a79c7598d63 100644 --- a/chromium/media/cdm/aes_cbc_crypto_unittest.cc +++ b/chromium/media/cdm/aes_cbc_crypto_unittest.cc @@ -7,13 +7,13 @@ #include <memory> #include "base/containers/span.h" -#include "base/optional.h" #include "base/stl_util.h" #include "crypto/encryptor.h" #include "crypto/symmetric_key.h" #include "media/base/decoder_buffer.h" #include "media/base/decrypt_config.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/boringssl/src/include/openssl/aes.h" #include "third_party/boringssl/src/include/openssl/crypto.h" #include "third_party/boringssl/src/include/openssl/err.h" diff --git a/chromium/media/cdm/aes_decryptor_unittest.cc b/chromium/media/cdm/aes_decryptor_unittest.cc index 36fd40537d5..caf7ec589b0 100644 --- a/chromium/media/cdm/aes_decryptor_unittest.cc +++ b/chromium/media/cdm/aes_decryptor_unittest.cc @@ -60,7 +60,7 @@ MATCHER(NotEmpty, "") { } MATCHER(IsJSONDictionary, "") { std::string result(arg.begin(), arg.end()); - base::Optional<base::Value> root = base::JSONReader::Read(result); + absl::optional<base::Value> root = base::JSONReader::Read(result); return (root && root->type() == base::Value::Type::DICTIONARY); } MATCHER(IsNullTime, "") { diff --git a/chromium/media/cdm/cbcs_decryptor_unittest.cc b/chromium/media/cdm/cbcs_decryptor_unittest.cc index 1d4192028bd..ac73c1844d9 100644 --- a/chromium/media/cdm/cbcs_decryptor_unittest.cc +++ b/chromium/media/cdm/cbcs_decryptor_unittest.cc @@ -9,7 +9,6 @@ #include <memory> #include "base/containers/span.h" -#include "base/optional.h" #include "base/stl_util.h" #include "base/time/time.h" #include "crypto/encryptor.h" @@ -17,6 +16,7 @@ #include "media/base/decoder_buffer.h" #include "media/base/decrypt_config.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -108,7 +108,7 @@ class CbcsDecryptorTest : public testing::Test { const std::vector<uint8_t>& data, const std::string& iv, const std::vector<SubsampleEntry>& subsample_entries, - base::Optional<EncryptionPattern> encryption_pattern) { + absl::optional<EncryptionPattern> encryption_pattern) { EXPECT_FALSE(data.empty()); EXPECT_FALSE(iv.empty()); diff --git a/chromium/media/cdm/cdm_adapter.cc b/chromium/media/cdm/cdm_adapter.cc index ae40d1a7709..c0a849ae689 100644 --- a/chromium/media/cdm/cdm_adapter.cc +++ b/chromium/media/cdm/cdm_adapter.cc @@ -413,9 +413,9 @@ Decryptor* CdmAdapter::GetDecryptor() { return this; } -base::Optional<base::UnguessableToken> CdmAdapter::GetCdmId() const { +absl::optional<base::UnguessableToken> CdmAdapter::GetCdmId() const { DCHECK(task_runner_->BelongsToCurrentThread()); - return base::nullopt; + return absl::nullopt; } void CdmAdapter::Decrypt(StreamType stream_type, diff --git a/chromium/media/cdm/cdm_adapter.h b/chromium/media/cdm/cdm_adapter.h index 57f2c4aeb0f..19976efc13d 100644 --- a/chromium/media/cdm/cdm_adapter.h +++ b/chromium/media/cdm/cdm_adapter.h @@ -13,7 +13,6 @@ #include "base/callback.h" #include "base/compiler_specific.h" -#include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -95,7 +94,7 @@ class MEDIA_EXPORT CdmAdapter final : public ContentDecryptionModule, // CdmContext implementation. std::unique_ptr<CallbackRegistration> RegisterEventCB(EventCB event_cb) final; Decryptor* GetDecryptor() final; - base::Optional<base::UnguessableToken> GetCdmId() const final; + absl::optional<base::UnguessableToken> GetCdmId() const final; // Decryptor implementation. void Decrypt(StreamType stream_type, diff --git a/chromium/media/cdm/cdm_auxiliary_helper.cc b/chromium/media/cdm/cdm_auxiliary_helper.cc index 6183e10da98..642c7834c7a 100644 --- a/chromium/media/cdm/cdm_auxiliary_helper.cc +++ b/chromium/media/cdm/cdm_auxiliary_helper.cc @@ -22,6 +22,10 @@ url::Origin CdmAuxiliaryHelper::GetCdmOrigin() { return url::Origin(); } +base::UnguessableToken CdmAuxiliaryHelper::GetCdmOriginId() { + return base::UnguessableToken::Null(); +} + cdm::Buffer* CdmAuxiliaryHelper::CreateCdmBuffer(size_t capacity) { return nullptr; } diff --git a/chromium/media/cdm/cdm_auxiliary_helper.h b/chromium/media/cdm/cdm_auxiliary_helper.h index 9bbf1301d12..5b9650e97bc 100644 --- a/chromium/media/cdm/cdm_auxiliary_helper.h +++ b/chromium/media/cdm/cdm_auxiliary_helper.h @@ -12,6 +12,7 @@ #include "base/callback.h" #include "base/macros.h" +#include "base/unguessable_token.h" #include "media/base/media_export.h" #include "media/cdm/cdm_allocator.h" #include "media/cdm/output_protection.h" @@ -51,6 +52,12 @@ class MEDIA_EXPORT CdmAuxiliaryHelper : public CdmAllocator, // if the origin is unavailable or if error happened. virtual url::Origin GetCdmOrigin(); + // Gets the origin ID of the frame associated with the CDM. The origin ID does + // not reveal the origin directly and is resettable by the user by clearing + // browsing data. The origin ID can be empty if an error happened and should + // be handled by the caller. + virtual base::UnguessableToken GetCdmOriginId(); + // CdmAllocator implementation. cdm::Buffer* CreateCdmBuffer(size_t capacity) override; std::unique_ptr<VideoFrameImpl> CreateCdmVideoFrame() override; diff --git a/chromium/media/cdm/cdm_capability.cc b/chromium/media/cdm/cdm_capability.cc new file mode 100644 index 00000000000..80ad67062c0 --- /dev/null +++ b/chromium/media/cdm/cdm_capability.cc @@ -0,0 +1,27 @@ +// Copyright 2021 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/cdm/cdm_capability.h" + +#include <utility> + +namespace media { + +CdmCapability::CdmCapability() = default; + +CdmCapability::CdmCapability( + std::vector<AudioCodec> audio_codecs, + std::vector<VideoCodec> video_codecs, + base::flat_set<EncryptionScheme> encryption_schemes, + base::flat_set<CdmSessionType> session_types) + : audio_codecs(std::move(audio_codecs)), + video_codecs(std::move(video_codecs)), + encryption_schemes(std::move(encryption_schemes)), + session_types(std::move(session_types)) {} + +CdmCapability::CdmCapability(const CdmCapability& other) = default; + +CdmCapability::~CdmCapability() = default; + +} // namespace media diff --git a/chromium/media/cdm/cdm_capability.h b/chromium/media/cdm/cdm_capability.h new file mode 100644 index 00000000000..0548a3e1d7e --- /dev/null +++ b/chromium/media/cdm/cdm_capability.h @@ -0,0 +1,51 @@ +// Copyright 2021 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. + +#ifndef MEDIA_CDM_CDM_CAPABILITY_H_ +#define MEDIA_CDM_CDM_CAPABILITY_H_ + +#include <vector> + +#include "base/containers/flat_set.h" +#include "media/base/audio_codecs.h" +#include "media/base/content_decryption_module.h" +#include "media/base/encryption_scheme.h" +#include "media/base/media_export.h" +#include "media/base/video_codecs.h" + +namespace media { + +// Capabilities supported by a Content Decryption Module. +struct MEDIA_EXPORT CdmCapability { + CdmCapability(); + CdmCapability(std::vector<AudioCodec> audio_codecs, + std::vector<VideoCodec> video_codecs, + base::flat_set<EncryptionScheme> encryption_schemes, + base::flat_set<CdmSessionType> session_types); + CdmCapability(const CdmCapability& other); + ~CdmCapability(); + + // List of audio codecs supported by the CDM (e.g. opus). This is the set of + // codecs supported by the media pipeline using the CDM, where CDM does the + // decryption, and the media pipeline does decoding. As this is generic, not + // all profiles or levels of the specified codecs may actually be supported. + std::vector<AudioCodec> audio_codecs; + + // List of video codecs supported by the CDM (e.g. vp8). This is the set of + // codecs supported by the media pipeline using the CDM, where CDM does the + // decryption, and the media pipeline does decoding. As this is generic, not + // all profiles or levels of the specified codecs may actually be supported. + // TODO(crbug.com/796725) Find a way to include profiles and levels. + std::vector<VideoCodec> video_codecs; + + // List of encryption schemes supported by the CDM (e.g. cenc). + base::flat_set<EncryptionScheme> encryption_schemes; + + // List of session types supported by the CDM. + base::flat_set<CdmSessionType> session_types; +}; + +} // namespace media + +#endif // MEDIA_CDM_CDM_CAPABILITY_H_ diff --git a/chromium/media/cdm/cdm_context_ref_impl.h b/chromium/media/cdm/cdm_context_ref_impl.h index 299690cd3ba..7ea73f99eb9 100644 --- a/chromium/media/cdm/cdm_context_ref_impl.h +++ b/chromium/media/cdm/cdm_context_ref_impl.h @@ -5,8 +5,6 @@ #ifndef MEDIA_CDM_CDM_CONTEXT_REF_IMPL_H_ #define MEDIA_CDM_CDM_CONTEXT_REF_IMPL_H_ -#include <memory> - #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/threading/thread_checker.h" diff --git a/chromium/media/cdm/cdm_paths.cc b/chromium/media/cdm/cdm_paths.cc index 211169c7e5d..84c4a471819 100644 --- a/chromium/media/cdm/cdm_paths.cc +++ b/chromium/media/cdm/cdm_paths.cc @@ -6,6 +6,7 @@ #include <string> +#include "base/system/sys_info.h" #include "media/media_buildflags.h" namespace media { @@ -39,4 +40,17 @@ base::FilePath GetPlatformSpecificDirectory(const std::string& cdm_base_path) { base::FilePath::FromUTF8Unsafe(cdm_base_path)); } +#if defined(OS_WIN) +const char kCdmStore[] = "CdmStore"; + +base::FilePath GetCdmStorePath(const base::FilePath& user_data_dir, + const base::UnguessableToken& cdm_origin_id, + const std::string& key_system) { + return user_data_dir.AppendASCII(kCdmStore) + .AppendASCII(base::SysInfo::ProcessCPUArchitecture()) + .AppendASCII(cdm_origin_id.ToString()) + .AppendASCII(key_system); +} +#endif // defined(OS_WIN) + } // namespace media diff --git a/chromium/media/cdm/cdm_paths.h b/chromium/media/cdm/cdm_paths.h index 7c67d1f0db5..d761a2bbddc 100644 --- a/chromium/media/cdm/cdm_paths.h +++ b/chromium/media/cdm/cdm_paths.h @@ -9,6 +9,8 @@ #include "base/files/file_path.h" #include "base/token.h" +#include "base/unguessable_token.h" +#include "build/build_config.h" namespace media { @@ -41,6 +43,17 @@ base::FilePath GetPlatformSpecificDirectory( const base::FilePath& cdm_base_path); base::FilePath GetPlatformSpecificDirectory(const std::string& cdm_base_path); +#if defined(OS_WIN) +// Returns the "CDM store path" to be passed to `MediaFoundationCdm`. The +// `user_data_dir` is typically the LPAC specific path, e.g. +// C:\Users\<user>\AppData\Local\Packages\ +// cr.sb.cdm4b414ceb52402c4e188a185dd531c100416d8daf\AC\Google\Chrome\User Data +// TODO(xhwang): Separate by Chromium user profile as well. +base::FilePath GetCdmStorePath(const base::FilePath& user_data_dir, + const base::UnguessableToken& cdm_origin_id, + const std::string& key_system); +#endif // defined(OS_WIN) + } // namespace media #endif // MEDIA_CDM_CDM_PATHS_H_ diff --git a/chromium/media/cdm/cdm_wrapper.h b/chromium/media/cdm/cdm_wrapper.h index ef0eab69bf2..d911516c6b9 100644 --- a/chromium/media/cdm/cdm_wrapper.h +++ b/chromium/media/cdm/cdm_wrapper.h @@ -7,8 +7,6 @@ #include <stdint.h> -#include <string> - #include "base/check.h" #include "base/compiler_specific.h" #include "base/feature_list.h" diff --git a/chromium/media/cdm/json_web_key.cc b/chromium/media/cdm/json_web_key.cc index d3d696229b0..0fdc9dbb89f 100644 --- a/chromium/media/cdm/json_web_key.cc +++ b/chromium/media/cdm/json_web_key.cc @@ -168,7 +168,7 @@ bool ExtractKeysFromJWKSet(const std::string& jwk_set, return false; } - base::Optional<base::Value> root = base::JSONReader::Read(jwk_set); + absl::optional<base::Value> root = base::JSONReader::Read(jwk_set); if (!root || root->type() != base::Value::Type::DICTIONARY) { DVLOG(1) << "Not valid JSON: " << jwk_set; return false; @@ -235,7 +235,7 @@ bool ExtractKeyIdsFromKeyIdsInitData(const std::string& input, return false; } - base::Optional<base::Value> root = base::JSONReader::Read(input); + absl::optional<base::Value> root = base::JSONReader::Read(input); if (!root || root->type() != base::Value::Type::DICTIONARY) { error_message->assign("Not valid JSON: "); error_message->append(ShortenTo64Characters(input)); @@ -297,8 +297,8 @@ void CreateLicenseRequest(const KeyIdList& key_ids, CdmSessionType session_type, std::vector<uint8_t>* license) { // Create the license request. - auto request = std::make_unique<base::DictionaryValue>(); - auto list = std::make_unique<base::ListValue>(); + base::Value request(base::Value::Type::DICTIONARY); + base::Value list(base::Value::Type::LIST); for (const auto& key_id : key_ids) { std::string key_id_string; base::Base64UrlEncode( @@ -306,32 +306,32 @@ void CreateLicenseRequest(const KeyIdList& key_ids, key_id.size()), base::Base64UrlEncodePolicy::OMIT_PADDING, &key_id_string); - list->AppendString(key_id_string); + list.Append(key_id_string); } - request->Set(kKeyIdsTag, std::move(list)); + request.SetKey(kKeyIdsTag, std::move(list)); switch (session_type) { case CdmSessionType::kTemporary: - request->SetString(kTypeTag, kTemporarySession); + request.SetStringKey(kTypeTag, kTemporarySession); break; case CdmSessionType::kPersistentLicense: - request->SetString(kTypeTag, kPersistentLicenseSession); + request.SetStringKey(kTypeTag, kPersistentLicenseSession); break; } // Serialize the license request as a string. std::string json; JSONStringValueSerializer serializer(&json); - serializer.Serialize(*request); + serializer.Serialize(request); // Convert the serialized license request into std::vector and return it. std::vector<uint8_t> result(json.begin(), json.end()); license->swap(result); } -void AddKeyIdsToDictionary(const KeyIdList& key_ids, - base::DictionaryValue* dictionary) { - auto list = std::make_unique<base::ListValue>(); +base::Value MakeKeyIdsDictionary(const KeyIdList& key_ids) { + base::Value dictionary(base::Value::Type::DICTIONARY); + base::Value list(base::Value::Type::LIST); for (const auto& key_id : key_ids) { std::string key_id_string; base::Base64UrlEncode( @@ -339,17 +339,18 @@ void AddKeyIdsToDictionary(const KeyIdList& key_ids, key_id.size()), base::Base64UrlEncodePolicy::OMIT_PADDING, &key_id_string); - list->AppendString(key_id_string); + list.Append(key_id_string); } - dictionary->Set(kKeyIdsTag, std::move(list)); + dictionary.SetKey(kKeyIdsTag, std::move(list)); + return dictionary; } std::vector<uint8_t> SerializeDictionaryToVector( - const base::DictionaryValue* dictionary) { + const base::Value& dictionary) { // Serialize the dictionary as a string. std::string json; JSONStringValueSerializer serializer(&json); - serializer.Serialize(*dictionary); + serializer.Serialize(dictionary); // Convert the serialized data into std::vector and return it. return std::vector<uint8_t>(json.begin(), json.end()); @@ -358,10 +359,9 @@ std::vector<uint8_t> SerializeDictionaryToVector( void CreateKeyIdsInitData(const KeyIdList& key_ids, std::vector<uint8_t>* init_data) { // Create the init_data. - auto dictionary = std::make_unique<base::DictionaryValue>(); - AddKeyIdsToDictionary(key_ids, dictionary.get()); + auto dictionary = MakeKeyIdsDictionary(key_ids); - auto data = SerializeDictionaryToVector(dictionary.get()); + auto data = SerializeDictionaryToVector(dictionary); init_data->swap(data); } @@ -372,9 +372,8 @@ void CreateKeyIdsInitData(const KeyIdList& key_ids, // of the octet sequence containing the key ID value. std::vector<uint8_t> CreateLicenseReleaseMessage(const KeyIdList& key_ids) { // Create the init_data. - auto dictionary = std::make_unique<base::DictionaryValue>(); - AddKeyIdsToDictionary(key_ids, dictionary.get()); - return SerializeDictionaryToVector(dictionary.get()); + auto dictionary = MakeKeyIdsDictionary(key_ids); + return SerializeDictionaryToVector(dictionary); } bool ExtractFirstKeyIdFromLicenseRequest(const std::vector<uint8_t>& license, @@ -387,7 +386,7 @@ bool ExtractFirstKeyIdFromLicenseRequest(const std::vector<uint8_t>& license, return false; } - base::Optional<base::Value> root = base::JSONReader::Read(license_as_str); + absl::optional<base::Value> root = base::JSONReader::Read(license_as_str); if (!root || root->type() != base::Value::Type::DICTIONARY) { DVLOG(1) << "Not valid JSON: " << license_as_str; return false; diff --git a/chromium/media/cdm/json_web_key.h b/chromium/media/cdm/json_web_key.h index d2add7bb3ee..c490a16a513 100644 --- a/chromium/media/cdm/json_web_key.h +++ b/chromium/media/cdm/json_web_key.h @@ -11,7 +11,6 @@ #include <utility> #include <vector> -#include "base/time/time.h" #include "media/base/media_export.h" namespace media { diff --git a/chromium/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc b/chromium/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc index 4a398807d72..9fd2daf5cb6 100644 --- a/chromium/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc +++ b/chromium/media/cdm/library_cdm/clear_key_cdm/cdm_video_decoder.cc @@ -15,7 +15,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/no_destructor.h" -#include "base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" // Necessary to convert async media::VideoDecoder to sync CdmVideoDecoder. // Typically not recommended for production code, but is ok here since // ClearKeyCdm is only for testing. @@ -280,8 +280,8 @@ class VideoDecoderAdapter final : public CdmVideoDecoder { // Results of |video_decoder_| operations. Set iff the callback of the // operation has been called. - base::Optional<Status> last_init_result_; - base::Optional<Status> last_decode_status_; + absl::optional<Status> last_init_result_; + absl::optional<Status> last_decode_status_; // Queue of decoded video frames. using VideoFrameQueue = base::queue<scoped_refptr<VideoFrame>>; diff --git a/chromium/media/cdm/mock_helpers.cc b/chromium/media/cdm/mock_helpers.cc index 0e8b68e6287..4934a98dfc3 100644 --- a/chromium/media/cdm/mock_helpers.cc +++ b/chromium/media/cdm/mock_helpers.cc @@ -15,10 +15,16 @@ MockCdmAuxiliaryHelper::~MockCdmAuxiliaryHelper() = default; void MockCdmAuxiliaryHelper::SetFileReadCB(FileReadCB file_read_cb) {} cdm::Buffer* MockCdmAuxiliaryHelper::CreateCdmBuffer(size_t capacity) { + if (!allocator_) + return nullptr; + return allocator_->CreateCdmBuffer(capacity); } std::unique_ptr<VideoFrameImpl> MockCdmAuxiliaryHelper::CreateCdmVideoFrame() { + if (!allocator_) + return nullptr; + return allocator_->CreateCdmVideoFrame(); } diff --git a/chromium/media/cdm/mock_helpers.h b/chromium/media/cdm/mock_helpers.h index 5c812113220..678bd11e8a0 100644 --- a/chromium/media/cdm/mock_helpers.h +++ b/chromium/media/cdm/mock_helpers.h @@ -21,6 +21,7 @@ namespace media { class MockCdmAuxiliaryHelper : public CdmAuxiliaryHelper { public: + // `allocator` is optional; can be null if no need to create buffers/frames. explicit MockCdmAuxiliaryHelper(std::unique_ptr<CdmAllocator> allocator); ~MockCdmAuxiliaryHelper() override; @@ -50,6 +51,8 @@ class MockCdmAuxiliaryHelper : public CdmAuxiliaryHelper { MOCK_METHOD1(GetStorageIdCalled, std::vector<uint8_t>(uint32_t version)); void GetStorageId(uint32_t version, StorageIdCB callback) override; + MOCK_METHOD0(GetCdmOriginId, base::UnguessableToken()); + private: std::unique_ptr<CdmAllocator> allocator_; diff --git a/chromium/media/cdm/supported_audio_codecs.cc b/chromium/media/cdm/supported_audio_codecs.cc new file mode 100644 index 00000000000..1f416ac1f6e --- /dev/null +++ b/chromium/media/cdm/supported_audio_codecs.cc @@ -0,0 +1,20 @@ +// Copyright 2021 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/cdm/supported_audio_codecs.h" + +#include "media/media_buildflags.h" + +namespace media { + +const std::vector<AudioCodec> GetCdmSupportedAudioCodecs() { + return { + AudioCodec::kCodecOpus, AudioCodec::kCodecVorbis, AudioCodec::kCodecFLAC, +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + AudioCodec::kCodecAAC, +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) + }; +} + +} // namespace media diff --git a/chromium/media/cdm/supported_audio_codecs.h b/chromium/media/cdm/supported_audio_codecs.h new file mode 100644 index 00000000000..c4e0d4bedfb --- /dev/null +++ b/chromium/media/cdm/supported_audio_codecs.h @@ -0,0 +1,25 @@ +// Copyright 2021 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. + +#ifndef MEDIA_CDM_SUPPORTED_AUDIO_CODECS_H_ +#define MEDIA_CDM_SUPPORTED_AUDIO_CODECS_H_ + +#include <vector> + +#include "media/base/audio_codecs.h" +#include "media/base/media_export.h" + +namespace media { + +// Returns a set of audio codecs that are supported for decoding by the +// browser after a CDM has decrypted the stream. This will be used by +// CDMs that only support decryption of audio content. +// Note that this should only be used on desktop CDMs. On other platforms +// (e.g. Android) we should query the system for (encrypted) audio codec +// support. +MEDIA_EXPORT const std::vector<AudioCodec> GetCdmSupportedAudioCodecs(); + +} // namespace media + +#endif // MEDIA_CDM_SUPPORTED_AUDIO_CODECS_H_ diff --git a/chromium/media/cdm/supported_cdm_versions.cc b/chromium/media/cdm/supported_cdm_versions.cc index 971895257f6..eca81444316 100644 --- a/chromium/media/cdm/supported_cdm_versions.cc +++ b/chromium/media/cdm/supported_cdm_versions.cc @@ -5,9 +5,9 @@ #include "media/cdm/supported_cdm_versions.h" #include "base/command_line.h" -#include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "media/base/media_switches.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -15,17 +15,17 @@ namespace { // Returns the overridden supported CDM interface version specified on command // line, which can be null if not specified. -base::Optional<int> GetSupportedCdmInterfaceVersionOverrideFromCommandLine() { +absl::optional<int> GetSupportedCdmInterfaceVersionOverrideFromCommandLine() { auto* command_line = base::CommandLine::ForCurrentProcess(); if (!command_line) - return base::nullopt; + return absl::nullopt; auto version_string = command_line->GetSwitchValueASCII( switches::kOverrideEnabledCdmInterfaceVersion); int version = 0; if (!base::StringToInt(version_string, &version)) - return base::nullopt; + return absl::nullopt; else return version; } diff --git a/chromium/media/cdm/win/media_foundation_cdm.cc b/chromium/media/cdm/win/media_foundation_cdm.cc index 548db42982e..b1f2ae2d08a 100644 --- a/chromium/media/cdm/win/media_foundation_cdm.cc +++ b/chromium/media/cdm/win/media_foundation_cdm.cc @@ -12,9 +12,10 @@ #include "base/win/scoped_co_mem.h" #include "base/win/scoped_propvariant.h" #include "base/win/win_util.h" +#include "base/win/windows_version.h" #include "media/base/bind_to_current_loop.h" #include "media/base/cdm_promise.h" -#include "media/base/win/mf_cdm_proxy.h" +#include "media/base/win/media_foundation_cdm_proxy.h" #include "media/base/win/mf_helpers.h" #include "media/cdm/win/media_foundation_cdm_session.h" @@ -95,16 +96,14 @@ HRESULT RefreshDecryptor(IMFTransform* decryptor, return S_OK; } -class CdmProxyImpl - : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IMFCdmProxy> { +class CdmProxyImpl : public MediaFoundationCdmProxy { public: explicit CdmProxyImpl(ComPtr<IMFContentDecryptionModule> mf_cdm) : mf_cdm_(mf_cdm) {} - ~CdmProxyImpl() override = default; - // IMFCdmProxy implementation + // MediaFoundationCdmProxy implementation - STDMETHODIMP GetPMPServer(REFIID riid, LPVOID* object_result) override { + HRESULT GetPMPServer(REFIID riid, LPVOID* object_result) override { DVLOG_FUNC(1); ComPtr<IMFGetService> cdm_services; RETURN_IF_FAILED(mf_cdm_.As(&cdm_services)); @@ -113,12 +112,12 @@ class CdmProxyImpl return S_OK; } - STDMETHODIMP GetInputTrustAuthority(uint32_t stream_id, - uint32_t /*stream_count*/, - const uint8_t* content_init_data, - uint32_t content_init_data_size, - REFIID riid, - IUnknown** object_out) override { + HRESULT GetInputTrustAuthority(uint32_t stream_id, + uint32_t /*stream_count*/, + const uint8_t* content_init_data, + uint32_t content_init_data_size, + REFIID riid, + IUnknown** object_out) override { DVLOG_FUNC(1); if (input_trust_authorities_.count(stream_id)) { @@ -147,13 +146,13 @@ class CdmProxyImpl return S_OK; } - STDMETHODIMP SetLastKeyId(uint32_t stream_id, REFGUID key_id) override { + HRESULT SetLastKeyId(uint32_t stream_id, REFGUID key_id) override { DVLOG_FUNC(1); last_key_ids_[stream_id] = key_id; return S_OK; } - STDMETHODIMP RefreshTrustedInput() override { + HRESULT RefreshTrustedInput() override { DVLOG_FUNC(1); // Refresh all decryptors of the last key IDs. @@ -179,7 +178,7 @@ class CdmProxyImpl return S_OK; } - STDMETHODIMP + HRESULT ProcessContentEnabler(IUnknown* request, IMFAsyncResult* result) override { DVLOG_FUNC(1); ComPtr<IMFContentEnabler> content_enabler; @@ -188,6 +187,8 @@ class CdmProxyImpl } private: + ~CdmProxyImpl() override = default; + HRESULT GetProtectionSystemId(GUID* protection_system_id) { // Typically the CDM should only return one protection system ID. So just // use the first one if available. @@ -222,6 +223,11 @@ class CdmProxyImpl } // namespace +// static +bool MediaFoundationCdm::IsAvailable() { + return base::win::GetVersion() >= base::win::Version::WIN10_20H1; +} + MediaFoundationCdm::MediaFoundationCdm( Microsoft::WRL::ComPtr<IMFContentDecryptionModule> mf_cdm, const SessionMessageCB& session_message_cb, @@ -397,7 +403,7 @@ bool MediaFoundationCdm::GetMediaFoundationCdmProxy( DVLOG_FUNC(1); if (!cdm_proxy_) - cdm_proxy_ = Make<CdmProxyImpl>(mf_cdm_); + cdm_proxy_ = base::MakeRefCounted<CdmProxyImpl>(mf_cdm_); BindToCurrentLoop(std::move(get_mf_cdm_proxy_cb)).Run(cdm_proxy_); return true; diff --git a/chromium/media/cdm/win/media_foundation_cdm.h b/chromium/media/cdm/win/media_foundation_cdm.h index 1020b732d0d..b5e80dfbf67 100644 --- a/chromium/media/cdm/win/media_foundation_cdm.h +++ b/chromium/media/cdm/win/media_foundation_cdm.h @@ -12,6 +12,7 @@ #include <memory> #include <string> +#include "base/memory/scoped_refptr.h" #include "media/base/cdm_context.h" #include "media/base/content_decryption_module.h" #include "media/base/media_export.h" @@ -25,6 +26,10 @@ class MediaFoundationCdmSession; class MEDIA_EXPORT MediaFoundationCdm : public ContentDecryptionModule, public CdmContext { public: + // Checks whether MediaFoundationCdm is available based on OS version. Further + // checks need to be made to determine the usability and the capabilities. + static bool IsAvailable(); + MediaFoundationCdm( Microsoft::WRL::ComPtr<IMFContentDecryptionModule> mf_cdm, const SessionMessageCB& session_message_cb, @@ -89,7 +94,7 @@ class MEDIA_EXPORT MediaFoundationCdm : public ContentDecryptionModule, // Session ID to session map. std::map<std::string, std::unique_ptr<MediaFoundationCdmSession>> sessions_; - Microsoft::WRL::ComPtr<IMFCdmProxy> cdm_proxy_; + scoped_refptr<MediaFoundationCdmProxy> cdm_proxy_; }; } // namespace media diff --git a/chromium/media/cdm/win/media_foundation_cdm_factory.cc b/chromium/media/cdm/win/media_foundation_cdm_factory.cc index bb94d7ca9ff..9fa61d821a4 100644 --- a/chromium/media/cdm/win/media_foundation_cdm_factory.cc +++ b/chromium/media/cdm/win/media_foundation_cdm_factory.cc @@ -5,8 +5,10 @@ #include "media/cdm/win/media_foundation_cdm_factory.h" #include <combaseapi.h> +#include <initguid.h> // Needed for DEFINE_PROPERTYKEY to work properly. #include <mferror.h> #include <mfmediaengine.h> +#include <propkeydef.h> // Needed for DEFINE_PROPERTYKEY. #include <propvarutil.h> #include "base/bind.h" @@ -17,7 +19,9 @@ #include "media/base/bind_to_current_loop.h" #include "media/base/cdm_config.h" #include "media/base/win/mf_helpers.h" +#include "media/cdm/cdm_paths.h" #include "media/cdm/win/media_foundation_cdm.h" +#include "media/cdm/win/media_foundation_cdm_module.h" namespace media { @@ -25,6 +29,22 @@ namespace { using Microsoft::WRL::ComPtr; +// Key to the CDM Origin ID to be passed to the CDM for privacy purposes. The +// same value is also used in MediaFoundation CDMs. Do NOT change this value! +DEFINE_PROPERTYKEY(EME_CONTENTDECRYPTIONMODULE_ORIGIN_ID, + 0x1218a3e2, + 0xcfb0, + 0x4c98, + 0x90, + 0xe5, + 0x5f, + 0x58, + 0x18, + 0xd4, + 0xb6, + 0x7e, + PID_FIRST_USABLE); + void SetBSTR(const wchar_t* str, PROPVARIANT* propvariant) { propvariant->vt = VT_BSTR; propvariant->bstrVal = SysAllocString(str); @@ -105,20 +125,25 @@ HRESULT BuildCdmAccessConfigurations(const CdmConfig& cdm_config, return S_OK; } -HRESULT BuildCdmProperties(ComPtr<IPropertyStore>& properties) { +HRESULT BuildCdmProperties(const base::UnguessableToken& origin_id, + const base::FilePath& store_path, + ComPtr<IPropertyStore>& properties) { + DCHECK(!origin_id.is_empty()); + ComPtr<IPropertyStore> temp_properties; RETURN_IF_FAILED(PSCreateMemoryPropertyStore(IID_PPV_ARGS(&temp_properties))); - // TODO(xhwang): Provide per-user, per-profile and per-key-system path here. - base::FilePath temp_dir; - CHECK(base::GetTempDir(&temp_dir)); - CHECK(base::DirectoryExists(temp_dir)); + base::win::ScopedPropVariant origin_id_var; + RETURN_IF_FAILED(InitPropVariantFromString( + base::UTF8ToWide(origin_id.ToString()).c_str(), origin_id_var.Receive())); + RETURN_IF_FAILED(temp_properties->SetValue( + EME_CONTENTDECRYPTIONMODULE_ORIGIN_ID, origin_id_var.get())); - base::win::ScopedPropVariant propvar; - RETURN_IF_FAILED( - InitPropVariantFromString(temp_dir.value().c_str(), propvar.Receive())); + base::win::ScopedPropVariant store_path_var; + RETURN_IF_FAILED(InitPropVariantFromString(store_path.value().c_str(), + store_path_var.Receive())); RETURN_IF_FAILED(temp_properties->SetValue( - MF_CONTENTDECRYPTIONMODULE_STOREPATH, propvar.get())); + MF_CONTENTDECRYPTIONMODULE_STOREPATH, store_path_var.get())); properties = temp_properties; return S_OK; @@ -126,11 +151,14 @@ HRESULT BuildCdmProperties(ComPtr<IPropertyStore>& properties) { } // namespace -MediaFoundationCdmFactory::MediaFoundationCdmFactory() = default; +MediaFoundationCdmFactory::MediaFoundationCdmFactory( + std::unique_ptr<CdmAuxiliaryHelper> helper, + const base::FilePath& user_data_dir) + : helper_(std::move(helper)), user_data_dir_(user_data_dir) {} MediaFoundationCdmFactory::~MediaFoundationCdmFactory() = default; -void MediaFoundationCdmFactory::SetCreateCdmFactoryCallback( +void MediaFoundationCdmFactory::SetCreateCdmFactoryCallbackForTesting( const std::string& key_system, CreateCdmFactoryCB create_cdm_factory_cb) { DCHECK(!create_cdm_factory_cbs_.count(key_system)); @@ -166,7 +194,7 @@ void MediaFoundationCdmFactory::Create( BindToCurrentLoop(std::move(cdm_created_cb)).Run(cdm, ""); } -HRESULT MediaFoundationCdmFactory::CreateMFCdmFactory( +HRESULT MediaFoundationCdmFactory::GetCdmFactory( const std::string& key_system, Microsoft::WRL::ComPtr<IMFContentDecryptionModuleFactory>& cdm_factory) { // Use key system specific `create_cdm_factory_cb` if there's one registered. @@ -180,14 +208,9 @@ HRESULT MediaFoundationCdmFactory::CreateMFCdmFactory( return S_OK; } - // Otherwise, use the default creation. - ComPtr<IMFMediaEngineClassFactory4> class_factory; - RETURN_IF_FAILED(CoCreateInstance(CLSID_MFMediaEngineClassFactory, nullptr, - CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&class_factory))); - auto key_system_str = base::UTF8ToWide(key_system); - RETURN_IF_FAILED(class_factory->CreateContentDecryptionModuleFactory( - key_system_str.c_str(), IID_PPV_ARGS(&cdm_factory))); + // Otherwise, use the one in MediaFoundationCdmModule. + RETURN_IF_FAILED(MediaFoundationCdmModule::GetInstance()->GetCdmFactory( + key_system, cdm_factory)); return S_OK; } @@ -196,7 +219,7 @@ HRESULT MediaFoundationCdmFactory::CreateCdmInternal( const CdmConfig& cdm_config, ComPtr<IMFContentDecryptionModule>& mf_cdm) { ComPtr<IMFContentDecryptionModuleFactory> cdm_factory; - RETURN_IF_FAILED(CreateMFCdmFactory(key_system, cdm_factory)); + RETURN_IF_FAILED(GetCdmFactory(key_system, cdm_factory)); auto key_system_str = base::UTF8ToWide(key_system); if (!cdm_factory->IsTypeSupported(key_system_str.c_str(), nullptr)) { @@ -213,9 +236,27 @@ HRESULT MediaFoundationCdmFactory::CreateCdmInternal( key_system_str.c_str(), configurations, ARRAYSIZE(configurations), &cdm_access)); + // Don't cache `origin_id` in this class since user can clear it any time. + base::UnguessableToken origin_id = helper_->GetCdmOriginId(); + if (origin_id.is_empty()) { + DLOG(ERROR) << "Failed to get CDM origin ID"; + return E_FAIL; + } + + // Provide a per-user, per-arch, per-origin and per-key-system path. + auto store_path = GetCdmStorePath(user_data_dir_, origin_id, key_system); + DVLOG(1) << "store_path=" << store_path; + + // Ensure the path exists. If it already exists, this call will do nothing. + base::File::Error file_error; + if (!base::CreateDirectoryAndGetError(store_path, &file_error)) { + DLOG(ERROR) << "Create CDM store path failed with " << file_error; + return E_FAIL; + } + ComPtr<IPropertyStore> cdm_properties; ComPtr<IMFContentDecryptionModule> cdm; - RETURN_IF_FAILED(BuildCdmProperties(cdm_properties)); + RETURN_IF_FAILED(BuildCdmProperties(origin_id, store_path, cdm_properties)); RETURN_IF_FAILED( cdm_access->CreateContentDecryptionModule(cdm_properties.Get(), &cdm)); diff --git a/chromium/media/cdm/win/media_foundation_cdm_factory.h b/chromium/media/cdm/win/media_foundation_cdm_factory.h index 98b6d08ca44..4cb2b8d794c 100644 --- a/chromium/media/cdm/win/media_foundation_cdm_factory.h +++ b/chromium/media/cdm/win/media_foundation_cdm_factory.h @@ -9,18 +9,23 @@ #include <wrl.h> #include <map> +#include <memory> #include <string> #include "base/callback.h" +#include "base/files/file_path.h" +#include "base/unguessable_token.h" #include "base/win/scoped_com_initializer.h" #include "media/base/cdm_factory.h" #include "media/base/media_export.h" +#include "media/cdm/cdm_auxiliary_helper.h" namespace media { class MEDIA_EXPORT MediaFoundationCdmFactory : public CdmFactory { public: - MediaFoundationCdmFactory(); + MediaFoundationCdmFactory(std::unique_ptr<CdmAuxiliaryHelper> helper, + const base::FilePath& user_data_dir); MediaFoundationCdmFactory(const MediaFoundationCdmFactory&) = delete; MediaFoundationCdmFactory& operator=(const MediaFoundationCdmFactory&) = delete; @@ -30,8 +35,9 @@ class MEDIA_EXPORT MediaFoundationCdmFactory : public CdmFactory { // support different key systems and for testing. using CreateCdmFactoryCB = base::RepeatingCallback<HRESULT( Microsoft::WRL::ComPtr<IMFContentDecryptionModuleFactory>& factory)>; - void SetCreateCdmFactoryCallback(const std::string& key_system, - CreateCdmFactoryCB create_cdm_factory_cb); + void SetCreateCdmFactoryCallbackForTesting( + const std::string& key_system, + CreateCdmFactoryCB create_cdm_factory_cb); // CdmFactory implementation. void Create(const std::string& key_system, @@ -43,7 +49,7 @@ class MEDIA_EXPORT MediaFoundationCdmFactory : public CdmFactory { CdmCreatedCB cdm_created_cb) final; private: - HRESULT CreateMFCdmFactory( + HRESULT GetCdmFactory( const std::string& key_system, Microsoft::WRL::ComPtr<IMFContentDecryptionModuleFactory>& cdm_factory); HRESULT CreateCdmInternal( @@ -51,6 +57,9 @@ class MEDIA_EXPORT MediaFoundationCdmFactory : public CdmFactory { const CdmConfig& cdm_config, Microsoft::WRL::ComPtr<IMFContentDecryptionModule>& mf_cdm); + std::unique_ptr<CdmAuxiliaryHelper> helper_; + base::FilePath user_data_dir_; + // IMFContentDecryptionModule implementations typically require MTA to run. base::win::ScopedCOMInitializer com_initializer_{ base::win::ScopedCOMInitializer::kMTA}; diff --git a/chromium/media/cdm/win/media_foundation_cdm_factory_unittest.cc b/chromium/media/cdm/win/media_foundation_cdm_factory_unittest.cc index 1ee8da42bf7..c5ac0650a47 100644 --- a/chromium/media/cdm/win/media_foundation_cdm_factory_unittest.cc +++ b/chromium/media/cdm/win/media_foundation_cdm_factory_unittest.cc @@ -11,6 +11,7 @@ #include "media/base/test_helpers.h" #include "media/base/win/mf_helpers.h" #include "media/base/win/mf_mocks.h" +#include "media/cdm/mock_helpers.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -34,7 +35,13 @@ class MediaFoundationCdmFactoryTest : public testing::Test { MediaFoundationCdmFactoryTest() : mf_cdm_factory_(MakeComPtr<MockMFCdmFactory>()), mf_cdm_access_(MakeComPtr<MockMFCdmAccess>()), - mf_cdm_(MakeComPtr<MockMFCdm>()) {} + mf_cdm_(MakeComPtr<MockMFCdm>()) { + auto cdm_helper = + std::make_unique<StrictMock<MockCdmAuxiliaryHelper>>(nullptr); + cdm_helper_ = cdm_helper.get(); + cdm_factory_ = std::make_unique<MediaFoundationCdmFactory>( + std::move(cdm_helper), base::FilePath()); + } ~MediaFoundationCdmFactoryTest() override = default; @@ -48,8 +55,8 @@ class MediaFoundationCdmFactoryTest : public testing::Test { return S_OK; } - void SetCreateCdmFactoryCallback(bool expect_success) { - cdm_factory_.SetCreateCdmFactoryCallback( + void SetCreateCdmFactoryCallbackForTesting(bool expect_success) { + cdm_factory_->SetCreateCdmFactoryCallbackForTesting( kClearKeyKeySystem, base::BindRepeating(&MediaFoundationCdmFactoryTest::GetMockCdmFactory, base::Unretained(this), expect_success)); @@ -57,7 +64,7 @@ class MediaFoundationCdmFactoryTest : public testing::Test { protected: void Create() { - cdm_factory_.Create( + cdm_factory_->Create( kClearKeyKeySystem, kHardwareSecureCdmConfig, base::BindRepeating(&MockCdmClient::OnSessionMessage, base::Unretained(&cdm_client_)), @@ -77,18 +84,21 @@ class MediaFoundationCdmFactoryTest : public testing::Test { ComPtr<MockMFCdmFactory> mf_cdm_factory_; ComPtr<MockMFCdmAccess> mf_cdm_access_; ComPtr<MockMFCdm> mf_cdm_; - MediaFoundationCdmFactory cdm_factory_; + StrictMock<MockCdmAuxiliaryHelper>* cdm_helper_ = nullptr; + std::unique_ptr<MediaFoundationCdmFactory> cdm_factory_; base::MockCallback<CdmCreatedCB> cdm_created_cb_; }; TEST_F(MediaFoundationCdmFactoryTest, Create) { - SetCreateCdmFactoryCallback(/*expect_success=*/true); + SetCreateCdmFactoryCallbackForTesting(/*expect_success=*/true); COM_EXPECT_CALL(mf_cdm_factory_, IsTypeSupported(NotNull(), IsNull())) .WillOnce(Return(TRUE)); COM_EXPECT_CALL(mf_cdm_factory_, CreateContentDecryptionModuleAccess( NotNull(), NotNull(), _, _)) .WillOnce(DoAll(SetComPointee<3>(mf_cdm_access_.Get()), Return(S_OK))); + EXPECT_CALL(*cdm_helper_, GetCdmOriginId()) + .WillOnce(Return(base::UnguessableToken::Create())); COM_EXPECT_CALL(mf_cdm_access_, CreateContentDecryptionModule(NotNull(), _)) .WillOnce(DoAll(SetComPointee<1>(mf_cdm_.Get()), Return(S_OK))); @@ -97,14 +107,14 @@ TEST_F(MediaFoundationCdmFactoryTest, Create) { } TEST_F(MediaFoundationCdmFactoryTest, CreateCdmFactoryFail) { - SetCreateCdmFactoryCallback(/*expect_success=*/false); + SetCreateCdmFactoryCallbackForTesting(/*expect_success=*/false); EXPECT_CALL(cdm_created_cb_, Run(IsNull(), _)); Create(); } TEST_F(MediaFoundationCdmFactoryTest, IsTypeSupportedFail) { - SetCreateCdmFactoryCallback(/*expect_success=*/true); + SetCreateCdmFactoryCallbackForTesting(/*expect_success=*/true); COM_EXPECT_CALL(mf_cdm_factory_, IsTypeSupported(NotNull(), IsNull())) .WillOnce(Return(FALSE)); @@ -114,7 +124,7 @@ TEST_F(MediaFoundationCdmFactoryTest, IsTypeSupportedFail) { } TEST_F(MediaFoundationCdmFactoryTest, CreateCdmAccessFail) { - SetCreateCdmFactoryCallback(/*expect_success=*/true); + SetCreateCdmFactoryCallbackForTesting(/*expect_success=*/true); COM_EXPECT_CALL(mf_cdm_factory_, IsTypeSupported(NotNull(), IsNull())) .WillOnce(Return(TRUE)); @@ -126,14 +136,31 @@ TEST_F(MediaFoundationCdmFactoryTest, CreateCdmAccessFail) { Create(); } +TEST_F(MediaFoundationCdmFactoryTest, NullCdmOriginIdFail) { + SetCreateCdmFactoryCallbackForTesting(/*expect_success=*/true); + + COM_EXPECT_CALL(mf_cdm_factory_, IsTypeSupported(NotNull(), IsNull())) + .WillOnce(Return(TRUE)); + COM_EXPECT_CALL(mf_cdm_factory_, CreateContentDecryptionModuleAccess( + NotNull(), NotNull(), _, _)) + .WillOnce(DoAll(SetComPointee<3>(mf_cdm_access_.Get()), Return(S_OK))); + EXPECT_CALL(*cdm_helper_, GetCdmOriginId()) + .WillOnce(Return(base::UnguessableToken::Null())); + + EXPECT_CALL(cdm_created_cb_, Run(IsNull(), _)); + Create(); +} + TEST_F(MediaFoundationCdmFactoryTest, CreateCdmFail) { - SetCreateCdmFactoryCallback(/*expect_success=*/true); + SetCreateCdmFactoryCallbackForTesting(/*expect_success=*/true); COM_EXPECT_CALL(mf_cdm_factory_, IsTypeSupported(NotNull(), IsNull())) .WillOnce(Return(TRUE)); COM_EXPECT_CALL(mf_cdm_factory_, CreateContentDecryptionModuleAccess( NotNull(), NotNull(), _, _)) .WillOnce(DoAll(SetComPointee<3>(mf_cdm_access_.Get()), Return(S_OK))); + EXPECT_CALL(*cdm_helper_, GetCdmOriginId()) + .WillOnce(Return(base::UnguessableToken::Create())); COM_EXPECT_CALL(mf_cdm_access_, CreateContentDecryptionModule(NotNull(), _)) .WillOnce(DoAll(SetComPointee<1>(mf_cdm_.Get()), Return(E_FAIL))); diff --git a/chromium/media/cdm/win/media_foundation_cdm_module.cc b/chromium/media/cdm/win/media_foundation_cdm_module.cc new file mode 100644 index 00000000000..d0595cf5bd1 --- /dev/null +++ b/chromium/media/cdm/win/media_foundation_cdm_module.cc @@ -0,0 +1,131 @@ +// Copyright 2021 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/cdm/win/media_foundation_cdm_module.h" + +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "base/win/scoped_hstring.h" +#include "media/base/win/mf_helpers.h" + +namespace media { + +namespace { + +using Microsoft::WRL::ComPtr; + +static MediaFoundationCdmModule* g_cdm_module = nullptr; + +} // namespace + +// static +MediaFoundationCdmModule* MediaFoundationCdmModule::GetInstance() { + if (!g_cdm_module) + g_cdm_module = new MediaFoundationCdmModule(); + + return g_cdm_module; +} + +MediaFoundationCdmModule::MediaFoundationCdmModule() = default; +MediaFoundationCdmModule::~MediaFoundationCdmModule() = default; + +void MediaFoundationCdmModule::Initialize(const base::FilePath& cdm_path) { + DVLOG(1) << __func__ << ": cdm_path=" << cdm_path.value(); + + DCHECK(!initialized_); + initialized_ = true; + + cdm_path_ = cdm_path; + + // If `cdm_path_` is not empty, load the CDM before the sandbox is sealed. + if (!cdm_path_.empty()) { + library_ = base::ScopedNativeLibrary(cdm_path_); + LOG_IF(ERROR, !library_.is_valid()) + << __func__ << ": Failed to load CDM at " << cdm_path_.value() + << " (Error: " << library_.GetError()->ToString() << ")"; + } +} + +HRESULT MediaFoundationCdmModule::GetCdmFactory( + const std::string& key_system, + Microsoft::WRL::ComPtr<IMFContentDecryptionModuleFactory>& cdm_factory) { + if (!initialized_) { + DLOG(ERROR) << __func__ << " failed: Not initialized"; + return E_NOT_VALID_STATE; + } + + if (key_system.empty()) { + DLOG(ERROR) << __func__ << " failed: Empty key system"; + return ERROR_INVALID_PARAMETER; + } + + if (key_system_.empty()) + key_system_ = key_system; + + if (key_system != key_system_) { + DLOG(ERROR) << __func__ << " failed: key system mismatch"; + return E_NOT_VALID_STATE; + } + + if (!cdm_factory_) + RETURN_IF_FAILED(ActivateCdmFactory()); + + cdm_factory = cdm_factory_; + return S_OK; +} + +HRESULT MediaFoundationCdmModule::ActivateCdmFactory() { + DCHECK(initialized_); + + // For OS or store CDM, the `cdm_path_` is empty. Just use default creation. + if (cdm_path_.empty()) { + DCHECK(!library_.is_valid()); + ComPtr<IMFMediaEngineClassFactory4> class_factory; + RETURN_IF_FAILED(CoCreateInstance(CLSID_MFMediaEngineClassFactory, nullptr, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&class_factory))); + auto key_system_str = base::UTF8ToWide(key_system_); + RETURN_IF_FAILED(class_factory->CreateContentDecryptionModuleFactory( + key_system_str.c_str(), IID_PPV_ARGS(&cdm_factory_))); + return S_OK; + } + + if (!library_.is_valid()) { + LOG(ERROR) << "CDM failed to load previously"; + return E_FAIL; + } + + // Initialization required to call base::win::ScopedHString::Create(); + if (!base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) + return E_FAIL; + + // Get function pointer to the activation factory. + using GetActivationFactoryFunc = + HRESULT(WINAPI*)(_In_ HSTRING activatible_class_id, + _COM_Outptr_ IActivationFactory * *factory); + const char kDllGetActivationFactory[] = "DllGetActivationFactory"; + auto get_activation_factory_func = reinterpret_cast<GetActivationFactoryFunc>( + library_.GetFunctionPointer(kDllGetActivationFactory)); + if (!get_activation_factory_func) { + LOG(ERROR) << "Cannot get function " << kDllGetActivationFactory; + return E_FAIL; + } + + // Activate CdmFactory. Assuming the class ID is always in the format + // "<key_system>.ContentDecryptionModuleFactory". + auto class_name = base::win::ScopedHString::Create( + base::StringPiece(key_system_ + ".ContentDecryptionModuleFactory")); + ComPtr<IActivationFactory> activation_factory; + RETURN_IF_FAILED( + get_activation_factory_func(class_name.get(), &activation_factory)); + + ComPtr<IInspectable> inspectable_factory; + RETURN_IF_FAILED(activation_factory->ActivateInstance(&inspectable_factory)); + RETURN_IF_FAILED(inspectable_factory.As(&cdm_factory_)); + + return S_OK; +} + +} // namespace media diff --git a/chromium/media/cdm/win/media_foundation_cdm_module.h b/chromium/media/cdm/win/media_foundation_cdm_module.h new file mode 100644 index 00000000000..7f438127024 --- /dev/null +++ b/chromium/media/cdm/win/media_foundation_cdm_module.h @@ -0,0 +1,58 @@ +// Copyright 2021 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. + +#ifndef MEDIA_CDM_WIN_MEDIA_FOUNDATION_CDM_MODULE_H_ +#define MEDIA_CDM_WIN_MEDIA_FOUNDATION_CDM_MODULE_H_ + +#include <string> + +#include <mfcontentdecryptionmodule.h> +#include <wrl.h> + +#include "base/files/file_path.h" +#include "base/scoped_native_library.h" +#include "media/base/media_export.h" + +namespace media { + +// A singleton in the MediaFoundationService process in charge of CDM loading +// and IMFContentDecryptionModuleFactory activation. +class MEDIA_EXPORT MediaFoundationCdmModule { + public: + static MediaFoundationCdmModule* GetInstance(); + + // Loads the CDM at `cdm_path` if not empty. So `ActivateCdmFactory()` can + // activate the IMFContentDecryptionModuleFactory from the CDM later. If the + // CDM is an OS or store CDM, `cdm_path` could be empty. See implementation + // details in ActivateCdmFactory() for how OS or store CDMs are handled. + // The caller should check `initialized()` and only call this function once. + void Initialize(const base::FilePath& cdm_path); + + HRESULT GetCdmFactory( + const std::string& key_system, + Microsoft::WRL::ComPtr<IMFContentDecryptionModuleFactory>& cdm_factory); + + bool initialized() const { return initialized_; } + const base::FilePath& cdm_path() const { return cdm_path_; } + + private: + MediaFoundationCdmModule(); + MediaFoundationCdmModule(const MediaFoundationCdmModule&) = delete; + MediaFoundationCdmModule& operator=(const MediaFoundationCdmModule&) = delete; + ~MediaFoundationCdmModule(); + + HRESULT ActivateCdmFactory(); + + // Declared first so it's destructed after `cdm_factory_`. + base::ScopedNativeLibrary library_; + + bool initialized_ = false; + base::FilePath cdm_path_; + std::string key_system_; + Microsoft::WRL::ComPtr<IMFContentDecryptionModuleFactory> cdm_factory_; +}; + +} // namespace media + +#endif // MEDIA_CDM_WIN_MEDIA_FOUNDATION_CDM_MODULE_H_ diff --git a/chromium/media/device_monitors/device_monitor_mac.mm b/chromium/media/device_monitors/device_monitor_mac.mm index 26bab09017d..91df5c668ec 100644 --- a/chromium/media/device_monitors/device_monitor_mac.mm +++ b/chromium/media/device_monitors/device_monitor_mac.mm @@ -134,7 +134,8 @@ class SuspendObserverDelegate; base::ThreadChecker _mainThreadChecker; } -- (id)initWithOnChangedCallback:(const base::RepeatingClosure&)callback; +- (instancetype)initWithOnChangedCallback: + (const base::RepeatingClosure&)callback; - (void)startObserving:(base::scoped_nsobject<AVCaptureDevice>)device; - (void)stopObserving:(AVCaptureDevice*)device; - (void)clearOnDeviceChangedCallback; @@ -348,7 +349,8 @@ void AVFoundationMonitorImpl::OnDeviceChanged() { @implementation CrAVFoundationDeviceObserver -- (id)initWithOnChangedCallback:(const base::RepeatingClosure&)callback { +- (instancetype)initWithOnChangedCallback: + (const base::RepeatingClosure&)callback { DCHECK(_mainThreadChecker.CalledOnValidThread()); if ((self = [super init])) { DCHECK(!callback.is_null()); diff --git a/chromium/media/device_monitors/system_message_window_win.cc b/chromium/media/device_monitors/system_message_window_win.cc index d20145cdfa9..30a7294070a 100644 --- a/chromium/media/device_monitors/system_message_window_win.cc +++ b/chromium/media/device_monitors/system_message_window_win.cc @@ -7,6 +7,8 @@ #include <dbt.h> #include <stddef.h> +#include <memory> + #include "base/logging.h" #include "base/no_destructor.h" #include "base/stl_util.h" @@ -98,7 +100,7 @@ SystemMessageWindowWin::SystemMessageWindowWin() { window_ = CreateWindow(kWindowClassName, 0, 0, 0, 0, 0, 0, 0, 0, instance_, 0); SetWindowLongPtr(window_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this)); - device_notifications_.reset(new DeviceNotifications(window_)); + device_notifications_ = std::make_unique<DeviceNotifications>(window_); } SystemMessageWindowWin::~SystemMessageWindowWin() { diff --git a/chromium/media/filters/BUILD.gn b/chromium/media/filters/BUILD.gn index 3cc37a4379f..9f7dc8c0036 100644 --- a/chromium/media/filters/BUILD.gn +++ b/chromium/media/filters/BUILD.gn @@ -11,6 +11,7 @@ source_set("filters") { # should be using //media and not directly DEP this roll-up target. visibility = [ "//media", + "//media/fuchsia/audio", "//media/renderers", ] diff --git a/chromium/media/filters/android/media_codec_audio_decoder.cc b/chromium/media/filters/android/media_codec_audio_decoder.cc index 1486e1adb2b..a2840b746dd 100644 --- a/chromium/media/filters/android/media_codec_audio_decoder.cc +++ b/chromium/media/filters/android/media_codec_audio_decoder.cc @@ -5,6 +5,7 @@ #include "media/filters/android/media_codec_audio_decoder.h" #include <cmath> +#include <memory> #include "base/android/build_info.h" #include "base/bind.h" @@ -153,10 +154,10 @@ bool MediaCodecAudioDecoder::CreateMediaCodecLoop() { return false; } - codec_loop_.reset( - new MediaCodecLoop(base::android::BuildInfo::GetInstance()->sdk_int(), - this, std::move(audio_codec_bridge), - scoped_refptr<base::SingleThreadTaskRunner>())); + codec_loop_ = std::make_unique<MediaCodecLoop>( + base::android::BuildInfo::GetInstance()->sdk_int(), this, + std::move(audio_codec_bridge), + scoped_refptr<base::SingleThreadTaskRunner>()); return true; } @@ -491,7 +492,7 @@ bool MediaCodecAudioDecoder::OnOutputFormatChanged() { timestamp_helper_->base_timestamp() == kNoTimestamp ? kNoTimestamp : timestamp_helper_->GetTimestamp(); - timestamp_helper_.reset(new AudioTimestampHelper(sample_rate_)); + timestamp_helper_ = std::make_unique<AudioTimestampHelper>(sample_rate_); if (base_timestamp != kNoTimestamp) timestamp_helper_->SetBaseTimestamp(base_timestamp); } @@ -523,7 +524,7 @@ void MediaCodecAudioDecoder::SetInitialConfiguration() { channel_count_ = ChannelLayoutToChannelCount(channel_layout_); sample_rate_ = config_.samples_per_second(); - timestamp_helper_.reset(new AudioTimestampHelper(sample_rate_)); + timestamp_helper_ = std::make_unique<AudioTimestampHelper>(sample_rate_); } void MediaCodecAudioDecoder::PumpMediaCodecLoop() { diff --git a/chromium/media/filters/android/media_codec_audio_decoder.h b/chromium/media/filters/android/media_codec_audio_decoder.h index ef8433c07a3..acf37982cb2 100644 --- a/chromium/media/filters/android/media_codec_audio_decoder.h +++ b/chromium/media/filters/android/media_codec_audio_decoder.h @@ -12,7 +12,6 @@ #include "base/containers/circular_deque.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/time/time.h" #include "base/timer/timer.h" #include "media/base/android/media_codec_loop.h" #include "media/base/android/media_crypto_context.h" diff --git a/chromium/media/filters/android/video_frame_extractor.h b/chromium/media/filters/android/video_frame_extractor.h index 53257da31af..11755107976 100644 --- a/chromium/media/filters/android/video_frame_extractor.h +++ b/chromium/media/filters/android/video_frame_extractor.h @@ -11,7 +11,6 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/time/time.h" #include "media/base/media_export.h" #include "media/filters/ffmpeg_demuxer.h" diff --git a/chromium/media/filters/audio_decoder_unittest.cc b/chromium/media/filters/audio_decoder_unittest.cc index 7b3899f6007..6abf4283f02 100644 --- a/chromium/media/filters/audio_decoder_unittest.cc +++ b/chromium/media/filters/audio_decoder_unittest.cc @@ -139,8 +139,8 @@ class AudioDecoderTest break; #if defined(OS_ANDROID) case MEDIA_CODEC: - decoder_.reset(new MediaCodecAudioDecoder( - task_environment_.GetMainThreadTaskRunner())); + decoder_ = std::make_unique<MediaCodecAudioDecoder>( + task_environment_.GetMainThreadTaskRunner()); break; #endif } diff --git a/chromium/media/filters/audio_renderer_algorithm.cc b/chromium/media/filters/audio_renderer_algorithm.cc index ef1196f1f34..d3e1e1fc834 100644 --- a/chromium/media/filters/audio_renderer_algorithm.cc +++ b/chromium/media/filters/audio_renderer_algorithm.cc @@ -357,7 +357,7 @@ void AudioRendererAlgorithm::EnqueueBuffer( } void AudioRendererAlgorithm::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { DCHECK_GE(playback_threshold_, min_playback_threshold_); DCHECK_LE(playback_threshold_, capacity_); DCHECK_LE(capacity_, max_capacity_); diff --git a/chromium/media/filters/audio_renderer_algorithm.h b/chromium/media/filters/audio_renderer_algorithm.h index 9c07d2ecee0..f2a1f779e5e 100644 --- a/chromium/media/filters/audio_renderer_algorithm.h +++ b/chromium/media/filters/audio_renderer_algorithm.h @@ -83,7 +83,7 @@ class MEDIA_EXPORT AudioRendererAlgorithm { // Sets a target queue latency. This target will be clamped and stored in // |playback_threshold_|. It may also cause an increase in |capacity_|. A // value of nullopt indicates the algorithm should restore the default value. - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint); + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint); // Sets a flag indicating whether apply pitch adjustments when playing back // at rates other than 1.0. Concretely, we use WSOLA when this is true, and @@ -217,7 +217,7 @@ class MEDIA_EXPORT AudioRendererAlgorithm { // Hint to adjust |playback_threshold_| as a means of controlling playback // start latency. See SetLatencyHint(); - base::Optional<base::TimeDelta> latency_hint_; + absl::optional<base::TimeDelta> latency_hint_; // Whether to apply pitch adjusments or not when playing back at rates other // than 1.0. In other words, we use WSOLA to preserve pitch when this is on, diff --git a/chromium/media/filters/audio_renderer_algorithm_unittest.cc b/chromium/media/filters/audio_renderer_algorithm_unittest.cc index b5a0eeb9569..b6ea7271944 100644 --- a/chromium/media/filters/audio_renderer_algorithm_unittest.cc +++ b/chromium/media/filters/audio_renderer_algorithm_unittest.cc @@ -976,7 +976,7 @@ TEST_F(AudioRendererAlgorithmTest, LowLatencyHint) { // Clearing the hint should restore the higher default playback threshold, // such that we no longer have enough buffer to be "adequate for playback". - algorithm_.SetLatencyHint(base::nullopt); + algorithm_.SetLatencyHint(absl::nullopt); EXPECT_FALSE(algorithm_.IsQueueAdequateForPlayback()); // Fill until "full". Verify that "adequate" now matches "full". @@ -1027,7 +1027,7 @@ TEST_F(AudioRendererAlgorithmTest, HighLatencyHint) { // Clearing the hint should restore the lower default playback threshold and // capacity. - algorithm_.SetLatencyHint(base::nullopt); + algorithm_.SetLatencyHint(absl::nullopt); EXPECT_EQ(algorithm_.QueueCapacity(), default_capacity); // The queue is over-full from our last fill when the hint was set. Flush and diff --git a/chromium/media/filters/audio_video_metadata_extractor.h b/chromium/media/filters/audio_video_metadata_extractor.h index 425793317af..b875caeaf04 100644 --- a/chromium/media/filters/audio_video_metadata_extractor.h +++ b/chromium/media/filters/audio_video_metadata_extractor.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_BASE_AUDIO_VIDEO_METADATA_EXTRACTOR_H_ -#define MEDIA_BASE_AUDIO_VIDEO_METADATA_EXTRACTOR_H_ +#ifndef MEDIA_FILTERS_AUDIO_VIDEO_METADATA_EXTRACTOR_H_ +#define MEDIA_FILTERS_AUDIO_VIDEO_METADATA_EXTRACTOR_H_ #include <map> #include <string> @@ -110,4 +110,4 @@ class MEDIA_EXPORT AudioVideoMetadataExtractor { } // namespace media -#endif // MEDIA_BASE_AUDIO_VIDEO_METADATA_EXTRACTOR_H_ +#endif // MEDIA_FILTERS_AUDIO_VIDEO_METADATA_EXTRACTOR_H_ diff --git a/chromium/media/filters/chunk_demuxer.cc b/chromium/media/filters/chunk_demuxer.cc index 5f650f37ec4..9965a49d5dd 100644 --- a/chromium/media/filters/chunk_demuxer.cc +++ b/chromium/media/filters/chunk_demuxer.cc @@ -570,9 +570,9 @@ int64_t ChunkDemuxer::GetMemoryUsage() const { return mem; } -base::Optional<container_names::MediaContainerName> +absl::optional<container_names::MediaContainerName> ChunkDemuxer::GetContainerForMetrics() const { - return base::nullopt; + return absl::nullopt; } void ChunkDemuxer::AbortPendingReads() { diff --git a/chromium/media/filters/chunk_demuxer.h b/chromium/media/filters/chunk_demuxer.h index 68a2488a13a..6f40e9c3656 100644 --- a/chromium/media/filters/chunk_demuxer.h +++ b/chromium/media/filters/chunk_demuxer.h @@ -225,7 +225,7 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { std::vector<DemuxerStream*> GetAllStreams() override; base::TimeDelta GetStartTime() const override; int64_t GetMemoryUsage() const override; - base::Optional<container_names::MediaContainerName> GetContainerForMetrics() + absl::optional<container_names::MediaContainerName> GetContainerForMetrics() const override; void AbortPendingReads() override; diff --git a/chromium/media/filters/decrypting_audio_decoder.h b/chromium/media/filters/decrypting_audio_decoder.h index ce507173ea2..9ca951e2950 100644 --- a/chromium/media/filters/decrypting_audio_decoder.h +++ b/chromium/media/filters/decrypting_audio_decoder.h @@ -11,7 +11,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/time/time.h" #include "media/base/audio_decoder.h" #include "media/base/callback_registry.h" #include "media/base/cdm_context.h" diff --git a/chromium/media/filters/ffmpeg_audio_decoder.h b/chromium/media/filters/ffmpeg_audio_decoder.h index 58b132a7445..bd8f074e23b 100644 --- a/chromium/media/filters/ffmpeg_audio_decoder.h +++ b/chromium/media/filters/ffmpeg_audio_decoder.h @@ -11,7 +11,6 @@ #include "base/callback.h" #include "base/macros.h" #include "base/sequence_checker.h" -#include "base/time/time.h" #include "media/base/audio_buffer.h" #include "media/base/audio_decoder.h" #include "media/base/demuxer_stream.h" diff --git a/chromium/media/filters/ffmpeg_demuxer.cc b/chromium/media/filters/ffmpeg_demuxer.cc index 828b043c051..9dfa1ddee89 100644 --- a/chromium/media/filters/ffmpeg_demuxer.cc +++ b/chromium/media/filters/ffmpeg_demuxer.cc @@ -585,6 +585,20 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { base::TimeDelta::FromMicroseconds(1)); } + // Fixup negative timestamps where the before-zero portion is completely + // discarded after decoding. + if (buffer->timestamp() < base::TimeDelta()) { + // Discard padding may also remove samples after zero. + auto fixed_ts = buffer->discard_padding().first + buffer->timestamp(); + + // Allow for rounding error in the discard padding calculations. + if (fixed_ts == base::TimeDelta::FromMicroseconds(-1)) + fixed_ts = base::TimeDelta(); + + if (fixed_ts >= base::TimeDelta()) + buffer->set_timestamp(fixed_ts); + } + // Only allow negative timestamps past if we know they'll be fixed up by the // code paths below; otherwise they should be treated as a parse error. if ((!fixup_chained_ogg_ || last_packet_timestamp_ == kNoTimestamp) && @@ -1173,7 +1187,7 @@ int64_t FFmpegDemuxer::GetMemoryUsage() const { return allocation_size; } -base::Optional<container_names::MediaContainerName> +absl::optional<container_names::MediaContainerName> FFmpegDemuxer::GetContainerForMetrics() const { return container(); } diff --git a/chromium/media/filters/ffmpeg_demuxer.h b/chromium/media/filters/ffmpeg_demuxer.h index c2fc118b3ca..b137a2b5685 100644 --- a/chromium/media/filters/ffmpeg_demuxer.h +++ b/chromium/media/filters/ffmpeg_demuxer.h @@ -229,7 +229,7 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer { std::vector<DemuxerStream*> GetAllStreams() override; base::TimeDelta GetStartTime() const override; int64_t GetMemoryUsage() const override; - base::Optional<container_names::MediaContainerName> GetContainerForMetrics() + absl::optional<container_names::MediaContainerName> GetContainerForMetrics() const override; // Calls |encrypted_media_init_data_cb_| with the initialization data diff --git a/chromium/media/filters/ffmpeg_demuxer_unittest.cc b/chromium/media/filters/ffmpeg_demuxer_unittest.cc index 63f7c08feed..8391036bda1 100644 --- a/chromium/media/filters/ffmpeg_demuxer_unittest.cc +++ b/chromium/media/filters/ffmpeg_demuxer_unittest.cc @@ -11,7 +11,6 @@ #include <utility> #include "base/bind.h" -#include "base/callback_forward.h" #include "base/files/file_path.h" #include "base/location.h" #include "base/logging.h" diff --git a/chromium/media/filters/ffmpeg_video_decoder.cc b/chromium/media/filters/ffmpeg_video_decoder.cc index c9ca3a8b6fa..6ee981a2942 100644 --- a/chromium/media/filters/ffmpeg_video_decoder.cc +++ b/chromium/media/filters/ffmpeg_video_decoder.cc @@ -109,7 +109,7 @@ SupportedVideoDecoderConfigs FFmpegVideoDecoder::SupportedConfigsForWebRTC() { } FFmpegVideoDecoder::FFmpegVideoDecoder(MediaLog* media_log) - : media_log_(media_log), state_(kUninitialized), decode_nalus_(false) { + : media_log_(media_log) { DVLOG(1) << __func__; DETACH_FROM_SEQUENCE(sequence_checker_); } @@ -159,6 +159,9 @@ int FFmpegVideoDecoder::GetVideoBuffer(struct AVCodecContext* codec_context, gfx::Size coded_size(std::max(size.width(), codec_context->coded_width), std::max(size.height(), codec_context->coded_height)); + if (force_allocation_error_) + return AVERROR(EINVAL); + // FFmpeg expects the initial allocation to be zero-initialized. Failure to // do so can lead to uninitialized value usage. See http://crbug.com/390941 scoped_refptr<VideoFrame> video_frame = frame_pool_.CreateFrame( diff --git a/chromium/media/filters/ffmpeg_video_decoder.h b/chromium/media/filters/ffmpeg_video_decoder.h index 4436e2bf906..08b59748605 100644 --- a/chromium/media/filters/ffmpeg_video_decoder.h +++ b/chromium/media/filters/ffmpeg_video_decoder.h @@ -57,6 +57,8 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { AVFrame* frame, int flags); + void force_allocation_error_for_testing() { force_allocation_error_ = true; } + private: enum DecoderState { kUninitialized, @@ -79,9 +81,9 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { SEQUENCE_CHECKER(sequence_checker_); - MediaLog* media_log_; + MediaLog* const media_log_; - DecoderState state_; + DecoderState state_ = kUninitialized; OutputCB output_cb_; @@ -92,7 +94,9 @@ class MEDIA_EXPORT FFmpegVideoDecoder : public VideoDecoder { VideoFramePool frame_pool_; - bool decode_nalus_; + bool decode_nalus_ = false; + + bool force_allocation_error_ = false; std::unique_ptr<FFmpegDecodingLoop> decoding_loop_; diff --git a/chromium/media/filters/ffmpeg_video_decoder_unittest.cc b/chromium/media/filters/ffmpeg_video_decoder_unittest.cc index 3a07a387ad1..dead41951b0 100644 --- a/chromium/media/filters/ffmpeg_video_decoder_unittest.cc +++ b/chromium/media/filters/ffmpeg_video_decoder_unittest.cc @@ -260,6 +260,14 @@ TEST_F(FFmpegVideoDecoderTest, DecodeFrame_Normal) { ASSERT_EQ(1U, output_frames_.size()); } +TEST_F(FFmpegVideoDecoderTest, DecodeFrame_OOM) { + Initialize(); + decoder_->force_allocation_error_for_testing(); + EXPECT_MEDIA_LOG(_); + EXPECT_FALSE(DecodeSingleFrame(i_frame_buffer_).is_ok()); + EXPECT_TRUE(output_frames_.empty()); +} + TEST_F(FFmpegVideoDecoderTest, DecodeFrame_DecodeError) { Initialize(); diff --git a/chromium/media/filters/file_data_source.h b/chromium/media/filters/file_data_source.h index 60fdcbe6be7..7b5fd6d340d 100644 --- a/chromium/media/filters/file_data_source.h +++ b/chromium/media/filters/file_data_source.h @@ -7,8 +7,6 @@ #include <stdint.h> -#include <string> - #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/memory_mapped_file.h" diff --git a/chromium/media/filters/frame_buffer_pool.cc b/chromium/media/filters/frame_buffer_pool.cc index c6aa7d03b4a..e3978b47284 100644 --- a/chromium/media/filters/frame_buffer_pool.cc +++ b/chromium/media/filters/frame_buffer_pool.cc @@ -9,6 +9,8 @@ #include "base/check_op.h" #include "base/location.h" #include "base/macros.h" +#include "base/memory/free_deleter.h" +#include "base/process/memory.h" #include "base/sequenced_task_runner.h" #include "base/stl_util.h" #include "base/threading/sequenced_task_runner_handle.h" @@ -21,9 +23,9 @@ namespace media { struct FrameBufferPool::FrameBuffer { // Not using std::vector<uint8_t> as resize() calls take a really long time // for large buffers. - std::unique_ptr<uint8_t[]> data; + std::unique_ptr<uint8_t, base::FreeDeleter> data; size_t data_size = 0u; - std::unique_ptr<uint8_t[]> alpha_data; + std::unique_ptr<uint8_t, base::FreeDeleter> alpha_data; size_t alpha_data_size = 0u; bool held_by_library = false; // Needs to be a counter since a frame buffer might be used multiple times. @@ -71,7 +73,16 @@ uint8_t* FrameBufferPool::GetFrameBuffer(size_t min_size, void** fb_priv) { // Free the existing |data| first so that the memory can be reused, // if possible. Note that the new array is purposely not initialized. frame_buffer->data.reset(); - frame_buffer->data.reset(new uint8_t[min_size]); + + uint8_t* data = nullptr; + if (force_allocation_error_ || + !base::UncheckedMalloc(min_size, reinterpret_cast<void**>(&data)) || + !data) { + frame_buffers_.erase(it); + return nullptr; + } + + frame_buffer->data.reset(data); frame_buffer->data_size = min_size; } @@ -102,7 +113,13 @@ uint8_t* FrameBufferPool::AllocateAlphaPlaneForFrameBuffer(size_t min_size, // Free the existing |alpha_data| first so that the memory can be reused, // if possible. Note that the new array is purposely not initialized. frame_buffer->alpha_data.reset(); - frame_buffer->alpha_data.reset(new uint8_t[min_size]); + uint8_t* data = nullptr; + if (force_allocation_error_ || + !base::UncheckedMalloc(min_size, reinterpret_cast<void**>(&data)) || + !data) { + return nullptr; + } + frame_buffer->alpha_data.reset(data); frame_buffer->alpha_data_size = min_size; } return frame_buffer->alpha_data.get(); diff --git a/chromium/media/filters/frame_buffer_pool.h b/chromium/media/filters/frame_buffer_pool.h index 9dddec6fb5d..d96132ed6c3 100644 --- a/chromium/media/filters/frame_buffer_pool.h +++ b/chromium/media/filters/frame_buffer_pool.h @@ -14,7 +14,6 @@ #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" #include "base/time/default_tick_clock.h" -#include "base/time/time.h" #include "base/trace_event/memory_dump_provider.h" #include "media/base/media_export.h" @@ -55,6 +54,8 @@ class MEDIA_EXPORT FrameBufferPool tick_clock_ = tick_clock; } + void force_allocation_error_for_testing() { force_allocation_error_ = true; } + // Called when no more GetFrameBuffer() calls are expected. All unused memory // is released at this time. As frames are returned their memory is released. // This should not be called until anything that might call GetFrameBuffer() @@ -92,6 +93,8 @@ class MEDIA_EXPORT FrameBufferPool bool registered_dump_provider_ = false; + bool force_allocation_error_ = false; + // |tick_clock_| is always a DefaultTickClock outside of testing. const base::TickClock* tick_clock_; diff --git a/chromium/media/filters/frame_buffer_pool_unittest.cc b/chromium/media/filters/frame_buffer_pool_unittest.cc index 8644ce37092..0cdf4d040b0 100644 --- a/chromium/media/filters/frame_buffer_pool_unittest.cc +++ b/chromium/media/filters/frame_buffer_pool_unittest.cc @@ -57,6 +57,18 @@ TEST(FrameBufferPool, BasicFunctionality) { EXPECT_EQ(0u, pool->get_pool_size_for_testing()); } +TEST(FrameBufferPool, ForceAllocationError) { + base::TestMessageLoop message_loop; + scoped_refptr<FrameBufferPool> pool = new FrameBufferPool(); + pool->force_allocation_error_for_testing(); + + void* priv1 = nullptr; + uint8_t* buf1 = pool->GetFrameBuffer(kBufferSize, &priv1); + ASSERT_FALSE(priv1); + ASSERT_FALSE(buf1); + pool->Shutdown(); +} + TEST(FrameBufferPool, DeferredDestruction) { base::TestMessageLoop message_loop; scoped_refptr<FrameBufferPool> pool = new FrameBufferPool(); diff --git a/chromium/media/filters/fuchsia/DIR_METADATA b/chromium/media/filters/fuchsia/DIR_METADATA index e88f62328ca..abc57ac0fd5 100644 --- a/chromium/media/filters/fuchsia/DIR_METADATA +++ b/chromium/media/filters/fuchsia/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto team_email: "cr-fuchsia@chromium.org" os: FUCHSIA
\ No newline at end of file diff --git a/chromium/media/filters/fuchsia/OWNERS b/chromium/media/filters/fuchsia/OWNERS index 3ebcc4268bd..e7034eabb1e 100644 --- a/chromium/media/filters/fuchsia/OWNERS +++ b/chromium/media/filters/fuchsia/OWNERS @@ -1 +1 @@ -file://build/fuchsia/OWNERS
\ No newline at end of file +file://build/fuchsia/OWNERS diff --git a/chromium/media/filters/fuchsia/fuchsia_video_decoder.cc b/chromium/media/filters/fuchsia/fuchsia_video_decoder.cc index fe5075e3d8e..d84c36aa7e9 100644 --- a/chromium/media/filters/fuchsia/fuchsia_video_decoder.cc +++ b/chromium/media/filters/fuchsia/fuchsia_video_decoder.cc @@ -6,10 +6,8 @@ #include <fuchsia/media/cpp/fidl.h> #include <fuchsia/mediacodec/cpp/fidl.h> -#include <fuchsia/sysmem/cpp/fidl.h> #include <lib/sys/cpp/component_context.h> #include <vulkan/vulkan.h> -#include <zircon/rights.h> #include "base/bind.h" #include "base/bits.h" @@ -31,7 +29,6 @@ #include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h" #include "media/base/bind_to_current_loop.h" #include "media/base/cdm_context.h" -#include "media/base/decryptor.h" #include "media/base/media_switches.h" #include "media/base/video_decoder.h" #include "media/base/video_decoder_config.h" @@ -40,9 +37,10 @@ #include "media/fuchsia/cdm/fuchsia_cdm_context.h" #include "media/fuchsia/cdm/fuchsia_decryptor.h" #include "media/fuchsia/cdm/fuchsia_stream_decryptor.h" +#include "media/fuchsia/common/decrypting_sysmem_buffer_stream.h" +#include "media/fuchsia/common/passthrough_sysmem_buffer_stream.h" #include "media/fuchsia/common/stream_processor_helper.h" -#include "media/fuchsia/common/sysmem_buffer_pool.h" -#include "media/fuchsia/common/sysmem_buffer_writer_queue.h" +#include "media/fuchsia/common/sysmem_client.h" #include "third_party/libyuv/include/libyuv/video_common.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/client_native_pixmap_factory.h" @@ -55,24 +53,26 @@ namespace { // Number of output buffers allocated "for camping". This value is passed to // sysmem to ensure that we get one output buffer for the frame currently // displayed on the screen. -const uint32_t kOutputBuffersForCamping = 1; +constexpr uint32_t kOutputBuffersForCamping = 1; // Maximum number of frames we expect to have queued up while playing video. // Higher values require more memory for output buffers. Lower values make it // more likely that renderer will stall because decoded frames are not available // on time. -const uint32_t kMaxUsedOutputBuffers = 5; +constexpr uint32_t kMaxUsedOutputBuffers = 5; -// Use 2 buffers for decoder input. Limiting total number of buffers to 2 allows -// to minimize required memory without significant effect on performance. -const size_t kNumInputBuffers = 2; +// Use 2 buffers for decoder input. Allocating more than one buffers ensures +// that when the decoder is done working on one packet it will have another one +// waiting in the queue. Limiting number of buffers to 2 allows to minimize +// required memory, without significant effect on performance. +constexpr size_t kNumInputBuffers = 2; // Some codecs do not support splitting video frames across multiple input // buffers, so the buffers need to be large enough to fit all video frames. The -// buffer size is calculated to fit 1080p frame with MinCR=2 (per H264 spec), -// plus 128KiB for SEI/SPS/PPS. (note that the same size is used for all codecs, -// not just H264). -const size_t kInputBufferSize = 1920 * 1080 * 3 / 2 / 2 + 128 * 1024; +// buffer size is calculated to fit 1080p I420 frame with MinCR=2 (per H264 +// spec), plus 128KiB for SEI/SPS/PPS. (note that the same size is used for all +// codecs, not just H264). +constexpr size_t kInputBufferSize = 1920 * 1080 * 3 / 2 / 2 + 128 * 1024; // Helper used to hold mailboxes for the output textures. OutputMailbox may // outlive FuchsiaVideoDecoder if is referenced by a VideoFrame. @@ -82,10 +82,9 @@ class OutputMailbox { scoped_refptr<viz::RasterContextProvider> raster_context_provider, std::unique_ptr<gfx::GpuMemoryBuffer> gmb) : raster_context_provider_(raster_context_provider), weak_factory_(this) { - uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER | - gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION | - gpu::SHARED_IMAGE_USAGE_DISPLAY | - gpu::SHARED_IMAGE_USAGE_SCANOUT; + uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY | + gpu::SHARED_IMAGE_USAGE_SCANOUT | + gpu::SHARED_IMAGE_USAGE_VIDEO_DECODE; mailbox_ = raster_context_provider_->SharedImageInterface()->CreateSharedImage( gmb.get(), nullptr, gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, @@ -186,13 +185,17 @@ struct InputDecoderPacket { } // namespace class FuchsiaVideoDecoder : public VideoDecoder, - public FuchsiaSecureStreamDecryptor::Client { + public SysmemBufferStream::Sink, + public StreamProcessorHelper::Client { public: FuchsiaVideoDecoder( scoped_refptr<viz::RasterContextProvider> raster_context_provider, bool enable_sw_decoding); ~FuchsiaVideoDecoder() override; + FuchsiaVideoDecoder(const FuchsiaVideoDecoder&) = delete; + FuchsiaVideoDecoder& operator=(const FuchsiaVideoDecoder&) = delete; + // Decoder implementation. bool IsPlatformDecoder() const override; bool SupportsDecryption() const override; @@ -212,29 +215,33 @@ class FuchsiaVideoDecoder : public VideoDecoder, int GetMaxDecodeRequests() const override; private: - bool InitializeDecryptor(CdmContext* cdm_context); - - // FuchsiaSecureStreamDecryptor::Client implementation. - size_t GetInputBufferSize() override; - void OnDecryptorOutputPacket(StreamProcessorHelper::IoPacket packet) override; - void OnDecryptorEndOfStreamPacket() override; - void OnDecryptorError() override; - void OnDecryptorNoKey() override; - - // Event handlers for |decoder_|. - void OnStreamFailed(uint64_t stream_lifetime_ordinal, - fuchsia::media::StreamError error); - void OnInputConstraints( - fuchsia::media::StreamBufferConstraints input_constraints); - void OnFreeInputPacket(fuchsia::media::PacketHeader free_input_packet); - void OnOutputConstraints( - fuchsia::media::StreamOutputConstraints output_constraints); - void OnOutputFormat(fuchsia::media::StreamOutputFormat output_format); - void OnOutputPacket(fuchsia::media::Packet output_packet, - bool error_detected_before, - bool error_detected_during); - void OnOutputEndOfStream(uint64_t stream_lifetime_ordinal, - bool error_detected_before); + StatusCode InitializeSysmemBufferStream(bool is_encrypted, + CdmContext* cdm_context, + bool* secure_mode); + + // SysmemBufferStream::Sink implementation. + void OnSysmemBufferStreamBufferCollectionToken( + fuchsia::sysmem::BufferCollectionTokenPtr token) override; + void OnSysmemBufferStreamOutputPacket( + StreamProcessorHelper::IoPacket packet) override; + void OnSysmemBufferStreamEndOfStream() override; + void OnSysmemBufferStreamError() override; + void OnSysmemBufferStreamNoKey() override; + + // StreamProcessorHelper::Client implementation. + void OnStreamProcessorAllocateOutputBuffers( + const fuchsia::media::StreamBufferConstraints& stream_constraints) + override; + void OnStreamProcessorEndOfStream() override; + void OnStreamProcessorOutputFormat( + fuchsia::media::StreamOutputFormat format) override; + void OnStreamProcessorOutputPacket( + StreamProcessorHelper::IoPacket packet) override; + void OnStreamProcessorNoKey() override; + void OnStreamProcessorError() override; + + // Calls next callback in the |decode_callbacks_| queue. + void CallNextDecodeCallback(); // Drops all pending input buffers and then calls all pending DecodeCB with // |status|. Returns true if the decoder still exists. @@ -243,29 +250,15 @@ class FuchsiaVideoDecoder : public VideoDecoder, // Called on errors to shutdown the decoder and notify the client. void OnError(); - // Callback for |input_buffer_collection_creator_->Create()|. - void OnInputBufferPoolCreated(std::unique_ptr<SysmemBufferPool> pool); - - // Callback for |input_buffer_collection_->CreateWriter()|. - void OnWriterCreated(std::unique_ptr<SysmemBufferWriter> writer); - - // Callbacks for |input_writer_|. - void SendInputPacket(const DecoderBuffer* buffer, - StreamProcessorHelper::IoPacket packet); - void ProcessEndOfStream(); + // Callback for SysmemBufferCollection::CreateSharedToken(), used to send the + // sysmem buffer collection token to the GPU process. + void SetBufferCollectionTokenForGpu( + fuchsia::sysmem::BufferCollectionTokenPtr token); - // Called by OnOutputConstraints() to initialize input buffers. - void InitializeOutputBufferCollection( - fuchsia::media::StreamBufferConstraints constraints, - fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_codec, - fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_gpu); + // Called by OutputMailbox to signal that the output buffer can be reused. + void ReleaseOutputPacket(StreamProcessorHelper::IoPacket packet); - // Called by OutputMailbox to signal that the mailbox and buffer can be - // reused. - void OnReuseMailbox(uint32_t buffer_index, uint32_t packet_index); - - // Releases BufferCollections used for input or output buffers if any. - void ReleaseInputBuffers(); + // Releases BufferCollection used for output buffers if any. void ReleaseOutputBuffers(); const scoped_refptr<viz::RasterContextProvider> raster_context_provider_; @@ -279,52 +272,39 @@ class FuchsiaVideoDecoder : public VideoDecoder, // value is used only if the aspect ratio is not specified in the bitstream. float container_pixel_aspect_ratio_ = 1.0; - // Decryptor is allocated only for encrypted streams. - std::unique_ptr<FuchsiaSecureStreamDecryptor> decryptor_; + std::unique_ptr<SysmemBufferStream> sysmem_buffer_stream_; - VideoCodec current_codec_ = kUnknownVideoCodec; + size_t max_decoder_requests_ = kNumInputBuffers + 1; - // TODO(crbug.com/1131175): Use StreamProcessorHelper. - fuchsia::media::StreamProcessorPtr decoder_; + VideoDecoderConfig current_config_; - base::Optional<fuchsia::media::StreamBufferConstraints> - decoder_input_constraints_; + std::unique_ptr<StreamProcessorHelper> decoder_; - BufferAllocator sysmem_allocator_; + SysmemAllocatorClient sysmem_allocator_; std::unique_ptr<gfx::ClientNativePixmapFactory> client_native_pixmap_factory_; - uint64_t stream_lifetime_ordinal_ = 1; - - // Set to true if we've sent an input packet with the current - // stream_lifetime_ordinal_. - bool active_stream_ = false; - // Callbacks for pending Decode() request. std::deque<DecodeCB> decode_callbacks_; - // Buffer queue for |decoder_|. Used only for clear streams, i.e. when there - // is no |decryptor_|. - SysmemBufferWriterQueue input_writer_queue_; - // Input buffers for |decoder_|. - uint64_t input_buffer_lifetime_ordinal_ = 1; - std::unique_ptr<SysmemBufferPool::Creator> input_buffer_collection_creator_; - std::unique_ptr<SysmemBufferPool> input_buffer_collection_; - base::flat_map<size_t, InputDecoderPacket> in_flight_input_packets_; + std::unique_ptr<SysmemCollectionClient> input_buffer_collection_; // Output buffers for |decoder_|. fuchsia::media::VideoUncompressedFormat output_format_; - uint64_t output_buffer_lifetime_ordinal_ = 1; - fuchsia::sysmem::BufferCollectionPtr output_buffer_collection_; + std::unique_ptr<SysmemCollectionClient> output_buffer_collection_; gfx::SysmemBufferCollectionId output_buffer_collection_id_; std::vector<OutputMailbox*> output_mailboxes_; size_t num_used_output_buffers_ = 0; base::WeakPtr<FuchsiaVideoDecoder> weak_this_; - base::WeakPtrFactory<FuchsiaVideoDecoder> weak_factory_; + base::WeakPtrFactory<FuchsiaVideoDecoder> weak_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(FuchsiaVideoDecoder); + // WeakPtrFactory used to schedule CallNextDecodeCallbacks(). These pointers + // are discarded in DropInputQueue() in order to avoid calling + // Decode() callback when the decoder queue is discarded. + base::WeakPtrFactory<FuchsiaVideoDecoder> decode_callbacks_weak_factory_{ + this}; }; FuchsiaVideoDecoder::FuchsiaVideoDecoder( @@ -335,16 +315,17 @@ FuchsiaVideoDecoder::FuchsiaVideoDecoder( use_overlays_for_video_(base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kUseOverlaysForVideo)), sysmem_allocator_("CrFuchsiaVideoDecoder"), - client_native_pixmap_factory_(ui::CreateClientNativePixmapFactoryOzone()), - weak_factory_(this) { + client_native_pixmap_factory_( + ui::CreateClientNativePixmapFactoryOzone()) { DCHECK(raster_context_provider_); weak_this_ = weak_factory_.GetWeakPtr(); } FuchsiaVideoDecoder::~FuchsiaVideoDecoder() { - // Call ReleaseInputBuffers() to make sure the corresponding fields are - // destroyed in the right order. - ReleaseInputBuffers(); + // Reset SysmemBufferStream to ensure it doesn't try to send new packets when + // the |decoder_| is destroyed. + sysmem_buffer_stream_.reset(); + decoder_.reset(); // Release mailboxes used for output frames. ReleaseOutputBuffers(); @@ -384,25 +365,25 @@ void FuchsiaVideoDecoder::Initialize(const VideoDecoderConfig& config, container_pixel_aspect_ratio_ = config.GetPixelAspectRatio(); // Keep decoder and decryptor if the configuration hasn't changed. - bool have_decryptor = decryptor_ != nullptr; - if (decoder_ && current_codec_ == config.codec() && - have_decryptor == config.is_encrypted()) { + if (decoder_ && current_config_.is_encrypted() == config.codec() && + current_config_.is_encrypted() == config.is_encrypted()) { std::move(done_callback).Run(OkStatus()); return; } - decryptor_.reset(); - decoder_.Unbind(); + sysmem_buffer_stream_.reset(); + decoder_.reset(); - // Initialize decryptor for encrypted streams. - if (config.is_encrypted() && !InitializeDecryptor(cdm_context)) { - std::move(done_callback) - .Run(StatusCode::kDecoderMissingCdmForEncryptedContent); + // Initialize the stream. + bool secure_mode = false; + StatusCode status = InitializeSysmemBufferStream(config.is_encrypted(), + cdm_context, &secure_mode); + if (status != StatusCode::kOk) { + std::move(done_callback).Run(StatusCode::kOk); return; } - // Reset IO buffers since we won't be able to re-use them. - ReleaseInputBuffers(); + // Reset output buffers since we won't be able to re-use them. ReleaseOutputBuffers(); fuchsia::mediacodec::CreateDecoder_Params decoder_params; @@ -430,18 +411,15 @@ void FuchsiaVideoDecoder::Initialize(const VideoDecoderConfig& config, return; } - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableProtectedVideoBuffers)) { - if (decryptor_) { - decoder_params.set_secure_input_mode( - fuchsia::mediacodec::SecureMemoryMode::ON); - } + if (secure_mode) { + decoder_params.set_secure_input_mode( + fuchsia::mediacodec::SecureMemoryMode::ON); + } - if (decryptor_ || base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kForceProtectedVideoOutputBuffers)) { - decoder_params.set_secure_output_mode( - fuchsia::mediacodec::SecureMemoryMode::ON); - } + if (secure_mode || base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kForceProtectedVideoOutputBuffers)) { + decoder_params.set_secure_output_mode( + fuchsia::mediacodec::SecureMemoryMode::ON); } decoder_params.set_promise_separate_access_units_on_input(true); @@ -450,32 +428,12 @@ void FuchsiaVideoDecoder::Initialize(const VideoDecoderConfig& config, auto decoder_factory = base::ComponentContextForProcess() ->svc() ->Connect<fuchsia::mediacodec::CodecFactory>(); + fuchsia::media::StreamProcessorPtr decoder; decoder_factory->CreateDecoder(std::move(decoder_params), - decoder_.NewRequest()); + decoder.NewRequest()); + decoder_ = std::make_unique<StreamProcessorHelper>(std::move(decoder), this); - decoder_.set_error_handler([this](zx_status_t status) { - ZX_LOG(ERROR, status) << "fuchsia.media.StreamProcessor disconnected."; - OnError(); - }); - - decoder_.events().OnStreamFailed = - fit::bind_member(this, &FuchsiaVideoDecoder::OnStreamFailed); - decoder_.events().OnInputConstraints = - fit::bind_member(this, &FuchsiaVideoDecoder::OnInputConstraints); - decoder_.events().OnFreeInputPacket = - fit::bind_member(this, &FuchsiaVideoDecoder::OnFreeInputPacket); - decoder_.events().OnOutputConstraints = - fit::bind_member(this, &FuchsiaVideoDecoder::OnOutputConstraints); - decoder_.events().OnOutputFormat = - fit::bind_member(this, &FuchsiaVideoDecoder::OnOutputFormat); - decoder_.events().OnOutputPacket = - fit::bind_member(this, &FuchsiaVideoDecoder::OnOutputPacket); - decoder_.events().OnOutputEndOfStream = - fit::bind_member(this, &FuchsiaVideoDecoder::OnOutputEndOfStream); - - decoder_->EnableOnStreamFailed(); - - current_codec_ = config.codec(); + current_config_ = config; std::move(done_callback).Run(OkStatus()); } @@ -493,11 +451,7 @@ void FuchsiaVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, decode_callbacks_.push_back(std::move(decode_cb)); - if (decryptor_) { - decryptor_->Decrypt(std::move(buffer)); - } else { - input_writer_queue_.EnqueueBuffer(buffer); - } + sysmem_buffer_stream_->EnqueueBuffer(std::move(buffer)); } void FuchsiaVideoDecoder::Reset(base::OnceClosure closure) { @@ -515,305 +469,113 @@ bool FuchsiaVideoDecoder::CanReadWithoutStalling() const { } int FuchsiaVideoDecoder::GetMaxDecodeRequests() const { - if (!decryptor_) { - // Add one extra request to be able to send a new InputBuffer immediately - // after OnFreeInputPacket(). - return input_writer_queue_.num_buffers() + 1; - } - - // For encrypted streams we need enough decode requests to fill the - // decryptor's queue and all decoder buffers. Add one extra same as above. - return decryptor_->GetMaxDecryptRequests() + kNumInputBuffers + 1; + return max_decoder_requests_; } -bool FuchsiaVideoDecoder::InitializeDecryptor(CdmContext* cdm_context) { - DCHECK(!decryptor_); +StatusCode FuchsiaVideoDecoder::InitializeSysmemBufferStream( + bool is_encrypted, + CdmContext* cdm_context, + bool* out_secure_mode) { + DCHECK(!sysmem_buffer_stream_); - // Caller makes sure |cdm_context| is available if the stream is encrypted. - if (!cdm_context) { - DLOG(ERROR) << "No cdm context for encrypted stream."; - return false; - } + *out_secure_mode = false; + + // By default queue as many decode requests as the input buffers available + // with one extra request to be able to send a new InputBuffer immediately. + max_decoder_requests_ = kNumInputBuffers + 1; - // If Cdm is not FuchsiaCdm then fail initialization to allow decoder - // selector to choose DecryptingDemuxerStream, which will handle the - // decryption and pass the clear stream to this decoder. - FuchsiaCdmContext* fuchsia_cdm = cdm_context->GetFuchsiaCdmContext(); - if (!fuchsia_cdm) { - DLOG(ERROR) << "FuchsiaVideoDecoder is compatible only with Fuchsia CDM."; - return false; + if (is_encrypted) { + // Caller makes sure |cdm_context| is available if the stream is encrypted. + if (!cdm_context) { + DLOG(ERROR) << "No cdm context for encrypted stream."; + return StatusCode::kDecoderMissingCdmForEncryptedContent; + } + + // Use FuchsiaStreamDecryptor with FuchsiaCdm (it doesn't support + // media::Decryptor interface). Otherwise (e.g. for ClearKey CDM) use + // DecryptingSysmemBufferStream. + FuchsiaCdmContext* fuchsia_cdm = cdm_context->GetFuchsiaCdmContext(); + if (fuchsia_cdm) { + *out_secure_mode = base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableProtectedVideoBuffers); + sysmem_buffer_stream_ = + fuchsia_cdm->CreateStreamDecryptor(*out_secure_mode); + + // For optimal performance allow more requests to fill the decryptor + // queue. + max_decoder_requests_ += FuchsiaStreamDecryptor::kInputBufferCount; + } else { + sysmem_buffer_stream_ = std::make_unique<DecryptingSysmemBufferStream>( + &sysmem_allocator_, cdm_context, Decryptor::kVideo); + } + } else { + sysmem_buffer_stream_ = + std::make_unique<PassthroughSysmemBufferStream>(&sysmem_allocator_); } - decryptor_ = fuchsia_cdm->CreateVideoDecryptor(this); + sysmem_buffer_stream_->Initialize(this, kInputBufferSize, kNumInputBuffers); - return true; + return StatusCode::kOk; } -size_t FuchsiaVideoDecoder::GetInputBufferSize() { - return kInputBufferSize; +void FuchsiaVideoDecoder::OnSysmemBufferStreamBufferCollectionToken( + fuchsia::sysmem::BufferCollectionTokenPtr token) { + DCHECK(decoder_); + decoder_->SetInputBufferCollectionToken(std::move(token)); } -void FuchsiaVideoDecoder::OnDecryptorOutputPacket( +void FuchsiaVideoDecoder::OnSysmemBufferStreamOutputPacket( StreamProcessorHelper::IoPacket packet) { - SendInputPacket(nullptr, std::move(packet)); + packet.AddOnDestroyClosure( + base::BindOnce(&FuchsiaVideoDecoder::CallNextDecodeCallback, + decode_callbacks_weak_factory_.GetWeakPtr())); + decoder_->Process(std::move(packet)); } -void FuchsiaVideoDecoder::OnDecryptorEndOfStreamPacket() { - ProcessEndOfStream(); +void FuchsiaVideoDecoder::OnSysmemBufferStreamEndOfStream() { + decoder_->ProcessEos(); } -void FuchsiaVideoDecoder::OnDecryptorError() { +void FuchsiaVideoDecoder::OnSysmemBufferStreamError() { OnError(); } -void FuchsiaVideoDecoder::OnDecryptorNoKey() { +void FuchsiaVideoDecoder::OnSysmemBufferStreamNoKey() { waiting_cb_.Run(WaitingReason::kNoDecryptionKey); } -void FuchsiaVideoDecoder::OnStreamFailed(uint64_t stream_lifetime_ordinal, - fuchsia::media::StreamError error) { - if (stream_lifetime_ordinal_ != stream_lifetime_ordinal) { - return; - } - - OnError(); -} +void FuchsiaVideoDecoder::OnStreamProcessorAllocateOutputBuffers( + const fuchsia::media::StreamBufferConstraints& output_constraints) { + ReleaseOutputBuffers(); -void FuchsiaVideoDecoder::OnInputConstraints( - fuchsia::media::StreamBufferConstraints stream_constraints) { - // Buffer lifetime ordinal is an odd number incremented by 2 for each buffer - // generation as required by StreamProcessor. - input_buffer_lifetime_ordinal_ += 2; - decoder_input_constraints_ = std::move(stream_constraints); + output_buffer_collection_ = sysmem_allocator_.AllocateNewCollection(); - ReleaseInputBuffers(); + output_buffer_collection_->CreateSharedToken( + base::BindOnce(&StreamProcessorHelper::CompleteOutputBuffersAllocation, + base::Unretained(decoder_.get())), + "codec"); + output_buffer_collection_->CreateSharedToken( + base::BindOnce(&FuchsiaVideoDecoder::SetBufferCollectionTokenForGpu, + base::Unretained(this)), + "gpu"); - // Create buffer constrains for the input buffer collection. - size_t num_tokens; fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; - - if (decryptor_) { - // For encrypted streams the sysmem buffer collection is used for decryptor - // output and decoder input. It is not used directly. - num_tokens = 2; - buffer_constraints.usage.none = fuchsia::sysmem::noneUsage; - buffer_constraints.min_buffer_count = kNumInputBuffers; - buffer_constraints.has_buffer_memory_constraints = true; - buffer_constraints.buffer_memory_constraints.min_size_bytes = - kInputBufferSize; - buffer_constraints.buffer_memory_constraints.ram_domain_supported = true; - buffer_constraints.buffer_memory_constraints.cpu_domain_supported = true; - buffer_constraints.buffer_memory_constraints.inaccessible_domain_supported = - true; - } else { - num_tokens = 1; - auto writer_constraints = SysmemBufferWriter::GetRecommendedConstraints( - kNumInputBuffers, kInputBufferSize); - if (!writer_constraints.has_value()) { - OnError(); - return; - } - buffer_constraints = std::move(writer_constraints).value(); - } - - input_buffer_collection_creator_ = - sysmem_allocator_.MakeBufferPoolCreator(num_tokens); - input_buffer_collection_creator_->Create( - std::move(buffer_constraints), - base::BindOnce(&FuchsiaVideoDecoder::OnInputBufferPoolCreated, - base::Unretained(this))); -} - -void FuchsiaVideoDecoder::OnInputBufferPoolCreated( - std::unique_ptr<SysmemBufferPool> pool) { - if (!pool) { - DLOG(ERROR) << "Fail to allocate input buffers for the codec."; - OnError(); - return; - } - - input_buffer_collection_ = std::move(pool); - - fuchsia::media::StreamBufferPartialSettings settings; - settings.set_buffer_lifetime_ordinal(input_buffer_lifetime_ordinal_); - settings.set_buffer_constraints_version_ordinal( - decoder_input_constraints_->buffer_constraints_version_ordinal()); - settings.set_sysmem_token(input_buffer_collection_->TakeToken()); - decoder_->SetInputBufferPartialSettings(std::move(settings)); - - if (decryptor_) { - decryptor_->SetOutputBufferCollectionToken( - input_buffer_collection_->TakeToken()); - } else { - input_buffer_collection_->CreateWriter(base::BindOnce( - &FuchsiaVideoDecoder::OnWriterCreated, base::Unretained(this))); - } -} - -void FuchsiaVideoDecoder::OnWriterCreated( - std::unique_ptr<SysmemBufferWriter> writer) { - if (!writer) { - OnError(); - return; - } - - input_writer_queue_.Start( - std::move(writer), - base::BindRepeating(&FuchsiaVideoDecoder::SendInputPacket, - base::Unretained(this)), - base::BindRepeating(&FuchsiaVideoDecoder::ProcessEndOfStream, - base::Unretained(this))); -} - -void FuchsiaVideoDecoder::SendInputPacket( - const DecoderBuffer* buffer, - StreamProcessorHelper::IoPacket packet) { - fuchsia::media::Packet media_packet; - media_packet.mutable_header()->set_buffer_lifetime_ordinal( - input_buffer_lifetime_ordinal_); - media_packet.mutable_header()->set_packet_index(packet.buffer_index()); - media_packet.set_buffer_index(packet.buffer_index()); - media_packet.set_timestamp_ish(packet.timestamp().InNanoseconds()); - media_packet.set_stream_lifetime_ordinal(stream_lifetime_ordinal_); - media_packet.set_start_offset(packet.offset()); - media_packet.set_valid_length_bytes(packet.size()); - media_packet.set_known_end_access_unit(packet.unit_end()); - decoder_->QueueInputPacket(std::move(media_packet)); - - active_stream_ = true; - - DCHECK(in_flight_input_packets_.find(packet.buffer_index()) == - in_flight_input_packets_.end()); - const size_t buffer_index = packet.buffer_index(); - in_flight_input_packets_.insert_or_assign( - buffer_index, InputDecoderPacket{std::move(packet)}); -} - -void FuchsiaVideoDecoder::ProcessEndOfStream() { - active_stream_ = true; - decoder_->QueueInputEndOfStream(stream_lifetime_ordinal_); - decoder_->FlushEndOfStreamAndCloseStream(stream_lifetime_ordinal_); -} - -void FuchsiaVideoDecoder::OnFreeInputPacket( - fuchsia::media::PacketHeader free_input_packet) { - if (!free_input_packet.has_buffer_lifetime_ordinal() || - !free_input_packet.has_packet_index()) { - DLOG(ERROR) << "Received OnFreeInputPacket() with missing required fields."; - OnError(); - return; - } - - if (free_input_packet.buffer_lifetime_ordinal() != - input_buffer_lifetime_ordinal_) { - return; - } - - auto it = in_flight_input_packets_.find(free_input_packet.packet_index()); - if (it == in_flight_input_packets_.end()) { - DLOG(ERROR) << "Received OnFreeInputPacket() with invalid packet index."; - OnError(); - return; - } - - // Call DecodeCB if this was a last packet for a Decode() request. Ignore - // packets from a previous stream. - bool call_decode_callback = - it->second.packet.unit_end() && it->second.used_for_current_stream; - - { - // The packet should be destroyed only after it's removed from - // |in_flight_input_packets_|. Otherwise SysmemBufferWriter may call - // SendInputPacket() while the packet is still in - // |in_flight_input_packets_|. - auto packet = std::move(it->second.packet); - in_flight_input_packets_.erase(it); - } - - if (call_decode_callback) { - DCHECK(!decode_callbacks_.empty()); - std::move(decode_callbacks_.front()).Run(DecodeStatus::OK); - decode_callbacks_.pop_front(); - } + buffer_constraints.usage.none = fuchsia::sysmem::noneUsage; + buffer_constraints.min_buffer_count_for_camping = kOutputBuffersForCamping; + buffer_constraints.min_buffer_count_for_shared_slack = + kMaxUsedOutputBuffers - kOutputBuffersForCamping; + output_buffer_collection_->Initialize(std::move(buffer_constraints), + "ChromiumVideoDecoderOutput"); } -void FuchsiaVideoDecoder::OnOutputConstraints( - fuchsia::media::StreamOutputConstraints output_constraints) { - if (!output_constraints.has_stream_lifetime_ordinal()) { - DLOG(ERROR) - << "Received OnOutputConstraints() with missing required fields."; - OnError(); - return; - } - - if (output_constraints.stream_lifetime_ordinal() != - stream_lifetime_ordinal_) { - return; - } - - if (!output_constraints.has_buffer_constraints_action_required() || - !output_constraints.buffer_constraints_action_required()) { - return; - } - - ReleaseOutputBuffers(); - - // mediacodec API expects odd buffer lifetime ordinal, which is incremented by - // 2 for each buffer generation. - output_buffer_lifetime_ordinal_ += 2; - - // Create a new sysmem buffer collection token for the output buffers. - fuchsia::sysmem::BufferCollectionTokenPtr collection_token; - sysmem_allocator_.raw()->AllocateSharedCollection( - collection_token.NewRequest()); - collection_token->SetName(100u, "ChromiumVideoDecoderOutput"); - collection_token->SetDebugClientInfo("chromium_video_decoder", 0u); - - // Create sysmem tokens for the gpu process and the codec. - fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_codec; - collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS, - collection_token_for_codec.NewRequest()); - collection_token_for_codec->SetDebugClientInfo("codec", 0u); - fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_gpu; - collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS, - collection_token_for_gpu.NewRequest()); - collection_token_for_gpu->SetDebugClientInfo("chromium_gpu", 0u); - - // Convert the token to a BufferCollection connection. - sysmem_allocator_.raw()->BindSharedCollection( - std::move(collection_token), output_buffer_collection_.NewRequest()); - output_buffer_collection_.set_error_handler([this](zx_status_t status) { - ZX_LOG(ERROR, status) << "fuchsia.sysmem.BufferCollection disconnected."; - OnError(); - }); - - // BufferCollection needs to be synchronized before we can use it. - output_buffer_collection_->Sync( - [this, - buffer_constraints = std::move( - std::move(*output_constraints.mutable_buffer_constraints())), - collection_token_for_codec = std::move(collection_token_for_codec), - collection_token_for_gpu = - std::move(collection_token_for_gpu)]() mutable { - InitializeOutputBufferCollection(std::move(buffer_constraints), - std::move(collection_token_for_codec), - std::move(collection_token_for_gpu)); - }); +void FuchsiaVideoDecoder::OnStreamProcessorEndOfStream() { + // Decode() is not supposed to be called again after EOF. + DCHECK_EQ(decode_callbacks_.size(), 1U); + CallNextDecodeCallback(); } -void FuchsiaVideoDecoder::OnOutputFormat( +void FuchsiaVideoDecoder::OnStreamProcessorOutputFormat( fuchsia::media::StreamOutputFormat output_format) { - if (!output_format.has_stream_lifetime_ordinal() || - !output_format.has_format_details()) { - DLOG(ERROR) << "Received OnOutputFormat() with missing required fields."; - OnError(); - return; - } - - if (output_format.stream_lifetime_ordinal() != stream_lifetime_ordinal_) { - return; - } - auto* format = output_format.mutable_format_details(); if (!format->has_domain() || !format->domain().is_video() || !format->domain().video().is_uncompressed()) { @@ -825,27 +587,8 @@ void FuchsiaVideoDecoder::OnOutputFormat( output_format_ = std::move(format->mutable_domain()->video().uncompressed()); } -void FuchsiaVideoDecoder::OnOutputPacket(fuchsia::media::Packet output_packet, - bool error_detected_before, - bool error_detected_during) { - if (!output_packet.has_header() || - !output_packet.header().has_buffer_lifetime_ordinal() || - !output_packet.header().has_packet_index() || - !output_packet.has_buffer_index()) { - DLOG(ERROR) << "Received OnOutputPacket() with missing required fields."; - OnError(); - return; - } - - if (output_packet.stream_lifetime_ordinal() != stream_lifetime_ordinal_) { - return; - } - - if (output_packet.header().buffer_lifetime_ordinal() != - output_buffer_lifetime_ordinal_) { - return; - } - +void FuchsiaVideoDecoder::OnStreamProcessorOutputPacket( + StreamProcessorHelper::IoPacket output_packet) { fuchsia::sysmem::PixelFormatType sysmem_pixel_format = output_format_.image_format.pixel_format.type; @@ -912,26 +655,24 @@ void FuchsiaVideoDecoder::OnOutputPacket(fuchsia::media::Packet output_packet, pixel_aspect_ratio = container_pixel_aspect_ratio_; } + auto timestamp = output_packet.timestamp(); + // SendInputPacket() sets timestamp for all packets sent to the decoder, so we // expect to receive timestamp for all decoded frames. Missing timestamp // indicates a bug in the decoder implementation. - if (!output_packet.has_timestamp_ish()) { + if (timestamp == kNoTimestamp) { LOG(ERROR) << "Received frame without timestamp."; OnError(); return; } - base::TimeDelta timestamp = - base::TimeDelta::FromNanoseconds(output_packet.timestamp_ish()); - num_used_output_buffers_++; auto frame = output_mailboxes_[buffer_index]->CreateFrame( pixel_format, coded_size, display_rect, GetNaturalSize(display_rect, pixel_aspect_ratio), timestamp, - base::BindOnce(&FuchsiaVideoDecoder::OnReuseMailbox, - base::Unretained(this), buffer_index, - output_packet.header().packet_index())); + base::BindOnce(&FuchsiaVideoDecoder::ReleaseOutputPacket, + base::Unretained(this), std::move(output_packet))); // Currently sysmem doesn't specify location of chroma samples relative to // luma (see fxb/13677). Assume they are cosited with luma. YCbCr info here @@ -958,41 +699,36 @@ void FuchsiaVideoDecoder::OnOutputPacket(fuchsia::media::Packet output_packet, output_cb_.Run(std::move(frame)); } -void FuchsiaVideoDecoder::OnOutputEndOfStream(uint64_t stream_lifetime_ordinal, - bool error_detected_before) { - if (stream_lifetime_ordinal != stream_lifetime_ordinal_) { - return; - } +void FuchsiaVideoDecoder::OnStreamProcessorNoKey() { + // Decoder is not expected to produce NoKey() error. + DLOG(ERROR) << "Video decoder failed with DECRYPTOR_NO_KEY expectedly"; + OnError(); +} - stream_lifetime_ordinal_ += 2; - active_stream_ = false; +void FuchsiaVideoDecoder::OnStreamProcessorError() { + OnError(); +} - // Decode() is not supposed to be called after EOF. - DCHECK_EQ(decode_callbacks_.size(), 1U); - auto flush_cb = std::move(decode_callbacks_.front()); +void FuchsiaVideoDecoder::CallNextDecodeCallback() { + DCHECK(!decode_callbacks_.empty()); + auto cb = std::move(decode_callbacks_.front()); decode_callbacks_.pop_front(); - std::move(flush_cb).Run(DecodeStatus::OK); + std::move(cb).Run(DecodeStatus::OK); } bool FuchsiaVideoDecoder::DropInputQueue(DecodeStatus status) { - input_writer_queue_.ResetQueue(); + // Invalidate callbacks for CallNextDecodeCallback(), so the callbacks are not + // called when the |decoder_| is dropped below. The callbacks are called + // explicitly later. + decode_callbacks_weak_factory_.InvalidateWeakPtrs(); - if (active_stream_) { - if (decoder_) { - decoder_->CloseCurrentStream(stream_lifetime_ordinal_, - /*release_input_buffers=*/false, - /*release_output_buffers=*/false); - } - stream_lifetime_ordinal_ += 2; - active_stream_ = false; + if (decoder_) { + decoder_->Reset(); } - if (decryptor_) - decryptor_->Reset(); - - for (auto& packet : in_flight_input_packets_) { - packet.second.used_for_current_stream = false; + if (sysmem_buffer_stream_) { + sysmem_buffer_stream_->Reset(); } auto weak_this = weak_this_; @@ -1010,69 +746,35 @@ bool FuchsiaVideoDecoder::DropInputQueue(DecodeStatus status) { } void FuchsiaVideoDecoder::OnError() { - decoder_.Unbind(); - decryptor_.reset(); + sysmem_buffer_stream_.reset(); + decoder_.reset(); - ReleaseInputBuffers(); ReleaseOutputBuffers(); DropInputQueue(DecodeStatus::DECODE_ERROR); } -void FuchsiaVideoDecoder::InitializeOutputBufferCollection( - fuchsia::media::StreamBufferConstraints constraints, - fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_codec, - fuchsia::sysmem::BufferCollectionTokenPtr collection_token_for_gpu) { - fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; - buffer_constraints.usage.none = fuchsia::sysmem::noneUsage; - buffer_constraints.min_buffer_count_for_camping = kOutputBuffersForCamping; - buffer_constraints.min_buffer_count_for_shared_slack = - kMaxUsedOutputBuffers - kOutputBuffersForCamping; - output_buffer_collection_->SetConstraints( - /*has_constraints=*/true, std::move(buffer_constraints)); - +void FuchsiaVideoDecoder::SetBufferCollectionTokenForGpu( + fuchsia::sysmem::BufferCollectionTokenPtr token) { // Register the new collection with the GPU process. DCHECK(!output_buffer_collection_id_); output_buffer_collection_id_ = gfx::SysmemBufferCollectionId::Create(); raster_context_provider_->SharedImageInterface() ->RegisterSysmemBufferCollection( - output_buffer_collection_id_, - collection_token_for_gpu.Unbind().TakeChannel(), + output_buffer_collection_id_, token.Unbind().TakeChannel(), gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::GPU_READ, use_overlays_for_video_ /*register_with_image_pipe*/); - // Pass new output buffer settings to the codec. - fuchsia::media::StreamBufferPartialSettings settings; - settings.set_buffer_lifetime_ordinal(output_buffer_lifetime_ordinal_); - settings.set_buffer_constraints_version_ordinal( - constraints.buffer_constraints_version_ordinal()); - settings.set_sysmem_token(std::move(collection_token_for_codec)); - decoder_->SetOutputBufferPartialSettings(std::move(settings)); - decoder_->CompleteOutputBufferPartialSettings( - output_buffer_lifetime_ordinal_); - // Exact number of buffers sysmem will allocate is unknown here. // |output_mailboxes_| is resized when we start receiving output frames. DCHECK(output_mailboxes_.empty()); } -void FuchsiaVideoDecoder::ReleaseInputBuffers() { - input_writer_queue_.ResetBuffers(); - input_buffer_collection_creator_.reset(); - input_buffer_collection_.reset(); - - // |in_flight_input_packets_| must be destroyed after - // |input_writer_queue_.ResetBuffers()|. Otherwise |input_writer_queue_| may - // call SendInputPacket() in response to the packet destruction callbacks. - in_flight_input_packets_.clear(); -} - void FuchsiaVideoDecoder::ReleaseOutputBuffers() { // Release the buffer collection. num_used_output_buffers_ = 0; if (output_buffer_collection_) { - output_buffer_collection_->Close(); - output_buffer_collection_.Unbind(); + output_buffer_collection_.reset(); } // Release all output mailboxes. @@ -1090,17 +792,10 @@ void FuchsiaVideoDecoder::ReleaseOutputBuffers() { } } -void FuchsiaVideoDecoder::OnReuseMailbox(uint32_t buffer_index, - uint32_t packet_index) { - DCHECK(decoder_); - +void FuchsiaVideoDecoder::ReleaseOutputPacket( + StreamProcessorHelper::IoPacket output_packet) { DCHECK_GT(num_used_output_buffers_, 0U); num_used_output_buffers_--; - - fuchsia::media::PacketHeader header; - header.set_buffer_lifetime_ordinal(output_buffer_lifetime_ordinal_); - header.set_packet_index(packet_index); - decoder_->RecycleOutputPacket(std::move(header)); } std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder( diff --git a/chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc b/chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc index 2b319eae494..24bebcc5a58 100644 --- a/chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc +++ b/chromium/media/filters/fuchsia/fuchsia_video_decoder_unittest.cc @@ -78,7 +78,7 @@ class TestBufferCollection { fuchsia::sysmem::AllocatorPtr sysmem_allocator_; fuchsia::sysmem::BufferCollectionSyncPtr buffers_collection_; - base::Optional<fuchsia::sysmem::BufferCollectionInfo_2> + absl::optional<fuchsia::sysmem::BufferCollectionInfo_2> buffer_collection_info_; DISALLOW_COPY_AND_ASSIGN(TestBufferCollection); @@ -115,6 +115,7 @@ class TestSharedImageInterface : public gpu::SharedImageInterface { gpu::Mailbox CreateSharedImage( gfx::GpuMemoryBuffer* gpu_memory_buffer, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + gfx::BufferPlane plane, const gfx::ColorSpace& color_space, GrSurfaceOrigin surface_origin, SkAlphaType alpha_type, diff --git a/chromium/media/filters/media_file_checker.h b/chromium/media/filters/media_file_checker.h index 86db498b03d..113f8434b02 100644 --- a/chromium/media/filters/media_file_checker.h +++ b/chromium/media/filters/media_file_checker.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_BASE_MEDIA_FILE_CHECKER_H_ -#define MEDIA_BASE_MEDIA_FILE_CHECKER_H_ +#ifndef MEDIA_FILTERS_MEDIA_FILE_CHECKER_H_ +#define MEDIA_FILTERS_MEDIA_FILE_CHECKER_H_ #include "base/files/file.h" #include "base/macros.h" @@ -36,4 +36,4 @@ class MEDIA_EXPORT MediaFileChecker { } // namespace media -#endif // MEDIA_BASE_MEDIA_FILE_CHECKER_H_ +#endif // MEDIA_FILTERS_MEDIA_FILE_CHECKER_H_ diff --git a/chromium/media/filters/pipeline_controller.cc b/chromium/media/filters/pipeline_controller.cc index 68b39ebe31a..b304bc826dc 100644 --- a/chromium/media/filters/pipeline_controller.cc +++ b/chromium/media/filters/pipeline_controller.cc @@ -384,7 +384,7 @@ void PipelineController::SetVolume(float volume) { } void PipelineController::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { DCHECK(!latency_hint || (*latency_hint >= base::TimeDelta())); pipeline_->SetLatencyHint(latency_hint); } @@ -433,7 +433,7 @@ void PipelineController::OnEnabledAudioTracksChanged( } void PipelineController::OnSelectedVideoTrackChanged( - base::Optional<MediaTrack::Id> selected_track_id) { + absl::optional<MediaTrack::Id> selected_track_id) { DCHECK(thread_checker_.CalledOnValidThread()); pending_video_track_change_ = true; diff --git a/chromium/media/filters/pipeline_controller.h b/chromium/media/filters/pipeline_controller.h index a77ab00085b..ea0370332dc 100644 --- a/chromium/media/filters/pipeline_controller.h +++ b/chromium/media/filters/pipeline_controller.h @@ -8,11 +8,11 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" #include "media/base/media_export.h" #include "media/base/pipeline.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -131,7 +131,7 @@ class MEDIA_EXPORT PipelineController { void SetPlaybackRate(double playback_rate); float GetVolume() const; void SetVolume(float volume); - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint); + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint); void SetPreservesPitch(bool preserves_pitch); void SetAutoplayInitiated(bool autoplay_initiated); base::TimeDelta GetMediaTime() const; @@ -143,7 +143,7 @@ class MEDIA_EXPORT PipelineController { void OnEnabledAudioTracksChanged( const std::vector<MediaTrack::Id>& enabled_track_ids); void OnSelectedVideoTrackChanged( - base::Optional<MediaTrack::Id> selected_track_id); + absl::optional<MediaTrack::Id> selected_track_id); // Used to fire the OnTrackChangeComplete function which is captured in a // OnceCallback, and doesn't play nicely with gmock. @@ -226,7 +226,7 @@ class MEDIA_EXPORT PipelineController { // |pending_video_track_change_|. base::TimeDelta pending_seek_time_; std::vector<MediaTrack::Id> pending_audio_track_change_ids_; - base::Optional<MediaTrack::Id> pending_video_track_change_id_; + absl::optional<MediaTrack::Id> pending_video_track_change_id_; // Set to true during Start(). Indicates that |seeked_cb_| must be fired once // we've completed startup. diff --git a/chromium/media/filters/pipeline_controller_unittest.cc b/chromium/media/filters/pipeline_controller_unittest.cc index 390dbc69409..5ca4b2a8be0 100644 --- a/chromium/media/filters/pipeline_controller_unittest.cc +++ b/chromium/media/filters/pipeline_controller_unittest.cc @@ -150,7 +150,7 @@ class PipelineControllerTest : public ::testing::Test, public Pipeline::Client { void OnAudioConfigChange(const AudioDecoderConfig& config) override {} void OnVideoConfigChange(const VideoDecoderConfig& config) override {} void OnVideoOpacityChange(bool opaque) override {} - void OnVideoFrameRateChange(base::Optional<int>) override {} + void OnVideoFrameRateChange(absl::optional<int>) override {} void OnVideoAverageKeyframeDistanceUpdate() override {} void OnAudioDecoderChange(const AudioDecoderInfo& info) override {} void OnVideoDecoderChange(const VideoDecoderInfo& info) override {} diff --git a/chromium/media/filters/source_buffer_stream.cc b/chromium/media/filters/source_buffer_stream.cc index 488f9e2a62b..3c877e35d0b 100644 --- a/chromium/media/filters/source_buffer_stream.cc +++ b/chromium/media/filters/source_buffer_stream.cc @@ -673,7 +673,6 @@ bool SourceBufferStream::IsDtsMonotonicallyIncreasing( const BufferQueue& buffers) { DCHECK(!buffers.empty()); DecodeTimestamp prev_dts = last_appended_buffer_decode_timestamp_; - bool prev_is_keyframe = last_appended_buffer_is_keyframe_; for (BufferQueue::const_iterator itr = buffers.begin(); itr != buffers.end(); ++itr) { DecodeTimestamp current_dts = (*itr)->GetDecodeTimestamp(); @@ -706,7 +705,6 @@ bool SourceBufferStream::IsDtsMonotonicallyIncreasing( } prev_dts = current_dts; - prev_is_keyframe = current_is_keyframe; } return true; } diff --git a/chromium/media/filters/stream_parser_factory.cc b/chromium/media/filters/stream_parser_factory.cc index 58a60adaa63..098ebd4e717 100644 --- a/chromium/media/filters/stream_parser_factory.cc +++ b/chromium/media/filters/stream_parser_factory.cc @@ -488,6 +488,18 @@ static SupportsType CheckTypeAndCodecs( bool found_codec = false; std::string codec_id = codecs[j]; for (int k = 0; type_info.codecs[k]; ++k) { + // Only check a codec pattern if there is one to check. Some types, + // like audio/mpeg and audio/aac require there be no codecs parameter, + // and instead have implicit codec. If a codec is provided for such a + // type then it is not supported by MSE. We don't check any other + // potential matches because none should be configured. + if (!type_info.codecs[k]->pattern) { + DCHECK(k == 0 && !type_info.codecs[1]) + << "For a type with implicit codec, then only one codec must " + "be configured"; + break; + } + if (base::MatchPattern(codec_id, type_info.codecs[k]->pattern) && (!type_info.codecs[k]->validator || type_info.codecs[k]->validator(codec_id, media_log))) { diff --git a/chromium/media/filters/video_cadence_estimator.h b/chromium/media/filters/video_cadence_estimator.h index 71cfeed693d..bed98a919ed 100644 --- a/chromium/media/filters/video_cadence_estimator.h +++ b/chromium/media/filters/video_cadence_estimator.h @@ -11,9 +11,9 @@ #include <vector> #include "base/macros.h" -#include "base/optional.h" #include "base/time/time.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -179,7 +179,7 @@ class MEDIA_EXPORT VideoCadenceEstimator { // In an ideal world, each video frame would be shown for this many display // intervals. It equals (display frequency) divided by (video frame rate). // Absent when a video has variable frame rate. - base::Optional<double> perfect_cadence_; + absl::optional<double> perfect_cadence_; } bm_; DISALLOW_COPY_AND_ASSIGN(VideoCadenceEstimator); diff --git a/chromium/media/filters/vp9_parser_unittest.cc b/chromium/media/filters/vp9_parser_unittest.cc index 639e0c1e767..0bca30b41b1 100644 --- a/chromium/media/filters/vp9_parser_unittest.cc +++ b/chromium/media/filters/vp9_parser_unittest.cc @@ -212,10 +212,10 @@ TEST_F(Vp9ParserTest, AlignedFrameSubsampleParsing) { std::vector<std::unique_ptr<DecryptConfig>> expected; expected.push_back(DecryptConfig::CreateCbcsConfig( - kKeyID, kInitialIV, {SubsampleEntry(16, 16)}, base::nullopt)); + kKeyID, kInitialIV, {SubsampleEntry(16, 16)}, absl::nullopt)); expected.push_back(DecryptConfig::CreateCbcsConfig( - kKeyID, kIVIncrementOne, {SubsampleEntry(16, 16)}, base::nullopt)); + kKeyID, kIVIncrementOne, {SubsampleEntry(16, 16)}, absl::nullopt)); CheckSubsampleValues( kSuperframe, sizeof(kSuperframe), @@ -253,10 +253,10 @@ TEST_F(Vp9ParserTest, UnalignedFrameSubsampleParsing) { std::vector<std::unique_ptr<DecryptConfig>> expected; expected.push_back(DecryptConfig::CreateCbcsConfig( - kKeyID, kInitialIV, {SubsampleEntry(32, 0)}, base::nullopt)); + kKeyID, kInitialIV, {SubsampleEntry(32, 0)}, absl::nullopt)); expected.push_back(DecryptConfig::CreateCbcsConfig( - kKeyID, kInitialIV, {SubsampleEntry(16, 16)}, base::nullopt)); + kKeyID, kInitialIV, {SubsampleEntry(16, 16)}, absl::nullopt)); CheckSubsampleValues(kSuperframe, sizeof(kSuperframe), DecryptConfig::CreateCencConfig( @@ -295,10 +295,10 @@ TEST_F(Vp9ParserTest, ClearSectionRollsOverSubsampleParsing) { std::vector<std::unique_ptr<DecryptConfig>> expected; expected.push_back(DecryptConfig::CreateCbcsConfig( kKeyID, kInitialIV, {SubsampleEntry(16, 16), SubsampleEntry(16, 0)}, - base::nullopt)); + absl::nullopt)); expected.push_back(DecryptConfig::CreateCbcsConfig( - kKeyID, kIVIncrementOne, {SubsampleEntry(16, 16)}, base::nullopt)); + kKeyID, kIVIncrementOne, {SubsampleEntry(16, 16)}, absl::nullopt)); CheckSubsampleValues( kSuperframe, sizeof(kSuperframe), @@ -340,10 +340,10 @@ TEST_F(Vp9ParserTest, FirstFrame2xSubsampleParsing) { std::vector<std::unique_ptr<DecryptConfig>> expected; expected.push_back(DecryptConfig::CreateCbcsConfig( kKeyID, kInitialIV, {SubsampleEntry(16, 16), SubsampleEntry(16, 16)}, - base::nullopt)); + absl::nullopt)); expected.push_back(DecryptConfig::CreateCbcsConfig( - kKeyID, kIVIncrementTwo, {SubsampleEntry(16, 16)}, base::nullopt)); + kKeyID, kIVIncrementTwo, {SubsampleEntry(16, 16)}, absl::nullopt)); CheckSubsampleValues(kSuperframe, sizeof(kSuperframe), DecryptConfig::CreateCencConfig( @@ -387,10 +387,10 @@ TEST_F(Vp9ParserTest, UnalignedBigFrameSubsampleParsing) { expected.push_back(DecryptConfig::CreateCbcsConfig( kKeyID, kInitialIV, {SubsampleEntry(16, 16), SubsampleEntry(16, 16), SubsampleEntry(8, 0)}, - base::nullopt)); + absl::nullopt)); expected.push_back(DecryptConfig::CreateCbcsConfig( - kKeyID, kIVIncrementTwo, {SubsampleEntry(16, 16)}, base::nullopt)); + kKeyID, kIVIncrementTwo, {SubsampleEntry(16, 16)}, absl::nullopt)); CheckSubsampleValues( kSuperframe, sizeof(kSuperframe), diff --git a/chromium/media/filters/vpx_video_decoder.cc b/chromium/media/filters/vpx_video_decoder.cc index 3204b5f7734..bfc29036943 100644 --- a/chromium/media/filters/vpx_video_decoder.cc +++ b/chromium/media/filters/vpx_video_decoder.cc @@ -83,7 +83,7 @@ static int32_t GetVP9FrameBuffer(void* user_priv, FrameBufferPool* pool = static_cast<FrameBufferPool*>(user_priv); fb->data = pool->GetFrameBuffer(min_size, &fb->priv); fb->size = min_size; - return 0; + return fb->data ? 0 : VPX_CODEC_MEM_ERROR; } static int32_t ReleaseVP9FrameBuffer(void* user_priv, @@ -556,6 +556,8 @@ bool VpxVideoDecoder::CopyVpxImageToVideoFrame( vpx_image_alpha->stride[VPX_PLANE_Y] * vpx_image_alpha->d_h; uint8_t* alpha_plane = memory_pool_->AllocateAlphaPlaneForFrameBuffer( alpha_plane_size, vpx_image->fb_priv); + if (!alpha_plane) // In case of OOM, abort copy. + return false; libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y], vpx_image_alpha->stride[VPX_PLANE_Y], alpha_plane, vpx_image_alpha->stride[VPX_PLANE_Y], diff --git a/chromium/media/filters/vpx_video_decoder.h b/chromium/media/filters/vpx_video_decoder.h index 37445263d39..34a8433258c 100644 --- a/chromium/media/filters/vpx_video_decoder.h +++ b/chromium/media/filters/vpx_video_decoder.h @@ -13,6 +13,7 @@ #include "media/base/video_decoder_config.h" #include "media/base/video_frame.h" #include "media/base/video_frame_pool.h" +#include "media/filters/frame_buffer_pool.h" #include "media/filters/offloading_video_decoder.h" struct vpx_codec_ctx; @@ -49,6 +50,10 @@ class MEDIA_EXPORT VpxVideoDecoder : public OffloadableVideoDecoder { // OffloadableVideoDecoder implementation. void Detach() override; + void force_allocation_error_for_testing() { + memory_pool_->force_allocation_error_for_testing(); + } + private: enum DecoderState { kUninitialized, diff --git a/chromium/media/filters/vpx_video_decoder_unittest.cc b/chromium/media/filters/vpx_video_decoder_unittest.cc index 6e428b72e53..6f37edb3067 100644 --- a/chromium/media/filters/vpx_video_decoder_unittest.cc +++ b/chromium/media/filters/vpx_video_decoder_unittest.cc @@ -196,6 +196,14 @@ TEST_F(VpxVideoDecoderTest, DecodeFrame_Normal) { ASSERT_EQ(1U, output_frames_.size()); } +TEST_F(VpxVideoDecoderTest, DecodeFrame_OOM) { + Initialize(); + static_cast<VpxVideoDecoder*>(decoder_.get()) + ->force_allocation_error_for_testing(); + EXPECT_FALSE(DecodeSingleFrame(i_frame_buffer_).is_ok()); + EXPECT_TRUE(output_frames_.empty()); +} + // Decode |i_frame_buffer_| and then a frame with a larger width and verify // the output size was adjusted. TEST_F(VpxVideoDecoderTest, DecodeFrame_LargerWidth) { diff --git a/chromium/media/formats/mp2t/descriptors.h b/chromium/media/formats/mp2t/descriptors.h index ad55322fc2e..817da22c93c 100644 --- a/chromium/media/formats/mp2t/descriptors.h +++ b/chromium/media/formats/mp2t/descriptors.h @@ -68,4 +68,4 @@ class Descriptors { } // namespace mp2t } // namespace media -#endif // MEDIA_FORMATS_MP2T_DESCRIPTOR_LIST_H_ +#endif // MEDIA_FORMATS_MP2T_DESCRIPTORS_H_ diff --git a/chromium/media/formats/mp2t/es_parser_adts.cc b/chromium/media/formats/mp2t/es_parser_adts.cc index c612e6e4b87..91470b75d25 100644 --- a/chromium/media/formats/mp2t/es_parser_adts.cc +++ b/chromium/media/formats/mp2t/es_parser_adts.cc @@ -9,7 +9,6 @@ #include <vector> #include "base/logging.h" -#include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "media/base/audio_timestamp_helper.h" #include "media/base/bit_reader.h" @@ -21,6 +20,7 @@ #include "media/formats/common/offset_byte_queue.h" #include "media/formats/mp2t/mp2t_common.h" #include "media/formats/mpeg/adts_constants.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { diff --git a/chromium/media/formats/mp2t/es_parser_adts.h b/chromium/media/formats/mp2t/es_parser_adts.h index 7a9950e516c..665ec3f7794 100644 --- a/chromium/media/formats/mp2t/es_parser_adts.h +++ b/chromium/media/formats/mp2t/es_parser_adts.h @@ -14,7 +14,6 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/time/time.h" #include "media/base/audio_decoder_config.h" #include "media/base/decrypt_config.h" #include "media/base/media_export.h" diff --git a/chromium/media/formats/mp2t/es_parser_h264.cc b/chromium/media/formats/mp2t/es_parser_h264.cc index 2093e21dabc..a00a90cad5f 100644 --- a/chromium/media/formats/mp2t/es_parser_h264.cc +++ b/chromium/media/formats/mp2t/es_parser_h264.cc @@ -8,7 +8,6 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" -#include "base/optional.h" #include "media/base/decrypt_config.h" #include "media/base/encryption_pattern.h" #include "media/base/media_util.h" @@ -18,6 +17,7 @@ #include "media/formats/common/offset_byte_queue.h" #include "media/formats/mp2t/mp2t_common.h" #include "media/video/h264_parser.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -490,11 +490,11 @@ bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps, int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width; int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height; - base::Optional<gfx::Size> coded_size = sps->GetCodedSize(); + absl::optional<gfx::Size> coded_size = sps->GetCodedSize(); if (!coded_size) return false; - base::Optional<gfx::Rect> visible_rect = sps->GetVisibleRect(); + absl::optional<gfx::Rect> visible_rect = sps->GetVisibleRect(); if (!visible_rect) return false; diff --git a/chromium/media/formats/mp2t/es_parser_h264.h b/chromium/media/formats/mp2t/es_parser_h264.h index 74c5a08e438..4a771af3bd2 100644 --- a/chromium/media/formats/mp2t/es_parser_h264.h +++ b/chromium/media/formats/mp2t/es_parser_h264.h @@ -13,7 +13,6 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/macros.h" -#include "base/time/time.h" #include "media/base/media_export.h" #include "media/base/ranges.h" #include "media/base/video_decoder_config.h" diff --git a/chromium/media/formats/mp2t/mp2t_stream_parser.cc b/chromium/media/formats/mp2t/mp2t_stream_parser.cc index b118f05ae6a..1e42091969b 100644 --- a/chromium/media/formats/mp2t/mp2t_stream_parser.cc +++ b/chromium/media/formats/mp2t/mp2t_stream_parser.cc @@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/callback_helpers.h" -#include "base/optional.h" #include "media/base/media_tracks.h" #include "media/base/stream_parser_buffer.h" #include "media/base/text_track_config.h" @@ -25,6 +24,7 @@ #include "media/formats/mp2t/ts_section_pat.h" #include "media/formats/mp2t/ts_section_pes.h" #include "media/formats/mp2t/ts_section_pmt.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) #include "media/formats/mp2t/ts_section_cat.h" @@ -968,7 +968,7 @@ void Mp2tStreamParser::RegisterNewKeyIdAndIv(const std::string& key_id, break; case EncryptionScheme::kCbcs: decrypt_config_ = - DecryptConfig::CreateCbcsConfig(key_id, iv, {}, base::nullopt); + DecryptConfig::CreateCbcsConfig(key_id, iv, {}, absl::nullopt); break; } } diff --git a/chromium/media/formats/mp2t/ts_section_cat.h b/chromium/media/formats/mp2t/ts_section_cat.h index 1dcd9672fb4..69ef68714e9 100644 --- a/chromium/media/formats/mp2t/ts_section_cat.h +++ b/chromium/media/formats/mp2t/ts_section_cat.h @@ -41,4 +41,4 @@ class TsSectionCat : public TsSectionPsi { } // namespace mp2t } // namespace media -#endif +#endif // MEDIA_FORMATS_MP2T_TS_SECTION_CAT_H_ diff --git a/chromium/media/formats/mp2t/ts_section_cets_ecm.h b/chromium/media/formats/mp2t/ts_section_cets_ecm.h index 6d17b8bff37..d2fb53414cf 100644 --- a/chromium/media/formats/mp2t/ts_section_cets_ecm.h +++ b/chromium/media/formats/mp2t/ts_section_cets_ecm.h @@ -47,4 +47,4 @@ class TsSectionCetsEcm : public TsSection { } // namespace mp2t } // namespace media -#endif +#endif // MEDIA_FORMATS_MP2T_TS_SECTION_CETS_ECM_H_ diff --git a/chromium/media/formats/mp2t/ts_section_cets_pssh.h b/chromium/media/formats/mp2t/ts_section_cets_pssh.h index b599bc3e04d..b4803068891 100644 --- a/chromium/media/formats/mp2t/ts_section_cets_pssh.h +++ b/chromium/media/formats/mp2t/ts_section_cets_pssh.h @@ -40,4 +40,4 @@ class TsSectionCetsPssh : public TsSection { } // namespace mp2t } // namespace media -#endif +#endif // MEDIA_FORMATS_MP2T_TS_SECTION_CETS_PSSH_H_ diff --git a/chromium/media/formats/mp4/avc_unittest.cc b/chromium/media/formats/mp4/avc_unittest.cc index e21c126f7fd..cc190e02631 100644 --- a/chromium/media/formats/mp4/avc_unittest.cc +++ b/chromium/media/formats/mp4/avc_unittest.cc @@ -8,7 +8,6 @@ #include <ostream> -#include "base/optional.h" #include "base/stl_util.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -20,6 +19,7 @@ #include "media/formats/mp4/nalu_test_helper.h" #include "media/video/h264_parser.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace mp4 { @@ -337,19 +337,19 @@ TEST_F(AVCConversionTest, ValidAnnexBConstructs) { TEST_F(AVCConversionTest, InvalidAnnexBConstructs) { struct { const char* case_string; - const base::Optional<bool> is_keyframe; + const absl::optional<bool> is_keyframe; } test_cases[] = { // For these cases, lack of conformance is determined before detecting any // IDR or non-IDR slices, so the non-conformant frames' keyframe analysis - // reports base::nullopt (which means undetermined analysis result). - {"AUD", base::nullopt}, // No VCL present. - {"AUD,SEI", base::nullopt}, // No VCL present. - {"SPS PPS", base::nullopt}, // No VCL present. - {"SPS PPS AUD I", base::nullopt}, // Parameter sets must come after AUD. - {"SPSExt SPS P", base::nullopt}, // SPS must come before SPSExt. - {"SPS PPS SPSExt P", base::nullopt}, // SPSExt must follow an SPS. - {"EOSeq", base::nullopt}, // EOSeq must come after a VCL. - {"EOStr", base::nullopt}, // EOStr must come after a VCL. + // reports absl::nullopt (which means undetermined analysis result). + {"AUD", absl::nullopt}, // No VCL present. + {"AUD,SEI", absl::nullopt}, // No VCL present. + {"SPS PPS", absl::nullopt}, // No VCL present. + {"SPS PPS AUD I", absl::nullopt}, // Parameter sets must come after AUD. + {"SPSExt SPS P", absl::nullopt}, // SPS must come before SPSExt. + {"SPS PPS SPSExt P", absl::nullopt}, // SPSExt must follow an SPS. + {"EOSeq", absl::nullopt}, // EOSeq must come after a VCL. + {"EOStr", absl::nullopt}, // EOStr must come after a VCL. // For these cases, IDR slice is first VCL and is detected before // conformance failure, so the non-conformant frame is reported as a diff --git a/chromium/media/formats/mp4/bitstream_converter.h b/chromium/media/formats/mp4/bitstream_converter.h index b6ad4a47cbf..4b9677131cc 100644 --- a/chromium/media/formats/mp4/bitstream_converter.h +++ b/chromium/media/formats/mp4/bitstream_converter.h @@ -10,8 +10,8 @@ #include <vector> #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -27,14 +27,14 @@ class MEDIA_EXPORT BitstreamConverter public: // Describes the result of Analyze(). Not all analyses are implemented or // enabled across mp4::BitstreamConverter implementations, hence the use of - // base::Optional<>. + // absl::optional<>. struct MEDIA_EXPORT AnalysisResult { AnalysisResult(); AnalysisResult(const AnalysisResult&); ~AnalysisResult(); - base::Optional<bool> is_conformant; - base::Optional<bool> is_keyframe; + absl::optional<bool> is_conformant; + absl::optional<bool> is_keyframe; }; // Converts a single frame/buffer |frame_buf| into the output format. diff --git a/chromium/media/formats/mp4/box_definitions.cc b/chromium/media/formats/mp4/box_definitions.cc index 6bc50c65f7a..f53b9347c8d 100644 --- a/chromium/media/formats/mp4/box_definitions.cc +++ b/chromium/media/formats/mp4/box_definitions.cc @@ -31,8 +31,8 @@ #include "media/video/h264_parser.h" // nogncheck #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) -#include "base/optional.h" #include "media/formats/mp4/dolby_vision.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #endif // BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) #if BUILDFLAG(ENABLE_PLATFORM_HEVC) @@ -50,7 +50,7 @@ const size_t kFlacMetadataBlockStreaminfoSize = 34; #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) // Parse dvcC or dvvC box. -base::Optional<DOVIDecoderConfigurationRecord> ParseDOVIConfig( +absl::optional<DOVIDecoderConfigurationRecord> ParseDOVIConfig( BoxReader* reader) { { DolbyVisionConfiguration dvcc; @@ -68,7 +68,7 @@ base::Optional<DOVIDecoderConfigurationRecord> ParseDOVIConfig( } } - return base::nullopt; + return absl::nullopt; } #endif // BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) diff --git a/chromium/media/formats/mp4/box_definitions.h b/chromium/media/formats/mp4/box_definitions.h index 8cc2c8379c7..450f3fc43c1 100644 --- a/chromium/media/formats/mp4/box_definitions.h +++ b/chromium/media/formats/mp4/box_definitions.h @@ -12,7 +12,6 @@ #include <vector> #include "base/compiler_specific.h" -#include "base/optional.h" #include "media/base/decrypt_config.h" #include "media/base/media_export.h" #include "media/base/media_log.h" @@ -22,6 +21,7 @@ #include "media/formats/mp4/box_reader.h" #include "media/formats/mp4/fourccs.h" #include "media/media_buildflags.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace mp4 { @@ -330,8 +330,8 @@ struct MEDIA_EXPORT VideoSampleEntry : Box { VideoCodecLevel video_codec_level; VideoColorSpace video_color_space; - base::Optional<MasteringDisplayColorVolume> mastering_display_color_volume; - base::Optional<ContentLightLevelInformation> content_light_level_information; + absl::optional<MasteringDisplayColorVolume> mastering_display_color_volume; + absl::optional<ContentLightLevelInformation> content_light_level_information; bool IsFormatValid() const; diff --git a/chromium/media/formats/mp4/dolby_vision.h b/chromium/media/formats/mp4/dolby_vision.h index c1bc9bd00d9..4ce6c1c2fc5 100644 --- a/chromium/media/formats/mp4/dolby_vision.h +++ b/chromium/media/formats/mp4/dolby_vision.h @@ -5,8 +5,6 @@ #ifndef MEDIA_FORMATS_MP4_DOLBY_VISION_H_ #define MEDIA_FORMATS_MP4_DOLBY_VISION_H_ -#include <vector> - #include "base/memory/ref_counted.h" #include "media/base/media_export.h" #include "media/formats/mp4/box_definitions.h" diff --git a/chromium/media/formats/mp4/hevc_unittest.cc b/chromium/media/formats/mp4/hevc_unittest.cc index 7bc641d996e..ce2b918ba9d 100644 --- a/chromium/media/formats/mp4/hevc_unittest.cc +++ b/chromium/media/formats/mp4/hevc_unittest.cc @@ -39,16 +39,16 @@ TEST(HEVCAnalyzeAnnexBTest, ValidAnnexBConstructs) { TEST(HEVCAnalyzeAnnexBTest, InvalidAnnexBConstructs) { struct { const char* case_string; - const base::Optional<bool> is_keyframe; + const absl::optional<bool> is_keyframe; } test_cases[] = { // For these cases, lack of conformance is determined before detecting any // IDR or non-IDR slices, so the non-conformant frames' keyframe analysis - // reports base::nullopt (which means undetermined analysis result). - {"AUD", base::nullopt}, // No VCL present. - {"AUD,SPS", base::nullopt}, // No VCL present. - {"SPS AUD I", base::nullopt}, // Parameter sets must come after AUD. - {"EOS", base::nullopt}, // EOS must come after a VCL. - {"EOB", base::nullopt}, // EOB must come after a VCL. + // reports absl::nullopt (which means undetermined analysis result). + {"AUD", absl::nullopt}, // No VCL present. + {"AUD,SPS", absl::nullopt}, // No VCL present. + {"SPS AUD I", absl::nullopt}, // Parameter sets must come after AUD. + {"EOS", absl::nullopt}, // EOS must come after a VCL. + {"EOB", absl::nullopt}, // EOB must come after a VCL. // For these cases, IDR slice is first VCL and is detected before // conformance failure, so the non-conformant frame is reported as a diff --git a/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h b/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h index c5dafee217a..85480ab1793 100644 --- a/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h +++ b/chromium/media/formats/webcodecs/webcodecs_encoded_chunk_stream_parser.h @@ -9,7 +9,6 @@ #include <memory> -#include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "media/base/audio_decoder_config.h" diff --git a/chromium/media/formats/webm/webm_colour_parser.cc b/chromium/media/formats/webm/webm_colour_parser.cc index 134f4f7583a..7deee8eaa10 100644 --- a/chromium/media/formats/webm/webm_colour_parser.cc +++ b/chromium/media/formats/webm/webm_colour_parser.cc @@ -4,6 +4,7 @@ #include "media/formats/webm/webm_colour_parser.h" +#include "base/check.h" #include "base/logging.h" #include "media/formats/webm/webm_constants.h" #include "third_party/libwebm/source/mkvmuxer/mkvmuxer.h" diff --git a/chromium/media/formats/webm/webm_colour_parser.h b/chromium/media/formats/webm/webm_colour_parser.h index dedd824f43b..2a97bc73168 100644 --- a/chromium/media/formats/webm/webm_colour_parser.h +++ b/chromium/media/formats/webm/webm_colour_parser.h @@ -6,9 +6,9 @@ #define MEDIA_FORMATS_WEBM_WEBM_COLOUR_PARSER_H_ #include "base/macros.h" -#include "base/optional.h" #include "media/base/video_color_space.h" #include "media/formats/webm/webm_parser.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/hdr_metadata.h" namespace media { @@ -26,7 +26,7 @@ struct MEDIA_EXPORT WebMColorMetadata { VideoColorSpace color_space; - base::Optional<gfx::HDRMetadata> hdr_metadata; + absl::optional<gfx::HDRMetadata> hdr_metadata; WebMColorMetadata(); WebMColorMetadata(const WebMColorMetadata& rhs); diff --git a/chromium/media/formats/webm/webm_stream_parser.h b/chromium/media/formats/webm/webm_stream_parser.h index dc0b9167a74..bab74de0a80 100644 --- a/chromium/media/formats/webm/webm_stream_parser.h +++ b/chromium/media/formats/webm/webm_stream_parser.h @@ -9,7 +9,6 @@ #include <memory> -#include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "media/base/audio_decoder_config.h" diff --git a/chromium/media/formats/webm/webm_stream_parser_unittest.cc b/chromium/media/formats/webm/webm_stream_parser_unittest.cc index 7c01c85a0ef..fdb19030b31 100644 --- a/chromium/media/formats/webm/webm_stream_parser_unittest.cc +++ b/chromium/media/formats/webm/webm_stream_parser_unittest.cc @@ -176,7 +176,7 @@ TEST_F(WebMStreamParserTest, ColourElement) { gfx::ColorSpace::RangeID::FULL); EXPECT_EQ(video_config.color_space_info(), expected_color_space); - base::Optional<gfx::HDRMetadata> hdr_metadata = video_config.hdr_metadata(); + absl::optional<gfx::HDRMetadata> hdr_metadata = video_config.hdr_metadata(); EXPECT_TRUE(hdr_metadata.has_value()); EXPECT_EQ(hdr_metadata->max_content_light_level, 11u); EXPECT_EQ(hdr_metadata->max_frame_average_light_level, 12u); diff --git a/chromium/media/fuchsia/audio/BUILD.gn b/chromium/media/fuchsia/audio/BUILD.gn index eb547274da2..618fdd7fa0f 100644 --- a/chromium/media/fuchsia/audio/BUILD.gn +++ b/chromium/media/fuchsia/audio/BUILD.gn @@ -7,11 +7,16 @@ source_set("audio") { deps = [ "//base", - "//media", + "//media/base", + "//media/filters", + "//media/fuchsia/cdm", + "//media/fuchsia/common", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.media.audio", "//third_party/fuchsia-sdk/sdk/pkg/sys_cpp", ] + configs += [ "//media:subcomponent_config" ] + sources = [ "fuchsia_audio_capturer_source.cc", "fuchsia_audio_capturer_source.h", @@ -40,7 +45,6 @@ source_set("unittests") { testonly = true deps = [ - ":audio", ":test_support", "//base", "//base/test:test_support", @@ -52,5 +56,6 @@ source_set("unittests") { sources = [ "fuchsia_audio_capturer_source_test.cc", "fuchsia_audio_output_device_test.cc", + "fuchsia_audio_renderer_test.cc", ] } diff --git a/chromium/media/fuchsia/audio/fake_audio_consumer.h b/chromium/media/fuchsia/audio/fake_audio_consumer.h index da1fcefb88c..e56bbfcbc75 100644 --- a/chromium/media/fuchsia/audio/fake_audio_consumer.h +++ b/chromium/media/fuchsia/audio/fake_audio_consumer.h @@ -11,6 +11,7 @@ #include <fuchsia/media/cpp/fidl_test_base.h> #include <lib/fidl/cpp/binding.h> +#include <list> #include <vector> #include "base/fuchsia/scoped_service_binding.h" diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source.cc b/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source.cc index 80c28b2a6e3..721365dff9d 100644 --- a/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source.cc +++ b/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source.cc @@ -11,6 +11,7 @@ #include "base/bits.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/location.h" +#include "base/stl_util.h" #include "base/task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "media/base/audio_parameters.h" @@ -170,7 +171,7 @@ void FuchsiaAudioCapturerSource::SetOutputDeviceForAec( void FuchsiaAudioCapturerSource::NotifyCaptureError( const std::string& message) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - callback_->OnCaptureError(message); + callback_->OnCaptureError(AudioCapturerSource::ErrorCode::kUnknown, message); } void FuchsiaAudioCapturerSource::NotifyCaptureStarted() { diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source.h b/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source.h index 58fb18f8b55..43563e9231d 100644 --- a/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source.h +++ b/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source.h @@ -10,10 +10,11 @@ #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" #include "media/base/audio_capturer_source.h" +#include "media/base/media_export.h" namespace media { -class FuchsiaAudioCapturerSource : public AudioCapturerSource { +class MEDIA_EXPORT FuchsiaAudioCapturerSource : public AudioCapturerSource { public: explicit FuchsiaAudioCapturerSource( fidl::InterfaceHandle<fuchsia::media::AudioCapturer> capturer_handle); diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source_test.cc b/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source_test.cc index c045c52c39f..3d9a04c82a6 100644 --- a/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source_test.cc +++ b/chromium/media/fuchsia/audio/fuchsia_audio_capturer_source_test.cc @@ -121,7 +121,7 @@ class TestAudioCapturer zx::vmo buffer_vmo_; uint64_t buffer_size_ = 0; - base::Optional<fuchsia::media::AudioStreamType> stream_type_; + absl::optional<fuchsia::media::AudioStreamType> stream_type_; bool is_active_ = false; size_t frames_per_packet_ = 0; std::vector<bool> packets_usage_; @@ -156,7 +156,8 @@ class TestCaptureCallback : public AudioCapturerSource::CaptureCallback { packets_.push_back(std::move(bus)); } - void OnCaptureError(const std::string& message) final { + void OnCaptureError(AudioCapturerSource::ErrorCode code, + const std::string& message) final { EXPECT_FALSE(have_error_); have_error_ = true; } diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_output_device.cc b/chromium/media/fuchsia/audio/fuchsia_audio_output_device.cc index 50429b46f06..3ebab0a45e6 100644 --- a/chromium/media/fuchsia/audio/fuchsia_audio_output_device.cc +++ b/chromium/media/fuchsia/audio/fuchsia_audio_output_device.cc @@ -9,7 +9,6 @@ #include "base/memory/shared_memory_mapping.h" #include "base/memory/writable_shared_memory_region.h" #include "base/no_destructor.h" -#include "base/strings/stringprintf.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "media/base/audio_timestamp_helper.h" @@ -386,46 +385,33 @@ void FuchsiaAudioOutputDevice::SchedulePumpSamples() { base::TimeTicks now = base::TimeTicks::Now(); - int skipped_frames = 0; - // Target time for when PumpSamples() should run. base::TimeTicks target_time = playback_time - min_lead_time_ - kLeadTimeExtra; - // Check if it's too late to send the next packet. If it is, then advance - // current stream position, adding kLeadTimeExtra to ensure the next packet - // doesn't miss the deadline. - auto lead_time = playback_time - now; - if (lead_time < min_lead_time_) { - auto new_playback_time = now + min_lead_time_ + kLeadTimeExtra; - auto skipped_time = new_playback_time - playback_time; - skipped_frames = - AudioTimestampHelper::TimeToFrames(skipped_time, params_.sample_rate()); - media_pos_frames_ += skipped_frames; - target_time = now; - playback_time += skipped_time; - } - base::TimeDelta delay = target_time - now; pump_samples_timer_.Start( FROM_HERE, delay, base::BindOnce(&FuchsiaAudioOutputDevice::PumpSamples, this, - playback_time, skipped_frames)); + playback_time)); } -void FuchsiaAudioOutputDevice::PumpSamples(base::TimeTicks playback_time, - int frames_skipped) { +void FuchsiaAudioOutputDevice::PumpSamples(base::TimeTicks playback_time) { DCHECK(CurrentThreadIsRenderingThread()); auto now = base::TimeTicks::Now(); - // Check if the timer has missed the deadline. It doesn't make sense to try - // sending the packet in that case (it's likely to arrive too late). - // Reschedule the timer. In this case SchedulePumpSamples() is expected to - // schedule PumpSamples() to run immediately with frames_skipped > 0. + int skipped_frames = 0; + + // Check if it's too late to send the next packet. If it is, then advance + // current stream position. auto lead_time = playback_time - now; if (lead_time < min_lead_time_) { - SchedulePumpSamples(); - return; + auto new_playback_time = now + min_lead_time_; + auto skipped_time = new_playback_time - playback_time; + skipped_frames = + AudioTimestampHelper::TimeToFrames(skipped_time, params_.sample_rate()); + media_pos_frames_ += skipped_frames; + playback_time += skipped_time; } int frames_filled; @@ -437,7 +423,7 @@ void FuchsiaAudioOutputDevice::PumpSamples(base::TimeTicks playback_time, if (!callback_) return; - frames_filled = callback_->Render(playback_time - now, now, frames_skipped, + frames_filled = callback_->Render(playback_time - now, now, skipped_frames, audio_bus_.get()); } @@ -489,4 +475,4 @@ void FuchsiaAudioOutputDevice::ReportError() { } } -} // namespace media
\ No newline at end of file +} // namespace media diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_output_device.h b/chromium/media/fuchsia/audio/fuchsia_audio_output_device.h index a08617ade56..985aac96c0f 100644 --- a/chromium/media/fuchsia/audio/fuchsia_audio_output_device.h +++ b/chromium/media/fuchsia/audio/fuchsia_audio_output_device.h @@ -16,6 +16,7 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "media/base/audio_renderer_sink.h" +#include "media/base/media_export.h" namespace base { class SingleThreadTaskRunner; @@ -31,7 +32,7 @@ namespace media { // All work is performed on the TaskRunner passed to Create(). It must be an IO // thread to allow FIDL usage. AudioRendererSink can be used on a different // thread. -class FuchsiaAudioOutputDevice : public AudioRendererSink { +class MEDIA_EXPORT FuchsiaAudioOutputDevice : public AudioRendererSink { public: static scoped_refptr<FuchsiaAudioOutputDevice> Create( fidl::InterfaceHandle<fuchsia::media::AudioConsumer> @@ -95,7 +96,7 @@ class FuchsiaAudioOutputDevice : public AudioRendererSink { // Pumps a single packet to AudioConsumer and calls SchedulePumpSamples() to // pump the next packet. - void PumpSamples(base::TimeTicks playback_time, int frames_skipped); + void PumpSamples(base::TimeTicks playback_time); // Callback for StreamSink::SendPacket(). void OnStreamSendDone(size_t buffer_index); diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_output_device_test.cc b/chromium/media/fuchsia/audio/fuchsia_audio_output_device_test.cc index d058dc76f68..1b8c6eb51af 100644 --- a/chromium/media/fuchsia/audio/fuchsia_audio_output_device_test.cc +++ b/chromium/media/fuchsia/audio/fuchsia_audio_output_device_test.cc @@ -98,8 +98,8 @@ class FuchsiaAudioOutputDeviceTest : public testing::Test { } void CallPumpSamples() { - output_device_->PumpSamples( - base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(200), 0); + output_device_->PumpSamples(base::TimeTicks::Now() + + base::TimeDelta::FromMilliseconds(200)); } void ValidatePresentationTime() { @@ -194,8 +194,8 @@ TEST_F(FuchsiaAudioOutputDeviceTest, Underflow) { // Advance time by 100ms, causing some frames to be skipped. task_environment_.AdvanceClock(kPeriod * 10); task_environment_.RunUntilIdle(); - EXPECT_EQ(renderer_.frames_rendered(), kFramesPerPeriod); - EXPECT_EQ(renderer_.frames_skipped(), kFramesPerPeriod * 9); + EXPECT_EQ(renderer_.frames_rendered(), kFramesPerPeriod * 3); + EXPECT_EQ(renderer_.frames_skipped(), kFramesPerPeriod * 7); renderer_.reset_frames_rendered(); ValidatePresentationTime(); diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_renderer.cc b/chromium/media/fuchsia/audio/fuchsia_audio_renderer.cc index 871c566c89f..20d98f09c31 100644 --- a/chromium/media/fuchsia/audio/fuchsia_audio_renderer.cc +++ b/chromium/media/fuchsia/audio/fuchsia_audio_renderer.cc @@ -12,9 +12,12 @@ #include "base/sequenced_task_runner.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h" +#include "media/base/cdm_context.h" #include "media/base/decoder_buffer.h" #include "media/base/renderer_client.h" -#include "media/filters/decrypting_demuxer_stream.h" +#include "media/fuchsia/cdm/fuchsia_cdm_context.h" +#include "media/fuchsia/common/decrypting_sysmem_buffer_stream.h" +#include "media/fuchsia/common/passthrough_sysmem_buffer_stream.h" namespace media { @@ -22,7 +25,7 @@ namespace { // nullopt is returned in case the codec is not supported. nullptr is returned // for uncompressed PCM streams. -base::Optional<std::unique_ptr<fuchsia::media::Compression>> +absl::optional<std::unique_ptr<fuchsia::media::Compression>> GetFuchsiaCompressionFromDecoderConfig(AudioDecoderConfig config) { auto compression = std::make_unique<fuchsia::media::Compression>(); switch (config.codec()) { @@ -46,7 +49,7 @@ GetFuchsiaCompressionFromDecoderConfig(AudioDecoderConfig config) { break; default: - return base::nullopt; + return absl::nullopt; } if (!config.extra_data().empty()) { @@ -56,7 +59,7 @@ GetFuchsiaCompressionFromDecoderConfig(AudioDecoderConfig config) { return std::move(compression); } -base::Optional<fuchsia::media::AudioSampleFormat> +absl::optional<fuchsia::media::AudioSampleFormat> GetFuchsiaSampleFormatFromSampleFormat(SampleFormat sample_format) { switch (sample_format) { case kSampleFormatU8: @@ -69,7 +72,7 @@ GetFuchsiaSampleFormatFromSampleFormat(SampleFormat sample_format) { return fuchsia::media::AudioSampleFormat::FLOAT; default: - return base::nullopt; + return absl::nullopt; } } @@ -85,12 +88,10 @@ constexpr size_t kNumBuffers = 16; FuchsiaAudioRenderer::FuchsiaAudioRenderer( MediaLog* media_log, fidl::InterfaceHandle<fuchsia::media::AudioConsumer> audio_consumer_handle) - : media_log_(media_log), - audio_consumer_handle_(std::move(audio_consumer_handle)) { + : audio_consumer_handle_(std::move(audio_consumer_handle)) { DETACH_FROM_THREAD(thread_checker_); } - FuchsiaAudioRenderer::~FuchsiaAudioRenderer() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); } @@ -105,6 +106,7 @@ void FuchsiaAudioRenderer::Initialize(DemuxerStream* stream, DCHECK(!init_cb_); init_cb_ = std::move(init_cb); + demuxer_stream_ = stream; client_ = client; audio_consumer_.Bind(std::move(audio_consumer_handle_)); @@ -118,8 +120,6 @@ void FuchsiaAudioRenderer::Initialize(DemuxerStream* stream, audio_consumer_.events().OnEndOfStream = [this]() { OnEndOfStream(); }; RequestAudioConsumerStatus(); - InitializeStreamSink(stream->audio_decoder_config()); - // AAC streams require bitstream conversion. Without it the demuxer may // produce decoded stream without ADTS headers which are required for AAC // streams in AudioConsumer. @@ -128,21 +128,27 @@ void FuchsiaAudioRenderer::Initialize(DemuxerStream* stream, stream->EnableBitstreamConverter(); } - // DecryptingDemuxerStream handles both encrypted and clear streams, so - // initialize it long as we have cdm_context. - if (cdm_context) { - WaitingCB waiting_cb = base::BindRepeating(&RendererClient::OnWaiting, - base::Unretained(client_)); - decrypting_demuxer_stream_ = std::make_unique<DecryptingDemuxerStream>( - base::ThreadTaskRunnerHandle::Get(), media_log_, waiting_cb); - decrypting_demuxer_stream_->Initialize( - stream, cdm_context, - base::BindRepeating(&FuchsiaAudioRenderer::OnDecryptorInitialized, - base::Unretained(this))); - return; + if (stream->audio_decoder_config().is_encrypted()) { + if (!cdm_context) { + DLOG(ERROR) << "No cdm context for encrypted stream."; + OnError(AUDIO_RENDERER_ERROR); + return; + } + + FuchsiaCdmContext* fuchsia_cdm = cdm_context->GetFuchsiaCdmContext(); + if (fuchsia_cdm) { + sysmem_buffer_stream_ = fuchsia_cdm->CreateStreamDecryptor(false); + } else { + sysmem_buffer_stream_ = std::make_unique<DecryptingSysmemBufferStream>( + &sysmem_allocator_, cdm_context, Decryptor::kAudio); + } + + } else { + sysmem_buffer_stream_ = + std::make_unique<PassthroughSysmemBufferStream>(&sysmem_allocator_); } - demuxer_stream_ = stream; + sysmem_buffer_stream_->Initialize(this, kBufferSize, kNumBuffers); std::move(init_cb_).Run(PIPELINE_OK); } @@ -159,41 +165,41 @@ void FuchsiaAudioRenderer::UpdateVolume() { volume_control_->SetVolume(volume_); } -void FuchsiaAudioRenderer::InitializeStreamSink( - const AudioDecoderConfig& config) { +void FuchsiaAudioRenderer::OnBuffersAcquired( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings&) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!stream_sink_); - DCHECK(stream_sink_buffers_.empty()); - DCHECK_EQ(num_pending_packets_, 0U); - // Allocate input buffers for the StreamSink. - stream_sink_buffers_.resize(kNumBuffers); - std::vector<zx::vmo> vmos_for_stream_sink; - vmos_for_stream_sink.reserve(kNumBuffers); - for (StreamSinkBuffer& buffer : stream_sink_buffers_) { - zx_status_t status = zx::vmo::create(kBufferSize, 0, &buffer.vmo); - ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create"; + input_buffers_ = std::move(buffers); + InitializeStreamSink(); - constexpr char kName[] = "cr-audio-renderer"; - status = - buffer.vmo.set_property(ZX_PROP_NAME, kName, base::size(kName) - 1); - ZX_DCHECK(status == ZX_OK, status); + while (!delayed_packets_.empty()) { + auto packet = std::move(delayed_packets_.front()); + delayed_packets_.pop_front(); + SendInputPacket(std::move(packet)); + } - // Duplicate VMO handle to pass to AudioConsumer. - zx::vmo readonly_vmo; - status = buffer.vmo.duplicate(ZX_RIGHT_DUPLICATE | ZX_RIGHT_TRANSFER | - ZX_RIGHT_READ | ZX_RIGHT_MAP | - ZX_RIGHT_GET_PROPERTY, - &readonly_vmo); - ZX_CHECK(status == ZX_OK, status) << "zx_handle_duplicate"; + if (is_at_end_of_stream_) { + OnSysmemBufferStreamEndOfStream(); + } +} + +void FuchsiaAudioRenderer::InitializeStreamSink() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!stream_sink_); - vmos_for_stream_sink.push_back(std::move(readonly_vmo)); + // Clone |buffers| to pass to StreamSink. + std::vector<zx::vmo> vmos_for_stream_sink; + vmos_for_stream_sink.reserve(input_buffers_.size()); + for (VmoBuffer& buffer : input_buffers_) { + vmos_for_stream_sink.push_back(buffer.Duplicate(/*writable=*/false)); } + auto config = demuxer_stream_->audio_decoder_config(); auto compression = GetFuchsiaCompressionFromDecoderConfig(config); if (!compression) { LOG(ERROR) << "Unsupported audio codec: " << GetCodecName(config.codec()); - std::move(init_cb_).Run(AUDIO_RENDERER_ERROR); + OnError(AUDIO_RENDERER_ERROR); return; } @@ -203,12 +209,12 @@ void FuchsiaAudioRenderer::InitializeStreamSink( // Set sample_format for uncompressed streams. if (!compression) { - base::Optional<fuchsia::media::AudioSampleFormat> sample_format = + absl::optional<fuchsia::media::AudioSampleFormat> sample_format = GetFuchsiaSampleFormatFromSampleFormat(config.sample_format()); if (!sample_format) { LOG(ERROR) << "Unsupported sample format: " << SampleFormatToString(config.sample_format()); - std::move(init_cb_).Run(AUDIO_RENDERER_ERROR); + OnError(AUDIO_RENDERER_ERROR); return; } stream_type.sample_format = sample_format.value(); @@ -221,6 +227,11 @@ void FuchsiaAudioRenderer::InitializeStreamSink( audio_consumer_->CreateStreamSink( std::move(vmos_for_stream_sink), std::move(stream_type), std::move(compression).value(), stream_sink_.NewRequest()); + + if (GetPlaybackState() == PlaybackState::kStartPending) + StartAudioConsumer(); + + ScheduleReadDemuxerStream(); } TimeSource* FuchsiaAudioRenderer::GetTimeSource() { @@ -231,12 +242,15 @@ void FuchsiaAudioRenderer::Flush(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); FlushInternal(); + renderer_started_ = false; + std::move(callback).Run(); } void FuchsiaAudioRenderer::StartPlaying() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + renderer_started_ = true; ScheduleReadDemuxerStream(); } @@ -248,7 +262,7 @@ void FuchsiaAudioRenderer::SetVolume(float volume) { } void FuchsiaAudioRenderer::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { // TODO(crbug.com/1131116): Implement at some later date after we've vetted // the API shape and usefulness outside of fuchsia. } @@ -260,13 +274,35 @@ void FuchsiaAudioRenderer::SetAutoplayInitiated(bool autoplay_initiated) {} void FuchsiaAudioRenderer::StartTicking() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // If StreamSink hasn't been created yet, then delay starting AudioConsumer + // until StreamSink is created. + if (!stream_sink_) { + base::AutoLock lock(timeline_lock_); + SetPlaybackState(PlaybackState::kStartPending); + return; + } + + StartAudioConsumer(); +} + +void FuchsiaAudioRenderer::StartAudioConsumer() { + DCHECK(stream_sink_); + fuchsia::media::AudioConsumerStartFlags flags{}; if (demuxer_stream_->liveness() == DemuxerStream::LIVENESS_LIVE) { flags = fuchsia::media::AudioConsumerStartFlags::LOW_LATENCY; } - if (GetPlaybackState() != PlaybackState::kStopped) { - audio_consumer_->Stop(); + // Stop the AudioConsumer if it's been started. + switch (GetPlaybackState()) { + case PlaybackState::kStopped: + case PlaybackState::kStartPending: + break; + + case PlaybackState::kStarting: + case PlaybackState::kPlaying: + audio_consumer_->Stop(); + break; } base::TimeDelta media_pos; @@ -384,6 +420,8 @@ void FuchsiaAudioRenderer::OnError(PipelineStatus status) { audio_consumer_.Unbind(); stream_sink_.Unbind(); + sysmem_buffer_stream_.reset(); + if (init_cb_) { std::move(init_cb_).Run(status); } else if (client_) { @@ -391,22 +429,6 @@ void FuchsiaAudioRenderer::OnError(PipelineStatus status) { } } -void FuchsiaAudioRenderer::OnDecryptorInitialized(PipelineStatus status) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // |init_cb_| may be cleared in OnError(), e.g. if AudioConsumer was - // disconnected. - if (!init_cb_) { - return; - } - - if (status == PIPELINE_OK) { - demuxer_stream_ = decrypting_demuxer_stream_.get(); - } - - std::move(init_cb_).Run(status); -} - void FuchsiaAudioRenderer::RequestAudioConsumerStatus() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); audio_consumer_->WatchStatus(fit::bind_member( @@ -423,6 +445,8 @@ void FuchsiaAudioRenderer::OnAudioConsumerStatusChanged( return; } + bool reschedule_read_timer = false; + if (status.has_presentation_timeline()) { if (GetPlaybackState() != PlaybackState::kStopped) { base::AutoLock lock(timeline_lock_); @@ -435,10 +459,11 @@ void FuchsiaAudioRenderer::OnAudioConsumerStatusChanged( status.presentation_timeline().subject_time); reference_delta_ = status.presentation_timeline().reference_delta; media_delta_ = status.presentation_timeline().subject_delta; + + reschedule_read_timer = true; } } - bool reschedule_read_timer = false; if (status.has_min_lead_time()) { auto new_min_lead_time = base::TimeDelta::FromZxDuration(status.min_lead_time()); @@ -469,21 +494,27 @@ void FuchsiaAudioRenderer::OnAudioConsumerStatusChanged( void FuchsiaAudioRenderer::ScheduleReadDemuxerStream() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (!demuxer_stream_ || read_timer_.IsRunning() || is_demuxer_read_pending_ || - is_at_end_of_stream_ || - num_pending_packets_ >= stream_sink_buffers_.size()) { + if (!renderer_started_ || !demuxer_stream_ || read_timer_.IsRunning() || + is_demuxer_read_pending_ || is_at_end_of_stream_) { return; } base::TimeDelta next_read_delay; if (!last_packet_timestamp_.is_min()) { - auto relative_buffer_pos = last_packet_timestamp_ - CurrentMediaTime(); - - if (!min_lead_time_.is_zero() && relative_buffer_pos > min_lead_time_) { - SetBufferState(BUFFERING_HAVE_ENOUGH); - } - - if (!max_lead_time_.is_zero() && relative_buffer_pos > max_lead_time_) { + std::vector<base::TimeTicks> wall_clock_times; + bool is_time_moving = + GetWallClockTimes({last_packet_timestamp_}, &wall_clock_times); + base::TimeDelta relative_buffer_pos = + wall_clock_times[0] - base::TimeTicks::Now(); + + // Check if we have buffered more than |max_lead_time_|. + if (relative_buffer_pos >= max_lead_time_) { + // If playback is not active then there is no need to buffer more. + if (!is_time_moving) + return; + + // If the buffer is larger than |max_lead_time_|, then the next read + // should be delayed. next_read_delay = relative_buffer_pos - max_lead_time_; } } @@ -523,11 +554,10 @@ void FuchsiaAudioRenderer::OnDemuxerStreamReadDone( OnError(PIPELINE_ERROR_READ); } else if (read_status == DemuxerStream::kConfigChanged) { stream_sink_.Unbind(); - stream_sink_buffers_.clear(); - num_pending_packets_ = 0; + sysmem_buffer_stream_->Reset(); - InitializeStreamSink(demuxer_stream_->audio_decoder_config()); - ScheduleReadDemuxerStream(); + InitializeStreamSink(); + client_->OnAudioConfigChange(demuxer_stream_->audio_decoder_config()); } else { DCHECK_EQ(read_status, DemuxerStream::kAborted); } @@ -536,71 +566,61 @@ void FuchsiaAudioRenderer::OnDemuxerStreamReadDone( if (buffer->end_of_stream()) { is_at_end_of_stream_ = true; - stream_sink_->EndOfStream(); - - // No more data is going to be buffered. Update buffering state to ensure - // RendererImpl starts playback in case it was waiting for buffering to - // finish. - SetBufferState(BUFFERING_HAVE_ENOUGH); - - return; - } + } else { + if (buffer->data_size() > kBufferSize) { + DLOG(ERROR) << "Demuxer returned buffer that is too big: " + << buffer->data_size(); + OnError(AUDIO_RENDERER_ERROR); + return; + } - if (buffer->data_size() > kBufferSize) { - DLOG(ERROR) << "Demuxer returned buffer that is too big: " - << buffer->data_size(); - OnError(AUDIO_RENDERER_ERROR); - return; + last_packet_timestamp_ = buffer->timestamp(); + if (buffer->duration() != kNoTimestamp) + last_packet_timestamp_ += buffer->duration(); } - // Find unused buffer. - auto it = std::find_if( - stream_sink_buffers_.begin(), stream_sink_buffers_.end(), - [](const StreamSinkBuffer& b) -> bool { return !b.is_used; }); - - // ReadDemuxerStream() is not supposed to be called unless there are unused - // buffers. - CHECK(it != stream_sink_buffers_.end()); + sysmem_buffer_stream_->EnqueueBuffer(std::move(buffer)); - ++num_pending_packets_; - DCHECK_LE(num_pending_packets_, stream_sink_buffers_.size()); - - it->is_used = true; - zx_status_t status = it->vmo.write(buffer->data(), 0, buffer->data_size()); - ZX_CHECK(status == ZX_OK, status) << "zx_vmo_write"; + ScheduleReadDemuxerStream(); +} - size_t buffer_index = it - stream_sink_buffers_.begin(); +void FuchsiaAudioRenderer::SendInputPacket( + StreamProcessorHelper::IoPacket packet) { + fuchsia::media::StreamPacket stream_packet; + stream_packet.payload_buffer_id = packet.buffer_index(); + stream_packet.pts = packet.timestamp().ToZxDuration(); + stream_packet.payload_offset = packet.offset(); + stream_packet.payload_size = packet.size(); - fuchsia::media::StreamPacket packet; - packet.payload_buffer_id = buffer_index; - packet.pts = buffer->timestamp().ToZxDuration(); - packet.payload_offset = 0; - packet.payload_size = buffer->data_size(); - - stream_sink_->SendPacket(std::move(packet), [this, buffer_index]() { - OnStreamSendDone(buffer_index); - }); + stream_sink_->SendPacket( + std::move(stream_packet), + [this, packet = std::make_unique<StreamProcessorHelper::IoPacket>( + std::move(packet))]() mutable { + OnStreamSendDone(std::move(packet)); + }); // AudioConsumer doesn't report exact time when the data is decoded, but it's // safe to report it as decoded right away since the packet is expected to be // decoded soon after AudioConsumer receives it. PipelineStatistics stats; - stats.audio_bytes_decoded = buffer->data_size(); + stats.audio_bytes_decoded = packet.size(); client_->OnStatisticsUpdate(stats); - - last_packet_timestamp_ = buffer->timestamp(); - - ScheduleReadDemuxerStream(); } -void FuchsiaAudioRenderer::OnStreamSendDone(size_t buffer_index) { +void FuchsiaAudioRenderer::OnStreamSendDone( + std::unique_ptr<StreamProcessorHelper::IoPacket> packet) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_LT(buffer_index, stream_sink_buffers_.size()); - DCHECK(stream_sink_buffers_[buffer_index].is_used); - stream_sink_buffers_[buffer_index].is_used = false; - DCHECK_GT(num_pending_packets_, 0U); - --num_pending_packets_; + // Check if we need to update buffering state after sending more than + // |min_lead_time_| to the AudioConsumer. + if (buffer_state_ == BUFFERING_HAVE_NOTHING) { + std::vector<base::TimeTicks> wall_clock_times; + GetWallClockTimes({packet->timestamp()}, &wall_clock_times); + base::TimeDelta relative_buffer_pos = + wall_clock_times[0] - base::TimeTicks::Now(); + if (relative_buffer_pos >= min_lead_time_) + SetBufferState(BUFFERING_HAVE_ENOUGH); + } ScheduleReadDemuxerStream(); } @@ -617,7 +637,9 @@ void FuchsiaAudioRenderer::FlushInternal() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(GetPlaybackState() == PlaybackState::kStopped || is_at_end_of_stream_); - stream_sink_->DiscardAllPacketsNoReply(); + if (stream_sink_) + stream_sink_->DiscardAllPacketsNoReply(); + SetBufferState(BUFFERING_HAVE_NOTHING); last_packet_timestamp_ = base::TimeDelta::Min(); read_timer_.Stop(); @@ -655,4 +677,64 @@ base::TimeDelta FuchsiaAudioRenderer::CurrentMediaTimeLocked() { media_delta_ / reference_delta_; } +void FuchsiaAudioRenderer::OnSysmemBufferStreamBufferCollectionToken( + fuchsia::sysmem::BufferCollectionTokenPtr token) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // Drop old buffers. + input_buffers_.clear(); + stream_sink_.Unbind(); + + // Acquire buffers for the new buffer collection. + input_buffer_collection_ = + sysmem_allocator_.BindSharedCollection(std::move(token)); + fuchsia::sysmem::BufferCollectionConstraints buffer_constraints = + VmoBuffer::GetRecommendedConstraints(kNumBuffers, kBufferSize, + /*writable=*/false); + input_buffer_collection_->Initialize(std::move(buffer_constraints), + "CrAudioRenderer"); + input_buffer_collection_->AcquireBuffers(base::BindOnce( + &FuchsiaAudioRenderer::OnBuffersAcquired, base::Unretained(this))); +} + +void FuchsiaAudioRenderer::OnSysmemBufferStreamOutputPacket( + StreamProcessorHelper::IoPacket packet) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (stream_sink_) { + SendInputPacket(std::move(packet)); + } else { + // The packet will be sent after StreamSink is connected. + delayed_packets_.push_back(std::move(packet)); + } + + ScheduleReadDemuxerStream(); +} + +void FuchsiaAudioRenderer::OnSysmemBufferStreamEndOfStream() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(is_at_end_of_stream_); + + // Stream sink is not bound yet, don't send EOS. + if (!stream_sink_) + return; + + stream_sink_->EndOfStream(); + + // No more data is going to be buffered. Update buffering state to ensure + // RendererImpl starts playback in case it was waiting for buffering to + // finish. + SetBufferState(BUFFERING_HAVE_ENOUGH); +} + +void FuchsiaAudioRenderer::OnSysmemBufferStreamError() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + OnError(AUDIO_RENDERER_ERROR); +} + +void FuchsiaAudioRenderer::OnSysmemBufferStreamNoKey() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + client_->OnWaiting(WaitingReason::kNoDecryptionKey); +} + } // namespace media diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_renderer.h b/chromium/media/fuchsia/audio/fuchsia_audio_renderer.h index 65dd995cd9e..78a8a356a74 100644 --- a/chromium/media/fuchsia/audio/fuchsia_audio_renderer.h +++ b/chromium/media/fuchsia/audio/fuchsia_audio_renderer.h @@ -13,17 +13,22 @@ #include "media/base/audio_renderer.h" #include "media/base/buffering_state.h" #include "media/base/demuxer_stream.h" +#include "media/base/media_export.h" #include "media/base/time_source.h" +#include "media/fuchsia/common/sysmem_buffer_stream.h" +#include "media/fuchsia/common/sysmem_client.h" +#include "media/fuchsia/common/vmo_buffer.h" namespace media { -class DecryptingDemuxerStream; class MediaLog; // AudioRenderer implementation that output audio to AudioConsumer interface on // Fuchsia. Unlike the default AudioRendererImpl it doesn't decode audio and // sends encoded stream directly to AudioConsumer provided by the platform. -class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource { +class MEDIA_EXPORT FuchsiaAudioRenderer : public AudioRenderer, + public TimeSource, + public SysmemBufferStream::Sink { public: FuchsiaAudioRenderer(MediaLog* media_log, fidl::InterfaceHandle<fuchsia::media::AudioConsumer> @@ -39,7 +44,7 @@ class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource { void Flush(base::OnceClosure callback) final; void StartPlaying() final; void SetVolume(float volume) final; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) final; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) final; void SetPreservesPitch(bool preserves_pitch) final; void SetAutoplayInitiated(bool autoplay_initiated) final; @@ -56,6 +61,11 @@ class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource { enum class PlaybackState { kStopped, + // StartTicking() was called, but sysmem buffers haven't been allocated yet. + // AudioConsumer::Start() will be called after CreateStreamSink() once the + // sysmem buffers are allocated. + kStartPending, + // We've called Start(), but haven't received updated state. |start_time_| // should not be used yet. kStarting, @@ -65,12 +75,7 @@ class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource { kPlaying, }; - // Struct used to store state of an input buffer shared with the - // |stream_sink_|. - struct StreamSinkBuffer { - zx::vmo vmo; - bool is_used = false; - }; + void StartAudioConsumer(); // Returns current PlaybackState. Should be used only on the main thread. PlaybackState GetPlaybackState() NO_THREAD_SAFETY_ANALYSIS; @@ -88,12 +93,14 @@ class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource { // |volume_|. void UpdateVolume(); + // Callback for input_buffer_collection_.AcquireBuffers(). + void OnBuffersAcquired( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings& buffer_settings); + // Initializes |stream_sink_|. Called during initialization and every time // configuration changes. - void InitializeStreamSink(const AudioDecoderConfig& config); - - // Callback for DecryptingDemuxerStream::Initialize(). - void OnDecryptorInitialized(PipelineStatus status); + void InitializeStreamSink(); // Helpers to receive AudioConsumerStatus from the |audio_consumer_|. void RequestAudioConsumerStatus(); @@ -105,8 +112,12 @@ class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource { void OnDemuxerStreamReadDone(DemuxerStream::Status status, scoped_refptr<DecoderBuffer> buffer); + // Sends the specified packet to |stream_sink_|. + void SendInputPacket(StreamProcessorHelper::IoPacket packet); + // Result handler for StreamSink::SendPacket(). - void OnStreamSendDone(size_t buffer_index); + void OnStreamSendDone( + std::unique_ptr<StreamProcessorHelper::IoPacket> packet); // Updates buffer state and notifies the |client_| if necessary. void SetBufferState(BufferingState buffer_state); @@ -132,7 +143,14 @@ class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource { base::TimeDelta CurrentMediaTimeLocked() EXCLUSIVE_LOCKS_REQUIRED(timeline_lock_); - MediaLog* const media_log_; + // SysmemBufferStream::Sink implementation. + void OnSysmemBufferStreamBufferCollectionToken( + fuchsia::sysmem::BufferCollectionTokenPtr token) override; + void OnSysmemBufferStreamOutputPacket( + StreamProcessorHelper::IoPacket packet) override; + void OnSysmemBufferStreamEndOfStream() override; + void OnSysmemBufferStreamError() override; + void OnSysmemBufferStreamNoKey() override; // Handle for |audio_consumer_|. It's stored here until Initialize() is // called. @@ -153,20 +171,32 @@ class FuchsiaAudioRenderer : public AudioRenderer, public TimeSource { // Initialize() completion callback. PipelineStatusCallback init_cb_; - std::unique_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream_; + // Indicates that StartPlaying() has been called. Note that playback doesn't + // start until TimeSource::StartTicking() is called. + bool renderer_started_ = false; BufferingState buffer_state_ = BUFFERING_HAVE_NOTHING; base::TimeDelta last_packet_timestamp_ = base::TimeDelta::Min(); base::OneShotTimer read_timer_; - std::vector<StreamSinkBuffer> stream_sink_buffers_; - size_t num_pending_packets_ = 0u; + SysmemAllocatorClient sysmem_allocator_{"CrFuchsiaAudioRenderer"}; + std::unique_ptr<SysmemCollectionClient> input_buffer_collection_; + + std::unique_ptr<SysmemBufferStream> sysmem_buffer_stream_; + + // VmoBuffers for the buffers |input_buffer_collection_|. + std::vector<VmoBuffer> input_buffers_; + + // Packets produced before the |stream_sink_| is connected. They are sent as + // soon as input buffers are acquired and |stream_sink_| is connected in + // OnBuffersAcquired(). + std::list<StreamProcessorHelper::IoPacket> delayed_packets_; - // Lead time range requested by the |audio_consumer_|. Initialized to 0 until - // the initial AudioConsumerStatus is received. - base::TimeDelta min_lead_time_; - base::TimeDelta max_lead_time_; + // Lead time range requested by the |audio_consumer_|. Initialized to the + // [100ms, 500ms] until the initial AudioConsumerStatus is received. + base::TimeDelta min_lead_time_ = base::TimeDelta::FromMilliseconds(100); + base::TimeDelta max_lead_time_ = base::TimeDelta::FromMilliseconds(500); // Set to true after we've received end-of-stream from the |demuxer_stream_|. // The renderer may be restarted after Flush(). diff --git a/chromium/media/fuchsia/audio/fuchsia_audio_renderer_test.cc b/chromium/media/fuchsia/audio/fuchsia_audio_renderer_test.cc new file mode 100644 index 00000000000..986856ce78a --- /dev/null +++ b/chromium/media/fuchsia/audio/fuchsia_audio_renderer_test.cc @@ -0,0 +1,1010 @@ +// Copyright 2021 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/fuchsia/audio/fuchsia_audio_renderer.h" + +#include <fuchsia/media/audio/cpp/fidl_test_base.h> +#include <fuchsia/media/cpp/fidl_test_base.h> +#include <lib/fidl/cpp/binding.h> + +#include "base/containers/queue.h" +#include "base/logging.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "base/threading/thread_task_runner_handle.h" +#include "media/base/cdm_context.h" +#include "media/base/decoder_buffer.h" +#include "media/base/renderer_client.h" +#include "media/fuchsia/cdm/fuchsia_cdm_context.h" +#include "media/fuchsia/common/passthrough_sysmem_buffer_stream.h" +#include "media/fuchsia/common/sysmem_client.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace media { + +namespace { + +constexpr int kDefaultSampleRate = 48000; +constexpr base::TimeDelta kPacketDuration = + base::TimeDelta::FromMilliseconds(20); +constexpr base::TimeDelta kMinLeadTime = base::TimeDelta::FromMilliseconds(100); +constexpr base::TimeDelta kMaxLeadTime = base::TimeDelta::FromMilliseconds(500); +const base::TimeDelta kTimeStep = base::TimeDelta::FromMilliseconds(2); + +class TestDemuxerStream : public DemuxerStream { + public: + struct ReadResult { + explicit ReadResult(scoped_refptr<DecoderBuffer> buffer) : buffer(buffer) {} + explicit ReadResult(const AudioDecoderConfig& config) : config(config) {} + + Status status; + absl::optional<AudioDecoderConfig> config; + scoped_refptr<DecoderBuffer> buffer; + }; + + explicit TestDemuxerStream(const AudioDecoderConfig& config) + : config_(config) {} + + ~TestDemuxerStream() override {} + + void QueueReadResult(ReadResult read_result) { + CHECK(read_result.config.has_value() == !read_result.buffer); + read_queue_.push(std::move(read_result)); + SatisfyRead(); + } + + void DiscardQueueAndAbortRead() { + while (!read_queue_.empty()) + read_queue_.pop(); + if (read_cb_) + std::move(read_cb_).Run(kAborted, nullptr); + } + + bool is_read_pending() const { return !!read_cb_; } + + // DemuxerStream implementation. + void Read(ReadCB read_cb) override { + read_cb_ = std::move(read_cb); + SatisfyRead(); + } + AudioDecoderConfig audio_decoder_config() override { return config_; } + VideoDecoderConfig video_decoder_config() override { + NOTREACHED(); + return VideoDecoderConfig(); + } + Type type() const override { return AUDIO; } + Liveness liveness() const override { return LIVENESS_RECORDED; } + bool SupportsConfigChanges() override { return true; } + + private: + void SatisfyRead() { + if (read_queue_.empty() || !read_cb_) + return; + + auto result = std::move(read_queue_.front()); + read_queue_.pop(); + + Status status; + if (result.config) { + config_ = result.config.value(); + status = kConfigChanged; + } else { + status = kOk; + } + + std::move(read_cb_).Run(status, result.buffer); + } + + AudioDecoderConfig config_; + ReadCB read_cb_; + + base::queue<ReadResult> read_queue_; +}; + +class TestStreamSink : public fuchsia::media::testing::StreamSink_TestBase { + public: + TestStreamSink( + std::vector<zx::vmo> buffers, + fuchsia::media::AudioStreamType stream_type, + std::unique_ptr<fuchsia::media::Compression> compression, + fidl::InterfaceRequest<fuchsia::media::StreamSink> stream_sink_request) + : binding_(this, std::move(stream_sink_request)), + buffers_(std::move(buffers)), + stream_type_(std::move(stream_type)), + compression_(std::move(compression)) {} + + const std::vector<zx::vmo>& buffers() const { return buffers_; } + const fuchsia::media::AudioStreamType& stream_type() const { + return stream_type_; + } + const fuchsia::media::Compression* compression() const { + return compression_.get(); + } + + std::vector<fuchsia::media::StreamPacket>* received_packets() { + return &received_packets_; + } + + std::vector<fuchsia::media::StreamPacket>* discarded_packets() { + return &discarded_packets_; + } + + bool received_end_of_stream() const { return received_end_of_stream_; } + + // fuchsia::media::StreamSink overrides. + void SendPacket(fuchsia::media::StreamPacket packet, + SendPacketCallback callback) override { + EXPECT_FALSE(received_end_of_stream_); + received_packets_.push_back(std::move(packet)); + callback(); + } + void EndOfStream() override { received_end_of_stream_ = true; } + void DiscardAllPackets(DiscardAllPacketsCallback callback) override { + DiscardAllPacketsNoReply(); + callback(); + } + void DiscardAllPacketsNoReply() override { + std::move(std::begin(received_packets_), std::end(received_packets_), + std::back_inserter(discarded_packets_)); + received_packets_.clear(); + } + + // Other methods are not expected to be called. + void NotImplemented_(const std::string& name) final { + FAIL() << ": " << name; + } + + private: + fidl::Binding<fuchsia::media::StreamSink> binding_; + + std::vector<zx::vmo> buffers_; + fuchsia::media::AudioStreamType stream_type_; + std::unique_ptr<fuchsia::media::Compression> compression_; + + std::vector<fuchsia::media::StreamPacket> received_packets_; + std::vector<fuchsia::media::StreamPacket> discarded_packets_; + + bool received_end_of_stream_ = false; +}; + +class TestAudioConsumer + : public fuchsia::media::testing::AudioConsumer_TestBase, + public fuchsia::media::audio::testing::VolumeControl_TestBase { + public: + explicit TestAudioConsumer( + fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request) + : binding_(this, std::move(request)), volume_control_binding_(this) {} + + std::unique_ptr<TestStreamSink> TakeStreamSink() { + return std::move(stream_sink_); + } + + std::unique_ptr<TestStreamSink> WaitStreamSinkConnected() { + if (!stream_sink_) { + base::RunLoop run_loop; + wait_stream_sink_created_loop_ = &run_loop; + run_loop.Run(); + wait_stream_sink_created_loop_ = nullptr; + } + EXPECT_TRUE(stream_sink_); + return TakeStreamSink(); + } + + void WaitStarted() { + if (started_) + return; + + base::RunLoop run_loop; + wait_started_loop_ = &run_loop; + run_loop.Run(); + wait_started_loop_ = nullptr; + EXPECT_TRUE(started_); + } + + void UpdateStatus(absl::optional<base::TimeTicks> reference_time, + absl::optional<base::TimeDelta> media_time) { + fuchsia::media::AudioConsumerStatus status; + if (reference_time) { + CHECK(media_time); + + fuchsia::media::TimelineFunction timeline; + timeline.reference_time = reference_time->ToZxTime(); + timeline.subject_time = media_time->ToZxDuration(); + timeline.reference_delta = 1000; + timeline.subject_delta = static_cast<int>(playback_rate_ * 1000.0); + status.set_presentation_timeline(std::move(timeline)); + } + + status.set_min_lead_time(kMinLeadTime.ToZxDuration()); + status.set_max_lead_time(kMaxLeadTime.ToZxDuration()); + status_update_ = std::move(status); + + if (status_callback_) + CallStatusCallback(); + } + + void SignalEndOfStream() { binding_.events().OnEndOfStream(); } + + bool started() const { return started_; } + base::TimeDelta start_media_time() const { return start_media_time_; } + float playback_rate() const { return playback_rate_; } + float volume() const { return volume_; } + + // fuchsia::media::AudioConsumer overrides. + void CreateStreamSink( + std::vector<zx::vmo> buffers, + fuchsia::media::AudioStreamType stream_type, + std::unique_ptr<fuchsia::media::Compression> compression, + fidl::InterfaceRequest<fuchsia::media::StreamSink> stream_sink_request) + override { + create_stream_sink_called_ = true; + stream_sink_ = std::make_unique<TestStreamSink>( + std::move(buffers), std::move(stream_type), std::move(compression), + std::move(stream_sink_request)); + if (wait_stream_sink_created_loop_) + wait_stream_sink_created_loop_->Quit(); + } + + void Start(fuchsia::media::AudioConsumerStartFlags flags, + int64_t reference_time, + int64_t media_time) override { + EXPECT_TRUE(create_stream_sink_called_); + EXPECT_FALSE(started_); + EXPECT_EQ(reference_time, fuchsia::media::NO_TIMESTAMP); + started_ = true; + start_media_time_ = base::TimeDelta::FromZxDuration(media_time); + if (wait_started_loop_) + wait_started_loop_->Quit(); + } + + void Stop() override { + EXPECT_TRUE(started_); + started_ = false; + } + + void SetRate(float rate) override { playback_rate_ = rate; } + + void BindVolumeControl( + fidl::InterfaceRequest<fuchsia::media::audio::VolumeControl> + volume_control_request) override { + volume_control_binding_.Bind(std::move(volume_control_request)); + } + + void WatchStatus(WatchStatusCallback callback) override { + EXPECT_FALSE(!!status_callback_); + + status_callback_ = std::move(callback); + + if (status_update_) { + CallStatusCallback(); + } + } + + // fuchsia::media::audio::VolumeControl overrides. + void SetVolume(float volume) override { volume_ = volume; } + + // Other methods are not expected to be called. + void NotImplemented_(const std::string& name) final { + FAIL() << ": " << name; + } + + private: + void CallStatusCallback() { + EXPECT_TRUE(status_callback_); + EXPECT_TRUE(status_update_); + + std::move(status_callback_)(std::move(status_update_.value())); + status_callback_ = {}; + status_update_ = absl::nullopt; + } + + fidl::Binding<fuchsia::media::AudioConsumer> binding_; + fidl::Binding<fuchsia::media::audio::VolumeControl> volume_control_binding_; + std::unique_ptr<TestStreamSink> stream_sink_; + + base::RunLoop* wait_stream_sink_created_loop_ = nullptr; + base::RunLoop* wait_started_loop_ = nullptr; + + bool create_stream_sink_called_ = false; + + WatchStatusCallback status_callback_; + absl::optional<fuchsia::media::AudioConsumerStatus> status_update_; + + bool started_ = false; + base::TimeDelta start_media_time_; + + float playback_rate_ = 1.0; + + float volume_ = 1.0; +}; + +class TestRendererClient : public RendererClient { + public: + TestRendererClient() = default; + ~TestRendererClient() { + EXPECT_EQ(expected_error_, PIPELINE_OK); + EXPECT_FALSE(expect_eos_); + } + + void ExpectError(PipelineStatus expected_error) { + EXPECT_EQ(expected_error_, PIPELINE_OK); + expected_error_ = expected_error; + } + + void ExpectEos() { + EXPECT_FALSE(expect_eos_); + expect_eos_ = true; + } + + BufferingState buffering_state() const { return buffering_state_; } + + absl::optional<AudioDecoderConfig> last_config_change() const { + return last_config_change_; + } + + // RendererClient implementation. + void OnError(PipelineStatus status) override { + EXPECT_EQ(status, expected_error_); + EXPECT_FALSE(have_error_); + have_error_ = true; + expected_error_ = PIPELINE_OK; + } + + void OnEnded() override { + EXPECT_TRUE(expect_eos_); + expect_eos_ = false; + } + + void OnStatisticsUpdate(const PipelineStatistics& stats) override { + bytes_decoded_ += stats.audio_bytes_decoded; + } + + void OnBufferingStateChange(BufferingState state, + BufferingStateChangeReason reason) override { + buffering_state_ = state; + } + + void OnWaiting(WaitingReason reason) override {} + void OnAudioConfigChange(const AudioDecoderConfig& config) override { + last_config_change_ = config; + } + void OnVideoConfigChange(const VideoDecoderConfig& config) override { + FAIL(); + } + void OnVideoNaturalSizeChange(const gfx::Size& size) override { FAIL(); } + void OnVideoOpacityChange(bool opaque) override { FAIL(); } + void OnVideoFrameRateChange(absl::optional<int> fps) override { FAIL(); } + + private: + PipelineStatus expected_error_ = PIPELINE_OK; + bool have_error_ = false; + bool expect_eos_ = false; + BufferingState buffering_state_ = BUFFERING_HAVE_NOTHING; + size_t bytes_decoded_ = 0; + absl::optional<AudioDecoderConfig> last_config_change_; +}; + +// SysmemBufferStream that asynchronously decouples buffer production from +// buffer consumption. Used to simulate stream decryptor. +class AsyncSysmemBufferStream : public SysmemBufferStream { + public: + AsyncSysmemBufferStream(); + ~AsyncSysmemBufferStream() override; + + AsyncSysmemBufferStream(const AsyncSysmemBufferStream&) = delete; + AsyncSysmemBufferStream& operator=(const AsyncSysmemBufferStream&) = delete; + + // SysmemBufferStream implementation: + void Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) override; + void EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer) override; + void Reset() override; + + private: + void DoEnqueueBuffer(scoped_refptr<DecoderBuffer> buffer); + + SysmemAllocatorClient sysmem_allocator_; + PassthroughSysmemBufferStream passthrough_stream_; + + bool is_at_end_of_stream_ = false; + + base::WeakPtrFactory<AsyncSysmemBufferStream> weak_factory_{this}; +}; + +AsyncSysmemBufferStream::AsyncSysmemBufferStream() + : sysmem_allocator_("AsyncSysmemBufferStream"), + passthrough_stream_(&sysmem_allocator_) {} + +AsyncSysmemBufferStream::~AsyncSysmemBufferStream() = default; + +void AsyncSysmemBufferStream::Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) { + passthrough_stream_.Initialize(sink, min_buffer_size, min_buffer_count); +} + +void AsyncSysmemBufferStream::EnqueueBuffer( + scoped_refptr<DecoderBuffer> buffer) { + if (buffer->end_of_stream()) { + EXPECT_FALSE(is_at_end_of_stream_); + is_at_end_of_stream_ = true; + } + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&AsyncSysmemBufferStream::DoEnqueueBuffer, + weak_factory_.GetWeakPtr(), std::move(buffer))); +} + +void AsyncSysmemBufferStream::Reset() { + passthrough_stream_.Reset(); + + // Drop pending DoEnqueueBuffer tasks. + weak_factory_.InvalidateWeakPtrs(); + + is_at_end_of_stream_ = false; +} + +void AsyncSysmemBufferStream::DoEnqueueBuffer( + scoped_refptr<DecoderBuffer> buffer) { + passthrough_stream_.EnqueueBuffer(std::move(buffer)); +} + +class TestFuchsiaCdmContext : public CdmContext, public FuchsiaCdmContext { + public: + // CdmContext overrides. + FuchsiaCdmContext* GetFuchsiaCdmContext() override { return this; } + + // FuchsiaCdmContext implementation. + std::unique_ptr<SysmemBufferStream> CreateStreamDecryptor( + bool secure_mode) override { + return std::make_unique<AsyncSysmemBufferStream>(); + } +}; + +} // namespace + +struct RendererTestConfig { + bool simulate_fuchsia_cdm; +}; + +class FuchsiaAudioRendererTest + : public testing::Test, + public testing::WithParamInterface<RendererTestConfig> { + public: + FuchsiaAudioRendererTest() = default; + ~FuchsiaAudioRendererTest() override = default; + + void CreateUninitializedRenderer(); + void CreateTestDemuxerStream(); + void InitializeRenderer(); + void CreateAndInitializeRenderer(); + void ProduceDemuxerPacket(base::TimeDelta duration); + void FillDemuxerStream(base::TimeDelta end_pos); + void FillBuffer(); + void StartPlayback(base::TimeDelta start_time = base::TimeDelta()); + void CheckGetWallClockTimes(absl::optional<base::TimeDelta> media_timestamp, + base::TimeTicks expected_wall_clock, + bool is_time_moving); + + // Starts playback from |start_time| at the specified |playback_rate| and + // verifies that the clock works correctly. + void StartPlaybackAndVerifyClock(base::TimeDelta start_time, + float playback_rate); + + protected: + base::test::SingleThreadTaskEnvironment task_environment_{ + base::test::SingleThreadTaskEnvironment::MainThreadType::IO, + base::test::TaskEnvironment::TimeSource::MOCK_TIME}; + + std::unique_ptr<CdmContext> cdm_context_; + std::unique_ptr<TestAudioConsumer> audio_consumer_; + std::unique_ptr<TestStreamSink> stream_sink_; + std::unique_ptr<TestDemuxerStream> demuxer_stream_; + TestRendererClient client_; + + std::unique_ptr<AudioRenderer> audio_renderer_; + TimeSource* time_source_; + base::TimeDelta demuxer_stream_pos_; +}; + +void FuchsiaAudioRendererTest::CreateUninitializedRenderer() { + fidl::InterfaceHandle<fuchsia::media::AudioConsumer> audio_consumer_handle; + audio_consumer_ = + std::make_unique<TestAudioConsumer>(audio_consumer_handle.NewRequest()); + audio_renderer_ = std::make_unique<FuchsiaAudioRenderer>( + /*media_log=*/nullptr, std::move(audio_consumer_handle)); + time_source_ = audio_renderer_->GetTimeSource(); +} + +void FuchsiaAudioRendererTest::CreateTestDemuxerStream() { + AudioDecoderConfig config(kCodecPCM, kSampleFormatF32, CHANNEL_LAYOUT_MONO, + kDefaultSampleRate, {}, + EncryptionScheme::kUnencrypted); + + if (GetParam().simulate_fuchsia_cdm) { + config.SetIsEncrypted(true); + cdm_context_ = std::make_unique<TestFuchsiaCdmContext>(); + } + + demuxer_stream_ = std::make_unique<TestDemuxerStream>(config); +} + +void FuchsiaAudioRendererTest::InitializeRenderer() { + if (!demuxer_stream_) + CreateTestDemuxerStream(); + + base::RunLoop run_loop; + PipelineStatus pipeline_status; + audio_renderer_->Initialize( + demuxer_stream_.get(), cdm_context_.get(), &client_, + base::BindLambdaForTesting( + [&run_loop, &pipeline_status](PipelineStatus s) { + pipeline_status = s; + run_loop.Quit(); + })); + run_loop.Run(); + + ASSERT_EQ(pipeline_status, PIPELINE_OK); + + audio_consumer_->UpdateStatus(absl::nullopt, absl::nullopt); + + task_environment_.RunUntilIdle(); +} + +void FuchsiaAudioRendererTest::CreateAndInitializeRenderer() { + CreateUninitializedRenderer(); + InitializeRenderer(); +} + +void FuchsiaAudioRendererTest::ProduceDemuxerPacket(base::TimeDelta duration) { + // Create a dummy packet that contains just 1 byte. + const size_t kBufferSize = 1; + scoped_refptr<DecoderBuffer> buffer = new DecoderBuffer(kBufferSize); + buffer->set_timestamp(demuxer_stream_pos_); + buffer->set_duration(duration); + demuxer_stream_pos_ += duration; + demuxer_stream_->QueueReadResult(TestDemuxerStream::ReadResult(buffer)); +} + +void FuchsiaAudioRendererTest::FillDemuxerStream(base::TimeDelta end_pos) { + EXPECT_LT(demuxer_stream_pos_, end_pos); + while (demuxer_stream_pos_ < end_pos) { + ProduceDemuxerPacket(kPacketDuration); + } +} + +void FuchsiaAudioRendererTest::FillBuffer() { + if (!stream_sink_) { + stream_sink_ = audio_consumer_->WaitStreamSinkConnected(); + } + + // The renderer expects one extra packet after reaching kMinLeadTime to get + // to the BUFFERING_HAVE_ENOUGH state. + const size_t kNumPackets = kMinLeadTime / kPacketDuration + 1; + for (size_t i = 0; i < kNumPackets; ++i) { + ProduceDemuxerPacket(kPacketDuration); + } + task_environment_.RunUntilIdle(); + + // Renderer should not start reading demuxer untile StartPlaying() is + // called. + EXPECT_EQ(client_.buffering_state(), BUFFERING_HAVE_NOTHING); + EXPECT_EQ(stream_sink_->received_packets()->size(), 0U); + + // Start playback. The renderer should push queued packets to the + // AudioConsumer and updated buffering state. + audio_renderer_->StartPlaying(); + task_environment_.RunUntilIdle(); + + EXPECT_EQ(stream_sink_->received_packets()->size(), kNumPackets); + EXPECT_EQ(client_.buffering_state(), BUFFERING_HAVE_ENOUGH); +} + +void FuchsiaAudioRendererTest::StartPlayback(base::TimeDelta start_time) { + EXPECT_FALSE(audio_consumer_->started()); + time_source_->SetMediaTime(start_time); + + ASSERT_NO_FATAL_FAILURE(FillBuffer()); + time_source_->StartTicking(); + task_environment_.RunUntilIdle(); + EXPECT_TRUE(audio_consumer_->started()); + EXPECT_EQ(audio_consumer_->start_media_time(), start_time); + + audio_consumer_->UpdateStatus(base::TimeTicks::Now(), start_time); + task_environment_.RunUntilIdle(); +} + +void FuchsiaAudioRendererTest::CheckGetWallClockTimes( + absl::optional<base::TimeDelta> media_timestamp, + base::TimeTicks expected_wall_clock, + bool is_time_moving) { + std::vector<base::TimeDelta> media_timestamps; + if (media_timestamp) + media_timestamps.push_back(media_timestamp.value()); + std::vector<base::TimeTicks> wall_clock; + bool result = time_source_->GetWallClockTimes(media_timestamps, &wall_clock); + EXPECT_EQ(wall_clock[0], expected_wall_clock); + EXPECT_EQ(result, is_time_moving); +} + +void FuchsiaAudioRendererTest::StartPlaybackAndVerifyClock( + base::TimeDelta start_time, + float playback_rate) { + time_source_->SetMediaTime(start_time); + time_source_->SetPlaybackRate(playback_rate); + + demuxer_stream_pos_ = start_time; + ASSERT_NO_FATAL_FAILURE(FillBuffer()); + + EXPECT_FALSE(audio_consumer_->started()); + time_source_->StartTicking(); + task_environment_.RunUntilIdle(); + EXPECT_TRUE(audio_consumer_->started()); + + // Start position should be reported before updated status is received. + EXPECT_EQ(time_source_->CurrentMediaTime(), start_time); + task_environment_.FastForwardBy(kTimeStep); + EXPECT_EQ(time_source_->CurrentMediaTime(), start_time); + + CheckGetWallClockTimes(absl::nullopt, base::TimeTicks(), false); + CheckGetWallClockTimes(start_time + kTimeStep, + base::TimeTicks::Now() + kTimeStep, false); + + // MediaTime will start moving once AudioConsumer updates timeline. + const base::TimeDelta kStartDelay = base::TimeDelta::FromMilliseconds(3); + base::TimeTicks start_wall_clock = base::TimeTicks::Now() + kStartDelay; + audio_consumer_->UpdateStatus(start_wall_clock, start_time); + task_environment_.RunUntilIdle(); + + EXPECT_EQ(time_source_->CurrentMediaTime(), + start_time - kStartDelay * playback_rate); + task_environment_.FastForwardBy(kTimeStep); + EXPECT_EQ(time_source_->CurrentMediaTime(), + start_time + (-kStartDelay + kTimeStep) * playback_rate); + + CheckGetWallClockTimes(absl::nullopt, base::TimeTicks::Now(), true); + CheckGetWallClockTimes(start_time + kTimeStep, + start_wall_clock + kTimeStep / playback_rate, true); + CheckGetWallClockTimes(start_time + 2 * kTimeStep, + start_wall_clock + 2.0 * kTimeStep / playback_rate, + true); +} + +// Run all FuchsiaAudioRendererTests with CDM enabled and disabled. +INSTANTIATE_TEST_SUITE_P(Unencrypted, + FuchsiaAudioRendererTest, + testing::Values(RendererTestConfig{false})); +INSTANTIATE_TEST_SUITE_P(Encrypted, + FuchsiaAudioRendererTest, + testing::Values(RendererTestConfig{true})); + +TEST_P(FuchsiaAudioRendererTest, Initialize) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); +} + +TEST_P(FuchsiaAudioRendererTest, InitializeAndBuffer) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(FillBuffer()); + + // Extra packets should be sent to AudioConsumer immediately. + stream_sink_->received_packets()->clear(); + ProduceDemuxerPacket(base::TimeDelta::FromMilliseconds(10)); + task_environment_.RunUntilIdle(); + EXPECT_EQ(stream_sink_->received_packets()->size(), 1U); +} + +TEST_P(FuchsiaAudioRendererTest, StartPlaybackBeforeStreamSinkConnected) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + + // Start playing immediately after initialization. The renderer should wait + // for buffers to be allocated before it starts reading from the demuxer. + audio_renderer_->StartPlaying(); + ProduceDemuxerPacket(base::TimeDelta::FromMilliseconds(10)); + task_environment_.RunUntilIdle(); + + stream_sink_ = audio_consumer_->WaitStreamSinkConnected(); + task_environment_.RunUntilIdle(); + EXPECT_EQ(stream_sink_->received_packets()->size(), 1U); +} + +TEST_P(FuchsiaAudioRendererTest, StartTicking) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(StartPlaybackAndVerifyClock( + /*start_pos=*/base::TimeDelta::FromMilliseconds(123), + /*playback_rate=*/1.0)); +} + +TEST_P(FuchsiaAudioRendererTest, StartTickingRate1_5) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(StartPlaybackAndVerifyClock( + /*start_pos=*/base::TimeDelta::FromMilliseconds(123), + /*playback_rate=*/1.5)); +} + +TEST_P(FuchsiaAudioRendererTest, StartTickingRate0_5) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(StartPlaybackAndVerifyClock( + /*start_pos=*/base::TimeDelta::FromMilliseconds(123), + /*playback_rate=*/0.5)); +} + +// Verify that the renderer doesn't send packets more than kMaxLeadTime ahead of +// time. +TEST_P(FuchsiaAudioRendererTest, MaxLeadTime) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(FillBuffer()); + + // Queue packets up to kMaxLeadTime with 10 extra packets. The Renderer + // shouldn't read these extra packets at the end. + FillDemuxerStream(kMaxLeadTime + kPacketDuration * 10); + + task_environment_.RunUntilIdle(); + + // Verify that the renderer has filled the buffer to kMaxLeadTime. + size_t expected_packets = kMaxLeadTime / kPacketDuration; + EXPECT_EQ(expected_packets, stream_sink_->received_packets()->size()); +} + +TEST_P(FuchsiaAudioRendererTest, Seek) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + + constexpr base::TimeDelta kStartPos = base::TimeDelta(); + ASSERT_NO_FATAL_FAILURE(StartPlayback(kStartPos)); + task_environment_.FastForwardBy(kTimeStep); + time_source_->StopTicking(); + demuxer_stream_->DiscardQueueAndAbortRead(); + + // Media time should be stopped after StopTicking(). + EXPECT_EQ(time_source_->CurrentMediaTime(), kStartPos + kTimeStep); + task_environment_.FastForwardBy(kTimeStep); + EXPECT_EQ(time_source_->CurrentMediaTime(), kStartPos + kTimeStep); + + // Flush the renderer. + base::RunLoop run_loop; + audio_renderer_->Flush(run_loop.QuitClosure()); + run_loop.Run(); + + // Restart playback from a new position. + const base::TimeDelta kSeekPos = base::TimeDelta::FromMilliseconds(123); + ASSERT_NO_FATAL_FAILURE(StartPlaybackAndVerifyClock(kSeekPos, + /*playback_rate=*/1.0)); + + ProduceDemuxerPacket(kPacketDuration); + + // Verify that old packets were discarded and StreamSink started received + // packets at the correct position. + EXPECT_GT(stream_sink_->discarded_packets()->size(), 0u); + EXPECT_EQ(stream_sink_->received_packets()->at(0).pts, + kSeekPos.ToZxDuration()); +} + +TEST_P(FuchsiaAudioRendererTest, ChangeConfig) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(StartPlayback()); + + const auto kConfigChangePos = base::TimeDelta::FromSeconds(1); + + // Queue packets up to kConfigChangePos. + FillDemuxerStream(kConfigChangePos); + + const size_t kNewSampleRate = 44100; + const std::vector<uint8_t> kArbitraryExtraData = {1, 2, 3}; + AudioDecoderConfig updated_config( + kCodecOpus, kSampleFormatF32, CHANNEL_LAYOUT_STEREO, kNewSampleRate, + kArbitraryExtraData, EncryptionScheme::kUnencrypted); + demuxer_stream_->QueueReadResult( + TestDemuxerStream::ReadResult(updated_config)); + + // Queue one more packet with the new config. + ProduceDemuxerPacket(kPacketDuration); + + task_environment_.FastForwardBy(kConfigChangePos); + + // The renderer should have created new StreamSink when config was changed. + auto new_stream_sink = audio_consumer_->TakeStreamSink(); + ASSERT_TRUE(new_stream_sink); + + ASSERT_TRUE(client_.last_config_change().has_value()); + EXPECT_TRUE(client_.last_config_change()->Matches(updated_config)); + + EXPECT_EQ(stream_sink_->stream_type().channels, 1U); + EXPECT_EQ(stream_sink_->stream_type().frames_per_second, + static_cast<uint32_t>(kDefaultSampleRate)); + EXPECT_EQ(stream_sink_->received_packets()->size(), + kConfigChangePos / kPacketDuration); + + EXPECT_EQ(new_stream_sink->stream_type().channels, + static_cast<uint32_t>(updated_config.channels())); + EXPECT_EQ(new_stream_sink->stream_type().frames_per_second, kNewSampleRate); + EXPECT_TRUE(new_stream_sink->compression()); + EXPECT_EQ(new_stream_sink->compression()->type, + fuchsia::media::AUDIO_ENCODING_OPUS); + EXPECT_EQ(new_stream_sink->compression()->parameters, kArbitraryExtraData); + EXPECT_EQ(new_stream_sink->received_packets()->size(), 1U); + EXPECT_EQ(new_stream_sink->received_packets()->at(0).pts, + kConfigChangePos.ToZxDuration()); +} + +TEST_P(FuchsiaAudioRendererTest, UpdateTimeline) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(StartPlayback()); + + FillDemuxerStream(base::TimeDelta::FromSeconds(2)); + + const auto kTimelineChangePos = base::TimeDelta::FromSeconds(1); + task_environment_.FastForwardBy(kTimelineChangePos); + + // Shift the timeline by 2ms. + const auto kMediaDelta = base::TimeDelta::FromMilliseconds(2); + audio_consumer_->UpdateStatus(base::TimeTicks::Now(), + kTimelineChangePos + kMediaDelta); + task_environment_.RunUntilIdle(); + + EXPECT_EQ(time_source_->CurrentMediaTime(), kTimelineChangePos + kMediaDelta); + task_environment_.FastForwardBy(kTimeStep); + EXPECT_EQ(time_source_->CurrentMediaTime(), + kTimelineChangePos + kMediaDelta + kTimeStep); +} + +TEST_P(FuchsiaAudioRendererTest, PauseAndResume) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(StartPlayback()); + + const auto kPauseTimestamp = base::TimeDelta::FromSeconds(1); + const auto kStreamLength = base::TimeDelta::FromSeconds(2); + + FillDemuxerStream(kStreamLength); + + task_environment_.FastForwardBy(kPauseTimestamp); + + // Pause playback by setting playback rate to 0.0. + time_source_->SetPlaybackRate(0.0); + task_environment_.RunUntilIdle(); + EXPECT_EQ(audio_consumer_->playback_rate(), 0.0); + + task_environment_.FastForwardBy(kTimeStep); + audio_consumer_->UpdateStatus(base::TimeTicks::Now(), kPauseTimestamp); + task_environment_.RunUntilIdle(); + + const size_t kExpectedQueuedPackets = + (kPauseTimestamp + kMaxLeadTime) / kPacketDuration + 1; + EXPECT_EQ(stream_sink_->received_packets()->size(), kExpectedQueuedPackets); + EXPECT_EQ(time_source_->CurrentMediaTime(), kPauseTimestamp); + + // Keep the stream paused for 10 seconds. The Renderer should not be sending + // new packets + task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10)); + EXPECT_EQ(stream_sink_->received_packets()->size(), kExpectedQueuedPackets); + EXPECT_EQ(time_source_->CurrentMediaTime(), kPauseTimestamp); + + // Resume playback. + time_source_->SetPlaybackRate(1.0); + task_environment_.RunUntilIdle(); + EXPECT_EQ(audio_consumer_->playback_rate(), 1.0); + audio_consumer_->UpdateStatus(base::TimeTicks::Now(), kPauseTimestamp); + task_environment_.RunUntilIdle(); + + EXPECT_EQ(time_source_->CurrentMediaTime(), kPauseTimestamp); + + // The renderer should start sending packets again. + task_environment_.FastForwardBy(kPacketDuration); + EXPECT_EQ(stream_sink_->received_packets()->size(), + kExpectedQueuedPackets + 1); + + EXPECT_EQ(time_source_->CurrentMediaTime(), + kPauseTimestamp + kPacketDuration); +} + +// Verify that end-of-stream is handled correctly when the renderer is buffered. +TEST_P(FuchsiaAudioRendererTest, EndOfStreamBuffered) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + ASSERT_NO_FATAL_FAILURE(StartPlayback()); + + const auto kStreamLength = base::TimeDelta::FromSeconds(1); + FillDemuxerStream(kStreamLength); + demuxer_stream_->QueueReadResult( + TestDemuxerStream::ReadResult(DecoderBuffer::CreateEOSBuffer())); + + // Queue second EOS buffer. The renderer should not read it. + demuxer_stream_->QueueReadResult( + TestDemuxerStream::ReadResult(DecoderBuffer::CreateEOSBuffer())); + + task_environment_.FastForwardBy(kStreamLength); + + EXPECT_EQ(stream_sink_->received_packets()->size(), + kStreamLength / kPacketDuration); + EXPECT_TRUE(stream_sink_->received_end_of_stream()); + + client_.ExpectEos(); + audio_consumer_->SignalEndOfStream(); + task_environment_.RunUntilIdle(); +} + +// Verifies that buffering state is updated after reaching EOS. See +// https://crbug.com/1162503 . +TEST_P(FuchsiaAudioRendererTest, EndOfStreamWhenBuffering) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + stream_sink_ = audio_consumer_->WaitStreamSinkConnected(); + + // Produce stream shorter than kMinLeadTime. + const auto kStreamLength = kMinLeadTime / 2; + FillDemuxerStream(kStreamLength); + demuxer_stream_->QueueReadResult( + TestDemuxerStream::ReadResult(DecoderBuffer::CreateEOSBuffer())); + task_environment_.RunUntilIdle(); + + // Start playback. The renderer should push queued packets to the + // AudioConsumer and updated buffering state when it reaches EOS. + audio_renderer_->StartPlaying(); + task_environment_.RunUntilIdle(); + + EXPECT_EQ(client_.buffering_state(), BUFFERING_HAVE_ENOUGH); + EXPECT_TRUE(stream_sink_->received_end_of_stream()); +} + +TEST_P(FuchsiaAudioRendererTest, EndOfStreamStart) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + stream_sink_ = audio_consumer_->WaitStreamSinkConnected(); + + // Queue EOS without any preceding packets. + demuxer_stream_->QueueReadResult( + TestDemuxerStream::ReadResult(DecoderBuffer::CreateEOSBuffer())); + task_environment_.RunUntilIdle(); + + // Start playback. The renderer should push queued packets to the + // AudioConsumer and updated buffering state when it reaches EOS. + audio_renderer_->StartPlaying(); + task_environment_.RunUntilIdle(); + + EXPECT_EQ(client_.buffering_state(), BUFFERING_HAVE_ENOUGH); + EXPECT_TRUE(stream_sink_->received_end_of_stream()); +} + +TEST_P(FuchsiaAudioRendererTest, SetVolume) { + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + + audio_renderer_->SetVolume(0.5); + task_environment_.RunUntilIdle(); + EXPECT_EQ(audio_consumer_->volume(), 0.5); +} + +TEST_P(FuchsiaAudioRendererTest, SetVolumeBeforeInitialize) { + ASSERT_NO_FATAL_FAILURE(CreateUninitializedRenderer()); + + // SetVolume() may be called before AudioRenderer is initialized. It should + // still be handled. + audio_renderer_->SetVolume(0.5); + + ASSERT_NO_FATAL_FAILURE(InitializeRenderer()); + EXPECT_EQ(audio_consumer_->volume(), 0.5); +} + +// Verify that the case when StartTicking() is called shortly after +// StartPlaying() is handled correctly. AudioConsumer::Start() should be sent +// only after CreateStreamSink(). See crbug.com/1219147 . +TEST_P(FuchsiaAudioRendererTest, PlaybackBeforeSinkCreation) { + CreateTestDemuxerStream(); + const auto kStreamLength = base::TimeDelta::FromMilliseconds(100); + FillDemuxerStream(kStreamLength); + demuxer_stream_->QueueReadResult( + TestDemuxerStream::ReadResult(DecoderBuffer::CreateEOSBuffer())); + + ASSERT_NO_FATAL_FAILURE(CreateAndInitializeRenderer()); + + // Call StartTicking() shortly after StartPlayback(). At this point sysmem + // buffer allocation hasn't been complete, so AudioConsumer::Start() should be + // delayed until the buffer are allocated. + audio_renderer_->StartPlaying(); + time_source_->StartTicking(); + + // Wait until the stream is started. Start() should be called only after + // StreamSink() is connected and the packets are buffered. + audio_consumer_->WaitStarted(); + stream_sink_ = audio_consumer_->TakeStreamSink(); + EXPECT_GT(stream_sink_->received_packets()->size(), 0U); +} + +} // namespace media diff --git a/chromium/media/fuchsia/camera/fake_fuchsia_camera.cc b/chromium/media/fuchsia/camera/fake_fuchsia_camera.cc index 718999edb22..3c1311bf5d0 100644 --- a/chromium/media/fuchsia/camera/fake_fuchsia_camera.cc +++ b/chromium/media/fuchsia/camera/fake_fuchsia_camera.cc @@ -285,37 +285,63 @@ void FakeCameraStream::SetBufferCollection( buffer_collection_.Unbind(); } - // Use a SyncPtr to be able to wait for Sync() synchronously. - fuchsia::sysmem::BufferCollectionTokenSyncPtr token; - token.Bind(std::move(token_handle)); + new_buffer_collection_token_.Bind(std::move(token_handle)); + new_buffer_collection_token_.set_error_handler( + fit::bind_member(this, &FakeCameraStream::OnBufferCollectionError)); // Duplicate the token to access from the stream. - fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> local_token; - zx_status_t status = - token->Duplicate(/*rights_attenuation_mask=*/0, local_token.NewRequest()); - EXPECT_EQ(status, ZX_OK); + fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> + token_for_client; + new_buffer_collection_token_->Duplicate(ZX_RIGHT_SAME_RIGHTS, + token_for_client.NewRequest()); fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> failed_token; if (first_buffer_collection_fail_mode_ == SysmemFailMode::kFailSync) { - // Create an additional token that's dropped before this method returns. - // This will cause sysmem to fail the collection, so the future attempt to - // Sync() the collection from the production code will fail as well. - zx_status_t status = token->Duplicate(/*rights_attenuation_mask=*/0, - failed_token.NewRequest()); - EXPECT_EQ(status, ZX_OK); + // Create an additional token that's dropped in OnBufferCollectionSyncDone() + // before buffers are allocated. This will cause sysmem to fail the + // collection, so the future attempt to Sync() the collection from the + // production code will fail as well. + new_buffer_collection_token_->Duplicate( + /*rights_attenuation_mask=*/0, failed_token.NewRequest()); } - status = token->Sync(); - EXPECT_EQ(status, ZX_OK); + new_buffer_collection_token_->Sync( + [this, token_for_client = std::move(token_for_client), + failed_token = std::move(failed_token)]() mutable { + OnBufferCollectionSyncDone(std::move(token_for_client), + std::move(failed_token)); + }); +} + +void FakeCameraStream::WatchBufferCollection( + WatchBufferCollectionCallback callback) { + EXPECT_FALSE(watch_buffer_collection_callback_); + watch_buffer_collection_callback_ = std::move(callback); + SendBufferCollection(); +} + +void FakeCameraStream::GetNextFrame(GetNextFrameCallback callback) { + EXPECT_FALSE(get_next_frame_callback_); + get_next_frame_callback_ = std::move(callback); + SendNextFrame(); +} + +void FakeCameraStream::NotImplemented_(const std::string& name) { + ADD_FAILURE() << "NotImplemented_: " << name; +} +void FakeCameraStream::OnBufferCollectionSyncDone( + fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> + token_for_client, + fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> + failed_token) { // Return the token back to the client. - new_buffer_collection_token_ = token.Unbind(); + new_buffer_collection_token_for_client_ = std::move(token_for_client); SendBufferCollection(); // Initialize the new collection using |local_token|. - sysmem_allocator_->BindSharedCollection(std::move(local_token), - buffer_collection_.NewRequest()); - EXPECT_EQ(status, ZX_OK); + sysmem_allocator_->BindSharedCollection( + std::move(new_buffer_collection_token_), buffer_collection_.NewRequest()); buffer_collection_.set_error_handler( fit::bind_member(this, &FakeCameraStream::OnBufferCollectionError)); @@ -353,23 +379,6 @@ void FakeCameraStream::SetBufferCollection( fit::bind_member(this, &FakeCameraStream::OnBufferCollectionAllocated)); } -void FakeCameraStream::WatchBufferCollection( - WatchBufferCollectionCallback callback) { - EXPECT_FALSE(watch_buffer_collection_callback_); - watch_buffer_collection_callback_ = std::move(callback); - SendBufferCollection(); -} - -void FakeCameraStream::GetNextFrame(GetNextFrameCallback callback) { - EXPECT_FALSE(get_next_frame_callback_); - get_next_frame_callback_ = std::move(callback); - SendNextFrame(); -} - -void FakeCameraStream::NotImplemented_(const std::string& name) { - ADD_FAILURE() << "NotImplemented_: " << name; -} - void FakeCameraStream::OnBufferCollectionError(zx_status_t status) { if (first_buffer_collection_fail_mode_ != SysmemFailMode::kNone) { first_buffer_collection_fail_mode_ = SysmemFailMode::kNone; @@ -438,12 +447,14 @@ void FakeCameraStream::SendOrientation() { } void FakeCameraStream::SendBufferCollection() { - if (!watch_buffer_collection_callback_ || !new_buffer_collection_token_) + if (!watch_buffer_collection_callback_ || + !new_buffer_collection_token_for_client_) { return; + } watch_buffer_collection_callback_( - std::move(new_buffer_collection_token_.value())); + std::move(new_buffer_collection_token_for_client_.value())); watch_buffer_collection_callback_ = {}; - new_buffer_collection_token_.reset(); + new_buffer_collection_token_for_client_.reset(); } void FakeCameraStream::SendNextFrame() { @@ -610,4 +621,4 @@ void FakeCameraDeviceWatcher::Client::NotImplemented_(const std::string& name) { ADD_FAILURE() << "NotImplemented_: " << name; } -} // namespace media
\ No newline at end of file +} // namespace media diff --git a/chromium/media/fuchsia/camera/fake_fuchsia_camera.h b/chromium/media/fuchsia/camera/fake_fuchsia_camera.h index 0fba3b2a1fe..6b9afa3cac3 100644 --- a/chromium/media/fuchsia/camera/fake_fuchsia_camera.h +++ b/chromium/media/fuchsia/camera/fake_fuchsia_camera.h @@ -14,8 +14,8 @@ #include <vector> #include "base/message_loop/message_pump_for_io.h" -#include "base/optional.h" #include "base/run_loop.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { @@ -86,6 +86,12 @@ class FakeCameraStream : public fuchsia::camera3::testing::Stream_TestBase, // fuchsia::camera3::testing::Stream_TestBase override. void NotImplemented_(const std::string& name) override; + void OnBufferCollectionSyncDone( + fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> + token_for_client, + fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> + failed_token); + void OnBufferCollectionError(zx_status_t status); void OnBufferCollectionAllocated( @@ -118,26 +124,28 @@ class FakeCameraStream : public fuchsia::camera3::testing::Stream_TestBase, fuchsia::camera3::Orientation orientation_ = fuchsia::camera3::Orientation::UP; - base::Optional<fuchsia::math::Size> resolution_update_ = fuchsia::math::Size{ + absl::optional<fuchsia::math::Size> resolution_update_ = fuchsia::math::Size{ kDefaultFrameSize.width(), kDefaultFrameSize.height()}; WatchResolutionCallback watch_resolution_callback_; - base::Optional<fuchsia::camera3::Orientation> orientation_update_ = + absl::optional<fuchsia::camera3::Orientation> orientation_update_ = fuchsia::camera3::Orientation::UP; WatchOrientationCallback watch_orientation_callback_; - base::Optional<fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>> - new_buffer_collection_token_; + fuchsia::sysmem::BufferCollectionTokenPtr new_buffer_collection_token_; + + absl::optional<fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>> + new_buffer_collection_token_for_client_; WatchBufferCollectionCallback watch_buffer_collection_callback_; - base::Optional<fuchsia::camera3::FrameInfo> next_frame_; + absl::optional<fuchsia::camera3::FrameInfo> next_frame_; GetNextFrameCallback get_next_frame_callback_; fuchsia::sysmem::AllocatorPtr sysmem_allocator_; fuchsia::sysmem::BufferCollectionPtr buffer_collection_; - base::Optional<base::RunLoop> wait_buffers_allocated_run_loop_; - base::Optional<base::RunLoop> wait_free_buffer_run_loop_; + absl::optional<base::RunLoop> wait_buffers_allocated_run_loop_; + absl::optional<base::RunLoop> wait_free_buffer_run_loop_; std::vector<std::unique_ptr<Buffer>> buffers_; size_t num_used_buffers_ = 0; diff --git a/chromium/media/fuchsia/cdm/fuchsia_cdm.cc b/chromium/media/fuchsia/cdm/fuchsia_cdm.cc index 23dba99d9e3..07bd76fa26a 100644 --- a/chromium/media/fuchsia/cdm/fuchsia_cdm.cc +++ b/chromium/media/fuchsia/cdm/fuchsia_cdm.cc @@ -4,14 +4,12 @@ #include "media/fuchsia/cdm/fuchsia_cdm.h" -#include "base/command_line.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/logging.h" -#include "base/optional.h" #include "fuchsia/base/mem_buffer_util.h" #include "media/base/callback_registry.h" #include "media/base/cdm_promise.h" -#include "media/base/media_switches.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #define REJECT_PROMISE_AND_RETURN_IF_BAD_CDM(promise, cdm) \ if (!cdm) { \ @@ -24,10 +22,6 @@ namespace media { namespace { -// Audio packets are normally smaller than 128kB (more than enough for 2 seconds -// at 320kb/s). -const size_t kAudioStreamBufferSize = 128 * 1024; - std::string GetInitDataTypeName(EmeInitDataType type) { switch (type) { case EmeInitDataType::WEBM: @@ -128,7 +122,7 @@ CdmPromise::Exception ToCdmPromiseException(fuchsia::media::drm::Error error) { class FuchsiaCdm::CdmSession { public: using ResultCB = - base::OnceCallback<void(base::Optional<CdmPromise::Exception>)>; + base::OnceCallback<void(absl::optional<CdmPromise::Exception>)>; using SessionReadyCB = base::OnceCallback<void(bool success)>; CdmSession(const FuchsiaCdm::SessionCallbacks* callbacks, @@ -258,8 +252,8 @@ class FuchsiaCdm::CdmSession { DCHECK(result_cb_); std::move(result_cb_) .Run(result.is_err() - ? base::make_optional(ToCdmPromiseException(result.err())) - : base::nullopt); + ? absl::make_optional(ToCdmPromiseException(result.err())) + : absl::nullopt); } const SessionCallbacks* const session_callbacks_; @@ -315,43 +309,28 @@ FuchsiaCdm::FuchsiaCdm(fuchsia::media::drm::ContentDecryptionModulePtr cdm, FuchsiaCdm::~FuchsiaCdm() = default; -std::unique_ptr<FuchsiaSecureStreamDecryptor> FuchsiaCdm::CreateVideoDecryptor( - FuchsiaSecureStreamDecryptor::Client* client) { +std::unique_ptr<SysmemBufferStream> FuchsiaCdm::CreateStreamDecryptor( + bool secure_mode) { fuchsia::media::drm::DecryptorParams params; - - bool secure_mode = base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableProtectedVideoBuffers); params.set_require_secure_mode(secure_mode); - params.mutable_input_details()->set_format_details_version_ordinal(0); + fuchsia::media::StreamProcessorPtr stream_processor; cdm_->CreateDecryptor(std::move(params), stream_processor.NewRequest()); - auto decryptor = std::make_unique<FuchsiaSecureStreamDecryptor>( - std::move(stream_processor), client); + auto decryptor = + std::make_unique<FuchsiaStreamDecryptor>(std::move(stream_processor)); // Save callback to use to notify the decryptor about a new key. auto new_key_cb = decryptor->GetOnNewKeyClosure(); { - base::AutoLock auto_lock(new_key_cb_for_video_lock_); - new_key_cb_for_video_ = new_key_cb; + base::AutoLock auto_lock(new_key_callbacks_lock_); + new_key_callbacks_.push_back(std::move(new_key_cb)); } return decryptor; } -std::unique_ptr<FuchsiaClearStreamDecryptor> -FuchsiaCdm::CreateAudioDecryptor() { - fuchsia::media::drm::DecryptorParams params; - params.set_require_secure_mode(false); - params.mutable_input_details()->set_format_details_version_ordinal(0); - fuchsia::media::StreamProcessorPtr stream_processor; - cdm_->CreateDecryptor(std::move(params), stream_processor.NewRequest()); - - return std::make_unique<FuchsiaClearStreamDecryptor>( - std::move(stream_processor), kAudioStreamBufferSize); -} - void FuchsiaCdm::SetServerCertificate( const std::vector<uint8_t>& certificate, std::unique_ptr<SimpleCdmPromise> promise) { @@ -434,7 +413,7 @@ void FuchsiaCdm::OnCreateSession(std::unique_ptr<CdmSession> session, void FuchsiaCdm::OnGenerateLicenseRequestStatus( CdmSession* session, uint32_t promise_id, - base::Optional<CdmPromise::Exception> exception) { + absl::optional<CdmPromise::Exception> exception) { DCHECK(session); std::string session_id = session->session_id(); @@ -522,7 +501,7 @@ void FuchsiaCdm::UpdateSession(const std::string& session_id, void FuchsiaCdm::OnProcessLicenseServerMessageStatus( const std::string& session_id, uint32_t promise_id, - base::Optional<CdmPromise::Exception> exception) { + absl::optional<CdmPromise::Exception> exception) { if (exception.has_value()) { promises_.RejectPromise(promise_id, exception.value(), 0, "fail to process license."); @@ -584,7 +563,7 @@ void FuchsiaCdm::RemoveSession(const std::string& session_id, void FuchsiaCdm::OnGenerateLicenseReleaseStatus( const std::string& session_id, uint32_t promise_id, - base::Optional<CdmPromise::Exception> exception) { + absl::optional<CdmPromise::Exception> exception) { if (exception.has_value()) { promises_.RejectPromise(promise_id, exception.value(), 0, "Failed to release license."); @@ -616,9 +595,18 @@ FuchsiaCdmContext* FuchsiaCdm::GetFuchsiaCdmContext() { void FuchsiaCdm::OnNewKey() { event_callbacks_.Notify(Event::kHasAdditionalUsableKey); { - base::AutoLock auto_lock(new_key_cb_for_video_lock_); - if (new_key_cb_for_video_) - new_key_cb_for_video_.Run(); + base::AutoLock auto_lock(new_key_callbacks_lock_); + + // Remove cancelled callbacks. + new_key_callbacks_.erase( + std::remove_if( + new_key_callbacks_.begin(), new_key_callbacks_.end(), + [](const base::RepeatingClosure& cb) { return cb.IsCancelled(); }), + new_key_callbacks_.end()); + + for (auto& cb : new_key_callbacks_) { + cb.Run(); + } } } diff --git a/chromium/media/fuchsia/cdm/fuchsia_cdm.h b/chromium/media/fuchsia/cdm/fuchsia_cdm.h index 6f3c2a10805..f1f058ba580 100644 --- a/chromium/media/fuchsia/cdm/fuchsia_cdm.h +++ b/chromium/media/fuchsia/cdm/fuchsia_cdm.h @@ -10,13 +10,13 @@ #include "base/callback_forward.h" #include "base/containers/flat_map.h" #include "base/macros.h" -#include "base/optional.h" #include "media/base/callback_registry.h" #include "media/base/cdm_context.h" #include "media/base/cdm_promise_adapter.h" #include "media/base/content_decryption_module.h" #include "media/fuchsia/cdm/fuchsia_cdm_context.h" #include "media/fuchsia/cdm/fuchsia_decryptor.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -71,9 +71,8 @@ class FuchsiaCdm : public ContentDecryptionModule, FuchsiaCdmContext* GetFuchsiaCdmContext() override; // FuchsiaCdmContext implementation: - std::unique_ptr<FuchsiaSecureStreamDecryptor> CreateVideoDecryptor( - FuchsiaSecureStreamDecryptor::Client* client) override; - std::unique_ptr<FuchsiaClearStreamDecryptor> CreateAudioDecryptor() override; + std::unique_ptr<SysmemBufferStream> CreateStreamDecryptor( + bool secure_mode) override; private: class CdmSession; @@ -87,11 +86,11 @@ class FuchsiaCdm : public ContentDecryptionModule, void OnGenerateLicenseRequestStatus( CdmSession* session, uint32_t promise_id, - base::Optional<CdmPromise::Exception> exception); + absl::optional<CdmPromise::Exception> exception); void OnProcessLicenseServerMessageStatus( const std::string& session_id, uint32_t promise_id, - base::Optional<CdmPromise::Exception> exception); + absl::optional<CdmPromise::Exception> exception); void OnSessionLoaded(std::unique_ptr<CdmSession> session, uint32_t promise_id, bool loaded); @@ -99,7 +98,7 @@ class FuchsiaCdm : public ContentDecryptionModule, void OnGenerateLicenseReleaseStatus( const std::string& session_id, uint32_t promise_id, - base::Optional<CdmPromise::Exception> exception); + absl::optional<CdmPromise::Exception> exception); void OnNewKey(); @@ -112,9 +111,9 @@ class FuchsiaCdm : public ContentDecryptionModule, FuchsiaDecryptor decryptor_; - base::Lock new_key_cb_for_video_lock_; - base::RepeatingClosure new_key_cb_for_video_ - GUARDED_BY(new_key_cb_for_video_lock_); + base::Lock new_key_callbacks_lock_; + std::vector<base::RepeatingClosure> new_key_callbacks_ + GUARDED_BY(new_key_callbacks_lock_); CallbackRegistry<EventCB::RunType> event_callbacks_; diff --git a/chromium/media/fuchsia/cdm/fuchsia_cdm_context.h b/chromium/media/fuchsia/cdm/fuchsia_cdm_context.h index 667b78d71a4..a382acb2468 100644 --- a/chromium/media/fuchsia/cdm/fuchsia_cdm_context.h +++ b/chromium/media/fuchsia/cdm/fuchsia_cdm_context.h @@ -5,20 +5,20 @@ #ifndef MEDIA_FUCHSIA_CDM_FUCHSIA_CDM_CONTEXT_H_ #define MEDIA_FUCHSIA_CDM_FUCHSIA_CDM_CONTEXT_H_ -#include "media/fuchsia/cdm/fuchsia_stream_decryptor.h" +#include <memory> namespace media { +class SysmemBufferStream; + // Interface for Fuchsia-specific extensions to the CdmContext interface. class FuchsiaCdmContext { public: FuchsiaCdmContext() = default; // Creates FuchsiaSecureStreamDecryptor instance for the CDM context. - virtual std::unique_ptr<FuchsiaSecureStreamDecryptor> CreateVideoDecryptor( - FuchsiaSecureStreamDecryptor::Client* client) = 0; - virtual std::unique_ptr<FuchsiaClearStreamDecryptor> - CreateAudioDecryptor() = 0; + virtual std::unique_ptr<SysmemBufferStream> CreateStreamDecryptor( + bool secure_mode) = 0; protected: virtual ~FuchsiaCdmContext() = default; diff --git a/chromium/media/fuchsia/cdm/fuchsia_decryptor.cc b/chromium/media/fuchsia/cdm/fuchsia_decryptor.cc index c046957b792..82ee7cad742 100644 --- a/chromium/media/fuchsia/cdm/fuchsia_decryptor.cc +++ b/chromium/media/fuchsia/cdm/fuchsia_decryptor.cc @@ -22,32 +22,16 @@ FuchsiaDecryptor::FuchsiaDecryptor(FuchsiaCdmContext* cdm_context) } FuchsiaDecryptor::~FuchsiaDecryptor() { - if (audio_decryptor_) { - audio_decryptor_task_runner_->DeleteSoon(FROM_HERE, - std::move(audio_decryptor_)); - } } void FuchsiaDecryptor::Decrypt(StreamType stream_type, scoped_refptr<DecoderBuffer> encrypted, DecryptCB decrypt_cb) { - if (stream_type != StreamType::kAudio) { - std::move(decrypt_cb).Run(Status::kError, nullptr); - return; - } - - if (!audio_decryptor_) { - audio_decryptor_task_runner_ = base::ThreadTaskRunnerHandle::Get(); - audio_decryptor_ = cdm_context_->CreateAudioDecryptor(); - } - - audio_decryptor_->Decrypt(std::move(encrypted), std::move(decrypt_cb)); + std::move(decrypt_cb).Run(Status::kError, nullptr); } void FuchsiaDecryptor::CancelDecrypt(StreamType stream_type) { - if (stream_type == StreamType::kAudio && audio_decryptor_) { - audio_decryptor_->CancelDecrypt(); - } + NOTREACHED(); } void FuchsiaDecryptor::InitializeAudioDecoder(const AudioDecoderConfig& config, diff --git a/chromium/media/fuchsia/cdm/fuchsia_decryptor.h b/chromium/media/fuchsia/cdm/fuchsia_decryptor.h index ae502e70454..006b079e094 100644 --- a/chromium/media/fuchsia/cdm/fuchsia_decryptor.h +++ b/chromium/media/fuchsia/cdm/fuchsia_decryptor.h @@ -5,8 +5,6 @@ #ifndef MEDIA_FUCHSIA_CDM_FUCHSIA_DECRYPTOR_H_ #define MEDIA_FUCHSIA_CDM_FUCHSIA_DECRYPTOR_H_ -#include <memory> - #include "base/memory/ref_counted.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" @@ -17,7 +15,6 @@ namespace media { class FuchsiaCdmContext; -class FuchsiaClearStreamDecryptor; class FuchsiaDecryptor : public Decryptor { public: @@ -45,8 +42,6 @@ class FuchsiaDecryptor : public Decryptor { private: FuchsiaCdmContext* const cdm_context_; - std::unique_ptr<FuchsiaClearStreamDecryptor> audio_decryptor_; - // TaskRunner for the thread on which |audio_decryptor_| was created. scoped_refptr<base::SingleThreadTaskRunner> audio_decryptor_task_runner_; diff --git a/chromium/media/fuchsia/cdm/fuchsia_stream_decryptor.cc b/chromium/media/fuchsia/cdm/fuchsia_stream_decryptor.cc index 5a3d1b205ef..9b2e4214546 100644 --- a/chromium/media/fuchsia/cdm/fuchsia_stream_decryptor.cc +++ b/chromium/media/fuchsia/cdm/fuchsia_stream_decryptor.cc @@ -15,17 +15,10 @@ #include "media/base/decrypt_config.h" #include "media/base/encryption_pattern.h" #include "media/base/subsample_entry.h" -#include "media/fuchsia/common/sysmem_buffer_reader.h" -#include "media/fuchsia/common/sysmem_buffer_writer.h" namespace media { namespace { -// Minimum number of buffers in the input and output buffer collection. -// Decryptors provided by fuchsia.media.drm API normally decrypt a single -// buffer at a time. Second buffer is useful to allow reading/writing a -// packet while the decryptor is working on another one. -const size_t kMinBufferCount = 2; std::string GetEncryptionScheme(EncryptionScheme mode) { switch (mode) { @@ -97,103 +90,159 @@ fuchsia::media::FormatDetails GetEncryptedFormatDetails( } // namespace -FuchsiaStreamDecryptorBase::FuchsiaStreamDecryptorBase( - fuchsia::media::StreamProcessorPtr processor, - size_t min_buffer_size) +FuchsiaStreamDecryptor::FuchsiaStreamDecryptor( + fuchsia::media::StreamProcessorPtr processor) : processor_(std::move(processor), this), - min_buffer_size_(min_buffer_size), - allocator_("CrFuchsiaStreamDecryptorBase") {} + allocator_("CrFuchsiaStreamDecryptor") {} -FuchsiaStreamDecryptorBase::~FuchsiaStreamDecryptorBase() { +FuchsiaStreamDecryptor::~FuchsiaStreamDecryptor() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } -int FuchsiaStreamDecryptorBase::GetMaxDecryptRequests() const { - return input_writer_queue_.num_buffers() + 1; +base::RepeatingClosure FuchsiaStreamDecryptor::GetOnNewKeyClosure() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + return BindToCurrentLoop(base::BindRepeating( + &FuchsiaStreamDecryptor::OnNewKey, weak_factory_.GetWeakPtr())); +} + +void FuchsiaStreamDecryptor::Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + sink_ = sink; + + min_buffer_size_ = min_buffer_size; + min_buffer_count_ = min_buffer_count; + + input_buffer_collection_ = allocator_.AllocateNewCollection(); + input_buffer_collection_->CreateSharedToken( + base::BindOnce(&StreamProcessorHelper::SetInputBufferCollectionToken, + base::Unretained(&processor_))); + auto buffer_constraints = VmoBuffer::GetRecommendedConstraints( + kInputBufferCount, min_buffer_size_, /*writable=*/true); + input_buffer_collection_->Initialize(std::move(buffer_constraints), + "CrFuchsiaStreamDecryptor"); + input_buffer_collection_->AcquireBuffers(base::BindOnce( + &FuchsiaStreamDecryptor::OnInputBuffersAcquired, base::Unretained(this))); } -void FuchsiaStreamDecryptorBase::DecryptInternal( - scoped_refptr<DecoderBuffer> encrypted) { +void FuchsiaStreamDecryptor::EnqueueBuffer( + scoped_refptr<DecoderBuffer> buffer) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - input_writer_queue_.EnqueueBuffer(std::move(encrypted)); + input_writer_queue_.EnqueueBuffer(std::move(buffer)); } -void FuchsiaStreamDecryptorBase::ResetStream() { +void FuchsiaStreamDecryptor::Reset() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Close current stream and drop all the cached decoder buffers. // Keep input and output buffers to avoid buffer re-allocation. processor_.Reset(); input_writer_queue_.ResetQueue(); + waiting_for_key_ = false; } -// StreamProcessorHelper::Client implementation: -void FuchsiaStreamDecryptorBase::AllocateInputBuffers( +void FuchsiaStreamDecryptor::OnStreamProcessorAllocateOutputBuffers( const fuchsia::media::StreamBufferConstraints& stream_constraints) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - base::Optional<fuchsia::sysmem::BufferCollectionConstraints> - buffer_constraints = SysmemBufferWriter::GetRecommendedConstraints( - kMinBufferCount, min_buffer_size_); - - if (!buffer_constraints.has_value()) { - OnError(); - return; - } - - input_pool_creator_ = - allocator_.MakeBufferPoolCreator(1 /* num_shared_token */); + output_buffer_collection_ = allocator_.AllocateNewCollection(); + output_buffer_collection_->CreateSharedToken( + base::BindOnce(&StreamProcessorHelper::CompleteOutputBuffersAllocation, + base::Unretained(&processor_))); + output_buffer_collection_->CreateSharedToken( + base::BindOnce(&Sink::OnSysmemBufferStreamBufferCollectionToken, + base::Unretained(sink_))); + + fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; + buffer_constraints.usage.none = fuchsia::sysmem::noneUsage; + buffer_constraints.min_buffer_count = min_buffer_count_; + buffer_constraints.has_buffer_memory_constraints = true; + buffer_constraints.buffer_memory_constraints.min_size_bytes = + min_buffer_size_; + buffer_constraints.buffer_memory_constraints.ram_domain_supported = true; + buffer_constraints.buffer_memory_constraints.cpu_domain_supported = true; + buffer_constraints.buffer_memory_constraints.inaccessible_domain_supported = + true; + + output_buffer_collection_->Initialize(std::move(buffer_constraints), + "CrFuchsiaStreamDecryptorOutput"); +} + +void FuchsiaStreamDecryptor::OnStreamProcessorEndOfStream() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - input_pool_creator_->Create( - std::move(buffer_constraints).value(), - base::BindOnce(&FuchsiaStreamDecryptorBase::OnInputBufferPoolCreated, - base::Unretained(this))); + sink_->OnSysmemBufferStreamEndOfStream(); } -void FuchsiaStreamDecryptorBase::OnOutputFormat( +void FuchsiaStreamDecryptor::OnStreamProcessorOutputFormat( fuchsia::media::StreamOutputFormat format) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } -void FuchsiaStreamDecryptorBase::OnInputBufferPoolCreated( - std::unique_ptr<SysmemBufferPool> pool) { +void FuchsiaStreamDecryptor::OnStreamProcessorOutputPacket( + StreamProcessorHelper::IoPacket packet) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!pool) { - DLOG(ERROR) << "Fail to allocate input buffer."; - OnError(); + sink_->OnSysmemBufferStreamOutputPacket(std::move(packet)); +} + +void FuchsiaStreamDecryptor::OnStreamProcessorNoKey() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(!waiting_for_key_); + + // Reset stream position, but keep all pending buffers. They will be + // resubmitted later, when we have a new key. + input_writer_queue_.ResetPositionAndPause(); + + if (retry_on_no_key_event_) { + retry_on_no_key_event_ = false; + input_writer_queue_.Unpause(); return; } - input_pool_ = std::move(pool); + waiting_for_key_ = true; + sink_->OnSysmemBufferStreamNoKey(); +} + +void FuchsiaStreamDecryptor::OnStreamProcessorError() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + OnError(); +} + +void FuchsiaStreamDecryptor::OnError() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // Provide token before enabling writer. Tokens must be provided to - // StreamProcessor before getting the allocated buffers. - processor_.CompleteInputBuffersAllocation(input_pool_->TakeToken()); + Reset(); - input_pool_->CreateWriter(base::BindOnce( - &FuchsiaStreamDecryptorBase::OnWriterCreated, base::Unretained(this))); + // No need to reset other fields since OnError() is called for non-recoverable + // errors. + + sink_->OnSysmemBufferStreamError(); } -void FuchsiaStreamDecryptorBase::OnWriterCreated( - std::unique_ptr<SysmemBufferWriter> writer) { +void FuchsiaStreamDecryptor::OnInputBuffersAcquired( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings&) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (!writer) { + if (buffers.empty()) { OnError(); return; } input_writer_queue_.Start( - std::move(writer), - base::BindRepeating(&FuchsiaStreamDecryptorBase::SendInputPacket, + std::move(buffers), + base::BindRepeating(&FuchsiaStreamDecryptor::SendInputPacket, base::Unretained(this)), - base::BindRepeating(&FuchsiaStreamDecryptorBase::ProcessEndOfStream, + base::BindRepeating(&FuchsiaStreamDecryptor::ProcessEndOfStream, base::Unretained(this))); } -void FuchsiaStreamDecryptorBase::SendInputPacket( +void FuchsiaStreamDecryptor::SendInputPacket( const DecoderBuffer* buffer, StreamProcessorHelper::IoPacket packet) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -217,279 +266,21 @@ void FuchsiaStreamDecryptorBase::SendInputPacket( processor_.Process(std::move(packet)); } -void FuchsiaStreamDecryptorBase::ProcessEndOfStream() { +void FuchsiaStreamDecryptor::ProcessEndOfStream() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); processor_.ProcessEos(); } -FuchsiaClearStreamDecryptor::FuchsiaClearStreamDecryptor( - fuchsia::media::StreamProcessorPtr processor, - size_t min_buffer_size) - : FuchsiaStreamDecryptorBase(std::move(processor), min_buffer_size) {} - -FuchsiaClearStreamDecryptor::~FuchsiaClearStreamDecryptor() = default; - -void FuchsiaClearStreamDecryptor::Decrypt( - scoped_refptr<DecoderBuffer> encrypted, - Decryptor::DecryptCB decrypt_cb) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!decrypt_cb_); - - decrypt_cb_ = std::move(decrypt_cb); - current_status_ = Decryptor::kSuccess; - DecryptInternal(std::move(encrypted)); -} - -void FuchsiaClearStreamDecryptor::CancelDecrypt() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - ResetStream(); - - // Fire |decrypt_cb_| immediately as required by Decryptor::CancelDecrypt. - if (decrypt_cb_) - std::move(decrypt_cb_).Run(Decryptor::kSuccess, nullptr); -} - -void FuchsiaClearStreamDecryptor::AllocateOutputBuffers( - const fuchsia::media::StreamBufferConstraints& stream_constraints) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - output_pool_creator_ = - allocator_.MakeBufferPoolCreator(1 /* num_shared_token */); - output_pool_creator_->Create( - SysmemBufferReader::GetRecommendedConstraints(kMinBufferCount, - min_buffer_size_), - base::BindOnce(&FuchsiaClearStreamDecryptor::OnOutputBufferPoolCreated, - base::Unretained(this))); -} - -void FuchsiaClearStreamDecryptor::OnProcessEos() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // Decryptor never pushes EOS frame. - NOTREACHED(); -} - -void FuchsiaClearStreamDecryptor::OnOutputPacket( - StreamProcessorHelper::IoPacket packet) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(decrypt_cb_); - - DCHECK(output_reader_); - if (!output_pool_->is_live()) { - DLOG(ERROR) << "Output buffer pool is dead."; - return; - } - - // If that's not the last packet for the current Decrypt() request then just - // store the output and wait for the next packet. - if (!packet.unit_end()) { - size_t pos = output_data_.size(); - output_data_.resize(pos + packet.size()); - - bool read_success = output_reader_->Read( - packet.buffer_index(), packet.offset(), - base::make_span(output_data_.data() + pos, packet.size())); - - if (!read_success) { - // If we've failed to read a partial packet then delay reporting the error - // until we've received the last packet to make sure we consume all output - // packets generated by the last Decrypt() call. - DLOG(ERROR) << "Fail to get decrypted result."; - current_status_ = Decryptor::kError; - output_data_.clear(); - } - - return; - } - - // We've received the last packet. Assemble DecoderBuffer and pass it to the - // DecryptCB. - auto clear_buffer = - base::MakeRefCounted<DecoderBuffer>(output_data_.size() + packet.size()); - clear_buffer->set_timestamp(packet.timestamp()); - - // Copy data received in the previous packets. - memcpy(clear_buffer->writable_data(), output_data_.data(), - output_data_.size()); - output_data_.clear(); - - // Copy data received in the last packet - bool read_success = output_reader_->Read( - packet.buffer_index(), packet.offset(), - base::make_span(clear_buffer->writable_data() + output_data_.size(), - packet.size())); - - if (!read_success) { - DLOG(ERROR) << "Fail to get decrypted result."; - current_status_ = Decryptor::kError; - } - - std::move(decrypt_cb_) - .Run(current_status_, current_status_ == Decryptor::kSuccess - ? std::move(clear_buffer) - : nullptr); -} - -void FuchsiaClearStreamDecryptor::OnNoKey() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // Reset the queue. The client is expected to call Decrypt() with the same - // buffer again when it gets kNoKey. - input_writer_queue_.ResetQueue(); - - if (decrypt_cb_) - std::move(decrypt_cb_).Run(Decryptor::kNoKey, nullptr); -} - -void FuchsiaClearStreamDecryptor::OnError() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - ResetStream(); - if (decrypt_cb_) - std::move(decrypt_cb_).Run(Decryptor::kError, nullptr); -} - -void FuchsiaClearStreamDecryptor::OnOutputBufferPoolCreated( - std::unique_ptr<SysmemBufferPool> pool) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!pool) { - LOG(ERROR) << "Fail to allocate output buffer."; - OnError(); - return; - } - - output_pool_ = std::move(pool); - - // Provide token before enabling reader. Tokens must be provided to - // StreamProcessor before getting the allocated buffers. - processor_.CompleteOutputBuffersAllocation(output_pool_->TakeToken()); - - output_pool_->CreateReader(base::BindOnce( - &FuchsiaClearStreamDecryptor::OnOutputBufferPoolReaderCreated, - base::Unretained(this))); -} - -void FuchsiaClearStreamDecryptor::OnOutputBufferPoolReaderCreated( - std::unique_ptr<SysmemBufferReader> reader) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (!reader) { - LOG(ERROR) << "Fail to enable output buffer reader."; - OnError(); - return; - } - - DCHECK(!output_reader_); - output_reader_ = std::move(reader); -} - -FuchsiaSecureStreamDecryptor::FuchsiaSecureStreamDecryptor( - fuchsia::media::StreamProcessorPtr processor, - Client* client) - : FuchsiaStreamDecryptorBase(std::move(processor), - client->GetInputBufferSize()), - client_(client) {} - -FuchsiaSecureStreamDecryptor::~FuchsiaSecureStreamDecryptor() = default; - -void FuchsiaSecureStreamDecryptor::SetOutputBufferCollectionToken( - fuchsia::sysmem::BufferCollectionTokenPtr token) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!complete_buffer_allocation_callback_); - complete_buffer_allocation_callback_ = - base::BindOnce(&StreamProcessorHelper::CompleteOutputBuffersAllocation, - base::Unretained(&processor_), std::move(token)); - if (waiting_output_buffers_) { - std::move(complete_buffer_allocation_callback_).Run(); - waiting_output_buffers_ = false; - } -} - -void FuchsiaSecureStreamDecryptor::Decrypt( - scoped_refptr<DecoderBuffer> encrypted) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - DecryptInternal(std::move(encrypted)); -} - -void FuchsiaSecureStreamDecryptor::Reset() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - ResetStream(); - waiting_for_key_ = false; -} - -void FuchsiaSecureStreamDecryptor::AllocateOutputBuffers( - const fuchsia::media::StreamBufferConstraints& stream_constraints) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - if (complete_buffer_allocation_callback_) { - std::move(complete_buffer_allocation_callback_).Run(); - } else { - waiting_output_buffers_ = true; - } -} - -void FuchsiaSecureStreamDecryptor::OnProcessEos() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - client_->OnDecryptorEndOfStreamPacket(); -} - -void FuchsiaSecureStreamDecryptor::OnOutputPacket( - StreamProcessorHelper::IoPacket packet) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - client_->OnDecryptorOutputPacket(std::move(packet)); -} - -base::RepeatingClosure FuchsiaSecureStreamDecryptor::GetOnNewKeyClosure() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - return BindToCurrentLoop(base::BindRepeating( - &FuchsiaSecureStreamDecryptor::OnNewKey, weak_factory_.GetWeakPtr())); -} - -void FuchsiaSecureStreamDecryptor::OnError() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - ResetStream(); - - // No need to reset other fields since OnError() is called for non-recoverable - // errors. - - client_->OnDecryptorError(); -} - -void FuchsiaSecureStreamDecryptor::OnNoKey() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(!waiting_for_key_); - - // Reset stream position, but keep all pending buffers. They will be - // resubmitted later, when we have a new key. - input_writer_queue_.ResetPositionAndPause(); - - if (retry_on_no_key_) { - retry_on_no_key_ = false; - input_writer_queue_.Unpause(); - return; - } - - waiting_for_key_ = true; - client_->OnDecryptorNoKey(); -} - -void FuchsiaSecureStreamDecryptor::OnNewKey() { +void FuchsiaStreamDecryptor::OnNewKey() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!waiting_for_key_) { - retry_on_no_key_ = true; + retry_on_no_key_event_ = true; return; } - DCHECK(!retry_on_no_key_); + DCHECK(!retry_on_no_key_event_); waiting_for_key_ = false; input_writer_queue_.Unpause(); } diff --git a/chromium/media/fuchsia/cdm/fuchsia_stream_decryptor.h b/chromium/media/fuchsia/cdm/fuchsia_stream_decryptor.h index e26fa6897a0..bba2d0cbe46 100644 --- a/chromium/media/fuchsia/cdm/fuchsia_stream_decryptor.h +++ b/chromium/media/fuchsia/cdm/fuchsia_stream_decryptor.h @@ -11,129 +11,31 @@ #include "base/sequence_checker.h" #include "media/base/decryptor.h" +#include "media/base/media_export.h" #include "media/fuchsia/common/stream_processor_helper.h" -#include "media/fuchsia/common/sysmem_buffer_pool.h" -#include "media/fuchsia/common/sysmem_buffer_writer_queue.h" +#include "media/fuchsia/common/sysmem_buffer_stream.h" +#include "media/fuchsia/common/sysmem_client.h" +#include "media/fuchsia/common/vmo_buffer_writer_queue.h" namespace media { -class SysmemBufferReader; -// Base class for media stream decryptor implementations. -class FuchsiaStreamDecryptorBase : public StreamProcessorHelper::Client { +// Stream decryptor used to decrypt protected media streams on Fuchsia. Must be +// created an used on the same thread. +class MEDIA_EXPORT FuchsiaStreamDecryptor + : public SysmemBufferStream, + public StreamProcessorHelper::Client { public: - FuchsiaStreamDecryptorBase(fuchsia::media::StreamProcessorPtr processor, - size_t min_buffer_size); - ~FuchsiaStreamDecryptorBase() override; + // Number of buffers that the decryptor allocates for input buffer + // collection. Decryptors provided by fuchsia.media.drm API normally decrypt a + // single buffer at a time. Second buffer is useful to allow reading/writing a + // packet while the decryptor is working on another one. + static constexpr size_t kInputBufferCount = 2; - int GetMaxDecryptRequests() const; + explicit FuchsiaStreamDecryptor(fuchsia::media::StreamProcessorPtr processor); + ~FuchsiaStreamDecryptor() override; - protected: - // StreamProcessorHelper::Client overrides. - void AllocateInputBuffers( - const fuchsia::media::StreamBufferConstraints& stream_constraints) final; - void OnOutputFormat(fuchsia::media::StreamOutputFormat format) final; - - void DecryptInternal(scoped_refptr<DecoderBuffer> encrypted); - void ResetStream(); - - StreamProcessorHelper processor_; - - const size_t min_buffer_size_; - - BufferAllocator allocator_; - - SysmemBufferWriterQueue input_writer_queue_; - - // Key ID for which we received the last OnNewKey() event. - std::string last_new_key_id_; - - SEQUENCE_CHECKER(sequence_checker_); - - private: - void OnInputBufferPoolCreated(std::unique_ptr<SysmemBufferPool> pool); - void OnWriterCreated(std::unique_ptr<SysmemBufferWriter> writer); - void SendInputPacket(const DecoderBuffer* buffer, - StreamProcessorHelper::IoPacket packet); - void ProcessEndOfStream(); - - std::unique_ptr<SysmemBufferPool::Creator> input_pool_creator_; - std::unique_ptr<SysmemBufferPool> input_pool_; - - DISALLOW_COPY_AND_ASSIGN(FuchsiaStreamDecryptorBase); -}; - -// Stream decryptor that copies output to clear DecodeBuffer's. Used for audio -// streams. -class FuchsiaClearStreamDecryptor : public FuchsiaStreamDecryptorBase { - public: - static std::unique_ptr<FuchsiaClearStreamDecryptor> Create( - fuchsia::media::drm::ContentDecryptionModule* cdm, - size_t min_buffer_size); - - FuchsiaClearStreamDecryptor(fuchsia::media::StreamProcessorPtr processor, - size_t min_buffer_size); - ~FuchsiaClearStreamDecryptor() override; - - // Decrypt() behavior should match media::Decryptor interface. - void Decrypt(scoped_refptr<DecoderBuffer> encrypted, - Decryptor::DecryptCB decrypt_cb); - void CancelDecrypt(); - - private: - // StreamProcessorHelper::Client overrides. - void AllocateOutputBuffers( - const fuchsia::media::StreamBufferConstraints& stream_constraints) final; - void OnProcessEos() final; - void OnOutputPacket(StreamProcessorHelper::IoPacket packet) final; - void OnNoKey() final; - void OnError() final; - - void OnOutputBufferPoolCreated(std::unique_ptr<SysmemBufferPool> pool); - void OnOutputBufferPoolReaderCreated( - std::unique_ptr<SysmemBufferReader> reader); - - Decryptor::DecryptCB decrypt_cb_; - - std::unique_ptr<SysmemBufferPool::Creator> output_pool_creator_; - std::unique_ptr<SysmemBufferPool> output_pool_; - std::unique_ptr<SysmemBufferReader> output_reader_; - - // Used to re-assemble decrypted output that was split between multiple sysmem - // buffers. - Decryptor::Status current_status_ = Decryptor::kSuccess; - std::vector<uint8_t> output_data_; - - DISALLOW_COPY_AND_ASSIGN(FuchsiaClearStreamDecryptor); -}; - -// Stream decryptor that decrypts data to protected sysmem buffers. Used for -// video stream. -class FuchsiaSecureStreamDecryptor : public FuchsiaStreamDecryptorBase { - public: - class Client { - public: - virtual size_t GetInputBufferSize() = 0; - virtual void OnDecryptorOutputPacket( - StreamProcessorHelper::IoPacket packet) = 0; - virtual void OnDecryptorEndOfStreamPacket() = 0; - virtual void OnDecryptorError() = 0; - virtual void OnDecryptorNoKey() = 0; - - protected: - virtual ~Client() = default; - }; - - FuchsiaSecureStreamDecryptor(fuchsia::media::StreamProcessorPtr processor, - Client* client); - ~FuchsiaSecureStreamDecryptor() override; - - void SetOutputBufferCollectionToken( - fuchsia::sysmem::BufferCollectionTokenPtr token); - - // Enqueues the specified buffer to the input queue. Caller is allowed to - // queue as many buffers as it needs without waiting for results from the - // previous Decrypt() calls. - void Decrypt(scoped_refptr<DecoderBuffer> encrypted); + FuchsiaStreamDecryptor(const FuchsiaStreamDecryptor&) = delete; + FuchsiaStreamDecryptor& operator=(const FuchsiaStreamDecryptor&) = delete; // Returns closure that should be called when the key changes. This class // uses this notification to handle NO_KEY errors. Note that this class can @@ -144,42 +46,70 @@ class FuchsiaSecureStreamDecryptor : public FuchsiaStreamDecryptorBase { // the key is updated. base::RepeatingClosure GetOnNewKeyClosure(); - // Drops all pending decryption requests. - void Reset(); + // SysmemBufferStream implementation. + void Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) override; + void EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer) override; + void Reset() override; private: // StreamProcessorHelper::Client overrides. - void AllocateOutputBuffers( + void OnStreamProcessorAllocateOutputBuffers( const fuchsia::media::StreamBufferConstraints& stream_constraints) final; - void OnProcessEos() final; - void OnOutputPacket(StreamProcessorHelper::IoPacket packet) final; - void OnNoKey() final; - void OnError() final; + void OnStreamProcessorEndOfStream() final; + void OnStreamProcessorOutputFormat( + fuchsia::media::StreamOutputFormat format) final; + void OnStreamProcessorOutputPacket( + StreamProcessorHelper::IoPacket packet) final; + void OnStreamProcessorNoKey() final; + void OnStreamProcessorError() final; + + void OnError(); + + void OnInputBuffersAcquired( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings& buffer_settings); + void SendInputPacket(const DecoderBuffer* buffer, + StreamProcessorHelper::IoPacket packet); + void ProcessEndOfStream(); // Callback returned by GetOnNewKeyClosure(). When waiting for a key this // method unpauses the stream to decrypt any pending buffers. void OnNewKey(); - Client* const client_; + StreamProcessorHelper processor_; + + SysmemAllocatorClient allocator_; + + Sink* sink_ = nullptr; - bool waiting_output_buffers_ = false; - base::OnceClosure complete_buffer_allocation_callback_; + size_t min_buffer_size_ = 0; + size_t min_buffer_count_ = 0; + + std::unique_ptr<SysmemCollectionClient> input_buffer_collection_; + VmoBufferWriterQueue input_writer_queue_; + + std::unique_ptr<SysmemCollectionClient> output_buffer_collection_; + + // Key ID for which we received the last OnNewKey() event. + std::string last_new_key_id_; // Set to true if some keys have been updated recently. New key notifications // are received from a LicenseSession, while DECRYPTOR_NO_KEY error is // received from StreamProcessor. These are separate FIDL connections that are // handled on different threads, so they are not synchronized. As result // OnNewKey() may be called before we get OnNoKey(). To handle this case - // correctly OnNewKey() sets |retry_on_no_key_| and then OnNoKey() tries to - // restart the stream immediately if this flag is set. - bool retry_on_no_key_ = false; + // correctly OnNewKey() sets |retry_on_no_key_event_| and then OnNoKey() tries + // to restart the stream immediately if this flag is set. + bool retry_on_no_key_event_ = false; // Set to true if the stream is paused while we are waiting for new keys. bool waiting_for_key_ = false; - base::WeakPtrFactory<FuchsiaSecureStreamDecryptor> weak_factory_{this}; + SEQUENCE_CHECKER(sequence_checker_); - DISALLOW_COPY_AND_ASSIGN(FuchsiaSecureStreamDecryptor); + base::WeakPtrFactory<FuchsiaStreamDecryptor> weak_factory_{this}; }; } // namespace media diff --git a/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc b/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc index 7edfa056a86..5fbf4223b89 100644 --- a/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc +++ b/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc @@ -18,11 +18,11 @@ #include "base/fuchsia/fuchsia_logging.h" #include "base/hash/hash.h" #include "base/logging.h" -#include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" #include "media/fuchsia/cdm/service/provisioning_fetcher_impl.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "url/origin.h" namespace media { @@ -126,7 +126,7 @@ std::string HexEncodeHash(const std::string& name) { } // Returns a nullopt if storage was created successfully. -base::Optional<base::File::Error> CreateStorageDirectory(base::FilePath path) { +absl::optional<base::File::Error> CreateStorageDirectory(base::FilePath path) { base::File::Error error; bool success = base::CreateDirectoryAndGetError(path, &error); if (!success) { @@ -168,7 +168,7 @@ class FuchsiaCdmManager::KeySystemClient { CreateFetcherCB create_fetcher_callback, fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule> request) { - base::Optional<DataStoreId> data_store_id = GetDataStoreIdForPath( + absl::optional<DataStoreId> data_store_id = GetDataStoreIdForPath( std::move(storage_path), std::move(create_fetcher_callback)); if (!data_store_id) { request.Close(ZX_ERR_NO_RESOURCES); @@ -186,7 +186,7 @@ class FuchsiaCdmManager::KeySystemClient { private: using DataStoreId = uint32_t; - base::Optional<DataStoreId> GetDataStoreIdForPath( + absl::optional<DataStoreId> GetDataStoreIdForPath( base::FilePath storage_path, CreateFetcherCB create_fetcher_callback) { // If we have already added a data store id for that path, just use that @@ -200,7 +200,7 @@ class FuchsiaCdmManager::KeySystemClient { base::OpenDirectoryHandle(storage_path); if (!data_directory.is_valid()) { DLOG(ERROR) << "Unable to OpenDirectory " << storage_path; - return base::nullopt; + return absl::nullopt; } auto provisioning_fetcher = std::make_unique<ProvisioningFetcherImpl>( @@ -264,7 +264,7 @@ class FuchsiaCdmManager::KeySystemClient { FuchsiaCdmManager::FuchsiaCdmManager( CreateKeySystemCallbackMap create_key_system_callbacks_by_name, base::FilePath cdm_data_path, - base::Optional<uint64_t> cdm_data_quota_bytes) + absl::optional<uint64_t> cdm_data_quota_bytes) : create_key_system_callbacks_by_name_( std::move(create_key_system_callbacks_by_name)), cdm_data_path_(std::move(cdm_data_path)), @@ -352,7 +352,7 @@ void FuchsiaCdmManager::CreateCdm( fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule> request, base::FilePath storage_path, - base::Optional<base::File::Error> storage_creation_error) { + absl::optional<base::File::Error> storage_creation_error) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (storage_creation_error) { diff --git a/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager.h b/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager.h index 40f91be48fa..718b3adcc17 100644 --- a/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager.h +++ b/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager.h @@ -14,10 +14,10 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "base/threading/thread_checker.h" #include "media/base/provision_fetcher.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace url { class Origin; @@ -41,7 +41,7 @@ class FuchsiaCdmManager { FuchsiaCdmManager( CreateKeySystemCallbackMap create_key_system_callbacks_by_name, base::FilePath cdm_data_path, - base::Optional<uint64_t> cdm_data_quota_bytes); + absl::optional<uint64_t> cdm_data_quota_bytes); ~FuchsiaCdmManager(); @@ -76,13 +76,13 @@ class FuchsiaCdmManager { fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule> request, base::FilePath storage_path, - base::Optional<base::File::Error> storage_creation_error); + absl::optional<base::File::Error> storage_creation_error); void OnKeySystemClientError(const std::string& key_system_name); // A map of callbacks to create KeySystem channels indexed by their EME name. const CreateKeySystemCallbackMap create_key_system_callbacks_by_name_; const base::FilePath cdm_data_path_; - const base::Optional<uint64_t> cdm_data_quota_bytes_; + const absl::optional<uint64_t> cdm_data_quota_bytes_; // Used for operations on the CDM data directory. const scoped_refptr<base::SequencedTaskRunner> storage_task_runner_; diff --git a/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager_unittest.cc b/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager_unittest.cc index 64a011a535e..4e6ef5a9c4e 100644 --- a/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager_unittest.cc +++ b/chromium/media/fuchsia/cdm/service/fuchsia_cdm_manager_unittest.cc @@ -78,7 +78,7 @@ class FuchsiaCdmManagerTest : public ::testing::Test { std::unique_ptr<FuchsiaCdmManager> CreateFuchsiaCdmManager( std::vector<base::StringPiece> key_systems, - base::Optional<uint64_t> cdm_data_quota_bytes = base::nullopt) { + absl::optional<uint64_t> cdm_data_quota_bytes = absl::nullopt) { FuchsiaCdmManager::CreateKeySystemCallbackMap create_key_system_callbacks; for (const base::StringPiece& name : key_systems) { diff --git a/chromium/media/fuchsia/common/BUILD.gn b/chromium/media/fuchsia/common/BUILD.gn index a7190bf4cde..381db174a5f 100644 --- a/chromium/media/fuchsia/common/BUILD.gn +++ b/chromium/media/fuchsia/common/BUILD.gn @@ -6,18 +6,23 @@ assert(is_fuchsia) source_set("common") { sources = [ + "decrypting_sysmem_buffer_stream.cc", + "decrypting_sysmem_buffer_stream.h", + "passthrough_sysmem_buffer_stream.cc", + "passthrough_sysmem_buffer_stream.h", "stream_processor_helper.cc", "stream_processor_helper.h", - "sysmem_buffer_pool.cc", - "sysmem_buffer_pool.h", - "sysmem_buffer_reader.cc", - "sysmem_buffer_reader.h", - "sysmem_buffer_writer.cc", - "sysmem_buffer_writer.h", - "sysmem_buffer_writer_queue.cc", - "sysmem_buffer_writer_queue.h", + "sysmem_buffer_stream.h", + "sysmem_client.cc", + "sysmem_client.h", + "vmo_buffer.cc", + "vmo_buffer.h", + "vmo_buffer_writer_queue.cc", + "vmo_buffer_writer_queue.h", ] + configs += [ "//media:subcomponent_config" ] + deps = [ "//base", "//media/base", diff --git a/chromium/media/fuchsia/common/decrypting_sysmem_buffer_stream.cc b/chromium/media/fuchsia/common/decrypting_sysmem_buffer_stream.cc new file mode 100644 index 00000000000..51a74989c83 --- /dev/null +++ b/chromium/media/fuchsia/common/decrypting_sysmem_buffer_stream.cc @@ -0,0 +1,123 @@ +// Copyright 2021 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/fuchsia/common/decrypting_sysmem_buffer_stream.h" + +#include "media/base/callback_registry.h" +#include "media/base/decoder_buffer.h" + +namespace media { + +DecryptingSysmemBufferStream::DecryptingSysmemBufferStream( + SysmemAllocatorClient* sysmem_allocator, + CdmContext* cdm_context, + Decryptor::StreamType stream_type) + : passthrough_stream_(sysmem_allocator), + decryptor_(cdm_context->GetDecryptor()), + stream_type_(stream_type) { + DCHECK(decryptor_); + + event_cb_registration_ = cdm_context->RegisterEventCB( + base::BindRepeating(&DecryptingSysmemBufferStream::OnCdmContextEvent, + weak_factory_.GetWeakPtr())); +} + +DecryptingSysmemBufferStream::~DecryptingSysmemBufferStream() = default; + +void DecryptingSysmemBufferStream::Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) { + sink_ = sink; + passthrough_stream_.Initialize(sink, min_buffer_size, min_buffer_count); +} + +void DecryptingSysmemBufferStream::EnqueueBuffer( + scoped_refptr<DecoderBuffer> buffer) { + buffer_queue_.push_back(std::move(buffer)); + DecryptNextBuffer(); +} + +void DecryptingSysmemBufferStream::Reset() { + buffer_queue_.clear(); + + if (state_ == State::kDecryptPending) { + decryptor_->CancelDecrypt(stream_type_); + } + + state_ = State::kIdle; + retry_on_no_key_ = false; +} + +void DecryptingSysmemBufferStream::OnCdmContextEvent(CdmContext::Event event) { + if (event != CdmContext::Event::kHasAdditionalUsableKey) + return; + + switch (state_) { + case State::kIdle: + break; + + case State::kDecryptPending: + retry_on_no_key_ = true; + break; + + case State::kWaitingKey: + state_ = State::kIdle; + DecryptNextBuffer(); + break; + } +} + +void DecryptingSysmemBufferStream::DecryptNextBuffer() { + if (buffer_queue_.empty() || state_ != State::kIdle) + return; + + if (buffer_queue_.front()->end_of_stream()) { + scoped_refptr<DecoderBuffer> buffer = std::move(buffer_queue_.front()); + buffer_queue_.pop_front(); + DCHECK(buffer_queue_.empty()); + passthrough_stream_.EnqueueBuffer(std::move(buffer)); + return; + } + + state_ = State::kDecryptPending; + decryptor_->Decrypt( + stream_type_, buffer_queue_.front(), + base::BindOnce(&DecryptingSysmemBufferStream::OnBufferDecrypted, + weak_factory_.GetWeakPtr())); +} + +void DecryptingSysmemBufferStream::OnBufferDecrypted( + Decryptor::Status status, + scoped_refptr<DecoderBuffer> decrypted_buffer) { + DCHECK(state_ == State::kDecryptPending); + state_ = State::kIdle; + + switch (status) { + case Decryptor::kError: + sink_->OnSysmemBufferStreamError(); + return; + + case Decryptor::kNoKey: + if (retry_on_no_key_) { + retry_on_no_key_ = false; + DecryptNextBuffer(); + } else { + state_ = State::kWaitingKey; + sink_->OnSysmemBufferStreamNoKey(); + } + return; + + case Decryptor::kNeedMoreData: + break; + + case Decryptor::kSuccess: + passthrough_stream_.EnqueueBuffer(std::move(decrypted_buffer)); + } + + buffer_queue_.pop_front(); + + DecryptNextBuffer(); +} + +} // namespace media diff --git a/chromium/media/fuchsia/common/decrypting_sysmem_buffer_stream.h b/chromium/media/fuchsia/common/decrypting_sysmem_buffer_stream.h new file mode 100644 index 00000000000..8fb00306abf --- /dev/null +++ b/chromium/media/fuchsia/common/decrypting_sysmem_buffer_stream.h @@ -0,0 +1,66 @@ +// Copyright 2021 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. + +#ifndef MEDIA_FUCHSIA_COMMON_DECRYPTING_SYSMEM_BUFFER_STREAM_H_ +#define MEDIA_FUCHSIA_COMMON_DECRYPTING_SYSMEM_BUFFER_STREAM_H_ + +#include "media/fuchsia/common/passthrough_sysmem_buffer_stream.h" + +#include <deque> + +#include "media/base/cdm_context.h" +#include "media/base/decryptor.h" + +namespace media { + +// A SysmemBufferStream that decrypts the stream before copying the data to +// sysmem buffers. +class MEDIA_EXPORT DecryptingSysmemBufferStream : public SysmemBufferStream { + public: + DecryptingSysmemBufferStream(SysmemAllocatorClient* sysmem_allocator, + CdmContext* cdm_context, + Decryptor::StreamType stream_type); + ~DecryptingSysmemBufferStream() override; + + DecryptingSysmemBufferStream(const DecryptingSysmemBufferStream&) = delete; + DecryptingSysmemBufferStream& operator=(const DecryptingSysmemBufferStream&) = + delete; + + // SysmemBufferStream implementation: + void Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) override; + void EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer) override; + void Reset() override; + + private: + enum class State { + kIdle, + kDecryptPending, + kWaitingKey, + }; + + void OnCdmContextEvent(CdmContext::Event event); + void DecryptNextBuffer(); + void OnBufferDecrypted(Decryptor::Status status, + scoped_refptr<DecoderBuffer> decrypted_buffer); + + PassthroughSysmemBufferStream passthrough_stream_; + Decryptor* const decryptor_; + const Decryptor::StreamType stream_type_; + + std::unique_ptr<CallbackRegistration> event_cb_registration_; + + Sink* sink_ = nullptr; + std::deque<scoped_refptr<DecoderBuffer>> buffer_queue_; + State state_ = State::kIdle; + + bool retry_on_no_key_ = false; + + base::WeakPtrFactory<DecryptingSysmemBufferStream> weak_factory_{this}; +}; + +} // namespace media + +#endif // MEDIA_FUCHSIA_COMMON_DECRYPTING_SYSMEM_BUFFER_STREAM_H_
\ No newline at end of file diff --git a/chromium/media/fuchsia/common/passthrough_sysmem_buffer_stream.cc b/chromium/media/fuchsia/common/passthrough_sysmem_buffer_stream.cc new file mode 100644 index 00000000000..bb04295fbe0 --- /dev/null +++ b/chromium/media/fuchsia/common/passthrough_sysmem_buffer_stream.cc @@ -0,0 +1,71 @@ +// Copyright 2021 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/fuchsia/common/passthrough_sysmem_buffer_stream.h" + +#include "media/base/decoder_buffer.h" + +namespace media { + +PassthroughSysmemBufferStream::PassthroughSysmemBufferStream( + SysmemAllocatorClient* sysmem_allocator) + : sysmem_allocator_(sysmem_allocator) { + DCHECK(sysmem_allocator_); +} + +PassthroughSysmemBufferStream::~PassthroughSysmemBufferStream() = default; + +void PassthroughSysmemBufferStream::Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) { + DCHECK(sink); + sink_ = sink; + + fuchsia::sysmem::BufferCollectionConstraints buffer_constraints = + VmoBuffer::GetRecommendedConstraints(min_buffer_count, min_buffer_size, + /*writable=*/true); + + // Create buffer collection. + output_buffer_collection_ = sysmem_allocator_->AllocateNewCollection(); + output_buffer_collection_->CreateSharedToken( + base::BindOnce(&Sink::OnSysmemBufferStreamBufferCollectionToken, + base::Unretained(sink_))); + output_buffer_collection_->Initialize(std::move(buffer_constraints), + "CrPassthroughSysmemBufferStream"); + output_buffer_collection_->AcquireBuffers( + base::BindOnce(&PassthroughSysmemBufferStream::OnBuffersAcquired, + base::Unretained(this))); +} + +void PassthroughSysmemBufferStream::EnqueueBuffer( + scoped_refptr<DecoderBuffer> buffer) { + queue_.EnqueueBuffer(std::move(buffer)); +} + +void PassthroughSysmemBufferStream::Reset() { + queue_.ResetQueue(); +} + +void PassthroughSysmemBufferStream::OnBuffersAcquired( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings& buffer_settings) { + queue_.Start( + std::move(buffers), + base::BindRepeating(&PassthroughSysmemBufferStream::ProcessOutputPacket, + base::Unretained(this)), + base::BindRepeating(&PassthroughSysmemBufferStream::ProcessEndOfStream, + base::Unretained(this))); +} + +void PassthroughSysmemBufferStream::ProcessOutputPacket( + const DecoderBuffer* buffer, + StreamProcessorHelper::IoPacket packet) { + sink_->OnSysmemBufferStreamOutputPacket(std::move(packet)); +} + +void PassthroughSysmemBufferStream::ProcessEndOfStream() { + sink_->OnSysmemBufferStreamEndOfStream(); +} + +} // namespace media diff --git a/chromium/media/fuchsia/common/passthrough_sysmem_buffer_stream.h b/chromium/media/fuchsia/common/passthrough_sysmem_buffer_stream.h new file mode 100644 index 00000000000..4cd9373e781 --- /dev/null +++ b/chromium/media/fuchsia/common/passthrough_sysmem_buffer_stream.h @@ -0,0 +1,52 @@ +// Copyright 2021 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. + +#ifndef MEDIA_FUCHSIA_COMMON_PASSTHROUGH_SYSMEM_BUFFER_STREAM_H_ +#define MEDIA_FUCHSIA_COMMON_PASSTHROUGH_SYSMEM_BUFFER_STREAM_H_ + +#include "media/fuchsia/common/sysmem_buffer_stream.h" +#include "media/fuchsia/common/sysmem_client.h" +#include "media/fuchsia/common/vmo_buffer_writer_queue.h" + +namespace media { + +// A SysmemBufferStream that simply writes the stream to sysmem buffers. +class MEDIA_EXPORT PassthroughSysmemBufferStream : public SysmemBufferStream { + public: + explicit PassthroughSysmemBufferStream( + SysmemAllocatorClient* sysmem_allocator); + ~PassthroughSysmemBufferStream() override; + + PassthroughSysmemBufferStream(const PassthroughSysmemBufferStream&) = delete; + PassthroughSysmemBufferStream& operator=( + const PassthroughSysmemBufferStream&) = delete; + + // SysmemBufferStream implementation: + void Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) override; + void EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer) override; + void Reset() override; + + private: + void OnBuffersAcquired( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings& buffer_settings); + + // Callbacks for VmoBufferWriterQueue. + void ProcessOutputPacket(const DecoderBuffer* buffer, + StreamProcessorHelper::IoPacket packet); + void ProcessEndOfStream(); + + Sink* sink_ = nullptr; + + SysmemAllocatorClient* const sysmem_allocator_; + std::unique_ptr<SysmemCollectionClient> output_buffer_collection_; + + VmoBufferWriterQueue queue_; +}; + +} // namespace media + +#endif // MEDIA_FUCHSIA_COMMON_PASSTHROUGH_SYSMEM_BUFFER_STREAM_H_
\ No newline at end of file diff --git a/chromium/media/fuchsia/common/stream_processor_helper.cc b/chromium/media/fuchsia/common/stream_processor_helper.cc index 17b95bef191..0ca556a7ac3 100644 --- a/chromium/media/fuchsia/common/stream_processor_helper.cc +++ b/chromium/media/fuchsia/common/stream_processor_helper.cc @@ -6,9 +6,18 @@ #include "base/bind.h" #include "base/fuchsia/fuchsia_logging.h" +#include "media/base/timestamp_constants.h" namespace media { +namespace { + +// Input buffers are allocate once per decoder, the |buffer_lifetime_ordinal| is +// always the same. +constexpr uint64_t kInputBufferLifetimeOrdinal = 1; + +} // namespace + StreamProcessorHelper::IoPacket::IoPacket(size_t index, size_t offset, size_t size, @@ -19,36 +28,23 @@ StreamProcessorHelper::IoPacket::IoPacket(size_t index, offset_(offset), size_(size), timestamp_(timestamp), - unit_end_(unit_end), - destroy_cb_(std::move(destroy_cb)) {} + unit_end_(unit_end) { + destroy_callbacks_.push_front(std::move(destroy_cb)); +} -StreamProcessorHelper::IoPacket::~IoPacket() = default; +StreamProcessorHelper::IoPacket::~IoPacket() { + for (auto& cb : destroy_callbacks_) { + std::move(cb).Run(); + } +} StreamProcessorHelper::IoPacket::IoPacket(IoPacket&&) = default; StreamProcessorHelper::IoPacket& StreamProcessorHelper::IoPacket::operator=( IoPacket&&) = default; -// static -StreamProcessorHelper::IoPacket StreamProcessorHelper::IoPacket::CreateInput( - size_t index, - size_t size, - base::TimeDelta timestamp, - bool unit_end, - base::OnceClosure destroy_cb) { - return IoPacket(index, 0 /* offset */, size, timestamp, unit_end, - std::move(destroy_cb)); -} - -// static -StreamProcessorHelper::IoPacket StreamProcessorHelper::IoPacket::CreateOutput( - size_t index, - size_t offset, - size_t size, - base::TimeDelta timestamp, - bool unit_end, - base::OnceClosure destroy_cb) { - return IoPacket(index, offset, size, timestamp, unit_end, - std::move(destroy_cb)); +void StreamProcessorHelper::IoPacket::AddOnDestroyClosure( + base::OnceClosure closure) { + destroy_callbacks_.push_front(std::move(closure)); } StreamProcessorHelper::StreamProcessorHelper( @@ -68,8 +64,6 @@ StreamProcessorHelper::StreamProcessorHelper( processor_.events().OnStreamFailed = fit::bind_member(this, &StreamProcessorHelper::OnStreamFailed); - processor_.events().OnInputConstraints = - fit::bind_member(this, &StreamProcessorHelper::OnInputConstraints); processor_.events().OnFreeInputPacket = fit::bind_member(this, &StreamProcessorHelper::OnFreeInputPacket); processor_.events().OnOutputConstraints = @@ -94,7 +88,7 @@ void StreamProcessorHelper::Process(IoPacket input) { fuchsia::media::Packet packet; packet.mutable_header()->set_buffer_lifetime_ordinal( - input_buffer_lifetime_ordinal_); + kInputBufferLifetimeOrdinal); packet.mutable_header()->set_packet_index(input.buffer_index()); packet.set_buffer_index(packet.header().packet_index()); packet.set_timestamp_ish(input.timestamp().InNanoseconds()); @@ -154,43 +148,23 @@ void StreamProcessorHelper::OnStreamFailed(uint64_t stream_lifetime_ordinal, // Always reset the stream since the current one has failed. Reset(); - client_->OnNoKey(); + client_->OnStreamProcessorNoKey(); return; } OnError(); } -void StreamProcessorHelper::OnInputConstraints( - fuchsia::media::StreamBufferConstraints constraints) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Buffer lifetime ordinal is an odd number incremented by 2 for each buffer - // generation as required by StreamProcessor. - input_buffer_lifetime_ordinal_ += 2; - - DCHECK(input_packets_.empty()); - input_buffer_constraints_ = std::move(constraints); - - client_->AllocateInputBuffers(input_buffer_constraints_); -} - void StreamProcessorHelper::OnFreeInputPacket( fuchsia::media::PacketHeader free_input_packet) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (!free_input_packet.has_buffer_lifetime_ordinal() || - !free_input_packet.has_packet_index()) { + if (!free_input_packet.has_packet_index()) { DLOG(ERROR) << "Received OnFreeInputPacket() with missing required fields."; OnError(); return; } - if (free_input_packet.buffer_lifetime_ordinal() != - input_buffer_lifetime_ordinal_) { - return; - } - auto it = input_packets_.find(free_input_packet.packet_index()); if (it == input_packets_.end()) { DLOG(ERROR) << "Received OnFreeInputPacket() with invalid packet index."; @@ -240,7 +214,7 @@ void StreamProcessorHelper::OnOutputConstraints( output_buffer_constraints_ = std::move(*output_constraints.mutable_buffer_constraints()); - client_->AllocateOutputBuffers(output_buffer_constraints_); + client_->OnStreamProcessorAllocateOutputBuffers(output_buffer_constraints_); } void StreamProcessorHelper::OnOutputFormat( @@ -258,7 +232,7 @@ void StreamProcessorHelper::OnOutputFormat( return; } - client_->OnOutputFormat(std::move(output_format)); + client_->OnStreamProcessorOutputFormat(std::move(output_format)); } void StreamProcessorHelper::OnOutputPacket(fuchsia::media::Packet output_packet, @@ -290,12 +264,12 @@ void StreamProcessorHelper::OnOutputPacket(fuchsia::media::Packet output_packet, auto buffer_index = output_packet.buffer_index(); auto packet_index = output_packet.header().packet_index(); - base::TimeDelta timestamp; - if (output_packet.has_timestamp_ish()) { - timestamp = base::TimeDelta::FromNanoseconds(output_packet.timestamp_ish()); - } + base::TimeDelta timestamp = + output_packet.has_timestamp_ish() + ? base::TimeDelta::FromNanoseconds(output_packet.timestamp_ish()) + : kNoTimestamp; - client_->OnOutputPacket(IoPacket::CreateOutput( + client_->OnStreamProcessorOutputPacket(IoPacket( buffer_index, output_packet.start_offset(), output_packet.valid_length_bytes(), timestamp, output_packet.known_end_access_unit(), @@ -315,22 +289,21 @@ void StreamProcessorHelper::OnOutputEndOfStream( stream_lifetime_ordinal_ += 2; active_stream_ = false; - client_->OnProcessEos(); + client_->OnStreamProcessorEndOfStream(); } void StreamProcessorHelper::OnError() { processor_.Unbind(); - client_->OnError(); + client_->OnStreamProcessorError(); } -void StreamProcessorHelper::CompleteInputBuffersAllocation( +void StreamProcessorHelper::SetInputBufferCollectionToken( fuchsia::sysmem::BufferCollectionTokenPtr sysmem_token) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!input_buffer_constraints_.IsEmpty()); + fuchsia::media::StreamBufferPartialSettings settings; - settings.set_buffer_lifetime_ordinal(input_buffer_lifetime_ordinal_); - settings.set_buffer_constraints_version_ordinal( - input_buffer_constraints_.buffer_constraints_version_ordinal()); + settings.set_buffer_lifetime_ordinal(kInputBufferLifetimeOrdinal); + settings.set_buffer_constraints_version_ordinal(0); settings.set_sysmem_token(std::move(sysmem_token)); processor_->SetInputBufferPartialSettings(std::move(settings)); } diff --git a/chromium/media/fuchsia/common/stream_processor_helper.h b/chromium/media/fuchsia/common/stream_processor_helper.h index 3b333d15daa..c2e32de77a4 100644 --- a/chromium/media/fuchsia/common/stream_processor_helper.h +++ b/chromium/media/fuchsia/common/stream_processor_helper.h @@ -8,14 +8,16 @@ #include <fuchsia/media/cpp/fidl.h> #include <fuchsia/sysmem/cpp/fidl.h> +#include <forward_list> + #include "base/callback.h" -#include "base/callback_helpers.h" #include "base/containers/flat_map.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/threading/thread_checker.h" #include "base/time/time.h" +#include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -23,23 +25,10 @@ namespace media { // 1. Data validation check. // 2. Stream/Buffer life time management. // 3. Configure StreamProcessor and input/output buffer settings. -class StreamProcessorHelper { +class MEDIA_EXPORT StreamProcessorHelper { public: - class IoPacket { + class MEDIA_EXPORT IoPacket { public: - static IoPacket CreateInput(size_t index, - size_t size, - base::TimeDelta timestamp, - bool unit_end, - base::OnceClosure destroy_cb); - - static IoPacket CreateOutput(size_t index, - size_t offset, - size_t size, - base::TimeDelta timestamp, - bool unit_end, - base::OnceClosure destroy_cb); - IoPacket(size_t index, size_t offset, size_t size, @@ -61,6 +50,9 @@ class StreamProcessorHelper { } const fuchsia::media::FormatDetails& format() const { return format_; } + // Adds a |closure| that will be called when the packet is destroyed. + void AddOnDestroyClosure(base::OnceClosure closure); + private: size_t index_; size_t offset_; @@ -68,38 +60,36 @@ class StreamProcessorHelper { base::TimeDelta timestamp_; bool unit_end_; fuchsia::media::FormatDetails format_; - base::ScopedClosureRunner destroy_cb_; + std::forward_list<base::OnceClosure> destroy_callbacks_; DISALLOW_COPY_AND_ASSIGN(IoPacket); }; class Client { public: - // Allocate input/output buffers with the given constraints. Client should - // call ProvideInput/OutputBufferCollectionToken to finish the buffer - // allocation flow. - virtual void AllocateInputBuffers( - const fuchsia::media::StreamBufferConstraints& stream_constraints) = 0; - virtual void AllocateOutputBuffers( + // Allocate output buffers with the given constraints. Client should call + // ProvideIOutputBufferCollectionToken to finish the buffer allocation flow. + virtual void OnStreamProcessorAllocateOutputBuffers( const fuchsia::media::StreamBufferConstraints& stream_constraints) = 0; // Called when all the pushed packets are processed. - virtual void OnProcessEos() = 0; + virtual void OnStreamProcessorEndOfStream() = 0; // Called when output format is available. - virtual void OnOutputFormat(fuchsia::media::StreamOutputFormat format) = 0; + virtual void OnStreamProcessorOutputFormat( + fuchsia::media::StreamOutputFormat format) = 0; // Called when output packet is available. Deleting |packet| will notify // StreamProcessor the output buffer is available to be re-used. Client // should delete |packet| on the same thread as this function. - virtual void OnOutputPacket(IoPacket packet) = 0; + virtual void OnStreamProcessorOutputPacket(IoPacket packet) = 0; // Only available for decryption, which indicates currently the // StreamProcessor doesn't have the content key to process. - virtual void OnNoKey() = 0; + virtual void OnStreamProcessorNoKey() = 0; // Called when any fatal errors happens. - virtual void OnError() = 0; + virtual void OnStreamProcessorError() = 0; protected: virtual ~Client() = default; @@ -117,10 +107,12 @@ class StreamProcessorHelper { // StreamProcessor without calling Reset. void ProcessEos(); - // Provide input/output BufferCollectionToken to finish StreamProcessor buffer - // setup flow. - void CompleteInputBuffersAllocation( + // Sets buffer collection tocken to use for input buffers. + void SetInputBufferCollectionToken( fuchsia::sysmem::BufferCollectionTokenPtr token); + + // Provide output BufferCollectionToken to finish StreamProcessor buffer + // setup flow. Should be called only after AllocateOutputBuffers. void CompleteOutputBuffersAllocation( fuchsia::sysmem::BufferCollectionTokenPtr token); @@ -156,10 +148,6 @@ class StreamProcessorHelper { // stream_lifetime_ordinal_. bool active_stream_ = false; - // Input buffers. - uint64_t input_buffer_lifetime_ordinal_ = 1; - fuchsia::media::StreamBufferConstraints input_buffer_constraints_; - // Map from packet index to corresponding input IoPacket. IoPacket should be // owned by this class until StreamProcessor released the buffer. base::flat_map<size_t, IoPacket> input_packets_; diff --git a/chromium/media/fuchsia/common/sysmem_buffer_pool.cc b/chromium/media/fuchsia/common/sysmem_buffer_pool.cc deleted file mode 100644 index de5e197c1c3..00000000000 --- a/chromium/media/fuchsia/common/sysmem_buffer_pool.cc +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2019 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/fuchsia/common/sysmem_buffer_pool.h" - -#include <zircon/rights.h> -#include <algorithm> - -#include "base/bind.h" -#include "base/fuchsia/fuchsia_logging.h" -#include "base/fuchsia/process_context.h" -#include "base/process/process_handle.h" -#include "media/fuchsia/common/sysmem_buffer_reader.h" -#include "media/fuchsia/common/sysmem_buffer_writer.h" - -namespace media { - -SysmemBufferPool::Creator::Creator( - fuchsia::sysmem::BufferCollectionPtr collection, - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens) - : collection_(std::move(collection)), - shared_tokens_(std::move(shared_tokens)) { - collection_.set_error_handler( - [this](zx_status_t status) { - ZX_DLOG(ERROR, status) - << "Connection to BufferCollection was disconnected."; - collection_.Unbind(); - - if (create_cb_) - std::move(create_cb_).Run(nullptr); - }); -} - -SysmemBufferPool::Creator::~Creator() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -void SysmemBufferPool::Creator::SetName(uint32_t priority, - base::StringPiece name) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!create_cb_); - collection_->SetName(priority, std::string(name)); -} - -void SysmemBufferPool::Creator::Create( - fuchsia::sysmem::BufferCollectionConstraints constraints, - CreateCB create_cb) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!create_cb_); - create_cb_ = std::move(create_cb); - // BufferCollection needs to be synchronized to ensure that all token - // duplicate requests have been processed and sysmem knows about all clients - // that will be using this buffer collection. - collection_->Sync([this, constraints = std::move(constraints)]() mutable { - collection_->SetConstraints(true /* has constraints */, - std::move(constraints)); - - DCHECK(create_cb_); - std::move(create_cb_) - .Run(std::make_unique<SysmemBufferPool>(std::move(collection_), - std::move(shared_tokens_))); - }); -} - -SysmemBufferPool::SysmemBufferPool( - fuchsia::sysmem::BufferCollectionPtr collection, - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens) - : collection_(std::move(collection)), - shared_tokens_(std::move(shared_tokens)) { - collection_.set_error_handler([this](zx_status_t status) { - ZX_LOG(ERROR, status) << "fuchsia.sysmem.BufferCollection disconnected."; - OnError(); - }); -} - -SysmemBufferPool::~SysmemBufferPool() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (collection_) - collection_->Close(); -} - -fuchsia::sysmem::BufferCollectionTokenPtr SysmemBufferPool::TakeToken() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!shared_tokens_.empty()); - auto token = std::move(shared_tokens_.back()); - shared_tokens_.pop_back(); - return token; -} - -void SysmemBufferPool::CreateReader(CreateReaderCB create_cb) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!create_reader_cb_); - create_reader_cb_ = std::move(create_cb); - collection_->WaitForBuffersAllocated( - fit::bind_member(this, &SysmemBufferPool::OnBuffersAllocated)); -} - -void SysmemBufferPool::CreateWriter(CreateWriterCB create_cb) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!create_writer_cb_); - create_writer_cb_ = std::move(create_cb); - collection_->WaitForBuffersAllocated( - fit::bind_member(this, &SysmemBufferPool::OnBuffersAllocated)); -} - -void SysmemBufferPool::OnBuffersAllocated( - zx_status_t status, - fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (status != ZX_OK) { - ZX_LOG(ERROR, status) << "Fail to allocate sysmem buffers."; - OnError(); - return; - } - - if (create_reader_cb_) { - std::move(create_reader_cb_) - .Run(SysmemBufferReader::Create(std::move(buffer_collection_info))); - } else if (create_writer_cb_) { - std::move(create_writer_cb_) - .Run(SysmemBufferWriter::Create(std::move(buffer_collection_info))); - } -} - -void SysmemBufferPool::OnError() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - collection_.Unbind(); - if (create_reader_cb_) - std::move(create_reader_cb_).Run(nullptr); - if (create_writer_cb_) - std::move(create_writer_cb_).Run(nullptr); -} - -BufferAllocator::BufferAllocator(base::StringPiece client_name) { - allocator_ = base::ComponentContextForProcess() - ->svc() - ->Connect<fuchsia::sysmem::Allocator>(); - - allocator_->SetDebugClientInfo(std::string(client_name), - base::GetCurrentProcId()); - - allocator_.set_error_handler([](zx_status_t status) { - // Just log a warning. We will handle BufferCollection the failure when - // trying to create a new BufferCollection. - ZX_DLOG(WARNING, status) - << "The fuchsia.sysmem.Allocator channel was disconnected."; - }); -} - -BufferAllocator::~BufferAllocator() = default; - -fuchsia::sysmem::BufferCollectionTokenPtr BufferAllocator::CreateNewToken() { - fuchsia::sysmem::BufferCollectionTokenPtr collection_token; - allocator_->AllocateSharedCollection(collection_token.NewRequest()); - return collection_token; -} - -std::unique_ptr<SysmemBufferPool::Creator> -BufferAllocator::MakeBufferPoolCreator(size_t num_of_tokens) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Create a new sysmem buffer collection token for the allocated buffers. - fuchsia::sysmem::BufferCollectionTokenPtr collection_token = CreateNewToken(); - - // Create collection token for sharing with other components. - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens; - for (size_t i = 0; i < num_of_tokens; i++) { - fuchsia::sysmem::BufferCollectionTokenPtr token; - collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS, token.NewRequest()); - shared_tokens.push_back(std::move(token)); - } - - fuchsia::sysmem::BufferCollectionPtr buffer_collection; - - // Convert the token to a BufferCollection connection. - allocator_->BindSharedCollection(std::move(collection_token), - buffer_collection.NewRequest()); - - return std::make_unique<SysmemBufferPool::Creator>( - std::move(buffer_collection), std::move(shared_tokens)); -} - -std::unique_ptr<SysmemBufferPool::Creator> -BufferAllocator::MakeBufferPoolCreatorFromToken( - fuchsia::sysmem::BufferCollectionTokenPtr token) { - fuchsia::sysmem::BufferCollectionPtr buffer_collection; - allocator_->BindSharedCollection(std::move(token), - buffer_collection.NewRequest()); - return std::make_unique<SysmemBufferPool::Creator>( - std::move(buffer_collection), - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr>{}); -} - -} // namespace media diff --git a/chromium/media/fuchsia/common/sysmem_buffer_pool.h b/chromium/media/fuchsia/common/sysmem_buffer_pool.h deleted file mode 100644 index 84407ccc59c..00000000000 --- a/chromium/media/fuchsia/common/sysmem_buffer_pool.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2019 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. - -#ifndef MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_POOL_H_ -#define MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_POOL_H_ - -#include <fuchsia/media/cpp/fidl.h> -#include <fuchsia/sysmem/cpp/fidl.h> -#include <lib/sys/cpp/component_context.h> - -#include <list> -#include <vector> - -#include "base/callback.h" -#include "base/containers/span.h" -#include "base/macros.h" -#include "base/threading/thread_checker.h" - -namespace media { - -class SysmemBufferReader; -class SysmemBufferWriter; - -// Pool of buffers allocated by sysmem. It owns BufferCollection. It doesn't -// provide any function read/write the buffers. Call should use -// ReadableBufferPool/WritableBufferPool for read/write. -class SysmemBufferPool { - public: - using CreateReaderCB = - base::OnceCallback<void(std::unique_ptr<SysmemBufferReader>)>; - using CreateWriterCB = - base::OnceCallback<void(std::unique_ptr<SysmemBufferWriter>)>; - - // Creates SysmemBufferPool asynchronously. It also owns the channel to - // fuchsia services. - class Creator { - public: - using CreateCB = - base::OnceCallback<void(std::unique_ptr<SysmemBufferPool>)>; - Creator( - fuchsia::sysmem::BufferCollectionPtr collection, - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens); - ~Creator(); - - // Sets the name of the created buffers. Priority is a number used to choose - // which name to use when multiple clients set names. Must be called before - // Create. See fuchsia.sysmem/BufferCollection.SetName for a description of - // the arguments. - void SetName(uint32_t priority, base::StringPiece name); - void Create(fuchsia::sysmem::BufferCollectionConstraints constraints, - CreateCB build_cb); - - private: - fuchsia::sysmem::BufferCollectionPtr collection_; - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens_; - CreateCB create_cb_; - - THREAD_CHECKER(thread_checker_); - - DISALLOW_COPY_AND_ASSIGN(Creator); - }; - - SysmemBufferPool( - fuchsia::sysmem::BufferCollectionPtr collection, - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens); - ~SysmemBufferPool(); - - fuchsia::sysmem::BufferCollectionTokenPtr TakeToken(); - - // Create Reader/Writer to access raw memory. The returned Reader/Writer is - // owned by SysmemBufferPool and lives as long as SysmemBufferPool. - void CreateReader(CreateReaderCB create_cb); - void CreateWriter(CreateWriterCB create_cb); - - // Returns if this object is still usable. Caller must check this before - // calling SysmemBufferReader/Writer APIs. - bool is_live() const { return collection_.is_bound(); } - - private: - friend class BufferAllocator; - - void OnBuffersAllocated( - zx_status_t status, - fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info); - void OnError(); - - fuchsia::sysmem::BufferCollectionPtr collection_; - std::vector<fuchsia::sysmem::BufferCollectionTokenPtr> shared_tokens_; - - CreateReaderCB create_reader_cb_; - CreateWriterCB create_writer_cb_; - - // FIDL interfaces are thread-affine (see crbug.com/1012875). - THREAD_CHECKER(thread_checker_); - - DISALLOW_COPY_AND_ASSIGN(SysmemBufferPool); -}; - -// Wrapper of sysmem Allocator. -class BufferAllocator { - public: - explicit BufferAllocator(base::StringPiece client_name); - ~BufferAllocator(); - - fuchsia::sysmem::BufferCollectionTokenPtr CreateNewToken(); - - std::unique_ptr<SysmemBufferPool::Creator> MakeBufferPoolCreator( - size_t num_shared_token); - - std::unique_ptr<SysmemBufferPool::Creator> MakeBufferPoolCreatorFromToken( - fuchsia::sysmem::BufferCollectionTokenPtr token); - - // TODO(crbug.com/1131183): Update FuchsiaVideoDecoder to use SysmemBufferPool - // and remove this function. - fuchsia::sysmem::Allocator* raw() { return allocator_.get(); } - - private: - fuchsia::sysmem::AllocatorPtr allocator_; - - THREAD_CHECKER(thread_checker_); - - DISALLOW_COPY_AND_ASSIGN(BufferAllocator); -}; - -} // namespace media - -#endif // MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_POOL_H_ diff --git a/chromium/media/fuchsia/common/sysmem_buffer_reader.cc b/chromium/media/fuchsia/common/sysmem_buffer_reader.cc deleted file mode 100644 index 3bc7cf268ac..00000000000 --- a/chromium/media/fuchsia/common/sysmem_buffer_reader.cc +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2019 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/fuchsia/common/sysmem_buffer_reader.h" - -#include "base/fuchsia/fuchsia_logging.h" - -namespace media { - -SysmemBufferReader::SysmemBufferReader( - fuchsia::sysmem::BufferCollectionInfo_2 info) - : collection_info_(std::move(info)) {} - -SysmemBufferReader::~SysmemBufferReader() = default; - -bool SysmemBufferReader::Read(size_t index, - size_t offset, - base::span<uint8_t> data) { - DCHECK_LT(index, num_buffers()); - DCHECK_LE(offset + data.size(), - collection_info_.settings.buffer_settings.size_bytes); - - const fuchsia::sysmem::VmoBuffer& buffer = collection_info_.buffers[index]; - size_t vmo_offset = buffer.vmo_usable_start + offset; - - InvalidateCacheIfNecessary(buffer.vmo, vmo_offset, data.size()); - - zx_status_t status = buffer.vmo.read(data.data(), vmo_offset, data.size()); - - ZX_LOG_IF(ERROR, status != ZX_OK, status) << "Fail to read"; - return status == ZX_OK; -} - -base::span<const uint8_t> SysmemBufferReader::GetMappingForBuffer( - size_t index) { - if (mappings_.empty()) - mappings_.resize(num_buffers()); - - DCHECK_LT(index, mappings_.size()); - - const fuchsia::sysmem::BufferMemorySettings& settings = - collection_info_.settings.buffer_settings; - fuchsia::sysmem::VmoBuffer& buffer = collection_info_.buffers[index]; - - auto& mapping = mappings_[index]; - size_t buffer_start = buffer.vmo_usable_start; - - if (!mapping.IsValid()) { - size_t mapping_size = buffer_start + settings.size_bytes; - auto region = base::ReadOnlySharedMemoryRegion::Deserialize( - base::subtle::PlatformSharedMemoryRegion::Take( - std::move(buffer.vmo), - base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly, - mapping_size, base::UnguessableToken::Create())); - - mapping = region.Map(); - - // Return the VMO handle back to buffer_. - buffer.vmo = base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( - std::move(region)) - .PassPlatformHandle(); - } - - if (!mapping.IsValid()) { - DLOG(WARNING) << "Failed to map VMO returned by sysmem"; - return {}; - } - - InvalidateCacheIfNecessary(buffer.vmo, buffer_start, settings.size_bytes); - - return base::make_span( - reinterpret_cast<const uint8_t*>(mapping.memory()) + buffer_start, - settings.size_bytes); -} - -void SysmemBufferReader::InvalidateCacheIfNecessary(const zx::vmo& vmo, - size_t offset, - size_t size) { - if (collection_info_.settings.buffer_settings.coherency_domain == - fuchsia::sysmem::CoherencyDomain::RAM) { - zx_status_t status = vmo.op_range(ZX_VMO_OP_CACHE_CLEAN_INVALIDATE, offset, - size, nullptr, 0); - ZX_LOG_IF(ERROR, status != ZX_OK, status) << "Fail to invalidate cache"; - } -} - -// static -std::unique_ptr<SysmemBufferReader> SysmemBufferReader::Create( - fuchsia::sysmem::BufferCollectionInfo_2 info) { - return std::make_unique<SysmemBufferReader>(std::move(info)); -} - -// static -fuchsia::sysmem::BufferCollectionConstraints -SysmemBufferReader::GetRecommendedConstraints( - size_t min_buffer_count, - base::Optional<size_t> min_buffer_size) { - fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; - buffer_constraints.usage.cpu = fuchsia::sysmem::cpuUsageRead; - buffer_constraints.min_buffer_count = min_buffer_count; - if (min_buffer_size) { - buffer_constraints.has_buffer_memory_constraints = true; - buffer_constraints.buffer_memory_constraints.min_size_bytes = - min_buffer_size.value(); - buffer_constraints.buffer_memory_constraints.ram_domain_supported = true; - buffer_constraints.buffer_memory_constraints.cpu_domain_supported = true; - } - return buffer_constraints; -} - -} // namespace media diff --git a/chromium/media/fuchsia/common/sysmem_buffer_reader.h b/chromium/media/fuchsia/common/sysmem_buffer_reader.h deleted file mode 100644 index c4c4e0b10a4..00000000000 --- a/chromium/media/fuchsia/common/sysmem_buffer_reader.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019 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. - -#ifndef MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_READER_H_ -#define MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_READER_H_ - -#include <fuchsia/media/cpp/fidl.h> -#include <fuchsia/sysmem/cpp/fidl.h> - -#include <memory> - -#include "base/containers/span.h" -#include "base/memory/read_only_shared_memory_region.h" -#include "base/optional.h" - -namespace media { - -// Helper class to read content from fuchsia::sysmem::BufferCollection. -class SysmemBufferReader { - public: - // Returns sysmem buffer constraints with the specified |min_buffer_count|. - // Currently it doesn't request buffers for camping or any shared slack, so - // the clients are expected to read incoming buffers (using Read() or - // GetMappingForBuffer()) and then release them back to the source. - static fuchsia::sysmem::BufferCollectionConstraints GetRecommendedConstraints( - size_t min_buffer_count, - base::Optional<size_t> min_buffer_size); - - static std::unique_ptr<SysmemBufferReader> Create( - fuchsia::sysmem::BufferCollectionInfo_2 info); - - explicit SysmemBufferReader(fuchsia::sysmem::BufferCollectionInfo_2 info); - ~SysmemBufferReader(); - - size_t num_buffers() const { return collection_info_.buffer_count; } - - const fuchsia::sysmem::SingleBufferSettings& buffer_settings() { - return collection_info_.settings; - } - - // Read the buffer content at |index| into |data|, starting from |offset|. - bool Read(size_t index, size_t offset, base::span<uint8_t> data); - - // Returns a span for the memory-mapping of the buffer with the specified - // |index|, invalidating the CPU cache for the specified buffer in the sysmem - // collection if necessary. Buffers are mapped lazily and remain mapped for - // the lifetime of SysmemBufferReader. Should be called every time before - // accessing the mapping to ensure that the CPU cache is invalidated for - // buffers with RAM coherency. - base::span<const uint8_t> GetMappingForBuffer(size_t index); - - private: - // Invalidates CPU cache for the specified range of the specified vmo in - // case the collection was allocated with RAM coherency. No-op for collections - // with CPU coherency. Called from Read() and GetMapping() to ensure clients - // get up-to-date buffer content in case the buffer was updated by other - // participants directly in RAM (bypassing CPU cache). - void InvalidateCacheIfNecessary(const zx::vmo& buffer, - size_t offset, - size_t size); - - fuchsia::sysmem::BufferCollectionInfo_2 collection_info_; - std::vector<base::ReadOnlySharedMemoryMapping> mappings_; - - DISALLOW_COPY_AND_ASSIGN(SysmemBufferReader); -}; - -} // namespace media - -#endif // MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_READER_H_ diff --git a/chromium/media/fuchsia/common/sysmem_buffer_stream.h b/chromium/media/fuchsia/common/sysmem_buffer_stream.h new file mode 100644 index 00000000000..f02ebe9d175 --- /dev/null +++ b/chromium/media/fuchsia/common/sysmem_buffer_stream.h @@ -0,0 +1,72 @@ +// Copyright 2021 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. + +#ifndef MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_STREAM_H_ +#define MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_STREAM_H_ + +#include <fuchsia/sysmem/cpp/fidl.h> + +#include "base/memory/scoped_refptr.h" +#include "media/fuchsia/common/stream_processor_helper.h" + +namespace media { + +class DecoderBuffer; + +// Abstract interface for media stream processors. SysmemBufferStream takes a +// stream of buffers in DecoderBuffer, processes them and then writes the output +// to sysmem buffers. +class MEDIA_EXPORT SysmemBufferStream { + public: + class Sink { + public: + // Called to set BufferCollectionToken for the output buffer collection. + virtual void OnSysmemBufferStreamBufferCollectionToken( + fuchsia::sysmem::BufferCollectionTokenPtr token) = 0; + + // Called when a packet has been processed. The client should drop the + // |packet| only after it's finished using it. + virtual void OnSysmemBufferStreamOutputPacket( + StreamProcessorHelper::IoPacket packet) = 0; + + // Called when the end of stream has been reached. + virtual void OnSysmemBufferStreamEndOfStream() = 0; + + // Called on error. + virtual void OnSysmemBufferStreamError() = 0; + + // Called to notify the sink that the SysmemBufferStream has stopped + // because it doesn't have a key. It will resume automatically once a new + // key is received. + virtual void OnSysmemBufferStreamNoKey() = 0; + + protected: + virtual ~Sink() = default; + }; + + SysmemBufferStream() {} + virtual ~SysmemBufferStream() {} + + // Allocates a buffer collection for the output and starts processing the + // stream, passing the output to the specified |sink|. |min_buffer_size| and + // |min_buffer_count| specify the minimum number of packets in the output + // buffer collection. + virtual void Initialize(Sink* sink, + size_t min_buffer_size, + size_t min_buffer_count) = 0; + + // Enqueues the specified buffer to the input queue. Caller is allowed to + // queue as many buffers as it needs without waiting for results from the + // previous Process() calls. May be called before Initialize(). Queued buffers + // will be processed only after Initialize(). + virtual void EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer) = 0; + + // Stops processing queued buffers and drops them. Keeps the |sink| passed to + // Start() and the output buffer collections. + virtual void Reset() = 0; +}; + +} // namespace media + +#endif // MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_STREAM_H_ diff --git a/chromium/media/fuchsia/common/sysmem_buffer_writer.cc b/chromium/media/fuchsia/common/sysmem_buffer_writer.cc deleted file mode 100644 index d2a1a28e4f0..00000000000 --- a/chromium/media/fuchsia/common/sysmem_buffer_writer.cc +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2019 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/fuchsia/common/sysmem_buffer_writer.h" - -#include <zircon/rights.h> -#include <algorithm> - -#include "base/bits.h" -#include "base/fuchsia/fuchsia_logging.h" -#include "base/process/process_metrics.h" - -namespace media { - -class SysmemBufferWriter::Buffer { - public: - Buffer() = default; - - ~Buffer() { - if (!base_address_) { - return; - } - - size_t mapped_bytes = - base::bits::Align(offset_ + size_, base::GetPageSize()); - zx_status_t status = zx::vmar::root_self()->unmap( - reinterpret_cast<uintptr_t>(base_address_), mapped_bytes); - ZX_DCHECK(status == ZX_OK, status) << "zx_vmar_unmap"; - } - - Buffer(Buffer&&) = default; - Buffer& operator=(Buffer&&) = default; - - bool Initialize(zx::vmo vmo, - size_t offset, - size_t size, - fuchsia::sysmem::CoherencyDomain coherency_domain) { - DCHECK(!base_address_); - DCHECK(vmo); - - // zx_vmo_write() doesn't work for sysmem-allocated VMOs (see ZX-4854), so - // the VMOs have to be mapped. - size_t bytes_to_map = base::bits::Align(offset + size, base::GetPageSize()); - uintptr_t addr; - zx_status_t status = zx::vmar::root_self()->map( - ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, /*vmar_offset=*/0, vmo, - /*vmo_offset=*/0, bytes_to_map, &addr); - if (status != ZX_OK) { - ZX_DLOG(ERROR, status) << "zx_vmar_map"; - return false; - } - - base_address_ = reinterpret_cast<uint8_t*>(addr); - offset_ = offset; - size_ = size; - coherency_domain_ = coherency_domain; - - return true; - } - - bool is_used() const { return is_used_; } - size_t size() const { return size_; } - - // Copies as much data as possible from |data| to this input buffer. - size_t Write(base::span<const uint8_t> data) { - DCHECK(!is_used_); - is_used_ = true; - - size_t bytes_to_fill = std::min(size_, data.size()); - memcpy(base_address_ + offset_, data.data(), bytes_to_fill); - - FlushBuffer(0, bytes_to_fill); - - return bytes_to_fill; - } - - base::span<uint8_t> ReserveAndMapBuffer() { - DCHECK(!is_used_); - is_used_ = true; - return base::make_span(base_address_ + offset_, size_); - } - - void FlushBuffer(size_t flush_offset, size_t flush_size) { - DCHECK(is_used_); - DCHECK_LE(flush_size, size_ - flush_offset); - - if (coherency_domain_ != fuchsia::sysmem::CoherencyDomain::RAM) - return; - - uint8_t* address = base_address_ + offset_ + flush_offset; - zx_status_t status = - zx_cache_flush(address, flush_size, ZX_CACHE_FLUSH_DATA); - ZX_DCHECK(status == ZX_OK, status) << "zx_cache_flush"; - } - - void Release() { is_used_ = false; } - - private: - uint8_t* base_address_ = nullptr; - - // Buffer settings provided by sysmem. - size_t offset_ = 0; - size_t size_ = 0; - fuchsia::sysmem::CoherencyDomain coherency_domain_; - - // Set to true when this buffer is being used by the codec. - bool is_used_ = false; -}; - -SysmemBufferWriter::SysmemBufferWriter(std::vector<Buffer> buffers) - : buffers_(std::move(buffers)) {} - -SysmemBufferWriter::~SysmemBufferWriter() = default; - -size_t SysmemBufferWriter::Write(size_t index, base::span<const uint8_t> data) { - DCHECK_LT(index, buffers_.size()); - DCHECK(!buffers_[index].is_used()); - - return buffers_[index].Write(data); -} - -base::Optional<size_t> SysmemBufferWriter::Acquire() { - auto it = std::find_if( - buffers_.begin(), buffers_.end(), - [](const SysmemBufferWriter::Buffer& buf) { return !buf.is_used(); }); - - if (it == buffers_.end()) - return base::nullopt; - - return it - buffers_.begin(); -} - -void SysmemBufferWriter::Release(size_t index) { - DCHECK_LT(index, buffers_.size()); - buffers_[index].Release(); -} - -void SysmemBufferWriter::ReleaseAll() { - for (auto& buf : buffers_) { - buf.Release(); - } -} - -size_t SysmemBufferWriter::num_buffers() const { - return buffers_.size(); -} - -// static -std::unique_ptr<SysmemBufferWriter> SysmemBufferWriter::Create( - fuchsia::sysmem::BufferCollectionInfo_2 info) { - std::vector<SysmemBufferWriter::Buffer> buffers; - buffers.resize(info.buffer_count); - - fuchsia::sysmem::BufferMemorySettings& settings = - info.settings.buffer_settings; - for (size_t i = 0; i < info.buffer_count; ++i) { - fuchsia::sysmem::VmoBuffer& buffer = info.buffers[i]; - if (!buffers[i].Initialize(std::move(buffer.vmo), buffer.vmo_usable_start, - settings.size_bytes, - settings.coherency_domain)) { - return nullptr; - } - } - - return std::make_unique<SysmemBufferWriter>(std::move(buffers)); -} - -// static -base::Optional<fuchsia::sysmem::BufferCollectionConstraints> -SysmemBufferWriter::GetRecommendedConstraints(size_t min_buffer_count, - size_t min_buffer_size) { - fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; - - // Currently we have to map buffers VMOs to write to them (see ZX-4854) and - // memory cannot be mapped as write-only (see ZX-4872), so request RW access - // even though we will never need to read from these buffers. - buffer_constraints.usage.cpu = - fuchsia::sysmem::cpuUsageRead | fuchsia::sysmem::cpuUsageWrite; - - buffer_constraints.min_buffer_count = min_buffer_count; - buffer_constraints.has_buffer_memory_constraints = true; - buffer_constraints.buffer_memory_constraints.min_size_bytes = min_buffer_size; - buffer_constraints.buffer_memory_constraints.ram_domain_supported = true; - buffer_constraints.buffer_memory_constraints.cpu_domain_supported = true; - - return buffer_constraints; -} - -base::span<uint8_t> SysmemBufferWriter::ReserveAndMapBuffer(size_t index) { - DCHECK_LT(index, buffers_.size()); - return buffers_[index].ReserveAndMapBuffer(); -} - -void SysmemBufferWriter::FlushBuffer(size_t index, - size_t flush_offset, - size_t flush_size) { - DCHECK_LT(index, buffers_.size()); - return buffers_[index].FlushBuffer(flush_offset, flush_size); -} - -} // namespace media diff --git a/chromium/media/fuchsia/common/sysmem_buffer_writer.h b/chromium/media/fuchsia/common/sysmem_buffer_writer.h deleted file mode 100644 index 376468d1b75..00000000000 --- a/chromium/media/fuchsia/common/sysmem_buffer_writer.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 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. - -#ifndef MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_WRITER_H_ -#define MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_WRITER_H_ - -#include <fuchsia/media/cpp/fidl.h> -#include <fuchsia/sysmem/cpp/fidl.h> - -#include <memory> - -#include "base/containers/span.h" -#include "base/memory/shared_memory_mapping.h" -#include "base/optional.h" - -namespace media { - -// Helper class to write content into fuchsia::sysmem::BufferCollection. -class SysmemBufferWriter { - public: - class Buffer; - - static base::Optional<fuchsia::sysmem::BufferCollectionConstraints> - GetRecommendedConstraints(size_t min_buffer_count, size_t min_buffer_size); - - static std::unique_ptr<SysmemBufferWriter> Create( - fuchsia::sysmem::BufferCollectionInfo_2 info); - - explicit SysmemBufferWriter(std::vector<Buffer> buffers); - ~SysmemBufferWriter(); - - SysmemBufferWriter(const SysmemBufferWriter&) = delete; - SysmemBufferWriter& operator=(const SysmemBufferWriter&) = delete; - - // Write the content of |data| into the buffer at |index|. Return num of bytes - // written into the buffer. Can be called only for an unused buffer. Marks - // the buffer as used. - size_t Write(size_t index, base::span<const uint8_t> data); - - // Returns a span for the memory-mapping of the buffer with the specified - // |index|. Can be called only for an unused buffer. Marks the buffer as used. - // Callers must call FlushCache() after they are finished updating the buffer. - base::span<uint8_t> ReserveAndMapBuffer(size_t index); - - // Flushes CPU cache for specified range in the buffer with the specified - // |index| in case the buffer collection uses RAM coherency. No-op for - // collections with RAM coherency. - void FlushBuffer(size_t index, size_t flush_offset, size_t flush_size); - - // Acquire unused buffer for write. If |min_size| is provided, the returned - // buffer will have available size larger than |min_size|. This will NOT - // mark the buffer as "used". - base::Optional<size_t> Acquire(); - - // Notify the pool buffer at |index| is free to write new data. - void Release(size_t index); - - // Mark all buffers as unused. - void ReleaseAll(); - - size_t num_buffers() const; - - private: - std::vector<Buffer> buffers_; -}; - -} // namespace media - -#endif // MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_WRITER_H_ diff --git a/chromium/media/fuchsia/common/sysmem_client.cc b/chromium/media/fuchsia/common/sysmem_client.cc new file mode 100644 index 00000000000..4c5d86dbeb1 --- /dev/null +++ b/chromium/media/fuchsia/common/sysmem_client.cc @@ -0,0 +1,172 @@ +// Copyright 2021 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/fuchsia/common/sysmem_client.h" + +#include <lib/sys/cpp/component_context.h> +#include <zircon/rights.h> + +#include <algorithm> + +#include "base/bind.h" +#include "base/fuchsia/fuchsia_logging.h" +#include "base/fuchsia/process_context.h" +#include "base/process/process_handle.h" +#include "media/fuchsia/common/vmo_buffer.h" + +namespace media { + +SysmemCollectionClient::SysmemCollectionClient( + fuchsia::sysmem::Allocator* allocator, + fuchsia::sysmem::BufferCollectionTokenPtr collection_token) + : allocator_(allocator), collection_token_(std::move(collection_token)) { + DCHECK(allocator_); + DCHECK(collection_token_); +} + +SysmemCollectionClient::~SysmemCollectionClient() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (collection_) + collection_->Close(); +} + +void SysmemCollectionClient::Initialize( + fuchsia::sysmem::BufferCollectionConstraints constraints, + base::StringPiece name, + uint32_t name_priority) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + writable_ = (constraints.usage.cpu & fuchsia::sysmem::cpuUsageWrite) == + fuchsia::sysmem::cpuUsageWrite; + + allocator_->BindSharedCollection(std::move(collection_token_), + collection_.NewRequest()); + + collection_.set_error_handler( + fit::bind_member(this, &SysmemCollectionClient::OnError)); + collection_->SetName(name_priority, std::string(name)); + + // If Sync() is not required then constraints can be set immediately. + if (sync_completion_closures_.empty()) { + collection_->SetConstraints(/*have_constraints=*/true, + std::move(constraints)); + return; + } + + sync_completion_closures_.push_back( + base::BindOnce(&fuchsia::sysmem::BufferCollection::SetConstraints, + base::Unretained(collection_.get()), + /*have_constraints=*/true, std::move(constraints))); + collection_->Sync( + fit::bind_member(this, &SysmemCollectionClient::OnSyncComplete)); +} + +void SysmemCollectionClient::CreateSharedToken( + GetSharedTokenCB cb, + base::StringPiece debug_client_name, + uint64_t debug_client_id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(collection_token_); + + fuchsia::sysmem::BufferCollectionTokenPtr token; + collection_token_->Duplicate(ZX_RIGHT_SAME_RIGHTS, token.NewRequest()); + + if (!debug_client_name.empty()) { + token->SetDebugClientInfo(std::string(debug_client_name), debug_client_id); + } + + sync_completion_closures_.push_back( + base::BindOnce(std::move(cb), std::move(token))); +} + +void SysmemCollectionClient::AcquireBuffers(AcquireBuffersCB cb) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!collection_token_); + + if (!collection_) { + std::move(cb).Run({}, {}); + return; + } + + acquire_buffers_cb_ = std::move(cb); + collection_->WaitForBuffersAllocated( + fit::bind_member(this, &SysmemCollectionClient::OnBuffersAllocated)); +} + +void SysmemCollectionClient::OnSyncComplete() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + std::vector<base::OnceClosure> sync_closures = + std::move(sync_completion_closures_); + for (auto& cb : sync_closures) { + std::move(cb).Run(); + } +} + +void SysmemCollectionClient::OnBuffersAllocated( + zx_status_t status, + fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (status != ZX_OK) { + ZX_LOG(ERROR, status) << "Failed to allocate sysmem buffers."; + OnError(status); + return; + } + + if (acquire_buffers_cb_) { + auto buffers = VmoBuffer::CreateBuffersFromSysmemCollection( + &buffer_collection_info, writable_); + std::move(acquire_buffers_cb_) + .Run(std::move(buffers), buffer_collection_info.settings); + } +} + +void SysmemCollectionClient::OnError(zx_status_t status) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + ZX_DLOG(ERROR, status) << "Connection to BufferCollection was disconnected."; + collection_.Unbind(); + if (acquire_buffers_cb_) + std::move(acquire_buffers_cb_).Run({}, {}); +} + +SysmemAllocatorClient::SysmemAllocatorClient(base::StringPiece client_name) { + allocator_ = base::ComponentContextForProcess() + ->svc() + ->Connect<fuchsia::sysmem::Allocator>(); + + allocator_->SetDebugClientInfo(std::string(client_name), + base::GetCurrentProcId()); + + allocator_.set_error_handler([](zx_status_t status) { + // Just log a warning. We will handle BufferCollection the failure when + // trying to create a new BufferCollection. + ZX_DLOG(WARNING, status) + << "The fuchsia.sysmem.Allocator channel was disconnected."; + }); +} + +SysmemAllocatorClient::~SysmemAllocatorClient() = default; + +fuchsia::sysmem::BufferCollectionTokenPtr +SysmemAllocatorClient::CreateNewToken() { + fuchsia::sysmem::BufferCollectionTokenPtr collection_token; + allocator_->AllocateSharedCollection(collection_token.NewRequest()); + return collection_token; +} + +std::unique_ptr<SysmemCollectionClient> +SysmemAllocatorClient::AllocateNewCollection() { + return std::make_unique<SysmemCollectionClient>(allocator_.get(), + CreateNewToken()); +} + +std::unique_ptr<SysmemCollectionClient> +SysmemAllocatorClient::BindSharedCollection( + fuchsia::sysmem::BufferCollectionTokenPtr token) { + return std::make_unique<SysmemCollectionClient>(allocator_.get(), + std::move(token)); +} + +} // namespace media diff --git a/chromium/media/fuchsia/common/sysmem_client.h b/chromium/media/fuchsia/common/sysmem_client.h new file mode 100644 index 00000000000..1b0b1b16e1d --- /dev/null +++ b/chromium/media/fuchsia/common/sysmem_client.h @@ -0,0 +1,114 @@ +// Copyright 2021 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. + +#ifndef MEDIA_FUCHSIA_COMMON_SYSMEM_CLIENT_H_ +#define MEDIA_FUCHSIA_COMMON_SYSMEM_CLIENT_H_ + +#include <fuchsia/media/cpp/fidl.h> +#include <fuchsia/sysmem/cpp/fidl.h> + +#include <vector> + +#include "base/callback.h" +#include "base/threading/thread_checker.h" +#include "media/base/media_export.h" + +namespace media { + +class VmoBuffer; + +// Wrapper for fuchsia.sysmem.BufferCollection . It provides the following two +// features: +// 1. Calls Sync() and ensures that it completes before buffer constrains are +// set and shared tokens are passed to other participants. +// 2. Provides AcquireBuffers() that allows to acquire buffers and handle +// possible errors. +class MEDIA_EXPORT SysmemCollectionClient { + public: + static constexpr uint32_t kDefaultNamePriority = 100; + + // Callback for GetSharedToken(). + using GetSharedTokenCB = + base::OnceCallback<void(fuchsia::sysmem::BufferCollectionTokenPtr token)>; + + // Callback for AcquireBuffers(). Called with an empty |buffers| if buffers + // allocation failed. + using AcquireBuffersCB = base::OnceCallback<void( + std::vector<VmoBuffer> buffers, + const fuchsia::sysmem::SingleBufferSettings& settings)>; + + SysmemCollectionClient( + fuchsia::sysmem::Allocator* allocator, + fuchsia::sysmem::BufferCollectionTokenPtr collection_token); + ~SysmemCollectionClient(); + + SysmemCollectionClient(const SysmemCollectionClient&) = delete; + SysmemCollectionClient& operator=(const SysmemCollectionClient&) = delete; + + // Creates one shared token to be shared with other participants and returns + // it asynchronously, when it's safe to pass it (i.e. after Sync()). Must be + // called before Initialize(). + void CreateSharedToken( + GetSharedTokenCB cb, + base::StringPiece debug_client_name = base::StringPiece(), + uint64_t debug_client_id = 0); + + // Initializes the collection with the given name and constraints. + void Initialize(fuchsia::sysmem::BufferCollectionConstraints constraints, + base::StringPiece name, + uint32_t name_priority = kDefaultNamePriority); + + // Create VmoBuffers to access raw memory. Should be called only after + // GetSharedToken() has been called for all shared tokens. + void AcquireBuffers(AcquireBuffersCB cb); + + private: + void OnSyncComplete(); + void OnBuffersAllocated( + zx_status_t status, + fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info); + void OnError(zx_status_t status); + + fuchsia::sysmem::Allocator* const allocator_; + fuchsia::sysmem::BufferCollectionTokenPtr collection_token_; + fuchsia::sysmem::BufferCollectionPtr collection_; + + bool writable_ = false; + std::vector<base::OnceClosure> sync_completion_closures_; + AcquireBuffersCB acquire_buffers_cb_; + + THREAD_CHECKER(thread_checker_); +}; + +// Helper fuchsia.sysmem.Allocator . +class MEDIA_EXPORT SysmemAllocatorClient { + public: + explicit SysmemAllocatorClient(base::StringPiece client_name); + ~SysmemAllocatorClient(); + + SysmemAllocatorClient(const SysmemAllocatorClient&) = delete; + SysmemAllocatorClient& operator=(const SysmemAllocatorClient&) = delete; + + fuchsia::sysmem::BufferCollectionTokenPtr CreateNewToken(); + + // Creates new buffer collection. + std::unique_ptr<SysmemCollectionClient> AllocateNewCollection(); + + // Binds the specified token to a SysmemCollectionClient. + std::unique_ptr<SysmemCollectionClient> BindSharedCollection( + fuchsia::sysmem::BufferCollectionTokenPtr token); + + // TODO(crbug.com/1131183): Update FuchsiaVideoDecoder to use + // SysmemCollectionClient and remove this function. + fuchsia::sysmem::Allocator* raw() { return allocator_.get(); } + + private: + friend SysmemCollectionClient; + + fuchsia::sysmem::AllocatorPtr allocator_; +}; + +} // namespace media + +#endif // MEDIA_FUCHSIA_COMMON_SYSMEM_CLIENT_H_ diff --git a/chromium/media/fuchsia/common/vmo_buffer.cc b/chromium/media/fuchsia/common/vmo_buffer.cc new file mode 100644 index 00000000000..6fb77333223 --- /dev/null +++ b/chromium/media/fuchsia/common/vmo_buffer.cc @@ -0,0 +1,171 @@ +// Copyright 2021 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/fuchsia/common/vmo_buffer.h" + +#include <zircon/rights.h> +#include <algorithm> + +#include "base/bits.h" +#include "base/fuchsia/fuchsia_logging.h" +#include "base/memory/page_size.h" + +namespace media { + +// static +fuchsia::sysmem::BufferCollectionConstraints +VmoBuffer::GetRecommendedConstraints(size_t min_buffer_count, + absl::optional<size_t> min_buffer_size, + bool writable) { + fuchsia::sysmem::BufferCollectionConstraints buffer_constraints; + + buffer_constraints.usage.cpu = fuchsia::sysmem::cpuUsageRead; + if (writable) + buffer_constraints.usage.cpu |= fuchsia::sysmem::cpuUsageWrite; + + buffer_constraints.min_buffer_count = min_buffer_count; + + if (min_buffer_size) { + buffer_constraints.has_buffer_memory_constraints = true; + buffer_constraints.buffer_memory_constraints.min_size_bytes = + min_buffer_size.value(); + buffer_constraints.buffer_memory_constraints.ram_domain_supported = true; + buffer_constraints.buffer_memory_constraints.cpu_domain_supported = true; + } + + return buffer_constraints; +} + +// static +std::vector<VmoBuffer> VmoBuffer::CreateBuffersFromSysmemCollection( + fuchsia::sysmem::BufferCollectionInfo_2* info, + bool writable) { + std::vector<VmoBuffer> buffers; + buffers.resize(info->buffer_count); + + fuchsia::sysmem::BufferMemorySettings& settings = + info->settings.buffer_settings; + for (size_t i = 0; i < info->buffer_count; ++i) { + fuchsia::sysmem::VmoBuffer& buffer = info->buffers[i]; + if (!buffers[i].Initialize(std::move(buffer.vmo), writable, + buffer.vmo_usable_start, settings.size_bytes, + settings.coherency_domain)) { + return {}; + } + } + + return buffers; +} + +VmoBuffer::VmoBuffer() = default; + +VmoBuffer::~VmoBuffer() { + if (!base_address_) { + return; + } + + zx_status_t status = zx::vmar::root_self()->unmap( + reinterpret_cast<uintptr_t>(base_address_), mapped_size()); + ZX_DCHECK(status == ZX_OK, status) << "zx_vmar_unmap"; +} + +VmoBuffer::VmoBuffer(VmoBuffer&&) = default; +VmoBuffer& VmoBuffer::operator=(VmoBuffer&&) = default; + +bool VmoBuffer::Initialize(zx::vmo vmo, + bool writable, + size_t offset, + size_t size, + fuchsia::sysmem::CoherencyDomain coherency_domain) { + DCHECK(!base_address_); + DCHECK(vmo); + + writable_ = writable; + offset_ = offset; + size_ = size; + coherency_domain_ = coherency_domain; + + zx_vm_option_t options = ZX_VM_PERM_READ; + if (writable) + options |= ZX_VM_PERM_WRITE; + + uintptr_t addr; + zx_status_t status = + zx::vmar::root_self()->map(options, /*vmar_offset=*/0, vmo, + /*vmo_offset=*/0, mapped_size(), &addr); + if (status != ZX_OK) { + ZX_DLOG(ERROR, status) << "zx_vmar_map"; + return false; + } + + vmo_ = std::move(vmo); + base_address_ = reinterpret_cast<uint8_t*>(addr); + + return true; +} + +size_t VmoBuffer::Read(size_t offset, base::span<uint8_t> data) { + if (offset >= size_) + return 0U; + size_t bytes_to_fill = std::min(size_ - offset, data.size()); + FlushCache(offset, bytes_to_fill, /*invalidate=*/true); + memcpy(data.data(), base_address_ + offset_ + offset, bytes_to_fill); + return bytes_to_fill; +} + +size_t VmoBuffer::Write(base::span<const uint8_t> data) { + DCHECK(writable_); + + size_t bytes_to_fill = std::min(size_, data.size()); + memcpy(base_address_ + offset_, data.data(), bytes_to_fill); + + FlushCache(0, bytes_to_fill, /*invalidate=*/false); + + return bytes_to_fill; +} + +base::span<const uint8_t> VmoBuffer::GetMemory() { + FlushCache(0, size_, /*invalidate=*/true); + return base::make_span(base_address_ + offset_, size_); +} + +base::span<uint8_t> VmoBuffer::GetWritableMemory() { + DCHECK(writable_); + return base::make_span(base_address_ + offset_, size_); +} + +void VmoBuffer::FlushCache(size_t flush_offset, + size_t flush_size, + bool invalidate) { + DCHECK_LE(flush_size, size_ - flush_offset); + + if (coherency_domain_ != fuchsia::sysmem::CoherencyDomain::RAM) + return; + + uint8_t* address = base_address_ + offset_ + flush_offset; + uint32_t options = ZX_CACHE_FLUSH_DATA; + if (invalidate) + options |= ZX_CACHE_FLUSH_INVALIDATE; + zx_status_t status = zx_cache_flush(address, flush_size, options); + ZX_DCHECK(status == ZX_OK, status) << "zx_cache_flush"; +} + +size_t VmoBuffer::mapped_size() { + return base::bits::Align(offset_ + size_, base::GetPageSize()); +} + +zx::vmo VmoBuffer::Duplicate(bool writable) { + zx_rights_t rights = ZX_RIGHT_DUPLICATE | ZX_RIGHT_TRANSFER | ZX_RIGHT_READ | + ZX_RIGHT_MAP | ZX_RIGHT_GET_PROPERTY; + if (writable) + rights |= ZX_RIGHT_WRITE; + + zx::vmo vmo; + zx_status_t status = vmo_.duplicate(rights, &vmo); + ZX_CHECK(status == ZX_OK, status) << "zx_handle_duplicate"; + + return vmo; +} + +} // namespace media diff --git a/chromium/media/fuchsia/common/vmo_buffer.h b/chromium/media/fuchsia/common/vmo_buffer.h new file mode 100644 index 00000000000..8a6ab02de51 --- /dev/null +++ b/chromium/media/fuchsia/common/vmo_buffer.h @@ -0,0 +1,99 @@ +// Copyright 2021 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. + +#ifndef MEDIA_FUCHSIA_COMMON_VMO_BUFFER_H_ +#define MEDIA_FUCHSIA_COMMON_VMO_BUFFER_H_ + +#include <fuchsia/media/cpp/fidl.h> +#include <fuchsia/sysmem/cpp/fidl.h> + +#include <memory> + +#include "base/compiler_specific.h" +#include "base/containers/span.h" +#include "base/memory/shared_memory_mapping.h" +#include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace media { + +class MEDIA_EXPORT VmoBuffer { + public: + // Returns sysmem buffer constraints to use to ensure that sysmem buffer + // collection is compatible with this class. + static fuchsia::sysmem::BufferCollectionConstraints GetRecommendedConstraints( + size_t min_buffer_count, + absl::optional<size_t> min_buffer_size, + bool writable); + + // Creates a set of buffers from a sysmem collection. An empty vector is + // returned in case of a failure. + static std::vector<VmoBuffer> CreateBuffersFromSysmemCollection( + fuchsia::sysmem::BufferCollectionInfo_2* info, + bool writable); + + VmoBuffer(); + ~VmoBuffer(); + + VmoBuffer(VmoBuffer&&); + VmoBuffer& operator=(VmoBuffer&&); + + // Initializes the buffer from the specified |vmo|. |writable| should be true + // for writable buffers. |offset| and |size| are used to specify the portion + // of the |vmo| that should be used for this buffer. Returns false if it fails + // to map the buffer. + bool Initialize(zx::vmo vmo, + bool writable, + size_t offset, + size_t size, + fuchsia::sysmem::CoherencyDomain coherency_domain) + WARN_UNUSED_RESULT; + + size_t size() const { return size_; } + + // Read the buffer content into |data|, starting from |offset|. For buffers + // with RAM coherency the cache is invalidated prior to read to ensure the + // data is read from RAM instead of the CPU cache. Returns number of bytes + // that have been copied. + size_t Read(size_t offset, base::span<uint8_t> data); + + // Writes |data| to this input buffer. If the |data| is larger than the buffer + // then writes only size() bytes from the head of the |data|. Returns number + // of bytes that have been copied. + size_t Write(base::span<const uint8_t> data); + + // Returns read-only memory corresponding to the buffer. Also invalidates CPU + // cache for buffers with RAM coherency. + base::span<const uint8_t> GetMemory(); + + // Returns writable memory span. The caller should call Flush() after writing + // to the buffer in order to ensure that the buffer is flushed in case it uses + // RAM coherency. + base::span<uint8_t> GetWritableMemory(); + + // Flushes the CPU cache if the buffers uses RAM coherency. No-op for buffers + // with CPU coherency. If |invalidate| flag is set then the cache is also + // invalidated. + void FlushCache(size_t flush_offset, size_t flush_size, bool invalidate); + + // Duplicates VMO. + zx::vmo Duplicate(bool writable); + + private: + // Returns size of the mapped region. + size_t mapped_size(); + + zx::vmo vmo_; + + uint8_t* base_address_ = nullptr; + + bool writable_ = false; + size_t offset_ = 0; + size_t size_ = 0; + fuchsia::sysmem::CoherencyDomain coherency_domain_; +}; + +} // namespace media + +#endif // MEDIA_FUCHSIA_COMMON_VMO_BUFFER_H_ diff --git a/chromium/media/fuchsia/common/sysmem_buffer_writer_queue.cc b/chromium/media/fuchsia/common/vmo_buffer_writer_queue.cc index defb54d059d..2367a8d3f91 100644 --- a/chromium/media/fuchsia/common/sysmem_buffer_writer_queue.cc +++ b/chromium/media/fuchsia/common/vmo_buffer_writer_queue.cc @@ -1,8 +1,8 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// Copyright 2021 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/fuchsia/common/sysmem_buffer_writer_queue.h" +#include "media/fuchsia/common/vmo_buffer_writer_queue.h" #include <zircon/rights.h> #include <algorithm> @@ -14,7 +14,7 @@ namespace media { -struct SysmemBufferWriterQueue::PendingBuffer { +struct VmoBufferWriterQueue::PendingBuffer { PendingBuffer(scoped_refptr<DecoderBuffer> buffer) : buffer(buffer) { DCHECK(buffer); } @@ -39,37 +39,50 @@ struct SysmemBufferWriterQueue::PendingBuffer { // Index of the last buffer in the sysmem buffer collection that was used to // send this input buffer. Should be set only when |bytes_left()==0|. - base::Optional<size_t> tail_sysmem_buffer_index; + absl::optional<size_t> tail_sysmem_buffer_index; }; -SysmemBufferWriterQueue::SysmemBufferWriterQueue() = default; -SysmemBufferWriterQueue::~SysmemBufferWriterQueue() = default; +VmoBufferWriterQueue::VmoBufferWriterQueue() { + DETACH_FROM_THREAD(thread_checker_); +} + +VmoBufferWriterQueue::~VmoBufferWriterQueue() = default; -void SysmemBufferWriterQueue::EnqueueBuffer( - scoped_refptr<DecoderBuffer> buffer) { +void VmoBufferWriterQueue::EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); pending_buffers_.push_back(PendingBuffer(buffer)); PumpPackets(); } -void SysmemBufferWriterQueue::Start(std::unique_ptr<SysmemBufferWriter> writer, - SendPacketCB send_packet_cb, - EndOfStreamCB end_of_stream_cb) { +void VmoBufferWriterQueue::Start(std::vector<VmoBuffer> buffers, + SendPacketCB send_packet_cb, + EndOfStreamCB end_of_stream_cb) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!writer_); + DCHECK(buffers_.empty()); + DCHECK(!buffers.empty()); - writer_ = std::move(writer); + buffers_ = std::move(buffers); send_packet_cb_ = std::move(send_packet_cb); end_of_stream_cb_ = std::move(end_of_stream_cb); + // Initialize |unused_buffers_|. + unused_buffers_.reserve(buffers_.size()); + for (size_t i = 0; i < buffers_.size(); ++i) { + unused_buffers_.push_back(i); + } + PumpPackets(); } -void SysmemBufferWriterQueue::PumpPackets() { +bool VmoBufferWriterQueue::IsBlocked() const { + return unused_buffers_.empty(); +} + +void VmoBufferWriterQueue::PumpPackets() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); auto weak_this = weak_factory_.GetWeakPtr(); - while (writer_ && !is_paused_ && + while (!buffers_.empty() && !is_paused_ && input_queue_position_ < pending_buffers_.size()) { PendingBuffer* current_buffer = &pending_buffers_[input_queue_position_]; @@ -81,30 +94,28 @@ void SysmemBufferWriterQueue::PumpPackets() { continue; } - base::Optional<size_t> index_opt = writer_->Acquire(); - - if (!index_opt.has_value()) { + if (unused_buffers_.empty()) { // No input buffer available. return; } - size_t sysmem_buffer_index = index_opt.value(); + size_t buffer_index = unused_buffers_.back(); + unused_buffers_.pop_back(); - size_t bytes_filled = writer_->Write( - sysmem_buffer_index, + size_t bytes_filled = buffers_[buffer_index].Write( base::make_span(current_buffer->data(), current_buffer->bytes_left())); current_buffer->AdvanceCurrentPos(bytes_filled); bool buffer_end = current_buffer->bytes_left() == 0; - auto packet = StreamProcessorHelper::IoPacket::CreateInput( - sysmem_buffer_index, bytes_filled, current_buffer->buffer->timestamp(), - buffer_end, - base::BindOnce(&SysmemBufferWriterQueue::ReleaseBuffer, - weak_factory_.GetWeakPtr(), sysmem_buffer_index)); + auto packet = StreamProcessorHelper::IoPacket( + buffer_index, /*offset=*/0, bytes_filled, + current_buffer->buffer->timestamp(), buffer_end, + base::BindOnce(&VmoBufferWriterQueue::ReleaseBuffer, + weak_factory_.GetWeakPtr(), buffer_index)); if (buffer_end) { - current_buffer->tail_sysmem_buffer_index = sysmem_buffer_index; + current_buffer->tail_sysmem_buffer_index = buffer_index; input_queue_position_ += 1; } @@ -114,16 +125,16 @@ void SysmemBufferWriterQueue::PumpPackets() { } } -void SysmemBufferWriterQueue::ResetQueue() { +void VmoBufferWriterQueue::ResetQueue() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); pending_buffers_.clear(); input_queue_position_ = 0; is_paused_ = false; } -void SysmemBufferWriterQueue::ResetBuffers() { +void VmoBufferWriterQueue::ResetBuffers() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - writer_.reset(); + buffers_.clear(); send_packet_cb_ = SendPacketCB(); end_of_stream_cb_ = EndOfStreamCB(); @@ -132,7 +143,7 @@ void SysmemBufferWriterQueue::ResetBuffers() { weak_factory_.InvalidateWeakPtrs(); } -void SysmemBufferWriterQueue::ResetPositionAndPause() { +void VmoBufferWriterQueue::ResetPositionAndPause() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); for (auto& buffer : pending_buffers_) { buffer.buffer_pos = 0; @@ -141,22 +152,22 @@ void SysmemBufferWriterQueue::ResetPositionAndPause() { // All packets that were pending will need to be resent. Reset // |tail_sysmem_buffer_index| to ensure that these packets are not removed // from the queue in ReleaseBuffer(). - buffer.tail_sysmem_buffer_index = base::nullopt; + buffer.tail_sysmem_buffer_index = absl::nullopt; } input_queue_position_ = 0; is_paused_ = true; } -void SysmemBufferWriterQueue::Unpause() { +void VmoBufferWriterQueue::Unpause() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(is_paused_); is_paused_ = false; PumpPackets(); } -void SysmemBufferWriterQueue::ReleaseBuffer(size_t buffer_index) { +void VmoBufferWriterQueue::ReleaseBuffer(size_t buffer_index) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(writer_); + DCHECK(!buffers_.empty()); // Mark the input buffer as complete. for (size_t i = 0; i < input_queue_position_; ++i) { @@ -176,13 +187,13 @@ void SysmemBufferWriterQueue::ReleaseBuffer(size_t buffer_index) { input_queue_position_--; } - writer_->Release(buffer_index); + unused_buffers_.push_back(buffer_index); PumpPackets(); } -size_t SysmemBufferWriterQueue::num_buffers() const { +size_t VmoBufferWriterQueue::num_buffers() const { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - return writer_ ? writer_->num_buffers() : 0; + return buffers_.size(); } } // namespace media diff --git a/chromium/media/fuchsia/common/sysmem_buffer_writer_queue.h b/chromium/media/fuchsia/common/vmo_buffer_writer_queue.h index 761d2b5aae1..543373077dd 100644 --- a/chromium/media/fuchsia/common/sysmem_buffer_writer_queue.h +++ b/chromium/media/fuchsia/common/vmo_buffer_writer_queue.h @@ -1,9 +1,9 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// Copyright 2021 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. -#ifndef MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_WRITER_QUEUE_H_ -#define MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_WRITER_QUEUE_H_ +#ifndef MEDIA_FUCHSIA_COMMON_VMO_BUFFER_WRITER_QUEUE_H_ +#define MEDIA_FUCHSIA_COMMON_VMO_BUFFER_WRITER_QUEUE_H_ #include <fuchsia/media/cpp/fidl.h> #include <fuchsia/sysmem/cpp/fidl.h> @@ -12,18 +12,19 @@ #include "base/containers/span.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/threading/thread_checker.h" +#include "media/base/media_export.h" #include "media/fuchsia/common/stream_processor_helper.h" -#include "media/fuchsia/common/sysmem_buffer_writer.h" +#include "media/fuchsia/common/vmo_buffer.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { class DecoderBuffer; -// A SysmemBufferWriter wrapper that keeps a queue of pending DecodeBuffers, -// writes them to sysmem buffers and generates StreamProcessor packets. -class SysmemBufferWriterQueue { +// A helper that keeps a queue of pending DecodeBuffers, writes them to a set of +// VmoBuffers and generates StreamProcessor packets. +class MEDIA_EXPORT VmoBufferWriterQueue { public: // Callback passed to StartSender(). |buffer| corresponds to the original // buffer from which the |packet| was generated. @@ -34,16 +35,19 @@ class SysmemBufferWriterQueue { // Called when processing DecoderBuffer that's marked as end-of-stream. using EndOfStreamCB = base::RepeatingClosure; - SysmemBufferWriterQueue(); - ~SysmemBufferWriterQueue(); + VmoBufferWriterQueue(); + ~VmoBufferWriterQueue(); + + VmoBufferWriterQueue(VmoBufferWriterQueue&) = delete; + VmoBufferWriterQueue& operator=(VmoBufferWriterQueue&) = delete; // Enqueues buffer to the queue. void EnqueueBuffer(scoped_refptr<DecoderBuffer> buffer); - // Sets the buffer writer to use and starts sending outgoing packets using + // Sets the buffers to use and starts sending outgoing packets using // |send_packet_cb|. |end_of_stream_cb| will be called when processing each // end-of-stream buffer. - void Start(std::unique_ptr<SysmemBufferWriter> writer, + void Start(std::vector<VmoBuffer> buffers, SendPacketCB send_packet_cb, EndOfStreamCB end_of_stream_cb); @@ -73,6 +77,10 @@ class SysmemBufferWriterQueue { // been allocated (i.e. before Start()). size_t num_buffers() const; + // Returns true of the queue is currently blocked, i.e. buffers passed + // to EnqueueBuffer() will not be sent immediately. + bool IsBlocked() const; + private: struct PendingBuffer; class SysmemBuffer; @@ -95,8 +103,11 @@ class SysmemBufferWriterQueue { // Unpause() is called. bool is_paused_ = false; - // Buffers for sysmem buffer collection. Not set until Start() is called. - std::unique_ptr<SysmemBufferWriter> writer_; + // Buffers for sysmem buffer collection. Empty until Start() is called. + std::vector<VmoBuffer> buffers_; + + // Usd to store indices of the buffers that are not being used currently. + std::vector<size_t> unused_buffers_; SendPacketCB send_packet_cb_; EndOfStreamCB end_of_stream_cb_; @@ -104,11 +115,9 @@ class SysmemBufferWriterQueue { // FIDL interfaces are thread-affine (see crbug.com/1012875). THREAD_CHECKER(thread_checker_); - base::WeakPtrFactory<SysmemBufferWriterQueue> weak_factory_{this}; - - DISALLOW_COPY_AND_ASSIGN(SysmemBufferWriterQueue); + base::WeakPtrFactory<VmoBufferWriterQueue> weak_factory_{this}; }; } // namespace media -#endif // MEDIA_FUCHSIA_COMMON_SYSMEM_BUFFER_WRITER_QUEUE_H_ +#endif // MEDIA_FUCHSIA_COMMON_VMO_BUFFER_WRITER_QUEUE_H_ diff --git a/chromium/media/gpu/BUILD.gn b/chromium/media/gpu/BUILD.gn index 9e5be7d3d5f..4fba7f3731e 100644 --- a/chromium/media/gpu/BUILD.gn +++ b/chromium/media/gpu/BUILD.gn @@ -222,6 +222,7 @@ component("gpu") { ] public_deps += [ "//media/base/win:media_foundation_util" ] deps += [ + "//gpu/ipc/common:common", "//media/base/win:hresult_status_helper", "//media/parsers", "//third_party/angle:includes", diff --git a/chromium/media/gpu/android/android_video_encode_accelerator.cc b/chromium/media/gpu/android/android_video_encode_accelerator.cc index a2e21c0273d..f5b1408bd2b 100644 --- a/chromium/media/gpu/android/android_video_encode_accelerator.cc +++ b/chromium/media/gpu/android/android_video_encode_accelerator.cc @@ -145,7 +145,7 @@ bool AndroidVideoEncodeAccelerator::Initialize(const Config& config, DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(client); - client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); + client_ptr_factory_ = std::make_unique<base::WeakPtrFactory<Client>>(client); if (config.input_format != PIXEL_FORMAT_I420) { DLOG(ERROR) << "Unexpected combo: " << config.input_format << ", " diff --git a/chromium/media/gpu/android/android_video_surface_chooser.h b/chromium/media/gpu/android/android_video_surface_chooser.h index 3b88a20655e..77ef846d4f2 100644 --- a/chromium/media/gpu/android/android_video_surface_chooser.h +++ b/chromium/media/gpu/android/android_video_surface_chooser.h @@ -8,10 +8,10 @@ #include "base/bind.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "media/base/android/android_overlay.h" #include "media/base/video_transformation.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" namespace media { @@ -83,7 +83,7 @@ class MEDIA_GPU_EXPORT AndroidVideoSurfaceChooser { // Updates the current state and makes a new surface choice with the new // state. If |new_factory| is empty, the factory is left as-is. Otherwise, // the factory is updated to |*new_factory|. - virtual void UpdateState(base::Optional<AndroidOverlayFactoryCB> new_factory, + virtual void UpdateState(absl::optional<AndroidOverlayFactoryCB> new_factory, const State& new_state) = 0; private: diff --git a/chromium/media/gpu/android/android_video_surface_chooser_impl.cc b/chromium/media/gpu/android/android_video_surface_chooser_impl.cc index fb0f8010f23..dc562f083f4 100644 --- a/chromium/media/gpu/android/android_video_surface_chooser_impl.cc +++ b/chromium/media/gpu/android/android_video_surface_chooser_impl.cc @@ -35,7 +35,7 @@ void AndroidVideoSurfaceChooserImpl::SetClientCallbacks( } void AndroidVideoSurfaceChooserImpl::UpdateState( - base::Optional<AndroidOverlayFactoryCB> new_factory, + absl::optional<AndroidOverlayFactoryCB> new_factory, const State& new_state) { DCHECK(use_overlay_cb_); bool entered_fullscreen = diff --git a/chromium/media/gpu/android/android_video_surface_chooser_impl.h b/chromium/media/gpu/android/android_video_surface_chooser_impl.h index 84f5f486f1c..a23aad8cd51 100644 --- a/chromium/media/gpu/android/android_video_surface_chooser_impl.h +++ b/chromium/media/gpu/android/android_video_surface_chooser_impl.h @@ -31,7 +31,7 @@ class MEDIA_GPU_EXPORT AndroidVideoSurfaceChooserImpl // AndroidVideoSurfaceChooser void SetClientCallbacks(UseOverlayCB use_overlay_cb, UseTextureOwnerCB use_texture_owner_cb) override; - void UpdateState(base::Optional<AndroidOverlayFactoryCB> new_factory, + void UpdateState(absl::optional<AndroidOverlayFactoryCB> new_factory, const State& new_state) override; private: diff --git a/chromium/media/gpu/android/android_video_surface_chooser_impl_unittest.cc b/chromium/media/gpu/android/android_video_surface_chooser_impl_unittest.cc index d3de47e086c..9bd5f3a60b9 100644 --- a/chromium/media/gpu/android/android_video_surface_chooser_impl_unittest.cc +++ b/chromium/media/gpu/android/android_video_surface_chooser_impl_unittest.cc @@ -141,7 +141,7 @@ class AndroidVideoSurfaceChooserImplTest base::BindRepeating(&MockClient::UseTextureOwner, base::Unretained(&client_))); chooser_->UpdateState( - factory ? base::make_optional(std::move(factory)) : base::nullopt, + factory ? absl::make_optional(std::move(factory)) : absl::nullopt, chooser_state_); } @@ -359,7 +359,7 @@ TEST_F(AndroidVideoSurfaceChooserImplTest, // Note that if it enforces a delay here before retrying, that might be okay // too. For now, we assume that it doesn't. EXPECT_CALL(*this, MockOnOverlayCreated()); - chooser_->UpdateState(base::Optional<AndroidOverlayFactoryCB>(), + chooser_->UpdateState(absl::optional<AndroidOverlayFactoryCB>(), chooser_state_); } @@ -391,7 +391,7 @@ TEST_F(AndroidVideoSurfaceChooserImplTest, AlwaysUseTextureOwner) { // instead. chooser_state_.always_use_texture_owner = true; EXPECT_CALL(client_, UseTextureOwner()); - chooser_->UpdateState(base::nullopt, chooser_state_); + chooser_->UpdateState(absl::nullopt, chooser_state_); } TEST_P(AndroidVideoSurfaceChooserImplTest, OverlayIsUsedOrNotBasedOnState) { diff --git a/chromium/media/gpu/android/codec_image.cc b/chromium/media/gpu/android/codec_image.cc index 3721ceb5f8e..f176cad8c3d 100644 --- a/chromium/media/gpu/android/codec_image.cc +++ b/chromium/media/gpu/android/codec_image.cc @@ -84,17 +84,24 @@ bool CodecImage::CopyTexImage(unsigned target) { if (!output_buffer_renderer_) return true; - GLint bound_service_id = 0; - glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); - // The currently bound texture should be the texture owner's texture. - if (bound_service_id != - static_cast<GLint>( - output_buffer_renderer_->texture_owner()->GetTextureId())) + GLint texture_id = 0; + glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id); + + // CopyTexImage will only be called for TextureOwner's SurfaceTexture + // implementation which binds texture to TextureOwner's texture_id on update. + DCHECK(output_buffer_renderer_->texture_owner()->binds_texture_on_update()); + if (texture_id > 0 && + static_cast<unsigned>(texture_id) != + output_buffer_renderer_->texture_owner()->GetTextureId()) { return false; + } - + // On some devices GL_TEXTURE_BINDING_EXTERNAL_OES is not supported as + // glGetIntegerv() parameter. In this case the value of |texture_id| will be + // zero and we assume that it is properly bound to TextureOwner's texture id. output_buffer_renderer_->RenderToTextureOwnerFrontBuffer( - BindingsMode::kEnsureTexImageBound); + BindingsMode::kEnsureTexImageBound, + output_buffer_renderer_->texture_owner()->GetTextureId()); return true; } @@ -168,8 +175,9 @@ bool CodecImage::IsUsingGpuMemory() const { return output_buffer_renderer_->was_tex_image_bound(); } -void CodecImage::UpdateAndBindTexImage() { - RenderToTextureOwnerFrontBuffer(BindingsMode::kEnsureTexImageBound); +void CodecImage::UpdateAndBindTexImage(GLuint service_id) { + RenderToTextureOwnerFrontBuffer(BindingsMode::kEnsureTexImageBound, + service_id); } bool CodecImage::HasTextureOwner() const { @@ -193,11 +201,12 @@ bool CodecImage::RenderToTextureOwnerBackBuffer() { return output_buffer_renderer_->RenderToTextureOwnerBackBuffer(); } -bool CodecImage::RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode) { +bool CodecImage::RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode, + GLuint service_id) { if (!output_buffer_renderer_) return false; - return output_buffer_renderer_->RenderToTextureOwnerFrontBuffer( - bindings_mode); + return output_buffer_renderer_->RenderToTextureOwnerFrontBuffer(bindings_mode, + service_id); } bool CodecImage::RenderToOverlay() { @@ -206,6 +215,12 @@ bool CodecImage::RenderToOverlay() { return output_buffer_renderer_->RenderToOverlay(); } +bool CodecImage::TextureOwnerBindsTextureOnUpdate() { + if (!output_buffer_renderer_) + return false; + return output_buffer_renderer_->texture_owner()->binds_texture_on_update(); +} + void CodecImage::ReleaseCodecBuffer() { output_buffer_renderer_.reset(); } @@ -219,7 +234,11 @@ CodecImage::GetAHardwareBuffer() { if (!output_buffer_renderer_) return nullptr; - RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestoreIfBound); + // Using BindingsMode::kDontRestoreIfBound here since we do not want to bind + // the image. We just want to get the AHardwareBuffer from the latest image. + // Hence pass service_id as 0. + RenderToTextureOwnerFrontBuffer(BindingsMode::kDontRestoreIfBound, + 0 /* service_id */); return output_buffer_renderer_->texture_owner()->GetAHardwareBuffer(); } diff --git a/chromium/media/gpu/android/codec_image.h b/chromium/media/gpu/android/codec_image.h index d71cda8f3a4..531f0d664ba 100644 --- a/chromium/media/gpu/android/codec_image.h +++ b/chromium/media/gpu/android/codec_image.h @@ -99,13 +99,14 @@ class MEDIA_GPU_EXPORT CodecImage // gpu::StreamTextureSharedImageInterface implementation. void ReleaseResources() override; bool IsUsingGpuMemory() const override; - void UpdateAndBindTexImage() override; + void UpdateAndBindTexImage(GLuint service_id) override; bool HasTextureOwner() const override; gpu::TextureBase* GetTextureBase() const override; void NotifyOverlayPromotion(bool promotion, const gfx::Rect& bounds) override; // Renders this image to the overlay. Returns true if the buffer is in the // overlay front buffer. Returns false if the buffer was invalidated. bool RenderToOverlay() override; + bool TextureOwnerBindsTextureOnUpdate() override; // Whether the codec buffer has been rendered to the front buffer. bool was_rendered_to_front_buffer() const { @@ -156,7 +157,12 @@ class MEDIA_GPU_EXPORT CodecImage // Renders this image to the texture owner front buffer by first rendering // it to the back buffer if it's not already there, and then waiting for the // frame available event before calling UpdateTexImage(). - bool RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode); + // Also bind the latest image + // to the provided |service_id| if TextureOwner does not binds texture on + // update. If |bindings_mode| is other than kEnsureTexImageBound, then + // |service_id| is not required. + bool RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode, + GLuint service_id); // Whether this image is texture_owner or overlay backed. bool is_texture_owner_backed_ = false; diff --git a/chromium/media/gpu/android/codec_image_group.h b/chromium/media/gpu/android/codec_image_group.h index 9eda7b27e99..0b27493e908 100644 --- a/chromium/media/gpu/android/codec_image_group.h +++ b/chromium/media/gpu/android/codec_image_group.h @@ -74,4 +74,4 @@ class MEDIA_GPU_EXPORT CodecImageGroup } // namespace media -#endif // MEDIA_GPU_ANDROID_CODEC_IMAGE_H_ +#endif // MEDIA_GPU_ANDROID_CODEC_IMAGE_GROUP_H_ diff --git a/chromium/media/gpu/android/codec_image_unittest.cc b/chromium/media/gpu/android/codec_image_unittest.cc index 29a09b3989d..bdc1676a7ff 100644 --- a/chromium/media/gpu/android/codec_image_unittest.cc +++ b/chromium/media/gpu/android/codec_image_unittest.cc @@ -207,20 +207,6 @@ TEST_F(CodecImageTest, CopyTexImageTriggersFrontBufferRendering) { ASSERT_TRUE(i->was_rendered_to_front_buffer()); } -TEST_F(CodecImageTestExplicitBind, CopyTexImageTriggersFrontBufferRendering) { - auto i = NewImage(kTextureOwner); - // Verify that the release comes before the wait. - InSequence s; - EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true)); - EXPECT_CALL(*codec_buffer_wait_coordinator_, WaitForFrameAvailable()); - EXPECT_CALL(*codec_buffer_wait_coordinator_->texture_owner(), - UpdateTexImage()); - EXPECT_CALL(*codec_buffer_wait_coordinator_->texture_owner(), - EnsureTexImageBound()); - i->CopyTexImage(GL_TEXTURE_EXTERNAL_OES); - ASSERT_TRUE(i->was_rendered_to_front_buffer()); -} - TEST_F(CodecImageTest, ScheduleOverlayPlaneTriggersFrontBufferRendering) { auto i = NewImage(kOverlay); EXPECT_CALL(*codec_, ReleaseOutputBuffer(_, true)); @@ -380,7 +366,8 @@ TEST_F(CodecImageTest, RenderAfterUnusedDoesntCrash) { i->NotifyUnused(); EXPECT_FALSE(i->RenderToTextureOwnerBackBuffer()); EXPECT_FALSE(i->RenderToTextureOwnerFrontBuffer( - CodecImage::BindingsMode::kEnsureTexImageBound)); + CodecImage::BindingsMode::kEnsureTexImageBound, + codec_buffer_wait_coordinator_->texture_owner()->GetTextureId())); } TEST_F(CodecImageTest, CodedSizeVsVisibleSize) { diff --git a/chromium/media/gpu/android/codec_output_buffer_renderer.cc b/chromium/media/gpu/android/codec_output_buffer_renderer.cc index b327de7c161..00cba42ab2a 100644 --- a/chromium/media/gpu/android/codec_output_buffer_renderer.cc +++ b/chromium/media/gpu/android/codec_output_buffer_renderer.cc @@ -7,13 +7,14 @@ #include "base/android/scoped_hardware_buffer_fence_sync.h" #include "base/callback_helpers.h" -#include "base/optional.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" #include "gpu/command_buffer/service/texture_manager.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gl/gl_context.h" #include "ui/gl/scoped_make_current.h" namespace media { + namespace { // Makes |texture_owner|'s context current if it isn't already. @@ -38,19 +39,6 @@ std::unique_ptr<ui::ScopedMakeCurrent> MakeCurrentIfNeeded( return scoped_current; } -class ScopedRestoreTextureBinding { - public: - ScopedRestoreTextureBinding() { - glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id_); - } - ~ScopedRestoreTextureBinding() { - glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id_); - } - - private: - GLint bound_service_id_; -}; - } // namespace CodecOutputBufferRenderer::CodecOutputBufferRenderer( @@ -93,7 +81,8 @@ bool CodecOutputBufferRenderer::RenderToTextureOwnerBackBuffer() { } bool CodecOutputBufferRenderer::RenderToTextureOwnerFrontBuffer( - BindingsMode bindings_mode) { + BindingsMode bindings_mode, + GLuint service_id) { // Normally, we should have a wait coordinator if we're called. However, if // the renderer is torn down (either VideoFrameSubmitter or the whole process) // before we get returns back from viz, then we can be notified that we're @@ -103,33 +92,33 @@ bool CodecOutputBufferRenderer::RenderToTextureOwnerFrontBuffer( return false; if (phase_ == Phase::kInFrontBuffer) { - EnsureBoundIfNeeded(bindings_mode); + EnsureBoundIfNeeded(bindings_mode, service_id); return true; } if (phase_ == Phase::kInvalidated) return false; std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current; + absl::optional<gpu::ScopedRestoreTextureBinding> scoped_restore_texture; - // If the texture_owner() binds the texture while doing the texture update - // (UpdateTexImage), like in SurfaceTexture case, then only make the context - // current. For AImageReader, since we only acquire the latest image from it - // during the texture update process, there is no need to make it's context - // current. if (codec_buffer_wait_coordinator_->texture_owner() ->binds_texture_on_update()) { + // If the texture_owner() binds the texture while doing the texture update + // (UpdateTexImage), like in SurfaceTexture case, then make sure that the + // texture owner's context is made current. This is because the texture + // which will be bound was generated on TextureOwner's context. + // For AImageReader case, the texture which will be bound will not + // necessarily be TextureOwner's texture and hence caller is responsible to + // handle making correct context current before binding the texture. scoped_make_current = MakeCurrentIfNeeded( codec_buffer_wait_coordinator_->texture_owner().get()); - } - // If updating the image will implicitly update the texture bindings then - // restore if requested or the update needed a context switch. - base::Optional<ScopedRestoreTextureBinding> scoped_restore_texture; - if (codec_buffer_wait_coordinator_->texture_owner() - ->binds_texture_on_update() && - (bindings_mode == BindingsMode::kRestoreIfBound || - !!scoped_make_current)) { - scoped_restore_texture.emplace(); + // If updating the image will implicitly update the texture bindings then + // restore if requested or the update needed a context switch. + if (bindings_mode == BindingsMode::kRestoreIfBound || + !!scoped_make_current) { + scoped_restore_texture.emplace(); + } } // Render it to the back buffer if it's not already there. @@ -157,21 +146,30 @@ bool CodecOutputBufferRenderer::RenderToTextureOwnerFrontBuffer( codec_buffer_wait_coordinator_->WaitForFrameAvailable(); codec_buffer_wait_coordinator_->texture_owner()->UpdateTexImage(); - EnsureBoundIfNeeded(bindings_mode); + EnsureBoundIfNeeded(bindings_mode, service_id); return true; } -void CodecOutputBufferRenderer::EnsureBoundIfNeeded(BindingsMode mode) { +void CodecOutputBufferRenderer::EnsureBoundIfNeeded(BindingsMode mode, + GLuint service_id) { DCHECK(codec_buffer_wait_coordinator_); if (codec_buffer_wait_coordinator_->texture_owner() ->binds_texture_on_update()) { + if (mode == BindingsMode::kEnsureTexImageBound) { + DCHECK_EQ( + service_id, + codec_buffer_wait_coordinator_->texture_owner()->GetTextureId()); + } was_tex_image_bound_ = true; return; } if (mode != BindingsMode::kEnsureTexImageBound) return; - codec_buffer_wait_coordinator_->texture_owner()->EnsureTexImageBound(); + + DCHECK_GT(service_id, 0u); + codec_buffer_wait_coordinator_->texture_owner()->EnsureTexImageBound( + service_id); was_tex_image_bound_ = true; } @@ -191,9 +189,11 @@ bool CodecOutputBufferRenderer::RenderToOverlay() { bool CodecOutputBufferRenderer::RenderToFrontBuffer() { // This code is used to trigger early rendering of the image before it is used - // for compositing, there is no need to bind the image. + // for compositing, there is no need to bind the image. Hence pass texture + // service_id as 0. return codec_buffer_wait_coordinator_ - ? RenderToTextureOwnerFrontBuffer(BindingsMode::kRestoreIfBound) + ? RenderToTextureOwnerFrontBuffer(BindingsMode::kRestoreIfBound, + 0 /* service_id */) : RenderToOverlay(); } diff --git a/chromium/media/gpu/android/codec_output_buffer_renderer.h b/chromium/media/gpu/android/codec_output_buffer_renderer.h index d809960aae0..e8c23774edc 100644 --- a/chromium/media/gpu/android/codec_output_buffer_renderer.h +++ b/chromium/media/gpu/android/codec_output_buffer_renderer.h @@ -39,7 +39,11 @@ class MEDIA_GPU_EXPORT CodecOutputBufferRenderer { // Renders this image to the texture owner front buffer by first rendering // it to the back buffer if it's not already there, and then waiting for the // frame available event before calling UpdateTexImage(). - bool RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode); + // Also bind the latest imagecto the provided |service_id| if TextureOwner + // does not binds texture on update. If |bindings_mode| is other than + // kEnsureTexImageBound, then |service_id| is not required. + bool RenderToTextureOwnerFrontBuffer(BindingsMode bindings_mode, + GLuint service_id); // Renders this image to the front buffer of its backing surface. // Returns true if the buffer is in the front buffer. Returns false if the @@ -80,7 +84,11 @@ class MEDIA_GPU_EXPORT CodecOutputBufferRenderer { // kInFrontBuffer and kInvalidated are terminal. enum class Phase { kInCodec, kInBackBuffer, kInFrontBuffer, kInvalidated }; - void EnsureBoundIfNeeded(BindingsMode mode); + // Ensure that the latest image is bound to the texture |service_id| if + // TextureOwner does not binds texture on update. If TextureOwner binds + // texture on update, then it will always be bound to the TextureOwners + // texture and |service_id| will be ignored. + void EnsureBoundIfNeeded(BindingsMode mode, GLuint service_id); void set_phase_for_testing(Phase phase) { phase_ = phase; } @@ -98,4 +106,4 @@ class MEDIA_GPU_EXPORT CodecOutputBufferRenderer { }; } // namespace media -#endif // MEDIA_GPU_ANDROID_CODEC_OUTPUT_BUFFER_RENDERER_H +#endif // MEDIA_GPU_ANDROID_CODEC_OUTPUT_BUFFER_RENDERER_H_ diff --git a/chromium/media/gpu/android/codec_wrapper.cc b/chromium/media/gpu/android/codec_wrapper.cc index be7a5ddd7a4..8083f4c5381 100644 --- a/chromium/media/gpu/android/codec_wrapper.cc +++ b/chromium/media/gpu/android/codec_wrapper.cc @@ -12,10 +12,10 @@ #include "base/bind.h" #include "base/memory/ptr_util.h" -#include "base/optional.h" #include "base/stl_util.h" #include "media/base/android/media_codec_util.h" #include "media/base/bind_to_current_loop.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -82,7 +82,7 @@ class CodecWrapperImpl : public base::RefCountedThreadSafe<CodecWrapperImpl> { // An input buffer that was dequeued but subsequently rejected from // QueueInputBuffer() because the codec didn't have the crypto key. We // maintain ownership of it and reuse it next time. - base::Optional<int> owned_input_buffer_; + absl::optional<int> owned_input_buffer_; // The current output size. Updated when DequeueOutputBuffer() reports // OUTPUT_FORMAT_CHANGED. diff --git a/chromium/media/gpu/android/direct_shared_image_video_provider.cc b/chromium/media/gpu/android/direct_shared_image_video_provider.cc index 11efbbe4db0..8fcc9ca3bc2 100644 --- a/chromium/media/gpu/android/direct_shared_image_video_provider.cc +++ b/chromium/media/gpu/android/direct_shared_image_video_provider.cc @@ -71,10 +71,8 @@ void DirectSharedImageVideoProvider::Initialize(GpuInitCB gpu_init_cb) { .WithArgs(std::move(gpu_init_cb)); } -void DirectSharedImageVideoProvider::RequestImage( - ImageReadyCB cb, - const ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner) { +void DirectSharedImageVideoProvider::RequestImage(ImageReadyCB cb, + const ImageSpec& spec) { // It's unclear that we should handle the image group, but since CodecImages // have to be registered on it, we do. If the CodecImage is ever re-used, // then part of that re-use would be to call the (then mis-named) @@ -87,8 +85,7 @@ void DirectSharedImageVideoProvider::RequestImage( // Note: `cb` is only run on successful creation, so this does not use // `AsyncCall()` + `Then()` to chain the callbacks. gpu_factory_.AsyncCall(&GpuSharedImageVideoFactory::CreateImage) - .WithArgs(BindToCurrentLoop(std::move(cb)), spec, - std::move(texture_owner)); + .WithArgs(BindToCurrentLoop(std::move(cb)), spec); } GpuSharedImageVideoFactory::GpuSharedImageVideoFactory( @@ -113,8 +110,6 @@ void GpuSharedImageVideoFactory::Initialize( return; } - decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context()); - gpu::ContextResult result; auto shared_context = GetSharedContext(stub_, &result); if (!shared_context) { @@ -145,8 +140,7 @@ void GpuSharedImageVideoFactory::Initialize( void GpuSharedImageVideoFactory::CreateImage( FactoryImageReadyCB image_ready_cb, - const SharedImageVideoProvider::ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner) { + const SharedImageVideoProvider::ImageSpec& spec) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Generate a shared image mailbox. @@ -155,8 +149,7 @@ void GpuSharedImageVideoFactory::CreateImage( TRACE_EVENT0("media", "GpuSharedImageVideoFactory::CreateVideoFrame"); - if (!CreateImageInternal(spec, std::move(texture_owner), mailbox, - codec_image)) { + if (!CreateImageInternal(spec, mailbox, codec_image)) { return; } @@ -192,7 +185,6 @@ void GpuSharedImageVideoFactory::CreateImage( bool GpuSharedImageVideoFactory::CreateImageInternal( const SharedImageVideoProvider::ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner, gpu::Mailbox mailbox, scoped_refptr<CodecImage> image) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -205,28 +197,6 @@ bool GpuSharedImageVideoFactory::CreateImageInternal( const auto& coded_size = spec.coded_size; - // Create a Texture and a CodecImage to back it. - // TODO(liberato): Once legacy mailbox support is removed, we don't need to - // create this texture. So, we won't need |texture_owner| either. - std::unique_ptr<AbstractTexture> texture = decoder_helper_->CreateTexture( - GL_TEXTURE_EXTERNAL_OES, GL_RGBA, coded_size.width(), coded_size.height(), - GL_RGBA, GL_UNSIGNED_BYTE); - - // Attach the image to the texture. - // Either way, we expect this to be UNBOUND (i.e., decoder-managed). For - // overlays, BindTexImage will return true, causing it to transition to the - // BOUND state, and thus receive ScheduleOverlayPlane calls. For TextureOwner - // backed images, BindTexImage will return false, and CopyTexImage will be - // tried next. - // TODO(liberato): consider not binding this as a StreamTextureImage if we're - // using an overlay. There's no advantage. We'd likely want to create (and - // initialize to a 1x1 texture) a 2D texture above in that case, in case - // somebody tries to sample from it. Be sure that promotion hints still - // work properly, though -- they might require a stream texture image. - GLuint texture_owner_service_id = - texture_owner ? texture_owner->GetTextureId() : 0; - texture->BindStreamTextureImage(image.get(), texture_owner_service_id); - gpu::ContextResult result; auto shared_context = GetSharedContext(stub_, &result); if (!shared_context) { @@ -244,8 +214,7 @@ bool GpuSharedImageVideoFactory::CreateImageInternal( auto shared_image = std::make_unique<gpu::SharedImageVideo>( mailbox, coded_size, gfx::ColorSpace::CreateSRGB(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, std::move(image), - std::move(texture), std::move(shared_context), - false /* is_thread_safe */); + std::move(shared_context), false /* is_thread_safe */); // Register it with shared image mailbox as well as legacy mailbox. This // keeps |shared_image| around until its destruction cb is called. @@ -253,7 +222,7 @@ bool GpuSharedImageVideoFactory::CreateImageInternal( // mailbox. DCHECK(stub_->channel()->gpu_channel_manager()->shared_image_manager()); stub_->channel()->shared_image_stub()->factory()->RegisterBacking( - std::move(shared_image), /* legacy_mailbox */ true); + std::move(shared_image), /*allow_legacy_mailbox=*/false); return true; } @@ -262,7 +231,6 @@ void GpuSharedImageVideoFactory::OnWillDestroyStub(bool have_context) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(stub_); stub_ = nullptr; - decoder_helper_ = nullptr; } } // namespace media diff --git a/chromium/media/gpu/android/direct_shared_image_video_provider.h b/chromium/media/gpu/android/direct_shared_image_video_provider.h index e140b6cad02..2499058a255 100644 --- a/chromium/media/gpu/android/direct_shared_image_video_provider.h +++ b/chromium/media/gpu/android/direct_shared_image_video_provider.h @@ -5,10 +5,7 @@ #ifndef MEDIA_GPU_ANDROID_DIRECT_SHARED_IMAGE_VIDEO_PROVIDER_H_ #define MEDIA_GPU_ANDROID_DIRECT_SHARED_IMAGE_VIDEO_PROVIDER_H_ -#include <memory> - #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "base/threading/sequence_bound.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" @@ -24,6 +21,7 @@ #include "media/gpu/android/video_frame_factory.h" #include "media/gpu/gles2_decoder_helper.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gl/gl_bindings.h" namespace media { @@ -41,9 +39,7 @@ class MEDIA_GPU_EXPORT DirectSharedImageVideoProvider // SharedImageVideoProvider void Initialize(GpuInitCB get_stub_cb) override; - void RequestImage(ImageReadyCB cb, - const ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner) override; + void RequestImage(ImageReadyCB cb, const ImageSpec& spec) override; private: base::SequenceBound<GpuSharedImageVideoFactory> gpu_factory_; @@ -79,23 +75,17 @@ class GpuSharedImageVideoFactory // create the per-frame texture. All of that is only needed for legacy // mailbox support, where we have to have one texture per CodecImage. void CreateImage(FactoryImageReadyCB cb, - const SharedImageVideoProvider::ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner); + const SharedImageVideoProvider::ImageSpec& spec); private: // Creates a SharedImage for |mailbox|, and returns success or failure. bool CreateImageInternal(const SharedImageVideoProvider::ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner, gpu::Mailbox mailbox, scoped_refptr<CodecImage> image); void OnWillDestroyStub(bool have_context) override; gpu::CommandBufferStub* stub_ = nullptr; - - // A helper for creating textures. Only valid while |stub_| is valid. - std::unique_ptr<GLES2DecoderHelper> decoder_helper_; - bool is_vulkan_ = false; THREAD_CHECKER(thread_checker_); diff --git a/chromium/media/gpu/android/frame_info_helper.cc b/chromium/media/gpu/android/frame_info_helper.cc index 6d4b20935e0..22950e69376 100644 --- a/chromium/media/gpu/android/frame_info_helper.cc +++ b/chromium/media/gpu/android/frame_info_helper.cc @@ -71,16 +71,17 @@ class FrameInfoHelperImpl : public FrameInfoHelper { void GetFrameInfoImpl( std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>, - base::Optional<FrameInfo>)> cb) { + absl::optional<FrameInfo>)> cb) { DCHECK(buffer_renderer); auto texture_owner = buffer_renderer->texture_owner(); DCHECK(texture_owner); - base::Optional<FrameInfo> info; + absl::optional<FrameInfo> info; if (buffer_renderer->RenderToTextureOwnerFrontBuffer( - CodecOutputBufferRenderer::BindingsMode::kDontRestoreIfBound)) { + CodecOutputBufferRenderer::BindingsMode::kDontRestoreIfBound, + 0)) { gfx::Size coded_size; gfx::Rect visible_rect; if (texture_owner->GetCodedSizeAndVisibleRect( @@ -98,7 +99,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper { void GetFrameInfo( std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, base::OnceCallback<void(std::unique_ptr<CodecOutputBufferRenderer>, - base::Optional<FrameInfo>)> cb) { + absl::optional<FrameInfo>)> cb) { DCHECK(buffer_renderer); auto texture_owner = buffer_renderer->texture_owner(); @@ -112,12 +113,12 @@ class FrameInfoHelperImpl : public FrameInfoHelper { private: // Gets YCbCrInfo from last rendered frame. - base::Optional<gpu::VulkanYCbCrInfo> GetYCbCrInfo( + absl::optional<gpu::VulkanYCbCrInfo> GetYCbCrInfo( gpu::TextureOwner* texture_owner) { gpu::ContextResult result; if (!stub_) - return base::nullopt; + return absl::nullopt; auto shared_context = stub_->channel()->gpu_channel_manager()->GetSharedContextState( @@ -125,7 +126,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper { auto context_provider = (result == gpu::ContextResult::kSuccess) ? shared_context : nullptr; if (!context_provider) - return base::nullopt; + return absl::nullopt; return gpu::SharedImageVideo::GetYcbcrInfo(texture_owner, context_provider); @@ -144,7 +145,7 @@ class FrameInfoHelperImpl : public FrameInfoHelper { void OnFrameInfoReady( std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer, - base::Optional<FrameInfo> frame_info) { + absl::optional<FrameInfo> frame_info) { DCHECK(buffer_renderer); DCHECK(!requests_.empty()); diff --git a/chromium/media/gpu/android/frame_info_helper.h b/chromium/media/gpu/android/frame_info_helper.h index 1f60bceb094..f4be1c76efd 100644 --- a/chromium/media/gpu/android/frame_info_helper.h +++ b/chromium/media/gpu/android/frame_info_helper.h @@ -5,9 +5,9 @@ #ifndef MEDIA_GPU_ANDROID_FRAME_INFO_HELPER_H_ #define MEDIA_GPU_ANDROID_FRAME_INFO_HELPER_H_ -#include "base/optional.h" #include "media/gpu/android/shared_image_video_provider.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { class CodecOutputBufferRenderer; @@ -25,7 +25,7 @@ class MEDIA_GPU_EXPORT FrameInfoHelper { gfx::Size coded_size; gfx::Rect visible_rect; - base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info; + absl::optional<gpu::VulkanYCbCrInfo> ycbcr_info; }; using FrameInfoReadyCB = diff --git a/chromium/media/gpu/android/maybe_render_early_manager.h b/chromium/media/gpu/android/maybe_render_early_manager.h index de26f8e23df..5a4c2a7ceb9 100644 --- a/chromium/media/gpu/android/maybe_render_early_manager.h +++ b/chromium/media/gpu/android/maybe_render_early_manager.h @@ -9,10 +9,10 @@ #include <vector> #include "base/memory/scoped_refptr.h" -#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "media/gpu/android/codec_image.h" // For CodecImage::BlockingMode #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { class CodecImageHolder; @@ -61,7 +61,7 @@ void MEDIA_GPU_EXPORT MaybeRenderEarly(std::vector<Image*>* image_vector_ptr) { return; // Find the latest image rendered to the front buffer (if any). - base::Optional<size_t> front_buffer_index; + absl::optional<size_t> front_buffer_index; for (int i = images.size() - 1; i >= 0; --i) { if (images[i]->was_rendered_to_front_buffer()) { front_buffer_index = i; diff --git a/chromium/media/gpu/android/media_codec_video_decoder.cc b/chromium/media/gpu/android/media_codec_video_decoder.cc index be37e450fbd..10c7deb0e10 100644 --- a/chromium/media/gpu/android/media_codec_video_decoder.cc +++ b/chromium/media/gpu/android/media_codec_video_decoder.cc @@ -564,8 +564,8 @@ void MediaCodecVideoDecoder::OnOverlayInfoChanged( surface_chooser_helper_.SetIsPersistentVideo( overlay_info_.is_persistent_video); surface_chooser_helper_.UpdateChooserState( - overlay_changed ? base::make_optional(CreateOverlayFactoryCb()) - : base::nullopt); + overlay_changed ? absl::make_optional(CreateOverlayFactoryCb()) + : absl::nullopt); } void MediaCodecVideoDecoder::OnSurfaceChosen( diff --git a/chromium/media/gpu/android/media_codec_video_decoder.h b/chromium/media/gpu/android/media_codec_video_decoder.h index 4b9d81a7821..6e7997ac53e 100644 --- a/chromium/media/gpu/android/media_codec_video_decoder.h +++ b/chromium/media/gpu/android/media_codec_video_decoder.h @@ -8,7 +8,6 @@ #include <vector> #include "base/containers/circular_deque.h" -#include "base/optional.h" #include "base/threading/thread_checker.h" #include "base/timer/elapsed_timer.h" #include "base/timer/timer.h" @@ -28,6 +27,7 @@ #include "media/gpu/android/surface_chooser_helper.h" #include "media/gpu/android/video_frame_factory.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -242,7 +242,7 @@ class MEDIA_GPU_EXPORT MediaCodecVideoDecoder final : public VideoDecoder { bool waiting_for_key_ = false; // The reason for the current drain operation if any. - base::Optional<DrainType> drain_type_; + absl::optional<DrainType> drain_type_; // The current reset cb if a Reset() is in progress. base::OnceClosure reset_cb_; diff --git a/chromium/media/gpu/android/mock_android_video_surface_chooser.cc b/chromium/media/gpu/android/mock_android_video_surface_chooser.cc index 35f701f1ab7..f490acf8834 100644 --- a/chromium/media/gpu/android/mock_android_video_surface_chooser.cc +++ b/chromium/media/gpu/android/mock_android_video_surface_chooser.cc @@ -18,7 +18,7 @@ void MockAndroidVideoSurfaceChooser::SetClientCallbacks( } void MockAndroidVideoSurfaceChooser::UpdateState( - base::Optional<AndroidOverlayFactoryCB> factory, + absl::optional<AndroidOverlayFactoryCB> factory, const State& new_state) { MockUpdateState(); if (factory) { diff --git a/chromium/media/gpu/android/mock_android_video_surface_chooser.h b/chromium/media/gpu/android/mock_android_video_surface_chooser.h index 24a2322f734..2f0fe248b00 100644 --- a/chromium/media/gpu/android/mock_android_video_surface_chooser.h +++ b/chromium/media/gpu/android/mock_android_video_surface_chooser.h @@ -28,7 +28,7 @@ class MockAndroidVideoSurfaceChooser : public AndroidVideoSurfaceChooser { void SetClientCallbacks(UseOverlayCB use_overlay_cb, UseTextureOwnerCB use_texture_owner_cb) override; - void UpdateState(base::Optional<AndroidOverlayFactoryCB> factory, + void UpdateState(absl::optional<AndroidOverlayFactoryCB> factory, const State& new_state) override; // Calls the corresponding callback to choose the surface. diff --git a/chromium/media/gpu/android/mock_shared_image_video_provider.cc b/chromium/media/gpu/android/mock_shared_image_video_provider.cc index c131f4ac8e5..ecde0e54d2a 100644 --- a/chromium/media/gpu/android/mock_shared_image_video_provider.cc +++ b/chromium/media/gpu/android/mock_shared_image_video_provider.cc @@ -8,11 +8,8 @@ namespace media { MockSharedImageVideoProvider::RequestImageArgs::RequestImageArgs( ImageReadyCB cb, - ImageSpec spec, - scoped_refptr<gpu::TextureOwner> texture_owner) - : cb_(std::move(cb)), - spec_(std::move(spec)), - texture_owner_(std::move(texture_owner)) {} + ImageSpec spec) + : cb_(std::move(cb)), spec_(std::move(spec)) {} MockSharedImageVideoProvider::RequestImageArgs::~RequestImageArgs() = default; diff --git a/chromium/media/gpu/android/mock_shared_image_video_provider.h b/chromium/media/gpu/android/mock_shared_image_video_provider.h index cd554aa2b46..4412dc95185 100644 --- a/chromium/media/gpu/android/mock_shared_image_video_provider.h +++ b/chromium/media/gpu/android/mock_shared_image_video_provider.h @@ -25,10 +25,8 @@ class MockSharedImageVideoProvider : public SharedImageVideoProvider { MOCK_METHOD1(Initialize_, void(GpuInitCB& gpu_init_cb)); - void RequestImage(ImageReadyCB cb, - const ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner) override { - requests_.emplace_back(std::move(cb), spec, std::move(texture_owner)); + void RequestImage(ImageReadyCB cb, const ImageSpec& spec) override { + requests_.emplace_back(std::move(cb), spec); MockRequestImage(); } @@ -59,13 +57,10 @@ class MockSharedImageVideoProvider : public SharedImageVideoProvider { // Most recent arguments to RequestImage. struct RequestImageArgs { - RequestImageArgs(ImageReadyCB cb, - ImageSpec spec, - scoped_refptr<gpu::TextureOwner> texture_owner); + RequestImageArgs(ImageReadyCB cb, ImageSpec spec); ~RequestImageArgs(); ImageReadyCB cb_; ImageSpec spec_; - scoped_refptr<gpu::TextureOwner> texture_owner_; }; std::list<RequestImageArgs> requests_; diff --git a/chromium/media/gpu/android/pooled_shared_image_video_provider.cc b/chromium/media/gpu/android/pooled_shared_image_video_provider.cc index a4b10ff30a7..b4e3d0a3171 100644 --- a/chromium/media/gpu/android/pooled_shared_image_video_provider.cc +++ b/chromium/media/gpu/android/pooled_shared_image_video_provider.cc @@ -52,10 +52,8 @@ void PooledSharedImageVideoProvider::Initialize(GpuInitCB gpu_init_cb) { provider_->Initialize(std::move(gpu_init_cb)); } -void PooledSharedImageVideoProvider::RequestImage( - ImageReadyCB cb, - const ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner) { +void PooledSharedImageVideoProvider::RequestImage(ImageReadyCB cb, + const ImageSpec& spec) { // See if the pool matches the requested spec. if (pool_spec_ != spec) { // Nope -- mark any outstanding images for destruction and start a new pool. @@ -106,7 +104,7 @@ void PooledSharedImageVideoProvider::RequestImage( auto ready_cb = base::BindOnce(&PooledSharedImageVideoProvider::OnImageCreated, weak_factory_.GetWeakPtr(), spec); - provider_->RequestImage(std::move(ready_cb), spec, std::move(texture_owner)); + provider_->RequestImage(std::move(ready_cb), spec); } void PooledSharedImageVideoProvider::OnImageCreated(ImageSpec spec, diff --git a/chromium/media/gpu/android/pooled_shared_image_video_provider.h b/chromium/media/gpu/android/pooled_shared_image_video_provider.h index a4d02393d3f..8f13b656d92 100644 --- a/chromium/media/gpu/android/pooled_shared_image_video_provider.h +++ b/chromium/media/gpu/android/pooled_shared_image_video_provider.h @@ -46,9 +46,7 @@ class MEDIA_GPU_EXPORT PooledSharedImageVideoProvider // SharedImageVideoProvider void Initialize(GpuInitCB gpu_init_cb) override; - void RequestImage(ImageReadyCB cb, - const ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner) override; + void RequestImage(ImageReadyCB cb, const ImageSpec& spec) override; private: friend class PooledSharedImageVideoProviderTest; diff --git a/chromium/media/gpu/android/pooled_shared_image_video_provider_unittest.cc b/chromium/media/gpu/android/pooled_shared_image_video_provider_unittest.cc index 174c8bb8c8b..0776d2b616a 100644 --- a/chromium/media/gpu/android/pooled_shared_image_video_provider_unittest.cc +++ b/chromium/media/gpu/android/pooled_shared_image_video_provider_unittest.cc @@ -10,7 +10,6 @@ #include "base/test/mock_callback.h" #include "base/test/task_environment.h" #include "base/threading/sequenced_task_runner_handle.h" -#include "gpu/command_buffer/service/abstract_texture_impl_shared_context_state.h" #include "gpu/ipc/common/command_buffer_id.h" #include "media/gpu/android/mock_shared_image_video_provider.h" #include "testing/gmock/include/gmock/gmock.h" @@ -70,7 +69,7 @@ class PooledSharedImageVideoProviderTest : public testing::Test { // |mock_provider_raw_|. Have |mock_provider_raw_| return an image, too. void RequestAndProvideImage(const SharedImageVideoProvider::ImageSpec& spec) { EXPECT_CALL(*mock_provider_raw_, MockRequestImage()).Times(1); - provider_->RequestImage(SaveImageRecordCB(), spec, texture_owner_); + provider_->RequestImage(SaveImageRecordCB(), spec); base::RunLoop().RunUntilIdle(); Mock::VerifyAndClearExpectations(mock_provider_raw_); mock_provider_raw_->ProvideOneRequestedImage(); @@ -155,7 +154,7 @@ TEST_F(PooledSharedImageVideoProviderTest, RequestImageReusesReturnedImages) { // Shouldn't call MockRequestImage a third time. EXPECT_CALL(*mock_provider_raw_, MockRequestImage()).Times(0); - provider_->RequestImage(SaveImageRecordCB(), spec, texture_owner_); + provider_->RequestImage(SaveImageRecordCB(), spec); base::RunLoop().RunUntilIdle(); EXPECT_EQ(image_records_.size(), 2u); } @@ -164,7 +163,7 @@ TEST_F(PooledSharedImageVideoProviderTest, DeletingProviderWithOutstandingImagesDoesntCrash) { // Destroying |provider_| with outstanding images shouldn't break anything. SharedImageVideoProvider::ImageSpec spec(gfx::Size(1, 1), 0u); - provider_->RequestImage(SaveImageRecordCB(), spec, texture_owner_); + provider_->RequestImage(SaveImageRecordCB(), spec); base::RunLoop().RunUntilIdle(); provider_.reset(); base::RunLoop().RunUntilIdle(); @@ -229,8 +228,8 @@ TEST_F(PooledSharedImageVideoProviderTest, InFlightSpecChangeProvidesImage) { // Request both images before providing either. EXPECT_CALL(*mock_provider_raw_, MockRequestImage()).Times(2); - provider_->RequestImage(SaveImageRecordCB(), spec_1, texture_owner_); - provider_->RequestImage(SaveImageRecordCB(), spec_2, texture_owner_); + provider_->RequestImage(SaveImageRecordCB(), spec_1); + provider_->RequestImage(SaveImageRecordCB(), spec_2); base::RunLoop().RunUntilIdle(); // Provide the |spec_1| image. Nothing should be released since it should diff --git a/chromium/media/gpu/android/promotion_hint_aggregator_impl.h b/chromium/media/gpu/android/promotion_hint_aggregator_impl.h index 9130800b34d..1d33c4cfa65 100644 --- a/chromium/media/gpu/android/promotion_hint_aggregator_impl.h +++ b/chromium/media/gpu/android/promotion_hint_aggregator_impl.h @@ -5,8 +5,6 @@ #ifndef MEDIA_GPU_ANDROID_PROMOTION_HINT_AGGREGATOR_IMPL_H_ #define MEDIA_GPU_ANDROID_PROMOTION_HINT_AGGREGATOR_IMPL_H_ -#include <memory> - #include "base/bind.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" diff --git a/chromium/media/gpu/android/shared_image_video_provider.h b/chromium/media/gpu/android/shared_image_video_provider.h index ffbac1331a5..87fa7ec8d2c 100644 --- a/chromium/media/gpu/android/shared_image_video_provider.h +++ b/chromium/media/gpu/android/shared_image_video_provider.h @@ -94,9 +94,7 @@ class MEDIA_GPU_EXPORT SharedImageVideoProvider { // Call |cb| when we have a shared image that matches |spec|. We may call // |cb| back before returning, or we might post it for later. - virtual void RequestImage(ImageReadyCB cb, - const ImageSpec& spec, - scoped_refptr<gpu::TextureOwner> texture_owner) = 0; + virtual void RequestImage(ImageReadyCB cb, const ImageSpec& spec) = 0; private: DISALLOW_COPY_AND_ASSIGN(SharedImageVideoProvider); diff --git a/chromium/media/gpu/android/surface_chooser_helper.cc b/chromium/media/gpu/android/surface_chooser_helper.cc index 2c858d090fb..36613fd5f51 100644 --- a/chromium/media/gpu/android/surface_chooser_helper.cc +++ b/chromium/media/gpu/android/surface_chooser_helper.cc @@ -100,7 +100,7 @@ void SurfaceChooserHelper::SetIsPersistentVideo(bool is_persistent_video) { } void SurfaceChooserHelper::UpdateChooserState( - base::Optional<AndroidOverlayFactoryCB> new_factory) { + absl::optional<AndroidOverlayFactoryCB> new_factory) { surface_chooser_->UpdateState(std::move(new_factory), surface_chooser_state_); } @@ -144,7 +144,7 @@ void SurfaceChooserHelper::NotifyPromotionHintAndUpdateChooser( if (update_state) { most_recent_chooser_retry_ = now; - UpdateChooserState(base::Optional<AndroidOverlayFactoryCB>()); + UpdateChooserState(absl::optional<AndroidOverlayFactoryCB>()); } } diff --git a/chromium/media/gpu/android/surface_chooser_helper.h b/chromium/media/gpu/android/surface_chooser_helper.h index a019d031e15..8f1f0ed407f 100644 --- a/chromium/media/gpu/android/surface_chooser_helper.h +++ b/chromium/media/gpu/android/surface_chooser_helper.h @@ -85,7 +85,7 @@ class MEDIA_GPU_EXPORT SurfaceChooserHelper { void SetIsPersistentVideo(bool is_persistent_video); // Update the chooser state using the given factory. - void UpdateChooserState(base::Optional<AndroidOverlayFactoryCB> new_factory); + void UpdateChooserState(absl::optional<AndroidOverlayFactoryCB> new_factory); // Notify us about a promotion hint. This will update the chooser state // if needed. diff --git a/chromium/media/gpu/android/surface_chooser_helper_unittest.cc b/chromium/media/gpu/android/surface_chooser_helper_unittest.cc index 353e9b0bfde..adb33255466 100644 --- a/chromium/media/gpu/android/surface_chooser_helper_unittest.cc +++ b/chromium/media/gpu/android/surface_chooser_helper_unittest.cc @@ -52,7 +52,7 @@ class SurfaceChooserHelperTest : public testing::Test { // Convenience function. void UpdateChooserState() { EXPECT_CALL(*chooser_, MockUpdateState()); - helper_->UpdateChooserState(base::Optional<AndroidOverlayFactoryCB>()); + helper_->UpdateChooserState(absl::optional<AndroidOverlayFactoryCB>()); } base::SimpleTestTickClock tick_clock_; diff --git a/chromium/media/gpu/android/video_frame_factory.h b/chromium/media/gpu/android/video_frame_factory.h index afc58cfe651..81c83bc2637 100644 --- a/chromium/media/gpu/android/video_frame_factory.h +++ b/chromium/media/gpu/android/video_frame_factory.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_ -#define MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_ +#ifndef MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_H_ +#define MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_H_ #include <memory> @@ -73,4 +73,4 @@ class MEDIA_GPU_EXPORT VideoFrameFactory { } // namespace media -#endif // MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_ +#endif // MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_H_ diff --git a/chromium/media/gpu/android/video_frame_factory_impl.cc b/chromium/media/gpu/android/video_frame_factory_impl.cc index 8be7a01fcb7..aae48f924ab 100644 --- a/chromium/media/gpu/android/video_frame_factory_impl.cc +++ b/chromium/media/gpu/android/video_frame_factory_impl.cc @@ -38,10 +38,10 @@ namespace { // (http://crbug.com/582170). This texture copy can be avoided if // AImageReader/AHardwareBuffer is supported and AImageReader // max size is not limited to 1 (crbug.com/1091945). -base::Optional<VideoFrameMetadata::CopyMode> GetVideoFrameCopyMode( +absl::optional<VideoFrameMetadata::CopyMode> GetVideoFrameCopyMode( bool enable_threaded_texture_mailboxes) { if (!enable_threaded_texture_mailboxes) - return base::nullopt; + return absl::nullopt; return features::IsWebViewZeroCopyVideoEnabled() ? VideoFrameMetadata::CopyMode::kCopyMailboxesOnly @@ -50,7 +50,7 @@ base::Optional<VideoFrameMetadata::CopyMode> GetVideoFrameCopyMode( gpu::TextureOwner::Mode GetTextureOwnerMode( VideoFrameFactory::OverlayMode overlay_mode, - const base::Optional<VideoFrameMetadata::CopyMode>& copy_mode) { + const absl::optional<VideoFrameMetadata::CopyMode>& copy_mode) { if (copy_mode == VideoFrameMetadata::kCopyMailboxesOnly) { DCHECK(features::IsWebViewZeroCopyVideoEnabled()); return gpu::TextureOwner::Mode::kAImageReaderInsecureMultithreaded; @@ -79,7 +79,7 @@ gpu::TextureOwner::Mode GetTextureOwnerMode( static void AllocateTextureOwnerOnGpuThread( VideoFrameFactory::InitCB init_cb, VideoFrameFactory::OverlayMode overlay_mode, - const base::Optional<VideoFrameMetadata::CopyMode>& copy_mode, + const absl::optional<VideoFrameMetadata::CopyMode>& copy_mode, scoped_refptr<gpu::SharedContextState> shared_context_state) { if (!shared_context_state) { std::move(init_cb).Run(nullptr); @@ -88,7 +88,7 @@ static void AllocateTextureOwnerOnGpuThread( std::move(init_cb).Run(gpu::TextureOwner::Create( gpu::TextureOwner::CreateTexture(shared_context_state), - GetTextureOwnerMode(overlay_mode, copy_mode))); + GetTextureOwnerMode(overlay_mode, copy_mode), shared_context_state)); } } // namespace @@ -202,8 +202,7 @@ void VideoFrameFactoryImpl::RequestImage( ImageWithInfoReadyCB image_ready_cb) { auto info_cb = base::BindOnce(&VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady, - weak_factory_.GetWeakPtr(), std::move(image_ready_cb), - codec_buffer_wait_coordinator_); + weak_factory_.GetWeakPtr(), std::move(image_ready_cb)); frame_info_helper_->GetFrameInfo(std::move(buffer_renderer), std::move(info_cb)); @@ -211,7 +210,6 @@ void VideoFrameFactoryImpl::RequestImage( void VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady( ImageWithInfoReadyCB image_ready_cb, - scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, FrameInfoHelper::FrameInfo frame_info) { // If we don't have output buffer here we can't rely on reply from @@ -237,11 +235,7 @@ void VideoFrameFactoryImpl::CreateVideoFrame_OnFrameInfoReady( auto cb = base::BindOnce(std::move(image_ready_cb), std::move(output_buffer_renderer), frame_info); - - auto texture_owner = codec_buffer_wait_coordinator - ? codec_buffer_wait_coordinator->texture_owner() - : nullptr; - image_provider_->RequestImage(std::move(cb), image_spec_, texture_owner); + image_provider_->RequestImage(std::move(cb), image_spec_); } // static @@ -254,7 +248,7 @@ void VideoFrameFactoryImpl::CreateVideoFrame_OnImageReady( PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb, VideoPixelFormat pixel_format, OverlayMode overlay_mode, - const base::Optional<VideoFrameMetadata::CopyMode>& copy_mode, + const absl::optional<VideoFrameMetadata::CopyMode>& copy_mode, scoped_refptr<base::SequencedTaskRunner> gpu_task_runner, std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, FrameInfoHelper::FrameInfo frame_info, diff --git a/chromium/media/gpu/android/video_frame_factory_impl.h b/chromium/media/gpu/android/video_frame_factory_impl.h index 6bf6ca6a5fc..ad0a0c722a5 100644 --- a/chromium/media/gpu/android/video_frame_factory_impl.h +++ b/chromium/media/gpu/android/video_frame_factory_impl.h @@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_IMPL_ -#define MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_IMPL_ +#ifndef MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_IMPL_H_ +#define MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_IMPL_H_ #include <memory> #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "gpu/config/gpu_preferences.h" #include "media/base/video_frame.h" @@ -20,6 +19,7 @@ #include "media/gpu/android/shared_image_video_provider.h" #include "media/gpu/android/video_frame_factory.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gl/gl_bindings.h" namespace media { @@ -94,7 +94,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { PromotionHintAggregator::NotifyPromotionHintCB promotion_hint_cb, VideoPixelFormat pixel_format, OverlayMode overlay_mode, - const base::Optional<VideoFrameMetadata::CopyMode>& copy_mode, + const absl::optional<VideoFrameMetadata::CopyMode>& copy_mode, scoped_refptr<base::SequencedTaskRunner> gpu_task_runner, std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, FrameInfoHelper::FrameInfo frame_info, @@ -102,7 +102,6 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { void CreateVideoFrame_OnFrameInfoReady( ImageWithInfoReadyCB image_ready_cb, - scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator, std::unique_ptr<CodecOutputBufferRenderer> output_buffer_renderer, FrameInfoHelper::FrameInfo frame_info); @@ -117,7 +116,7 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { OverlayMode overlay_mode_ = OverlayMode::kDontRequestPromotionHints; // Indicates how video frame needs to be copied when required. - base::Optional<VideoFrameMetadata::CopyMode> copy_mode_; + absl::optional<VideoFrameMetadata::CopyMode> copy_mode_; // Current group that new CodecImages should belong to. Do not use this on // our thread; everything must be posted to the gpu main thread, including @@ -141,4 +140,4 @@ class MEDIA_GPU_EXPORT VideoFrameFactoryImpl : public VideoFrameFactory { } // namespace media -#endif // MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_IMPL_ +#endif // MEDIA_GPU_ANDROID_VIDEO_FRAME_FACTORY_IMPL_H_ diff --git a/chromium/media/gpu/av1_decoder.h b/chromium/media/gpu/av1_decoder.h index 02bee3a1ec2..5c0391e1e81 100644 --- a/chromium/media/gpu/av1_decoder.h +++ b/chromium/media/gpu/av1_decoder.h @@ -19,7 +19,7 @@ // For libgav1::RefCountedBufferPtr. #include "third_party/libgav1/src/src/buffer_pool.h" -// For libgav1::ObuSequenceHeader. base::Optional demands ObuSequenceHeader to +// For libgav1::ObuSequenceHeader. absl::optional demands ObuSequenceHeader to // fulfill std::is_trivially_constructible if it is forward-declared. But // ObuSequenceHeader doesn't. #include "third_party/libgav1/src/src/obu_parser.h" @@ -138,8 +138,8 @@ class MEDIA_GPU_EXPORT AV1Decoder : public AcceleratedVideoDecoder { const std::unique_ptr<AV1Accelerator> accelerator_; AV1ReferenceFrameVector ref_frames_; - base::Optional<libgav1::ObuSequenceHeader> current_sequence_header_; - base::Optional<libgav1::ObuFrameHeader> current_frame_header_; + absl::optional<libgav1::ObuSequenceHeader> current_sequence_header_; + absl::optional<libgav1::ObuFrameHeader> current_frame_header_; libgav1::RefCountedBufferPtr current_frame_; gfx::Rect visible_rect_; diff --git a/chromium/media/gpu/av1_picture.h b/chromium/media/gpu/av1_picture.h index 505c9cd4670..d770f9f3f37 100644 --- a/chromium/media/gpu/av1_picture.h +++ b/chromium/media/gpu/av1_picture.h @@ -5,8 +5,6 @@ #ifndef MEDIA_GPU_AV1_PICTURE_H_ #define MEDIA_GPU_AV1_PICTURE_H_ -#include <memory> - #include "media/gpu/codec_picture.h" #include "media/gpu/media_gpu_export.h" #include "third_party/libgav1/src/src/utils/types.h" diff --git a/chromium/media/gpu/chromeos/chromeos_video_decoder_factory.cc b/chromium/media/gpu/chromeos/chromeos_video_decoder_factory.cc index 262c36fbbfe..9721219921a 100644 --- a/chromium/media/gpu/chromeos/chromeos_video_decoder_factory.cc +++ b/chromium/media/gpu/chromeos/chromeos_video_decoder_factory.cc @@ -7,6 +7,8 @@ #include <utility> #include "base/sequenced_task_runner.h" +#include "gpu/config/gpu_driver_bug_workarounds.h" +#include "gpu/config/gpu_preferences.h" #include "media/base/video_decoder.h" #include "media/gpu/buildflags.h" #include "media/gpu/chromeos/mailbox_video_frame_converter.h" @@ -27,12 +29,34 @@ namespace media { SupportedVideoDecoderConfigs ChromeosVideoDecoderFactory::GetSupportedConfigs( const gpu::GpuDriverBugWorkarounds& workarounds) { #if BUILDFLAG(USE_VAAPI) - return VaapiVideoDecoder::GetSupportedConfigs(workarounds); + auto configs = VaapiVideoDecoder::GetSupportedConfigs(); #elif BUILDFLAG(USE_V4L2_CODEC) - return V4L2VideoDecoder::GetSupportedConfigs(); + auto configs = V4L2VideoDecoder::GetSupportedConfigs(); #endif -} + if (workarounds.disable_accelerated_vp8_decode) { + base::EraseIf(configs, [](const auto& config) { + return config.profile_min >= VP8PROFILE_MIN && + config.profile_max <= VP8PROFILE_MAX; + }); + } + + if (workarounds.disable_accelerated_vp9_decode) { + base::EraseIf(configs, [](const auto& config) { + return config.profile_min >= VP9PROFILE_PROFILE0 && + config.profile_max <= VP9PROFILE_PROFILE0; + }); + } + + if (workarounds.disable_accelerated_vp9_profile2_decode) { + base::EraseIf(configs, [](const auto& config) { + return config.profile_min >= VP9PROFILE_PROFILE2 && + config.profile_max <= VP9PROFILE_PROFILE2; + }); + } + + return configs; +} // static std::unique_ptr<VideoDecoder> ChromeosVideoDecoderFactory::Create( scoped_refptr<base::SequencedTaskRunner> client_task_runner, diff --git a/chromium/media/gpu/chromeos/dmabuf_video_frame_pool.h b/chromium/media/gpu/chromeos/dmabuf_video_frame_pool.h index b874b62005f..aff3c945182 100644 --- a/chromium/media/gpu/chromeos/dmabuf_video_frame_pool.h +++ b/chromium/media/gpu/chromeos/dmabuf_video_frame_pool.h @@ -6,12 +6,12 @@ #define MEDIA_GPU_CHROMEOS_DMABUF_VIDEO_FRAME_POOL_H_ #include "base/memory/scoped_refptr.h" -#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "media/base/video_frame.h" #include "media/gpu/chromeos/fourcc.h" #include "media/gpu/chromeos/gpu_buffer_layout.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -42,7 +42,7 @@ class MEDIA_GPU_EXPORT DmabufVideoFramePool { // Sets the parameters of allocating frames and the maximum number of frames // which can be allocated. Returns a valid GpuBufferLayout if VideoFrame // will be created by GetFrame(). - virtual base::Optional<GpuBufferLayout> Initialize( + virtual absl::optional<GpuBufferLayout> Initialize( const Fourcc& fourcc, const gfx::Size& coded_size, const gfx::Rect& visible_rect, diff --git a/chromium/media/gpu/chromeos/fourcc.cc b/chromium/media/gpu/chromeos/fourcc.cc index af87c3fd762..bc68962308d 100644 --- a/chromium/media/gpu/chromeos/fourcc.cc +++ b/chromium/media/gpu/chromeos/fourcc.cc @@ -6,7 +6,6 @@ #include "base/logging.h" #include "base/notreached.h" -#include "base/strings/stringprintf.h" #include "media/gpu/macros.h" #if BUILDFLAG(USE_V4L2_CODEC) @@ -24,7 +23,7 @@ Fourcc::~Fourcc() = default; Fourcc& Fourcc::operator=(const Fourcc& other) = default; // static -base::Optional<Fourcc> Fourcc::FromUint32(uint32_t fourcc) { +absl::optional<Fourcc> Fourcc::FromUint32(uint32_t fourcc) { switch (fourcc) { case AR24: case AB24: @@ -47,11 +46,11 @@ base::Optional<Fourcc> Fourcc::FromUint32(uint32_t fourcc) { return Fourcc(static_cast<Value>(fourcc)); } DVLOGF(3) << "Unmapped fourcc: " << FourccToString(fourcc); - return base::nullopt; + return absl::nullopt; } // static -base::Optional<Fourcc> Fourcc::FromVideoPixelFormat( +absl::optional<Fourcc> Fourcc::FromVideoPixelFormat( VideoPixelFormat pixel_format, bool single_planar) { if (single_planar) { @@ -147,7 +146,7 @@ base::Optional<Fourcc> Fourcc::FromVideoPixelFormat( } DVLOGF(3) << "Unmapped " << VideoPixelFormatToString(pixel_format) << " for " << (single_planar ? "single-planar" : "multi-planar"); - return base::nullopt; + return absl::nullopt; } VideoPixelFormat Fourcc::ToVideoPixelFormat() const { @@ -200,7 +199,7 @@ VideoPixelFormat Fourcc::ToVideoPixelFormat() const { #if BUILDFLAG(USE_V4L2_CODEC) // static -base::Optional<Fourcc> Fourcc::FromV4L2PixFmt(uint32_t v4l2_pix_fmt) { +absl::optional<Fourcc> Fourcc::FromV4L2PixFmt(uint32_t v4l2_pix_fmt) { // We can do that because we adopt the same internal definition of Fourcc as // V4L2. return FromUint32(v4l2_pix_fmt); @@ -215,7 +214,7 @@ uint32_t Fourcc::ToV4L2PixFmt() const { #if BUILDFLAG(USE_VAAPI) // static -base::Optional<Fourcc> Fourcc::FromVAFourCC(uint32_t va_fourcc) { +absl::optional<Fourcc> Fourcc::FromVAFourCC(uint32_t va_fourcc) { switch (va_fourcc) { case VA_FOURCC_I420: return Fourcc(YU12); @@ -241,10 +240,10 @@ base::Optional<Fourcc> Fourcc::FromVAFourCC(uint32_t va_fourcc) { return Fourcc(P010); } DVLOGF(3) << "Unmapped VAFourCC: " << FourccToString(va_fourcc); - return base::nullopt; + return absl::nullopt; } -base::Optional<uint32_t> Fourcc::ToVAFourCC() const { +absl::optional<uint32_t> Fourcc::ToVAFourCC() const { switch (value_) { case YU12: return VA_FOURCC_I420; @@ -278,15 +277,15 @@ base::Optional<uint32_t> Fourcc::ToVAFourCC() const { // VAAPI does not know about these formats, so signal this by returning // nullopt. DVLOGF(3) << "Fourcc not convertible to VaFourCC: " << ToString(); - return base::nullopt; + return absl::nullopt; } NOTREACHED() << "Unmapped Fourcc: " << ToString(); - return base::nullopt; + return absl::nullopt; } #endif // BUILDFLAG(USE_VAAPI) -base::Optional<Fourcc> Fourcc::ToSinglePlanar() const { +absl::optional<Fourcc> Fourcc::ToSinglePlanar() const { switch (value_) { case AR24: case AB24: @@ -311,7 +310,7 @@ base::Optional<Fourcc> Fourcc::ToSinglePlanar() const { case YM16: case MT21: case MM21: - return base::nullopt; + return absl::nullopt; } } diff --git a/chromium/media/gpu/chromeos/fourcc.h b/chromium/media/gpu/chromeos/fourcc.h index f9e5d691174..560305c70ef 100644 --- a/chromium/media/gpu/chromeos/fourcc.h +++ b/chromium/media/gpu/chromeos/fourcc.h @@ -8,10 +8,10 @@ #include <stdint.h> #include <string> -#include "base/optional.h" #include "media/base/video_types.h" #include "media/gpu/buildflags.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -124,24 +124,24 @@ class MEDIA_GPU_EXPORT Fourcc { // Builds a Fourcc from a given fourcc code. This will return a valid // Fourcc if the argument is part of the |Value| enum, or nullopt otherwise. - static base::Optional<Fourcc> FromUint32(uint32_t fourcc); + static absl::optional<Fourcc> FromUint32(uint32_t fourcc); // Converts a VideoPixelFormat to Fourcc. // Returns nullopt for invalid input. // Note that a VideoPixelFormat may have two Fourcc counterparts. Caller has // to specify if it is for single-planar or multi-planar format. - static base::Optional<Fourcc> FromVideoPixelFormat( + static absl::optional<Fourcc> FromVideoPixelFormat( VideoPixelFormat pixel_format, bool single_planar = true); #if BUILDFLAG(USE_V4L2_CODEC) // Converts a V4L2PixFmt to Fourcc. // Returns nullopt for invalid input. - static base::Optional<Fourcc> FromV4L2PixFmt(uint32_t v4l2_pix_fmt); + static absl::optional<Fourcc> FromV4L2PixFmt(uint32_t v4l2_pix_fmt); #endif // BUILDFLAG(USE_V4L2_CODEC) #if BUILDFLAG(USE_VAAPI) // Converts a VAFourCC to Fourcc. // Returns nullopt for invalid input. - static base::Optional<Fourcc> FromVAFourCC(uint32_t va_fourcc); + static absl::optional<Fourcc> FromVAFourCC(uint32_t va_fourcc); #endif // BUILDFLAG(USE_VAAPI) // Value getters: @@ -156,12 +156,12 @@ class MEDIA_GPU_EXPORT Fourcc { #if BUILDFLAG(USE_VAAPI) // Returns the VAFourCC counterpart of the value. // Returns nullopt if no mapping is found. - base::Optional<uint32_t> ToVAFourCC() const; + absl::optional<uint32_t> ToVAFourCC() const; #endif // BUILDFLAG(USE_VAAPI) // Returns the single-planar Fourcc of the value. If value is a single-planar, // returns the same Fourcc. Returns nullopt if no mapping is found. - base::Optional<Fourcc> ToSinglePlanar() const; + absl::optional<Fourcc> ToSinglePlanar() const; // Returns whether |value_| is multi planar format. bool IsMultiPlanar() const; diff --git a/chromium/media/gpu/chromeos/fourcc_unittests.cc b/chromium/media/gpu/chromeos/fourcc_unittests.cc index d59b317ee0b..4ee99544c68 100644 --- a/chromium/media/gpu/chromeos/fourcc_unittests.cc +++ b/chromium/media/gpu/chromeos/fourcc_unittests.cc @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/optional.h" #include "media/gpu/chromeos/fourcc.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "media/gpu/buildflags.h" #include "testing/gtest/include/gtest/gtest.h" @@ -21,8 +21,8 @@ namespace media { // Checks that converting a V4L2 pixel format to Fourcc and back to V4L2 // yields the same format as the original one. static void CheckFromV4L2PixFmtAndBack(uint32_t fmt) { - base::Optional<Fourcc> fourcc = Fourcc::FromV4L2PixFmt(fmt); - EXPECT_NE(fourcc, base::nullopt); + absl::optional<Fourcc> fourcc = Fourcc::FromV4L2PixFmt(fmt); + EXPECT_NE(fourcc, absl::nullopt); EXPECT_EQ(fourcc->ToV4L2PixFmt(), fmt); } @@ -84,7 +84,7 @@ TEST(FourccTest, V4L2PixFmtToVideoPixelFormat) { Fourcc::FromV4L2PixFmt(V4L2_PIX_FMT_RGB32)->ToVideoPixelFormat()); // Randomly pick an unmapped v4l2 fourcc. - EXPECT_EQ(base::nullopt, Fourcc::FromV4L2PixFmt(V4L2_PIX_FMT_Z16)); + EXPECT_EQ(absl::nullopt, Fourcc::FromV4L2PixFmt(V4L2_PIX_FMT_Z16)); } TEST(FourccTest, VideoPixelFormatToV4L2PixFmt) { @@ -115,10 +115,10 @@ TEST(FourccTest, VideoPixelFormatToV4L2PixFmt) { // Checks that converting a VaFourCC to Fourcc and back to VaFourCC // yields the same format as the original one. static void CheckFromVAFourCCAndBack(uint32_t va_fourcc) { - base::Optional<Fourcc> fourcc = Fourcc::FromVAFourCC(va_fourcc); - EXPECT_NE(fourcc, base::nullopt); - base::Optional<uint32_t> to_va_fourcc = fourcc->ToVAFourCC(); - EXPECT_NE(to_va_fourcc, base::nullopt); + absl::optional<Fourcc> fourcc = Fourcc::FromVAFourCC(va_fourcc); + EXPECT_NE(fourcc, absl::nullopt); + absl::optional<uint32_t> to_va_fourcc = fourcc->ToVAFourCC(); + EXPECT_NE(to_va_fourcc, absl::nullopt); EXPECT_EQ(*to_va_fourcc, va_fourcc); } diff --git a/chromium/media/gpu/chromeos/gpu_buffer_layout.cc b/chromium/media/gpu/chromeos/gpu_buffer_layout.cc index d2adee82885..578884f536b 100644 --- a/chromium/media/gpu/chromeos/gpu_buffer_layout.cc +++ b/chromium/media/gpu/chromeos/gpu_buffer_layout.cc @@ -29,7 +29,7 @@ std::string VectorToString(const std::vector<T>& vec) { } // namespace // static -base::Optional<GpuBufferLayout> GpuBufferLayout::Create( +absl::optional<GpuBufferLayout> GpuBufferLayout::Create( const Fourcc& fourcc, const gfx::Size& size, const std::vector<ColorPlaneLayout>& planes, @@ -41,7 +41,7 @@ base::Optional<GpuBufferLayout> GpuBufferLayout::Create( << ", size: " << size.ToString() << ", planes: " << VectorToString(planes) << ", modifier: " << std::hex << modifier; - return base::nullopt; + return absl::nullopt; } return GpuBufferLayout(fourcc, size, planes, modifier); diff --git a/chromium/media/gpu/chromeos/gpu_buffer_layout.h b/chromium/media/gpu/chromeos/gpu_buffer_layout.h index 06f52be9f31..833c1824b6f 100644 --- a/chromium/media/gpu/chromeos/gpu_buffer_layout.h +++ b/chromium/media/gpu/chromeos/gpu_buffer_layout.h @@ -9,17 +9,17 @@ #include <string> #include <vector> -#include "base/optional.h" #include "media/base/color_plane_layout.h" #include "media/gpu/chromeos/fourcc.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { class MEDIA_GPU_EXPORT GpuBufferLayout { public: - static base::Optional<GpuBufferLayout> Create( + static absl::optional<GpuBufferLayout> Create( const Fourcc& fourcc, const gfx::Size& size, const std::vector<ColorPlaneLayout>& planes, diff --git a/chromium/media/gpu/chromeos/image_processor.cc b/chromium/media/gpu/chromeos/image_processor.cc index 6b3dccc35e6..b3408b243ed 100644 --- a/chromium/media/gpu/chromeos/image_processor.cc +++ b/chromium/media/gpu/chromeos/image_processor.cc @@ -131,7 +131,7 @@ bool ImageProcessor::Process(scoped_refptr<VideoFrame> input_frame, // static void ImageProcessor::OnProcessDoneThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<ImageProcessor>> weak_this, + absl::optional<base::WeakPtr<ImageProcessor>> weak_this, int cb_index, scoped_refptr<VideoFrame> frame) { DVLOGF(4); @@ -178,7 +178,7 @@ bool ImageProcessor::Process(scoped_refptr<VideoFrame> frame, // static void ImageProcessor::OnProcessLegacyDoneThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<ImageProcessor>> weak_this, + absl::optional<base::WeakPtr<ImageProcessor>> weak_this, int cb_index, size_t buffer_id, scoped_refptr<VideoFrame> frame) { diff --git a/chromium/media/gpu/chromeos/image_processor.h b/chromium/media/gpu/chromeos/image_processor.h index ac62dbaf8cd..c64aebe384d 100644 --- a/chromium/media/gpu/chromeos/image_processor.h +++ b/chromium/media/gpu/chromeos/image_processor.h @@ -108,12 +108,12 @@ class MEDIA_GPU_EXPORT ImageProcessor { // Callbacks of processing frames. static void OnProcessDoneThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<ImageProcessor>> weak_this, + absl::optional<base::WeakPtr<ImageProcessor>> weak_this, int cb_index, scoped_refptr<VideoFrame> frame); static void OnProcessLegacyDoneThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<ImageProcessor>> weak_this, + absl::optional<base::WeakPtr<ImageProcessor>> weak_this, int cb_index, size_t buffer_id, scoped_refptr<VideoFrame> frame); diff --git a/chromium/media/gpu/chromeos/image_processor_factory.h b/chromium/media/gpu/chromeos/image_processor_factory.h index a81eddde318..0d29d87e80c 100644 --- a/chromium/media/gpu/chromeos/image_processor_factory.h +++ b/chromium/media/gpu/chromeos/image_processor_factory.h @@ -22,7 +22,7 @@ namespace media { class MEDIA_GPU_EXPORT ImageProcessorFactory { public: // Callback to pick a valid format from given |candidates| formats. - using PickFormatCB = base::RepeatingCallback<base::Optional<Fourcc>( + using PickFormatCB = base::RepeatingCallback<absl::optional<Fourcc>( const std::vector<Fourcc>& /* candidates */)>; // Factory method to create ImageProcessor. diff --git a/chromium/media/gpu/chromeos/image_processor_with_pool.cc b/chromium/media/gpu/chromeos/image_processor_with_pool.cc index 2c03db29ef3..bbd9c64b168 100644 --- a/chromium/media/gpu/chromeos/image_processor_with_pool.cc +++ b/chromium/media/gpu/chromeos/image_processor_with_pool.cc @@ -18,7 +18,7 @@ std::unique_ptr<ImageProcessorWithPool> ImageProcessorWithPool::Create( size_t num_frames, const scoped_refptr<base::SequencedTaskRunner> task_runner) { const ImageProcessor::PortConfig& config = image_processor->output_config(); - base::Optional<GpuBufferLayout> layout = frame_pool->Initialize( + absl::optional<GpuBufferLayout> layout = frame_pool->Initialize( config.fourcc, config.size, config.visible_rect, config.size, num_frames, /*use_protected=*/false); if (!layout || layout->size() != config.size) { diff --git a/chromium/media/gpu/chromeos/libyuv_image_processor_backend.cc b/chromium/media/gpu/chromeos/libyuv_image_processor_backend.cc index 1c7566c7dcf..4990c87b982 100644 --- a/chromium/media/gpu/chromeos/libyuv_image_processor_backend.cc +++ b/chromium/media/gpu/chromeos/libyuv_image_processor_backend.cc @@ -4,6 +4,7 @@ #include "media/gpu/chromeos/libyuv_image_processor_backend.h" +#include "base/containers/contains.h" #include "base/memory/ptr_util.h" #include "media/gpu/chromeos/fourcc.h" #include "media/gpu/macros.h" diff --git a/chromium/media/gpu/chromeos/mailbox_video_frame_converter.cc b/chromium/media/gpu/chromeos/mailbox_video_frame_converter.cc index c7ce5363d4b..afa3bf56b76 100644 --- a/chromium/media/gpu/chromeos/mailbox_video_frame_converter.cc +++ b/chromium/media/gpu/chromeos/mailbox_video_frame_converter.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/containers/contains.h" #include "base/location.h" #include "base/memory/ptr_util.h" #include "base/single_thread_task_runner.h" @@ -237,6 +238,7 @@ void MailboxVideoFrameConverter::WrapMailboxAndVideoFrameAndOutput( GetRectSizeFromOrigin(frame->visible_rect()), frame->visible_rect(), frame->natural_size(), frame->timestamp()); mailbox_frame->set_color_space(frame->ColorSpace()); + mailbox_frame->set_hdr_metadata(frame->hdr_metadata()); mailbox_frame->set_metadata(frame->metadata()); mailbox_frame->metadata().read_lock_fences_enabled = true; @@ -355,8 +357,9 @@ bool MailboxVideoFrameConverter::GenerateSharedImageOnGPUThread( const bool success = shared_image_stub->CreateSharedImage( mailbox, gpu::kPlatformVideoFramePoolClientId, std::move(gpu_memory_buffer_handle), *buffer_format, - gpu::kNullSurfaceHandle, shared_image_size, video_frame->ColorSpace(), - kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, shared_image_usage); + gfx::BufferPlane::DEFAULT, gpu::kNullSurfaceHandle, shared_image_size, + video_frame->ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, + shared_image_usage); if (!success) { OnError(FROM_HERE, "Failed to create shared image."); return false; diff --git a/chromium/media/gpu/chromeos/platform_video_frame_pool.cc b/chromium/media/gpu/chromeos/platform_video_frame_pool.cc index 401aa08aa93..db9a3086fe2 100644 --- a/chromium/media/gpu/chromeos/platform_video_frame_pool.cc +++ b/chromium/media/gpu/chromeos/platform_video_frame_pool.cc @@ -7,13 +7,13 @@ #include <utility> #include "base/logging.h" -#include "base/optional.h" #include "base/task/post_task.h" #include "media/base/video_util.h" #include "media/gpu/chromeos/gpu_buffer_layout.h" #include "media/gpu/chromeos/platform_video_frame_utils.h" #include "media/gpu/macros.h" #include "media/media_buildflags.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -138,7 +138,7 @@ scoped_refptr<VideoFrame> PlatformVideoFramePool::GetFrame() { return wrapped_frame; } -base::Optional<GpuBufferLayout> PlatformVideoFramePool::Initialize( +absl::optional<GpuBufferLayout> PlatformVideoFramePool::Initialize( const Fourcc& fourcc, const gfx::Size& coded_size, const gfx::Rect& visible_rect, @@ -152,13 +152,13 @@ base::Optional<GpuBufferLayout> PlatformVideoFramePool::Initialize( VideoPixelFormat format = fourcc.ToVideoPixelFormat(); if (format == PIXEL_FORMAT_UNKNOWN) { VLOGF(1) << "Unsupported fourcc: " << fourcc.ToString(); - return base::nullopt; + return absl::nullopt; } #if !BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) if (use_protected) { VLOGF(1) << "Protected buffers unsupported"; - return base::nullopt; + return absl::nullopt; } #endif @@ -186,7 +186,7 @@ base::Optional<GpuBufferLayout> PlatformVideoFramePool::Initialize( if (!frame) { VLOGF(1) << "Failed to create video frame " << format << " (fourcc " << fourcc.ToString() << ")"; - return base::nullopt; + return absl::nullopt; } frame_layout_ = GpuBufferLayout::Create(fourcc, frame->coded_size(), frame->layout().planes(), @@ -243,7 +243,7 @@ void PlatformVideoFramePool::NotifyWhenFrameAvailable(base::OnceClosure cb) { // static void PlatformVideoFramePool::OnFrameReleasedThunk( - base::Optional<base::WeakPtr<PlatformVideoFramePool>> pool, + absl::optional<base::WeakPtr<PlatformVideoFramePool>> pool, scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<VideoFrame> origin_frame) { DCHECK(pool); diff --git a/chromium/media/gpu/chromeos/platform_video_frame_pool.h b/chromium/media/gpu/chromeos/platform_video_frame_pool.h index ed8c875baa5..5e1391aa1a1 100644 --- a/chromium/media/gpu/chromeos/platform_video_frame_pool.h +++ b/chromium/media/gpu/chromeos/platform_video_frame_pool.h @@ -13,7 +13,6 @@ #include "base/files/scoped_file.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "base/synchronization/lock.h" #include "base/thread_annotations.h" @@ -21,6 +20,7 @@ #include "media/base/video_types.h" #include "media/gpu/chromeos/dmabuf_video_frame_pool.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/gpu_memory_buffer.h" namespace gpu { @@ -48,7 +48,7 @@ class MEDIA_GPU_EXPORT PlatformVideoFramePool : public DmabufVideoFramePool { static gfx::GpuMemoryBufferId GetGpuMemoryBufferId(const VideoFrame& frame); // DmabufVideoFramePool implementation. - base::Optional<GpuBufferLayout> Initialize(const Fourcc& fourcc, + absl::optional<GpuBufferLayout> Initialize(const Fourcc& fourcc, const gfx::Size& coded_size, const gfx::Rect& visible_rect, const gfx::Size& natural_size, @@ -71,10 +71,10 @@ class MEDIA_GPU_EXPORT PlatformVideoFramePool : public DmabufVideoFramePool { // Thunk to post OnFrameReleased() to |task_runner|. // Because this thunk may be called in any thread, We don't want to - // dereference WeakPtr. Therefore we wrap the WeakPtr by base::Optional to + // dereference WeakPtr. Therefore we wrap the WeakPtr by absl::optional to // avoid the task runner defererencing the WeakPtr. static void OnFrameReleasedThunk( - base::Optional<base::WeakPtr<PlatformVideoFramePool>> pool, + absl::optional<base::WeakPtr<PlatformVideoFramePool>> pool, scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<VideoFrame> origin_frame); // Called when a wrapped frame gets destroyed. @@ -116,7 +116,7 @@ class MEDIA_GPU_EXPORT PlatformVideoFramePool : public DmabufVideoFramePool { // The arguments of current frame. We allocate new frames only if a pixel // format or size in |frame_layout_| is changed. When GetFrame() is // called, we update |visible_rect_| and |natural_size_| of wrapped frames. - base::Optional<GpuBufferLayout> frame_layout_ GUARDED_BY(lock_); + absl::optional<GpuBufferLayout> frame_layout_ GUARDED_BY(lock_); gfx::Rect visible_rect_ GUARDED_BY(lock_); gfx::Size natural_size_ GUARDED_BY(lock_); diff --git a/chromium/media/gpu/chromeos/platform_video_frame_pool_unittest.cc b/chromium/media/gpu/chromeos/platform_video_frame_pool_unittest.cc index fbb9f6589ac..d6d5dc24854 100644 --- a/chromium/media/gpu/chromeos/platform_video_frame_pool_unittest.cc +++ b/chromium/media/gpu/chromeos/platform_video_frame_pool_unittest.cc @@ -32,7 +32,7 @@ scoped_refptr<VideoFrame> CreateGpuMemoryBufferVideoFrame( const gfx::Size& natural_size, bool use_protected, base::TimeDelta timestamp) { - base::Optional<gfx::BufferFormat> gfx_format = + absl::optional<gfx::BufferFormat> gfx_format = VideoPixelFormatToGfxBufferFormat(format); DCHECK(gfx_format); const gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes] = {}; @@ -96,7 +96,7 @@ class PlatformVideoFramePoolTest base::test::TaskEnvironment task_environment_; std::unique_ptr<PlatformVideoFramePool> pool_; - base::Optional<GpuBufferLayout> layout_; + absl::optional<GpuBufferLayout> layout_; gfx::Rect visible_rect_; gfx::Size natural_size_; }; diff --git a/chromium/media/gpu/chromeos/platform_video_frame_utils.cc b/chromium/media/gpu/chromeos/platform_video_frame_utils.cc index 24dd4216171..7d79759066c 100644 --- a/chromium/media/gpu/chromeos/platform_video_frame_utils.cc +++ b/chromium/media/gpu/chromeos/platform_video_frame_utils.cc @@ -16,6 +16,7 @@ #include "base/files/scoped_file.h" #include "base/no_destructor.h" #include "base/posix/eintr_wrapper.h" +#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/synchronization/lock.h" #include "gpu/ipc/common/gpu_client_ids.h" @@ -253,7 +254,7 @@ scoped_refptr<VideoFrame> CreatePlatformVideoFrame( return frame; } -base::Optional<VideoFrameLayout> GetPlatformVideoFrameLayout( +absl::optional<VideoFrameLayout> GetPlatformVideoFrameLayout( gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory, VideoPixelFormat pixel_format, const gfx::Size& coded_size, @@ -263,8 +264,8 @@ base::Optional<VideoFrameLayout> GetPlatformVideoFrameLayout( auto frame = CreatePlatformVideoFrame( gpu_memory_buffer_factory, pixel_format, coded_size, gfx::Rect(coded_size), coded_size, base::TimeDelta(), buffer_usage); - return frame ? base::make_optional<VideoFrameLayout>(frame->layout()) - : base::nullopt; + return frame ? absl::make_optional<VideoFrameLayout>(frame->layout()) + : absl::nullopt; } gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferHandle( diff --git a/chromium/media/gpu/chromeos/platform_video_frame_utils.h b/chromium/media/gpu/chromeos/platform_video_frame_utils.h index f1bd0d85aef..b3320540245 100644 --- a/chromium/media/gpu/chromeos/platform_video_frame_utils.h +++ b/chromium/media/gpu/chromeos/platform_video_frame_utils.h @@ -66,7 +66,7 @@ MEDIA_GPU_EXPORT scoped_refptr<VideoFrame> CreatePlatformVideoFrame( // encoding when the usage is VEA_READ_CAMERA_AND_CPU_READ_WRITE). It's // safe to call this function concurrently from multiple threads (as long as // either |gpu_memory_buffer_factory| is thread-safe or nullptr). -MEDIA_GPU_EXPORT base::Optional<VideoFrameLayout> GetPlatformVideoFrameLayout( +MEDIA_GPU_EXPORT absl::optional<VideoFrameLayout> GetPlatformVideoFrameLayout( gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory, VideoPixelFormat pixel_format, const gfx::Size& coded_size, diff --git a/chromium/media/gpu/chromeos/platform_video_frame_utils_unittest.cc b/chromium/media/gpu/chromeos/platform_video_frame_utils_unittest.cc index ba698cb838d..32aae281a41 100644 --- a/chromium/media/gpu/chromeos/platform_video_frame_utils_unittest.cc +++ b/chromium/media/gpu/chromeos/platform_video_frame_utils_unittest.cc @@ -10,13 +10,12 @@ #include <utility> #include <vector> +#include "base/containers/contains.h" #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" -#include "base/optional.h" -#include "base/stl_util.h" #include "base/time/time.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h" #include "media/base/color_plane_layout.h" @@ -26,6 +25,7 @@ #include "media/base/video_types.h" #include "media/video/fake_gpu_memory_buffer.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/buffer_types.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -42,7 +42,7 @@ scoped_refptr<VideoFrame> CreateMockDmaBufVideoFrame( const gfx::Size& coded_size, const gfx::Rect& visible_rect, const gfx::Size& natural_size) { - const base::Optional<VideoFrameLayout> layout = + const absl::optional<VideoFrameLayout> layout = VideoFrameLayout::Create(pixel_format, coded_size); if (!layout) { LOG(ERROR) << "Failed to create video frame layout"; @@ -129,7 +129,7 @@ TEST(PlatformVideoFrameUtilsTest, CreateNativePixmapDmaBuf) { constexpr VideoPixelFormat kPixelFormat = PIXEL_FORMAT_NV12; constexpr gfx::Size kCodedSize(320, 240); - const base::Optional<gfx::BufferFormat> gfx_format = + const absl::optional<gfx::BufferFormat> gfx_format = VideoPixelFormatToGfxBufferFormat(kPixelFormat); ASSERT_TRUE(gfx_format) << "Invalid pixel format: " << kPixelFormat; diff --git a/chromium/media/gpu/chromeos/vd_video_decode_accelerator.cc b/chromium/media/gpu/chromeos/vd_video_decode_accelerator.cc index e582898f58c..32311997c2c 100644 --- a/chromium/media/gpu/chromeos/vd_video_decode_accelerator.cc +++ b/chromium/media/gpu/chromeos/vd_video_decode_accelerator.cc @@ -103,7 +103,7 @@ void VdVideoDecodeAccelerator::Destroy() { // Because VdaVideoFramePool is blocked for this callback, we must call the // callback before destroying. if (notify_layout_changed_cb_) - std::move(notify_layout_changed_cb_).Run(base::nullopt); + std::move(notify_layout_changed_cb_).Run(absl::nullopt); client_ = nullptr; vd_.reset(); @@ -209,7 +209,7 @@ void VdVideoDecodeAccelerator::OnFrameReady(scoped_refptr<VideoFrame> frame) { DCHECK(frame); DCHECK(client_); - base::Optional<Picture> picture = GetPicture(*frame); + absl::optional<Picture> picture = GetPicture(*frame); if (!picture) { VLOGF(1) << "Failed to get picture."; OnError(FROM_HERE, PLATFORM_FAILURE); @@ -331,7 +331,7 @@ void VdVideoDecodeAccelerator::ImportBufferForPicture( auto fourcc = Fourcc::FromVideoPixelFormat(pixel_format); if (!fourcc) { VLOGF(1) << "Failed to convert to Fourcc."; - std::move(notify_layout_changed_cb_).Run(base::nullopt); + std::move(notify_layout_changed_cb_).Run(absl::nullopt); return; } @@ -349,7 +349,7 @@ void VdVideoDecodeAccelerator::ImportBufferForPicture( << ", coded_size: " << coded_size_.ToString() << ", planes: " << VectorToString(planes) << ", modifier: " << std::hex << modifier; - std::move(notify_layout_changed_cb_).Run(base::nullopt); + std::move(notify_layout_changed_cb_).Run(absl::nullopt); return; } @@ -395,7 +395,7 @@ void VdVideoDecodeAccelerator::ImportBufferForPicture( import_frame_cb_.Run(std::move(wrapped_frame)); } -base::Optional<Picture> VdVideoDecodeAccelerator::GetPicture( +absl::optional<Picture> VdVideoDecodeAccelerator::GetPicture( const VideoFrame& frame) { DVLOGF(4); DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); @@ -404,18 +404,18 @@ base::Optional<Picture> VdVideoDecodeAccelerator::GetPicture( frame_id_to_picture_id_.find(DmabufVideoFramePool::GetDmabufId(frame)); if (it == frame_id_to_picture_id_.end()) { VLOGF(1) << "Failed to find the picture buffer id."; - return base::nullopt; + return absl::nullopt; } int32_t picture_buffer_id = it->second; int32_t bitstream_id = FakeTimestampToBitstreamId(frame.timestamp()); - return base::make_optional(Picture(picture_buffer_id, bitstream_id, + return absl::make_optional(Picture(picture_buffer_id, bitstream_id, frame.visible_rect(), frame.ColorSpace(), frame.metadata().allow_overlay)); } // static void VdVideoDecodeAccelerator::OnFrameReleasedThunk( - base::Optional<base::WeakPtr<VdVideoDecodeAccelerator>> weak_this, + absl::optional<base::WeakPtr<VdVideoDecodeAccelerator>> weak_this, scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<VideoFrame> origin_frame) { DVLOGF(4); diff --git a/chromium/media/gpu/chromeos/vd_video_decode_accelerator.h b/chromium/media/gpu/chromeos/vd_video_decode_accelerator.h index f4ea148df36..be844f68b99 100644 --- a/chromium/media/gpu/chromeos/vd_video_decode_accelerator.h +++ b/chromium/media/gpu/chromeos/vd_video_decode_accelerator.h @@ -11,10 +11,8 @@ #include "base/callback_forward.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" -#include "base/time/time.h" #include "media/base/status.h" #include "media/base/video_decoder.h" #include "media/gpu/chromeos/dmabuf_video_frame_pool.h" @@ -23,6 +21,7 @@ #include "media/gpu/chromeos/video_frame_converter.h" #include "media/gpu/media_gpu_export.h" #include "media/video/video_decode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -100,15 +99,15 @@ class MEDIA_GPU_EXPORT VdVideoDecodeAccelerator void OnResetDone(); // Get Picture instance that represents the same buffer as |frame|. Return - // base::nullopt if the buffer is already dismissed. - base::Optional<Picture> GetPicture(const VideoFrame& frame); + // absl::nullopt if the buffer is already dismissed. + absl::optional<Picture> GetPicture(const VideoFrame& frame); // Thunk to post OnFrameReleased() to |task_runner|. // Because this thunk may be called in any thread, We don't want to - // dereference WeakPtr. Therefore we wrap the WeakPtr by base::Optional to + // dereference WeakPtr. Therefore we wrap the WeakPtr by absl::optional to // avoid the task runner defererencing the WeakPtr. static void OnFrameReleasedThunk( - base::Optional<base::WeakPtr<VdVideoDecodeAccelerator>> weak_this, + absl::optional<base::WeakPtr<VdVideoDecodeAccelerator>> weak_this, scoped_refptr<base::SequencedTaskRunner> task_runner, scoped_refptr<VideoFrame> origin_frame); // Called when a frame gets destroyed. @@ -133,7 +132,7 @@ class MEDIA_GPU_EXPORT VdVideoDecodeAccelerator gfx::Size pending_coded_size_; // The formats of the current buffers. gfx::Size coded_size_; - base::Optional<VideoFrameLayout> layout_; + absl::optional<VideoFrameLayout> layout_; // Mapping from VideoFrame's DmabufId to picture buffer id. std::map<DmabufId, int32_t /* picture_buffer_id */> frame_id_to_picture_id_; diff --git a/chromium/media/gpu/chromeos/vda_video_frame_pool.cc b/chromium/media/gpu/chromeos/vda_video_frame_pool.cc index f7ba7977be4..305b7a2a411 100644 --- a/chromium/media/gpu/chromeos/vda_video_frame_pool.cc +++ b/chromium/media/gpu/chromeos/vda_video_frame_pool.cc @@ -29,7 +29,7 @@ VdaVideoFramePool::~VdaVideoFramePool() { weak_this_factory_.InvalidateWeakPtrs(); } -base::Optional<GpuBufferLayout> VdaVideoFramePool::Initialize( +absl::optional<GpuBufferLayout> VdaVideoFramePool::Initialize( const Fourcc& fourcc, const gfx::Size& coded_size, const gfx::Rect& visible_rect, @@ -41,7 +41,7 @@ base::Optional<GpuBufferLayout> VdaVideoFramePool::Initialize( if (use_protected) { LOG(ERROR) << "Cannot allocated protected buffers for VDA"; - return base::nullopt; + return absl::nullopt; } visible_rect_ = visible_rect; @@ -65,7 +65,7 @@ base::Optional<GpuBufferLayout> VdaVideoFramePool::Initialize( // Clear the pool and reset the layout to prevent previous frames are recycled // back to the pool. frame_pool_ = {}; - layout_ = base::nullopt; + layout_ = absl::nullopt; // Receive the layout from the callback. |layout_| is accessed on // |parent_task_runner_| except OnRequestFramesDone(). However, we block @@ -89,7 +89,7 @@ base::Optional<GpuBufferLayout> VdaVideoFramePool::Initialize( void VdaVideoFramePool::OnRequestFramesDone( base::WaitableEvent* done, - base::Optional<GpuBufferLayout> value) { + absl::optional<GpuBufferLayout> value) { DVLOGF(3); // RequestFrames() is blocked on |parent_task_runner_| to wait for this method // finishes, so this method must not be run on the same sequence. @@ -107,7 +107,7 @@ void VdaVideoFramePool::OnRequestFramesDone( // static void VdaVideoFramePool::ImportFrameThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<VdaVideoFramePool>> weak_this, + absl::optional<base::WeakPtr<VdaVideoFramePool>> weak_this, scoped_refptr<VideoFrame> frame) { DVLOGF(3); DCHECK(weak_this); diff --git a/chromium/media/gpu/chromeos/vda_video_frame_pool.h b/chromium/media/gpu/chromeos/vda_video_frame_pool.h index fd2995a9af7..0955a9f2886 100644 --- a/chromium/media/gpu/chromeos/vda_video_frame_pool.h +++ b/chromium/media/gpu/chromeos/vda_video_frame_pool.h @@ -5,16 +5,14 @@ #ifndef MEDIA_GPU_CHROMEOS_VDA_VIDEO_FRAME_POOL_H_ #define MEDIA_GPU_CHROMEOS_VDA_VIDEO_FRAME_POOL_H_ -#include <vector> - #include "base/containers/queue.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "media/base/video_frame.h" #include "media/gpu/chromeos/dmabuf_video_frame_pool.h" #include "media/gpu/chromeos/fourcc.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class WaitableEvent; @@ -38,7 +36,7 @@ class VdaVideoFramePool : public DmabufVideoFramePool { public: // Callback for returning the layout of requested buffer. using NotifyLayoutChangedCb = - base::OnceCallback<void(base::Optional<GpuBufferLayout>)>; + base::OnceCallback<void(absl::optional<GpuBufferLayout>)>; // Callback for importing available frames to this pool. using ImportFrameCb = base::RepeatingCallback<void(scoped_refptr<VideoFrame>)>; @@ -62,7 +60,7 @@ class VdaVideoFramePool : public DmabufVideoFramePool { ~VdaVideoFramePool() override; // DmabufVideoFramePool implementation. - base::Optional<GpuBufferLayout> Initialize(const Fourcc& fourcc, + absl::optional<GpuBufferLayout> Initialize(const Fourcc& fourcc, const gfx::Size& coded_size, const gfx::Rect& visible_rect, const gfx::Size& natural_size, @@ -76,15 +74,15 @@ class VdaVideoFramePool : public DmabufVideoFramePool { // Update the layout of the buffers. |vda_| calls this as // NotifyLayoutChangedCb. void OnRequestFramesDone(base::WaitableEvent* done, - base::Optional<GpuBufferLayout> value); + absl::optional<GpuBufferLayout> value); // Thunk to post ImportFrame() to |task_runner|. // Because this thunk may be called in any thread, We don't want to - // dereference WeakPtr. Therefore we wrap the WeakPtr by base::Optional to + // dereference WeakPtr. Therefore we wrap the WeakPtr by absl::optional to // avoid the task runner defererencing the WeakPtr. static void ImportFrameThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<VdaVideoFramePool>> weak_this, + absl::optional<base::WeakPtr<VdaVideoFramePool>> weak_this, scoped_refptr<VideoFrame> frame); // Import an available frame. void ImportFrame(scoped_refptr<VideoFrame> frame); @@ -104,11 +102,11 @@ class VdaVideoFramePool : public DmabufVideoFramePool { base::OnceClosure frame_available_cb_; // The layout of the frames in |frame_pool_|. - base::Optional<GpuBufferLayout> layout_; + absl::optional<GpuBufferLayout> layout_; // Data passed from Initialize(). size_t max_num_frames_ = 0; - base::Optional<Fourcc> fourcc_; + absl::optional<Fourcc> fourcc_; gfx::Size coded_size_; gfx::Rect visible_rect_; gfx::Size natural_size_; diff --git a/chromium/media/gpu/chromeos/video_decoder_pipeline.cc b/chromium/media/gpu/chromeos/video_decoder_pipeline.cc index 2c59b384add..80f1f59324e 100644 --- a/chromium/media/gpu/chromeos/video_decoder_pipeline.cc +++ b/chromium/media/gpu/chromeos/video_decoder_pipeline.cc @@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/memory/ptr_util.h" -#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" @@ -23,6 +22,7 @@ #include "media/gpu/chromeos/platform_video_frame_pool.h" #include "media/gpu/macros.h" #include "media/media_buildflags.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace { @@ -33,7 +33,7 @@ constexpr size_t kNumFramesForImageProcessor = limits::kMaxVideoFrames + 1; // Pick a compositor renderable format from |candidates|. // Return zero if not found. -base::Optional<Fourcc> PickRenderableFourcc( +absl::optional<Fourcc> PickRenderableFourcc( const std::vector<Fourcc>& candidates) { // Hardcode compositor renderable format now. // TODO: figure out a way to pick the best one dynamically. @@ -54,7 +54,7 @@ base::Optional<Fourcc> PickRenderableFourcc( return Fourcc(value); } } - return base::nullopt; + return absl::nullopt; } } // namespace @@ -455,7 +455,7 @@ DmabufVideoFramePool* VideoDecoderPipeline::GetVideoFramePool() const { return main_frame_pool_.get(); } -base::Optional<std::pair<Fourcc, gfx::Size>> +absl::optional<std::pair<Fourcc, gfx::Size>> VideoDecoderPipeline::PickDecoderOutputFormat( const std::vector<std::pair<Fourcc, gfx::Size>>& candidates, const gfx::Rect& visible_rect) { @@ -463,7 +463,7 @@ VideoDecoderPipeline::PickDecoderOutputFormat( DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); if (candidates.empty()) - return base::nullopt; + return absl::nullopt; image_processor_.reset(); @@ -478,7 +478,7 @@ VideoDecoderPipeline::PickDecoderOutputFormat( if (candidate.first == renderable_fourcc) return candidate; DVLOGF(2) << "Renderable Fourcc not in candidates list. This is a bug."; - return base::nullopt; + return absl::nullopt; } std::unique_ptr<ImageProcessor> image_processor = @@ -489,7 +489,7 @@ VideoDecoderPipeline::PickDecoderOutputFormat( decoder_weak_this_)); if (!image_processor) { DVLOGF(2) << "Unable to find ImageProcessor to convert format"; - return base::nullopt; + return absl::nullopt; } // Note that fourcc is specified in ImageProcessor's factory method. @@ -502,7 +502,7 @@ VideoDecoderPipeline::PickDecoderOutputFormat( kNumFramesForImageProcessor, decoder_task_runner_); if (!image_processor_) { DVLOGF(2) << "Unable to create ImageProcessorWithPool."; - return base::nullopt; + return absl::nullopt; } return std::make_pair(fourcc, size); diff --git a/chromium/media/gpu/chromeos/video_decoder_pipeline.h b/chromium/media/gpu/chromeos/video_decoder_pipeline.h index ea17d274fd1..1c4530a59e2 100644 --- a/chromium/media/gpu/chromeos/video_decoder_pipeline.h +++ b/chromium/media/gpu/chromeos/video_decoder_pipeline.h @@ -9,7 +9,6 @@ #include "base/callback_forward.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "media/base/video_decoder.h" #include "media/base/video_decoder_config.h" @@ -17,6 +16,7 @@ #include "media/gpu/chromeos/image_processor_with_pool.h" #include "media/gpu/chromeos/video_frame_converter.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace base { @@ -62,8 +62,8 @@ class MEDIA_GPU_EXPORT DecoderInterface { // Return a valid format and size for |decoder_| output from given // |candidates| and the visible rect. The size might be modified from the // ones provided originally to accommodate the needs of the pipeline. - // Return base::nullopt if no valid format is found. - virtual base::Optional<std::pair<Fourcc, gfx::Size>> + // Return absl::nullopt if no valid format is found. + virtual absl::optional<std::pair<Fourcc, gfx::Size>> PickDecoderOutputFormat( const std::vector<std::pair<Fourcc, gfx::Size>>& candidates, const gfx::Rect& visible_rect) = 0; @@ -166,7 +166,7 @@ class MEDIA_GPU_EXPORT VideoDecoderPipeline : public VideoDecoder, // After picking a format, it instantiates an |image_processor_| if none of // format in |candidates| is renderable and an ImageProcessor can convert a // candidate to renderable format. - base::Optional<std::pair<Fourcc, gfx::Size>> PickDecoderOutputFormat( + absl::optional<std::pair<Fourcc, gfx::Size>> PickDecoderOutputFormat( const std::vector<std::pair<Fourcc, gfx::Size>>& candidates, const gfx::Rect& visible_rect) override; diff --git a/chromium/media/gpu/chromeos/video_decoder_pipeline_unittest.cc b/chromium/media/gpu/chromeos/video_decoder_pipeline_unittest.cc index 9582d9493b8..6823dfc83df 100644 --- a/chromium/media/gpu/chromeos/video_decoder_pipeline_unittest.cc +++ b/chromium/media/gpu/chromeos/video_decoder_pipeline_unittest.cc @@ -36,7 +36,7 @@ class MockVideoFramePool : public DmabufVideoFramePool { // DmabufVideoFramePool implementation. MOCK_METHOD6(Initialize, - base::Optional<GpuBufferLayout>(const Fourcc&, + absl::optional<GpuBufferLayout>(const Fourcc&, const gfx::Size&, const gfx::Rect&, const gfx::Size&, diff --git a/chromium/media/gpu/command_buffer_helper.cc b/chromium/media/gpu/command_buffer_helper.cc index a15549c0a6e..36c9aab569a 100644 --- a/chromium/media/gpu/command_buffer_helper.cc +++ b/chromium/media/gpu/command_buffer_helper.cc @@ -32,7 +32,10 @@ class CommandBufferHelperImpl public gpu::CommandBufferStub::DestructionObserver { public: explicit CommandBufferHelperImpl(gpu::CommandBufferStub* stub) - : CommandBufferHelper(stub->channel()->task_runner()), stub_(stub) { + : CommandBufferHelper(stub->channel()->task_runner()), + stub_(stub), + memory_tracker_(this), + memory_type_tracker_(&memory_tracker_) { DVLOG(1) << __func__; DCHECK(stub_->channel()->task_runner()->BelongsToCurrentThread()); @@ -48,8 +51,6 @@ class CommandBufferHelperImpl #endif // defined(OS_MAC) ); decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context()); - tracker_ = - std::make_unique<gpu::MemoryTypeTracker>(stub_->GetMemoryTracker()); } gl::GLContext* GetGLContext() override { @@ -63,6 +64,11 @@ class CommandBufferHelperImpl } gpu::SharedImageStub* GetSharedImageStub() override { + return shared_image_stub(); + } + + // Const variant of above method for internal callers. + gpu::SharedImageStub* shared_image_stub() const { if (!stub_) return nullptr; return stub_->channel()->shared_image_stub(); @@ -89,7 +95,7 @@ class CommandBufferHelperImpl return stub_->channel() ->gpu_channel_manager() ->shared_image_manager() - ->Register(std::move(backing), tracker_.get()); + ->Register(std::move(backing), &memory_type_tracker_); } gpu::TextureBase* GetTexture(GLuint service_id) const override { @@ -209,6 +215,51 @@ class CommandBufferHelperImpl } private: + // Helper class to forward memory tracking calls to shared image stub. + // Necessary because the underlying stub and channel can get destroyed before + // the CommandBufferHelper and its clients. + class MemoryTrackerImpl : public gpu::MemoryTracker { + public: + explicit MemoryTrackerImpl(CommandBufferHelperImpl* helper) + : helper_(helper) { + if (auto* stub = helper_->shared_image_stub()) { + // We assume these don't change after initialization. + client_id_ = stub->ClientId(); + client_tracing_id_ = stub->ClientTracingId(); + context_group_tracing_id_ = stub->ContextGroupTracingId(); + } + } + ~MemoryTrackerImpl() override = default; + + MemoryTrackerImpl(const MemoryTrackerImpl&) = delete; + MemoryTrackerImpl& operator=(const MemoryTrackerImpl&) = delete; + + void TrackMemoryAllocatedChange(int64_t delta) override { + if (auto* stub = helper_->shared_image_stub()) + stub->TrackMemoryAllocatedChange(delta); + } + + uint64_t GetSize() const override { + if (auto* stub = helper_->shared_image_stub()) + return stub->GetSize(); + return 0; + } + + int ClientId() const override { return client_id_; } + + uint64_t ClientTracingId() const override { return client_tracing_id_; } + + uint64_t ContextGroupTracingId() const override { + return context_group_tracing_id_; + } + + private: + CommandBufferHelperImpl* const helper_; + int client_id_ = 0; + uint64_t client_tracing_id_ = 0; + uint64_t context_group_tracing_id_ = 0; + }; + ~CommandBufferHelperImpl() override { DVLOG(1) << __func__; DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -257,7 +308,8 @@ class CommandBufferHelperImpl WillDestroyStubCB will_destroy_stub_cb_; - std::unique_ptr<gpu::MemoryTypeTracker> tracker_; + MemoryTrackerImpl memory_tracker_; + gpu::MemoryTypeTracker memory_type_tracker_; THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(CommandBufferHelperImpl); diff --git a/chromium/media/gpu/gles2_decoder_helper.h b/chromium/media/gpu/gles2_decoder_helper.h index f97e5f4152e..1645c5b607d 100644 --- a/chromium/media/gpu/gles2_decoder_helper.h +++ b/chromium/media/gpu/gles2_decoder_helper.h @@ -10,8 +10,8 @@ #include <memory> #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gl/gl_bindings.h" namespace gpu { diff --git a/chromium/media/gpu/gpu_video_accelerator_util.h b/chromium/media/gpu/gpu_video_accelerator_util.h index 8cf8c12b7bb..c8fe4910064 100644 --- a/chromium/media/gpu/gpu_video_accelerator_util.h +++ b/chromium/media/gpu/gpu_video_accelerator_util.h @@ -5,8 +5,6 @@ #ifndef MEDIA_GPU_GPU_VIDEO_ACCELERATOR_UTIL_H_ #define MEDIA_GPU_GPU_VIDEO_ACCELERATOR_UTIL_H_ -#include <vector> - #include "gpu/config/gpu_info.h" #include "media/gpu/media_gpu_export.h" #include "media/video/video_decode_accelerator.h" diff --git a/chromium/media/gpu/gpu_video_decode_accelerator_factory.cc b/chromium/media/gpu/gpu_video_decode_accelerator_factory.cc index 360f54ec0d7..0e55ef47ec6 100644 --- a/chromium/media/gpu/gpu_video_decode_accelerator_factory.cc +++ b/chromium/media/gpu/gpu_video_decode_accelerator_factory.cc @@ -59,7 +59,7 @@ gpu::VideoDecodeAcceleratorCapabilities GetDecoderCapabilitiesInternal( #elif BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION) #if BUILDFLAG(USE_VAAPI) capabilities.supported_profiles = - VaapiVideoDecodeAccelerator::GetSupportedProfiles(workarounds); + VaapiVideoDecodeAccelerator::GetSupportedProfiles(); #elif BUILDFLAG(USE_V4L2_CODEC) GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles( V4L2VideoDecodeAccelerator::GetSupportedProfiles(), diff --git a/chromium/media/gpu/gpu_video_encode_accelerator_factory.cc b/chromium/media/gpu/gpu_video_encode_accelerator_factory.cc index 3ddcd3cf273..9469934be87 100644 --- a/chromium/media/gpu/gpu_video_encode_accelerator_factory.cc +++ b/chromium/media/gpu/gpu_video_encode_accelerator_factory.cc @@ -197,6 +197,11 @@ GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles( }); } + base::EraseIf(profiles, [](const auto& vea_profile) { + return vea_profile.profile >= HEVCPROFILE_MIN && + vea_profile.profile <= HEVCPROFILE_MAX; + }); + return profiles; } diff --git a/chromium/media/gpu/h264_decoder.cc b/chromium/media/gpu/h264_decoder.cc index 20538297e8b..771eedc557a 100644 --- a/chromium/media/gpu/h264_decoder.cc +++ b/chromium/media/gpu/h264_decoder.cc @@ -11,11 +11,11 @@ #include "base/feature_list.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" -#include "base/optional.h" #include "base/stl_util.h" #include "media/base/media_switches.h" #include "media/gpu/h264_decoder.h" #include "media/video/h264_level_limits.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace { @@ -1050,7 +1050,7 @@ bool H264Decoder::FinishPicture(scoped_refptr<H264Picture> pic) { // outputting all pictures before it, to avoid outputting corrupted // frames. (*output_candidate)->frame_num == *recovery_frame_num_) { - recovery_frame_num_ = base::nullopt; + recovery_frame_num_ = absl::nullopt; if (!OutputPic(*output_candidate)) return false; } diff --git a/chromium/media/gpu/h264_decoder.h b/chromium/media/gpu/h264_decoder.h index d01ab1544ea..9b4f0830ce1 100644 --- a/chromium/media/gpu/h264_decoder.h +++ b/chromium/media/gpu/h264_decoder.h @@ -384,12 +384,12 @@ class MEDIA_GPU_EXPORT H264Decoder : public AcceleratedVideoDecoder { std::vector<base::span<const uint8_t>> encrypted_sei_nalus_; std::vector<SubsampleEntry> sei_subsamples_; - // These are base::nullopt unless get recovery point SEI message after Reset. + // These are absl::nullopt unless get recovery point SEI message after Reset. // A frame_num of the frame at output order that is correct in content. - base::Optional<int> recovery_frame_num_; + absl::optional<int> recovery_frame_num_; // A value in the recovery point SEI message to compute |recovery_frame_num_| // later. - base::Optional<int> recovery_frame_cnt_; + absl::optional<int> recovery_frame_cnt_; // Output picture size. gfx::Size pic_size_; diff --git a/chromium/media/gpu/h265_decoder.cc b/chromium/media/gpu/h265_decoder.cc index 64d5106de33..547154689a8 100644 --- a/chromium/media/gpu/h265_decoder.cc +++ b/chromium/media/gpu/h265_decoder.cc @@ -40,7 +40,7 @@ bool IsValidBitDepth(uint8_t bit_depth, VideoCodecProfile profile) { case HEVCPROFILE_MAIN_STILL_PICTURE: return bit_depth == 8u; default: - NOTREACHED(); + DVLOG(1) << "Invalid profile specified for H265"; return false; } } diff --git a/chromium/media/gpu/ipc/common/BUILD.gn b/chromium/media/gpu/ipc/common/BUILD.gn index 194f6e5e7d3..1d8f8bca6a2 100644 --- a/chromium/media/gpu/ipc/common/BUILD.gn +++ b/chromium/media/gpu/ipc/common/BUILD.gn @@ -4,8 +4,6 @@ source_set("common") { sources = [ - "create_video_encoder_params.cc", - "create_video_encoder_params.h", "media_message_generator.cc", "media_message_generator.h", "media_messages.h", diff --git a/chromium/media/gpu/ipc/common/create_video_encoder_params.cc b/chromium/media/gpu/ipc/common/create_video_encoder_params.cc deleted file mode 100644 index 4de82bf0bfd..00000000000 --- a/chromium/media/gpu/ipc/common/create_video_encoder_params.cc +++ /dev/null @@ -1,19 +0,0 @@ -// 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/gpu/ipc/common/create_video_encoder_params.h" - -#include "ipc/ipc_message.h" - -namespace media { - -CreateVideoEncoderParams::CreateVideoEncoderParams() - : input_format(PIXEL_FORMAT_UNKNOWN), - output_profile(VIDEO_CODEC_PROFILE_UNKNOWN), - initial_bitrate(0), - encoder_route_id(MSG_ROUTING_NONE) {} - -CreateVideoEncoderParams::~CreateVideoEncoderParams() = default; - -} // namespace media diff --git a/chromium/media/gpu/ipc/common/create_video_encoder_params.h b/chromium/media/gpu/ipc/common/create_video_encoder_params.h deleted file mode 100644 index 995a6d9aa36..00000000000 --- a/chromium/media/gpu/ipc/common/create_video_encoder_params.h +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -#ifndef MEDIA_GPU_IPC_COMMON_CREATE_VIDEO_ENCODER_PARAMS_H_ -#define MEDIA_GPU_IPC_COMMON_CREATE_VIDEO_ENCODER_PARAMS_H_ - -#include "media/base/video_codecs.h" -#include "media/base/video_types.h" -#include "ui/gfx/geometry/size.h" - -namespace media { - -struct CreateVideoEncoderParams { - CreateVideoEncoderParams(); - ~CreateVideoEncoderParams(); - VideoPixelFormat input_format; - gfx::Size input_visible_size; - VideoCodecProfile output_profile; - uint32_t initial_bitrate; - int32_t encoder_route_id; -}; - -} // namespace media - -#endif // MEDIA_GPU_IPC_COMMON_CREATE_VIDEO_ENCODER_PARAMS_H_ diff --git a/chromium/media/gpu/ipc/common/media_messages.h b/chromium/media/gpu/ipc/common/media_messages.h index 3f47f08cdf6..8d0e1f87b81 100644 --- a/chromium/media/gpu/ipc/common/media_messages.h +++ b/chromium/media/gpu/ipc/common/media_messages.h @@ -11,6 +11,7 @@ #include "gpu/config/gpu_info.h" #include "gpu/ipc/common/gpu_param_traits_macros.h" #include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_start.h" #include "ipc/param_traits_macros.h" #include "media/base/overlay_info.h" #include "media/gpu/ipc/common/media_param_traits.h" diff --git a/chromium/media/gpu/ipc/common/media_param_traits_macros.h b/chromium/media/gpu/ipc/common/media_param_traits_macros.h index 22d0b7eb247..a15d8d03cd6 100644 --- a/chromium/media/gpu/ipc/common/media_param_traits_macros.h +++ b/chromium/media/gpu/ipc/common/media_param_traits_macros.h @@ -8,7 +8,6 @@ #include "gpu/config/gpu_info.h" #include "ipc/ipc_message_macros.h" #include "media/base/ipc/media_param_traits.h" -#include "media/gpu/ipc/common/create_video_encoder_params.h" #include "media/video/video_decode_accelerator.h" #include "media/video/video_encode_accelerator.h" #include "ui/gfx/ipc/color/gfx_param_traits.h" @@ -32,12 +31,4 @@ IPC_STRUCT_TRAITS_BEGIN(media::VideoDecodeAccelerator::Config) IPC_STRUCT_TRAITS_MEMBER(hdr_metadata) IPC_STRUCT_TRAITS_END() -IPC_STRUCT_TRAITS_BEGIN(media::CreateVideoEncoderParams) - IPC_STRUCT_TRAITS_MEMBER(input_format) - IPC_STRUCT_TRAITS_MEMBER(input_visible_size) - IPC_STRUCT_TRAITS_MEMBER(output_profile) - IPC_STRUCT_TRAITS_MEMBER(initial_bitrate) - IPC_STRUCT_TRAITS_MEMBER(encoder_route_id) -IPC_STRUCT_TRAITS_END() - #endif // MEDIA_GPU_IPC_COMMON_MEDIA_PARAM_TRAITS_MACROS_H_ diff --git a/chromium/media/gpu/ipc/service/media_gpu_channel.h b/chromium/media/gpu/ipc/service/media_gpu_channel.h index 04db47080be..8d21c2a8026 100644 --- a/chromium/media/gpu/ipc/service/media_gpu_channel.h +++ b/chromium/media/gpu/ipc/service/media_gpu_channel.h @@ -5,18 +5,12 @@ #ifndef MEDIA_GPU_IPC_SERVICE_MEDIA_GPU_CHANNEL_H_ #define MEDIA_GPU_IPC_SERVICE_MEDIA_GPU_CHANNEL_H_ -#include <memory> - #include "base/unguessable_token.h" #include "ipc/ipc_listener.h" #include "ipc/ipc_sender.h" #include "media/base/android_overlay_mojo_factory.h" #include "media/video/video_decode_accelerator.h" -namespace media { -struct CreateVideoEncoderParams; -} - namespace gpu { class GpuChannel; } @@ -47,9 +41,6 @@ class MediaGpuChannel : public IPC::Listener, public IPC::Sender { const VideoDecodeAccelerator::Config& config, int32_t route_id, IPC::Message* reply_message); - void OnCreateVideoEncoder(int32_t command_buffer_route_id, - const CreateVideoEncoderParams& params, - IPC::Message* reply_message); gpu::GpuChannel* const channel_; scoped_refptr<MediaGpuChannelFilter> filter_; diff --git a/chromium/media/gpu/mac/vt_config_util.h b/chromium/media/gpu/mac/vt_config_util.h index d3b4a5e3e31..ea86e465f56 100644 --- a/chromium/media/gpu/mac/vt_config_util.h +++ b/chromium/media/gpu/mac/vt_config_util.h @@ -8,10 +8,10 @@ #include <CoreFoundation/CoreFoundation.h> #include <CoreMedia/CoreMedia.h> -#include "base/optional.h" #include "media/base/video_codecs.h" #include "media/base/video_color_space.h" #include "media/gpu/media_gpu_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/hdr_metadata.h" namespace media { @@ -20,7 +20,7 @@ MEDIA_GPU_EXPORT CFMutableDictionaryRef CreateFormatExtensions(CMVideoCodecType codec_type, VideoCodecProfile profile, const VideoColorSpace& color_space, - base::Optional<gfx::HDRMetadata> hdr_metadata); + absl::optional<gfx::HDRMetadata> hdr_metadata); } // namespace media diff --git a/chromium/media/gpu/mac/vt_config_util.mm b/chromium/media/gpu/mac/vt_config_util.mm index 09d03a517ee..8e659e63ec6 100644 --- a/chromium/media/gpu/mac/vt_config_util.mm +++ b/chromium/media/gpu/mac/vt_config_util.mm @@ -228,7 +228,7 @@ CFMutableDictionaryRef CreateFormatExtensions( CMVideoCodecType codec_type, VideoCodecProfile profile, const VideoColorSpace& color_space, - base::Optional<gfx::HDRMetadata> hdr_metadata) { + absl::optional<gfx::HDRMetadata> hdr_metadata) { auto* extensions = [[NSMutableDictionary alloc] init]; SetDictionaryValue(extensions, kCMFormatDescriptionExtension_FormatName, CMVideoCodecTypeToString(codec_type)); diff --git a/chromium/media/gpu/mac/vt_config_util_unittest.cc b/chromium/media/gpu/mac/vt_config_util_unittest.cc index 3c264e1aec8..6fbb4144e1f 100644 --- a/chromium/media/gpu/mac/vt_config_util_unittest.cc +++ b/chromium/media/gpu/mac/vt_config_util_unittest.cc @@ -136,7 +136,7 @@ namespace media { TEST(VTConfigUtil, CreateFormatExtensions_H264_BT709) { base::ScopedCFTypeRef<CFDictionaryRef> fmt( CreateFormatExtensions(kCMVideoCodecType_H264, H264PROFILE_MAIN, - VideoColorSpace::REC709(), base::nullopt)); + VideoColorSpace::REC709(), absl::nullopt)); EXPECT_EQ("avc1", GetStrValue(fmt, kCMFormatDescriptionExtension_FormatName)); EXPECT_EQ(24, GetIntValue(fmt, kCMFormatDescriptionExtension_Depth)); EXPECT_EQ(kCMFormatDescriptionColorPrimaries_ITU_R_709_2, @@ -271,7 +271,7 @@ TEST(VTConfigUtil, CreateFormatExtensions_VP9Profile0) { constexpr VideoCodecProfile kTestProfile = VP9PROFILE_PROFILE0; const auto kTestColorSpace = VideoColorSpace::REC709(); base::ScopedCFTypeRef<CFDictionaryRef> fmt(CreateFormatExtensions( - kCMVideoCodecType_VP9, kTestProfile, kTestColorSpace, base::nullopt)); + kCMVideoCodecType_VP9, kTestProfile, kTestColorSpace, absl::nullopt)); EXPECT_EQ(8, GetIntValue(fmt, base::SysUTF8ToCFStringRef(kBitDepthKey))); auto vpcc = GetNestedDataValue( @@ -293,7 +293,7 @@ TEST(VTConfigUtil, CreateFormatExtensions_VP9Profile2) { VideoColorSpace::TransferID::SMPTEST2084, VideoColorSpace::MatrixID::BT2020_NCL, gfx::ColorSpace::RangeID::LIMITED); base::ScopedCFTypeRef<CFDictionaryRef> fmt(CreateFormatExtensions( - kCMVideoCodecType_VP9, kTestProfile, kTestColorSpace, base::nullopt)); + kCMVideoCodecType_VP9, kTestProfile, kTestColorSpace, absl::nullopt)); EXPECT_EQ(10, GetIntValue(fmt, base::SysUTF8ToCFStringRef(kBitDepthKey))); auto vpcc = GetNestedDataValue( diff --git a/chromium/media/gpu/mac/vt_video_decode_accelerator_mac.cc b/chromium/media/gpu/mac/vt_video_decode_accelerator_mac.cc index f00df04b313..af3230f4b54 100644 --- a/chromium/media/gpu/mac/vt_video_decode_accelerator_mac.cc +++ b/chromium/media/gpu/mac/vt_video_decode_accelerator_mac.cc @@ -196,7 +196,7 @@ base::ScopedCFTypeRef<CMFormatDescriptionRef> CreateVideoFormatH264( base::ScopedCFTypeRef<CMFormatDescriptionRef> CreateVideoFormatVP9( media::VideoColorSpace color_space, media::VideoCodecProfile profile, - base::Optional<gfx::HDRMetadata> hdr_metadata, + absl::optional<gfx::HDRMetadata> hdr_metadata, const gfx::Size& coded_size) { base::ScopedCFTypeRef<CFMutableDictionaryRef> format_config( CreateFormatExtensions(kCMVideoCodecType_VP9, profile, color_space, @@ -325,7 +325,7 @@ bool InitializeVideoToolboxInternal() { // Create a VP9 decoding session. if (!CreateVideoToolboxSession( CreateVideoFormatVP9(VideoColorSpace::REC709(), VP9PROFILE_PROFILE0, - base::nullopt, gfx::Size(720, 480)), + absl::nullopt, gfx::Size(720, 480)), /*require_hardware=*/true, /*is_hbd=*/false, &callback, &session, &configured_size)) { DVLOG(1) << "Hardware VP9 decoding with VideoToolbox is not supported"; @@ -933,7 +933,7 @@ void VTVideoDecodeAccelerator::DecodeTask(scoped_refptr<DecoderBuffer> buffer, // Compute and store frame properties. |image_size| gets filled in // later, since it comes from the decoder configuration. - base::Optional<int32_t> pic_order_cnt = + absl::optional<int32_t> pic_order_cnt = poc_.ComputePicOrderCnt(sps, slice_hdr); if (!pic_order_cnt.has_value()) { WriteToMediaLog(MediaLogMessageLevel::kERROR, diff --git a/chromium/media/gpu/mac/vt_video_encode_accelerator_mac.cc b/chromium/media/gpu/mac/vt_video_encode_accelerator_mac.cc index a879e765372..a7e1c74d7f4 100644 --- a/chromium/media/gpu/mac/vt_video_encode_accelerator_mac.cc +++ b/chromium/media/gpu/mac/vt_video_encode_accelerator_mac.cc @@ -166,6 +166,7 @@ bool VTVideoEncodeAccelerator::Initialize(const Config& config, frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; initial_bitrate_ = config.initial_bitrate; bitstream_buffer_size_ = config.input_visible_size.GetArea(); + require_low_delay_ = config.require_low_delay; if (!encoder_thread_.Start()) { DLOG(ERROR) << "Failed spawning encoder thread."; @@ -560,10 +561,19 @@ bool VTVideoEncodeAccelerator::ConfigureCompressionSession() { kVTCompressionPropertyKey_MaxKeyFrameInterval, 7200); rv &= session_property_setter.Set( kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240); - rv &= + DLOG_IF(ERROR, !rv) << " Setting session property failed."; + + // Setting MaxFrameDelayCount fails on low resolutions and arm64 macs, + // but we can use accelerated encoder anyway. See: crbug.com/1195177 + bool delay_count_rv = session_property_setter.Set(kVTCompressionPropertyKey_MaxFrameDelayCount, static_cast<int>(kNumInputBuffers)); - DLOG_IF(ERROR, !rv) << " Setting session property failed."; + if (!delay_count_rv) { + DLOG(ERROR) << " Setting frame delay count failed."; + if (require_low_delay_) + return false; + } + return rv; } diff --git a/chromium/media/gpu/mac/vt_video_encode_accelerator_mac.h b/chromium/media/gpu/mac/vt_video_encode_accelerator_mac.h index 70d1f764e54..43b2942a693 100644 --- a/chromium/media/gpu/mac/vt_video_encode_accelerator_mac.h +++ b/chromium/media/gpu/mac/vt_video_encode_accelerator_mac.h @@ -110,6 +110,13 @@ class MEDIA_GPU_EXPORT VTVideoEncodeAccelerator int32_t encoder_set_bitrate_; VideoCodecProfile h264_profile_; + // If True, the encoder fails initialization if setting of session's property + // kVTCompressionPropertyKey_MaxFrameDelayCount returns an error. + // Encoder can work even after if MaxFrameDelayCount fails, but it'll + // have larger latency on low resolutions, and it's bad for RTC. + // Context: https://crbug.com/1195177 https://crbug.com/webrtc/7304 + bool require_low_delay_ = true; + // Bitrate adjuster used to fix VideoToolbox's inconsistent bitrate issues. webrtc::BitrateAdjuster bitrate_adjuster_; diff --git a/chromium/media/gpu/v4l2/BUILD.gn b/chromium/media/gpu/v4l2/BUILD.gn index 32cc30eb84e..755f8bc4cae 100644 --- a/chromium/media/gpu/v4l2/BUILD.gn +++ b/chromium/media/gpu/v4l2/BUILD.gn @@ -35,10 +35,10 @@ source_set("v4l2") { "v4l2_device.h", "v4l2_device_poller.cc", "v4l2_device_poller.h", + "v4l2_framerate_control.cc", + "v4l2_framerate_control.h", "v4l2_h264_accelerator.cc", "v4l2_h264_accelerator.h", - "v4l2_h264_accelerator_chromium.cc", - "v4l2_h264_accelerator_chromium.h", "v4l2_h264_accelerator_legacy.cc", "v4l2_h264_accelerator_legacy.h", "v4l2_image_processor_backend.cc", diff --git a/chromium/media/gpu/v4l2/buffer_affinity_tracker.cc b/chromium/media/gpu/v4l2/buffer_affinity_tracker.cc index fdb62c9252a..7ada30e1960 100644 --- a/chromium/media/gpu/v4l2/buffer_affinity_tracker.cc +++ b/chromium/media/gpu/v4l2/buffer_affinity_tracker.cc @@ -23,7 +23,7 @@ void BufferAffinityTracker::resize(size_t nb_buffers) { DVLOGF(4) << this << " resize: " << nb_buffers; } -base::Optional<size_t> BufferAffinityTracker::get_buffer_for_id( +absl::optional<size_t> BufferAffinityTracker::get_buffer_for_id( gfx::GenericSharedMemoryId id) { base::AutoLock lock(lock_); @@ -39,7 +39,7 @@ base::Optional<size_t> BufferAffinityTracker::get_buffer_for_id( // No buffer available? No luck then. if (id_to_buffer_map_.size() == nb_buffers()) { DVLOGF(4) << this << " tracker is full!"; - return base::nullopt; + return absl::nullopt; } const size_t v4l2_id = id_to_buffer_map_.size(); diff --git a/chromium/media/gpu/v4l2/buffer_affinity_tracker.h b/chromium/media/gpu/v4l2/buffer_affinity_tracker.h index 0516efaf778..5019518967e 100644 --- a/chromium/media/gpu/v4l2/buffer_affinity_tracker.h +++ b/chromium/media/gpu/v4l2/buffer_affinity_tracker.h @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_GPU_V4L2_V4L2_BUFFER_AFFINITY_TRACKER_H_ -#define MEDIA_GPU_V4L2_V4L2_BUFFER_AFFINITY_TRACKER_H_ +#ifndef MEDIA_GPU_V4L2_BUFFER_AFFINITY_TRACKER_H_ +#define MEDIA_GPU_V4L2_BUFFER_AFFINITY_TRACKER_H_ #include <cstddef> #include <map> -#include "base/optional.h" #include "base/synchronization/lock.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/generic_shared_memory_id.h" namespace media { @@ -42,7 +42,7 @@ class BufferAffinityTracker { * On subsequent calls with the same id, that same V4L2 buffer will be * returned. */ - base::Optional<size_t> get_buffer_for_id(gfx::GenericSharedMemoryId id); + absl::optional<size_t> get_buffer_for_id(gfx::GenericSharedMemoryId id); private: base::Lock lock_; @@ -53,4 +53,4 @@ class BufferAffinityTracker { } // namespace media -#endif // MEDIA_GPU_V4L2_V4L2_BUFFER_AFFINITY_TRACKER_H_ +#endif // MEDIA_GPU_V4L2_BUFFER_AFFINITY_TRACKER_H_ diff --git a/chromium/media/gpu/v4l2/v4l2_decode_surface.h b/chromium/media/gpu/v4l2/v4l2_decode_surface.h index 865883b5df8..424752c0549 100644 --- a/chromium/media/gpu/v4l2/v4l2_decode_surface.h +++ b/chromium/media/gpu/v4l2/v4l2_decode_surface.h @@ -10,9 +10,9 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "media/gpu/v4l2/v4l2_device.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" struct v4l2_ext_controls; diff --git a/chromium/media/gpu/v4l2/v4l2_device.cc b/chromium/media/gpu/v4l2/v4l2_device.cc index 1cff2201faf..ba587e59247 100644 --- a/chromium/media/gpu/v4l2/v4l2_device.cc +++ b/chromium/media/gpu/v4l2/v4l2_device.cc @@ -300,9 +300,9 @@ class V4L2BuffersList : public base::RefCountedThreadSafe<V4L2BuffersList> { // Note that it is illegal to return the same buffer twice. void ReturnBuffer(size_t buffer_id); // Get any of the buffers in the list. There is no order guarantee whatsoever. - base::Optional<size_t> GetFreeBuffer(); + absl::optional<size_t> GetFreeBuffer(); // Get the buffer with specified index. - base::Optional<size_t> GetFreeBuffer(size_t requested_buffer_id); + absl::optional<size_t> GetFreeBuffer(size_t requested_buffer_id); // Number of buffers currently in this list. size_t size() const; @@ -322,13 +322,13 @@ void V4L2BuffersList::ReturnBuffer(size_t buffer_id) { DCHECK(inserted.second); } -base::Optional<size_t> V4L2BuffersList::GetFreeBuffer() { +absl::optional<size_t> V4L2BuffersList::GetFreeBuffer() { base::AutoLock auto_lock(lock_); auto iter = free_buffers_.begin(); if (iter == free_buffers_.end()) { DVLOGF(4) << "No free buffer available!"; - return base::nullopt; + return absl::nullopt; } size_t buffer_id = *iter; @@ -337,13 +337,13 @@ base::Optional<size_t> V4L2BuffersList::GetFreeBuffer() { return buffer_id; } -base::Optional<size_t> V4L2BuffersList::GetFreeBuffer( +absl::optional<size_t> V4L2BuffersList::GetFreeBuffer( size_t requested_buffer_id) { base::AutoLock auto_lock(lock_); return (free_buffers_.erase(requested_buffer_id) > 0) - ? base::make_optional(requested_buffer_id) - : base::nullopt; + ? absl::make_optional(requested_buffer_id) + : absl::nullopt; } size_t V4L2BuffersList::size() const { @@ -966,46 +966,46 @@ V4L2Queue::~V4L2Queue() { std::move(destroy_cb_).Run(); } -base::Optional<struct v4l2_format> V4L2Queue::SetFormat(uint32_t fourcc, +absl::optional<struct v4l2_format> V4L2Queue::SetFormat(uint32_t fourcc, const gfx::Size& size, size_t buffer_size) { struct v4l2_format format = BuildV4L2Format(type_, fourcc, size, buffer_size); if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0 || format.fmt.pix_mp.pixelformat != fourcc) { VPQLOGF(2) << "Failed to set format fourcc: " << FourccToString(fourcc); - return base::nullopt; + return absl::nullopt; } current_format_ = format; return current_format_; } -base::Optional<struct v4l2_format> V4L2Queue::TryFormat(uint32_t fourcc, +absl::optional<struct v4l2_format> V4L2Queue::TryFormat(uint32_t fourcc, const gfx::Size& size, size_t buffer_size) { struct v4l2_format format = BuildV4L2Format(type_, fourcc, size, buffer_size); if (device_->Ioctl(VIDIOC_TRY_FMT, &format) != 0 || format.fmt.pix_mp.pixelformat != fourcc) { VPQLOGF(2) << "Failed to try format fourcc: " << FourccToString(fourcc); - return base::nullopt; + return absl::nullopt; } return format; } -std::pair<base::Optional<struct v4l2_format>, int> V4L2Queue::GetFormat() { +std::pair<absl::optional<struct v4l2_format>, int> V4L2Queue::GetFormat() { struct v4l2_format format; memset(&format, 0, sizeof(format)); format.type = type_; if (device_->Ioctl(VIDIOC_G_FMT, &format) != 0) { VPQLOGF(2) << "Failed to get format"; - return std::make_pair(base::nullopt, errno); + return std::make_pair(absl::nullopt, errno); } return std::make_pair(format, 0); } -base::Optional<gfx::Rect> V4L2Queue::GetVisibleRect() { +absl::optional<gfx::Rect> V4L2Queue::GetVisibleRect() { // Some drivers prior to 4.13 only accept the non-MPLANE variant when using // VIDIOC_G_SELECTION. This block can be removed once we stop supporting // kernels < 4.13. @@ -1044,7 +1044,7 @@ base::Optional<gfx::Rect> V4L2Queue::GetVisibleRect() { } VQLOGF(1) << "Failed to get visible rect"; - return base::nullopt; + return absl::nullopt; } size_t V4L2Queue::AllocateBuffers(size_t count, enum v4l2_memory memory) { @@ -1069,7 +1069,7 @@ size_t V4L2Queue::AllocateBuffers(size_t count, enum v4l2_memory memory) { } // First query the number of planes in the buffers we are about to request. - base::Optional<v4l2_format> format = GetFormat().first; + absl::optional<v4l2_format> format = GetFormat().first; if (!format) { VQLOGF(1) << "Cannot get format."; return 0; @@ -1166,50 +1166,50 @@ v4l2_memory V4L2Queue::GetMemoryType() const { return memory_; } -base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer() { +absl::optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // No buffers allocated at the moment? if (!free_buffers_) - return base::nullopt; + return absl::nullopt; auto buffer_id = free_buffers_->GetFreeBuffer(); if (!buffer_id.has_value()) - return base::nullopt; + return absl::nullopt; return V4L2BufferRefFactory::CreateWritableRef( buffers_[buffer_id.value()]->v4l2_buffer(), weak_this_factory_.GetWeakPtr()); } -base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer( +absl::optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer( size_t requested_buffer_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // No buffers allocated at the moment? if (!free_buffers_) - return base::nullopt; + return absl::nullopt; auto buffer_id = free_buffers_->GetFreeBuffer(requested_buffer_id); if (!buffer_id.has_value()) - return base::nullopt; + return absl::nullopt; return V4L2BufferRefFactory::CreateWritableRef( buffers_[buffer_id.value()]->v4l2_buffer(), weak_this_factory_.GetWeakPtr()); } -base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBufferForFrame( +absl::optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBufferForFrame( const VideoFrame& frame) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // No buffers allocated at the moment? if (!free_buffers_) - return base::nullopt; + return absl::nullopt; if (memory_ != V4L2_MEMORY_DMABUF) { DVLOGF(1) << "Queue is not DMABUF"; - return base::nullopt; + return absl::nullopt; } gfx::GenericSharedMemoryId id; @@ -1219,12 +1219,12 @@ base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBufferForFrame( id = gfx::GenericSharedMemoryId(frame.DmabufFds()[0].get()); } else { DVLOGF(1) << "Unsupported frame provided"; - return base::nullopt; + return absl::nullopt; } const auto v4l2_id = affinity_tracker_.get_buffer_for_id(id); if (!v4l2_id) { - return base::nullopt; + return absl::nullopt; } return GetFreeBuffer(*v4l2_id); @@ -1381,7 +1381,7 @@ bool V4L2Queue::SupportsRequests() { return supports_requests_; } -base::Optional<struct v4l2_format> V4L2Queue::SetModifierFormat( +absl::optional<struct v4l2_format> V4L2Queue::SetModifierFormat( uint64_t modifier, const gfx::Size& size) { if (DRM_FORMAT_MOD_QCOM_COMPRESSED == modifier) { @@ -1391,7 +1391,7 @@ base::Optional<struct v4l2_format> V4L2Queue::SetModifierFormat( VPLOGF(1) << "Failed to set magic modifier format."; return format; } - return base::nullopt; + return absl::nullopt; } // This class is used to expose V4L2Queue's constructor to this module. This is @@ -1777,12 +1777,12 @@ gfx::Size V4L2Device::AllocatedSizeFromV4L2Format( } // static -base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout( +absl::optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout( const struct v4l2_format& format) { if (!V4L2_TYPE_IS_MULTIPLANAR(format.type)) { VLOGF(1) << "v4l2_buf_type is not multiplanar: " << std::hex << "0x" << format.type; - return base::nullopt; + return absl::nullopt; } const v4l2_pix_format_mplane& pix_mp = format.fmt.pix_mp; const uint32_t& pix_fmt = pix_mp.pixelformat; @@ -1790,7 +1790,7 @@ base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout( if (!video_fourcc) { VLOGF(1) << "Failed to convert pixel format to VideoPixelFormat: " << FourccToString(pix_fmt); - return base::nullopt; + return absl::nullopt; } const VideoPixelFormat video_format = video_fourcc->ToVideoPixelFormat(); const size_t num_buffers = pix_mp.num_planes; @@ -1798,14 +1798,14 @@ base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout( if (num_color_planes == 0) { VLOGF(1) << "Unsupported video format for NumPlanes(): " << VideoPixelFormatToString(video_format); - return base::nullopt; + return absl::nullopt; } if (num_buffers > num_color_planes) { VLOGF(1) << "pix_mp.num_planes: " << num_buffers << " should not be larger than NumPlanes(" << VideoPixelFormatToString(video_format) << "): " << num_color_planes; - return base::nullopt; + return absl::nullopt; } // Reserve capacity in advance to prevent unnecessary vector reallocation. std::vector<ColorPlaneLayout> planes; @@ -1839,7 +1839,7 @@ base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout( if (y_stride % 2 != 0 || pix_mp.height % 2 != 0) { VLOGF(1) << "Plane-Y stride and height should be even; stride: " << y_stride << ", height: " << pix_mp.height; - return base::nullopt; + return absl::nullopt; } const int32_t half_stride = y_stride / 2; const size_t plane_0_area = y_stride_abs * pix_mp.height; @@ -1853,7 +1853,7 @@ base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout( default: VLOGF(1) << "Cannot derive stride for each plane for pixel format " << FourccToString(pix_fmt); - return base::nullopt; + return absl::nullopt; } } @@ -1873,7 +1873,7 @@ base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout( // static size_t V4L2Device::GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt) { - base::Optional<Fourcc> fourcc = Fourcc::FromV4L2PixFmt(pix_fmt); + absl::optional<Fourcc> fourcc = Fourcc::FromV4L2PixFmt(pix_fmt); if (fourcc && fourcc->IsMultiPlanar()) { return VideoFrame::NumPlanes(fourcc->ToVideoPixelFormat()); } @@ -2041,7 +2041,7 @@ void V4L2Device::SchedulePoll() { device_poller_->SchedulePoll(); } -base::Optional<struct v4l2_event> V4L2Device::DequeueEvent() { +absl::optional<struct v4l2_event> V4L2Device::DequeueEvent() { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); struct v4l2_event event; memset(&event, 0, sizeof(event)); @@ -2050,7 +2050,7 @@ base::Optional<struct v4l2_event> V4L2Device::DequeueEvent() { // The ioctl will fail if there are no pending events. This is part of the // normal flow, so keep this log level low. VPLOGF(4) << "Failed to dequeue event"; - return base::nullopt; + return absl::nullopt; } return event; @@ -2119,7 +2119,7 @@ bool V4L2Device::SetExtCtrls(uint32_t ctrl_class, return result == 0; } -base::Optional<struct v4l2_ext_control> V4L2Device::GetCtrl(uint32_t ctrl_id) { +absl::optional<struct v4l2_ext_control> V4L2Device::GetCtrl(uint32_t ctrl_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_); struct v4l2_ext_control ctrl; memset(&ctrl, 0, sizeof(ctrl)); @@ -2132,7 +2132,7 @@ base::Optional<struct v4l2_ext_control> V4L2Device::GetCtrl(uint32_t ctrl_id) { if (Ioctl(VIDIOC_G_EXT_CTRLS, &ext_ctrls) != 0) { VPLOGF(3) << "Failed to get control"; - return base::nullopt; + return absl::nullopt; } return ctrl; @@ -2343,14 +2343,14 @@ bool V4L2RequestRef::ApplyQueueBuffer(struct v4l2_buffer* buffer) const { return request_->ApplyQueueBuffer(buffer); } -base::Optional<V4L2SubmittedRequestRef> V4L2RequestRef::Submit() && { +absl::optional<V4L2SubmittedRequestRef> V4L2RequestRef::Submit() && { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_NE(request_, nullptr); V4L2RequestRef self(std::move(*this)); if (!self.request_->Submit()) - return base::nullopt; + return absl::nullopt; return V4L2SubmittedRequestRef(self.request_); } @@ -2375,7 +2375,7 @@ V4L2RequestsQueue::~V4L2RequestsQueue() { media_fd_.reset(); } -base::Optional<base::ScopedFD> V4L2RequestsQueue::CreateRequestFD() { +absl::optional<base::ScopedFD> V4L2RequestsQueue::CreateRequestFD() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); int request_fd; @@ -2383,13 +2383,13 @@ base::Optional<base::ScopedFD> V4L2RequestsQueue::CreateRequestFD() { ioctl(media_fd_.get(), MEDIA_IOC_REQUEST_ALLOC, &request_fd)); if (ret < 0) { VPLOGF(1) << "Failed to create request"; - return base::nullopt; + return absl::nullopt; } return base::ScopedFD(request_fd); } -base::Optional<V4L2RequestRef> V4L2RequestsQueue::GetFreeRequest() { +absl::optional<V4L2RequestRef> V4L2RequestsQueue::GetFreeRequest() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); V4L2Request* request_ptr = @@ -2402,7 +2402,7 @@ base::Optional<V4L2RequestRef> V4L2RequestsQueue::GetFreeRequest() { auto request_fd = CreateRequestFD(); if (!request_fd.has_value()) { VLOGF(1) << "Error while creating a new request FD!"; - return base::nullopt; + return absl::nullopt; } // Not using std::make_unique because constructor is private. std::unique_ptr<V4L2Request> request( @@ -2417,7 +2417,7 @@ base::Optional<V4L2RequestRef> V4L2RequestsQueue::GetFreeRequest() { << "request is blocking."; if (!request_ptr->WaitForCompletion()) { VLOG(1) << "Timeout while waiting for request to complete."; - return base::nullopt; + return absl::nullopt; } free_requests_.pop(); } @@ -2425,7 +2425,7 @@ base::Optional<V4L2RequestRef> V4L2RequestsQueue::GetFreeRequest() { DCHECK(request_ptr); if (!request_ptr->Reset()) { VPLOGF(1) << "Failed to reset request"; - return base::nullopt; + return absl::nullopt; } return V4L2RequestRef(request_ptr); diff --git a/chromium/media/gpu/v4l2/v4l2_device.h b/chromium/media/gpu/v4l2/v4l2_device.h index 62262043721..50ddba9fa07 100644 --- a/chromium/media/gpu/v4l2/v4l2_device.h +++ b/chromium/media/gpu/v4l2/v4l2_device.h @@ -20,7 +20,6 @@ #include "base/containers/flat_map.h" #include "base/files/scoped_file.h" #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "media/base/video_codecs.h" #include "media/base/video_decoder_config.h" @@ -32,6 +31,7 @@ #include "media/gpu/v4l2/v4l2_device_poller.h" #include "media/video/video_decode_accelerator.h" #include "media/video/video_encode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_pixmap_handle.h" #include "ui/gl/gl_bindings.h" @@ -304,7 +304,7 @@ class MEDIA_GPU_EXPORT V4L2Queue // format is returned. It is guaranteed to feature the specified |fourcc|, // but any other parameter (including |size| and |buffer_size| may have been // adjusted by the driver, so the caller must check their values. - base::Optional<struct v4l2_format> SetFormat(uint32_t fourcc, + absl::optional<struct v4l2_format> SetFormat(uint32_t fourcc, const gfx::Size& size, size_t buffer_size) WARN_UNUSED_RESULT; @@ -313,16 +313,16 @@ class MEDIA_GPU_EXPORT V4L2Queue // be called anytime. // Returns an adjusted V4L2 format if |fourcc| is supported by the queue, or // |nullopt| if |fourcc| is not supported or an ioctl error happened. - base::Optional<struct v4l2_format> TryFormat(uint32_t fourcc, + absl::optional<struct v4l2_format> TryFormat(uint32_t fourcc, const gfx::Size& size, size_t buffer_size) WARN_UNUSED_RESULT; // Returns the currently set format on the queue. The result is returned as - // a std::pair where the first member is the format, or base::nullopt if the + // a std::pair where the first member is the format, or absl::nullopt if the // format could not be obtained due to an ioctl error. The second member is // only used in case of an error and contains the |errno| set by the failing - // ioctl. If the first member is not base::nullopt, the second member will + // ioctl. If the first member is not absl::nullopt, the second member will // always be zero. // // If the second member is 0, then the first member is guaranteed to have @@ -332,11 +332,11 @@ class MEDIA_GPU_EXPORT V4L2Queue // This pair is used because not all failures to get the format are // necessarily errors, so we need to way to let the use decide whether it // is one or not. - std::pair<base::Optional<struct v4l2_format>, int> GetFormat(); + std::pair<absl::optional<struct v4l2_format>, int> GetFormat(); // Codec-specific method to get the visible rectangle of the queue, using the // VIDIOC_G_SELECTION ioctl if available, or VIDIOC_G_CROP as a fallback. - base::Optional<gfx::Rect> GetVisibleRect(); + absl::optional<gfx::Rect> GetVisibleRect(); // Allocate |count| buffers for the current format of this queue, with a // specific |memory| allocation, and returns the number of buffers allocated @@ -367,13 +367,13 @@ class MEDIA_GPU_EXPORT V4L2Queue // // If the caller discards the returned reference, the underlying buffer is // made available to clients again. - base::Optional<V4L2WritableBufferRef> GetFreeBuffer(); + absl::optional<V4L2WritableBufferRef> GetFreeBuffer(); // Return the buffer at index |requested_buffer_id|, if it is available at // this time. // // If the buffer is currently in use or the provided index is invalid, - // return |base::nullopt|. - base::Optional<V4L2WritableBufferRef> GetFreeBuffer( + // return |absl::nullopt|. + absl::optional<V4L2WritableBufferRef> GetFreeBuffer( size_t requested_buffer_id); // Return a V4L2 buffer suitable for the passed VideoFrame. // @@ -390,7 +390,7 @@ class MEDIA_GPU_EXPORT V4L2Queue // since it will maximize performance in that case provided the number of // different VideoFrames passed to this method does not exceed the number of // V4L2 buffers allocated on the queue. - base::Optional<V4L2WritableBufferRef> GetFreeBufferForFrame( + absl::optional<V4L2WritableBufferRef> GetFreeBufferForFrame( const VideoFrame& frame); // Attempt to dequeue a buffer, and return a reference to it if one was @@ -433,7 +433,7 @@ class MEDIA_GPU_EXPORT V4L2Queue // TODO (b/166275274) : Remove this once V4L2 properly supports modifiers. // Out of band method to configure V4L2 for modifier use. - base::Optional<struct v4l2_format> SetModifierFormat(uint64_t modifier, + absl::optional<struct v4l2_format> SetModifierFormat(uint64_t modifier, const gfx::Size& size); private: @@ -450,7 +450,7 @@ class MEDIA_GPU_EXPORT V4L2Queue bool supports_requests_ = false; size_t planes_count_ = 0; // Current format as set by SetFormat. - base::Optional<struct v4l2_format> current_format_; + absl::optional<struct v4l2_format> current_format_; std::vector<std::unique_ptr<V4L2Buffer>> buffers_; @@ -520,7 +520,7 @@ class MEDIA_GPU_EXPORT V4L2RequestRef : public V4L2RequestRefBase { // Apply buffer to the request. bool ApplyQueueBuffer(struct v4l2_buffer* buffer) const; // Submits the request to the driver. - base::Optional<V4L2SubmittedRequestRef> Submit() &&; + absl::optional<V4L2SubmittedRequestRef> Submit() &&; private: friend class V4L2RequestsQueue; @@ -565,7 +565,7 @@ class MEDIA_GPU_EXPORT V4L2RequestsQueue { public: // Gets a free request. If no request is available, a non-valid request // reference will be returned. - base::Optional<V4L2RequestRef> GetFreeRequest(); + absl::optional<V4L2RequestRef> GetFreeRequest(); private: // File descriptor of the media device (/dev/mediaX) from which requests @@ -577,7 +577,7 @@ class MEDIA_GPU_EXPORT V4L2RequestsQueue { std::queue<V4L2Request*> free_requests_; // Returns a new request file descriptor. - base::Optional<base::ScopedFD> CreateRequestFD(); + absl::optional<base::ScopedFD> CreateRequestFD(); friend class V4L2Request; // Returns a request to the queue after being used. @@ -610,8 +610,8 @@ class MEDIA_GPU_EXPORT V4L2Device static int32_t H264LevelIdcToV4L2H264Level(uint8_t level_idc); // Composes VideoFrameLayout based on v4l2_format. - // If error occurs, it returns base::nullopt. - static base::Optional<VideoFrameLayout> V4L2FormatToVideoFrameLayout( + // If error occurs, it returns absl::nullopt. + static absl::optional<VideoFrameLayout> V4L2FormatToVideoFrameLayout( const struct v4l2_format& format); // Returns number of planes of |pix_fmt|. @@ -758,7 +758,7 @@ class MEDIA_GPU_EXPORT V4L2Device void SchedulePoll(); // Attempt to dequeue a V4L2 event and return it. - base::Optional<struct v4l2_event> DequeueEvent(); + absl::optional<struct v4l2_event> DequeueEvent(); // Returns requests queue to get free requests. A null pointer is returned if // the queue creation failed or if requests are not supported. @@ -773,9 +773,9 @@ class MEDIA_GPU_EXPORT V4L2Device std::vector<V4L2ExtCtrl> ctrls, V4L2RequestRef* request_ref = nullptr); - // Get the value of a single control, or base::nullopt of the control is not + // Get the value of a single control, or absl::nullopt of the control is not // exposed by the device. - base::Optional<struct v4l2_ext_control> GetCtrl(uint32_t ctrl_id); + absl::optional<struct v4l2_ext_control> GetCtrl(uint32_t ctrl_id); // Set periodic keyframe placement (group of pictures length) bool SetGOPLength(uint32_t gop_length); diff --git a/chromium/media/gpu/v4l2/v4l2_framerate_control.cc b/chromium/media/gpu/v4l2/v4l2_framerate_control.cc new file mode 100644 index 00000000000..6ba06543d51 --- /dev/null +++ b/chromium/media/gpu/v4l2/v4l2_framerate_control.cc @@ -0,0 +1,129 @@ +// Copyright 2021 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/gpu/v4l2/v4l2_framerate_control.h" + +#include "base/sequence_checker.h" + +namespace media { + +static constexpr int kMovingAverageWindowSize = 32; +static constexpr base::TimeDelta kFrameIntervalFor120fps = + base::TimeDelta::FromMilliseconds(8); +static constexpr base::TimeDelta kFrameIntervalFor24fps = + base::TimeDelta::FromMilliseconds(41); + +V4L2FrameRateControl::V4L2FrameRateControl( + scoped_refptr<V4L2Device> device, + scoped_refptr<base::SequencedTaskRunner> task_runner) + : device_(device), + framerate_control_present_(FrameRateControlPresent()), + current_frame_duration_avg_ms_(0), + last_frame_display_time_(base::TimeTicks::Now()), + frame_duration_moving_average_(kMovingAverageWindowSize), + task_runner_(task_runner), + weak_this_factory_(this) {} + +V4L2FrameRateControl::~V4L2FrameRateControl() = default; + +void V4L2FrameRateControl::UpdateFrameRate() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if ((frame_duration_moving_average_.count() < + frame_duration_moving_average_.depth())) { + return; + } + + const base::TimeDelta frame_duration_avg = + frame_duration_moving_average_.Average(); + + if (frame_duration_avg > kFrameIntervalFor120fps && + frame_duration_avg < kFrameIntervalFor24fps && + frame_duration_avg.InMilliseconds() != current_frame_duration_avg_ms_) { + current_frame_duration_avg_ms_ = frame_duration_avg.InMilliseconds(); + + struct v4l2_streamparm parms; + memset(&parms, 0, sizeof(parms)); + parms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + parms.parm.output.timeperframe.numerator = current_frame_duration_avg_ms_; + parms.parm.output.timeperframe.denominator = 1000L; + + const auto result = device_->Ioctl(VIDIOC_S_PARM, &parms); + LOG_IF(ERROR, result != 0) << "Failed to issue VIDIOC_S_PARM command"; + + VLOG(1) << "Average framerate: " << frame_duration_avg.ToHz(); + } +} + +// static +void V4L2FrameRateControl::RecordFrameDurationThunk( + base::WeakPtr<V4L2FrameRateControl> weak_this, + scoped_refptr<base::SequencedTaskRunner> task_runner) { + if (task_runner->RunsTasksInCurrentSequence()) { + if (weak_this) { + weak_this->RecordFrameDuration(); + } + } else { + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&V4L2FrameRateControl::RecordFrameDuration, weak_this)); + } +} + +void V4L2FrameRateControl::RecordFrameDuration() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + constexpr base::TimeDelta kMaxFrameInterval = + base::TimeDelta::FromMilliseconds(500); + const base::TimeTicks frame_display_time = base::TimeTicks::Now(); + const base::TimeDelta duration = + frame_display_time - last_frame_display_time_; + + // Frames are expected to be returned at a consistent cadence because the + // durations are recorded after the frame is displayed, but this isn't always + // the case. If the video is not visible, then the frames will be returned + // as soon as they are decoded. The window needs to be large enough to + // handle this scenario. The video may also be paused, in which case there + // could be a large duration. In this case, reset the filter. + if (duration > kMaxFrameInterval) + frame_duration_moving_average_.Reset(); + else + frame_duration_moving_average_.AddSample(duration); + + last_frame_display_time_ = frame_display_time; + + UpdateFrameRate(); +} + +void V4L2FrameRateControl::AttachToVideoFrame( + scoped_refptr<VideoFrame>& video_frame) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!framerate_control_present_) + return; + + video_frame->AddDestructionObserver( + base::BindOnce(&V4L2FrameRateControl::RecordFrameDurationThunk, + weak_this_factory_.GetWeakPtr(), task_runner_)); +} + +bool V4L2FrameRateControl::FrameRateControlPresent() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(device_); + + struct v4l2_streamparm parms; + memset(&parms, 0, sizeof(parms)); + parms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + // Try to set the framerate to 30fps to see if the control is available. + // VIDIOC_G_PARM can not be used as it does not return the current framerate. + parms.parm.output.timeperframe.numerator = 30; + parms.parm.output.timeperframe.denominator = 1000L; + + if (device_->Ioctl(VIDIOC_S_PARM, &parms) != 0) { + VLOG(1) << "Failed to issue VIDIOC_S_PARM command"; + return false; + } + + return parms.parm.output.capability & V4L2_CAP_TIMEPERFRAME; +} + +} // namespace media diff --git a/chromium/media/gpu/v4l2/v4l2_framerate_control.h b/chromium/media/gpu/v4l2/v4l2_framerate_control.h new file mode 100644 index 00000000000..c82d5c9949b --- /dev/null +++ b/chromium/media/gpu/v4l2/v4l2_framerate_control.h @@ -0,0 +1,61 @@ +// Copyright 2021 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. + +#ifndef MEDIA_GPU_V4L2_V4L2_FRAMERATE_CONTROL_H_ +#define MEDIA_GPU_V4L2_V4L2_FRAMERATE_CONTROL_H_ + +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "base/sequenced_task_runner.h" +#include "base/time/time.h" +#include "media/base/moving_average.h" +#include "media/base/video_frame.h" +#include "media/gpu/v4l2/v4l2_device.h" + +namespace media { + +// Some hardware decoder implementations (Qualcomm) need to know the framerate +// of the content being decoded. On these platforms the hardware uses the +// framerate to allocate resources correctly. The number of simultaneous +// contexts supported is dependent on hardware usage, i.e. only 1 4KP60 decode +// may be supported but if the framerate is reduce to 30 fps, 2 4KP30 clips +// can be decoded simultaneously. +class V4L2FrameRateControl { + public: + V4L2FrameRateControl(scoped_refptr<V4L2Device> device, + scoped_refptr<base::SequencedTaskRunner> task_runner); + ~V4L2FrameRateControl(); + + // Trampoline method for VideoFrame destructor callbacks to be directed + // to this class' task runner. + static void RecordFrameDurationThunk( + base::WeakPtr<V4L2FrameRateControl> weak_this, + scoped_refptr<base::SequencedTaskRunner> task_runner); + + // Called from the VideoFrame destructor. Stores the duration between + // subsequent video frames into the moving average. + void RecordFrameDuration(); + + // Register this class as a VideoFrame destructor observer. + void AttachToVideoFrame(scoped_refptr<VideoFrame>& video_frame); + + private: + void UpdateFrameRate(); + bool FrameRateControlPresent(); + + scoped_refptr<V4L2Device> device_; + const bool framerate_control_present_; + int64_t current_frame_duration_avg_ms_; + base::TimeTicks last_frame_display_time_; + MovingAverage frame_duration_moving_average_; + + const scoped_refptr<base::SequencedTaskRunner> task_runner_; + base::WeakPtrFactory<V4L2FrameRateControl> weak_this_factory_; + + SEQUENCE_CHECKER(sequence_checker_); +}; + +} // namespace media + +#endif // MEDIA_GPU_V4L2_V4L2_FRAMERATE_CONTROL_H_ diff --git a/chromium/media/gpu/v4l2/v4l2_h264_accelerator.cc b/chromium/media/gpu/v4l2/v4l2_h264_accelerator.cc index 5afa0cd7012..26616559494 100644 --- a/chromium/media/gpu/v4l2/v4l2_h264_accelerator.cc +++ b/chromium/media/gpu/v4l2/v4l2_h264_accelerator.cc @@ -44,32 +44,6 @@ class V4L2H264Picture : public H264Picture { DISALLOW_COPY_AND_ASSIGN(V4L2H264Picture); }; -// static -bool V4L2H264Accelerator::SupportsUpstreamABI(V4L2Device* device) { - struct v4l2_querymenu qmenu; - - // This accelerator currently supports frame-based decoding only. Print an - // error at runtime if we try to use it with a slice-based decoder. - memset(&qmenu, 0, sizeof(qmenu)); - qmenu.id = V4L2_CID_STATELESS_H264_DECODE_MODE; - qmenu.index = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED; - - if (device->Ioctl(VIDIOC_QUERYMENU, &qmenu) < 0) { - switch (errno) { - case EINVAL: - VLOGF(1) - << "This decoder does not support the frame-based stateless API"; - return false; - default: - VPLOGF(1) << "Error while checking for H264_DECODE_MODE control"; - return false; - } - } - - VLOGF(1) << "This decoder supports the frame-based stateless API"; - return true; -} - V4L2H264Accelerator::V4L2H264Accelerator( V4L2DecodeSurfaceHandler* surface_handler, V4L2Device* device) @@ -322,14 +296,6 @@ H264Decoder::H264Accelerator::Status V4L2H264Accelerator::SubmitSlice( SHDR_TO_V4L2DPARM(pic_order_cnt_bit_size); #undef SHDR_TO_V4L2DPARM -#define SET_V4L2_DPARM_FLAG_IF(cond, flag) \ - priv_->v4l2_decode_param.flags |= ((slice_hdr->cond) ? (flag) : 0) - SET_V4L2_DPARM_FLAG_IF(idr_pic_flag, V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC); - SET_V4L2_DPARM_FLAG_IF(field_pic_flag, V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC); - SET_V4L2_DPARM_FLAG_IF(bottom_field_flag, - V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD); -#undef SET_V4L2_DPARM_FLAG_IF - scoped_refptr<V4L2DecodeSurface> dec_surface = H264PictureToV4L2DecodeSurface(pic.get()); @@ -353,9 +319,24 @@ H264Decoder::H264Accelerator::Status V4L2H264Accelerator::SubmitDecode( scoped_refptr<V4L2DecodeSurface> dec_surface = H264PictureToV4L2DecodeSurface(pic.get()); - if (pic->idr) { - priv_->v4l2_decode_param.flags |= 1; + + switch (pic->field) { + case H264Picture::FIELD_NONE: + priv_->v4l2_decode_param.flags = 0; + break; + case H264Picture::FIELD_TOP: + priv_->v4l2_decode_param.flags = V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC; + break; + case H264Picture::FIELD_BOTTOM: + priv_->v4l2_decode_param.flags = + (V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC | + V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD); + break; } + + if (pic->idr) + priv_->v4l2_decode_param.flags |= V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC; + priv_->v4l2_decode_param.top_field_order_cnt = pic->top_field_order_cnt; priv_->v4l2_decode_param.bottom_field_order_cnt = pic->bottom_field_order_cnt; diff --git a/chromium/media/gpu/v4l2/v4l2_h264_accelerator.h b/chromium/media/gpu/v4l2/v4l2_h264_accelerator.h index 7d1f2893451..38b90b1494f 100644 --- a/chromium/media/gpu/v4l2/v4l2_h264_accelerator.h +++ b/chromium/media/gpu/v4l2/v4l2_h264_accelerator.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_UPSTREAM_H_ -#define MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_UPSTREAM_H_ +#ifndef MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_H_ +#define MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_H_ #include <memory> #include <vector> @@ -24,10 +24,6 @@ class V4L2H264Accelerator : public H264Decoder::H264Accelerator { public: using Status = H264Decoder::H264Accelerator::Status; - // Checks whether drivers support the upstream ABI or whether we should - // fallback to the V4L2ChromeH264Accelerator. - static bool SupportsUpstreamABI(V4L2Device* device); - explicit V4L2H264Accelerator(V4L2DecodeSurfaceHandler* surface_handler, V4L2Device* device); ~V4L2H264Accelerator() override; @@ -71,4 +67,4 @@ class V4L2H264Accelerator : public H264Decoder::H264Accelerator { } // namespace media -#endif // MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_UPSTREAM_H_ +#endif // MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_H_ diff --git a/chromium/media/gpu/v4l2/v4l2_h264_accelerator_chromium.cc b/chromium/media/gpu/v4l2/v4l2_h264_accelerator_chromium.cc deleted file mode 100644 index 672cc7fb32a..00000000000 --- a/chromium/media/gpu/v4l2/v4l2_h264_accelerator_chromium.cc +++ /dev/null @@ -1,491 +0,0 @@ -// Copyright 2018 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/gpu/v4l2/v4l2_h264_accelerator_chromium.h" - -// TODO(987856): prevent legacy headers being included from videodev2.h until -// v4.14 -// support is deprecated. -#define _H264_CTRLS_LEGACY_H_ - -#include <linux/media/h264-ctrls.h> -#include <linux/videodev2.h> -#include <type_traits> - -#include "base/logging.h" -#include "base/stl_util.h" -#include "media/gpu/macros.h" -#include "media/gpu/v4l2/v4l2_decode_surface.h" -#include "media/gpu/v4l2/v4l2_decode_surface_handler.h" -#include "media/gpu/v4l2/v4l2_device.h" - -namespace media { - -// This struct contains the kernel-specific parts of the H264 acceleration, -// that we don't want to expose in the .h file since they may differ from -// upstream. -struct V4L2H264AcceleratorPrivate { - // TODO(posciak): This should be queried from hardware once supported. - static constexpr size_t kMaxSlices = 16; - - struct v4l2_ctrl_h264_slice_params v4l2_slice_params[kMaxSlices]; - struct v4l2_ctrl_h264_decode_params v4l2_decode_param; -}; - -class V4L2H264Picture : public H264Picture { - public: - explicit V4L2H264Picture(scoped_refptr<V4L2DecodeSurface> dec_surface) - : dec_surface_(std::move(dec_surface)) {} - - V4L2H264Picture* AsV4L2H264Picture() override { return this; } - scoped_refptr<V4L2DecodeSurface> dec_surface() { return dec_surface_; } - - private: - ~V4L2H264Picture() override {} - - scoped_refptr<V4L2DecodeSurface> dec_surface_; - - DISALLOW_COPY_AND_ASSIGN(V4L2H264Picture); -}; - -V4L2ChromiumH264Accelerator::V4L2ChromiumH264Accelerator( - V4L2DecodeSurfaceHandler* surface_handler, - V4L2Device* device) - : num_slices_(0), - surface_handler_(surface_handler), - device_(device), - priv_(std::make_unique<V4L2H264AcceleratorPrivate>()) { - DCHECK(surface_handler_); -} - -V4L2ChromiumH264Accelerator::~V4L2ChromiumH264Accelerator() {} - -scoped_refptr<H264Picture> V4L2ChromiumH264Accelerator::CreateH264Picture() { - scoped_refptr<V4L2DecodeSurface> dec_surface = - surface_handler_->CreateSurface(); - if (!dec_surface) - return nullptr; - - return new V4L2H264Picture(dec_surface); -} - -void V4L2ChromiumH264Accelerator::H264PictureListToDPBIndicesList( - const H264Picture::Vector& src_pic_list, - uint8_t dst_list[kDPBIndicesListSize]) { - size_t i; - for (i = 0; i < src_pic_list.size() && i < kDPBIndicesListSize; ++i) { - const H264Picture* pic = (src_pic_list[i]).get(); - dst_list[i] = pic ? pic->dpb_position : VIDEO_MAX_FRAME; - } - - while (i < kDPBIndicesListSize) - dst_list[i++] = VIDEO_MAX_FRAME; -} - -void V4L2ChromiumH264Accelerator::H264DPBToV4L2DPB( - const H264DPB& dpb, - std::vector<scoped_refptr<V4L2DecodeSurface>>* ref_surfaces) { - memset(priv_->v4l2_decode_param.dpb, 0, sizeof(priv_->v4l2_decode_param.dpb)); - size_t i = 0; - for (const auto& pic : dpb) { - if (i >= base::size(priv_->v4l2_decode_param.dpb)) { - VLOGF(1) << "Invalid DPB size"; - break; - } - - int index = VIDEO_MAX_FRAME; - if (!pic->nonexisting) { - scoped_refptr<V4L2DecodeSurface> dec_surface = - H264PictureToV4L2DecodeSurface(pic.get()); - index = dec_surface->GetReferenceID(); - ref_surfaces->push_back(dec_surface); - } - - struct v4l2_h264_dpb_entry& entry = priv_->v4l2_decode_param.dpb[i++]; - entry.reference_ts = index; - entry.frame_num = pic->frame_num; - entry.pic_num = pic->pic_num; - entry.top_field_order_cnt = pic->top_field_order_cnt; - entry.bottom_field_order_cnt = pic->bottom_field_order_cnt; - entry.flags = (pic->ref ? V4L2_H264_DPB_ENTRY_FLAG_ACTIVE : 0) | - (pic->long_term ? V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0); - } -} - -H264Decoder::H264Accelerator::Status V4L2ChromiumH264Accelerator::SubmitFrameMetadata( - const H264SPS* sps, - const H264PPS* pps, - const H264DPB& dpb, - const H264Picture::Vector& ref_pic_listp0, - const H264Picture::Vector& ref_pic_listb0, - const H264Picture::Vector& ref_pic_listb1, - scoped_refptr<H264Picture> pic) { - struct v4l2_ext_control ctrl; - std::vector<struct v4l2_ext_control> ctrls; - - struct v4l2_ctrl_h264_sps v4l2_sps; - memset(&v4l2_sps, 0, sizeof(v4l2_sps)); - v4l2_sps.constraint_set_flags = - (sps->constraint_set0_flag ? V4L2_H264_SPS_CONSTRAINT_SET0_FLAG : 0) | - (sps->constraint_set1_flag ? V4L2_H264_SPS_CONSTRAINT_SET1_FLAG : 0) | - (sps->constraint_set2_flag ? V4L2_H264_SPS_CONSTRAINT_SET2_FLAG : 0) | - (sps->constraint_set3_flag ? V4L2_H264_SPS_CONSTRAINT_SET3_FLAG : 0) | - (sps->constraint_set4_flag ? V4L2_H264_SPS_CONSTRAINT_SET4_FLAG : 0) | - (sps->constraint_set5_flag ? V4L2_H264_SPS_CONSTRAINT_SET5_FLAG : 0); -#define SPS_TO_V4L2SPS(a) v4l2_sps.a = sps->a - SPS_TO_V4L2SPS(profile_idc); - SPS_TO_V4L2SPS(level_idc); - SPS_TO_V4L2SPS(seq_parameter_set_id); - SPS_TO_V4L2SPS(chroma_format_idc); - SPS_TO_V4L2SPS(bit_depth_luma_minus8); - SPS_TO_V4L2SPS(bit_depth_chroma_minus8); - SPS_TO_V4L2SPS(log2_max_frame_num_minus4); - SPS_TO_V4L2SPS(pic_order_cnt_type); - SPS_TO_V4L2SPS(log2_max_pic_order_cnt_lsb_minus4); - SPS_TO_V4L2SPS(offset_for_non_ref_pic); - SPS_TO_V4L2SPS(offset_for_top_to_bottom_field); - SPS_TO_V4L2SPS(num_ref_frames_in_pic_order_cnt_cycle); - - static_assert(std::extent<decltype(v4l2_sps.offset_for_ref_frame)>() == - std::extent<decltype(sps->offset_for_ref_frame)>(), - "offset_for_ref_frame arrays must be same size"); - for (size_t i = 0; i < base::size(v4l2_sps.offset_for_ref_frame); ++i) - v4l2_sps.offset_for_ref_frame[i] = sps->offset_for_ref_frame[i]; - SPS_TO_V4L2SPS(max_num_ref_frames); - SPS_TO_V4L2SPS(pic_width_in_mbs_minus1); - SPS_TO_V4L2SPS(pic_height_in_map_units_minus1); -#undef SPS_TO_V4L2SPS - -#define SET_V4L2_SPS_FLAG_IF(cond, flag) \ - v4l2_sps.flags |= ((sps->cond) ? (flag) : 0) - SET_V4L2_SPS_FLAG_IF(separate_colour_plane_flag, - V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE); - SET_V4L2_SPS_FLAG_IF(qpprime_y_zero_transform_bypass_flag, - V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); - SET_V4L2_SPS_FLAG_IF(delta_pic_order_always_zero_flag, - V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); - SET_V4L2_SPS_FLAG_IF(gaps_in_frame_num_value_allowed_flag, - V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED); - SET_V4L2_SPS_FLAG_IF(frame_mbs_only_flag, V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); - SET_V4L2_SPS_FLAG_IF(mb_adaptive_frame_field_flag, - V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); - SET_V4L2_SPS_FLAG_IF(direct_8x8_inference_flag, - V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); -#undef SET_V4L2_SPS_FLAG_IF - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_VIDEO_H264_SPS; - ctrl.size = sizeof(v4l2_sps); - ctrl.ptr = &v4l2_sps; - ctrls.push_back(ctrl); - - struct v4l2_ctrl_h264_pps v4l2_pps; - memset(&v4l2_pps, 0, sizeof(v4l2_pps)); -#define PPS_TO_V4L2PPS(a) v4l2_pps.a = pps->a - PPS_TO_V4L2PPS(pic_parameter_set_id); - PPS_TO_V4L2PPS(seq_parameter_set_id); - PPS_TO_V4L2PPS(num_slice_groups_minus1); - PPS_TO_V4L2PPS(num_ref_idx_l0_default_active_minus1); - PPS_TO_V4L2PPS(num_ref_idx_l1_default_active_minus1); - PPS_TO_V4L2PPS(weighted_bipred_idc); - PPS_TO_V4L2PPS(pic_init_qp_minus26); - PPS_TO_V4L2PPS(pic_init_qs_minus26); - PPS_TO_V4L2PPS(chroma_qp_index_offset); - PPS_TO_V4L2PPS(second_chroma_qp_index_offset); -#undef PPS_TO_V4L2PPS - -#define SET_V4L2_PPS_FLAG_IF(cond, flag) \ - v4l2_pps.flags |= ((pps->cond) ? (flag) : 0) - SET_V4L2_PPS_FLAG_IF(entropy_coding_mode_flag, - V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); - SET_V4L2_PPS_FLAG_IF( - bottom_field_pic_order_in_frame_present_flag, - V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); - SET_V4L2_PPS_FLAG_IF(weighted_pred_flag, V4L2_H264_PPS_FLAG_WEIGHTED_PRED); - SET_V4L2_PPS_FLAG_IF(deblocking_filter_control_present_flag, - V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); - SET_V4L2_PPS_FLAG_IF(constrained_intra_pred_flag, - V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); - SET_V4L2_PPS_FLAG_IF(redundant_pic_cnt_present_flag, - V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); - SET_V4L2_PPS_FLAG_IF(transform_8x8_mode_flag, - V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); - SET_V4L2_PPS_FLAG_IF(pic_scaling_matrix_present_flag, - V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT); -#undef SET_V4L2_PPS_FLAG_IF - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_VIDEO_H264_PPS; - ctrl.size = sizeof(v4l2_pps); - ctrl.ptr = &v4l2_pps; - ctrls.push_back(ctrl); - - struct v4l2_ctrl_h264_scaling_matrix v4l2_scaling_matrix; - memset(&v4l2_scaling_matrix, 0, sizeof(v4l2_scaling_matrix)); - - static_assert( - std::extent<decltype(v4l2_scaling_matrix.scaling_list_4x4)>() <= - std::extent<decltype(pps->scaling_list4x4)>() && - std::extent<decltype(v4l2_scaling_matrix.scaling_list_4x4[0])>() <= - std::extent<decltype(pps->scaling_list4x4[0])>() && - std::extent<decltype(v4l2_scaling_matrix.scaling_list_8x8)>() <= - std::extent<decltype(pps->scaling_list8x8)>() && - std::extent<decltype(v4l2_scaling_matrix.scaling_list_8x8[0])>() <= - std::extent<decltype(pps->scaling_list8x8[0])>(), - "scaling_lists must be of correct size"); - static_assert( - std::extent<decltype(v4l2_scaling_matrix.scaling_list_4x4)>() <= - std::extent<decltype(sps->scaling_list4x4)>() && - std::extent<decltype(v4l2_scaling_matrix.scaling_list_4x4[0])>() <= - std::extent<decltype(sps->scaling_list4x4[0])>() && - std::extent<decltype(v4l2_scaling_matrix.scaling_list_8x8)>() <= - std::extent<decltype(sps->scaling_list8x8)>() && - std::extent<decltype(v4l2_scaling_matrix.scaling_list_8x8[0])>() <= - std::extent<decltype(sps->scaling_list8x8[0])>(), - "scaling_lists must be of correct size"); - - const auto* scaling_list4x4 = &sps->scaling_list4x4[0]; - const auto* scaling_list8x8 = &sps->scaling_list8x8[0]; - if (pps->pic_scaling_matrix_present_flag) { - scaling_list4x4 = &pps->scaling_list4x4[0]; - scaling_list8x8 = &pps->scaling_list8x8[0]; - } - - for (size_t i = 0; i < base::size(v4l2_scaling_matrix.scaling_list_4x4); - ++i) { - for (size_t j = 0; j < base::size(v4l2_scaling_matrix.scaling_list_4x4[i]); - ++j) { - v4l2_scaling_matrix.scaling_list_4x4[i][j] = scaling_list4x4[i][j]; - } - } - for (size_t i = 0; i < base::size(v4l2_scaling_matrix.scaling_list_8x8); - ++i) { - for (size_t j = 0; j < base::size(v4l2_scaling_matrix.scaling_list_8x8[i]); - ++j) { - v4l2_scaling_matrix.scaling_list_8x8[i][j] = scaling_list8x8[i][j]; - } - } - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX; - ctrl.size = sizeof(v4l2_scaling_matrix); - ctrl.ptr = &v4l2_scaling_matrix; - ctrls.push_back(ctrl); - - scoped_refptr<V4L2DecodeSurface> dec_surface = - H264PictureToV4L2DecodeSurface(pic.get()); - - struct v4l2_ext_controls ext_ctrls; - memset(&ext_ctrls, 0, sizeof(ext_ctrls)); - ext_ctrls.count = ctrls.size(); - ext_ctrls.controls = &ctrls[0]; - dec_surface->PrepareSetCtrls(&ext_ctrls); - if (device_->Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) != 0) { - VPLOGF(1) << "ioctl() failed: VIDIOC_S_EXT_CTRLS"; - return Status::kFail; - } - - H264PictureListToDPBIndicesList(ref_pic_listp0, - priv_->v4l2_decode_param.ref_pic_list_p0); - H264PictureListToDPBIndicesList(ref_pic_listb0, - priv_->v4l2_decode_param.ref_pic_list_b0); - H264PictureListToDPBIndicesList(ref_pic_listb1, - priv_->v4l2_decode_param.ref_pic_list_b1); - - std::vector<scoped_refptr<V4L2DecodeSurface>> ref_surfaces; - H264DPBToV4L2DPB(dpb, &ref_surfaces); - dec_surface->SetReferenceSurfaces(ref_surfaces); - - return Status::kOk; -} - -H264Decoder::H264Accelerator::Status V4L2ChromiumH264Accelerator::SubmitSlice( - const H264PPS* pps, - const H264SliceHeader* slice_hdr, - const H264Picture::Vector& ref_pic_list0, - const H264Picture::Vector& ref_pic_list1, - scoped_refptr<H264Picture> pic, - const uint8_t* data, - size_t size, - const std::vector<SubsampleEntry>& subsamples) { - if (num_slices_ == priv_->kMaxSlices) { - VLOGF(1) << "Over limit of supported slices per frame"; - return Status::kFail; - } - - struct v4l2_ctrl_h264_slice_params& v4l2_slice_param = - priv_->v4l2_slice_params[num_slices_++]; - memset(&v4l2_slice_param, 0, sizeof(v4l2_slice_param)); - - v4l2_slice_param.size = size; -#define SHDR_TO_V4L2SPARM(a) v4l2_slice_param.a = slice_hdr->a - SHDR_TO_V4L2SPARM(header_bit_size); - SHDR_TO_V4L2SPARM(first_mb_in_slice); - SHDR_TO_V4L2SPARM(slice_type); - SHDR_TO_V4L2SPARM(pic_parameter_set_id); - SHDR_TO_V4L2SPARM(colour_plane_id); - SHDR_TO_V4L2SPARM(frame_num); - SHDR_TO_V4L2SPARM(idr_pic_id); - SHDR_TO_V4L2SPARM(pic_order_cnt_lsb); - SHDR_TO_V4L2SPARM(delta_pic_order_cnt_bottom); - SHDR_TO_V4L2SPARM(delta_pic_order_cnt0); - SHDR_TO_V4L2SPARM(delta_pic_order_cnt1); - SHDR_TO_V4L2SPARM(redundant_pic_cnt); - SHDR_TO_V4L2SPARM(dec_ref_pic_marking_bit_size); - SHDR_TO_V4L2SPARM(cabac_init_idc); - SHDR_TO_V4L2SPARM(slice_qp_delta); - SHDR_TO_V4L2SPARM(slice_qs_delta); - SHDR_TO_V4L2SPARM(disable_deblocking_filter_idc); - SHDR_TO_V4L2SPARM(slice_alpha_c0_offset_div2); - SHDR_TO_V4L2SPARM(slice_beta_offset_div2); - SHDR_TO_V4L2SPARM(num_ref_idx_l0_active_minus1); - SHDR_TO_V4L2SPARM(num_ref_idx_l1_active_minus1); - SHDR_TO_V4L2SPARM(pic_order_cnt_bit_size); -#undef SHDR_TO_V4L2SPARM - -#define SET_V4L2_SPARM_FLAG_IF(cond, flag) \ - v4l2_slice_param.flags |= ((slice_hdr->cond) ? (flag) : 0) - SET_V4L2_SPARM_FLAG_IF(field_pic_flag, V4L2_H264_SLICE_FLAG_FIELD_PIC); - SET_V4L2_SPARM_FLAG_IF(bottom_field_flag, V4L2_H264_SLICE_FLAG_BOTTOM_FIELD); - SET_V4L2_SPARM_FLAG_IF(direct_spatial_mv_pred_flag, - V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED); - SET_V4L2_SPARM_FLAG_IF(sp_for_switch_flag, - V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH); -#undef SET_V4L2_SPARM_FLAG_IF - - struct v4l2_h264_pred_weight_table* pred_weight_table = - &v4l2_slice_param.pred_weight_table; - - if (((slice_hdr->IsPSlice() || slice_hdr->IsSPSlice()) && - pps->weighted_pred_flag) || - (slice_hdr->IsBSlice() && pps->weighted_bipred_idc == 1)) { - pred_weight_table->luma_log2_weight_denom = - slice_hdr->luma_log2_weight_denom; - pred_weight_table->chroma_log2_weight_denom = - slice_hdr->chroma_log2_weight_denom; - - struct v4l2_h264_weight_factors* factorsl0 = - &pred_weight_table->weight_factors[0]; - - for (int i = 0; i < 32; ++i) { - factorsl0->luma_weight[i] = - slice_hdr->pred_weight_table_l0.luma_weight[i]; - factorsl0->luma_offset[i] = - slice_hdr->pred_weight_table_l0.luma_offset[i]; - - for (int j = 0; j < 2; ++j) { - factorsl0->chroma_weight[i][j] = - slice_hdr->pred_weight_table_l0.chroma_weight[i][j]; - factorsl0->chroma_offset[i][j] = - slice_hdr->pred_weight_table_l0.chroma_offset[i][j]; - } - } - - if (slice_hdr->IsBSlice()) { - struct v4l2_h264_weight_factors* factorsl1 = - &pred_weight_table->weight_factors[1]; - - for (int i = 0; i < 32; ++i) { - factorsl1->luma_weight[i] = - slice_hdr->pred_weight_table_l1.luma_weight[i]; - factorsl1->luma_offset[i] = - slice_hdr->pred_weight_table_l1.luma_offset[i]; - - for (int j = 0; j < 2; ++j) { - factorsl1->chroma_weight[i][j] = - slice_hdr->pred_weight_table_l1.chroma_weight[i][j]; - factorsl1->chroma_offset[i][j] = - slice_hdr->pred_weight_table_l1.chroma_offset[i][j]; - } - } - } - } - - H264PictureListToDPBIndicesList(ref_pic_list0, - v4l2_slice_param.ref_pic_list0); - H264PictureListToDPBIndicesList(ref_pic_list1, - v4l2_slice_param.ref_pic_list1); - - scoped_refptr<V4L2DecodeSurface> dec_surface = - H264PictureToV4L2DecodeSurface(pic.get()); - - priv_->v4l2_decode_param.nal_ref_idc = slice_hdr->nal_ref_idc; - - // TODO(posciak): Don't add start code back here, but have it passed from - // the parser. - size_t data_copy_size = size + 3; - std::unique_ptr<uint8_t[]> data_copy(new uint8_t[data_copy_size]); - memset(data_copy.get(), 0, data_copy_size); - data_copy[2] = 0x01; - memcpy(data_copy.get() + 3, data, size); - return surface_handler_->SubmitSlice(dec_surface.get(), data_copy.get(), - data_copy_size) - ? Status::kOk - : Status::kFail; -} - -H264Decoder::H264Accelerator::Status V4L2ChromiumH264Accelerator::SubmitDecode( - scoped_refptr<H264Picture> pic) { - scoped_refptr<V4L2DecodeSurface> dec_surface = - H264PictureToV4L2DecodeSurface(pic.get()); - - priv_->v4l2_decode_param.num_slices = num_slices_; - if (pic->idr) { - priv_->v4l2_decode_param.flags |= 1; - } - priv_->v4l2_decode_param.top_field_order_cnt = pic->top_field_order_cnt; - priv_->v4l2_decode_param.bottom_field_order_cnt = pic->bottom_field_order_cnt; - - struct v4l2_ext_control ctrl; - std::vector<struct v4l2_ext_control> ctrls; - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS; - ctrl.size = sizeof(priv_->v4l2_slice_params); - ctrl.ptr = priv_->v4l2_slice_params; - ctrls.push_back(ctrl); - - memset(&ctrl, 0, sizeof(ctrl)); - ctrl.id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS; - ctrl.size = sizeof(priv_->v4l2_decode_param); - ctrl.ptr = &priv_->v4l2_decode_param; - ctrls.push_back(ctrl); - - struct v4l2_ext_controls ext_ctrls; - memset(&ext_ctrls, 0, sizeof(ext_ctrls)); - ext_ctrls.count = ctrls.size(); - ext_ctrls.controls = &ctrls[0]; - dec_surface->PrepareSetCtrls(&ext_ctrls); - if (device_->Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) != 0) { - VPLOGF(1) << "ioctl() failed: VIDIOC_S_EXT_CTRLS"; - return Status::kFail; - } - - Reset(); - - DVLOGF(4) << "Submitting decode for surface: " << dec_surface->ToString(); - surface_handler_->DecodeSurface(dec_surface); - return Status::kOk; -} - -bool V4L2ChromiumH264Accelerator::OutputPicture(scoped_refptr<H264Picture> pic) { - // TODO(crbug.com/647725): Insert correct color space. - surface_handler_->SurfaceReady(H264PictureToV4L2DecodeSurface(pic.get()), - pic->bitstream_id(), pic->visible_rect(), - VideoColorSpace()); - return true; -} - -void V4L2ChromiumH264Accelerator::Reset() { - num_slices_ = 0; - memset(&priv_->v4l2_decode_param, 0, sizeof(priv_->v4l2_decode_param)); - memset(&priv_->v4l2_slice_params, 0, sizeof(priv_->v4l2_slice_params)); -} - -scoped_refptr<V4L2DecodeSurface> -V4L2ChromiumH264Accelerator::H264PictureToV4L2DecodeSurface(H264Picture* pic) { - V4L2H264Picture* v4l2_pic = pic->AsV4L2H264Picture(); - CHECK(v4l2_pic); - return v4l2_pic->dec_surface(); -} - -} // namespace media diff --git a/chromium/media/gpu/v4l2/v4l2_h264_accelerator_chromium.h b/chromium/media/gpu/v4l2/v4l2_h264_accelerator_chromium.h deleted file mode 100644 index 0e0171f9766..00000000000 --- a/chromium/media/gpu/v4l2/v4l2_h264_accelerator_chromium.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 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. - -#ifndef MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_CHROMIUM_H_ -#define MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_CHROMIUM_H_ - -#include <memory> -#include <vector> - -#include "base/macros.h" -#include "base/memory/scoped_refptr.h" -#include "media/gpu/h264_decoder.h" -#include "media/gpu/h264_dpb.h" - -namespace media { - -class V4L2Device; -class V4L2DecodeSurface; -class V4L2DecodeSurfaceHandler; -struct V4L2H264AcceleratorPrivate; - -// H.264 accelerator supported the old Chromium-only ABI with the kernel. -class V4L2ChromiumH264Accelerator : public H264Decoder::H264Accelerator { - public: - using Status = H264Decoder::H264Accelerator::Status; - - explicit V4L2ChromiumH264Accelerator(V4L2DecodeSurfaceHandler* surface_handler, - V4L2Device* device); - ~V4L2ChromiumH264Accelerator() override; - - // H264Decoder::H264Accelerator implementation. - scoped_refptr<H264Picture> CreateH264Picture() override; - Status SubmitFrameMetadata(const H264SPS* sps, - const H264PPS* pps, - const H264DPB& dpb, - const H264Picture::Vector& ref_pic_listp0, - const H264Picture::Vector& ref_pic_listb0, - const H264Picture::Vector& ref_pic_listb1, - scoped_refptr<H264Picture> pic) override; - Status SubmitSlice(const H264PPS* pps, - const H264SliceHeader* slice_hdr, - const H264Picture::Vector& ref_pic_list0, - const H264Picture::Vector& ref_pic_list1, - scoped_refptr<H264Picture> pic, - const uint8_t* data, - size_t size, - const std::vector<SubsampleEntry>& subsamples) override; - Status SubmitDecode(scoped_refptr<H264Picture> pic) override; - bool OutputPicture(scoped_refptr<H264Picture> pic) override; - void Reset() override; - - private: - // Max size of reference list. - static constexpr size_t kDPBIndicesListSize = 32; - - void H264PictureListToDPBIndicesList(const H264Picture::Vector& src_pic_list, - uint8_t dst_list[kDPBIndicesListSize]); - void H264DPBToV4L2DPB( - const H264DPB& dpb, - std::vector<scoped_refptr<V4L2DecodeSurface>>* ref_surfaces); - scoped_refptr<V4L2DecodeSurface> H264PictureToV4L2DecodeSurface( - H264Picture* pic); - - size_t num_slices_; - V4L2DecodeSurfaceHandler* const surface_handler_; - V4L2Device* const device_; - - // Contains the kernel-specific structures that we don't want to expose - // outside of the compilation unit. - const std::unique_ptr<V4L2H264AcceleratorPrivate> priv_; - - DISALLOW_COPY_AND_ASSIGN(V4L2ChromiumH264Accelerator); -}; - -} // namespace media - -#endif // MEDIA_GPU_V4L2_V4L2_H264_ACCELERATOR_CHROMIUM_H_ diff --git a/chromium/media/gpu/v4l2/v4l2_image_processor_backend.cc b/chromium/media/gpu/v4l2/v4l2_image_processor_backend.cc index a6d2ebae6c2..30097973821 100644 --- a/chromium/media/gpu/v4l2/v4l2_image_processor_backend.cc +++ b/chromium/media/gpu/v4l2/v4l2_image_processor_backend.cc @@ -56,12 +56,12 @@ enum v4l2_buf_type ToSingleV4L2Planar(enum v4l2_buf_type type) { } } -base::Optional<gfx::GpuMemoryBufferHandle> CreateHandle( +absl::optional<gfx::GpuMemoryBufferHandle> CreateHandle( const VideoFrame* frame) { gfx::GpuMemoryBufferHandle handle = CreateGpuMemoryBufferHandle(frame); if (handle.is_null() || handle.type != gfx::NATIVE_PIXMAP) - return base::nullopt; + return absl::nullopt; return handle; } @@ -624,7 +624,7 @@ void V4L2ImageProcessorBackend::ProcessJobsTask() { } // We need one input and one output buffer to schedule the job - base::Optional<V4L2WritableBufferRef> input_buffer; + absl::optional<V4L2WritableBufferRef> input_buffer; // If we are using DMABUF frames, try to always obtain the same V4L2 buffer. if (input_memory_type_ == V4L2_MEMORY_DMABUF) { const VideoFrame& input_frame = @@ -634,7 +634,7 @@ void V4L2ImageProcessorBackend::ProcessJobsTask() { if (!input_buffer) input_buffer = input_queue_->GetFreeBuffer(); - base::Optional<V4L2WritableBufferRef> output_buffer; + absl::optional<V4L2WritableBufferRef> output_buffer; // If we are using DMABUF frames, try to always obtain the same V4L2 buffer. if (output_memory_type_ == V4L2_MEMORY_DMABUF) { const VideoFrame& output_frame = @@ -906,7 +906,7 @@ void V4L2ImageProcessorBackend::EnqueueOutput(JobRecord* job_record, // static void V4L2ImageProcessorBackend::V4L2VFRecycleThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<V4L2ImageProcessorBackend>> image_processor, + absl::optional<base::WeakPtr<V4L2ImageProcessorBackend>> image_processor, V4L2ReadableBufferRef buf) { DVLOGF(4); DCHECK(image_processor); diff --git a/chromium/media/gpu/v4l2/v4l2_image_processor_backend.h b/chromium/media/gpu/v4l2/v4l2_image_processor_backend.h index 4652bda62b7..e8a9629d584 100644 --- a/chromium/media/gpu/v4l2/v4l2_image_processor_backend.h +++ b/chromium/media/gpu/v4l2/v4l2_image_processor_backend.h @@ -17,13 +17,13 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" #include "media/gpu/chromeos/image_processor_backend.h" #include "media/gpu/media_gpu_export.h" #include "media/gpu/v4l2/v4l2_device.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { @@ -148,7 +148,7 @@ class MEDIA_GPU_EXPORT V4L2ImageProcessorBackend // task to |device_task_runner_|. static void V4L2VFRecycleThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<V4L2ImageProcessorBackend>> image_processor, + absl::optional<base::WeakPtr<V4L2ImageProcessorBackend>> image_processor, V4L2ReadableBufferRef buf); void V4L2VFRecycleTask(V4L2ReadableBufferRef buf); diff --git a/chromium/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.h b/chromium/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.h index f025ca06636..181b6b10019 100644 --- a/chromium/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.h +++ b/chromium/media/gpu/v4l2/v4l2_jpeg_encode_accelerator.h @@ -24,7 +24,6 @@ #include "media/base/video_frame.h" #include "media/gpu/media_gpu_export.h" #include "media/gpu/v4l2/v4l2_device.h" -#include "media/gpu/v4l2/v4l2_jpeg_encode_accelerator.h" #include "media/parsers/jpeg_parser.h" namespace { @@ -330,7 +329,7 @@ class MEDIA_GPU_EXPORT V4L2JpegEncodeAccelerator V4L2JpegEncodeAccelerator* parent_; // Layout that represents the input data. - base::Optional<VideoFrameLayout> device_input_layout_; + absl::optional<VideoFrameLayout> device_input_layout_; // The V4L2Device this class is operating upon. scoped_refptr<V4L2Device> device_; diff --git a/chromium/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc b/chromium/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc index e9d961454d6..f2ed447f5aa 100644 --- a/chromium/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc +++ b/chromium/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc @@ -17,8 +17,8 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/files/scoped_file.h" +#include "base/memory/page_size.h" #include "base/numerics/safe_conversions.h" -#include "base/process/process_metrics.h" #include "base/stl_util.h" #include "base/threading/thread_task_runner_handle.h" #include "media/base/bitstream_buffer.h" @@ -755,7 +755,7 @@ void V4L2MjpegDecodeAccelerator::DevicePollTask() { bool V4L2MjpegDecodeAccelerator::DequeueSourceChangeEvent() { DCHECK(decoder_task_runner_->BelongsToCurrentThread()); - if (base::Optional<struct v4l2_event> event = device_->DequeueEvent()) { + if (absl::optional<struct v4l2_event> event = device_->DequeueEvent()) { if (event->type == V4L2_EVENT_SOURCE_CHANGE) { VLOGF(2) << ": got source change event: " << event->u.src_change.changes; if (event->u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) { diff --git a/chromium/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/chromium/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc index 771e3281a86..c09ed75e000 100644 --- a/chromium/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc +++ b/chromium/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc @@ -41,7 +41,6 @@ #include "media/gpu/macros.h" #include "media/gpu/v4l2/v4l2_decode_surface.h" #include "media/gpu/v4l2/v4l2_h264_accelerator.h" -#include "media/gpu/v4l2/v4l2_h264_accelerator_chromium.h" #include "media/gpu/v4l2/v4l2_h264_accelerator_legacy.h" #include "media/gpu/v4l2/v4l2_image_processor_backend.h" #include "media/gpu/v4l2/v4l2_utils.h" @@ -297,14 +296,9 @@ bool V4L2SliceVideoDecodeAccelerator::Initialize(const Config& config, if (video_profile_ >= H264PROFILE_MIN && video_profile_ <= H264PROFILE_MAX) { if (supports_requests_) { - if (V4L2H264Accelerator::SupportsUpstreamABI(device_.get())) - decoder_ = std::make_unique<H264Decoder>( - std::make_unique<V4L2H264Accelerator>(this, device_.get()), - video_profile_); - else - decoder_ = std::make_unique<H264Decoder>( - std::make_unique<V4L2ChromiumH264Accelerator>(this, device_.get()), - video_profile_); + decoder_ = std::make_unique<H264Decoder>( + std::make_unique<V4L2H264Accelerator>(this, device_.get()), + video_profile_); } else { decoder_ = std::make_unique<H264Decoder>( std::make_unique<V4L2LegacyH264Accelerator>(this, device_.get()), @@ -519,7 +513,7 @@ bool V4L2SliceVideoDecodeAccelerator::SetupFormats() { // output format or not may depend on the input format. memset(&fmtdesc, 0, sizeof(fmtdesc)); fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - output_format_fourcc_ = base::nullopt; + output_format_fourcc_ = absl::nullopt; output_planes_count_ = 0; while (device_->Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0) { auto fourcc = Fourcc::FromV4L2PixFmt(fmtdesc.pixelformat); @@ -1478,9 +1472,18 @@ void V4L2SliceVideoDecodeAccelerator::CreateGLImageFor( gl::ScopedTextureBinder bind_restore(gl_device->GetTextureTarget(), texture_id); bool ret = gl_image->BindTexImage(gl_device->GetTextureTarget()); - DCHECK(ret); - bind_image_cb_.Run(client_texture_id, gl_device->GetTextureTarget(), gl_image, - true); + if (!ret) { + LOG(ERROR) << "Error while binding tex image"; + NOTIFY_ERROR(PLATFORM_FAILURE); + return; + } + ret = bind_image_cb_.Run(client_texture_id, gl_device->GetTextureTarget(), + gl_image, true); + if (!ret) { + LOG(ERROR) << "Error while running bind image callback"; + NOTIFY_ERROR(PLATFORM_FAILURE); + return; + } } void V4L2SliceVideoDecodeAccelerator::ImportBufferForPicture( @@ -1512,7 +1515,9 @@ void V4L2SliceVideoDecodeAccelerator::ImportBufferForPictureForImportTask( if (pixel_format != gl_image_format_fourcc_->ToVideoPixelFormat()) { LOG(ERROR) << "Unsupported import format: " - << VideoPixelFormatToString(pixel_format); + << VideoPixelFormatToString(pixel_format) << ", expected " + << VideoPixelFormatToString( + gl_image_format_fourcc_->ToVideoPixelFormat()); NOTIFY_ERROR(INVALID_ARGUMENT); return; } @@ -2093,7 +2098,7 @@ V4L2SliceVideoDecodeAccelerator::CreateSurface() { if (supports_requests_) { // Get a free request from the queue for a new surface. - base::Optional<V4L2RequestRef> request_ref = + absl::optional<V4L2RequestRef> request_ref = requests_queue_->GetFreeRequest(); if (!request_ref) { LOG(ERROR) << "Failed getting a request"; diff --git a/chromium/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h b/chromium/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h index 6c9fac3ec46..864a50b38b1 100644 --- a/chromium/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h +++ b/chromium/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h @@ -18,7 +18,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/trace_event/memory_dump_provider.h" @@ -31,6 +30,7 @@ #include "media/gpu/vp8_decoder.h" #include "media/gpu/vp9_decoder.h" #include "media/video/video_decode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/native_pixmap_handle.h" #include "ui/gl/gl_fence_egl.h" @@ -418,7 +418,7 @@ class MEDIA_GPU_EXPORT V4L2SliceVideoDecodeAccelerator VideoCodecProfile video_profile_; uint32_t input_format_fourcc_; - base::Optional<Fourcc> output_format_fourcc_; + absl::optional<Fourcc> output_format_fourcc_; gfx::Size coded_size_; struct BitstreamBufferRef; @@ -501,7 +501,7 @@ class MEDIA_GPU_EXPORT V4L2SliceVideoDecodeAccelerator std::unique_ptr<ImageProcessor> image_processor_; // The format of GLImage. - base::Optional<Fourcc> gl_image_format_fourcc_; + absl::optional<Fourcc> gl_image_format_fourcc_; // The logical dimensions of GLImage buffer in pixels. gfx::Size gl_image_size_; // Number of planes for GLImage. diff --git a/chromium/media/gpu/v4l2/v4l2_vda_helpers.cc b/chromium/media/gpu/v4l2/v4l2_vda_helpers.cc index ca557f5b5b6..adec5b8c064 100644 --- a/chromium/media/gpu/v4l2/v4l2_vda_helpers.cc +++ b/chromium/media/gpu/v4l2/v4l2_vda_helpers.cc @@ -16,7 +16,7 @@ namespace media { namespace v4l2_vda_helpers { -base::Optional<Fourcc> FindImageProcessorInputFormat(V4L2Device* vda_device) { +absl::optional<Fourcc> FindImageProcessorInputFormat(V4L2Device* vda_device) { std::vector<uint32_t> processor_input_formats = V4L2ImageProcessorBackend::GetSupportedInputFormats(); @@ -32,10 +32,10 @@ base::Optional<Fourcc> FindImageProcessorInputFormat(V4L2Device* vda_device) { } ++fmtdesc.index; } - return base::nullopt; + return absl::nullopt; } -base::Optional<Fourcc> FindImageProcessorOutputFormat(V4L2Device* ip_device) { +absl::optional<Fourcc> FindImageProcessorOutputFormat(V4L2Device* ip_device) { // Prefer YVU420 and NV12 because ArcGpuVideoDecodeAccelerator only supports // single physical plane. static constexpr uint32_t kPreferredFormats[] = {V4L2_PIX_FMT_NV12, @@ -63,7 +63,7 @@ base::Optional<Fourcc> FindImageProcessorOutputFormat(V4L2Device* ip_device) { } } - return base::nullopt; + return absl::nullopt; } std::unique_ptr<ImageProcessor> CreateImageProcessor( diff --git a/chromium/media/gpu/v4l2/v4l2_vda_helpers.h b/chromium/media/gpu/v4l2/v4l2_vda_helpers.h index 05b74a3205d..0fc4dfcf614 100644 --- a/chromium/media/gpu/v4l2/v4l2_vda_helpers.h +++ b/chromium/media/gpu/v4l2/v4l2_vda_helpers.h @@ -8,10 +8,10 @@ #include <memory> #include "base/memory/scoped_refptr.h" -#include "base/optional.h" #include "media/base/video_codecs.h" #include "media/gpu/chromeos/fourcc.h" #include "media/gpu/chromeos/image_processor.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { @@ -26,9 +26,9 @@ class H264Parser; namespace v4l2_vda_helpers { // Returns a usable input format of image processor, or nullopt if not found. -base::Optional<Fourcc> FindImageProcessorInputFormat(V4L2Device* vda_device); +absl::optional<Fourcc> FindImageProcessorInputFormat(V4L2Device* vda_device); // Return a usable output format of image processor, or nullopt if not found. -base::Optional<Fourcc> FindImageProcessorOutputFormat(V4L2Device* ip_device); +absl::optional<Fourcc> FindImageProcessorOutputFormat(V4L2Device* ip_device); // Create and return an image processor for the given parameters, or nullptr // if it cannot be created. diff --git a/chromium/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/chromium/media/gpu/v4l2/v4l2_video_decode_accelerator.cc index f0822769361..6ebf5f38b85 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_decode_accelerator.cc +++ b/chromium/media/gpu/v4l2/v4l2_video_decode_accelerator.cc @@ -590,7 +590,9 @@ void V4L2VideoDecodeAccelerator::ImportBufferForPictureForImportTask( // the final output format from the image processor (if exists). // Use |egl_image_format_fourcc_|, it will be the final output format. if (pixel_format != egl_image_format_fourcc_->ToVideoPixelFormat()) { - LOG(ERROR) << "Unsupported import format: " << pixel_format; + LOG(ERROR) << "Unsupported import format: " << pixel_format << ", expected " + << VideoPixelFormatToString( + egl_image_format_fourcc_->ToVideoPixelFormat()); NOTIFY_ERROR(INVALID_ARGUMENT); return; } @@ -1401,7 +1403,7 @@ bool V4L2VideoDecodeAccelerator::DequeueResolutionChangeEvent() { DCHECK_NE(decoder_state_, kUninitialized); DVLOGF(3); - while (base::Optional<struct v4l2_event> event = device_->DequeueEvent()) { + while (absl::optional<struct v4l2_event> event = device_->DequeueEvent()) { if (event->type == V4L2_EVENT_SOURCE_CHANGE) { if (event->u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION) { VLOGF(2) << "got resolution change event."; diff --git a/chromium/media/gpu/v4l2/v4l2_video_decode_accelerator.h b/chromium/media/gpu/v4l2/v4l2_video_decode_accelerator.h index 1460737b26e..6dacbdc5bdc 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_decode_accelerator.h +++ b/chromium/media/gpu/v4l2/v4l2_video_decode_accelerator.h @@ -24,7 +24,6 @@ #include "base/containers/queue.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/trace_event/memory_dump_provider.h" @@ -37,6 +36,7 @@ #include "media/gpu/v4l2/v4l2_device.h" #include "media/video/picture.h" #include "media/video/video_decode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_fence_egl.h" @@ -539,7 +539,7 @@ class MEDIA_GPU_EXPORT V4L2VideoDecodeAccelerator // thread manipulates them. // - base::Optional<V4L2WritableBufferRef> current_input_buffer_; + absl::optional<V4L2WritableBufferRef> current_input_buffer_; scoped_refptr<V4L2Queue> input_queue_; scoped_refptr<V4L2Queue> output_queue_; @@ -601,7 +601,7 @@ class MEDIA_GPU_EXPORT V4L2VideoDecodeAccelerator // Chosen input format for the video profile we are decoding from. uint32_t input_format_fourcc_; // Chosen output format. - base::Optional<Fourcc> output_format_fourcc_; + absl::optional<Fourcc> output_format_fourcc_; // Image processor device, if one is in use. scoped_refptr<V4L2Device> image_processor_device_; @@ -609,7 +609,7 @@ class MEDIA_GPU_EXPORT V4L2VideoDecodeAccelerator std::unique_ptr<ImageProcessor> image_processor_; // The format of EGLImage. - base::Optional<Fourcc> egl_image_format_fourcc_; + absl::optional<Fourcc> egl_image_format_fourcc_; // The logical dimensions of EGLImage buffer in pixels. gfx::Size egl_image_size_; diff --git a/chromium/media/gpu/v4l2/v4l2_video_decoder.cc b/chromium/media/gpu/v4l2/v4l2_video_decoder.cc index 34c2fc68463..b9a93a02a22 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_decoder.cc +++ b/chromium/media/gpu/v4l2/v4l2_video_decoder.cc @@ -202,7 +202,7 @@ StatusCode V4L2VideoDecoder::InitializeBackend() { constexpr bool kStateful = false; constexpr bool kStateless = true; - base::Optional<std::pair<bool, uint32_t>> api_and_format; + absl::optional<std::pair<bool, uint32_t>> api_and_format; // Try both kStateful and kStateless APIs via |fourcc| and select the first // combination where Open()ing the |device_| works. for (const auto api : {kStateful, kStateless}) { @@ -333,7 +333,7 @@ bool V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size, continue; } - base::Optional<struct v4l2_format> format = + absl::optional<struct v4l2_format> format = output_queue_->TryFormat(pixfmt, size, 0); if (!format) continue; @@ -344,7 +344,7 @@ bool V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size, } // Ask the pipeline to pick the output format. - const base::Optional<std::pair<Fourcc, gfx::Size>> output_format = + const absl::optional<std::pair<Fourcc, gfx::Size>> output_format = client_->PickDecoderOutputFormat(candidates, visible_rect); if (!output_format) { VLOGF(1) << "Failed to pick an output format."; @@ -354,7 +354,7 @@ bool V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size, gfx::Size picked_size = std::move(output_format->second); // We successfully picked the output format. Now setup output format again. - base::Optional<struct v4l2_format> format = + absl::optional<struct v4l2_format> format = output_queue_->SetFormat(fourcc.ToV4L2PixFmt(), picked_size, 0); DCHECK(format); gfx::Size adjusted_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height); @@ -374,7 +374,7 @@ bool V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size, // created by VideoFramePool. DmabufVideoFramePool* pool = client_->GetVideoFramePool(); if (pool) { - base::Optional<GpuBufferLayout> layout = pool->Initialize( + absl::optional<GpuBufferLayout> layout = pool->Initialize( fourcc, adjusted_size, visible_rect, GetNaturalSize(visible_rect, pixel_aspect_ratio_), num_output_frames_, /*use_protected=*/false); @@ -393,7 +393,7 @@ bool V4L2VideoDecoder::SetupOutputFormat(const gfx::Size& size, VLOGF(1) << "buffer modifier: " << std::hex << layout->modifier(); if (layout->modifier() && layout->modifier() != gfx::NativePixmapHandle::kNoModifier) { - base::Optional<struct v4l2_format> modifier_format = + absl::optional<struct v4l2_format> modifier_format = output_queue_->SetModifierFormat(layout->modifier(), picked_size); if (!modifier_format) return false; diff --git a/chromium/media/gpu/v4l2/v4l2_video_decoder.h b/chromium/media/gpu/v4l2/v4l2_video_decoder.h index 094465cd094..9d96b5b442a 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_decoder.h +++ b/chromium/media/gpu/v4l2/v4l2_video_decoder.h @@ -18,7 +18,6 @@ #include "base/containers/queue.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" #include "base/threading/thread.h" @@ -31,6 +30,7 @@ #include "media/gpu/media_gpu_export.h" #include "media/gpu/v4l2/v4l2_device.h" #include "media/gpu/v4l2/v4l2_video_decoder_backend.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { diff --git a/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc b/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc index bc23ecda02a..5953f4118ef 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc +++ b/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.cc @@ -10,9 +10,7 @@ #include <utility> #include "base/bind.h" -#include "base/callback_forward.h" #include "base/logging.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/sequenced_task_runner.h" #include "media/base/video_codecs.h" @@ -21,6 +19,7 @@ #include "media/gpu/v4l2/v4l2_device.h" #include "media/gpu/v4l2/v4l2_vda_helpers.h" #include "media/gpu/v4l2/v4l2_video_decoder_backend.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -96,6 +95,9 @@ bool V4L2StatefulVideoDecoderBackend::Initialize() { return false; } + framerate_control_ = + std::make_unique<V4L2FrameRateControl>(device_, task_runner_); + return true; } @@ -238,7 +240,7 @@ void V4L2StatefulVideoDecoderBackend::ScheduleDecodeWork() { } void V4L2StatefulVideoDecoderBackend::ProcessEventQueue() { - while (base::Optional<struct v4l2_event> ev = device_->DequeueEvent()) { + while (absl::optional<struct v4l2_event> ev = device_->DequeueEvent()) { if (ev->type == V4L2_EVENT_SOURCE_CHANGE && (ev->u.src_change.changes & V4L2_EVENT_SRC_CH_RESOLUTION)) { ChangeResolution(); @@ -269,7 +271,7 @@ void V4L2StatefulVideoDecoderBackend::EnqueueOutputBuffers() { bool ret = false; bool no_buffer = false; - base::Optional<V4L2WritableBufferRef> buffer; + absl::optional<V4L2WritableBufferRef> buffer; switch (mem_type) { case V4L2_MEMORY_MMAP: buffer = output_queue_->GetFreeBuffer(); @@ -292,6 +294,7 @@ void V4L2StatefulVideoDecoderBackend::EnqueueOutputBuffers() { break; } + framerate_control_->AttachToVideoFrame(video_frame); ret = std::move(*buffer).QueueDMABuf(std::move(video_frame)); break; } @@ -341,7 +344,7 @@ scoped_refptr<VideoFrame> V4L2StatefulVideoDecoderBackend::GetPoolVideoFrame() { // static void V4L2StatefulVideoDecoderBackend::ReuseOutputBufferThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<V4L2StatefulVideoDecoderBackend>> weak_this, + absl::optional<base::WeakPtr<V4L2StatefulVideoDecoderBackend>> weak_this, V4L2ReadableBufferRef buffer) { DVLOGF(3); DCHECK(weak_this); diff --git a/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h b/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h index b91230cec80..3d133864913 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h +++ b/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateful.h @@ -10,11 +10,12 @@ #include "base/containers/queue.h" #include "base/macros.h" -#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "media/base/video_codecs.h" #include "media/gpu/v4l2/v4l2_device.h" +#include "media/gpu/v4l2/v4l2_framerate_control.h" #include "media/gpu/v4l2/v4l2_video_decoder_backend.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -87,7 +88,7 @@ class V4L2StatefulVideoDecoderBackend : public V4L2VideoDecoderBackend { static void ReuseOutputBufferThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<V4L2StatefulVideoDecoderBackend>> weak_this, + absl::optional<base::WeakPtr<V4L2StatefulVideoDecoderBackend>> weak_this, V4L2ReadableBufferRef buffer); void ReuseOutputBuffer(V4L2ReadableBufferRef buffer); @@ -129,14 +130,14 @@ class V4L2StatefulVideoDecoderBackend : public V4L2VideoDecoderBackend { base::queue<DecodeRequest> decode_request_queue_; // The decode request which is currently processed. - base::Optional<DecodeRequest> current_decode_request_; + absl::optional<DecodeRequest> current_decode_request_; // V4L2 input buffer currently being prepared. - base::Optional<V4L2WritableBufferRef> current_input_buffer_; + absl::optional<V4L2WritableBufferRef> current_input_buffer_; std::unique_ptr<v4l2_vda_helpers::InputBufferFragmentSplitter> frame_splitter_; - base::Optional<gfx::Rect> visible_rect_; + absl::optional<gfx::Rect> visible_rect_; // Callback of the buffer that triggered a flush, to be called when the // flush completes. @@ -151,6 +152,10 @@ class V4L2StatefulVideoDecoderBackend : public V4L2VideoDecoderBackend { // flush or reset. bool has_pending_requests_ = false; + // The venus driver is the only implementation that requires the client + // to inform the driver of the framerate. + std::unique_ptr<V4L2FrameRateControl> framerate_control_; + base::WeakPtr<V4L2StatefulVideoDecoderBackend> weak_this_; base::WeakPtrFactory<V4L2StatefulVideoDecoderBackend> weak_this_factory_{ this}; diff --git a/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc b/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc index 60bac877b75..82b4eebadf5 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc +++ b/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.cc @@ -23,7 +23,6 @@ #include "media/gpu/macros.h" #include "media/gpu/v4l2/v4l2_device.h" #include "media/gpu/v4l2/v4l2_h264_accelerator.h" -#include "media/gpu/v4l2/v4l2_h264_accelerator_chromium.h" #include "media/gpu/v4l2/v4l2_h264_accelerator_legacy.h" #include "media/gpu/v4l2/v4l2_vp8_accelerator.h" #include "media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h" @@ -147,7 +146,7 @@ bool V4L2StatelessVideoDecoderBackend::Initialize() { // static void V4L2StatelessVideoDecoderBackend::ReuseOutputBufferThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<V4L2StatelessVideoDecoderBackend>> weak_this, + absl::optional<base::WeakPtr<V4L2StatelessVideoDecoderBackend>> weak_this, V4L2ReadableBufferRef buffer) { DVLOGF(3); DCHECK(weak_this); @@ -266,7 +265,7 @@ V4L2StatelessVideoDecoderBackend::CreateSurface() { scoped_refptr<V4L2DecodeSurface> dec_surface; if (input_queue_->SupportsRequests()) { - base::Optional<V4L2RequestRef> request_ref = + absl::optional<V4L2RequestRef> request_ref = requests_queue_->GetFreeRequest(); if (!request_ref) { DVLOGF(1) << "Could not get free request."; @@ -418,7 +417,7 @@ bool V4L2StatelessVideoDecoderBackend::PumpDecodeTask() { if (current_decode_request_) { DCHECK(current_decode_request_->decode_cb); std::move(current_decode_request_->decode_cb).Run(DecodeStatus::OK); - current_decode_request_ = base::nullopt; + current_decode_request_ = absl::nullopt; } // Process next decode request. @@ -441,7 +440,7 @@ bool V4L2StatelessVideoDecoderBackend::PumpDecodeTask() { output_request_queue_.push(OutputRequest::FlushFence()); PumpOutputSurfaces(); - current_decode_request_ = base::nullopt; + current_decode_request_ = absl::nullopt; return true; } @@ -608,7 +607,7 @@ void V4L2StatelessVideoDecoderBackend::ClearPendingRequests( // Clear current_decode_request_ and decode_request_queue_. if (current_decode_request_) { std::move(current_decode_request_->decode_cb).Run(status); - current_decode_request_ = base::nullopt; + current_decode_request_ = absl::nullopt; } while (!decode_request_queue_.empty()) { @@ -651,14 +650,8 @@ bool V4L2StatelessVideoDecoderBackend::CreateAvd() { if (profile_ >= H264PROFILE_MIN && profile_ <= H264PROFILE_MAX) { if (input_queue_->SupportsRequests()) { - std::unique_ptr<H264Decoder::H264Accelerator> accelerator; - if (V4L2H264Accelerator::SupportsUpstreamABI(device_.get())) - accelerator = - std::make_unique<V4L2H264Accelerator>(this, device_.get()); - else - accelerator = - std::make_unique<V4L2ChromiumH264Accelerator>(this, device_.get()); - avd_ = std::make_unique<H264Decoder>(std::move(accelerator), profile_); + avd_ = std::make_unique<H264Decoder>( + std::make_unique<V4L2H264Accelerator>(this, device_.get()), profile_); } else { avd_ = std::make_unique<H264Decoder>( std::make_unique<V4L2LegacyH264Accelerator>(this, device_.get()), diff --git a/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h b/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h index 704d6171f7f..b475bb1aa00 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h +++ b/chromium/media/gpu/v4l2/v4l2_video_decoder_backend_stateless.h @@ -104,7 +104,7 @@ class V4L2StatelessVideoDecoderBackend : public V4L2VideoDecoderBackend, // Callback which is called when the output buffer is not used anymore. static void ReuseOutputBufferThunk( scoped_refptr<base::SequencedTaskRunner> task_runner, - base::Optional<base::WeakPtr<V4L2StatelessVideoDecoderBackend>> weak_this, + absl::optional<base::WeakPtr<V4L2StatelessVideoDecoderBackend>> weak_this, V4L2ReadableBufferRef buffer); void ReuseOutputBuffer(V4L2ReadableBufferRef buffer); @@ -140,7 +140,7 @@ class V4L2StatelessVideoDecoderBackend : public V4L2VideoDecoderBackend, std::unique_ptr<AcceleratedVideoDecoder> avd_; // The decode request which is currently processed. - base::Optional<DecodeRequest> current_decode_request_; + absl::optional<DecodeRequest> current_decode_request_; // Surfaces enqueued to V4L2 device. Since we are stateless, they are // guaranteed to be proceeded in FIFO order. base::queue<scoped_refptr<V4L2DecodeSurface>> surfaces_at_device_; diff --git a/chromium/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/chromium/media/gpu/v4l2/v4l2_video_encode_accelerator.cc index eb1810645a6..addf790f003 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_encode_accelerator.cc +++ b/chromium/media/gpu/v4l2/v4l2_video_encode_accelerator.cc @@ -22,7 +22,6 @@ #include "base/callback_helpers.h" #include "base/command_line.h" #include "base/numerics/safe_conversions.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/task/post_task.h" @@ -43,6 +42,7 @@ #include "media/gpu/macros.h" #include "media/video/h264_level_limits.h" #include "media/video/h264_parser.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #define NOTIFY_ERROR(x) \ do { \ @@ -102,7 +102,7 @@ namespace media { namespace { // Convert VideoFrameLayout to ImageProcessor::PortConfig. -base::Optional<ImageProcessor::PortConfig> VideoFrameLayoutToPortConfig( +absl::optional<ImageProcessor::PortConfig> VideoFrameLayoutToPortConfig( const VideoFrameLayout& layout, const gfx::Rect& visible_rect, const std::vector<VideoFrame::StorageType>& preferred_storage_types) { @@ -111,7 +111,7 @@ base::Optional<ImageProcessor::PortConfig> VideoFrameLayoutToPortConfig( if (!fourcc) { DVLOGF(1) << "Failed to create Fourcc from video pixel format " << VideoPixelFormatToString(layout.format()); - return base::nullopt; + return absl::nullopt; } return ImageProcessor::PortConfig(*fourcc, layout.coded_size(), layout.planes(), visible_rect, @@ -119,10 +119,10 @@ base::Optional<ImageProcessor::PortConfig> VideoFrameLayoutToPortConfig( } // Create Layout from |layout| with is_multi_planar = true. -base::Optional<VideoFrameLayout> AsMultiPlanarLayout( +absl::optional<VideoFrameLayout> AsMultiPlanarLayout( const VideoFrameLayout& layout) { if (layout.is_multi_planar()) - return base::make_optional<VideoFrameLayout>(layout); + return absl::make_optional<VideoFrameLayout>(layout); return VideoFrameLayout::CreateMultiPlanar( layout.format(), layout.coded_size(), layout.planes()); } @@ -1046,7 +1046,7 @@ void V4L2VideoEncodeAccelerator::Enqueue() { break; } - base::Optional<V4L2WritableBufferRef> input_buffer; + absl::optional<V4L2WritableBufferRef> input_buffer; switch (input_memory_type_) { case V4L2_MEMORY_DMABUF: input_buffer = input_queue_->GetFreeBufferForFrame( @@ -1060,7 +1060,7 @@ void V4L2VideoEncodeAccelerator::Enqueue() { input_buffer = input_queue_->GetFreeBuffer(); break; } - // input_buffer cannot be base::nullopt since we checked for + // input_buffer cannot be absl::nullopt since we checked for // input_queue_->FreeBuffersCount() > 0 before entering the loop. DCHECK(input_buffer); if (!EnqueueInputRecord(std::move(*input_buffer))) @@ -1516,7 +1516,7 @@ bool V4L2VideoEncodeAccelerator::SetOutputFormat( // Sets 0 to width and height in CAPTURE queue, which should be ignored by the // driver. - base::Optional<struct v4l2_format> format = output_queue_->SetFormat( + absl::optional<struct v4l2_format> format = output_queue_->SetFormat( output_format_fourcc_, gfx::Size(), output_buffer_byte_size_); if (!format) { return false; @@ -1530,7 +1530,7 @@ bool V4L2VideoEncodeAccelerator::SetOutputFormat( return true; } -base::Optional<struct v4l2_format> +absl::optional<struct v4l2_format> V4L2VideoEncodeAccelerator::NegotiateInputFormat(VideoPixelFormat input_format, const gfx::Size& size) { VLOGF(2); @@ -1544,7 +1544,7 @@ V4L2VideoEncodeAccelerator::NegotiateInputFormat(VideoPixelFormat input_format, if (!input_fourcc) { DVLOGF(2) << "Invalid input format " << VideoPixelFormatToString(input_format); - return base::nullopt; + return absl::nullopt; } pix_fmt_candidates.push_back(input_fourcc->ToV4L2PixFmt()); // Second try preferred input formats for both single-planar and @@ -1557,7 +1557,7 @@ V4L2VideoEncodeAccelerator::NegotiateInputFormat(VideoPixelFormat input_format, for (const auto pix_fmt : pix_fmt_candidates) { DVLOGF(3) << "Trying S_FMT with " << FourccToString(pix_fmt); - base::Optional<struct v4l2_format> format = + absl::optional<struct v4l2_format> format = input_queue_->SetFormat(pix_fmt, size, 0); if (!format) continue; @@ -1566,7 +1566,7 @@ V4L2VideoEncodeAccelerator::NegotiateInputFormat(VideoPixelFormat input_format, device_input_layout_ = V4L2Device::V4L2FormatToVideoFrameLayout(*format); if (!device_input_layout_) { VLOGF(1) << "Invalid device_input_layout_"; - return base::nullopt; + return absl::nullopt; } DVLOG(3) << "Negotiated device_input_layout_: " << *device_input_layout_; if (!gfx::Rect(device_input_layout_->coded_size()) @@ -1574,17 +1574,17 @@ V4L2VideoEncodeAccelerator::NegotiateInputFormat(VideoPixelFormat input_format, VLOGF(1) << "Input size " << size.ToString() << " exceeds encoder capability. Size encoder can handle: " << device_input_layout_->coded_size().ToString(); - return base::nullopt; + return absl::nullopt; } // Make sure that the crop is preserved as we have changed the input // resolution. if (!ApplyCrop()) { - return base::nullopt; + return absl::nullopt; } return format; } - return base::nullopt; + return absl::nullopt; } bool V4L2VideoEncodeAccelerator::ApplyCrop() { @@ -1730,11 +1730,9 @@ bool V4L2VideoEncodeAccelerator::InitControlsH264(const Config& config) { DVLOGF(2) << "Will inject SPS+PPS before each IDR, unsupported by device"; } - // Optional H264 controls. - std::vector<V4L2ExtCtrl> h264_ctrls; - // No B-frames, for lowest decoding latency. - h264_ctrls.emplace_back(V4L2_CID_MPEG_VIDEO_B_FRAMES, 0); + device_->SetExtCtrls(V4L2_CTRL_CLASS_MPEG, + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_B_FRAMES, 0)}); // Set H.264 profile. int32_t profile_value = @@ -1743,7 +1741,14 @@ bool V4L2VideoEncodeAccelerator::InitControlsH264(const Config& config) { NOTIFY_ERROR(kInvalidArgumentError); return false; } - h264_ctrls.emplace_back(V4L2_CID_MPEG_VIDEO_H264_PROFILE, profile_value); + if (!device_->SetExtCtrls( + V4L2_CTRL_CLASS_MPEG, + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_H264_PROFILE, profile_value)})) { + VLOGF(1) << "Unsupported profile: " + << GetProfileName(config.output_profile); + NOTIFY_ERROR(kInvalidArgumentError); + return false; + } // Set H.264 output level from config. Use Level 4.0 as fallback default. uint8_t h264_level = config.h264_output_level.value_or(H264SPS::kLevelIDC4p0); @@ -1763,7 +1768,7 @@ bool V4L2VideoEncodeAccelerator::InitControlsH264(const Config& config) { if (!CheckH264LevelLimits(config.output_profile, h264_level, config.initial_bitrate, framerate, framesize_in_mbs)) { - base::Optional<uint8_t> valid_level = + absl::optional<uint8_t> valid_level = FindValidH264Level(config.output_profile, config.initial_bitrate, framerate, framesize_in_mbs); if (!valid_level) { @@ -1780,14 +1785,41 @@ bool V4L2VideoEncodeAccelerator::InitControlsH264(const Config& config) { } int32_t level_value = V4L2Device::H264LevelIdcToV4L2H264Level(h264_level); - h264_ctrls.emplace_back(V4L2_CID_MPEG_VIDEO_H264_LEVEL, level_value); + device_->SetExtCtrls( + V4L2_CTRL_CLASS_MPEG, + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_H264_LEVEL, level_value)}); // Ask not to put SPS and PPS into separate bitstream buffers. - h264_ctrls.emplace_back(V4L2_CID_MPEG_VIDEO_HEADER_MODE, - V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); - - // Ignore return value as these controls are optional. - device_->SetExtCtrls(V4L2_CTRL_CLASS_MPEG, std::move(h264_ctrls)); + device_->SetExtCtrls( + V4L2_CTRL_CLASS_MPEG, + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_HEADER_MODE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME)}); + + // H264 coding tools parameter. Since a driver may not support some of them, + // EXT_S_CTRLS is called to each of them to enable as many coding tools as + // possible. + // Don't produce Intra-only frame. + device_->SetExtCtrls(V4L2_CTRL_CLASS_MPEG, + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, 0)}); + // Enable deblocking filter. + device_->SetExtCtrls( + V4L2_CTRL_CLASS_MPEG, + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED)}); + // Use CABAC in Main and High profiles. + if (config.output_profile == H264PROFILE_MAIN || + config.output_profile == H264PROFILE_HIGH) { + device_->SetExtCtrls( + V4L2_CTRL_CLASS_MPEG, + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)}); + } + // Use 8x8 transform in High profile. + if (config.output_profile == H264PROFILE_HIGH) { + device_->SetExtCtrls( + V4L2_CTRL_CLASS_MPEG, + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, true)}); + } // Quantization parameter. The h264 qp range is 0-51. // Note: Webrtc default values are 24 and 37 respectively, see @@ -1795,7 +1827,7 @@ bool V4L2VideoEncodeAccelerator::InitControlsH264(const Config& config) { // These values were copied from the VA-API encoder. // Ignore return values as these controls are optional. device_->SetExtCtrls(V4L2_CTRL_CLASS_MPEG, - {V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 42}); + {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 42)}); // Don't set MIN_QP with other controls since it is not supported by // some devices and may prevent other controls from being set. device_->SetExtCtrls(V4L2_CTRL_CLASS_MPEG, diff --git a/chromium/media/gpu/v4l2/v4l2_video_encode_accelerator.h b/chromium/media/gpu/v4l2/v4l2_video_encode_accelerator.h index 792bc4e57f1..86881939599 100644 --- a/chromium/media/gpu/v4l2/v4l2_video_encode_accelerator.h +++ b/chromium/media/gpu/v4l2/v4l2_video_encode_accelerator.h @@ -18,7 +18,6 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread.h" @@ -27,6 +26,7 @@ #include "media/gpu/media_gpu_export.h" #include "media/gpu/v4l2/v4l2_device.h" #include "media/video/video_encode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { @@ -70,7 +70,7 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator // This is valid only if image processor is used. The buffer associated with // this index can be reused in Dequeue(). - base::Optional<size_t> ip_output_buffer_index; + absl::optional<size_t> ip_output_buffer_index; }; // Store all the information of input frame passed to Encode(). @@ -87,7 +87,7 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator // This is valid only if image processor is used. This info needs to be // propagated to InputRecord. - base::Optional<size_t> ip_output_buffer_index; + absl::optional<size_t> ip_output_buffer_index; }; enum { @@ -209,9 +209,9 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator // Try to set up the device to the input format we were Initialized() with, // or if the device doesn't support it, use one it can support, so that we // can later instantiate an ImageProcessor to convert to it. Return - // base::nullopt if no format is supported, otherwise return v4l2_format + // absl::nullopt if no format is supported, otherwise return v4l2_format // adjusted by the driver. - base::Optional<struct v4l2_format> NegotiateInputFormat( + absl::optional<struct v4l2_format> NegotiateInputFormat( VideoPixelFormat input_format, const gfx::Size& frame_size); @@ -274,7 +274,7 @@ class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator gfx::Rect encoder_input_visible_rect_; // Layout of device accepted input VideoFrame. - base::Optional<VideoFrameLayout> device_input_layout_; + absl::optional<VideoFrameLayout> device_input_layout_; // Stands for whether an input buffer is native graphic buffer. bool native_input_mode_; diff --git a/chromium/media/gpu/v4l2/v4l2_vp8_accelerator.h b/chromium/media/gpu/v4l2/v4l2_vp8_accelerator.h index 8ea3b196e12..ef0087b98b7 100644 --- a/chromium/media/gpu/v4l2/v4l2_vp8_accelerator.h +++ b/chromium/media/gpu/v4l2/v4l2_vp8_accelerator.h @@ -5,8 +5,6 @@ #ifndef MEDIA_GPU_V4L2_V4L2_VP8_ACCELERATOR_H_ #define MEDIA_GPU_V4L2_V4L2_VP8_ACCELERATOR_H_ -#include <vector> - #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "media/gpu/vp8_decoder.h" diff --git a/chromium/media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h b/chromium/media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h index 95fb4ad52a0..5920d41fa7f 100644 --- a/chromium/media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h +++ b/chromium/media/gpu/v4l2/v4l2_vp8_accelerator_legacy.h @@ -5,8 +5,6 @@ #ifndef MEDIA_GPU_V4L2_V4L2_VP8_ACCELERATOR_LEGACY_H_ #define MEDIA_GPU_V4L2_V4L2_VP8_ACCELERATOR_LEGACY_H_ -#include <vector> - #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "media/gpu/vp8_decoder.h" diff --git a/chromium/media/gpu/v4l2/v4l2_vp9_accelerator_legacy.h b/chromium/media/gpu/v4l2/v4l2_vp9_accelerator_legacy.h index 9e01a272f86..d93d44f6bba 100644 --- a/chromium/media/gpu/v4l2/v4l2_vp9_accelerator_legacy.h +++ b/chromium/media/gpu/v4l2/v4l2_vp9_accelerator_legacy.h @@ -5,8 +5,6 @@ #ifndef MEDIA_GPU_V4L2_V4L2_VP9_ACCELERATOR_LEGACY_H_ #define MEDIA_GPU_V4L2_V4L2_VP9_ACCELERATOR_LEGACY_H_ -#include <vector> - #include "base/callback.h" #include "base/macros.h" #include "base/memory/scoped_refptr.h" diff --git a/chromium/media/gpu/vaapi/OWNERS b/chromium/media/gpu/vaapi/OWNERS index 93cfc79bb9a..54ca4a0e14f 100644 --- a/chromium/media/gpu/vaapi/OWNERS +++ b/chromium/media/gpu/vaapi/OWNERS @@ -7,4 +7,4 @@ jkardatzke@google.com # Legacy owners. dstaessens@chromium.org kcwu@chromium.org -posciak@chromium.org
\ No newline at end of file +posciak@chromium.org diff --git a/chromium/media/gpu/vaapi/h264_encoder.cc b/chromium/media/gpu/vaapi/h264_encoder.cc index b17d1d23494..dcdcc298d30 100644 --- a/chromium/media/gpu/vaapi/h264_encoder.cc +++ b/chromium/media/gpu/vaapi/h264_encoder.cc @@ -110,7 +110,7 @@ bool H264Encoder::Initialize( // framerate and dimension. if (!CheckH264LevelLimits(profile_, level_, config.initial_bitrate, initial_framerate, mb_width_ * mb_height_)) { - base::Optional<uint8_t> valid_level = + absl::optional<uint8_t> valid_level = FindValidH264Level(profile_, config.initial_bitrate, initial_framerate, mb_width_ * mb_height_); if (!valid_level) { diff --git a/chromium/media/gpu/vaapi/h264_encoder_unittest.cc b/chromium/media/gpu/vaapi/h264_encoder_unittest.cc index 423cdafdb78..0280fedc1bd 100644 --- a/chromium/media/gpu/vaapi/h264_encoder_unittest.cc +++ b/chromium/media/gpu/vaapi/h264_encoder_unittest.cc @@ -24,8 +24,8 @@ VideoEncodeAccelerator::Config kDefaultVEAConfig( H264PROFILE_BASELINE, 14000000 /* = maximum bitrate in bits per second for level 3.1 */, VideoEncodeAccelerator::kDefaultFramerate, - base::nullopt /* gop_length */, - base::nullopt /* h264 output level*/, + absl::nullopt /* gop_length */, + absl::nullopt /* h264 output level*/, false /* is_constrained_h264 */, VideoEncodeAccelerator::Config::StorageType::kShmem, VideoEncodeAccelerator::Config::ContentType::kCamera); diff --git a/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc index 40ec7291eb1..3b0d6580cae 100644 --- a/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc @@ -16,11 +16,10 @@ #include "base/files/scoped_file.h" #include "base/location.h" #include "base/logging.h" +#include "base/memory/page_size.h" #include "base/metrics/histogram_macros.h" #include "base/numerics/checked_math.h" #include "base/numerics/safe_conversions.h" -#include "base/optional.h" -#include "base/process/process_metrics.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" @@ -38,6 +37,7 @@ #include "media/gpu/vaapi/vaapi_image_decoder.h" #include "media/gpu/vaapi/vaapi_utils.h" #include "media/gpu/vaapi/vaapi_wrapper.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/libyuv/include/libyuv.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -220,7 +220,7 @@ bool VaapiMjpegDecodeAccelerator::OutputPictureLibYuvOnTaskRunner( if (video_frame->HasDmaBufs()) { // Dmabuf-backed frame needs to be mapped for SW access. DCHECK(gpu_memory_buffer_support_); - base::Optional<gfx::BufferFormat> gfx_format = + absl::optional<gfx::BufferFormat> gfx_format = VideoPixelFormatToGfxBufferFormat(video_frame->format()); if (!gfx_format) { VLOGF(1) << "Unsupported format: " << video_frame->format(); diff --git a/chromium/media/gpu/vaapi/vaapi_picture_factory.cc b/chromium/media/gpu/vaapi/vaapi_picture_factory.cc index 50d5f245f83..719035b87c8 100644 --- a/chromium/media/gpu/vaapi/vaapi_picture_factory.cc +++ b/chromium/media/gpu/vaapi/vaapi_picture_factory.cc @@ -4,6 +4,7 @@ #include "media/gpu/vaapi/vaapi_picture_factory.h" +#include "base/containers/contains.h" #include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/video/picture.h" #include "ui/base/ui_base_features.h" diff --git a/chromium/media/gpu/vaapi/vaapi_unittest.cc b/chromium/media/gpu/vaapi/vaapi_unittest.cc index d6adb5b876b..79f4eeca0ff 100644 --- a/chromium/media/gpu/vaapi/vaapi_unittest.cc +++ b/chromium/media/gpu/vaapi/vaapi_unittest.cc @@ -14,27 +14,28 @@ #include <va/va_str.h> #include "base/callback_helpers.h" +#include "base/containers/contains.h" +#include "base/cpu.h" #include "base/files/file.h" #include "base/files/scoped_file.h" #include "base/logging.h" -#include "base/optional.h" #include "base/process/launch.h" -#include "base/stl_util.h" #include "base/strings/pattern.h" #include "base/strings/string_split.h" +#include "base/strings/string_util.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_suite.h" #include "build/chromeos_buildflags.h" -#include "gpu/config/gpu_driver_bug_workarounds.h" #include "media/base/media_switches.h" #include "media/gpu/vaapi/vaapi_wrapper.h" #include "media/media_buildflags.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace { -base::Optional<VAProfile> ConvertToVAProfile(VideoCodecProfile profile) { +absl::optional<VAProfile> ConvertToVAProfile(VideoCodecProfile profile) { // A map between VideoCodecProfile and VAProfile. const std::map<VideoCodecProfile, VAProfile> kProfileMap = { // VAProfileH264Baseline is deprecated in <va/va.h> from libva 2.0.0. @@ -51,12 +52,12 @@ base::Optional<VAProfile> ConvertToVAProfile(VideoCodecProfile profile) { #endif }; auto it = kProfileMap.find(profile); - return it != kProfileMap.end() ? base::make_optional<VAProfile>(it->second) - : base::nullopt; + return it != kProfileMap.end() ? absl::make_optional<VAProfile>(it->second) + : absl::nullopt; } // Converts the given string to VAProfile -base::Optional<VAProfile> StringToVAProfile(const std::string& va_profile) { +absl::optional<VAProfile> StringToVAProfile(const std::string& va_profile) { const std::map<std::string, VAProfile> kStringToVAProfile = { {"VAProfileNone", VAProfileNone}, {"VAProfileH264ConstrainedBaseline", VAProfileH264ConstrainedBaseline}, @@ -81,12 +82,12 @@ base::Optional<VAProfile> StringToVAProfile(const std::string& va_profile) { auto it = kStringToVAProfile.find(va_profile); return it != kStringToVAProfile.end() - ? base::make_optional<VAProfile>(it->second) - : base::nullopt; + ? absl::make_optional<VAProfile>(it->second) + : absl::nullopt; } // Converts the given string to VAEntrypoint -base::Optional<VAEntrypoint> StringToVAEntrypoint( +absl::optional<VAEntrypoint> StringToVAEntrypoint( const std::string& va_entrypoint) { const std::map<std::string, VAEntrypoint> kStringToVAEntrypoint = { {"VAEntrypointVLD", VAEntrypointVLD}, @@ -101,8 +102,8 @@ base::Optional<VAEntrypoint> StringToVAEntrypoint( auto it = kStringToVAEntrypoint.find(va_entrypoint); return it != kStringToVAEntrypoint.end() - ? base::make_optional<VAEntrypoint>(it->second) - : base::nullopt; + ? absl::make_optional<VAEntrypoint>(it->second) + : absl::nullopt; } std::unique_ptr<base::test::ScopedFeatureList> CreateScopedFeatureList() { @@ -196,8 +197,7 @@ TEST_F(VaapiTest, VerifyNoVAProfileH264Baseline) { TEST_F(VaapiTest, GetSupportedDecodeProfiles) { const auto va_info = RetrieveVAInfoOutput(); - for (const auto& profile : VaapiWrapper::GetSupportedDecodeProfiles( - gpu::GpuDriverBugWorkarounds())) { + for (const auto& profile : VaapiWrapper::GetSupportedDecodeProfiles()) { const auto va_profile = ConvertToVAProfile(profile.profile); ASSERT_TRUE(va_profile.has_value()); diff --git a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc index 9d9cb7a1713..35c4b45ead4 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.cc @@ -11,6 +11,7 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/containers/contains.h" #include "base/cpu.h" #include "base/files/scoped_file.h" #include "base/json/json_writer.h" @@ -21,6 +22,7 @@ #include "base/numerics/safe_conversions.h" #include "base/stl_util.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/memory_dump_manager.h" @@ -151,7 +153,6 @@ VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( const BindGLImageCallback& bind_image_cb) : state_(kUninitialized), input_ready_(&lock_), - vaapi_picture_factory_(new VaapiPictureFactory()), buffer_allocation_mode_(BufferAllocationMode::kNormal), surfaces_available_(&lock_), va_surface_format_(VA_INVALID_ID), @@ -190,6 +191,8 @@ bool VaapiVideoDecodeAccelerator::Initialize(const Config& config, return false; #endif + vaapi_picture_factory_ = std::make_unique<VaapiPictureFactory>(); + if (config.is_encrypted()) { NOTREACHED() << "Encrypted streams are not supported for this VDA"; return false; @@ -646,7 +649,7 @@ void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() { << " pictures of size: " << requested_pic_size_.ToString() << " and visible rectangle = " << requested_visible_rect_.ToString(); - const base::Optional<VideoPixelFormat> format = + const absl::optional<VideoPixelFormat> format = GfxBufferFormatToVideoPixelFormat( vaapi_picture_factory_->GetBufferFormat()); CHECK(format); @@ -1196,10 +1199,9 @@ void VaapiVideoDecodeAccelerator::RecycleVASurface( // static VideoDecodeAccelerator::SupportedProfiles -VaapiVideoDecodeAccelerator::GetSupportedProfiles( - const gpu::GpuDriverBugWorkarounds& workarounds) { +VaapiVideoDecodeAccelerator::GetSupportedProfiles() { VideoDecodeAccelerator::SupportedProfiles profiles = - VaapiWrapper::GetSupportedDecodeProfiles(workarounds); + VaapiWrapper::GetSupportedDecodeProfiles(); // VaVDA never supported VP9 Profile 2, AV1 and HEVC, but VaapiWrapper does. // Filter them out. base::EraseIf(profiles, [](const auto& profile) { diff --git a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.h b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.h index 07ae2d85c52..d347fb95f62 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.h +++ b/chromium/media/gpu/vaapi/vaapi_video_decode_accelerator.h @@ -40,10 +40,6 @@ namespace gl { class GLImage; } -namespace gpu { -class GpuDriverBugWorkarounds; -} - namespace media { class AcceleratedVideoDecoder; @@ -92,8 +88,7 @@ class MEDIA_GPU_EXPORT VaapiVideoDecodeAccelerator const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) override; - static VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles( - const gpu::GpuDriverBugWorkarounds& workarounds); + static VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(); // DecodeSurfaceHandler implementation. scoped_refptr<VASurface> CreateSurface() override; diff --git a/chromium/media/gpu/vaapi/vaapi_video_decoder.cc b/chromium/media/gpu/vaapi/vaapi_video_decoder.cc index e04ae1a0328..66c1b732e0e 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decoder.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_decoder.cc @@ -10,10 +10,10 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h" +#include "base/containers/contains.h" #include "base/containers/fixed_flat_map.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" -#include "base/stl_util.h" #include "base/trace_event/trace_event.h" #include "build/chromeos_buildflags.h" #include "media/base/bind_to_current_loop.h" @@ -50,7 +50,7 @@ namespace { // Size of the timestamp cache, needs to be large enough for frame-reordering. constexpr size_t kTimestampCacheSize = 128; -base::Optional<VideoPixelFormat> GetPixelFormatForBitDepth(uint8_t bit_depth) { +absl::optional<VideoPixelFormat> GetPixelFormatForBitDepth(uint8_t bit_depth) { constexpr auto kSupportedBitDepthAndGfxFormats = base::MakeFixedFlatMap< uint8_t, gfx::BufferFormat>({ #if defined(USE_OZONE) @@ -61,7 +61,7 @@ base::Optional<VideoPixelFormat> GetPixelFormatForBitDepth(uint8_t bit_depth) { }); if (!base::Contains(kSupportedBitDepthAndGfxFormats, bit_depth)) { VLOGF(1) << "Unsupported bit depth: " << base::strict_cast<int>(bit_depth); - return base::nullopt; + return absl::nullopt; } return GfxBufferFormatToVideoPixelFormat( kSupportedBitDepthAndGfxFormats.at(bit_depth)); @@ -100,10 +100,9 @@ std::unique_ptr<DecoderInterface> VaapiVideoDecoder::Create( } // static -SupportedVideoDecoderConfigs VaapiVideoDecoder::GetSupportedConfigs( - const gpu::GpuDriverBugWorkarounds& workarounds) { +SupportedVideoDecoderConfigs VaapiVideoDecoder::GetSupportedConfigs() { return ConvertFromSupportedProfiles( - VaapiWrapper::GetSupportedDecodeProfiles(workarounds), + VaapiWrapper::GetSupportedDecodeProfiles(), #if BUILDFLAG(USE_CHROMEOS_PROTECTED_MEDIA) true /* allow_encrypted */); #else @@ -275,6 +274,7 @@ void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config, profile_ = profile; color_space_ = config.color_space_info(); + hdr_metadata_ = config.hdr_metadata(); encryption_scheme_ = config.encryption_scheme(); auto accel_status = CreateAcceleratedVideoDecoder(); if (!accel_status.is_ok()) { @@ -380,7 +380,7 @@ void VaapiVideoDecoder::HandleDecodeTask() { // Decoding was successful, notify client and try to schedule the next // task. Switch to the idle state if we ran out of buffers to decode. std::move(current_decode_task_->decode_done_cb_).Run(DecodeStatus::OK); - current_decode_task_ = base::nullopt; + current_decode_task_ = absl::nullopt; if (!decode_task_queue_.empty()) { ScheduleNextDecodeTask(); } else { @@ -428,7 +428,7 @@ void VaapiVideoDecoder::ClearDecodeTaskQueue(DecodeStatus status) { if (current_decode_task_) { std::move(current_decode_task_->decode_done_cb_).Run(status); - current_decode_task_ = base::nullopt; + current_decode_task_ = absl::nullopt; } while (!decode_task_queue_.empty()) { @@ -607,7 +607,7 @@ void VaapiVideoDecoder::SurfaceReady(scoped_refptr<VASurface> va_surface, const auto gfx_color_space = color_space.ToGfxColorSpace(); if (gfx_color_space.IsValid()) video_frame->set_color_space(gfx_color_space); - + video_frame->set_hdr_metadata(hdr_metadata_); output_cb_.Run(std::move(video_frame)); } @@ -651,7 +651,7 @@ void VaapiVideoDecoder::ApplyResolutionChangeWithScreenSizes( return; const uint8_t bit_depth = decoder_->GetBitDepth(); - const base::Optional<VideoPixelFormat> format = + const absl::optional<VideoPixelFormat> format = GetPixelFormatForBitDepth(bit_depth); if (!format) { SetState(State::kError); @@ -740,7 +740,7 @@ void VaapiVideoDecoder::ApplyResolutionChangeWithScreenSizes( // Create the surface pool for decoding, the normal pool will be used for // output. const size_t decode_pool_size = decoder_->GetRequiredNumOfPictures(); - const base::Optional<gfx::BufferFormat> buffer_format = + const absl::optional<gfx::BufferFormat> buffer_format = VideoPixelFormatToGfxBufferFormat(*format); if (!buffer_format) { decode_to_output_scale_factor_.reset(); @@ -761,7 +761,7 @@ void VaapiVideoDecoder::ApplyResolutionChangeWithScreenSizes( std::unique_ptr<ScopedVASurface> surface = vaapi_wrapper_->CreateScopedVASurface( base::strict_cast<unsigned int>(va_rt_format), decoder_pic_size, - /*visible_size=*/base::nullopt, va_fourcc); + /*visible_size=*/absl::nullopt, va_fourcc); if (!surface) { while (!decode_surface_pool_for_scaling_.empty()) decode_surface_pool_for_scaling_.pop(); @@ -893,7 +893,7 @@ void VaapiVideoDecoder::Flush() { // Notify the client flushing is done. std::move(current_decode_task_->decode_done_cb_).Run(DecodeStatus::OK); - current_decode_task_ = base::nullopt; + current_decode_task_ = absl::nullopt; // Wait for new decodes, no decode tasks should be queued while flushing. SetState(State::kWaitingForInput); diff --git a/chromium/media/gpu/vaapi/vaapi_video_decoder.h b/chromium/media/gpu/vaapi/vaapi_video_decoder.h index 06cdb0004df..8aabb95f147 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_decoder.h +++ b/chromium/media/gpu/vaapi/vaapi_video_decoder.h @@ -19,7 +19,6 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/sequence_checker.h" #include "base/time/time.h" #include "build/chromeos_buildflags.h" @@ -32,13 +31,11 @@ #include "media/gpu/chromeos/video_decoder_pipeline.h" #include "media/gpu/decode_surface_handler.h" #include "media/gpu/vaapi/vaapi_utils.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_memory_buffer.h" - -namespace gpu { -class GpuDriverBugWorkarounds; -} +#include "ui/gfx/hdr_metadata.h" namespace media { @@ -56,8 +53,7 @@ class VaapiVideoDecoder : public DecoderInterface, scoped_refptr<base::SequencedTaskRunner> decoder_task_runner, base::WeakPtr<DecoderInterface::Client> client); - static SupportedVideoDecoderConfigs GetSupportedConfigs( - const gpu::GpuDriverBugWorkarounds& workarounds); + static SupportedVideoDecoderConfigs GetSupportedConfigs(); // DecoderInterface implementation. void Initialize(const VideoDecoderConfig& config, @@ -172,10 +168,10 @@ class VaapiVideoDecoder : public DecoderInterface, // request a reset. (Used in protected decoding). WaitingCB waiting_cb_; - // The video stream's profile. + // Bitstream information, written during Initialize(). VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN; - // Color space of the video frame. VideoColorSpace color_space_; + absl::optional<gfx::HDRMetadata> hdr_metadata_; // Ratio of natural size to |visible_rect_| of the output frames. double pixel_aspect_ratio_ = 0.0; @@ -192,7 +188,7 @@ class VaapiVideoDecoder : public DecoderInterface, // Queue containing all requested decode tasks. base::queue<DecodeTask> decode_task_queue_; // The decode task we're currently trying to execute. - base::Optional<DecodeTask> current_decode_task_; + absl::optional<DecodeTask> current_decode_task_; // The next input buffer id. int32_t next_buffer_id_ = 0; @@ -240,7 +236,7 @@ class VaapiVideoDecoder : public DecoderInterface, // When we are doing scaled decoding, this is the scale factor we are using, // and applies the same in both dimensions. - base::Optional<float> decode_to_output_scale_factor_; + absl::optional<float> decode_to_output_scale_factor_; SEQUENCE_CHECKER(sequence_checker_); diff --git a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc index 035361dea27..059f3f68b65 100644 --- a/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_video_encode_accelerator.cc @@ -92,7 +92,7 @@ gfx::Size GetInputFrameSize(VideoPixelFormat format, const gfx::Size& visible_size) { // Get a VideoFrameLayout of a graphic buffer with the same gfx::BufferUsage // as camera stack. - base::Optional<VideoFrameLayout> layout = GetPlatformVideoFrameLayout( + absl::optional<VideoFrameLayout> layout = GetPlatformVideoFrameLayout( /*gpu_memory_buffer_factory=*/nullptr, format, visible_size, gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE); if (!layout || layout->planes().empty()) { @@ -1092,7 +1092,7 @@ bool VaapiVideoEncodeAccelerator::H264Accelerator::SubmitFrameParameters( seq_param.bits_per_second = encode_params.bitrate_bps; SPS_TO_SP(max_num_ref_frames); - base::Optional<gfx::Size> coded_size = sps.GetCodedSize(); + absl::optional<gfx::Size> coded_size = sps.GetCodedSize(); if (!coded_size) { DVLOGF(1) << "Invalid coded size"; return false; diff --git a/chromium/media/gpu/vaapi/vaapi_wrapper.cc b/chromium/media/gpu/vaapi/vaapi_wrapper.cc index df500d8bdeb..4333c6adc0d 100644 --- a/chromium/media/gpu/vaapi/vaapi_wrapper.cc +++ b/chromium/media/gpu/vaapi/vaapi_wrapper.cc @@ -23,6 +23,7 @@ #include "base/bind.h" #include "base/bits.h" #include "base/callback_helpers.h" +#include "base/containers/contains.h" #include "base/cpu.h" #include "base/environment.h" #include "base/files/scoped_file.h" @@ -51,7 +52,6 @@ // Auto-generated for dlopen libva libraries #include "media/gpu/vaapi/va_stubs.h" -#include "gpu/config/gpu_driver_bug_workarounds.h" #include "third_party/libva_protected_content/va_protected_content.h" #include "third_party/libyuv/include/libyuv.h" #include "third_party/minigbm/src/external/i915_drm.h" @@ -1433,8 +1433,7 @@ VaapiWrapper::GetSupportedEncodeProfiles() { // static VideoDecodeAccelerator::SupportedProfiles -VaapiWrapper::GetSupportedDecodeProfiles( - const gpu::GpuDriverBugWorkarounds& workarounds) { +VaapiWrapper::GetSupportedDecodeProfiles() { VideoDecodeAccelerator::SupportedProfiles profiles; for (const auto& media_to_va_profile_map_entry : GetProfileCodecMap()) { @@ -1442,15 +1441,6 @@ VaapiWrapper::GetSupportedDecodeProfiles( const VAProfile va_profile = media_to_va_profile_map_entry.second; DCHECK(va_profile != VAProfileNone); - if (media_profile == VP8PROFILE_ANY && - workarounds.disable_accelerated_vp8_decode) { - continue; - } - if (media_profile == VP9PROFILE_PROFILE2 && - workarounds.disable_accelerated_vp9_profile2_decode) { - continue; - } - const VASupportedProfiles::ProfileInfo* profile_info = VASupportedProfiles::Get().IsProfileSupported(kDecode, va_profile); if (!profile_info) @@ -1601,11 +1591,11 @@ bool VaapiWrapper::IsVppResolutionAllowed(const gfx::Size& size) { VAProfileNone); if (!profile_info) return false; - return gfx::Rect(profile_info->min_resolution.width(), - profile_info->min_resolution.height(), - profile_info->max_resolution.width(), - profile_info->max_resolution.height()) - .Contains(size.width(), size.height()); + + return size.width() >= profile_info->min_resolution.width() && + size.width() <= profile_info->max_resolution.width() && + size.height() >= profile_info->min_resolution.height() && + size.height() <= profile_info->max_resolution.height(); } // static @@ -1765,7 +1755,7 @@ bool VaapiWrapper::CreateContextAndSurfaces( std::unique_ptr<ScopedVASurface> VaapiWrapper::CreateContextAndScopedVASurface( unsigned int va_format, const gfx::Size& size, - const base::Optional<gfx::Size>& visible_size) { + const absl::optional<gfx::Size>& visible_size) { if (va_context_id_ != VA_INVALID_ID) { LOG(ERROR) << "The current context should be destroyed before creating a " "new one"; @@ -2549,7 +2539,10 @@ bool VaapiWrapper::DownloadFromVABuffer(VABufferID buffer_id, base::AutoLock auto_lock(*va_lock_); TRACE_EVENT0("media,gpu", "VaapiWrapper::DownloadFromVABufferLocked"); - { + // vaSyncSurface() is not necessary on Intel platforms as long as there is a + // vaMapBuffer() like in ScopedVABufferMapping below, see b/184312032. + if (GetImplementationType() != VAImplementation::kIntelI965 && + GetImplementationType() != VAImplementation::kIntelIHD) { TRACE_EVENT0("media,gpu", "VaapiWrapper::DownloadFromVABuffer_SyncSurface"); const VAStatus va_res = vaSyncSurface(va_display_, sync_surface_id); VA_SUCCESS_OR_RETURN(va_res, VaapiFunctions::kVASyncSurface, false); @@ -2622,8 +2615,8 @@ bool VaapiWrapper::IsRotationSupported() { bool VaapiWrapper::BlitSurface(const VASurface& va_surface_src, const VASurface& va_surface_dest, - base::Optional<gfx::Rect> src_rect, - base::Optional<gfx::Rect> dest_rect, + absl::optional<gfx::Rect> src_rect, + absl::optional<gfx::Rect> dest_rect, VideoRotation rotation) { DCHECK_EQ(mode_, kVideoProcess); base::AutoLock auto_lock(*va_lock_); @@ -2919,7 +2912,7 @@ bool VaapiWrapper::CreateSurfaces(unsigned int va_format, std::unique_ptr<ScopedVASurface> VaapiWrapper::CreateScopedVASurface( unsigned int va_rt_format, const gfx::Size& size, - const base::Optional<gfx::Size>& visible_size, + const absl::optional<gfx::Size>& visible_size, uint32_t va_fourcc) { if (kInvalidVaRtFormat == va_rt_format) { LOG(ERROR) << "Invalid VA RT format to CreateScopedVASurface"; diff --git a/chromium/media/gpu/vaapi/vaapi_wrapper.h b/chromium/media/gpu/vaapi/vaapi_wrapper.h index 29b68649982..da1e5477233 100644 --- a/chromium/media/gpu/vaapi/vaapi_wrapper.h +++ b/chromium/media/gpu/vaapi/vaapi_wrapper.h @@ -24,7 +24,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" -#include "base/optional.h" #include "base/synchronization/lock.h" #include "base/thread_annotations.h" #include "build/chromeos_buildflags.h" @@ -33,6 +32,7 @@ #include "media/gpu/vaapi/vaapi_utils.h" #include "media/video/video_decode_accelerator.h" #include "media/video/video_encode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" #if defined(USE_X11) @@ -46,10 +46,6 @@ class NativePixmapDmaBuf; class Rect; } -namespace gpu { -class GpuDriverBugWorkarounds; -} - namespace media { constexpr unsigned int kInvalidVaRtFormat = 0u; @@ -169,8 +165,7 @@ class MEDIA_GPU_EXPORT VaapiWrapper static VideoEncodeAccelerator::SupportedProfiles GetSupportedEncodeProfiles(); // Return the supported video decode profiles. - static VideoDecodeAccelerator::SupportedProfiles GetSupportedDecodeProfiles( - const gpu::GpuDriverBugWorkarounds& workarounds); + static VideoDecodeAccelerator::SupportedProfiles GetSupportedDecodeProfiles(); // Return true when decoding using |va_profile| is supported. static bool IsDecodeSupported(VAProfile va_profile); @@ -269,7 +264,7 @@ class MEDIA_GPU_EXPORT VaapiWrapper std::unique_ptr<ScopedVASurface> CreateContextAndScopedVASurface( unsigned int va_format, const gfx::Size& size, - const base::Optional<gfx::Size>& visible_size = base::nullopt); + const absl::optional<gfx::Size>& visible_size = absl::nullopt); // Attempts to create a protected session that will be attached to the // decoding context to enable encrypted video decoding. If it cannot be @@ -315,7 +310,7 @@ class MEDIA_GPU_EXPORT VaapiWrapper std::unique_ptr<ScopedVASurface> CreateScopedVASurface( unsigned int va_rt_format, const gfx::Size& size, - const base::Optional<gfx::Size>& visible_size = base::nullopt, + const absl::optional<gfx::Size>& visible_size = absl::nullopt, uint32_t va_fourcc = 0); // Creates a self-releasing VASurface from |pixmap|. The created VASurface @@ -469,8 +464,8 @@ class MEDIA_GPU_EXPORT VaapiWrapper // be used to specify the area used in the blit. bool BlitSurface(const VASurface& va_surface_src, const VASurface& va_surface_dest, - base::Optional<gfx::Rect> src_rect = base::nullopt, - base::Optional<gfx::Rect> dest_rect = base::nullopt, + absl::optional<gfx::Rect> src_rect = absl::nullopt, + absl::optional<gfx::Rect> dest_rect = absl::nullopt, VideoRotation rotation = VIDEO_ROTATION_0) WARN_UNUSED_RESULT; diff --git a/chromium/media/gpu/vaapi/vp9_encoder_unittest.cc b/chromium/media/gpu/vaapi/vp9_encoder_unittest.cc index 689506089bf..bed699b56bb 100644 --- a/chromium/media/gpu/vaapi/vp9_encoder_unittest.cc +++ b/chromium/media/gpu/vaapi/vp9_encoder_unittest.cc @@ -12,13 +12,13 @@ #include "base/callback_helpers.h" #include "base/logging.h" #include "base/numerics/safe_conversions.h" -#include "base/optional.h" #include "base/stl_util.h" #include "media/filters/vp9_parser.h" #include "media/gpu/vaapi/vp9_rate_control.h" #include "media/gpu/vaapi/vp9_temporal_layers.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/libvpx/source/libvpx/vp9/common/vp9_blockd.h" #include "third_party/libvpx/source/libvpx/vp9/ratectrl_rtc.h" @@ -42,8 +42,8 @@ VideoEncodeAccelerator::Config kDefaultVideoEncodeAcceleratorConfig( VP9PROFILE_PROFILE0, 14000000 /* = maximum bitrate in bits per second for level 3.1 */, VideoEncodeAccelerator::kDefaultFramerate, - base::nullopt /* gop_length */, - base::nullopt /* h264 output level*/, + absl::nullopt /* gop_length */, + absl::nullopt /* h264 output level*/, false /* is_constrained_h264 */, VideoEncodeAccelerator::Config::StorageType::kShmem); @@ -56,7 +56,7 @@ void GetTemporalLayer(bool keyframe, int index, size_t num_temporal_layers, std::array<bool, kVp9NumRefsPerFrame>* ref_frames_used, - base::Optional<uint8_t>* temporal_layer_id) { + absl::optional<uint8_t>* temporal_layer_id) { switch (num_temporal_layers) { case 1: *ref_frames_used = @@ -211,9 +211,9 @@ class VP9EncoderTest : public ::testing::TestWithParam<VP9EncoderTestParam> { void EncodeSequence(bool is_keyframe); void EncodeConstantQuantizationParameterSequence( bool is_keyframe, - base::Optional<std::array<bool, kVp9NumRefsPerFrame>> + absl::optional<std::array<bool, kVp9NumRefsPerFrame>> expected_ref_frames_used, - base::Optional<uint8_t> expected_temporal_layer_id = base::nullopt); + absl::optional<uint8_t> expected_temporal_layer_id = absl::nullopt); void UpdateRatesTest(BitrateControl bitrate_control, size_t num_temporal_layers); @@ -312,9 +312,9 @@ void VP9EncoderTest::EncodeSequence(bool is_keyframe) { void VP9EncoderTest::EncodeConstantQuantizationParameterSequence( bool is_keyframe, - base::Optional<std::array<bool, kVp9NumRefsPerFrame>> + absl::optional<std::array<bool, kVp9NumRefsPerFrame>> expected_ref_frames_used, - base::Optional<uint8_t> expected_temporal_layer_id) { + absl::optional<uint8_t> expected_temporal_layer_id) { InSequence seq; auto encode_job = CreateEncodeJob(is_keyframe); scoped_refptr<VP9Picture> picture(new VP9Picture); @@ -390,7 +390,7 @@ void VP9EncoderTest::UpdateRatesTest(BitrateControl bitrate_control, num_temporal_layers); if (bitrate_control == BitrateControl::kConstantQuantizationParameter) { EncodeConstantQuantizationParameterSequence(is_keyframe, {}, - base::nullopt); + absl::nullopt); } else { EncodeSequence(is_keyframe); } @@ -460,7 +460,7 @@ TEST_P(VP9EncoderTest, EncodeWithSoftwareBitrateControl) { for (size_t i = 0; i < kEncodeFrames; i++) { const bool is_keyframe = i == 0; std::array<bool, kVp9NumRefsPerFrame> ref_frames_used; - base::Optional<uint8_t> temporal_layer_id; + absl::optional<uint8_t> temporal_layer_id; GetTemporalLayer(is_keyframe, i, num_temporal_layers, &ref_frames_used, &temporal_layer_id); EncodeConstantQuantizationParameterSequence(is_keyframe, ref_frames_used, @@ -495,7 +495,7 @@ TEST_P(VP9EncoderTest, ForceKeyFrameWithSoftwareBitrateControl) { for (size_t i = 0; i < kKeyFrameInterval; i++) { const bool is_keyframe = i == 0; std::array<bool, kVp9NumRefsPerFrame> ref_frames_used; - base::Optional<uint8_t> temporal_layer_id; + absl::optional<uint8_t> temporal_layer_id; GetTemporalLayer(is_keyframe, i, num_temporal_layers, &ref_frames_used, &temporal_layer_id); EncodeConstantQuantizationParameterSequence(is_keyframe, ref_frames_used, diff --git a/chromium/media/gpu/vaapi/vp9_rate_control.h b/chromium/media/gpu/vaapi/vp9_rate_control.h index 116f47f5895..5c03eb3db09 100644 --- a/chromium/media/gpu/vaapi/vp9_rate_control.h +++ b/chromium/media/gpu/vaapi/vp9_rate_control.h @@ -7,7 +7,7 @@ #include <memory> #include "base/callback.h" -#include "base/optional.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace libvpx { struct VP9FrameParamsQpRTC; diff --git a/chromium/media/gpu/vaapi/vp9_temporal_layers_unittest.cc b/chromium/media/gpu/vaapi/vp9_temporal_layers_unittest.cc index 7b4f3cb3795..354138ab62d 100644 --- a/chromium/media/gpu/vaapi/vp9_temporal_layers_unittest.cc +++ b/chromium/media/gpu/vaapi/vp9_temporal_layers_unittest.cc @@ -9,12 +9,13 @@ #include <map> #include <vector> -#include "base/optional.h" +#include "base/containers/contains.h" #include "media/filters/vp9_parser.h" #include "media/gpu/vp9_picture.h" #include "media/gpu/vp9_reference_frame_vector.h" #include "media/video/video_encode_accelerator.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { class VP9TemporalLayersTest : public ::testing::TestWithParam<size_t> { diff --git a/chromium/media/gpu/video_decode_accelerator_perf_tests.cc b/chromium/media/gpu/video_decode_accelerator_perf_tests.cc index 8037133f95f..d6fd4d309bb 100644 --- a/chromium/media/gpu/video_decode_accelerator_perf_tests.cc +++ b/chromium/media/gpu/video_decode_accelerator_perf_tests.cc @@ -9,7 +9,6 @@ #include "base/command_line.h" #include "base/files/file_util.h" #include "base/json/json_writer.h" -#include "base/strings/stringprintf.h" #include "media/base/test_data_util.h" #include "media/gpu/test/video.h" #include "media/gpu/test/video_player/frame_renderer_dummy.h" diff --git a/chromium/media/gpu/video_encode_accelerator_perf_tests.cc b/chromium/media/gpu/video_encode_accelerator_perf_tests.cc index 6e54c3d784f..d38d78f9c36 100644 --- a/chromium/media/gpu/video_encode_accelerator_perf_tests.cc +++ b/chromium/media/gpu/video_encode_accelerator_perf_tests.cc @@ -10,8 +10,6 @@ #include "base/command_line.h" #include "base/files/file_util.h" #include "base/json/json_writer.h" -#include "base/optional.h" -#include "base/strings/stringprintf.h" #include "media/base/bitstream_buffer.h" #include "media/base/media_util.h" #include "media/base/test_data_util.h" @@ -24,6 +22,7 @@ #include "media/gpu/test/video_frame_validator.h" #include "media/gpu/test/video_test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace test { @@ -584,7 +583,7 @@ int main(int argc, char** argv) { base::FilePath video_metadata_path = (args.size() >= 2) ? base::FilePath(args[1]) : base::FilePath(); std::string codec = "h264"; - base::Optional<uint32_t> encode_bitrate; + absl::optional<uint32_t> encode_bitrate; // Parse command line arguments. base::FilePath::StringType output_folder = media::test::kDefaultOutputFolder; diff --git a/chromium/media/gpu/video_encode_accelerator_tests.cc b/chromium/media/gpu/video_encode_accelerator_tests.cc index 99c1d1db010..1948f123838 100644 --- a/chromium/media/gpu/video_encode_accelerator_tests.cc +++ b/chromium/media/gpu/video_encode_accelerator_tests.cc @@ -8,7 +8,6 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" -#include "base/optional.h" #include "base/strings/string_number_conversions.h" #include "media/base/media_util.h" #include "media/base/test_data_util.h" @@ -29,6 +28,7 @@ #include "media/gpu/test/video_test_environment.h" #include "media/gpu/test/video_test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace test { @@ -128,7 +128,7 @@ class VideoEncoderTest : public ::testing::Test { const VideoDecoderConfig& decoder_config, const size_t last_frame_index, VideoFrameValidator::GetModelFrameCB get_model_frame_cb, - base::Optional<size_t> num_vp9_temporal_layers_to_decode) { + absl::optional<size_t> num_vp9_temporal_layers_to_decode) { std::vector<std::unique_ptr<VideoFrameProcessor>> video_frame_processors; // Attach a video frame writer to store individual frames to disk if @@ -255,7 +255,7 @@ class VideoEncoderTest : public ::testing::Test { } else { bitstream_processors.emplace_back(CreateBitstreamValidator( video, decoder_config, config.num_frames_to_encode - 1, - get_model_frame_cb, base::nullopt)); + get_model_frame_cb, absl::nullopt)); LOG_ASSERT(bitstream_processors.back()); } return bitstream_processors; @@ -276,19 +276,19 @@ class VideoEncoderTest : public ::testing::Test { std::unique_ptr<RawDataHelper> raw_data_helper_; }; -base::Optional<std::string> SupportsDynamicFramerate() { +absl::optional<std::string> SupportsDynamicFramerate() { return g_env->IsKeplerUsed() - ? base::make_optional<std::string>( + ? absl::make_optional<std::string>( "The rate controller in the kepler firmware doesn't handle " "frame rate changes correctly.") - : base::nullopt; + : absl::nullopt; } -base::Optional<std::string> SupportsNV12DmaBufInput() { - return g_env->IsKeplerUsed() ? base::make_optional<std::string>( +absl::optional<std::string> SupportsNV12DmaBufInput() { + return g_env->IsKeplerUsed() ? absl::make_optional<std::string>( "Encoding with dmabuf input frames is not " "supported in kepler.") - : base::nullopt; + : absl::nullopt; } } // namespace @@ -722,7 +722,7 @@ int main(int argc, char** argv) { media::test::VideoEncoderTestEnvironment::Create( video_path, video_metadata_path, enable_bitstream_validator, output_folder, codec, num_temporal_layers, output_bitstream, - /*output_bitrate=*/base::nullopt, frame_output_config); + /*output_bitrate=*/absl::nullopt, frame_output_config); if (!test_environment) return EXIT_FAILURE; diff --git a/chromium/media/gpu/vp9_picture.h b/chromium/media/gpu/vp9_picture.h index a200bbd2bb7..75490d1c309 100644 --- a/chromium/media/gpu/vp9_picture.h +++ b/chromium/media/gpu/vp9_picture.h @@ -8,10 +8,10 @@ #include <memory> #include "base/macros.h" -#include "base/optional.h" #include "media/filters/vp9_parser.h" #include "media/gpu/codec_picture.h" #include "media/video/video_encode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -33,7 +33,7 @@ class VP9Picture : public CodecPicture { std::unique_ptr<Vp9FrameHeader> frame_hdr; - base::Optional<Vp9Metadata> metadata_for_encoding; + absl::optional<Vp9Metadata> metadata_for_encoding; protected: ~VP9Picture() override; diff --git a/chromium/media/gpu/windows/d3d11_copying_texture_wrapper.cc b/chromium/media/gpu/windows/d3d11_copying_texture_wrapper.cc index 96e72747877..8d0a4c2cc15 100644 --- a/chromium/media/gpu/windows/d3d11_copying_texture_wrapper.cc +++ b/chromium/media/gpu/windows/d3d11_copying_texture_wrapper.cc @@ -20,7 +20,7 @@ CopyingTexture2DWrapper::CopyingTexture2DWrapper( std::unique_ptr<Texture2DWrapper> output_wrapper, scoped_refptr<VideoProcessorProxy> processor, ComD3D11Texture2D output_texture, - base::Optional<gfx::ColorSpace> output_color_space) + absl::optional<gfx::ColorSpace> output_color_space) : size_(size), video_processor_(std::move(processor)), output_texture_wrapper_(std::move(output_wrapper)), diff --git a/chromium/media/gpu/windows/d3d11_copying_texture_wrapper.h b/chromium/media/gpu/windows/d3d11_copying_texture_wrapper.h index 5fb2fffef9b..31c6a40570b 100644 --- a/chromium/media/gpu/windows/d3d11_copying_texture_wrapper.h +++ b/chromium/media/gpu/windows/d3d11_copying_texture_wrapper.h @@ -8,10 +8,10 @@ #include <memory> #include <vector> -#include "base/optional.h" #include "media/gpu/media_gpu_export.h" #include "media/gpu/windows/d3d11_picture_buffer.h" #include "media/gpu/windows/d3d11_video_processor_proxy.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -28,7 +28,7 @@ class MEDIA_GPU_EXPORT CopyingTexture2DWrapper : public Texture2DWrapper { std::unique_ptr<Texture2DWrapper> output_wrapper, scoped_refptr<VideoProcessorProxy> processor, ComD3D11Texture2D output_texture, - base::Optional<gfx::ColorSpace> output_color_space); + absl::optional<gfx::ColorSpace> output_color_space); ~CopyingTexture2DWrapper() override; Status ProcessTexture(const gfx::ColorSpace& input_color_space, @@ -50,10 +50,10 @@ class MEDIA_GPU_EXPORT CopyingTexture2DWrapper : public Texture2DWrapper { std::unique_ptr<Texture2DWrapper> output_texture_wrapper_; ComD3D11Texture2D output_texture_; // If set, then this is the desired output color space for the copy. - base::Optional<gfx::ColorSpace> output_color_space_; + absl::optional<gfx::ColorSpace> output_color_space_; // If set, this is the color space that we last saw in ProcessTexture. - base::Optional<gfx::ColorSpace> previous_input_color_space_; + absl::optional<gfx::ColorSpace> previous_input_color_space_; ComD3D11Texture2D texture_; size_t array_slice_ = 0; diff --git a/chromium/media/gpu/windows/d3d11_copying_texture_wrapper_unittest.cc b/chromium/media/gpu/windows/d3d11_copying_texture_wrapper_unittest.cc index a999fe50fe3..4119647c6ae 100644 --- a/chromium/media/gpu/windows/d3d11_copying_texture_wrapper_unittest.cc +++ b/chromium/media/gpu/windows/d3d11_copying_texture_wrapper_unittest.cc @@ -76,10 +76,10 @@ class MockVideoProcessorProxy : public VideoProcessorProxy { MOCK_METHOD0(MockVideoProcessorBlt, HRESULT()); // Most recent arguments to SetStream/OutputColorSpace()/etc. - base::Optional<gfx::ColorSpace> last_stream_color_space_; - base::Optional<gfx::ColorSpace> last_output_color_space_; - base::Optional<DXGI_HDR_METADATA_HDR10> last_stream_metadata_; - base::Optional<DXGI_HDR_METADATA_HDR10> last_display_metadata_; + absl::optional<gfx::ColorSpace> last_stream_color_space_; + absl::optional<gfx::ColorSpace> last_output_color_space_; + absl::optional<DXGI_HDR_METADATA_HDR10> last_stream_metadata_; + absl::optional<DXGI_HDR_METADATA_HDR10> last_display_metadata_; private: ~MockVideoProcessorProxy() override = default; @@ -212,7 +212,7 @@ TEST_P(D3D11CopyingTexture2DWrapperTest, MockVideoProcessorProxy* processor_raw = processor.get(); // Provide an unlikely color space, to see if it gets to the video processor, // if we're not just doing a pass-through of the input. - base::Optional<gfx::ColorSpace> copy_color_space; + absl::optional<gfx::ColorSpace> copy_color_space; if (!GetPassthroughColorSpace()) copy_color_space = gfx::ColorSpace::CreateDisplayP3D65(); auto texture_wrapper = ExpectTextureWrapper(); diff --git a/chromium/media/gpu/windows/d3d11_h264_accelerator.h b/chromium/media/gpu/windows/d3d11_h264_accelerator.h index 08ca39f8bd8..59198167366 100644 --- a/chromium/media/gpu/windows/d3d11_h264_accelerator.h +++ b/chromium/media/gpu/windows/d3d11_h264_accelerator.h @@ -123,4 +123,4 @@ class D3D11H264Accelerator : public H264Decoder::H264Accelerator { } // namespace media -#endif // MEDIA_GPU_D3D11_WINDOWS_H264_ACCELERATOR_H_ +#endif // MEDIA_GPU_WINDOWS_D3D11_H264_ACCELERATOR_H_ diff --git a/chromium/media/gpu/windows/d3d11_texture_selector.cc b/chromium/media/gpu/windows/d3d11_texture_selector.cc index 7a92a8f5280..34f5db5bdbb 100644 --- a/chromium/media/gpu/windows/d3d11_texture_selector.cc +++ b/chromium/media/gpu/windows/d3d11_texture_selector.cc @@ -50,7 +50,7 @@ std::unique_ptr<TextureSelector> TextureSelector::Create( MediaLog* media_log) { VideoPixelFormat output_pixel_format; DXGI_FORMAT output_dxgi_format; - base::Optional<gfx::ColorSpace> output_color_space; + absl::optional<gfx::ColorSpace> output_color_space; // TODO(liberato): add other options here, like "copy to rgb" for NV12. switch (decoder_output_format) { @@ -66,7 +66,6 @@ std::unique_ptr<TextureSelector> TextureSelector::Create( } case DXGI_FORMAT_P010: { MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder producing P010"; - output_pixel_format = PIXEL_FORMAT_ARGB; // TODO(liberato): handle case where we bind P010 directly (see dxva). @@ -94,6 +93,7 @@ std::unique_ptr<TextureSelector> TextureSelector::Create( // TODO(liberato): use the format checker, else bind P010. MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder: 8 bit sRGB"; output_dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM; + output_pixel_format = PIXEL_FORMAT_ARGB; output_color_space = gfx::ColorSpace::CreateSRGB(); } else { // Bind P010 directly, since we can't copy. @@ -116,9 +116,10 @@ std::unique_ptr<TextureSelector> TextureSelector::Create( output_color_space = gfx::ColorSpace::CreateSCRGBLinear(); } else if (format_checker->CheckOutputFormatSupport( DXGI_FORMAT_R10G10B10A2_UNORM)) { - MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder: BGRA10 scRGBLinear"; + MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder: RGB10A2 HDR10/PQ"; output_dxgi_format = DXGI_FORMAT_R10G10B10A2_UNORM; - output_color_space = gfx::ColorSpace::CreateSCRGBLinear(); + output_pixel_format = PIXEL_FORMAT_XB30; + output_color_space = gfx::ColorSpace::CreateHDR10(); } else { // No support at all. Just bind P010, and hope for the best. MEDIA_LOG(INFO, media_log) @@ -149,9 +150,10 @@ std::unique_ptr<TextureSelector> TextureSelector::Create( // If we're trying to produce an output texture that's different from what // the decoder is providing, then we need to copy it. If sharing decoder // textures is not allowed, then copy either way. - bool needs_texture_copy = !SupportsZeroCopy(gpu_preferences, workarounds) || - (decoder_output_format != output_dxgi_format) || - base::FeatureList::IsEnabled(kD3D11VideoDecoderAlwaysCopy); + bool needs_texture_copy = + !SupportsZeroCopy(gpu_preferences, workarounds) || + (decoder_output_format != output_dxgi_format) || + base::FeatureList::IsEnabled(kD3D11VideoDecoderAlwaysCopy); MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder output color space: " @@ -178,8 +180,7 @@ std::unique_ptr<Texture2DWrapper> TextureSelector::CreateTextureWrapper( ComD3D11Device device, gfx::Size size) { // TODO(liberato): If the output format is rgb, then create a pbuffer wrapper. - return std::make_unique<DefaultTexture2DWrapper>(size, OutputDXGIFormat(), - PixelFormat()); + return std::make_unique<DefaultTexture2DWrapper>(size, OutputDXGIFormat()); } bool TextureSelector::WillCopyForTesting() const { @@ -190,7 +191,7 @@ CopyTextureSelector::CopyTextureSelector( VideoPixelFormat pixfmt, DXGI_FORMAT input_dxgifmt, DXGI_FORMAT output_dxgifmt, - base::Optional<gfx::ColorSpace> output_color_space, + absl::optional<gfx::ColorSpace> output_color_space, ComD3D11VideoDevice video_device, ComD3D11DeviceContext device_context) : TextureSelector(pixfmt, @@ -228,9 +229,7 @@ std::unique_ptr<Texture2DWrapper> CopyTextureSelector::CreateTextureWrapper( return nullptr; return std::make_unique<CopyingTexture2DWrapper>( - size, - std::make_unique<DefaultTexture2DWrapper>(size, OutputDXGIFormat(), - PixelFormat()), + size, std::make_unique<DefaultTexture2DWrapper>(size, OutputDXGIFormat()), video_processor_proxy_, out_texture, output_color_space_); } diff --git a/chromium/media/gpu/windows/d3d11_texture_selector.h b/chromium/media/gpu/windows/d3d11_texture_selector.h index 7de0a4d891f..f27444bcb0d 100644 --- a/chromium/media/gpu/windows/d3d11_texture_selector.h +++ b/chromium/media/gpu/windows/d3d11_texture_selector.h @@ -78,7 +78,7 @@ class MEDIA_GPU_EXPORT CopyTextureSelector : public TextureSelector { CopyTextureSelector(VideoPixelFormat pixfmt, DXGI_FORMAT input_dxgifmt, DXGI_FORMAT output_dxgifmt, - base::Optional<gfx::ColorSpace> output_color_space, + absl::optional<gfx::ColorSpace> output_color_space, ComD3D11VideoDevice video_device, ComD3D11DeviceContext d3d11_device_context); ~CopyTextureSelector() override; @@ -90,7 +90,7 @@ class MEDIA_GPU_EXPORT CopyTextureSelector : public TextureSelector { bool WillCopyForTesting() const override; private: - base::Optional<gfx::ColorSpace> output_color_space_; + absl::optional<gfx::ColorSpace> output_color_space_; scoped_refptr<VideoProcessorProxy> video_processor_proxy_; }; diff --git a/chromium/media/gpu/windows/d3d11_texture_selector_unittest.cc b/chromium/media/gpu/windows/d3d11_texture_selector_unittest.cc index 12bd030c458..9ebb9c34ca6 100644 --- a/chromium/media/gpu/windows/d3d11_texture_selector_unittest.cc +++ b/chromium/media/gpu/windows/d3d11_texture_selector_unittest.cc @@ -129,7 +129,7 @@ TEST_F(D3D11TextureSelectorUnittest, P010CopiesTo10BitRGBInHDR) { CreateWithDefaultGPUInfo(DXGI_FORMAT_P010, ZeroCopyEnabled::kTrue, TextureSelector::HDRMode::kSDROrHDR); - EXPECT_EQ(tex_sel->PixelFormat(), PIXEL_FORMAT_ARGB); + EXPECT_EQ(tex_sel->PixelFormat(), PIXEL_FORMAT_XB30); EXPECT_EQ(tex_sel->OutputDXGIFormat(), DXGI_FORMAT_R10G10B10A2_UNORM); EXPECT_TRUE(tex_sel->WillCopyForTesting()); } diff --git a/chromium/media/gpu/windows/d3d11_texture_wrapper.cc b/chromium/media/gpu/windows/d3d11_texture_wrapper.cc index ed2ede8d1eb..0d1da963177 100644 --- a/chromium/media/gpu/windows/d3d11_texture_wrapper.cc +++ b/chromium/media/gpu/windows/d3d11_texture_wrapper.cc @@ -22,90 +22,43 @@ namespace media { namespace { -// Populates Viz |texture_formats| that map to the corresponding DXGI format and -// VideoPixelFormat. Returns true if they can be successfully mapped. -bool DXGIFormatToVizFormat( - DXGI_FORMAT dxgi_format, - VideoPixelFormat pixel_format, - size_t textures_per_picture, - std::array<viz::ResourceFormat, VideoFrame::kMaxPlanes>& texture_formats) { +bool SupportsFormat(DXGI_FORMAT dxgi_format) { switch (dxgi_format) { case DXGI_FORMAT_NV12: - DCHECK_EQ(textures_per_picture, 2u); - texture_formats[0] = viz::RED_8; // Y - texture_formats[1] = viz::RG_88; // UV - return true; case DXGI_FORMAT_P010: - // TODO(crbug.com/1011555): P010 formats are not fully supported. - // Treat them to be the same as NV12 for the time being. - DCHECK_EQ(textures_per_picture, 2u); - texture_formats[0] = viz::RED_8; - texture_formats[1] = viz::RG_88; - return true; case DXGI_FORMAT_B8G8R8A8_UNORM: - DCHECK_EQ(textures_per_picture, 1u); - if (pixel_format != PIXEL_FORMAT_ARGB) { - return false; - } - texture_formats[0] = viz::BGRA_8888; - return true; + case DXGI_FORMAT_R10G10B10A2_UNORM: case DXGI_FORMAT_R16G16B16A16_FLOAT: - DCHECK_EQ(textures_per_picture, 1u); - if (pixel_format != PIXEL_FORMAT_RGBAF16) - return false; - texture_formats[0] = viz::RGBA_F16; return true; - default: // Unsupported + default: return false; } } -} // anonymous namespace - -// Handy structure so that we can activate / bind one or two textures. -struct ScopedTextureEverything { - ScopedTextureEverything(GLenum unit, GLuint service_id) - : active_(unit), binder_(GL_TEXTURE_EXTERNAL_OES, service_id) {} - ~ScopedTextureEverything() = default; - - // Order is important; we need |active_| to be constructed first - // and destructed last. - gl::ScopedActiveTexture active_; - gl::ScopedTextureBinder binder_; - - DISALLOW_COPY_AND_ASSIGN(ScopedTextureEverything); -}; - -// Another handy helper class to guarantee that ScopedTextureEverythings -// are deleted in reverse order. This is required so that the scoped -// active texture unit doesn't change. Surprisingly, none of the stl -// containers, or the chromium ones, seem to guarantee anything about -// the order of destruction. -struct OrderedDestructionList { - OrderedDestructionList() = default; - ~OrderedDestructionList() { - // Erase last-to-first. - while (!list_.empty()) - list_.pop_back(); - } - - template <typename... Args> - void emplace_back(Args&&... args) { - list_.emplace_back(std::forward<Args>(args)...); +size_t NumPlanes(DXGI_FORMAT dxgi_format) { + switch (dxgi_format) { + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_P010: + return 2; + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return 1; + default: + NOTREACHED(); + return 0; } +} - std::list<ScopedTextureEverything> list_; - DISALLOW_COPY_AND_ASSIGN(OrderedDestructionList); -}; +} // anonymous namespace Texture2DWrapper::Texture2DWrapper() = default; Texture2DWrapper::~Texture2DWrapper() = default; DefaultTexture2DWrapper::DefaultTexture2DWrapper(const gfx::Size& size, - DXGI_FORMAT dxgi_format, - VideoPixelFormat pixel_format) - : size_(size), dxgi_format_(dxgi_format), pixel_format_(pixel_format) {} + DXGI_FORMAT dxgi_format) + : size_(size), dxgi_format_(dxgi_format) {} DefaultTexture2DWrapper::~DefaultTexture2DWrapper() = default; @@ -135,28 +88,17 @@ Status DefaultTexture2DWrapper::Init( GetCommandBufferHelperCB get_helper_cb, ComD3D11Texture2D texture, size_t array_slice) { - gpu_resources_ = base::SequenceBound<GpuResources>( - std::move(gpu_task_runner), - BindToCurrentLoop(base::BindOnce(&DefaultTexture2DWrapper::OnError, - weak_factory_.GetWeakPtr()))); - - const size_t textures_per_picture = VideoFrame::NumPlanes(pixel_format_); - - std::array<viz::ResourceFormat, VideoFrame::kMaxPlanes> texture_formats; - if (!DXGIFormatToVizFormat(dxgi_format_, pixel_format_, textures_per_picture, - texture_formats)) { + if (!SupportsFormat(dxgi_format_)) return Status(StatusCode::kUnsupportedTextureFormatForBind); - } // Generate mailboxes and holders. // TODO(liberato): Verify that this is really okay off the GPU main thread. // The current implementation is. std::vector<gpu::Mailbox> mailboxes; - for (size_t texture_idx = 0; texture_idx < textures_per_picture; - texture_idx++) { + for (size_t plane = 0; plane < NumPlanes(dxgi_format_); plane++) { mailboxes.push_back(gpu::Mailbox::GenerateForSharedImage()); - mailbox_holders_[texture_idx] = gpu::MailboxHolder( - mailboxes[texture_idx], gpu::SyncToken(), GL_TEXTURE_EXTERNAL_OES); + mailbox_holders_[plane] = gpu::MailboxHolder( + mailboxes[plane], gpu::SyncToken(), GL_TEXTURE_EXTERNAL_OES); } // Start construction of the GpuResources. @@ -164,10 +106,12 @@ Status DefaultTexture2DWrapper::Init( // device for decoding. Sharing seems not to work very well. Otherwise, we // would create the texture with KEYED_MUTEX and NTHANDLE, then send along // a handle that we get from |texture| as an IDXGIResource1. - gpu_resources_.AsyncCall(&GpuResources::Init) - .WithArgs(std::move(get_helper_cb), std::move(mailboxes), - GL_TEXTURE_EXTERNAL_OES, size_, textures_per_picture, - texture_formats, pixel_format_, texture, array_slice); + auto on_error_cb = BindToCurrentLoop(base::BindOnce( + &DefaultTexture2DWrapper::OnError, weak_factory_.GetWeakPtr())); + gpu_resources_ = base::SequenceBound<GpuResources>( + std::move(gpu_task_runner), std::move(on_error_cb), + std::move(get_helper_cb), std::move(mailboxes), size_, dxgi_format_, + texture, array_slice); return OkStatus(); } @@ -182,217 +126,47 @@ void DefaultTexture2DWrapper::SetStreamHDRMetadata( void DefaultTexture2DWrapper::SetDisplayHDRMetadata( const DXGI_HDR_METADATA_HDR10& dxgi_display_metadata) {} -DefaultTexture2DWrapper::GpuResources::GpuResources(OnErrorCB on_error_cb) - : on_error_cb_(std::move(on_error_cb)) {} - -DefaultTexture2DWrapper::GpuResources::~GpuResources() { - if (helper_ && helper_->MakeContextCurrent()) { - for (uint32_t service_id : service_ids_) - helper_->DestroyTexture(service_id); - } -} - -void DefaultTexture2DWrapper::GpuResources::Init( +DefaultTexture2DWrapper::GpuResources::GpuResources( + OnErrorCB on_error_cb, GetCommandBufferHelperCB get_helper_cb, - const std::vector<gpu::Mailbox> mailboxes, - GLenum target, - gfx::Size size, - size_t textures_per_picture, - std::array<viz::ResourceFormat, VideoFrame::kMaxPlanes> texture_formats, - VideoPixelFormat pixel_format, + const std::vector<gpu::Mailbox>& mailboxes, + const gfx::Size& size, + DXGI_FORMAT dxgi_format, ComD3D11Texture2D texture, size_t array_slice) { helper_ = get_helper_cb.Run(); if (!helper_ || !helper_->MakeContextCurrent()) { - NotifyError(StatusCode::kMakeContextCurrentFailed); - return; - } - - // Create the stream for zero-copy use by gl. - EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay(); - const EGLint stream_attributes[] = { - // clang-format off - EGL_CONSUMER_LATENCY_USEC_KHR, 0, - EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 0, - EGL_NONE, - // clang-format on - }; - EGLStreamKHR stream = eglCreateStreamKHR(egl_display, stream_attributes); - if (!stream) { - NotifyError(StatusCode::kCreateEglStreamFailed); + std::move(on_error_cb) + .Run(std::move(StatusCode::kMakeContextCurrentFailed)); return; } - // |stream| will be destroyed when the GLImage is. - // TODO(liberato): for tests, it will be destroyed pretty much at the end of - // this function unless |helper_| retains it. Also, this won't work if we - // have a FakeCommandBufferHelper since the service IDs aren't meaningful. - gl_image_ = base::MakeRefCounted<gl::GLImageDXGI>(size, stream); - - // Create the textures and attach them to the mailboxes. - // TODO(liberato): Should we use GL_FLOAT for an fp16 texture? It doesn't - // really seem to matter so far as I can tell. - for (size_t texture_idx = 0; texture_idx < textures_per_picture; - texture_idx++) { - const viz::ResourceFormat format = texture_formats[texture_idx]; - const GLenum internal_format = viz::GLInternalFormat(format); - const GLenum data_type = viz::GLDataType(format); - const GLenum data_format = viz::GLDataFormat(format); - - // Adjust the size by the subsampling factor. - const size_t width = - VideoFrame::Columns(texture_idx, pixel_format, size.width()); - const size_t height = - VideoFrame::Rows(texture_idx, pixel_format, size.height()); - const gfx::Size plane_size(width, height); - - // TODO(crbug.com/1011555): CreateTexture allocates a GL texture, figure out - // if this can be removed. - const uint32_t service_id = - helper_->CreateTexture(target, internal_format, plane_size.width(), - plane_size.height(), data_format, data_type); + // Usage flags to allow the display compositor to draw from it, video to + // decode, and allow webgl/canvas access. + constexpr uint32_t usage = + gpu::SHARED_IMAGE_USAGE_VIDEO_DECODE | gpu::SHARED_IMAGE_USAGE_GLES2 | + gpu::SHARED_IMAGE_USAGE_RASTER | gpu::SHARED_IMAGE_USAGE_DISPLAY | + gpu::SHARED_IMAGE_USAGE_SCANOUT; - const auto& mailbox = mailboxes[texture_idx]; - - // Shared image does not need to store the colorspace since it is already - // stored on the VideoFrame which is provided upon presenting the overlay. - // To prevent the developer from mistakenly using it, provide the invalid - // value from default-construction. - const gfx::ColorSpace kInvalidColorSpace; - - // Usage flags to allow the display compositor to draw from it, video to - // decode, and allow webgl/canvas access. - const uint32_t shared_image_usage = - gpu::SHARED_IMAGE_USAGE_VIDEO_DECODE | gpu::SHARED_IMAGE_USAGE_GLES2 | - gpu::SHARED_IMAGE_USAGE_RASTER | gpu::SHARED_IMAGE_USAGE_DISPLAY | - gpu::SHARED_IMAGE_USAGE_SCANOUT; - - // Create a shared image - // TODO(crbug.com/1011555): Need key shared mutex if shared image is ever - // used by another device. - scoped_refptr<gpu::gles2::TexturePassthrough> gl_texture = - gpu::gles2::TexturePassthrough::CheckedCast( - helper_->GetTexture(service_id)); - - auto shared_image = std::make_unique<gpu::SharedImageBackingD3D>( - mailbox, format, plane_size, kInvalidColorSpace, - kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, shared_image_usage, - /*swap_chain=*/nullptr, std::move(gl_texture), gl_image_, - /*buffer_index=*/0, texture, base::win::ScopedHandle(), - /*dxgi_key_mutex=*/nullptr); - - // Caller is assumed to provide cleared d3d textures. - shared_image->SetCleared(); - - // Shared images will be destroyed when this wrapper goes away. - // Only GpuResource can be used to safely destroy the shared images on the - // gpu main thread. - shared_images_.push_back(helper_->Register(std::move(shared_image))); - - service_ids_.push_back(service_id); - } - - // Bind all the textures so that the stream can find them. - OrderedDestructionList texture_everythings; - for (size_t i = 0; i < textures_per_picture; i++) - texture_everythings.emplace_back(GL_TEXTURE0 + i, service_ids_[i]); - - std::vector<EGLAttrib> consumer_attributes; - if (textures_per_picture == 2) { - // Assume NV12. - consumer_attributes = { - // clang-format off - EGL_COLOR_BUFFER_TYPE, EGL_YUV_BUFFER_EXT, - EGL_YUV_NUMBER_OF_PLANES_EXT, 2, - EGL_YUV_PLANE0_TEXTURE_UNIT_NV, 0, - EGL_YUV_PLANE1_TEXTURE_UNIT_NV, 1, - EGL_NONE, - // clang-format on - }; - } else { - // Assume some rgb format. - consumer_attributes = { - // clang-format off - EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, - EGL_NONE, - // clang-format on - }; - } - EGLBoolean result = eglStreamConsumerGLTextureExternalAttribsNV( - egl_display, stream, consumer_attributes.data()); - if (!result) { - NotifyError(StatusCode::kCreateEglStreamConsumerFailed); - return; - } - - EGLAttrib producer_attributes[] = { - EGL_NONE, - }; - - result = eglCreateStreamProducerD3DTextureANGLE(egl_display, stream, - producer_attributes); - if (!result) { - NotifyError(StatusCode::kCreateEglStreamProducerFailed); + auto shared_image_backings = + gpu::SharedImageBackingD3D::CreateFromVideoTexture( + mailboxes, dxgi_format, size, usage, texture, array_slice); + if (shared_image_backings.empty()) { + std::move(on_error_cb).Run(std::move(StatusCode::kCreateSharedImageFailed)); return; } + DCHECK_EQ(shared_image_backings.size(), NumPlanes(dxgi_format)); - // Note that this is valid as long as |gl_image_| is valid; it is - // what deletes the stream. - stream_ = stream; - - // Bind the image to each texture. - for (size_t texture_idx = 0; texture_idx < service_ids_.size(); - texture_idx++) { - helper_->BindImage(service_ids_[texture_idx], gl_image_.get(), - false /* client_managed */); - } - - // Specify the texture so ProcessTexture knows how to process it using a GL - // image. - gl_image_->SetTexture(texture, array_slice); - - PushNewTexture(); + for (auto& backing : shared_image_backings) + shared_images_.push_back(helper_->Register(std::move(backing))); } -void DefaultTexture2DWrapper::GpuResources::PushNewTexture() { - // If init didn't complete, then signal (another) error that will probably be - // ignored in favor of whatever we signalled earlier. - if (!gl_image_ || !stream_) { - NotifyError(StatusCode::kDecoderInitializeNeverCompleted); - return; - } - - if (!helper_ || !helper_->MakeContextCurrent()) { - NotifyError(StatusCode::kMakeContextCurrentFailed); - return; - } - - // Notify angle that it has a new texture. - EGLAttrib frame_attributes[] = { - EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, - gl_image_->level(), - EGL_NONE, - }; - - EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay(); - if (!eglStreamPostD3DTextureANGLE( - egl_display, stream_, static_cast<void*>(gl_image_->texture().Get()), - frame_attributes)) { - NotifyError(StatusCode::kPostTextureFailed); - return; - } - - if (!eglStreamConsumerAcquireKHR(egl_display, stream_)) { - NotifyError(StatusCode::kPostAcquireStreamFailed); +DefaultTexture2DWrapper::GpuResources::~GpuResources() { + // Destroy shared images with a current context. + if (!helper_ || !helper_->MakeContextCurrent()) return; - } -} - -void DefaultTexture2DWrapper::GpuResources::NotifyError(Status status) { - if (on_error_cb_) - std::move(on_error_cb_).Run(std::move(status)); - // else this isn't the first error, so skip it. + shared_images_.clear(); } } // namespace media diff --git a/chromium/media/gpu/windows/d3d11_texture_wrapper.h b/chromium/media/gpu/windows/d3d11_texture_wrapper.h index 5c097ec9cac..88171c16a82 100644 --- a/chromium/media/gpu/windows/d3d11_texture_wrapper.h +++ b/chromium/media/gpu/windows/d3d11_texture_wrapper.h @@ -11,7 +11,6 @@ #include <vector> #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/threading/sequence_bound.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/texture_manager.h" @@ -20,6 +19,7 @@ #include "media/gpu/command_buffer_helper.h" #include "media/gpu/media_gpu_export.h" #include "media/gpu/windows/d3d11_com_defs.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/color_space.h" #include "ui/gfx/hdr_metadata.h" #include "ui/gl/gl_bindings.h" @@ -74,9 +74,7 @@ class MEDIA_GPU_EXPORT DefaultTexture2DWrapper : public Texture2DWrapper { // While the specific texture instance can change on every call to // ProcessTexture, the dxgi format must be the same for all of them. - DefaultTexture2DWrapper(const gfx::Size& size, - DXGI_FORMAT dxgi_format, - VideoPixelFormat pixel_format); + DefaultTexture2DWrapper(const gfx::Size& size, DXGI_FORMAT dxgi_format); ~DefaultTexture2DWrapper() override; Status Init(scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, @@ -99,36 +97,17 @@ class MEDIA_GPU_EXPORT DefaultTexture2DWrapper : public Texture2DWrapper { // can use the mailbox. class GpuResources { public: - GpuResources(OnErrorCB on_error_cb); + GpuResources(OnErrorCB on_error_cb, + GetCommandBufferHelperCB get_helper_cb, + const std::vector<gpu::Mailbox>& mailboxes, + const gfx::Size& size, + DXGI_FORMAT dxgi_format, + ComD3D11Texture2D texture, + size_t array_slice); ~GpuResources(); - void Init( - GetCommandBufferHelperCB get_helper_cb, - const std::vector<gpu::Mailbox> mailboxes, - GLenum target, - gfx::Size size, - size_t textures_per_picture, - std::array<viz::ResourceFormat, VideoFrame::kMaxPlanes> texture_formats, - VideoPixelFormat pixel_format, - ComD3D11Texture2D texture, - size_t array_slice); - - std::vector<uint32_t> service_ids_; - private: - // Push a new |texture|, |array_slice| to |gl_image_|. - // Both |texture| and |array_slice| were set by Init. - void PushNewTexture(); - - // Notify our wrapper about |status|, if we haven't before. - void NotifyError(Status status); - - // May be empty if we've already sent an error. - OnErrorCB on_error_cb_; - scoped_refptr<CommandBufferHelper> helper_; - scoped_refptr<gl::GLImageDXGI> gl_image_; - EGLStreamKHR stream_; std::vector<std::unique_ptr<gpu::SharedImageRepresentationFactoryRef>> shared_images_; @@ -140,13 +119,12 @@ class MEDIA_GPU_EXPORT DefaultTexture2DWrapper : public Texture2DWrapper { void OnError(Status status); // The first error status that we've received from |gpu_resources_|, if any. - base::Optional<Status> received_error_; + absl::optional<Status> received_error_; gfx::Size size_; base::SequenceBound<GpuResources> gpu_resources_; MailboxHolderArray mailbox_holders_; DXGI_FORMAT dxgi_format_; - VideoPixelFormat pixel_format_; base::WeakPtrFactory<DefaultTexture2DWrapper> weak_factory_{this}; }; diff --git a/chromium/media/gpu/windows/d3d11_texture_wrapper_unittest.cc b/chromium/media/gpu/windows/d3d11_texture_wrapper_unittest.cc index 3142782db7f..cfcd5fafc91 100644 --- a/chromium/media/gpu/windows/d3d11_texture_wrapper_unittest.cc +++ b/chromium/media/gpu/windows/d3d11_texture_wrapper_unittest.cc @@ -88,10 +88,8 @@ class D3D11TextureWrapperUnittest : public ::testing::Test { TEST_F(D3D11TextureWrapperUnittest, NV12InitSucceeds) { STOP_IF_WIN7(); const DXGI_FORMAT dxgi_format = DXGI_FORMAT_NV12; - const VideoPixelFormat pixel_format = PIXEL_FORMAT_NV12; - auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format, - pixel_format); + auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format); const Status init_result = wrapper->Init( task_runner_, get_helper_cb_, /*texture_d3d=*/nullptr, /*array_slice=*/0); EXPECT_TRUE(init_result.is_ok()); @@ -102,10 +100,8 @@ TEST_F(D3D11TextureWrapperUnittest, NV12InitSucceeds) { TEST_F(D3D11TextureWrapperUnittest, BGRA8InitSucceeds) { STOP_IF_WIN7(); const DXGI_FORMAT dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM; - const VideoPixelFormat pixel_format = PIXEL_FORMAT_ARGB; - auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format, - pixel_format); + auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format); const Status init_result = wrapper->Init( task_runner_, get_helper_cb_, /*texture_d3d=*/nullptr, /*array_slice=*/0); EXPECT_TRUE(init_result.is_ok()); @@ -114,10 +110,8 @@ TEST_F(D3D11TextureWrapperUnittest, BGRA8InitSucceeds) { TEST_F(D3D11TextureWrapperUnittest, FP16InitSucceeds) { STOP_IF_WIN7(); const DXGI_FORMAT dxgi_format = DXGI_FORMAT_R16G16B16A16_FLOAT; - const VideoPixelFormat pixel_format = PIXEL_FORMAT_RGBAF16; - auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format, - pixel_format); + auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format); const Status init_result = wrapper->Init( task_runner_, get_helper_cb_, /*texture_d3d=*/nullptr, /*array_slice=*/0); EXPECT_TRUE(init_result.is_ok()); @@ -126,10 +120,8 @@ TEST_F(D3D11TextureWrapperUnittest, FP16InitSucceeds) { TEST_F(D3D11TextureWrapperUnittest, P010InitSucceeds) { STOP_IF_WIN7(); const DXGI_FORMAT dxgi_format = DXGI_FORMAT_P010; - const VideoPixelFormat pixel_format = PIXEL_FORMAT_NV12; - auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format, - pixel_format); + auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format); const Status init_result = wrapper->Init( task_runner_, get_helper_cb_, /*texture_d3d=*/nullptr, /*array_slice=*/0); EXPECT_TRUE(init_result.is_ok()); @@ -138,13 +130,11 @@ TEST_F(D3D11TextureWrapperUnittest, P010InitSucceeds) { TEST_F(D3D11TextureWrapperUnittest, UnknownInitFails) { STOP_IF_WIN7(); const DXGI_FORMAT dxgi_format = DXGI_FORMAT_UNKNOWN; - const VideoPixelFormat pixel_format = PIXEL_FORMAT_UNKNOWN; - auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format, - pixel_format); + auto wrapper = std::make_unique<DefaultTexture2DWrapper>(size_, dxgi_format); const Status init_result = wrapper->Init( task_runner_, get_helper_cb_, /*texture_d3d=*/nullptr, /*array_slice=*/0); EXPECT_FALSE(init_result.is_ok()); } -} // namespace media
\ No newline at end of file +} // namespace media diff --git a/chromium/media/gpu/windows/d3d11_video_decoder.cc b/chromium/media/gpu/windows/d3d11_video_decoder.cc index 04e0d58eb65..6d5da96ac7f 100644 --- a/chromium/media/gpu/windows/d3d11_video_decoder.cc +++ b/chromium/media/gpu/windows/d3d11_video_decoder.cc @@ -718,7 +718,7 @@ void D3D11VideoDecoder::CreatePictureBuffers() { stream_metadata = *config_.hdr_metadata(); // else leave |stream_metadata| default-initialized. We might use it anyway. - base::Optional<DXGI_HDR_METADATA_HDR10> display_metadata; + absl::optional<DXGI_HDR_METADATA_HDR10> display_metadata; if (decoder_configurator_->TextureFormat() == DXGI_FORMAT_P010) { // For HDR formats, try to get the display metadata. This may fail, which // is okay. We'll just skip sending the metadata. diff --git a/chromium/media/gpu/windows/d3d11_video_decoder.h b/chromium/media/gpu/windows/d3d11_video_decoder.h index e41d8c38add..a539820a129 100644 --- a/chromium/media/gpu/windows/d3d11_video_decoder.h +++ b/chromium/media/gpu/windows/d3d11_video_decoder.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_GPU_D3D11_VIDEO_DECODER_H_ -#define MEDIA_GPU_D3D11_VIDEO_DECODER_H_ +#ifndef MEDIA_GPU_WINDOWS_D3D11_VIDEO_DECODER_H_ +#define MEDIA_GPU_WINDOWS_D3D11_VIDEO_DECODER_H_ #include <d3d11.h> #include <string> @@ -308,4 +308,4 @@ class MEDIA_GPU_EXPORT D3D11VideoDecoder : public VideoDecoder, } // namespace media -#endif // MEDIA_GPU_D3D11_VIDEO_DECODER_H_ +#endif // MEDIA_GPU_WINDOWS_D3D11_VIDEO_DECODER_H_ diff --git a/chromium/media/gpu/windows/d3d11_video_decoder_impl.h b/chromium/media/gpu/windows/d3d11_video_decoder_impl.h index 770d81cf88f..4a7f1449e71 100644 --- a/chromium/media/gpu/windows/d3d11_video_decoder_impl.h +++ b/chromium/media/gpu/windows/d3d11_video_decoder_impl.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_GPU_D3D11_VIDEO_DECODER_IMPL_H_ -#define MEDIA_GPU_D3D11_VIDEO_DECODER_IMPL_H_ +#ifndef MEDIA_GPU_WINDOWS_D3D11_VIDEO_DECODER_IMPL_H_ +#define MEDIA_GPU_WINDOWS_D3D11_VIDEO_DECODER_IMPL_H_ #include <d3d11_1.h> #include <wrl/client.h> @@ -86,4 +86,4 @@ class MEDIA_GPU_EXPORT D3D11VideoDecoderImpl { } // namespace media -#endif // MEDIA_GPU_D3D11_VIDEO_DECODER_IMPL_H_ +#endif // MEDIA_GPU_WINDOWS_D3D11_VIDEO_DECODER_IMPL_H_ diff --git a/chromium/media/gpu/windows/d3d11_video_decoder_unittest.cc b/chromium/media/gpu/windows/d3d11_video_decoder_unittest.cc index 91b53e6d129..a3c5e9ca7df 100644 --- a/chromium/media/gpu/windows/d3d11_video_decoder_unittest.cc +++ b/chromium/media/gpu/windows/d3d11_video_decoder_unittest.cc @@ -11,7 +11,6 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/memory/ptr_util.h" -#include "base/optional.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/test/scoped_feature_list.h" @@ -27,6 +26,7 @@ #include "media/base/win/d3d11_mocks.h" #include "media/gpu/windows/d3d11_video_decoder_impl.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" using ::testing::_; using ::testing::DoAll; @@ -153,7 +153,7 @@ class D3D11VideoDecoderTest : public ::testing::Test { } // Most recently provided video decoder desc. - base::Optional<D3D11_VIDEO_DECODER_DESC> last_video_decoder_desc_; + absl::optional<D3D11_VIDEO_DECODER_DESC> last_video_decoder_desc_; D3D11_VIDEO_DECODER_CONFIG video_decoder_config_; void TearDown() override { @@ -177,8 +177,8 @@ class D3D11VideoDecoderTest : public ::testing::Test { // use it. Otherwise, we'll use the list that's autodetected by the // decoder based on the current device mock. void CreateDecoder( - base::Optional<D3D11VideoDecoder::SupportedConfigs> supported_configs = - base::Optional<D3D11VideoDecoder::SupportedConfigs>()) { + absl::optional<D3D11VideoDecoder::SupportedConfigs> supported_configs = + absl::optional<D3D11VideoDecoder::SupportedConfigs>()) { auto get_device_cb = base::BindRepeating( [](Microsoft::WRL::ComPtr<ID3D11Device> device) { return device; }, mock_d3d11_device_); @@ -249,7 +249,7 @@ class D3D11VideoDecoderTest : public ::testing::Test { DXGI_ADAPTER_DESC mock_adapter_desc_; - base::Optional<base::test::ScopedFeatureList> scoped_feature_list_; + absl::optional<base::test::ScopedFeatureList> scoped_feature_list_; base::win::ScopedCOMInitializer com_initializer_; }; @@ -323,7 +323,7 @@ TEST_F(D3D11VideoDecoderTest, DoesNotSupportH264IfNoSupportedConfig) { // config check kinda works. // For whatever reason, Optional<SupportedConfigs>({}) results in one that // doesn't have a value, rather than one that has an empty vector. - base::Optional<D3D11VideoDecoder::SupportedConfigs> empty_configs; + absl::optional<D3D11VideoDecoder::SupportedConfigs> empty_configs; empty_configs.emplace(std::vector<SupportedVideoDecoderConfig>()); CreateDecoder(empty_configs); diff --git a/chromium/media/gpu/windows/d3d11_video_device_format_support.h b/chromium/media/gpu/windows/d3d11_video_device_format_support.h index 0e07a4ecddf..bf75e839b17 100644 --- a/chromium/media/gpu/windows/d3d11_video_device_format_support.h +++ b/chromium/media/gpu/windows/d3d11_video_device_format_support.h @@ -6,12 +6,11 @@ #define MEDIA_GPU_WINDOWS_D3D11_VIDEO_DEVICE_FORMAT_SUPPORT_H_ #include <d3d11_1.h> -#include <vector> -#include "base/optional.h" #include "media/base/media_log.h" #include "media/gpu/media_gpu_export.h" #include "media/gpu/windows/d3d11_com_defs.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { diff --git a/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc index 55c4d9329ee..02a7a850394 100644 --- a/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc +++ b/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.cc @@ -24,6 +24,7 @@ #include "base/bind_post_task.h" #include "base/callback.h" #include "base/command_line.h" +#include "base/containers/contains.h" #include "base/file_version_info.h" #include "base/files/file_path.h" #include "base/location.h" @@ -321,6 +322,10 @@ bool ConfigChangeDetector::IsYUV420() const { return false; } +bool ConfigChangeDetector::is_vp9_resilient_mode() const { + return false; +} + // Provides functionality to detect H.264 stream configuration changes. // TODO(ananta) // Move this to a common place so that all VDA's can use this. @@ -364,7 +369,7 @@ bool H264ConfigChangeDetector::DetectConfig(const uint8_t* stream, bool idr_seen = false; if (!parser_.get()) - parser_.reset(new H264Parser); + parser_ = std::make_unique<H264Parser>(); parser_->SetStream(stream, size); config_changed_ = false; @@ -508,6 +513,9 @@ class VP9ConfigChangeDetector : public ConfigChangeDetector { color_space_ = fhdr.GetColorSpace(); gfx::Size new_size(fhdr.frame_width, fhdr.frame_height); + if (!gfx::Rect(new_size).Contains(visible_rect_)) { + visible_rect_ = gfx::Rect(new_size); + } if (!size_.IsEmpty() && !pending_config_changed_ && !config_changed_ && size_ != new_size) { pending_config_changed_ = true; @@ -516,6 +524,8 @@ class VP9ConfigChangeDetector : public ConfigChangeDetector { } size_ = new_size; + is_resilient_mode_ |= fhdr.error_resilient_mode; + // Resolution changes can happen on any frame technically, so wait for a // keyframe before signaling the config change. if (fhdr.IsKeyframe() && pending_config_changed_) { @@ -539,11 +549,14 @@ class VP9ConfigChangeDetector : public ConfigChangeDetector { : color_space_; } + bool is_vp9_resilient_mode() const override { return is_resilient_mode_; } + private: gfx::Size size_; bool pending_config_changed_ = false; gfx::Rect visible_rect_; VideoColorSpace color_space_; + bool is_resilient_mode_ = false; Vp9Parser parser_; }; @@ -661,6 +674,8 @@ DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( !workarounds.disable_accelerated_vp8_decode), enable_accelerated_vp9_decode_( !workarounds.disable_accelerated_vp9_decode), + disallow_vp9_resilient_dxva_decoding_( + workarounds.disallow_vp9_resilient_dxva_decoding), processing_config_changed_(false), use_empty_video_hdr_metadata_(workarounds.use_empty_video_hdr_metadata) { weak_ptr_ = weak_this_factory_.GetWeakPtr(); @@ -807,11 +822,11 @@ bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", false); if (codec_ == kCodecH264) - config_change_detector_.reset(new H264ConfigChangeDetector()); + config_change_detector_ = std::make_unique<H264ConfigChangeDetector>(); if (codec_ == kCodecVP8) - config_change_detector_.reset(new VP8ConfigChangeDetector()); + config_change_detector_ = std::make_unique<VP8ConfigChangeDetector>(); if (codec_ == kCodecVP9) - config_change_detector_.reset(new VP9ConfigChangeDetector()); + config_change_detector_ = std::make_unique<VP9ConfigChangeDetector>(); processing_config_changed_ = false; SetState(kNormal); @@ -2328,6 +2343,12 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to check video stream config", PLATFORM_FAILURE, ); + if (disallow_vp9_resilient_dxva_decoding_ && + config_change_detector_->is_vp9_resilient_mode()) { + RETURN_AND_NOTIFY_ON_HR_FAILURE( + E_FAIL, "Incompatible GPU for VP9 resilient mode", PLATFORM_FAILURE, ); + } + // https://crbug.com/1160623 -- non 4:2:0 content hangs the decoder. RETURN_AND_NOTIFY_ON_FAILURE( codec_ != kCodecH264 || config_change_detector_->IsYUV420(), @@ -2377,7 +2398,11 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( PLATFORM_FAILURE, ); hr = decoder_->ProcessInput(0, sample.Get(), 0); } - // If we continue to get the MF_E_NOTACCEPTING error we do the following:- + // If we continue to get the MF_E_NOTACCEPTING error we do the following: + // 1. Check if MF appears to be stuck in a not-accepting loop. When this + // occurs we want to break out of the loop early to allow recovery + // without prolonged ux hangs or running into potential OOM issues. + // If not in a loop then: // 1. Add the input sample to the pending queue. // 2. If we don't have any output samples we post the // DecodePendingInputBuffers task to process the pending input samples. @@ -2387,6 +2412,17 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( // given time due to the limitation with the Microsoft media foundation // decoder where it recycles the output Decoder surfaces. if (hr == MF_E_NOTACCEPTING) { + // Check if we appear to be stuck in a loop + if (inputs_before_decode_ >= 1000) { + // The value of 1000 is an arbitrary upper bound here since processing + // is not gated on any media timings. In practice we typically see + // maximum values in the 5 to 10 range for normal execution, so 1000 + // affords two orders of magnitude outside of the expected range. + RETURN_AND_NOTIFY_ON_HR_FAILURE( + hr, "Input processing appears stuck in MF_E_NOTACCEPTING loop.", + PLATFORM_FAILURE, ); + } + pending_input_buffers_.push_back(sample); decoder_thread_task_runner_->PostTask( FROM_HERE, @@ -2732,16 +2768,12 @@ void DXVAVideoDecodeAccelerator::BindPictureBufferToSample( // this |picture_buffer| will be updated when the video frame is created. const auto& mailbox = gpu::Mailbox::GenerateForSharedImage(); - auto shared_image = std::make_unique<gpu::SharedImageBackingD3D>( + auto shared_image = gpu::SharedImageBackingD3D::CreateFromGLTexture( mailbox, viz_formats[texture_idx], picture_buffer->texture_size(texture_idx), picture_buffer->color_space(), kTopLeft_GrSurfaceOrigin, - kPremul_SkAlphaType, shared_image_usage, - /*swap_chain=*/nullptr, std::move(gl_texture), - picture_buffer->gl_image(), - /*buffer_index=*/0, gl_image_dxgi->texture(), - base::win::ScopedHandle(), - /*dxgi_keyed_mutex=*/nullptr); + kPremul_SkAlphaType, shared_image_usage, gl_image_dxgi->texture(), + std::move(gl_texture)); // Caller is assumed to provide cleared d3d textures. shared_image->SetCleared(); diff --git a/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.h b/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.h index b7fc1b95e4c..c4c5463f9ed 100644 --- a/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.h +++ b/chromium/media/gpu/windows/dxva_video_decode_accelerator_win.h @@ -65,6 +65,7 @@ class ConfigChangeDetector { virtual VideoColorSpace current_color_space( const VideoColorSpace& container_color_space) const = 0; virtual bool IsYUV420() const; + virtual bool is_vp9_resilient_mode() const; bool config_changed() const { return config_changed_; } protected: @@ -612,6 +613,8 @@ class MEDIA_GPU_EXPORT DXVAVideoDecodeAccelerator const bool enable_accelerated_vp8_decode_; const bool enable_accelerated_vp9_decode_; + const bool disallow_vp9_resilient_dxva_decoding_; + // The media foundation H.264 decoder has problems handling changes like // resolution change, bitrate change etc. If we reinitialize the decoder // when these changes occur then, the decoder works fine. The @@ -630,7 +633,7 @@ class MEDIA_GPU_EXPORT DXVAVideoDecodeAccelerator gfx::Rect current_visible_rect_; VideoColorSpace current_color_space_; - base::Optional<gl::HDRMetadataHelperWin> hdr_metadata_helper_; + absl::optional<gl::HDRMetadataHelperWin> hdr_metadata_helper_; bool use_empty_video_hdr_metadata_ = false; // Have we delivered any decoded frames since the last call to Initialize()? diff --git a/chromium/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/chromium/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc index e61b7fd921b..31394a96f9d 100644 --- a/chromium/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc +++ b/chromium/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc @@ -14,6 +14,7 @@ #include <objbase.h> #include <iterator> +#include <memory> #include <utility> #include <vector> @@ -24,10 +25,12 @@ #include "base/win/scoped_co_mem.h" #include "base/win/scoped_variant.h" #include "base/win/windows_version.h" +#include "gpu/ipc/common/dxgi_helpers.h" #include "media/base/media_switches.h" #include "media/base/win/mf_helpers.h" #include "media/base/win/mf_initializer.h" #include "third_party/libyuv/include/libyuv.h" +#include "ui/gfx/color_space_win.h" #include "ui/gfx/gpu_memory_buffer.h" using media::MediaBufferScopedPointer; @@ -245,7 +248,8 @@ bool MediaFoundationVideoEncodeAccelerator::Initialize(const Config& config, } } - main_client_weak_factory_.reset(new base::WeakPtrFactory<Client>(client)); + main_client_weak_factory_ = + std::make_unique<base::WeakPtrFactory<Client>>(client); main_client_ = main_client_weak_factory_->GetWeakPtr(); input_visible_size_ = config.input_visible_size; if (config.initial_framerate.has_value()) @@ -404,6 +408,10 @@ void MediaFoundationVideoEncodeAccelerator::Destroy() { delete this; } +bool MediaFoundationVideoEncodeAccelerator::IsGpuFrameResizeSupported() { + return true; +} + // static bool MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization() { bool result = true; @@ -851,18 +859,41 @@ HRESULT MediaFoundationVideoEncodeAccelerator::PopulateInputSampleBuffer( HRESULT hr = d3d_device.As(&device1); RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D11Device1", hr); - Microsoft::WRL::ComPtr<ID3D11Texture2D> texture; + Microsoft::WRL::ComPtr<ID3D11Texture2D> input_texture; hr = device1->OpenSharedResource1(buffer_handle.dxgi_handle.Get(), - IID_PPV_ARGS(&texture)); + IID_PPV_ARGS(&input_texture)); RETURN_ON_HR_FAILURE(hr, "Failed to open shared GMB D3D texture", hr); + // Check if we need to scale the input texture + D3D11_TEXTURE2D_DESC input_desc = {}; + input_texture->GetDesc(&input_desc); + + Microsoft::WRL::ComPtr<ID3D11Texture2D> sample_texture; + if (input_desc.Width != uint32_t{input_visible_size_.width()} || + input_desc.Height != uint32_t{input_visible_size_.height()}) { + hr = PerformD3DScaling(input_texture.Get()); + RETURN_ON_HR_FAILURE(hr, "Failed to perform D3D video processing", hr); + sample_texture = scaled_d3d11_texture_; + } else { + sample_texture = input_texture; + } + Microsoft::WRL::ComPtr<IMFMediaBuffer> input_buffer; - hr = MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), texture.Get(), 0, - FALSE, &input_buffer); + hr = MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), + sample_texture.Get(), 0, FALSE, + &input_buffer); RETURN_ON_HR_FAILURE(hr, "Failed to create MF DXGI surface buffer", hr); + // Some encoder MFTs (e.g. Qualcomm) depend on the sample buffer having a + // valid current length. Call GetMaxLength() to compute the plane size. + DWORD buffer_length = 0; + hr = input_buffer->GetMaxLength(&buffer_length); + RETURN_ON_HR_FAILURE(hr, "Failed to get max buffer length", hr); + hr = input_buffer->SetCurrentLength(buffer_length); + RETURN_ON_HR_FAILURE(hr, "Failed to set current buffer length", hr); + hr = input_sample_->RemoveAllBuffers(); - RETURN_ON_HR_FAILURE(hr, "Failed remove buffers from sample", hr); + RETURN_ON_HR_FAILURE(hr, "Failed to remove buffers from sample", hr); hr = input_sample_->AddBuffer(input_buffer.Get()); RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", hr); return S_OK; @@ -1255,4 +1286,161 @@ void MediaFoundationVideoEncodeAccelerator::ReleaseEncoderResources() { output_sample_.Reset(); } +HRESULT MediaFoundationVideoEncodeAccelerator::InitializeD3DVideoProcessing( + ID3D11Texture2D* input_texture) { + D3D11_TEXTURE2D_DESC input_desc = {}; + input_texture->GetDesc(&input_desc); + if (vp_desc_.InputWidth == input_desc.Width && + vp_desc_.InputHeight == input_desc.Height) { + return S_OK; + } + + // Input/output framerates are dummy values for passthrough. + D3D11_VIDEO_PROCESSOR_CONTENT_DESC vp_desc = { + .InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE, + .InputFrameRate = {60, 1}, + .InputWidth = input_desc.Width, + .InputHeight = input_desc.Height, + .OutputFrameRate = {60, 1}, + .OutputWidth = input_visible_size_.width(), + .OutputHeight = input_visible_size_.height(), + .Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL}; + + Microsoft::WRL::ComPtr<ID3D11Device> texture_device; + input_texture->GetDevice(&texture_device); + Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device; + HRESULT hr = texture_device.As(&video_device); + RETURN_ON_HR_FAILURE(hr, "Failed to query for ID3D11VideoDevice", hr); + + Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator> + video_processor_enumerator; + hr = video_device->CreateVideoProcessorEnumerator( + &vp_desc, &video_processor_enumerator); + RETURN_ON_HR_FAILURE(hr, "CreateVideoProcessorEnumerator failed", hr); + + Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor; + hr = video_device->CreateVideoProcessor(video_processor_enumerator.Get(), 0, + &video_processor); + RETURN_ON_HR_FAILURE(hr, "CreateVideoProcessor failed", hr); + + Microsoft::WRL::ComPtr<ID3D11DeviceContext> device_context; + texture_device->GetImmediateContext(&device_context); + Microsoft::WRL::ComPtr<ID3D11VideoContext> video_context; + hr = device_context.As(&video_context); + RETURN_ON_HR_FAILURE(hr, "Failed to query for ID3D11VideoContext", hr); + + // Auto stream processing (the default) can hurt power consumption. + video_context->VideoProcessorSetStreamAutoProcessingMode( + video_processor.Get(), 0, FALSE); + + D3D11_TEXTURE2D_DESC scaled_desc = { + .Width = input_visible_size_.width(), + .Height = input_visible_size_.height(), + .MipLevels = 1, + .ArraySize = 1, + .Format = DXGI_FORMAT_NV12, + .SampleDesc = {1, 0}, + .Usage = D3D11_USAGE_DEFAULT, + .BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, + .CPUAccessFlags = 0, + .MiscFlags = 0}; + Microsoft::WRL::ComPtr<ID3D11Texture2D> scaled_d3d11_texture; + hr = texture_device->CreateTexture2D(&scaled_desc, nullptr, + &scaled_d3d11_texture); + RETURN_ON_HR_FAILURE(hr, "Failed to create texture", hr); + + D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC output_desc = {}; + output_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; + output_desc.Texture2D.MipSlice = 0; + Microsoft::WRL::ComPtr<ID3D11VideoProcessorOutputView> vp_output_view; + hr = video_device->CreateVideoProcessorOutputView( + scaled_d3d11_texture.Get(), video_processor_enumerator.Get(), + &output_desc, &vp_output_view); + RETURN_ON_HR_FAILURE(hr, "CreateVideoProcessorOutputView failed", hr); + + video_device_ = std::move(video_device); + video_processor_enumerator_ = std::move(video_processor_enumerator); + video_processor_ = std::move(video_processor); + video_context_ = std::move(video_context); + vp_desc_ = std::move(vp_desc); + scaled_d3d11_texture_ = std::move(scaled_d3d11_texture); + vp_output_view_ = std::move(vp_output_view); + return S_OK; +} + +HRESULT MediaFoundationVideoEncodeAccelerator::PerformD3DScaling( + ID3D11Texture2D* input_texture) { + HRESULT hr = InitializeD3DVideoProcessing(input_texture); + RETURN_ON_HR_FAILURE(hr, "Couldn't initialize D3D video processing", hr); + + // Set the color space for passthrough. + auto src_color_space = gfx::ColorSpace::CreateSRGB(); + auto output_color_space = gfx::ColorSpace::CreateSRGB(); + + D3D11_VIDEO_PROCESSOR_COLOR_SPACE src_d3d11_color_space = + gfx::ColorSpaceWin::GetD3D11ColorSpace(src_color_space); + video_context_->VideoProcessorSetStreamColorSpace(video_processor_.Get(), 0, + &src_d3d11_color_space); + D3D11_VIDEO_PROCESSOR_COLOR_SPACE output_d3d11_color_space = + gfx::ColorSpaceWin::GetD3D11ColorSpace(output_color_space); + video_context_->VideoProcessorSetOutputColorSpace(video_processor_.Get(), + &output_d3d11_color_space); + + { + absl::optional<gpu::DXGIScopedReleaseKeyedMutex> release_keyed_mutex; + Microsoft::WRL::ComPtr<IDXGIKeyedMutex> keyed_mutex; + hr = input_texture->QueryInterface(IID_PPV_ARGS(&keyed_mutex)); + if (SUCCEEDED(hr)) { + // The producer may still be using this texture for a short period of + // time, so wait long enough to hopefully avoid glitches. For example, + // all levels of the texture share the same keyed mutex, so if the + // hardware decoder acquired the mutex to decode into a different array + // level then it still may block here temporarily. + constexpr int kMaxSyncTimeMs = 100; + hr = keyed_mutex->AcquireSync(0, kMaxSyncTimeMs); + RETURN_ON_HR_FAILURE(hr, "Failed to acquire keyed mutex", hr); + release_keyed_mutex.emplace(std::move(keyed_mutex), 0); + } + + // Setup |video_context_| for VPBlt operation. + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC input_desc = {}; + input_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; + input_desc.Texture2D.ArraySlice = 0; + Microsoft::WRL::ComPtr<ID3D11VideoProcessorInputView> input_view; + hr = video_device_->CreateVideoProcessorInputView( + input_texture, video_processor_enumerator_.Get(), &input_desc, + &input_view); + RETURN_ON_HR_FAILURE(hr, "CreateVideoProcessorInputView failed", hr); + + D3D11_VIDEO_PROCESSOR_STREAM stream = {.Enable = true, + .OutputIndex = 0, + .InputFrameOrField = 0, + .PastFrames = 0, + .FutureFrames = 0, + .pInputSurface = input_view.Get()}; + + D3D11_TEXTURE2D_DESC input_texture_desc = {}; + input_texture->GetDesc(&input_texture_desc); + RECT source_rect = {0, 0, input_texture_desc.Width, + input_texture_desc.Height}; + video_context_->VideoProcessorSetStreamSourceRect(video_processor_.Get(), 0, + TRUE, &source_rect); + + D3D11_TEXTURE2D_DESC output_texture_desc = {}; + scaled_d3d11_texture_->GetDesc(&output_texture_desc); + RECT dest_rect = {0, 0, output_texture_desc.Width, + output_texture_desc.Height}; + video_context_->VideoProcessorSetOutputTargetRect(video_processor_.Get(), + TRUE, &dest_rect); + video_context_->VideoProcessorSetStreamDestRect(video_processor_.Get(), 0, + TRUE, &dest_rect); + + hr = video_context_->VideoProcessorBlt( + video_processor_.Get(), vp_output_view_.Get(), 0, 1, &stream); + RETURN_ON_HR_FAILURE(hr, "VideoProcessorBlt failed", hr); + } + + return hr; +} + } // namespace media diff --git a/chromium/media/gpu/windows/media_foundation_video_encode_accelerator_win.h b/chromium/media/gpu/windows/media_foundation_video_encode_accelerator_win.h index 3ce96cc475e..6be82c57351 100644 --- a/chromium/media/gpu/windows/media_foundation_video_encode_accelerator_win.h +++ b/chromium/media/gpu/windows/media_foundation_video_encode_accelerator_win.h @@ -48,6 +48,7 @@ class MEDIA_GPU_EXPORT MediaFoundationVideoEncodeAccelerator void RequestEncodingParametersChange(uint32_t bitrate, uint32_t framerate) override; void Destroy() override; + bool IsGpuFrameResizeSupported() override; // Preloads dlls required for encoding. Returns true if all required dlls are // correctly loaded. @@ -117,6 +118,12 @@ class MEDIA_GPU_EXPORT MediaFoundationVideoEncodeAccelerator // Releases resources encoder holds. void ReleaseEncoderResources(); + // Initialize video processing (for scaling) + HRESULT InitializeD3DVideoProcessing(ID3D11Texture2D* input_texture); + + // Perform D3D11 scaling operation + HRESULT PerformD3DScaling(ID3D11Texture2D* input_texture); + const bool compatible_with_win7_; // Flag to enable the usage of MFTEnumEx. @@ -139,7 +146,7 @@ class MEDIA_GPU_EXPORT MediaFoundationVideoEncodeAccelerator // Group of picture length for encoded output stream, indicates the // distance between two key frames. - base::Optional<uint32_t> gop_length_; + absl::optional<uint32_t> gop_length_; Microsoft::WRL::ComPtr<IMFActivate> activate_; Microsoft::WRL::ComPtr<IMFTransform> encoder_; @@ -155,6 +162,14 @@ class MEDIA_GPU_EXPORT MediaFoundationVideoEncodeAccelerator bool input_required_; Microsoft::WRL::ComPtr<IMFSample> input_sample_; Microsoft::WRL::ComPtr<IMFSample> output_sample_; + Microsoft::WRL::ComPtr<ID3D11VideoProcessor> video_processor_; + Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator> + video_processor_enumerator_; + Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device_; + Microsoft::WRL::ComPtr<ID3D11VideoContext> video_context_; + D3D11_VIDEO_PROCESSOR_CONTENT_DESC vp_desc_ = {}; + Microsoft::WRL::ComPtr<ID3D11Texture2D> scaled_d3d11_texture_; + Microsoft::WRL::ComPtr<ID3D11VideoProcessorOutputView> vp_output_view_; // To expose client callbacks from VideoEncodeAccelerator. // NOTE: all calls to this object *MUST* be executed on diff --git a/chromium/media/gpu/windows/output_with_release_mailbox_cb.h b/chromium/media/gpu/windows/output_with_release_mailbox_cb.h index d653c3a1d32..9fcfcb509e2 100644 --- a/chromium/media/gpu/windows/output_with_release_mailbox_cb.h +++ b/chromium/media/gpu/windows/output_with_release_mailbox_cb.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_BASE_OUTPUT_WITH_RELEASE_MAILBOX_CB_H_ -#define MEDIA_BASE_OUTPUT_WITH_RELEASE_MAILBOX_CB_H_ +#ifndef MEDIA_GPU_WINDOWS_OUTPUT_WITH_RELEASE_MAILBOX_CB_H_ +#define MEDIA_GPU_WINDOWS_OUTPUT_WITH_RELEASE_MAILBOX_CB_H_ #include "base/callback.h" #include "base/memory/ref_counted.h" @@ -23,4 +23,4 @@ using OutputWithReleaseMailboxCB = } // namespace media -#endif // MEDIA_BASE_OUTPUT_WITH_RELEASE_MAILBOX_CB_H_ +#endif // MEDIA_GPU_WINDOWS_OUTPUT_WITH_RELEASE_MAILBOX_CB_H_ diff --git a/chromium/media/learning/common/learning_task.h b/chromium/media/learning/common/learning_task.h index 9d70b93e1e1..90a19a131c9 100644 --- a/chromium/media/learning/common/learning_task.h +++ b/chromium/media/learning/common/learning_task.h @@ -10,8 +10,8 @@ #include <vector> #include "base/component_export.h" -#include "base/optional.h" #include "media/learning/common/value.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace learning { @@ -121,7 +121,7 @@ struct COMPONENT_EXPORT(LEARNING_COMMON) LearningTask { // of feature to train the model with, to allow for feature importance // measurement. Note that UMA reporting only supports subsets of size one, or // the whole set. - base::Optional<int> feature_subset_size; + absl::optional<int> feature_subset_size; // RandomForest parameters diff --git a/chromium/media/learning/common/learning_task_controller.h b/chromium/media/learning/common/learning_task_controller.h index 64ba5a2cbc7..0644e2d85f8 100644 --- a/chromium/media/learning/common/learning_task_controller.h +++ b/chromium/media/learning/common/learning_task_controller.h @@ -8,12 +8,12 @@ #include "base/callback.h" #include "base/component_export.h" #include "base/macros.h" -#include "base/optional.h" #include "base/unguessable_token.h" #include "media/learning/common/labelled_example.h" #include "media/learning/common/learning_task.h" #include "media/learning/common/target_histogram.h" #include "services/metrics/public/cpp/ukm_source_id.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace learning { @@ -46,7 +46,7 @@ struct ObservationCompletion { class COMPONENT_EXPORT(LEARNING_COMMON) LearningTaskController { public: using PredictionCB = base::OnceCallback<void( - const base::Optional<TargetHistogram>& predicted)>; + const absl::optional<TargetHistogram>& predicted)>; LearningTaskController() = default; virtual ~LearningTaskController() = default; @@ -68,8 +68,8 @@ class COMPONENT_EXPORT(LEARNING_COMMON) LearningTaskController { virtual void BeginObservation( base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target = base::nullopt, - const base::Optional<ukm::SourceId>& source_id = base::nullopt) = 0; + const absl::optional<TargetValue>& default_target = absl::nullopt, + const absl::optional<ukm::SourceId>& source_id = absl::nullopt) = 0; // Complete an observation by sending a completion. virtual void CompleteObservation(base::UnguessableToken id, @@ -85,13 +85,13 @@ class COMPONENT_EXPORT(LEARNING_COMMON) LearningTaskController { // default value was given. virtual void UpdateDefaultTarget( base::UnguessableToken id, - const base::Optional<TargetValue>& default_target) = 0; + const absl::optional<TargetValue>& default_target) = 0; // Returns the LearningTask associated with |this|. virtual const LearningTask& GetLearningTask() = 0; // Asynchronously predicts distribution for given |features|. |callback| will - // receive a base::nullopt prediction when model is not available. |callback| + // receive a absl::nullopt prediction when model is not available. |callback| // may be called immediately without posting. virtual void PredictDistribution(const FeatureVector& features, PredictionCB callback) = 0; diff --git a/chromium/media/learning/impl/distribution_reporter.h b/chromium/media/learning/impl/distribution_reporter.h index 5ec60e9205b..6a96cf7aac4 100644 --- a/chromium/media/learning/impl/distribution_reporter.h +++ b/chromium/media/learning/impl/distribution_reporter.h @@ -11,11 +11,11 @@ #include "base/component_export.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "media/learning/common/learning_task.h" #include "media/learning/common/target_histogram.h" #include "media/learning/impl/model.h" #include "services/metrics/public/cpp/ukm_source_id.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace learning { @@ -81,7 +81,7 @@ class COMPONENT_EXPORT(LEARNING_IMPL) DistributionReporter { virtual void OnPrediction(const PredictionInfo& prediction_info, TargetHistogram predicted) = 0; - const base::Optional<std::set<int>>& feature_indices() const { + const absl::optional<std::set<int>>& feature_indices() const { return feature_indices_; } @@ -90,7 +90,7 @@ class COMPONENT_EXPORT(LEARNING_IMPL) DistributionReporter { // If provided, then these are the features that are used to train the model. // Otherwise, we assume that all features are used. - base::Optional<std::set<int>> feature_indices_; + absl::optional<std::set<int>> feature_indices_; base::WeakPtrFactory<DistributionReporter> weak_factory_{this}; diff --git a/chromium/media/learning/impl/feature_provider.h b/chromium/media/learning/impl/feature_provider.h index 3932905885a..c53fb81374a 100644 --- a/chromium/media/learning/impl/feature_provider.h +++ b/chromium/media/learning/impl/feature_provider.h @@ -5,9 +5,6 @@ #ifndef MEDIA_LEARNING_IMPL_FEATURE_PROVIDER_H_ #define MEDIA_LEARNING_IMPL_FEATURE_PROVIDER_H_ -#include <map> -#include <string> - #include "base/callback.h" #include "base/component_export.h" #include "base/macros.h" diff --git a/chromium/media/learning/impl/fisher_iris_dataset.h b/chromium/media/learning/impl/fisher_iris_dataset.h index 09d7c8132d7..6117ddf54b6 100644 --- a/chromium/media/learning/impl/fisher_iris_dataset.h +++ b/chromium/media/learning/impl/fisher_iris_dataset.h @@ -5,8 +5,6 @@ #ifndef MEDIA_LEARNING_IMPL_FISHER_IRIS_DATASET_H_ #define MEDIA_LEARNING_IMPL_FISHER_IRIS_DATASET_H_ -#include <vector> - #include "base/memory/ref_counted.h" #include "media/learning/common/labelled_example.h" diff --git a/chromium/media/learning/impl/learning_fuzzertest.cc b/chromium/media/learning/impl/learning_fuzzertest.cc index 8dc05543ed7..d6d00b9efcc 100644 --- a/chromium/media/learning/impl/learning_fuzzertest.cc +++ b/chromium/media/learning/impl/learning_fuzzertest.cc @@ -64,11 +64,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Build random examples. while (provider.remaining_bytes() > 0) { base::UnguessableToken id = base::UnguessableToken::Create(); - base::Optional<TargetValue> default_target; + absl::optional<TargetValue> default_target; if (provider.ConsumeBool()) default_target = TargetValue(ConsumeDouble(&provider)); controller.BeginObservation(id, ConsumeFeatureVector(&provider), - default_target, base::nullopt); + default_target, absl::nullopt); controller.CompleteObservation( id, ObservationCompletion(TargetValue(ConsumeDouble(&provider)), ConsumeDouble(&provider))); diff --git a/chromium/media/learning/impl/learning_session_impl.cc b/chromium/media/learning/impl/learning_session_impl.cc index cfe5ababfe7..620bd91b874 100644 --- a/chromium/media/learning/impl/learning_session_impl.cc +++ b/chromium/media/learning/impl/learning_session_impl.cc @@ -35,7 +35,7 @@ class WeakLearningTaskController : public LearningTaskController { // Cancel any outstanding observation, unless they have a default value. In // that case, complete them. for (auto& id : outstanding_observations_) { - const base::Optional<TargetValue>& default_value = id.second; + const absl::optional<TargetValue>& default_value = id.second; if (default_value) { controller_->AsyncCall(&LearningTaskController::CompleteObservation) .WithArgs(id.first, *default_value); @@ -49,8 +49,8 @@ class WeakLearningTaskController : public LearningTaskController { void BeginObservation( base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target, - const base::Optional<ukm::SourceId>& source_id) override { + const absl::optional<TargetValue>& default_target, + const absl::optional<ukm::SourceId>& source_id) override { if (!weak_session_) return; @@ -59,7 +59,7 @@ class WeakLearningTaskController : public LearningTaskController { // doesn't support it. Since all client calls eventually come through us // anyway, it seems okay to handle it here. controller_->AsyncCall(&LearningTaskController::BeginObservation) - .WithArgs(id, features, base::nullopt, source_id); + .WithArgs(id, features, absl::nullopt, source_id); } void CompleteObservation(base::UnguessableToken id, @@ -81,7 +81,7 @@ class WeakLearningTaskController : public LearningTaskController { void UpdateDefaultTarget( base::UnguessableToken id, - const base::Optional<TargetValue>& default_target) override { + const absl::optional<TargetValue>& default_target) override { if (!weak_session_) return; @@ -104,7 +104,7 @@ class WeakLearningTaskController : public LearningTaskController { // Set of ids that have been started but not completed / cancelled yet, and // any default target value. - std::map<base::UnguessableToken, base::Optional<TargetValue>> + std::map<base::UnguessableToken, absl::optional<TargetValue>> outstanding_observations_; }; diff --git a/chromium/media/learning/impl/learning_session_impl_unittest.cc b/chromium/media/learning/impl/learning_session_impl_unittest.cc index 86df5620ca7..bb3b17155b4 100644 --- a/chromium/media/learning/impl/learning_session_impl_unittest.cc +++ b/chromium/media/learning/impl/learning_session_impl_unittest.cc @@ -42,8 +42,8 @@ class LearningSessionImplTest : public testing::Test { void BeginObservation( base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target, - const base::Optional<ukm::SourceId>& source_id) override { + const absl::optional<TargetValue>& default_target, + const absl::optional<ukm::SourceId>& source_id) override { id_ = id; observation_features_ = features; default_target_ = default_target; @@ -64,7 +64,7 @@ class LearningSessionImplTest : public testing::Test { void UpdateDefaultTarget( base::UnguessableToken id, - const base::Optional<TargetValue>& default_target) override { + const absl::optional<TargetValue>& default_target) override { // Should not be called, since LearningTaskControllerImpl doesn't support // default values. updated_id_ = id; @@ -86,15 +86,15 @@ class LearningSessionImplTest : public testing::Test { FeatureVector observation_features_; FeatureVector predict_features_; PredictionCB predict_cb_; - base::Optional<TargetValue> default_target_; - base::Optional<ukm::SourceId> source_id_; + absl::optional<TargetValue> default_target_; + absl::optional<ukm::SourceId> source_id_; LabelledExample example_; // Most recently cancelled id. base::UnguessableToken cancelled_id_; // Id of most recently changed default target value. - base::Optional<base::UnguessableToken> updated_id_; + absl::optional<base::UnguessableToken> updated_id_; }; class FakeFeatureProvider : public FeatureProvider { @@ -191,7 +191,7 @@ TEST_F(LearningSessionImplTest, ExamplesAreForwardedToCorrectTask) { std::unique_ptr<LearningTaskController> ltc_0 = session_->GetController(task_0_.name); ukm::SourceId source_id(123); - ltc_0->BeginObservation(id, example_0.features, base::nullopt, source_id); + ltc_0->BeginObservation(id, example_0.features, absl::nullopt, source_id); ltc_0->CompleteObservation( id, ObservationCompletion(example_0.target_value, example_0.weight)); @@ -290,7 +290,7 @@ TEST_F(LearningSessionImplTest, ChangeDefaultTargetToValue) { // Start an observation without a default, then add one. base::UnguessableToken id = base::UnguessableToken::Create(); - controller->BeginObservation(id, FeatureVector(), base::nullopt); + controller->BeginObservation(id, FeatureVector(), absl::nullopt); TargetValue default_target(123); controller->UpdateDefaultTarget(id, default_target); task_environment_.RunUntilIdle(); @@ -316,7 +316,7 @@ TEST_F(LearningSessionImplTest, ChangeDefaultTargetToNoValue) { base::UnguessableToken id = base::UnguessableToken::Create(); TargetValue default_target(123); controller->BeginObservation(id, FeatureVector(), default_target); - controller->UpdateDefaultTarget(id, base::nullopt); + controller->UpdateDefaultTarget(id, absl::nullopt); task_environment_.RunUntilIdle(); EXPECT_EQ(task_controllers_[0]->id_, id); @@ -341,7 +341,7 @@ TEST_F(LearningSessionImplTest, PredictDistribution) { controller->PredictDistribution( features, base::BindOnce( [](TargetHistogram* test_storage, - const base::Optional<TargetHistogram>& predicted) { + const absl::optional<TargetHistogram>& predicted) { *test_storage = *predicted; }, &observed_prediction)); diff --git a/chromium/media/learning/impl/learning_task_controller_helper.cc b/chromium/media/learning/impl/learning_task_controller_helper.cc index 59dee3cbbe5..37a823fd943 100644 --- a/chromium/media/learning/impl/learning_task_controller_helper.cc +++ b/chromium/media/learning/impl/learning_task_controller_helper.cc @@ -27,7 +27,7 @@ LearningTaskControllerHelper::~LearningTaskControllerHelper() = default; void LearningTaskControllerHelper::BeginObservation( base::UnguessableToken id, FeatureVector features, - base::Optional<ukm::SourceId> source_id) { + absl::optional<ukm::SourceId> source_id) { auto& pending_example = pending_examples_[id]; if (source_id) diff --git a/chromium/media/learning/impl/learning_task_controller_helper.h b/chromium/media/learning/impl/learning_task_controller_helper.h index 69e59a1de21..1f45a9c4aae 100644 --- a/chromium/media/learning/impl/learning_task_controller_helper.h +++ b/chromium/media/learning/impl/learning_task_controller_helper.h @@ -49,7 +49,7 @@ class COMPONENT_EXPORT(LEARNING_IMPL) LearningTaskControllerHelper // See LearningTaskController::BeginObservation. void BeginObservation(base::UnguessableToken id, FeatureVector features, - base::Optional<ukm::SourceId> source_id); + absl::optional<ukm::SourceId> source_id); void CompleteObservation(base::UnguessableToken id, const ObservationCompletion& completion); void CancelObservation(base::UnguessableToken id); diff --git a/chromium/media/learning/impl/learning_task_controller_helper_unittest.cc b/chromium/media/learning/impl/learning_task_controller_helper_unittest.cc index 1d0774246fd..427f68d0a8e 100644 --- a/chromium/media/learning/impl/learning_task_controller_helper_unittest.cc +++ b/chromium/media/learning/impl/learning_task_controller_helper_unittest.cc @@ -93,7 +93,7 @@ class LearningTaskControllerHelperTest : public testing::Test { FeatureProvider::FeatureVectorCB fp_cb_; // Most recently added example via OnLabelledExample, if any. - base::Optional<LabelledExample> most_recent_example_; + absl::optional<LabelledExample> most_recent_example_; ukm::SourceId most_recent_source_id_; LearningTask task_; @@ -122,7 +122,7 @@ TEST_F(LearningTaskControllerHelperTest, AddingAnExampleWithoutFPWorks) { TEST_F(LearningTaskControllerHelperTest, DropTargetValueWithoutFPWorks) { // Verify that we can drop an example without labelling it. CreateClient(false); - helper_->BeginObservation(id_, example_.features, base::nullopt); + helper_->BeginObservation(id_, example_.features, absl::nullopt); EXPECT_EQ(pending_example_count(), 1u); helper_->CancelObservation(id_); task_environment_.RunUntilIdle(); @@ -133,7 +133,7 @@ TEST_F(LearningTaskControllerHelperTest, DropTargetValueWithoutFPWorks) { TEST_F(LearningTaskControllerHelperTest, AddTargetValueBeforeFP) { // Verify that an example is added if the target value arrives first. CreateClient(true); - helper_->BeginObservation(id_, example_.features, base::nullopt); + helper_->BeginObservation(id_, example_.features, absl::nullopt); EXPECT_EQ(pending_example_count(), 1u); task_environment_.RunUntilIdle(); // The feature provider should know about the example. @@ -158,7 +158,7 @@ TEST_F(LearningTaskControllerHelperTest, AddTargetValueBeforeFP) { TEST_F(LearningTaskControllerHelperTest, DropTargetValueBeforeFP) { // Verify that an example is correctly dropped before the FP adds features. CreateClient(true); - helper_->BeginObservation(id_, example_.features, base::nullopt); + helper_->BeginObservation(id_, example_.features, absl::nullopt); EXPECT_EQ(pending_example_count(), 1u); task_environment_.RunUntilIdle(); // The feature provider should know about the example. @@ -181,7 +181,7 @@ TEST_F(LearningTaskControllerHelperTest, DropTargetValueBeforeFP) { TEST_F(LearningTaskControllerHelperTest, AddTargetValueAfterFP) { // Verify that an example is added if the target value arrives second. CreateClient(true); - helper_->BeginObservation(id_, example_.features, base::nullopt); + helper_->BeginObservation(id_, example_.features, absl::nullopt); EXPECT_EQ(pending_example_count(), 1u); task_environment_.RunUntilIdle(); // The feature provider should know about the example. @@ -207,7 +207,7 @@ TEST_F(LearningTaskControllerHelperTest, AddTargetValueAfterFP) { TEST_F(LearningTaskControllerHelperTest, DropTargetValueAfterFP) { // Verify that we can cancel the observationc after sending features. CreateClient(true); - helper_->BeginObservation(id_, example_.features, base::nullopt); + helper_->BeginObservation(id_, example_.features, absl::nullopt); EXPECT_EQ(pending_example_count(), 1u); task_environment_.RunUntilIdle(); // The feature provider should know about the example. diff --git a/chromium/media/learning/impl/learning_task_controller_impl.cc b/chromium/media/learning/impl/learning_task_controller_impl.cc index 45c812d2489..895f94f8681 100644 --- a/chromium/media/learning/impl/learning_task_controller_impl.cc +++ b/chromium/media/learning/impl/learning_task_controller_impl.cc @@ -52,8 +52,8 @@ LearningTaskControllerImpl::~LearningTaskControllerImpl() = default; void LearningTaskControllerImpl::BeginObservation( base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target, - const base::Optional<ukm::SourceId>& source_id) { + const absl::optional<TargetValue>& default_target, + const absl::optional<ukm::SourceId>& source_id) { // TODO(liberato): Should we enforce that the right number of features are // present here? Right now, we allow it to be shorter, so that features from // a FeatureProvider may be omitted. Of course, they have to be at the end in @@ -87,7 +87,7 @@ void LearningTaskControllerImpl::CancelObservation(base::UnguessableToken id) { void LearningTaskControllerImpl::UpdateDefaultTarget( base::UnguessableToken id, - const base::Optional<TargetValue>& default_target) { + const absl::optional<TargetValue>& default_target) { NOTREACHED(); } @@ -101,7 +101,7 @@ void LearningTaskControllerImpl::PredictDistribution( if (model_) std::move(callback).Run(model_->PredictDistribution(features)); else - std::move(callback).Run(base::nullopt); + std::move(callback).Run(absl::nullopt); } void LearningTaskControllerImpl::AddFinishedExample(LabelledExample example, diff --git a/chromium/media/learning/impl/learning_task_controller_impl.h b/chromium/media/learning/impl/learning_task_controller_impl.h index 1453f1b779c..bc32ddf86eb 100644 --- a/chromium/media/learning/impl/learning_task_controller_impl.h +++ b/chromium/media/learning/impl/learning_task_controller_impl.h @@ -54,14 +54,14 @@ class COMPONENT_EXPORT(LEARNING_IMPL) LearningTaskControllerImpl void BeginObservation( base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target, - const base::Optional<ukm::SourceId>& source_id) override; + const absl::optional<TargetValue>& default_target, + const absl::optional<ukm::SourceId>& source_id) override; void CompleteObservation(base::UnguessableToken id, const ObservationCompletion& completion) override; void CancelObservation(base::UnguessableToken id) override; void UpdateDefaultTarget( base::UnguessableToken id, - const base::Optional<TargetValue>& default_target) override; + const absl::optional<TargetValue>& default_target) override; const LearningTask& GetLearningTask() override; void PredictDistribution(const FeatureVector& features, PredictionCB callback) override; diff --git a/chromium/media/learning/impl/learning_task_controller_impl_unittest.cc b/chromium/media/learning/impl/learning_task_controller_impl_unittest.cc index 38945699bc7..ad8b059645f 100644 --- a/chromium/media/learning/impl/learning_task_controller_impl_unittest.cc +++ b/chromium/media/learning/impl/learning_task_controller_impl_unittest.cc @@ -23,7 +23,7 @@ class LearningTaskControllerImplTest : public testing::Test { : DistributionReporter(task) {} // protected => public - const base::Optional<std::set<int>>& feature_indices() const { + const absl::optional<std::set<int>>& feature_indices() const { return DistributionReporter::feature_indices(); } @@ -133,21 +133,21 @@ class LearningTaskControllerImplTest : public testing::Test { } void AddExample(const LabelledExample& example, - base::Optional<ukm::SourceId> source_id = base::nullopt) { + absl::optional<ukm::SourceId> source_id = absl::nullopt) { base::UnguessableToken id = base::UnguessableToken::Create(); - controller_->BeginObservation(id, example.features, base::nullopt, + controller_->BeginObservation(id, example.features, absl::nullopt, source_id); controller_->CompleteObservation( id, ObservationCompletion(example.target_value, example.weight)); } void VerifyPrediction(const FeatureVector& features, - base::Optional<TargetHistogram> expectation) { - base::Optional<TargetHistogram> observed_prediction; + absl::optional<TargetHistogram> expectation) { + absl::optional<TargetHistogram> observed_prediction; controller_->PredictDistribution( features, base::BindOnce( - [](base::Optional<TargetHistogram>* test_storage, - const base::Optional<TargetHistogram>& predicted) { + [](absl::optional<TargetHistogram>* test_storage, + const absl::optional<TargetHistogram>& predicted) { *test_storage = predicted; }, &observed_prediction)); @@ -279,9 +279,9 @@ TEST_F(LearningTaskControllerImplTest, FeatureSubsetsWork) { TEST_F(LearningTaskControllerImplTest, PredictDistribution) { CreateController(); - // Predictions should be base::nullopt until we have a model. + // Predictions should be absl::nullopt until we have a model. LabelledExample example; - VerifyPrediction(example.features, base::nullopt); + VerifyPrediction(example.features, absl::nullopt); AddExample(example); TargetHistogram expected_histogram; diff --git a/chromium/media/learning/impl/lookup_table_trainer.h b/chromium/media/learning/impl/lookup_table_trainer.h index 5417c84823d..f17e6173b2a 100644 --- a/chromium/media/learning/impl/lookup_table_trainer.h +++ b/chromium/media/learning/impl/lookup_table_trainer.h @@ -5,9 +5,6 @@ #ifndef MEDIA_LEARNING_IMPL_LOOKUP_TABLE_TRAINER_H_ #define MEDIA_LEARNING_IMPL_LOOKUP_TABLE_TRAINER_H_ -#include <memory> -#include <vector> - #include "base/component_export.h" #include "base/macros.h" #include "media/learning/common/learning_task.h" diff --git a/chromium/media/learning/impl/model.h b/chromium/media/learning/impl/model.h index 673b61e4c43..793455c8505 100644 --- a/chromium/media/learning/impl/model.h +++ b/chromium/media/learning/impl/model.h @@ -9,7 +9,6 @@ #include "base/component_export.h" #include "media/learning/common/labelled_example.h" #include "media/learning/common/target_histogram.h" -#include "media/learning/impl/model.h" namespace media { namespace learning { diff --git a/chromium/media/learning/impl/one_hot.h b/chromium/media/learning/impl/one_hot.h index b48b66ec924..23e69845c38 100644 --- a/chromium/media/learning/impl/one_hot.h +++ b/chromium/media/learning/impl/one_hot.h @@ -11,11 +11,11 @@ #include "base/component_export.h" #include "base/macros.h" -#include "base/optional.h" #include "media/learning/common/labelled_example.h" #include "media/learning/common/learning_task.h" #include "media/learning/common/value.h" #include "media/learning/impl/model.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace learning { @@ -53,7 +53,7 @@ class COMPONENT_EXPORT(LEARNING_IMPL) OneHotConverter { // [original task feature index] = optional converter for it. If the feature // was kNumeric to begin with, then there will be no converter. - std::vector<base::Optional<ValueVectorIndexMap>> converters_; + std::vector<absl::optional<ValueVectorIndexMap>> converters_; DISALLOW_COPY_AND_ASSIGN(OneHotConverter); }; diff --git a/chromium/media/learning/impl/random_number_generator.h b/chromium/media/learning/impl/random_number_generator.h index e4ee413dad9..aeb4514b18e 100644 --- a/chromium/media/learning/impl/random_number_generator.h +++ b/chromium/media/learning/impl/random_number_generator.h @@ -6,7 +6,6 @@ #define MEDIA_LEARNING_IMPL_RANDOM_NUMBER_GENERATOR_H_ #include <cstdint> -#include <memory> #include "base/component_export.h" #include "base/macros.h" diff --git a/chromium/media/learning/impl/random_tree_trainer.cc b/chromium/media/learning/impl/random_tree_trainer.cc index b75deafec04..041cd884e24 100644 --- a/chromium/media/learning/impl/random_tree_trainer.cc +++ b/chromium/media/learning/impl/random_tree_trainer.cc @@ -8,8 +8,8 @@ #include "base/bind.h" #include "base/check_op.h" -#include "base/optional.h" #include "base/threading/sequenced_task_runner_handle.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { namespace learning { @@ -177,9 +177,9 @@ std::unique_ptr<Model> RandomTreeTrainer::Build( // and the target value, if the Optional has a value then it's the singular // value that we've found so far. If we find a second one, then we'll clear // the Optional. - base::Optional<TargetValue> target_value( + absl::optional<TargetValue> target_value( training_data[training_idx[0]].target_value); - std::vector<base::Optional<FeatureValue>> feature_values; + std::vector<absl::optional<FeatureValue>> feature_values; feature_values.resize(training_data[0].features.size()); for (size_t feature_idx : unused_set) { feature_values[feature_idx] = diff --git a/chromium/media/learning/mojo/mojo_learning_task_controller_service.cc b/chromium/media/learning/mojo/mojo_learning_task_controller_service.cc index 92dc1e179c9..af2b814525d 100644 --- a/chromium/media/learning/mojo/mojo_learning_task_controller_service.cc +++ b/chromium/media/learning/mojo/mojo_learning_task_controller_service.cc @@ -28,7 +28,7 @@ MojoLearningTaskControllerService::~MojoLearningTaskControllerService() = void MojoLearningTaskControllerService::BeginObservation( const base::UnguessableToken& id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target) { + const absl::optional<TargetValue>& default_target) { // Drop the observation if it doesn't match the feature description size. if (features.size() != task_.feature_descriptions.size()) return; @@ -66,7 +66,7 @@ void MojoLearningTaskControllerService::CancelObservation( void MojoLearningTaskControllerService::UpdateDefaultTarget( const base::UnguessableToken& id, - const base::Optional<TargetValue>& default_target) { + const absl::optional<TargetValue>& default_target) { auto iter = in_flight_observations_.find(id); if (iter == in_flight_observations_.end()) return; diff --git a/chromium/media/learning/mojo/mojo_learning_task_controller_service.h b/chromium/media/learning/mojo/mojo_learning_task_controller_service.h index eff098fe99c..9cdb8eae8ea 100644 --- a/chromium/media/learning/mojo/mojo_learning_task_controller_service.h +++ b/chromium/media/learning/mojo/mojo_learning_task_controller_service.h @@ -34,13 +34,13 @@ class COMPONENT_EXPORT(MEDIA_LEARNING_MOJO) MojoLearningTaskControllerService void BeginObservation( const base::UnguessableToken& id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target) override; + const absl::optional<TargetValue>& default_target) override; void CompleteObservation(const base::UnguessableToken& id, const ObservationCompletion& completion) override; void CancelObservation(const base::UnguessableToken& id) override; void UpdateDefaultTarget( const base::UnguessableToken& id, - const base::Optional<TargetValue>& default_target) override; + const absl::optional<TargetValue>& default_target) override; void PredictDistribution(const FeatureVector& features, PredictDistributionCallback callback) override; diff --git a/chromium/media/learning/mojo/mojo_learning_task_controller_service_unittest.cc b/chromium/media/learning/mojo/mojo_learning_task_controller_service_unittest.cc index 971e6dcbe3d..59675cab5d5 100644 --- a/chromium/media/learning/mojo/mojo_learning_task_controller_service_unittest.cc +++ b/chromium/media/learning/mojo/mojo_learning_task_controller_service_unittest.cc @@ -28,8 +28,8 @@ class MojoLearningTaskControllerServiceTest : public ::testing::Test { void BeginObservation( base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target, - const base::Optional<ukm::SourceId>& source_id) override { + const absl::optional<TargetValue>& default_target, + const absl::optional<ukm::SourceId>& source_id) override { begin_args_.id_ = id; begin_args_.features_ = features; begin_args_.default_target_ = default_target; @@ -48,7 +48,7 @@ class MojoLearningTaskControllerServiceTest : public ::testing::Test { void UpdateDefaultTarget( base::UnguessableToken id, - const base::Optional<TargetValue>& default_target) override { + const absl::optional<TargetValue>& default_target) override { update_default_args_.id_ = id; update_default_args_.default_target_ = default_target; } @@ -66,8 +66,8 @@ class MojoLearningTaskControllerServiceTest : public ::testing::Test { struct { base::UnguessableToken id_; FeatureVector features_; - base::Optional<TargetValue> default_target_; - base::Optional<ukm::SourceId> source_id_; + absl::optional<TargetValue> default_target_; + absl::optional<ukm::SourceId> source_id_; } begin_args_; struct { @@ -81,7 +81,7 @@ class MojoLearningTaskControllerServiceTest : public ::testing::Test { struct { base::UnguessableToken id_; - base::Optional<TargetValue> default_target_; + absl::optional<TargetValue> default_target_; } update_default_args_; struct { @@ -122,7 +122,7 @@ class MojoLearningTaskControllerServiceTest : public ::testing::Test { TEST_F(MojoLearningTaskControllerServiceTest, BeginComplete) { base::UnguessableToken id = base::UnguessableToken::Create(); FeatureVector features = {FeatureValue(123), FeatureValue(456)}; - service_->BeginObservation(id, features, base::nullopt); + service_->BeginObservation(id, features, absl::nullopt); EXPECT_EQ(id, controller_raw_->begin_args_.id_); EXPECT_EQ(features, controller_raw_->begin_args_.features_); EXPECT_FALSE(controller_raw_->begin_args_.default_target_); @@ -140,7 +140,7 @@ TEST_F(MojoLearningTaskControllerServiceTest, BeginComplete) { TEST_F(MojoLearningTaskControllerServiceTest, BeginCancel) { base::UnguessableToken id = base::UnguessableToken::Create(); FeatureVector features = {FeatureValue(123), FeatureValue(456)}; - service_->BeginObservation(id, features, base::nullopt); + service_->BeginObservation(id, features, absl::nullopt); EXPECT_EQ(id, controller_raw_->begin_args_.id_); EXPECT_EQ(features, controller_raw_->begin_args_.features_); EXPECT_FALSE(controller_raw_->begin_args_.default_target_); @@ -166,7 +166,7 @@ TEST_F(MojoLearningTaskControllerServiceTest, TooFewFeaturesIsIgnored) { // A FeatureVector with too few elements should be ignored. base::UnguessableToken id = base::UnguessableToken::Create(); FeatureVector short_features = {FeatureValue(123)}; - service_->BeginObservation(id, short_features, base::nullopt); + service_->BeginObservation(id, short_features, absl::nullopt); EXPECT_NE(id, controller_raw_->begin_args_.id_); EXPECT_EQ(controller_raw_->begin_args_.features_.size(), 0u); } @@ -176,7 +176,7 @@ TEST_F(MojoLearningTaskControllerServiceTest, TooManyFeaturesIsIgnored) { base::UnguessableToken id = base::UnguessableToken::Create(); FeatureVector long_features = {FeatureValue(123), FeatureValue(456), FeatureValue(789)}; - service_->BeginObservation(id, long_features, base::nullopt); + service_->BeginObservation(id, long_features, absl::nullopt); EXPECT_NE(id, controller_raw_->begin_args_.id_); EXPECT_EQ(controller_raw_->begin_args_.features_.size(), 0u); } @@ -197,7 +197,7 @@ TEST_F(MojoLearningTaskControllerServiceTest, CancelWithoutBeginFails) { TEST_F(MojoLearningTaskControllerServiceTest, UpdateDefaultTargetToValue) { base::UnguessableToken id = base::UnguessableToken::Create(); FeatureVector features = {FeatureValue(123), FeatureValue(456)}; - service_->BeginObservation(id, features, base::nullopt); + service_->BeginObservation(id, features, absl::nullopt); TargetValue default_target(987); service_->UpdateDefaultTarget(id, default_target); EXPECT_EQ(id, controller_raw_->update_default_args_.id_); @@ -210,9 +210,9 @@ TEST_F(MojoLearningTaskControllerServiceTest, UpdateDefaultTargetToNoValue) { FeatureVector features = {FeatureValue(123), FeatureValue(456)}; TargetValue default_target(987); service_->BeginObservation(id, features, default_target); - service_->UpdateDefaultTarget(id, base::nullopt); + service_->UpdateDefaultTarget(id, absl::nullopt); EXPECT_EQ(id, controller_raw_->update_default_args_.id_); - EXPECT_EQ(base::nullopt, + EXPECT_EQ(absl::nullopt, controller_raw_->update_default_args_.default_target_); } @@ -222,7 +222,7 @@ TEST_F(MojoLearningTaskControllerServiceTest, PredictDistribution) { service_->PredictDistribution( features, base::BindOnce( [](TargetHistogram* test_storage, - const base::Optional<TargetHistogram>& predicted) { + const absl::optional<TargetHistogram>& predicted) { *test_storage = *predicted; }, &observed_prediction)); diff --git a/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller.cc b/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller.cc index 3d7b16cb6f5..aaca1ad3896 100644 --- a/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller.cc +++ b/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller.cc @@ -19,8 +19,8 @@ MojoLearningTaskController::~MojoLearningTaskController() = default; void MojoLearningTaskController::BeginObservation( base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target, - const base::Optional<ukm::SourceId>& source_id) { + const absl::optional<TargetValue>& default_target, + const absl::optional<ukm::SourceId>& source_id) { // We don't need to keep track of in-flight observations, since the service // side handles it for us. Also note that |source_id| is ignored; the service // has no reason to trust it. It will fill it in for us. DCHECK in case @@ -41,7 +41,7 @@ void MojoLearningTaskController::CancelObservation(base::UnguessableToken id) { void MojoLearningTaskController::UpdateDefaultTarget( base::UnguessableToken id, - const base::Optional<TargetValue>& default_target) { + const absl::optional<TargetValue>& default_target) { controller_->UpdateDefaultTarget(id, default_target); } diff --git a/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller.h b/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller.h index efe5067778e..f58305908a5 100644 --- a/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller.h +++ b/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller.h @@ -5,8 +5,6 @@ #ifndef MEDIA_LEARNING_MOJO_PUBLIC_CPP_MOJO_LEARNING_TASK_CONTROLLER_H_ #define MEDIA_LEARNING_MOJO_PUBLIC_CPP_MOJO_LEARNING_TASK_CONTROLLER_H_ -#include <utility> - #include "base/component_export.h" #include "base/macros.h" #include "media/learning/common/learning_task_controller.h" @@ -31,14 +29,14 @@ class COMPONENT_EXPORT(MEDIA_LEARNING_MOJO) MojoLearningTaskController void BeginObservation( base::UnguessableToken id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target, - const base::Optional<ukm::SourceId>& source_id) override; + const absl::optional<TargetValue>& default_target, + const absl::optional<ukm::SourceId>& source_id) override; void CompleteObservation(base::UnguessableToken id, const ObservationCompletion& completion) override; void CancelObservation(base::UnguessableToken id) override; void UpdateDefaultTarget( base::UnguessableToken id, - const base::Optional<TargetValue>& default_target) override; + const absl::optional<TargetValue>& default_target) override; const LearningTask& GetLearningTask() override; void PredictDistribution(const FeatureVector& features, PredictionCB callback) override; diff --git a/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller_unittest.cc b/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller_unittest.cc index 37232a6b313..9d7beecef00 100644 --- a/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller_unittest.cc +++ b/chromium/media/learning/mojo/public/cpp/mojo_learning_task_controller_unittest.cc @@ -26,7 +26,7 @@ class MojoLearningTaskControllerTest : public ::testing::Test { void BeginObservation( const base::UnguessableToken& id, const FeatureVector& features, - const base::Optional<TargetValue>& default_target) override { + const absl::optional<TargetValue>& default_target) override { begin_args_.id_ = id; begin_args_.features_ = features; begin_args_.default_target_ = default_target; @@ -44,7 +44,7 @@ class MojoLearningTaskControllerTest : public ::testing::Test { void UpdateDefaultTarget( const base::UnguessableToken& id, - const base::Optional<TargetValue>& default_target) override { + const absl::optional<TargetValue>& default_target) override { update_default_args_.id_ = id; update_default_args_.default_target_ = default_target; } @@ -58,7 +58,7 @@ class MojoLearningTaskControllerTest : public ::testing::Test { struct { base::UnguessableToken id_; FeatureVector features_; - base::Optional<TargetValue> default_target_; + absl::optional<TargetValue> default_target_; } begin_args_; struct { @@ -72,7 +72,7 @@ class MojoLearningTaskControllerTest : public ::testing::Test { struct { base::UnguessableToken id_; - base::Optional<TargetValue> default_target_; + absl::optional<TargetValue> default_target_; } update_default_args_; struct { @@ -115,8 +115,8 @@ TEST_F(MojoLearningTaskControllerTest, GetLearningTask) { TEST_F(MojoLearningTaskControllerTest, BeginWithoutDefaultTarget) { base::UnguessableToken id = base::UnguessableToken::Create(); FeatureVector features = {FeatureValue(123), FeatureValue(456)}; - learning_controller_->BeginObservation(id, features, base::nullopt, - base::nullopt); + learning_controller_->BeginObservation(id, features, absl::nullopt, + absl::nullopt); task_environment_.RunUntilIdle(); EXPECT_EQ(id, fake_learning_controller_.begin_args_.id_); EXPECT_EQ(features, fake_learning_controller_.begin_args_.features_); @@ -128,7 +128,7 @@ TEST_F(MojoLearningTaskControllerTest, BeginWithDefaultTarget) { TargetValue default_target(987); FeatureVector features = {FeatureValue(123), FeatureValue(456)}; learning_controller_->BeginObservation(id, features, default_target, - base::nullopt); + absl::nullopt); task_environment_.RunUntilIdle(); EXPECT_EQ(id, fake_learning_controller_.begin_args_.id_); EXPECT_EQ(features, fake_learning_controller_.begin_args_.features_); @@ -140,8 +140,8 @@ TEST_F(MojoLearningTaskControllerTest, UpdateDefaultTargetToValue) { // Test if we can update the default target to a non-nullopt. base::UnguessableToken id = base::UnguessableToken::Create(); FeatureVector features = {FeatureValue(123), FeatureValue(456)}; - learning_controller_->BeginObservation(id, features, base::nullopt, - base::nullopt); + learning_controller_->BeginObservation(id, features, absl::nullopt, + absl::nullopt); TargetValue default_target(987); learning_controller_->UpdateDefaultTarget(id, default_target); task_environment_.RunUntilIdle(); @@ -157,12 +157,12 @@ TEST_F(MojoLearningTaskControllerTest, UpdateDefaultTargetToNoValue) { FeatureVector features = {FeatureValue(123), FeatureValue(456)}; TargetValue default_target(987); learning_controller_->BeginObservation(id, features, default_target, - base::nullopt); - learning_controller_->UpdateDefaultTarget(id, base::nullopt); + absl::nullopt); + learning_controller_->UpdateDefaultTarget(id, absl::nullopt); task_environment_.RunUntilIdle(); EXPECT_EQ(id, fake_learning_controller_.update_default_args_.id_); EXPECT_EQ(features, fake_learning_controller_.begin_args_.features_); - EXPECT_EQ(base::nullopt, + EXPECT_EQ(absl::nullopt, fake_learning_controller_.update_default_args_.default_target_); } @@ -190,7 +190,7 @@ TEST_F(MojoLearningTaskControllerTest, PredictDistribution) { learning_controller_->PredictDistribution( features, base::BindOnce( [](TargetHistogram* test_storage, - const base::Optional<TargetHistogram>& predicted) { + const absl::optional<TargetHistogram>& predicted) { *test_storage = *predicted; }, &observed_prediction)); diff --git a/chromium/media/learning/mojo/public/mojom/learning_task_controller.mojom b/chromium/media/learning/mojo/public/mojom/learning_task_controller.mojom index 782c8608ca7..4c4d9bf0e7e 100644 --- a/chromium/media/learning/mojo/public/mojom/learning_task_controller.mojom +++ b/chromium/media/learning/mojo/public/mojom/learning_task_controller.mojom @@ -43,7 +43,7 @@ interface LearningTaskController { TargetValue? default_target); // Asynchronously predicts distribution for given |features|. |callback| will - // receive a base::nullopt prediction when model is not available. + // receive a absl::nullopt prediction when model is not available. PredictDistribution(array<FeatureValue> features) => (TargetHistogram? predicted); }; diff --git a/chromium/media/media_options.gni b/chromium/media/media_options.gni index 61c804e9624..303b2e323d5 100644 --- a/chromium/media/media_options.gni +++ b/chromium/media/media_options.gni @@ -249,6 +249,7 @@ media_subcomponent_deps = [ if (is_fuchsia) { media_subcomponent_deps += [ + "//media/fuchsia/audio", "//media/fuchsia/cdm", "//media/fuchsia/common", ] @@ -258,6 +259,6 @@ if (media_use_ffmpeg) { media_subcomponent_deps += [ "//media/ffmpeg" ] } -if (enable_library_cdms) { +if (enable_library_cdms || is_win) { media_subcomponent_deps += [ "//media/cdm:cdm_type_conversion" ] } diff --git a/chromium/media/midi/DIR_METADATA b/chromium/media/midi/DIR_METADATA index d6aec82bd66..b44dd56948b 100644 --- a/chromium/media/midi/DIR_METADATA +++ b/chromium/media/midi/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Blink>WebMIDI" diff --git a/chromium/media/midi/midi_manager_alsa_unittest.cc b/chromium/media/midi/midi_manager_alsa_unittest.cc index 88baa7580f6..995ccc350bd 100644 --- a/chromium/media/midi/midi_manager_alsa_unittest.cc +++ b/chromium/media/midi/midi_manager_alsa_unittest.cc @@ -18,101 +18,116 @@ class MidiManagerAlsaTest : public ::testing::Test { // following tests. // Inputs. port_input_0_ == port_input_1_. - port_input_0_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + port_input_0_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 2, 5, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_1_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_1_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 2, 5, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_minimal_.reset(new MidiManagerAlsa::MidiPort( + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_minimal_ = std::make_unique<MidiManagerAlsa::MidiPort>( "", MidiManagerAlsa::MidiPort::Id(), 0, 0, 0, "", "", "", "", - MidiManagerAlsa::MidiPort::Type::kInput)); + MidiManagerAlsa::MidiPort::Type::kInput); // Outputs. port_output_0_ == port_output_1_. - port_output_0_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + port_output_0_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 2, 5, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kOutput)); - port_output_1_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + MidiManagerAlsa::MidiPort::Type::kOutput); + port_output_1_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 2, 5, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kOutput)); + MidiManagerAlsa::MidiPort::Type::kOutput); // MidiPort fields that differ from port_input_0_ in a single way each time. // Used for testing the Match* and Find* methods. - port_input_0_alt_path_.reset(new MidiManagerAlsa::MidiPort( - "path2", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + port_input_0_alt_path_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path2", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 2, 5, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_alt_id_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial2"), + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_alt_id_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial2"), 1, 2, 5, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_alt_client_name_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_alt_client_name_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 2, 5, "client_name2", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_alt_port_name_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_alt_port_name_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 2, 5, "client_name", "port_name2", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_alt_client_id_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_alt_client_id_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 2, 2, 5, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_alt_port_id_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_alt_port_id_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 3, 5, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_alt_midi_device_.reset(new MidiManagerAlsa::MidiPort( - "path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", - "interface", "serial"), + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_alt_midi_device_ = std::make_unique<MidiManagerAlsa::MidiPort>( + "path", + MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model", "interface", + "serial"), 1, 2, 6, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); + MidiManagerAlsa::MidiPort::Type::kInput); // "No card" variants of above. For testing FindDisconnected. - port_input_0_no_card_.reset(new MidiManagerAlsa::MidiPort( + port_input_0_no_card_ = std::make_unique<MidiManagerAlsa::MidiPort>( "", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_1_no_card_.reset(new MidiManagerAlsa::MidiPort( + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_1_no_card_ = std::make_unique<MidiManagerAlsa::MidiPort>( "", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_output_0_no_card_.reset(new MidiManagerAlsa::MidiPort( + MidiManagerAlsa::MidiPort::Type::kInput); + port_output_0_no_card_ = std::make_unique<MidiManagerAlsa::MidiPort>( "", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name", "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kOutput)); + MidiManagerAlsa::MidiPort::Type::kOutput); // No card variants of the alt variants from above. For more testing // of Match* and Find*. - port_input_0_no_card_alt_client_name_.reset(new MidiManagerAlsa::MidiPort( - "", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name2", - "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_no_card_alt_port_name_.reset(new MidiManagerAlsa::MidiPort( - "", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name", - "port_name2", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_no_card_alt_client_id_.reset(new MidiManagerAlsa::MidiPort( - "", MidiManagerAlsa::MidiPort::Id(), 2, 2, -1, "client_name", - "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); - port_input_0_no_card_alt_port_id_.reset(new MidiManagerAlsa::MidiPort( - "", MidiManagerAlsa::MidiPort::Id(), 1, 3, -1, "client_name", - "port_name", "manufacturer", "version", - MidiManagerAlsa::MidiPort::Type::kInput)); + port_input_0_no_card_alt_client_name_ = + std::make_unique<MidiManagerAlsa::MidiPort>( + "", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name2", + "port_name", "manufacturer", "version", + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_no_card_alt_port_name_ = + std::make_unique<MidiManagerAlsa::MidiPort>( + "", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name", + "port_name2", "manufacturer", "version", + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_no_card_alt_client_id_ = + std::make_unique<MidiManagerAlsa::MidiPort>( + "", MidiManagerAlsa::MidiPort::Id(), 2, 2, -1, "client_name", + "port_name", "manufacturer", "version", + MidiManagerAlsa::MidiPort::Type::kInput); + port_input_0_no_card_alt_port_id_ = + std::make_unique<MidiManagerAlsa::MidiPort>( + "", MidiManagerAlsa::MidiPort::Id(), 1, 3, -1, "client_name", + "port_name", "manufacturer", "version", + MidiManagerAlsa::MidiPort::Type::kInput); } // Counts ports for help with testing ToMidiPortState(). diff --git a/chromium/media/midi/midi_manager_win.cc b/chromium/media/midi/midi_manager_win.cc index 4f1f67d5168..5ddf29b44dc 100644 --- a/chromium/media/midi/midi_manager_win.cc +++ b/chromium/media/midi/midi_manager_win.cc @@ -14,6 +14,7 @@ #include <algorithm> #include <limits> #include <map> +#include <memory> #include <string> #include <utility> @@ -21,7 +22,6 @@ #include "base/callback.h" #include "base/callback_helpers.h" #include "base/logging.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" @@ -34,6 +34,7 @@ #include "media/midi/midi_service.mojom.h" #include "media/midi/midi_switches.h" #include "services/device/public/cpp/usb/usb_ids.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace midi { @@ -118,7 +119,7 @@ base::Lock* GetInstanceIdLock() { } // Issues unique MidiManager instance ID. -int64_t IssueNextInstanceId(base::Optional<int64_t> override_id) { +int64_t IssueNextInstanceId(absl::optional<int64_t> override_id) { static int64_t id = kInvalidInstanceId; if (override_id) { int64_t result = ++id; @@ -633,7 +634,7 @@ MidiManagerWin::PortManager::HandleMidiInCallback(HMIDIIN hmi, if (IsRunningInsideMidiInGetNumDevs()) GetTaskLock()->AssertAcquired(); else - task_lock.reset(new base::AutoLock(*GetTaskLock())); + task_lock = std::make_unique<base::AutoLock>(*GetTaskLock()); { base::AutoLock lock(*GetInstanceIdLock()); if (instance_id != g_active_instance_id) @@ -702,7 +703,7 @@ void MidiManagerWin::OverflowInstanceIdForTesting() { MidiManagerWin::MidiManagerWin(MidiService* service) : MidiManager(service), - instance_id_(IssueNextInstanceId(base::nullopt)), + instance_id_(IssueNextInstanceId(absl::nullopt)), port_manager_(std::make_unique<PortManager>()) { base::AutoLock lock(*GetInstanceIdLock()); CHECK_EQ(kInvalidInstanceId, g_active_instance_id); diff --git a/chromium/media/midi/midi_manager_winrt.cc b/chromium/media/midi/midi_manager_winrt.cc index 9ec6bad7047..eb1de49d6d4 100644 --- a/chromium/media/midi/midi_manager_winrt.cc +++ b/chromium/media/midi/midi_manager_winrt.cc @@ -22,6 +22,7 @@ #include <wrl/event.h> #include <iomanip> +#include <memory> #include <unordered_map> #include <unordered_set> @@ -828,8 +829,8 @@ void MidiManagerWinrt::InitializeOnComRunner() { return; } - port_manager_in_.reset(new MidiInPortManager(this)); - port_manager_out_.reset(new MidiOutPortManager(this)); + port_manager_in_ = std::make_unique<MidiInPortManager>(this); + port_manager_out_ = std::make_unique<MidiOutPortManager>(this); if (!(port_manager_in_->StartWatcher() && port_manager_out_->StartWatcher())) { diff --git a/chromium/media/midi/midi_output_port_android.h b/chromium/media/midi/midi_output_port_android.h index 0574c276145..f2da111b426 100644 --- a/chromium/media/midi/midi_output_port_android.h +++ b/chromium/media/midi/midi_output_port_android.h @@ -10,7 +10,6 @@ #include <vector> #include "base/android/scoped_java_ref.h" -#include "base/time/time.h" namespace midi { diff --git a/chromium/media/midi/task_service.cc b/chromium/media/midi/task_service.cc index fb190688880..21bb8dc0a9b 100644 --- a/chromium/media/midi/task_service.cc +++ b/chromium/media/midi/task_service.cc @@ -151,7 +151,7 @@ scoped_refptr<base::SingleThreadTaskRunner> TaskService::GetTaskRunner( #elif defined(OS_MAC) options.message_pump_type = base::MessagePumpType::UI; #endif - threads_[thread]->StartWithOptions(options); + threads_[thread]->StartWithOptions(std::move(options)); } return threads_[thread]->task_runner(); } diff --git a/chromium/media/midi/usb_midi_device_factory_android.h b/chromium/media/midi/usb_midi_device_factory_android.h index d0dae559ac7..feb6fafdbda 100644 --- a/chromium/media/midi/usb_midi_device_factory_android.h +++ b/chromium/media/midi/usb_midi_device_factory_android.h @@ -6,7 +6,6 @@ #define MEDIA_MIDI_USB_MIDI_DEVICE_FACTORY_ANDROID_H_ #include <jni.h> -#include <vector> #include "base/android/scoped_java_ref.h" #include "base/callback.h" diff --git a/chromium/media/mojo/clients/mojo_android_overlay.h b/chromium/media/mojo/clients/mojo_android_overlay.h index 333a537e8b1..0e2e8a8cafb 100644 --- a/chromium/media/mojo/clients/mojo_android_overlay.h +++ b/chromium/media/mojo/clients/mojo_android_overlay.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_BASE_MOJO_ANDROID_OVERLAY_H_ -#define MEDIA_BASE_MOJO_ANDROID_OVERLAY_H_ +#ifndef MEDIA_MOJO_CLIENTS_MOJO_ANDROID_OVERLAY_H_ +#define MEDIA_MOJO_CLIENTS_MOJO_ANDROID_OVERLAY_H_ #include "base/macros.h" #include "base/unguessable_token.h" @@ -51,4 +51,4 @@ class MojoAndroidOverlay : public AndroidOverlay, } // namespace media -#endif // MEDIA_BASE_MOJO_ANDROID_OVERLAY_H_ +#endif // MEDIA_MOJO_CLIENTS_MOJO_ANDROID_OVERLAY_H_ diff --git a/chromium/media/mojo/clients/mojo_android_overlay_unittest.cc b/chromium/media/mojo/clients/mojo_android_overlay_unittest.cc index ca09bfd567b..cbe08142895 100644 --- a/chromium/media/mojo/clients/mojo_android_overlay_unittest.cc +++ b/chromium/media/mojo/clients/mojo_android_overlay_unittest.cc @@ -112,9 +112,9 @@ class MojoAndroidOverlayTest : public ::testing::Test { base::UnguessableToken routing_token = base::UnguessableToken::Create(); - overlay_client_.reset( - new MojoAndroidOverlay(provider_receiver_.BindNewPipeAndPassRemote(), - std::move(config_), routing_token)); + overlay_client_ = std::make_unique<MojoAndroidOverlay>( + provider_receiver_.BindNewPipeAndPassRemote(), std::move(config_), + routing_token); overlay_client_->AddSurfaceDestroyedCallback(base::BindOnce( &MockClientCallbacks::OnDestroyed, base::Unretained(&callbacks_))); base::RunLoop().RunUntilIdle(); diff --git a/chromium/media/mojo/clients/mojo_audio_decoder.cc b/chromium/media/mojo/clients/mojo_audio_decoder.cc index 76259add30c..105647f5f36 100644 --- a/chromium/media/mojo/clients/mojo_audio_decoder.cc +++ b/chromium/media/mojo/clients/mojo_audio_decoder.cc @@ -75,7 +75,7 @@ void MojoAudioDecoder::Initialize(const AudioDecoderConfig& config, } // Fail immediately if the stream is encrypted but |cdm_context| is invalid. - base::Optional<base::UnguessableToken> cdm_id; + absl::optional<base::UnguessableToken> cdm_id; if (config.is_encrypted() && cdm_context) cdm_id = cdm_context->GetCdmId(); diff --git a/chromium/media/mojo/clients/mojo_cdm.cc b/chromium/media/mojo/clients/mojo_cdm.cc index f0098346345..3a7e883efef 100644 --- a/chromium/media/mojo/clients/mojo_cdm.cc +++ b/chromium/media/mojo/clients/mojo_cdm.cc @@ -267,7 +267,7 @@ Decryptor* MojoCdm::GetDecryptor() { return decryptor_.get(); } -base::Optional<base::UnguessableToken> MojoCdm::GetCdmId() const { +absl::optional<base::UnguessableToken> MojoCdm::GetCdmId() const { // Can be called on a different thread. base::AutoLock auto_lock(lock_); DVLOG(2) << __func__ << ": cdm_id=" diff --git a/chromium/media/mojo/clients/mojo_cdm.h b/chromium/media/mojo/clients/mojo_cdm.h index ca886cc99cf..b4e04d4ef37 100644 --- a/chromium/media/mojo/clients/mojo_cdm.h +++ b/chromium/media/mojo/clients/mojo_cdm.h @@ -78,7 +78,7 @@ class MojoCdm final : public ContentDecryptionModule, // All GetDecryptor() calls must be made on the same thread. std::unique_ptr<CallbackRegistration> RegisterEventCB(EventCB event_cb) final; Decryptor* GetDecryptor() final; - base::Optional<base::UnguessableToken> GetCdmId() const final; + absl::optional<base::UnguessableToken> GetCdmId() const final; #if defined(OS_WIN) bool RequiresMediaFoundationRenderer() final; #endif // defined(OS_WIN) @@ -124,7 +124,7 @@ class MojoCdm final : public ContentDecryptionModule, // CDM ID of the remote CDM. Set after initialization is completed. Must not // be invalid if initialization succeeded. - base::Optional<base::UnguessableToken> cdm_id_ GUARDED_BY(lock_); + absl::optional<base::UnguessableToken> cdm_id_ GUARDED_BY(lock_); // The mojo::PendingRemote<mojom::Decryptor> exposed by the remote CDM. Set // after initialization is completed and cleared after |decryptor_| is diff --git a/chromium/media/mojo/clients/mojo_demuxer_stream_impl.cc b/chromium/media/mojo/clients/mojo_demuxer_stream_impl.cc index e2bae040316..2149c8aaef3 100644 --- a/chromium/media/mojo/clients/mojo_demuxer_stream_impl.cc +++ b/chromium/media/mojo/clients/mojo_demuxer_stream_impl.cc @@ -31,8 +31,8 @@ void MojoDemuxerStreamImpl::Initialize(InitializeCallback callback) { DVLOG(2) << __func__; // Prepare the initial config. - base::Optional<AudioDecoderConfig> audio_config; - base::Optional<VideoDecoderConfig> video_config; + absl::optional<AudioDecoderConfig> audio_config; + absl::optional<VideoDecoderConfig> video_config; if (stream_->type() == Type::AUDIO) { audio_config = stream_->audio_decoder_config(); } else if (stream_->type() == Type::VIDEO) { @@ -64,8 +64,8 @@ void MojoDemuxerStreamImpl::EnableBitstreamConverter() { void MojoDemuxerStreamImpl::OnBufferReady(ReadCallback callback, Status status, scoped_refptr<DecoderBuffer> buffer) { - base::Optional<AudioDecoderConfig> audio_config; - base::Optional<VideoDecoderConfig> video_config; + absl::optional<AudioDecoderConfig> audio_config; + absl::optional<VideoDecoderConfig> video_config; if (status == Status::kConfigChanged) { DVLOG(2) << __func__ << ": ConfigChange!"; diff --git a/chromium/media/mojo/clients/mojo_renderer.cc b/chromium/media/mojo/clients/mojo_renderer.cc index 3e3a752134b..52fada6caed 100644 --- a/chromium/media/mojo/clients/mojo_renderer.cc +++ b/chromium/media/mojo/clients/mojo_renderer.cc @@ -120,7 +120,7 @@ void MojoRenderer::InitializeRendererFromUrl(media::RendererClient* client) { url_params.top_frame_origin, url_params.allow_credentials, url_params.is_hls); remote_renderer_->Initialize(client_receiver_.BindNewEndpointAndPassRemote(), - base::nullopt, std::move(media_url_params), + absl::nullopt, std::move(media_url_params), base::BindOnce(&MojoRenderer::OnInitialized, base::Unretained(this), client)); } @@ -139,7 +139,7 @@ void MojoRenderer::SetCdm(CdmContext* cdm_context, return; } - base::Optional<base::UnguessableToken> cdm_id = cdm_context->GetCdmId(); + absl::optional<base::UnguessableToken> cdm_id = cdm_context->GetCdmId(); if (!cdm_id) { DVLOG(2) << "MojoRenderer only works with remote CDMs but the CDM ID " "is invalid."; @@ -156,7 +156,7 @@ void MojoRenderer::SetCdm(CdmContext* cdm_context, } void MojoRenderer::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { // TODO(chcunningham): Proxy to remote renderer if needed. } @@ -254,7 +254,7 @@ void MojoRenderer::OnError(const Status& status) { DCHECK(!init_cb_); encountered_error_ = true; - base::Optional<PipelineStatus> pipeline_status = + absl::optional<PipelineStatus> pipeline_status = StatusCodeToPipelineStatus(status.code()); // If an unexpected status code is encountered default diff --git a/chromium/media/mojo/clients/mojo_renderer.h b/chromium/media/mojo/clients/mojo_renderer.h index 50354d88b73..096f6e24e66 100644 --- a/chromium/media/mojo/clients/mojo_renderer.h +++ b/chromium/media/mojo/clients/mojo_renderer.h @@ -11,7 +11,6 @@ #include <vector> #include "base/macros.h" -#include "base/optional.h" #include "base/time/default_tick_clock.h" #include "base/unguessable_token.h" #include "media/base/demuxer_stream.h" @@ -21,6 +20,7 @@ #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class SingleThreadTaskRunner; @@ -56,7 +56,7 @@ class MojoRenderer : public Renderer, public mojom::RendererClient { media::RendererClient* client, PipelineStatusCallback init_cb) override; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void Flush(base::OnceClosure flush_cb) override; void StartPlayingFrom(base::TimeDelta time) override; void SetPlaybackRate(double playback_rate) override; @@ -158,7 +158,7 @@ class MojoRenderer : public Renderer, public mojom::RendererClient { mutable base::Lock lock_; media::TimeDeltaInterpolator media_time_interpolator_; - base::Optional<PipelineStatistics> pending_stats_; + absl::optional<PipelineStatistics> pending_stats_; DISALLOW_COPY_AND_ASSIGN(MojoRenderer); }; diff --git a/chromium/media/mojo/clients/mojo_renderer_wrapper.cc b/chromium/media/mojo/clients/mojo_renderer_wrapper.cc index 2971244b9fa..0bf3197a414 100644 --- a/chromium/media/mojo/clients/mojo_renderer_wrapper.cc +++ b/chromium/media/mojo/clients/mojo_renderer_wrapper.cc @@ -42,7 +42,7 @@ void MojoRendererWrapper::SetCdm(CdmContext* cdm_context, } void MojoRendererWrapper::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { mojo_renderer_->SetLatencyHint(latency_hint); } diff --git a/chromium/media/mojo/clients/mojo_renderer_wrapper.h b/chromium/media/mojo/clients/mojo_renderer_wrapper.h index 891b4ff0de7..23fbb053d08 100644 --- a/chromium/media/mojo/clients/mojo_renderer_wrapper.h +++ b/chromium/media/mojo/clients/mojo_renderer_wrapper.h @@ -27,7 +27,7 @@ class MojoRendererWrapper : public Renderer { RendererClient* client, PipelineStatusCallback init_cb) override; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void Flush(base::OnceClosure flush_cb) override; void StartPlayingFrom(base::TimeDelta time) override; void SetPlaybackRate(double playback_rate) override; diff --git a/chromium/media/mojo/clients/mojo_video_decoder.cc b/chromium/media/mojo/clients/mojo_video_decoder.cc index 23c3bc5d7c1..d516b23b432 100644 --- a/chromium/media/mojo/clients/mojo_video_decoder.cc +++ b/chromium/media/mojo/clients/mojo_video_decoder.cc @@ -169,8 +169,8 @@ void MojoVideoDecoder::Initialize(const VideoDecoderConfig& config, return; } - base::Optional<base::UnguessableToken> cdm_id = - cdm_context ? cdm_context->GetCdmId() : base::nullopt; + absl::optional<base::UnguessableToken> cdm_id = + cdm_context ? cdm_context->GetCdmId() : absl::nullopt; // Fail immediately if the stream is encrypted but |cdm_id| is invalid. // This check is needed to avoid unnecessary IPC to the remote process. @@ -255,7 +255,7 @@ void MojoVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, void MojoVideoDecoder::OnVideoFrameDecoded( const scoped_refptr<VideoFrame>& frame, bool can_read_without_stalling, - const base::Optional<base::UnguessableToken>& release_token) { + const absl::optional<base::UnguessableToken>& release_token) { DVLOG(3) << __func__; DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); diff --git a/chromium/media/mojo/clients/mojo_video_decoder.h b/chromium/media/mojo/clients/mojo_video_decoder.h index 1d85f48837d..cd486c3dd1d 100644 --- a/chromium/media/mojo/clients/mojo_video_decoder.h +++ b/chromium/media/mojo/clients/mojo_video_decoder.h @@ -80,7 +80,7 @@ class MojoVideoDecoder final : public VideoDecoder, void OnVideoFrameDecoded( const scoped_refptr<VideoFrame>& frame, bool can_read_without_stalling, - const base::Optional<base::UnguessableToken>& release_token) final; + const absl::optional<base::UnguessableToken>& release_token) final; void OnWaiting(WaitingReason reason) final; void RequestOverlayInfo(bool restart_for_transitions) final; diff --git a/chromium/media/mojo/clients/mojo_video_encode_accelerator_unittest.cc b/chromium/media/mojo/clients/mojo_video_encode_accelerator_unittest.cc index e2fbe73d745..9eda59e756f 100644 --- a/chromium/media/mojo/clients/mojo_video_encode_accelerator_unittest.cc +++ b/chromium/media/mojo/clients/mojo_video_encode_accelerator_unittest.cc @@ -4,6 +4,9 @@ #include <stddef.h> +#include <memory> + +#include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/test/task_environment.h" #include "gpu/config/gpu_info.h" @@ -146,9 +149,10 @@ class MojoVideoEncodeAcceleratorTest : public ::testing::Test { std::make_unique<MockMojoVideoEncodeAccelerator>(), mojo_vea.InitWithNewPipeAndPassReceiver()); - mojo_vea_.reset(new MojoVideoEncodeAccelerator( - std::move(mojo_vea), - media::VideoEncodeAccelerator::SupportedProfiles())); + mojo_vea_ = + base::WrapUnique<VideoEncodeAccelerator>(new MojoVideoEncodeAccelerator( + std::move(mojo_vea), + media::VideoEncodeAccelerator::SupportedProfiles())); } void TearDown() override { @@ -184,7 +188,7 @@ class MojoVideoEncodeAcceleratorTest : public ::testing::Test { const VideoEncodeAccelerator::Config config( PIXEL_FORMAT_I420, kInputVisibleSize, kOutputProfile, kInitialBitrate, - base::nullopt, base::nullopt, base::nullopt, false, base::nullopt, + absl::nullopt, absl::nullopt, absl::nullopt, false, absl::nullopt, kContentType); EXPECT_TRUE(mojo_vea()->Initialize(config, mock_vea_client)); base::RunLoop().RunUntilIdle(); diff --git a/chromium/media/mojo/clients/win/media_foundation_renderer_client.cc b/chromium/media/mojo/clients/win/media_foundation_renderer_client.cc index 66ef3880041..e2f85301a60 100644 --- a/chromium/media/mojo/clients/win/media_foundation_renderer_client.cc +++ b/chromium/media/mojo/clients/win/media_foundation_renderer_client.cc @@ -282,7 +282,7 @@ void MediaFoundationRendererClient::SetCdm(CdmContext* cdm_context, } void MediaFoundationRendererClient::SetLatencyHint( - base::Optional<base::TimeDelta> /*latency_hint*/) { + absl::optional<base::TimeDelta> /*latency_hint*/) { // We do not use the latency hint today } @@ -377,7 +377,7 @@ void MediaFoundationRendererClient::OnVideoOpacityChange(bool opaque) { } void MediaFoundationRendererClient::OnVideoFrameRateChange( - base::Optional<int> fps) { + absl::optional<int> fps) { DVLOG_FUNC(1) << "fps=" << (fps ? *fps : -1); DCHECK(has_video_); client_->OnVideoFrameRateChange(fps); diff --git a/chromium/media/mojo/clients/win/media_foundation_renderer_client.h b/chromium/media/mojo/clients/win/media_foundation_renderer_client.h index f9afedaa4f7..c4b655b30b3 100644 --- a/chromium/media/mojo/clients/win/media_foundation_renderer_client.h +++ b/chromium/media/mojo/clients/win/media_foundation_renderer_client.h @@ -56,7 +56,7 @@ class MediaFoundationRendererClient RendererClient* client, PipelineStatusCallback init_cb) override; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void Flush(base::OnceClosure flush_cb) override; void StartPlayingFrom(base::TimeDelta time) override; void SetPlaybackRate(double playback_rate) override; @@ -77,7 +77,7 @@ class MediaFoundationRendererClient void OnVideoConfigChange(const media::VideoDecoderConfig& config) override; void OnVideoNaturalSizeChange(const gfx::Size& size) override; void OnVideoOpacityChange(bool opaque) override; - void OnVideoFrameRateChange(base::Optional<int>) override; + void OnVideoFrameRateChange(absl::optional<int>) override; // media::VideoRendererSink::RenderCallback implementation. scoped_refptr<media::VideoFrame> Render( diff --git a/chromium/media/mojo/common/BUILD.gn b/chromium/media/mojo/common/BUILD.gn index 8d33e8dc97c..a570c550931 100644 --- a/chromium/media/mojo/common/BUILD.gn +++ b/chromium/media/mojo/common/BUILD.gn @@ -6,6 +6,8 @@ source_set("common") { sources = [ "audio_data_s16_converter.cc", "audio_data_s16_converter.h", + "input_error_code_converter.cc", + "input_error_code_converter.h", "media_type_converters.cc", "media_type_converters.h", "mojo_data_pipe_read_write.cc", @@ -19,7 +21,7 @@ source_set("common") { deps = [ ":mojo_shared_buffer_video_frame", "//base", - "//gpu/ipc/common:mojom_traits", + "//gpu/ipc/common", "//media", "//media/mojo/mojom", "//mojo/public/cpp/bindings", diff --git a/chromium/media/mojo/common/input_error_code_converter.cc b/chromium/media/mojo/common/input_error_code_converter.cc new file mode 100644 index 00000000000..3829bb7cbc3 --- /dev/null +++ b/chromium/media/mojo/common/input_error_code_converter.cc @@ -0,0 +1,18 @@ +// Copyright 2021 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/mojo/common/input_error_code_converter.h" + +namespace media { +AudioCapturerSource::ErrorCode ConvertToCaptureCallbackCode( + mojom::InputStreamErrorCode code) { + switch (code) { + case mojom::InputStreamErrorCode::kSystemPermissions: + return AudioCapturerSource::ErrorCode::kSystemPermissions; + case mojom::InputStreamErrorCode::kUnknown: + break; + } + return AudioCapturerSource::ErrorCode::kUnknown; +} +} // namespace media diff --git a/chromium/media/mojo/common/input_error_code_converter.h b/chromium/media/mojo/common/input_error_code_converter.h new file mode 100644 index 00000000000..99a1f0b1059 --- /dev/null +++ b/chromium/media/mojo/common/input_error_code_converter.h @@ -0,0 +1,16 @@ +// Copyright 2021 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. + +#ifndef MEDIA_MOJO_COMMON_INPUT_ERROR_CODE_CONVERTER_H_ +#define MEDIA_MOJO_COMMON_INPUT_ERROR_CODE_CONVERTER_H_ + +#include "media/base/audio_capturer_source.h" +#include "media/mojo/mojom/media_types.mojom.h" + +namespace media { +AudioCapturerSource::ErrorCode ConvertToCaptureCallbackCode( + mojom::InputStreamErrorCode code); +} + +#endif diff --git a/chromium/media/mojo/common/mojo_data_pipe_read_write.h b/chromium/media/mojo/common/mojo_data_pipe_read_write.h index 85b767c08a7..553d356b461 100644 --- a/chromium/media/mojo/common/mojo_data_pipe_read_write.h +++ b/chromium/media/mojo/common/mojo_data_pipe_read_write.h @@ -5,8 +5,6 @@ #ifndef MEDIA_MOJO_COMMON_MOJO_DATA_PIPE_READ_WRITE_H_ #define MEDIA_MOJO_COMMON_MOJO_DATA_PIPE_READ_WRITE_H_ -#include <memory> - #include "base/macros.h" #include "base/memory/ref_counted.h" #include "mojo/public/cpp/system/data_pipe.h" diff --git a/chromium/media/mojo/common/mojo_decoder_buffer_converter.h b/chromium/media/mojo/common/mojo_decoder_buffer_converter.h index 7c8ca3d99e7..c1ea6eeb892 100644 --- a/chromium/media/mojo/common/mojo_decoder_buffer_converter.h +++ b/chromium/media/mojo/common/mojo_decoder_buffer_converter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_MOJO_COMMON_MOJO_DECODER_BUFFER_CONVERTER_ -#define MEDIA_MOJO_COMMON_MOJO_DECODER_BUFFER_CONVERTER_ +#ifndef MEDIA_MOJO_COMMON_MOJO_DECODER_BUFFER_CONVERTER_H_ +#define MEDIA_MOJO_COMMON_MOJO_DECODER_BUFFER_CONVERTER_H_ #include <memory> @@ -156,4 +156,4 @@ class MojoDecoderBufferWriter { } // namespace media -#endif // MEDIA_MOJO_COMMON_MOJO_DECODER_BUFFER_CONVERTER_ +#endif // MEDIA_MOJO_COMMON_MOJO_DECODER_BUFFER_CONVERTER_H_ diff --git a/chromium/media/mojo/mojom/BUILD.gn b/chromium/media/mojo/mojom/BUILD.gn index 341e26de457..2caa8635a66 100644 --- a/chromium/media/mojo/mojom/BUILD.gn +++ b/chromium/media/mojo/mojom/BUILD.gn @@ -18,6 +18,7 @@ mojom("mojom") { "audio_output_stream.mojom", "audio_parameters.mojom", "audio_stream_factory.mojom", + "capture_handle.mojom", "cdm_service.mojom", "cdm_storage.mojom", "content_decryption_module.mojom", @@ -536,6 +537,17 @@ mojom("mojom") { "//ui/gfx/geometry/mojom", ] }, + { + types = [ + { + mojom = "media.mojom.CdmCapability" + cpp = "::media::CdmCapability" + }, + ] + traits_headers = [ "cdm_capability_mojom_traits.h" ] + traits_sources = [ "cdm_capability_mojom_traits.cc" ] + traits_public_deps = [ "//media" ] + }, ] cpp_typemaps += shared_typemaps @@ -554,8 +566,7 @@ source_set("shared_mojom_traits") { public_deps = [ ":mojom_shared", - "//gpu/ipc/common:common", - "//gpu/ipc/common:mojom_traits", + "//gpu/ipc/common", "//media", "//media/base/ipc:ipc", "//mojo/public/mojom/base", diff --git a/chromium/media/mojo/mojom/audio_input_stream.mojom b/chromium/media/mojo/mojom/audio_input_stream.mojom index f77ac9dde6f..9f48a3aab08 100644 --- a/chromium/media/mojo/mojom/audio_input_stream.mojom +++ b/chromium/media/mojo/mojom/audio_input_stream.mojom @@ -21,7 +21,7 @@ interface AudioInputStream { // An interface for receiving notifications of state changes of an // AudioInputStream. interface AudioInputStreamClient { - OnError(); + OnError(InputStreamErrorCode code); OnMutedStateChanged(bool is_muted); }; @@ -42,6 +42,7 @@ interface AudioInputStreamObserver { kTerminatedByClient = 2, kStreamCreationFailed = 3, kDocumentDestroyed = 4, + kSystemPermissions = 5, }; // It will be called only once when input stream starts recording. diff --git a/chromium/media/mojo/mojom/capture_handle.mojom b/chromium/media/mojo/mojom/capture_handle.mojom new file mode 100644 index 00000000000..7dc157bd82d --- /dev/null +++ b/chromium/media/mojo/mojom/capture_handle.mojom @@ -0,0 +1,13 @@ +// Copyright 2021 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. + +module media.mojom; + +import "mojo/public/mojom/base/string16.mojom"; +import "url/mojom/origin.mojom"; + +struct CaptureHandle { + url.mojom.Origin origin; + mojo_base.mojom.String16 capture_handle; +}; diff --git a/chromium/media/mojo/mojom/cdm_capability_mojom_traits.cc b/chromium/media/mojo/mojom/cdm_capability_mojom_traits.cc new file mode 100644 index 00000000000..f72a0d32b7e --- /dev/null +++ b/chromium/media/mojo/mojom/cdm_capability_mojom_traits.cc @@ -0,0 +1,39 @@ +// Copyright 2021 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/mojo/mojom/cdm_capability_mojom_traits.h" + +#include <utility> + +namespace mojo { + +// static +bool StructTraits<media::mojom::CdmCapabilityDataView, media::CdmCapability>:: + Read(media::mojom::CdmCapabilityDataView input, + media::CdmCapability* output) { + std::vector<media::AudioCodec> audio_codecs; + if (!input.ReadAudioCodecs(&audio_codecs)) + return false; + + std::vector<media::VideoCodec> video_codecs; + if (!input.ReadVideoCodecs(&video_codecs)) + return false; + + std::vector<media::EncryptionScheme> encryption_schemes; + if (!input.ReadEncryptionSchemes(&encryption_schemes)) + return false; + + std::vector<media::CdmSessionType> session_types; + if (!input.ReadSessionTypes(&session_types)) + return false; + + // |encryption_schemes| and |session_types| are convert to a base::flat_map + // implicitly. + *output = media::CdmCapability( + std::move(audio_codecs), std::move(video_codecs), + std::move(encryption_schemes), std::move(session_types)); + return true; +} + +} // namespace mojo diff --git a/chromium/media/mojo/mojom/cdm_capability_mojom_traits.h b/chromium/media/mojo/mojom/cdm_capability_mojom_traits.h new file mode 100644 index 00000000000..178b17a7863 --- /dev/null +++ b/chromium/media/mojo/mojom/cdm_capability_mojom_traits.h @@ -0,0 +1,50 @@ +// Copyright 2021 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. + +#ifndef MEDIA_MOJO_MOJOM_CDM_CAPABILITY_MOJOM_TRAITS_H_ +#define MEDIA_MOJO_MOJOM_CDM_CAPABILITY_MOJOM_TRAITS_H_ + +#include <vector> + +#include "base/containers/flat_set.h" +#include "media/base/audio_codecs.h" +#include "media/base/content_decryption_module.h" +#include "media/base/encryption_scheme.h" +#include "media/base/video_codecs.h" +#include "media/cdm/cdm_capability.h" +#include "media/mojo/mojom/key_system_support.mojom.h" + +namespace mojo { + +template <> +struct StructTraits<media::mojom::CdmCapabilityDataView, media::CdmCapability> { + static const std::vector<media::AudioCodec>& audio_codecs( + const media::CdmCapability& input) { + return input.audio_codecs; + } + + static const std::vector<media::VideoCodec>& video_codecs( + const media::CdmCapability& input) { + return input.video_codecs; + } + + // List of encryption schemes supported by the CDM (e.g. cenc). + static const base::flat_set<media::EncryptionScheme>& encryption_schemes( + const media::CdmCapability& input) { + return input.encryption_schemes; + } + + // List of session types supported by the CDM. + static const base::flat_set<media::CdmSessionType>& session_types( + const media::CdmCapability& input) { + return input.session_types; + } + + static bool Read(media::mojom::CdmCapabilityDataView input, + media::CdmCapability* output); +}; + +} // namespace mojo + +#endif // MEDIA_MOJO_MOJOM_CDM_CAPABILITY_MOJOM_TRAITS_H_ diff --git a/chromium/media/mojo/mojom/display_media_information.mojom b/chromium/media/mojo/mojom/display_media_information.mojom index ad441305339..387d8cb8a96 100644 --- a/chromium/media/mojo/mojom/display_media_information.mojom +++ b/chromium/media/mojo/mojom/display_media_information.mojom @@ -4,6 +4,8 @@ module media.mojom; +import "media/mojo/mojom/capture_handle.mojom"; + // Mojo equivalent to media::DisplayMediaInformation. See also // media/base/display_media_information.h @@ -24,4 +26,5 @@ struct DisplayMediaInformation { DisplayCaptureSurfaceType display_surface; bool logical_surface; CursorCaptureType cursor; + CaptureHandle? capture_handle; }; diff --git a/chromium/media/mojo/mojom/key_system_support.mojom b/chromium/media/mojo/mojom/key_system_support.mojom index ce6267224bd..371c259a7f4 100644 --- a/chromium/media/mojo/mojom/key_system_support.mojom +++ b/chromium/media/mojo/mojom/key_system_support.mojom @@ -10,20 +10,19 @@ import "media/mojo/mojom/media_types.mojom"; // TODO(xhwang): Use "set" instead of "array" if supported by mojom. // TODO(crbug.com/796725) Find a way to include profiles and levels for // supported codecs. -struct KeySystemCapability { - // Software secure codecs and encryption schemes supported by the CDM. +struct CdmCapability { + array<AudioCodec> audio_codecs; array<VideoCodec> video_codecs; array<EncryptionScheme> encryption_schemes; - - // Hardware secure codecs and encryption schemes supported by the CDM. - array<VideoCodec> hw_secure_video_codecs; - array<EncryptionScheme> hw_secure_encryption_schemes; - - // Session types supported in software secure mode if no - // |hw_secure_video_codecs| is supported, or in both modes otherwise. array<CdmSessionType> session_types; }; +struct KeySystemCapability { + CdmCapability? sw_secure_capability; + CdmCapability? hw_secure_capability; +}; + +// Used to query the browser to see if a specific key system is supported. interface KeySystemSupport { // Query to determine if the browser supports the |key_system|. If supported, // |key_system_capability| is non-null indicating supported capability. diff --git a/chromium/media/mojo/mojom/media_types.mojom b/chromium/media/mojo/mojom/media_types.mojom index 1db4788ed02..f9d24e84613 100644 --- a/chromium/media/mojo/mojom/media_types.mojom +++ b/chromium/media/mojo/mojom/media_types.mojom @@ -471,3 +471,10 @@ enum MediaStreamType { kRemote = 5, // The source is a remote peer connection. kNone = 6, // Not a media stream. }; + +// Error codes propagated by Input media streams OnError methods to indicate the +// reason for an error. +enum InputStreamErrorCode { + kUnknown = 0, + kSystemPermissions = 1, +}; diff --git a/chromium/media/mojo/mojom/output_protection.mojom b/chromium/media/mojo/mojom/output_protection.mojom index 87dc10d37bf..0d09055e9c7 100644 --- a/chromium/media/mojo/mojom/output_protection.mojom +++ b/chromium/media/mojo/mojom/output_protection.mojom @@ -8,14 +8,16 @@ module media.mojom; // on links that support it. interface OutputProtection { + [Stable, Extensible] enum ProtectionType { - NONE = 0, + [Default] NONE = 0, HDCP = 1, }; // Video output link types. + [Stable, Extensible] enum LinkType { - NONE = 0, + [Default] NONE = 0, UNKNOWN = 1, INTERNAL = 2, VGA = 4, diff --git a/chromium/media/mojo/mojom/pipeline_status_mojom_traits.h b/chromium/media/mojo/mojom/pipeline_status_mojom_traits.h index d2893e209d9..220323d75ce 100644 --- a/chromium/media/mojo/mojom/pipeline_status_mojom_traits.h +++ b/chromium/media/mojo/mojom/pipeline_status_mojom_traits.h @@ -5,8 +5,6 @@ #ifndef MEDIA_MOJO_MOJOM_PIPELINE_STATUS_MOJOM_TRAITS_H_ #define MEDIA_MOJO_MOJOM_PIPELINE_STATUS_MOJOM_TRAITS_H_ -#include <string> - #include "media/base/pipeline_status.h" #include "media/mojo/mojom/media_types.mojom.h" diff --git a/chromium/media/mojo/mojom/platform_verification.mojom b/chromium/media/mojo/mojom/platform_verification.mojom index c96c33bb887..c3cf5b7ab5f 100644 --- a/chromium/media/mojo/mojom/platform_verification.mojom +++ b/chromium/media/mojo/mojom/platform_verification.mojom @@ -33,6 +33,6 @@ interface PlatformVerification { GetStorageId(uint32 version) => (uint32 version, array<uint8> storage_id); // Returns true if Verified Access is enabled in settings, false otherwise. - [EnableIf=is_chromeos] + [EnableIf=is_chromeos_ash] IsVerifiedAccessEnabled() => (bool enabled); }; diff --git a/chromium/media/mojo/mojom/speech_recognition_service.mojom b/chromium/media/mojo/mojom/speech_recognition_service.mojom index ab4d55221b5..55cf313f7c7 100644 --- a/chromium/media/mojo/mojom/speech_recognition_service.mojom +++ b/chromium/media/mojo/mojom/speech_recognition_service.mojom @@ -30,7 +30,8 @@ interface SpeechRecognitionContext { // indicating whether multichannel audio is supported by the speech // recognition service. BindRecognizer(pending_receiver<SpeechRecognitionRecognizer> receiver, - pending_remote<SpeechRecognitionRecognizerClient> client) + pending_remote<SpeechRecognitionRecognizerClient> client, + SpeechRecognitionOptions options) => (bool is_multichannel_supported); // Prepares microphone audio to be captured from within the @@ -38,7 +39,8 @@ interface SpeechRecognitionContext { // SpeechRecognitionRecognizerClient. BindAudioSourceFetcher( pending_receiver<AudioSourceFetcher> fetcher_receiver, - pending_remote<SpeechRecognitionRecognizerClient> client) + pending_remote<SpeechRecognitionRecognizerClient> client, + SpeechRecognitionOptions options) => (bool is_multichannel_supported); }; @@ -94,26 +96,21 @@ interface SpeechRecognitionRecognizer { // to the originating media. SendAudioToSpeechRecognitionService(AudioDataS16 buffer); - // Notify the speech recognition recognizer that the caption bubble was - // closed. Used to determine whether the caption bubble was visible when - // recording watch time. - OnCaptionBubbleClosed(); - - // Notify the speech recognition recognizer that audio was received by the - // renderer after the caption bubble was closed. - AudioReceivedAfterBubbleClosed(mojo_base.mojom.TimeDelta duration); - // Notify the speech recognition recognizer that the language changed. Takes // in the locale string (e.g. "en-US"). OnLanguageChanged(string language); }; // The interface used to return speech recognition events from the speech -// recognition service back to the originating media. The remote lives in the -// speech recognition process and the receiver lives in the renderer process. +// recognition service to the client that will display the results to the user. +// The remote lives in the speech recognition process and the receiver lives in +// the browser process. interface SpeechRecognitionRecognizerClient { // Triggered by speech recognition process on a speech recognition event. - OnSpeechRecognitionRecognitionEvent(SpeechRecognitionResult result); + // Returns whether the result was received successfully. Speech recognition + // will halt if this returns false. + OnSpeechRecognitionRecognitionEvent(SpeechRecognitionResult result) + => (bool success); // Triggered by an error within the speech recognition service. OnSpeechRecognitionError(); @@ -123,7 +120,7 @@ interface SpeechRecognitionRecognizerClient { }; // A speech recognition result created by the speech service and passed to the -// renderer. +// browser. struct SpeechRecognitionResult { string transcription; @@ -164,3 +161,23 @@ interface SpeechRecognitionClientBrowserInterface { BindSpeechRecognitionBrowserObserver( pending_remote<SpeechRecognitionBrowserObserver> observer); }; + +// Corresponds to ExtendedSodaConfigMsg in +// chrome/services/speech/soda/proto/soda_api.proto. +enum SpeechRecognitionMode { + kUnknown, + // Intended for voice input for keyboard usage. + kIme, + // Intended to caption a stream of audio. + kCaption, +}; + +// Options for speech recognition. +// TODO(crbug.com/1195916): Add language identifier. +// TODO(crbug.com/1165437): Add option to include timing metrics in the result. +struct SpeechRecognitionOptions { + // What kind of recognition to use. + // In the case of web fallback (not for launch, used for development only), + // this option will be ignored. + SpeechRecognitionMode recognition_mode; +}; diff --git a/chromium/media/mojo/mojom/status_mojom_traits.cc b/chromium/media/mojo/mojom/status_mojom_traits.cc index 9efb4af6e57..639e8462643 100644 --- a/chromium/media/mojo/mojom/status_mojom_traits.cc +++ b/chromium/media/mojo/mojom/status_mojom_traits.cc @@ -24,7 +24,7 @@ bool StructTraits<media::mojom::StatusDataView, media::Status>::Read( if (media::StatusCode::kOk == code) return true; - base::Optional<std::string> optional_message; + absl::optional<std::string> optional_message; if (!data.ReadMessage(&optional_message)) return false; message = std::move(optional_message).value_or(std::string()); @@ -38,7 +38,7 @@ bool StructTraits<media::mojom::StatusDataView, media::Status>::Read( if (!data.ReadCauses(&output->data_->causes)) return false; - base::Optional<base::Value> optional_data; + absl::optional<base::Value> optional_data; if (!data.ReadData(&optional_data)) return false; output->data_->data = std::move(optional_data).value_or(base::Value()); diff --git a/chromium/media/mojo/mojom/status_mojom_traits.h b/chromium/media/mojo/mojom/status_mojom_traits.h index 03eb5ab36ed..8896ea76130 100644 --- a/chromium/media/mojo/mojom/status_mojom_traits.h +++ b/chromium/media/mojo/mojom/status_mojom_traits.h @@ -6,11 +6,11 @@ #define MEDIA_MOJO_MOJOM_STATUS_MOJOM_TRAITS_H_ #include "base/containers/span.h" -#include "base/optional.h" #include "base/values.h" #include "media/base/ipc/media_param_traits.h" #include "media/base/status.h" #include "media/mojo/mojom/media_types.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace mojo { @@ -20,9 +20,9 @@ struct StructTraits<media::mojom::StatusDataView, media::Status> { return input.code(); } - static base::Optional<std::string> message(const media::Status& input) { + static absl::optional<std::string> message(const media::Status& input) { if (input.is_ok()) - return base::nullopt; + return absl::nullopt; DCHECK(input.data_); return input.message(); } @@ -41,12 +41,12 @@ struct StructTraits<media::mojom::StatusDataView, media::Status> { return input.data_->causes; } - static base::Optional<base::Value> data(const media::Status& input) { + static absl::optional<base::Value> data(const media::Status& input) { if (!input.is_ok()) { DCHECK(input.data_); return input.data_->data.Clone(); } - return base::nullopt; + return absl::nullopt; } static bool Read(media::mojom::StatusDataView data, media::Status* output); diff --git a/chromium/media/mojo/mojom/video_decoder_config_mojom_traits.cc b/chromium/media/mojo/mojom/video_decoder_config_mojom_traits.cc index 4699902207f..f968638da35 100644 --- a/chromium/media/mojo/mojom/video_decoder_config_mojom_traits.cc +++ b/chromium/media/mojo/mojom/video_decoder_config_mojom_traits.cc @@ -47,7 +47,7 @@ bool StructTraits<media::mojom::VideoDecoderConfigDataView, if (!input.ReadColorSpaceInfo(&color_space)) return false; - base::Optional<gfx::HDRMetadata> hdr_metadata; + absl::optional<gfx::HDRMetadata> hdr_metadata; if (!input.ReadHdrMetadata(&hdr_metadata)) return false; diff --git a/chromium/media/mojo/mojom/video_decoder_config_mojom_traits.h b/chromium/media/mojo/mojom/video_decoder_config_mojom_traits.h index f89cfcc2f87..19a0d2f61a1 100644 --- a/chromium/media/mojo/mojom/video_decoder_config_mojom_traits.h +++ b/chromium/media/mojo/mojom/video_decoder_config_mojom_traits.h @@ -64,7 +64,7 @@ struct StructTraits<media::mojom::VideoDecoderConfigDataView, return input.video_transformation(); } - static const base::Optional<gfx::HDRMetadata>& hdr_metadata( + static const absl::optional<gfx::HDRMetadata>& hdr_metadata( const media::VideoDecoderConfig& input) { return input.hdr_metadata(); } diff --git a/chromium/media/mojo/mojom/video_encode_accelerator.mojom b/chromium/media/mojo/mojom/video_encode_accelerator.mojom index 3516920dd39..82cf95f9a6a 100644 --- a/chromium/media/mojo/mojom/video_encode_accelerator.mojom +++ b/chromium/media/mojo/mojom/video_encode_accelerator.mojom @@ -101,6 +101,7 @@ struct VideoEncodeAcceleratorConfig { bool has_storage_type; // Whether or not config has storage type config ContentType content_type; array<SpatialLayer> spatial_layers; + bool require_low_delay; }; interface VideoEncodeAccelerator { diff --git a/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits.cc b/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits.cc index df744f70048..506a38e71f7 100644 --- a/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits.cc +++ b/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits.cc @@ -5,10 +5,10 @@ #include "media/mojo/mojom/video_encode_accelerator_mojom_traits.h" #include "base/notreached.h" -#include "base/optional.h" #include "media/base/video_bitrate_allocation.h" #include "media/mojo/mojom/video_encode_accelerator.mojom.h" #include "mojo/public/cpp/base/time_mojom_traits.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace mojo { @@ -258,21 +258,21 @@ bool StructTraits<media::mojom::VideoEncodeAcceleratorConfigDataView, if (!input.ReadOutputProfile(&output_profile)) return false; - base::Optional<uint32_t> initial_framerate; + absl::optional<uint32_t> initial_framerate; if (input.has_initial_framerate()) initial_framerate = input.initial_framerate(); - base::Optional<uint32_t> gop_length; + absl::optional<uint32_t> gop_length; if (input.has_gop_length()) gop_length = input.gop_length(); - base::Optional<uint8_t> h264_output_level; + absl::optional<uint8_t> h264_output_level; if (input.has_h264_output_level()) h264_output_level = input.h264_output_level(); bool is_constrained_h264 = input.is_constrained_h264(); - base::Optional<media::VideoEncodeAccelerator::Config::StorageType> + absl::optional<media::VideoEncodeAccelerator::Config::StorageType> storage_type; if (input.has_storage_type()) { if (!input.ReadStorageType(&storage_type)) @@ -292,6 +292,8 @@ bool StructTraits<media::mojom::VideoEncodeAcceleratorConfigDataView, input_format, input_visible_size, output_profile, input.initial_bitrate(), initial_framerate, gop_length, h264_output_level, is_constrained_h264, storage_type, content_type, spatial_layers); + + output->require_low_delay = input.require_low_delay(); return true; } diff --git a/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits.h b/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits.h index 569b7f912a3..7cc9dc720d0 100644 --- a/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits.h +++ b/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits.h @@ -304,6 +304,11 @@ struct StructTraits<media::mojom::VideoEncodeAcceleratorConfigDataView, return input.spatial_layers; } + static bool require_low_delay( + const media::VideoEncodeAccelerator::Config& input) { + return input.require_low_delay; + } + static bool Read(media::mojom::VideoEncodeAcceleratorConfigDataView input, media::VideoEncodeAccelerator::Config* output); }; diff --git a/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc b/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc index 15d59d1d76a..57dc0256efb 100644 --- a/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc +++ b/chromium/media/mojo/mojom/video_encode_accelerator_mojom_traits_unittest.cc @@ -67,7 +67,7 @@ TEST(VideoEncodeAcceleratorConfigStructTraitTest, RoundTrip) { } ::media::VideoEncodeAccelerator::Config input_config( ::media::PIXEL_FORMAT_NV12, kBaseSize, ::media::VP9PROFILE_PROFILE0, - kBaseBitrateBps, kBaseFramerate, base::nullopt, base::nullopt, false, + kBaseBitrateBps, kBaseFramerate, absl::nullopt, absl::nullopt, false, ::media::VideoEncodeAccelerator::Config::StorageType::kGpuMemoryBuffer, ::media::VideoEncodeAccelerator::Config::ContentType::kCamera, input_spatial_layers); diff --git a/chromium/media/mojo/mojom/video_frame_metadata_mojom_traits.cc b/chromium/media/mojo/mojom/video_frame_metadata_mojom_traits.cc index 0e77001b970..95666aaf226 100644 --- a/chromium/media/mojo/mojom/video_frame_metadata_mojom_traits.cc +++ b/chromium/media/mojo/mojom/video_frame_metadata_mojom_traits.cc @@ -14,13 +14,13 @@ namespace mojo { -// Deserializes has_field and field into a base::Optional. +// Deserializes has_field and field into a absl::optional. #define DESERIALIZE_INTO_OPT(field) \ if (input.has_##field()) \ output->field = input.field() #define READ_AND_ASSIGN_OPT(type, field, FieldInCamelCase) \ - base::Optional<type> field; \ + absl::optional<type> field; \ if (!input.Read##FieldInCamelCase(&field)) \ return false; \ \ diff --git a/chromium/media/mojo/mojom/video_frame_metadata_mojom_traits.h b/chromium/media/mojo/mojom/video_frame_metadata_mojom_traits.h index 06b7cf3ebc8..c545248edb1 100644 --- a/chromium/media/mojo/mojom/video_frame_metadata_mojom_traits.h +++ b/chromium/media/mojo/mojom/video_frame_metadata_mojom_traits.h @@ -6,7 +6,6 @@ #define MEDIA_MOJO_MOJOM_VIDEO_FRAME_METADATA_MOJOM_TRAITS_H_ #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "media/base/ipc/media_param_traits_macros.h" #include "media/base/video_frame_metadata.h" #include "media/base/video_transformation.h" @@ -14,11 +13,12 @@ #include "media/mojo/mojom/media_types_enum_mojom_traits.h" #include "media/mojo/mojom/video_transformation_mojom_traits.h" #include "mojo/public/cpp/bindings/struct_traits.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/mojom/geometry_mojom_traits.h" namespace mojo { -// Creates a has_foo() and a foo() to serialize a foo base::Optional<>. +// Creates a has_foo() and a foo() to serialize a foo absl::optional<>. #define GENERATE_OPT_SERIALIZATION(type, field, default_value) \ static bool has_##field(const media::VideoFrameMetadata& input) { \ return input.field.has_value(); \ @@ -79,7 +79,7 @@ struct StructTraits<media::mojom::VideoFrameMetadataDataView, copy_mode, media::VideoFrameMetadata::CopyMode::kCopyToNewTexture) - static base::Optional<media::VideoTransformation> transformation( + static absl::optional<media::VideoTransformation> transformation( const media::VideoFrameMetadata& input) { return input.transformation; } @@ -92,57 +92,57 @@ struct StructTraits<media::mojom::VideoFrameMetadataDataView, GENERATE_OPT_SERIALIZATION(double, frame_rate, 0.0) GENERATE_OPT_SERIALIZATION(double, rtp_timestamp, 0.0) - static base::Optional<gfx::Rect> capture_update_rect( + static absl::optional<gfx::Rect> capture_update_rect( const media::VideoFrameMetadata& input) { return input.capture_update_rect; } - static base::Optional<base::UnguessableToken> overlay_plane_id( + static absl::optional<base::UnguessableToken> overlay_plane_id( const media::VideoFrameMetadata& input) { return input.overlay_plane_id; } - static base::Optional<base::TimeTicks> receive_time( + static absl::optional<base::TimeTicks> receive_time( const media::VideoFrameMetadata& input) { return input.receive_time; } - static base::Optional<base::TimeTicks> capture_begin_time( + static absl::optional<base::TimeTicks> capture_begin_time( const media::VideoFrameMetadata& input) { return input.capture_begin_time; } - static base::Optional<base::TimeTicks> capture_end_time( + static absl::optional<base::TimeTicks> capture_end_time( const media::VideoFrameMetadata& input) { return input.capture_end_time; } - static base::Optional<base::TimeTicks> decode_begin_time( + static absl::optional<base::TimeTicks> decode_begin_time( const media::VideoFrameMetadata& input) { return input.decode_begin_time; } - static base::Optional<base::TimeTicks> decode_end_time( + static absl::optional<base::TimeTicks> decode_end_time( const media::VideoFrameMetadata& input) { return input.decode_end_time; } - static base::Optional<base::TimeTicks> reference_time( + static absl::optional<base::TimeTicks> reference_time( const media::VideoFrameMetadata& input) { return input.reference_time; } - static base::Optional<base::TimeDelta> processing_time( + static absl::optional<base::TimeDelta> processing_time( const media::VideoFrameMetadata& input) { return input.processing_time; } - static base::Optional<base::TimeDelta> frame_duration( + static absl::optional<base::TimeDelta> frame_duration( const media::VideoFrameMetadata& input) { return input.frame_duration; } - static base::Optional<base::TimeDelta> wallclock_frame_duration( + static absl::optional<base::TimeDelta> wallclock_frame_duration( const media::VideoFrameMetadata& input) { return input.wallclock_frame_duration; } diff --git a/chromium/media/mojo/mojom/video_frame_mojom_traits.cc b/chromium/media/mojo/mojom/video_frame_mojom_traits.cc index 08ad8fc66ef..268def5e1c8 100644 --- a/chromium/media/mojo/mojom/video_frame_mojom_traits.cc +++ b/chromium/media/mojo/mojom/video_frame_mojom_traits.cc @@ -174,7 +174,7 @@ bool StructTraits<media::mojom::VideoFrameDataView, for (size_t i = 0; i < mailbox_holder.size(); i++) mailbox_holder_array[i] = mailbox_holder[i]; - base::Optional<gfx::BufferFormat> buffer_format = + absl::optional<gfx::BufferFormat> buffer_format = VideoPixelFormatToGfxBufferFormat(format); if (!buffer_format) return false; @@ -203,7 +203,7 @@ bool StructTraits<media::mojom::VideoFrameDataView, for (size_t i = 0; i < media::VideoFrame::kMaxPlanes; i++) mailbox_holder_array[i] = mailbox_holder[i]; - base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info; + absl::optional<gpu::VulkanYCbCrInfo> ycbcr_info; if (!mailbox_data.ReadYcbcrData(&ycbcr_info)) return false; @@ -231,7 +231,7 @@ bool StructTraits<media::mojom::VideoFrameDataView, return false; frame->set_color_space(color_space); - base::Optional<gfx::HDRMetadata> hdr_metadata; + absl::optional<gfx::HDRMetadata> hdr_metadata; if (!input.ReadHdrMetadata(&hdr_metadata)) return false; frame->set_hdr_metadata(std::move(hdr_metadata)); diff --git a/chromium/media/mojo/mojom/video_frame_mojom_traits.h b/chromium/media/mojo/mojom/video_frame_mojom_traits.h index 9071089bd2e..93c515276e5 100644 --- a/chromium/media/mojo/mojom/video_frame_mojom_traits.h +++ b/chromium/media/mojo/mojom/video_frame_mojom_traits.h @@ -6,14 +6,13 @@ #define MEDIA_MOJO_MOJOM_VIDEO_FRAME_MOJOM_TRAITS_H_ #include "base/memory/ref_counted.h" -#include "base/optional.h" -#include "base/values.h" #include "gpu/ipc/common/mailbox_holder_mojom_traits.h" #include "gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h" #include "media/base/ipc/media_param_traits_macros.h" #include "media/base/video_frame.h" #include "media/mojo/mojom/media_types.mojom.h" #include "mojo/public/cpp/bindings/struct_traits.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/mojom/geometry_mojom_traits.h" #include "ui/gfx/ipc/color/gfx_param_traits.h" @@ -62,12 +61,12 @@ struct StructTraits<media::mojom::VideoFrameDataView, return input->ColorSpace(); } - static const base::Optional<gfx::HDRMetadata>& hdr_metadata( + static const absl::optional<gfx::HDRMetadata>& hdr_metadata( const scoped_refptr<media::VideoFrame>& input) { return input->hdr_metadata(); } - static const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info( + static const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info( const scoped_refptr<media::VideoFrame>& input) { return input->ycbcr_info(); } diff --git a/chromium/media/mojo/services/BUILD.gn b/chromium/media/mojo/services/BUILD.gn index 3a87515b49c..2e80cb73ae4 100644 --- a/chromium/media/mojo/services/BUILD.gn +++ b/chromium/media/mojo/services/BUILD.gn @@ -123,16 +123,6 @@ component("services") { sources += [ "cdm_service.cc", "cdm_service.h", - "mojo_cdm_allocator.cc", - "mojo_cdm_allocator.h", - "mojo_cdm_file_io.cc", - "mojo_cdm_file_io.h", - "mojo_cdm_helper.cc", - "mojo_cdm_helper.h", - ] - deps += [ - "//media/cdm:cdm_api", - "//media/cdm:cdm_paths", ] # TODO(xhwang): Ideally media should not worry about sandbox. Find a way to @@ -142,6 +132,18 @@ component("services") { } } + if (is_win || enable_library_cdms) { + sources += [ + "mojo_cdm_allocator.cc", + "mojo_cdm_allocator.h", + "mojo_cdm_file_io.cc", + "mojo_cdm_file_io.h", + "mojo_cdm_helper.cc", + "mojo_cdm_helper.h", + ] + deps += [ "//media/cdm:cdm_api" ] + } + if (is_chromeos_ash) { deps += [ "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_gpu" ] diff --git a/chromium/media/mojo/services/gpu_mojo_media_client.cc b/chromium/media/mojo/services/gpu_mojo_media_client.cc index 49eb8786b5f..1a2f25bda04 100644 --- a/chromium/media/mojo/services/gpu_mojo_media_client.cc +++ b/chromium/media/mojo/services/gpu_mojo_media_client.cc @@ -238,9 +238,9 @@ std::unique_ptr<VideoDecoder> GpuMojoMediaClient::CreateVideoDecoder( auto get_stub_cb = base::BindRepeating( &GetCommandBufferStub, gpu_task_runner_, media_gpu_channel_manager_, command_buffer_id->channel_token, command_buffer_id->route_id); - std::unique_ptr<SharedImageVideoProvider> image_provider; - image_provider = std::make_unique<DirectSharedImageVideoProvider>( - gpu_task_runner_, get_stub_cb); + std::unique_ptr<SharedImageVideoProvider> image_provider = + std::make_unique<DirectSharedImageVideoProvider>(gpu_task_runner_, + get_stub_cb); if (base::FeatureList::IsEnabled(kUsePooledSharedImageVideoProvider)) { // Wrap |image_provider| in a pool. image_provider = PooledSharedImageVideoProvider::Create( diff --git a/chromium/media/mojo/services/gpu_mojo_media_client.h b/chromium/media/mojo/services/gpu_mojo_media_client.h index 667b43a0115..7e70788ba3d 100644 --- a/chromium/media/mojo/services/gpu_mojo_media_client.h +++ b/chromium/media/mojo/services/gpu_mojo_media_client.h @@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "build/build_config.h" #include "gpu/config/gpu_driver_bug_workarounds.h" @@ -20,6 +19,7 @@ #include "media/base/supported_video_decoder_config.h" #include "media/media_buildflags.h" #include "media/mojo/services/mojo_media_client.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace gpu { class GpuMemoryBufferFactory; @@ -67,10 +67,10 @@ class GpuMojoMediaClient final : public MojoMediaClient { #if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION) // Indirectly owned by GpuChildThread. gpu::GpuMemoryBufferFactory* const gpu_memory_buffer_factory_; - base::Optional<SupportedVideoDecoderConfigs> cros_supported_configs_; + absl::optional<SupportedVideoDecoderConfigs> cros_supported_configs_; #endif // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION) #if defined(OS_WIN) - base::Optional<SupportedVideoDecoderConfigs> d3d11_supported_configs_; + absl::optional<SupportedVideoDecoderConfigs> d3d11_supported_configs_; #endif // defined(OS_WIN) DISALLOW_COPY_AND_ASSIGN(GpuMojoMediaClient); diff --git a/chromium/media/mojo/services/media_foundation_mojo_media_client.cc b/chromium/media/mojo/services/media_foundation_mojo_media_client.cc index 27de9b14c14..98162339f0e 100644 --- a/chromium/media/mojo/services/media_foundation_mojo_media_client.cc +++ b/chromium/media/mojo/services/media_foundation_mojo_media_client.cc @@ -7,10 +7,13 @@ #include "media/base/win/mf_helpers.h" #include "media/cdm/win/media_foundation_cdm_factory.h" #include "media/mojo/services/media_foundation_renderer_wrapper.h" +#include "media/mojo/services/mojo_cdm_helper.h" namespace media { -MediaFoundationMojoMediaClient::MediaFoundationMojoMediaClient() { +MediaFoundationMojoMediaClient::MediaFoundationMojoMediaClient( + const base::FilePath& user_data_dir) + : user_data_dir_(user_data_dir) { DVLOG_FUNC(1); } @@ -32,7 +35,8 @@ MediaFoundationMojoMediaClient::CreateMediaFoundationRenderer( std::unique_ptr<CdmFactory> MediaFoundationMojoMediaClient::CreateCdmFactory( mojom::FrameInterfaceFactory* frame_interfaces) { DVLOG_FUNC(1); - return std::make_unique<MediaFoundationCdmFactory>(); + return std::make_unique<MediaFoundationCdmFactory>( + std::make_unique<MojoCdmHelper>(frame_interfaces), user_data_dir_); } } // namespace media diff --git a/chromium/media/mojo/services/media_foundation_mojo_media_client.h b/chromium/media/mojo/services/media_foundation_mojo_media_client.h index 45286fb39b1..a4b4b4dba83 100644 --- a/chromium/media/mojo/services/media_foundation_mojo_media_client.h +++ b/chromium/media/mojo/services/media_foundation_mojo_media_client.h @@ -5,6 +5,7 @@ #ifndef MEDIA_MOJO_SERVICES_MEDIA_FOUNDATION_MOJO_MEDIA_CLIENT_H_ #define MEDIA_MOJO_SERVICES_MEDIA_FOUNDATION_MOJO_MEDIA_CLIENT_H_ +#include "base/files/file_path.h" #include "base/macros.h" #include "base/single_thread_task_runner.h" #include "media/mojo/services/mojo_media_client.h" @@ -16,7 +17,7 @@ namespace media { // process hosting MediaFoundationRenderer and MediaFoundationCdm. class MediaFoundationMojoMediaClient : public MojoMediaClient { public: - MediaFoundationMojoMediaClient(); + explicit MediaFoundationMojoMediaClient(const base::FilePath& user_data_dir); ~MediaFoundationMojoMediaClient() final; // MojoMediaClient implementation. @@ -28,6 +29,7 @@ class MediaFoundationMojoMediaClient : public MojoMediaClient { mojom::FrameInterfaceFactory* frame_interfaces) final; private: + base::FilePath user_data_dir_; DISALLOW_COPY_AND_ASSIGN(MediaFoundationMojoMediaClient); }; diff --git a/chromium/media/mojo/services/media_foundation_renderer_wrapper.cc b/chromium/media/mojo/services/media_foundation_renderer_wrapper.cc index 21953a23dfe..58ec1770da4 100644 --- a/chromium/media/mojo/services/media_foundation_renderer_wrapper.cc +++ b/chromium/media/mojo/services/media_foundation_renderer_wrapper.cc @@ -11,13 +11,16 @@ namespace media { +// TODO(xhwang): Remove `force_dcomp_mode_for_testing=true` after composition is +// working by default. MediaFoundationRendererWrapper::MediaFoundationRendererWrapper( bool web_contents_muted, scoped_refptr<base::SequencedTaskRunner> task_runner, mojo::PendingReceiver<RendererExtension> renderer_extension_receiver) : renderer_(std::make_unique<media::MediaFoundationRenderer>( web_contents_muted, - std::move(task_runner))), + std::move(task_runner), + /*force_dcomp_mode_for_testing=*/true)), renderer_extension_receiver_(this, std::move(renderer_extension_receiver)) { DVLOG_FUNC(1); @@ -40,7 +43,7 @@ void MediaFoundationRendererWrapper::SetCdm(CdmContext* cdm_context, } void MediaFoundationRendererWrapper::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { renderer_->SetLatencyHint(latency_hint); } diff --git a/chromium/media/mojo/services/media_foundation_renderer_wrapper.h b/chromium/media/mojo/services/media_foundation_renderer_wrapper.h index 01f8fa0ea06..88aaefee6e7 100644 --- a/chromium/media/mojo/services/media_foundation_renderer_wrapper.h +++ b/chromium/media/mojo/services/media_foundation_renderer_wrapper.h @@ -40,7 +40,7 @@ class MediaFoundationRendererWrapper media::RendererClient* client, media::PipelineStatusCallback init_cb) override; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void Flush(base::OnceClosure flush_cb) override; void StartPlayingFrom(base::TimeDelta time) override; void SetPlaybackRate(double playback_rate) override; diff --git a/chromium/media/mojo/services/media_foundation_service.cc b/chromium/media/mojo/services/media_foundation_service.cc index 892cbd96381..4410d231dc9 100644 --- a/chromium/media/mojo/services/media_foundation_service.cc +++ b/chromium/media/mojo/services/media_foundation_service.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/check.h" +#include "media/cdm/win/media_foundation_cdm_module.h" #include "media/media_buildflags.h" #include "media/mojo/mojom/interface_factory.mojom.h" #include "media/mojo/services/interface_factory_impl.h" @@ -15,17 +16,28 @@ namespace media { MediaFoundationService::MediaFoundationService( - mojo::PendingReceiver<mojom::MediaFoundationService> receiver) - : receiver_(this, std::move(receiver)) { + mojo::PendingReceiver<mojom::MediaFoundationService> receiver, + const base::FilePath& user_data_dir, + base::OnceClosure ensure_sandboxed_cb) + : receiver_(this, std::move(receiver)), + ensure_sandboxed_cb_(std::move(ensure_sandboxed_cb)), + mojo_media_client_(user_data_dir) { mojo_media_client_.Initialize(); } MediaFoundationService::~MediaFoundationService() = default; void MediaFoundationService::Initialize(const base::FilePath& cdm_path) { - // TODO(xhwang): Support loading MediaFoundation CDM and activating - // IMFContentDecryptionModuleFactory. - NOTIMPLEMENTED(); + DVLOG(1) << __func__ << ": cdm_path=" << cdm_path; + + auto* instance = MediaFoundationCdmModule::GetInstance(); + if (instance->initialized()) { + DCHECK_EQ(cdm_path, instance->cdm_path()); + return; + } + + instance->Initialize(cdm_path); + std::move(ensure_sandboxed_cb_).Run(); } void MediaFoundationService::IsKeySystemSupported( @@ -34,6 +46,7 @@ void MediaFoundationService::IsKeySystemSupported( // TODO(crbug.com/1115687): Implement MediaFoundation-based key system support // query. NOTIMPLEMENTED(); + std::move(callback).Run(false, nullptr); } void MediaFoundationService::CreateInterfaceFactory( diff --git a/chromium/media/mojo/services/media_foundation_service.h b/chromium/media/mojo/services/media_foundation_service.h index ad25361a377..0e3745f477b 100644 --- a/chromium/media/mojo/services/media_foundation_service.h +++ b/chromium/media/mojo/services/media_foundation_service.h @@ -5,7 +5,8 @@ #ifndef MEDIA_MOJO_SERVICES_MEDIA_FOUNDATION_SERVICE_H_ #define MEDIA_MOJO_SERVICES_MEDIA_FOUNDATION_SERVICE_H_ -#include "build/build_config.h" +#include "base/callback.h" +#include "base/files/file_path.h" #include "media/mojo/mojom/frame_interface_factory.mojom.h" #include "media/mojo/mojom/interface_factory.mojom.h" #include "media/mojo/mojom/media_foundation_service.mojom.h" @@ -23,13 +24,17 @@ namespace media { class MEDIA_MOJO_EXPORT MediaFoundationService final : public mojom::MediaFoundationService { public: - explicit MediaFoundationService( - mojo::PendingReceiver<mojom::MediaFoundationService> receiver); + // The MediaFoundationService process is NOT sandboxed after startup. The + // `ensure_sandboxed_cb` must be called after necessary initialization to + // ensure the process is sandboxed. + MediaFoundationService( + mojo::PendingReceiver<mojom::MediaFoundationService> receiver, + const base::FilePath& user_data_dir, + base::OnceClosure ensure_sandboxed_cb); MediaFoundationService(const MediaFoundationService&) = delete; MediaFoundationService operator=(const MediaFoundationService&) = delete; ~MediaFoundationService() final; - private: // mojom::MediaFoundationService implementation: void Initialize(const base::FilePath& cdm_path) final; void IsKeySystemSupported(const std::string& key_system, @@ -38,7 +43,9 @@ class MEDIA_MOJO_EXPORT MediaFoundationService final mojo::PendingReceiver<mojom::InterfaceFactory> receiver, mojo::PendingRemote<mojom::FrameInterfaceFactory> frame_interfaces) final; + private: mojo::Receiver<mojom::MediaFoundationService> receiver_; + base::OnceClosure ensure_sandboxed_cb_; MediaFoundationMojoMediaClient mojo_media_client_; mojo::UniqueReceiverSet<mojom::InterfaceFactory> interface_factory_receivers_; }; diff --git a/chromium/media/mojo/services/media_metrics_provider.h b/chromium/media/mojo/services/media_metrics_provider.h index e10715732bd..8c7d8d4583a 100644 --- a/chromium/media/mojo/services/media_metrics_provider.h +++ b/chromium/media/mojo/services/media_metrics_provider.h @@ -160,7 +160,7 @@ class MEDIA_MOJO_EXPORT MediaMetricsProvider base::TimeDelta time_to_first_frame_ = kNoTimestamp; base::TimeDelta time_to_play_ready_ = kNoTimestamp; - base::Optional<container_names::MediaContainerName> container_name_; + absl::optional<container_names::MediaContainerName> container_name_; DISALLOW_COPY_AND_ASSIGN(MediaMetricsProvider); }; diff --git a/chromium/media/mojo/services/media_mojo_export.h b/chromium/media/mojo/services/media_mojo_export.h index 1eba90a358c..a0ddd1d9127 100644 --- a/chromium/media/mojo/services/media_mojo_export.h +++ b/chromium/media/mojo/services/media_mojo_export.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_MOJO_COMMON_MEDIA_MOJO_EXPORT_H_ -#define MEDIA_MOJO_COMMON_MEDIA_MOJO_EXPORT_H_ +#ifndef MEDIA_MOJO_SERVICES_MEDIA_MOJO_EXPORT_H_ +#define MEDIA_MOJO_SERVICES_MEDIA_MOJO_EXPORT_H_ // Define MEDIA_MOJO_EXPORT so that functionality implemented by the // media/mojo module can be exported to consumers. @@ -29,4 +29,4 @@ #define MEDIA_MOJO_EXPORT #endif -#endif // MEDIA_MOJO_COMMON_MEDIA_MOJO_EXPORT_H_ +#endif // MEDIA_MOJO_SERVICES_MEDIA_MOJO_EXPORT_H_ diff --git a/chromium/media/mojo/services/mojo_audio_decoder_service.cc b/chromium/media/mojo/services/mojo_audio_decoder_service.cc index 90f071bb723..c4c25b4c908 100644 --- a/chromium/media/mojo/services/mojo_audio_decoder_service.cc +++ b/chromium/media/mojo/services/mojo_audio_decoder_service.cc @@ -36,7 +36,7 @@ void MojoAudioDecoderService::Construct( void MojoAudioDecoderService::Initialize( const AudioDecoderConfig& config, - const base::Optional<base::UnguessableToken>& cdm_id, + const absl::optional<base::UnguessableToken>& cdm_id, InitializeCallback callback) { DVLOG(1) << __func__ << " " << config.AsHumanReadableString(); diff --git a/chromium/media/mojo/services/mojo_audio_decoder_service.h b/chromium/media/mojo/services/mojo_audio_decoder_service.h index 3b0b340196a..8fd5a0583df 100644 --- a/chromium/media/mojo/services/mojo_audio_decoder_service.h +++ b/chromium/media/mojo/services/mojo_audio_decoder_service.h @@ -36,7 +36,7 @@ class MEDIA_MOJO_EXPORT MojoAudioDecoderService final void Construct( mojo::PendingAssociatedRemote<mojom::AudioDecoderClient> client) final; void Initialize(const AudioDecoderConfig& config, - const base::Optional<base::UnguessableToken>& cdm_id, + const absl::optional<base::UnguessableToken>& cdm_id, InitializeCallback callback) final; void SetDataSource(mojo::ScopedDataPipeConsumerHandle receive_pipe) final; @@ -78,7 +78,7 @@ class MEDIA_MOJO_EXPORT MojoAudioDecoderService final // The CDM ID and the corresponding CdmContextRef, which must be held to keep // the CdmContext alive for the lifetime of the |decoder_|. - base::Optional<base::UnguessableToken> cdm_id_; + absl::optional<base::UnguessableToken> cdm_id_; std::unique_ptr<CdmContextRef> cdm_context_ref_; // The AudioDecoder that does actual decoding work. diff --git a/chromium/media/mojo/services/mojo_audio_input_stream.cc b/chromium/media/mojo/services/mojo_audio_input_stream.cc index 246d3b2e639..d0a43d63ad6 100644 --- a/chromium/media/mojo/services/mojo_audio_input_stream.cc +++ b/chromium/media/mojo/services/mojo_audio_input_stream.cc @@ -101,7 +101,7 @@ void MojoAudioInputStream::OnMuted(int stream_id, bool is_muted) { void MojoAudioInputStream::OnStreamError(int stream_id) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - client_->OnError(); + client_->OnError(mojom::InputStreamErrorCode::kUnknown); OnError(); } diff --git a/chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc b/chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc index 45f13d98dd4..dda1bd435cd 100644 --- a/chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc +++ b/chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc @@ -118,7 +118,7 @@ class MockClient : public mojom::AudioInputStreamClient { MOCK_METHOD1(OnMutedStateChanged, void(bool)); - MOCK_METHOD0(OnError, void()); + MOCK_METHOD1(OnError, void(mojom::InputStreamErrorCode)); private: base::ReadOnlySharedMemoryRegion region_; @@ -190,7 +190,7 @@ class MojoAudioInputStreamTest : public Test { TEST_F(MojoAudioInputStreamTest, NoDelegate_SignalsError) { bool deleter_called = false; - EXPECT_CALL(client_, OnError()); + EXPECT_CALL(client_, OnError(mojom::InputStreamErrorCode::kUnknown)); mojo::Remote<mojom::AudioInputStream> stream_remote; MojoAudioInputStream stream( stream_remote.BindNewPipeAndPassReceiver(), @@ -252,7 +252,7 @@ TEST_F(MojoAudioInputStreamTest, Created_NotifiesClient) { TEST_F(MojoAudioInputStreamTest, SetVolumeTooLarge_Error) { auto audio_input = CreateAudioInput(); EXPECT_CALL(deleter_, Finished()); - EXPECT_CALL(client_, OnError()); + EXPECT_CALL(client_, OnError(mojom::InputStreamErrorCode::kUnknown)); audio_input->SetVolume(15); base::RunLoop().RunUntilIdle(); @@ -262,7 +262,7 @@ TEST_F(MojoAudioInputStreamTest, SetVolumeTooLarge_Error) { TEST_F(MojoAudioInputStreamTest, SetVolumeNegative_Error) { auto audio_input = CreateAudioInput(); EXPECT_CALL(deleter_, Finished()); - EXPECT_CALL(client_, OnError()); + EXPECT_CALL(client_, OnError(mojom::InputStreamErrorCode::kUnknown)); audio_input->SetVolume(-0.5); base::RunLoop().RunUntilIdle(); @@ -272,7 +272,7 @@ TEST_F(MojoAudioInputStreamTest, SetVolumeNegative_Error) { TEST_F(MojoAudioInputStreamTest, DelegateErrorBeforeCreated_PropagatesError) { auto audio_input = CreateAudioInput(); EXPECT_CALL(deleter_, Finished()); - EXPECT_CALL(client_, OnError()); + EXPECT_CALL(client_, OnError(mojom::InputStreamErrorCode::kUnknown)); ASSERT_NE(nullptr, delegate_event_handler_); delegate_event_handler_->OnStreamError(kStreamId); @@ -285,7 +285,7 @@ TEST_F(MojoAudioInputStreamTest, DelegateErrorAfterCreated_PropagatesError) { auto audio_input = CreateAudioInput(); EXPECT_CALL(client_, GotNotification(kInitiallyNotMuted)); EXPECT_CALL(deleter_, Finished()); - EXPECT_CALL(client_, OnError()); + EXPECT_CALL(client_, OnError(mojom::InputStreamErrorCode::kUnknown)); base::RunLoop().RunUntilIdle(); ASSERT_NE(nullptr, delegate_event_handler_); diff --git a/chromium/media/mojo/services/mojo_audio_output_stream_provider.h b/chromium/media/mojo/services/mojo_audio_output_stream_provider.h index 52c23ee60ee..8d632351d55 100644 --- a/chromium/media/mojo/services/mojo_audio_output_stream_provider.h +++ b/chromium/media/mojo/services/mojo_audio_output_stream_provider.h @@ -62,7 +62,7 @@ class MEDIA_MOJO_EXPORT MojoAudioOutputStreamProvider DeleterCallback deleter_callback_; std::unique_ptr<mojom::AudioOutputStreamObserver> observer_; mojo::Receiver<mojom::AudioOutputStreamObserver> observer_receiver_; - base::Optional<MojoAudioOutputStream> audio_output_; + absl::optional<MojoAudioOutputStream> audio_output_; mojo::Remote<mojom::AudioOutputStreamProviderClient> provider_client_; DISALLOW_COPY_AND_ASSIGN(MojoAudioOutputStreamProvider); diff --git a/chromium/media/mojo/services/mojo_cdm_promise.cc b/chromium/media/mojo/services/mojo_cdm_promise.cc index 5bd1295a42f..3641388b5ce 100644 --- a/chromium/media/mojo/services/mojo_cdm_promise.cc +++ b/chromium/media/mojo/services/mojo_cdm_promise.cc @@ -12,6 +12,7 @@ #include "base/check.h" #include "media/base/content_decryption_module.h" #include "media/base/decryptor.h" +#include "media/mojo/mojom/content_decryption_module.mojom.h" namespace media { diff --git a/chromium/media/mojo/services/mojo_cdm_promise.h b/chromium/media/mojo/services/mojo_cdm_promise.h index b6c0988eb97..d5db3d8a604 100644 --- a/chromium/media/mojo/services/mojo_cdm_promise.h +++ b/chromium/media/mojo/services/mojo_cdm_promise.h @@ -10,7 +10,6 @@ #include "base/callback.h" #include "base/macros.h" #include "media/base/cdm_promise.h" -#include "media/mojo/mojom/content_decryption_module.mojom.h" namespace media { diff --git a/chromium/media/mojo/services/mojo_cdm_service.h b/chromium/media/mojo/services/mojo_cdm_service.h index 18195fb1c73..53d736d9999 100644 --- a/chromium/media/mojo/services/mojo_cdm_service.h +++ b/chromium/media/mojo/services/mojo_cdm_service.h @@ -112,7 +112,7 @@ class MEDIA_MOJO_EXPORT MojoCdmService final std::unique_ptr<mojo::Receiver<mojom::Decryptor>> decryptor_receiver_; // Set to a valid CDM ID if the |cdm_| is successfully created. - base::Optional<base::UnguessableToken> cdm_id_; + absl::optional<base::UnguessableToken> cdm_id_; mojo::AssociatedRemote<mojom::ContentDecryptionModuleClient> client_; diff --git a/chromium/media/mojo/services/mojo_demuxer_stream_adapter.cc b/chromium/media/mojo/services/mojo_demuxer_stream_adapter.cc index d9f40c7eefc..c248002d029 100644 --- a/chromium/media/mojo/services/mojo_demuxer_stream_adapter.cc +++ b/chromium/media/mojo/services/mojo_demuxer_stream_adapter.cc @@ -70,8 +70,8 @@ bool MojoDemuxerStreamAdapter::SupportsConfigChanges() { void MojoDemuxerStreamAdapter::OnStreamReady( Type type, mojo::ScopedDataPipeConsumerHandle consumer_handle, - const base::Optional<AudioDecoderConfig>& audio_config, - const base::Optional<VideoDecoderConfig>& video_config) { + const absl::optional<AudioDecoderConfig>& audio_config, + const absl::optional<VideoDecoderConfig>& video_config) { DVLOG(1) << __func__; DCHECK_EQ(UNKNOWN, type_); DCHECK(consumer_handle.is_valid()); @@ -89,8 +89,8 @@ void MojoDemuxerStreamAdapter::OnStreamReady( void MojoDemuxerStreamAdapter::OnBufferReady( Status status, mojom::DecoderBufferPtr buffer, - const base::Optional<AudioDecoderConfig>& audio_config, - const base::Optional<VideoDecoderConfig>& video_config) { + const absl::optional<AudioDecoderConfig>& audio_config, + const absl::optional<VideoDecoderConfig>& video_config) { DVLOG(3) << __func__; DCHECK(read_cb_); DCHECK_NE(type_, UNKNOWN); @@ -123,8 +123,8 @@ void MojoDemuxerStreamAdapter::OnBufferRead( } void MojoDemuxerStreamAdapter::UpdateConfig( - const base::Optional<AudioDecoderConfig>& audio_config, - const base::Optional<VideoDecoderConfig>& video_config) { + const absl::optional<AudioDecoderConfig>& audio_config, + const absl::optional<VideoDecoderConfig>& video_config) { DCHECK_NE(type_, UNKNOWN); switch(type_) { diff --git a/chromium/media/mojo/services/mojo_demuxer_stream_adapter.h b/chromium/media/mojo/services/mojo_demuxer_stream_adapter.h index 1cb22c8ea3f..4d5b55fc3d4 100644 --- a/chromium/media/mojo/services/mojo_demuxer_stream_adapter.h +++ b/chromium/media/mojo/services/mojo_demuxer_stream_adapter.h @@ -9,13 +9,13 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "media/base/audio_decoder_config.h" #include "media/base/demuxer_stream.h" #include "media/base/video_decoder_config.h" #include "media/mojo/mojom/demuxer_stream.mojom.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -49,20 +49,20 @@ class MojoDemuxerStreamAdapter : public DemuxerStream { private: void OnStreamReady(Type type, mojo::ScopedDataPipeConsumerHandle consumer_handle, - const base::Optional<AudioDecoderConfig>& audio_config, - const base::Optional<VideoDecoderConfig>& video_config); + const absl::optional<AudioDecoderConfig>& audio_config, + const absl::optional<VideoDecoderConfig>& video_config); // The callback from |demuxer_stream_| that a read operation has completed. // |read_cb| is a callback from the client who invoked Read() on |this|. void OnBufferReady(Status status, mojom::DecoderBufferPtr buffer, - const base::Optional<AudioDecoderConfig>& audio_config, - const base::Optional<VideoDecoderConfig>& video_config); + const absl::optional<AudioDecoderConfig>& audio_config, + const absl::optional<VideoDecoderConfig>& video_config); void OnBufferRead(scoped_refptr<DecoderBuffer> buffer); - void UpdateConfig(const base::Optional<AudioDecoderConfig>& audio_config, - const base::Optional<VideoDecoderConfig>& video_config); + void UpdateConfig(const absl::optional<AudioDecoderConfig>& audio_config, + const absl::optional<VideoDecoderConfig>& video_config); // See constructor for descriptions. mojo::Remote<mojom::DemuxerStream> demuxer_stream_; diff --git a/chromium/media/mojo/services/mojo_media_client.h b/chromium/media/mojo/services/mojo_media_client.h index cba23037f32..1f63e9f357f 100644 --- a/chromium/media/mojo/services/mojo_media_client.h +++ b/chromium/media/mojo/services/mojo_media_client.h @@ -9,7 +9,6 @@ #include <string> #include <vector> -#include "base/callback_forward.h" #include "base/memory/ref_counted.h" #include "base/unguessable_token.h" #include "media/base/overlay_info.h" diff --git a/chromium/media/mojo/services/mojo_media_drm_storage.cc b/chromium/media/mojo/services/mojo_media_drm_storage.cc index 113535f14ff..49f0405e08a 100644 --- a/chromium/media/mojo/services/mojo_media_drm_storage.cc +++ b/chromium/media/mojo/services/mojo_media_drm_storage.cc @@ -9,10 +9,10 @@ #include "base/bind.h" #include "base/callback_helpers.h" -#include "base/optional.h" #include "base/unguessable_token.h" #include "media/mojo/mojom/media_drm_storage.mojom.h" #include "mojo/public/cpp/bindings/callback_helpers.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -30,7 +30,7 @@ MojoMediaDrmStorage::~MojoMediaDrmStorage() {} void MojoMediaDrmStorage::Initialize(InitCB init_cb) { DVLOG(1) << __func__; media_drm_storage_->Initialize(mojo::WrapCallbackWithDefaultInvokeIfNotRun( - std::move(init_cb), false, base::nullopt)); + std::move(init_cb), false, absl::nullopt)); } void MojoMediaDrmStorage::OnProvisioned(ResultCB result_cb) { diff --git a/chromium/media/mojo/services/mojo_renderer_service.cc b/chromium/media/mojo/services/mojo_renderer_service.cc index 5fbf6cf0e4c..31967288a8b 100644 --- a/chromium/media/mojo/services/mojo_renderer_service.cc +++ b/chromium/media/mojo/services/mojo_renderer_service.cc @@ -9,13 +9,13 @@ #include "base/bind.h" #include "base/memory/ptr_util.h" -#include "base/optional.h" #include "media/base/cdm_context.h" #include "media/base/media_url_demuxer.h" #include "media/base/renderer.h" #include "media/mojo/common/media_type_converters.h" #include "media/mojo/services/media_resource_shim.h" #include "media/mojo/services/mojo_cdm_service_context.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -54,7 +54,7 @@ MojoRendererService::~MojoRendererService() = default; void MojoRendererService::Initialize( mojo::PendingAssociatedRemote<mojom::RendererClient> client, - base::Optional<std::vector<mojo::PendingRemote<mojom::DemuxerStream>>> + absl::optional<std::vector<mojo::PendingRemote<mojom::DemuxerStream>>> streams, mojom::MediaUrlParamsPtr media_url_params, InitializeCallback callback) { @@ -112,7 +112,7 @@ void MojoRendererService::SetVolume(float volume) { } void MojoRendererService::SetCdm( - const base::Optional<base::UnguessableToken>& cdm_id, + const absl::optional<base::UnguessableToken>& cdm_id, SetCdmCallback callback) { if (cdm_context_ref_) { DVLOG(1) << "Switching CDM not supported"; @@ -204,7 +204,7 @@ void MojoRendererService::OnVideoOpacityChange(bool opaque) { client_->OnVideoOpacityChange(opaque); } -void MojoRendererService::OnVideoFrameRateChange(base::Optional<int> fps) { +void MojoRendererService::OnVideoFrameRateChange(absl::optional<int> fps) { DVLOG(2) << __func__ << "(" << (fps ? *fps : -1) << ")"; // TODO(liberato): plumb to |client_|. } diff --git a/chromium/media/mojo/services/mojo_renderer_service.h b/chromium/media/mojo/services/mojo_renderer_service.h index 08953954f11..0c7c7d6b8c0 100644 --- a/chromium/media/mojo/services/mojo_renderer_service.h +++ b/chromium/media/mojo/services/mojo_renderer_service.h @@ -56,7 +56,7 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer, // mojom::Renderer implementation. void Initialize( mojo::PendingAssociatedRemote<mojom::RendererClient> client, - base::Optional<std::vector<mojo::PendingRemote<mojom::DemuxerStream>>> + absl::optional<std::vector<mojo::PendingRemote<mojom::DemuxerStream>>> streams, mojom::MediaUrlParamsPtr media_url_params, InitializeCallback callback) final; @@ -64,7 +64,7 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer, void StartPlayingFrom(base::TimeDelta time_delta) final; void SetPlaybackRate(double playback_rate) final; void SetVolume(float volume) final; - void SetCdm(const base::Optional<base::UnguessableToken>& cdm_id, + void SetCdm(const absl::optional<base::UnguessableToken>& cdm_id, SetCdmCallback callback) final; private: @@ -87,7 +87,7 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer, void OnVideoConfigChange(const VideoDecoderConfig& config) final; void OnVideoNaturalSizeChange(const gfx::Size& size) final; void OnVideoOpacityChange(bool opaque) final; - void OnVideoFrameRateChange(base::Optional<int> fps) final; + void OnVideoFrameRateChange(absl::optional<int> fps) final; // Called when the MediaResourceShim is ready to go (has a config, // pipe handle, etc) and can be handed off to a renderer for use. diff --git a/chromium/media/mojo/services/mojo_video_decoder_service.cc b/chromium/media/mojo/services/mojo_video_decoder_service.cc index 19e7d34f60a..80bc77c3e47 100644 --- a/chromium/media/mojo/services/mojo_video_decoder_service.cc +++ b/chromium/media/mojo/services/mojo_video_decoder_service.cc @@ -13,7 +13,6 @@ #include "base/macros.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/optional.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_task_runner_handle.h" #include "base/timer/elapsed_timer.h" @@ -31,6 +30,7 @@ #include "mojo/public/cpp/bindings/message.h" #include "mojo/public/cpp/system/buffer.h" #include "mojo/public/cpp/system/handle.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -195,7 +195,7 @@ void MojoVideoDecoderService::Construct( void MojoVideoDecoderService::Initialize( const VideoDecoderConfig& config, bool low_delay, - const base::Optional<base::UnguessableToken>& cdm_id, + const absl::optional<base::UnguessableToken>& cdm_id, InitializeCallback callback) { DVLOG(1) << __func__ << " config = " << config.AsHumanReadableString() << ", cdm_id = " @@ -382,7 +382,7 @@ void MojoVideoDecoderService::OnDecoderOutput(scoped_refptr<VideoFrame> frame) { // you can remove this DCHECK. DCHECK(frame->metadata().power_efficient); - base::Optional<base::UnguessableToken> release_token; + absl::optional<base::UnguessableToken> release_token; if (frame->HasReleaseMailboxCB() && video_frame_handle_releaser_) { // |video_frame_handle_releaser_| is explicitly constructed with a // VideoFrameHandleReleaserImpl in Construct(). diff --git a/chromium/media/mojo/services/mojo_video_decoder_service.h b/chromium/media/mojo/services/mojo_video_decoder_service.h index d04d177d3bf..06ec7e5a6e3 100644 --- a/chromium/media/mojo/services/mojo_video_decoder_service.h +++ b/chromium/media/mojo/services/mojo_video_decoder_service.h @@ -55,7 +55,7 @@ class MEDIA_MOJO_EXPORT MojoVideoDecoderService final const gfx::ColorSpace& target_color_space) final; void Initialize(const VideoDecoderConfig& config, bool low_delay, - const base::Optional<base::UnguessableToken>& cdm_id, + const absl::optional<base::UnguessableToken>& cdm_id, InitializeCallback callback) final; void Decode(mojom::DecoderBufferPtr buffer, DecodeCallback callback) final; void Reset(ResetCallback callback) final; @@ -87,7 +87,7 @@ class MEDIA_MOJO_EXPORT MojoVideoDecoderService final ProvideOverlayInfoCB provide_overlay_info_cb); // Implementation value provided at the time of Construct(). - base::Optional<VideoDecoderImplementation> implementation_; + absl::optional<VideoDecoderImplementation> implementation_; // Whether this instance is active (Decode() was called at least once). bool is_active_instance_ = false; @@ -114,7 +114,7 @@ class MEDIA_MOJO_EXPORT MojoVideoDecoderService final // The CDM ID and the corresponding CdmContextRef, which must be held to keep // the CdmContext alive for the lifetime of the |decoder_|. - base::Optional<base::UnguessableToken> cdm_id_; + absl::optional<base::UnguessableToken> cdm_id_; std::unique_ptr<CdmContextRef> cdm_context_ref_; std::unique_ptr<media::VideoDecoder> decoder_; diff --git a/chromium/media/mojo/services/playback_events_recorder.h b/chromium/media/mojo/services/playback_events_recorder.h index 39f248e03f7..df7de722016 100644 --- a/chromium/media/mojo/services/playback_events_recorder.h +++ b/chromium/media/mojo/services/playback_events_recorder.h @@ -50,7 +50,7 @@ class MEDIA_MOJO_EXPORT PlaybackEventsRecorder final size_t audio_bytes_ = 0; size_t video_bytes_ = 0; - base::Optional<PipelineStatistics> last_stats_; + absl::optional<PipelineStatistics> last_stats_; base::TimeTicks last_stats_time_; }; diff --git a/chromium/media/mojo/services/video_decode_perf_history_unittest.cc b/chromium/media/mojo/services/video_decode_perf_history_unittest.cc index e6eeddb2364..7d2bfc29ee6 100644 --- a/chromium/media/mojo/services/video_decode_perf_history_unittest.cc +++ b/chromium/media/mojo/services/video_decode_perf_history_unittest.cc @@ -10,7 +10,6 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "base/task/post_task.h" #include "base/test/bind.h" #include "base/test/scoped_feature_list.h" diff --git a/chromium/media/mojo/services/video_decode_stats_recorder.h b/chromium/media/mojo/services/video_decode_stats_recorder.h index 72bbd0a7b5c..f4901789b84 100644 --- a/chromium/media/mojo/services/video_decode_stats_recorder.h +++ b/chromium/media/mojo/services/video_decode_stats_recorder.h @@ -6,9 +6,7 @@ #define MEDIA_MOJO_SERVICES_VIDEO_DECODE_STATS_RECORDER_H_ #include <stdint.h> -#include <string> -#include "base/time/time.h" #include "media/base/video_codecs.h" #include "media/learning/common/value.h" #include "media/mojo/mojom/media_types.mojom.h" diff --git a/chromium/media/mojo/services/watch_time_recorder.cc b/chromium/media/mojo/services/watch_time_recorder.cc index 6cb630ed5d0..414751e8aa3 100644 --- a/chromium/media/mojo/services/watch_time_recorder.cc +++ b/chromium/media/mojo/services/watch_time_recorder.cc @@ -31,7 +31,7 @@ static void RecordWatchTimeInternal( base::TimeDelta value, base::TimeDelta minimum = kMinimumElapsedWatchTime) { DCHECK(!key.empty()); - base::UmaHistogramCustomTimes(key.as_string(), value, minimum, + base::UmaHistogramCustomTimes(std::string(key), value, minimum, base::TimeDelta::FromHours(10), 50); } @@ -47,13 +47,13 @@ static void RecordMeanTimeBetweenRebuffers(base::StringPiece key, static void RecordDiscardedWatchTime(base::StringPiece key, base::TimeDelta value) { DCHECK(!key.empty()); - base::UmaHistogramCustomTimes(key.as_string(), value, base::TimeDelta(), + base::UmaHistogramCustomTimes(std::string(key), value, base::TimeDelta(), kMinimumElapsedWatchTime, 50); } static void RecordRebuffersCount(base::StringPiece key, int underflow_count) { DCHECK(!key.empty()); - base::UmaHistogramCounts100(key.as_string(), underflow_count); + base::UmaHistogramCounts100(std::string(key), underflow_count); } WatchTimeRecorder::WatchTimeUkmRecord::WatchTimeUkmRecord( @@ -328,7 +328,7 @@ void WatchTimeRecorder::RecordUkmPlaybackData() { return; // Round duration to the most significant digit in milliseconds for privacy. - base::Optional<uint64_t> clamped_duration_ms; + absl::optional<uint64_t> clamped_duration_ms; if (duration_ != kNoTimestamp && duration_ != kInfiniteDuration) { clamped_duration_ms = duration_.InMilliseconds(); if (duration_ > base::TimeDelta::FromSeconds(1)) { diff --git a/chromium/media/mojo/services/watch_time_recorder.h b/chromium/media/mojo/services/watch_time_recorder.h index 3b373f3b19a..77e768fe570 100644 --- a/chromium/media/mojo/services/watch_time_recorder.h +++ b/chromium/media/mojo/services/watch_time_recorder.h @@ -126,7 +126,7 @@ class MEDIA_MOJO_EXPORT WatchTimeRecorder : public mojom::WatchTimeRecorder { PipelineStatus pipeline_status_ = PIPELINE_OK; base::TimeDelta duration_ = kNoTimestamp; base::TimeDelta last_timestamp_ = kNoTimestamp; - base::Optional<bool> autoplay_initiated_; + absl::optional<bool> autoplay_initiated_; RecordAggregateWatchTimeCallback record_playback_cb_; DISALLOW_COPY_AND_ASSIGN(WatchTimeRecorder); diff --git a/chromium/media/mojo/services/watch_time_recorder_unittest.cc b/chromium/media/mojo/services/watch_time_recorder_unittest.cc index 08467f09fef..126f57436f1 100644 --- a/chromium/media/mojo/services/watch_time_recorder_unittest.cc +++ b/chromium/media/mojo/services/watch_time_recorder_unittest.cc @@ -14,6 +14,7 @@ #include "base/hash/hash.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "base/test/test_message_loop.h" @@ -110,10 +111,10 @@ class WatchTimeRecorderTest : public testing::Test { continue; auto it = std::find(keys.begin(), keys.end(), test_key); if (it == keys.end()) { - histogram_tester_->ExpectTotalCount(test_key.as_string(), 0); + histogram_tester_->ExpectTotalCount(test_key, 0); } else { - histogram_tester_->ExpectUniqueSample(test_key.as_string(), - value.InMilliseconds(), 1); + histogram_tester_->ExpectUniqueSample(test_key, value.InMilliseconds(), + 1); } } } @@ -124,9 +125,9 @@ class WatchTimeRecorderTest : public testing::Test { for (auto key : full_key_list) { auto it = std::find(keys.begin(), keys.end(), key); if (it == keys.end()) - histogram_tester_->ExpectTotalCount(key.as_string(), 0); + histogram_tester_->ExpectTotalCount(key, 0); else - histogram_tester_->ExpectUniqueSample(key.as_string(), value, 1); + histogram_tester_->ExpectUniqueSample(key, value, 1); } } @@ -225,7 +226,7 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) { auto key_str = ConvertWatchTimeKeyToStringForUma(key); SCOPED_TRACE(key_str.empty() ? base::NumberToString(i) - : key_str.as_string()); + : std::string(key_str)); // Values for |is_background| and |is_muted| don't matter in this test since // they don't prevent the muted or background keys from being recorded. @@ -376,7 +377,7 @@ TEST_F(WatchTimeRecorderTest, TestBasicReportingMediaStream) { auto key_str = ConvertWatchTimeKeyToStringForUma(key); SCOPED_TRACE(key_str.empty() ? base::NumberToString(i) - : key_str.as_string()); + : std::string(key_str)); // Values for |is_background| and |is_muted| don't matter in this test since // they don't prevent the muted or background keys from being recorded. @@ -558,7 +559,7 @@ TEST_F(WatchTimeRecorderTest, TestRebufferingMetrics) { // Nothing should be logged since this doesn't meet requirements. ExpectMtbrTime({}, base::TimeDelta()); for (auto key : smooth_keys_) - histogram_tester_->ExpectTotalCount(key.as_string(), 0); + histogram_tester_->ExpectTotalCount(key, 0); } TEST_F(WatchTimeRecorderTest, TestRebufferingMetricsMediaStream) { @@ -607,8 +608,7 @@ TEST_F(WatchTimeRecorderTest, TestDiscardMetrics) { // Verify the time was instead logged to the discard keys. for (auto key : discard_keys_) { - histogram_tester_->ExpectUniqueSample(key.as_string(), - kWatchTime.InMilliseconds(), 1); + histogram_tester_->ExpectUniqueSample(key, kWatchTime.InMilliseconds(), 1); } // UKM watch time won't be logged because we aren't sending "All" keys. @@ -631,7 +631,7 @@ TEST_F(WatchTimeRecorderTest, TestDiscardMetricsMediaStream) { // No watch time and no discard metrics should be logged. ExpectWatchTime({}, base::TimeDelta()); for (auto key : discard_keys_) { - histogram_tester_->ExpectTotalCount(key.as_string(), 0); + histogram_tester_->ExpectTotalCount(key, 0); } // UKM watch time won't be logged because we aren't sending "All" keys. diff --git a/chromium/media/muxers/DIR_METADATA b/chromium/media/muxers/DIR_METADATA index af1480ef95e..25b8514c4b7 100644 --- a/chromium/media/muxers/DIR_METADATA +++ b/chromium/media/muxers/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Blink>MediaRecording" diff --git a/chromium/media/muxers/webm_muxer.cc b/chromium/media/muxers/webm_muxer.cc index 7c9091b6449..bca545a5de9 100644 --- a/chromium/media/muxers/webm_muxer.cc +++ b/chromium/media/muxers/webm_muxer.cc @@ -110,7 +110,7 @@ static const char* MkvCodeIcForMediaVideoCodecId(VideoCodec video_codec) { } } -base::Optional<mkvmuxer::Colour> ColorFromColorSpace( +absl::optional<mkvmuxer::Colour> ColorFromColorSpace( const gfx::ColorSpace& color) { using mkvmuxer::Colour; using MatrixID = gfx::ColorSpace::MatrixID; @@ -127,7 +127,7 @@ base::Optional<mkvmuxer::Colour> ColorFromColorSpace( matrix_coefficients = Colour::kBt2020NonConstantLuminance; break; default: - return base::nullopt; + return absl::nullopt; } colour.set_matrix_coefficients(matrix_coefficients); int range; @@ -139,7 +139,7 @@ base::Optional<mkvmuxer::Colour> ColorFromColorSpace( range = Colour::kFullRange; break; default: - return base::nullopt; + return absl::nullopt; } colour.set_range(range); int transfer_characteristics; @@ -154,7 +154,7 @@ base::Optional<mkvmuxer::Colour> ColorFromColorSpace( transfer_characteristics = Colour::kSmpteSt2084; break; default: - return base::nullopt; + return absl::nullopt; } colour.set_transfer_characteristics(transfer_characteristics); int primaries; @@ -166,7 +166,7 @@ base::Optional<mkvmuxer::Colour> ColorFromColorSpace( primaries = Colour::kIturBt2020; break; default: - return base::nullopt; + return absl::nullopt; } colour.set_primaries(primaries); return colour; @@ -185,7 +185,7 @@ WebmMuxer::VideoParameters::VideoParameters( gfx::Size visible_rect_size, double frame_rate, VideoCodec codec, - base::Optional<gfx::ColorSpace> color_space) + absl::optional<gfx::ColorSpace> color_space) : visible_rect_size(visible_rect_size), frame_rate(frame_rate), codec(codec), @@ -349,7 +349,7 @@ bool WebmMuxer::Flush() { void WebmMuxer::AddVideoTrack( const gfx::Size& frame_size, double frame_rate, - const base::Optional<gfx::ColorSpace>& color_space) { + const absl::optional<gfx::ColorSpace>& color_space) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(0u, video_track_index_) << "WebmMuxer can only be initialized once."; diff --git a/chromium/media/muxers/webm_muxer.h b/chromium/media/muxers/webm_muxer.h index 63b6dc87194..7121c83d753 100644 --- a/chromium/media/muxers/webm_muxer.h +++ b/chromium/media/muxers/webm_muxer.h @@ -21,6 +21,7 @@ #include "media/base/media_export.h" #include "media/base/video_codecs.h" #include "media/base/video_color_space.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/libwebm/source/mkvmuxer.hpp" #include "ui/gfx/geometry/size.h" @@ -57,13 +58,13 @@ class MEDIA_EXPORT WebmMuxer : public mkvmuxer::IMkvWriter { VideoParameters(gfx::Size visible_rect_size, double frame_rate, VideoCodec codec, - base::Optional<gfx::ColorSpace> color_space); + absl::optional<gfx::ColorSpace> color_space); VideoParameters(const VideoParameters&); ~VideoParameters(); gfx::Size visible_rect_size; double frame_rate; VideoCodec codec; - base::Optional<gfx::ColorSpace> color_space; + absl::optional<gfx::ColorSpace> color_space; }; // |audio_codec| should coincide with whatever is sent in OnEncodedAudio(), @@ -121,7 +122,7 @@ class MEDIA_EXPORT WebmMuxer : public mkvmuxer::IMkvWriter { // frame size. void AddVideoTrack(const gfx::Size& frame_size, double frame_rate, - const base::Optional<gfx::ColorSpace>& color_space); + const absl::optional<gfx::ColorSpace>& color_space); void AddAudioTrack(const media::AudioParameters& params); // IMkvWriter interface. diff --git a/chromium/media/remoting/DIR_METADATA b/chromium/media/remoting/DIR_METADATA index 9e255559a4f..7c577c4a958 100644 --- a/chromium/media/remoting/DIR_METADATA +++ b/chromium/media/remoting/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Internals>Cast>Streaming" diff --git a/chromium/media/remoting/courier_renderer.cc b/chromium/media/remoting/courier_renderer.cc index ea0a946088d..773f87e8ab5 100644 --- a/chromium/media/remoting/courier_renderer.cc +++ b/chromium/media/remoting/courier_renderer.cc @@ -138,7 +138,7 @@ void CourierRenderer::Initialize(MediaResource* media_resource, } void CourierRenderer::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) {} + absl::optional<base::TimeDelta> latency_hint) {} void CourierRenderer::Flush(base::OnceClosure flush_cb) { DCHECK(media_task_runner_->BelongsToCurrentThread()); @@ -154,10 +154,10 @@ void CourierRenderer::Flush(base::OnceClosure flush_cb) { } state_ = STATE_FLUSHING; - base::Optional<uint32_t> flush_audio_count; + absl::optional<uint32_t> flush_audio_count; if (audio_demuxer_stream_adapter_) flush_audio_count = audio_demuxer_stream_adapter_->SignalFlush(true); - base::Optional<uint32_t> flush_video_count; + absl::optional<uint32_t> flush_video_count; if (video_demuxer_stream_adapter_) flush_video_count = video_demuxer_stream_adapter_->SignalFlush(true); // Makes sure flush count is valid if stream is available or both audio and @@ -520,7 +520,7 @@ void CourierRenderer::OnBufferingStateChange( OnFatalError(RPC_INVALID); return; } - base::Optional<BufferingState> state = ToMediaBufferingState( + absl::optional<BufferingState> state = ToMediaBufferingState( message->rendererclient_onbufferingstatechange_rpc().state()); BufferingStateChangeReason reason = BUFFERING_CHANGE_REASON_UNKNOWN; if (!state.has_value()) diff --git a/chromium/media/remoting/courier_renderer.h b/chromium/media/remoting/courier_renderer.h index ea0cef06a58..8e3e985b45a 100644 --- a/chromium/media/remoting/courier_renderer.h +++ b/chromium/media/remoting/courier_renderer.h @@ -75,7 +75,7 @@ class CourierRenderer final : public Renderer { void Initialize(MediaResource* media_resource, RendererClient* client, PipelineStatusCallback init_cb) final; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) final; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) final; void Flush(base::OnceClosure flush_cb) final; void StartPlayingFrom(base::TimeDelta time) final; void SetPlaybackRate(double playback_rate) final; diff --git a/chromium/media/remoting/courier_renderer_unittest.cc b/chromium/media/remoting/courier_renderer_unittest.cc index cec0ff3b658..1fdafa56f8b 100644 --- a/chromium/media/remoting/courier_renderer_unittest.cc +++ b/chromium/media/remoting/courier_renderer_unittest.cc @@ -96,7 +96,7 @@ class RendererClientImpl final : public RendererClient { void OnWaiting(WaitingReason reason) override {} MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size& size)); MOCK_METHOD1(OnVideoOpacityChange, void(bool opaque)); - MOCK_METHOD1(OnVideoFrameRateChange, void(base::Optional<int>)); + MOCK_METHOD1(OnVideoFrameRateChange, void(absl::optional<int>)); MOCK_METHOD1(OnRemotePlayStateChange, void(MediaStatus::State state)); void DelegateOnStatisticsUpdate(const PipelineStatistics& stats) { @@ -439,7 +439,7 @@ class CourierRendererTest : public testing::Test { // Issue RPC_RC_ONBUFFERINGSTATECHANGE RPC message. void IssuesBufferingStateRpc(BufferingState state) { - base::Optional< + absl::optional< openscreen::cast::RendererClientOnBufferingStateChange::State> pb_state = ToProtoMediaBufferingState(state); if (!pb_state.has_value()) diff --git a/chromium/media/remoting/demuxer_stream_adapter.cc b/chromium/media/remoting/demuxer_stream_adapter.cc index cccf161e42e..9039908e07c 100644 --- a/chromium/media/remoting/demuxer_stream_adapter.cc +++ b/chromium/media/remoting/demuxer_stream_adapter.cc @@ -81,13 +81,13 @@ int64_t DemuxerStreamAdapter::GetBytesWrittenAndReset() { return current_count; } -base::Optional<uint32_t> DemuxerStreamAdapter::SignalFlush(bool flushing) { +absl::optional<uint32_t> DemuxerStreamAdapter::SignalFlush(bool flushing) { DCHECK(media_task_runner_->BelongsToCurrentThread()); DEMUXER_VLOG(2) << "flushing=" << flushing; // Ignores if |pending_flush_| states is same. if (pending_flush_ == flushing) - return base::nullopt; + return absl::nullopt; // Cleans up pending frame data. pending_frame_is_eos_ = false; diff --git a/chromium/media/remoting/demuxer_stream_adapter.h b/chromium/media/remoting/demuxer_stream_adapter.h index 3e55c6cebdf..a30444c8c48 100644 --- a/chromium/media/remoting/demuxer_stream_adapter.h +++ b/chromium/media/remoting/demuxer_stream_adapter.h @@ -13,7 +13,6 @@ #include "base/callback_forward.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "media/base/audio_decoder_config.h" #include "media/base/demuxer_stream.h" #include "media/base/video_decoder_config.h" @@ -25,6 +24,7 @@ #include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/system/data_pipe.h" #include "mojo/public/cpp/system/simple_watcher.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class SingleThreadTaskRunner; @@ -84,8 +84,8 @@ class DemuxerStreamAdapter { // signal when flush starts and when is done. During flush operation, all // fetching data actions will be discarded. The return value indicates frame // count in order to signal receiver what frames are in flight before flush, - // or base::nullopt if the flushing state was unchanged. - base::Optional<uint32_t> SignalFlush(bool flushing); + // or absl::nullopt if the flushing state was unchanged. + absl::optional<uint32_t> SignalFlush(bool flushing); bool is_processing_read_request() const { // |read_until_callback_handle_| is set when RPC_DS_READUNTIL message is diff --git a/chromium/media/remoting/end2end_test_renderer.cc b/chromium/media/remoting/end2end_test_renderer.cc index 4f71628b829..b431f565fdd 100644 --- a/chromium/media/remoting/end2end_test_renderer.cc +++ b/chromium/media/remoting/end2end_test_renderer.cc @@ -362,7 +362,7 @@ void End2EndTestRenderer::OnAcquireRendererDone(int receiver_renderer_handle) { } void End2EndTestRenderer::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { courier_renderer_->SetLatencyHint(latency_hint); } diff --git a/chromium/media/remoting/end2end_test_renderer.h b/chromium/media/remoting/end2end_test_renderer.h index 61749c758a1..deab7964849 100644 --- a/chromium/media/remoting/end2end_test_renderer.h +++ b/chromium/media/remoting/end2end_test_renderer.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MEDIA_REMOTING_END2END_RENDERER_H_ -#define MEDIA_REMOTING_END2END_RENDERER_H_ +#ifndef MEDIA_REMOTING_END2END_TEST_RENDERER_H_ +#define MEDIA_REMOTING_END2END_TEST_RENDERER_H_ #include <memory> #include <vector> @@ -32,7 +32,7 @@ class End2EndTestRenderer final : public Renderer { void Initialize(MediaResource* media_resource, RendererClient* client, PipelineStatusCallback init_cb) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void SetPreservesPitch(bool preserves_pitch) override; void Flush(base::OnceClosure flush_cb) override; void StartPlayingFrom(base::TimeDelta time) override; @@ -102,4 +102,4 @@ class End2EndTestRenderer final : public Renderer { } // namespace remoting } // namespace media -#endif // MEDIA_REMOTING_END2END_RENDERER_H_ +#endif // MEDIA_REMOTING_END2END_TEST_RENDERER_H_ diff --git a/chromium/media/remoting/integration_test.cc b/chromium/media/remoting/integration_test.cc index bbac6f6a8a8..805a425e1d0 100644 --- a/chromium/media/remoting/integration_test.cc +++ b/chromium/media/remoting/integration_test.cc @@ -25,9 +25,9 @@ class MediaRemotingIntegrationTest : public testing::Test, private: std::unique_ptr<Renderer> CreateEnd2EndTestRenderer( - base::Optional<RendererFactoryType> factory_type) { + absl::optional<RendererType> renderer_type) { return std::make_unique<End2EndTestRenderer>( - this->CreateDefaultRenderer(factory_type)); + this->CreateDefaultRenderer(renderer_type)); } DISALLOW_COPY_AND_ASSIGN(MediaRemotingIntegrationTest); diff --git a/chromium/media/remoting/metrics.cc b/chromium/media/remoting/metrics.cc index fd3252c558a..c2f9f03a271 100644 --- a/chromium/media/remoting/metrics.cc +++ b/chromium/media/remoting/metrics.cc @@ -116,7 +116,7 @@ void SessionMetricsRecorder::WillStopSession(StopTrigger trigger) { // Reset |start_trigger_| since metrics recording of the current remoting // session has now completed. - start_trigger_ = base::nullopt; + start_trigger_ = absl::nullopt; } void SessionMetricsRecorder::OnPipelineMetadataChanged( @@ -182,6 +182,10 @@ void SessionMetricsRecorder::RecordVideoPixelRateSupport( void SessionMetricsRecorder::RecordCompatibility( RemotingCompatibility compatibility) { + if (did_record_compatibility_) { + return; + } + did_record_compatibility_ = true; base::UmaHistogramEnumeration("Media.Remoting.Compatibility", compatibility); } diff --git a/chromium/media/remoting/metrics.h b/chromium/media/remoting/metrics.h index 017ad9de60f..c08e8779b77 100644 --- a/chromium/media/remoting/metrics.h +++ b/chromium/media/remoting/metrics.h @@ -6,10 +6,10 @@ #define MEDIA_REMOTING_METRICS_H_ #include "base/macros.h" -#include "base/optional.h" #include "base/time/time.h" #include "media/base/pipeline_metadata.h" #include "media/remoting/triggers.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { @@ -70,7 +70,8 @@ class SessionMetricsRecorder { // for the recorder instance. void RecordVideoPixelRateSupport(PixelRateSupport support); - // Records the compatibility of a media content with remoting. + // Records the compatibility of a media content with remoting. Records only on + // the first call for the recorder instance. void RecordCompatibility(RemotingCompatibility compatibility); private: @@ -95,7 +96,7 @@ class SessionMetricsRecorder { void RecordTrackConfiguration(); // |start_trigger_| is set while a remoting session is active. - base::Optional<StartTrigger> start_trigger_; + absl::optional<StartTrigger> start_trigger_; // When the current (or last) remoting session started. base::TimeTicks start_time_; @@ -114,6 +115,7 @@ class SessionMetricsRecorder { bool remote_playback_is_disabled_ = false; bool did_record_pixel_rate_support_ = false; + bool did_record_compatibility_ = false; DISALLOW_COPY_AND_ASSIGN(SessionMetricsRecorder); }; diff --git a/chromium/media/remoting/metrics_unittest.cc b/chromium/media/remoting/metrics_unittest.cc index 8ac9b0b6b76..cd6f8b6f020 100644 --- a/chromium/media/remoting/metrics_unittest.cc +++ b/chromium/media/remoting/metrics_unittest.cc @@ -51,13 +51,13 @@ TEST_F(MediaRemotingMetricsTest, RecordCompatibility) { recorder_.RecordCompatibility(RemotingCompatibility::kCompatible); recorder_.RecordCompatibility(RemotingCompatibility::kIncompatibleVideoCodec); + // We record only for the first RecordCompatibility() call for the + // given SessionMetricsRecorder instance. EXPECT_THAT( tester.GetAllSamples(kCompatibilityHistogramName), - ElementsAre( - Bucket(static_cast<int>(RemotingCompatibility::kCompatible), 1), - Bucket( - static_cast<int>(RemotingCompatibility::kIncompatibleVideoCodec), - 2))); + ElementsAre(Bucket( + static_cast<int>(RemotingCompatibility::kIncompatibleVideoCodec), + 1))); } } // namespace remoting diff --git a/chromium/media/remoting/proto_enum_utils.cc b/chromium/media/remoting/proto_enum_utils.cc index 6d1c9d59be1..e080e050580 100644 --- a/chromium/media/remoting/proto_enum_utils.cc +++ b/chromium/media/remoting/proto_enum_utils.cc @@ -11,7 +11,7 @@ namespace remoting { case OriginType::x: \ return OtherType::x -base::Optional<AudioCodec> ToMediaAudioCodec( +absl::optional<AudioCodec> ToMediaAudioCodec( openscreen::cast::AudioDecoderConfig::Codec value) { using OriginType = openscreen::cast::AudioDecoderConfig; using OtherType = AudioCodec; @@ -35,10 +35,10 @@ base::Optional<AudioCodec> ToMediaAudioCodec( CASE_RETURN_OTHER(kCodecAC3); CASE_RETURN_OTHER(kCodecMpegHAudio); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<openscreen::cast::AudioDecoderConfig::Codec> +absl::optional<openscreen::cast::AudioDecoderConfig::Codec> ToProtoAudioDecoderConfigCodec(AudioCodec value) { using OriginType = AudioCodec; using OtherType = openscreen::cast::AudioDecoderConfig; @@ -62,10 +62,10 @@ ToProtoAudioDecoderConfigCodec(AudioCodec value) { CASE_RETURN_OTHER(kCodecAC3); CASE_RETURN_OTHER(kCodecMpegHAudio); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<SampleFormat> ToMediaSampleFormat( +absl::optional<SampleFormat> ToMediaSampleFormat( openscreen::cast::AudioDecoderConfig::SampleFormat value) { using OriginType = openscreen::cast::AudioDecoderConfig; using OtherType = SampleFormat; @@ -83,10 +83,10 @@ base::Optional<SampleFormat> ToMediaSampleFormat( CASE_RETURN_OTHER(kSampleFormatEac3); CASE_RETURN_OTHER(kSampleFormatMpegHAudio); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<openscreen::cast::AudioDecoderConfig::SampleFormat> +absl::optional<openscreen::cast::AudioDecoderConfig::SampleFormat> ToProtoAudioDecoderConfigSampleFormat(SampleFormat value) { using OriginType = SampleFormat; using OtherType = openscreen::cast::AudioDecoderConfig; @@ -104,10 +104,10 @@ ToProtoAudioDecoderConfigSampleFormat(SampleFormat value) { CASE_RETURN_OTHER(kSampleFormatEac3); CASE_RETURN_OTHER(kSampleFormatMpegHAudio); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<ChannelLayout> ToMediaChannelLayout( +absl::optional<ChannelLayout> ToMediaChannelLayout( openscreen::cast::AudioDecoderConfig::ChannelLayout value) { using OriginType = openscreen::cast::AudioDecoderConfig; using OtherType = ChannelLayout; @@ -146,10 +146,10 @@ base::Optional<ChannelLayout> ToMediaChannelLayout( CASE_RETURN_OTHER(CHANNEL_LAYOUT_4_1_QUAD_SIDE); CASE_RETURN_OTHER(CHANNEL_LAYOUT_BITSTREAM); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<openscreen::cast::AudioDecoderConfig::ChannelLayout> +absl::optional<openscreen::cast::AudioDecoderConfig::ChannelLayout> ToProtoAudioDecoderConfigChannelLayout(ChannelLayout value) { using OriginType = ChannelLayout; using OtherType = openscreen::cast::AudioDecoderConfig; @@ -188,10 +188,10 @@ ToProtoAudioDecoderConfigChannelLayout(ChannelLayout value) { CASE_RETURN_OTHER(CHANNEL_LAYOUT_4_1_QUAD_SIDE); CASE_RETURN_OTHER(CHANNEL_LAYOUT_BITSTREAM); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<VideoCodec> ToMediaVideoCodec( +absl::optional<VideoCodec> ToMediaVideoCodec( openscreen::cast::VideoDecoderConfig::Codec value) { using OriginType = openscreen::cast::VideoDecoderConfig; using OtherType = VideoCodec; @@ -208,10 +208,10 @@ base::Optional<VideoCodec> ToMediaVideoCodec( CASE_RETURN_OTHER(kCodecDolbyVision); CASE_RETURN_OTHER(kCodecAV1); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<openscreen::cast::VideoDecoderConfig::Codec> +absl::optional<openscreen::cast::VideoDecoderConfig::Codec> ToProtoVideoDecoderConfigCodec(VideoCodec value) { using OriginType = VideoCodec; using OtherType = openscreen::cast::VideoDecoderConfig; @@ -228,10 +228,10 @@ ToProtoVideoDecoderConfigCodec(VideoCodec value) { CASE_RETURN_OTHER(kCodecDolbyVision); CASE_RETURN_OTHER(kCodecAV1); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<VideoCodecProfile> ToMediaVideoCodecProfile( +absl::optional<VideoCodecProfile> ToMediaVideoCodecProfile( openscreen::cast::VideoDecoderConfig::Profile value) { using OriginType = openscreen::cast::VideoDecoderConfig; using OtherType = VideoCodecProfile; @@ -267,10 +267,10 @@ base::Optional<VideoCodecProfile> ToMediaVideoCodecProfile( CASE_RETURN_OTHER(AV1PROFILE_PROFILE_HIGH); CASE_RETURN_OTHER(AV1PROFILE_PROFILE_PRO); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<openscreen::cast::VideoDecoderConfig::Profile> +absl::optional<openscreen::cast::VideoDecoderConfig::Profile> ToProtoVideoDecoderConfigProfile(VideoCodecProfile value) { using OriginType = VideoCodecProfile; using OtherType = openscreen::cast::VideoDecoderConfig; @@ -306,10 +306,10 @@ ToProtoVideoDecoderConfigProfile(VideoCodecProfile value) { CASE_RETURN_OTHER(AV1PROFILE_PROFILE_HIGH); CASE_RETURN_OTHER(AV1PROFILE_PROFILE_PRO); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<VideoPixelFormat> ToMediaVideoPixelFormat( +absl::optional<VideoPixelFormat> ToMediaVideoPixelFormat( openscreen::cast::VideoDecoderConfig::Format value) { using OriginType = openscreen::cast::VideoDecoderConfig; using OtherType = VideoPixelFormat; @@ -344,12 +344,12 @@ base::Optional<VideoPixelFormat> ToMediaVideoPixelFormat( CASE_RETURN_OTHER(PIXEL_FORMAT_XB30); // PIXEL_FORMAT_UYVY, PIXEL_FORMAT_RGB32 and PIXEL_FORMAT_Y8 are deprecated. case openscreen::cast::VideoDecoderConfig_Format_PIXEL_FORMAT_RGB32: - return base::nullopt; + return absl::nullopt; } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<BufferingState> ToMediaBufferingState( +absl::optional<BufferingState> ToMediaBufferingState( openscreen::cast::RendererClientOnBufferingStateChange::State value) { using OriginType = openscreen::cast::RendererClientOnBufferingStateChange; using OtherType = BufferingState; @@ -357,10 +357,10 @@ base::Optional<BufferingState> ToMediaBufferingState( CASE_RETURN_OTHER(BUFFERING_HAVE_NOTHING); CASE_RETURN_OTHER(BUFFERING_HAVE_ENOUGH); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<openscreen::cast::RendererClientOnBufferingStateChange::State> +absl::optional<openscreen::cast::RendererClientOnBufferingStateChange::State> ToProtoMediaBufferingState(BufferingState value) { using OriginType = BufferingState; using OtherType = openscreen::cast::RendererClientOnBufferingStateChange; @@ -368,10 +368,10 @@ ToProtoMediaBufferingState(BufferingState value) { CASE_RETURN_OTHER(BUFFERING_HAVE_NOTHING); CASE_RETURN_OTHER(BUFFERING_HAVE_ENOUGH); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<DemuxerStream::Status> ToDemuxerStreamStatus( +absl::optional<DemuxerStream::Status> ToDemuxerStreamStatus( openscreen::cast::DemuxerStreamReadUntilCallback::Status value) { using OriginType = openscreen::cast::DemuxerStreamReadUntilCallback; using OtherType = DemuxerStream; @@ -381,10 +381,10 @@ base::Optional<DemuxerStream::Status> ToDemuxerStreamStatus( CASE_RETURN_OTHER(kConfigChanged); CASE_RETURN_OTHER(kError); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } -base::Optional<openscreen::cast::DemuxerStreamReadUntilCallback::Status> +absl::optional<openscreen::cast::DemuxerStreamReadUntilCallback::Status> ToProtoDemuxerStreamStatus(DemuxerStream::Status value) { using OriginType = DemuxerStream; using OtherType = openscreen::cast::DemuxerStreamReadUntilCallback; @@ -394,7 +394,7 @@ ToProtoDemuxerStreamStatus(DemuxerStream::Status value) { CASE_RETURN_OTHER(kConfigChanged); CASE_RETURN_OTHER(kError); } - return base::nullopt; // Not a 'default' to ensure compile-time checks. + return absl::nullopt; // Not a 'default' to ensure compile-time checks. } } // namespace remoting diff --git a/chromium/media/remoting/proto_enum_utils.h b/chromium/media/remoting/proto_enum_utils.h index d4dd1362024..1748d4f5d16 100644 --- a/chromium/media/remoting/proto_enum_utils.h +++ b/chromium/media/remoting/proto_enum_utils.h @@ -5,7 +5,6 @@ #ifndef MEDIA_REMOTING_PROTO_ENUM_UTILS_H_ #define MEDIA_REMOTING_PROTO_ENUM_UTILS_H_ -#include "base/optional.h" #include "media/base/audio_codecs.h" #include "media/base/buffering_state.h" #include "media/base/channel_layout.h" @@ -13,6 +12,7 @@ #include "media/base/sample_format.h" #include "media/base/video_codecs.h" #include "media/base/video_types.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/openscreen/src/cast/streaming/remoting.pb.h" namespace media { @@ -24,45 +24,45 @@ namespace remoting { // modules while maintaining compile-time checks to ensure that there are always // valid, backwards-compatible mappings between the two. // -// Each returns a base::Optional value. If it is not set, that indicates the +// Each returns a absl::optional value. If it is not set, that indicates the // conversion failed. -base::Optional<AudioCodec> ToMediaAudioCodec( +absl::optional<AudioCodec> ToMediaAudioCodec( openscreen::cast::AudioDecoderConfig::Codec value); -base::Optional<openscreen::cast::AudioDecoderConfig::Codec> +absl::optional<openscreen::cast::AudioDecoderConfig::Codec> ToProtoAudioDecoderConfigCodec(AudioCodec value); -base::Optional<SampleFormat> ToMediaSampleFormat( +absl::optional<SampleFormat> ToMediaSampleFormat( openscreen::cast::AudioDecoderConfig::SampleFormat value); -base::Optional<openscreen::cast::AudioDecoderConfig::SampleFormat> +absl::optional<openscreen::cast::AudioDecoderConfig::SampleFormat> ToProtoAudioDecoderConfigSampleFormat(SampleFormat value); -base::Optional<ChannelLayout> ToMediaChannelLayout( +absl::optional<ChannelLayout> ToMediaChannelLayout( openscreen::cast::AudioDecoderConfig::ChannelLayout value); -base::Optional<openscreen::cast::AudioDecoderConfig::ChannelLayout> +absl::optional<openscreen::cast::AudioDecoderConfig::ChannelLayout> ToProtoAudioDecoderConfigChannelLayout(ChannelLayout value); -base::Optional<VideoCodec> ToMediaVideoCodec( +absl::optional<VideoCodec> ToMediaVideoCodec( openscreen::cast::VideoDecoderConfig::Codec value); -base::Optional<openscreen::cast::VideoDecoderConfig::Codec> +absl::optional<openscreen::cast::VideoDecoderConfig::Codec> ToProtoVideoDecoderConfigCodec(VideoCodec value); -base::Optional<VideoCodecProfile> ToMediaVideoCodecProfile( +absl::optional<VideoCodecProfile> ToMediaVideoCodecProfile( openscreen::cast::VideoDecoderConfig::Profile value); -base::Optional<openscreen::cast::VideoDecoderConfig::Profile> +absl::optional<openscreen::cast::VideoDecoderConfig::Profile> ToProtoVideoDecoderConfigProfile(VideoCodecProfile value); -base::Optional<VideoPixelFormat> ToMediaVideoPixelFormat( +absl::optional<VideoPixelFormat> ToMediaVideoPixelFormat( openscreen::cast::VideoDecoderConfig::Format value); -base::Optional<BufferingState> ToMediaBufferingState( +absl::optional<BufferingState> ToMediaBufferingState( openscreen::cast::RendererClientOnBufferingStateChange::State value); -base::Optional<openscreen::cast::RendererClientOnBufferingStateChange::State> +absl::optional<openscreen::cast::RendererClientOnBufferingStateChange::State> ToProtoMediaBufferingState(BufferingState value); -base::Optional<DemuxerStream::Status> ToDemuxerStreamStatus( +absl::optional<DemuxerStream::Status> ToDemuxerStreamStatus( openscreen::cast::DemuxerStreamReadUntilCallback::Status value); -base::Optional<openscreen::cast::DemuxerStreamReadUntilCallback::Status> +absl::optional<openscreen::cast::DemuxerStreamReadUntilCallback::Status> ToProtoDemuxerStreamStatus(DemuxerStream::Status value); } // namespace remoting diff --git a/chromium/media/remoting/receiver.cc b/chromium/media/remoting/receiver.cc index 80772aaf894..fa5fda9ed55 100644 --- a/chromium/media/remoting/receiver.cc +++ b/chromium/media/remoting/receiver.cc @@ -85,7 +85,7 @@ void Receiver::SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) { } // No-op. Controlled by sender via RPC calls instead. -void Receiver::SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) {} +void Receiver::SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) {} // No-op. Controlled by sender via RPC calls instead. void Receiver::Flush(base::OnceClosure flush_cb) {} @@ -358,7 +358,7 @@ void Receiver::OnVideoOpacityChange(bool opaque) { SendRpcMessageOnMainThread(std::move(rpc)); } -void Receiver::OnVideoFrameRateChange(base::Optional<int>) {} +void Receiver::OnVideoFrameRateChange(absl::optional<int>) {} } // namespace remoting } // namespace media diff --git a/chromium/media/remoting/receiver.h b/chromium/media/remoting/receiver.h index 868329dca49..885dc2e1b74 100644 --- a/chromium/media/remoting/receiver.h +++ b/chromium/media/remoting/receiver.h @@ -54,7 +54,7 @@ class Receiver final : public Renderer, public RendererClient { RendererClient* client, PipelineStatusCallback init_cb) override; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void Flush(base::OnceClosure flush_cb) override; void StartPlayingFrom(base::TimeDelta time) override; void SetPlaybackRate(double playback_rate) override; @@ -72,7 +72,7 @@ class Receiver final : public Renderer, public RendererClient { void OnVideoConfigChange(const VideoDecoderConfig& config) override; void OnVideoNaturalSizeChange(const gfx::Size& size) override; void OnVideoOpacityChange(bool opaque) override; - void OnVideoFrameRateChange(base::Optional<int>) override; + void OnVideoFrameRateChange(absl::optional<int>) override; // Used to set |remote_handle_| after Receiver is created, because the remote // handle might be received after Receiver is created. diff --git a/chromium/media/remoting/receiver_unittest.cc b/chromium/media/remoting/receiver_unittest.cc index 60e74939eb1..e5c46712d62 100644 --- a/chromium/media/remoting/receiver_unittest.cc +++ b/chromium/media/remoting/receiver_unittest.cc @@ -7,7 +7,6 @@ #include <utility> #include "base/check.h" -#include "base/optional.h" #include "base/test/gmock_callback_support.h" #include "base/test/task_environment.h" #include "media/base/audio_decoder_config.h" @@ -21,6 +20,7 @@ #include "media/remoting/proto_utils.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" using base::test::RunOnceCallback; using testing::_; @@ -78,7 +78,7 @@ class MockSender { break; } case openscreen::cast::RpcMessage::RPC_RC_ONBUFFERINGSTATECHANGE: { - base::Optional<BufferingState> state = ToMediaBufferingState( + absl::optional<BufferingState> state = ToMediaBufferingState( message->rendererclient_onbufferingstatechange_rpc().state()); if (state.has_value()) OnBufferingStateChange(state.value()); diff --git a/chromium/media/remoting/renderer_controller.h b/chromium/media/remoting/renderer_controller.h index 4bcc0e1c1b0..72e966dcdab 100644 --- a/chromium/media/remoting/renderer_controller.h +++ b/chromium/media/remoting/renderer_controller.h @@ -9,7 +9,6 @@ #include "base/callback.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/threading/thread_checker.h" #include "base/timer/timer.h" #include "build/build_config.h" @@ -23,6 +22,7 @@ #include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #if BUILDFLAG(ENABLE_MEDIA_REMOTING_RPC) #include "media/remoting/rpc_broker.h" // nogncheck diff --git a/chromium/media/remoting/stream_provider.cc b/chromium/media/remoting/stream_provider.cc index 1966bc51bf0..15c1d134e7b 100644 --- a/chromium/media/remoting/stream_provider.cc +++ b/chromium/media/remoting/stream_provider.cc @@ -477,9 +477,9 @@ int64_t StreamProvider::GetMemoryUsage() const { return 0; } -base::Optional<container_names::MediaContainerName> +absl::optional<container_names::MediaContainerName> StreamProvider::GetContainerForMetrics() const { - return base::Optional<container_names::MediaContainerName>(); + return absl::optional<container_names::MediaContainerName>(); } void StreamProvider::OnEnabledAudioTracksChanged( diff --git a/chromium/media/remoting/stream_provider.h b/chromium/media/remoting/stream_provider.h index 5073bc42852..d7352ab854b 100644 --- a/chromium/media/remoting/stream_provider.h +++ b/chromium/media/remoting/stream_provider.h @@ -52,7 +52,7 @@ class StreamProvider final : public Demuxer { base::TimeDelta GetStartTime() const override; base::Time GetTimelineOffset() const override; int64_t GetMemoryUsage() const override; - base::Optional<container_names::MediaContainerName> GetContainerForMetrics() + absl::optional<container_names::MediaContainerName> GetContainerForMetrics() const override; void OnEnabledAudioTracksChanged(const std::vector<MediaTrack::Id>& track_ids, base::TimeDelta curr_time, diff --git a/chromium/media/renderers/BUILD.gn b/chromium/media/renderers/BUILD.gn index 42981ccb8b3..154f6be4c05 100644 --- a/chromium/media/renderers/BUILD.gn +++ b/chromium/media/renderers/BUILD.gn @@ -26,6 +26,8 @@ source_set("renderers") { "renderer_impl.h", "video_frame_yuv_converter.cc", "video_frame_yuv_converter.h", + "video_frame_yuv_mailboxes_holder.cc", + "video_frame_yuv_mailboxes_holder.h", "video_overlay_factory.cc", "video_overlay_factory.h", "video_renderer_impl.cc", @@ -72,8 +74,6 @@ source_set("renderers") { "win/media_foundation_renderer.cc", "win/media_foundation_renderer.h", "win/media_foundation_renderer_extension.h", - "win/media_foundation_renderer_factory.cc", - "win/media_foundation_renderer_factory.h", "win/media_foundation_source_wrapper.cc", "win/media_foundation_source_wrapper.h", "win/media_foundation_stream_wrapper.cc", diff --git a/chromium/media/renderers/audio_renderer_impl.cc b/chromium/media/renderers/audio_renderer_impl.cc index 587534a9073..cdcae8e2639 100644 --- a/chromium/media/renderers/audio_renderer_impl.cc +++ b/chromium/media/renderers/audio_renderer_impl.cc @@ -641,7 +641,7 @@ void AudioRendererImpl::OnAudioDecoderStreamInitialized(bool success) { auto params = (media_client ? media_client->GetAudioRendererAlgorithmParameters( audio_parameters_) - : base::nullopt); + : absl::nullopt); if (params && !client_->IsVideoStreamAvailable()) { algorithm_ = std::make_unique<AudioRendererAlgorithm>(media_log_, params.value()); @@ -777,7 +777,7 @@ void AudioRendererImpl::SetVolume(float volume) { } void AudioRendererImpl::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { base::AutoLock auto_lock(lock_); latency_hint_ = latency_hint; diff --git a/chromium/media/renderers/audio_renderer_impl.h b/chromium/media/renderers/audio_renderer_impl.h index 90d5a18a089..d9ea713331c 100644 --- a/chromium/media/renderers/audio_renderer_impl.h +++ b/chromium/media/renderers/audio_renderer_impl.h @@ -25,7 +25,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/power_monitor/power_observer.h" #include "base/synchronization/lock.h" #include "media/base/audio_decoder.h" @@ -38,6 +37,7 @@ #include "media/filters/audio_renderer_algorithm.h" #include "media/filters/decoder_stream.h" #include "media/renderers/default_renderer_factory.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace base { class SingleThreadTaskRunner; @@ -99,7 +99,7 @@ class MEDIA_EXPORT AudioRendererImpl void Flush(base::OnceClosure callback) override; void StartPlaying() override; void SetVolume(float volume) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void SetPreservesPitch(bool preserves_pitch) override; void SetAutoplayInitiated(bool autoplay_initiated) override; @@ -310,7 +310,7 @@ class MEDIA_EXPORT AudioRendererImpl // Stored value from last call to SetLatencyHint(). Passed to |algorithm_| // during Initialize(). - base::Optional<base::TimeDelta> latency_hint_; + absl::optional<base::TimeDelta> latency_hint_; // Passed to |algorithm_|. Indicates whether |algorithm_| should or should not // make pitch adjustments at playbacks other than 1.0. diff --git a/chromium/media/renderers/audio_renderer_impl_unittest.cc b/chromium/media/renderers/audio_renderer_impl_unittest.cc index 7f25d00afee..101fd5f218c 100644 --- a/chromium/media/renderers/audio_renderer_impl_unittest.cc +++ b/chromium/media/renderers/audio_renderer_impl_unittest.cc @@ -222,7 +222,7 @@ class AudioRendererImplTest : public ::testing::Test, public RendererClient { MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&)); MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&)); MOCK_METHOD1(OnVideoOpacityChange, void(bool)); - MOCK_METHOD1(OnVideoFrameRateChange, void(base::Optional<int>)); + MOCK_METHOD1(OnVideoFrameRateChange, void(absl::optional<int>)); MOCK_METHOD1(OnDurationChange, void(base::TimeDelta)); MOCK_METHOD1(OnRemotePlayStateChange, void(MediaStatus::State state)); MOCK_METHOD1(TranscribeAudioCallback, void(scoped_refptr<AudioBuffer>)); diff --git a/chromium/media/renderers/decrypting_renderer.cc b/chromium/media/renderers/decrypting_renderer.cc index 346a774f33e..d1d21d9e5c8 100644 --- a/chromium/media/renderers/decrypting_renderer.cc +++ b/chromium/media/renderers/decrypting_renderer.cc @@ -107,7 +107,7 @@ void DecryptingRenderer::SetCdm(CdmContext* cdm_context, } void DecryptingRenderer::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { renderer_->SetLatencyHint(latency_hint); } diff --git a/chromium/media/renderers/decrypting_renderer.h b/chromium/media/renderers/decrypting_renderer.h index a51d2482bf3..d803b7504ff 100644 --- a/chromium/media/renderers/decrypting_renderer.h +++ b/chromium/media/renderers/decrypting_renderer.h @@ -45,7 +45,7 @@ class MEDIA_EXPORT DecryptingRenderer : public Renderer { RendererClient* client, PipelineStatusCallback init_cb) override; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void SetPreservesPitch(bool preserves_pitch) override; void SetAutoplayInitiated(bool autoplay_initiated) override; diff --git a/chromium/media/renderers/default_decoder_factory.cc b/chromium/media/renderers/default_decoder_factory.cc index eafe4947f40..5e242d3623a 100644 --- a/chromium/media/renderers/default_decoder_factory.cc +++ b/chromium/media/renderers/default_decoder_factory.cc @@ -100,15 +100,6 @@ DefaultDecoderFactory::GetSupportedVideoDecoderConfigsForWebRTC() { } } -#if defined(OS_FUCHSIA) - // TODO(crbug.com/1173503): Implement capabilities for fuchsia. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableSoftwareVideoDecoders)) { - // Bypass software codec registration. - return supported_configs; - } -#endif - if (!base::FeatureList::IsEnabled(media::kExposeSwDecodersToWebRTC)) return supported_configs; @@ -191,12 +182,6 @@ void DefaultDecoderFactory::CreateVideoDecoders( << "Can't create FuchsiaVideoDecoder due to GPU context loss."; } } - - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableSoftwareVideoDecoders)) { - // Bypass software codec registration. - return; - } #endif #if BUILDFLAG(ENABLE_LIBVPX) diff --git a/chromium/media/renderers/paint_canvas_video_renderer.cc b/chromium/media/renderers/paint_canvas_video_renderer.cc index fd23d7d3740..cb27f53305f 100644 --- a/chromium/media/renderers/paint_canvas_video_renderer.cc +++ b/chromium/media/renderers/paint_canvas_video_renderer.cc @@ -812,7 +812,7 @@ void PaintCanvasVideoRenderer::Paint( cc::PaintImage image = cache_->paint_image; DCHECK(image); - base::Optional<ScopedSharedImageAccess> source_access; + absl::optional<ScopedSharedImageAccess> source_access; if (video_frame->HasTextures() && cache_->source_texture) { DCHECK(cache_->texture_backing); source_access.emplace(raster_context_provider->RasterInterface(), @@ -896,21 +896,19 @@ void PaintCanvasVideoRenderer::Paint( } else if (video_frame->HasTextures()) { DCHECK_EQ(video_frame->coded_size(), gfx::Size(image.width(), image.height())); - canvas->drawImageRect( - image, gfx::RectToSkRect(video_frame->visible_rect()), - SkRect::MakeWH(video_frame->visible_rect().width(), - video_frame->visible_rect().height()), - SkSamplingOptions(flags.getFilterQuality(), - SkSamplingOptions::kMedium_asMipmapLinear), - &video_flags, SkCanvas::kStrict_SrcRectConstraint); + canvas->drawImageRect(image, gfx::RectToSkRect(video_frame->visible_rect()), + SkRect::MakeWH(video_frame->visible_rect().width(), + video_frame->visible_rect().height()), + cc::PaintFlags::FilterQualityToSkSamplingOptions( + flags.getFilterQuality()), + &video_flags, SkCanvas::kStrict_SrcRectConstraint); } else { DCHECK_EQ(video_frame->visible_rect().size(), gfx::Size(image.width(), image.height())); - canvas->drawImage( - image, 0, 0, - SkSamplingOptions(flags.getFilterQuality(), - SkSamplingOptions::kMedium_asMipmapLinear), - &video_flags); + canvas->drawImage(image, 0, 0, + cc::PaintFlags::FilterQualityToSkSamplingOptions( + flags.getFilterQuality()), + &video_flags); } if (need_transform) @@ -1477,7 +1475,8 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameYUVDataToGLTexture( int level, bool premultiply_alpha, bool flip_y) { - DCHECK(raster_context_provider); + if (!raster_context_provider) + return false; #if defined(OS_ANDROID) // TODO(crbug.com/1181993): These formats don't work with the passthrough // command decoder on Android for some reason. diff --git a/chromium/media/renderers/paint_canvas_video_renderer.h b/chromium/media/renderers/paint_canvas_video_renderer.h index c7c6bec8e10..b8ad267ab88 100644 --- a/chromium/media/renderers/paint_canvas_video_renderer.h +++ b/chromium/media/renderers/paint_canvas_video_renderer.h @@ -10,9 +10,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/optional.h" #include "base/threading/thread_checker.h" -#include "base/time/time.h" #include "base/timer/timer.h" #include "cc/paint/paint_canvas.h" #include "cc/paint/paint_flags.h" @@ -23,6 +21,7 @@ #include "media/base/video_frame.h" #include "media/base/video_transformation.h" #include "media/renderers/video_frame_yuv_converter.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace gfx { class RectF; @@ -258,7 +257,7 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer { bool CacheBackingWrapsTexture() const; - base::Optional<Cache> cache_; + absl::optional<Cache> cache_; // If |cache_| is not used for a while, it's deleted to save memory. base::DelayTimer cache_deleting_timer_; diff --git a/chromium/media/renderers/paint_canvas_video_renderer_unittest.cc b/chromium/media/renderers/paint_canvas_video_renderer_unittest.cc index b85126b2bbe..acfa87f7662 100644 --- a/chromium/media/renderers/paint_canvas_video_renderer_unittest.cc +++ b/chromium/media/renderers/paint_canvas_video_renderer_unittest.cc @@ -162,8 +162,7 @@ static SkBitmap AllocBitmap(int width, int height) { } static scoped_refptr<VideoFrame> CreateCroppedFrame() { - scoped_refptr<VideoFrame> cropped_frame; - cropped_frame = VideoFrame::CreateFrame( + scoped_refptr<VideoFrame> cropped_frame = VideoFrame::CreateFrame( PIXEL_FORMAT_I420, gfx::Size(16, 16), gfx::Rect(6, 6, 8, 6), gfx::Size(8, 6), base::TimeDelta::FromMilliseconds(4)); // Make sure the cropped video frame's aspect ratio matches the output device. @@ -1078,7 +1077,7 @@ class PaintCanvasVideoRendererWithGLTest : public testing::TestWithParam<bool> { scoped_refptr<VideoFrame> cropped_frame() { return cropped_frame_; } protected: - base::Optional<gl::DisableNullDrawGLBindings> enable_pixels_; + absl::optional<gl::DisableNullDrawGLBindings> enable_pixels_; scoped_refptr<viz::TestInProcessContextProvider> media_context_; scoped_refptr<viz::TestInProcessContextProvider> gles2_context_; scoped_refptr<viz::TestInProcessContextProvider> destination_context_; diff --git a/chromium/media/renderers/renderer_impl.cc b/chromium/media/renderers/renderer_impl.cc index 049ffcf0883..7357ba495f2 100644 --- a/chromium/media/renderers/renderer_impl.cc +++ b/chromium/media/renderers/renderer_impl.cc @@ -65,7 +65,7 @@ class RendererImpl::RendererClientInternal final : public RendererClient { DCHECK(type_ == DemuxerStream::VIDEO); renderer_->OnVideoOpacityChange(opaque); } - void OnVideoFrameRateChange(base::Optional<int> fps) override { + void OnVideoFrameRateChange(absl::optional<int> fps) override { DCHECK(type_ == DemuxerStream::VIDEO); renderer_->OnVideoFrameRateChange(fps); } @@ -178,7 +178,7 @@ void RendererImpl::SetCdm(CdmContext* cdm_context, } void RendererImpl::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { DVLOG(1) << __func__; DCHECK(!latency_hint || (*latency_hint >= base::TimeDelta())); DCHECK(task_runner_->BelongsToCurrentThread()); @@ -950,7 +950,7 @@ void RendererImpl::OnVideoOpacityChange(bool opaque) { client_->OnVideoOpacityChange(opaque); } -void RendererImpl::OnVideoFrameRateChange(base::Optional<int> fps) { +void RendererImpl::OnVideoFrameRateChange(absl::optional<int> fps) { DCHECK(task_runner_->BelongsToCurrentThread()); client_->OnVideoFrameRateChange(fps); } diff --git a/chromium/media/renderers/renderer_impl.h b/chromium/media/renderers/renderer_impl.h index 5c0d688aa6e..69abeb247da 100644 --- a/chromium/media/renderers/renderer_impl.h +++ b/chromium/media/renderers/renderer_impl.h @@ -58,7 +58,7 @@ class MEDIA_EXPORT RendererImpl final : public Renderer { RendererClient* client, PipelineStatusCallback init_cb) final; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) final; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) final; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) final; void SetPreservesPitch(bool preserves_pitch) final; void SetAutoplayInitiated(bool autoplay_initiated) final; void Flush(base::OnceClosure flush_cb) final; @@ -199,7 +199,7 @@ class MEDIA_EXPORT RendererImpl final : public Renderer { void OnAudioConfigChange(const AudioDecoderConfig& config); void OnVideoConfigChange(const VideoDecoderConfig& config); void OnVideoOpacityChange(bool opaque); - void OnVideoFrameRateChange(base::Optional<int> fps); + void OnVideoFrameRateChange(absl::optional<int> fps); void OnStreamRestartCompleted(); diff --git a/chromium/media/renderers/renderer_impl_unittest.cc b/chromium/media/renderers/renderer_impl_unittest.cc index 4ac4867400a..a7e80c0ca91 100644 --- a/chromium/media/renderers/renderer_impl_unittest.cc +++ b/chromium/media/renderers/renderer_impl_unittest.cc @@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/macros.h" -#include "base/optional.h" #include "base/run_loop.h" #include "base/test/gmock_callback_support.h" #include "base/test/gmock_move_support.h" @@ -21,6 +20,7 @@ #include "media/base/test_helpers.h" #include "media/renderers/renderer_impl.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" using ::base::test::RunCallback; using ::base::test::RunClosure; diff --git a/chromium/media/renderers/video_frame_yuv_converter.cc b/chromium/media/renderers/video_frame_yuv_converter.cc index 6eded70dac3..e2f04012210 100644 --- a/chromium/media/renderers/video_frame_yuv_converter.cc +++ b/chromium/media/renderers/video_frame_yuv_converter.cc @@ -12,6 +12,7 @@ #include "gpu/command_buffer/client/shared_image_interface.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "media/base/video_frame.h" +#include "media/renderers/video_frame_yuv_mailboxes_holder.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -26,50 +27,6 @@ namespace media { namespace { -SkYUVColorSpace ColorSpaceToSkYUVColorSpace( - const gfx::ColorSpace& color_space) { - // TODO(crbug.com/828599): This should really default to rec709. - SkYUVColorSpace sk_color_space = kRec601_SkYUVColorSpace; - color_space.ToSkYUVColorSpace(&sk_color_space); - return sk_color_space; -} - -viz::ResourceFormat PlaneResourceFormat(int num_channels) { - switch (num_channels) { - case 1: - return viz::LUMINANCE_8; - case 2: - return viz::RG_88; - case 3: - return viz::RGBX_8888; - case 4: - return viz::RGBA_8888; - } - NOTREACHED(); - return viz::RGBA_8888; -} - -GLenum PlaneGLFormat(int num_channels) { - return viz::TextureStorageFormat(PlaneResourceFormat(num_channels)); -} - -std::tuple<SkYUVAInfo::PlaneConfig, SkYUVAInfo::Subsampling> -VideoPixelFormatToSkiaValues(VideoPixelFormat video_format) { - // To expand support for additional VideoFormats expand this switch. Note that - // we do assume 8 bit formats. With that exception, anything else should work. - switch (video_format) { - case PIXEL_FORMAT_NV12: - return {SkYUVAInfo::PlaneConfig::kY_UV, SkYUVAInfo::Subsampling::k420}; - case PIXEL_FORMAT_I420: - return {SkYUVAInfo::PlaneConfig::kY_U_V, SkYUVAInfo::Subsampling::k420}; - case PIXEL_FORMAT_I420A: - return {SkYUVAInfo::PlaneConfig::kY_U_V_A, SkYUVAInfo::Subsampling::k420}; - default: - return {SkYUVAInfo::PlaneConfig::kUnknown, - SkYUVAInfo::Subsampling::kUnknown}; - } -} - SkColorType GetCompatibleSurfaceColorType(GrGLenum format) { switch (format) { case GL_RGBA8: @@ -132,22 +89,6 @@ bool DrawYUVImageToSkSurface(const VideoFrame* video_frame, return true; } -bool YUVGrBackendTexturesToSkSurface( - GrDirectContext* gr_context, - const VideoFrame* video_frame, - const GrYUVABackendTextures& yuva_backend_textures, - sk_sp<SkSurface> surface, - bool use_visible_rect) { - auto image = SkImage::MakeFromYUVATextures(gr_context, yuva_backend_textures, - SkColorSpace::MakeSRGB()); - - if (!image) { - return false; - } - - return DrawYUVImageToSkSurface(video_frame, image, surface, use_visible_rect); -} - bool YUVPixmapsToSkSurface(GrDirectContext* gr_context, const VideoFrame* video_frame, const SkYUVAPixmaps yuva_pixmaps, @@ -166,281 +107,13 @@ bool YUVPixmapsToSkSurface(GrDirectContext* gr_context, } // namespace -class VideoFrameYUVConverter::VideoFrameYUVMailboxesHolder { - public: - VideoFrameYUVMailboxesHolder() = default; - ~VideoFrameYUVMailboxesHolder() { ReleaseCachedData(); } - - void ReleaseCachedData(); - void ReleaseTextures(); - - // Extracts shared image information if |video_frame| is texture backed or - // creates new shared images and uploads YUV data to GPU if |video_frame| is - // mappable. This function can be called repeatedly to re-use shared images in - // the case of CPU backed VideoFrames. The planes are returned in |mailboxes|. - void VideoFrameToMailboxes( - const VideoFrame* video_frame, - viz::RasterContextProvider* raster_context_provider, - gpu::Mailbox mailboxes[]); - - // Like VideoFrameToMailboxes but imports the textures from the mailboxes and - // returns the planes as a set of YUVA GrBackendTextures. - GrYUVABackendTextures VideoFrameToSkiaTextures( - const VideoFrame* video_frame, - viz::RasterContextProvider* raster_context_provider); - - SkYUVAPixmaps VideoFrameToSkiaPixmaps(const VideoFrame* video_frame); - - SkYUVAInfo::PlaneConfig plane_config() const { return plane_config_; } - - SkYUVAInfo::Subsampling subsampling() const { return subsampling_; } - - private: - static constexpr size_t kMaxPlanes = - static_cast<size_t>(SkYUVAInfo::kMaxPlanes); - - void ImportTextures(); - size_t NumPlanes() { - return static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config_)); - } - - scoped_refptr<viz::RasterContextProvider> provider_; - bool imported_textures_ = false; - SkYUVAInfo::PlaneConfig plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown; - SkYUVAInfo::Subsampling subsampling_ = SkYUVAInfo::Subsampling::kUnknown; - bool created_shared_images_ = false; - gfx::Size cached_video_size_; - gfx::ColorSpace cached_video_color_space_; - std::array<gpu::MailboxHolder, kMaxPlanes> holders_; - - struct YUVPlaneTextureInfo { - GrGLTextureInfo texture = {0, 0}; - bool is_shared_image = false; - }; - std::array<YUVPlaneTextureInfo, kMaxPlanes> textures_; -}; - -void VideoFrameYUVConverter::VideoFrameYUVMailboxesHolder::ReleaseCachedData() { - if (holders_[0].mailbox.IsZero()) - return; - - ReleaseTextures(); - - // Don't destroy shared images we don't own. - if (!created_shared_images_) - return; - - auto* ri = provider_->RasterInterface(); - DCHECK(ri); - gpu::SyncToken token; - ri->GenUnverifiedSyncTokenCHROMIUM(token.GetData()); - - auto* sii = provider_->SharedImageInterface(); - DCHECK(sii); - for (auto& mailbox_holder : holders_) { - if (!mailbox_holder.mailbox.IsZero()) - sii->DestroySharedImage(token, mailbox_holder.mailbox); - mailbox_holder.mailbox.SetZero(); - } - - created_shared_images_ = false; -} - -void VideoFrameYUVConverter::VideoFrameYUVMailboxesHolder:: - VideoFrameToMailboxes(const VideoFrame* video_frame, - viz::RasterContextProvider* raster_context_provider, - gpu::Mailbox mailboxes[]) { - std::tie(plane_config_, subsampling_) = - VideoPixelFormatToSkiaValues(video_frame->format()); - DCHECK_NE(plane_config_, SkYUVAInfo::PlaneConfig::kUnknown); - - // If we have cached shared images but the provider or video has changed we - // need to release shared images created on the old context and recreate them. - if (created_shared_images_ && - (provider_.get() != raster_context_provider || - video_frame->coded_size() != cached_video_size_ || - video_frame->ColorSpace() != cached_video_color_space_)) - ReleaseCachedData(); - provider_ = raster_context_provider; - DCHECK(provider_); - auto* ri = provider_->RasterInterface(); - DCHECK(ri); - - gfx::Size video_size = video_frame->coded_size(); - SkISize plane_sizes[SkYUVAInfo::kMaxPlanes]; - size_t num_planes = SkYUVAInfo::PlaneDimensions( - {video_size.width(), video_size.height()}, plane_config_, subsampling_, - kTopLeft_SkEncodedOrigin, plane_sizes); - - if (video_frame->HasTextures()) { - DCHECK_EQ(num_planes, video_frame->NumTextures()); - for (size_t plane = 0; plane < video_frame->NumTextures(); ++plane) { - holders_[plane] = video_frame->mailbox_holder(plane); - DCHECK(holders_[plane].texture_target == GL_TEXTURE_2D || - holders_[plane].texture_target == GL_TEXTURE_EXTERNAL_OES || - holders_[plane].texture_target == GL_TEXTURE_RECTANGLE_ARB) - << "Unsupported texture target " << std::hex << std::showbase - << holders_[plane].texture_target; - ri->WaitSyncTokenCHROMIUM(holders_[plane].sync_token.GetConstData()); - mailboxes[plane] = holders_[plane].mailbox; - } - } else { - if (!created_shared_images_) { - auto* sii = provider_->SharedImageInterface(); - DCHECK(sii); - uint32_t mailbox_usage; - if (provider_->ContextCapabilities().supports_oop_raster) { - mailbox_usage = gpu::SHARED_IMAGE_USAGE_RASTER | - gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION; - } else { - mailbox_usage = gpu::SHARED_IMAGE_USAGE_GLES2; - } - for (size_t plane = 0; plane < num_planes; ++plane) { - gfx::Size tex_size = {plane_sizes[plane].width(), - plane_sizes[plane].height()}; - int num_channels = SkYUVAInfo::NumChannelsInPlane(plane_config_, plane); - viz::ResourceFormat format = PlaneResourceFormat(num_channels); - holders_[plane].mailbox = sii->CreateSharedImage( - format, tex_size, video_frame->ColorSpace(), - kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, mailbox_usage, - gpu::kNullSurfaceHandle); - holders_[plane].texture_target = GL_TEXTURE_2D; - } - - // Split up shared image creation from upload so we only have to wait on - // one sync token. - ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); - - cached_video_size_ = video_frame->coded_size(); - cached_video_color_space_ = video_frame->ColorSpace(); - created_shared_images_ = true; - } - - // If we have cached shared images that have been imported release them to - // prevent writing to a shared image for which we're holding read access. - ReleaseTextures(); - - for (size_t plane = 0; plane < num_planes; ++plane) { - int num_channels = SkYUVAInfo::NumChannelsInPlane(plane_config_, plane); - SkColorType color_type = SkYUVAPixmapInfo::DefaultColorTypeForDataType( - SkYUVAPixmaps::DataType::kUnorm8, num_channels); - SkImageInfo info = SkImageInfo::Make(plane_sizes[plane], color_type, - kUnknown_SkAlphaType); - ri->WritePixels(holders_[plane].mailbox, 0, 0, GL_TEXTURE_2D, - video_frame->stride(plane), info, - video_frame->data(plane)); - mailboxes[plane] = holders_[plane].mailbox; - } - } -} - -GrYUVABackendTextures -VideoFrameYUVConverter::VideoFrameYUVMailboxesHolder::VideoFrameToSkiaTextures( - const VideoFrame* video_frame, - viz::RasterContextProvider* raster_context_provider) { - gpu::Mailbox mailboxes[kMaxPlanes]; - VideoFrameToMailboxes(video_frame, raster_context_provider, mailboxes); - ImportTextures(); - SkISize video_size{video_frame->coded_size().width(), - video_frame->coded_size().height()}; - SkYUVAInfo yuva_info(video_size, plane_config_, subsampling_, - ColorSpaceToSkYUVColorSpace(video_frame->ColorSpace())); - GrBackendTexture backend_textures[SkYUVAInfo::kMaxPlanes]; - SkISize plane_sizes[SkYUVAInfo::kMaxPlanes]; - int num_planes = yuva_info.planeDimensions(plane_sizes); - for (int i = 0; i < num_planes; ++i) { - backend_textures[i] = {plane_sizes[i].width(), plane_sizes[i].height(), - GrMipmapped::kNo, textures_[i].texture}; - } - return GrYUVABackendTextures(yuva_info, backend_textures, - kTopLeft_GrSurfaceOrigin); -} - -SkYUVAPixmaps -VideoFrameYUVConverter::VideoFrameYUVMailboxesHolder::VideoFrameToSkiaPixmaps( - const VideoFrame* video_frame) { - std::tie(plane_config_, subsampling_) = - VideoPixelFormatToSkiaValues(video_frame->format()); - DCHECK_NE(plane_config_, SkYUVAInfo::PlaneConfig::kUnknown); - - SkISize video_size{video_frame->coded_size().width(), - video_frame->coded_size().height()}; - SkYUVAInfo yuva_info(video_size, plane_config_, subsampling_, - ColorSpaceToSkYUVColorSpace(video_frame->ColorSpace())); - SkPixmap pixmaps[SkYUVAInfo::kMaxPlanes]; - SkISize plane_sizes[SkYUVAInfo::kMaxPlanes]; - int num_planes = yuva_info.planeDimensions(plane_sizes); - - // Create SkImageInfos with the appropriate color types for 8 bit unorm data - // based on plane config. - size_t row_bytes[kMaxPlanes]; - for (int i = 0; i < num_planes; ++i) { - row_bytes[i] = - VideoFrame::RowBytes(i, video_frame->format(), plane_sizes[i].width()); - } - - SkYUVAPixmapInfo pixmaps_infos(yuva_info, SkYUVAPixmaps::DataType::kUnorm8, - row_bytes); - - for (int i = 0; i < num_planes; ++i) { - pixmaps[i].reset(pixmaps_infos.planeInfo(i), video_frame->data(i), - pixmaps_infos.rowBytes(i)); - } - - return SkYUVAPixmaps::FromExternalPixmaps(yuva_info, pixmaps); -} - -void VideoFrameYUVConverter::VideoFrameYUVMailboxesHolder::ImportTextures() { - DCHECK(!imported_textures_) - << "Textures should always be released after converting video frame. " - "Call ReleaseTextures() for each call to VideoFrameToSkiaTextures()"; - - auto* ri = provider_->RasterInterface(); - for (size_t plane = 0; plane < NumPlanes(); ++plane) { - textures_[plane].texture.fID = - ri->CreateAndConsumeForGpuRaster(holders_[plane].mailbox); - if (holders_[plane].mailbox.IsSharedImage()) { - textures_[plane].is_shared_image = true; - ri->BeginSharedImageAccessDirectCHROMIUM( - textures_[plane].texture.fID, - GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM); - } - - int num_channels = SkYUVAInfo::NumChannelsInPlane(plane_config_, plane); - textures_[plane].texture.fTarget = holders_[plane].texture_target; - textures_[plane].texture.fFormat = PlaneGLFormat(num_channels); - } - - imported_textures_ = true; -} - -void VideoFrameYUVConverter::VideoFrameYUVMailboxesHolder::ReleaseTextures() { - if (!imported_textures_) - return; - - auto* ri = provider_->RasterInterface(); - DCHECK(ri); - for (auto& tex_info : textures_) { - if (!tex_info.texture.fID) - continue; - - if (tex_info.is_shared_image) - ri->EndSharedImageAccessDirectCHROMIUM(tex_info.texture.fID); - ri->DeleteGpuRasterTexture(tex_info.texture.fID); - - tex_info.texture.fID = 0; - } - - imported_textures_ = false; -} - VideoFrameYUVConverter::VideoFrameYUVConverter() = default; VideoFrameYUVConverter::~VideoFrameYUVConverter() = default; bool VideoFrameYUVConverter::IsVideoFrameFormatSupported( const VideoFrame& video_frame) { - return std::get<0>(VideoPixelFormatToSkiaValues(video_frame.format())) != - SkYUVAInfo::PlaneConfig::kUnknown; + return std::get<0>(VideoFrameYUVMailboxesHolder::VideoPixelFormatToSkiaValues( + video_frame.format())) != SkYUVAInfo::PlaneConfig::kUnknown; } bool VideoFrameYUVConverter::ConvertYUVVideoFrameNoCaching( @@ -481,15 +154,14 @@ bool VideoFrameYUVConverter::ConvertYUVVideoFrame( auto* ri = raster_context_provider->RasterInterface(); DCHECK(ri); ri->WaitSyncTokenCHROMIUM(dest_mailbox_holder.sync_token.GetConstData()); - SkYUVColorSpace color_space = - ColorSpaceToSkYUVColorSpace(video_frame->ColorSpace()); gpu::Mailbox mailboxes[SkYUVAInfo::kMaxPlanes]{}; holder_->VideoFrameToMailboxes(video_frame, raster_context_provider, mailboxes); - ri->ConvertYUVAMailboxesToRGB(dest_mailbox_holder.mailbox, color_space, - holder_->plane_config(), holder_->subsampling(), - mailboxes); + ri->ConvertYUVAMailboxesToRGB(dest_mailbox_holder.mailbox, + holder_->yuva_info().yuvColorSpace(), + holder_->yuva_info().planeConfig(), + holder_->yuva_info().subsampling(), mailboxes); return true; } @@ -594,13 +266,11 @@ bool VideoFrameYUVConverter::ConvertFromVideoFrameYUVSkia( result = YUVPixmapsToSkSurface(gr_context, video_frame, yuva_pixmaps, surface, use_visible_rect); } else { - GrYUVABackendTextures yuva_backend_textures = - holder_->VideoFrameToSkiaTextures(video_frame, raster_context_provider); - DCHECK(yuva_backend_textures.isValid()); + auto image = + holder_->VideoFrameToSkImage(video_frame, raster_context_provider); + result = + DrawYUVImageToSkSurface(video_frame, image, surface, use_visible_rect); - result = YUVGrBackendTexturesToSkSurface(gr_context, video_frame, - yuva_backend_textures, surface, - use_visible_rect); // Release textures to guarantee |holder_| doesn't hold read access on // textures it doesn't own. holder_->ReleaseTextures(); diff --git a/chromium/media/renderers/video_frame_yuv_converter.h b/chromium/media/renderers/video_frame_yuv_converter.h index c8e761fece9..c7f4759e212 100644 --- a/chromium/media/renderers/video_frame_yuv_converter.h +++ b/chromium/media/renderers/video_frame_yuv_converter.h @@ -20,6 +20,7 @@ class RasterContextProvider; namespace media { class VideoFrame; +class VideoFrameYUVMailboxesHolder; // Converts YUV video frames to RGB format and stores the results in the // provided mailbox. The caller of functions in this class maintains ownership @@ -87,9 +88,8 @@ class MEDIA_EXPORT VideoFrameYUVConverter { bool use_visible_rect, bool use_sk_pixmap); - class VideoFrameYUVMailboxesHolder; std::unique_ptr<VideoFrameYUVMailboxesHolder> holder_; }; } // namespace media -#endif // MEDIA_RENDERERS_VIDEO_FRAME_YUV_CONVERTER_H_
\ No newline at end of file +#endif // MEDIA_RENDERERS_VIDEO_FRAME_YUV_CONVERTER_H_ diff --git a/chromium/media/renderers/video_frame_yuv_mailboxes_holder.cc b/chromium/media/renderers/video_frame_yuv_mailboxes_holder.cc new file mode 100644 index 00000000000..495a96081be --- /dev/null +++ b/chromium/media/renderers/video_frame_yuv_mailboxes_holder.cc @@ -0,0 +1,346 @@ +// Copyright 2021 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/renderers/video_frame_yuv_mailboxes_holder.h" + +#include <GLES3/gl3.h> + +#include "base/logging.h" +#include "components/viz/common/gpu/raster_context_provider.h" +#include "components/viz/common/resources/resource_format_utils.h" +#include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/raster_interface.h" +#include "gpu/command_buffer/client/shared_image_interface.h" +#include "gpu/command_buffer/common/shared_image_usage.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/include/core/SkYUVAPixmaps.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" +#include "third_party/skia/include/gpu/gl/GrGLTypes.h" + +namespace media { + +namespace { + +viz::ResourceFormat PlaneResourceFormat(int num_channels, bool for_surface) { + switch (num_channels) { + case 1: + return for_surface ? viz::RED_8 : viz::LUMINANCE_8; + case 2: + return viz::RG_88; + case 3: + return viz::RGBX_8888; + case 4: + return viz::RGBA_8888; + } + NOTREACHED(); + return viz::RGBA_8888; +} + +GLenum PlaneGLFormat(int num_channels, bool for_surface) { + return viz::TextureStorageFormat( + PlaneResourceFormat(num_channels, for_surface)); +} + +} // namespace + +VideoFrameYUVMailboxesHolder::VideoFrameYUVMailboxesHolder() = default; + +VideoFrameYUVMailboxesHolder::~VideoFrameYUVMailboxesHolder() { + ReleaseCachedData(); +} + +void VideoFrameYUVMailboxesHolder::ReleaseCachedData() { + if (holders_[0].mailbox.IsZero()) + return; + + ReleaseTextures(); + + // Don't destroy shared images we don't own. + if (!created_shared_images_) + return; + + auto* ri = provider_->RasterInterface(); + DCHECK(ri); + gpu::SyncToken token; + ri->GenUnverifiedSyncTokenCHROMIUM(token.GetData()); + + auto* sii = provider_->SharedImageInterface(); + DCHECK(sii); + for (auto& mailbox_holder : holders_) { + if (!mailbox_holder.mailbox.IsZero()) + sii->DestroySharedImage(token, mailbox_holder.mailbox); + mailbox_holder.mailbox.SetZero(); + } + + created_shared_images_ = false; +} + +void VideoFrameYUVMailboxesHolder::VideoFrameToMailboxes( + const VideoFrame* video_frame, + viz::RasterContextProvider* raster_context_provider, + gpu::Mailbox mailboxes[SkYUVAInfo::kMaxPlanes]) { + yuva_info_ = VideoFrameGetSkYUVAInfo(video_frame); + num_planes_ = yuva_info_.planeDimensions(plane_sizes_); + + // If we have cached shared images but the provider or video has changed we + // need to release shared images created on the old context and recreate them. + if (created_shared_images_ && + (provider_.get() != raster_context_provider || + video_frame->coded_size() != cached_video_size_ || + video_frame->ColorSpace() != cached_video_color_space_)) { + ReleaseCachedData(); + } + provider_ = raster_context_provider; + DCHECK(provider_); + auto* ri = provider_->RasterInterface(); + DCHECK(ri); + + if (video_frame->HasTextures()) { + DCHECK_EQ(num_planes_, video_frame->NumTextures()); + for (size_t plane = 0; plane < video_frame->NumTextures(); ++plane) { + holders_[plane] = video_frame->mailbox_holder(plane); + DCHECK(holders_[plane].texture_target == GL_TEXTURE_2D || + holders_[plane].texture_target == GL_TEXTURE_EXTERNAL_OES || + holders_[plane].texture_target == GL_TEXTURE_RECTANGLE_ARB) + << "Unsupported texture target " << std::hex << std::showbase + << holders_[plane].texture_target; + ri->WaitSyncTokenCHROMIUM(holders_[plane].sync_token.GetConstData()); + mailboxes[plane] = holders_[plane].mailbox; + } + return; + } + + // Create a shared image to upload the data to, if one doesn't exist already. + if (!created_shared_images_) { + auto* sii = provider_->SharedImageInterface(); + DCHECK(sii); + uint32_t mailbox_usage; + if (provider_->ContextCapabilities().supports_oop_raster) { + mailbox_usage = gpu::SHARED_IMAGE_USAGE_RASTER | + gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION; + } else { + mailbox_usage = gpu::SHARED_IMAGE_USAGE_GLES2; + } + for (size_t plane = 0; plane < num_planes_; ++plane) { + gfx::Size tex_size = {plane_sizes_[plane].width(), + plane_sizes_[plane].height()}; + int num_channels = yuva_info_.numChannelsInPlane(plane); + viz::ResourceFormat format = PlaneResourceFormat(num_channels, false); + holders_[plane].mailbox = sii->CreateSharedImage( + format, tex_size, video_frame->ColorSpace(), kTopLeft_GrSurfaceOrigin, + kPremul_SkAlphaType, mailbox_usage, gpu::kNullSurfaceHandle); + holders_[plane].texture_target = GL_TEXTURE_2D; + } + + // Split up shared image creation from upload so we only have to wait on + // one sync token. + ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData()); + + cached_video_size_ = video_frame->coded_size(); + cached_video_color_space_ = video_frame->ColorSpace(); + created_shared_images_ = true; + } + + // If we have cached shared images that have been imported release them to + // prevent writing to a shared image for which we're holding read access. + ReleaseTextures(); + + for (size_t plane = 0; plane < num_planes_; ++plane) { + int num_channels = yuva_info_.numChannelsInPlane(plane); + SkColorType color_type = SkYUVAPixmapInfo::DefaultColorTypeForDataType( + SkYUVAPixmaps::DataType::kUnorm8, num_channels); + SkImageInfo info = SkImageInfo::Make(plane_sizes_[plane], color_type, + kUnknown_SkAlphaType); + ri->WritePixels(holders_[plane].mailbox, 0, 0, GL_TEXTURE_2D, + video_frame->stride(plane), info, video_frame->data(plane)); + mailboxes[plane] = holders_[plane].mailbox; + } +} + +GrYUVABackendTextures VideoFrameYUVMailboxesHolder::VideoFrameToSkiaTextures( + const VideoFrame* video_frame, + viz::RasterContextProvider* raster_context_provider, + bool for_surface) { + gpu::Mailbox mailboxes[kMaxPlanes]; + VideoFrameToMailboxes(video_frame, raster_context_provider, mailboxes); + ImportTextures(for_surface); + GrBackendTexture backend_textures[SkYUVAInfo::kMaxPlanes]; + for (size_t plane = 0; plane < num_planes_; ++plane) { + backend_textures[plane] = {plane_sizes_[plane].width(), + plane_sizes_[plane].height(), GrMipmapped::kNo, + textures_[plane].texture}; + } + return GrYUVABackendTextures(yuva_info_, backend_textures, + kTopLeft_GrSurfaceOrigin); +} + +sk_sp<SkImage> VideoFrameYUVMailboxesHolder::VideoFrameToSkImage( + const VideoFrame* video_frame, + viz::RasterContextProvider* raster_context_provider) { + GrDirectContext* gr_context = raster_context_provider->GrContext(); + DCHECK(gr_context); + + GrYUVABackendTextures yuva_backend_textures = VideoFrameToSkiaTextures( + video_frame, raster_context_provider, /*for_surface=*/false); + + DCHECK(yuva_backend_textures.isValid()); + auto result = SkImage::MakeFromYUVATextures(gr_context, yuva_backend_textures, + SkColorSpace::MakeSRGB()); + DCHECK(result); + return result; +} + +bool VideoFrameYUVMailboxesHolder::VideoFrameToPlaneSkSurfaces( + const VideoFrame* video_frame, + viz::RasterContextProvider* raster_context_provider, + sk_sp<SkSurface> surfaces[SkYUVAInfo::kMaxPlanes]) { + for (size_t plane = 0; plane < SkYUVAInfo::kMaxPlanes; ++plane) + surfaces[plane] = nullptr; + + if (!video_frame->HasTextures()) { + // The below call to VideoFrameToSkiaTextures would blit |video_frame| into + // a temporary SharedImage, which would be exposed as a SkSurface. That is + // probably undesirable (it has no current use cases), so just return an + // error. + DLOG(ERROR) << "VideoFrameToPlaneSkSurfaces requires texture backing."; + return false; + } + + GrDirectContext* gr_context = raster_context_provider->GrContext(); + DCHECK(gr_context); + GrYUVABackendTextures yuva_backend_textures = VideoFrameToSkiaTextures( + video_frame, raster_context_provider, /*for_surface=*/true); + + bool result = true; + for (size_t plane = 0; plane < num_planes_; ++plane) { + const int num_channels = yuva_info_.numChannelsInPlane(plane); + SkColorType color_type = SkYUVAPixmapInfo::DefaultColorTypeForDataType( + SkYUVAPixmaps::DataType::kUnorm8, num_channels); + // Gray is not renderable. + if (color_type == kGray_8_SkColorType) + color_type = kAlpha_8_SkColorType; + + auto surface = SkSurface::MakeFromBackendTexture( + gr_context, yuva_backend_textures.texture(plane), + kTopLeft_GrSurfaceOrigin, /*sampleCnt=*/1, color_type, + SkColorSpace::MakeSRGB(), nullptr); + if (!surface) { + DLOG(ERROR) + << "VideoFrameToPlaneSkSurfaces failed to make surface for plane " + << plane << " of " << num_planes_ << "."; + result = false; + } + surfaces[plane] = surface; + } + return result; +} + +SkYUVAPixmaps VideoFrameYUVMailboxesHolder::VideoFrameToSkiaPixmaps( + const VideoFrame* video_frame) { + yuva_info_ = VideoFrameGetSkYUVAInfo(video_frame); + num_planes_ = yuva_info_.planeDimensions(plane_sizes_); + + // Create SkImageInfos with the appropriate color types for 8 bit unorm data + // based on plane config. + size_t row_bytes[kMaxPlanes]; + for (size_t plane = 0; plane < num_planes_; ++plane) { + row_bytes[plane] = VideoFrame::RowBytes(plane, video_frame->format(), + plane_sizes_[plane].width()); + } + + SkYUVAPixmapInfo pixmaps_infos(yuva_info_, SkYUVAPixmaps::DataType::kUnorm8, + row_bytes); + SkPixmap pixmaps[SkYUVAInfo::kMaxPlanes]; + for (size_t plane = 0; plane < num_planes_; ++plane) { + pixmaps[plane].reset(pixmaps_infos.planeInfo(plane), + video_frame->data(plane), + pixmaps_infos.rowBytes(plane)); + } + return SkYUVAPixmaps::FromExternalPixmaps(yuva_info_, pixmaps); +} + +void VideoFrameYUVMailboxesHolder::ImportTextures(bool for_surface) { + DCHECK(!imported_textures_) + << "Textures should always be released after converting video frame. " + "Call ReleaseTextures() for each call to VideoFrameToSkiaTextures()"; + + auto* ri = provider_->RasterInterface(); + for (size_t plane = 0; plane < num_planes_; ++plane) { + textures_[plane].texture.fID = + ri->CreateAndConsumeForGpuRaster(holders_[plane].mailbox); + if (holders_[plane].mailbox.IsSharedImage()) { + textures_[plane].is_shared_image = true; + ri->BeginSharedImageAccessDirectCHROMIUM( + textures_[plane].texture.fID, + for_surface ? GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM + : GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM); + } else { + textures_[plane].is_shared_image = false; + } + + int num_channels = yuva_info_.numChannelsInPlane(plane); + textures_[plane].texture.fTarget = holders_[plane].texture_target; + textures_[plane].texture.fFormat = PlaneGLFormat(num_channels, for_surface); + } + + imported_textures_ = true; +} + +void VideoFrameYUVMailboxesHolder::ReleaseTextures() { + if (!imported_textures_) + return; + + auto* ri = provider_->RasterInterface(); + DCHECK(ri); + for (auto& tex_info : textures_) { + if (!tex_info.texture.fID) + continue; + + if (tex_info.is_shared_image) + ri->EndSharedImageAccessDirectCHROMIUM(tex_info.texture.fID); + ri->DeleteGpuRasterTexture(tex_info.texture.fID); + + tex_info.texture.fID = 0; + } + + imported_textures_ = false; +} + +// static +std::tuple<SkYUVAInfo::PlaneConfig, SkYUVAInfo::Subsampling> +VideoFrameYUVMailboxesHolder::VideoPixelFormatToSkiaValues( + VideoPixelFormat video_format) { + // To expand support for additional VideoFormats expand this switch. Note that + // we do assume 8 bit formats. With that exception, anything else should work. + switch (video_format) { + case PIXEL_FORMAT_NV12: + return {SkYUVAInfo::PlaneConfig::kY_UV, SkYUVAInfo::Subsampling::k420}; + case PIXEL_FORMAT_I420: + return {SkYUVAInfo::PlaneConfig::kY_U_V, SkYUVAInfo::Subsampling::k420}; + case PIXEL_FORMAT_I420A: + return {SkYUVAInfo::PlaneConfig::kY_U_V_A, SkYUVAInfo::Subsampling::k420}; + default: + return {SkYUVAInfo::PlaneConfig::kUnknown, + SkYUVAInfo::Subsampling::kUnknown}; + } +} + +// static +SkYUVAInfo VideoFrameYUVMailboxesHolder::VideoFrameGetSkYUVAInfo( + const VideoFrame* video_frame) { + SkISize video_size{video_frame->coded_size().width(), + video_frame->coded_size().height()}; + auto plane_config = SkYUVAInfo::PlaneConfig::kUnknown; + auto subsampling = SkYUVAInfo::Subsampling::kUnknown; + std::tie(plane_config, subsampling) = + VideoPixelFormatToSkiaValues(video_frame->format()); + + // TODO(crbug.com/828599): This should really default to rec709. + SkYUVColorSpace color_space = kRec601_SkYUVColorSpace; + video_frame->ColorSpace().ToSkYUVColorSpace(&color_space); + return SkYUVAInfo(video_size, plane_config, subsampling, color_space); +} + +} // namespace media diff --git a/chromium/media/renderers/video_frame_yuv_mailboxes_holder.h b/chromium/media/renderers/video_frame_yuv_mailboxes_holder.h new file mode 100644 index 00000000000..5a1e51ba226 --- /dev/null +++ b/chromium/media/renderers/video_frame_yuv_mailboxes_holder.h @@ -0,0 +1,99 @@ +// Copyright 2021 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. + +#ifndef MEDIA_RENDERERS_VIDEO_FRAME_YUV_MAILBOXES_HOLDER_H_ +#define MEDIA_RENDERERS_VIDEO_FRAME_YUV_MAILBOXES_HOLDER_H_ + +#include "media/base/media_export.h" +#include "media/base/video_frame.h" +#include "third_party/skia/include/core/SkYUVAInfo.h" +#include "third_party/skia/include/gpu/GrYUVABackendTextures.h" +#include "third_party/skia/include/gpu/gl/GrGLTypes.h" + +namespace viz { +class RasterContextProvider; +} // namespace viz + +namespace media { + +class MEDIA_EXPORT VideoFrameYUVMailboxesHolder { + public: + VideoFrameYUVMailboxesHolder(); + ~VideoFrameYUVMailboxesHolder(); + + void ReleaseCachedData(); + void ReleaseTextures(); + + // Extracts shared image information if |video_frame| is texture backed or + // creates new shared images and uploads YUV data to GPU if |video_frame| is + // mappable. This function can be called repeatedly to re-use shared images in + // the case of CPU backed VideoFrames. The planes are returned in |mailboxes|. + void VideoFrameToMailboxes( + const VideoFrame* video_frame, + viz::RasterContextProvider* raster_context_provider, + gpu::Mailbox mailboxes[SkYUVAInfo::kMaxPlanes]); + + // Returns a YUV SkImage for the specified video frame. + sk_sp<SkImage> VideoFrameToSkImage( + const VideoFrame* video_frame, + viz::RasterContextProvider* raster_context_provider); + + // Creates SkSurfaces for each plane for the specified video frame. Returns + // true only if surfaces for all planes were created. + bool VideoFrameToPlaneSkSurfaces( + const VideoFrame* video_frame, + viz::RasterContextProvider* raster_context_provider, + sk_sp<SkSurface> surfaces[SkYUVAInfo::kMaxPlanes]); + + SkYUVAPixmaps VideoFrameToSkiaPixmaps(const VideoFrame* video_frame); + + const SkYUVAInfo& yuva_info() const { return yuva_info_; } + + // Utility to convert a media pixel format to SkYUVAInfo. + static std::tuple<SkYUVAInfo::PlaneConfig, SkYUVAInfo::Subsampling> + VideoPixelFormatToSkiaValues(VideoPixelFormat video_format); + + // Utility to populate a SkYUVAInfo from a video frame. + static SkYUVAInfo VideoFrameGetSkYUVAInfo(const VideoFrame* video_frame); + + private: + static constexpr size_t kMaxPlanes = + static_cast<size_t>(SkYUVAInfo::kMaxPlanes); + + // Like VideoFrameToMailboxes but imports the textures from the mailboxes and + // returns the planes as a set of YUVA GrBackendTextures. If |for_surface| is + // true, then select color types and pixel formats that are renderable as + // SkSurfaces. + GrYUVABackendTextures VideoFrameToSkiaTextures( + const VideoFrame* video_frame, + viz::RasterContextProvider* raster_context_provider, + bool for_surface); + + void ImportTextures(bool for_surface); + + scoped_refptr<viz::RasterContextProvider> provider_; + bool imported_textures_ = false; + bool created_shared_images_ = false; + gfx::Size cached_video_size_; + gfx::ColorSpace cached_video_color_space_; + + // The properties of the most recently received video frame. + size_t num_planes_ = 0; + SkYUVAInfo yuva_info_; + SkISize plane_sizes_[SkYUVAInfo::kMaxPlanes]; + + // Populated by VideoFrameToMailboxes. + std::array<gpu::MailboxHolder, kMaxPlanes> holders_; + + // Populated by ImportTextures. + struct YUVPlaneTextureInfo { + GrGLTextureInfo texture = {0, 0}; + bool is_shared_image = false; + }; + std::array<YUVPlaneTextureInfo, kMaxPlanes> textures_; +}; + +} // namespace media + +#endif // MEDIA_RENDERERS_VIDEO_FRAME_YUV_MAILBOXES_HOLDER_H_ diff --git a/chromium/media/renderers/video_renderer_impl.cc b/chromium/media/renderers/video_renderer_impl.cc index c67759babb7..83497d5bdd2 100644 --- a/chromium/media/renderers/video_renderer_impl.cc +++ b/chromium/media/renderers/video_renderer_impl.cc @@ -466,7 +466,7 @@ void VideoRendererImpl::OnTimeStopped() { } void VideoRendererImpl::SetLatencyHint( - base::Optional<base::TimeDelta> latency_hint) { + absl::optional<base::TimeDelta> latency_hint) { base::AutoLock auto_lock(lock_); latency_hint_ = latency_hint; @@ -829,7 +829,7 @@ void VideoRendererImpl::ReportFrameRateIfNeeded_Locked() { DCHECK(task_runner_->BelongsToCurrentThread()); lock_.AssertAcquired(); - base::Optional<int> current_fps = fps_estimator_.ComputeFPS(); + absl::optional<int> current_fps = fps_estimator_.ComputeFPS(); if (last_reported_fps_ && current_fps && *last_reported_fps_ == *current_fps) { // Reported an FPS before, and it hasn't changed. diff --git a/chromium/media/renderers/video_renderer_impl.h b/chromium/media/renderers/video_renderer_impl.h index 524fa1f748e..00c4d08743f 100644 --- a/chromium/media/renderers/video_renderer_impl.h +++ b/chromium/media/renderers/video_renderer_impl.h @@ -73,7 +73,7 @@ class MEDIA_EXPORT VideoRendererImpl void StartPlayingFrom(base::TimeDelta timestamp) override; void OnTimeProgressing() override; void OnTimeStopped() override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void SetTickClockForTesting(const base::TickClock* tick_clock); size_t frames_queued_for_testing() const { @@ -338,11 +338,11 @@ class MEDIA_EXPORT VideoRendererImpl FrameRateEstimator fps_estimator_; // Last FPS, if any, reported to the client. - base::Optional<int> last_reported_fps_; + absl::optional<int> last_reported_fps_; // Value saved from last call to SetLatencyHint(). Used to recompute buffering // limits as framerate fluctuates. - base::Optional<base::TimeDelta> latency_hint_; + absl::optional<base::TimeDelta> latency_hint_; // When latency_hint_ > 0, we make regular adjustments to buffering caps as // |algorithm_->average_frame_duration()| fluctuates, but we only want to emit diff --git a/chromium/media/renderers/video_renderer_impl_unittest.cc b/chromium/media/renderers/video_renderer_impl_unittest.cc index 7fd1b5f80a5..d5f94b32cfd 100644 --- a/chromium/media/renderers/video_renderer_impl_unittest.cc +++ b/chromium/media/renderers/video_renderer_impl_unittest.cc @@ -635,7 +635,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) { EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(100))); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(absl::optional<int>(100))); StartPlayingFrom(59); Destroy(); } @@ -649,7 +649,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) { EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(100))); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(absl::optional<int>(100))); StartPlayingFrom(61); Destroy(); } @@ -1150,12 +1150,12 @@ TEST_F(VideoRendererImplTest, VideoFrameRateChange) { EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); // Send 50fps frames first. - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(50))); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(absl::optional<int>(50))); QueueFrames("0 20 40 60 80 100 120 140 160 180 200"); QueueFrames("220 240 260 280 300 320 340 360 380 400"); // Also queue some frames that aren't at 50fps, so that we get an unknown fps. - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>())); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(absl::optional<int>())); QueueFrames("500 600"); // Drain everything. @@ -1376,7 +1376,7 @@ TEST_P(UnderflowTest, UnderflowAndRecoverTest) { // the have enough state. case UnderflowTestType::NORMAL: QueueFrames("80 100 120 140 160"); - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(50))); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(absl::optional<int>(50))); break; // In either of these modes the HAVE_ENOUGH transition should still // occur with a single frame. @@ -1483,7 +1483,7 @@ TEST_F(VideoRendererLatencyHintTest, HaveEnough_LowLatencyHint) { EXPECT_EQ(renderer_->frames_queued_for_testing(), 4u); // Unset latencyHint, to verify default behavior. - renderer_->SetLatencyHint(base::nullopt); + renderer_->SetLatencyHint(absl::nullopt); // Flush to return to clean slate. EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, _)); @@ -1518,7 +1518,7 @@ TEST_F(VideoRendererLatencyHintTest, HaveEnough_HighLatencyHint) { // Queue 12 frames, each 30 ms apart. At this framerate, 400ms rounds to 13 // frames, so 12 frames should be 1 shy of the HaveEnough threshold. - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(33))); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(absl::optional<int>(33))); EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)) .Times(0); QueueFrames("0 30 60 90 120 150 180 210 240 270 300 330"); @@ -1538,7 +1538,7 @@ TEST_F(VideoRendererLatencyHintTest, HaveEnough_HighLatencyHint) { Mock::VerifyAndClearExpectations(&mock_cb_); // Unset latencyHint, to verify default behavior. - renderer_->SetLatencyHint(base::nullopt); + renderer_->SetLatencyHint(absl::nullopt); // Flush to return to clean slate. EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, _)); @@ -1574,7 +1574,7 @@ TEST_F(VideoRendererLatencyHintTest, EXPECT_CALL(mock_cb_, OnVideoNaturalSizeChange(_)).Times(1); EXPECT_CALL(mock_cb_, OnVideoOpacityChange(_)).Times(1); EXPECT_CALL(mock_cb_, OnStatisticsUpdate(_)).Times(AnyNumber()); - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(33))); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(absl::optional<int>(33))); EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)); QueueFrames("0 30 60 90 120 150 180"); StartPlayingFrom(0); @@ -1634,7 +1634,7 @@ TEST_F(VideoRendererLatencyHintTest, LatencyHintOverridesLowDelay) { // 7 frames, so 6 frames should be 1 shy of the HaveEnough threshold. Verify // that HAVE_ENOUGH is not triggered in spite of being initialized with low // delay mode. - EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(base::Optional<int>(33))); + EXPECT_CALL(mock_cb_, OnVideoFrameRateChange(absl::optional<int>(33))); EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)) .Times(0); QueueFrames("0 30 60 90 120 150"); @@ -1654,7 +1654,7 @@ TEST_F(VideoRendererLatencyHintTest, LatencyHintOverridesLowDelay) { // Unset latencyHint, to verify default behavior. NOTE: low delay mode is not // restored when latency hint unset. - renderer_->SetLatencyHint(base::nullopt); + renderer_->SetLatencyHint(absl::nullopt); // Flush to return to clean slate. EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, _)); @@ -1711,7 +1711,7 @@ TEST_F(VideoRendererLatencyHintTest, Mock::VerifyAndClearExpectations(&mock_cb_); // Unset latency hint to verify 1-frame HAVE_ENOUGH threshold is maintained. - renderer_->SetLatencyHint(base::nullopt); + renderer_->SetLatencyHint(absl::nullopt); // Flush to return to clean slate. EXPECT_CALL(mock_cb_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING, _)); diff --git a/chromium/media/renderers/video_resource_updater.cc b/chromium/media/renderers/video_resource_updater.cc index 6169cc98e13..f8af767fb27 100644 --- a/chromium/media/renderers/video_resource_updater.cc +++ b/chromium/media/renderers/video_resource_updater.cc @@ -13,6 +13,7 @@ #include "base/atomic_sequence_num.h" #include "base/bind.h" #include "base/bit_cast.h" +#include "base/containers/contains.h" #include "base/logging.h" #include "base/memory/shared_memory_mapping.h" #include "base/memory/unsafe_shared_memory_region.h" @@ -522,8 +523,7 @@ void VideoResourceUpdater::ObtainFrameResources( for (size_t i = 0; i < external_resources.resources.size(); ++i) { viz::ResourceId resource_id = resource_provider_->ImportResource( external_resources.resources[i], - viz::SingleReleaseCallback::Create( - std::move(external_resources.release_callbacks[i]))); + std::move(external_resources.release_callbacks[i])); frame_resources_.emplace_back(resource_id, external_resources.resources[i].size); } @@ -545,8 +545,7 @@ void VideoResourceUpdater::AppendQuads( gfx::Rect quad_rect, gfx::Rect visible_quad_rect, const gfx::MaskFilterInfo& mask_filter_info, - gfx::Rect clip_rect, - bool is_clipped, + absl::optional<gfx::Rect> clip_rect, bool contents_opaque, float draw_opacity, int sorting_context_id) { @@ -554,10 +553,9 @@ void VideoResourceUpdater::AppendQuads( viz::SharedQuadState* shared_quad_state = render_pass->CreateAndAppendSharedQuadState(); - shared_quad_state->SetAll(transform, quad_rect, visible_quad_rect, - mask_filter_info, clip_rect, is_clipped, - contents_opaque, draw_opacity, - SkBlendMode::kSrcOver, sorting_context_id); + shared_quad_state->SetAll( + transform, quad_rect, visible_quad_rect, mask_filter_info, clip_rect, + contents_opaque, draw_opacity, SkBlendMode::kSrcOver, sorting_context_id); bool needs_blending = !contents_opaque; @@ -912,6 +910,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( mailbox, GL_LINEAR, mailbox_holder.texture_target, sync_token, plane_size, video_frame->metadata().allow_overlay); transfer_resource.color_space = resource_color_space; + transfer_resource.hdr_metadata = video_frame->hdr_metadata(); transfer_resource.read_lock_fences_enabled = video_frame->metadata().read_lock_fences_enabled; transfer_resource.format = viz::GetResourceFormat(buffer_formats[i]); diff --git a/chromium/media/renderers/video_resource_updater.h b/chromium/media/renderers/video_resource_updater.h index e23887c3fe2..d2ad861f59a 100644 --- a/chromium/media/renderers/video_resource_updater.h +++ b/chromium/media/renderers/video_resource_updater.h @@ -15,7 +15,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/time/time.h" #include "base/trace_event/memory_dump_provider.h" #include "base/unguessable_token.h" #include "components/viz/common/resources/release_callback.h" @@ -124,8 +123,7 @@ class MEDIA_EXPORT VideoResourceUpdater gfx::Rect quad_rect, gfx::Rect visible_quad_rect, const gfx::MaskFilterInfo& mask_filter_info, - gfx::Rect clip_rect, - bool is_clipped, + absl::optional<gfx::Rect> clip_rect, bool context_opaque, float draw_opacity, int sorting_context_id); diff --git a/chromium/media/renderers/video_resource_updater_unittest.cc b/chromium/media/renderers/video_resource_updater_unittest.cc index 65814ed93cf..286a083aa4f 100644 --- a/chromium/media/renderers/video_resource_updater_unittest.cc +++ b/chromium/media/renderers/video_resource_updater_unittest.cc @@ -213,7 +213,7 @@ class VideoResourceUpdaterTest : public testing::Test { } scoped_refptr<VideoFrame> CreateTestStreamTextureHardwareVideoFrame( - base::Optional<VideoFrameMetadata::CopyMode> copy_mode) { + absl::optional<VideoFrameMetadata::CopyMode> copy_mode) { scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame( PIXEL_FORMAT_ARGB, GL_TEXTURE_EXTERNAL_OES); video_frame->metadata().copy_mode = std::move(copy_mode); @@ -577,7 +577,7 @@ TEST_F(VideoResourceUpdaterTest, CreateUpdaterForHardware(true); EXPECT_EQ(0u, GetSharedImageCount()); scoped_refptr<VideoFrame> video_frame = - CreateTestStreamTextureHardwareVideoFrame(base::nullopt); + CreateTestStreamTextureHardwareVideoFrame(absl::nullopt); VideoFrameExternalResources resources = updater->CreateExternalResourcesFromVideoFrame(video_frame); @@ -608,7 +608,7 @@ TEST_F(VideoResourceUpdaterTest, CreateUpdaterForHardware(true); EXPECT_EQ(0u, GetSharedImageCount()); scoped_refptr<VideoFrame> video_frame = - CreateTestStreamTextureHardwareVideoFrame(base::nullopt); + CreateTestStreamTextureHardwareVideoFrame(absl::nullopt); VideoFrameExternalResources resources = updater->CreateExternalResourcesFromVideoFrame(video_frame); EXPECT_EQ(VideoFrameResourceType::STREAM_TEXTURE, resources.type); @@ -637,7 +637,7 @@ TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_TextureQuad) { std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware(); EXPECT_EQ(0u, GetSharedImageCount()); scoped_refptr<VideoFrame> video_frame = - CreateTestStreamTextureHardwareVideoFrame(base::nullopt); + CreateTestStreamTextureHardwareVideoFrame(absl::nullopt); VideoFrameExternalResources resources = updater->CreateExternalResourcesFromVideoFrame(video_frame); @@ -793,5 +793,42 @@ TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_DualNV12) { EXPECT_EQ(0u, GetSharedImageCount()); } +TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_SingleP016HDR) { + constexpr auto kHDR10ColorSpace = gfx::ColorSpace::CreateHDR10(); + gfx::HDRMetadata hdr_metadata{}; + hdr_metadata.mastering_metadata.luminance_max = 1000; + std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware(); + EXPECT_EQ(0u, GetSharedImageCount()); + scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame( + PIXEL_FORMAT_P016LE, GL_TEXTURE_EXTERNAL_OES); + video_frame->set_color_space(kHDR10ColorSpace); + video_frame->set_hdr_metadata(hdr_metadata); + + VideoFrameExternalResources resources = + updater->CreateExternalResourcesFromVideoFrame(video_frame); + EXPECT_EQ(VideoFrameResourceType::RGB, resources.type); + EXPECT_EQ(1u, resources.resources.size()); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), + resources.resources[0].mailbox_holder.texture_target); + EXPECT_EQ(viz::P010, resources.resources[0].format); + EXPECT_EQ(kHDR10ColorSpace, resources.resources[0].color_space); + EXPECT_EQ(hdr_metadata, resources.resources[0].hdr_metadata); + + video_frame = CreateTestYuvHardwareVideoFrame(PIXEL_FORMAT_P016LE, 1, + GL_TEXTURE_RECTANGLE_ARB); + video_frame->set_color_space(kHDR10ColorSpace); + video_frame->set_hdr_metadata(hdr_metadata); + resources = updater->CreateExternalResourcesFromVideoFrame(video_frame); + EXPECT_EQ(VideoFrameResourceType::RGB, resources.type); + EXPECT_EQ(1u, resources.resources.size()); + EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB), + resources.resources[0].mailbox_holder.texture_target); + EXPECT_EQ(viz::P010, resources.resources[0].format); + EXPECT_EQ(kHDR10ColorSpace, resources.resources[0].color_space); + EXPECT_EQ(hdr_metadata, resources.resources[0].hdr_metadata); + + EXPECT_EQ(0u, GetSharedImageCount()); +} + } // namespace } // namespace media diff --git a/chromium/media/renderers/win/media_engine_notify_impl.h b/chromium/media/renderers/win/media_engine_notify_impl.h index b0dcf6a4001..cf3cafc6045 100644 --- a/chromium/media/renderers/win/media_engine_notify_impl.h +++ b/chromium/media/renderers/win/media_engine_notify_impl.h @@ -10,7 +10,6 @@ #include "base/callback.h" #include "base/synchronization/lock.h" -#include "base/time/time.h" #include "media/base/buffering_state.h" #include "media/base/pipeline_status.h" diff --git a/chromium/media/renderers/win/media_foundation_protection_manager.cc b/chromium/media/renderers/win/media_foundation_protection_manager.cc index d7ef8edf861..01827989857 100644 --- a/chromium/media/renderers/win/media_foundation_protection_manager.cc +++ b/chromium/media/renderers/win/media_foundation_protection_manager.cc @@ -18,8 +18,13 @@ namespace media { using Microsoft::WRL::ComPtr; -MediaFoundationProtectionManager::MediaFoundationProtectionManager() = default; -MediaFoundationProtectionManager::~MediaFoundationProtectionManager() = default; +MediaFoundationProtectionManager::MediaFoundationProtectionManager() { + DVLOG_FUNC(1); +} + +MediaFoundationProtectionManager::~MediaFoundationProtectionManager() { + DVLOG_FUNC(1); +} HRESULT MediaFoundationProtectionManager::RuntimeClassInitialize() { DVLOG_FUNC(1); @@ -36,11 +41,12 @@ HRESULT MediaFoundationProtectionManager::RuntimeClassInitialize() { return S_OK; } -HRESULT MediaFoundationProtectionManager::SetCdmProxy(IMFCdmProxy* cdm_proxy) { +HRESULT MediaFoundationProtectionManager::SetCdmProxy( + scoped_refptr<MediaFoundationCdmProxy> cdm_proxy) { DVLOG_FUNC(1); DCHECK(cdm_proxy); - cdm_proxy_ = cdm_proxy; + cdm_proxy_ = std::move(cdm_proxy); ComPtr<ABI::Windows::Media::Protection::IMediaProtectionPMPServer> pmp_server; RETURN_IF_FAILED(cdm_proxy_->GetPMPServer(IID_PPV_ARGS(&pmp_server))); RETURN_IF_FAILED(SetPMPServer(pmp_server.Get())); diff --git a/chromium/media/renderers/win/media_foundation_protection_manager.h b/chromium/media/renderers/win/media_foundation_protection_manager.h index 3ccb8b39ae9..201ac76f787 100644 --- a/chromium/media/renderers/win/media_foundation_protection_manager.h +++ b/chromium/media/renderers/win/media_foundation_protection_manager.h @@ -10,7 +10,8 @@ #include <windows.media.protection.h> #include <wrl.h> -#include "media/base/win/mf_cdm_proxy.h" +#include "base/memory/scoped_refptr.h" +#include "media/base/win/media_foundation_cdm_proxy.h" namespace media { @@ -33,7 +34,7 @@ class MediaFoundationProtectionManager ~MediaFoundationProtectionManager() override; HRESULT RuntimeClassInitialize(); - HRESULT SetCdmProxy(IMFCdmProxy* cdm_proxy); + HRESULT SetCdmProxy(scoped_refptr<MediaFoundationCdmProxy> cdm_proxy); // IMFContentProtectionManager. IFACEMETHODIMP BeginEnableContent(IMFActivate* enabler_activate, @@ -65,7 +66,8 @@ class MediaFoundationProtectionManager protected: Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IPropertySet> property_set_; - Microsoft::WRL::ComPtr<IMFCdmProxy> cdm_proxy_; + + scoped_refptr<MediaFoundationCdmProxy> cdm_proxy_; HRESULT SetPMPServer( ABI::Windows::Media::Protection::IMediaProtectionPMPServer* pmp_server); diff --git a/chromium/media/renderers/win/media_foundation_renderer.cc b/chromium/media/renderers/win/media_foundation_renderer.cc index b69263da83a..4e97cec3b74 100644 --- a/chromium/media/renderers/win/media_foundation_renderer.cc +++ b/chromium/media/renderers/win/media_foundation_renderer.cc @@ -320,13 +320,13 @@ void MediaFoundationRenderer::SetCdm(CdmContext* cdm_context, } void MediaFoundationRenderer::SetLatencyHint( - base::Optional<base::TimeDelta> /*latency_hint*/) { + absl::optional<base::TimeDelta> /*latency_hint*/) { // TODO(frankli): Ensure MFMediaEngine rendering pipeine is in real time mode. NOTIMPLEMENTED() << "We do not use the latency hint today"; } void MediaFoundationRenderer::OnCdmProxyReceived( - ComPtr<IMFCdmProxy> cdm_proxy) { + scoped_refptr<MediaFoundationCdmProxy> cdm_proxy) { DVLOG_FUNC(1); if (!waiting_for_mf_cdm_ || !content_protection_manager_) { @@ -337,8 +337,8 @@ void MediaFoundationRenderer::OnCdmProxyReceived( waiting_for_mf_cdm_ = false; - content_protection_manager_->SetCdmProxy(cdm_proxy.Get()); - mf_source_->SetCdmProxy(cdm_proxy.Get()); + content_protection_manager_->SetCdmProxy(cdm_proxy); + mf_source_->SetCdmProxy(cdm_proxy); HRESULT hr = SetSourceOnMediaEngine(); if (FAILED(hr)) { DLOG(ERROR) << "Failed to set source on media engine: " << PrintHr(hr); diff --git a/chromium/media/renderers/win/media_foundation_renderer.h b/chromium/media/renderers/win/media_foundation_renderer.h index 70a209f94aa..21b7d383f73 100644 --- a/chromium/media/renderers/win/media_foundation_renderer.h +++ b/chromium/media/renderers/win/media_foundation_renderer.h @@ -54,7 +54,7 @@ class MEDIA_EXPORT MediaFoundationRenderer RendererClient* client, PipelineStatusCallback init_cb) override; void SetCdm(CdmContext* cdm_context, CdmAttachedCB cdm_attached_cb) override; - void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) override; + void SetLatencyHint(absl::optional<base::TimeDelta> latency_hint) override; void Flush(base::OnceClosure flush_cb) override; void StartPlayingFrom(base::TimeDelta time) override; void SetPlaybackRate(double playback_rate) override; @@ -86,7 +86,7 @@ class MEDIA_EXPORT MediaFoundationRenderer void OnVideoNaturalSizeChange(); void OnTimeUpdate(); - void OnCdmProxyReceived(Microsoft::WRL::ComPtr<IMFCdmProxy> cdm_proxy); + void OnCdmProxyReceived(scoped_refptr<MediaFoundationCdmProxy> cdm_proxy); HRESULT SetDCompModeInternal(bool enabled); HRESULT GetDCompSurfaceInternal(HANDLE* surface_handle); diff --git a/chromium/media/renderers/win/media_foundation_renderer_factory.cc b/chromium/media/renderers/win/media_foundation_renderer_factory.cc deleted file mode 100644 index f44de378857..00000000000 --- a/chromium/media/renderers/win/media_foundation_renderer_factory.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 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/renderers/win/media_foundation_renderer_factory.h" - -#include "base/single_thread_task_runner.h" -#include "media/renderers/win/media_foundation_renderer.h" - -namespace media { - -MediaFoundationRendererFactory::MediaFoundationRendererFactory() = default; - -MediaFoundationRendererFactory::~MediaFoundationRendererFactory() = default; - -// MediaFoundationRenderer does most audio/video rendering by itself and doesn't -// use most of the parameters passed in. -std::unique_ptr<Renderer> MediaFoundationRendererFactory::CreateRenderer( - const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, - const scoped_refptr<base::TaskRunner>& /*worker_task_runner*/, - AudioRendererSink* /*audio_renderer_sink*/, - VideoRendererSink* /*video_renderer_sink*/, - RequestOverlayInfoCB /*request_overlay_info_cb*/, - const gfx::ColorSpace& /*target_color_space*/) { - // TODO(xhwang): Investigate how to set |muted| and update after composition - // is connected. - auto renderer = std::make_unique<MediaFoundationRenderer>( - /*muted=*/false, media_task_runner, - /*force_dcomp_mode_for_testing=*/true); - - return renderer; -} - -} // namespace media
\ No newline at end of file diff --git a/chromium/media/renderers/win/media_foundation_renderer_factory.h b/chromium/media/renderers/win/media_foundation_renderer_factory.h deleted file mode 100644 index 50a9b9d1d8b..00000000000 --- a/chromium/media/renderers/win/media_foundation_renderer_factory.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2020 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. - -#ifndef MEDIA_RENDERERS_WIN_MEDIA_FOUNDATION_RENDERER_FACTORY_H_ -#define MEDIA_RENDERERS_WIN_MEDIA_FOUNDATION_RENDERER_FACTORY_H_ - -#include <stdint.h> - -#include "media/base/media_export.h" -#include "media/base/renderer_factory.h" - -namespace media { - -// RendererFactory to create MediaFoundationRendererFactory. -class MEDIA_EXPORT MediaFoundationRendererFactory : public RendererFactory { - public: - MediaFoundationRendererFactory(); - MediaFoundationRendererFactory(const MediaFoundationRendererFactory&) = - delete; - MediaFoundationRendererFactory& operator=( - const MediaFoundationRendererFactory&) = delete; - ~MediaFoundationRendererFactory() final; - - // RendererFactory implementation. - std::unique_ptr<Renderer> CreateRenderer( - const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, - const scoped_refptr<base::TaskRunner>& worker_task_runner, - AudioRendererSink* audio_renderer_sink, - VideoRendererSink* video_renderer_sink, - RequestOverlayInfoCB request_overlay_info_cb, - const gfx::ColorSpace& target_color_space) final; -}; - -} // namespace media - -#endif // MEDIA_RENDERERS_WIN_MEDIA_FOUNDATION_RENDERER_FACTORY_H_ diff --git a/chromium/media/renderers/win/media_foundation_renderer_integration_test.cc b/chromium/media/renderers/win/media_foundation_renderer_integration_test.cc index 163708f6905..b9b4b462239 100644 --- a/chromium/media/renderers/win/media_foundation_renderer_integration_test.cc +++ b/chromium/media/renderers/win/media_foundation_renderer_integration_test.cc @@ -61,7 +61,7 @@ class MediaFoundationRendererIntegrationTest private: std::unique_ptr<Renderer> CreateMediaFoundationRenderer( - base::Optional<RendererFactoryType> factory_type) { + absl::optional<RendererType> /*renderer_type*/) { auto renderer = std::make_unique<MediaFoundationRenderer>( /*muted=*/false, task_environment_.GetMainThreadTaskRunner(), /*force_dcomp_mode_for_testing=*/true); diff --git a/chromium/media/renderers/win/media_foundation_renderer_unittest.cc b/chromium/media/renderers/win/media_foundation_renderer_unittest.cc index 9f74d065f30..b5ebb75391d 100644 --- a/chromium/media/renderers/win/media_foundation_renderer_unittest.cc +++ b/chromium/media/renderers/win/media_foundation_renderer_unittest.cc @@ -8,10 +8,12 @@ #include "base/bind.h" #include "base/callback_helpers.h" +#include "base/memory/scoped_refptr.h" #include "base/single_thread_task_runner.h" #include "base/test/mock_callback.h" #include "base/test/task_environment.h" #include "base/win/scoped_com_initializer.h" +#include "media/base/bind_to_current_loop.h" #include "media/base/demuxer_stream.h" #include "media/base/mock_filters.h" #include "media/base/test_helpers.h" @@ -29,33 +31,30 @@ namespace media { using ABI::Windows::Media::Protection::IMediaProtectionPMPServer; using Microsoft::WRL::ComPtr; -class MockMFCdmProxy - : public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, - IMFCdmProxy> { +class MockMediaFoundationCdmProxy : public MediaFoundationCdmProxy { public: - MockMFCdmProxy(); - ~MockMFCdmProxy() override; - - // IMFCdmProxy. - MOCK_STDCALL_METHOD2(GetPMPServer, - HRESULT(REFIID riid, void** object_result)); - MOCK_STDCALL_METHOD6(GetInputTrustAuthority, - HRESULT(uint32_t stream_id, - uint32_t stream_count, - const uint8_t* content_init_data, - uint32_t content_init_data_size, - REFIID riid, - IUnknown** object_result)); - MOCK_STDCALL_METHOD2(SetLastKeyId, - HRESULT(uint32_t stream_id, REFGUID key_id)); - MOCK_STDCALL_METHOD0(RefreshTrustedInput, HRESULT()); - MOCK_STDCALL_METHOD2(ProcessContentEnabler, - HRESULT(IUnknown* request, IMFAsyncResult* result)); + MockMediaFoundationCdmProxy(); + + // MediaFoundationCdmProxy. + MOCK_METHOD2(GetPMPServer, HRESULT(REFIID riid, void** object_result)); + MOCK_METHOD6(GetInputTrustAuthority, + HRESULT(uint32_t stream_id, + uint32_t stream_count, + const uint8_t* content_init_data, + uint32_t content_init_data_size, + REFIID riid, + IUnknown** object_result)); + MOCK_METHOD2(SetLastKeyId, HRESULT(uint32_t stream_id, REFGUID key_id)); + MOCK_METHOD0(RefreshTrustedInput, HRESULT()); + MOCK_METHOD2(ProcessContentEnabler, + HRESULT(IUnknown* request, IMFAsyncResult* result)); + + protected: + ~MockMediaFoundationCdmProxy() override; }; -MockMFCdmProxy::MockMFCdmProxy() = default; -MockMFCdmProxy::~MockMFCdmProxy() = default; +MockMediaFoundationCdmProxy::MockMediaFoundationCdmProxy() = default; +MockMediaFoundationCdmProxy::~MockMediaFoundationCdmProxy() = default; class MockMediaProtectionPMPServer : public Microsoft::WRL::RuntimeClass< @@ -92,6 +91,13 @@ class MediaFoundationRendererTest : public testing::Test { if (!MediaFoundationRenderer::IsSupported()) return; + mf_cdm_proxy_ = + base::MakeRefCounted<NiceMock<MockMediaFoundationCdmProxy>>(); + + // MF MediaEngine holds IMFMediaSource (MediaFoundationSourceWrapper) even + // after the test finishes, which holds a reference to the `mf_cdm_proxy_`. + testing::Mock::AllowLeak(mf_cdm_proxy_.get()); + MockMediaProtectionPMPServer::MakeMockMediaProtectionPMPServer( &pmp_server_); @@ -100,11 +106,11 @@ class MediaFoundationRendererTest : public testing::Test { // Some default actions. ON_CALL(cdm_context_, GetMediaFoundationCdmProxy(_)) + .WillByDefault(Invoke( + this, &MediaFoundationRendererTest::GetMediaFoundationCdmProxy)); + ON_CALL(*mf_cdm_proxy_, GetPMPServer(_, _)) .WillByDefault( - Invoke(this, &MediaFoundationRendererTest::MockGetMFCdm)); - ON_CALL(mf_cdm_proxy_, GetPMPServer(_, _)) - .WillByDefault( - Invoke(this, &MediaFoundationRendererTest::MockGetPMPServer)); + Invoke(this, &MediaFoundationRendererTest::GetPMPServer)); // Some expected calls with return values. EXPECT_CALL(media_resource_, GetAllStreams()) @@ -130,23 +136,14 @@ class MediaFoundationRendererTest : public testing::Test { return streams; } - void OnSendCdmProxy( - CdmContext::GetMediaFoundationCdmProxyCB get_mf_cdm_proxy_cb) { - std::move(get_mf_cdm_proxy_cb).Run(&mf_cdm_proxy_); - } - - bool MockGetMFCdm( + bool GetMediaFoundationCdmProxy( CdmContext::GetMediaFoundationCdmProxyCB get_mf_cdm_proxy_cb) { - // The callback should be invoked asynchronously per API contract. Post - // to make callback from OnSendCdmProxy(). - task_environment_.GetMainThreadTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(&MediaFoundationRendererTest::OnSendCdmProxy, - base::Unretained(this), std::move(get_mf_cdm_proxy_cb))); + // Call the callback asynchronously per API contract. + BindToCurrentLoop(std::move(get_mf_cdm_proxy_cb)).Run(mf_cdm_proxy_); return true; } - HRESULT MockGetPMPServer(REFIID riid, LPVOID* object_result) { + HRESULT GetPMPServer(REFIID riid, LPVOID* object_result) { ComPtr<IMediaProtectionPMPServer> pmp_server; if (riid != __uuidof(**(&pmp_server)) || !object_result) { return E_INVALIDARG; @@ -164,7 +161,7 @@ class MediaFoundationRendererTest : public testing::Test { NiceMock<MockCdmContext> cdm_context_; NiceMock<MockMediaResource> media_resource_; NiceMock<MockRendererClient> renderer_client_; - NiceMock<MockMFCdmProxy> mf_cdm_proxy_; + scoped_refptr<NiceMock<MockMediaFoundationCdmProxy>> mf_cdm_proxy_; ComPtr<IMediaProtectionPMPServer> pmp_server_; std::unique_ptr<MediaFoundationRenderer> mf_renderer_; std::vector<std::unique_ptr<StrictMock<MockDemuxerStream>>> streams_; diff --git a/chromium/media/renderers/win/media_foundation_source_wrapper.cc b/chromium/media/renderers/win/media_foundation_source_wrapper.cc index ee8dd306197..3a41567f5c4 100644 --- a/chromium/media/renderers/win/media_foundation_source_wrapper.cc +++ b/chromium/media/renderers/win/media_foundation_source_wrapper.cc @@ -18,6 +18,8 @@ using Microsoft::WRL::ComPtr; MediaFoundationSourceWrapper::MediaFoundationSourceWrapper() = default; MediaFoundationSourceWrapper::~MediaFoundationSourceWrapper() { + DVLOG_FUNC(1); + if (!cdm_proxy_) return; @@ -506,13 +508,14 @@ bool MediaFoundationSourceWrapper::HasEncryptedStream() const { return false; } -void MediaFoundationSourceWrapper::SetCdmProxy(IMFCdmProxy* cdm_proxy) { +void MediaFoundationSourceWrapper::SetCdmProxy( + scoped_refptr<MediaFoundationCdmProxy> cdm_proxy) { DVLOG_FUNC(2); DCHECK(task_runner_->RunsTasksInCurrentSequence()); // cdm_proxy_ should never change. DCHECK(!cdm_proxy_); - cdm_proxy_ = cdm_proxy; + cdm_proxy_ = std::move(cdm_proxy); HRESULT hr = cdm_proxy_->RefreshTrustedInput(); DLOG_IF(ERROR, FAILED(hr)) diff --git a/chromium/media/renderers/win/media_foundation_source_wrapper.h b/chromium/media/renderers/win/media_foundation_source_wrapper.h index 2c8a8c00f32..88ca8f96b44 100644 --- a/chromium/media/renderers/win/media_foundation_source_wrapper.h +++ b/chromium/media/renderers/win/media_foundation_source_wrapper.h @@ -12,9 +12,10 @@ #include <map> #include <vector> +#include "base/memory/scoped_refptr.h" #include "base/sequenced_task_runner.h" #include "media/base/media_resource.h" -#include "media/base/win/mf_cdm_proxy.h" +#include "media/base/win/media_foundation_cdm_proxy.h" #include "media/renderers/win/media_foundation_stream_wrapper.h" namespace media { @@ -40,6 +41,7 @@ class MediaFoundationSourceWrapper public: MediaFoundationSourceWrapper(); ~MediaFoundationSourceWrapper() override; + // This is only called on |task_runner|. void DetachResource(); @@ -109,7 +111,7 @@ class MediaFoundationSourceWrapper // |media_streams_| has encrypted stream or not. bool HasEncryptedStream() const; // Set the internal |cdm_proxy_|. - void SetCdmProxy(IMFCdmProxy* cdm_proxy); + void SetCdmProxy(scoped_refptr<MediaFoundationCdmProxy> cdm_proxy); // Set the internal |video_stream_enabled_|. Returns true if we are // re-enabling a video stream which has previously reached EOS. bool SetVideoStreamEnabled(bool enabled); @@ -130,7 +132,7 @@ class MediaFoundationSourceWrapper Microsoft::WRL::ComPtr<IMFMediaEventQueue> mf_media_event_queue_; // The proxy interface to communicate with MFCdm. - Microsoft::WRL::ComPtr<IMFCdmProxy> cdm_proxy_; + scoped_refptr<MediaFoundationCdmProxy> cdm_proxy_; bool video_stream_enabled_ = true; float current_rate_ = 0.0f; diff --git a/chromium/media/video/fake_gpu_memory_buffer.cc b/chromium/media/video/fake_gpu_memory_buffer.cc index b7d570c2fa6..87223970100 100644 --- a/chromium/media/video/fake_gpu_memory_buffer.cc +++ b/chromium/media/video/fake_gpu_memory_buffer.cc @@ -64,7 +64,7 @@ FakeGpuMemoryBuffer::FakeGpuMemoryBuffer(const gfx::Size& size, gfx::BufferFormat format, uint64_t modifier) : size_(size), format_(format) { - base::Optional<VideoPixelFormat> video_pixel_format = + absl::optional<VideoPixelFormat> video_pixel_format = GfxBufferFormatToVideoPixelFormat(format); CHECK(video_pixel_format); video_pixel_format_ = *video_pixel_format; diff --git a/chromium/media/video/gpu_memory_buffer_video_frame_pool.cc b/chromium/media/video/gpu_memory_buffer_video_frame_pool.cc index 89f65952080..a5327db33ce 100644 --- a/chromium/media/video/gpu_memory_buffer_video_frame_pool.cc +++ b/chromium/media/video/gpu_memory_buffer_video_frame_pool.cc @@ -595,16 +595,21 @@ gfx::Size CodedSize(const VideoFrame* video_frame, GpuVideoAcceleratorFactories::OutputFormat output_format) { DCHECK(gfx::Rect(video_frame->coded_size()) .Contains(video_frame->visible_rect())); - DCHECK((video_frame->visible_rect().x() & 1) == 0); + DCHECK_EQ(video_frame->visible_rect().x() % 2, 0); gfx::Size output; switch (output_format) { case GpuVideoAcceleratorFactories::OutputFormat::I420: case GpuVideoAcceleratorFactories::OutputFormat::P010: case GpuVideoAcceleratorFactories::OutputFormat::NV12_SINGLE_GMB: case GpuVideoAcceleratorFactories::OutputFormat::NV12_DUAL_GMB: - DCHECK((video_frame->visible_rect().y() & 1) == 0); - output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, - (video_frame->visible_rect().height() + 1) & ~1); + if (gfx::AllowOddHeightMultiPlanarBuffers()) { + output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, + video_frame->visible_rect().height()); + } else { + DCHECK((video_frame->visible_rect().y() & 1) == 0); + output = gfx::Size((video_frame->visible_rect().width() + 1) & ~1, + (video_frame->visible_rect().height() + 1) & ~1); + } break; case GpuVideoAcceleratorFactories::OutputFormat::XR30: case GpuVideoAcceleratorFactories::OutputFormat::XB30: @@ -702,14 +707,21 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame( } passthrough = true; } - // TODO(dcastagna): Handle odd positioned video frame input, see - // https://crbug.com/638906. - // TODO(emircan): Eliminate odd size video frame input cases as they are not - // valid, see https://crbug.com/webrtc/9033. - if ((video_frame->visible_rect().x() & 1) || - (video_frame->visible_rect().y() & 1) || - (video_frame->coded_size().width() & 1) || - (video_frame->coded_size().height() & 1)) { + + // TODO(https://crbug.com/638906): Handle odd positioned video frame input. + if (video_frame->visible_rect().x() % 2) + passthrough = true; + if (video_frame->visible_rect().y() % 2 && + !gfx::AllowOddHeightMultiPlanarBuffers()) { + passthrough = true; + } + + // TODO(https://crbug.com/webrtc/9033): Eliminate odd size video frame input + // cases as they are not valid. + if (video_frame->coded_size().width() % 2) + passthrough = true; + if (video_frame->coded_size().height() % 2 && + !gfx::AllowOddHeightMultiPlanarBuffers()) { passthrough = true; } diff --git a/chromium/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc b/chromium/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc index 90123897655..3dd9536affd 100644 --- a/chromium/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc +++ b/chromium/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc @@ -15,6 +15,7 @@ #include "media/video/gpu_memory_buffer_video_frame_pool.h" #include "media/video/mock_gpu_video_accelerator_factories.h" #include "testing/gmock/include/gmock/gmock.h" +#include "ui/gfx/buffer_format_util.h" using ::testing::_; using ::testing::AtLeast; @@ -612,13 +613,13 @@ TEST_F(GpuMemoryBufferVideoFramePoolTest, PreservesOrder) { std::vector<scoped_refptr<VideoFrame>> frame_outputs; scoped_refptr<VideoFrame> software_frame_1 = CreateTestYUVVideoFrame(10); - scoped_refptr<VideoFrame> frame_1 = nullptr; + scoped_refptr<VideoFrame> frame_1; gpu_memory_buffer_pool_->MaybeCreateHardwareFrame( software_frame_1, base::BindOnce(MaybeCreateHardwareFrameCallback, &frame_1)); scoped_refptr<VideoFrame> software_frame_2 = CreateTestYUVVideoFrame(10); - scoped_refptr<VideoFrame> frame_2 = nullptr; + scoped_refptr<VideoFrame> frame_2; base::TimeTicks time_2; gpu_memory_buffer_pool_->MaybeCreateHardwareFrame( software_frame_2, @@ -626,7 +627,7 @@ TEST_F(GpuMemoryBufferVideoFramePoolTest, PreservesOrder) { &time_2)); scoped_refptr<VideoFrame> software_frame_3 = VideoFrame::CreateEOSFrame(); - scoped_refptr<VideoFrame> frame_3 = nullptr; + scoped_refptr<VideoFrame> frame_3; base::TimeTicks time_3; gpu_memory_buffer_pool_->MaybeCreateHardwareFrame( software_frame_3, diff --git a/chromium/media/video/gpu_video_accelerator_factories.h b/chromium/media/video/gpu_video_accelerator_factories.h index 331233b05df..40137ef5740 100644 --- a/chromium/media/video/gpu_video_accelerator_factories.h +++ b/chromium/media/video/gpu_video_accelerator_factories.h @@ -14,7 +14,6 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/unsafe_shared_memory_region.h" -#include "base/optional.h" #include "base/unguessable_token.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/common/mailbox.h" @@ -24,6 +23,7 @@ #include "media/base/video_decoder.h" #include "media/base/video_types.h" #include "media/video/video_encode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/gpu_memory_buffer.h" namespace base { @@ -52,10 +52,10 @@ class MediaLog; // video accelerator. // Threading model: // * The GpuVideoAcceleratorFactories may be constructed on any thread. -// * The GpuVideoAcceleratorFactories has an associated message loop, which may -// be retrieved as |GetMessageLoop()|. -// * All calls to the Factories after construction must be made on its message -// loop, unless otherwise documented below. +// * The GpuVideoAcceleratorFactories has an associated task runner, which may +// be retrieved as |GetTaskRunner()|. +// * All calls to the Factories after construction must be made on its task +// runnner, unless otherwise documented below. class MEDIA_EXPORT GpuVideoAcceleratorFactories { public: enum class OutputFormat { @@ -137,7 +137,7 @@ class MEDIA_EXPORT GpuVideoAcceleratorFactories { // // TODO(sandersd): Remove Optional if/when all clients check // IsEncoderSupportKnown(). - virtual base::Optional<VideoEncodeAccelerator::SupportedProfiles> + virtual absl::optional<VideoEncodeAccelerator::SupportedProfiles> GetVideoEncodeAcceleratorSupportedProfiles() = 0; // Returns true if GetVideoEncodeAcceleratorSupportedProfiles() is populated. diff --git a/chromium/media/video/h264_level_limits.cc b/chromium/media/video/h264_level_limits.cc index a51d34a1472..2c6427c2013 100644 --- a/chromium/media/video/h264_level_limits.cc +++ b/chromium/media/video/h264_level_limits.cc @@ -142,7 +142,7 @@ bool CheckH264LevelLimits(VideoCodecProfile profile, return true; } -base::Optional<uint8_t> FindValidH264Level(VideoCodecProfile profile, +absl::optional<uint8_t> FindValidH264Level(VideoCodecProfile profile, uint32_t bitrate, uint32_t framerate, uint32_t framesize_in_mbs) { @@ -162,7 +162,7 @@ base::Optional<uint8_t> FindValidH264Level(VideoCodecProfile profile, return level; } } - return base::nullopt; + return absl::nullopt; } } // namespace media diff --git a/chromium/media/video/h264_level_limits.h b/chromium/media/video/h264_level_limits.h index fcc8eb8c8b1..2c46d7d1fbf 100644 --- a/chromium/media/video/h264_level_limits.h +++ b/chromium/media/video/h264_level_limits.h @@ -7,9 +7,9 @@ #include <stddef.h> -#include "base/optional.h" #include "media/base/media_export.h" #include "media/base/video_codecs.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -40,8 +40,8 @@ bool MEDIA_EXPORT CheckH264LevelLimits(VideoCodecProfile profile, // Return a minimum level that comforts Table A-1 in spec with |profile|, // |bitrate|, |framerate| and |framesize_in_mbs|. If there is no proper level, -// returns base::nullopt. -base::Optional<uint8_t> MEDIA_EXPORT +// returns absl::nullopt. +absl::optional<uint8_t> MEDIA_EXPORT FindValidH264Level(VideoCodecProfile profile, uint32_t bitrate, uint32_t framerate, diff --git a/chromium/media/video/h264_parser.cc b/chromium/media/video/h264_parser.cc index f4a10a12899..12332ca0678 100644 --- a/chromium/media/video/h264_parser.cc +++ b/chromium/media/video/h264_parser.cc @@ -107,7 +107,7 @@ H264SPS::H264SPS() { // Based on T-REC-H.264 7.4.2.1.1, "Sequence parameter set data semantics", // available from http://www.itu.int/rec/T-REC-H.264. -base::Optional<gfx::Size> H264SPS::GetCodedSize() const { +absl::optional<gfx::Size> H264SPS::GetCodedSize() const { // Interlaced frames are twice the height of each field. const int mb_unit = 16; int map_unit = frame_mbs_only_flag ? 16 : 32; @@ -121,7 +121,7 @@ base::Optional<gfx::Size> H264SPS::GetCodedSize() const { if (pic_width_in_mbs_minus1 > max_mb_minus1 || pic_height_in_map_units_minus1 > max_map_units_minus1) { DVLOG(1) << "Coded size is too large."; - return base::nullopt; + return absl::nullopt; } return gfx::Size(mb_unit * (pic_width_in_mbs_minus1 + 1), @@ -129,10 +129,10 @@ base::Optional<gfx::Size> H264SPS::GetCodedSize() const { } // Also based on section 7.4.2.1.1. -base::Optional<gfx::Rect> H264SPS::GetVisibleRect() const { - base::Optional<gfx::Size> coded_size = GetCodedSize(); +absl::optional<gfx::Rect> H264SPS::GetVisibleRect() const { + absl::optional<gfx::Size> coded_size = GetCodedSize(); if (!coded_size) - return base::nullopt; + return absl::nullopt; if (!frame_cropping_flag) return gfx::Rect(coded_size.value()); @@ -161,7 +161,7 @@ base::Optional<gfx::Rect> H264SPS::GetVisibleRect() const { coded_size->height() / crop_unit_y < frame_crop_top_offset || coded_size->height() / crop_unit_y < frame_crop_bottom_offset) { DVLOG(1) << "Frame cropping exceeds coded size."; - return base::nullopt; + return absl::nullopt; } int crop_left = crop_unit_x * frame_crop_left_offset; int crop_right = crop_unit_x * frame_crop_right_offset; @@ -174,7 +174,7 @@ base::Optional<gfx::Rect> H264SPS::GetVisibleRect() const { if (coded_size->width() - crop_left <= crop_right || coded_size->height() - crop_top <= crop_bottom) { DVLOG(1) << "Frame cropping excludes entire frame."; - return base::nullopt; + return absl::nullopt; } return gfx::Rect(crop_left, crop_top, diff --git a/chromium/media/video/h264_parser.h b/chromium/media/video/h264_parser.h index 652cbe9f70f..af8cdc8d75e 100644 --- a/chromium/media/video/h264_parser.h +++ b/chromium/media/video/h264_parser.h @@ -16,12 +16,12 @@ #include <vector> #include "base/macros.h" -#include "base/optional.h" #include "media/base/media_export.h" #include "media/base/ranges.h" #include "media/base/video_codecs.h" #include "media/base/video_color_space.h" #include "media/video/h264_bit_reader.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace gfx { class Rect; @@ -214,10 +214,10 @@ struct MEDIA_EXPORT H264SPS { bool* constraint_set3_flag); // Helpers to compute frequently-used values. These methods return - // base::nullopt if they encounter integer overflow. They do not verify that + // absl::nullopt if they encounter integer overflow. They do not verify that // the results are in-spec for the given profile or level. - base::Optional<gfx::Size> GetCodedSize() const; - base::Optional<gfx::Rect> GetVisibleRect() const; + absl::optional<gfx::Size> GetCodedSize() const; + absl::optional<gfx::Rect> GetVisibleRect() const; VideoColorSpace GetColorSpace() const; // Helper to compute indicated level from parsed SPS data. The value of diff --git a/chromium/media/video/h264_parser_fuzzertest.cc b/chromium/media/video/h264_parser_fuzzertest.cc index e8355193371..6ded4dcc95c 100644 --- a/chromium/media/video/h264_parser_fuzzertest.cc +++ b/chromium/media/video/h264_parser_fuzzertest.cc @@ -5,8 +5,8 @@ #include <stddef.h> #include "base/numerics/safe_conversions.h" -#include "base/optional.h" #include "media/video/h264_parser.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -46,9 +46,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { break; // Also test the SPS helper methods. We make sure that the results are // used so that the calls are not optimized away. - base::Optional<gfx::Size> coded_size = sps->GetCodedSize(); + absl::optional<gfx::Size> coded_size = sps->GetCodedSize(); volatile_sink = coded_size.value_or(gfx::Size()).ToString().length(); - base::Optional<gfx::Rect> visible_rect = sps->GetVisibleRect(); + absl::optional<gfx::Rect> visible_rect = sps->GetVisibleRect(); volatile_sink = visible_rect.value_or(gfx::Rect()).ToString().length(); break; } diff --git a/chromium/media/video/h264_parser_unittest.cc b/chromium/media/video/h264_parser_unittest.cc index 7a67fe81e4d..96d997dcde8 100644 --- a/chromium/media/video/h264_parser_unittest.cc +++ b/chromium/media/video/h264_parser_unittest.cc @@ -9,13 +9,13 @@ #include "base/command_line.h" #include "base/files/memory_mapped_file.h" #include "base/logging.h" -#include "base/optional.h" #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "media/base/subsample_entry.h" #include "media/base/test_data_util.h" #include "media/video/h264_parser.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -62,7 +62,7 @@ TEST_F(H264SPSTest, GetCodedSize) { // Overflow. sps->pic_width_in_mbs_minus1 = std::numeric_limits<int>::max(); - EXPECT_EQ(base::nullopt, sps->GetCodedSize()); + EXPECT_EQ(absl::nullopt, sps->GetCodedSize()); } TEST_F(H264SPSTest, GetVisibleRect) { @@ -89,14 +89,14 @@ TEST_F(H264SPSTest, GetVisibleRect) { sps->frame_crop_right_offset = 1; sps->frame_crop_top_offset = 0; sps->frame_crop_bottom_offset = 0; - EXPECT_EQ(base::nullopt, sps->GetVisibleRect()); + EXPECT_EQ(absl::nullopt, sps->GetVisibleRect()); // Overflow. sps->frame_crop_left_offset = std::numeric_limits<int>::max() / 2 + 1; sps->frame_crop_right_offset = 0; sps->frame_crop_top_offset = 0; sps->frame_crop_bottom_offset = 0; - EXPECT_EQ(base::nullopt, sps->GetVisibleRect()); + EXPECT_EQ(absl::nullopt, sps->GetVisibleRect()); } TEST(H264ParserTest, StreamFileParsing) { diff --git a/chromium/media/video/h264_poc.cc b/chromium/media/video/h264_poc.cc index 59c0ae7b651..d06729240a1 100644 --- a/chromium/media/video/h264_poc.cc +++ b/chromium/media/video/h264_poc.cc @@ -57,12 +57,12 @@ void H264POC::Reset() { pending_mmco5_ = false; } -base::Optional<int32_t> H264POC::ComputePicOrderCnt( +absl::optional<int32_t> H264POC::ComputePicOrderCnt( const H264SPS* sps, const H264SliceHeader& slice_hdr) { if (slice_hdr.field_pic_flag) { DLOG(ERROR) << "Interlaced frames are not supported"; - return base::nullopt; + return absl::nullopt; } int32_t pic_order_cnt = 0; @@ -166,7 +166,7 @@ base::Optional<int32_t> H264POC::ComputePicOrderCnt( // Moved inside 8-9 to avoid division when this check is not done. if (sps->num_ref_frames_in_pic_order_cnt_cycle == 0) { DLOG(ERROR) << "Invalid num_ref_frames_in_pic_order_cnt_cycle"; - return base::nullopt; + return absl::nullopt; } // H264Parser checks that num_ref_frames_in_pic_order_cnt_cycle < 255. @@ -246,7 +246,7 @@ base::Optional<int32_t> H264POC::ComputePicOrderCnt( default: DLOG(ERROR) << "Invalid pic_order_cnt_type: " << sps->pic_order_cnt_type; - return base::nullopt; + return absl::nullopt; } return pic_order_cnt; diff --git a/chromium/media/video/h264_poc.h b/chromium/media/video/h264_poc.h index 06a0dfd3411..0f0b242cfe4 100644 --- a/chromium/media/video/h264_poc.h +++ b/chromium/media/video/h264_poc.h @@ -20,7 +20,7 @@ class MEDIA_EXPORT H264POC { ~H264POC(); // Returns the picture order count for a slice. - base::Optional<int32_t> ComputePicOrderCnt(const H264SPS* sps, + absl::optional<int32_t> ComputePicOrderCnt(const H264SPS* sps, const H264SliceHeader& slice_hdr); // As specified, the POC of a frame with MMCO5 changes (to zero) after diff --git a/chromium/media/video/h264_poc_unittest.cc b/chromium/media/video/h264_poc_unittest.cc index cc667ea0216..60a485cb40a 100644 --- a/chromium/media/video/h264_poc_unittest.cc +++ b/chromium/media/video/h264_poc_unittest.cc @@ -43,7 +43,7 @@ class H264POCTest : public testing::Test { slice_hdr_.ref_pic_marking[2].memory_mgmnt_control_operation = 0; } - base::Optional<int32_t> poc_; + absl::optional<int32_t> poc_; H264SPS sps_; H264SliceHeader slice_hdr_; diff --git a/chromium/media/video/h265_parser.cc b/chromium/media/video/h265_parser.cc index 61fcbbc3f8c..aababea9d8a 100644 --- a/chromium/media/video/h265_parser.cc +++ b/chromium/media/video/h265_parser.cc @@ -988,6 +988,14 @@ H265Parser::Result H265Parser::ParseSliceHeader(const H265NALU& nalu, memcpy(reinterpret_cast<uint8_t*>(shdr) + skip_amount, reinterpret_cast<uint8_t*>(prior_shdr) + skip_amount, sizeof(H265SliceHeader) - skip_amount); + + // We also need to validate the fields that have conditions that depend on + // anything unique in this slice (i.e. anything already parsed). + if ((shdr->irap_pic || + sps->sps_max_dec_pic_buffering_minus1[pps->temporal_id] == 0) && + nalu.nuh_layer_id == 0) { + TRUE_OR_RETURN(shdr->slice_type == 2); + } } else { // Set these defaults if they are not present here. shdr->pic_output_flag = 1; diff --git a/chromium/media/video/h265_parser.h b/chromium/media/video/h265_parser.h index e322aa81358..b3d4198e0f7 100644 --- a/chromium/media/video/h265_parser.h +++ b/chromium/media/video/h265_parser.h @@ -360,6 +360,10 @@ struct MEDIA_EXPORT H265SliceHeader { size_t header_size; // calculated, not including emulation prevention bytes size_t header_emulation_prevention_bytes; + // Calculated, but needs to be preserved when we copy slice dependent data + // so put it at the front. + bool irap_pic; + // Syntax elements. bool first_slice_segment_in_pic_flag; bool no_output_of_prior_pics_flag; @@ -403,7 +407,6 @@ struct MEDIA_EXPORT H265SliceHeader { // Calculated. int curr_rps_idx; int num_pic_total_curr; - bool irap_pic; // Number of bits st_ref_pic_set takes after removing emulation prevention // bytes. int st_rps_bits; diff --git a/chromium/media/video/mock_gpu_video_accelerator_factories.h b/chromium/media/video/mock_gpu_video_accelerator_factories.h index a1aadde4566..98363d62d71 100644 --- a/chromium/media/video/mock_gpu_video_accelerator_factories.h +++ b/chromium/media/video/mock_gpu_video_accelerator_factories.h @@ -84,7 +84,7 @@ class MockGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories { std::unique_ptr<VideoEncodeAccelerator> CreateVideoEncodeAccelerator() override; - base::Optional<VideoEncodeAccelerator::SupportedProfiles> + absl::optional<VideoEncodeAccelerator::SupportedProfiles> GetVideoEncodeAcceleratorSupportedProfiles() override { return VideoEncodeAccelerator::SupportedProfiles(); } diff --git a/chromium/media/video/openh264_video_encoder.cc b/chromium/media/video/openh264_video_encoder.cc index 8aab81210f5..fd01eea3fa5 100644 --- a/chromium/media/video/openh264_video_encoder.cc +++ b/chromium/media/video/openh264_video_encoder.cc @@ -8,7 +8,6 @@ #include <limits> #include "base/logging.h" -#include "base/strings/stringprintf.h" #include "base/system/sys_info.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" @@ -191,7 +190,7 @@ Status OpenH264VideoEncoder::DrainOutputs(const SFrameBSInfo& frame_info, if (!h264_converter_) { result.size = total_chunk_size; - output_cb_.Run(std::move(result), base::Optional<CodecDescription>()); + output_cb_.Run(std::move(result), absl::optional<CodecDescription>()); return OkStatus(); } @@ -207,7 +206,7 @@ Status OpenH264VideoEncoder::DrainOutputs(const SFrameBSInfo& frame_info, result.size = converted_output_size; - base::Optional<CodecDescription> desc; + absl::optional<CodecDescription> desc; if (config_changed) { const auto& config = h264_converter_->GetCurrentConfig(); desc = CodecDescription(); diff --git a/chromium/media/video/openh264_video_encoder.h b/chromium/media/video/openh264_video_encoder.h index 3a4a57b2c33..47e0bdd8230 100644 --- a/chromium/media/video/openh264_video_encoder.h +++ b/chromium/media/video/openh264_video_encoder.h @@ -8,7 +8,6 @@ #include <memory> #include <vector> -#include "base/callback_forward.h" #include "media/base/media_export.h" #include "media/base/video_encoder.h" #include "media/base/video_frame_pool.h" diff --git a/chromium/media/video/software_video_encoder_test.cc b/chromium/media/video/software_video_encoder_test.cc index e8ba147bb85..83e23d9ff1d 100644 --- a/chromium/media/video/software_video_encoder_test.cc +++ b/chromium/media/video/software_video_encoder_test.cc @@ -12,7 +12,6 @@ #include "base/memory/scoped_refptr.h" #include "base/sequenced_task_runner.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "base/test/bind.h" #include "base/test/gmock_callback_support.h" #include "base/test/task_environment.h" @@ -189,6 +188,20 @@ class SoftwareVideoEncoderTest }); } + void DecodeAndWaitForStatus( + scoped_refptr<DecoderBuffer> buffer, + const base::Location& location = base::Location::Current()) { + base::RunLoop run_loop; + decoder_->Decode( + std::move(buffer), base::BindLambdaForTesting([&](Status status) { + EXPECT_TRUE(status.is_ok()) + << " Callback created: " << location.ToString() + << " Code: " << status.code() << " Error: " << status.message(); + run_loop.Quit(); + })); + run_loop.Run(location); + } + int CountDifferentPixels(VideoFrame& frame1, VideoFrame& frame2) { int diff_cnt = 0; uint8_t tolerance = 10; @@ -241,7 +254,7 @@ TEST_P(SoftwareVideoEncoderTest, InitializeAndFlush) { options.frame_size = gfx::Size(640, 480); bool output_called = false; VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { output_called = true; }); @@ -262,7 +275,7 @@ TEST_P(SoftwareVideoEncoderTest, ForceAllKeyFrames) { VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( [&](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription> desc) { + absl::optional<VideoEncoder::CodecDescription> desc) { EXPECT_TRUE(output.key_frame); outputs_count++; }); @@ -290,7 +303,7 @@ TEST_P(SoftwareVideoEncoderTest, ResizeFrames) { VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( [&](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription> desc) { + absl::optional<VideoEncoder::CodecDescription> desc) { outputs_count++; }); @@ -325,7 +338,7 @@ TEST_P(SoftwareVideoEncoderTest, OutputCountEqualsFrameCount) { VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( [&](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription> desc) { + absl::optional<VideoEncoder::CodecDescription> desc) { EXPECT_NE(output.data, nullptr); EXPECT_EQ(output.timestamp, frame_duration * outputs_count); outputs_count++; @@ -369,7 +382,7 @@ TEST_P(SoftwareVideoEncoderTest, EncodeAndDecode) { VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting( [&, this](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription> desc) { + absl::optional<VideoEncoder::CodecDescription> desc) { auto buffer = DecoderBuffer::FromArray(std::move(output.data), output.size); buffer->set_timestamp(output.timestamp); @@ -400,8 +413,7 @@ TEST_P(SoftwareVideoEncoderTest, EncodeAndDecode) { } encoder_->Flush(ValidatingStatusCB()); - decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), ValidatingStatusCB()); - RunUntilIdle(); + DecodeAndWaitForStatus(DecoderBuffer::CreateEOSBuffer()); EXPECT_EQ(decoded_frames.size(), frames_to_encode.size()); for (auto i = 0u; i < decoded_frames.size(); i++) { auto original_frame = frames_to_encode[i]; @@ -435,7 +447,7 @@ TEST_P(SVCVideoEncoderTest, EncodeClipTemporalSvc) { VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting( [&](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription> desc) { + absl::optional<VideoEncoder::CodecDescription> desc) { chunks.push_back(std::move(output)); }); @@ -476,12 +488,10 @@ TEST_P(SVCVideoEncoderTest, EncodeClipTemporalSvc) { auto buffer = DecoderBuffer::CopyFrom(chunk.data.get(), chunk.size); buffer->set_timestamp(chunk.timestamp); buffer->set_is_key_frame(chunk.key_frame); - decoder_->Decode(std::move(buffer), ValidatingStatusCB()); - RunUntilIdle(); + DecodeAndWaitForStatus(std::move(buffer)); } } - decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), ValidatingStatusCB()); - RunUntilIdle(); + DecodeAndWaitForStatus(DecoderBuffer::CreateEOSBuffer()); int rate_decimator = (1 << (options.temporal_layers - 1)) / (1 << max_layer); @@ -504,7 +514,7 @@ TEST_P(H264VideoEncoderTest, AvcExtraData) { VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( [&](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription> desc) { + absl::optional<VideoEncoder::CodecDescription> desc) { switch (outputs_count) { case 0: // First frame should have extra_data @@ -549,7 +559,7 @@ TEST_P(H264VideoEncoderTest, AnnexB) { VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( [&](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription> desc) { + absl::optional<VideoEncoder::CodecDescription> desc) { EXPECT_FALSE(desc.has_value()); EXPECT_NE(output.data, nullptr); @@ -591,7 +601,7 @@ TEST_P(H264VideoEncoderTest, EncodeAndDecodeWithConfig) { options.avc.produce_annexb = false; struct ChunkWithConfig { VideoEncoderOutput output; - base::Optional<VideoEncoder::CodecDescription> desc; + absl::optional<VideoEncoder::CodecDescription> desc; }; std::vector<scoped_refptr<VideoFrame>> frames_to_encode; std::vector<scoped_refptr<VideoFrame>> decoded_frames; @@ -602,7 +612,7 @@ TEST_P(H264VideoEncoderTest, EncodeAndDecodeWithConfig) { VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting( [&](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription> desc) { + absl::optional<VideoEncoder::CodecDescription> desc) { chunks.push_back({std::move(output), std::move(desc)}); }); @@ -632,9 +642,7 @@ TEST_P(H264VideoEncoderTest, EncodeAndDecodeWithConfig) { if (chunk.desc.has_value()) { if (decoder_) - decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), - ValidatingStatusCB()); - RunUntilIdle(); + DecodeAndWaitForStatus(DecoderBuffer::CreateEOSBuffer()); PrepareDecoder(options.frame_size, std::move(decoder_output_cb), chunk.desc.value()); } @@ -642,11 +650,9 @@ TEST_P(H264VideoEncoderTest, EncodeAndDecodeWithConfig) { auto buffer = DecoderBuffer::FromArray(std::move(output.data), output.size); buffer->set_timestamp(output.timestamp); buffer->set_is_key_frame(output.key_frame); - decoder_->Decode(std::move(buffer), ValidatingStatusCB()); - RunUntilIdle(); + DecodeAndWaitForStatus(std::move(buffer)); } - decoder_->Decode(DecoderBuffer::CreateEOSBuffer(), ValidatingStatusCB()); - RunUntilIdle(); + DecodeAndWaitForStatus(DecoderBuffer::CreateEOSBuffer()); EXPECT_EQ(decoded_frames.size(), total_frames_count); } diff --git a/chromium/media/video/video_decode_accelerator.h b/chromium/media/video/video_decode_accelerator.h index 5821cc9ece5..12a0c37b559 100644 --- a/chromium/media/video/video_decode_accelerator.h +++ b/chromium/media/video/video_decode_accelerator.h @@ -12,7 +12,6 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/unguessable_token.h" #include "media/base/bitstream_buffer.h" #include "media/base/cdm_context.h" @@ -22,6 +21,7 @@ #include "media/base/status.h" #include "media/base/video_decoder_config.h" #include "media/video/picture.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/color_space.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -156,7 +156,7 @@ class MEDIA_EXPORT VideoDecodeAccelerator { // The CDM that the VDA should use to decode encrypted streams. Must be // set to a valid ID if |is_encrypted|. - base::Optional<base::UnguessableToken> cdm_id; + absl::optional<base::UnguessableToken> cdm_id; // Whether the client supports deferred initialization. bool is_deferred_initialization_allowed = false; @@ -189,7 +189,7 @@ class MEDIA_EXPORT VideoDecodeAccelerator { gfx::ColorSpace target_color_space; // HDR metadata specified by the container. - base::Optional<gfx::HDRMetadata> hdr_metadata; + absl::optional<gfx::HDRMetadata> hdr_metadata; }; // Interface for collaborating with picture interface to provide memory for diff --git a/chromium/media/video/video_encode_accelerator.cc b/chromium/media/video/video_encode_accelerator.cc index e0e0fe45b9a..361e53ade2d 100644 --- a/chromium/media/video/video_encode_accelerator.cc +++ b/chromium/media/video/video_encode_accelerator.cc @@ -49,11 +49,11 @@ VideoEncodeAccelerator::Config::Config( const gfx::Size& input_visible_size, VideoCodecProfile output_profile, uint32_t initial_bitrate, - base::Optional<uint32_t> initial_framerate, - base::Optional<uint32_t> gop_length, - base::Optional<uint8_t> h264_output_level, + absl::optional<uint32_t> initial_framerate, + absl::optional<uint32_t> gop_length, + absl::optional<uint8_t> h264_output_level, bool is_constrained_h264, - base::Optional<StorageType> storage_type, + absl::optional<StorageType> storage_type, ContentType content_type, const std::vector<SpatialLayer>& spatial_layers) : input_format(input_format), diff --git a/chromium/media/video/video_encode_accelerator.h b/chromium/media/video/video_encode_accelerator.h index 0bea721e347..3e0584a9d57 100644 --- a/chromium/media/video/video_encode_accelerator.h +++ b/chromium/media/video/video_encode_accelerator.h @@ -14,7 +14,6 @@ #include "base/callback_forward.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "media/base/bitstream_buffer.h" #include "media/base/media_export.h" @@ -23,6 +22,7 @@ #include "media/base/video_frame.h" #include "media/video/h264_parser.h" #include "media/video/video_encoder_info.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -86,8 +86,8 @@ struct MEDIA_EXPORT BitstreamBufferMetadata final { // Either |vp8| or |vp9| may be set, but not both of them. Presumably, it's // also possible for none of them to be set. - base::Optional<Vp8Metadata> vp8; - base::Optional<Vp9Metadata> vp9; + absl::optional<Vp8Metadata> vp8; + absl::optional<Vp9Metadata> vp9; }; // Video encoder interface. @@ -100,6 +100,8 @@ class MEDIA_EXPORT VideoEncodeAccelerator { const gfx::Size& max_resolution, uint32_t max_framerate_numerator = 0u, uint32_t max_framerate_denominator = 1u); + SupportedProfile(const SupportedProfile& other) = default; + SupportedProfile& operator=(const SupportedProfile& other) = default; ~SupportedProfile(); VideoCodecProfile profile; gfx::Size min_resolution; @@ -160,11 +162,11 @@ class MEDIA_EXPORT VideoEncodeAccelerator { const gfx::Size& input_visible_size, VideoCodecProfile output_profile, uint32_t initial_bitrate, - base::Optional<uint32_t> initial_framerate = base::nullopt, - base::Optional<uint32_t> gop_length = base::nullopt, - base::Optional<uint8_t> h264_output_level = base::nullopt, + absl::optional<uint32_t> initial_framerate = absl::nullopt, + absl::optional<uint32_t> gop_length = absl::nullopt, + absl::optional<uint8_t> h264_output_level = absl::nullopt, bool is_constrained_h264 = false, - base::Optional<StorageType> storage_type = base::nullopt, + absl::optional<StorageType> storage_type = absl::nullopt, ContentType content_type = ContentType::kCamera, const std::vector<SpatialLayer>& spatial_layers = {}); @@ -191,17 +193,17 @@ class MEDIA_EXPORT VideoEncodeAccelerator { // Initial encoding framerate in frames per second. This is optional and // VideoEncodeAccelerator should use |kDefaultFramerate| if not given. - base::Optional<uint32_t> initial_framerate; + absl::optional<uint32_t> initial_framerate; // Group of picture length for encoded output stream, indicates the // distance between two key frames, i.e. IPPPIPPP would be represent as 4. - base::Optional<uint32_t> gop_length; + absl::optional<uint32_t> gop_length; // Codec level of encoded output stream for H264 only. This value should // be aligned to the H264 standard definition of SPS.level_idc. // If this is not given, VideoEncodeAccelerator selects one of proper H.264 // levels for |input_visible_size| and |initial_framerate|. - base::Optional<uint8_t> h264_output_level; + absl::optional<uint8_t> h264_output_level; // Indicates baseline profile or constrained baseline profile for H264 only. bool is_constrained_h264; @@ -211,7 +213,7 @@ class MEDIA_EXPORT VideoEncodeAccelerator { // Encode(). // This is kShmem iff a video frame is mapped in user space. // This is kDmabuf iff a video frame has dmabuf. - base::Optional<StorageType> storage_type; + absl::optional<StorageType> storage_type; // Indicates captured video (from a camera) or generated (screen grabber). // Screen content has a number of special properties such as lack of noise, @@ -225,6 +227,12 @@ class MEDIA_EXPORT VideoEncodeAccelerator { // empty, VideoEncodeAccelerator should refer the width, height, bitrate and // etc. of |spatial_layers|. std::vector<SpatialLayer> spatial_layers; + + // Currently it's Mac only! This flag forces Mac encoder to enforce low + // latency mode. Initialize() will fail if the system can't do it for some + // reason. See VTVideoEncodeAccelerator::require_low_delay_ for more + // details. + bool require_low_delay = true; }; // Interface for clients that use VideoEncodeAccelerator. These callbacks will diff --git a/chromium/media/video/video_encode_accelerator_adapter.cc b/chromium/media/video/video_encode_accelerator_adapter.cc index 15c2888b9d5..8e47cf2406e 100644 --- a/chromium/media/video/video_encode_accelerator_adapter.cc +++ b/chromium/media/video/video_encode_accelerator_adapter.cc @@ -12,7 +12,6 @@ #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/sequenced_task_runner.h" -#include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/time/time.h" #include "build/build_config.h" @@ -37,7 +36,7 @@ VideoEncodeAccelerator::Config SetUpVeaConfig( const VideoEncoder::Options& opts, VideoPixelFormat format, VideoFrame::StorageType storage_type) { - base::Optional<uint32_t> initial_framerate; + absl::optional<uint32_t> initial_framerate; if (opts.framerate.has_value()) initial_framerate = static_cast<uint32_t>(opts.framerate.value()); @@ -58,6 +57,9 @@ VideoEncodeAccelerator::Config SetUpVeaConfig( config.spatial_layers.push_back(layer); } + // We don't mind if Mac encoding will have higher latency on low resolutions. + config.require_low_delay = false; + const bool is_rgb = format == PIXEL_FORMAT_XBGR || format == PIXEL_FORMAT_XRGB || format == PIXEL_FORMAT_ABGR || format == PIXEL_FORMAT_ARGB; @@ -289,9 +291,9 @@ void VideoEncodeAcceleratorAdapter::EncodeOnAcceleratorThread( StatusOr<scoped_refptr<VideoFrame>> result(nullptr); if (use_gpu_buffer) - result = PrepareGpuFrame(options_.frame_size, frame); + result = PrepareGpuFrame(input_coded_size_, frame); else - result = PrepareCpuFrame(options_.frame_size, frame); + result = PrepareCpuFrame(input_coded_size_, frame); if (result.has_error()) { auto status = std::move(result).error(); @@ -417,6 +419,7 @@ void VideoEncodeAcceleratorAdapter::RequireBitstreamBuffers( size_t output_buffer_size) { DCHECK_CALLED_ON_VALID_SEQUENCE(accelerator_sequence_checker_); + input_coded_size_ = input_coded_size; input_buffer_size_ = VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_coded_size); @@ -438,7 +441,7 @@ void VideoEncodeAcceleratorAdapter::RequireBitstreamBuffers( void VideoEncodeAcceleratorAdapter::BitstreamBufferReady( int32_t buffer_id, const BitstreamBufferMetadata& metadata) { - base::Optional<CodecDescription> desc; + absl::optional<CodecDescription> desc; VideoEncoderOutput result; result.key_frame = metadata.key_frame; result.timestamp = metadata.timestamp; @@ -627,7 +630,7 @@ VideoEncodeAcceleratorAdapter::PrepareCpuFrame( ? ConvertToMemoryMappedFrame(src_frame) : src_frame; auto shared_frame = VideoFrame::WrapExternalData( - PIXEL_FORMAT_I420, options_.frame_size, gfx::Rect(size), size, + PIXEL_FORMAT_I420, size, gfx::Rect(size), size, mapping.GetMemoryAsSpan<uint8_t>().data(), mapping.size(), src_frame->timestamp()); diff --git a/chromium/media/video/video_encode_accelerator_adapter.h b/chromium/media/video/video_encode_accelerator_adapter.h index f190477a04d..b0248a3cc89 100644 --- a/chromium/media/video/video_encode_accelerator_adapter.h +++ b/chromium/media/video/video_encode_accelerator_adapter.h @@ -13,11 +13,11 @@ #include "base/containers/queue.h" #include "base/memory/scoped_refptr.h" #include "base/memory/unsafe_shared_memory_pool.h" -#include "base/optional.h" #include "base/synchronization/lock.h" #include "media/base/media_export.h" #include "media/base/video_encoder.h" #include "media/video/video_encode_accelerator.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace base { @@ -142,7 +142,7 @@ class MEDIA_EXPORT VideoEncodeAcceleratorAdapter scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; State state_ = State::kNotInitialized; - base::Optional<bool> flush_support_; + absl::optional<bool> flush_support_; // True if underlying instance of VEA can handle GPU backed frames with a // size different from what VEA was configured for. @@ -166,6 +166,8 @@ class MEDIA_EXPORT VideoEncodeAcceleratorAdapter VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN; Options options_; OutputCB output_cb_; + + gfx::Size input_coded_size_; }; } // namespace media diff --git a/chromium/media/video/video_encode_accelerator_adapter_test.cc b/chromium/media/video/video_encode_accelerator_adapter_test.cc index f7cab8ab448..baa9c4fa0d3 100644 --- a/chromium/media/video/video_encode_accelerator_adapter_test.cc +++ b/chromium/media/video/video_encode_accelerator_adapter_test.cc @@ -11,7 +11,6 @@ #include "base/logging.h" #include "base/memory/scoped_refptr.h" #include "base/sequenced_task_runner.h" -#include "base/strings/stringprintf.h" #include "base/task/thread_pool.h" #include "base/test/bind.h" #include "base/test/gmock_callback_support.h" @@ -180,7 +179,7 @@ TEST_F(VideoEncodeAcceleratorAdapterTest, PreInitialize) { VideoEncoder::Options options; options.frame_size = gfx::Size(640, 480); VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { }); adapter()->Initialize(profile_, options, std::move(output_cb), @@ -194,7 +193,7 @@ TEST_F(VideoEncodeAcceleratorAdapterTest, InitializeAfterFirstFrame) { int outputs_count = 0; auto pixel_format = PIXEL_FORMAT_I420; VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { outputs_count++; }); @@ -223,7 +222,7 @@ TEST_F(VideoEncodeAcceleratorAdapterTest, TemporalSvc) { auto pixel_format = PIXEL_FORMAT_I420; VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( [&](VideoEncoderOutput output, - base::Optional<VideoEncoder::CodecDescription>) { + absl::optional<VideoEncoder::CodecDescription>) { if (output.timestamp == base::TimeDelta::FromMilliseconds(1)) EXPECT_EQ(output.temporal_id, 1); else @@ -263,7 +262,7 @@ TEST_F(VideoEncodeAcceleratorAdapterTest, FlushDuringInitialize) { int outputs_count = 0; auto pixel_format = PIXEL_FORMAT_I420; VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { outputs_count++; }); @@ -293,7 +292,7 @@ TEST_F(VideoEncodeAcceleratorAdapterTest, InitializationError) { int outputs_count = 0; auto pixel_format = PIXEL_FORMAT_I420; VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { outputs_count++; }); @@ -323,7 +322,7 @@ TEST_P(VideoEncodeAcceleratorAdapterTest, TwoFramesResize) { gfx::Size large_size(800, 600); auto pixel_format = GetParam(); VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { outputs_count++; }); @@ -359,7 +358,7 @@ TEST_F(VideoEncodeAcceleratorAdapterTest, AutomaticResizeSupport) { gfx::Size small_size(480, 320); auto pixel_format = PIXEL_FORMAT_NV12; VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { outputs_count++; }); @@ -398,7 +397,7 @@ TEST_P(VideoEncodeAcceleratorAdapterTest, RunWithAllPossibleInputConversions) { adapter()->SetInputBufferPreferenceForTesting(input_kind); VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting( - [&](VideoEncoderOutput, base::Optional<VideoEncoder::CodecDescription>) { + [&](VideoEncoderOutput, absl::optional<VideoEncoder::CodecDescription>) { outputs_count++; }); diff --git a/chromium/media/video/video_encoder_info.h b/chromium/media/video/video_encoder_info.h index f6d7fbb0ea1..892017e0d18 100644 --- a/chromium/media/video/video_encoder_info.h +++ b/chromium/media/video/video_encoder_info.h @@ -9,8 +9,8 @@ #include <string> #include <vector> -#include "base/optional.h" #include "media/base/media_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "ui/gfx/geometry/size.h" namespace media { diff --git a/chromium/media/video/vpx_video_encoder.h b/chromium/media/video/vpx_video_encoder.h index 4fffc12237f..f3775caa838 100644 --- a/chromium/media/video/vpx_video_encoder.h +++ b/chromium/media/video/vpx_video_encoder.h @@ -8,7 +8,6 @@ #include <memory> #include <vector> -#include "base/callback_forward.h" #include "media/base/media_export.h" #include "media/base/video_encoder.h" #include "media/base/video_frame_pool.h" @@ -56,4 +55,4 @@ class MEDIA_EXPORT VpxVideoEncoder : public VideoEncoder { }; } // namespace media -#endif // MEDIA_VIDEO_VPX_VIDEO_ENCODER_H_
\ No newline at end of file +#endif // MEDIA_VIDEO_VPX_VIDEO_ENCODER_H_ diff --git a/chromium/media/webrtc/DIR_METADATA b/chromium/media/webrtc/DIR_METADATA index 7ae006c85b7..e28b9ae8a63 100644 --- a/chromium/media/webrtc/DIR_METADATA +++ b/chromium/media/webrtc/DIR_METADATA @@ -1,10 +1,10 @@ # Metadata information for this directory. # # For more information on DIR_METADATA files, see: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md # # For the schema of this file, see Metadata message: -# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto +# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto monorail { component: "Blink>WebRTC>Audio" diff --git a/chromium/media/webrtc/helpers.h b/chromium/media/webrtc/helpers.h index 4e27fefcdf3..c748f86f58a 100644 --- a/chromium/media/webrtc/helpers.h +++ b/chromium/media/webrtc/helpers.h @@ -23,4 +23,4 @@ bool LeftAndRightChannelsAreSymmetric(const AudioBus& audio); } // namespace media -#endif // MEDIA_WEBRTC_WEBRTC_HELPERS_H_ +#endif // MEDIA_WEBRTC_HELPERS_H_ diff --git a/chromium/media/webrtc/webrtc_switches.cc b/chromium/media/webrtc/webrtc_switches.cc index 3c16994bca6..051228d7519 100644 --- a/chromium/media/webrtc/webrtc_switches.cc +++ b/chromium/media/webrtc/webrtc_switches.cc @@ -20,6 +20,11 @@ const char kAgcStartupMinVolume[] = "agc-startup-min-volume"; namespace features { +// When enabled we will tell WebRTC that we want to use the +// Windows.Graphics.Capture API based DesktopCapturer, if it is available. +const base::Feature kWebRtcAllowWgcDesktopCapturer{ + "AllowWgcDesktopCapturer", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables multichannel capture audio to be processed without downmixing in the // WebRTC audio processing module. const base::Feature kWebRtcEnableCaptureMultiChannelApm{ @@ -36,4 +41,8 @@ const base::Feature kWebRtcAllow48kHzProcessingOnArm{ const base::Feature kWebRtcHybridAgc{"WebRtcHybridAgc", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables and configures the clipping control in the WebRTC analog AGC. +const base::Feature kWebRtcAnalogAgcClippingControl{ + "WebRtcAnalogAgcClippingControl", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features diff --git a/chromium/media/webrtc/webrtc_switches.h b/chromium/media/webrtc/webrtc_switches.h index 1c223d9066c..c7675917c10 100644 --- a/chromium/media/webrtc/webrtc_switches.h +++ b/chromium/media/webrtc/webrtc_switches.h @@ -19,6 +19,9 @@ COMPONENT_EXPORT(MEDIA_WEBRTC) extern const char kAgcStartupMinVolume[]; namespace features { COMPONENT_EXPORT(MEDIA_WEBRTC) +extern const base::Feature kWebRtcAllowWgcDesktopCapturer; + +COMPONENT_EXPORT(MEDIA_WEBRTC) extern const base::Feature kWebRtcEnableCaptureMultiChannelApm; COMPONENT_EXPORT(MEDIA_WEBRTC) @@ -27,6 +30,9 @@ extern const base::Feature kWebRtcAllow48kHzProcessingOnArm; COMPONENT_EXPORT(MEDIA_WEBRTC) extern const base::Feature kWebRtcHybridAgc; +COMPONENT_EXPORT(MEDIA_WEBRTC) +extern const base::Feature kWebRtcAnalogAgcClippingControl; + } // namespace features #endif // MEDIA_WEBRTC_WEBRTC_SWITCHES_H_ |