Home | History | Annotate | Download | only in source
      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