| OLD | NEW |
| (Empty) |
| 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 | |
| 24 I420Encoder::I420Encoder() | |
| 25 : _inited(false), _encodedImage(), _encodedCompleteCallback(NULL) {} | |
| 26 | |
| 27 I420Encoder::~I420Encoder() { | |
| 28 _inited = false; | |
| 29 delete[] _encodedImage._buffer; | |
| 30 } | |
| 31 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 133 int I420Encoder::RegisterEncodeCompleteCallback( | |
| 134 EncodedImageCallback* callback) { | |
| 135 _encodedCompleteCallback = callback; | |
| 136 return WEBRTC_VIDEO_CODEC_OK; | |
| 137 } | |
| 138 | |
| 139 I420Decoder::I420Decoder() | |
| 140 : _decodedImage(), | |
| 141 _width(0), | |
| 142 _height(0), | |
| 143 _inited(false), | |
| 144 _decodeCompleteCallback(NULL) {} | |
| 145 | |
| 146 I420Decoder::~I420Decoder() { | |
| 147 Release(); | |
| 148 } | |
| 149 | |
| 150 int I420Decoder::InitDecode(const VideoCodec* codecSettings, | |
| 151 int /*numberOfCores */) { | |
| 152 if (codecSettings == NULL) { | |
| 153 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 154 } else if (codecSettings->width < 1 || codecSettings->height < 1) { | |
| 155 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 156 } | |
| 157 _width = codecSettings->width; | |
| 158 _height = codecSettings->height; | |
| 159 _inited = true; | |
| 160 return WEBRTC_VIDEO_CODEC_OK; | |
| 161 } | |
| 162 | |
| 163 int I420Decoder::Decode(const EncodedImage& inputImage, | |
| 164 bool /*missingFrames*/, | |
| 165 const RTPFragmentationHeader* /*fragmentation*/, | |
| 166 const CodecSpecificInfo* /*codecSpecificInfo*/, | |
| 167 int64_t /*renderTimeMs*/) { | |
| 168 if (inputImage._buffer == NULL) { | |
| 169 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 170 } | |
| 171 if (_decodeCompleteCallback == NULL) { | |
| 172 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
| 173 } | |
| 174 if (inputImage._length <= 0) { | |
| 175 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 176 } | |
| 177 if (inputImage._completeFrame == false) { | |
| 178 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 179 } | |
| 180 if (!_inited) { | |
| 181 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
| 182 } | |
| 183 if (inputImage._length < kI420HeaderSize) { | |
| 184 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 185 } | |
| 186 | |
| 187 const uint8_t* buffer = inputImage._buffer; | |
| 188 uint16_t width, height; | |
| 189 | |
| 190 buffer = ExtractHeader(buffer, &width, &height); | |
| 191 _width = width; | |
| 192 _height = height; | |
| 193 | |
| 194 // Verify that the available length is sufficient: | |
| 195 size_t req_length = CalcBufferSize(kI420, _width, _height) + kI420HeaderSize; | |
| 196 | |
| 197 if (req_length > inputImage._length) { | |
| 198 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 199 } | |
| 200 // Set decoded image parameters. | |
| 201 int half_width = (_width + 1) / 2; | |
| 202 _decodedImage.CreateEmptyFrame(_width, _height, _width, half_width, | |
| 203 half_width); | |
| 204 // Converting from buffer to plane representation. | |
| 205 int ret = ConvertToI420(kI420, buffer, 0, 0, _width, _height, 0, | |
| 206 kVideoRotation_0, &_decodedImage); | |
| 207 if (ret < 0) { | |
| 208 return WEBRTC_VIDEO_CODEC_MEMORY; | |
| 209 } | |
| 210 _decodedImage.set_timestamp(inputImage._timeStamp); | |
| 211 | |
| 212 _decodeCompleteCallback->Decoded(_decodedImage); | |
| 213 return WEBRTC_VIDEO_CODEC_OK; | |
| 214 } | |
| 215 | |
| 216 const uint8_t* I420Decoder::ExtractHeader(const uint8_t* buffer, | |
| 217 uint16_t* width, | |
| 218 uint16_t* height) { | |
| 219 *width = static_cast<uint16_t>(*buffer++) << 8; | |
| 220 *width |= *buffer++; | |
| 221 *height = static_cast<uint16_t>(*buffer++) << 8; | |
| 222 *height |= *buffer++; | |
| 223 | |
| 224 return buffer; | |
| 225 } | |
| 226 | |
| 227 int I420Decoder::RegisterDecodeCompleteCallback( | |
| 228 DecodedImageCallback* callback) { | |
| 229 _decodeCompleteCallback = callback; | |
| 230 return WEBRTC_VIDEO_CODEC_OK; | |
| 231 } | |
| 232 | |
| 233 int I420Decoder::Release() { | |
| 234 _inited = false; | |
| 235 return WEBRTC_VIDEO_CODEC_OK; | |
| 236 } | |
| 237 } // namespace webrtc | |
| OLD | NEW |