xref: /haiku/src/apps/tv/VideoView.cpp (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
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