diff options
-rw-r--r-- | remoting/codec/video_decoder_vpx_unittest.cc | 94 | ||||
-rw-r--r-- | remoting/codec/video_encoder_vpx.cc | 50 | ||||
-rw-r--r-- | remoting/codec/video_encoder_vpx.h | 1 | ||||
-rw-r--r-- | remoting/codec/video_encoder_vpx_unittest.cc | 6 | ||||
-rw-r--r-- | remoting/host/client_session.cc | 2 |
5 files changed, 140 insertions, 13 deletions
diff --git a/remoting/codec/video_decoder_vpx_unittest.cc b/remoting/codec/video_decoder_vpx_unittest.cc index eab0274..63cf870 100644 --- a/remoting/codec/video_decoder_vpx_unittest.cc +++ b/remoting/codec/video_decoder_vpx_unittest.cc @@ -12,6 +12,8 @@ namespace remoting { +namespace { + class VideoDecoderVpxTest : public testing::Test { protected: scoped_ptr<VideoEncoderVpx> encoder_; @@ -32,49 +34,121 @@ class VideoDecoderVpxTest : public testing::Test { } }; -TEST_F(VideoDecoderVpxTest, VideoEncodeAndDecode) { +class VideoDecoderVp8Test : public VideoDecoderVpxTest { + protected: + VideoDecoderVp8Test() { + encoder_ = VideoEncoderVpx::CreateForVP8(); + decoder_ = VideoDecoderVpx::CreateForVP8(); + } +}; + +class VideoDecoderVp9Test : public VideoDecoderVpxTest { + protected: + VideoDecoderVp9Test() { + encoder_ = VideoEncoderVpx::CreateForVP9(); + decoder_ = VideoDecoderVpx::CreateForVP9(); + } +}; + +} // namespace + +// +// Test the VP8 codec. +// + +TEST_F(VideoDecoderVp8Test, VideoEncodeAndDecode) { + TestVideoEncoderDecoder(encoder_.get(), decoder_.get(), false); +} + +// Check that encoding and decoding a particular frame doesn't change the +// frame too much. The frame used is a gradient, which does not contain sharp +// transitions, so encoding lossiness should not be too high. +TEST_F(VideoDecoderVp8Test, Gradient) { + TestGradient(320, 240, 320, 240, 0.04, 0.02); +} + +TEST_F(VideoDecoderVp8Test, GradientScaleUpEvenToEven) { + TestGradient(320, 240, 640, 480, 0.04, 0.02); +} + +TEST_F(VideoDecoderVp8Test, GradientScaleUpEvenToOdd) { + TestGradient(320, 240, 641, 481, 0.04, 0.02); +} + +TEST_F(VideoDecoderVp8Test, GradientScaleUpOddToEven) { + TestGradient(321, 241, 640, 480, 0.04, 0.02); +} + +TEST_F(VideoDecoderVp8Test, GradientScaleUpOddToOdd) { + TestGradient(321, 241, 641, 481, 0.04, 0.02); +} + +TEST_F(VideoDecoderVp8Test, GradientScaleDownEvenToEven) { + TestGradient(320, 240, 160, 120, 0.04, 0.02); +} + +TEST_F(VideoDecoderVp8Test, GradientScaleDownEvenToOdd) { + // The maximum error is non-deterministic. The mean error is not too high, + // which suggests that the problem is restricted to a small area of the output + // image. See crbug.com/139437 and crbug.com/139633. + TestGradient(320, 240, 161, 121, 1.0, 0.02); +} + +TEST_F(VideoDecoderVp8Test, GradientScaleDownOddToEven) { + TestGradient(321, 241, 160, 120, 0.04, 0.02); +} + +TEST_F(VideoDecoderVp8Test, GradientScaleDownOddToOdd) { + TestGradient(321, 241, 161, 121, 0.04, 0.02); +} + +// +// Test the VP9 codec. +// + +TEST_F(VideoDecoderVp9Test, VideoEncodeAndDecode) { TestVideoEncoderDecoder(encoder_.get(), decoder_.get(), false); } // Check that encoding and decoding a particular frame doesn't change the // frame too much. The frame used is a gradient, which does not contain sharp // transitions, so encoding lossiness should not be too high. -TEST_F(VideoDecoderVpxTest, Gradient) { +TEST_F(VideoDecoderVp9Test, Gradient) { TestGradient(320, 240, 320, 240, 0.04, 0.02); } -TEST_F(VideoDecoderVpxTest, GradientScaleUpEvenToEven) { +TEST_F(VideoDecoderVp9Test, GradientScaleUpEvenToEven) { TestGradient(320, 240, 640, 480, 0.04, 0.02); } -TEST_F(VideoDecoderVpxTest, GradientScaleUpEvenToOdd) { +TEST_F(VideoDecoderVp9Test, GradientScaleUpEvenToOdd) { TestGradient(320, 240, 641, 481, 0.04, 0.02); } -TEST_F(VideoDecoderVpxTest, GradientScaleUpOddToEven) { +TEST_F(VideoDecoderVp9Test, GradientScaleUpOddToEven) { TestGradient(321, 241, 640, 480, 0.04, 0.02); } -TEST_F(VideoDecoderVpxTest, GradientScaleUpOddToOdd) { +TEST_F(VideoDecoderVp9Test, GradientScaleUpOddToOdd) { TestGradient(321, 241, 641, 481, 0.04, 0.02); } -TEST_F(VideoDecoderVpxTest, GradientScaleDownEvenToEven) { +TEST_F(VideoDecoderVp9Test, GradientScaleDownEvenToEven) { TestGradient(320, 240, 160, 120, 0.04, 0.02); } -TEST_F(VideoDecoderVpxTest, GradientScaleDownEvenToOdd) { +TEST_F(VideoDecoderVp9Test, GradientScaleDownEvenToOdd) { // The maximum error is non-deterministic. The mean error is not too high, // which suggests that the problem is restricted to a small area of the output // image. See crbug.com/139437 and crbug.com/139633. TestGradient(320, 240, 161, 121, 1.0, 0.02); } -TEST_F(VideoDecoderVpxTest, GradientScaleDownOddToEven) { +TEST_F(VideoDecoderVp9Test, GradientScaleDownOddToEven) { TestGradient(321, 241, 160, 120, 0.04, 0.02); } -TEST_F(VideoDecoderVpxTest, GradientScaleDownOddToOdd) { +TEST_F(VideoDecoderVp9Test, GradientScaleDownOddToOdd) { TestGradient(321, 241, 161, 121, 0.04, 0.02); } diff --git a/remoting/codec/video_encoder_vpx.cc b/remoting/codec/video_encoder_vpx.cc index 02df60b..0977564 100644 --- a/remoting/codec/video_encoder_vpx.cc +++ b/remoting/codec/video_encoder_vpx.cc @@ -77,6 +77,50 @@ ScopedVpxCodec CreateVP8Codec(const webrtc::DesktopSize& size) { return codec.Pass(); } +ScopedVpxCodec CreateVP9Codec(const webrtc::DesktopSize& size) { + ScopedVpxCodec codec(new vpx_codec_ctx_t); + + // Configure the encoder. + vpx_codec_enc_cfg_t config; + const vpx_codec_iface_t* algo = vpx_codec_vp9_cx(); + CHECK(algo); + vpx_codec_err_t ret = vpx_codec_enc_config_default(algo, &config, 0); + if (ret != VPX_CODEC_OK) + return ScopedVpxCodec(); + + //config.rc_target_bitrate = size.width() * size.height() * + // config.rc_target_bitrate / config.g_w / config.g_h; + config.g_w = size.width(); + config.g_h = size.height(); + config.g_pass = VPX_RC_ONE_PASS; + + // Only the default profile is currently supported for VP9 encoding. + config.g_profile = 0; + + // Start emitting packets immediately. + config.g_lag_in_frames = 0; + + // Prevent VP9 from ruining output quality with quantization. + config.rc_max_quantizer = 0; + + if (vpx_codec_enc_init(codec.get(), algo, &config, 0)) + return ScopedVpxCodec(); + + // VP9 encode doesn't yet support Realtime, so falls back to Good quality, + // for which 4 is the lowest CPU usage. + // Note that this is configured via the same parameter as for VP8. + if (vpx_codec_control(codec.get(), VP8E_SET_CPUUSED, 4)) + return ScopedVpxCodec(); + + // Use the lowest level of noise sensitivity so as to spend less time + // on motion estimation and inter-prediction mode. + // Note that this is configured via the same parameter as for VP8. + if (vpx_codec_control(codec.get(), VP8E_SET_NOISE_SENSITIVITY, 0)) + return ScopedVpxCodec(); + + return codec.Pass(); +} + } // namespace // static @@ -85,6 +129,12 @@ scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP8() { new VideoEncoderVpx(base::Bind(&CreateVP8Codec))); } +// static +scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP9() { + return scoped_ptr<VideoEncoderVpx>( + new VideoEncoderVpx(base::Bind(&CreateVP9Codec))); +} + VideoEncoderVpx::~VideoEncoderVpx() {} scoped_ptr<VideoPacket> VideoEncoderVpx::Encode( diff --git a/remoting/codec/video_encoder_vpx.h b/remoting/codec/video_encoder_vpx.h index f847bb5..286745f 100644 --- a/remoting/codec/video_encoder_vpx.h +++ b/remoting/codec/video_encoder_vpx.h @@ -22,6 +22,7 @@ class VideoEncoderVpx : public VideoEncoder { public: // Create encoder for the specified protocol. static scoped_ptr<VideoEncoderVpx> CreateForVP8(); + static scoped_ptr<VideoEncoderVpx> CreateForVP9(); virtual ~VideoEncoderVpx(); diff --git a/remoting/codec/video_encoder_vpx_unittest.cc b/remoting/codec/video_encoder_vpx_unittest.cc index f5a0c8d..462af9c 100644 --- a/remoting/codec/video_encoder_vpx_unittest.cc +++ b/remoting/codec/video_encoder_vpx_unittest.cc @@ -21,14 +21,14 @@ const int kIntMax = std::numeric_limits<int>::max(); namespace remoting { -TEST(VideoEncoderVpxTest, TestVideoEncoder) { +TEST(VideoEncoderVp8Test, TestVideoEncoder) { scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8()); TestVideoEncoder(encoder.get(), false); } // Test that calling Encode with a differently-sized media::ScreenCaptureData // does not leak memory. -TEST(VideoEncoderVpxTest, TestSizeChangeNoLeak) { +TEST(VideoEncoderVp8Test, TestSizeChangeNoLeak) { int height = 1000; int width = 1000; @@ -49,7 +49,7 @@ TEST(VideoEncoderVpxTest, TestSizeChangeNoLeak) { // Test that the DPI information is correctly propagated from the // media::ScreenCaptureData to the VideoPacket. -TEST(VideoEncoderVpxTest, TestDpiPropagation) { +TEST(VideoEncoderVp8Test, TestDpiPropagation) { int height = 32; int width = 32; diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index 6057f12..7a3c76c 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc @@ -444,6 +444,8 @@ scoped_ptr<VideoEncoder> ClientSession::CreateVideoEncoder( if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) { return remoting::VideoEncoderVpx::CreateForVP8().PassAs<VideoEncoder>(); + } else if (video_config.codec == protocol::ChannelConfig::CODEC_VP9) { + return remoting::VideoEncoderVpx::CreateForVP9().PassAs<VideoEncoder>(); } NOTREACHED(); |