Home | History | Annotate | Download | only in video
      1 /*
      2  *  Copyright (c) 2015 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/video_encoder.h"
     12 
     13 #include "webrtc/base/checks.h"
     14 #include "webrtc/base/logging.h"
     15 #include "webrtc/modules/video_coding/codecs/h264/include/h264.h"
     16 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
     17 #include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
     18 
     19 namespace webrtc {
     20 VideoEncoder* VideoEncoder::Create(VideoEncoder::EncoderType codec_type) {
     21   switch (codec_type) {
     22     case kH264:
     23       RTC_DCHECK(H264Encoder::IsSupported());
     24       return H264Encoder::Create();
     25     case kVp8:
     26       return VP8Encoder::Create();
     27     case kVp9:
     28       return VP9Encoder::Create();
     29     case kUnsupportedCodec:
     30       RTC_NOTREACHED();
     31       return nullptr;
     32   }
     33   RTC_NOTREACHED();
     34   return nullptr;
     35 }
     36 
     37 VideoEncoder::EncoderType CodecToEncoderType(VideoCodecType codec_type) {
     38   switch (codec_type) {
     39     case kVideoCodecH264:
     40       return VideoEncoder::kH264;
     41     case kVideoCodecVP8:
     42       return VideoEncoder::kVp8;
     43     case kVideoCodecVP9:
     44       return VideoEncoder::kVp9;
     45     default:
     46       return VideoEncoder::kUnsupportedCodec;
     47   }
     48 }
     49 
     50 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper(
     51     VideoCodecType codec_type,
     52     webrtc::VideoEncoder* encoder)
     53     : rates_set_(false),
     54       channel_parameters_set_(false),
     55       encoder_type_(CodecToEncoderType(codec_type)),
     56       encoder_(encoder),
     57       callback_(nullptr) {}
     58 
     59 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() {
     60   RTC_CHECK(encoder_type_ != kUnsupportedCodec)
     61       << "Encoder requesting fallback to codec not supported in software.";
     62   fallback_encoder_.reset(VideoEncoder::Create(encoder_type_));
     63   if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_,
     64                                     max_payload_size_) !=
     65       WEBRTC_VIDEO_CODEC_OK) {
     66     LOG(LS_ERROR) << "Failed to initialize software-encoder fallback.";
     67     fallback_encoder_->Release();
     68     fallback_encoder_.reset();
     69     return false;
     70   }
     71   // Replay callback, rates, and channel parameters.
     72   if (callback_)
     73     fallback_encoder_->RegisterEncodeCompleteCallback(callback_);
     74   if (rates_set_)
     75     fallback_encoder_->SetRates(bitrate_, framerate_);
     76   if (channel_parameters_set_)
     77     fallback_encoder_->SetChannelParameters(packet_loss_, rtt_);
     78 
     79   fallback_implementation_name_ =
     80       std::string(fallback_encoder_->ImplementationName()) +
     81       " (fallback from: " + encoder_->ImplementationName() + ")";
     82   // Since we're switching to the fallback encoder, Release the real encoder. It
     83   // may be re-initialized via InitEncode later, and it will continue to get
     84   // Set calls for rates and channel parameters in the meantime.
     85   encoder_->Release();
     86   return true;
     87 }
     88 
     89 int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode(
     90     const VideoCodec* codec_settings,
     91     int32_t number_of_cores,
     92     size_t max_payload_size) {
     93   // Store settings, in case we need to dynamically switch to the fallback
     94   // encoder after a failed Encode call.
     95   codec_settings_ = *codec_settings;
     96   number_of_cores_ = number_of_cores;
     97   max_payload_size_ = max_payload_size;
     98   // Clear stored rate/channel parameters.
     99   rates_set_ = false;
    100   channel_parameters_set_ = false;
    101 
    102   int32_t ret =
    103       encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size);
    104   if (ret == WEBRTC_VIDEO_CODEC_OK || encoder_type_ == kUnsupportedCodec) {
    105     if (fallback_encoder_)
    106       fallback_encoder_->Release();
    107     fallback_encoder_.reset();
    108     if (callback_)
    109       encoder_->RegisterEncodeCompleteCallback(callback_);
    110     return ret;
    111   }
    112   // Try to instantiate software codec.
    113   if (InitFallbackEncoder()) {
    114     return WEBRTC_VIDEO_CODEC_OK;
    115   }
    116   // Software encoder failed, use original return code.
    117   return ret;
    118 }
    119 
    120 int32_t VideoEncoderSoftwareFallbackWrapper::RegisterEncodeCompleteCallback(
    121     EncodedImageCallback* callback) {
    122   callback_ = callback;
    123   int32_t ret = encoder_->RegisterEncodeCompleteCallback(callback);
    124   if (fallback_encoder_)
    125     return fallback_encoder_->RegisterEncodeCompleteCallback(callback);
    126   return ret;
    127 }
    128 
    129 int32_t VideoEncoderSoftwareFallbackWrapper::Release() {
    130   // If the fallback_encoder_ is non-null, it means it was created via
    131   // InitFallbackEncoder which has Release()d encoder_, so we should only ever
    132   // need to Release() whichever one is active.
    133   if (fallback_encoder_)
    134     return fallback_encoder_->Release();
    135   return encoder_->Release();
    136 }
    137 
    138 int32_t VideoEncoderSoftwareFallbackWrapper::Encode(
    139     const VideoFrame& frame,
    140     const CodecSpecificInfo* codec_specific_info,
    141     const std::vector<FrameType>* frame_types) {
    142   if (fallback_encoder_)
    143     return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
    144   int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types);
    145   // If requested, try a software fallback.
    146   if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) {
    147     // Fallback was successful, so start using it with this frame.
    148     return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
    149   }
    150   return ret;
    151 }
    152 
    153 int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters(
    154     uint32_t packet_loss,
    155     int64_t rtt) {
    156   channel_parameters_set_ = true;
    157   packet_loss_ = packet_loss;
    158   rtt_ = rtt;
    159   int32_t ret = encoder_->SetChannelParameters(packet_loss, rtt);
    160   if (fallback_encoder_)
    161     return fallback_encoder_->SetChannelParameters(packet_loss, rtt);
    162   return ret;
    163 }
    164 
    165 int32_t VideoEncoderSoftwareFallbackWrapper::SetRates(uint32_t bitrate,
    166                                                       uint32_t framerate) {
    167   rates_set_ = true;
    168   bitrate_ = bitrate;
    169   framerate_ = framerate;
    170   int32_t ret = encoder_->SetRates(bitrate, framerate);
    171   if (fallback_encoder_)
    172     return fallback_encoder_->SetRates(bitrate, framerate);
    173   return ret;
    174 }
    175 
    176 void VideoEncoderSoftwareFallbackWrapper::OnDroppedFrame() {
    177   if (fallback_encoder_)
    178     return fallback_encoder_->OnDroppedFrame();
    179   return encoder_->OnDroppedFrame();
    180 }
    181 
    182 bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
    183   if (fallback_encoder_)
    184     return fallback_encoder_->SupportsNativeHandle();
    185   return encoder_->SupportsNativeHandle();
    186 }
    187 
    188 const char* VideoEncoderSoftwareFallbackWrapper::ImplementationName() const {
    189   if (fallback_encoder_)
    190     return fallback_implementation_name_.c_str();
    191   return encoder_->ImplementationName();
    192 }
    193 
    194 int VideoEncoderSoftwareFallbackWrapper::GetTargetFramerate() {
    195   if (fallback_encoder_)
    196     return fallback_encoder_->GetTargetFramerate();
    197   return encoder_->GetTargetFramerate();
    198 }
    199 
    200 }  // namespace webrtc
    201