1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
11 #include "webrtc/modules/video_coding/codecs/i420/include/i420.h"
12
13 #include <limits>
14 #include <string>
15
16 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
17
18 namespace {
19 const size_t kI420HeaderSize = 4;
20 }
21
22 namespace webrtc {
23
I420Encoder()24 I420Encoder::I420Encoder()
25 : _inited(false), _encodedImage(), _encodedCompleteCallback(NULL) {}
26
~I420Encoder()27 I420Encoder::~I420Encoder() {
28 _inited = false;
29 delete[] _encodedImage._buffer;
30 }
31
Release()32 int I420Encoder::Release() {
33 // Should allocate an encoded frame and then release it here, for that we
34 // actually need an init flag.
35 if (_encodedImage._buffer != NULL) {
36 delete[] _encodedImage._buffer;
37 _encodedImage._buffer = NULL;
38 }
39 _inited = false;
40 return WEBRTC_VIDEO_CODEC_OK;
41 }
42
InitEncode(const VideoCodec * codecSettings,int,size_t)43 int I420Encoder::InitEncode(const VideoCodec* codecSettings,
44 int /*numberOfCores*/,
45 size_t /*maxPayloadSize */) {
46 if (codecSettings == NULL) {
47 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
48 }
49 if (codecSettings->width < 1 || codecSettings->height < 1) {
50 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
51 }
52
53 // Allocating encoded memory.
54 if (_encodedImage._buffer != NULL) {
55 delete[] _encodedImage._buffer;
56 _encodedImage._buffer = NULL;
57 _encodedImage._size = 0;
58 }
59 const size_t newSize =
60 CalcBufferSize(kI420, codecSettings->width, codecSettings->height) +
61 kI420HeaderSize;
62 uint8_t* newBuffer = new uint8_t[newSize];
63 if (newBuffer == NULL) {
64 return WEBRTC_VIDEO_CODEC_MEMORY;
65 }
66 _encodedImage._size = newSize;
67 _encodedImage._buffer = newBuffer;
68
69 // If no memory allocation, no point to init.
70 _inited = true;
71 return WEBRTC_VIDEO_CODEC_OK;
72 }
73
Encode(const VideoFrame & inputImage,const CodecSpecificInfo *,const std::vector<FrameType> *)74 int I420Encoder::Encode(const VideoFrame& inputImage,
75 const CodecSpecificInfo* /*codecSpecificInfo*/,
76 const std::vector<FrameType>* /*frame_types*/) {
77 if (!_inited) {
78 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
79 }
80 if (_encodedCompleteCallback == NULL) {
81 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
82 }
83
84 _encodedImage._frameType = kVideoFrameKey;
85 _encodedImage._timeStamp = inputImage.timestamp();
86 _encodedImage._encodedHeight = inputImage.height();
87 _encodedImage._encodedWidth = inputImage.width();
88
89 int width = inputImage.width();
90 if (width > std::numeric_limits<uint16_t>::max()) {
91 return WEBRTC_VIDEO_CODEC_ERR_SIZE;
92 }
93 int height = inputImage.height();
94 if (height > std::numeric_limits<uint16_t>::max()) {
95 return WEBRTC_VIDEO_CODEC_ERR_SIZE;
96 }
97
98 size_t req_length =
99 CalcBufferSize(kI420, inputImage.width(), inputImage.height()) +
100 kI420HeaderSize;
101 if (_encodedImage._size > req_length) {
102 // Reallocate buffer.
103 delete[] _encodedImage._buffer;
104
105 _encodedImage._buffer = new uint8_t[req_length];
106 _encodedImage._size = req_length;
107 }
108
109 uint8_t* buffer = _encodedImage._buffer;
110
111 buffer = InsertHeader(buffer, width, height);
112
113 int ret_length =
114 ExtractBuffer(inputImage, req_length - kI420HeaderSize, buffer);
115 if (ret_length < 0)
116 return WEBRTC_VIDEO_CODEC_MEMORY;
117 _encodedImage._length = ret_length + kI420HeaderSize;
118
119 _encodedCompleteCallback->Encoded(_encodedImage, NULL, NULL);
120 return WEBRTC_VIDEO_CODEC_OK;
121 }
122
InsertHeader(uint8_t * buffer,uint16_t width,uint16_t height)123 uint8_t* I420Encoder::InsertHeader(uint8_t* buffer,
124 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 }
132
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)133 int I420Encoder::RegisterEncodeCompleteCallback(
134 EncodedImageCallback* callback) {
135 _encodedCompleteCallback = callback;
136 return WEBRTC_VIDEO_CODEC_OK;
137 }
138
I420Decoder()139 I420Decoder::I420Decoder()
140 : _decodedImage(),
141 _width(0),
142 _height(0),
143 _inited(false),
144 _decodeCompleteCallback(NULL) {}
145
~I420Decoder()146 I420Decoder::~I420Decoder() {
147 Release();
148 }
149
Reset()150 int I420Decoder::Reset() {
151 return WEBRTC_VIDEO_CODEC_OK;
152 }
153
InitDecode(const VideoCodec * codecSettings,int)154 int I420Decoder::InitDecode(const VideoCodec* codecSettings,
155 int /*numberOfCores */) {
156 if (codecSettings == NULL) {
157 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
158 } else if (codecSettings->width < 1 || codecSettings->height < 1) {
159 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
160 }
161 _width = codecSettings->width;
162 _height = codecSettings->height;
163 _inited = true;
164 return WEBRTC_VIDEO_CODEC_OK;
165 }
166
Decode(const EncodedImage & inputImage,bool,const RTPFragmentationHeader *,const CodecSpecificInfo *,int64_t)167 int I420Decoder::Decode(const EncodedImage& inputImage,
168 bool /*missingFrames*/,
169 const RTPFragmentationHeader* /*fragmentation*/,
170 const CodecSpecificInfo* /*codecSpecificInfo*/,
171 int64_t /*renderTimeMs*/) {
172 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 }
181 if (inputImage._completeFrame == false) {
182 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
183 }
184 if (!_inited) {
185 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
186 }
187 if (inputImage._length < kI420HeaderSize) {
188 return WEBRTC_VIDEO_CODEC_ERROR;
189 }
190
191 const uint8_t* buffer = inputImage._buffer;
192 uint16_t width, height;
193
194 buffer = ExtractHeader(buffer, &width, &height);
195 _width = width;
196 _height = height;
197
198 // Verify that the available length is sufficient:
199 size_t req_length = CalcBufferSize(kI420, _width, _height) + kI420HeaderSize;
200
201 if (req_length > inputImage._length) {
202 return WEBRTC_VIDEO_CODEC_ERROR;
203 }
204 // Set decoded image parameters.
205 int half_width = (_width + 1) / 2;
206 _decodedImage.CreateEmptyFrame(_width, _height, _width, half_width,
207 half_width);
208 // Converting from buffer to plane representation.
209 int ret = ConvertToI420(kI420, buffer, 0, 0, _width, _height, 0,
210 kVideoRotation_0, &_decodedImage);
211 if (ret < 0) {
212 return WEBRTC_VIDEO_CODEC_MEMORY;
213 }
214 _decodedImage.set_timestamp(inputImage._timeStamp);
215
216 _decodeCompleteCallback->Decoded(_decodedImage);
217 return WEBRTC_VIDEO_CODEC_OK;
218 }
219
ExtractHeader(const uint8_t * buffer,uint16_t * width,uint16_t * height)220 const uint8_t* I420Decoder::ExtractHeader(const uint8_t* buffer,
221 uint16_t* width,
222 uint16_t* height) {
223 *width = static_cast<uint16_t>(*buffer++) << 8;
224 *width |= *buffer++;
225 *height = static_cast<uint16_t>(*buffer++) << 8;
226 *height |= *buffer++;
227
228 return buffer;
229 }
230
RegisterDecodeCompleteCallback(DecodedImageCallback * callback)231 int I420Decoder::RegisterDecodeCompleteCallback(
232 DecodedImageCallback* callback) {
233 _decodeCompleteCallback = callback;
234 return WEBRTC_VIDEO_CODEC_OK;
235 }
236
Release()237 int I420Decoder::Release() {
238 _inited = false;
239 return WEBRTC_VIDEO_CODEC_OK;
240 }
241 } // namespace webrtc
242