webrtc/api/video/video_frame_buffer.cc
Henrik Boström f412976eca Provide a default implementation of NV12BufferInterface::CropAndScale.
This avoids falling back on the VideoFrameBuffer::CropAndScale default
implementation which performs ToI420. This has two major benefits:
1. We save CPU by not converting to I420 for NV12 frames.
2. We make is possible for simulcast encoders to use Scale() and be
   able to trust that the scaled simulcast layers have the same pixel
   format as the top layer, which is required by libvpx.

In order to invoke NV12Buffer::CropAndScaleFrom() without introducing a
circular dependency, nv12_buffer.[h/cc] is moved to the "video_frame"
build target.

Bug: webrtc:12595, webrtc:12469
Change-Id: I81aac5c6b3e81c49f32a7be6dc2640e6b40f7692
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/212643
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33521}
2021-03-22 11:09:36 +00:00

157 lines
4.1 KiB
C++

/*
* Copyright (c) 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 "api/video/video_frame_buffer.h"
#include "api/video/i420_buffer.h"
#include "api/video/nv12_buffer.h"
#include "rtc_base/checks.h"
namespace webrtc {
rtc::scoped_refptr<VideoFrameBuffer> VideoFrameBuffer::CropAndScale(
int offset_x,
int offset_y,
int crop_width,
int crop_height,
int scaled_width,
int scaled_height) {
rtc::scoped_refptr<I420Buffer> result =
I420Buffer::Create(scaled_width, scaled_height);
result->CropAndScaleFrom(*this->ToI420(), offset_x, offset_y, crop_width,
crop_height);
return result;
}
const I420BufferInterface* VideoFrameBuffer::GetI420() const {
// Overridden by subclasses that can return an I420 buffer without any
// conversion, in particular, I420BufferInterface.
return nullptr;
}
const I420ABufferInterface* VideoFrameBuffer::GetI420A() const {
RTC_CHECK(type() == Type::kI420A);
return static_cast<const I420ABufferInterface*>(this);
}
const I444BufferInterface* VideoFrameBuffer::GetI444() const {
RTC_CHECK(type() == Type::kI444);
return static_cast<const I444BufferInterface*>(this);
}
const I010BufferInterface* VideoFrameBuffer::GetI010() const {
RTC_CHECK(type() == Type::kI010);
return static_cast<const I010BufferInterface*>(this);
}
const NV12BufferInterface* VideoFrameBuffer::GetNV12() const {
RTC_CHECK(type() == Type::kNV12);
return static_cast<const NV12BufferInterface*>(this);
}
rtc::scoped_refptr<VideoFrameBuffer> VideoFrameBuffer::GetMappedFrameBuffer(
rtc::ArrayView<Type> types) {
RTC_CHECK(type() == Type::kNative);
return nullptr;
}
VideoFrameBuffer::Type I420BufferInterface::type() const {
return Type::kI420;
}
const char* VideoFrameBufferTypeToString(VideoFrameBuffer::Type type) {
switch (type) {
case VideoFrameBuffer::Type::kNative:
return "kNative";
case VideoFrameBuffer::Type::kI420:
return "kI420";
case VideoFrameBuffer::Type::kI420A:
return "kI420A";
case VideoFrameBuffer::Type::kI444:
return "kI444";
case VideoFrameBuffer::Type::kI010:
return "kI010";
case VideoFrameBuffer::Type::kNV12:
return "kNV12";
default:
RTC_NOTREACHED();
}
}
int I420BufferInterface::ChromaWidth() const {
return (width() + 1) / 2;
}
int I420BufferInterface::ChromaHeight() const {
return (height() + 1) / 2;
}
rtc::scoped_refptr<I420BufferInterface> I420BufferInterface::ToI420() {
return this;
}
const I420BufferInterface* I420BufferInterface::GetI420() const {
return this;
}
VideoFrameBuffer::Type I420ABufferInterface::type() const {
return Type::kI420A;
}
VideoFrameBuffer::Type I444BufferInterface::type() const {
return Type::kI444;
}
int I444BufferInterface::ChromaWidth() const {
return width();
}
int I444BufferInterface::ChromaHeight() const {
return height();
}
VideoFrameBuffer::Type I010BufferInterface::type() const {
return Type::kI010;
}
int I010BufferInterface::ChromaWidth() const {
return (width() + 1) / 2;
}
int I010BufferInterface::ChromaHeight() const {
return (height() + 1) / 2;
}
VideoFrameBuffer::Type NV12BufferInterface::type() const {
return Type::kNV12;
}
int NV12BufferInterface::ChromaWidth() const {
return (width() + 1) / 2;
}
int NV12BufferInterface::ChromaHeight() const {
return (height() + 1) / 2;
}
rtc::scoped_refptr<VideoFrameBuffer> NV12BufferInterface::CropAndScale(
int offset_x,
int offset_y,
int crop_width,
int crop_height,
int scaled_width,
int scaled_height) {
rtc::scoped_refptr<NV12Buffer> result =
NV12Buffer::Create(scaled_width, scaled_height);
result->CropAndScaleFrom(*this, offset_x, offset_y, crop_width, crop_height);
return result;
}
} // namespace webrtc