mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 06:10:40 +01:00

Intention is to make the member private, but downstream callers must be updated to use the accessor methods first. Bug: webrtc:9378 Change-Id: I3495bd8d545b7234fbea10abfd14f082caa420b6 Reviewed-on: https://webrtc-review.googlesource.com/82160 Reviewed-by: Magnus Jedvert <magjed@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Philip Eliasson <philipel@webrtc.org> Commit-Queue: Niels Moller <nisse@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24352}
229 lines
7.1 KiB
C++
229 lines
7.1 KiB
C++
/*
|
|
* 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 "third_party/libyuv/include/libyuv.h"
|
|
|
|
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.SetTimestamp(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() : _decodeCompleteCallback(NULL) {}
|
|
|
|
I420Decoder::~I420Decoder() {
|
|
Release();
|
|
}
|
|
|
|
int I420Decoder::InitDecode(const VideoCodec* codecSettings,
|
|
int /*numberOfCores */) {
|
|
return WEBRTC_VIDEO_CODEC_OK;
|
|
}
|
|
|
|
int I420Decoder::Decode(const EncodedImage& inputImage,
|
|
bool /*missingFrames*/,
|
|
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 (inputImage._length < kI420HeaderSize) {
|
|
return WEBRTC_VIDEO_CODEC_ERROR;
|
|
}
|
|
|
|
const uint8_t* buffer = inputImage._buffer;
|
|
uint16_t width, height;
|
|
buffer = ExtractHeader(buffer, &width, &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 =
|
|
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() {
|
|
return WEBRTC_VIDEO_CODEC_OK;
|
|
}
|
|
} // namespace webrtc
|