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