• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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