Index: content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc |
diff --git a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc |
index 96b6fe32af607570b192f469204a6f3298979e64..9c7a7efc5de81ec71b2b0630060f672fa54ba86f 100644 |
--- a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc |
+++ b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc |
@@ -6,12 +6,18 @@ |
#include "base/bind.h" |
#include "base/memory/aligned_memory.h" |
+#include "base/synchronization/waitable_event.h" |
#include "base/trace_event/trace_event.h" |
-#include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h" |
+#include "content/common/gpu/client/context_provider_command_buffer.h" |
+#include "content/renderer/render_thread_impl.h" |
+#include "media/base/bind_to_current_loop.h" |
#include "media/base/timestamp_constants.h" |
#include "media/base/video_util.h" |
+#include "skia/ext/platform_canvas.h" |
+#include "third_party/libyuv/include/libyuv/convert.h" |
#include "third_party/libyuv/include/libyuv/convert_from.h" |
#include "third_party/libyuv/include/libyuv/scale.h" |
+#include "third_party/skia/include/core/SkSurface.h" |
#include "third_party/webrtc/common_video/include/video_frame_buffer.h" |
#include "third_party/webrtc/common_video/rotation.h" |
#include "third_party/webrtc/media/engine/webrtcvideoframe.h" |
@@ -27,71 +33,21 @@ void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) { |
} // anonymous namespace |
WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast) |
- : is_screencast_(is_screencast), |
- running_(false) { |
+ : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
+ provider_(RenderThreadImpl::current()->SharedMainThreadContextProvider()), |
+ is_screencast_(is_screencast), |
+ running_(false), |
+ weak_factory_(this) { |
thread_checker_.DetachFromThread(); |
+ copy_texture_callback_ = |
+ base::Bind(&WebRtcVideoCapturerAdapter::CopyTextureFrame, |
+ weak_factory_.GetWeakPtr()); |
} |
WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() { |
DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor"; |
mcasas
2016/10/26 16:06:02
unrelated nit: I'm trying to correct these stateme
emircan
2016/10/27 00:37:56
Done.
|
} |
-cricket::CaptureState WebRtcVideoCapturerAdapter::Start( |
- const cricket::VideoFormat& capture_format) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- DCHECK(!running_); |
- DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width |
- << " h = " << capture_format.height; |
- |
- running_ = true; |
- return cricket::CS_RUNNING; |
-} |
- |
-void WebRtcVideoCapturerAdapter::Stop() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- DVLOG(3) << " WebRtcVideoCapturerAdapter::Stop "; |
- DCHECK(running_); |
- running_ = false; |
- SetCaptureFormat(NULL); |
- SignalStateChange(this, cricket::CS_STOPPED); |
-} |
- |
-bool WebRtcVideoCapturerAdapter::IsRunning() { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- return running_; |
-} |
- |
-bool WebRtcVideoCapturerAdapter::GetPreferredFourccs( |
- std::vector<uint32_t>* fourccs) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- DCHECK(!fourccs || fourccs->empty()); |
- if (fourccs) |
- fourccs->push_back(cricket::FOURCC_I420); |
- return fourccs != NULL; |
-} |
- |
-bool WebRtcVideoCapturerAdapter::IsScreencast() const { |
- return is_screencast_; |
-} |
- |
-bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat( |
- const cricket::VideoFormat& desired, |
- cricket::VideoFormat* best_format) { |
- DCHECK(thread_checker_.CalledOnValidThread()); |
- DVLOG(3) << " GetBestCaptureFormat:: " |
- << " w = " << desired.width |
- << " h = " << desired.height; |
- |
- // Capability enumeration is done in MediaStreamVideoSource. The adapter can |
- // just use what is provided. |
- // Use the desired format as the best format. |
- best_format->width = desired.width; |
- best_format->height = desired.height; |
- best_format->fourcc = cricket::FOURCC_I420; |
- best_format->interval = desired.interval; |
- return true; |
-} |
- |
void WebRtcVideoCapturerAdapter::OnFrameCaptured( |
const scoped_refptr<media::VideoFrame>& input_frame) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
@@ -99,9 +55,13 @@ void WebRtcVideoCapturerAdapter::OnFrameCaptured( |
if (!(input_frame->IsMappable() && |
(input_frame->format() == media::PIXEL_FORMAT_I420 || |
input_frame->format() == media::PIXEL_FORMAT_YV12 || |
- input_frame->format() == media::PIXEL_FORMAT_YV12A))) { |
+ input_frame->format() == media::PIXEL_FORMAT_YV12A)) && |
+ !input_frame->HasTextures()) { |
// Since connecting sources and sinks do not check the format, we need to |
// just ignore formats that we can not handle. |
+ LOG(ERROR) << "We cannot send frame with storage type: " |
+ << input_frame->storage_type() |
+ << " format: " << input_frame->format(); |
mcasas
2016/10/26 16:06:02
These are going to print numbers, right?
Consider
emircan
2016/10/27 00:37:56
Done.
|
NOTREACHED(); |
return; |
} |
@@ -133,11 +93,10 @@ void WebRtcVideoCapturerAdapter::OnFrameCaptured( |
// Return |frame| directly if it is texture backed, because there is no |
// cropping support for texture yet. See http://crbug/503653. |
- // Return |frame| directly if it is GpuMemoryBuffer backed, as we want to |
- // keep the frame on native buffers. |
if (frame->HasTextures()) { |
OnFrame(cricket::WebRtcVideoFrame( |
- new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(frame), |
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>( |
+ frame, copy_texture_callback_), |
webrtc::kVideoRotation_0, translated_camera_time_us), |
orig_width, orig_height); |
return; |
@@ -164,7 +123,8 @@ void WebRtcVideoCapturerAdapter::OnFrameCaptured( |
// If no scaling is needed, return a wrapped version of |frame| directly. |
if (video_frame->natural_size() == video_frame->visible_rect().size()) { |
OnFrame(cricket::WebRtcVideoFrame( |
- new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(video_frame), |
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>( |
+ video_frame, copy_texture_callback_), |
webrtc::kVideoRotation_0, translated_camera_time_us), |
orig_width, orig_height); |
return; |
@@ -192,9 +152,130 @@ void WebRtcVideoCapturerAdapter::OnFrameCaptured( |
adapted_width, adapted_height, libyuv::kFilterBilinear); |
OnFrame(cricket::WebRtcVideoFrame( |
- new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(scaled_frame), |
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>( |
+ scaled_frame, copy_texture_callback_), |
webrtc::kVideoRotation_0, translated_camera_time_us), |
orig_width, orig_height); |
} |
+cricket::CaptureState WebRtcVideoCapturerAdapter::Start( |
+ const cricket::VideoFormat& capture_format) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DCHECK(!running_); |
+ DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width |
+ << " h = " << capture_format.height; |
+ |
+ running_ = true; |
+ return cricket::CS_RUNNING; |
+} |
+ |
+void WebRtcVideoCapturerAdapter::Stop() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DVLOG(3) << " WebRtcVideoCapturerAdapter::Stop "; |
+ DCHECK(running_); |
+ running_ = false; |
+ SetCaptureFormat(NULL); |
+ SignalStateChange(this, cricket::CS_STOPPED); |
+} |
+ |
+bool WebRtcVideoCapturerAdapter::IsRunning() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ return running_; |
+} |
+ |
+bool WebRtcVideoCapturerAdapter::GetPreferredFourccs( |
+ std::vector<uint32_t>* fourccs) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DCHECK(!fourccs || fourccs->empty()); |
mcasas
2016/10/26 16:06:02
nit: not your code, but here we should not DCHECK(
emircan
2016/10/27 00:37:56
Done.
|
+ if (fourccs) |
+ fourccs->push_back(cricket::FOURCC_I420); |
+ return fourccs != NULL; |
+} |
+ |
+bool WebRtcVideoCapturerAdapter::IsScreencast() const { |
+ return is_screencast_; |
+} |
+ |
+bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat( |
+ const cricket::VideoFormat& desired, |
+ cricket::VideoFormat* best_format) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ DVLOG(3) << " GetBestCaptureFormat:: " |
+ << " w = " << desired.width |
+ << " h = " << desired.height; |
mcasas
2016/10/26 16:06:02
nit:
DVLOG(3) << __func__ << " desired: " << desir
emircan
2016/10/27 00:37:56
Done.
|
+ |
+ // Capability enumeration is done in MediaStreamVideoSource. The adapter can |
+ // just use what is provided. |
+ // Use the desired format as the best format. |
+ best_format->width = desired.width; |
+ best_format->height = desired.height; |
+ best_format->fourcc = cricket::FOURCC_I420; |
+ best_format->interval = desired.interval; |
+ return true; |
+} |
+ |
+void WebRtcVideoCapturerAdapter::CopyTextureFrame( |
+ const scoped_refptr<media::VideoFrame>& frame, |
+ scoped_refptr<media::VideoFrame>* new_frame) { |
+ base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::MANUAL, |
+ base::WaitableEvent::InitialState::NOT_SIGNALED); |
+ main_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&WebRtcVideoCapturerAdapter::CopyTextureFrameOnMainThread, |
+ base::Unretained(this), frame, new_frame, &waiter)); |
mcasas
2016/10/26 16:06:02
weak_factory_.GetWeakPtr() ?
emircan
2016/10/27 00:37:56
I can add a WeakPtr here to be used on main thread
|
+ waiter.Wait(); |
+} |
+ |
+void WebRtcVideoCapturerAdapter::CopyTextureFrameOnMainThread( |
+ const scoped_refptr<media::VideoFrame>& frame, |
+ scoped_refptr<media::VideoFrame>* new_frame, |
+ base::WaitableEvent* waiter) { |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
+ DCHECK(frame->format() == media::PIXEL_FORMAT_ARGB || |
+ frame->format() == media::PIXEL_FORMAT_XRGB || |
+ frame->format() == media::PIXEL_FORMAT_I420 || |
+ frame->format() == media::PIXEL_FORMAT_UYVY || |
+ frame->format() == media::PIXEL_FORMAT_NV12); |
+ *new_frame = media::VideoFrame::CreateFrame( |
+ media::PIXEL_FORMAT_I420, frame->coded_size(), frame->visible_rect(), |
+ frame->natural_size(), frame->timestamp()); |
+ |
+ sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( |
+ frame->visible_rect().width(), frame->visible_rect().height()); |
+ |
+ if (surface && provider_) { |
+ DCHECK(provider_->ContextGL()); |
+ canvas_video_renderer_.Copy( |
+ frame.get(), surface->getCanvas(), |
+ media::Context3D(provider_->ContextGL(), provider_->GrContext())); |
+ } else { |
+ // Return a black frame (yuv = {0, 0x80, 0x80}). |
+ *new_frame = media::VideoFrame::CreateColorFrame( |
+ frame->visible_rect().size(), 0u, 0x80, 0x80, frame->timestamp()); |
mcasas
2016/10/26 16:06:02
Shouldn't you return here (and in l.259)? Ah but t
emircan
2016/10/27 00:37:56
Thanks. I added it to this file and restructured t
|
+ } |
+ |
+ SkPixmap pixmap; |
+ const bool result = surface->getCanvas()->peekPixels(&pixmap); |
+ DCHECK(result) << "Error trying to access SkSurface's pixels"; |
+ |
+ const uint32 source_pixel_format = |
+ (kN32_SkColorType == kRGBA_8888_SkColorType) ? cricket::FOURCC_ABGR |
+ : cricket::FOURCC_ARGB; |
+ libyuv::ConvertToI420(static_cast<const uint8*>(pixmap.addr(0, 0)), |
+ pixmap.getSafeSize64(), |
+ (*new_frame)->visible_data(media::VideoFrame::kYPlane), |
+ (*new_frame)->stride(media::VideoFrame::kYPlane), |
+ (*new_frame)->visible_data(media::VideoFrame::kUPlane), |
+ (*new_frame)->stride(media::VideoFrame::kUPlane), |
+ (*new_frame)->visible_data(media::VideoFrame::kVPlane), |
+ (*new_frame)->stride(media::VideoFrame::kVPlane), |
+ 0 /* crop_x */, 0 /* crop_y */, pixmap.width(), |
+ pixmap.height(), (*new_frame)->visible_rect().width(), |
+ (*new_frame)->visible_rect().height(), libyuv::kRotate0, |
+ source_pixel_format); |
+ |
+ if (waiter) |
+ waiter->Signal(); |
mcasas
2016/10/26 16:06:02
Is there a chance that |waiter| might be nullptr?
emircan
2016/10/27 00:37:56
Done.
|
+} |
+ |
} // namespace content |