Refactoring videoFrame - I420VideoFrame will eventually replace VideoFrame which is currently defined in modules_common_types. Main changes: the new class allows per plane pointers, stride and uses scoped_array.
BUG= Review URL: https://webrtc-codereview.appspot.com/774004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2781 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
2e7c22da7d
commit
043ed9ecbd
@ -50,6 +50,8 @@
|
||||
}],
|
||||
],
|
||||
'sources': [
|
||||
'interface/i420_video_frame.h',
|
||||
'i420_video_frame.cc',
|
||||
'jpeg/include/jpeg.h',
|
||||
'jpeg/data_manager.cc',
|
||||
'jpeg/data_manager.h',
|
||||
@ -58,6 +60,8 @@
|
||||
'libyuv/include/scaler.h',
|
||||
'libyuv/webrtc_libyuv.cc',
|
||||
'libyuv/scaler.cc',
|
||||
'plane.h',
|
||||
'plane.cc',
|
||||
],
|
||||
},
|
||||
], # targets
|
||||
@ -74,9 +78,11 @@
|
||||
'<(webrtc_root)/test/test.gyp:test_support_main',
|
||||
],
|
||||
'sources': [
|
||||
'i420_video_frame_unittest.cc',
|
||||
'jpeg/jpeg_unittest.cc',
|
||||
'libyuv/libyuv_unittest.cc',
|
||||
'libyuv/scaler_unittest.cc',
|
||||
'plane_unittest.cc',
|
||||
],
|
||||
},
|
||||
], # targets
|
||||
|
144
src/common_video/i420_video_frame.cc
Normal file
144
src/common_video/i420_video_frame.cc
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "common_video/interface/i420_video_frame.h"
|
||||
|
||||
#include <algorithm> // swap
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
I420VideoFrame::I420VideoFrame()
|
||||
: width_(0),
|
||||
height_(0),
|
||||
timestamp_(0),
|
||||
render_time_ms_(0) {}
|
||||
|
||||
I420VideoFrame::~I420VideoFrame() {}
|
||||
|
||||
int I420VideoFrame::CreateEmptyFrame(int width, int height,
|
||||
int stride_y, int stride_u, int stride_v) {
|
||||
if (CheckDimensions(width, height, stride_y, stride_u, stride_v) < 0)
|
||||
return -1;
|
||||
int size_y = stride_y * height;
|
||||
int size_u = (stride_u + 1) * (height + 1) / 4;
|
||||
int size_v = (stride_v + 1) * (height + 1) / 4;
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
y_plane_.CreateEmptyPlane(size_y, stride_y, size_y);
|
||||
u_plane_.CreateEmptyPlane(size_u, stride_u, size_u);
|
||||
v_plane_.CreateEmptyPlane(size_v, stride_v, size_v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I420VideoFrame::CreateFrame(int size_y, const uint8_t& buffer_y,
|
||||
int size_u, const uint8_t& buffer_u,
|
||||
int size_v, const uint8_t& buffer_v,
|
||||
int width, int height,
|
||||
int stride_y, int stride_u, int stride_v) {
|
||||
if (size_y < 1 || size_u < 1 || size_v < 1)
|
||||
return -1;
|
||||
if (CheckDimensions(width, height, stride_y, stride_u, stride_v) < 0)
|
||||
return -1;
|
||||
y_plane_.Copy(size_y, stride_y, buffer_y);
|
||||
u_plane_.Copy(size_u, stride_u, buffer_u);
|
||||
v_plane_.Copy(size_v, stride_v, buffer_v);
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I420VideoFrame::CopyFrame(const I420VideoFrame& videoFrame) {
|
||||
int ret = CreateFrame(videoFrame.size(kYPlane), *videoFrame.buffer(kYPlane),
|
||||
videoFrame.size(kUPlane), *videoFrame.buffer(kUPlane),
|
||||
videoFrame.size(kVPlane), *videoFrame.buffer(kVPlane),
|
||||
videoFrame.width_, videoFrame.height_,
|
||||
videoFrame.stride(kYPlane), videoFrame.stride(kUPlane),
|
||||
videoFrame.stride(kVPlane));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
timestamp_ = videoFrame.timestamp_;
|
||||
render_time_ms_ = videoFrame.render_time_ms_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void I420VideoFrame::SwapFrame(I420VideoFrame* videoFrame) {
|
||||
y_plane_.Swap(videoFrame->y_plane_);
|
||||
u_plane_.Swap(videoFrame->u_plane_);
|
||||
v_plane_.Swap(videoFrame->v_plane_);
|
||||
std::swap(width_, videoFrame->width_);
|
||||
std::swap(height_, videoFrame->height_);
|
||||
std::swap(timestamp_, videoFrame->timestamp_);
|
||||
std::swap(render_time_ms_, videoFrame->render_time_ms_);
|
||||
}
|
||||
|
||||
const uint8_t* I420VideoFrame::buffer(PlaneType type) const {
|
||||
const Plane* plane_ptr = GetPlane(type);
|
||||
if (plane_ptr)
|
||||
return plane_ptr->buffer();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int I420VideoFrame::size(PlaneType type) const {
|
||||
const Plane* plane_ptr = GetPlane(type);
|
||||
if (plane_ptr)
|
||||
return plane_ptr->allocated_size();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int I420VideoFrame::stride(PlaneType type) const {
|
||||
const Plane* plane_ptr = GetPlane(type);
|
||||
if (plane_ptr)
|
||||
return plane_ptr->stride();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int I420VideoFrame::set_width(int width) {
|
||||
if (CheckDimensions(width, height_,
|
||||
y_plane_.stride(), u_plane_.stride(),
|
||||
v_plane_.stride()) < 0)
|
||||
return -1;
|
||||
width_ = width;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I420VideoFrame::set_height(int height) {
|
||||
if (CheckDimensions(width_, height,
|
||||
y_plane_.stride(), u_plane_.stride(),
|
||||
v_plane_.stride()) < 0)
|
||||
return -1;
|
||||
height_ = height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int I420VideoFrame::CheckDimensions(int width, int height,
|
||||
int stride_y, int stride_u, int stride_v) {
|
||||
int half_width = (width + 1) / 2;
|
||||
if (width < 1 || height < 1 ||
|
||||
stride_y < width || stride_u < half_width || stride_v < half_width)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Plane* I420VideoFrame::GetPlane(PlaneType type) const {
|
||||
switch (type) {
|
||||
case kYPlane :
|
||||
return &y_plane_;
|
||||
case kUPlane :
|
||||
return &u_plane_;
|
||||
case kVPlane :
|
||||
return &v_plane_;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
} // namespace webrtc
|
228
src/common_video/i420_video_frame_unittest.cc
Normal file
228
src/common_video/i420_video_frame_unittest.cc
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common_video/interface/i420_video_frame.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
bool EqualFrames(const I420VideoFrame& videoFrame1,
|
||||
const I420VideoFrame& videoFrame2);
|
||||
bool EqualFramesExceptSize(const I420VideoFrame& frame1,
|
||||
const I420VideoFrame& frame2);
|
||||
|
||||
TEST(TestI420VideoFrame, InitialValues) {
|
||||
I420VideoFrame frame;
|
||||
// Invalid arguments - one call for each variable.
|
||||
EXPECT_EQ(-1, frame.CreateEmptyFrame(0, 10, 10, 14, 14));
|
||||
EXPECT_EQ(-1, frame.CreateEmptyFrame(10, -1, 10, 90, 14));
|
||||
EXPECT_EQ(-1, frame.CreateEmptyFrame(10, 10, 0, 14, 18));
|
||||
EXPECT_EQ(-1, frame.CreateEmptyFrame(10, 10, 10, -2, 13));
|
||||
EXPECT_EQ(-1, frame.CreateEmptyFrame(10, 10, 10, 14, 0));
|
||||
EXPECT_EQ(0, frame.CreateEmptyFrame(10, 10, 10, 14, 90));
|
||||
}
|
||||
|
||||
TEST(TestI420VideoFrame, WidthHeightValues) {
|
||||
I420VideoFrame frame;
|
||||
const int valid_value = 10;
|
||||
const int invalid_value = -1;
|
||||
EXPECT_EQ(0, frame.CreateEmptyFrame(10, 10, 10, 14, 90));
|
||||
EXPECT_EQ(valid_value, frame.width());
|
||||
EXPECT_EQ(invalid_value, frame.set_width(invalid_value));
|
||||
EXPECT_EQ(valid_value, frame.height());
|
||||
EXPECT_EQ(valid_value, frame.height());
|
||||
EXPECT_EQ(invalid_value, frame.set_height(0));
|
||||
EXPECT_EQ(valid_value, frame.height());
|
||||
frame.set_timestamp(100u);
|
||||
EXPECT_EQ(100u, frame.timestamp());
|
||||
frame.set_render_time_ms(100);
|
||||
EXPECT_EQ(100, frame.render_time_ms());
|
||||
}
|
||||
|
||||
TEST(TestI420VideoFrame, SizeAllocation) {
|
||||
I420VideoFrame frame;
|
||||
EXPECT_EQ(0, frame. CreateEmptyFrame(10, 10, 12, 14, 220));
|
||||
int width = frame.width();
|
||||
int height = frame.height();
|
||||
int stride_y = frame.stride(kYPlane);
|
||||
int stride_u = frame.stride(kUPlane);
|
||||
int stride_v = frame.stride(kVPlane);
|
||||
// Verify that allocated size was computed correctly.
|
||||
EXPECT_EQ(width * stride_y, frame.size(kYPlane));
|
||||
EXPECT_EQ((height + 1) * (stride_u + 1) / 4, frame.size(kUPlane));
|
||||
EXPECT_EQ((height + 1) * (stride_v + 1) / 4, frame.size(kVPlane));
|
||||
}
|
||||
|
||||
TEST(TestI420VideoFrame, CopyFrame) {
|
||||
I420VideoFrame frame1, frame2;
|
||||
uint32_t timestamp = 1;
|
||||
int64_t render_time_ms = 1;
|
||||
int stride_y = 15;
|
||||
int stride_u = 10;
|
||||
int stride_v = 10;
|
||||
int width = 15;
|
||||
int height = 15;
|
||||
// Copy frame.
|
||||
EXPECT_EQ(0, frame1.CreateEmptyFrame(width, height,
|
||||
stride_y, stride_u, stride_v));
|
||||
frame1.set_timestamp(timestamp);
|
||||
frame1.set_render_time_ms(render_time_ms);
|
||||
int size_y = frame1.size(kYPlane);
|
||||
int size_u = frame1.size(kUPlane);
|
||||
int size_v = frame1.size(kVPlane);
|
||||
EXPECT_EQ(0, frame2.CreateEmptyFrame(width + 5, height + 5,
|
||||
stride_y + 5, stride_u, stride_v));
|
||||
// Frame of smaller dimensions - allocated sizes should not vary.
|
||||
EXPECT_EQ(0, frame2.CopyFrame(frame1));
|
||||
EXPECT_TRUE(EqualFramesExceptSize(frame1, frame2));
|
||||
EXPECT_EQ(size_y, frame1.size(kYPlane));
|
||||
EXPECT_EQ(size_u, frame1.size(kUPlane));
|
||||
EXPECT_EQ(size_v, frame1.size(kVPlane));
|
||||
// Verify copy of all parameters.
|
||||
// Frame of larger dimensions - update allocated sizes.
|
||||
EXPECT_EQ(0, frame1.CopyFrame(frame2));
|
||||
EXPECT_TRUE(EqualFrames(frame1, frame2));
|
||||
}
|
||||
|
||||
TEST(TestI420VideoFrame, CopyBuffer) {
|
||||
I420VideoFrame frame1, frame2;
|
||||
int width = 15;
|
||||
int height = 15;
|
||||
int stride_y = 15;
|
||||
int stride_u = 10;
|
||||
int stride_v = 10;
|
||||
const int kSizeY = 225;
|
||||
const int kSizeUv = 37; // (stride_u + 1) * (height + 1) / 4;
|
||||
EXPECT_EQ(0, frame2.CreateEmptyFrame(width + 5, height + 5,
|
||||
stride_y + 5, stride_u, stride_v));
|
||||
EXPECT_EQ(0, frame2.CreateEmptyFrame(width, height,
|
||||
stride_y, stride_u, stride_v));
|
||||
uint8_t buffer_y[kSizeY];
|
||||
uint8_t buffer_u[kSizeUv];
|
||||
uint8_t buffer_v[kSizeUv];
|
||||
memset(buffer_y, 16, kSizeY);
|
||||
memset(buffer_u, 8, kSizeUv);
|
||||
memset(buffer_v, 4, kSizeUv);
|
||||
frame2.CreateFrame(kSizeY, *buffer_y,
|
||||
kSizeUv, *buffer_u,
|
||||
kSizeUv, *buffer_v,
|
||||
width, height, stride_y, stride_u, stride_v);
|
||||
// Copy memory (at least allocated size).
|
||||
EXPECT_EQ(memcmp(buffer_y, frame2.buffer(kYPlane), kSizeY), 0);
|
||||
EXPECT_EQ(memcmp(buffer_u, frame2.buffer(kUPlane), kSizeUv), 0);
|
||||
EXPECT_EQ(memcmp(buffer_v, frame2.buffer(kVPlane), kSizeUv), 0);
|
||||
// Comapre size.
|
||||
EXPECT_LE(kSizeY, frame2.size(kYPlane));
|
||||
EXPECT_LE(kSizeUv, frame2.size(kUPlane));
|
||||
EXPECT_LE(kSizeUv, frame2.size(kVPlane));
|
||||
}
|
||||
|
||||
TEST(TestI420VideoFrame, FrameSwap) {
|
||||
I420VideoFrame frame1, frame2;
|
||||
uint32_t timestamp1 = 1;
|
||||
int64_t render_time_ms1 = 1;
|
||||
int stride_y1 = 15;
|
||||
int stride_u1 = 10;
|
||||
int stride_v1 = 10;
|
||||
int width1 = 15;
|
||||
int height1 = 15;
|
||||
const int kSizeY1 = 225;
|
||||
const int kSizeU1 = 37;
|
||||
const int kSizeV1 = 37;
|
||||
uint32_t timestamp2 = 2;
|
||||
int64_t render_time_ms2 = 4;
|
||||
int stride_y2 = 30;
|
||||
int stride_u2 = 20;
|
||||
int stride_v2 = 20;
|
||||
int width2 = 30;
|
||||
int height2 = 30;
|
||||
const int kSizeY2 = 900;
|
||||
const int kSizeU2 = 150;
|
||||
const int kSizeV2 = 150;
|
||||
// Initialize frame1 values.
|
||||
EXPECT_EQ(0, frame1.CreateEmptyFrame(width1, height1,
|
||||
stride_y1, stride_u1, stride_v1));
|
||||
frame1.set_timestamp(timestamp1);
|
||||
frame1.set_render_time_ms(render_time_ms1);
|
||||
// Set memory for frame1.
|
||||
uint8_t buffer_y1[kSizeY1];
|
||||
uint8_t buffer_u1[kSizeU1];
|
||||
uint8_t buffer_v1[kSizeV1];
|
||||
memset(buffer_y1, 2, kSizeY1);
|
||||
memset(buffer_u1, 4, kSizeU1);
|
||||
memset(buffer_v1, 8, kSizeV1);
|
||||
frame1.CreateFrame(kSizeY1, *buffer_y1,
|
||||
kSizeU1, *buffer_u1,
|
||||
kSizeV1, *buffer_v1,
|
||||
width1, height1, stride_y1, stride_u1, stride_v1);
|
||||
// Initialize frame2 values.
|
||||
EXPECT_EQ(0, frame2.CreateEmptyFrame(width2, height2,
|
||||
stride_y2, stride_u2, stride_v2));
|
||||
frame2.set_timestamp(timestamp2);
|
||||
frame2.set_render_time_ms(render_time_ms2);
|
||||
// Set memory for frame2.
|
||||
uint8_t buffer_y2[kSizeY2];
|
||||
uint8_t buffer_u2[kSizeU2];
|
||||
uint8_t buffer_v2[kSizeV2];
|
||||
memset(buffer_y2, 0, kSizeY2);
|
||||
memset(buffer_u2, 1, kSizeU2);
|
||||
memset(buffer_v2, 2, kSizeV2);
|
||||
frame2.CreateFrame(kSizeY2, *buffer_y2,
|
||||
kSizeU2, *buffer_u2,
|
||||
kSizeV2, *buffer_v2,
|
||||
width2, height2, stride_y2, stride_u2, stride_v2);
|
||||
// Copy frames for subsequent comparison.
|
||||
I420VideoFrame frame1_copy, frame2_copy;
|
||||
frame1_copy.CopyFrame(frame1);
|
||||
frame2_copy.CopyFrame(frame2);
|
||||
// Swap frames.
|
||||
frame1.SwapFrame(&frame2);
|
||||
// Verify swap.
|
||||
EXPECT_TRUE(EqualFrames(frame1_copy, frame2));
|
||||
EXPECT_TRUE(EqualFrames(frame2_copy, frame1));
|
||||
}
|
||||
|
||||
bool EqualFrames(const I420VideoFrame& frame1,
|
||||
const I420VideoFrame& frame2) {
|
||||
if (!EqualFramesExceptSize(frame1, frame2))
|
||||
return false;
|
||||
// Compare allocated memory size.
|
||||
bool ret = true;
|
||||
ret |= (frame1.size(kYPlane) == frame2.size(kYPlane));
|
||||
ret |= (frame1.size(kUPlane) == frame2.size(kUPlane));
|
||||
ret |= (frame1.size(kVPlane) == frame2.size(kVPlane));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool EqualFramesExceptSize(const I420VideoFrame& frame1,
|
||||
const I420VideoFrame& frame2) {
|
||||
bool ret = true;
|
||||
ret |= (frame1.width() == frame2.width());
|
||||
ret |= (frame1.height() == frame2.height());
|
||||
ret |= (frame1.stride(kYPlane) == frame2.stride(kYPlane));
|
||||
ret |= (frame1.stride(kUPlane) == frame2.stride(kUPlane));
|
||||
ret |= (frame1.stride(kVPlane) == frame2.stride(kVPlane));
|
||||
ret |= (frame1.timestamp() == frame2.timestamp());
|
||||
ret |= (frame1.render_time_ms() == frame2.render_time_ms());
|
||||
// Memory should be the equal for the minimum of the two sizes.
|
||||
int size_y = std::min(frame1.size(kYPlane), frame2.size(kYPlane));
|
||||
int size_u = std::min(frame1.size(kUPlane), frame1.size(kUPlane));
|
||||
int size_v = std::min(frame1.size(kVPlane), frame1.size(kVPlane));
|
||||
ret |= memcmp(frame1.buffer(kYPlane), frame2.buffer(kYPlane), size_y);
|
||||
ret |= memcmp(frame1.buffer(kUPlane), frame2.buffer(kYPlane), size_u);
|
||||
ret |= memcmp(frame1.buffer(kVPlane), frame2.buffer(kYPlane), size_v);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
113
src/common_video/interface/i420_video_frame.h
Normal file
113
src/common_video/interface/i420_video_frame.h
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H
|
||||
#define COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H
|
||||
|
||||
// I420VideoFrame class
|
||||
//
|
||||
// Storing and handling of YUV (I420) video frames.
|
||||
|
||||
#include "common_video/plane.h"
|
||||
#include "typedefs.h" //NOLINT
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
enum PlaneType {
|
||||
kYPlane = 0,
|
||||
kUPlane = 1,
|
||||
kVPlane = 2
|
||||
};
|
||||
|
||||
class I420VideoFrame {
|
||||
public:
|
||||
I420VideoFrame();
|
||||
~I420VideoFrame();
|
||||
|
||||
// CreateEmptyFrame: Sets frame dimensions and allocates buffers based
|
||||
// on set dimensions - height and plane stride.
|
||||
// If required size is bigger than the allocated one, new buffers of adequate
|
||||
// size will be allocated.
|
||||
// Return value: 0 on success ,-1 on error.
|
||||
int CreateEmptyFrame(int width, int height,
|
||||
int stride_y, int stride_u, int stride_v);
|
||||
|
||||
// CreateFrame: Sets the frame's members and buffers. If required size is
|
||||
// bigger than allocated one, new buffers of adequate size will be allocated.
|
||||
// Return value: 0 on success ,-1 on error.
|
||||
int CreateFrame(int size_y, const uint8_t& buffer_y,
|
||||
int size_u, const uint8_t& buffer_u,
|
||||
int size_v, const uint8_t& buffer_v,
|
||||
int width, int height,
|
||||
int stride_y, int stride_u, int stride_v);
|
||||
|
||||
// Copy frame: If required size is bigger than allocated one, new buffers of
|
||||
// adequate size will be allocated.
|
||||
// Return value: 0 on success ,-1 on error.
|
||||
int CopyFrame(const I420VideoFrame& videoFrame);
|
||||
|
||||
// Swap Frame.
|
||||
void SwapFrame(I420VideoFrame* videoFrame);
|
||||
|
||||
// Get pointer to buffer per plane.
|
||||
const uint8_t* buffer(PlaneType type) const;
|
||||
|
||||
// Get allocated size per plane.
|
||||
int size(PlaneType type) const;
|
||||
|
||||
// Get allocated stride per plane.
|
||||
int stride(PlaneType type) const;
|
||||
|
||||
// Set frame width.
|
||||
int set_width(int width);
|
||||
|
||||
// Set frame height.
|
||||
int set_height(int height);
|
||||
|
||||
// Get frame width.
|
||||
int width() const {return width_;}
|
||||
|
||||
// Get frame height.
|
||||
int height() const {return height_;}
|
||||
|
||||
// Set frame timestamp (90kHz).
|
||||
void set_timestamp(const uint32_t timestamp) {timestamp_ = timestamp;}
|
||||
|
||||
// Get frame timestamp (90kHz).
|
||||
uint32_t timestamp() const {return timestamp_;}
|
||||
|
||||
// Set render time in miliseconds.
|
||||
void set_render_time_ms(int64_t render_time_ms) {render_time_ms_ =
|
||||
render_time_ms;}
|
||||
|
||||
// Get render time in miliseconds.
|
||||
int64_t render_time_ms() const {return render_time_ms_;}
|
||||
|
||||
private:
|
||||
// Verifies legality of parameters.
|
||||
// Return value: 0 on success ,-1 on error.
|
||||
int CheckDimensions(int width, int height,
|
||||
int stride_y, int stride_u, int stride_v);
|
||||
// Get the pointer to a specific plane.
|
||||
const Plane* GetPlane(PlaneType type) const;
|
||||
|
||||
Plane y_plane_;
|
||||
Plane u_plane_;
|
||||
Plane v_plane_;
|
||||
int width_;
|
||||
int height_;
|
||||
uint32_t timestamp_;
|
||||
int64_t render_time_ms_;
|
||||
}; // I420VideoFrame
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // COMMON_VIDEO_INTERFACE_I420_VIDEO_FRAME_H
|
||||
|
76
src/common_video/plane.cc
Normal file
76
src/common_video/plane.cc
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "common_video/plane.h"
|
||||
|
||||
#include <algorithm> // swap
|
||||
#include <cstring> // memcpy
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
Plane::Plane()
|
||||
: buffer_(NULL),
|
||||
allocated_size_(0),
|
||||
plane_size_(0),
|
||||
stride_(0) {}
|
||||
|
||||
Plane::~Plane() {}
|
||||
|
||||
int Plane::CreateEmptyPlane(int allocated_size, int stride, int plane_size) {
|
||||
if (allocated_size < 1 || stride < 1 || plane_size < 1)
|
||||
return -1;
|
||||
stride_ = stride;
|
||||
plane_size_ = plane_size;
|
||||
MaybeResize(allocated_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Plane::MaybeResize(int new_size) {
|
||||
if (new_size <= 0)
|
||||
return -1;
|
||||
if (new_size <= allocated_size_)
|
||||
return 0;
|
||||
uint8_t* new_buffer = new uint8_t[new_size];
|
||||
if (buffer_.get()) {
|
||||
memcpy(new_buffer, buffer_.get(), plane_size_);
|
||||
buffer_.reset();
|
||||
}
|
||||
buffer_.reset(new_buffer);
|
||||
allocated_size_ = new_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Plane::Copy(const Plane& plane) {
|
||||
if (MaybeResize(plane.allocated_size_) < 0)
|
||||
return -1;
|
||||
if (plane.buffer_.get())
|
||||
memcpy(buffer_.get(), plane.buffer_.get(), plane.plane_size_);
|
||||
stride_ = plane.stride_;
|
||||
plane_size_ = plane.plane_size_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Plane::Copy(int size, int stride, const uint8_t& buffer) {
|
||||
if (MaybeResize(size) < 0)
|
||||
return -1;
|
||||
memcpy(buffer_.get(), &buffer, size);
|
||||
plane_size_ = size;
|
||||
stride_ = stride;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Plane::Swap(Plane& plane) {
|
||||
std::swap(stride_, plane.stride_);
|
||||
std::swap(allocated_size_, plane.allocated_size_);
|
||||
std::swap(plane_size_, plane.plane_size_);
|
||||
buffer_.swap(plane.buffer_);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
66
src/common_video/plane.h
Normal file
66
src/common_video/plane.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_VIDEO_PLANE_H
|
||||
#define COMMON_VIDEO_PLANE_H
|
||||
|
||||
#include "system_wrappers/interface/scoped_ptr.h"
|
||||
#include "typedefs.h" //NOLINT
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Helper class for I420VideoFrame: Store plane data and perform basic plane
|
||||
// operations.
|
||||
class Plane {
|
||||
public:
|
||||
Plane();
|
||||
~Plane();
|
||||
// CreateEmptyPlane - set allocated size, actual plane size and stride:
|
||||
// If current size is smaller than current size, then a buffer of sufficient
|
||||
// size will be allocated.
|
||||
// Return value: 0 on success ,-1 on error.
|
||||
int CreateEmptyPlane(int allocated_size, int stride, int plane_size);
|
||||
|
||||
// Copy the entire plane data.
|
||||
// Return value: 0 on success ,-1 on error.
|
||||
int Copy(const Plane& plane);
|
||||
|
||||
// Copy buffer: If current size is smaller
|
||||
// than current size, then a buffer of sufficient size will be allocated.
|
||||
// Return value: 0 on success ,-1 on error.
|
||||
int Copy(int size, int stride, const uint8_t& buffer);
|
||||
|
||||
// Swap plane data.
|
||||
void Swap(Plane& plane);
|
||||
|
||||
// Get allocated size.
|
||||
int allocated_size() const {return allocated_size_;}
|
||||
|
||||
// Get stride value.
|
||||
int stride() const {return stride_;}
|
||||
|
||||
// Return data pointer.
|
||||
const uint8_t* buffer() const {return buffer_.get();}
|
||||
|
||||
private:
|
||||
// Resize when needed: If current allocated size is less than new_size, buffer
|
||||
// will be updated. Old data will be copied to new buffer.
|
||||
// Return value: 0 on success ,-1 on error.
|
||||
int MaybeResize(int new_size);
|
||||
|
||||
scoped_array<uint8_t> buffer_;
|
||||
int allocated_size_;
|
||||
int plane_size_;
|
||||
int stride_;
|
||||
}; // Plane
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // COMMON_VIDEO_PLANE_H
|
80
src/common_video/plane_unittest.cc
Normal file
80
src/common_video/plane_unittest.cc
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "common_video/plane.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
TEST(TestPlane, CreateEmptyPlaneialValues) {
|
||||
Plane plane;
|
||||
int size, stride;
|
||||
EXPECT_EQ(0, plane.allocated_size());
|
||||
EXPECT_EQ(0, plane.stride());
|
||||
size = 0;
|
||||
stride = 20;
|
||||
EXPECT_EQ(-1, plane.CreateEmptyPlane(size, stride, 1));
|
||||
EXPECT_EQ(-1, plane.CreateEmptyPlane(10, stride, size));
|
||||
size = 20;
|
||||
stride = 0;
|
||||
EXPECT_EQ(-1, plane.CreateEmptyPlane(size, stride, size));
|
||||
stride = 20;
|
||||
EXPECT_EQ(0, plane.CreateEmptyPlane(size, stride, size));
|
||||
EXPECT_EQ(size, plane.allocated_size());
|
||||
EXPECT_EQ(stride, plane.stride());
|
||||
}
|
||||
|
||||
TEST(TestPlane, PlaneCopy) {
|
||||
Plane plane1, plane2;
|
||||
// Copy entire plane.
|
||||
plane1.CreateEmptyPlane(100, 10, 100);
|
||||
int size1 = plane1.allocated_size();
|
||||
int size2 = 30;
|
||||
plane2.CreateEmptyPlane(50, 15, size2);
|
||||
int stride1 = plane1.stride();
|
||||
int stride2 = plane2.stride();
|
||||
plane1.Copy(plane2);
|
||||
// Smaller size - keep buffer size as is.
|
||||
EXPECT_EQ(size1, plane1.allocated_size());
|
||||
EXPECT_EQ(stride2, plane1.stride());
|
||||
plane2.Copy(plane1);
|
||||
// Verify increment of allocated size.
|
||||
EXPECT_EQ(plane1.allocated_size(), plane2.allocated_size());
|
||||
EXPECT_EQ(stride2, plane2.stride());
|
||||
// Copy buffer.
|
||||
uint8_t buffer1[100];
|
||||
size1 = 80;
|
||||
memset(&buffer1, 0, size1);
|
||||
plane2.Copy(size1, stride1, *buffer1);
|
||||
EXPECT_GE(plane2.allocated_size(), size1);
|
||||
EXPECT_EQ(0, memcmp(buffer1, plane2.buffer(), size1));
|
||||
}
|
||||
|
||||
TEST(TestPlane, PlaneSwap) {
|
||||
Plane plane1, plane2;
|
||||
int size1, size2, stride1, stride2;
|
||||
plane1.CreateEmptyPlane(100, 10, 100);
|
||||
plane2.CreateEmptyPlane(50, 15, 50);
|
||||
size1 = plane1.allocated_size();
|
||||
stride1 = plane1.stride();
|
||||
stride2 = plane2.stride();
|
||||
size2 = plane2.allocated_size();
|
||||
plane1.Swap(plane2);
|
||||
EXPECT_EQ(size1, plane2.allocated_size());
|
||||
EXPECT_EQ(size2, plane1.allocated_size());
|
||||
EXPECT_EQ(stride2, plane1.stride());
|
||||
EXPECT_EQ(stride1, plane2.stride());
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
Loading…
x
Reference in New Issue
Block a user