Issue 4366: Adapted frames have wrong width and height and are cropped.
When a frame being stretched, the original rotation information is lost. This is to ensure it's carried over.
Also removed StretchToBuffer function as it's not called and dangerous.
BUG=4366
R=pthatcher@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/51869004
Cr-Commit-Position: refs/heads/master@{#9224}
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp
index 3ca2f1f..80cd1fa 100755
--- a/talk/libjingle_tests.gyp
+++ b/talk/libjingle_tests.gyp
@@ -103,6 +103,7 @@
'media/webrtc/webrtcvideocapturer_unittest.cc',
'media/base/videoframe_unittest.h',
'media/webrtc/webrtcvideoframe_unittest.cc',
+ 'media/webrtc/webrtcvideoframefactory_unittest.cc',
# Disabled because some tests fail.
# TODO(ronghuawu): Reenable these tests.
diff --git a/talk/media/base/videoframe.cc b/talk/media/base/videoframe.cc
index 79f52fc..7e79bf6 100644
--- a/talk/media/base/videoframe.cc
+++ b/talk/media/base/videoframe.cc
@@ -190,28 +190,6 @@
static_cast<int>(width), static_cast<int>(height), interpolate);
}
-size_t VideoFrame::StretchToBuffer(size_t dst_width, size_t dst_height,
- uint8* dst_buffer, size_t size,
- bool interpolate, bool vert_crop) const {
- if (!dst_buffer) {
- LOG(LS_ERROR) << "NULL dst_buffer pointer.";
- return 0;
- }
-
- size_t needed = SizeOf(dst_width, dst_height);
- if (needed <= size) {
- uint8* dst_y = dst_buffer;
- uint8* dst_u = dst_y + dst_width * dst_height;
- uint8* dst_v = dst_u + ((dst_width + 1) >> 1) * ((dst_height + 1) >> 1);
- StretchToPlanes(dst_y, dst_u, dst_v,
- static_cast<int32>(dst_width),
- static_cast<int32>((dst_width + 1) >> 1),
- static_cast<int32>((dst_width + 1) >> 1),
- dst_width, dst_height, interpolate, vert_crop);
- }
- return needed;
-}
-
void VideoFrame::StretchToFrame(VideoFrame* dst,
bool interpolate, bool vert_crop) const {
if (!dst) {
@@ -225,6 +203,8 @@
interpolate, vert_crop);
dst->SetElapsedTime(GetElapsedTime());
dst->SetTimeStamp(GetTimeStamp());
+ // Stretched frame should have the same rotation as the source.
+ dst->SetRotation(GetVideoRotation());
}
VideoFrame* VideoFrame::Stretch(size_t dst_width, size_t dst_height,
diff --git a/talk/media/base/videoframe.h b/talk/media/base/videoframe.h
index 0aac645..ac53ca2 100644
--- a/talk/media/base/videoframe.h
+++ b/talk/media/base/videoframe.h
@@ -188,16 +188,6 @@
uint8 *y, uint8 *u, uint8 *v, int32 pitchY, int32 pitchU, int32 pitchV,
size_t width, size_t height, bool interpolate, bool crop) const;
- // Writes the frame into the given frame buffer, stretched to the given width
- // and height, provided that it is of sufficient size. Returns the frame's
- // actual size, regardless of whether it was written or not (like snprintf).
- // If there is insufficient space, nothing is written. The parameter
- // "interpolate" controls whether to interpolate or just take the
- // nearest-point. The parameter "crop" controls whether to crop this frame to
- // the aspect ratio of the given dimensions before stretching.
- virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size,
- bool interpolate, bool crop) const;
-
// Writes the frame into the target VideoFrame, stretched to the size of that
// frame. The parameter "interpolate" controls whether to interpolate or just
// take the nearest-point. The parameter "crop" controls whether to crop this
@@ -230,6 +220,7 @@
size_t pixel_height,
int64_t elapsed_time,
int64_t time_stamp) const = 0;
+ virtual void SetRotation(webrtc::VideoRotation rotation) = 0;
};
} // namespace cricket
diff --git a/talk/media/webrtc/webrtcvideoframe.h b/talk/media/webrtc/webrtcvideoframe.h
index 06ac52b..7900472 100644
--- a/talk/media/webrtc/webrtcvideoframe.h
+++ b/talk/media/webrtc/webrtcvideoframe.h
@@ -131,7 +131,9 @@
const VideoFrame* GetCopyWithRotationApplied() const override;
protected:
- void SetRotation(webrtc::VideoRotation rotation) { rotation_ = rotation; }
+ void SetRotation(webrtc::VideoRotation rotation) override {
+ rotation_ = rotation;
+ }
private:
virtual VideoFrame* CreateEmptyFrame(int w, int h, size_t pixel_width,
diff --git a/talk/media/webrtc/webrtcvideoframefactory_unittest.cc b/talk/media/webrtc/webrtcvideoframefactory_unittest.cc
new file mode 100644
index 0000000..4dbad05
--- /dev/null
+++ b/talk/media/webrtc/webrtcvideoframefactory_unittest.cc
@@ -0,0 +1,125 @@
+/*
+ * libjingle
+ * Copyright 2015 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "talk/media/base/videoframe_unittest.h"
+#include "talk/media/webrtc/webrtcvideoframe.h"
+#include "talk/media/webrtc/webrtcvideoframefactory.h"
+
+class WebRtcVideoFrameFactoryTest
+ : public VideoFrameTest<cricket::WebRtcVideoFrameFactory> {
+ public:
+ WebRtcVideoFrameFactoryTest() {}
+
+ void InitFrame(webrtc::VideoRotation frame_rotation) {
+ const int frame_width = 1920;
+ const int frame_height = 1080;
+
+ // Build the CapturedFrame.
+ captured_frame_.fourcc = cricket::FOURCC_I420;
+ captured_frame_.pixel_width = 1;
+ captured_frame_.pixel_height = 1;
+ captured_frame_.elapsed_time = 1234;
+ captured_frame_.time_stamp = 5678;
+ captured_frame_.rotation = frame_rotation;
+ captured_frame_.width = frame_width;
+ captured_frame_.height = frame_height;
+ captured_frame_.data_size =
+ (frame_width * frame_height) +
+ ((frame_width + 1) / 2) * ((frame_height + 1) / 2) * 2;
+ captured_frame_buffer_.reset(new uint8[captured_frame_.data_size]);
+ // Initialize memory to satisfy DrMemory tests.
+ memset(captured_frame_buffer_.get(), 0, captured_frame_.data_size);
+ captured_frame_.data = captured_frame_buffer_.get();
+ }
+
+ void VerifyFrame(cricket::VideoFrame* dest_frame,
+ webrtc::VideoRotation src_rotation,
+ int src_width,
+ int src_height,
+ bool apply_rotation) {
+ if (!apply_rotation) {
+ EXPECT_EQ(dest_frame->GetRotation(), src_rotation);
+ EXPECT_EQ(dest_frame->GetWidth(), src_width);
+ EXPECT_EQ(dest_frame->GetHeight(), src_height);
+ } else {
+ EXPECT_EQ(dest_frame->GetRotation(), webrtc::kVideoRotation_0);
+ if (src_rotation == webrtc::kVideoRotation_90 ||
+ src_rotation == webrtc::kVideoRotation_270) {
+ EXPECT_EQ(dest_frame->GetWidth(), src_height);
+ EXPECT_EQ(dest_frame->GetHeight(), src_width);
+ } else {
+ EXPECT_EQ(dest_frame->GetWidth(), src_width);
+ EXPECT_EQ(dest_frame->GetHeight(), src_height);
+ }
+ }
+ }
+
+ void TestCreateAliasedFrame(bool apply_rotation) {
+ cricket::VideoFrameFactory& factory = factory_;
+ factory.SetApplyRotation(apply_rotation);
+ InitFrame(webrtc::kVideoRotation_270);
+ const cricket::CapturedFrame& captured_frame = get_captured_frame();
+ // Create the new frame from the CapturedFrame.
+ rtc::scoped_ptr<cricket::VideoFrame> frame;
+ int new_width = captured_frame.width / 2;
+ int new_height = captured_frame.height / 2;
+ frame.reset(factory.CreateAliasedFrame(&captured_frame, new_width,
+ new_height, new_width, new_height));
+ VerifyFrame(frame.get(), webrtc::kVideoRotation_270, new_width, new_height,
+ apply_rotation);
+
+ frame.reset(factory.CreateAliasedFrame(
+ &captured_frame, new_width, new_height, new_width / 2, new_height / 2));
+ VerifyFrame(frame.get(), webrtc::kVideoRotation_270, new_width / 2,
+ new_height / 2, apply_rotation);
+
+ // Reset the frame first so it's exclusive hence we could go through the
+ // StretchToFrame code path in CreateAliasedFrame.
+ frame.reset();
+ frame.reset(factory.CreateAliasedFrame(
+ &captured_frame, new_width, new_height, new_width / 2, new_height / 2));
+ VerifyFrame(frame.get(), webrtc::kVideoRotation_270, new_width / 2,
+ new_height / 2, apply_rotation);
+ }
+
+ const cricket::CapturedFrame& get_captured_frame() { return captured_frame_; }
+
+ private:
+ cricket::CapturedFrame captured_frame_;
+ rtc::scoped_ptr<uint8[]> captured_frame_buffer_;
+ cricket::WebRtcVideoFrameFactory factory_;
+};
+
+TEST_F(WebRtcVideoFrameFactoryTest, NoApplyRotation) {
+ TestCreateAliasedFrame(false);
+}
+
+TEST_F(WebRtcVideoFrameFactoryTest, ApplyRotation) {
+ TestCreateAliasedFrame(true);
+}