| /* |
| * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "media/engine/fake_webrtc_video_engine.h" |
| |
| #include <algorithm> |
| #include <memory> |
| |
| #include "absl/strings/match.h" |
| #include "api/environment/environment.h" |
| #include "media/base/codec.h" |
| #include "media/base/media_constants.h" |
| #include "media/engine/simulcast_encoder_adapter.h" |
| #include "modules/video_coding/include/video_error_codes.h" |
| #include "rtc_base/time_utils.h" |
| |
| namespace cricket { |
| |
| namespace { |
| |
| using ::webrtc::Environment; |
| |
| static constexpr webrtc::TimeDelta kEventTimeout = |
| webrtc::TimeDelta::Seconds(10); |
| |
| bool IsScalabilityModeSupported( |
| const std::vector<webrtc::SdpVideoFormat>& formats, |
| std::optional<std::string> scalability_mode) { |
| if (!scalability_mode.has_value()) { |
| return true; |
| } |
| for (const auto& format : formats) { |
| for (const auto& mode : format.scalability_modes) { |
| if (ScalabilityModeToString(mode) == scalability_mode) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } // namespace |
| |
| // Decoder. |
| FakeWebRtcVideoDecoder::FakeWebRtcVideoDecoder( |
| FakeWebRtcVideoDecoderFactory* factory) |
| : num_frames_received_(0), factory_(factory) {} |
| |
| FakeWebRtcVideoDecoder::~FakeWebRtcVideoDecoder() { |
| if (factory_) { |
| factory_->DecoderDestroyed(this); |
| } |
| } |
| |
| bool FakeWebRtcVideoDecoder::Configure(const Settings& /* settings */) { |
| return true; |
| } |
| |
| int32_t FakeWebRtcVideoDecoder::Decode(const webrtc::EncodedImage&, |
| int64_t) { |
| num_frames_received_++; |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| |
| int32_t FakeWebRtcVideoDecoder::RegisterDecodeCompleteCallback( |
| webrtc::DecodedImageCallback*) { |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| |
| int32_t FakeWebRtcVideoDecoder::Release() { |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| |
| int FakeWebRtcVideoDecoder::GetNumFramesReceived() const { |
| return num_frames_received_; |
| } |
| |
| // Decoder factory. |
| FakeWebRtcVideoDecoderFactory::FakeWebRtcVideoDecoderFactory() |
| : num_created_decoders_(0) {} |
| |
| std::vector<webrtc::SdpVideoFormat> |
| FakeWebRtcVideoDecoderFactory::GetSupportedFormats() const { |
| std::vector<webrtc::SdpVideoFormat> formats; |
| |
| for (const webrtc::SdpVideoFormat& format : supported_codec_formats_) { |
| // Don't add same codec twice. |
| if (!format.IsCodecInList(formats)) |
| formats.push_back(format); |
| } |
| |
| return formats; |
| } |
| |
| std::unique_ptr<webrtc::VideoDecoder> FakeWebRtcVideoDecoderFactory::Create( |
| const webrtc::Environment& /* env */, |
| const webrtc::SdpVideoFormat& format) { |
| if (format.IsCodecInList(supported_codec_formats_)) { |
| num_created_decoders_++; |
| std::unique_ptr<FakeWebRtcVideoDecoder> decoder = |
| std::make_unique<FakeWebRtcVideoDecoder>(this); |
| decoders_.push_back(decoder.get()); |
| return decoder; |
| } |
| |
| return nullptr; |
| } |
| |
| void FakeWebRtcVideoDecoderFactory::DecoderDestroyed( |
| FakeWebRtcVideoDecoder* decoder) { |
| decoders_.erase(std::remove(decoders_.begin(), decoders_.end(), decoder), |
| decoders_.end()); |
| } |
| |
| void FakeWebRtcVideoDecoderFactory::AddSupportedVideoCodecType( |
| const std::string& name) { |
| // This is to match the default H264 params of cricket::Codec. |
| cricket::Codec video_codec = cricket::CreateVideoCodec(name); |
| supported_codec_formats_.push_back( |
| webrtc::SdpVideoFormat(video_codec.name, video_codec.params)); |
| } |
| |
| int FakeWebRtcVideoDecoderFactory::GetNumCreatedDecoders() { |
| return num_created_decoders_; |
| } |
| |
| const std::vector<FakeWebRtcVideoDecoder*>& |
| FakeWebRtcVideoDecoderFactory::decoders() { |
| return decoders_; |
| } |
| |
| // Encoder. |
| FakeWebRtcVideoEncoder::FakeWebRtcVideoEncoder( |
| FakeWebRtcVideoEncoderFactory* factory) |
| : num_frames_encoded_(0), factory_(factory) {} |
| |
| FakeWebRtcVideoEncoder::~FakeWebRtcVideoEncoder() { |
| if (factory_) { |
| factory_->EncoderDestroyed(this); |
| } |
| } |
| |
| void FakeWebRtcVideoEncoder::SetFecControllerOverride( |
| webrtc::FecControllerOverride* /* fec_controller_override */) { |
| // Ignored. |
| } |
| |
| int32_t FakeWebRtcVideoEncoder::InitEncode( |
| const webrtc::VideoCodec* codecSettings, |
| const VideoEncoder::Settings& /* settings */) { |
| webrtc::MutexLock lock(&mutex_); |
| codec_settings_ = *codecSettings; |
| init_encode_event_.Set(); |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| |
| int32_t FakeWebRtcVideoEncoder::Encode( |
| const webrtc::VideoFrame& /* inputImage */, |
| const std::vector<webrtc::VideoFrameType>* /* frame_types */) { |
| webrtc::MutexLock lock(&mutex_); |
| ++num_frames_encoded_; |
| init_encode_event_.Set(); |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| |
| int32_t FakeWebRtcVideoEncoder::RegisterEncodeCompleteCallback( |
| webrtc::EncodedImageCallback* /* callback */) { |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| |
| int32_t FakeWebRtcVideoEncoder::Release() { |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| |
| void FakeWebRtcVideoEncoder::SetRates( |
| const RateControlParameters& /* parameters */) {} |
| |
| webrtc::VideoEncoder::EncoderInfo FakeWebRtcVideoEncoder::GetEncoderInfo() |
| const { |
| EncoderInfo info; |
| info.is_hardware_accelerated = true; |
| return info; |
| } |
| |
| bool FakeWebRtcVideoEncoder::WaitForInitEncode() { |
| return init_encode_event_.Wait(kEventTimeout); |
| } |
| |
| webrtc::VideoCodec FakeWebRtcVideoEncoder::GetCodecSettings() { |
| webrtc::MutexLock lock(&mutex_); |
| return codec_settings_; |
| } |
| |
| int FakeWebRtcVideoEncoder::GetNumEncodedFrames() { |
| webrtc::MutexLock lock(&mutex_); |
| return num_frames_encoded_; |
| } |
| |
| // Video encoder factory. |
| FakeWebRtcVideoEncoderFactory::FakeWebRtcVideoEncoderFactory() |
| : num_created_encoders_(0), vp8_factory_mode_(false) {} |
| |
| std::vector<webrtc::SdpVideoFormat> |
| FakeWebRtcVideoEncoderFactory::GetSupportedFormats() const { |
| std::vector<webrtc::SdpVideoFormat> formats; |
| |
| for (const webrtc::SdpVideoFormat& format : formats_) { |
| // Don't add same codec twice. |
| if (!format.IsCodecInList(formats)) |
| formats.push_back(format); |
| } |
| |
| return formats; |
| } |
| |
| webrtc::VideoEncoderFactory::CodecSupport |
| FakeWebRtcVideoEncoderFactory::QueryCodecSupport( |
| const webrtc::SdpVideoFormat& format, |
| std::optional<std::string> scalability_mode) const { |
| std::vector<webrtc::SdpVideoFormat> supported_formats; |
| for (const auto& f : formats_) { |
| if (format.IsSameCodec(f)) |
| supported_formats.push_back(f); |
| } |
| if (format.IsCodecInList(formats_)) { |
| return {.is_supported = IsScalabilityModeSupported(supported_formats, |
| scalability_mode)}; |
| } |
| return {.is_supported = false}; |
| } |
| |
| std::unique_ptr<webrtc::VideoEncoder> FakeWebRtcVideoEncoderFactory::Create( |
| const Environment& env, |
| const webrtc::SdpVideoFormat& format) { |
| webrtc::MutexLock lock(&mutex_); |
| std::unique_ptr<webrtc::VideoEncoder> encoder; |
| if (format.IsCodecInList(formats_)) { |
| if (absl::EqualsIgnoreCase(format.name, kVp8CodecName) && |
| !vp8_factory_mode_) { |
| // The simulcast adapter will ask this factory for multiple VP8 |
| // encoders. Enter vp8_factory_mode so that we now create these encoders |
| // instead of more adapters. |
| vp8_factory_mode_ = true; |
| encoder = std::make_unique<webrtc::SimulcastEncoderAdapter>( |
| env, /*primary_factory=*/this, /*fallback_factory=*/nullptr, format); |
| } else { |
| num_created_encoders_++; |
| created_video_encoder_event_.Set(); |
| encoder = std::make_unique<FakeWebRtcVideoEncoder>(this); |
| encoders_.push_back(static_cast<FakeWebRtcVideoEncoder*>(encoder.get())); |
| } |
| } |
| return encoder; |
| } |
| |
| bool FakeWebRtcVideoEncoderFactory::WaitForCreatedVideoEncoders( |
| int num_encoders) { |
| int64_t start_offset_ms = rtc::TimeMillis(); |
| int64_t wait_time = kEventTimeout.ms(); |
| do { |
| if (GetNumCreatedEncoders() >= num_encoders) |
| return true; |
| wait_time = kEventTimeout.ms() - (rtc::TimeMillis() - start_offset_ms); |
| } while (wait_time > 0 && created_video_encoder_event_.Wait( |
| webrtc::TimeDelta::Millis(wait_time))); |
| return false; |
| } |
| |
| void FakeWebRtcVideoEncoderFactory::EncoderDestroyed( |
| FakeWebRtcVideoEncoder* encoder) { |
| webrtc::MutexLock lock(&mutex_); |
| encoders_.erase(std::remove(encoders_.begin(), encoders_.end(), encoder), |
| encoders_.end()); |
| } |
| |
| void FakeWebRtcVideoEncoderFactory::AddSupportedVideoCodec( |
| const webrtc::SdpVideoFormat& format) { |
| formats_.push_back(format); |
| } |
| |
| void FakeWebRtcVideoEncoderFactory::AddSupportedVideoCodecType( |
| const std::string& name, |
| const std::vector<webrtc::ScalabilityMode>& scalability_modes) { |
| // This is to match the default H264 params of cricket::Codec. |
| cricket::Codec video_codec = cricket::CreateVideoCodec(name); |
| formats_.push_back(webrtc::SdpVideoFormat( |
| video_codec.name, video_codec.params, |
| {scalability_modes.begin(), scalability_modes.end()})); |
| } |
| |
| int FakeWebRtcVideoEncoderFactory::GetNumCreatedEncoders() { |
| webrtc::MutexLock lock(&mutex_); |
| return num_created_encoders_; |
| } |
| |
| const std::vector<FakeWebRtcVideoEncoder*> |
| FakeWebRtcVideoEncoderFactory::encoders() { |
| webrtc::MutexLock lock(&mutex_); |
| return encoders_; |
| } |
| |
| } // namespace cricket |