summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-19 22:14:54 +0000
committerwez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-19 22:14:54 +0000
commita43cfae9c2ead7b9b14882101f2264a785f17f41 (patch)
tree0c715d27bef0304b2a7122ca622238673a34cb1e
parentffd8afd8391366b1a0bdcc849d973dc1e5fee6d9 (diff)
downloadchromium_src-a43cfae9c2ead7b9b14882101f2264a785f17f41.zip
chromium_src-a43cfae9c2ead7b9b14882101f2264a785f17f41.tar.gz
chromium_src-a43cfae9c2ead7b9b14882101f2264a785f17f41.tar.bz2
Move VideoDecoderVp8 to VideoDecoderVpx base that will support VP8/9.
BUG=260879 Review URL: https://codereview.chromium.org/26888009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229624 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--remoting/client/rectangle_update_decoder.cc6
-rw-r--r--remoting/codec/scoped_vpx_codec.cc23
-rw-r--r--remoting/codec/scoped_vpx_codec.h24
-rw-r--r--remoting/codec/video_decoder_vpx.cc (renamed from remoting/codec/video_decoder_vp8.cc)114
-rw-r--r--remoting/codec/video_decoder_vpx.h (renamed from remoting/codec/video_decoder_vp8.h)37
-rw-r--r--remoting/codec/video_decoder_vpx_unittest.cc (renamed from remoting/codec/video_decoder_vp8_unittest.cc)40
-rw-r--r--remoting/codec/video_encoder_vpx.cc (renamed from remoting/codec/video_encoder_vp8.cc)312
-rw-r--r--remoting/codec/video_encoder_vpx.h (renamed from remoting/codec/video_encoder_vp8.h)41
-rw-r--r--remoting/codec/video_encoder_vpx_unittest.cc (renamed from remoting/codec/video_encoder_vp8_unittest.cc)36
-rw-r--r--remoting/host/client_session.cc4
-rw-r--r--remoting/remoting.gyp14
11 files changed, 348 insertions, 303 deletions
diff --git a/remoting/client/rectangle_update_decoder.cc b/remoting/client/rectangle_update_decoder.cc
index 3ff2be1..53541b7 100644
--- a/remoting/client/rectangle_update_decoder.cc
+++ b/remoting/client/rectangle_update_decoder.cc
@@ -11,10 +11,10 @@
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "remoting/base/util.h"
+#include "remoting/client/frame_consumer.h"
#include "remoting/codec/video_decoder.h"
#include "remoting/codec/video_decoder_verbatim.h"
-#include "remoting/codec/video_decoder_vp8.h"
-#include "remoting/client/frame_consumer.h"
+#include "remoting/codec/video_decoder_vpx.h"
#include "remoting/protocol/session_config.h"
#include "third_party/libyuv/include/libyuv/convert_argb.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
@@ -101,7 +101,7 @@ void RectangleUpdateDecoder::Initialize(const SessionConfig& config) {
if (codec == ChannelConfig::CODEC_VERBATIM) {
decoder_.reset(new VideoDecoderVerbatim());
} else if (codec == ChannelConfig::CODEC_VP8) {
- decoder_.reset(new VideoDecoderVp8());
+ decoder_ = VideoDecoderVpx::CreateForVP8();
} else {
NOTREACHED() << "Invalid Encoding found: " << codec;
}
diff --git a/remoting/codec/scoped_vpx_codec.cc b/remoting/codec/scoped_vpx_codec.cc
new file mode 100644
index 0000000..dda986e
--- /dev/null
+++ b/remoting/codec/scoped_vpx_codec.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/codec/scoped_vpx_codec.h"
+
+#include "base/logging.h"
+
+extern "C" {
+#define VPX_CODEC_DISABLE_COMPAT 1
+#include "third_party/libvpx/source/libvpx/vpx/vpx_codec.h"
+}
+namespace remoting {
+
+void VpxCodecDeleter::operator()(vpx_codec_ctx_t* codec) {
+ if (codec) {
+ vpx_codec_err_t ret = vpx_codec_destroy(codec);
+ CHECK_EQ(ret, VPX_CODEC_OK) << "Failed to destroy codec";
+ delete codec;
+ }
+}
+
+} // namespace remoting
diff --git a/remoting/codec/scoped_vpx_codec.h b/remoting/codec/scoped_vpx_codec.h
new file mode 100644
index 0000000..bf03c64
--- /dev/null
+++ b/remoting/codec/scoped_vpx_codec.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_CODEC_SCOPED_VPX_CODEC_H_
+#define REMOTING_CODEC_SCOPED_VPX_CODEC_H_
+
+#include "base/memory/scoped_ptr.h"
+
+extern "C" {
+typedef struct vpx_codec_ctx vpx_codec_ctx_t;
+}
+
+namespace remoting {
+
+struct VpxCodecDeleter {
+ void operator()(vpx_codec_ctx_t* codec);
+};
+
+typedef scoped_ptr<vpx_codec_ctx_t, VpxCodecDeleter> ScopedVpxCodec;
+
+} // namespace remoting
+
+#endif // REMOTING_CODEC_SCOPED_VPX_CODEC_H_
diff --git a/remoting/codec/video_decoder_vp8.cc b/remoting/codec/video_decoder_vpx.cc
index 0d43f15..ba65e88 100644
--- a/remoting/codec/video_decoder_vp8.cc
+++ b/remoting/codec/video_decoder_vpx.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "remoting/codec/video_decoder_vp8.h"
+#include "remoting/codec/video_decoder_vpx.h"
#include <math.h>
@@ -21,69 +21,73 @@ extern "C" {
namespace remoting {
-const uint32 kTransparent = 0;
+namespace {
-VideoDecoderVp8::VideoDecoderVp8()
- : state_(kUninitialized),
- codec_(NULL),
- last_image_(NULL) {
+const uint32 kTransparentColor = 0;
+
+// Fills the rectangle |rect| with the given ARGB color |color| in |buffer|.
+void FillRect(uint8* buffer,
+ int stride,
+ const webrtc::DesktopRect& rect,
+ uint32 color) {
+ uint32* ptr = reinterpret_cast<uint32*>(buffer + (rect.top() * stride) +
+ (rect.left() * VideoDecoder::kBytesPerPixel));
+ int width = rect.width();
+ for (int height = rect.height(); height > 0; --height) {
+ std::fill(ptr, ptr + width, color);
+ ptr += stride / VideoDecoder::kBytesPerPixel;
+ }
}
-VideoDecoderVp8::~VideoDecoderVp8() {
- if (codec_) {
- vpx_codec_err_t ret = vpx_codec_destroy(codec_);
- CHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec";
+} // namespace
+
+// static
+scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP8() {
+ ScopedVpxCodec codec(new vpx_codec_ctx_t);
+
+ // TODO(hclam): Scale the number of threads with number of cores of the
+ // machine.
+ vpx_codec_dec_cfg config;
+ config.w = 0;
+ config.h = 0;
+ config.threads = 2;
+ vpx_codec_err_t ret =
+ vpx_codec_dec_init(codec.get(), vpx_codec_vp8_dx(), &config, 0);
+ if (ret != VPX_CODEC_OK) {
+ LOG(INFO) << "Cannot initialize codec.";
+ return scoped_ptr<VideoDecoderVpx>();
}
- delete codec_;
+
+ return scoped_ptr<VideoDecoderVpx>(new VideoDecoderVpx(codec.Pass()));
}
-void VideoDecoderVp8::Initialize(const webrtc::DesktopSize& screen_size) {
+VideoDecoderVpx::~VideoDecoderVpx() {}
+
+void VideoDecoderVpx::Initialize(const webrtc::DesktopSize& screen_size) {
DCHECK(!screen_size.is_empty());
screen_size_ = screen_size;
- state_ = kReady;
transparent_region_.SetRect(webrtc::DesktopRect::MakeSize(screen_size_));
}
-bool VideoDecoderVp8::DecodePacket(const VideoPacket& packet) {
- DCHECK_EQ(kReady, state_);
-
- // Initialize the codec as needed.
- if (!codec_) {
- codec_ = new vpx_codec_ctx_t();
-
- // TODO(hclam): Scale the number of threads with number of cores of the
- // machine.
- vpx_codec_dec_cfg config;
- config.w = 0;
- config.h = 0;
- config.threads = 2;
- vpx_codec_err_t ret =
- vpx_codec_dec_init(codec_, vpx_codec_vp8_dx(), &config, 0);
- if (ret != VPX_CODEC_OK) {
- LOG(INFO) << "Cannot initialize codec.";
- delete codec_;
- codec_ = NULL;
- state_ = kError;
- return false;
- }
- }
+bool VideoDecoderVpx::DecodePacket(const VideoPacket& packet) {
+ DCHECK(!screen_size_.is_empty());
// Do the actual decoding.
vpx_codec_err_t ret = vpx_codec_decode(
- codec_, reinterpret_cast<const uint8*>(packet.data().data()),
+ codec_.get(), reinterpret_cast<const uint8*>(packet.data().data()),
packet.data().size(), NULL, 0);
if (ret != VPX_CODEC_OK) {
LOG(INFO) << "Decoding failed:" << vpx_codec_err_to_string(ret) << "\n"
- << "Details: " << vpx_codec_error(codec_) << "\n"
- << vpx_codec_error_detail(codec_);
+ << "Details: " << vpx_codec_error(codec_.get()) << "\n"
+ << vpx_codec_error_detail(codec_.get());
return false;
}
// Gets the decoded data.
vpx_codec_iter_t iter = NULL;
- vpx_image_t* image = vpx_codec_get_frame(codec_, &iter);
+ vpx_image_t* image = vpx_codec_get_frame(codec_.get(), &iter);
if (!image) {
LOG(INFO) << "No video frame decoded";
return false;
@@ -121,9 +125,8 @@ bool VideoDecoderVp8::DecodePacket(const VideoPacket& packet) {
return true;
}
-void VideoDecoderVp8::Invalidate(const webrtc::DesktopSize& view_size,
+void VideoDecoderVpx::Invalidate(const webrtc::DesktopSize& view_size,
const webrtc::DesktopRegion& region) {
- DCHECK_EQ(kReady, state_);
DCHECK(!view_size.is_empty());
for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
@@ -138,12 +141,12 @@ void VideoDecoderVp8::Invalidate(const webrtc::DesktopSize& view_size,
transparent_region_.AddRegion(difference);
}
-void VideoDecoderVp8::RenderFrame(const webrtc::DesktopSize& view_size,
+void VideoDecoderVpx::RenderFrame(const webrtc::DesktopSize& view_size,
const webrtc::DesktopRect& clip_area,
uint8* image_buffer,
int image_stride,
webrtc::DesktopRegion* output_region) {
- DCHECK_EQ(kReady, state_);
+ DCHECK(!screen_size_.is_empty());
DCHECK(!view_size.is_empty());
// Early-return and do nothing if we haven't yet decoded any frames.
@@ -244,7 +247,7 @@ void VideoDecoderVp8::RenderFrame(const webrtc::DesktopSize& view_size,
continue;
// Fill the rectange with transparent pixels.
- FillRect(image_buffer, image_stride, rect, kTransparent);
+ FillRect(image_buffer, image_stride, rect, kTransparentColor);
output_region->AddRect(rect);
}
@@ -254,24 +257,17 @@ void VideoDecoderVp8::RenderFrame(const webrtc::DesktopSize& view_size,
transparent_region_.Subtract(scaled_clip_area);
}
-const webrtc::DesktopRegion* VideoDecoderVp8::GetImageShape() {
+const webrtc::DesktopRegion* VideoDecoderVpx::GetImageShape() {
return &desktop_shape_;
}
-void VideoDecoderVp8::FillRect(uint8* buffer,
- int stride,
- const webrtc::DesktopRect& rect,
- uint32 color) {
- uint32* ptr = reinterpret_cast<uint32*>(buffer + (rect.top() * stride) +
- (rect.left() * kBytesPerPixel));
- int width = rect.width();
- for (int height = rect.height(); height > 0; --height) {
- std::fill(ptr, ptr + width, color);
- ptr += stride / kBytesPerPixel;
- }
+VideoDecoderVpx::VideoDecoderVpx(ScopedVpxCodec codec)
+ : codec_(codec.Pass()),
+ last_image_(NULL) {
+ DCHECK(codec_);
}
-void VideoDecoderVp8::UpdateImageShapeRegion(
+void VideoDecoderVpx::UpdateImageShapeRegion(
webrtc::DesktopRegion* new_desktop_shape) {
// Add all areas that have been updated or become transparent to the
// transparent region. Exclude anything within the new desktop shape.
diff --git a/remoting/codec/video_decoder_vp8.h b/remoting/codec/video_decoder_vpx.h
index 42a3176..800c873 100644
--- a/remoting/codec/video_decoder_vp8.h
+++ b/remoting/codec/video_decoder_vpx.h
@@ -1,26 +1,29 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef REMOTING_CODEC_VIDEO_DECODER_VP8_H_
-#define REMOTING_CODEC_VIDEO_DECODER_VP8_H_
+#ifndef REMOTING_CODEC_VIDEO_DECODER_VPX_H_
+#define REMOTING_CODEC_VIDEO_DECODER_VPX_H_
#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "remoting/codec/scoped_vpx_codec.h"
#include "remoting/codec/video_decoder.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
-typedef struct vpx_codec_ctx vpx_codec_ctx_t;
typedef struct vpx_image vpx_image_t;
namespace remoting {
-class VideoDecoderVp8 : public VideoDecoder {
+class VideoDecoderVpx : public VideoDecoder {
public:
- VideoDecoderVp8();
- virtual ~VideoDecoderVp8();
+ // Creates a decoder for VP8.
+ static scoped_ptr<VideoDecoderVpx> CreateForVP8();
- // VideoDecoder implementations.
+ virtual ~VideoDecoderVpx();
+
+ // VideoDecoder interface.
virtual void Initialize(const webrtc::DesktopSize& screen_size) OVERRIDE;
virtual bool DecodePacket(const VideoPacket& packet) OVERRIDE;
virtual void Invalidate(const webrtc::DesktopSize& view_size,
@@ -33,26 +36,14 @@ class VideoDecoderVp8 : public VideoDecoder {
virtual const webrtc::DesktopRegion* GetImageShape() OVERRIDE;
private:
- enum State {
- kUninitialized,
- kReady,
- kError,
- };
-
- // Fills the rectangle |rect| with the given ARGB color |color| in |buffer|.
- void FillRect(uint8* buffer, int stride,
- const webrtc::DesktopRect& rect,
- uint32 color);
+ explicit VideoDecoderVpx(ScopedVpxCodec codec);
// Calculates the difference between the desktop shape regions in two
// consecutive frames and updates |updated_region_| and |transparent_region_|
// accordingly.
void UpdateImageShapeRegion(webrtc::DesktopRegion* new_desktop_shape);
- // The internal state of the decoder.
- State state_;
-
- vpx_codec_ctx_t* codec_;
+ ScopedVpxCodec codec_;
// Pointer to the last decoded image.
vpx_image_t* last_image_;
@@ -69,7 +60,7 @@ class VideoDecoderVp8 : public VideoDecoder {
// The region that should be make transparent.
webrtc::DesktopRegion transparent_region_;
- DISALLOW_COPY_AND_ASSIGN(VideoDecoderVp8);
+ DISALLOW_COPY_AND_ASSIGN(VideoDecoderVpx);
};
} // namespace remoting
diff --git a/remoting/codec/video_decoder_vp8_unittest.cc b/remoting/codec/video_decoder_vpx_unittest.cc
index 64d30df..eab0274 100644
--- a/remoting/codec/video_decoder_vp8_unittest.cc
+++ b/remoting/codec/video_decoder_vpx_unittest.cc
@@ -1,76 +1,80 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "remoting/codec/video_decoder_vp8.h"
+#include "remoting/codec/video_decoder_vpx.h"
#include "media/base/video_frame.h"
#include "remoting/codec/codec_test.h"
-#include "remoting/codec/video_encoder_vp8.h"
+#include "remoting/codec/video_encoder_vpx.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
namespace remoting {
-class VideoDecoderVp8Test : public testing::Test {
+class VideoDecoderVpxTest : public testing::Test {
protected:
- VideoEncoderVp8 encoder_;
- VideoDecoderVp8 decoder_;
+ scoped_ptr<VideoEncoderVpx> encoder_;
+ scoped_ptr<VideoDecoderVpx> decoder_;
+
+ VideoDecoderVpxTest() : encoder_(VideoEncoderVpx::CreateForVP8()),
+ decoder_(VideoDecoderVpx::CreateForVP8()) {
+ }
void TestGradient(int screen_width, int screen_height,
int view_width, int view_height,
double max_error_limit, double mean_error_limit) {
TestVideoEncoderDecoderGradient(
- &encoder_, &decoder_,
+ encoder_.get(), decoder_.get(),
webrtc::DesktopSize(screen_width, screen_height),
webrtc::DesktopSize(view_width, view_height),
max_error_limit, mean_error_limit);
}
};
-TEST_F(VideoDecoderVp8Test, VideoEncodeAndDecode) {
- TestVideoEncoderDecoder(&encoder_, &decoder_, false);
+TEST_F(VideoDecoderVpxTest, 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) {
+TEST_F(VideoDecoderVpxTest, Gradient) {
TestGradient(320, 240, 320, 240, 0.04, 0.02);
}
-TEST_F(VideoDecoderVp8Test, GradientScaleUpEvenToEven) {
+TEST_F(VideoDecoderVpxTest, GradientScaleUpEvenToEven) {
TestGradient(320, 240, 640, 480, 0.04, 0.02);
}
-TEST_F(VideoDecoderVp8Test, GradientScaleUpEvenToOdd) {
+TEST_F(VideoDecoderVpxTest, GradientScaleUpEvenToOdd) {
TestGradient(320, 240, 641, 481, 0.04, 0.02);
}
-TEST_F(VideoDecoderVp8Test, GradientScaleUpOddToEven) {
+TEST_F(VideoDecoderVpxTest, GradientScaleUpOddToEven) {
TestGradient(321, 241, 640, 480, 0.04, 0.02);
}
-TEST_F(VideoDecoderVp8Test, GradientScaleUpOddToOdd) {
+TEST_F(VideoDecoderVpxTest, GradientScaleUpOddToOdd) {
TestGradient(321, 241, 641, 481, 0.04, 0.02);
}
-TEST_F(VideoDecoderVp8Test, GradientScaleDownEvenToEven) {
+TEST_F(VideoDecoderVpxTest, GradientScaleDownEvenToEven) {
TestGradient(320, 240, 160, 120, 0.04, 0.02);
}
-TEST_F(VideoDecoderVp8Test, GradientScaleDownEvenToOdd) {
+TEST_F(VideoDecoderVpxTest, 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) {
+TEST_F(VideoDecoderVpxTest, GradientScaleDownOddToEven) {
TestGradient(321, 241, 160, 120, 0.04, 0.02);
}
-TEST_F(VideoDecoderVp8Test, GradientScaleDownOddToOdd) {
+TEST_F(VideoDecoderVpxTest, GradientScaleDownOddToOdd) {
TestGradient(321, 241, 161, 121, 0.04, 0.02);
}
diff --git a/remoting/codec/video_encoder_vp8.cc b/remoting/codec/video_encoder_vpx.cc
index 077bdd1..6c39d47 100644
--- a/remoting/codec/video_encoder_vp8.cc
+++ b/remoting/codec/video_encoder_vpx.cc
@@ -1,9 +1,10 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "remoting/codec/video_encoder_vp8.h"
+#include "remoting/codec/video_encoder_vpx.h"
+#include "base/bind.h"
#include "base/logging.h"
#include "base/sys_info.h"
#include "base/time/time.h"
@@ -20,37 +21,171 @@ extern "C" {
#include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
}
+namespace remoting {
+
namespace {
// Defines the dimension of a macro block. This is used to compute the active
// map for the encoder.
const int kMacroBlockSize = 16;
-} // namespace remoting
+ScopedVpxCodec CreateVP8Codec(const webrtc::DesktopSize& size) {
+ ScopedVpxCodec codec(new vpx_codec_ctx_t);
-namespace remoting {
+ // Configure the encoder.
+ vpx_codec_enc_cfg_t config;
+ const vpx_codec_iface_t* algo = vpx_codec_vp8_cx();
+ CHECK(algo);
+ vpx_codec_err_t ret = vpx_codec_enc_config_default(algo, &config, 0);
+ if (ret != VPX_CODEC_OK)
+ return ScopedVpxCodec();
-VideoEncoderVp8::VideoEncoderVp8()
- : initialized_(false),
- active_map_width_(0),
- active_map_height_(0),
- last_timestamp_(0) {}
+ 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;
-VideoEncoderVp8::~VideoEncoderVp8() {
- Destroy();
+ // Value of 2 means using the real time profile. This is basically a
+ // redundant option since we explicitly select real time mode when doing
+ // encoding.
+ config.g_profile = 2;
+
+ // Using 2 threads gives a great boost in performance for most systems with
+ // adequate processing power. NB: Going to multiple threads on low end
+ // windows systems can really hurt performance.
+ // http://crbug.com/99179
+ config.g_threads = (base::SysInfo::NumberOfProcessors() > 2) ? 2 : 1;
+ config.rc_min_quantizer = 20;
+ config.rc_max_quantizer = 30;
+ config.g_timebase.num = 1;
+ config.g_timebase.den = 20;
+
+ if (vpx_codec_enc_init(codec.get(), algo, &config, 0))
+ return ScopedVpxCodec();
+
+ // Value of 16 will have the smallest CPU load. This turns off subpixel
+ // motion search.
+ if (vpx_codec_control(codec.get(), VP8E_SET_CPUUSED, 16))
+ return ScopedVpxCodec();
+
+ // Use the lowest level of noise sensitivity so as to spend less time
+ // on motion estimation and inter-prediction mode.
+ if (vpx_codec_control(codec.get(), VP8E_SET_NOISE_SENSITIVITY, 0))
+ return ScopedVpxCodec();
+
+ return codec.Pass();
+}
+
+} // namespace
+
+// static
+scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP8() {
+ return scoped_ptr<VideoEncoderVpx>(
+ new VideoEncoderVpx(base::Bind(&CreateVP8Codec)));
}
-void VideoEncoderVp8::Destroy() {
- if (initialized_) {
- vpx_codec_err_t ret = vpx_codec_destroy(codec_.get());
- DCHECK_EQ(ret, VPX_CODEC_OK) << "Failed to destroy codec";
- initialized_ = false;
+VideoEncoderVpx::~VideoEncoderVpx() {}
+
+scoped_ptr<VideoPacket> VideoEncoderVpx::Encode(
+ const webrtc::DesktopFrame& frame) {
+ DCHECK_LE(32, frame.size().width());
+ DCHECK_LE(32, frame.size().height());
+
+ base::Time encode_start_time = base::Time::Now();
+
+ if (!codec_ ||
+ !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h))) {
+ bool ret = Initialize(frame.size());
+ // TODO(hclam): Handle error better.
+ CHECK(ret) << "Initialization of encoder failed";
+ }
+
+ // Convert the updated capture data ready for encode.
+ webrtc::DesktopRegion updated_region;
+ PrepareImage(frame, &updated_region);
+
+ // Update active map based on updated region.
+ PrepareActiveMap(updated_region);
+
+ // Apply active map to the encoder.
+ vpx_active_map_t act_map;
+ act_map.rows = active_map_height_;
+ act_map.cols = active_map_width_;
+ act_map.active_map = active_map_.get();
+ if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) {
+ LOG(ERROR) << "Unable to apply active map";
+ }
+
+ // Do the actual encoding.
+ vpx_codec_err_t ret = vpx_codec_encode(codec_.get(), image_.get(),
+ last_timestamp_,
+ 1, 0, VPX_DL_REALTIME);
+ DCHECK_EQ(ret, VPX_CODEC_OK)
+ << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n"
+ << "Details: " << vpx_codec_error(codec_.get()) << "\n"
+ << vpx_codec_error_detail(codec_.get());
+
+ // TODO(hclam): Apply the proper timestamp here.
+ last_timestamp_ += 50;
+
+ // Read the encoded data.
+ vpx_codec_iter_t iter = NULL;
+ bool got_data = false;
+
+ // TODO(hclam): Make sure we get exactly one frame from the packet.
+ // TODO(hclam): We should provide the output buffer to avoid one copy.
+ scoped_ptr<VideoPacket> packet(new VideoPacket());
+
+ while (!got_data) {
+ const vpx_codec_cx_pkt_t* vpx_packet =
+ vpx_codec_get_cx_data(codec_.get(), &iter);
+ if (!vpx_packet)
+ continue;
+
+ switch (vpx_packet->kind) {
+ case VPX_CODEC_CX_FRAME_PKT:
+ got_data = true;
+ packet->set_data(vpx_packet->data.frame.buf, vpx_packet->data.frame.sz);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Construct the VideoPacket message.
+ packet->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8);
+ packet->mutable_format()->set_screen_width(frame.size().width());
+ packet->mutable_format()->set_screen_height(frame.size().height());
+ packet->set_capture_time_ms(frame.capture_time_ms());
+ packet->set_encode_time_ms(
+ (base::Time::Now() - encode_start_time).InMillisecondsRoundedUp());
+ if (!frame.dpi().is_zero()) {
+ packet->mutable_format()->set_x_dpi(frame.dpi().x());
+ packet->mutable_format()->set_y_dpi(frame.dpi().y());
}
+ for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd();
+ r.Advance()) {
+ Rect* rect = packet->add_dirty_rects();
+ rect->set_x(r.rect().left());
+ rect->set_y(r.rect().top());
+ rect->set_width(r.rect().width());
+ rect->set_height(r.rect().height());
+ }
+
+ return packet.Pass();
+}
+
+VideoEncoderVpx::VideoEncoderVpx(const InitializeCodecCallback& init_codec)
+ : init_codec_(init_codec),
+ active_map_width_(0),
+ active_map_height_(0),
+ last_timestamp_(0) {
}
-bool VideoEncoderVp8::Init(const webrtc::DesktopSize& size) {
- Destroy();
- codec_.reset(new vpx_codec_ctx_t());
+bool VideoEncoderVpx::Initialize(const webrtc::DesktopSize& size) {
+ codec_.reset();
+
image_.reset(new vpx_image_t());
memset(image_.get(), 0, sizeof(vpx_image_t));
@@ -101,51 +236,13 @@ bool VideoEncoderVp8::Init(const webrtc::DesktopSize& size) {
image_->stride[1] = uv_width;
image_->stride[2] = uv_width;
- // Configure the encoder.
- vpx_codec_enc_cfg_t config;
- const vpx_codec_iface_t* algo = vpx_codec_vp8_cx();
- CHECK(algo);
- vpx_codec_err_t ret = vpx_codec_enc_config_default(algo, &config, 0);
- if (ret != VPX_CODEC_OK)
- return false;
-
- config.rc_target_bitrate = image_->w * image_->h *
- config.rc_target_bitrate / config.g_w / config.g_h;
- config.g_w = image_->w;
- config.g_h = image_->h;
- config.g_pass = VPX_RC_ONE_PASS;
-
- // Value of 2 means using the real time profile. This is basically a
- // redundant option since we explicitly select real time mode when doing
- // encoding.
- config.g_profile = 2;
-
- // Using 2 threads gives a great boost in performance for most systems with
- // adequate processing power. NB: Going to multiple threads on low end
- // windows systems can really hurt performance.
- // http://crbug.com/99179
- config.g_threads = (base::SysInfo::NumberOfProcessors() > 2) ? 2 : 1;
- config.rc_min_quantizer = 20;
- config.rc_max_quantizer = 30;
- config.g_timebase.num = 1;
- config.g_timebase.den = 20;
-
- if (vpx_codec_enc_init(codec_.get(), algo, &config, 0))
- return false;
+ // Initialize the codec.
+ codec_ = init_codec_.Run(size);
- // Value of 16 will have the smallest CPU load. This turns off subpixel
- // motion search.
- if (vpx_codec_control(codec_.get(), VP8E_SET_CPUUSED, 16))
- return false;
-
- // Use the lowest level of noise sensitivity so as to spend less time
- // on motion estimation and inter-prediction mode.
- if (vpx_codec_control(codec_.get(), VP8E_SET_NOISE_SENSITIVITY, 0))
- return false;
- return true;
+ return codec_;
}
-void VideoEncoderVp8::PrepareImage(const webrtc::DesktopFrame& frame,
+void VideoEncoderVpx::PrepareImage(const webrtc::DesktopFrame& frame,
webrtc::DesktopRegion* updated_region) {
if (frame.updated_region().is_empty()) {
updated_region->Clear();
@@ -191,7 +288,7 @@ void VideoEncoderVp8::PrepareImage(const webrtc::DesktopFrame& frame,
}
}
-void VideoEncoderVp8::PrepareActiveMap(
+void VideoEncoderVpx::PrepareActiveMap(
const webrtc::DesktopRegion& updated_region) {
// Clear active map first.
memset(active_map_.get(), 0, active_map_width_ * active_map_height_);
@@ -216,95 +313,4 @@ void VideoEncoderVp8::PrepareActiveMap(
}
}
-scoped_ptr<VideoPacket> VideoEncoderVp8::Encode(
- const webrtc::DesktopFrame& frame) {
- DCHECK_LE(32, frame.size().width());
- DCHECK_LE(32, frame.size().height());
-
- base::Time encode_start_time = base::Time::Now();
-
- if (!initialized_ ||
- !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h))) {
- bool ret = Init(frame.size());
- // TODO(hclam): Handle error better.
- CHECK(ret) << "Initialization of encoder failed";
- initialized_ = ret;
- }
-
- // Convert the updated capture data ready for encode.
- webrtc::DesktopRegion updated_region;
- PrepareImage(frame, &updated_region);
-
- // Update active map based on updated region.
- PrepareActiveMap(updated_region);
-
- // Apply active map to the encoder.
- vpx_active_map_t act_map;
- act_map.rows = active_map_height_;
- act_map.cols = active_map_width_;
- act_map.active_map = active_map_.get();
- if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) {
- LOG(ERROR) << "Unable to apply active map";
- }
-
- // Do the actual encoding.
- vpx_codec_err_t ret = vpx_codec_encode(codec_.get(), image_.get(),
- last_timestamp_,
- 1, 0, VPX_DL_REALTIME);
- DCHECK_EQ(ret, VPX_CODEC_OK)
- << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n"
- << "Details: " << vpx_codec_error(codec_.get()) << "\n"
- << vpx_codec_error_detail(codec_.get());
-
- // TODO(hclam): Apply the proper timestamp here.
- last_timestamp_ += 50;
-
- // Read the encoded data.
- vpx_codec_iter_t iter = NULL;
- bool got_data = false;
-
- // TODO(hclam): Make sure we get exactly one frame from the packet.
- // TODO(hclam): We should provide the output buffer to avoid one copy.
- scoped_ptr<VideoPacket> packet(new VideoPacket());
-
- while (!got_data) {
- const vpx_codec_cx_pkt_t* vpx_packet =
- vpx_codec_get_cx_data(codec_.get(), &iter);
- if (!vpx_packet)
- continue;
-
- switch (vpx_packet->kind) {
- case VPX_CODEC_CX_FRAME_PKT:
- got_data = true;
- // TODO(sergeyu): Split each frame into multiple partitions.
- packet->set_data(vpx_packet->data.frame.buf, vpx_packet->data.frame.sz);
- break;
- default:
- break;
- }
- }
-
- // Construct the VideoPacket message.
- packet->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8);
- packet->mutable_format()->set_screen_width(frame.size().width());
- packet->mutable_format()->set_screen_height(frame.size().height());
- packet->set_capture_time_ms(frame.capture_time_ms());
- packet->set_encode_time_ms(
- (base::Time::Now() - encode_start_time).InMillisecondsRoundedUp());
- if (!frame.dpi().is_zero()) {
- packet->mutable_format()->set_x_dpi(frame.dpi().x());
- packet->mutable_format()->set_y_dpi(frame.dpi().y());
- }
- for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd();
- r.Advance()) {
- Rect* rect = packet->add_dirty_rects();
- rect->set_x(r.rect().left());
- rect->set_y(r.rect().top());
- rect->set_width(r.rect().width());
- rect->set_height(r.rect().height());
- }
-
- return packet.Pass();
-}
-
} // namespace remoting
diff --git a/remoting/codec/video_encoder_vp8.h b/remoting/codec/video_encoder_vpx.h
index 25b00b3..2e76532 100644
--- a/remoting/codec/video_encoder_vp8.h
+++ b/remoting/codec/video_encoder_vpx.h
@@ -1,14 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef REMOTING_CODEC_VIDEO_ENCODER_VP8_H_
-#define REMOTING_CODEC_VIDEO_ENCODER_VP8_H_
+#ifndef REMOTING_CODEC_VIDEO_ENCODER_VPX_H_
+#define REMOTING_CODEC_VIDEO_ENCODER_VPX_H_
-#include "base/gtest_prod_util.h"
+#include "base/callback.h"
+#include "remoting/codec/scoped_vpx_codec.h"
#include "remoting/codec/video_encoder.h"
-typedef struct vpx_codec_ctx vpx_codec_ctx_t;
typedef struct vpx_image vpx_image_t;
namespace webrtc {
@@ -19,39 +19,38 @@ class DesktopSize;
namespace remoting {
// A class that uses VP8 to perform encoding.
-class VideoEncoderVp8 : public VideoEncoder {
+class VideoEncoderVpx : public VideoEncoder {
public:
- VideoEncoderVp8();
- virtual ~VideoEncoderVp8();
+ // Creates a encoder for VP8.
+ static scoped_ptr<VideoEncoderVpx> CreateForVP8();
+
+ virtual ~VideoEncoderVpx();
// VideoEncoder interface.
virtual scoped_ptr<VideoPacket> Encode(
const webrtc::DesktopFrame& frame) OVERRIDE;
private:
- FRIEND_TEST_ALL_PREFIXES(VideoEncoderVp8Test, AlignAndClipRect);
+ typedef base::Callback<ScopedVpxCodec(const webrtc::DesktopSize&)>
+ InitializeCodecCallback;
- // Initialize the encoder. Returns true if successful.
- bool Init(const webrtc::DesktopSize& size);
+ VideoEncoderVpx(const InitializeCodecCallback& init_codec);
- // Destroy the encoder.
- void Destroy();
+ // Initializes the codec for frames of |size|. Returns true if successful.
+ bool Initialize(const webrtc::DesktopSize& size);
- // Prepare |image_| for encoding. Write updated rectangles into
+ // Prepares |image_| for encoding. Writes updated rectangles into
// |updated_region|.
- //
- // TODO(sergeyu): Update this code to use webrtc::DesktopRegion.
void PrepareImage(const webrtc::DesktopFrame& frame,
webrtc::DesktopRegion* updated_region);
- // Update the active map according to |updated_region|. Active map is then
+ // Updates the active map according to |updated_region|. Active map is then
// given to the encoder to speed up encoding.
void PrepareActiveMap(const webrtc::DesktopRegion& updated_region);
- // True if the encoder is initialized.
- bool initialized_;
+ InitializeCodecCallback init_codec_;
- scoped_ptr<vpx_codec_ctx_t> codec_;
+ ScopedVpxCodec codec_;
scoped_ptr<vpx_image_t> image_;
scoped_ptr<uint8[]> active_map_;
int active_map_width_;
@@ -61,7 +60,7 @@ class VideoEncoderVp8 : public VideoEncoder {
// Buffer for storing the yuv image.
scoped_ptr<uint8[]> yuv_image_;
- DISALLOW_COPY_AND_ASSIGN(VideoEncoderVp8);
+ DISALLOW_COPY_AND_ASSIGN(VideoEncoderVpx);
};
} // namespace remoting
diff --git a/remoting/codec/video_encoder_vp8_unittest.cc b/remoting/codec/video_encoder_vpx_unittest.cc
index a8871ba..f5a0c8d 100644
--- a/remoting/codec/video_encoder_vp8_unittest.cc
+++ b/remoting/codec/video_encoder_vpx_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "remoting/codec/video_encoder_vp8.h"
+#include "remoting/codec/video_encoder_vpx.h"
#include <limits>
#include <vector>
@@ -21,44 +21,44 @@ const int kIntMax = std::numeric_limits<int>::max();
namespace remoting {
-TEST(VideoEncoderVp8Test, TestVideoEncoder) {
- VideoEncoderVp8 encoder;
- TestVideoEncoder(&encoder, false);
+TEST(VideoEncoderVpxTest, 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(VideoEncoderVp8Test, TestSizeChangeNoLeak) {
+TEST(VideoEncoderVpxTest, TestSizeChangeNoLeak) {
int height = 1000;
int width = 1000;
- VideoEncoderVp8 encoder;
+ scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
- scoped_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(
- webrtc::DesktopSize(width, height)));
+ scoped_ptr<webrtc::DesktopFrame> frame(
+ new webrtc::BasicDesktopFrame(webrtc::DesktopSize(width, height)));
- scoped_ptr<VideoPacket> packet = encoder.Encode(*frame);
+ scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
EXPECT_TRUE(packet);
height /= 2;
- frame.reset(new webrtc::BasicDesktopFrame(
- webrtc::DesktopSize(width, height)));
- packet = encoder.Encode(*frame);
+ frame.reset(
+ new webrtc::BasicDesktopFrame(webrtc::DesktopSize(width, height)));
+ packet = encoder->Encode(*frame);
EXPECT_TRUE(packet);
}
// Test that the DPI information is correctly propagated from the
// media::ScreenCaptureData to the VideoPacket.
-TEST(VideoEncoderVp8Test, TestDpiPropagation) {
+TEST(VideoEncoderVpxTest, TestDpiPropagation) {
int height = 32;
int width = 32;
- VideoEncoderVp8 encoder;
+ scoped_ptr<VideoEncoderVpx> encoder(VideoEncoderVpx::CreateForVP8());
- scoped_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(
- webrtc::DesktopSize(width, height)));
+ scoped_ptr<webrtc::DesktopFrame> frame(
+ new webrtc::BasicDesktopFrame(webrtc::DesktopSize(width, height)));
frame->set_dpi(webrtc::DesktopVector(96, 97));
- scoped_ptr<VideoPacket> packet = encoder.Encode(*frame);
+ scoped_ptr<VideoPacket> packet = encoder->Encode(*frame);
EXPECT_EQ(packet->format().x_dpi(), 96);
EXPECT_EQ(packet->format().y_dpi(), 97);
}
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index 67f4a95..1a5e36b 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -13,7 +13,7 @@
#include "remoting/codec/audio_encoder_verbatim.h"
#include "remoting/codec/video_encoder.h"
#include "remoting/codec/video_encoder_verbatim.h"
-#include "remoting/codec/video_encoder_vp8.h"
+#include "remoting/codec/video_encoder_vpx.h"
#include "remoting/host/audio_capturer.h"
#include "remoting/host/audio_scheduler.h"
#include "remoting/host/desktop_environment.h"
@@ -427,7 +427,7 @@ scoped_ptr<VideoEncoder> ClientSession::CreateVideoEncoder(
const protocol::ChannelConfig& video_config = config.video_config();
if (video_config.codec == protocol::ChannelConfig::CODEC_VP8) {
- return scoped_ptr<VideoEncoder>(new remoting::VideoEncoderVp8());
+ return remoting::VideoEncoderVpx::CreateForVP8().PassAs<VideoEncoder>();
}
NOTREACHED();
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 49abcf7..d32f837 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -2507,16 +2507,18 @@
'codec/audio_encoder_opus.h',
'codec/audio_encoder_verbatim.cc',
'codec/audio_encoder_verbatim.h',
+ 'codec/scoped_vpx_codec.cc',
+ 'codec/scoped_vpx_codec.h',
'codec/video_decoder.h',
'codec/video_decoder_verbatim.cc',
'codec/video_decoder_verbatim.h',
- 'codec/video_decoder_vp8.cc',
- 'codec/video_decoder_vp8.h',
+ 'codec/video_decoder_vpx.cc',
+ 'codec/video_decoder_vpx.h',
'codec/video_encoder.h',
'codec/video_encoder_verbatim.cc',
'codec/video_encoder_verbatim.h',
- 'codec/video_encoder_vp8.cc',
- 'codec/video_encoder_vp8.h',
+ 'codec/video_encoder_vpx.cc',
+ 'codec/video_encoder_vpx.h',
],
}, # end of target 'remoting_base'
@@ -2784,9 +2786,9 @@
'codec/audio_encoder_opus_unittest.cc',
'codec/codec_test.cc',
'codec/codec_test.h',
- 'codec/video_decoder_vp8_unittest.cc',
+ 'codec/video_decoder_vpx_unittest.cc',
'codec/video_encoder_verbatim_unittest.cc',
- 'codec/video_encoder_vp8_unittest.cc',
+ 'codec/video_encoder_vpx_unittest.cc',
'host/audio_silence_detector_unittest.cc',
'host/branding.cc',
'host/branding.h',