Commit 102c78bf authored by Anand K Mistry's avatar Anand K Mistry Committed by Commit Bot

VideoTrackRecorder: Defer initialization to after HW encoder support is known

Since querying of supported encoder profiles is asynchronous, it is
possible for a site to create a MediaRecorder before the list of
supported profiles is known. So wait until that list retrieved from the
browser before continuing initialization.

Bug: b:168834129
Change-Id: I8310e3342b413a120ad45a5ae0f7ac66fde41ede
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2417873
Commit-Queue: Miguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Reviewed-by: default avatarMarkus Handell <handellm@google.com>
Cr-Commit-Position: refs/heads/master@{#827116}
parent 87831f15
...@@ -86,6 +86,24 @@ static_assert(base::size(kPreferredCodecIdAndVEAProfiles) == ...@@ -86,6 +86,24 @@ static_assert(base::size(kPreferredCodecIdAndVEAProfiles) ==
// encoder implementation. // encoder implementation.
const int kMaxNumberOfFramesInEncode = 10; const int kMaxNumberOfFramesInEncode = 10;
void NotifyEncoderSupportKnown(base::OnceClosure callback) {
if (!Platform::Current()) {
DVLOG(2) << "Couldn't access the render thread";
std::move(callback).Run();
return;
}
media::GpuVideoAcceleratorFactories* const gpu_factories =
Platform::Current()->GetGpuFactories();
if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) {
DVLOG(2) << "Couldn't initialize GpuVideoAcceleratorFactories";
std::move(callback).Run();
return;
}
gpu_factories->NotifyEncoderSupportKnown(std::move(callback));
}
// Obtains video encode accelerator's supported profiles. // Obtains video encode accelerator's supported profiles.
media::VideoEncodeAccelerator::SupportedProfiles GetVEASupportedProfiles() { media::VideoEncodeAccelerator::SupportedProfiles GetVEASupportedProfiles() {
if (!Platform::Current()) { if (!Platform::Current()) {
...@@ -642,6 +660,33 @@ void VideoTrackRecorderImpl::InitializeEncoder( ...@@ -642,6 +660,33 @@ void VideoTrackRecorderImpl::InitializeEncoder(
DVLOG(3) << __func__ << frame->visible_rect().size().ToString(); DVLOG(3) << __func__ << frame->visible_rect().size().ToString();
DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
auto on_encoder_support_known_cb = WTF::Bind(
&VideoTrackRecorderImpl::InitializeEncoderOnEncoderSupportKnown,
weak_factory_.GetWeakPtr(), codec_profile, on_encoded_video_cb,
bits_per_second, allow_vea_encoder, std::move(frame), capture_time);
if (!allow_vea_encoder) {
// If HW encoding is not being used, no need to wait for encoder
// enumeration.
std::move(on_encoder_support_known_cb).Run();
return;
}
// Delay initializing the encoder until HW support is known, so that
// CanUseAcceleratedEncoder() can give a reliable and consistent answer.
NotifyEncoderSupportKnown(std::move(on_encoder_support_known_cb));
}
void VideoTrackRecorderImpl::InitializeEncoderOnEncoderSupportKnown(
CodecProfile codec_profile,
const OnEncodedVideoCB& on_encoded_video_cb,
int32_t bits_per_second,
bool allow_vea_encoder,
scoped_refptr<media::VideoFrame> frame,
base::TimeTicks capture_time) {
DVLOG(3) << __func__ << frame->visible_rect().size().ToString();
DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_);
// Avoid reinitializing |encoder_| when there are multiple frames sent to the // Avoid reinitializing |encoder_| when there are multiple frames sent to the
// sink to initialize, https://crbug.com/698441. // sink to initialize, https://crbug.com/698441.
if (encoder_) if (encoder_)
......
...@@ -341,6 +341,13 @@ class MODULES_EXPORT VideoTrackRecorderImpl : public VideoTrackRecorder { ...@@ -341,6 +341,13 @@ class MODULES_EXPORT VideoTrackRecorderImpl : public VideoTrackRecorder {
bool allow_vea_encoder, bool allow_vea_encoder,
scoped_refptr<media::VideoFrame> frame, scoped_refptr<media::VideoFrame> frame,
base::TimeTicks capture_time); base::TimeTicks capture_time);
void InitializeEncoderOnEncoderSupportKnown(
CodecProfile codec_profile,
const OnEncodedVideoCB& on_encoded_video_cb,
int32_t bits_per_second,
bool allow_vea_encoder,
scoped_refptr<media::VideoFrame> frame,
base::TimeTicks capture_time);
void OnError(); void OnError();
void ConnectToTrack(const VideoCaptureDeliverFrameCB& callback); void ConnectToTrack(const VideoCaptureDeliverFrameCB& callback);
......
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "media/base/video_codecs.h" #include "media/base/video_codecs.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "media/video/mock_gpu_video_accelerator_factories.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
...@@ -82,6 +84,14 @@ media::VideoCodec MediaVideoCodecFromCodecId(VideoTrackRecorder::CodecId id) { ...@@ -82,6 +84,14 @@ media::VideoCodec MediaVideoCodecFromCodecId(VideoTrackRecorder::CodecId id) {
return media::kUnknownVideoCodec; return media::kUnknownVideoCodec;
} }
class MockTestingPlatform : public IOTaskRunnerTestingPlatformSupport {
public:
MockTestingPlatform() = default;
~MockTestingPlatform() override = default;
MOCK_METHOD0(GetGpuFactories, media::GpuVideoAcceleratorFactories*());
};
class VideoTrackRecorderTest class VideoTrackRecorderTest
: public TestWithParam<testing::tuple<VideoTrackRecorder::CodecId, : public TestWithParam<testing::tuple<VideoTrackRecorder::CodecId,
gfx::Size, gfx::Size,
...@@ -109,6 +119,8 @@ class VideoTrackRecorderTest ...@@ -109,6 +119,8 @@ class VideoTrackRecorderTest
source_->GetPlatformSource()); source_->GetPlatformSource());
EXPECT_TRUE(scheduler::GetSingleThreadTaskRunnerForTesting() EXPECT_TRUE(scheduler::GetSingleThreadTaskRunnerForTesting()
->BelongsToCurrentThread()); ->BelongsToCurrentThread());
ON_CALL(*platform_, GetGpuFactories()).WillByDefault(Return(nullptr));
} }
~VideoTrackRecorderTest() { ~VideoTrackRecorderTest() {
...@@ -163,7 +175,7 @@ class VideoTrackRecorderTest ...@@ -163,7 +175,7 @@ class VideoTrackRecorderTest
return video_track_recorder_->encoder_->num_frames_in_encode_->count(); return video_track_recorder_->encoder_->num_frames_in_encode_->count();
} }
ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_; ScopedTestingPlatformSupport<MockTestingPlatform> platform_;
// All members are non-const due to the series of initialize() calls needed. // All members are non-const due to the series of initialize() calls needed.
// |mock_source_| is owned by |source_|, |track_| by |component_|. // |mock_source_| is owned by |source_|, |track_| by |component_|.
...@@ -439,6 +451,28 @@ TEST_F(VideoTrackRecorderTest, ReleasesFrame) { ...@@ -439,6 +451,28 @@ TEST_F(VideoTrackRecorderTest, ReleasesFrame) {
Mock::VerifyAndClearExpectations(this); Mock::VerifyAndClearExpectations(this);
} }
// Waits for HW encoder support to be enumerated before setting up and
// performing an encode.
TEST_F(VideoTrackRecorderTest, WaitForEncoderSupport) {
media::MockGpuVideoAcceleratorFactories mock_gpu_factories(nullptr);
EXPECT_CALL(*platform_, GetGpuFactories())
.WillRepeatedly(Return(&mock_gpu_factories));
EXPECT_CALL(mock_gpu_factories, NotifyEncoderSupportKnown(_))
.WillOnce(base::test::RunOnceClosure<0>());
InitializeRecorder(VideoTrackRecorder::CodecId::VP8);
const gfx::Size& frame_size = kTrackRecorderTestSize[0];
scoped_refptr<VideoFrame> video_frame =
VideoFrame::CreateBlackFrame(frame_size);
base::RunLoop run_loop;
EXPECT_CALL(*this, OnEncodedVideo(_, _, _, _, true))
.WillOnce(RunClosure(run_loop.QuitWhenIdleClosure()));
Encode(video_frame, base::TimeTicks::Now());
run_loop.Run();
}
TEST_F(VideoTrackRecorderTest, RequiredRefreshRate) { TEST_F(VideoTrackRecorderTest, RequiredRefreshRate) {
// |RequestRefreshFrame| will be called first by |AddSink| and the second time // |RequestRefreshFrame| will be called first by |AddSink| and the second time
// by the refresh timer using the required min fps. // by the refresh timer using the required min fps.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment