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