| Index: media/capture/video/fake_video_capture_device.cc
|
| diff --git a/media/capture/video/fake_video_capture_device.cc b/media/capture/video/fake_video_capture_device.cc
|
| index 333bca72ba09e6691058f4fcffa8a795adfc8962..922865fc9dd8bea03ab00b5f41040692a0c4e226 100644
|
| --- a/media/capture/video/fake_video_capture_device.cc
|
| +++ b/media/capture/video/fake_video_capture_device.cc
|
| @@ -28,20 +28,70 @@ namespace media {
|
| static const float kPacmanAngularVelocity = 600;
|
| // Beep every 500 ms.
|
| static const int kBeepInterval = 500;
|
| +// Gradient travels from bottom to top in 5 seconds.
|
| +static const float kGradientFrequency = 1.f / 5;
|
|
|
| static const uint32_t kMinZoom = 100;
|
| static const uint32_t kMaxZoom = 400;
|
| static const uint32_t kZoomStep = 1;
|
|
|
| -void DrawPacman(bool use_argb,
|
| +// Starting from top left, -45 deg gradient. Value at point (row, column) is
|
| +// calculated as (top_left_value + (row + column) * step) % MAX_VALUE, where
|
| +// step is MAX_VALUE / (width + height). MAX_VALUE is 255 (for 8 bit per
|
| +// component) or 65535 for Y16.
|
| +// This is handy for pixel tests where we use the squares to verify rendering.
|
| +void DrawGradientSquares(VideoPixelFormat frame_format,
|
| + uint8_t* const pixels,
|
| + base::TimeDelta elapsed_time,
|
| + const gfx::Size& frame_size) {
|
| + const int width = frame_size.width();
|
| + const int height = frame_size.height();
|
| + const int side = width / 16; // square side length.
|
| + DCHECK(side);
|
| + const gfx::Point squares[] = {{0, 0},
|
| + {width - side, 0},
|
| + {0, height - side},
|
| + {width - side, height - side}};
|
| + const float start =
|
| + fmod(65536 * elapsed_time.InSecondsF() * kGradientFrequency, 65536);
|
| + const float color_step = 65535 / static_cast<float>(width + height);
|
| + for (const auto& corner : squares) {
|
| + for (int y = corner.y(); y < corner.y() + side; ++y) {
|
| + for (int x = corner.x(); x < corner.x() + side; ++x) {
|
| + const unsigned int value =
|
| + static_cast<unsigned int>(start + (x + y) * color_step) & 0xFFFF;
|
| + size_t offset = (y * width) + x;
|
| + switch (frame_format) {
|
| + case PIXEL_FORMAT_Y16:
|
| + pixels[offset * sizeof(uint16_t)] = value & 0xFF;
|
| + pixels[offset * sizeof(uint16_t) + 1] = value >> 8;
|
| + break;
|
| + case PIXEL_FORMAT_ARGB:
|
| + pixels[offset * sizeof(uint32_t) + 1] = value >> 8;
|
| + pixels[offset * sizeof(uint32_t) + 2] = value >> 8;
|
| + pixels[offset * sizeof(uint32_t) + 3] = value >> 8;
|
| + break;
|
| + default:
|
| + pixels[offset] = value >> 8;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +void DrawPacman(VideoPixelFormat frame_format,
|
| uint8_t* const data,
|
| base::TimeDelta elapsed_time,
|
| float frame_rate,
|
| const gfx::Size& frame_size,
|
| uint32_t zoom) {
|
| // |kN32_SkColorType| stands for the appropriate RGBA/BGRA format.
|
| - const SkColorType colorspace =
|
| - use_argb ? kN32_SkColorType : kAlpha_8_SkColorType;
|
| + const SkColorType colorspace = (frame_format == PIXEL_FORMAT_ARGB)
|
| + ? kN32_SkColorType
|
| + : kAlpha_8_SkColorType;
|
| + // Skia doesn't support 16 bit alpha rendering, so we 8 bit alpha and then use
|
| + // this as high byte values in 16 bit pixels.
|
| const SkImageInfo info = SkImageInfo::Make(
|
| frame_size.width(), frame_size.height(), colorspace, kOpaque_SkAlphaType);
|
| SkBitmap bitmap;
|
| @@ -58,7 +108,7 @@ void DrawPacman(bool use_argb,
|
| canvas.setMatrix(matrix);
|
|
|
| // Equalize Alpha_8 that has light green background while RGBA has white.
|
| - if (use_argb) {
|
| + if (frame_format == PIXEL_FORMAT_ARGB) {
|
| const SkRect full_frame =
|
| SkRect::MakeWH(frame_size.width(), frame_size.height());
|
| paint.setARGB(255, 0, 127, 0);
|
| @@ -87,6 +137,14 @@ void DrawPacman(bool use_argb,
|
| milliseconds, frame_count);
|
| canvas.scale(3, 3);
|
| canvas.drawText(time_string.data(), time_string.length(), 30, 20, paint);
|
| +
|
| + if (frame_format == PIXEL_FORMAT_Y16) {
|
| + // Use 8 bit bitmap rendered to first half of the buffer as high byte values
|
| + // for the whole buffer. Low byte values are not important.
|
| + for (int i = frame_size.GetArea() - 1; i >= 0; --i)
|
| + data[i * 2 + 1] = data[i];
|
| + }
|
| + DrawGradientSquares(frame_format, data, elapsed_time, frame_size);
|
| }
|
|
|
| // Creates a PNG-encoded frame and sends it back to |callback|. The other
|
| @@ -99,7 +157,7 @@ void DoTakeFakePhoto(VideoCaptureDevice::TakePhotoCallback callback,
|
| std::unique_ptr<uint8_t[]> buffer(new uint8_t[VideoFrame::AllocationSize(
|
| PIXEL_FORMAT_ARGB, capture_format.frame_size)]);
|
|
|
| - DrawPacman(true /* use_argb */, buffer.get(), elapsed_time, fake_capture_rate,
|
| + DrawPacman(PIXEL_FORMAT_ARGB, buffer.get(), elapsed_time, fake_capture_rate,
|
| capture_format.frame_size, zoom);
|
|
|
| mojom::BlobPtr blob = mojom::Blob::New();
|
| @@ -114,9 +172,11 @@ void DoTakeFakePhoto(VideoCaptureDevice::TakePhotoCallback callback,
|
| }
|
|
|
| FakeVideoCaptureDevice::FakeVideoCaptureDevice(BufferOwnership buffer_ownership,
|
| - float fake_capture_rate)
|
| + float fake_capture_rate,
|
| + VideoPixelFormat pixel_format)
|
| : buffer_ownership_(buffer_ownership),
|
| fake_capture_rate_(fake_capture_rate),
|
| + pixel_format_(pixel_format),
|
| current_zoom_(kMinZoom),
|
| weak_factory_(this) {}
|
|
|
| @@ -141,22 +201,25 @@ void FakeVideoCaptureDevice::AllocateAndStart(
|
| capture_format_.frame_size.SetSize(1280, 720);
|
| else if (params.requested_format.frame_size.width() > 320)
|
| capture_format_.frame_size.SetSize(640, 480);
|
| - else
|
| + else if (params.requested_format.frame_size.width() > 96)
|
| capture_format_.frame_size.SetSize(320, 240);
|
| + else
|
| + capture_format_.frame_size.SetSize(96, 96);
|
|
|
| + capture_format_.pixel_format = pixel_format_;
|
| if (buffer_ownership_ == BufferOwnership::CLIENT_BUFFERS) {
|
| capture_format_.pixel_storage = PIXEL_STORAGE_CPU;
|
| capture_format_.pixel_format = PIXEL_FORMAT_ARGB;
|
| DVLOG(1) << "starting with client argb buffers";
|
| } else if (buffer_ownership_ == BufferOwnership::OWN_BUFFERS) {
|
| capture_format_.pixel_storage = PIXEL_STORAGE_CPU;
|
| - capture_format_.pixel_format = PIXEL_FORMAT_I420;
|
| - DVLOG(1) << "starting with own I420 buffers";
|
| + DVLOG(1) << "starting with own " << VideoPixelFormatToString(pixel_format_)
|
| + << " buffers";
|
| }
|
|
|
| - if (capture_format_.pixel_format == PIXEL_FORMAT_I420) {
|
| + if (buffer_ownership_ == BufferOwnership::OWN_BUFFERS) {
|
| fake_frame_.reset(new uint8_t[VideoFrame::AllocationSize(
|
| - PIXEL_FORMAT_I420, capture_format_.frame_size)]);
|
| + pixel_format_, capture_format_.frame_size)]);
|
| }
|
|
|
| beep_time_ = base::TimeDelta();
|
| @@ -235,11 +298,10 @@ void FakeVideoCaptureDevice::CaptureUsingOwnBuffers(
|
| base::TimeTicks expected_execution_time) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| const size_t frame_size = capture_format_.ImageAllocationSize();
|
| - memset(fake_frame_.get(), 0, frame_size);
|
|
|
| - DrawPacman(false /* use_argb */, fake_frame_.get(), elapsed_time_,
|
| + memset(fake_frame_.get(), 0, frame_size);
|
| + DrawPacman(capture_format_.pixel_format, fake_frame_.get(), elapsed_time_,
|
| fake_capture_rate_, capture_format_.frame_size, current_zoom_);
|
| -
|
| // Give the captured frame to the client.
|
| base::TimeTicks now = base::TimeTicks::Now();
|
| if (first_ref_time_.is_null())
|
| @@ -265,11 +327,10 @@ void FakeVideoCaptureDevice::CaptureUsingClientBuffers(
|
| DCHECK(capture_buffer->data()) << "Buffer has NO backing memory";
|
|
|
| DCHECK_EQ(PIXEL_STORAGE_CPU, capture_format_.pixel_storage);
|
| - DCHECK_EQ(PIXEL_FORMAT_ARGB, capture_format_.pixel_format);
|
| uint8_t* data_ptr = static_cast<uint8_t*>(capture_buffer->data());
|
| memset(data_ptr, 0, capture_buffer->mapped_size());
|
| - DrawPacman(true /* use_argb */, data_ptr, elapsed_time_, fake_capture_rate_,
|
| - capture_format_.frame_size, current_zoom_);
|
| + DrawPacman(capture_format_.pixel_format, data_ptr, elapsed_time_,
|
| + fake_capture_rate_, capture_format_.frame_size, current_zoom_);
|
|
|
| // Give the captured frame to the client.
|
| base::TimeTicks now = base::TimeTicks::Now();
|
|
|