1 /* 2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de> 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without restriction, 7 * including without limitation the rights to use, copy, modify, 8 * merge, publish, distribute, sublicense, and/or sell copies of 9 * the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <Bitmap.h> 26 #include <MediaRoster.h> 27 #include <MessageRunner.h> 28 #include "VideoView.h" 29 #include "VideoNode.h" 30 #include "ConvertBitmap.h" 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #define CHECK_ACTIVITY 'ChkA' 37 38 VideoView::VideoView(BRect frame, const char *name, uint32 resizeMask, uint32 flags) 39 : BView(frame, name, resizeMask, flags) 40 , fVideoNode(0) 41 , fVideoActive(false) 42 , fOverlayActive(false) 43 , fActivityCheckMsgRunner(0) 44 , fLastFrame(0) 45 { 46 SetViewColor(B_TRANSPARENT_COLOR); 47 48 status_t err = B_OK; 49 BMediaRoster *mroster = BMediaRoster::Roster(&err); 50 if (!mroster || err) { 51 printf("VideoView::VideoView: media_server is dead\n"); 52 exit(1); 53 } else { 54 fVideoNode = new VideoNode("video in", this); 55 err = mroster->RegisterNode(fVideoNode); 56 } 57 } 58 59 60 VideoView::~VideoView() 61 { 62 delete fActivityCheckMsgRunner; 63 64 if (fVideoNode) { 65 BMediaRoster::Roster()->UnregisterNode(fVideoNode); 66 delete fVideoNode; 67 } 68 } 69 70 71 void 72 VideoView::AttachedToWindow() 73 { 74 BMessage msg(CHECK_ACTIVITY); 75 fActivityCheckMsgRunner = new BMessageRunner(BMessenger(this), &msg, 200000); 76 } 77 78 79 VideoNode * 80 VideoView::Node() 81 { 82 return fVideoNode; 83 } 84 85 86 void 87 VideoView::OverlayLockAcquire() 88 { 89 printf("VideoView::OverlayLockAcquire\n"); 90 } 91 92 93 void 94 VideoView::OverlayLockRelease() 95 { /* [19:54] <Francois> Rudolf forwarded me a mail once about it 96 * [19:55] <Francois> when you get relmease msg you are supposed to UnlockBits() on the overlay bitmaps you use 97 * [19:55] <Francois> it's used when switching workspaces 98 * [19:55] <Francois> as the bits might get relocated 99 */ 100 printf("VideoView::OverlayLockRelease\n"); 101 102 } 103 104 105 void 106 VideoView::OverlayScreenshotPrepare() 107 { 108 printf("OverlayScreenshotPrepare enter\n"); 109 /* 110 fVideoNode->LockBitmap(); 111 if (fOverlayActive) { 112 BBitmap *bmp = fVideoNode->Bitmap(); 113 if (bmp) { 114 // Window()->UpdateIfNeeded(); 115 // Sync(); 116 BBitmap *tmp = new BBitmap(bmp->Bounds(), 0, B_RGB32); 117 // ConvertBitmap(tmp, bmp); 118 ClearViewOverlay(); 119 DrawBitmap(tmp, Bounds()); 120 delete tmp; 121 // Sync(); 122 } 123 } 124 fVideoNode->UnlockBitmap(); 125 */ 126 printf("OverlayScreenshotPrepare leave\n"); 127 } 128 129 130 void 131 VideoView::OverlayScreenshotCleanup() 132 { 133 printf("OverlayScreenshotCleanup enter\n"); 134 /* 135 snooze(50000); // give app server some time to take the screenshot 136 fVideoNode->LockBitmap(); 137 if (fOverlayActive) { 138 BBitmap *bmp = fVideoNode->Bitmap(); 139 if (bmp) { 140 DrawBitmap(bmp, Bounds()); 141 SetViewOverlay(bmp, bmp->Bounds(), Bounds(), &fOverlayKeyColor, 142 B_FOLLOW_ALL, B_OVERLAY_FILTER_HORIZONTAL | B_OVERLAY_FILTER_VERTICAL); 143 Invalidate(); 144 } 145 } 146 fVideoNode->UnlockBitmap(); 147 */ 148 printf("OverlayScreenshotCleanup leave\n"); 149 } 150 151 152 void 153 VideoView::RemoveVideoDisplay() 154 { 155 printf("VideoView::RemoveVideoDisplay\n"); 156 157 if (fOverlayActive) { 158 ClearViewOverlay(); 159 fOverlayActive = false; 160 } 161 fVideoActive = false; 162 Invalidate(); 163 } 164 165 166 void 167 VideoView::RemoveOverlay() 168 { 169 printf("VideoView::RemoveOverlay\n"); 170 if (LockLooperWithTimeout(50000) == B_OK) { 171 ClearViewOverlay(); 172 fOverlayActive = false; 173 UnlockLooper(); 174 } 175 } 176 177 178 void 179 VideoView::CheckActivity() 180 { 181 if (!fVideoActive) 182 return; 183 if (system_time() - fLastFrame < 700000) 184 return; 185 186 printf("VideoView::CheckActivity: lag detected\n"); 187 188 fVideoActive = false; 189 Invalidate(); 190 } 191 192 193 void 194 VideoView::Draw(BRect updateRect) 195 { 196 if (!fVideoActive) { 197 DrawTestImage(); 198 return; 199 } 200 if (fOverlayActive) { 201 SetHighColor(fOverlayKeyColor); 202 FillRect(updateRect); 203 } else { 204 fVideoNode->LockBitmap(); 205 BBitmap *bmp = fVideoNode->Bitmap(); 206 if (bmp) 207 DrawBitmap(bmp, Bounds()); 208 fVideoNode->UnlockBitmap(); 209 } 210 } 211 212 213 void 214 VideoView::DrawFrame() 215 { 216 // printf("VideoView::DrawFrame\n"); 217 if (!fVideoActive) { 218 fVideoActive = true; 219 if (LockLooperWithTimeout(50000) != B_OK) 220 return; 221 Invalidate(); 222 UnlockLooper(); 223 } 224 fLastFrame = system_time(); 225 226 bool want_overlay = fVideoNode->IsOverlayActive(); 227 228 if (!want_overlay && fOverlayActive) { 229 if (LockLooperWithTimeout(50000) == B_OK) { 230 ClearViewOverlay(); 231 UnlockLooper(); 232 fOverlayActive = false; 233 } else { 234 printf("can't ClearViewOverlay, as LockLooperWithTimeout failed\n"); 235 } 236 } 237 if (want_overlay && !fOverlayActive) { 238 fVideoNode->LockBitmap(); 239 BBitmap *bmp = fVideoNode->Bitmap(); 240 if (bmp && LockLooperWithTimeout(50000) == B_OK) { 241 SetViewOverlay(bmp, bmp->Bounds(), Bounds(), &fOverlayKeyColor, 242 B_FOLLOW_ALL, B_OVERLAY_FILTER_HORIZONTAL | B_OVERLAY_FILTER_VERTICAL); 243 fOverlayActive = true; 244 245 Invalidate(); 246 UnlockLooper(); 247 } 248 fVideoNode->UnlockBitmap(); 249 } 250 if (!fOverlayActive) { 251 if (LockLooperWithTimeout(50000) != B_OK) 252 return; 253 Invalidate(); 254 UnlockLooper(); 255 } 256 } 257 258 259 void 260 VideoView::DrawTestImage() 261 { 262 static const rgb_color cols[8] = { 263 {255,255,255}, {255,255,0}, {0,255,255}, {0,255,0}, 264 {255,0,255}, {255,0,0}, {0,0,255}, {0,0,0} 265 // {255,255,255}, {255,255,0}, {0,255,255}, 266 // {255,0,255}, {255,0,0}, {0,255,0}, {0,0,255}, {0,0,0} 267 }; 268 float bar_width; 269 float left; 270 float right; 271 272 BRect bnd = Bounds(); 273 int seperator_y1 = int(0.60 * (bnd.Height() + 1)); 274 int seperator_y2 = int(0.80 * (bnd.Height() + 1)); 275 int steps; 276 277 bar_width = bnd.Width() / 8; 278 if (bar_width < 1) 279 bar_width = 1; 280 281 left = 0; 282 for (int i = 0; i < 8; i++) { 283 SetHighColor(cols[i]); 284 right = (i != 7) ? left + bar_width - 1 : bnd.right; 285 FillRect(BRect(left, 0, right, seperator_y1)); 286 left = right + 1; 287 } 288 289 steps = 32; 290 291 bar_width = bnd.Width() / steps; 292 // if (bar_width < 1) 293 // bar_width = 1; 294 295 left = 0; 296 for (int i = 0; i < steps; i++) { 297 uint8 c = i * 255 / (steps - 1); 298 SetHighColor(c, c, c); 299 right = (i != steps - 1) ? left + bar_width - 1 : bnd.right; 300 FillRect(BRect(left, seperator_y1 + 1, right, seperator_y2)); 301 left = right + 1; 302 } 303 304 steps = 256; 305 306 bar_width = bnd.Width() / steps; 307 if (bar_width < 1) 308 bar_width = 1; 309 310 left = 0; 311 for (int i = 0; i < steps; i++) { 312 uint8 c = 255 - (i * 255 / (steps - 1)); 313 SetHighColor(c, c, c); 314 right = (i != steps - 1) ? left + bar_width - 1 : bnd.right; 315 FillRect(BRect(left, seperator_y2 + 1, right, bnd.bottom)); 316 left = right + 1; 317 } 318 } 319 320 321 void 322 VideoView::MessageReceived(BMessage *msg) 323 { 324 switch (msg->what) { 325 case CHECK_ACTIVITY: 326 CheckActivity(); 327 break; 328 default: 329 BView::MessageReceived(msg); 330 } 331 } 332 333 334 bool 335 VideoView::IsOverlaySupported() 336 { 337 struct colorcombo { 338 color_space colspace; 339 const char *name; 340 } colspace[] = { 341 { B_RGB32, "B_RGB32"}, 342 { B_RGBA32, "B_RGBA32"}, 343 { B_RGB24, "B_RGB24"}, 344 { B_RGB16, "B_RGB16"}, 345 { B_RGB15, "B_RGB15"}, 346 { B_RGBA15, "B_RGBA15"}, 347 { B_RGB32_BIG, "B_RGB32_BIG"}, 348 { B_RGBA32_BIG, "B_RGBA32_BIG "}, 349 { B_RGB24_BIG, "B_RGB24_BIG "}, 350 { B_RGB16_BIG, "B_RGB16_BIG "}, 351 { B_RGB15_BIG, "B_RGB15_BIG "}, 352 { B_RGBA15_BIG, "B_RGBA15_BIG "}, 353 { B_YCbCr422, "B_YCbCr422"}, 354 { B_YCbCr411, "B_YCbCr411"}, 355 { B_YCbCr444, "B_YCbCr444"}, 356 { B_YCbCr420, "B_YCbCr420"}, 357 { B_YUV422, "B_YUV422"}, 358 { B_YUV411, "B_YUV411"}, 359 { B_YUV444, "B_YUV444"}, 360 { B_YUV420, "B_YUV420"}, 361 { B_NO_COLOR_SPACE, NULL} 362 }; 363 364 bool supported = false; 365 for (int i = 0; colspace[i].name; i++) { 366 BBitmap *test = new BBitmap(BRect(0,0,320,240), B_BITMAP_WILL_OVERLAY | B_BITMAP_RESERVE_OVERLAY_CHANNEL, colspace[i].colspace); 367 if (test->InitCheck() == B_OK) { 368 printf("Display supports %s (0x%08x) overlay\n", colspace[i].name, colspace[i].colspace); 369 overlay_restrictions restrict; 370 if (B_OK == test->GetOverlayRestrictions(&restrict)) { 371 printf("Overlay restrictions: source horizontal_alignment %d\n", restrict.source.horizontal_alignment); 372 printf("Overlay restrictions: source vertical_alignment %d\n", restrict.source.vertical_alignment); 373 printf("Overlay restrictions: source width_alignment %d\n", restrict.source.width_alignment); 374 printf("Overlay restrictions: source height_alignment %d\n", restrict.source.height_alignment); 375 printf("Overlay restrictions: source min_width %d\n", restrict.source.min_width); 376 printf("Overlay restrictions: source max_width %d\n", restrict.source.max_width); 377 printf("Overlay restrictions: source min_height %d\n", restrict.source.min_height); 378 printf("Overlay restrictions: source max_height %d\n", restrict.source.max_height); 379 printf("Overlay restrictions: destination horizontal_alignment %d\n", restrict.destination.horizontal_alignment); 380 printf("Overlay restrictions: destination vertical_alignment %d\n", restrict.destination.vertical_alignment); 381 printf("Overlay restrictions: destination width_alignment %d\n", restrict.destination.width_alignment); 382 printf("Overlay restrictions: destination height_alignment %d\n", restrict.destination.height_alignment); 383 printf("Overlay restrictions: destination min_width %d\n", restrict.destination.min_width); 384 printf("Overlay restrictions: destination max_width %d\n", restrict.destination.max_width); 385 printf("Overlay restrictions: destination min_height %d\n", restrict.destination.min_height); 386 printf("Overlay restrictions: destination max_height %d\n", restrict.destination.max_height); 387 printf("Overlay restrictions: min_width_scale %.3f\n", restrict.min_width_scale); 388 printf("Overlay restrictions: max_width_scale %.3f\n", restrict.max_width_scale); 389 printf("Overlay restrictions: min_height_scale %.3f\n", restrict.min_height_scale); 390 printf("Overlay restrictions: max_height_scale %.3f\n", restrict.max_height_scale); 391 } 392 supported = true; 393 } 394 delete test; 395 // if (supported) 396 // break; 397 } 398 return supported; 399 } 400 401