Revert "Revert "Revert "Support more formats in RTCVideoFrame"""

This reverts commit 7583390d1a3a7c4e9a77da0d77250abac0c34d1d.

Reason for revert: Breaks unit tests

Original change's description:
> Revert "Revert "Support more formats in RTCVideoFrame""
> 
> This reverts commit 0789dab2cbd1617e94d7300e375163d42345f3d4.
> 
> Reason for revert: Include obc_corevideoframebuffer target
> 
> Original change's description:
> > Revert "Support more formats in RTCVideoFrame"
> > 
> > This reverts commit bd2220a9c496ef2e8567b68d4be9435a110bdc34.
> > 
> > Reason for revert: Broke external clients
> > 
> > Original change's description:
> > > Support more formats in RTCVideoFrame
> > > 
> > > Implement Obj-C version of webrtc::VideoFrameBuffer and use that in
> > > RTCVideoFrame.
> > > 
> > > Bug: webrtc:7785
> > > Change-Id: I49f42bcf451dd6769b3a79a65fe7b400dce22677
> > > Reviewed-on: https://chromium-review.googlesource.com/536773
> > > Commit-Queue: Anders Carlsson <andersc@webrtc.org>
> > > Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
> > > Cr-Commit-Position: refs/heads/master@{#18691}
> > 
> > TBR=magjed@webrtc.org,andersc@webrtc.org
> > 
> > Change-Id: Id765dd9543ed0613a6b2de108b268c3501025fcd
> > No-Presubmit: true
> > No-Tree-Checks: true
> > No-Try: true
> > Bug: webrtc:7785
> > Reviewed-on: https://chromium-review.googlesource.com/542837
> > Reviewed-by: Anders Carlsson <andersc@webrtc.org>
> > Commit-Queue: Anders Carlsson <andersc@webrtc.org>
> > Cr-Commit-Position: refs/heads/master@{#18697}
> 
> TBR=magjed@webrtc.org,andersc@webrtc.org
> 
> Change-Id: I1ef5313b4a6c56eb8c7fd02d95db62c4e3c00255
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: webrtc:7785
> Reviewed-on: https://chromium-review.googlesource.com/542838
> Commit-Queue: Anders Carlsson <andersc@webrtc.org>
> Reviewed-by: Anders Carlsson <andersc@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#18716}

TBR=magjed@webrtc.org,andersc@webrtc.org

Change-Id: Id12f33698eb02041607cb9a5c54f37f01bfac5b1
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:7785
Reviewed-on: https://chromium-review.googlesource.com/544840
Reviewed-by: Anders Carlsson <andersc@webrtc.org>
Commit-Queue: Anders Carlsson <andersc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#18718}
This commit is contained in:
Anders Carlsson
2017-06-22 13:06:39 +00:00
committed by Commit Bot
parent d0fc37a884
commit 1cfeb43542
24 changed files with 168 additions and 783 deletions

View File

@ -1,188 +0,0 @@
/*
* Copyright 2017 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.
*/
#import "WebRTC/RTCVideoFrameBuffer.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
@implementation RTCCVPixelBuffer {
int _width;
int _height;
int _bufferWidth;
int _bufferHeight;
int _cropWidth;
int _cropHeight;
int _cropX;
int _cropY;
}
@synthesize pixelBuffer = _pixelBuffer;
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer {
return [self initWithPixelBuffer:pixelBuffer
adaptedWidth:CVPixelBufferGetWidth(pixelBuffer)
adaptedHeight:CVPixelBufferGetHeight(pixelBuffer)
cropWidth:CVPixelBufferGetWidth(pixelBuffer)
cropHeight:CVPixelBufferGetHeight(pixelBuffer)
cropX:0
cropY:0];
}
- (instancetype)initWithPixelBuffer:(CVPixelBufferRef)pixelBuffer
adaptedWidth:(int)adaptedWidth
adaptedHeight:(int)adaptedHeight
cropWidth:(int)cropWidth
cropHeight:(int)cropHeight
cropX:(int)cropX
cropY:(int)cropY {
if (self = [super init]) {
_width = adaptedWidth;
_height = adaptedHeight;
_pixelBuffer = pixelBuffer;
_bufferWidth = CVPixelBufferGetWidth(_pixelBuffer);
_bufferHeight = CVPixelBufferGetHeight(_pixelBuffer);
_cropWidth = cropWidth;
_cropHeight = cropHeight;
// Can only crop at even pixels.
_cropX = cropX & ~1;
_cropY = cropY & ~1;
CVBufferRetain(_pixelBuffer);
}
return self;
}
- (void)dealloc {
CVBufferRelease(_pixelBuffer);
}
- (int)width {
return _width;
}
- (int)height {
return _height;
}
- (BOOL)requiresCropping {
return _cropWidth != _bufferWidth || _cropHeight != _bufferHeight;
}
- (BOOL)requiresScalingToWidth:(int)width height:(int)height {
return _cropWidth != width || _cropHeight != height;
}
- (int)bufferSizeForCroppingAndScalingToWidth:(int)width height:(int)height {
int srcChromaWidth = (_cropWidth + 1) / 2;
int srcChromaHeight = (_cropHeight + 1) / 2;
int dstChromaWidth = (width + 1) / 2;
int dstChromaHeight = (height + 1) / 2;
return srcChromaWidth * srcChromaHeight * 2 + dstChromaWidth * dstChromaHeight * 2;
}
- (BOOL)cropAndScaleTo:(CVPixelBufferRef)outputPixelBuffer withTempBuffer:(uint8_t*)tmpBuffer {
// Prepare output pointers.
RTC_DCHECK_EQ(CVPixelBufferGetPixelFormatType(outputPixelBuffer),
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
CVReturn cvRet = CVPixelBufferLockBaseAddress(outputPixelBuffer, 0);
if (cvRet != kCVReturnSuccess) {
LOG(LS_ERROR) << "Failed to lock base address: " << cvRet;
return NO;
}
const int dstWidth = CVPixelBufferGetWidth(outputPixelBuffer);
const int dstHeight = CVPixelBufferGetHeight(outputPixelBuffer);
uint8_t* dstY =
reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 0));
const int dstYStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 0);
uint8_t* dstUV =
reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 1));
const int dstUVStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 1);
// Prepare source pointers.
const OSType srcPixelFormat = CVPixelBufferGetPixelFormatType(_pixelBuffer);
RTC_DCHECK(srcPixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
srcPixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
CVPixelBufferLockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
const uint8_t* srcY =
static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
const int srcYStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 0);
const uint8_t* srcUV =
static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
const int srcUVStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 1);
// Crop just by modifying pointers.
srcY += srcYStride * _cropY + _cropX;
srcUV += srcUVStride * (_cropY / 2) + _cropX;
webrtc::NV12Scale(tmpBuffer,
srcY,
srcYStride,
srcUV,
srcUVStride,
_cropWidth,
_cropHeight,
dstY,
dstYStride,
dstUV,
dstUVStride,
dstWidth,
dstHeight);
CVPixelBufferUnlockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
CVPixelBufferUnlockBaseAddress(outputPixelBuffer, 0);
return YES;
}
- (id<RTCI420Buffer>)toI420 {
const OSType pixelFormat = CVPixelBufferGetPixelFormatType(_pixelBuffer);
RTC_DCHECK(pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
CVPixelBufferLockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
const uint8_t* srcY =
static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 0));
const int srcYStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 0);
const uint8_t* srcUV =
static_cast<const uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(_pixelBuffer, 1));
const int srcUVStride = CVPixelBufferGetBytesPerRowOfPlane(_pixelBuffer, 1);
// Crop just by modifying pointers.
srcY += srcYStride * _cropY + _cropX;
srcUV += srcUVStride * (_cropY / 2) + _cropX;
// TODO(magjed): Use a frame buffer pool.
webrtc::NV12ToI420Scaler nv12ToI420Scaler;
RTCMutableI420Buffer* i420Buffer =
[[RTCMutableI420Buffer alloc] initWithWidth:[self width] height:[self height]];
nv12ToI420Scaler.NV12ToI420Scale(srcY,
srcYStride,
srcUV,
srcUVStride,
_cropWidth,
_cropHeight,
i420Buffer.mutableDataY,
i420Buffer.strideY,
i420Buffer.mutableDataU,
i420Buffer.strideU,
i420Buffer.mutableDataV,
i420Buffer.strideV,
i420Buffer.width,
i420Buffer.height);
CVPixelBufferUnlockBaseAddress(_pixelBuffer, kCVPixelBufferLock_ReadOnly);
return i420Buffer;
}
@end

