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/engine_configurations.h"
     12 #include "webrtc/modules/video_coding/main/source/encoded_frame.h"
     13 #include "webrtc/modules/video_coding/main/source/generic_encoder.h"
     14 #include "webrtc/modules/video_coding/main/source/media_optimization.h"
     15 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     16 #include "webrtc/system_wrappers/interface/logging.h"
     17 
     18 namespace webrtc {
     19 namespace {
     20 // Map information from info into rtp. If no relevant information is found
     21 // in info, rtp is set to NULL.
     22 void CopyCodecSpecific(const CodecSpecificInfo* info, RTPVideoHeader** rtp) {
     23   if (!info) {
     24     *rtp = NULL;
     25     return;
     26   }
     27   switch (info->codecType) {
     28     case kVideoCodecVP8: {
     29       (*rtp)->codec = kRtpVideoVp8;
     30       (*rtp)->codecHeader.VP8.InitRTPVideoHeaderVP8();
     31       (*rtp)->codecHeader.VP8.pictureId = info->codecSpecific.VP8.pictureId;
     32       (*rtp)->codecHeader.VP8.nonReference =
     33           info->codecSpecific.VP8.nonReference;
     34       (*rtp)->codecHeader.VP8.temporalIdx = info->codecSpecific.VP8.temporalIdx;
     35       (*rtp)->codecHeader.VP8.layerSync = info->codecSpecific.VP8.layerSync;
     36       (*rtp)->codecHeader.VP8.tl0PicIdx = info->codecSpecific.VP8.tl0PicIdx;
     37       (*rtp)->codecHeader.VP8.keyIdx = info->codecSpecific.VP8.keyIdx;
     38       (*rtp)->simulcastIdx = info->codecSpecific.VP8.simulcastIdx;
     39       return;
     40     }
     41     case kVideoCodecH264:
     42       (*rtp)->codec = kRtpVideoH264;
     43       return;
     44     case kVideoCodecGeneric:
     45       (*rtp)->codec = kRtpVideoGeneric;
     46       (*rtp)->simulcastIdx = info->codecSpecific.generic.simulcast_idx;
     47       return;
     48     default:
     49       // No codec specific info. Change RTP header pointer to NULL.
     50       *rtp = NULL;
     51       return;
     52   }
     53 }
     54 }  // namespace
     55 
     56 //#define DEBUG_ENCODER_BIT_STREAM
     57 
     58 VCMGenericEncoder::VCMGenericEncoder(VideoEncoder& encoder, bool internalSource /*= false*/)
     59 :
     60 _encoder(encoder),
     61 _codecType(kVideoCodecUnknown),
     62 _VCMencodedFrameCallback(NULL),
     63 _bitRate(0),
     64 _frameRate(0),
     65 _internalSource(internalSource)
     66 {
     67 }
     68 
     69 
     70 VCMGenericEncoder::~VCMGenericEncoder()
     71 {
     72 }
     73 
     74 int32_t VCMGenericEncoder::Release()
     75 {
     76     _bitRate = 0;
     77     _frameRate = 0;
     78     _VCMencodedFrameCallback = NULL;
     79     return _encoder.Release();
     80 }
     81 
     82 int32_t
     83 VCMGenericEncoder::InitEncode(const VideoCodec* settings,
     84                               int32_t numberOfCores,
     85                               uint32_t maxPayloadSize)
     86 {
     87     _bitRate = settings->startBitrate * 1000;
     88     _frameRate = settings->maxFramerate;
     89     _codecType = settings->codecType;
     90     if (_encoder.InitEncode(settings, numberOfCores, maxPayloadSize) != 0) {
     91       LOG(LS_ERROR) << "Failed to initialize the encoder associated with "
     92                        "payload name: " << settings->plName;
     93       return -1;
     94     }
     95     return 0;
     96 }
     97 
     98 int32_t
     99 VCMGenericEncoder::Encode(const I420VideoFrame& inputFrame,
    100                           const CodecSpecificInfo* codecSpecificInfo,
    101                           const std::vector<FrameType>& frameTypes) {
    102   std::vector<VideoFrameType> video_frame_types(frameTypes.size(),
    103                                                 kDeltaFrame);
    104   VCMEncodedFrame::ConvertFrameTypes(frameTypes, &video_frame_types);
    105   return _encoder.Encode(inputFrame, codecSpecificInfo, &video_frame_types);
    106 }
    107 
    108 int32_t
    109 VCMGenericEncoder::SetChannelParameters(int32_t packetLoss, int rtt)
    110 {
    111     return _encoder.SetChannelParameters(packetLoss, rtt);
    112 }
    113 
    114 int32_t
    115 VCMGenericEncoder::SetRates(uint32_t newBitRate, uint32_t frameRate)
    116 {
    117     uint32_t target_bitrate_kbps = (newBitRate + 500) / 1000;
    118     int32_t ret = _encoder.SetRates(target_bitrate_kbps, frameRate);
    119     if (ret < 0)
    120     {
    121         return ret;
    122     }
    123     _bitRate = newBitRate;
    124     _frameRate = frameRate;
    125     return VCM_OK;
    126 }
    127 
    128 int32_t
    129 VCMGenericEncoder::CodecConfigParameters(uint8_t* buffer, int32_t size)
    130 {
    131     int32_t ret = _encoder.CodecConfigParameters(buffer, size);
    132     if (ret < 0)
    133     {
    134         return ret;
    135     }
    136     return ret;
    137 }
    138 
    139 uint32_t VCMGenericEncoder::BitRate() const
    140 {
    141     return _bitRate;
    142 }
    143 
    144 uint32_t VCMGenericEncoder::FrameRate() const
    145 {
    146     return _frameRate;
    147 }
    148 
    149 int32_t
    150 VCMGenericEncoder::SetPeriodicKeyFrames(bool enable)
    151 {
    152     return _encoder.SetPeriodicKeyFrames(enable);
    153 }
    154 
    155 int32_t VCMGenericEncoder::RequestFrame(
    156     const std::vector<FrameType>& frame_types) {
    157   I420VideoFrame image;
    158   std::vector<VideoFrameType> video_frame_types(frame_types.size(),
    159                                                 kDeltaFrame);
    160   VCMEncodedFrame::ConvertFrameTypes(frame_types, &video_frame_types);
    161   return _encoder.Encode(image, NULL, &video_frame_types);
    162 }
    163 
    164 int32_t
    165 VCMGenericEncoder::RegisterEncodeCallback(VCMEncodedFrameCallback* VCMencodedFrameCallback)
    166 {
    167    _VCMencodedFrameCallback = VCMencodedFrameCallback;
    168    _VCMencodedFrameCallback->SetInternalSource(_internalSource);
    169    return _encoder.RegisterEncodeCompleteCallback(_VCMencodedFrameCallback);
    170 }
    171 
    172 bool
    173 VCMGenericEncoder::InternalSource() const
    174 {
    175     return _internalSource;
    176 }
    177 
    178  /***************************
    179   * Callback Implementation
    180   ***************************/
    181 VCMEncodedFrameCallback::VCMEncodedFrameCallback(
    182     EncodedImageCallback* post_encode_callback):
    183 _sendCallback(),
    184 _mediaOpt(NULL),
    185 _payloadType(0),
    186 _internalSource(false),
    187 post_encode_callback_(post_encode_callback)
    188 #ifdef DEBUG_ENCODER_BIT_STREAM
    189 , _bitStreamAfterEncoder(NULL)
    190 #endif
    191 {
    192 #ifdef DEBUG_ENCODER_BIT_STREAM
    193     _bitStreamAfterEncoder = fopen("encoderBitStream.bit", "wb");
    194 #endif
    195 }
    196 
    197 VCMEncodedFrameCallback::~VCMEncodedFrameCallback()
    198 {
    199 #ifdef DEBUG_ENCODER_BIT_STREAM
    200     fclose(_bitStreamAfterEncoder);
    201 #endif
    202 }
    203 
    204 int32_t
    205 VCMEncodedFrameCallback::SetTransportCallback(VCMPacketizationCallback* transport)
    206 {
    207     _sendCallback = transport;
    208     return VCM_OK;
    209 }
    210 
    211 int32_t
    212 VCMEncodedFrameCallback::Encoded(
    213     EncodedImage &encodedImage,
    214     const CodecSpecificInfo* codecSpecificInfo,
    215     const RTPFragmentationHeader* fragmentationHeader)
    216 {
    217     post_encode_callback_->Encoded(encodedImage);
    218 
    219     FrameType frameType = VCMEncodedFrame::ConvertFrameType(encodedImage._frameType);
    220 
    221     uint32_t encodedBytes = 0;
    222     if (_sendCallback != NULL)
    223     {
    224         encodedBytes = encodedImage._length;
    225 
    226 #ifdef DEBUG_ENCODER_BIT_STREAM
    227         if (_bitStreamAfterEncoder != NULL)
    228         {
    229             fwrite(encodedImage._buffer, 1, encodedImage._length, _bitStreamAfterEncoder);
    230         }
    231 #endif
    232 
    233         RTPVideoHeader rtpVideoHeader;
    234         RTPVideoHeader* rtpVideoHeaderPtr = &rtpVideoHeader;
    235         CopyCodecSpecific(codecSpecificInfo, &rtpVideoHeaderPtr);
    236 
    237         int32_t callbackReturn = _sendCallback->SendData(
    238             frameType,
    239             _payloadType,
    240             encodedImage._timeStamp,
    241             encodedImage.capture_time_ms_,
    242             encodedImage._buffer,
    243             encodedBytes,
    244             *fragmentationHeader,
    245             rtpVideoHeaderPtr);
    246        if (callbackReturn < 0)
    247        {
    248            return callbackReturn;
    249        }
    250     }
    251     else
    252     {
    253         return VCM_UNINITIALIZED;
    254     }
    255     if (_mediaOpt != NULL) {
    256       _mediaOpt->UpdateWithEncodedData(encodedBytes, encodedImage._timeStamp,
    257                                        frameType);
    258       if (_internalSource)
    259       {
    260           return _mediaOpt->DropFrame(); // Signal to encoder to drop next frame
    261       }
    262     }
    263     return VCM_OK;
    264 }
    265 
    266 void
    267 VCMEncodedFrameCallback::SetMediaOpt(
    268     media_optimization::MediaOptimization *mediaOpt)
    269 {
    270     _mediaOpt = mediaOpt;
    271 }
    272 
    273 }  // namespace webrtc
    274