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