Commit a0332b50 authored by Evan Shrubsole's avatar Evan Shrubsole Committed by Commit Bot

Avoid copying GMB NV12 frames behind feature

Adds blink feature WebRtvLibvpxEncoderNV12. When enabled  which
will avoid copying and converting GMB frames in NV12 format, by mapping
the data for reading. This is only available when scaling does not need
to be done. When scaling is needed, the frame will be converted to I420
and scaled as before.

Comparing encode times with the feature on and off shows trivial
differences with the Mac facetime camera, capturing NV12 to an IOSurface
shows a trivial difference in encode time (10.2ms for I420 vs 9.8ms
NV12 on mapped GMB). Both runs done in compiled Chrome with appr.tc
sending HD encoded with VP9. Power draw is also about the same (+0.2W
with I420 at a stddev of 2.4W)

Tested running Chrome with the feature on and off, confirming that NV12
images were encoded with the VP9 encoder.

Bug: 1134165
Change-Id: I479e3541536317268c5ca25a3e88c4898bfa2ff1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2467860Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Commit-Queue: Evan Shrubsole <eshr@google.com>
Cr-Commit-Position: refs/heads/master@{#818819}
parent d3fe4eeb
...@@ -784,5 +784,10 @@ const base::Feature kLogUnexpectedIPCPostedToBackForwardCachedDocuments{ ...@@ -784,5 +784,10 @@ const base::Feature kLogUnexpectedIPCPostedToBackForwardCachedDocuments{
// https://github.com/WICG/pwa-url-handler/blob/master/explainer.md // https://github.com/WICG/pwa-url-handler/blob/master/explainer.md
const base::Feature kWebAppEnableUrlHandlers{"WebAppEnableUrlHandlers", const base::Feature kWebAppEnableUrlHandlers{"WebAppEnableUrlHandlers",
base::FEATURE_DISABLED_BY_DEFAULT}; base::FEATURE_DISABLED_BY_DEFAULT};
// When enabled NV12 frames on a GPU will be forwarded to libvpx encoders
// without conversion to I420.
const base::Feature kWebRtcLibvpxEncodeNV12{"WebRtcLibvpxEncodeNV12",
base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features } // namespace features
} // namespace blink } // namespace blink
...@@ -318,6 +318,7 @@ BLINK_COMMON_EXPORT extern const base::Feature ...@@ -318,6 +318,7 @@ BLINK_COMMON_EXPORT extern const base::Feature
kLogUnexpectedIPCPostedToBackForwardCachedDocuments; kLogUnexpectedIPCPostedToBackForwardCachedDocuments;
BLINK_COMMON_EXPORT extern const base::Feature kWebAppEnableUrlHandlers; BLINK_COMMON_EXPORT extern const base::Feature kWebAppEnableUrlHandlers;
BLINK_COMMON_EXPORT extern const base::Feature kWebRtcLibvpxEncodeNV12;
} // namespace features } // namespace features
} // namespace blink } // namespace blink
......
...@@ -56,17 +56,19 @@ class PLATFORM_EXPORT WebRtcVideoFrameAdapter ...@@ -56,17 +56,19 @@ class PLATFORM_EXPORT WebRtcVideoFrameAdapter
rtc::scoped_refptr<webrtc::I420BufferInterface> ToI420() override; rtc::scoped_refptr<webrtc::I420BufferInterface> ToI420() override;
const webrtc::I420BufferInterface* GetI420() const override; const webrtc::I420BufferInterface* GetI420() const override;
rtc::scoped_refptr<webrtc::VideoFrameBuffer> GetMappedFrameBuffer(
rtc::ArrayView<webrtc::VideoFrameBuffer::Type> types) override;
protected: protected:
~WebRtcVideoFrameAdapter() override; ~WebRtcVideoFrameAdapter() override;
rtc::scoped_refptr<webrtc::I420BufferInterface> CreateFrameAdapter() const; rtc::scoped_refptr<webrtc::VideoFrameBuffer> CreateFrameAdapter() const;
mutable base::Lock adapter_lock_; mutable base::Lock adapter_lock_;
// Used to cache result of CreateFrameAdapter. Which is called from const // Used to cache result of CreateFrameAdapter. Which is called from const
// GetI420(). // GetI420().
mutable rtc::scoped_refptr<webrtc::I420BufferInterface> frame_adapter_ mutable rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_adapter_
GUARDED_BY(adapter_lock_); GUARDED_BY(adapter_lock_);
scoped_refptr<media::VideoFrame> frame_; scoped_refptr<media::VideoFrame> frame_;
......
...@@ -4,8 +4,10 @@ ...@@ -4,8 +4,10 @@
#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h" #include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
#include "base/test/scoped_feature_list.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/platform/testing/video_frame_utils.h" #include "third_party/blink/renderer/platform/testing/video_frame_utils.h"
#include "third_party/webrtc/api/video/video_frame_buffer.h" #include "third_party/webrtc/api/video/video_frame_buffer.h"
#include "third_party/webrtc/rtc_base/ref_counted_object.h" #include "third_party/webrtc/rtc_base/ref_counted_object.h"
...@@ -65,7 +67,14 @@ TEST(WebRtcVideoFrameAdapterTest, ToI420DownScale) { ...@@ -65,7 +67,14 @@ TEST(WebRtcVideoFrameAdapterTest, ToI420DownScale) {
auto i420_frame = owned_memory_frame_adapter->ToI420(); auto i420_frame = owned_memory_frame_adapter->ToI420();
EXPECT_EQ(i420_frame->width(), kNaturalSize.width()); EXPECT_EQ(i420_frame->width(), kNaturalSize.width());
EXPECT_EQ(i420_frame->height(), kNaturalSize.height()); EXPECT_EQ(i420_frame->height(), kNaturalSize.height());
}
TEST(WebRtcVideoFrameAdapterTest, ToI420DownScaleGmb) {
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
const gfx::Size kNaturalSize(640, 360);
scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
new WebRtcVideoFrameAdapter::BufferPoolOwner();
auto gmb_frame = auto gmb_frame =
CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize, CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER); media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
...@@ -79,7 +88,49 @@ TEST(WebRtcVideoFrameAdapterTest, ToI420DownScale) { ...@@ -79,7 +88,49 @@ TEST(WebRtcVideoFrameAdapterTest, ToI420DownScale) {
EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height()); EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
// The I420 frame should have the same size as the natural size // The I420 frame should have the same size as the natural size
i420_frame = gmb_frame_adapter->ToI420(); auto i420_frame = gmb_frame_adapter->ToI420();
EXPECT_EQ(i420_frame->width(), kNaturalSize.width());
EXPECT_EQ(i420_frame->height(), kNaturalSize.height());
}
TEST(WebRtcVideoFrameAdapterTest, Nv12WrapsGmbWhenNoScalingNeeeded) {
base::test::ScopedFeatureList scoped_feautre_list;
scoped_feautre_list.InitAndEnableFeature(
blink::features::kWebRtcLibvpxEncodeNV12);
const gfx::Size kCodedSize(1280, 960);
const gfx::Rect kVisibleRect(0, 120, 1280, 720);
// Same size as visible rect so no scaling.
const gfx::Size kNaturalSize = kVisibleRect.size();
scoped_refptr<WebRtcVideoFrameAdapter::BufferPoolOwner> pool =
new WebRtcVideoFrameAdapter::BufferPoolOwner();
auto gmb_frame =
CreateTestFrame(kCodedSize, kVisibleRect, kNaturalSize,
media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
// The adapter should report width and height from the natural size for
// VideoFrame backed by GpuMemoryBuffer.
rtc::scoped_refptr<webrtc::VideoFrameBuffer> gmb_frame_adapter(
new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(gmb_frame, pool));
EXPECT_EQ(gmb_frame_adapter->width(), kNaturalSize.width());
EXPECT_EQ(gmb_frame_adapter->height(), kNaturalSize.height());
// Under feature, expect that the adapted frame is NV12 with frame should
// have the same size as the natural size.
std::vector<webrtc::VideoFrameBuffer::Type> nv12_type{
webrtc::VideoFrameBuffer::Type::kNV12};
auto nv12_frame = gmb_frame_adapter->GetMappedFrameBuffer(nv12_type);
ASSERT_TRUE(nv12_frame);
EXPECT_EQ(webrtc::VideoFrameBuffer::Type::kNV12, nv12_frame->type());
EXPECT_EQ(nv12_frame->width(), kNaturalSize.width());
EXPECT_EQ(nv12_frame->height(), kNaturalSize.height());
// Even though we have an NV12 frame, ToI420 should return an I420 frame.
std::vector<webrtc::VideoFrameBuffer::Type> i420_type{
webrtc::VideoFrameBuffer::Type::kI420};
EXPECT_FALSE(gmb_frame_adapter->GetMappedFrameBuffer(i420_type));
auto i420_frame = gmb_frame_adapter->ToI420();
ASSERT_TRUE(i420_frame);
EXPECT_EQ(i420_frame->width(), kNaturalSize.width()); EXPECT_EQ(i420_frame->width(), kNaturalSize.width());
EXPECT_EQ(i420_frame->height(), kNaturalSize.height()); EXPECT_EQ(i420_frame->height(), kNaturalSize.height());
} }
......
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