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, 39 uint32 flags) 40 : BView(frame, name, resizeMask, flags) 41 , fVideoNode(0) 42 , fVideoActive(false) 43 , fOverlayActive(false) 44 , fActivityCheckMsgRunner(0) 45 , fLastFrame(0) 46 { 47 SetViewColor(B_TRANSPARENT_COLOR); 48 49 status_t err = B_OK; 50 BMediaRoster *mroster = BMediaRoster::Roster(&err); 51 if (!mroster || err) { 52 printf("VideoView::VideoView: media_server is dead\n"); 53 exit(1); 54 } else { 55 fVideoNode = new VideoNode("video in", this); 56 err = mroster->RegisterNode(fVideoNode); 57 } 58 } 59 60 61 VideoView::~VideoView() 62 { 63 delete fActivityCheckMsgRunner; 64 65 if (fVideoNode) { 66 BMediaRoster::Roster()->UnregisterNode(fVideoNode); 67 delete fVideoNode; 68 } 69 } 70 71 72 void 73 VideoView::AttachedToWindow() 74 { 75 BMessage msg(CHECK_ACTIVITY); 76 fActivityCheckMsgRunner = new BMessageRunner(BMessenger(this), &msg, 77 200000); 78 } 79 80 81 VideoNode * 82 VideoView::Node() 83 { 84 return fVideoNode; 85 } 86 87 88 void 89 VideoView::OverlayLockAcquire() 90 { 91 printf("VideoView::OverlayLockAcquire\n"); 92 } 93 94 95 void 96 VideoView::OverlayLockRelease() 97 { /* [19:54] <Francois> Rudolf forwarded me a mail once about it 98 * [19:55] <Francois> when you get relmease msg you are supposed to 99 UnlockBits() on the overlay bitmaps you use 100 * [19:55] <Francois> it's used when switching workspaces 101 * [19:55] <Francois> as the bits might get relocated 102 */ 103 printf("VideoView::OverlayLockRelease\n"); 104 105 } 106 107 108 void 109 VideoView::OverlayScreenshotPrepare() 110 { 111 printf("OverlayScreenshotPrepare enter\n"); 112 /* 113 fVideoNode->LockBitmap(); 114 if (fOverlayActive) { 115 BBitmap *bmp = fVideoNode->Bitmap(); 116 if (bmp) { 117 // Window()->UpdateIfNeeded(); 118 // Sync(); 119 BBitmap *tmp = new BBitmap(bmp->Bounds(), 0, B_RGB32); 120 // ConvertBitmap(tmp, bmp); 121 ClearViewOverlay(); 122 DrawBitmap(tmp, Bounds()); 123 delete tmp; 124 // Sync(); 125 } 126 } 127 fVideoNode->UnlockBitmap(); 128 */ 129 printf("OverlayScreenshotPrepare leave\n"); 130 } 131 132 133 void 134 VideoView::OverlayScreenshotCleanup() 135 { 136 printf("OverlayScreenshotCleanup enter\n"); 137 /* 138 snooze(50000); // give app server some time to take the screenshot 139 fVideoNode->LockBitmap(); 140 if (fOverlayActive) { 141 BBitmap *bmp = fVideoNode->Bitmap(); 142 if (bmp) { 143 DrawBitmap(bmp, Bounds()); 144 SetViewOverlay(bmp, bmp->Bounds(), Bounds(), &fOverlayKeyColor, 145 B_FOLLOW_ALL, B_OVERLAY_FILTER_HORIZONTAL 146 | B_OVERLAY_FILTER_VERTICAL); 147 Invalidate(); 148 } 149 } 150 fVideoNode->UnlockBitmap(); 151 */ 152 printf("OverlayScreenshotCleanup leave\n"); 153 } 154 155 156 void 157 VideoView::RemoveVideoDisplay() 158 { 159 printf("VideoView::RemoveVideoDisplay\n"); 160 161 if (fOverlayActive) { 162 ClearViewOverlay(); 163 fOverlayActive = false; 164 } 165 fVideoActive = false; 166 Invalidate(); 167 } 168 169 170 void 171 VideoView::RemoveOverlay() 172 { 173 printf("VideoView::RemoveOverlay\n"); 174 if (LockLooperWithTimeout(50000) == B_OK) { 175 ClearViewOverlay(); 176 fOverlayActive = false; 177 UnlockLooper(); 178 } 179 } 180 181 182 void 183 VideoView::CheckActivity() 184 { 185 if (!fVideoActive) 186 return; 187 if (system_time() - fLastFrame < 700000) 188 return; 189 190 printf("VideoView::CheckActivity: lag detected\n"); 191 192 fVideoActive = false; 193 Invalidate(); 194 } 195 196 197 void 198 VideoView::Draw(BRect updateRect) 199 { 200 if (!fVideoActive) { 201 DrawTestImage(); 202 return; 203 } 204 if (fOverlayActive) { 205 SetHighColor(fOverlayKeyColor); 206 FillRect(updateRect); 207 } else { 208 fVideoNode->LockBitmap(); 209 BBitmap *bmp = fVideoNode->Bitmap(); 210 if (bmp) 211 DrawBitmap(bmp, Bounds()); 212 fVideoNode->UnlockBitmap(); 213 } 214 } 215 216 217 void 218 VideoView::DrawFrame() 219 { 220 // printf("VideoView::DrawFrame\n"); 221 if (!fVideoActive) { 222 fVideoActive = true; 223 if (LockLooperWithTimeout(50000) != B_OK) 224 return; 225 Invalidate(); 226 UnlockLooper(); 227 } 228 fLastFrame = system_time(); 229 230 bool want_overlay = fVideoNode->IsOverlayActive(); 231 232 if (!want_overlay && fOverlayActive) { 233 if (LockLooperWithTimeout(50000) == B_OK) { 234 ClearViewOverlay(); 235 UnlockLooper(); 236 fOverlayActive = false; 237 } else { 238 printf("can't ClearViewOverlay, as LockLooperWithTimeout " 239 "failed\n"); 240 } 241 } 242 if (want_overlay && !fOverlayActive) { 243 fVideoNode->LockBitmap(); 244 BBitmap *bmp = fVideoNode->Bitmap(); 245 if (bmp && LockLooperWithTimeout(50000) == B_OK) { 246 SetViewOverlay(bmp, bmp->Bounds(), Bounds(), &fOverlayKeyColor, 247 B_FOLLOW_ALL, B_OVERLAY_FILTER_HORIZONTAL 248 | B_OVERLAY_FILTER_VERTICAL); 249 fOverlayActive = true; 250 251 Invalidate(); 252 UnlockLooper(); 253 } 254 fVideoNode->UnlockBitmap(); 255 } 256 if (!fOverlayActive) { 257 if (LockLooperWithTimeout(50000) != B_OK) 258 return; 259 Invalidate(); 260 UnlockLooper(); 261 } 262 } 263 264 265 void 266 VideoView::DrawTestImage() 267 { 268 static const rgb_color cols[8] = { 269 {255,255,255}, {255,255,0}, {0,255,255}, {0,255,0}, 270 {255,0,255}, {255,0,0}, {0,0,255}, {0,0,0} 271 // {255,255,255}, {255,255,0}, {0,255,255}, 272 // {255,0,255}, {255,0,0}, {0,255,0}, {0,0,255}, {0,0,0} 273 }; 274 float bar_width; 275 float left; 276 float right; 277 278 BRect bnd = Bounds(); 279 int seperator_y1 = int(0.60 * (bnd.Height() + 1)); 280 int seperator_y2 = int(0.80 * (bnd.Height() + 1)); 281 int steps; 282 283 bar_width = bnd.Width() / 8; 284 if (bar_width < 1) 285 bar_width = 1; 286 287 left = 0; 288 for (int i = 0; i < 8; i++) { 289 SetHighColor(cols[i]); 290 right = (i != 7) ? left + bar_width - 1 : bnd.right; 291 FillRect(BRect(left, 0, right, seperator_y1)); 292 left = right + 1; 293 } 294 295 steps = 32; 296 297 bar_width = bnd.Width() / steps; 298 // if (bar_width < 1) 299 // bar_width = 1; 300 301 left = 0; 302 for (int i = 0; i < steps; i++) { 303 uint8 c = i * 255 / (steps - 1); 304 SetHighColor(c, c, c); 305 right = (i != steps - 1) ? left + bar_width - 1 : bnd.right; 306 FillRect(BRect(left, seperator_y1 + 1, right, seperator_y2)); 307 left = right + 1; 308 } 309 310 steps = 256; 311 312 bar_width = bnd.Width() / steps; 313 if (bar_width < 1) 314 bar_width = 1; 315 316 left = 0; 317 for (int i = 0; i < steps; i++) { 318 uint8 c = 255 - (i * 255 / (steps - 1)); 319 SetHighColor(c, c, c); 320 right = (i != steps - 1) ? left + bar_width - 1 : bnd.right; 321 FillRect(BRect(left, seperator_y2 + 1, right, bnd.bottom)); 322 left = right + 1; 323 } 324 } 325 326 327 void 328 VideoView::MessageReceived(BMessage *msg) 329 { 330 switch (msg->what) { 331 case CHECK_ACTIVITY: 332 CheckActivity(); 333 break; 334 default: 335 BView::MessageReceived(msg); 336 } 337 } 338 339 340 bool 341 VideoView::IsOverlaySupported() 342 { 343 struct colorcombo { 344 color_space colspace; 345 const char *name; 346 } colspace[] = { 347 { B_RGB32, "B_RGB32"}, 348 { B_RGBA32, "B_RGBA32"}, 349 { B_RGB24, "B_RGB24"}, 350 { B_RGB16, "B_RGB16"}, 351 { B_RGB15, "B_RGB15"}, 352 { B_RGBA15, "B_RGBA15"}, 353 { B_RGB32_BIG, "B_RGB32_BIG"}, 354 { B_RGBA32_BIG, "B_RGBA32_BIG "}, 355 { B_RGB24_BIG, "B_RGB24_BIG "}, 356 { B_RGB16_BIG, "B_RGB16_BIG "}, 357 { B_RGB15_BIG, "B_RGB15_BIG "}, 358 { B_RGBA15_BIG, "B_RGBA15_BIG "}, 359 { B_YCbCr422, "B_YCbCr422"}, 360 { B_YCbCr411, "B_YCbCr411"}, 361 { B_YCbCr444, "B_YCbCr444"}, 362 { B_YCbCr420, "B_YCbCr420"}, 363 { B_YUV422, "B_YUV422"}, 364 { B_YUV411, "B_YUV411"}, 365 { B_YUV444, "B_YUV444"}, 366 { B_YUV420, "B_YUV420"}, 367 { B_NO_COLOR_SPACE, NULL} 368 }; 369 370 bool supported = false; 371 for (int i = 0; colspace[i].name; i++) { 372 BBitmap *test = new BBitmap(BRect(0,0,320,240), B_BITMAP_WILL_OVERLAY 373 | B_BITMAP_RESERVE_OVERLAY_CHANNEL, colspace[i].colspace); 374 if (test->InitCheck() == B_OK) { 375 printf("Display supports %s (0x%08x) overlay\n", colspace[i].name, 376 colspace[i].colspace); 377 overlay_restrictions restrict; 378 if (B_OK == test->GetOverlayRestrictions(&restrict)) { 379 printf( 380 "Overlay restrictions: source horizontal_alignment %d\n", 381 restrict.source.horizontal_alignment); 382 printf("Overlay restrictions: source vertical_alignment %d\n", 383 restrict.source.vertical_alignment); 384 printf("Overlay restrictions: source width_alignment %d\n", 385 restrict.source.width_alignment); 386 printf("Overlay restrictions: source height_alignment %d\n", 387 restrict.source.height_alignment); 388 printf("Overlay restrictions: source min_width %d\n", 389 restrict.source.min_width); 390 printf("Overlay restrictions: source max_width %d\n", 391 restrict.source.max_width); 392 printf("Overlay restrictions: source min_height %d\n", 393 restrict.source.min_height); 394 printf("Overlay restrictions: source max_height %d\n", 395 restrict.source.max_height); 396 printf( 397 "Overlay restrictions: destination horizontal_alignment " 398 "%d\n", restrict.destination.horizontal_alignment); 399 printf("Overlay restrictions: destination vertical_alignment " 400 "%d\n", restrict.destination.vertical_alignment); 401 printf("Overlay restrictions: destination width_alignment " 402 "%d\n", restrict.destination.width_alignment); 403 printf("Overlay restrictions: destination height_alignment " 404 "%d\n", restrict.destination.height_alignment); 405 printf("Overlay restrictions: destination min_width %d\n", 406 restrict.destination.min_width); 407 printf("Overlay restrictions: destination max_width %d\n", 408 restrict.destination.max_width); 409 printf("Overlay restrictions: destination min_height %d\n", 410 restrict.destination.min_height); 411 printf("Overlay restrictions: destination max_height %d\n", 412 restrict.destination.max_height); 413 printf("Overlay restrictions: min_width_scale %.3f\n", 414 restrict.min_width_scale); 415 printf("Overlay restrictions: max_width_scale %.3f\n", 416 restrict.max_width_scale); 417 printf("Overlay restrictions: min_height_scale %.3f\n", 418 restrict.min_height_scale); 419 printf("Overlay restrictions: max_height_scale %.3f\n", 420 restrict.max_height_scale); 421 } 422 supported = true; 423 } 424 delete test; 425 // if (supported) 426 // break; 427 } 428 return supported; 429 } 430 431