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