diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-29 17:34:32 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-29 17:34:32 +0000 |
commit | 622b788650a636236c3842f1287126fc60fb80ed (patch) | |
tree | da3e6045ec78f3c4929a6f11779bb8ac21b5adb1 /remoting | |
parent | 3190f36c2f7ac99d06a07b3df1e12ac36fc11d08 (diff) | |
download | chromium_src-622b788650a636236c3842f1287126fc60fb80ed.zip chromium_src-622b788650a636236c3842f1287126fc60fb80ed.tar.gz chromium_src-622b788650a636236c3842f1287126fc60fb80ed.tar.bz2 |
VP8 decoder for chromoting
Added DecoderVp8 and unit test for chromoting.
TEST=remoting_unittests
BUG=50235
Review URL: http://codereview.chromium.org/3032047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60960 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/base/codec_test.cc | 6 | ||||
-rw-r--r-- | remoting/base/decoder_vp8.cc | 165 | ||||
-rw-r--r-- | remoting/base/decoder_vp8.h | 56 | ||||
-rw-r--r-- | remoting/base/decoder_vp8_unittest.cc | 21 | ||||
-rw-r--r-- | remoting/remoting.gyp | 3 |
5 files changed, 248 insertions, 3 deletions
diff --git a/remoting/base/codec_test.cc b/remoting/base/codec_test.cc index e8f17ca..ae5c9eb 100644 --- a/remoting/base/codec_test.cc +++ b/remoting/base/codec_test.cc @@ -165,15 +165,15 @@ class DecoderTester { void ReceivedMessage(ChromotingHostMessage* message) { if (message->has_update_stream_packet()) { - decoder_->PartialDecode(message); + EXPECT_TRUE(decoder_->PartialDecode(message)); return; } if (message->has_begin_update_stream()) { - decoder_->BeginDecode( + EXPECT_TRUE(decoder_->BeginDecode( frame_, &update_rects_, NewRunnableMethod(this, &DecoderTester::OnPartialDecodeDone), - NewRunnableMethod(this, &DecoderTester::OnDecodeDone)); + NewRunnableMethod(this, &DecoderTester::OnDecodeDone))); } if (message->has_end_update_stream()) { diff --git a/remoting/base/decoder_vp8.cc b/remoting/base/decoder_vp8.cc new file mode 100644 index 0000000..0ede4ab --- /dev/null +++ b/remoting/base/decoder_vp8.cc @@ -0,0 +1,165 @@ +// Copyright (c) 2010 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/base/decoder_vp8.h" + +#include "media/base/media.h" +#include "media/base/yuv_convert.h" +#include "remoting/base/protocol_util.h" + +extern "C" { +#define VPX_CODEC_DISABLE_COMPAT 1 +#include "third_party/libvpx/include/vpx/vpx_codec.h" +#include "third_party/libvpx/include/vpx/vpx_decoder.h" +#include "third_party/libvpx/include/vpx/vp8dx.h" +} + +namespace remoting { + +DecoderVp8::DecoderVp8() + : state_(kWaitingForBeginRect), + rect_x_(0), + rect_y_(0), + rect_width_(0), + rect_height_(0), + updated_rects_(NULL), + codec_(NULL) { +} + +DecoderVp8::~DecoderVp8() { + if (codec_) { + vpx_codec_err_t ret = vpx_codec_destroy(codec_); + CHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec"; + } + delete codec_; +} + +bool DecoderVp8::BeginDecode(scoped_refptr<media::VideoFrame> frame, + UpdatedRects* updated_rects, + Task* partial_decode_done, + Task* decode_done) { + DCHECK(!partial_decode_done_.get()); + DCHECK(!decode_done_.get()); + DCHECK(!updated_rects_); + DCHECK_EQ(kWaitingForBeginRect, state_); + + partial_decode_done_.reset(partial_decode_done); + decode_done_.reset(decode_done); + updated_rects_ = updated_rects; + + if (frame->format() != media::VideoFrame::RGB32) { + LOG(INFO) << "DecoderVp8 only supports RGB32 as output"; + return false; + } + frame_ = frame; + return true; +} + +bool DecoderVp8::PartialDecode(ChromotingHostMessage* message) { + scoped_ptr<ChromotingHostMessage> msg_deleter(message); + DCHECK(message->has_update_stream_packet()); + + bool ret = true; + if (message->update_stream_packet().has_begin_rect()) + ret = HandleBeginRect(message); + if (ret && message->update_stream_packet().has_rect_data()) + ret = HandleRectData(message); + if (ret && message->update_stream_packet().has_end_rect()) + ret = HandleEndRect(message); + return ret; +} + +void DecoderVp8::EndDecode() { + DCHECK_EQ(kWaitingForBeginRect, state_); + decode_done_->Run(); + + partial_decode_done_.reset(); + decode_done_.reset(); + frame_ = NULL; + updated_rects_ = NULL; +} + +bool DecoderVp8::HandleBeginRect(ChromotingHostMessage* message) { + DCHECK_EQ(kWaitingForBeginRect, state_); + state_ = kWaitingForRectData; + + rect_width_ = message->update_stream_packet().begin_rect().width(); + rect_height_ = message->update_stream_packet().begin_rect().height(); + rect_x_ = message->update_stream_packet().begin_rect().x(); + rect_y_ = message->update_stream_packet().begin_rect().y(); + + PixelFormat pixel_format = + message->update_stream_packet().begin_rect().pixel_format(); + if (pixel_format != PixelFormatYv12) + return false; + return true; +} + +bool DecoderVp8::HandleRectData(ChromotingHostMessage* message) { + DCHECK_EQ(kWaitingForRectData, state_); + DCHECK_EQ(0, + message->update_stream_packet().rect_data().sequence_number()); + + // Initialize the codec as needed. + if (!codec_) { + codec_ = new vpx_codec_ctx_t(); + vpx_codec_err_t ret = + vpx_codec_dec_init( + codec_, + (const vpx_codec_iface_t*)media::GetVp8DxAlgoAddress(), NULL, 0); + if (ret != VPX_CODEC_OK) { + LOG(INFO) << "Cannot initialize codec."; + delete codec_; + codec_ = NULL; + return false; + } + } + + // Do the actual decoding. + vpx_codec_err_t ret = vpx_codec_decode( + codec_, + (uint8_t*)message->update_stream_packet().rect_data().data().c_str(), + message->update_stream_packet().rect_data().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_); + return false; + } + + // Gets the decoded data. + vpx_codec_iter_t iter = NULL; + vpx_image_t* image = vpx_codec_get_frame(codec_, &iter); + if (!image) { + LOG(INFO) << "No video frame decoded"; + return false; + } + + // Perform YUV conversion. + media::ConvertYUVToRGB32(image->planes[0], image->planes[1], image->planes[2], + frame_->data(media::VideoFrame::kRGBPlane), + rect_width_, rect_height_, + image->stride[0], image->stride[1], + frame_->stride(media::VideoFrame::kRGBPlane), + media::YV12); + + updated_rects_->clear(); + updated_rects_->push_back(gfx::Rect(rect_x_, rect_y_, + rect_width_, rect_height_)); + partial_decode_done_->Run(); + return true; +} + +bool DecoderVp8::HandleEndRect(ChromotingHostMessage* message) { + DCHECK_EQ(kWaitingForRectData, state_); + state_ = kWaitingForBeginRect; + return true; +} + +} // namespace remoting diff --git a/remoting/base/decoder_vp8.h b/remoting/base/decoder_vp8.h new file mode 100644 index 0000000..5fe0169 --- /dev/null +++ b/remoting/base/decoder_vp8.h @@ -0,0 +1,56 @@ +// Copyright (c) 2010 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_BASE_DECODER_VP8_H_ +#define REMOTING_BASE_DECODER_VP8_H_ + +#include "remoting/base/decoder.h" + +typedef struct vpx_codec_ctx vpx_codec_ctx_t; + +namespace remoting { + +class DecoderVp8 : public Decoder { + public: + DecoderVp8(); + ~DecoderVp8(); + + // Decoder implementations. + virtual bool BeginDecode(scoped_refptr<media::VideoFrame> frame, + UpdatedRects* update_rects, + Task* partial_decode_done, + Task* decode_done); + virtual bool PartialDecode(ChromotingHostMessage* message); + virtual void EndDecode(); + + private: + bool HandleBeginRect(ChromotingHostMessage* message); + bool HandleRectData(ChromotingHostMessage* message); + bool HandleEndRect(ChromotingHostMessage* message); + + // The internal state of the decoder. + State state_; + + // Keeps track of the updating rect. + int rect_x_; + int rect_y_; + int rect_width_; + int rect_height_; + + // Tasks to call when decode is done. + scoped_ptr<Task> partial_decode_done_; + scoped_ptr<Task> decode_done_; + + // The video frame to write to. + scoped_refptr<media::VideoFrame> frame_; + UpdatedRects* updated_rects_; + + vpx_codec_ctx_t* codec_; + + DISALLOW_COPY_AND_ASSIGN(DecoderVp8); +}; + +} // namespace remoting + +#endif // REMOTING_BASE_DECODER_VP8_H_ diff --git a/remoting/base/decoder_vp8_unittest.cc b/remoting/base/decoder_vp8_unittest.cc new file mode 100644 index 0000000..25ff6ac --- /dev/null +++ b/remoting/base/decoder_vp8_unittest.cc @@ -0,0 +1,21 @@ +// Copyright (c) 2010 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 "media/base/video_frame.h" +#include "remoting/base/codec_test.h" +#include "remoting/base/decoder_vp8.h" +#include "remoting/base/encoder_vp8.h" +#include "remoting/client/mock_objects.h" +#include "testing/gtest/include/gtest/gtest.h" + + +namespace remoting { + +TEST(DecoderVp8Test, EncodeAndDecode) { + EncoderVp8 encoder; + DecoderVp8 decoder; + TestEncoderDecoder(&encoder, &decoder, false); +} + +} // namespace remoting diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 33339cb..47d498c 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -137,6 +137,8 @@ 'base/decoder.h', 'base/decoder_verbatim.cc', 'base/decoder_verbatim.h', + 'base/decoder_vp8.cc', + 'base/decoder_vp8.h', 'base/decoder_zlib.cc', 'base/decoder_zlib.h', 'base/decompressor.h', @@ -400,6 +402,7 @@ 'base/codec_test.h', 'base/compressor_zlib_unittest.cc', 'base/decoder_verbatim_unittest.cc', + 'base/decoder_vp8_unittest.cc', 'base/decoder_zlib_unittest.cc', 'base/decompressor_zlib_unittest.cc', 'base/encoder_verbatim_unittest.cc', |