summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--remoting/codec/video_decoder_vpx_unittest.cc94
-rw-r--r--remoting/codec/video_encoder_vpx.cc50
-rw-r--r--remoting/codec/video_encoder_vpx.h1
-rw-r--r--remoting/codec/video_encoder_vpx_unittest.cc6
-rw-r--r--remoting/host/client_session.cc2
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();