diff --git a/webrtc/common_video/i420_video_frame.cc b/webrtc/common_video/i420_video_frame.cc index e369ffe108..332a1e8126 100644 --- a/webrtc/common_video/i420_video_frame.cc +++ b/webrtc/common_video/i420_video_frame.cc @@ -58,6 +58,23 @@ int I420VideoFrame::CreateFrame(int size_y, const uint8_t* buffer_y, return 0; } +int I420VideoFrame::AliasBuffers(int size_y, uint8_t* buffer_y, + int size_u, uint8_t* buffer_u, + int size_v, 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_.Alias(size_y, stride_y, buffer_y); + u_plane_.Alias(size_u, stride_u, buffer_u); + v_plane_.Alias(size_v, stride_v, buffer_v); + width_ = width; + height_ = height; + return 0; +} + int I420VideoFrame::CopyFrame(const I420VideoFrame& videoFrame) { int ret = CreateFrame(videoFrame.allocated_size(kYPlane), videoFrame.buffer(kYPlane), diff --git a/webrtc/common_video/i420_video_frame_unittest.cc b/webrtc/common_video/i420_video_frame_unittest.cc index 5c738bd791..9fb8c04687 100644 --- a/webrtc/common_video/i420_video_frame_unittest.cc +++ b/webrtc/common_video/i420_video_frame_unittest.cc @@ -118,7 +118,7 @@ TEST(TestI420VideoFrame, CopyFrame) { EXPECT_TRUE(EqualFrames(frame1, frame2)); } -TEST(TestI420VideoFrame, CopyBuffer) { +TEST(TestI420VideoFrame, CreateFrame) { I420VideoFrame frame1, frame2; int width = 15; int height = 15; @@ -148,6 +148,34 @@ TEST(TestI420VideoFrame, CopyBuffer) { EXPECT_LE(kSizeUv, frame2.allocated_size(kVPlane)); } +TEST(TestI420VideoFrame, AliasBuffers) { + I420VideoFrame frame; + int width = 15; + int height = 15; + int stride_y = 15; + int stride_uv = 10; + const int kSizeY = 225; + const int kSizeUv = 80; + EXPECT_EQ( + 0, frame.CreateEmptyFrame(width, height, stride_y, stride_uv, stride_uv)); + 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); + frame.AliasBuffers(kSizeY, buffer_y, + kSizeUv, buffer_u, + kSizeUv, buffer_v, + width, height, stride_y, stride_uv, stride_uv); + EXPECT_EQ(buffer_y, frame.buffer(kYPlane)); + EXPECT_EQ(buffer_u, frame.buffer(kUPlane)); + EXPECT_EQ(buffer_v, frame.buffer(kVPlane)); + EXPECT_EQ(0, frame.allocated_size(kYPlane)); + EXPECT_EQ(0, frame.allocated_size(kUPlane)); + EXPECT_EQ(0, frame.allocated_size(kVPlane)); +} + TEST(TestI420VideoFrame, FrameSwap) { I420VideoFrame frame1, frame2; uint32_t timestamp1 = 1; diff --git a/webrtc/common_video/interface/i420_video_frame.h b/webrtc/common_video/interface/i420_video_frame.h index 45f2ec3039..a9e1b3540a 100644 --- a/webrtc/common_video/interface/i420_video_frame.h +++ b/webrtc/common_video/interface/i420_video_frame.h @@ -62,6 +62,15 @@ class I420VideoFrame { int width, int height, int stride_y, int stride_u, int stride_v); + // AliasBuffers: Sets the frame's members and buffers from a set of buffers. + // The buffers are not copied, only the pointers, and the frame does not take + // ownership of the buffers (i.e.: the buffers must outlive the frame). + virtual int AliasBuffers(int size_y, uint8_t* buffer_y, + int size_u, uint8_t* buffer_u, + int size_v, 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. diff --git a/webrtc/common_video/interface/texture_video_frame.h b/webrtc/common_video/interface/texture_video_frame.h index e905ea7338..802320051c 100644 --- a/webrtc/common_video/interface/texture_video_frame.h +++ b/webrtc/common_video/interface/texture_video_frame.h @@ -48,6 +48,17 @@ class TextureVideoFrame : public I420VideoFrame { int stride_y, int stride_u, int stride_v) OVERRIDE; + virtual int AliasBuffers(int size_y, + uint8_t* buffer_y, + int size_u, + uint8_t* buffer_u, + int size_v, + uint8_t* buffer_v, + int width, + int height, + int stride_y, + int stride_u, + int stride_v) OVERRIDE; virtual int CopyFrame(const I420VideoFrame& videoFrame) OVERRIDE; virtual void SwapFrame(I420VideoFrame* videoFrame) OVERRIDE; virtual uint8_t* buffer(PlaneType type) OVERRIDE; diff --git a/webrtc/common_video/plane.cc b/webrtc/common_video/plane.cc index 68d32cd459..97829172fe 100644 --- a/webrtc/common_video/plane.cc +++ b/webrtc/common_video/plane.cc @@ -17,65 +17,75 @@ namespace webrtc { // Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. -static const int kBufferAlignment = 64; +static const int kBufferAlignment = 64; Plane::Plane() - : buffer_(NULL), + : pointer_(NULL), + allocation_(NULL), allocated_size_(0), plane_size_(0), stride_(0) {} Plane::~Plane() {} -int Plane::CreateEmptyPlane(int allocated_size, int stride, int plane_size) { +int Plane::CreateEmptyPlane(int allocated_size, + int stride, + int plane_size) { if (allocated_size < 1 || stride < 1 || plane_size < 1) return -1; stride_ = stride; - if (MaybeResize(allocated_size) < 0) + if (Reallocate(allocated_size) < 0) return -1; plane_size_ = plane_size; return 0; } -int Plane::MaybeResize(int new_size) { +int Plane::Reallocate(int new_size) { if (new_size <= 0) return -1; if (new_size <= allocated_size_) return 0; Allocator::scoped_ptr_aligned new_buffer( AlignedMalloc(new_size, kBufferAlignment)); - if (buffer_.get()) { - memcpy(new_buffer.get(), buffer_.get(), plane_size_); - } - buffer_.reset(new_buffer.release()); + allocation_.reset(new_buffer.release()); + pointer_ = allocation_.get(); allocated_size_ = new_size; return 0; } int Plane::Copy(const Plane& plane) { - if (MaybeResize(plane.allocated_size_) < 0) + if (Reallocate(plane.allocated_size_) < 0) return -1; - if (plane.buffer_.get()) - memcpy(buffer_.get(), plane.buffer_.get(), plane.plane_size_); + if (plane.pointer_) + memcpy(pointer_, plane.pointer_, 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) + if (Reallocate(size) < 0) return -1; - memcpy(buffer_.get(), buffer, size); + memcpy(pointer_, buffer, size); plane_size_ = size; stride_ = stride; return 0; } +void Plane::Alias(int size, int stride, uint8_t* buffer) { + allocation_.reset(); + allocated_size_ = 0; + pointer_ = buffer; + stride_ = stride; + plane_size_ = size; +} + void Plane::Swap(Plane& plane) { - std::swap(stride_, plane.stride_); + std::swap(pointer_, plane.pointer_); + allocation_.swap(plane.allocation_); std::swap(allocated_size_, plane.allocated_size_); std::swap(plane_size_, plane.plane_size_); - buffer_.swap(plane.buffer_); + std::swap(stride_, plane.stride_); } } // namespace webrtc diff --git a/webrtc/common_video/plane.h b/webrtc/common_video/plane.h index 1b74f37ec0..612429f3da 100644 --- a/webrtc/common_video/plane.h +++ b/webrtc/common_video/plane.h @@ -25,23 +25,26 @@ class 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. + // 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. + // 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. + // Return value: 0 on success, -1 on error. int Copy(int size, int stride, const uint8_t* buffer); + // Make this plane refer to a memory buffer. Plane will not own buffer. + void Alias(int size, int stride, uint8_t* buffer); + // Swap plane data. void Swap(Plane& plane); // Get allocated size. - int allocated_size() const {return allocated_size_;} + int allocated_size() const { return allocated_size_; } // Set actual size. void ResetSize() {plane_size_ = 0;} @@ -50,20 +53,21 @@ class Plane { bool IsZeroSize() const {return plane_size_ == 0;} // Get stride value. - int stride() const {return stride_;} + int stride() const { return stride_; } // Return data pointer. - const uint8_t* buffer() const {return buffer_.get();} + const uint8_t* buffer() const { return pointer_; } // Overloading with non-const. - uint8_t* buffer() {return buffer_.get();} + uint8_t* buffer() { return pointer_; } 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); + // Reallocate when needed: If current allocated size is less than new_size, + // buffer will be updated. In any case, old data becomes undefined. + // Return value: 0 on success, -1 on error. + int Reallocate(int new_size); - Allocator::scoped_ptr_aligned buffer_; + uint8_t* pointer_; + Allocator::scoped_ptr_aligned allocation_; int allocated_size_; int plane_size_; int stride_; diff --git a/webrtc/common_video/plane_unittest.cc b/webrtc/common_video/plane_unittest.cc index d165598287..6738f512c2 100644 --- a/webrtc/common_video/plane_unittest.cc +++ b/webrtc/common_video/plane_unittest.cc @@ -78,6 +78,15 @@ TEST(TestPlane, PlaneCopy) { EXPECT_EQ(0, memcmp(buffer1, plane2.buffer(), size1)); } +TEST(TestPlane, PlaneAlias) { + Plane plane; + plane.CreateEmptyPlane(100, 10, 100); + uint8_t buffer[256]; + plane.Alias(sizeof(buffer), sizeof(buffer) / 16, buffer); + EXPECT_EQ(buffer, plane.buffer()); + EXPECT_EQ(0, plane.allocated_size()); +} + TEST(TestPlane, PlaneSwap) { Plane plane1, plane2; int size1, size2, stride1, stride2; diff --git a/webrtc/common_video/texture_video_frame.cc b/webrtc/common_video/texture_video_frame.cc index ea53dc25cf..9bd667113e 100644 --- a/webrtc/common_video/texture_video_frame.cc +++ b/webrtc/common_video/texture_video_frame.cc @@ -60,6 +60,21 @@ int TextureVideoFrame::CreateFrame(int size_y, return -1; } +int TextureVideoFrame::AliasBuffers(int size_y, + uint8_t* buffer_y, + int size_u, + uint8_t* buffer_u, + int size_v, + uint8_t* buffer_v, + int width, + int height, + int stride_y, + int stride_u, + int stride_v) { + NOTREACHED(); + return -1; +} + int TextureVideoFrame::CopyFrame(const I420VideoFrame& videoFrame) { NOTREACHED(); return -1; diff --git a/webrtc/modules/video_capture/video_capture_impl.cc b/webrtc/modules/video_capture/video_capture_impl.cc index a23d22b3a5..592d5233b5 100644 --- a/webrtc/modules/video_capture/video_capture_impl.cc +++ b/webrtc/modules/video_capture/video_capture_impl.cc @@ -314,10 +314,9 @@ int32_t VideoCaptureImpl::IncomingFrame( // Setting absolute height (in case it was negative). // In Windows, the image starts bottom left, instead of top left. // Setting a negative source height, inverts the image (within LibYuv). - int ret = _captureFrame.CreateEmptyFrame(target_width, - abs(target_height), - stride_y, - stride_uv, stride_uv); + I420VideoFrame captureFrame; + int ret = captureFrame.CreateEmptyFrame( + target_width, abs(target_height), stride_y, stride_uv, stride_uv); if (ret < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, @@ -330,7 +329,7 @@ int32_t VideoCaptureImpl::IncomingFrame( width, height, videoFrameLength, _rotateFrame, - &_captureFrame); + &captureFrame); if (conversionResult < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, @@ -338,7 +337,7 @@ int32_t VideoCaptureImpl::IncomingFrame( frameInfo.rawType); return -1; } - DeliverCapturedFrame(_captureFrame, captureTime); + DeliverCapturedFrame(captureFrame, captureTime); } else // Encoded format { @@ -365,8 +364,8 @@ int32_t VideoCaptureImpl::IncomingFrameI420( int size_y = video_frame.height * video_frame.y_pitch; int size_u = video_frame.u_pitch * ((video_frame.height + 1) / 2); int size_v = video_frame.v_pitch * ((video_frame.height + 1) / 2); - // TODO(mikhal): Can we use Swap here? This will do a memcpy. - int ret = _captureFrame.CreateFrame(size_y, video_frame.y_plane, + I420VideoFrame captureFrame; + int ret = captureFrame.AliasBuffers(size_y, video_frame.y_plane, size_u, video_frame.u_plane, size_v, video_frame.v_plane, video_frame.width, video_frame.height, @@ -374,11 +373,11 @@ int32_t VideoCaptureImpl::IncomingFrameI420( video_frame.v_pitch); if (ret < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, - "Failed to create I420VideoFrame"); + "Failed to alias I420VideoFrame"); return -1; } - DeliverCapturedFrame(_captureFrame, captureTime); + DeliverCapturedFrame(captureFrame, captureTime); return 0; } diff --git a/webrtc/modules/video_capture/video_capture_impl.h b/webrtc/modules/video_capture/video_capture_impl.h index 41f555c3dd..2fee61c4b4 100644 --- a/webrtc/modules/video_capture/video_capture_impl.h +++ b/webrtc/modules/video_capture/video_capture_impl.h @@ -134,7 +134,6 @@ private: TickTime _incomingFrameTimes[kFrameRateCountHistorySize];// timestamp for local captured frames VideoRotationMode _rotateFrame; //Set if the frame should be rotated by the capture module. - I420VideoFrame _captureFrame; VideoFrame _capture_encoded_frame; // Used to make sure incoming timestamp is increasing for every frame. diff --git a/webrtc/video_engine/include/vie_image_process.h b/webrtc/video_engine/include/vie_image_process.h index 9a12748e25..c1365f6e2b 100644 --- a/webrtc/video_engine/include/vie_image_process.h +++ b/webrtc/video_engine/include/vie_image_process.h @@ -18,7 +18,6 @@ #define WEBRTC_VIDEO_ENGINE_INCLUDE_VIE_IMAGE_PROCESS_H_ #include "webrtc/common_types.h" -#include "webrtc/common_video/interface/i420_video_frame.h" namespace webrtc {