OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 // Implementation of CarbonVideoRenderer |
| 12 |
| 13 #include "webrtc/media/devices/carbonvideorenderer.h" |
| 14 |
| 15 #include "webrtc/base/logging.h" |
| 16 #include "webrtc/media/base/videocommon.h" |
| 17 #include "webrtc/media/base/videoframe.h" |
| 18 |
| 19 namespace cricket { |
| 20 |
| 21 CarbonVideoRenderer::CarbonVideoRenderer(int x, int y) |
| 22 : image_width_(0), |
| 23 image_height_(0), |
| 24 x_(x), |
| 25 y_(y), |
| 26 window_ref_(NULL) { |
| 27 } |
| 28 |
| 29 CarbonVideoRenderer::~CarbonVideoRenderer() { |
| 30 if (window_ref_) { |
| 31 DisposeWindow(window_ref_); |
| 32 } |
| 33 } |
| 34 |
| 35 // Called from the main event loop. All renderering needs to happen on |
| 36 // the main thread. |
| 37 OSStatus CarbonVideoRenderer::DrawEventHandler(EventHandlerCallRef handler, |
| 38 EventRef event, |
| 39 void* data) { |
| 40 OSStatus status = noErr; |
| 41 CarbonVideoRenderer* renderer = static_cast<CarbonVideoRenderer*>(data); |
| 42 if (renderer != NULL) { |
| 43 if (!renderer->DrawFrame()) { |
| 44 LOG(LS_ERROR) << "Failed to draw frame."; |
| 45 } |
| 46 } |
| 47 return status; |
| 48 } |
| 49 |
| 50 bool CarbonVideoRenderer::DrawFrame() { |
| 51 // Grab the image lock to make sure it is not changed why we'll draw it. |
| 52 rtc::CritScope cs(&image_crit_); |
| 53 |
| 54 if (image_.get() == NULL) { |
| 55 // Nothing to draw, just return. |
| 56 return true; |
| 57 } |
| 58 int width = image_width_; |
| 59 int height = image_height_; |
| 60 CGDataProviderRef provider = |
| 61 CGDataProviderCreateWithData(NULL, image_.get(), width * height * 4, |
| 62 NULL); |
| 63 CGColorSpaceRef color_space_ref = CGColorSpaceCreateDeviceRGB(); |
| 64 CGBitmapInfo bitmap_info = kCGBitmapByteOrderDefault; |
| 65 CGColorRenderingIntent rendering_intent = kCGRenderingIntentDefault; |
| 66 CGImageRef image_ref = CGImageCreate(width, height, 8, 32, width * 4, |
| 67 color_space_ref, bitmap_info, provider, |
| 68 NULL, false, rendering_intent); |
| 69 CGDataProviderRelease(provider); |
| 70 |
| 71 if (image_ref == NULL) { |
| 72 return false; |
| 73 } |
| 74 CGContextRef context; |
| 75 SetPortWindowPort(window_ref_); |
| 76 if (QDBeginCGContext(GetWindowPort(window_ref_), &context) != noErr) { |
| 77 CGImageRelease(image_ref); |
| 78 return false; |
| 79 } |
| 80 Rect window_bounds; |
| 81 GetWindowPortBounds(window_ref_, &window_bounds); |
| 82 |
| 83 // Anchor the image to the top left corner. |
| 84 int x = 0; |
| 85 int y = window_bounds.bottom - CGImageGetHeight(image_ref); |
| 86 CGRect dst_rect = CGRectMake(x, y, CGImageGetWidth(image_ref), |
| 87 CGImageGetHeight(image_ref)); |
| 88 CGContextDrawImage(context, dst_rect, image_ref); |
| 89 CGContextFlush(context); |
| 90 QDEndCGContext(GetWindowPort(window_ref_), &context); |
| 91 CGImageRelease(image_ref); |
| 92 return true; |
| 93 } |
| 94 |
| 95 bool CarbonVideoRenderer::SetSize(int width, int height) { |
| 96 if (width != image_width_ || height != image_height_) { |
| 97 // Grab the image lock while changing its size. |
| 98 rtc::CritScope cs(&image_crit_); |
| 99 image_width_ = width; |
| 100 image_height_ = height; |
| 101 image_.reset(new uint8_t[width * height * 4]); |
| 102 memset(image_.get(), 255, width * height * 4); |
| 103 } |
| 104 return true; |
| 105 } |
| 106 |
| 107 void CarbonVideoRenderer::OnFrame(const VideoFrame& video_frame) { |
| 108 { |
| 109 const cricket::WebRtcVideoFrame frame( |
| 110 webrtc::I420Buffer::Rotate(video_frame.video_frame_buffer(), |
| 111 video_frame.rotation()), |
| 112 webrtc::kVideoRotation_0, video_frame.timestamp_us()); |
| 113 |
| 114 if (!SetSize(frame.width(), frame.height())) { |
| 115 return false; |
| 116 } |
| 117 |
| 118 // Grab the image lock so we are not trashing up the image being drawn. |
| 119 rtc::CritScope cs(&image_crit_); |
| 120 frame.ConvertToRgbBuffer(cricket::FOURCC_ABGR, |
| 121 image_.get(), |
| 122 static_cast<size_t>(frame.width()) * |
| 123 frame.height() * 4, |
| 124 frame.width() * 4); |
| 125 } |
| 126 |
| 127 // Trigger a repaint event for the whole window. |
| 128 Rect bounds; |
| 129 InvalWindowRect(window_ref_, GetWindowPortBounds(window_ref_, &bounds)); |
| 130 return true; |
| 131 } |
| 132 |
| 133 bool CarbonVideoRenderer::Initialize() { |
| 134 OSStatus err; |
| 135 WindowAttributes attributes = |
| 136 kWindowStandardDocumentAttributes | |
| 137 kWindowLiveResizeAttribute | |
| 138 kWindowFrameworkScaledAttribute | |
| 139 kWindowStandardHandlerAttribute; |
| 140 |
| 141 struct Rect bounds; |
| 142 bounds.top = y_; |
| 143 bounds.bottom = 480; |
| 144 bounds.left = x_; |
| 145 bounds.right = 640; |
| 146 err = CreateNewWindow(kDocumentWindowClass, attributes, |
| 147 &bounds, &window_ref_); |
| 148 if (!window_ref_ || err != noErr) { |
| 149 LOG(LS_ERROR) << "CreateNewWindow failed, error code: " << err; |
| 150 return false; |
| 151 } |
| 152 static const EventTypeSpec event_spec = { |
| 153 kEventClassWindow, |
| 154 kEventWindowDrawContent |
| 155 }; |
| 156 |
| 157 err = InstallWindowEventHandler( |
| 158 window_ref_, |
| 159 NewEventHandlerUPP(CarbonVideoRenderer::DrawEventHandler), |
| 160 GetEventTypeCount(event_spec), |
| 161 &event_spec, |
| 162 this, |
| 163 NULL); |
| 164 if (err != noErr) { |
| 165 LOG(LS_ERROR) << "Failed to install event handler, error code: " << err; |
| 166 return false; |
| 167 } |
| 168 SelectWindow(window_ref_); |
| 169 ShowWindow(window_ref_); |
| 170 return true; |
| 171 } |
| 172 |
| 173 } // namespace cricket |
OLD | NEW |