blob: 82ac24985c17d1befd7227ded74cc37da83ba843 [file] [log] [blame]
// Copyright 2018 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 "content/browser/media/capture/fake_video_capture_stack.h"
#include <stdint.h>
#include <utility>
#include "base/bind_helpers.h"
#include "content/browser/media/capture/frame_test_util.h"
#include "media/base/video_frame.h"
#include "media/capture/video/video_frame_receiver.h"
#include "media/capture/video_capture_types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "ui/gfx/geometry/rect.h"
namespace content {
FakeVideoCaptureStack::FakeVideoCaptureStack() = default;
FakeVideoCaptureStack::~FakeVideoCaptureStack() = default;
void FakeVideoCaptureStack::Reset() {
frames_.clear();
last_frame_timestamp_ = base::TimeDelta::Min();
}
class FakeVideoCaptureStack::Receiver : public media::VideoFrameReceiver {
public:
explicit Receiver(FakeVideoCaptureStack* capture_stack)
: capture_stack_(capture_stack) {}
~Receiver() final = default;
private:
using Buffer = media::VideoCaptureDevice::Client::Buffer;
void OnNewBuffer(int buffer_id,
media::mojom::VideoBufferHandlePtr buffer_handle) final {
buffers_[buffer_id] = std::move(buffer_handle);
}
void OnFrameReadyInBuffer(
int buffer_id,
int frame_feedback_id,
std::unique_ptr<Buffer::ScopedAccessPermission> access,
media::mojom::VideoFrameInfoPtr frame_info) final {
const auto it = buffers_.find(buffer_id);
CHECK(it != buffers_.end());
CHECK(it->second->is_read_only_shmem_region());
base::ReadOnlySharedMemoryMapping mapping =
it->second->get_read_only_shmem_region().Map();
CHECK(mapping.IsValid());
CHECK_LE(media::VideoCaptureFormat(frame_info->coded_size, 0.0f,
frame_info->pixel_format)
.ImageAllocationSize(),
mapping.size());
auto frame = media::VideoFrame::WrapExternalData(
frame_info->pixel_format, frame_info->coded_size,
frame_info->visible_rect, frame_info->visible_rect.size(),
const_cast<uint8_t*>(static_cast<const uint8_t*>(mapping.memory())),
mapping.size(), frame_info->timestamp);
CHECK(frame);
frame->metadata()->MergeInternalValuesFrom(frame_info->metadata);
if (frame_info->color_space.has_value())
frame->set_color_space(frame_info->color_space.value());
// This destruction observer will unmap the shared memory when the
// VideoFrame goes out-of-scope.
frame->AddDestructionObserver(base::BindOnce(
base::DoNothing::Once<base::ReadOnlySharedMemoryMapping>(),
std::move(mapping)));
// This destruction observer will notify the video capture device once all
// downstream code is done using the VideoFrame.
frame->AddDestructionObserver(base::BindOnce(
[](std::unique_ptr<Buffer::ScopedAccessPermission> access) {},
std::move(access)));
capture_stack_->OnReceivedFrame(std::move(frame));
}
void OnBufferRetired(int buffer_id) final {
const auto it = buffers_.find(buffer_id);
CHECK(it != buffers_.end());
buffers_.erase(it);
}
void OnError(media::VideoCaptureError) final {
capture_stack_->error_occurred_ = true;
}
void OnFrameDropped(media::VideoCaptureFrameDropReason) final {}
void OnLog(const std::string& message) final {
capture_stack_->log_messages_.push_back(message);
}
void OnStarted() final { capture_stack_->started_ = true; }
void OnStartedUsingGpuDecode() final { NOTREACHED(); }
FakeVideoCaptureStack* const capture_stack_;
base::flat_map<int, media::mojom::VideoBufferHandlePtr> buffers_;
DISALLOW_COPY_AND_ASSIGN(Receiver);
};
std::unique_ptr<media::VideoFrameReceiver>
FakeVideoCaptureStack::CreateFrameReceiver() {
return std::make_unique<Receiver>(this);
}
SkBitmap FakeVideoCaptureStack::NextCapturedFrame() {
CHECK(!frames_.empty());
media::VideoFrame& frame = *(frames_.front());
SkBitmap bitmap = FrameTestUtil::ConvertToBitmap(frame);
frames_.pop_front();
return bitmap;
}
void FakeVideoCaptureStack::ClearCapturedFramesQueue() {
frames_.clear();
}
void FakeVideoCaptureStack::ExpectHasLogMessages() {
EXPECT_FALSE(log_messages_.empty());
while (!log_messages_.empty()) {
VLOG(1) << "Next log message: " << log_messages_.front();
log_messages_.pop_front();
}
}
void FakeVideoCaptureStack::ExpectNoLogMessages() {
while (!log_messages_.empty()) {
ADD_FAILURE() << "Unexpected log message: " << log_messages_.front();
log_messages_.pop_front();
}
}
void FakeVideoCaptureStack::OnReceivedFrame(
scoped_refptr<media::VideoFrame> frame) {
// Frame timestamps should be monotionically increasing.
EXPECT_LT(last_frame_timestamp_, frame->timestamp());
last_frame_timestamp_ = frame->timestamp();
EXPECT_TRUE(frame->ColorSpace().IsValid());
frames_.emplace_back(std::move(frame));
}
} // namespace content