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

Commit 38e9b06

Browse files
Ilya NikolaevskiyCommit Bot
authored andcommitted
Reland "Add scaling interface to VideoFrameBuffer"
(Reland with no changes after the fix to the downstream project) This can be overriden for kNative frame types to perform scaling efficiently. Default implementations for existing buffer types require actual buffer implementation, thus this CL also merges "video_frame" with "video_frame_I420" build targets. Originally Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186303 (Landing with TBR as it's unchaged reland of already approved CL) [email protected],[email protected] Bug: webrtc:11976, chromium:1132299 Change-Id: Ia23f7d3e474bd9cdc177104cc5c6d772f04b210f Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/187345 Commit-Queue: Ilya Nikolaevskiy <[email protected]> Reviewed-by: Ilya Nikolaevskiy <[email protected]> Reviewed-by: Mirko Bonadei <[email protected]> Reviewed-by: Stefan Holmer <[email protected]> Cr-Commit-Position: refs/heads/master@{#32362}
1 parent 44d0dff commit 38e9b06

File tree

26 files changed

+162
-116
lines changed

26 files changed

+162
-116
lines changed

api/video/BUILD.gn

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ rtc_library("video_rtp_headers") {
4242
rtc_library("video_frame") {
4343
visibility = [ "*" ]
4444
sources = [
45+
"i420_buffer.cc",
46+
"i420_buffer.h",
4547
"video_codec_type.h",
4648
"video_frame.cc",
4749
"video_frame.h",
@@ -59,7 +61,9 @@ rtc_library("video_frame") {
5961
"..:scoped_refptr",
6062
"../../rtc_base:checks",
6163
"../../rtc_base:rtc_base_approved",
64+
"../../rtc_base/memory:aligned_malloc",
6265
"../../rtc_base/system:rtc_export",
66+
"//third_party/libyuv",
6367
]
6468
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
6569
}
@@ -70,42 +74,11 @@ if (is_android) {
7074
}
7175
}
7276

73-
rtc_source_set("recordable_encoded_frame") {
77+
# Deprecated empty target. Use "video_frame" instead.
78+
rtc_source_set("video_frame_i420") {
7479
visibility = [ "*" ]
75-
sources = [ "recordable_encoded_frame.h" ]
76-
77-
deps = [
78-
":encoded_image",
79-
":video_frame",
80-
":video_rtp_headers",
81-
"..:array_view",
82-
"..:scoped_refptr",
83-
"../../rtc_base:refcount",
84-
"../units:timestamp",
85-
]
86-
}
87-
88-
rtc_source_set("video_frame_type") {
89-
visibility = [ "*" ]
90-
sources = [ "video_frame_type.h" ]
91-
}
92-
93-
rtc_library("video_frame_i420") {
94-
visibility = [ "*" ]
95-
sources = [
96-
"i420_buffer.cc",
97-
"i420_buffer.h",
98-
]
99-
deps = [
100-
":video_frame",
101-
":video_rtp_headers",
102-
"..:scoped_refptr",
103-
"../../rtc_base",
104-
"../../rtc_base:checks",
105-
"../../rtc_base/memory:aligned_malloc",
106-
"../../rtc_base/system:rtc_export",
107-
"//third_party/libyuv",
108-
]
80+
sources = []
81+
deps = [ ":video_frame" ]
10982
}
11083

11184
rtc_library("video_frame_i010") {
@@ -116,7 +89,6 @@ rtc_library("video_frame_i010") {
11689
]
11790
deps = [
11891
":video_frame",
119-
":video_frame_i420",
12092
":video_rtp_headers",
12193
"..:scoped_refptr",
12294
"../../rtc_base",
@@ -134,7 +106,6 @@ rtc_library("video_frame_nv12") {
134106
]
135107
deps = [
136108
":video_frame",
137-
":video_frame_i420",
138109
"..:scoped_refptr",
139110
"../../rtc_base",
140111
"../../rtc_base:checks",
@@ -144,6 +115,26 @@ rtc_library("video_frame_nv12") {
144115
]
145116
}
146117

118+
rtc_source_set("recordable_encoded_frame") {
119+
visibility = [ "*" ]
120+
sources = [ "recordable_encoded_frame.h" ]
121+
122+
deps = [
123+
":encoded_image",
124+
":video_frame",
125+
":video_rtp_headers",
126+
"..:array_view",
127+
"..:scoped_refptr",
128+
"../../rtc_base:refcount",
129+
"../units:timestamp",
130+
]
131+
}
132+
133+
rtc_source_set("video_frame_type") {
134+
visibility = [ "*" ]
135+
sources = [ "video_frame_type.h" ]
136+
}
137+
147138
rtc_library("encoded_image") {
148139
visibility = [ "*" ]
149140
sources = [

api/video/nv12_buffer.cc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "rtc_base/checks.h"
1515
#include "rtc_base/ref_counted_object.h"
1616
#include "third_party/libyuv/include/libyuv/convert.h"
17+
#include "third_party/libyuv/include/libyuv/scale.h"
1718

1819
namespace webrtc {
1920

@@ -122,4 +123,35 @@ void NV12Buffer::InitializeData() {
122123
memset(data_.get(), 0, NV12DataSize(height_, stride_y_, stride_uv_));
123124
}
124125

126+
void NV12Buffer::CropAndScaleFrom(const NV12BufferInterface& src,
127+
int offset_x,
128+
int offset_y,
129+
int crop_width,
130+
int crop_height) {
131+
RTC_CHECK_LE(crop_width, src.width());
132+
RTC_CHECK_LE(crop_height, src.height());
133+
RTC_CHECK_LE(crop_width + offset_x, src.width());
134+
RTC_CHECK_LE(crop_height + offset_y, src.height());
135+
RTC_CHECK_GE(offset_x, 0);
136+
RTC_CHECK_GE(offset_y, 0);
137+
138+
// Make sure offset is even so that u/v plane becomes aligned.
139+
const int uv_offset_x = offset_x / 2;
140+
const int uv_offset_y = offset_y / 2;
141+
offset_x = uv_offset_x * 2;
142+
offset_y = uv_offset_y * 2;
143+
144+
const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x;
145+
const uint8_t* uv_plane =
146+
src.DataUV() + src.StrideUV() * uv_offset_y + uv_offset_x * 2;
147+
148+
// kFilterBox is unsupported in libyuv, so using kFilterBilinear instead.
149+
int res = libyuv::NV12Scale(y_plane, src.StrideY(), uv_plane, src.StrideUV(),
150+
crop_width, crop_height, MutableDataY(),
151+
StrideY(), MutableDataUV(), StrideUV(), width(),
152+
height(), libyuv::kFilterBilinear);
153+
154+
RTC_DCHECK_EQ(res, 0);
155+
}
156+
125157
} // namespace webrtc

api/video/nv12_buffer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ class RTC_EXPORT NV12Buffer : public NV12BufferInterface {
5656
// are resolved in a better way. Or in the mean time, use SetBlack.
5757
void InitializeData();
5858

59+
// Scale the cropped area of |src| to the size of |this| buffer, and
60+
// write the result into |this|.
61+
void CropAndScaleFrom(const NV12BufferInterface& src,
62+
int offset_x,
63+
int offset_y,
64+
int crop_width,
65+
int crop_height);
66+
5967
protected:
6068
NV12Buffer(int width, int height);
6169
NV12Buffer(int width, int height, int stride_y, int stride_uv);

api/video/test/BUILD.gn

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ rtc_library("rtc_api_video_unittests") {
2020
"..:video_adaptation",
2121
"..:video_bitrate_allocation",
2222
"..:video_frame",
23-
"..:video_frame_i420",
2423
"..:video_frame_nv12",
2524
"..:video_rtp_headers",
2625
"../../../test:frame_utils",

api/video/video_frame_buffer.cc

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,25 @@
1010

1111
#include "api/video/video_frame_buffer.h"
1212

13+
#include "api/video/i420_buffer.h"
1314
#include "rtc_base/checks.h"
1415

1516
namespace webrtc {
1617

18+
rtc::scoped_refptr<VideoFrameBuffer> VideoFrameBuffer::CropAndScale(
19+
int offset_x,
20+
int offset_y,
21+
int crop_width,
22+
int crop_height,
23+
int scaled_width,
24+
int scaled_height) {
25+
rtc::scoped_refptr<I420Buffer> result =
26+
I420Buffer::Create(scaled_width, scaled_height);
27+
result->CropAndScaleFrom(*this->ToI420(), offset_x, offset_y, crop_width,
28+
crop_height);
29+
return result;
30+
}
31+
1732
const I420BufferInterface* VideoFrameBuffer::GetI420() const {
1833
// Overridden by subclasses that can return an I420 buffer without any
1934
// conversion, in particular, I420BufferInterface.
@@ -124,5 +139,4 @@ int NV12BufferInterface::ChromaWidth() const {
124139
int NV12BufferInterface::ChromaHeight() const {
125140
return (height() + 1) / 2;
126141
}
127-
128142
} // namespace webrtc

api/video/video_frame_buffer.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,24 @@ class RTC_EXPORT VideoFrameBuffer : public rtc::RefCountInterface {
7979
// behave as the other GetXXX methods below.
8080
virtual const I420BufferInterface* GetI420() const;
8181

82+
// A format specific scale function. Default implementation works by
83+
// converting to I420. But more efficient implementations may override it,
84+
// especially for kNative.
85+
// First, the image is cropped to |crop_width| and |crop_height| and then
86+
// scaled to |scaled_width| and |scaled_height|.
87+
virtual rtc::scoped_refptr<VideoFrameBuffer> CropAndScale(int offset_x,
88+
int offset_y,
89+
int crop_width,
90+
int crop_height,
91+
int scaled_width,
92+
int scaled_height);
93+
94+
// Alias for common use case.
95+
rtc::scoped_refptr<VideoFrameBuffer> Scale(int scaled_width,
96+
int scaled_height) {
97+
return CropAndScale(0, 0, width(), height(), scaled_width, scaled_height);
98+
}
99+
82100
// These functions should only be called if type() is of the correct type.
83101
// Calling with a different type will result in a crash.
84102
const I420ABufferInterface* GetI420A() const;

api/video_codecs/BUILD.gn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ rtc_library("rtc_software_fallback_wrappers") {
137137
deps = [
138138
":video_codecs_api",
139139
"..:fec_controller_api",
140-
"../../api/video:video_frame_i420",
140+
"../../api/video:video_frame",
141141
"../../media:rtc_h264_profile_id",
142142
"../../media:rtc_media_base",
143143
"../../modules/video_coding:video_codec_interface",

api/video_codecs/test/BUILD.gn

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ if (rtc_include_tests) {
3636
"../../video:encoded_image",
3737
"../../video:video_bitrate_allocation",
3838
"../../video:video_frame",
39-
"../../video:video_frame_i420",
4039
"../../video:video_rtp_headers",
4140
"//testing/gtest",
4241
]

common_video/BUILD.gn

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ rtc_library("common_video") {
4949
"../api/video:video_bitrate_allocation",
5050
"../api/video:video_bitrate_allocator",
5151
"../api/video:video_frame",
52-
"../api/video:video_frame_i420",
5352
"../api/video:video_frame_nv12",
5453
"../api/video:video_rtp_headers",
5554
"../api/video_codecs:bitstream_parser_api",
@@ -105,7 +104,7 @@ if (rtc_include_tests) {
105104
"../api/units:time_delta",
106105
"../api/video:video_frame",
107106
"../api/video:video_frame_i010",
108-
"../api/video:video_frame_i420",
107+
"../api/video:video_frame_nv12",
109108
"../api/video:video_rtp_headers",
110109
"../media:rtc_h264_profile_id",
111110
"../rtc_base",

common_video/video_frame_unittest.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "api/video/i010_buffer.h"
1717
#include "api/video/i420_buffer.h"
18+
#include "api/video/nv12_buffer.h"
1819
#include "rtc_base/bind.h"
1920
#include "rtc_base/time_utils.h"
2021
#include "test/fake_texture_frame.h"
@@ -157,6 +158,29 @@ rtc::scoped_refptr<PlanarYuvBuffer> CreateGradient(VideoFrameBuffer::Type type,
157158
return I010Buffer::Copy(*buffer);
158159
}
159160

161+
rtc::scoped_refptr<NV12BufferInterface> CreateNV12Gradient(int width,
162+
int height) {
163+
rtc::scoped_refptr<NV12Buffer> buffer(NV12Buffer::Create(width, height));
164+
// Initialize with gradient, Y = 128(x/w + y/h), U = 256 x/w, V = 256 y/h
165+
for (int x = 0; x < width; x++) {
166+
for (int y = 0; y < height; y++) {
167+
buffer->MutableDataY()[x + y * width] =
168+
128 * (x * height + y * width) / (width * height);
169+
}
170+
}
171+
int chroma_width = buffer->ChromaWidth();
172+
int chroma_height = buffer->ChromaHeight();
173+
for (int x = 0; x < chroma_width; x++) {
174+
for (int y = 0; y < chroma_height; y++) {
175+
buffer->MutableDataUV()[x * 2 + y * buffer->StrideUV()] =
176+
255 * x / (chroma_width - 1);
177+
buffer->MutableDataUV()[x * 2 + 1 + y * buffer->StrideUV()] =
178+
255 * y / (chroma_height - 1);
179+
}
180+
}
181+
return buffer;
182+
}
183+
160184
// The offsets and sizes describe the rectangle extracted from the
161185
// original (gradient) frame, in relative coordinates where the
162186
// original frame correspond to the unit square, 0.0 <= x, y < 1.0.
@@ -495,6 +519,35 @@ INSTANTIATE_TEST_SUITE_P(All,
495519
::testing::Values(VideoFrameBuffer::Type::kI420,
496520
VideoFrameBuffer::Type::kI010));
497521

522+
TEST(TestNV12Buffer, CropAndScale) {
523+
const int kSourceWidth = 640;
524+
const int kSourceHeight = 480;
525+
const int kScaledWidth = 320;
526+
const int kScaledHeight = 240;
527+
const int kCropLeft = 40;
528+
const int kCropTop = 30;
529+
const int kCropRight = 0;
530+
const int kCropBottom = 30;
531+
532+
rtc::scoped_refptr<VideoFrameBuffer> buf =
533+
CreateNV12Gradient(kSourceWidth, kSourceHeight);
534+
535+
rtc::scoped_refptr<VideoFrameBuffer> scaled_buffer = buf->CropAndScale(
536+
kCropLeft, kCropTop, kSourceWidth - kCropLeft - kCropRight,
537+
kSourceHeight - kCropTop - kCropBottom, kScaledWidth, kScaledHeight);
538+
539+
// Parameters to CheckCrop indicate what part of the source frame is in the
540+
// scaled frame.
541+
const float kOffsetX = (kCropLeft + 0.0) / kSourceWidth;
542+
const float kOffsetY = (kCropTop + 0.0) / kSourceHeight;
543+
const float kRelativeWidth =
544+
(kSourceWidth - kCropLeft - kCropRight + 0.0) / kSourceWidth;
545+
const float kRelativeHeight =
546+
(kSourceHeight - kCropTop - kCropBottom + 0.0) / kSourceHeight;
547+
CheckCrop(*scaled_buffer->ToI420(), kOffsetX, kOffsetY, kRelativeWidth,
548+
kRelativeHeight);
549+
}
550+
498551
class TestPlanarYuvBufferRotate
499552
: public ::testing::TestWithParam<
500553
std::tuple<webrtc::VideoRotation, VideoFrameBuffer::Type>> {};

0 commit comments

Comments
 (0)