Home | History | Annotate | Download | only in i420
      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::Reset() {
    151   return WEBRTC_VIDEO_CODEC_OK;
    152 }
    153 
    154 int 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 
    167 int 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 
    220 const 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 
    231 int I420Decoder::RegisterDecodeCompleteCallback(
    232     DecodedImageCallback* callback) {
    233   _decodeCompleteCallback = callback;
    234   return WEBRTC_VIDEO_CODEC_OK;
    235 }
    236 
    237 int I420Decoder::Release() {
    238   _inited = false;
    239   return WEBRTC_VIDEO_CODEC_OK;
    240 }
    241 }  // namespace webrtc
    242