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 18namespace { 19const size_t kI420HeaderSize = 4; 20} 21 22namespace webrtc { 23 24I420Encoder::I420Encoder() 25 : _inited(false), _encodedImage(), _encodedCompleteCallback(NULL) {} 26 27I420Encoder::~I420Encoder() { 28 _inited = false; 29 delete[] _encodedImage._buffer; 30} 31 32int 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 43int 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 74int 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 123uint8_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 133int I420Encoder::RegisterEncodeCompleteCallback( 134 EncodedImageCallback* callback) { 135 _encodedCompleteCallback = callback; 136 return WEBRTC_VIDEO_CODEC_OK; 137} 138 139I420Decoder::I420Decoder() 140 : _decodedImage(), 141 _width(0), 142 _height(0), 143 _inited(false), 144 _decodeCompleteCallback(NULL) {} 145 146I420Decoder::~I420Decoder() { 147 Release(); 148} 149 150int I420Decoder::Reset() { 151 return WEBRTC_VIDEO_CODEC_OK; 152} 153 154int 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 167int 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 220const 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 231int I420Decoder::RegisterDecodeCompleteCallback( 232 DecodedImageCallback* callback) { 233 _decodeCompleteCallback = callback; 234 return WEBRTC_VIDEO_CODEC_OK; 235} 236 237int I420Decoder::Release() { 238 _inited = false; 239 return WEBRTC_VIDEO_CODEC_OK; 240} 241} // namespace webrtc 242