/* * Copyright (c) 2012 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 "webrtc/modules/video_coding/generic_encoder.h" #include #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/base/trace_event.h" #include "webrtc/engine_configurations.h" #include "webrtc/modules/video_coding/encoded_frame.h" #include "webrtc/modules/video_coding/media_optimization.h" #include "webrtc/system_wrappers/include/critical_section_wrapper.h" namespace webrtc { VCMGenericEncoder::VCMGenericEncoder( VideoEncoder* encoder, VideoEncoderRateObserver* rate_observer, VCMEncodedFrameCallback* encoded_frame_callback, bool internal_source) : encoder_(encoder), rate_observer_(rate_observer), vcm_encoded_frame_callback_(encoded_frame_callback), internal_source_(internal_source), encoder_params_({0, 0, 0, 0}), is_screenshare_(false) {} VCMGenericEncoder::~VCMGenericEncoder() {} int32_t VCMGenericEncoder::Release() { TRACE_EVENT0("webrtc", "VCMGenericEncoder::Release"); return encoder_->Release(); } int32_t VCMGenericEncoder::InitEncode(const VideoCodec* settings, int32_t number_of_cores, size_t max_payload_size) { TRACE_EVENT0("webrtc", "VCMGenericEncoder::InitEncode"); { rtc::CritScope lock(¶ms_lock_); encoder_params_.target_bitrate = settings->startBitrate * 1000; encoder_params_.input_frame_rate = settings->maxFramerate; } is_screenshare_ = settings->mode == VideoCodecMode::kScreensharing; if (encoder_->InitEncode(settings, number_of_cores, max_payload_size) != 0) { LOG(LS_ERROR) << "Failed to initialize the encoder associated with " "payload name: " << settings->plName; return -1; } encoder_->RegisterEncodeCompleteCallback(vcm_encoded_frame_callback_); return 0; } int32_t VCMGenericEncoder::Encode(const VideoFrame& frame, const CodecSpecificInfo* codec_specific, const std::vector& frame_types) { TRACE_EVENT1("webrtc", "VCMGenericEncoder::Encode", "timestamp", frame.timestamp()); for (FrameType frame_type : frame_types) RTC_DCHECK(frame_type == kVideoFrameKey || frame_type == kVideoFrameDelta); int32_t result = encoder_->Encode(frame, codec_specific, &frame_types); if (vcm_encoded_frame_callback_) { vcm_encoded_frame_callback_->SignalLastEncoderImplementationUsed( encoder_->ImplementationName()); } if (is_screenshare_ && result == WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT) { // Target bitrate exceeded, encoder state has been reset - try again. return encoder_->Encode(frame, codec_specific, &frame_types); } return result; } void VCMGenericEncoder::SetEncoderParameters(const EncoderParameters& params) { bool channel_parameters_have_changed; bool rates_have_changed; { rtc::CritScope lock(¶ms_lock_); channel_parameters_have_changed = params.loss_rate != encoder_params_.loss_rate || params.rtt != encoder_params_.rtt; rates_have_changed = params.target_bitrate != encoder_params_.target_bitrate || params.input_frame_rate != encoder_params_.input_frame_rate; encoder_params_ = params; } if (channel_parameters_have_changed) encoder_->SetChannelParameters(params.loss_rate, params.rtt); if (rates_have_changed) { uint32_t target_bitrate_kbps = (params.target_bitrate + 500) / 1000; encoder_->SetRates(target_bitrate_kbps, params.input_frame_rate); if (rate_observer_) { rate_observer_->OnSetRates(params.target_bitrate, params.input_frame_rate); } } } EncoderParameters VCMGenericEncoder::GetEncoderParameters() const { rtc::CritScope lock(¶ms_lock_); return encoder_params_; } int32_t VCMGenericEncoder::SetPeriodicKeyFrames(bool enable) { return encoder_->SetPeriodicKeyFrames(enable); } int32_t VCMGenericEncoder::RequestFrame( const std::vector& frame_types) { VideoFrame image; return encoder_->Encode(image, NULL, &frame_types); } bool VCMGenericEncoder::InternalSource() const { return internal_source_; } void VCMGenericEncoder::OnDroppedFrame() { encoder_->OnDroppedFrame(); } bool VCMGenericEncoder::SupportsNativeHandle() const { return encoder_->SupportsNativeHandle(); } VCMEncodedFrameCallback::VCMEncodedFrameCallback( EncodedImageCallback* post_encode_callback) : send_callback_(), media_opt_(nullptr), internal_source_(false), post_encode_callback_(post_encode_callback) {} VCMEncodedFrameCallback::~VCMEncodedFrameCallback() {} int32_t VCMEncodedFrameCallback::SetTransportCallback( VCMPacketizationCallback* transport) { send_callback_ = transport; return VCM_OK; } int32_t VCMEncodedFrameCallback::Encoded( const EncodedImage& encoded_image, const CodecSpecificInfo* codec_specific, const RTPFragmentationHeader* fragmentation_header) { TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded", "timestamp", encoded_image._timeStamp); int ret_val = post_encode_callback_->Encoded(encoded_image, codec_specific, fragmentation_header); if (ret_val < 0) return ret_val; if (media_opt_) { media_opt_->UpdateWithEncodedData(encoded_image); if (internal_source_) return media_opt_->DropFrame(); // Signal to encoder to drop next frame. } return VCM_OK; } void VCMEncodedFrameCallback::SetMediaOpt( media_optimization::MediaOptimization* mediaOpt) { media_opt_ = mediaOpt; } void VCMEncodedFrameCallback::SignalLastEncoderImplementationUsed( const char* implementation_name) { if (send_callback_) send_callback_->OnEncoderImplementationName(implementation_name); } } // namespace webrtc