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(
if (!client_)
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 =
client_->ReserveOutputBuffer(video_frame_format_,
params_.requested_format.frame_size);
client_->ReserveOutputBuffer(video_frame_format_, coded_size);
const bool should_capture =
oracle_->ObserveEventAndDecideCapture(event, damage_rect, event_time);
const bool content_is_dirty =
......@@ -123,9 +128,9 @@ bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
if (video_frame_format_ != media::VideoFrame::NATIVE_TEXTURE) {
*storage = media::VideoFrame::WrapExternalPackedMemory(
video_frame_format_,
params_.requested_format.frame_size,
gfx::Rect(params_.requested_format.frame_size),
params_.requested_format.frame_size,
coded_size,
gfx::Rect(visible_size),
visible_size,
static_cast<uint8*>(output_buffer->data()),
output_buffer->size(),
base::SharedMemory::NULLHandle(),
......
......@@ -251,16 +251,9 @@ void DesktopVideoCaptureMachine::Stop(const base::Closure& callback) {
void DesktopVideoCaptureMachine::UpdateCaptureSize() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (oracle_proxy_.get() && desktop_window_) {
ui::Layer* layer = desktop_window_->layer();
gfx::Size capture_size =
ui::ConvertSizeToPixel(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);
ui::Layer* layer = desktop_window_->layer();
oracle_proxy_->UpdateCaptureSize(ui::ConvertSizeToPixel(
layer, layer->bounds().size()));
}
ClearCursorState();
}
......
......@@ -604,7 +604,8 @@ void VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread(
}
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 =
......
......@@ -9,6 +9,10 @@
#include "base/time/time.h"
#include "content/common/content_export.h"
namespace gfx {
class Rect;
} // namespace gfx
namespace gpu {
struct MailboxHolder;
} // namespace gpu
......@@ -51,6 +55,7 @@ class CONTENT_EXPORT VideoCaptureControllerEventHandler {
virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) = 0;
// A texture mailbox buffer has been filled with data.
......
......@@ -68,6 +68,7 @@ class MockVideoCaptureControllerEventHandler
virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) OVERRIDE {
DoBufferReady(id);
base::MessageLoop::current()->PostTask(
......
......@@ -77,6 +77,7 @@ void VideoCaptureHost::OnBufferReady(
const VideoCaptureControllerID& controller_id,
int buffer_id,
const media::VideoCaptureFormat& frame_format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) {
BrowserThread::PostTask(
BrowserThread::IO,
......@@ -86,6 +87,7 @@ void VideoCaptureHost::OnBufferReady(
controller_id,
buffer_id,
frame_format,
visible_rect,
timestamp));
}
......@@ -143,6 +145,7 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread(
const VideoCaptureControllerID& controller_id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
......@@ -150,7 +153,7 @@ void VideoCaptureHost::DoSendFilledBufferOnIOThread(
return;
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(
......
......@@ -86,6 +86,7 @@ class CONTENT_EXPORT VideoCaptureHost
virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) OVERRIDE;
virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
......@@ -155,6 +156,7 @@ class CONTENT_EXPORT VideoCaptureHost
const VideoCaptureControllerID& controller_id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp);
// Sends a filled texture mailbox buffer to the VideoCaptureMessageFilter.
......
......@@ -126,10 +126,11 @@ class MockVideoCaptureHost : public VideoCaptureHost {
int buffer_id));
MOCK_METHOD2(OnBufferFreed,
void(int device_id, int buffer_id));
MOCK_METHOD4(OnBufferFilled,
MOCK_METHOD5(OnBufferFilled,
void(int device_id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp));
MOCK_METHOD5(OnMailboxBufferFilled,
void(int device_id,
......@@ -222,6 +223,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
void OnBufferFilledDispatch(int device_id,
int buffer_id,
const media::VideoCaptureFormat& frame_format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) {
base::SharedMemory* dib = filled_dib_[buffer_id];
ASSERT_TRUE(dib != NULL);
......@@ -238,7 +240,7 @@ class MockVideoCaptureHost : public VideoCaptureHost {
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_) {
VideoCaptureHost::OnReceiveEmptyBuffer(device_id, buffer_id, 0);
}
......@@ -393,7 +395,7 @@ class VideoCaptureHostTest : public testing::Test {
.WillRepeatedly(Return());
base::RunLoop run_loop;
EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _))
EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _))
.Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
......@@ -426,7 +428,7 @@ class VideoCaptureHostTest : public testing::Test {
.Times(AnyNumber()).WillRepeatedly(Return());
base::RunLoop run_loop;
EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _))
EXPECT_CALL(*host_, OnBufferFilled(kDeviceId, _, _, _, _))
.Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
......@@ -458,7 +460,7 @@ class VideoCaptureHostTest : public testing::Test {
void NotifyPacketReady() {
base::RunLoop run_loop;
EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _))
EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _))
.Times(AnyNumber())
.WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()))
.RetiresOnSaturation();
......
......@@ -54,6 +54,7 @@ class MockFrameObserver : public VideoCaptureControllerEventHandler {
virtual void OnBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) OVERRIDE {}
virtual void OnMailboxBufferReady(const VideoCaptureControllerID& id,
int buffer_id,
......
......@@ -45,10 +45,11 @@ IPC_MESSAGE_CONTROL2(VideoCaptureMsg_FreeBuffer,
int /* buffer_id */)
// 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 /* buffer_id */,
media::VideoCaptureFormat /* format */,
gfx::Rect /* visible_rect */,
base::TimeTicks /* timestamp */)
// Tell the renderer process that a texture mailbox buffer is available from
......
......@@ -206,6 +206,7 @@ void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) {
void VideoCaptureImpl::OnBufferReceived(int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) {
DCHECK(thread_checker_.CalledOnValidThread());
......@@ -235,8 +236,8 @@ void VideoCaptureImpl::OnBufferReceived(int buffer_id,
media::VideoFrame::WrapExternalPackedMemory(
media::VideoFrame::I420,
last_frame_format_.frame_size,
gfx::Rect(last_frame_format_.frame_size),
last_frame_format_.frame_size,
visible_rect,
gfx::Size(visible_rect.width(), visible_rect.height()),
reinterpret_cast<uint8*>(buffer->buffer->memory()),
buffer->buffer_size,
buffer->buffer->handle(),
......
......@@ -114,6 +114,7 @@ class CONTENT_EXPORT VideoCaptureImpl
virtual void OnBufferDestroyed(int buffer_id) OVERRIDE;
virtual void OnBufferReceived(int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks) OVERRIDE;
virtual void OnMailboxBufferReceived(int buffer_id,
const gpu::MailboxHolder& mailbox_holder,
......
......@@ -125,6 +125,7 @@ void VideoCaptureMessageFilter::OnBufferReceived(
int device_id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) {
Delegate* delegate = find_delegate(device_id);
if (!delegate) {
......@@ -137,7 +138,7 @@ void VideoCaptureMessageFilter::OnBufferReceived(
return;
}
delegate->OnBufferReceived(buffer_id, format, timestamp);
delegate->OnBufferReceived(buffer_id, format, visible_rect, timestamp);
}
void VideoCaptureMessageFilter::OnMailboxBufferReceived(
......
......@@ -38,6 +38,7 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter {
// Called when a video frame buffer is received from the browser process.
virtual void OnBufferReceived(int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp) = 0;
// Called when a video mailbox buffer is received from the browser process.
......@@ -104,6 +105,7 @@ class CONTENT_EXPORT VideoCaptureMessageFilter : public IPC::MessageFilter {
void OnBufferReceived(int device_id,
int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp);
// Receive a filled texture mailbox buffer from browser process.
......
......@@ -29,9 +29,10 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate {
int length,
int buffer_id));
MOCK_METHOD1(OnBufferDestroyed, void(int buffer_id));
MOCK_METHOD3(OnBufferReceived,
MOCK_METHOD4(OnBufferReceived,
void(int buffer_id,
const media::VideoCaptureFormat& format,
const gfx::Rect& visible_rect,
base::TimeTicks timestamp));
MOCK_METHOD4(OnMailboxBufferReceived,
void(int buffer_id,
......@@ -94,10 +95,11 @@ TEST(VideoCaptureMessageFilterTest, Basic) {
const media::VideoCaptureFormat shm_format(
gfx::Size(234, 512), 30, media::PIXEL_FORMAT_I420);
media::VideoCaptureFormat saved_format;
EXPECT_CALL(delegate, OnBufferReceived(buffer_id, _, timestamp))
EXPECT_CALL(delegate, OnBufferReceived(buffer_id, _, _, timestamp))
.WillRepeatedly(SaveArg<1>(&saved_format));
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);
EXPECT_EQ(shm_format.frame_size, saved_format.frame_size);
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