| Index: media/capture/screen_capture_device_core.cc
|
| diff --git a/content/browser/media/capture/content_video_capture_device_core.cc b/media/capture/screen_capture_device_core.cc
|
| similarity index 20%
|
| copy from content/browser/media/capture/content_video_capture_device_core.cc
|
| copy to media/capture/screen_capture_device_core.cc
|
| index 336bcd63a7f578d4e757b8de39a5c5d7688dff55..a8993e7ef897b64691500c27b04eedcfbf7d2293 100644
|
| --- a/content/browser/media/capture/content_video_capture_device_core.cc
|
| +++ b/media/capture/screen_capture_device_core.cc
|
| @@ -2,228 +2,30 @@
|
| // 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/content_video_capture_device_core.h"
|
| +#include "media/capture/screen_capture_device_core.h"
|
|
|
| -#include "base/basictypes.h"
|
| #include "base/bind.h"
|
| -#include "base/callback_forward.h"
|
| -#include "base/callback_helpers.h"
|
| #include "base/logging.h"
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/memory/weak_ptr.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/sequenced_task_runner.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/stringprintf.h"
|
| -#include "base/synchronization/lock.h"
|
| -#include "base/threading/thread.h"
|
| #include "base/threading/thread_checker.h"
|
| -#include "base/time/time.h"
|
| -#include "base/trace_event/trace_event.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "media/base/video_capture_types.h"
|
| -#include "media/base/video_frame.h"
|
| -#include "media/base/video_frame_metadata.h"
|
| -#include "media/base/video_util.h"
|
| -#include "ui/gfx/geometry/rect.h"
|
|
|
| -namespace content {
|
| +namespace media {
|
|
|
| namespace {
|
|
|
| -void DeleteCaptureMachineOnUIThread(
|
| +void DeleteCaptureMachine(
|
| scoped_ptr<VideoCaptureMachine> capture_machine) {
|
| - DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
| -
|
| capture_machine.reset();
|
| }
|
|
|
| } // namespace
|
|
|
| -ThreadSafeCaptureOracle::ThreadSafeCaptureOracle(
|
| - scoped_ptr<media::VideoCaptureDevice::Client> client,
|
| - const media::VideoCaptureParams& params)
|
| - : client_(client.Pass()),
|
| - oracle_(base::TimeDelta::FromMicroseconds(
|
| - static_cast<int64>(1000000.0 / params.requested_format.frame_rate +
|
| - 0.5 /* to round to nearest int */))),
|
| - params_(params),
|
| - resolution_chooser_(params.requested_format.frame_size,
|
| - params.resolution_change_policy) {}
|
| -
|
| -ThreadSafeCaptureOracle::~ThreadSafeCaptureOracle() {}
|
| -
|
| -bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
|
| - VideoCaptureOracle::Event event,
|
| - const gfx::Rect& damage_rect,
|
| - base::TimeTicks event_time,
|
| - scoped_refptr<media::VideoFrame>* storage,
|
| - CaptureFrameCallback* callback) {
|
| - // Grab the current time before waiting to acquire the |lock_|.
|
| - const base::TimeTicks capture_begin_time = base::TimeTicks::Now();
|
| -
|
| - base::AutoLock guard(lock_);
|
| -
|
| - if (!client_)
|
| - return false; // Capture is stopped.
|
| -
|
| - const gfx::Size visible_size = resolution_chooser_.capture_size();
|
| - // Always round up the coded size to multiple of 16 pixels.
|
| - // See http://crbug.com/402151.
|
| - const gfx::Size coded_size((visible_size.width() + 15) & ~15,
|
| - (visible_size.height() + 15) & ~15);
|
| -
|
| - scoped_ptr<media::VideoCaptureDevice::Client::Buffer> output_buffer(
|
| - client_->ReserveOutputBuffer(params_.requested_format.pixel_format,
|
| - coded_size));
|
| - // TODO(miu): Use current buffer pool utilization to drive automatic video
|
| - // resolution changes. http://crbug.com/156767.
|
| - VLOG(2) << "Current buffer pool utilization is "
|
| - << (client_->GetBufferPoolUtilization() * 100.0) << '%';
|
| -
|
| - const bool should_capture =
|
| - oracle_.ObserveEventAndDecideCapture(event, damage_rect, event_time);
|
| -
|
| - const char* event_name =
|
| - (event == VideoCaptureOracle::kTimerPoll ? "poll" :
|
| - (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" :
|
| - "unknown"));
|
| -
|
| - // Consider the various reasons not to initiate a capture.
|
| - if (should_capture && !output_buffer.get()) {
|
| - TRACE_EVENT_INSTANT1("gpu.capture",
|
| - "PipelineLimited",
|
| - TRACE_EVENT_SCOPE_THREAD,
|
| - "trigger",
|
| - event_name);
|
| - return false;
|
| - } else if (!should_capture && output_buffer.get()) {
|
| - if (event == VideoCaptureOracle::kCompositorUpdate) {
|
| - // This is a normal and acceptable way to drop a frame. We've hit our
|
| - // capture rate limit: for example, the content is animating at 60fps but
|
| - // we're capturing at 30fps.
|
| - TRACE_EVENT_INSTANT1("gpu.capture", "FpsRateLimited",
|
| - TRACE_EVENT_SCOPE_THREAD,
|
| - "trigger", event_name);
|
| - }
|
| - return false;
|
| - } else if (!should_capture && !output_buffer.get()) {
|
| - // We decided not to capture, but we wouldn't have been able to if we wanted
|
| - // to because no output buffer was available.
|
| - TRACE_EVENT_INSTANT1("gpu.capture", "NearlyPipelineLimited",
|
| - TRACE_EVENT_SCOPE_THREAD,
|
| - "trigger", event_name);
|
| - return false;
|
| - }
|
| - int frame_number = oracle_.RecordCapture();
|
| - TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", output_buffer.get(),
|
| - "frame_number", frame_number,
|
| - "trigger", event_name);
|
| - // NATIVE_TEXTURE frames wrap a texture mailbox, which we don't have at the
|
| - // moment. We do not construct those frames.
|
| - if (params_.requested_format.pixel_format != media::PIXEL_FORMAT_TEXTURE) {
|
| - *storage = media::VideoFrame::WrapExternalData(
|
| - media::VideoFrame::I420,
|
| - coded_size,
|
| - gfx::Rect(visible_size),
|
| - visible_size,
|
| - static_cast<uint8*>(output_buffer->data()),
|
| - output_buffer->size(),
|
| - base::TimeDelta());
|
| - DCHECK(*storage);
|
| - }
|
| - *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame,
|
| - this,
|
| - frame_number,
|
| - base::Passed(&output_buffer),
|
| - capture_begin_time,
|
| - oracle_.estimated_frame_duration());
|
| - return true;
|
| -}
|
| -
|
| -gfx::Size ThreadSafeCaptureOracle::GetCaptureSize() const {
|
| - base::AutoLock guard(lock_);
|
| - return resolution_chooser_.capture_size();
|
| -}
|
| -
|
| -void ThreadSafeCaptureOracle::UpdateCaptureSize(const gfx::Size& source_size) {
|
| - base::AutoLock guard(lock_);
|
| - resolution_chooser_.SetSourceSize(source_size);
|
| - VLOG(1) << "Source size changed to " << source_size.ToString()
|
| - << " --> Capture size is now "
|
| - << resolution_chooser_.capture_size().ToString();
|
| -}
|
| -
|
| -void ThreadSafeCaptureOracle::Stop() {
|
| - base::AutoLock guard(lock_);
|
| - client_.reset();
|
| -}
|
| -
|
| -void ThreadSafeCaptureOracle::ReportError(const std::string& reason) {
|
| - base::AutoLock guard(lock_);
|
| - if (client_)
|
| - client_->OnError(reason);
|
| -}
|
| -
|
| -void ThreadSafeCaptureOracle::DidCaptureFrame(
|
| - int frame_number,
|
| - scoped_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
|
| - base::TimeTicks capture_begin_time,
|
| - base::TimeDelta estimated_frame_duration,
|
| - const scoped_refptr<media::VideoFrame>& frame,
|
| - base::TimeTicks timestamp,
|
| - bool success) {
|
| - base::AutoLock guard(lock_);
|
| - TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", buffer.get(),
|
| - "success", success,
|
| - "timestamp", timestamp.ToInternalValue());
|
| -
|
| - if (oracle_.CompleteCapture(frame_number, success, ×tamp)) {
|
| - TRACE_EVENT_INSTANT0("gpu.capture", "CaptureSucceeded",
|
| - TRACE_EVENT_SCOPE_THREAD);
|
| -
|
| - if (!client_)
|
| - return; // Capture is stopped.
|
| -
|
| - frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
|
| - params_.requested_format.frame_rate);
|
| - frame->metadata()->SetTimeTicks(
|
| - media::VideoFrameMetadata::CAPTURE_BEGIN_TIME, capture_begin_time);
|
| - frame->metadata()->SetTimeTicks(
|
| - media::VideoFrameMetadata::CAPTURE_END_TIME, base::TimeTicks::Now());
|
| - frame->metadata()->SetTimeDelta(media::VideoFrameMetadata::FRAME_DURATION,
|
| - estimated_frame_duration);
|
| -
|
| - frame->AddDestructionObserver(base::Bind(
|
| - &ThreadSafeCaptureOracle::DidConsumeFrame,
|
| - this,
|
| - frame_number,
|
| - frame->metadata()));
|
| -
|
| - client_->OnIncomingCapturedVideoFrame(buffer.Pass(), frame, timestamp);
|
| - }
|
| -}
|
| -
|
| -void ThreadSafeCaptureOracle::DidConsumeFrame(
|
| - int frame_number,
|
| - const media::VideoFrameMetadata* metadata) {
|
| - // Note: This function may be called on any thread by the VideoFrame
|
| - // destructor. |metadata| is still valid for read-access at this point.
|
| - double utilization = -1.0;
|
| - if (metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION,
|
| - &utilization) &&
|
| - utilization >= 0.0) {
|
| - VLOG(2) << "Consumer resource utilization for frame " << frame_number
|
| - << ": " << utilization;
|
| - }
|
| -
|
| - // TODO(miu): Use |utilization| to drive automatic video resolution changes.
|
| - // http://crbug.com/156767.
|
| -}
|
| -
|
| -void ContentVideoCaptureDeviceCore::AllocateAndStart(
|
| - const media::VideoCaptureParams& params,
|
| - scoped_ptr<media::VideoCaptureDevice::Client> client) {
|
| +void ScreenCaptureDeviceCore::AllocateAndStart(
|
| + const VideoCaptureParams& params,
|
| + scoped_ptr<VideoCaptureDevice::Client> client) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| if (state_ != kIdle) {
|
| @@ -239,8 +41,8 @@ void ContentVideoCaptureDeviceCore::AllocateAndStart(
|
| return;
|
| }
|
|
|
| - if (params.requested_format.pixel_format != media::PIXEL_FORMAT_I420 &&
|
| - params.requested_format.pixel_format != media::PIXEL_FORMAT_TEXTURE) {
|
| + if (params.requested_format.pixel_format != PIXEL_FORMAT_I420 &&
|
| + params.requested_format.pixel_format != PIXEL_FORMAT_TEXTURE) {
|
| std::string error_msg = base::StringPrintf(
|
| "unsupported format: %d", params.requested_format.pixel_format);
|
| DVLOG(1) << error_msg;
|
| @@ -258,20 +60,15 @@ void ContentVideoCaptureDeviceCore::AllocateAndStart(
|
|
|
| oracle_proxy_ = new ThreadSafeCaptureOracle(client.Pass(), params);
|
|
|
| - // Starts the capture machine asynchronously.
|
| - BrowserThread::PostTaskAndReplyWithResult(
|
| - BrowserThread::UI,
|
| - FROM_HERE,
|
| - base::Bind(&VideoCaptureMachine::Start,
|
| - base::Unretained(capture_machine_.get()),
|
| - oracle_proxy_,
|
| - params),
|
| - base::Bind(&ContentVideoCaptureDeviceCore::CaptureStarted, AsWeakPtr()));
|
| + capture_machine_->Start(
|
| + oracle_proxy_,
|
| + params,
|
| + base::Bind(&ScreenCaptureDeviceCore::CaptureStarted, AsWeakPtr()));
|
|
|
| TransitionStateTo(kCapturing);
|
| }
|
|
|
| -void ContentVideoCaptureDeviceCore::StopAndDeAllocate() {
|
| +void ScreenCaptureDeviceCore::StopAndDeAllocate() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| if (state_ != kCapturing)
|
| @@ -282,15 +79,10 @@ void ContentVideoCaptureDeviceCore::StopAndDeAllocate() {
|
|
|
| TransitionStateTo(kIdle);
|
|
|
| - // Stops the capture machine asynchronously.
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE, base::Bind(
|
| - &VideoCaptureMachine::Stop,
|
| - base::Unretained(capture_machine_.get()),
|
| - base::Bind(&base::DoNothing)));
|
| + capture_machine_->Stop(base::Bind(&base::DoNothing));
|
| }
|
|
|
| -void ContentVideoCaptureDeviceCore::CaptureStarted(bool success) {
|
| +void ScreenCaptureDeviceCore::CaptureStarted(bool success) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| if (!success) {
|
| std::string reason("Failed to start capture machine.");
|
| @@ -299,31 +91,24 @@ void ContentVideoCaptureDeviceCore::CaptureStarted(bool success) {
|
| }
|
| }
|
|
|
| -ContentVideoCaptureDeviceCore::ContentVideoCaptureDeviceCore(
|
| +ScreenCaptureDeviceCore::ScreenCaptureDeviceCore(
|
| scoped_ptr<VideoCaptureMachine> capture_machine)
|
| : state_(kIdle),
|
| capture_machine_(capture_machine.Pass()) {
|
| DCHECK(capture_machine_.get());
|
| }
|
|
|
| -ContentVideoCaptureDeviceCore::~ContentVideoCaptureDeviceCore() {
|
| +ScreenCaptureDeviceCore::~ScreenCaptureDeviceCore() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| DCHECK_NE(state_, kCapturing);
|
| - // If capture_machine is not NULL, then we need to return to the UI thread to
|
| - // safely stop the capture machine.
|
| if (capture_machine_) {
|
| - VideoCaptureMachine* capture_machine_ptr = capture_machine_.get();
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - base::Bind(&VideoCaptureMachine::Stop,
|
| - base::Unretained(capture_machine_ptr),
|
| - base::Bind(&DeleteCaptureMachineOnUIThread,
|
| - base::Passed(&capture_machine_))));
|
| + capture_machine_->Stop(base::Bind(&DeleteCaptureMachine,
|
| + base::Passed(&capture_machine_)));
|
| }
|
| - DVLOG(1) << "ContentVideoCaptureDeviceCore@" << this << " destroying.";
|
| + DVLOG(1) << "ScreenCaptureDeviceCore@" << this << " destroying.";
|
| }
|
|
|
| -void ContentVideoCaptureDeviceCore::TransitionStateTo(State next_state) {
|
| +void ScreenCaptureDeviceCore::TransitionStateTo(State next_state) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| #ifndef NDEBUG
|
| @@ -337,7 +122,7 @@ void ContentVideoCaptureDeviceCore::TransitionStateTo(State next_state) {
|
| state_ = next_state;
|
| }
|
|
|
| -void ContentVideoCaptureDeviceCore::Error(const std::string& reason) {
|
| +void ScreenCaptureDeviceCore::Error(const std::string& reason) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| if (state_ == kIdle)
|
| @@ -350,4 +135,4 @@ void ContentVideoCaptureDeviceCore::Error(const std::string& reason) {
|
| TransitionStateTo(kError);
|
| }
|
|
|
| -} // namespace content
|
| +} // namespace media
|
|
|