Implement SimulcastEncoderAdapter support.
R=stefan@webrtc.org BUG=1788 Review URL: https://webrtc-codereview.appspot.com/37589004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@8061 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
8315d7de85
commit
f18fba2f7b
@ -153,9 +153,16 @@ class FakeWebRtcVideoEncoder : public webrtc::VideoEncoder {
|
|||||||
virtual int32 InitEncode(const webrtc::VideoCodec* codecSettings,
|
virtual int32 InitEncode(const webrtc::VideoCodec* codecSettings,
|
||||||
int32 numberOfCores,
|
int32 numberOfCores,
|
||||||
size_t maxPayloadSize) {
|
size_t maxPayloadSize) {
|
||||||
|
rtc::CritScope lock(&crit_);
|
||||||
|
codec_settings_ = *codecSettings;
|
||||||
return WEBRTC_VIDEO_CODEC_OK;
|
return WEBRTC_VIDEO_CODEC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webrtc::VideoCodec GetCodecSettings() {
|
||||||
|
rtc::CritScope lock(&crit_);
|
||||||
|
return codec_settings_;
|
||||||
|
}
|
||||||
|
|
||||||
virtual int32 Encode(
|
virtual int32 Encode(
|
||||||
const webrtc::I420VideoFrame& inputImage,
|
const webrtc::I420VideoFrame& inputImage,
|
||||||
const webrtc::CodecSpecificInfo* codecSpecificInfo,
|
const webrtc::CodecSpecificInfo* codecSpecificInfo,
|
||||||
@ -192,6 +199,7 @@ class FakeWebRtcVideoEncoder : public webrtc::VideoEncoder {
|
|||||||
private:
|
private:
|
||||||
rtc::CriticalSection crit_;
|
rtc::CriticalSection crit_;
|
||||||
int num_frames_encoded_ GUARDED_BY(crit_);
|
int num_frames_encoded_ GUARDED_BY(crit_);
|
||||||
|
webrtc::VideoCodec codec_settings_ GUARDED_BY(crit_);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fake class for mocking out WebRtcVideoEncoderFactory.
|
// Fake class for mocking out WebRtcVideoEncoderFactory.
|
||||||
|
@ -138,36 +138,6 @@ class EncoderFactoryAdapter : public webrtc::VideoEncoderFactory {
|
|||||||
cricket::WebRtcVideoEncoderFactory* factory_;
|
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<webrtc::VideoEncoderFactory>(
|
|
||||||
new EncoderFactoryAdapter(factory_)).Pass());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const std::vector<VideoCodec>& codecs() const OVERRIDE {
|
|
||||||
return factory_->codecs();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE {
|
|
||||||
delete encoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
cricket::WebRtcVideoEncoderFactory* factory_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace cricket {
|
namespace cricket {
|
||||||
@ -316,6 +286,37 @@ std::vector<VideoCodec> DefaultVideoCodecList() {
|
|||||||
return codecs;
|
return codecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebRtcSimulcastEncoderFactory::WebRtcSimulcastEncoderFactory(
|
||||||
|
cricket::WebRtcVideoEncoderFactory* factory)
|
||||||
|
: factory_(factory) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WebRtcSimulcastEncoderFactory::~WebRtcSimulcastEncoderFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebRtcSimulcastEncoderFactory::UseSimulcastEncoderFactory(
|
||||||
|
const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& 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<WebRtcVideoEncoderFactory::VideoCodec>&
|
||||||
|
WebRtcSimulcastEncoderFactory::codecs() const {
|
||||||
|
return factory_->codecs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRtcSimulcastEncoderFactory::DestroyVideoEncoder(
|
||||||
|
webrtc::VideoEncoder* encoder) {
|
||||||
|
delete encoder;
|
||||||
|
}
|
||||||
|
|
||||||
struct FlushBlackFrameData : public rtc::MessageData {
|
struct FlushBlackFrameData : public rtc::MessageData {
|
||||||
FlushBlackFrameData(uint32 s, int64 t, int i)
|
FlushBlackFrameData(uint32 s, int64 t, int i)
|
||||||
: ssrc(s), timestamp(t), interval(i) {
|
: ssrc(s), timestamp(t), interval(i) {
|
||||||
@ -1690,15 +1691,15 @@ void WebRtcVideoEngine::SetExternalEncoderFactory(
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// No matter what happens we shouldn't hold on to a stale
|
// No matter what happens we shouldn't hold on to a stale
|
||||||
// SimulcastEncoderFactory.
|
// WebRtcSimulcastEncoderFactory.
|
||||||
simulcast_encoder_factory_.reset();
|
simulcast_encoder_factory_.reset();
|
||||||
|
|
||||||
if (encoder_factory) {
|
if (encoder_factory) {
|
||||||
const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs =
|
const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs =
|
||||||
encoder_factory->codecs();
|
encoder_factory->codecs();
|
||||||
if (codecs.size() == 1 && codecs[0].type == webrtc::kVideoCodecVP8) {
|
if (WebRtcSimulcastEncoderFactory::UseSimulcastEncoderFactory(codecs)) {
|
||||||
simulcast_encoder_factory_.reset(
|
simulcast_encoder_factory_.reset(
|
||||||
new SimulcastEncoderFactory(encoder_factory));
|
new WebRtcSimulcastEncoderFactory(encoder_factory));
|
||||||
encoder_factory = simulcast_encoder_factory_.get();
|
encoder_factory = simulcast_encoder_factory_.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,6 +523,28 @@ class WebRtcVideoMediaChannel : public rtc::MessageHandler,
|
|||||||
int ratio_h_;
|
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<VideoCodec>& codecs);
|
||||||
|
|
||||||
|
virtual webrtc::VideoEncoder* CreateVideoEncoder(
|
||||||
|
webrtc::VideoCodecType type) OVERRIDE;
|
||||||
|
virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
|
||||||
|
virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
cricket::WebRtcVideoEncoderFactory* factory_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
|
||||||
#endif // TALK_MEDIA_WEBRTCVIDEOENGINE_H_
|
#endif // TALK_MEDIA_WEBRTCVIDEOENGINE_H_
|
||||||
|
@ -477,6 +477,20 @@ void WebRtcVideoEngine2::SetExternalDecoderFactory(
|
|||||||
void WebRtcVideoEngine2::SetExternalEncoderFactory(
|
void WebRtcVideoEngine2::SetExternalEncoderFactory(
|
||||||
WebRtcVideoEncoderFactory* encoder_factory) {
|
WebRtcVideoEncoderFactory* encoder_factory) {
|
||||||
assert(!initialized_);
|
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;
|
external_encoder_factory_ = encoder_factory;
|
||||||
|
|
||||||
video_codecs_ = GetSupportedCodecs();
|
video_codecs_ = GetSupportedCodecs();
|
||||||
|
@ -208,6 +208,7 @@ class WebRtcVideoEngine2 : public sigslot::has_slots<> {
|
|||||||
|
|
||||||
WebRtcVideoDecoderFactory* external_decoder_factory_;
|
WebRtcVideoDecoderFactory* external_decoder_factory_;
|
||||||
WebRtcVideoEncoderFactory* external_encoder_factory_;
|
WebRtcVideoEncoderFactory* external_encoder_factory_;
|
||||||
|
rtc::scoped_ptr<WebRtcVideoEncoderFactory> simulcast_encoder_factory_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebRtcVideoChannel2 : public rtc::MessageHandler,
|
class WebRtcVideoChannel2 : public rtc::MessageHandler,
|
||||||
|
@ -592,6 +592,35 @@ VideoMediaChannel* WebRtcVideoEngine2Test::SetUpForExternalDecoderFactory(
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRtcVideoEngine2Test, UsesSimulcastAdapterForVp8Factories) {
|
||||||
|
cricket::FakeWebRtcVideoEncoderFactory encoder_factory;
|
||||||
|
encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
|
||||||
|
std::vector<cricket::VideoCodec> codecs;
|
||||||
|
codecs.push_back(kVp8Codec);
|
||||||
|
|
||||||
|
rtc::scoped_ptr<VideoMediaChannel> channel(
|
||||||
|
SetUpForExternalEncoderFactory(&encoder_factory, codecs));
|
||||||
|
|
||||||
|
std::vector<uint32> 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) {
|
TEST_F(WebRtcVideoEngine2Test, ChannelWithExternalH264CanChangeToInternalVp8) {
|
||||||
cricket::FakeWebRtcVideoEncoderFactory encoder_factory;
|
cricket::FakeWebRtcVideoEncoderFactory encoder_factory;
|
||||||
encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecH264, "H264");
|
encoder_factory.AddSupportedVideoCodecType(webrtc::kVideoCodecH264, "H264");
|
||||||
|
@ -116,9 +116,8 @@ struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayers::Factory {
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
SimulcastEncoderAdapter::SimulcastEncoderAdapter(
|
SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory)
|
||||||
scoped_ptr<VideoEncoderFactory> factory)
|
: factory_(factory), encoded_complete_callback_(NULL) {
|
||||||
: factory_(factory.Pass()), encoded_complete_callback_(NULL) {
|
|
||||||
memset(&codec_, 0, sizeof(webrtc::VideoCodec));
|
memset(&codec_, 0, sizeof(webrtc::VideoCodec));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,7 @@ class VideoEncoderFactory {
|
|||||||
class SimulcastEncoderAdapter : public VP8Encoder,
|
class SimulcastEncoderAdapter : public VP8Encoder,
|
||||||
public EncodedImageCallback {
|
public EncodedImageCallback {
|
||||||
public:
|
public:
|
||||||
explicit SimulcastEncoderAdapter(scoped_ptr<VideoEncoderFactory> factory);
|
explicit SimulcastEncoderAdapter(VideoEncoderFactory* factory);
|
||||||
|
|
||||||
virtual ~SimulcastEncoderAdapter();
|
virtual ~SimulcastEncoderAdapter();
|
||||||
|
|
||||||
// Implements VideoEncoder
|
// Implements VideoEncoder
|
||||||
|
@ -171,8 +171,7 @@ class TestSimulcastEncoderAdapterFakeHelper {
|
|||||||
// Can only be called once as the SimulcastEncoderAdapter will take the
|
// Can only be called once as the SimulcastEncoderAdapter will take the
|
||||||
// ownership of |factory_|.
|
// ownership of |factory_|.
|
||||||
VP8Encoder* CreateMockEncoderAdapter() {
|
VP8Encoder* CreateMockEncoderAdapter() {
|
||||||
scoped_ptr<VideoEncoderFactory> scoped_factory(factory_);
|
return new SimulcastEncoderAdapter(factory_);
|
||||||
return new SimulcastEncoderAdapter(scoped_factory.Pass());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) {
|
void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) {
|
||||||
|
@ -32,8 +32,7 @@ class VP8EncoderImplFactory : public VideoEncoderFactory {
|
|||||||
|
|
||||||
VP8Encoder* VP8Encoder::Create() {
|
VP8Encoder* VP8Encoder::Create() {
|
||||||
if (VP8EncoderFactoryConfig::use_simulcast_adapter()) {
|
if (VP8EncoderFactoryConfig::use_simulcast_adapter()) {
|
||||||
scoped_ptr<VideoEncoderFactory> factory(new VP8EncoderImplFactory());
|
return new SimulcastEncoderAdapter(new VP8EncoderImplFactory());
|
||||||
return new SimulcastEncoderAdapter(factory.Pass());
|
|
||||||
} else {
|
} else {
|
||||||
return new VP8EncoderImpl();
|
return new VP8EncoderImpl();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user