View File

@ -1,24 +0,0 @@
/*
* Copyright 2017 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.
*/
#import "WebRTC/RTCVideoFrameBuffer.h"
#include "webrtc/api/video/i420_buffer.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCI420Buffer ()
/** Initialize an RTCI420Buffer with its backing I420BufferInterface. */
- (instancetype)initWithFrameBuffer:(rtc::scoped_refptr<webrtc::I420BufferInterface>)i420Buffer;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,108 +0,0 @@
/*
* Copyright 2017 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.
*/
#import "WebRTC/RTCVideoFrameBuffer.h"
#include "webrtc/api/video/i420_buffer.h"
@implementation RTCI420Buffer {
@protected
rtc::scoped_refptr<webrtc::I420BufferInterface> _i420Buffer;
}
- (instancetype)initWithWidth:(int)width height:(int)height {
if (self = [super init]) {
_i420Buffer = webrtc::I420Buffer::Create(width, height);
}
return self;
}
- (instancetype)initWithWidth:(int)width
height:(int)height
strideY:(int)strideY
strideU:(int)strideU
strideV:(int)strideV {
if (self = [super init]) {
_i420Buffer = webrtc::I420Buffer::Create(width, height, strideY, strideU, strideV);
}
return self;
}
- (instancetype)initWithFrameBuffer:(rtc::scoped_refptr<webrtc::I420BufferInterface>)i420Buffer {
if (self = [super init]) {
_i420Buffer = i420Buffer;
}
return self;
}
- (int)width {
return _i420Buffer->width();
}
- (int)height {
return _i420Buffer->height();
}
- (int)strideY {
return _i420Buffer->StrideY();
}
- (int)strideU {
return _i420Buffer->StrideU();
}
- (int)strideV {
return _i420Buffer->StrideV();
}
- (int)chromaWidth {
return _i420Buffer->ChromaWidth();
}
- (int)chromaHeight {
return _i420Buffer->ChromaHeight();
}
- (const uint8_t *)dataY {
return _i420Buffer->DataY();
}
- (const uint8_t *)dataU {
return _i420Buffer->DataU();
}
- (const uint8_t *)dataV {
return _i420Buffer->DataV();
}
- (id<RTCI420Buffer>)toI420 {
return self;
}
@end
@implementation RTCMutableI420Buffer
- (uint8_t *)mutableDataY {
return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataY();
}
- (uint8_t *)mutableDataU {
return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataU();
}
- (uint8_t *)mutableDataV {
return static_cast<webrtc::I420Buffer *>(_i420Buffer.get())->MutableDataV();
}
@end

