blob: 8bf3ed41658cbaca6ba68edac6c54882d5082047 [file] [log] [blame]
magjed614d5b72016-11-15 06:30:54 -08001/*
2 * Copyright (c) 2016 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/media/engine/videoencodersoftwarefallbackwrapper.h"
12
Henrik Kjellandera80c16a2017-07-01 16:48:15 +020013#include "webrtc/base/logging.h"
magjed509e4fe2016-11-18 01:34:11 -080014#include "webrtc/media/engine/internalencoderfactory.h"
magjed614d5b72016-11-15 06:30:54 -080015#include "webrtc/modules/video_coding/include/video_error_codes.h"
16
17namespace webrtc {
18
19VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper(
magjed509e4fe2016-11-18 01:34:11 -080020 const cricket::VideoCodec& codec,
magjed614d5b72016-11-15 06:30:54 -080021 webrtc::VideoEncoder* encoder)
Erik Språng08127a92016-11-16 16:41:30 +010022 : number_of_cores_(0),
23 max_payload_size_(0),
24 rates_set_(false),
25 framerate_(0),
magjed614d5b72016-11-15 06:30:54 -080026 channel_parameters_set_(false),
Erik Språng08127a92016-11-16 16:41:30 +010027 packet_loss_(0),
28 rtt_(0),
magjed509e4fe2016-11-18 01:34:11 -080029 codec_(codec),
magjed614d5b72016-11-15 06:30:54 -080030 encoder_(encoder),
31 callback_(nullptr) {}
32
33bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() {
magjed509e4fe2016-11-18 01:34:11 -080034 cricket::InternalEncoderFactory internal_factory;
35 if (!FindMatchingCodec(internal_factory.supported_codecs(), codec_)) {
magjed614d5b72016-11-15 06:30:54 -080036 LOG(LS_WARNING)
37 << "Encoder requesting fallback to codec not supported in software.";
38 return false;
39 }
magjed509e4fe2016-11-18 01:34:11 -080040 fallback_encoder_.reset(internal_factory.CreateVideoEncoder(codec_));
magjed614d5b72016-11-15 06:30:54 -080041 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_,
42 max_payload_size_) !=
43 WEBRTC_VIDEO_CODEC_OK) {
44 LOG(LS_ERROR) << "Failed to initialize software-encoder fallback.";
45 fallback_encoder_->Release();
46 fallback_encoder_.reset();
47 return false;
48 }
49 // Replay callback, rates, and channel parameters.
50 if (callback_)
51 fallback_encoder_->RegisterEncodeCompleteCallback(callback_);
52 if (rates_set_)
Erik Språng08127a92016-11-16 16:41:30 +010053 fallback_encoder_->SetRateAllocation(bitrate_allocation_, framerate_);
magjed614d5b72016-11-15 06:30:54 -080054 if (channel_parameters_set_)
55 fallback_encoder_->SetChannelParameters(packet_loss_, rtt_);
56
57 fallback_implementation_name_ =
58 std::string(fallback_encoder_->ImplementationName()) +
59 " (fallback from: " + encoder_->ImplementationName() + ")";
60 // Since we're switching to the fallback encoder, Release the real encoder. It
61 // may be re-initialized via InitEncode later, and it will continue to get
62 // Set calls for rates and channel parameters in the meantime.
63 encoder_->Release();
64 return true;
65}
66
67int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode(
68 const VideoCodec* codec_settings,
69 int32_t number_of_cores,
70 size_t max_payload_size) {
71 // Store settings, in case we need to dynamically switch to the fallback
72 // encoder after a failed Encode call.
73 codec_settings_ = *codec_settings;
74 number_of_cores_ = number_of_cores;
75 max_payload_size_ = max_payload_size;
76 // Clear stored rate/channel parameters.
77 rates_set_ = false;
78 channel_parameters_set_ = false;
79
80 int32_t ret =
81 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size);
magjed509e4fe2016-11-18 01:34:11 -080082 if (ret == WEBRTC_VIDEO_CODEC_OK || codec_.name.empty()) {
magjed614d5b72016-11-15 06:30:54 -080083 if (fallback_encoder_)
84 fallback_encoder_->Release();
85 fallback_encoder_.reset();
86 if (callback_)
87 encoder_->RegisterEncodeCompleteCallback(callback_);
88 return ret;
89 }
90 // Try to instantiate software codec.
91 if (InitFallbackEncoder()) {
92 return WEBRTC_VIDEO_CODEC_OK;
93 }
94 // Software encoder failed, use original return code.
95 return ret;
96}
97
98int32_t VideoEncoderSoftwareFallbackWrapper::RegisterEncodeCompleteCallback(
99 EncodedImageCallback* callback) {
100 callback_ = callback;
101 int32_t ret = encoder_->RegisterEncodeCompleteCallback(callback);
102 if (fallback_encoder_)
103 return fallback_encoder_->RegisterEncodeCompleteCallback(callback);
104 return ret;
105}
106
107int32_t VideoEncoderSoftwareFallbackWrapper::Release() {
108 // If the fallback_encoder_ is non-null, it means it was created via
109 // InitFallbackEncoder which has Release()d encoder_, so we should only ever
110 // need to Release() whichever one is active.
111 if (fallback_encoder_)
112 return fallback_encoder_->Release();
113 return encoder_->Release();
114}
115
116int32_t VideoEncoderSoftwareFallbackWrapper::Encode(
117 const VideoFrame& frame,
118 const CodecSpecificInfo* codec_specific_info,
119 const std::vector<FrameType>* frame_types) {
120 if (fallback_encoder_)
121 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
122 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types);
123 // If requested, try a software fallback.
124 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) {
Magnus Jedvert7a721e82017-06-14 11:28:08 +0200125 if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative &&
magjed614d5b72016-11-15 06:30:54 -0800126 !fallback_encoder_->SupportsNativeHandle()) {
127 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, "
128 << "dropping one frame.";
129 return WEBRTC_VIDEO_CODEC_ERROR;
130 }
131
132 // Fallback was successful, so start using it with this frame.
133 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
134 }
135 return ret;
136}
137
138int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters(
139 uint32_t packet_loss,
140 int64_t rtt) {
141 channel_parameters_set_ = true;
142 packet_loss_ = packet_loss;
143 rtt_ = rtt;
144 int32_t ret = encoder_->SetChannelParameters(packet_loss, rtt);
145 if (fallback_encoder_)
146 return fallback_encoder_->SetChannelParameters(packet_loss, rtt);
147 return ret;
148}
149
Erik Språng08127a92016-11-16 16:41:30 +0100150int32_t VideoEncoderSoftwareFallbackWrapper::SetRateAllocation(
151 const BitrateAllocation& bitrate_allocation,
152 uint32_t framerate) {
magjed614d5b72016-11-15 06:30:54 -0800153 rates_set_ = true;
Erik Språng08127a92016-11-16 16:41:30 +0100154 bitrate_allocation_ = bitrate_allocation;
magjed614d5b72016-11-15 06:30:54 -0800155 framerate_ = framerate;
Erik Språng08127a92016-11-16 16:41:30 +0100156 int32_t ret = encoder_->SetRateAllocation(bitrate_allocation_, framerate);
magjed614d5b72016-11-15 06:30:54 -0800157 if (fallback_encoder_)
Erik Språng08127a92016-11-16 16:41:30 +0100158 return fallback_encoder_->SetRateAllocation(bitrate_allocation_, framerate);
magjed614d5b72016-11-15 06:30:54 -0800159 return ret;
160}
161
magjed614d5b72016-11-15 06:30:54 -0800162bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
163 if (fallback_encoder_)
164 return fallback_encoder_->SupportsNativeHandle();
165 return encoder_->SupportsNativeHandle();
166}
167
kthelgason876222f2016-11-29 01:44:11 -0800168VideoEncoder::ScalingSettings
169VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const {
170 return encoder_->GetScalingSettings();
171}
172
kthelgason535dbd32017-01-26 00:36:31 -0800173const char *VideoEncoderSoftwareFallbackWrapper::ImplementationName() const {
174 if (fallback_encoder_)
175 return fallback_encoder_->ImplementationName();
176 return encoder_->ImplementationName();
177}
178
magjed614d5b72016-11-15 06:30:54 -0800179} // namespace webrtc