Commit 90afa8ca authored by Mario Sanchez Prada's avatar Mario Sanchez Prada Committed by Commit Bot

Migrate references to viz::mojom::FrameSinkVideoConsumerFrameCallbacks interface

Convert the remaining bits in both the implementation and clients from the
browser and renderer processes for the FrameSinkVideoConsumerFrameCallbacks
interface, and adapt unit tests.

Bug: 955171, 978694
Change-Id: I32d5ad59de88e231ce86670725ca1473491f7998
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1860534Reviewed-by: default avatarOksana Zhuravlova <oksamyt@chromium.org>
Reviewed-by: default avatarDana Fried <dfried@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarenne <enne@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarYuri Wiitala <miu@chromium.org>
Commit-Queue: Mario Sanchez Prada <mario@igalia.com>
Cr-Commit-Position: refs/heads/master@{#707096}
parent 8227ef43
......@@ -21,6 +21,7 @@
#include "media/base/limits.h"
#include "media/base/video_frame.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/public/platform/web_mouse_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
......@@ -266,7 +267,8 @@ void DevToolsEyeDropper::OnFrameCaptured(
base::ReadOnlySharedMemoryRegion data,
::media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) {
gfx::Size view_size = host_->GetView()->GetViewBounds().size();
if (view_size != content_rect.size()) {
video_capturer_->SetResolutionConstraints(view_size, view_size, true);
......@@ -274,8 +276,11 @@ void DevToolsEyeDropper::OnFrameCaptured(
return;
}
mojo::Remote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks_remote(std::move(callbacks));
if (!data.IsValid()) {
callbacks->Done();
callbacks_remote->Done();
return;
}
base::ReadOnlySharedMemoryMapping mapping = data.Map();
......@@ -305,7 +310,7 @@ void DevToolsEyeDropper::OnFrameCaptured(
base::ReadOnlySharedMemoryMapping mapping;
// Prevents FrameSinkVideoCapturer from recycling the shared memory that
// backs |frame_|.
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr releaser;
mojo::Remote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> releaser;
};
frame_.installPixels(
SkImageInfo::MakeN32(content_rect.width(), content_rect.height(),
......@@ -317,7 +322,7 @@ void DevToolsEyeDropper::OnFrameCaptured(
[](void* addr, void* context) {
delete static_cast<FramePinner*>(context);
},
new FramePinner{std::move(mapping), std::move(callbacks)});
new FramePinner{std::move(mapping), std::move(callbacks_remote)});
frame_.setImmutable();
UpdateCursor();
......
......@@ -12,6 +12,7 @@
#include "components/viz/host/client_frame_sink_video_capturer.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace blink {
......@@ -47,7 +48,8 @@ class DevToolsEyeDropper : public content::WebContentsObserver,
base::ReadOnlySharedMemoryRegion data,
::media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) override;
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) override;
void OnStopped() override;
EyeDropperCallback callback_;
......
......@@ -20,6 +20,7 @@
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/scrollbar_size.h"
......@@ -211,15 +212,19 @@ void ThumbnailTabHelper::OnFrameCaptured(
base::ReadOnlySharedMemoryRegion data,
::media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
::viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
mojo::PendingRemote<::viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) {
CHECK(video_capturer_);
if (!ShouldKeepUpdatingThumbnail())
StopVideoCapture();
mojo::Remote<::viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks_remote(std::move(callbacks));
// Process captured image.
if (!data.IsValid()) {
callbacks->Done();
callbacks_remote->Done();
return;
}
base::ReadOnlySharedMemoryMapping mapping = data.Map();
......@@ -249,7 +254,7 @@ void ThumbnailTabHelper::OnFrameCaptured(
base::ReadOnlySharedMemoryMapping mapping;
// Prevents FrameSinkVideoCapturer from recycling the shared memory that
// backs |frame_|.
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr releaser;
mojo::Remote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> releaser;
};
content::RenderWidgetHostView* const source_view = GetView();
......@@ -284,7 +289,7 @@ void ThumbnailTabHelper::OnFrameCaptured(
[](void* addr, void* context) {
delete static_cast<FramePinner*>(context);
},
new FramePinner{std::move(mapping), std::move(callbacks)});
new FramePinner{std::move(mapping), std::move(callbacks_remote)});
frame.setImmutable();
SkBitmap cropped_frame;
......
......@@ -18,6 +18,7 @@
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
class ThumbnailTabHelper
: public content::WebContentsUserData<ThumbnailTabHelper>,
......@@ -60,7 +61,8 @@ class ThumbnailTabHelper
base::ReadOnlySharedMemoryRegion data,
::media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
::viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) override;
mojo::PendingRemote<::viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) override;
void OnStopped() override;
// The last known visibility WebContents visibility.
......
......@@ -149,7 +149,8 @@ void ClientFrameSinkVideoCapturer::OnFrameCaptured(
base::ReadOnlySharedMemoryRegion data,
media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
mojo::PendingRemote<mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
consumer_->OnFrameCaptured(std::move(data), std::move(info), content_rect,
......
......@@ -118,7 +118,8 @@ class VIZ_HOST_EXPORT ClientFrameSinkVideoCapturer
base::ReadOnlySharedMemoryRegion data,
media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) final;
mojo::PendingRemote<mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) final;
void OnStopped() final;
// Establishes connection to FrameSinkVideoCapturer and sends the existing
......
......@@ -25,7 +25,8 @@
#include "media/base/limits.h"
#include "media/base/video_util.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"
......@@ -787,12 +788,12 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
DCHECK(frame->ColorSpace().IsValid()); // Ensure it was set by this point.
info->color_space = frame->ColorSpace();
// Create an InFlightFrameDelivery for this frame, owned by its mojo binding.
// Create an InFlightFrameDelivery for this frame, owned by its mojo receiver.
// It responds to the consumer's Done() notification by returning the video
// frame to the |frame_pool_|. It responds to the optional ProvideFeedback()
// by forwarding the measurement to the |oracle_|.
mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks;
mojo::MakeStrongBinding(
mojo::PendingRemote<mojom::FrameSinkVideoConsumerFrameCallbacks> callbacks;
mojo::MakeSelfOwnedReceiver(
std::make_unique<InFlightFrameDelivery>(
base::BindOnce(
[](scoped_refptr<VideoFrame> frame) {
......@@ -802,7 +803,7 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
base::BindOnce(&VideoCaptureOracle::RecordConsumerFeedback,
feedback_weak_factory_.GetWeakPtr(),
oracle_frame_number)),
mojo::MakeRequest(&callbacks));
callbacks.InitWithNewPipeAndPassReceiver());
// Send the frame to the consumer.
consumer_->OnFrameCaptured(std::move(handle), std::move(info), content_rect,
......
......@@ -142,13 +142,17 @@ class MockConsumer : public mojom::FrameSinkVideoConsumer {
base::ReadOnlySharedMemoryRegion data,
media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& expected_content_rect,
mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) final {
mojo::PendingRemote<mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) final {
ASSERT_TRUE(data.IsValid());
const auto required_bytes_to_hold_planes =
static_cast<uint32_t>(info->coded_size.GetArea() * 3 / 2);
ASSERT_LE(required_bytes_to_hold_planes, data.GetSize());
ASSERT_TRUE(info);
ASSERT_TRUE(callbacks.get());
mojo::Remote<mojom::FrameSinkVideoConsumerFrameCallbacks> callbacks_remote(
std::move(callbacks));
ASSERT_TRUE(callbacks_remote.get());
// Map the shared memory buffer and re-constitute a VideoFrame instance
// around it for analysis via TakeFrame().
......@@ -175,7 +179,7 @@ class MockConsumer : public mojom::FrameSinkVideoConsumer {
frames_.push_back(std::move(frame));
done_callbacks_.push_back(
base::BindOnce(&mojom::FrameSinkVideoConsumerFrameCallbacks::Done,
std::move(callbacks)));
std::move(callbacks_remote)));
}
mojo::Receiver<mojom::FrameSinkVideoConsumer> receiver_{this};
......
......@@ -135,7 +135,8 @@ void DevToolsVideoConsumer::OnFrameCaptured(
base::ReadOnlySharedMemoryRegion data,
::media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) {
if (!data.IsValid())
return;
......@@ -169,7 +170,8 @@ void DevToolsVideoConsumer::OnFrameCaptured(
}
frame->AddDestructionObserver(base::BindOnce(
[](base::ReadOnlySharedMemoryMapping mapping,
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {},
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) {},
std::move(mapping), std::move(callbacks)));
frame->metadata()->MergeInternalValuesFrom(info->metadata);
if (info->color_space.has_value())
......
......@@ -10,6 +10,7 @@
#include "base/time/time.h"
#include "components/viz/host/client_frame_sink_video_capturer.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "ui/gfx/geometry/size.h"
class SkBitmap;
......@@ -66,7 +67,8 @@ class CONTENT_EXPORT DevToolsVideoConsumer
base::ReadOnlySharedMemoryRegion data,
::media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) override;
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) override;
void OnStopped() override;
// Default min frame size is 1x1, as otherwise, nothing would be captured.
......
......@@ -131,10 +131,12 @@ class MockFrameSinkVideoCapturer : public viz::mojom::FrameSinkVideoCapturer {
class MockFrameSinkVideoConsumerFrameCallbacks
: public viz::mojom::FrameSinkVideoConsumerFrameCallbacks {
public:
MockFrameSinkVideoConsumerFrameCallbacks() {}
MockFrameSinkVideoConsumerFrameCallbacks() = default;
void Bind(viz::mojom::FrameSinkVideoConsumerFrameCallbacksRequest request) {
receiver_.Bind(std::move(request));
void Bind(
mojo::PendingReceiver<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
receiver) {
receiver_.Bind(std::move(receiver));
}
MOCK_METHOD0(Done, void());
......@@ -185,8 +187,9 @@ class DevToolsVideoConsumerTest : public testing::Test {
}
void SimulateFrameCapture(base::ReadOnlySharedMemoryRegion data) {
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks_ptr;
callbacks.Bind(mojo::MakeRequest(&callbacks_ptr));
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks_remote;
callbacks.Bind(callbacks_remote.InitWithNewPipeAndPassReceiver());
media::mojom::VideoFrameInfoPtr info = media::mojom::VideoFrameInfo::New(
base::TimeDelta(), base::Value(base::Value::Type::DICTIONARY), kFormat,
......@@ -195,7 +198,7 @@ class DevToolsVideoConsumerTest : public testing::Test {
consumer_->OnFrameCaptured(std::move(data), std::move(info),
gfx::Rect(kResolution),
std::move(callbacks_ptr));
std::move(callbacks_remote));
}
void StartCaptureWithMockCapturer() {
......
......@@ -206,12 +206,16 @@ void FrameSinkVideoCaptureDevice::OnFrameCaptured(
base::ReadOnlySharedMemoryRegion data,
media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callbacks);
mojo::Remote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks_remote(std::move(callbacks));
if (!receiver_ || !data.IsValid()) {
callbacks->Done();
callbacks_remote->Done();
return;
}
......@@ -225,11 +229,11 @@ void FrameSinkVideoCaptureDevice::OnFrameCaptured(
// number of frames in-flight.
constexpr size_t kMaxInFlightFrames = 32; // Arbitrarily-chosen limit.
DCHECK_LT(frame_callbacks_.size(), kMaxInFlightFrames);
frame_callbacks_.emplace_back(std::move(callbacks));
frame_callbacks_.emplace_back(std::move(callbacks_remote));
break;
}
if (!frame_callbacks_[index].is_bound()) {
frame_callbacks_[index] = std::move(callbacks);
frame_callbacks_[index] = std::move(callbacks_remote);
break;
}
}
......
......@@ -22,6 +22,7 @@
#include "media/capture/video/video_capture_device.h"
#include "media/capture/video/video_frame_receiver.h"
#include "media/capture/video_capture_types.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
......@@ -78,7 +79,8 @@ class CONTENT_EXPORT FrameSinkVideoCaptureDevice
base::ReadOnlySharedMemoryRegion data,
media::mojom::VideoFrameInfoPtr info,
const gfx::Rect& content_rect,
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) final;
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) final;
void OnStopped() final;
// These are called to notify when the capture target has changed or was
......@@ -145,12 +147,12 @@ class CONTENT_EXPORT FrameSinkVideoCaptureDevice
std::unique_ptr<viz::ClientFrameSinkVideoCapturer> capturer_;
// A vector that holds the "callbacks" mojo InterfacePtr for each frame while
// the frame is being processed by VideoFrameReceiver. The index corresponding
// to a particular frame is used as the BufferId passed to VideoFrameReceiver.
// A vector that holds the "callbacks" mojo::Remote for each frame while the
// frame is being processed by VideoFrameReceiver. The index corresponding to
// a particular frame is used as the BufferId passed to VideoFrameReceiver.
// Therefore, non-null pointers in this vector must never move to a different
// position.
std::vector<viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr>
std::vector<mojo::Remote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>>
frame_callbacks_;
// Set when OnFatalError() is called. This prevents any future
......
......@@ -20,7 +20,9 @@
#include "media/capture/video_capture_types.h"
#include "mojo/public/cpp/base/shared_memory_utils.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -136,18 +138,21 @@ class MockFrameSinkVideoCapturer : public viz::mojom::FrameSinkVideoCapturer {
class MockFrameSinkVideoConsumerFrameCallbacks
: public viz::mojom::FrameSinkVideoConsumerFrameCallbacks {
public:
MockFrameSinkVideoConsumerFrameCallbacks() : binding_(this) {}
MockFrameSinkVideoConsumerFrameCallbacks() = default;
void Bind(viz::mojom::FrameSinkVideoConsumerFrameCallbacksRequest request) {
void Bind(
mojo::PendingReceiver<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
receiver) {
DCHECK_NOT_ON_DEVICE_THREAD();
binding_.Bind(std::move(request));
receiver_.Bind(std::move(receiver));
}
MOCK_METHOD0(Done, void());
MOCK_METHOD1(ProvideFeedback, void(double utilization));
private:
mojo::Binding<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> binding_;
mojo::Receiver<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> receiver_{
this};
};
// Mock for the VideoFrameReceiver, the point-of-injection of video frames into
......@@ -365,16 +370,16 @@ class FrameSinkVideoCaptureDeviceTest : public testing::Test {
memset(region.mapping.memory(), GetFrameFillValue(frame_number),
region.mapping.size());
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks_ptr;
callbacks->Bind(mojo::MakeRequest(&callbacks_ptr));
// |callbacks_ptr| is bound on the main thread, so it needs to be re-bound
// to the device thread before calling OnFrameCaptured().
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks_remote;
callbacks->Bind(callbacks_remote.InitWithNewPipeAndPassReceiver());
// |callbacks_remote| is bound on the main thread, so it needs to be
// re-bound to the device thread before calling OnFrameCaptured().
POST_DEVICE_TASK(base::BindOnce(
[](FrameSinkVideoCaptureDevice* device,
base::ReadOnlySharedMemoryRegion data, int frame_number,
mojo::InterfacePtrInfo<
viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks_info) {
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks_remote) {
device->OnFrameCaptured(
std::move(data),
media::mojom::VideoFrameInfo::New(
......@@ -382,12 +387,10 @@ class FrameSinkVideoCaptureDeviceTest : public testing::Test {
base::Value(base::Value::Type::DICTIONARY), kFormat,
kResolution, gfx::Rect(kResolution),
gfx::ColorSpace::CreateREC709(), nullptr),
gfx::Rect(kResolution),
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr(
std::move(callbacks_info)));
gfx::Rect(kResolution), std::move(callbacks_remote));
},
base::Unretained(device_.get()), std::move(region.region), frame_number,
callbacks_ptr.PassInterface()));
std::move(callbacks_remote)));
}
// Returns a byte value based on the given |frame_number|.
......
......@@ -15,7 +15,8 @@
#include "media/base/video_util.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "mojo/public/cpp/base/shared_memory_utils.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "ui/gfx/geometry/rect.h"
using media::VideoFrame;
......@@ -364,11 +365,12 @@ void LameWindowCapturerChromeOS::DeliverFrame(
const gfx::Rect content_rect = in_flight_frame->content_rect();
// Create a mojo message pipe and bind to the InFlightFrame to wait for the
// Done() signal from the consumer. The mojo::StrongBinding takes ownership of
// the InFlightFrame.
viz::mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks;
mojo::MakeStrongBinding(std::move(in_flight_frame),
mojo::MakeRequest(&callbacks));
// Done() signal from the consumer. The mojo::SelfOwnedReceiver takes
// ownership of the InFlightFrame.
mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks;
mojo::MakeSelfOwnedReceiver(std::move(in_flight_frame),
callbacks.InitWithNewPipeAndPassReceiver());
// Send the frame to the consumer.
consumer_->OnFrameCaptured(std::move(handle), std::move(info), content_rect,
......
......@@ -46,7 +46,8 @@ interface FrameSinkVideoConsumer {
OnFrameCaptured(mojo_base.mojom.ReadOnlySharedMemoryRegion data,
media.mojom.VideoFrameInfo info,
gfx.mojom.Rect content_rect,
FrameSinkVideoConsumerFrameCallbacks callbacks);
pending_remote<FrameSinkVideoConsumerFrameCallbacks>
callbacks);
// Indicates that OnFrameCaptured() will not be called again, an end-of-stream
// signal.
......
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