Commit e79241d8 authored by Haixia Shi's avatar Haixia Shi

Video capture frame size: separate coded size and visible size.

The coded size should always be rounded up to multiples of 16 pixels to accomodate
alignment requirements of HW encoders, while the visible size reflects the actual
content size.

Update video capture messages to pass visible rect from browser to renderer process.

BUG=402501
TEST=verify that non-multiple-of-16-pixel capture works and no black border is shown
R=dalecurtis@chromium.org, hclam@chromium.org, palmer@chromium.org

Review URL: https://codereview.chromium.org/500653003

Cr-Commit-Position: refs/heads/master@{#292717}
parent 587325d3
...@@ -75,9 +75,14 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( ...@@ -75,9 +75,14 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
if (!client_) if (!client_)
return false; // Capture is stopped. return false; // Capture is stopped.
// Always round up the coded size to multiple of 16 pixels.
// See http://crbug.com/402151.
const gfx::Size visible_size = params_.requested_format.frame_size;
const gfx::Size coded_size((visible_size.width() + 15) & ~15,
(visible_size.height() + 15) & ~15);
scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer = scoped_refptr<media::VideoCaptureDevice::Client::Buffer> output_buffer =
client_->ReserveOutputBuffer(video_frame_format_, client_->ReserveOutputBuffer(video_frame_format_, coded_size);
params_.requested_format.frame_size);
const bool should_capture = const bool should_capture =
oracle_->ObserveEventAndDecideCapture(event, damage_rect, event_time); oracle_->ObserveEventAndDecideCapture(event, damage_rect, event_time);
const bool content_is_dirty = const bool content_is_dirty =
...@@ -123,9 +128,9 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture( ...@@ -123,9 +128,9 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
if (video_frame_format_ != media::VideoFrame::NATIVE_TEXTURE) { if (video_frame_format_ != media::VideoFrame::NATIVE_TEXTURE) {
*storage = media::VideoFrame::WrapExternalPackedMemory( *storage = media::VideoFrame::WrapExternalPackedMemory(
video_frame_format_, video_frame_format_,
params_.requested_format.frame_size, coded_size,
gfx::Rect(params_.requested_format.frame_size), gfx::Rect(visible_size),
params_.requested_format.frame_size, visible_size,
static_cast<uint8*>(output_buffer->data()), static_cast<uint8*>(output_buffer->data()),
output_buffer->size(), output_buffer->size(),
base::SharedMemory::NULLHandle(), base::SharedMemory::NULLHandle(),
......
...@@ -251,16 +251,9 @@ void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) { ...@@ -251,16 +251,9 @@ void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) {
void DesktopVideoCaptureMachine::UpdateCaptureSize() { void DesktopVideoCaptureMachine::UpdateCaptureSize() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (oracle_proxy_.get() && desktop_window_) { if (oracle_proxy_.get() && desktop_window_) {
ui::Layer* layer = desktop_window_->layer(); ui::Layer* layer = desktop_window_->layer();
gfx::Size capture_size = oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel(
ui::ConvertSizeToPixel(layer, layer->bounds().size()); layer, layer->bounds().size()));
#if defined(OS_CHROMEOS)
// Pad desktop capture size to multiples of 16 pixels to accommodate HW
// encoder. TODO(hshi): remove this hack. See http://crbug.com/402151
capture_size.SetSize((capture_size.width() + 15) & ~15,
(capture_size.height() + 15) & ~15);
#endif
oracle_proxy_->UpdateCaptureSize(capture_size);
} }
ClearCursorState(); ClearCursorState();
} }
......
...@@ -604,7 +604,8 @@ void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread( ...@@ -604,7 +604,8 @@ void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
} }
client->event_handler->OnBufferReady( client->event_handler->OnBufferReady(
client->controller_id, buffer->id(), buffer_format, timestamp); client->controller_id, buffer->id(), buffer_format,
frame->visible_rect(), timestamp);
} }
bool inserted = bool inserted =
......
...@@ -9,6 +9,10 @@ ...@@ -9,6 +9,10 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
namespace gfx {
class Rect;
} // namespace gfx
namespace gpu { namespace gpu {
struct MailboxHolder; struct MailboxHolder;
} // namespace gpu } // namespace gpu
...@@ -51,6 +55,7 @@ class CONTENT_EXPORT VideoCaptureControllerEventHandler { ...@@ -51,6 +55,7 @@ class CONTENT_EXPORT VideoCaptureControllerEventHandler {
virtual void OnBufferReady(const VideoCaptureControllerID& id, virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) = 0; base::TimeTicks timestamp) = 0;
// A texture mailbox buffer has been filled with data. // A texture mailbox buffer has been filled with data.
......
...@@ -68,6 +68,7 @@ class MockVideoCaptureControllerEventHandler ...@@ -68,6 +68,7 @@ class MockVideoCaptureControllerEventHandler
virtual void OnBufferReady(const VideoCaptureControllerID& id, virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) OVERRIDE { base::TimeTicks timestamp) OVERRIDE {
DoBufferReady(id); DoBufferReady(id);
base::MessageLoop::current()->PostTask( base::MessageLoop::current()->PostTask(
......
...@@ -77,6 +77,7 @@ void VideoCaptureHost::OnBufferReady( ...@@ -77,6 +77,7 @@ void VideoCaptureHost::OnBufferReady(
const VideoCaptureControllerID& controller_id, const VideoCaptureControllerID& controller_id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& frame_format, const media::VideoCaptureFormat& frame_format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) { base::TimeTicks timestamp) {
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, BrowserThread::IO,
...@@ -86,6 +87,7 @@ void VideoCaptureHost::OnBufferReady( ...@@ -86,6 +87,7 @@ void VideoCaptureHost::OnBufferReady(
controller_id, controller_id,
buffer_id, buffer_id,
frame_format, frame_format,
visible_rect,
timestamp)); timestamp));
} }
...@@ -143,6 +145,7 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread( ...@@ -143,6 +145,7 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread(
const VideoCaptureControllerID& controller_id, const VideoCaptureControllerID& controller_id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) { base::TimeTicks timestamp) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
...@@ -150,7 +153,7 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread( ...@@ -150,7 +153,7 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread(
return; return;
Send(new VideoCaptureMsg_BufferReady( Send(new VideoCaptureMsg_BufferReady(
controller_id.device_id, buffer_id, format, timestamp)); controller_id.device_id, buffer_id, format, visible_rect, timestamp));
} }
void VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread( void VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread(
......
...@@ -86,6 +86,7 @@ class CONTENT_EXPORT VideoCaptureHost ...@@ -86,6 +86,7 @@ class CONTENT_EXPORT VideoCaptureHost
virtual void OnBufferReady(const VideoCaptureControllerID& id, virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) OVERRIDE; base::TimeTicks timestamp) OVERRIDE;
virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id, virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
int buffer_id, int buffer_id,
...@@ -155,6 +156,7 @@ class CONTENT_EXPORT VideoCaptureHost ...@@ -155,6 +156,7 @@ class CONTENT_EXPORT VideoCaptureHost
const VideoCaptureControllerID& controller_id, const VideoCaptureControllerID& controller_id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp); base::TimeTicks timestamp);
// Sends a filled texture mailbox buffer to the VideoCaptureMessageFilter. // Sends a filled texture mailbox buffer to the VideoCaptureMessageFilter.
......
...@@ -126,10 +126,11 @@ class MockVideoCaptureHost : public VideoCaptureHost { ...@@ -126,10 +126,11 @@ class MockVideoCaptureHost : public VideoCaptureHost {
int buffer_id)); int buffer_id));
MOCK_METHOD2(OnBufferFreed, MOCK_METHOD2(OnBufferFreed,
void(int device_id, int buffer_id)); void(int device_id, int buffer_id));
MOCK_METHOD4(OnBufferFilled, MOCK_METHOD5(OnBufferFilled,
void(int device_id, void(int device_id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp)); base::TimeTicks timestamp));
MOCK_METHOD5(OnMailboxBufferFilled, MOCK_METHOD5(OnMailboxBufferFilled,
void(int device_id, void(int device_id,
...@@ -222,6 +223,7 @@ class MockVideoCaptureHost : public VideoCaptureHost { ...@@ -222,6 +223,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
void OnBufferFilledDispatch(int device_id, void OnBufferFilledDispatch(int device_id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& frame_format, const media::VideoCaptureFormat& frame_format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) { base::TimeTicks timestamp) {
base::SharedMemory* dib = filled_dib_[buffer_id]; base::SharedMemory* dib = filled_dib_[buffer_id];
ASSERT_TRUE(dib != NULL); ASSERT_TRUE(dib != NULL);
...@@ -238,7 +240,7 @@ class MockVideoCaptureHost : public VideoCaptureHost { ...@@ -238,7 +240,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
dumper_.NewVideoFrame(dib->memory()); dumper_.NewVideoFrame(dib->memory());
} }
OnBufferFilled(device_id, buffer_id, frame_format, timestamp); OnBufferFilled(device_id, buffer_id, frame_format, visible_rect, timestamp);
if (return_buffers_) { if (return_buffers_) {
VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0); VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0);
} }
...@@ -393,7 +395,7 @@ class VideoCaptureHostTest : public testing::Test { ...@@ -393,7 +395,7 @@ class VideoCaptureHostTest : public testing::Test {
.WillRepeatedly(Return()); .WillRepeatedly(Return());
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _)) EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _))
.Times(AnyNumber()) .Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure())); .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
...@@ -426,7 +428,7 @@ class VideoCaptureHostTest : public testing::Test { ...@@ -426,7 +428,7 @@ class VideoCaptureHostTest : public testing::Test {
.Times(AnyNumber()).WillRepeatedly(Return()); .Times(AnyNumber()).WillRepeatedly(Return());
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _)) EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _, _))
.Times(AnyNumber()) .Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure())); .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
...@@ -458,7 +460,7 @@ class VideoCaptureHostTest : public testing::Test { ...@@ -458,7 +460,7 @@ class VideoCaptureHostTest : public testing::Test {
void NotifyPacketReady() { void NotifyPacketReady() {
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _)) EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _))
.Times(AnyNumber()) .Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure())) .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()))
.RetiresOnSaturation(); .RetiresOnSaturation();
......
...@@ -54,6 +54,7 @@ class MockFrameObserver : public VideoCaptureControllerEventHandler { ...@@ -54,6 +54,7 @@ class MockFrameObserver : public VideoCaptureControllerEventHandler {
virtual void OnBufferReady(const VideoCaptureControllerID& id, virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) OVERRIDE {} base::TimeTicks timestamp) OVERRIDE {}
virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id, virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
int buffer_id, int buffer_id,
......
...@@ -45,10 +45,11 @@ IPC_MESSAGE_CONTROL2(VideoCaptureMsg_FreeBuffer, ...@@ -45,10 +45,11 @@ IPC_MESSAGE_CONTROL2(VideoCaptureMsg_FreeBuffer,
int /* buffer_id */) int /* buffer_id */)
// Tell the renderer process that a buffer is available from video capture. // Tell the renderer process that a buffer is available from video capture.
IPC_MESSAGE_CONTROL4(VideoCaptureMsg_BufferReady, IPC_MESSAGE_CONTROL5(VideoCaptureMsg_BufferReady,
int /* device id */, int /* device id */,
int /* buffer_id */, int /* buffer_id */,
media::VideoCaptureFormat /* format */, media::VideoCaptureFormat /* format */,
gfx::Rect /* visible_rect */,
base::TimeTicks /* timestamp */) base::TimeTicks /* timestamp */)
// Tell the renderer process that a texture mailbox buffer is available from // Tell the renderer process that a texture mailbox buffer is available from
......
...@@ -206,6 +206,7 @@ void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { ...@@ -206,6 +206,7 @@ void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) {
void VideoCaptureImpl::OnBufferReceived(int buffer_id, void VideoCaptureImpl::OnBufferReceived(int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) { base::TimeTicks timestamp) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
...@@ -235,8 +236,8 @@ void VideoCaptureImpl::OnBufferReceived(int buffer_id, ...@@ -235,8 +236,8 @@ void VideoCaptureImpl::OnBufferReceived(int buffer_id,
media::VideoFrame::WrapExternalPackedMemory( media::VideoFrame::WrapExternalPackedMemory(
media::VideoFrame::I420, media::VideoFrame::I420,
last_frame_format_.frame_size, last_frame_format_.frame_size,
gfx::Rect(last_frame_format_.frame_size), visible_rect,
last_frame_format_.frame_size, gfx::Size(visible_rect.width(), visible_rect.height()),
reinterpret_cast<uint8*>(buffer->buffer->memory()), reinterpret_cast<uint8*>(buffer->buffer->memory()),
buffer->buffer_size, buffer->buffer_size,
buffer->buffer->handle(), buffer->buffer->handle(),
......
...@@ -114,6 +114,7 @@ class CONTENT_EXPORT VideoCaptureImpl ...@@ -114,6 +114,7 @@ class CONTENT_EXPORT VideoCaptureImpl
virtual void OnBufferDestroyed(int buffer_id) OVERRIDE; virtual void OnBufferDestroyed(int buffer_id) OVERRIDE;
virtual void OnBufferReceived(int buffer_id, virtual void OnBufferReceived(int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks) OVERRIDE; base::TimeTicks) OVERRIDE;
virtual void OnMailboxBufferReceived(int buffer_id, virtual void OnMailboxBufferReceived(int buffer_id,
const gpu::MailboxHolder& mailbox_holder, const gpu::MailboxHolder& mailbox_holder,
......
...@@ -125,6 +125,7 @@ void VideoCaptureMessageFilter::OnBufferReceived( ...@@ -125,6 +125,7 @@ void VideoCaptureMessageFilter::OnBufferReceived(
int device_id, int device_id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) { base::TimeTicks timestamp) {
Delegate* delegate = find_delegate(device_id); Delegate* delegate = find_delegate(device_id);
if (!delegate) { if (!delegate) {
...@@ -137,7 +138,7 @@ void VideoCaptureMessageFilter::OnBufferReceived( ...@@ -137,7 +138,7 @@ void VideoCaptureMessageFilter::OnBufferReceived(
return; return;
} }
delegate->OnBufferReceived(buffer_id, format, timestamp); delegate->OnBufferReceived(buffer_id, format, visible_rect, timestamp);
} }
void VideoCaptureMessageFilter::OnMailboxBufferReceived( void VideoCaptureMessageFilter::OnMailboxBufferReceived(
......
...@@ -38,6 +38,7 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter { ...@@ -38,6 +38,7 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter {
// Called when a video frame buffer is received from the browser process. // Called when a video frame buffer is received from the browser process.
virtual void OnBufferReceived(int buffer_id, virtual void OnBufferReceived(int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) = 0; base::TimeTicks timestamp) = 0;
// Called when a video mailbox buffer is received from the browser process. // Called when a video mailbox buffer is received from the browser process.
...@@ -104,6 +105,7 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter { ...@@ -104,6 +105,7 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter {
void OnBufferReceived(int device_id, void OnBufferReceived(int device_id,
int buffer_id, int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp); base::TimeTicks timestamp);
// Receive a filled texture mailbox buffer from browser process. // Receive a filled texture mailbox buffer from browser process.
......
...@@ -29,9 +29,10 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate { ...@@ -29,9 +29,10 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate {
int length, int length,
int buffer_id)); int buffer_id));
MOCK_METHOD1(OnBufferDestroyed, void(int buffer_id)); MOCK_METHOD1(OnBufferDestroyed, void(int buffer_id));
MOCK_METHOD3(OnBufferReceived, MOCK_METHOD4(OnBufferReceived,
void(int buffer_id, void(int buffer_id,
const media::VideoCaptureFormat& format, const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp)); base::TimeTicks timestamp));
MOCK_METHOD4(OnMailboxBufferReceived, MOCK_METHOD4(OnMailboxBufferReceived,
void(int buffer_id, void(int buffer_id,
...@@ -94,10 +95,11 @@ TEST(VideoCaptureMessageFilterTest, Basic) { ...@@ -94,10 +95,11 @@ TEST(VideoCaptureMessageFilterTest, Basic) {
const media::VideoCaptureFormat shm_format( const media::VideoCaptureFormat shm_format(
gfx::Size(234, 512), 30, media::PIXEL_FORMAT_I420); gfx::Size(234, 512), 30, media::PIXEL_FORMAT_I420);
media::VideoCaptureFormat saved_format; media::VideoCaptureFormat saved_format;
EXPECT_CALL(delegate, OnBufferReceived(buffer_id, _, timestamp)) EXPECT_CALL(delegate, OnBufferReceived(buffer_id, _, _, timestamp))
.WillRepeatedly(SaveArg<1>(&saved_format)); .WillRepeatedly(SaveArg<1>(&saved_format));
filter->OnMessageReceived(VideoCaptureMsg_BufferReady( filter->OnMessageReceived(VideoCaptureMsg_BufferReady(
delegate.device_id(), buffer_id, shm_format, timestamp)); delegate.device_id(), buffer_id, shm_format, gfx::Rect(234, 512),
timestamp));
Mock::VerifyAndClearExpectations(&delegate); Mock::VerifyAndClearExpectations(&delegate);
EXPECT_EQ(shm_format.frame_size, saved_format.frame_size); EXPECT_EQ(shm_format.frame_size, saved_format.frame_size);
EXPECT_EQ(shm_format.frame_rate, saved_format.frame_rate); EXPECT_EQ(shm_format.frame_rate, saved_format.frame_rate);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment