blob: cc37a91736e9e1df696e32ecbba445ff0bd43c4b [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
13#include "webrtc/base/logging.h"
14#include "webrtc/modules/video_coding/include/video_error_codes.h"
15
16namespace webrtc {
17
18VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper(
magjedeacbaea2016-11-17 08:51:59 -080019 VideoCodecType codec_type,
magjed614d5b72016-11-15 06:30:54 -080020 webrtc::VideoEncoder* encoder)
Erik Språng08127a92016-11-16 16:41:30 +010021 : number_of_cores_(0),
22 max_payload_size_(0),
23 rates_set_(false),
24 framerate_(0),
magjed614d5b72016-11-15 06:30:54 -080025 channel_parameters_set_(false),
Erik Språng08127a92016-11-16 16:41:30 +010026 packet_loss_(0),
27 rtt_(0),
magjedeacbaea2016-11-17 08:51:59 -080028 encoder_type_(CodecToEncoderType(codec_type)),
magjed614d5b72016-11-15 06:30:54 -080029 encoder_(encoder),
30 callback_(nullptr) {}
31
32bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() {
magjedeacbaea2016-11-17 08:51:59 -080033 if (!VideoEncoder::IsSupportedSoftware(encoder_type_)) {
magjed614d5b72016-11-15 06:30:54 -080034 LOG(LS_WARNING)
35 << "Encoder requesting fallback to codec not supported in software.";
36 return false;
37 }
magjedeacbaea2016-11-17 08:51:59 -080038 fallback_encoder_.reset(VideoEncoder::Create(encoder_type_));
magjed614d5b72016-11-15 06:30:54 -080039 if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_,
40 max_payload_size_) !=
41 WEBRTC_VIDEO_CODEC_OK) {
42 LOG(LS_ERROR) << "Failed to initialize software-encoder fallback.";
43 fallback_encoder_->Release();
44 fallback_encoder_.reset();
45 return false;
46 }
47 // Replay callback, rates, and channel parameters.
48 if (callback_)
49 fallback_encoder_->RegisterEncodeCompleteCallback(callback_);
50 if (rates_set_)
Erik Språng08127a92016-11-16 16:41:30 +010051 fallback_encoder_->SetRateAllocation(bitrate_allocation_, framerate_);
magjed614d5b72016-11-15 06:30:54 -080052 if (channel_parameters_set_)
53 fallback_encoder_->SetChannelParameters(packet_loss_, rtt_);
54
55 fallback_implementation_name_ =
56 std::string(fallback_encoder_->ImplementationName()) +
57 " (fallback from: " + encoder_->ImplementationName() + ")";
58 // Since we're switching to the fallback encoder, Release the real encoder. It
59 // may be re-initialized via InitEncode later, and it will continue to get
60 // Set calls for rates and channel parameters in the meantime.
61 encoder_->Release();
62 return true;
63}
64
65int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode(
66 const VideoCodec* codec_settings,
67 int32_t number_of_cores,
68 size_t max_payload_size) {
69 // Store settings, in case we need to dynamically switch to the fallback
70 // encoder after a failed Encode call.
71 codec_settings_ = *codec_settings;
72 number_of_cores_ = number_of_cores;
73 max_payload_size_ = max_payload_size;
74 // Clear stored rate/channel parameters.
75 rates_set_ = false;
76 channel_parameters_set_ = false;
77
78 int32_t ret =
79 encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size);
magjedeacbaea2016-11-17 08:51:59 -080080 if (ret == WEBRTC_VIDEO_CODEC_OK || encoder_type_ == kUnsupportedCodec) {
magjed614d5b72016-11-15 06:30:54 -080081 if (fallback_encoder_)
82 fallback_encoder_->Release();
83 fallback_encoder_.reset();
84 if (callback_)
85 encoder_->RegisterEncodeCompleteCallback(callback_);
86 return ret;
87 }
88 // Try to instantiate software codec.
89 if (InitFallbackEncoder()) {
90 return WEBRTC_VIDEO_CODEC_OK;
91 }
92 // Software encoder failed, use original return code.
93 return ret;
94}
95
96int32_t VideoEncoderSoftwareFallbackWrapper::RegisterEncodeCompleteCallback(
97 EncodedImageCallback* callback) {
98 callback_ = callback;
99 int32_t ret = encoder_->RegisterEncodeCompleteCallback(callback);
100 if (fallback_encoder_)
101 return fallback_encoder_->RegisterEncodeCompleteCallback(callback);
102 return ret;
103}
104
105int32_t VideoEncoderSoftwareFallbackWrapper::Release() {
106 // If the fallback_encoder_ is non-null, it means it was created via
107 // InitFallbackEncoder which has Release()d encoder_, so we should only ever
108 // need to Release() whichever one is active.
109 if (fallback_encoder_)
110 return fallback_encoder_->Release();
111 return encoder_->Release();
112}
113
114int32_t VideoEncoderSoftwareFallbackWrapper::Encode(
115 const VideoFrame& frame,
116 const CodecSpecificInfo* codec_specific_info,
117 const std::vector<FrameType>* frame_types) {
118 if (fallback_encoder_)
119 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
120 int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types);
121 // If requested, try a software fallback.
122 if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) {
123 if (frame.video_frame_buffer()->native_handle() &&
124 !fallback_encoder_->SupportsNativeHandle()) {
125 LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, "
126 << "dropping one frame.";
127 return WEBRTC_VIDEO_CODEC_ERROR;
128 }
129
130 // Fallback was successful, so start using it with this frame.
131 return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
132 }
133 return ret;
134}
135
136int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters(
137 uint32_t packet_loss,
138 int64_t rtt) {
139 channel_parameters_set_ = true;
140 packet_loss_ = packet_loss;
141 rtt_ = rtt;
142 int32_t ret = encoder_->SetChannelParameters(packet_loss, rtt);
143 if (fallback_encoder_)
144 return fallback_encoder_->SetChannelParameters(packet_loss, rtt);
145 return ret;
146}
147
Erik Språng08127a92016-11-16 16:41:30 +0100148int32_t VideoEncoderSoftwareFallbackWrapper::SetRateAllocation(
149 const BitrateAllocation& bitrate_allocation,
150 uint32_t framerate) {
magjed614d5b72016-11-15 06:30:54 -0800151 rates_set_ = true;
Erik Språng08127a92016-11-16 16:41:30 +0100152 bitrate_allocation_ = bitrate_allocation;
magjed614d5b72016-11-15 06:30:54 -0800153 framerate_ = framerate;
Erik Språng08127a92016-11-16 16:41:30 +0100154 int32_t ret = encoder_->SetRateAllocation(bitrate_allocation_, framerate);
magjed614d5b72016-11-15 06:30:54 -0800155 if (fallback_encoder_)
Erik Språng08127a92016-11-16 16:41:30 +0100156 return fallback_encoder_->SetRateAllocation(bitrate_allocation_, framerate);
magjed614d5b72016-11-15 06:30:54 -0800157 return ret;
158}
159
160void VideoEncoderSoftwareFallbackWrapper::OnDroppedFrame() {
161 if (fallback_encoder_)
162 return fallback_encoder_->OnDroppedFrame();
163 return encoder_->OnDroppedFrame();
164}
165
166bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
167 if (fallback_encoder_)
168 return fallback_encoder_->SupportsNativeHandle();
169 return encoder_->SupportsNativeHandle();
170}
171
172} // namespace webrtc