blob: cf546a07a1bb9e03508d8c19c3e35e7cbfa73416 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgfdf21c82012-02-02 12:46:58 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Henrik Kjellandera74c08d2015-10-22 12:23:11 +020011#include "webrtc/modules/video_coding/codecs/i420/include/i420.h"
mikhal@webrtc.org538f0ab2012-07-11 18:20:39 +000012
pbos@webrtc.org8911ce42013-03-18 16:39:03 +000013#include <limits>
pbos@webrtc.orga4407322013-07-16 12:32:05 +000014#include <string>
niklase@google.com470e71d2011-07-07 08:21:25 +000015
pbos@webrtc.orga4407322013-07-16 12:32:05 +000016#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
mikhal@webrtc.org538f0ab2012-07-11 18:20:39 +000017
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000018namespace {
19const size_t kI420HeaderSize = 4;
20}
21
pbos@webrtc.org8911ce42013-03-18 16:39:03 +000022namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000023
pbos@webrtc.org8911ce42013-03-18 16:39:03 +000024I420Encoder::I420Encoder() : _inited(false), _encodedImage(),
25 _encodedCompleteCallback(NULL) {
26}
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +000027
28I420Encoder::~I420Encoder() {
29 _inited = false;
pbos@webrtc.org8911ce42013-03-18 16:39:03 +000030 delete [] _encodedImage._buffer;
niklase@google.com470e71d2011-07-07 08:21:25 +000031}
32
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +000033int I420Encoder::Release() {
34 // Should allocate an encoded frame and then release it here, for that we
35 // actually need an init flag.
36 if (_encodedImage._buffer != NULL) {
37 delete [] _encodedImage._buffer;
38 _encodedImage._buffer = NULL;
39 }
40 _inited = false;
41 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +000042}
43
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +000044int I420Encoder::InitEncode(const VideoCodec* codecSettings,
mikhal@webrtc.orga2031d52012-07-31 15:53:44 +000045 int /*numberOfCores*/,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000046 size_t /*maxPayloadSize */) {
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +000047 if (codecSettings == NULL) {
48 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
49 }
50 if (codecSettings->width < 1 || codecSettings->height < 1) {
51 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
52 }
53
54 // Allocating encoded memory.
55 if (_encodedImage._buffer != NULL) {
56 delete [] _encodedImage._buffer;
57 _encodedImage._buffer = NULL;
58 _encodedImage._size = 0;
59 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000060 const size_t newSize =
61 CalcBufferSize(kI420, codecSettings->width, codecSettings->height) +
62 kI420HeaderSize;
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +000063 uint8_t* newBuffer = new uint8_t[newSize];
64 if (newBuffer == NULL) {
65 return WEBRTC_VIDEO_CODEC_MEMORY;
66 }
67 _encodedImage._size = newSize;
68 _encodedImage._buffer = newBuffer;
69
70 // If no memory allocation, no point to init.
71 _inited = true;
72 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +000073}
74
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070075int I420Encoder::Encode(const VideoFrame& inputImage,
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000076 const CodecSpecificInfo* /*codecSpecificInfo*/,
pbos22993e12015-10-19 02:39:06 -070077 const std::vector<FrameType>* /*frame_types*/) {
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +000078 if (!_inited) {
79 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
80 }
81 if (_encodedCompleteCallback == NULL) {
82 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
83 }
84
Peter Boström49e196a2015-10-23 15:58:18 +020085 _encodedImage._frameType = kVideoFrameKey;
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000086 _encodedImage._timeStamp = inputImage.timestamp();
87 _encodedImage._encodedHeight = inputImage.height();
88 _encodedImage._encodedWidth = inputImage.width();
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +000089
pbos@webrtc.org8911ce42013-03-18 16:39:03 +000090 int width = inputImage.width();
91 if (width > std::numeric_limits<uint16_t>::max()) {
92 return WEBRTC_VIDEO_CODEC_ERR_SIZE;
93 }
94 int height = inputImage.height();
95 if (height > std::numeric_limits<uint16_t>::max()) {
96 return WEBRTC_VIDEO_CODEC_ERR_SIZE;
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +000097 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +000098
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000099 size_t req_length =
100 CalcBufferSize(kI420, inputImage.width(), inputImage.height()) +
101 kI420HeaderSize;
102 if (_encodedImage._size > req_length) {
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000103 // Reallocate buffer.
104 delete [] _encodedImage._buffer;
105
106 _encodedImage._buffer = new uint8_t[req_length];
107 _encodedImage._size = req_length;
108 }
109
110 uint8_t *buffer = _encodedImage._buffer;
111
112 buffer = InsertHeader(buffer, width, height);
113
114 int ret_length = ExtractBuffer(inputImage, req_length - kI420HeaderSize,
115 buffer);
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000116 if (ret_length < 0)
117 return WEBRTC_VIDEO_CODEC_MEMORY;
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000118 _encodedImage._length = ret_length + kI420HeaderSize;
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000119
changbin.shao@webrtc.orgf31f56d2015-02-09 09:14:03 +0000120 _encodedCompleteCallback->Encoded(_encodedImage, NULL, NULL);
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000121 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +0000122}
123
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000124uint8_t* I420Encoder::InsertHeader(uint8_t *buffer, uint16_t width,
125 uint16_t height) {
126 *buffer++ = static_cast<uint8_t>(width >> 8);
127 *buffer++ = static_cast<uint8_t>(width & 0xFF);
128 *buffer++ = static_cast<uint8_t>(height >> 8);
129 *buffer++ = static_cast<uint8_t>(height & 0xFF);
130 return buffer;
131}
niklase@google.com470e71d2011-07-07 08:21:25 +0000132
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000133int
134I420Encoder::RegisterEncodeCompleteCallback(EncodedImageCallback* callback) {
135 _encodedCompleteCallback = callback;
136 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +0000137}
138
139
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000140I420Decoder::I420Decoder() : _decodedImage(), _width(0), _height(0),
141 _inited(false), _decodeCompleteCallback(NULL) {
142}
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000143
144I420Decoder::~I420Decoder() {
145 Release();
niklase@google.com470e71d2011-07-07 08:21:25 +0000146}
147
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000148int
149I420Decoder::Reset() {
150 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151}
152
153
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000154int
155I420Decoder::InitDecode(const VideoCodec* codecSettings,
156 int /*numberOfCores */) {
157 if (codecSettings == NULL) {
158 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
159 } else if (codecSettings->width < 1 || codecSettings->height < 1) {
160 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
161 }
162 _width = codecSettings->width;
163 _height = codecSettings->height;
164 _inited = true;
165 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +0000166}
167
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000168int I420Decoder::Decode(const EncodedImage& inputImage, bool /*missingFrames*/,
169 const RTPFragmentationHeader* /*fragmentation*/,
170 const CodecSpecificInfo* /*codecSpecificInfo*/,
171 int64_t /*renderTimeMs*/) {
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000172 if (inputImage._buffer == NULL) {
173 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
174 }
175 if (_decodeCompleteCallback == NULL) {
176 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
177 }
178 if (inputImage._length <= 0) {
179 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
180 }
mikhal@webrtc.org9e9cc722012-11-14 17:56:46 +0000181 if (inputImage._completeFrame == false) {
182 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
183 }
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000184 if (!_inited) {
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000185 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000186 }
pbos@webrtc.org86850902013-03-19 11:39:03 +0000187 if (inputImage._length < kI420HeaderSize) {
188 return WEBRTC_VIDEO_CODEC_ERROR;
189 }
190
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000191 const uint8_t* buffer = inputImage._buffer;
192 uint16_t width, height;
193
194 buffer = ExtractHeader(buffer, &width, &height);
195 _width = width;
196 _height = height;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197
mikhal@webrtc.org9e9cc722012-11-14 17:56:46 +0000198 // Verify that the available length is sufficient:
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000199 size_t req_length = CalcBufferSize(kI420, _width, _height) + kI420HeaderSize;
pbos@webrtc.org86850902013-03-19 11:39:03 +0000200
201 if (req_length > inputImage._length) {
mikhal@webrtc.org9e9cc722012-11-14 17:56:46 +0000202 return WEBRTC_VIDEO_CODEC_ERROR;
203 }
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000204 // Set decoded image parameters.
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000205 int half_width = (_width + 1) / 2;
mikhal@webrtc.org658d4232013-01-08 19:19:59 +0000206 _decodedImage.CreateEmptyFrame(_width, _height,
207 _width, half_width, half_width);
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000208 // Converting from buffer to plane representation.
guoweis@webrtc.org59140d62015-03-09 17:07:31 +0000209 int ret = ConvertToI420(kI420, buffer, 0, 0, _width, _height, 0,
210 kVideoRotation_0, &_decodedImage);
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000211 if (ret < 0) {
mikhal@webrtc.orga2031d52012-07-31 15:53:44 +0000212 return WEBRTC_VIDEO_CODEC_MEMORY;
213 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000214 _decodedImage.set_timestamp(inputImage._timeStamp);
niklase@google.com470e71d2011-07-07 08:21:25 +0000215
magjed@webrtc.org2056ee32015-03-16 13:46:52 +0000216 _decodeCompleteCallback->Decoded(_decodedImage);
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000217 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +0000218}
219
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000220const uint8_t* I420Decoder::ExtractHeader(const uint8_t* buffer,
221 uint16_t* width, uint16_t* height) {
222 *width = static_cast<uint16_t>(*buffer++) << 8;
223 *width |= *buffer++;
224 *height = static_cast<uint16_t>(*buffer++) << 8;
225 *height |= *buffer++;
226
227 return buffer;
228}
229
230int I420Decoder::RegisterDecodeCompleteCallback(
231 DecodedImageCallback* callback) {
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000232 _decodeCompleteCallback = callback;
233 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +0000234}
235
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000236int I420Decoder::Release() {
mikhal@webrtc.orgb95e9ca2012-07-10 20:58:08 +0000237 _inited = false;
238 return WEBRTC_VIDEO_CODEC_OK;
niklase@google.com470e71d2011-07-07 08:21:25 +0000239}
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000240} // namespace webrtc