View File

@ -9,7 +9,6 @@
*/
#import "RTCI420TextureCache.h"
#import "WebRTC/RTCVideoFrameBuffer.h"
#if TARGET_OS_IPHONE
#import <OpenGLES/ES3/gl.h>
@ -124,32 +123,31 @@ static const GLsizei kNumTextures = kNumTexturesPerSet * kNumTextureSets;
- (void)uploadFrameToTextures:(RTCVideoFrame *)frame {
_currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
id<RTCI420Buffer> buffer = [frame.buffer toI420];
const int chromaWidth = buffer.chromaWidth;
const int chromaHeight = buffer.chromaHeight;
if (buffer.strideY != frame.width || buffer.strideU != chromaWidth ||
buffer.strideV != chromaWidth) {
_planeBuffer.resize(buffer.width * buffer.height);
const int chromaWidth = (frame.width + 1) / 2;
const int chromaHeight = (frame.height + 1) / 2;
if (frame.strideY != frame.width ||
frame.strideU != chromaWidth ||
frame.strideV != chromaWidth) {
_planeBuffer.resize(frame.width * frame.height);
}
[self uploadPlane:buffer.dataY
[self uploadPlane:frame.dataY
texture:self.yTexture
width:buffer.width
height:buffer.height
stride:buffer.strideY];
width:frame.width
height:frame.height
stride:frame.strideY];
[self uploadPlane:buffer.dataU
[self uploadPlane:frame.dataU
texture:self.uTexture
width:chromaWidth
height:chromaHeight
stride:buffer.strideU];
stride:frame.strideU];
[self uploadPlane:buffer.dataV
[self uploadPlane:frame.dataV
texture:self.vTexture
width:chromaWidth
height:chromaHeight
stride:buffer.strideV];
stride:frame.strideV];
}
@end

View File

@ -11,7 +11,6 @@
#import "RTCNV12TextureCache.h"
#import "WebRTC/RTCVideoFrame.h"
#import "WebRTC/RTCVideoFrameBuffer.h"
@implementation RTCNV12TextureCache {
CVOpenGLESTextureCacheRef _textureCache;
@ -74,10 +73,8 @@
}
- (BOOL)uploadFrameToTextures:(RTCVideoFrame *)frame {
NSAssert([frame.buffer isKindOfClass:[RTCCVPixelBuffer class]],
@"frame must be CVPixelBuffer backed");
RTCCVPixelBuffer *rtcPixelBuffer = (RTCCVPixelBuffer *)frame.buffer;
CVPixelBufferRef pixelBuffer = rtcPixelBuffer.pixelBuffer;
CVPixelBufferRef pixelBuffer = frame.nativeHandle;
NSParameterAssert(pixelBuffer);
return [self loadTexture:&_yTextureRef
pixelBuffer:pixelBuffer
planeIndex:0

View File

@ -15,7 +15,6 @@
#import "RTCAVFoundationVideoCapturerInternal.h"
#import "RTCDispatcher+Private.h"
#import "WebRTC/RTCLogging.h"
#import "WebRTC/RTCVideoFrameBuffer.h"
#include "avfoundationformatmapper.h"
@ -24,7 +23,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/thread.h"
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
#include "webrtc/sdk/objc/Framework/Classes/Video/corevideo_frame_buffer.h"
namespace webrtc {
@ -151,15 +150,12 @@ void AVFoundationVideoCapturer::CaptureSampleBuffer(
return;
}
RTCCVPixelBuffer* rtcPixelBuffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:image_buffer
adaptedWidth:adapted_width
adaptedHeight:adapted_height
cropWidth:crop_width
cropHeight:crop_height
cropX:crop_x
cropY:crop_y];
rtc::scoped_refptr<VideoFrameBuffer> buffer =
new rtc::RefCountedObject<ObjCFrameBuffer>(rtcPixelBuffer);
new rtc::RefCountedObject<CoreVideoFrameBuffer>(
image_buffer,
adapted_width, adapted_height,
crop_width, crop_height,
crop_x, crop_y);
// Applying rotation is only supported for legacy reasons and performance is
// not critical here.

View File

@ -1,44 +0,0 @@
/*
* Copyright 2017 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 WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_VIDEO_OBJC_FRAME_BUFFER_H_
#define WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_VIDEO_OBJC_FRAME_BUFFER_H_
#import <CoreVideo/CoreVideo.h>
#include "webrtc/common_video/include/video_frame_buffer.h"
@protocol RTCVideoFrameBuffer;
namespace webrtc {
class ObjCFrameBuffer : public VideoFrameBuffer {
public:
explicit ObjCFrameBuffer(id<RTCVideoFrameBuffer>);
~ObjCFrameBuffer() override;
Type type() const override;
int width() const override;
int height() const override;
rtc::scoped_refptr<I420BufferInterface> ToI420() override;
id<RTCVideoFrameBuffer> wrapped_frame_buffer() const;
private:
id<RTCVideoFrameBuffer> frame_buffer_;
int width_;
int height_;
};
} // namespace webrtc
#endif // WEBRTC_SDK_OBJC_FRAMEWORK_CLASSES_VIDEO_OBJC_FRAME_BUFFER_H_

View File

@ -1,78 +0,0 @@
/*
* Copyright 2017 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 "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
#import "WebRTC/RTCVideoFrameBuffer.h"
namespace webrtc {
namespace {
/** ObjCFrameBuffer that conforms to I420BufferInterface by wrapping RTCI420Buffer */
class ObjCI420FrameBuffer : public I420BufferInterface {
public:
explicit ObjCI420FrameBuffer(id<RTCI420Buffer> frame_buffer)
: frame_buffer_(frame_buffer), width_(frame_buffer.width), height_(frame_buffer.height) {}
~ObjCI420FrameBuffer() override{};
int width() const override { return width_; }
int height() const override { return height_; }
const uint8_t* DataY() const override { return frame_buffer_.dataY; }
const uint8_t* DataU() const override { return frame_buffer_.dataU; }
const uint8_t* DataV() const override { return frame_buffer_.dataV; }
int StrideY() const override { return frame_buffer_.strideY; }
int StrideU() const override { return frame_buffer_.strideU; }
int StrideV() const override { return frame_buffer_.strideV; }
private:
id<RTCI420Buffer> frame_buffer_;
int width_;
int height_;
};
} // namespace
ObjCFrameBuffer::ObjCFrameBuffer(id<RTCVideoFrameBuffer> frame_buffer)
: frame_buffer_(frame_buffer), width_(frame_buffer.width), height_(frame_buffer.height) {}
ObjCFrameBuffer::~ObjCFrameBuffer() {}
VideoFrameBuffer::Type ObjCFrameBuffer::type() const {
return Type::kNative;
}
int ObjCFrameBuffer::width() const {
return width_;
}
int ObjCFrameBuffer::height() const {
return height_;
}
rtc::scoped_refptr<I420BufferInterface> ObjCFrameBuffer::ToI420() {
rtc::scoped_refptr<I420BufferInterface> buffer =
new rtc::RefCountedObject<ObjCI420FrameBuffer>([frame_buffer_ toI420]);
return buffer;
}
id<RTCVideoFrameBuffer> ObjCFrameBuffer::wrapped_frame_buffer() const {
return frame_buffer_;
}
} // namespace webrtc

View File

@ -10,11 +10,10 @@
#include "webrtc/sdk/objc/Framework/Classes/Video/objcvideotracksource.h"
#import "WebRTC/RTCVideoFrame.h"
#import "WebRTC/RTCVideoFrameBuffer.h"
#import "RTCVideoFrame+Private.h"
#include "webrtc/api/video/i420_buffer.h"
#include "webrtc/sdk/objc/Framework/Classes/Video/objc_frame_buffer.h"
#include "webrtc/sdk/objc/Framework/Classes/Video/corevideo_frame_buffer.h"
namespace webrtc {
@ -44,24 +43,18 @@ void ObjcVideoTrackSource::OnCapturedFrame(RTCVideoFrame* frame) {
rtc::scoped_refptr<VideoFrameBuffer> buffer;
if (adapted_width == frame.width && adapted_height == frame.height) {
// No adaption - optimized path.
buffer = new rtc::RefCountedObject<ObjCFrameBuffer>(frame.buffer);
} else if ([frame.buffer isKindOfClass:[RTCCVPixelBuffer class]]) {
buffer = frame.videoBuffer;
} else if (frame.nativeHandle) {
// Adapted CVPixelBuffer frame.
RTCCVPixelBuffer *rtcPixelBuffer = (RTCCVPixelBuffer *)frame.buffer;
buffer = new rtc::RefCountedObject<ObjCFrameBuffer>([[RTCCVPixelBuffer alloc]
initWithPixelBuffer:rtcPixelBuffer.pixelBuffer
adaptedWidth:adapted_width
adaptedHeight:adapted_height
cropWidth:crop_width
cropHeight:crop_height
cropX:crop_x
cropY:crop_y]);
buffer = new rtc::RefCountedObject<CoreVideoFrameBuffer>(
static_cast<CVPixelBufferRef>(frame.nativeHandle), adapted_width, adapted_height,
crop_width, crop_height, crop_x, crop_y);
} else {
// Adapted I420 frame.
// TODO(magjed): Optimize this I420 path.
rtc::scoped_refptr<I420Buffer> i420_buffer = I420Buffer::Create(adapted_width, adapted_height);
buffer = new rtc::RefCountedObject<ObjCFrameBuffer>(frame.buffer);
i420_buffer->CropAndScaleFrom(*buffer->ToI420(), crop_x, crop_y, crop_width, crop_height);
i420_buffer->CropAndScaleFrom(
*frame.videoBuffer->ToI420(), crop_x, crop_y, crop_width, crop_height);
buffer = i420_buffer;
}