调用栈
Channel中的SetRecvParameters
第一步,获取解码器变化的参数,然后获取最优解码器参数;
第二步,保存媒体协商时的接收到的解码器参数。
bool WebRtcVideoChannel::SetRecvParameters(const VideoRecvParameters& params) {
RTC_DCHECK_RUN_ON(&thread_checker_);
TRACE_EVENT0("webrtc", "WebRtcVideoChannel::SetRecvParameters");
RTC_DLOG(LS_INFO) << "SetRecvParameters: " << params.ToString();
ChangedRecvParameters changed_params;
if (!GetChangedRecvParameters(params, &changed_params)) {
return false;
}
if (changed_params.flexfec_payload_type) {
RTC_DLOG(LS_INFO) << "Changing FlexFEC payload type (recv) from "
<< recv_flexfec_payload_type_ << " to "
<< *changed_params.flexfec_payload_type;
recv_flexfec_payload_type_ = *changed_params.flexfec_payload_type;
}
if (changed_params.rtp_header_extensions) {
recv_rtp_extensions_ = *changed_params.rtp_header_extensions;
}
if (changed_params.codec_settings) {
RTC_DLOG(LS_INFO) << "Changing recv codecs from "
<< CodecSettingsVectorToString(recv_codecs_) << " to "
<< CodecSettingsVectorToString(
*changed_params.codec_settings);
recv_codecs_ = *changed_params.codec_settings;
}
for (auto& kv : receive_streams_) {
kv.second->SetRecvParameters(changed_params);
}
recv_params_ = params;
return true;
}
WebRtcVideoChannel::GetChangedRecvParameters
就是通过对比接收到的解码器信息,和创建解码器时的信息,获取改变的参数,这里忽略flexfec的参数变化。
bool WebRtcVideoChannel::GetChangedRecvParameters(
const VideoRecvParameters& params,
ChangedRecvParameters* changed_params) const {
if (!ValidateCodecFormats(params.codecs) ||
!ValidateRtpExtensions(params.extensions)) {
return false;
}
// Handle receive codecs.
const std::vector<VideoCodecSettings> mapped_codecs =
MapCodecs(params.codecs);
if (mapped_codecs.empty()) {
RTC_LOG(LS_ERROR)
<< "GetChangedRecvParameters called without any video codecs.";
return false;
}
// Verify that every mapped codec is supported locally.
if (params.is_stream_active) {
const std::vector<VideoCodec> local_supported_codecs =
GetPayloadTypesAndDefaultCodecs(decoder_factory_,
/*is_decoder_factory=*/true,
call_->trials());
for (const VideoCodecSettings& mapped_codec : mapped_codecs) {
if (!FindMatchingCodec(local_supported_codecs, mapped_codec.codec)) {
RTC_LOG(LS_ERROR)
<< "GetChangedRecvParameters called with unsupported video codec: "
<< mapped_codec.codec.ToString();
return false;
}
}
}
if (NonFlexfecReceiveCodecsHaveChanged(recv_codecs_, mapped_codecs)) {
changed_params->codec_settings =
absl::optional<std::vector<VideoCodecSettings>>(mapped_codecs);
}
// Handle RTP header extensions.
std::vector<webrtc::RtpExtension> filtered_extensions = FilterRtpExtensions(
params.extensions, webrtc::RtpExtension::IsSupportedForVideo, false,
call_->trials());
if (filtered_extensions != recv_rtp_extensions_) {
changed_params->rtp_header_extensions =
absl::optional<std::vector<webrtc::RtpExtension>>(filtered_extensions);
}
int flexfec_payload_type = mapped_codecs.front().flexfec_payload_type;
if (flexfec_payload_type != recv_flexfec_payload_type_) {
changed_params->flexfec_payload_type = flexfec_payload_type;
}
return true;
}
WebRtcVideoChannel中的recvcodecs参数
这里是指构造WebRtcVideoChannel对象时,它的recvcodecs参数是从encoderfactory编码工厂中获取到的,这时候获取的编码的payloadtype值还是不确定的。
协商后的这个值,是从MediaSessionDescriptionFactory对象后获得的,是最终确定的编码参数值。
WebRtcVideoChannel::WebRtcVideoChannel(
webrtc::Call* call,
const MediaConfig& config,
const VideoOptions& options,
const webrtc::CryptoOptions& crypto_options,
webrtc::VideoEncoderFactory* encoder_factory,
webrtc::VideoDecoderFactory* decoder_factory,
webrtc::VideoBitrateAllocatorFactory* bitrate_allocator_factory)
: VideoMediaChannel(config),
worker_thread_(rtc::Thread::Current()),
call_(call),
unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_),
video_config_(config.video),
encoder_factory_(encoder_factory),
decoder_factory_(decoder_factory),
bitrate_allocator_factory_(bitrate_allocator_factory),
default_send_options_(options),
last_stats_log_ms_(-1),
discard_unknown_ssrc_packets_(
IsEnabled(call_->trials(),
"WebRTC-Video-DiscardPacketsWithUnknownSsrc")),
crypto_options_(crypto_options),
unknown_ssrc_packet_buffer_(
IsEnabled(call_->trials(),
"WebRTC-Video-BufferPacketsWithUnknownSsrc")
? new UnhandledPacketsBuffer()
: nullptr) {
RTC_DCHECK_RUN_ON(&thread_checker_);
network_thread_checker_.Detach();
rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc;
sending_ = false;
recv_codecs_ = MapCodecs(GetPayloadTypesAndDefaultCodecs(
decoder_factory_, /*is_decoder_factory=*/true, call_->trials()));
recv_flexfec_payload_type_ =
recv_codecs_.empty() ? 0 : recv_codecs_.front().flexfec_payload_type;
}
GetPayloadTypesAndDefaultCodecs
// This function will assign dynamic payload types (in the range [96, 127]) to
// the input codecs, and also add ULPFEC, RED, FlexFEC, and associated RTX
// codecs for recognized codecs (VP8, VP9, H264, and RED). It will also add
// default feedback params to the codecs.
// is_decoder_factory is needed to keep track of the implict assumption that any
// H264 decoder also supports constrained base line profile.
// Also, is_decoder_factory is used to decide whether FlexFEC video format
// should be advertised as supported.
// TODO(kron): Perhaps it is better to move the implicit knowledge to the place
// where codecs are negotiated.
template <class T>
std::vector<VideoCodec> GetPayloadTypesAndDefaultCodecs(
const T* factory,
bool is_decoder_factory,
const webrtc::WebRtcKeyValueConfig& trials) {
if (!factory) {
return {};
}
std::vector<webrtc::SdpVideoFormat> supported_formats =
factory->GetSupportedFormats();
if (is_decoder_factory) {
AddH264ConstrainedBaselineProfileToSupportedFormats(&supported_formats);
}
if (supported_formats.empty())
return std::vector<VideoCodec>();
// Due to interoperability issues with old Chrome/WebRTC versions only use
// the lower range for new codecs.
static const int kFirstDynamicPayloadTypeLowerRange = 35;
static const int kLastDynamicPayloadTypeLowerRange = 65;
static const int kFirstDynamicPayloadTypeUpperRange = 96;
static const int kLastDynamicPayloadTypeUpperRange = 127;
int payload_type_upper = kFirstDynamicPayloadTypeUpperRange;
int payload_type_lower = kFirstDynamicPayloadTypeLowerRange;
supported_formats.push_back(webrtc::SdpVideoFormat(kRedCodecName));
supported_formats.push_back(webrtc::SdpVideoFormat(kUlpfecCodecName));
// flexfec-03 is supported as
// - receive codec unless WebRTC-FlexFEC-03-Advertised is disabled
// - send codec if WebRTC-FlexFEC-03-Advertised is enabled
if ((is_decoder_factory &&
!IsDisabled(trials, "WebRTC-FlexFEC-03-Advertised")) ||
(!is_decoder_factory &&
IsEnabled(trials, "WebRTC-FlexFEC-03-Advertised"))) {
webrtc::SdpVideoFormat flexfec_format(kFlexfecCodecName);
// This value is currently arbitrarily set to 10 seconds. (The unit
// is microseconds.) This parameter MUST be present in the SDP, but
// we never use the actual value anywhere in our code however.
// TODO(brandtr): Consider honouring this value in the sender and receiver.
flexfec_format.parameters = {{kFlexfecFmtpRepairWindow, "10000000"}};
supported_formats.push_back(flexfec_format);
}
std::vector<VideoCodec> output_codecs;
for (const webrtc::SdpVideoFormat& format : supported_formats) {
VideoCodec codec(format);
bool isCodecValidForLowerRange =
absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName) ||
absl::EqualsIgnoreCase(codec.name, kAv1CodecName);
if (!isCodecValidForLowerRange) {
codec.id = payload_type_upper++;
} else {
codec.id = payload_type_lower++;
}
AddDefaultFeedbackParams(&codec, trials);
output_codecs.push_back(codec);
if (payload_type_upper > kLastDynamicPayloadTypeUpperRange) {
RTC_LOG(LS_ERROR)
<< "Out of dynamic payload types [96,127], skipping the rest.";
// TODO(https://bugs.chromium.org/p/webrtc/issues/detail?id=12194):
// continue in lower range.
break;
}
if (payload_type_lower > kLastDynamicPayloadTypeLowerRange) {
// TODO(https://bugs.chromium.org/p/webrtc/issues/detail?id=12248):
// return an error.
RTC_LOG(LS_ERROR)
<< "Out of dynamic payload types [35,65], skipping the rest.";
break;
}
// Add associated RTX codec for non-FEC codecs.
if (!absl::EqualsIgnoreCase(codec.name, kUlpfecCodecName) &&
!absl::EqualsIgnoreCase(codec.name, kFlexfecCodecName)) {
if (!isCodecValidForLowerRange) {
output_codecs.push_back(
VideoCodec::CreateRtxCodec(payload_type_upper++, codec.id));
} else {
output_codecs.push_back(
VideoCodec::CreateRtxCodec(payload_type_lower++, codec.id));
}
if (payload_type_upper > kLastDynamicPayloadTypeUpperRange) {
RTC_LOG(LS_ERROR)
<< "Out of dynamic payload types [96,127], skipping rtx.";
// TODO(https://bugs.chromium.org/p/webrtc/issues/detail?id=12194):
// continue in lower range.
break;
}
if (payload_type_lower > kLastDynamicPayloadTypeLowerRange) {
// TODO(https://bugs.chromium.org/p/webrtc/issues/detail?id=12248):
// return an error.
RTC_LOG(LS_ERROR)
<< "Out of dynamic payload types [35,65], skipping rtx.";
break;
}
}
}
return output_codecs;
}