diff --git a/talk/media/webrtc/fakewebrtcvideoengine.h b/talk/media/webrtc/fakewebrtcvideoengine.h index b4e6b3b39..73d9c3553 100644 --- a/talk/media/webrtc/fakewebrtcvideoengine.h +++ b/talk/media/webrtc/fakewebrtcvideoengine.h @@ -153,9 +153,16 @@ class FakeWebRtcVideoEncoder : public webrtc::VideoEncoder { virtual int32 InitEncode(const webrtc::VideoCodec* codecSettings, int32 numberOfCores, size_t maxPayloadSize) { + rtc::CritScope lock(&crit_); + codec_settings_ = *codecSettings; return WEBRTC_VIDEO_CODEC_OK; } + webrtc::VideoCodec GetCodecSettings() { + rtc::CritScope lock(&crit_); + return codec_settings_; + } + virtual int32 Encode( const webrtc::I420VideoFrame& inputImage, const webrtc::CodecSpecificInfo* codecSpecificInfo, @@ -192,6 +199,7 @@ class FakeWebRtcVideoEncoder : public webrtc::VideoEncoder { private: rtc::CriticalSection crit_; int num_frames_encoded_ GUARDED_BY(crit_); + webrtc::VideoCodec codec_settings_ GUARDED_BY(crit_); }; // Fake class for mocking out WebRtcVideoEncoderFactory. diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc index ec8445e97..63b977e4c 100644 --- a/talk/media/webrtc/webrtcvideoengine.cc +++ b/talk/media/webrtc/webrtcvideoengine.cc @@ -138,36 +138,6 @@ class EncoderFactoryAdapter : public webrtc::VideoEncoderFactory { cricket::WebRtcVideoEncoderFactory* factory_; }; -// Wrap encoder factory to a simulcast encoder factory. -class SimulcastEncoderFactory : public cricket::WebRtcVideoEncoderFactory { - public: - // SimulcastEncoderFactory doesn't take ownership of |factory|, which is owned - // by e.g. PeerConnectionFactory. - explicit SimulcastEncoderFactory(cricket::WebRtcVideoEncoderFactory* factory) - : factory_(factory) {} - virtual ~SimulcastEncoderFactory() {} - - virtual webrtc::VideoEncoder* CreateVideoEncoder( - webrtc::VideoCodecType type) OVERRIDE { - ASSERT(type == webrtc::kVideoCodecVP8); - ASSERT(factory_ != NULL); - return new webrtc::SimulcastEncoderAdapter( - webrtc::scoped_ptr( - new EncoderFactoryAdapter(factory_)).Pass()); - } - - virtual const std::vector& codecs() const OVERRIDE { - return factory_->codecs(); - } - - virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE { - delete encoder; - } - - private: - cricket::WebRtcVideoEncoderFactory* factory_; -}; - } // namespace namespace cricket { @@ -316,6 +286,37 @@ std::vector DefaultVideoCodecList() { return codecs; } +WebRtcSimulcastEncoderFactory::WebRtcSimulcastEncoderFactory( + cricket::WebRtcVideoEncoderFactory* factory) + : factory_(factory) { +} + +WebRtcSimulcastEncoderFactory::~WebRtcSimulcastEncoderFactory() { +} + +bool WebRtcSimulcastEncoderFactory::UseSimulcastEncoderFactory( + const std::vector& codecs) { + return codecs.size() == 1 && codecs[0].type == webrtc::kVideoCodecVP8; +} + +webrtc::VideoEncoder* WebRtcSimulcastEncoderFactory::CreateVideoEncoder( + webrtc::VideoCodecType type) { + ASSERT(type == webrtc::kVideoCodecVP8); + ASSERT(factory_ != NULL); + return new webrtc::SimulcastEncoderAdapter( + new EncoderFactoryAdapter(factory_)); +} + +const std::vector& +WebRtcSimulcastEncoderFactory::codecs() const { + return factory_->codecs(); +} + +void WebRtcSimulcastEncoderFactory::DestroyVideoEncoder( + webrtc::VideoEncoder* encoder) { + delete encoder; +} + struct FlushBlackFrameData : public rtc::MessageData { FlushBlackFrameData(uint32 s, int64 t, int i) : ssrc(s), timestamp(t), interval(i) { @@ -1690,15 +1691,15 @@ void WebRtcVideoEngine::SetExternalEncoderFactory( return; // No matter what happens we shouldn't hold on to a stale - // SimulcastEncoderFactory. + // WebRtcSimulcastEncoderFactory. simulcast_encoder_factory_.reset(); if (encoder_factory) { const std::vector& codecs = encoder_factory->codecs(); - if (codecs.size() == 1 && codecs[0].type == webrtc::kVideoCodecVP8) { + if (WebRtcSimulcastEncoderFactory::UseSimulcastEncoderFactory(codecs)) { simulcast_encoder_factory_.reset( - new SimulcastEncoderFactory(encoder_factory)); + new WebRtcSimulcastEncoderFactory(encoder_factory)); encoder_factory = simulcast_encoder_factory_.get(); } } diff --git a/talk/media/webrtc/webrtcvideoengine.h b/talk/media/webrtc/webrtcvideoengine.h index 78a10e0bf..73f86b08f 100644 --- a/talk/media/webrtc/webrtcvideoengine.h +++ b/talk/media/webrtc/webrtcvideoengine.h @@ -523,6 +523,28 @@ class WebRtcVideoMediaChannel : public rtc::MessageHandler, int ratio_h_; }; +// Wrap encoder factory to a simulcast encoder factory. Exposed here for code to +// be shared with WebRtcVideoEngine2, not to be used externally. +class WebRtcSimulcastEncoderFactory + : public cricket::WebRtcVideoEncoderFactory { + public: + // WebRtcSimulcastEncoderFactory doesn't take ownership of |factory|, which is + // owned by e.g. PeerConnectionFactory. + explicit WebRtcSimulcastEncoderFactory( + cricket::WebRtcVideoEncoderFactory* factory); + virtual ~WebRtcSimulcastEncoderFactory(); + + static bool UseSimulcastEncoderFactory(const std::vector& codecs); + + virtual webrtc::VideoEncoder* CreateVideoEncoder( + webrtc::VideoCodecType type) OVERRIDE; + virtual const std::vector& codecs() const OVERRIDE; + virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE; + + private: + cricket::WebRtcVideoEncoderFactory* factory_; +}; + } // namespace cricket #endif // TALK_MEDIA_WEBRTCVIDEOENGINE_H_ diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc index d066eb9c9..2bb104ac3 100644 --- a/talk/media/webrtc/webrtcvideoengine2.cc +++ b/talk/media/webrtc/webrtcvideoengine2.cc @@ -477,6 +477,20 @@ void WebRtcVideoEngine2::SetExternalDecoderFactory( void WebRtcVideoEngine2::SetExternalEncoderFactory( WebRtcVideoEncoderFactory* encoder_factory) { assert(!initialized_); + if (external_encoder_factory_ == encoder_factory) + return; + + // No matter what happens we shouldn't hold on to a stale + // WebRtcSimulcastEncoderFactory. + simulcast_encoder_factory_.reset(); + + if (encoder_factory && + WebRtcSimulcastEncoderFactory::UseSimulcastEncoderFactory( + encoder_factory->codecs())) { + simulcast_encoder_factory_.reset( + new WebRtcSimulcastEncoderFactory(encoder_factory)); + encoder_factory = simulcast_encoder_factory_.get(); + } external_encoder_factory_ = encoder_factory; video_codecs_ = GetSupportedCodecs(); diff --git a/talk/media/webrtc/webrtcvideoengine2.h b/talk/media/webrtc/webrtcvideoengine2.h index 2318971db..f5a97a26a 100644 --- a/talk/media/webrtc/webrtcvideoengine2.h +++ b/talk/media/webrtc/webrtcvideoengine2.h @@ -208,6 +208,7 @@ class WebRtcVideoEngine2 : public sigslot::has_slots<> { WebRtcVideoDecoderFactory* external_decoder_factory_; WebRtcVideoEncoderFactory* external_encoder_factory_; + rtc::scoped_ptr simulcast_encoder_factory_; }; class WebRtcVideoChannel2 : public rtc::MessageHandler, diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc index 93660a572..1796500c5 100644 --- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc +++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc @@ -592,6 +592,35 @@ VideoMediaChannel* WebRtcVideoEngine2Test::SetUpForExternalDecoderFactory( return channel; } +TEST_F(WebRtcVideoEngine2Test, UsesSimulcastAdapterForVp8Factories) { + cricket::FakeWebRtcVideoEncoderFactory encoder_factory; + encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8"); + std::vector codecs; + codecs.push_back(kVp8Codec); + + rtc::scoped_ptr channel( + SetUpForExternalEncoderFactory(&encoder_factory, codecs)); + + std::vector ssrcs = MAKE_VECTOR(kSsrcs3); + + EXPECT_TRUE( + channel->AddSendStream(CreateSimStreamParams("cname", ssrcs))); + EXPECT_TRUE(channel->SetSend(true)); + + EXPECT_GT(encoder_factory.encoders().size(), 1u); + + // Verify that encoders are configured for simulcast through adapter + // (increasing resolution and only configured to send one stream each). + int prev_width = -1; + for (size_t i = 0; i < encoder_factory.encoders().size(); ++i) { + webrtc::VideoCodec codec_settings = + encoder_factory.encoders()[i]->GetCodecSettings(); + EXPECT_EQ(0, codec_settings.numberOfSimulcastStreams); + EXPECT_GT(codec_settings.width, prev_width); + prev_width = codec_settings.width; + } +} + TEST_F(WebRtcVideoEngine2Test, ChannelWithExternalH264CanChangeToInternalVp8) { cricket::FakeWebRtcVideoEncoderFactory encoder_factory; encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecH264, "H264"); diff --git a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc index d37308b01..15b6023d9 100644 --- a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc +++ b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.cc @@ -116,9 +116,8 @@ struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayers::Factory { namespace webrtc { -SimulcastEncoderAdapter::SimulcastEncoderAdapter( - scoped_ptr factory) - : factory_(factory.Pass()), encoded_complete_callback_(NULL) { +SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory) + : factory_(factory), encoded_complete_callback_(NULL) { memset(&codec_, 0, sizeof(webrtc::VideoCodec)); } diff --git a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h index 51127fbef..ca900e0f8 100644 --- a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h +++ b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h @@ -33,8 +33,7 @@ class VideoEncoderFactory { class SimulcastEncoderAdapter : public VP8Encoder, public EncodedImageCallback { public: - explicit SimulcastEncoderAdapter(scoped_ptr factory); - + explicit SimulcastEncoderAdapter(VideoEncoderFactory* factory); virtual ~SimulcastEncoderAdapter(); // Implements VideoEncoder diff --git a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc index 870dcc72d..36a30a38e 100644 --- a/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc +++ b/webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter_unittest.cc @@ -171,8 +171,7 @@ class TestSimulcastEncoderAdapterFakeHelper { // Can only be called once as the SimulcastEncoderAdapter will take the // ownership of |factory_|. VP8Encoder* CreateMockEncoderAdapter() { - scoped_ptr scoped_factory(factory_); - return new SimulcastEncoderAdapter(scoped_factory.Pass()); + return new SimulcastEncoderAdapter(factory_); } void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) { diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_factory.cc b/webrtc/modules/video_coding/codecs/vp8/vp8_factory.cc index eb274c6a9..414b3a704 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_factory.cc +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_factory.cc @@ -32,8 +32,7 @@ class VP8EncoderImplFactory : public VideoEncoderFactory { VP8Encoder* VP8Encoder::Create() { if (VP8EncoderFactoryConfig::use_simulcast_adapter()) { - scoped_ptr factory(new VP8EncoderImplFactory()); - return new SimulcastEncoderAdapter(factory.Pass()); + return new SimulcastEncoderAdapter(new VP8EncoderImplFactory()); } else { return new VP8EncoderImpl(); }