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 {
Create(VideoEncoder::EncoderType codec_type)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
CodecToEncoderType(VideoCodecType codec_type)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
VideoEncoderSoftwareFallbackWrapper(VideoCodecType codec_type,webrtc::VideoEncoder * encoder)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
InitFallbackEncoder()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
InitEncode(const VideoCodec * codec_settings,int32_t number_of_cores,size_t max_payload_size)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
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)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
Release()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
Encode(const VideoFrame & frame,const CodecSpecificInfo * codec_specific_info,const std::vector<FrameType> * frame_types)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
SetChannelParameters(uint32_t packet_loss,int64_t rtt)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
SetRates(uint32_t bitrate,uint32_t framerate)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
OnDroppedFrame()176 void VideoEncoderSoftwareFallbackWrapper::OnDroppedFrame() {
177 if (fallback_encoder_)
178 return fallback_encoder_->OnDroppedFrame();
179 return encoder_->OnDroppedFrame();
180 }
181
SupportsNativeHandle() const182 bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
183 if (fallback_encoder_)
184 return fallback_encoder_->SupportsNativeHandle();
185 return encoder_->SupportsNativeHandle();
186 }
187
ImplementationName() const188 const char* VideoEncoderSoftwareFallbackWrapper::ImplementationName() const {
189 if (fallback_encoder_)
190 return fallback_implementation_name_.c_str();
191 return encoder_->ImplementationName();
192 }
193
GetTargetFramerate()194 int VideoEncoderSoftwareFallbackWrapper::GetTargetFramerate() {
195 if (fallback_encoder_)
196 return fallback_encoder_->GetTargetFramerate();
197 return encoder_->GetTargetFramerate();
198 }
199
200 } // namespace webrtc
201