Index: webrtc/media/devices/carbonvideorenderer.cc |
diff --git a/webrtc/media/devices/carbonvideorenderer.cc b/webrtc/media/devices/carbonvideorenderer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..766904231c88f1552cb35bb4b4ccb2924fea2def |
--- /dev/null |
+++ b/webrtc/media/devices/carbonvideorenderer.cc |
@@ -0,0 +1,173 @@ |
+/* |
+ * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+// Implementation of CarbonVideoRenderer |
+ |
+#include "webrtc/media/devices/carbonvideorenderer.h" |
+ |
+#include "webrtc/base/logging.h" |
+#include "webrtc/media/base/videocommon.h" |
+#include "webrtc/media/base/videoframe.h" |
+ |
+namespace cricket { |
+ |
+CarbonVideoRenderer::CarbonVideoRenderer(int x, int y) |
+ : image_width_(0), |
+ image_height_(0), |
+ x_(x), |
+ y_(y), |
+ window_ref_(NULL) { |
+} |
+ |
+CarbonVideoRenderer::~CarbonVideoRenderer() { |
+ if (window_ref_) { |
+ DisposeWindow(window_ref_); |
+ } |
+} |
+ |
+// Called from the main event loop. All renderering needs to happen on |
+// the main thread. |
+OSStatus CarbonVideoRenderer::DrawEventHandler(EventHandlerCallRef handler, |
+ EventRef event, |
+ void* data) { |
+ OSStatus status = noErr; |
+ CarbonVideoRenderer* renderer = static_cast<CarbonVideoRenderer*>(data); |
+ if (renderer != NULL) { |
+ if (!renderer->DrawFrame()) { |
+ LOG(LS_ERROR) << "Failed to draw frame."; |
+ } |
+ } |
+ return status; |
+} |
+ |
+bool CarbonVideoRenderer::DrawFrame() { |
+ // Grab the image lock to make sure it is not changed why we'll draw it. |
+ rtc::CritScope cs(&image_crit_); |
+ |
+ if (image_.get() == NULL) { |
+ // Nothing to draw, just return. |
+ return true; |
+ } |
+ int width = image_width_; |
+ int height = image_height_; |
+ CGDataProviderRef provider = |
+ CGDataProviderCreateWithData(NULL, image_.get(), width * height * 4, |
+ NULL); |
+ CGColorSpaceRef color_space_ref = CGColorSpaceCreateDeviceRGB(); |
+ CGBitmapInfo bitmap_info = kCGBitmapByteOrderDefault; |
+ CGColorRenderingIntent rendering_intent = kCGRenderingIntentDefault; |
+ CGImageRef image_ref = CGImageCreate(width, height, 8, 32, width * 4, |
+ color_space_ref, bitmap_info, provider, |
+ NULL, false, rendering_intent); |
+ CGDataProviderRelease(provider); |
+ |
+ if (image_ref == NULL) { |
+ return false; |
+ } |
+ CGContextRef context; |
+ SetPortWindowPort(window_ref_); |
+ if (QDBeginCGContext(GetWindowPort(window_ref_), &context) != noErr) { |
+ CGImageRelease(image_ref); |
+ return false; |
+ } |
+ Rect window_bounds; |
+ GetWindowPortBounds(window_ref_, &window_bounds); |
+ |
+ // Anchor the image to the top left corner. |
+ int x = 0; |
+ int y = window_bounds.bottom - CGImageGetHeight(image_ref); |
+ CGRect dst_rect = CGRectMake(x, y, CGImageGetWidth(image_ref), |
+ CGImageGetHeight(image_ref)); |
+ CGContextDrawImage(context, dst_rect, image_ref); |
+ CGContextFlush(context); |
+ QDEndCGContext(GetWindowPort(window_ref_), &context); |
+ CGImageRelease(image_ref); |
+ return true; |
+} |
+ |
+bool CarbonVideoRenderer::SetSize(int width, int height) { |
+ if (width != image_width_ || height != image_height_) { |
+ // Grab the image lock while changing its size. |
+ rtc::CritScope cs(&image_crit_); |
+ image_width_ = width; |
+ image_height_ = height; |
+ image_.reset(new uint8_t[width * height * 4]); |
+ memset(image_.get(), 255, width * height * 4); |
+ } |
+ return true; |
+} |
+ |
+void CarbonVideoRenderer::OnFrame(const VideoFrame& video_frame) { |
+ { |
+ const cricket::WebRtcVideoFrame frame( |
+ webrtc::I420Buffer::Rotate(video_frame.video_frame_buffer(), |
+ video_frame.rotation()), |
+ webrtc::kVideoRotation_0, video_frame.timestamp_us()); |
+ |
+ if (!SetSize(frame.width(), frame.height())) { |
+ return false; |
+ } |
+ |
+ // Grab the image lock so we are not trashing up the image being drawn. |
+ rtc::CritScope cs(&image_crit_); |
+ frame.ConvertToRgbBuffer(cricket::FOURCC_ABGR, |
+ image_.get(), |
+ static_cast<size_t>(frame.width()) * |
+ frame.height() * 4, |
+ frame.width() * 4); |
+ } |
+ |
+ // Trigger a repaint event for the whole window. |
+ Rect bounds; |
+ InvalWindowRect(window_ref_, GetWindowPortBounds(window_ref_, &bounds)); |
+ return true; |
+} |
+ |
+bool CarbonVideoRenderer::Initialize() { |
+ OSStatus err; |
+ WindowAttributes attributes = |
+ kWindowStandardDocumentAttributes | |
+ kWindowLiveResizeAttribute | |
+ kWindowFrameworkScaledAttribute | |
+ kWindowStandardHandlerAttribute; |
+ |
+ struct Rect bounds; |
+ bounds.top = y_; |
+ bounds.bottom = 480; |
+ bounds.left = x_; |
+ bounds.right = 640; |
+ err = CreateNewWindow(kDocumentWindowClass, attributes, |
+ &bounds, &window_ref_); |
+ if (!window_ref_ || err != noErr) { |
+ LOG(LS_ERROR) << "CreateNewWindow failed, error code: " << err; |
+ return false; |
+ } |
+ static const EventTypeSpec event_spec = { |
+ kEventClassWindow, |
+ kEventWindowDrawContent |
+ }; |
+ |
+ err = InstallWindowEventHandler( |
+ window_ref_, |
+ NewEventHandlerUPP(CarbonVideoRenderer::DrawEventHandler), |
+ GetEventTypeCount(event_spec), |
+ &event_spec, |
+ this, |
+ NULL); |
+ if (err != noErr) { |
+ LOG(LS_ERROR) << "Failed to install event handler, error code: " << err; |
+ return false; |
+ } |
+ SelectWindow(window_ref_); |
+ ShowWindow(window_ref_); |
+ return true; |
+} |
+ |
+} // namespace cricket |