| 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
|
|
|