| Index: webrtc/media/engine/webrtcvideoengine.cc
|
| diff --git a/webrtc/media/engine/webrtcvideoengine.cc b/webrtc/media/engine/webrtcvideoengine.cc
|
| index b6447329e265519da1f19d29f1227006feeff8c0..e38bc81610d3349fe0f440f3f57fbf383c0bc68d 100644
|
| --- a/webrtc/media/engine/webrtcvideoengine.cc
|
| +++ b/webrtc/media/engine/webrtcvideoengine.cc
|
| @@ -21,6 +21,7 @@
|
| #include "webrtc/api/video_codecs/video_encoder.h"
|
| #include "webrtc/call/call.h"
|
| #include "webrtc/common_video/h264/profile_level_id.h"
|
| +#include "webrtc/media/base/codec.h"
|
| #include "webrtc/media/engine/constants.h"
|
| #include "webrtc/media/engine/internaldecoderfactory.h"
|
| #include "webrtc/media/engine/internalencoderfactory.h"
|
| @@ -31,6 +32,8 @@
|
| #include "webrtc/media/engine/webrtcmediaengine.h"
|
| #include "webrtc/media/engine/webrtcvideoencoderfactory.h"
|
| #include "webrtc/media/engine/webrtcvoiceengine.h"
|
| +#include "webrtc/modules/video_coding/codecs/stereo/include/stereo_decoder_adapter.h"
|
| +#include "webrtc/modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
|
| #include "webrtc/rtc_base/copyonwritebuffer.h"
|
| #include "webrtc/rtc_base/logging.h"
|
| #include "webrtc/rtc_base/stringutils.h"
|
| @@ -62,6 +65,30 @@ bool IsVideoContentTypeExtensionFieldTrialEnabled() {
|
| return webrtc::field_trial::IsEnabled("WebRTC-VideoContentTypeExtension");
|
| }
|
|
|
| +// Wrap cricket::WebRtcVideoEncoderFactory as a webrtc::VideoEncoderFactory.
|
| +class EncoderFactoryAdapter : public webrtc::VideoEncoderFactory {
|
| + public:
|
| + // EncoderFactoryAdapter doesn't take ownership of |factory|, which is owned
|
| + // by e.g. PeerConnectionFactory.
|
| + explicit EncoderFactoryAdapter(cricket::WebRtcVideoEncoderFactory* factory,
|
| + const cricket::VideoCodec& codec)
|
| + : factory_(factory), codec_(codec) {}
|
| + virtual ~EncoderFactoryAdapter() {}
|
| +
|
| + // Implement webrtc::VideoEncoderFactory.
|
| + webrtc::VideoEncoder* Create() override {
|
| + return factory_->CreateVideoEncoder(codec_);
|
| + }
|
| +
|
| + void Destroy(webrtc::VideoEncoder* encoder) override {
|
| + return factory_->DestroyVideoEncoder(encoder);
|
| + }
|
| +
|
| + private:
|
| + cricket::WebRtcVideoEncoderFactory* const factory_;
|
| + const cricket::VideoCodec codec_;
|
| +};
|
| +
|
| // An encoder factory that wraps Create requests for simulcastable codec types
|
| // with a webrtc::SimulcastEncoderAdapter. Non simulcastable codec type
|
| // requests are just passed through to the contained encoder factory.
|
| @@ -131,6 +158,102 @@ class WebRtcSimulcastEncoderFactory
|
| std::vector<webrtc::VideoEncoder*> non_simulcast_encoders_;
|
| };
|
|
|
| +// An encoder factory that wraps Create requests for all codec types
|
| +// with a webrtc::StereoEncoderAdapter.
|
| +class WebRtcStereoEncoderFactory : public cricket::WebRtcVideoEncoderFactory {
|
| + public:
|
| + explicit WebRtcStereoEncoderFactory(
|
| + cricket::WebRtcVideoEncoderFactory* factory)
|
| + : factory_(factory) {}
|
| +
|
| + webrtc::VideoEncoder* CreateVideoEncoder(
|
| + const cricket::VideoCodec& codec) override {
|
| + RTC_DCHECK(factory_ != NULL);
|
| + return new webrtc::StereoEncoderAdapter(
|
| + new EncoderFactoryAdapter(factory_, codec));
|
| + }
|
| +
|
| + const std::vector<cricket::VideoCodec>& supported_codecs() const override {
|
| + return factory_->supported_codecs();
|
| + }
|
| +
|
| + bool EncoderTypeHasInternalSource(
|
| + webrtc::VideoCodecType type) const override {
|
| + return factory_->EncoderTypeHasInternalSource(type);
|
| + }
|
| +
|
| + void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override {
|
| + delete encoder;
|
| + }
|
| +
|
| + private:
|
| + cricket::WebRtcVideoEncoderFactory* factory_;
|
| +};
|
| +
|
| +// Wrap cricket::WebRtcVideoDecoderFactory as a webrtc::VideoDecoderFactory.
|
| +class DecoderFactoryAdapter : public webrtc::VideoDecoderFactory {
|
| + public:
|
| + // DecoderFactoryAdapter doesn't take ownership of |factory|.
|
| + explicit DecoderFactoryAdapter(cricket::WebRtcVideoDecoderFactory* factory,
|
| + webrtc::VideoCodecType type,
|
| + VideoDecoderParams* params)
|
| + : factory_(factory), type_(type) {
|
| + if (params) {
|
| + params_.reset(new VideoDecoderParams(*params));
|
| + }
|
| + }
|
| + virtual ~DecoderFactoryAdapter() {}
|
| +
|
| + // Implement webrtc::VideoDecoderFactory.
|
| + webrtc::VideoDecoder* Create() override {
|
| + RTC_DCHECK(factory_);
|
| + if (params_)
|
| + return factory_->CreateVideoDecoderWithParams(type_, *params_);
|
| + else
|
| + return factory_->CreateVideoDecoder(type_);
|
| + }
|
| +
|
| + void Destroy(webrtc::VideoDecoder* decoder) override {
|
| + return factory_->DestroyVideoDecoder(decoder);
|
| + }
|
| +
|
| + private:
|
| + cricket::WebRtcVideoDecoderFactory* const factory_;
|
| + const webrtc::VideoCodecType type_;
|
| + std::unique_ptr<VideoDecoderParams> params_;
|
| +};
|
| +
|
| +// A decoder factory that wraps Create requests for all codec types
|
| +// with a webrtc::StereoDecoderAdapter.
|
| +class WebRtcStereoDecoderFactory : public cricket::WebRtcVideoDecoderFactory {
|
| + public:
|
| + explicit WebRtcStereoDecoderFactory(
|
| + cricket::WebRtcVideoDecoderFactory* factory)
|
| + : factory_(factory) {}
|
| +
|
| + webrtc::VideoDecoder* CreateVideoDecoder(
|
| + webrtc::VideoCodecType type) override {
|
| + RTC_DCHECK(factory_ != NULL);
|
| + return new webrtc::StereoDecoderAdapter(
|
| + new DecoderFactoryAdapter(factory_, webrtc::kVideoCodecVP9, nullptr));
|
| + }
|
| +
|
| + webrtc::VideoDecoder* CreateVideoDecoderWithParams(
|
| + webrtc::VideoCodecType type,
|
| + VideoDecoderParams params) override {
|
| + RTC_DCHECK(factory_ != NULL);
|
| + return new webrtc::StereoDecoderAdapter(
|
| + new DecoderFactoryAdapter(factory_, webrtc::kVideoCodecVP9, ¶ms));
|
| + }
|
| +
|
| + void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) override {
|
| + delete decoder;
|
| + }
|
| +
|
| + private:
|
| + cricket::WebRtcVideoDecoderFactory* factory_;
|
| +};
|
| +
|
| void AddDefaultFeedbackParams(VideoCodec* codec) {
|
| codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamCcm, kRtcpFbCcmParamFir));
|
| codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
|
| @@ -526,6 +649,15 @@ static void AppendVideoCodecs(const std::vector<VideoCodec>& input_codecs,
|
| unified_codecs->push_back(
|
| VideoCodec::CreateRtxCodec(*rtx_payload_type, codec.id));
|
| }
|
| +
|
| + if (CodecNamesEq(codec.name, kVp9CodecName)) {
|
| + const rtc::Optional<int> stereo_payload_type =
|
| + NextFreePayloadType(*unified_codecs);
|
| + if (!stereo_payload_type)
|
| + return;
|
| + unified_codecs->push_back(
|
| + VideoCodec::CreateStereoCodec(*stereo_payload_type, codec));
|
| + }
|
| }
|
| }
|
|
|
| @@ -584,8 +716,12 @@ WebRtcVideoChannel::SelectSendVideoCodec(
|
| const std::vector<VideoCodecSettings>& remote_mapped_codecs) const {
|
| const std::vector<VideoCodec> local_supported_codecs =
|
| GetSupportedCodecs(external_encoder_factory_);
|
| +
|
| // Select the first remote codec that is supported locally.
|
| for (const VideoCodecSettings& remote_mapped_codec : remote_mapped_codecs) {
|
| + // HARDCODE TO ALPHA
|
| + if (!cricket::VideoCodec::IsStereoCodec(remote_mapped_codec.codec))
|
| + continue;
|
| // For H264, we will limit the encode level to the remote offered level
|
| // regardless if level asymmetry is allowed or not. This is strictly not
|
| // following the spec in https://tools.ietf.org/html/rfc6184#section-8.2.2
|
| @@ -598,6 +734,24 @@ WebRtcVideoChannel::SelectSendVideoCodec(
|
| return rtc::Optional<VideoCodecSettings>();
|
| }
|
|
|
| +rtc::Optional<WebRtcVideoChannel::VideoCodecSettings>
|
| +WebRtcVideoChannel::SelectStereoAssociatedVideoCodec(
|
| + const std::vector<VideoCodecSettings>& remote_mapped_codecs) const {
|
| + const std::vector<VideoCodec> local_supported_codecs =
|
| + GetSupportedCodecs(external_encoder_factory_);
|
| +
|
| + // Select the first remote codec that is supported locally.
|
| + for (const VideoCodecSettings& remote_mapped_codec : remote_mapped_codecs) {
|
| + // HARDCODE TO VP9
|
| + if (!CodecNamesEq(remote_mapped_codec.codec.name.c_str(), kVp9CodecName))
|
| + continue;
|
| + if (!cricket::VideoCodec::IsStereoCodec(remote_mapped_codec.codec) &&
|
| + FindMatchingCodec(local_supported_codecs, remote_mapped_codec.codec))
|
| + return rtc::Optional<VideoCodecSettings>(remote_mapped_codec);
|
| + }
|
| + return rtc::Optional<VideoCodecSettings>();
|
| +}
|
| +
|
| bool WebRtcVideoChannel::NonFlexfecReceiveCodecsHaveChanged(
|
| std::vector<VideoCodecSettings> before,
|
| std::vector<VideoCodecSettings> after) {
|
| @@ -644,6 +798,19 @@ bool WebRtcVideoChannel::GetChangedSendParameters(
|
| return false;
|
| }
|
|
|
| + if (VideoCodec::IsStereoCodec(selected_send_codec->codec)) {
|
| + rtc::Optional<VideoCodecSettings> associated_codec_settings =
|
| + SelectStereoAssociatedVideoCodec(MapCodecs(params.codecs));
|
| + LOG(LS_ERROR) << __func__ << associated_codec_settings->codec.ToString();
|
| + if (!associated_codec_settings) {
|
| + LOG(LS_ERROR)
|
| + << "Stereo codec is not associated with any supported codec.";
|
| + return false;
|
| + }
|
| + associated_codec_settings->stereo_codec.emplace(selected_send_codec->codec);
|
| + selected_send_codec = associated_codec_settings;
|
| + }
|
| +
|
| // Never enable sending FlexFEC, unless we are in the experiment.
|
| if (!IsFlexfecFieldTrialEnabled()) {
|
| if (selected_send_codec->flexfec_payload_type != -1) {
|
| @@ -1672,6 +1839,16 @@ WebRtcVideoChannel::WebRtcVideoSendStream::GetSsrcs() const {
|
| }
|
|
|
| WebRtcVideoChannel::WebRtcVideoSendStream::AllocatedEncoder
|
| +WebRtcVideoChannel::WebRtcVideoSendStream::CreateStereoVideoEncoder(
|
| + const VideoCodec& codec) {
|
| + WebRtcStereoEncoderFactory* stereo_factory =
|
| + new WebRtcStereoEncoderFactory(internal_encoder_factory_.get());
|
| + stereo_encoder_factory_.reset(stereo_factory);
|
| + return AllocatedEncoder(stereo_factory->CreateVideoEncoder(codec), codec,
|
| + false /* is_external */);
|
| +}
|
| +
|
| +WebRtcVideoChannel::WebRtcVideoSendStream::AllocatedEncoder
|
| WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoder(
|
| const VideoCodec& codec,
|
| bool force_encoder_allocation) {
|
| @@ -1730,12 +1907,21 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::SetCodec(
|
| parameters_.encoder_config = CreateVideoEncoderConfig(codec_settings.codec);
|
| RTC_DCHECK_GT(parameters_.encoder_config.number_of_streams, 0);
|
|
|
| + const bool is_stereo_codec = codec_settings.stereo_codec.has_value();
|
| AllocatedEncoder new_encoder =
|
| - CreateVideoEncoder(codec_settings.codec, force_encoder_allocation);
|
| + is_stereo_codec
|
| + ? CreateStereoVideoEncoder(codec_settings.codec)
|
| + : CreateVideoEncoder(codec_settings.codec, force_encoder_allocation);
|
| + VideoCodec payload_codec = is_stereo_codec
|
| + ? codec_settings.stereo_codec.value()
|
| + : codec_settings.codec;
|
| +
|
| parameters_.config.encoder_settings.encoder = new_encoder.encoder;
|
| + parameters_.config.encoder_settings.payload_name = payload_codec.name;
|
| + parameters_.config.encoder_settings.payload_type = payload_codec.id;
|
| + parameters_.config.encoder_settings.stereo_associated_payload_name =
|
| + codec_settings.codec.name;
|
| parameters_.config.encoder_settings.full_overuse_time = new_encoder.external;
|
| - parameters_.config.encoder_settings.payload_name = codec_settings.codec.name;
|
| - parameters_.config.encoder_settings.payload_type = codec_settings.codec.id;
|
| if (new_encoder.external) {
|
| webrtc::VideoCodecType type =
|
| webrtc::PayloadNameToCodecType(codec_settings.codec.name)
|
| @@ -1989,6 +2175,7 @@ VideoSenderInfo WebRtcVideoChannel::WebRtcVideoSendStream::GetVideoSenderInfo(
|
| for (uint32_t ssrc : parameters_.config.rtp.ssrcs)
|
| info.add_ssrc(ssrc);
|
|
|
| + // TODO(emircan): Add stereo codec case.
|
| if (parameters_.codec_settings) {
|
| info.codec_name = parameters_.codec_settings->codec.name;
|
| info.codec_payload_type = rtc::Optional<int>(
|
| @@ -2125,6 +2312,7 @@ WebRtcVideoChannel::WebRtcVideoReceiveStream::WebRtcVideoReceiveStream(
|
| flexfec_config_(flexfec_config),
|
| flexfec_stream_(nullptr),
|
| external_decoder_factory_(external_decoder_factory),
|
| + internal_decoder_factory_(new InternalDecoderFactory()),
|
| sink_(NULL),
|
| first_frame_timestamp_(-1),
|
| estimated_remote_start_ntp_time_ms_(0) {
|
| @@ -2179,6 +2367,19 @@ WebRtcVideoChannel::WebRtcVideoReceiveStream::GetFirstPrimarySsrc() const {
|
| }
|
|
|
| WebRtcVideoChannel::WebRtcVideoReceiveStream::AllocatedDecoder
|
| +WebRtcVideoChannel::WebRtcVideoReceiveStream::CreateStereoVideoDecoder(
|
| + const VideoCodec& codec) {
|
| + LOG(LS_ERROR) << __func__;
|
| + webrtc::VideoCodecType type = webrtc::PayloadNameToCodecType(codec.name)
|
| + .value_or(webrtc::kVideoCodecUnknown);
|
| + stereo_decoder_factory_.reset(
|
| + new WebRtcStereoDecoderFactory(internal_decoder_factory_.get()));
|
| + return AllocatedDecoder(stereo_decoder_factory_->CreateVideoDecoderWithParams(
|
| + type, {stream_params_.id}),
|
| + type, false /* is_external */);
|
| +}
|
| +
|
| +WebRtcVideoChannel::WebRtcVideoReceiveStream::AllocatedDecoder
|
| WebRtcVideoChannel::WebRtcVideoReceiveStream::CreateOrReuseVideoDecoder(
|
| std::vector<AllocatedDecoder>* old_decoders,
|
| const VideoCodec& codec) {
|
| @@ -2216,8 +2417,12 @@ void WebRtcVideoChannel::WebRtcVideoReceiveStream::ConfigureCodecs(
|
| allocated_decoders_.clear();
|
| config_.decoders.clear();
|
| for (size_t i = 0; i < recv_codecs.size(); ++i) {
|
| + const bool is_stereo_codec =
|
| + cricket::VideoCodec::IsStereoCodec(recv_codecs[i].codec);
|
| AllocatedDecoder allocated_decoder =
|
| - CreateOrReuseVideoDecoder(old_decoders, recv_codecs[i].codec);
|
| + is_stereo_codec
|
| + ? CreateStereoVideoDecoder(recv_codecs[i].codec)
|
| + : CreateOrReuseVideoDecoder(old_decoders, recv_codecs[i].codec);
|
| allocated_decoders_.push_back(allocated_decoder);
|
|
|
| webrtc::VideoReceiveStream::Decoder decoder;
|
|
|