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 20 I420Encoder::I420Encoder() : _inited(false), _encodedImage(), 21 _encodedCompleteCallback(NULL) { 22 } 23 24 I420Encoder::~I420Encoder() { 25 _inited = false; 26 delete [] _encodedImage._buffer; 27 } 28 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 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 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 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 132 I420Encoder::RegisterEncodeCompleteCallback(EncodedImageCallback* callback) { 133 _encodedCompleteCallback = callback; 134 return WEBRTC_VIDEO_CODEC_OK; 135 } 136 137 138 I420Decoder::I420Decoder() : _decodedImage(), _width(0), _height(0), 139 _inited(false), _decodeCompleteCallback(NULL) { 140 } 141 142 I420Decoder::~I420Decoder() { 143 Release(); 144 } 145 146 int 147 I420Decoder::Reset() { 148 return WEBRTC_VIDEO_CODEC_OK; 149 } 150 151 152 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 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 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 229 int I420Decoder::RegisterDecodeCompleteCallback( 230 DecodedImageCallback* callback) { 231 _decodeCompleteCallback = callback; 232 return WEBRTC_VIDEO_CODEC_OK; 233 } 234 235 int I420Decoder::Release() { 236 _inited = false; 237 return WEBRTC_VIDEO_CODEC_OK; 238 } 239 } // namespace webrtc 240