Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit b556b08

Browse files
eshrubsCommit Bot
authored andcommitted
Allow encoders to receive preferred pixel formats from native buffers
Adds a field to EncoderInfo called preferred_pixel_formats which a software encoder populates with the pixel formats it supports. When a kNative frame is received for encoding, the VideoStreamEncoder will first try to get a frame that is accessible by the software encoder in that pixel format from the kNative frame. If this fails it will fallback to converting the frame using ToI420. This minimizes the number of conversions made in the case that the encoder supports the pixel format of the native buffer or where conversion can be accelerated. For example, in Chromium, the capturer can emit an NV12 frame, which can be consumed by libvpx which supports NV12. Testing: Tested in Chrome with media::VideoFrame adapters. Bug: webrtc:11977 Change-Id: I9becc4100136b0c0128f4fa06dedf9ee4dc62f37 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/187121 Reviewed-by: Niels Moller <[email protected]> Reviewed-by: Ilya Nikolaevskiy <[email protected]> Reviewed-by: Markus Handell <[email protected]> Commit-Queue: Evan Shrubsole <[email protected]> Cr-Commit-Position: refs/heads/master@{#32353}
1 parent c79f1d8 commit b556b08

13 files changed

+158
-10
lines changed

api/video/video_codec_constants.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ enum : int { kMaxEncoderBuffers = 8 };
1717
enum : int { kMaxSimulcastStreams = 3 };
1818
enum : int { kMaxSpatialLayers = 5 };
1919
enum : int { kMaxTemporalStreams = 4 };
20+
enum : int { kMaxPreferredPixelFormats = 5 };
2021

2122
} // namespace webrtc
2223

api/video/video_frame_buffer.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,35 @@ const NV12BufferInterface* VideoFrameBuffer::GetNV12() const {
5555
return static_cast<const NV12BufferInterface*>(this);
5656
}
5757

58+
rtc::scoped_refptr<VideoFrameBuffer> VideoFrameBuffer::GetMappedFrameBuffer(
59+
rtc::ArrayView<Type> types) {
60+
RTC_CHECK(type() == Type::kNative);
61+
return nullptr;
62+
}
63+
5864
VideoFrameBuffer::Type I420BufferInterface::type() const {
5965
return Type::kI420;
6066
}
6167

68+
const char* VideoFrameBufferTypeToString(VideoFrameBuffer::Type type) {
69+
switch (type) {
70+
case VideoFrameBuffer::Type::kNative:
71+
return "kNative";
72+
case VideoFrameBuffer::Type::kI420:
73+
return "kI420";
74+
case VideoFrameBuffer::Type::kI420A:
75+
return "kI420A";
76+
case VideoFrameBuffer::Type::kI444:
77+
return "kI444";
78+
case VideoFrameBuffer::Type::kI010:
79+
return "kI010";
80+
case VideoFrameBuffer::Type::kNV12:
81+
return "kNV12";
82+
default:
83+
RTC_NOTREACHED();
84+
}
85+
}
86+
6287
int I420BufferInterface::ChromaWidth() const {
6388
return (width() + 1) / 2;
6489
}

api/video/video_frame_buffer.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <stdint.h>
1515

