Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

250 lines
7.6 KiB
C++
Raw Normal View History

/*
* 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 "modules/video_coding/codecs/i420/include/i420.h"
#include <limits>
#include <string>
#include "api/video/i420_buffer.h"
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "libyuv.h" // NOLINT
namespace {
const size_t kI420HeaderSize = 4;
}
namespace webrtc {
I420Encoder::I420Encoder()
: _inited(false), _encodedImage(), _encodedCompleteCallback(NULL) {}
I420Encoder::~I420Encoder() {
_inited = false;
delete[] _encodedImage._buffer;
}
int I420Encoder::Release() {
// Should allocate an encoded frame and then release it here, for that we
// actually need an init flag.
if (_encodedImage._buffer != NULL) {
delete[] _encodedImage._buffer;
_encodedImage._buffer = NULL;
}
_inited = false;
return WEBRTC_VIDEO_CODEC_OK;
}
int I420Encoder::InitEncode(const VideoCodec* codecSettings,
int /*numberOfCores*/,
size_t /*maxPayloadSize */) {
if (codecSettings == NULL) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (codecSettings->width < 1 || codecSettings->height < 1) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
// Allocating encoded memory.
if (_encodedImage._buffer != NULL) {
delete[] _encodedImage._buffer;
_encodedImage._buffer = NULL;
_encodedImage._size = 0;
}
const size_t newSize = CalcBufferSize(VideoType::kI420, codecSettings->width,
codecSettings->height) +
kI420HeaderSize;
uint8_t* newBuffer = new uint8_t[newSize];
if (newBuffer == NULL) {
return WEBRTC_VIDEO_CODEC_MEMORY;
}
_encodedImage._size = newSize;
_encodedImage._buffer = newBuffer;
// If no memory allocation, no point to init.
_inited = true;
return WEBRTC_VIDEO_CODEC_OK;
}
int I420Encoder::Encode(const VideoFrame& inputImage,
const CodecSpecificInfo* /*codecSpecificInfo*/,
const std::vector<FrameType>* /*frame_types*/) {
if (!_inited) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (_encodedCompleteCallback == NULL) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
_encodedImage._frameType = kVideoFrameKey;
_encodedImage._timeStamp = inputImage.timestamp();
_encodedImage._encodedHeight = inputImage.height();
_encodedImage._encodedWidth = inputImage.width();
int width = inputImage.width();
if (width > std::numeric_limits<uint16_t>::max()) {
return WEBRTC_VIDEO_CODEC_ERR_SIZE;
}
int height = inputImage.height();
if (height > std::numeric_limits<uint16_t>::max()) {
return WEBRTC_VIDEO_CODEC_ERR_SIZE;
}
size_t req_length = CalcBufferSize(VideoType::kI420, inputImage.width(),
inputImage.height()) +
kI420HeaderSize;
if (_encodedImage._size > req_length) {
// Reallocate buffer.
delete[] _encodedImage._buffer;
_encodedImage._buffer = new uint8_t[req_length];
_encodedImage._size = req_length;
}
uint8_t* buffer = _encodedImage._buffer;
buffer = InsertHeader(buffer, width, height);
int ret_length =
ExtractBuffer(inputImage, req_length - kI420HeaderSize, buffer);
if (ret_length < 0)
return WEBRTC_VIDEO_CODEC_MEMORY;
_encodedImage._length = ret_length + kI420HeaderSize;
_encodedCompleteCallback->OnEncodedImage(_encodedImage, nullptr, nullptr);
return WEBRTC_VIDEO_CODEC_OK;
}
uint8_t* I420Encoder::InsertHeader(uint8_t* buffer,
uint16_t width,
uint16_t height) {
*buffer++ = static_cast<uint8_t>(width >> 8);
*buffer++ = static_cast<uint8_t>(width & 0xFF);
*buffer++ = static_cast<uint8_t>(height >> 8);
*buffer++ = static_cast<uint8_t>(height & 0xFF);
return buffer;
}
int I420Encoder::RegisterEncodeCompleteCallback(
EncodedImageCallback* callback) {
_encodedCompleteCallback = callback;
return WEBRTC_VIDEO_CODEC_OK;
}
I420Decoder::I420Decoder()
: _width(0),
_height(0),
_inited(false),
_decodeCompleteCallback(NULL) {}
I420Decoder::~I420Decoder() {
Release();
}
int I420Decoder::InitDecode(const VideoCodec* codecSettings,
int /*numberOfCores */) {
if (codecSettings == NULL) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
} else if (codecSettings->width < 1 || codecSettings->height < 1) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
_width = codecSettings->width;
_height = codecSettings->height;
_inited = true;
return WEBRTC_VIDEO_CODEC_OK;
}
int I420Decoder::Decode(const EncodedImage& inputImage,
bool /*missingFrames*/,
const RTPFragmentationHeader* /*fragmentation*/,
const CodecSpecificInfo* /*codecSpecificInfo*/,
int64_t /*renderTimeMs*/) {
if (inputImage._buffer == NULL) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (_decodeCompleteCallback == NULL) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (inputImage._length <= 0) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (inputImage._completeFrame == false) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (!_inited) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (inputImage._length < kI420HeaderSize) {
return WEBRTC_VIDEO_CODEC_ERROR;
}
const uint8_t* buffer = inputImage._buffer;
uint16_t width, height;
buffer = ExtractHeader(buffer, &width, &height);
_width = width;
_height = height;
// Verify that the available length is sufficient:
size_t req_length =
CalcBufferSize(VideoType::kI420, _width, _height) + kI420HeaderSize;
if (req_length > inputImage._length) {
return WEBRTC_VIDEO_CODEC_ERROR;
}
// Set decoded image parameters.
rtc::scoped_refptr<webrtc::I420Buffer> frame_buffer =
Revert "Revert "Update video_coding/codecs to new VideoFrameBuffer interface"" This reverts commit 88f94fa36aa61f7904d30251205c544ada2c4301. Chromium code has been updated. Original change's description: > Revert "Update video_coding/codecs to new VideoFrameBuffer interface" > > This reverts commit 20ebf4ede803cd4f628ef9378700f60b72f2eab0. > > Reason for revert: > > Suspect of breaking FYI bots. > See https://build.chromium.org/p/chromium.webrtc.fyi/builders/Win7%20Tester/builds/9036 and others. > > Sample logs: > Backtrace: > [5024:1036:0607/173649.857:FATAL:webrtc_video_frame_adapter.cc(98)] Check failed: false. > Backtrace: > base::debug::StackTrace::StackTrace [0x02D04A37+55] > base::debug::StackTrace::StackTrace [0x02CCBB8A+10] > content::WebRtcVideoFrameAdapter::NativeToI420Buffer [0x0508AD71+305] > webrtc::VideoFrameBuffer::ToI420 [0x0230BF67+39] > webrtc::H264EncoderImpl::Encode [0x057E8D0B+267] > webrtc::VCMGenericEncoder::Encode [0x057E0E34+333] > webrtc::vcm::VideoSender::AddVideoFrame [0x057DED9B+796] > webrtc::ViEEncoder::EncodeVideoFrame [0x057C00F6+884] > webrtc::ViEEncoder::EncodeTask::Run [0x057C12D7+215] > rtc::TaskQueue::PostTask [0x03EE5CFB+194] > base::internal::Invoker<base::internal::BindState<enum extensions::`anonymous namespace'::VerificationResult (__cdecl*)(std::unique_ptr<extensions::NetworkingCastPrivateDelegate::Credentials,std::default_delete<extensions::NetworkingCastPrivateDelegate::C [0x02DDCAA5+31] > base::internal::Invoker<base::internal::BindState<enum extensions::`anonymous namespace'::VerificationResult (__cdecl*)(std::unique_ptr<extensions::NetworkingCastPrivateDelegate::Credentials,std::default_delete<extensions::NetworkingCastPrivateDelegate::C [0x02DDEE86+22] > base::debug::TaskAnnotator::RunTask [0x02D08289+409] > base::MessageLoop::RunTask [0x02C8CEC1+1233] > base::MessageLoop::DoWork [0x02C8C1AD+765] > base::MessagePumpDefault::Run [0x02D0A20B+219] > base::MessageLoop::Run [0x02C8C9DB+107] > base::RunLoop::Run [0x02C89583+147] > base::Thread::Run [0x02CBEFCD+173] > base::Thread::ThreadMain [0x02CBFADE+622] > base::PlatformThread::Sleep [0x02C9E1A2+290] > BaseThreadInitThunk [0x75C3338A+18] > RtlInitializeExceptionChain [0x773A9902+99] > RtlInitializeExceptionChain [0x773A98D5+54] > > Original change's description: > > Update video_coding/codecs to new VideoFrameBuffer interface > > > > This is a follow-up cleanup for CL > > https://codereview.webrtc.org/2847383002/. > > > > Bug: webrtc:7632 > > Change-Id: I47861d779968f2fee94db9c017102a8e87e67fb7 > > Reviewed-on: https://chromium-review.googlesource.com/524163 > > Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> > > Reviewed-by: Niels Moller <nisse@webrtc.org> > > Commit-Queue: Magnus Jedvert <magjed@webrtc.org> > > Cr-Commit-Position: refs/heads/master@{#18477} > > TBR=magjed@webrtc.org,nisse@webrtc.org,brandtr@webrtc.org > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: webrtc:7632 > > Change-Id: I3b73fc7d16ff19ceba196e964dcb36a36510912c > Reviewed-on: https://chromium-review.googlesource.com/527793 > Reviewed-by: Guido Urdaneta <guidou@chromium.org> > Commit-Queue: Guido Urdaneta <guidou@chromium.org> > Cr-Commit-Position: refs/heads/master@{#18489} TBR=tterriberry@mozilla.com,mflodman@webrtc.org,magjed@webrtc.org,stefan@webrtc.org,guidou@chromium.org,nisse@webrtc.org,brandtr@webrtc.org,webrtc-reviews@webrtc.org # Not skipping CQ checks because original CL landed > 1 day ago. No-Presubmit: true Bug: webrtc:7632 Change-Id: I0962a704e8a9939d4364ce9069c863c9951654c9 Reviewed-on: https://chromium-review.googlesource.com/530684 Commit-Queue: Magnus Jedvert <magjed@webrtc.org> Reviewed-by: Magnus Jedvert <magjed@webrtc.org> Cr-Commit-Position: refs/heads/master@{#18527}
2017-06-10 17:03:37 +00:00
I420Buffer::Create(_width, _height);
// Converting from raw buffer I420Buffer.
int y_stride = 16 * ((_width + 15) / 16);
int uv_stride = 16 * ((_width + 31) / 32);
int y_size = y_stride * height;
int u_size = uv_stride * frame_buffer->ChromaHeight();
int ret = libyuv::I420Copy(
buffer, y_stride, buffer + y_size, uv_stride, buffer + y_size + u_size,
uv_stride, frame_buffer.get()->MutableDataY(),
frame_buffer.get()->StrideY(), frame_buffer.get()->MutableDataU(),
frame_buffer.get()->StrideU(), frame_buffer.get()->MutableDataV(),
frame_buffer.get()->StrideV(), _width, _height);
if (ret < 0) {
return WEBRTC_VIDEO_CODEC_MEMORY;
}
VideoFrame decoded_image(frame_buffer, inputImage._timeStamp, 0,
webrtc::kVideoRotation_0);
_decodeCompleteCallback->Decoded(decoded_image);
return WEBRTC_VIDEO_CODEC_OK;
}
const uint8_t* I420Decoder::ExtractHeader(const uint8_t* buffer,
uint16_t* width,
uint16_t* height) {
*width = static_cast<uint16_t>(*buffer++) << 8;
*width |= *buffer++;
*height = static_cast<uint16_t>(*buffer++) << 8;
*height |= *buffer++;
return buffer;
}
int I420Decoder::RegisterDecodeCompleteCallback(
DecodedImageCallback* callback) {
_decodeCompleteCallback = callback;
return WEBRTC_VIDEO_CODEC_OK;
}
int I420Decoder::Release() {
_inited = false;
return WEBRTC_VIDEO_CODEC_OK;
}
} // namespace webrtc