webrtc/modules/video_coding/codecs/i420/i420.cc
Niels Möller 2377588c82 Add accessor methods for RTP timestamp of EncodedImage.
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}
2018-08-21 09:15:51 +00:00

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