16+
#include "api/array_view.h"
1617
#include "api/scoped_refptr.h"
1718
#include "rtc_base/ref_count.h"
1819
#include "rtc_base/system/rtc_export.h"
@@ -74,6 +75,8 @@ class RTC_EXPORT VideoFrameBuffer : public rtc::RefCountInterface {
7475
// WebrtcVideoFrameAdapter in Chrome - it's I420 buffer backed by a shared
7576
// memory buffer. Therefore it must have type kNative. Yet, ToI420()
7677
// doesn't affect binary data at all. Another example is any I420A buffer.
78+
// TODO(https://crbug.com/webrtc/12021): Make this method non-virtual and
79+
// behave as the other GetXXX methods below.
7780
virtual const I420BufferInterface* GetI420() const;
7881

7982
// A format specific scale function. Default implementation works by
@@ -101,10 +104,21 @@ class RTC_EXPORT VideoFrameBuffer : public rtc::RefCountInterface {
101104
const I010BufferInterface* GetI010() const;
102105
const NV12BufferInterface* GetNV12() const;
103106

107+
// From a kNative frame, returns a VideoFrameBuffer with a pixel format in
108+
// the list of types that is in the main memory with a pixel perfect
109+
// conversion for encoding with a software encoder. Returns nullptr if the
110+
// frame type is not supported, mapping is not possible, or if the kNative
111+
// frame has not implemented this method. Only callable if type() is kNative.
112+
virtual rtc::scoped_refptr<VideoFrameBuffer> GetMappedFrameBuffer(
113+
rtc::ArrayView<Type> types);
114+
104115
protected:
105116
~VideoFrameBuffer() override {}
106117
};
107118

119+
// Update when VideoFrameBuffer::Type is updated.
120+
const char* VideoFrameBufferTypeToString(VideoFrameBuffer::Type type);
121+
108122
// This interface represents planar formats.
109123
class PlanarYuvBuffer : public VideoFrameBuffer {
110124
public:

api/video_codecs/video_encoder.cc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ VideoEncoder::EncoderInfo::EncoderInfo()
103103
fps_allocation{absl::InlinedVector<uint8_t, kMaxTemporalStreams>(
104104
1,
105105
kMaxFramerateFraction)},
106-
supports_simulcast(false) {}
106+
supports_simulcast(false),
107+
preferred_pixel_formats{VideoFrameBuffer::Type::kI420} {}
107108

108109
VideoEncoder::EncoderInfo::EncoderInfo(const EncoderInfo&) = default;
109110

@@ -169,7 +170,15 @@ std::string VideoEncoder::EncoderInfo::ToString() const {
169170
}
170171
oss << "] "
171172
", supports_simulcast = "
172-
<< supports_simulcast << "}";
173+
<< supports_simulcast;
174+
oss << ", preferred_pixel_formats = [";
175+
for (size_t i = 0; i < preferred_pixel_formats.size(); ++i) {
176+
if (i > 0)
177+
oss << ", ";
178+
oss << VideoFrameBufferTypeToString(preferred_pixel_formats.at(i));
179+
}
180+
oss << "]";
181+
oss << "}";
173182
return oss.str();
174183
}
175184

api/video_codecs/video_encoder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,12 @@ class RTC_EXPORT VideoEncoder {
254254
// in such case the encoder should return
255255
// WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED.
256256
bool supports_simulcast;
257+
258+
// The list of pixel formats preferred by the encoder. It is assumed that if
259+
// the list is empty and supports_native_handle is false, then {I420} is the
260+
// preferred pixel format. The order of the formats does not matter.
261+
absl::InlinedVector<VideoFrameBuffer::Type, kMaxPreferredPixelFormats>
262+
preferred_pixel_formats;
257263
};
258264

259265
struct RTC_EXPORT RateControlParameters {

modules/video_coding/codecs/av1/libaom_av1_encoder.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ VideoEncoder::EncoderInfo LibaomAv1Encoder::GetEncoderInfo() const {
603603
info.has_trusted_rate_controller = true;
604604
info.is_hardware_accelerated = false;
605605
info.scaling_settings = VideoEncoder::ScalingSettings(kMinQindex, kMaxQindex);
606+
info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420};
606607
return info;
607608
}
608609

modules/video_coding/codecs/h264/h264_encoder_impl.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ VideoEncoder::EncoderInfo H264EncoderImpl::GetEncoderInfo() const {
615615
info.is_hardware_accelerated = false;
616616
info.has_internal_source = false;
617617
info.supports_simulcast = true;
618+
info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420};
618619
return info;
619620
}
620621

modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,8 @@ VideoEncoder::EncoderInfo LibvpxVp8Encoder::GetEncoderInfo() const {
12441244
info.scaling_settings.min_pixels_per_frame =
12451245
rate_control_settings_.LibvpxVp8MinPixels().value();
12461246
}
1247+
info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420,
1248+
VideoFrameBuffer::Type::kNV12};
12471249

12481250
if (inited_) {
12491251
// |encoder_idx| is libvpx index where 0 is highest resolution.

modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,9 @@ TEST(LibvpxVp8EncoderTest, GetEncoderInfoReturnsStaticInformation) {
604604
EXPECT_TRUE(info.supports_simulcast);
605605
EXPECT_EQ(info.implementation_name, "libvpx");
606606
EXPECT_EQ(info.requested_resolution_alignment, 1);
607+
EXPECT_THAT(info.preferred_pixel_formats,
608+
testing::UnorderedElementsAre(VideoFrameBuffer::Type::kNV12,
609+
VideoFrameBuffer::Type::kI420));
607610
}
608611

609612
TEST(LibvpxVp8EncoderTest, RequestedResolutionAlignmentFromFieldTrial) {

modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,12 @@ TEST_F(TestVp9Impl, ScalabilityStructureIsAvailableInFlexibleMode) {
13371337
EXPECT_TRUE(codec_specific_info.codecSpecific.VP9.ss_data_available);
13381338
}
13391339

1340+
TEST_F(TestVp9Impl, Profile0PreferredPixelFormats) {
1341+
EXPECT_THAT(encoder_->GetEncoderInfo().preferred_pixel_formats,
1342+
testing::UnorderedElementsAre(VideoFrameBuffer::Type::kNV12,
1343+
VideoFrameBuffer::Type::kI420));
1344+
}
1345+
13401346
TEST_F(TestVp9Impl, EncoderInfoFpsAllocation) {
13411347
const uint8_t kNumSpatialLayers = 3;
13421348
const uint8_t kNumTemporalLayers = 3;

0 commit comments

Comments
 (0)