xref: /haiku/src/apps/mediaplayer/InfoWin.cpp (revision 23d878482ed22e55dad6d1fca1df7bea42eb157c)
1 /*
2  * InfoWin.cpp - Media Player for the Haiku Operating System
3  *
4  * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  */
20 
21 
22 #include "InfoWin.h"
23 
24 #include <math.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include <Bitmap.h>
29 #include <Catalog.h>
30 #include <Debug.h>
31 #include <MediaDefs.h>
32 #include <Mime.h>
33 #include <NodeInfo.h>
34 #include <String.h>
35 #include <StringView.h>
36 #include <TextView.h>
37 
38 #include "Controller.h"
39 #include "ControllerObserver.h"
40 #include "PlaylistItem.h"
41 
42 
43 #define NAME "File info"
44 #define MIN_WIDTH 400
45 
46 #define BASE_HEIGHT (32 + 32)
47 
48 //const rgb_color kGreen = { 152, 203, 152, 255 };
49 const rgb_color kRed =   { 203, 152, 152, 255 };
50 const rgb_color kBlue =  {   0,   0, 220, 255 };
51 const rgb_color kGreen = { 171, 221, 161, 255 };
52 const rgb_color kBlack = {   0,   0,   0, 255 };
53 
54 #undef B_TRANSLATION_CONTEXT
55 #define B_TRANSLATION_CONTEXT "MediaPlayer-InfoWin"
56 
57 // should later draw an icon
58 class InfoView : public BView {
59 public:
60 						InfoView(BRect frame, const char* name, float divider);
61 	virtual				~InfoView();
62 	virtual	void		Draw(BRect updateRect);
63 
64 			status_t	SetIcon(const PlaylistItem* item);
65 			status_t	SetIcon(const char* mimeType);
66 			void		SetGenericIcon();
67 
68 private:
69 			float		fDivider;
70 			BBitmap*	fIconBitmap;
71 };
72 
73 
74 InfoView::InfoView(BRect frame, const char *name, float divider)
75 	: BView(frame, name, B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
76 	  fDivider(divider),
77 	  fIconBitmap(NULL)
78 {
79 	BRect rect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1);
80 
81 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
82 	fIconBitmap = new BBitmap(rect, B_RGBA32);
83 #else
84 	fIconBitmap = new BBitmap(rect, B_CMAP8);
85 #endif
86 }
87 
88 
89 InfoView::~InfoView()
90 {
91 	delete fIconBitmap;
92 }
93 
94 void
95 InfoView::Draw(BRect updateRect)
96 {
97 	SetHighColor(kGreen);
98 	BRect r(Bounds());
99 	r.right = r.left + fDivider;
100 	FillRect(r);
101 
102 	if (fIconBitmap) {
103 		float left = r.left + ( r.right - r.left ) / 2 - B_LARGE_ICON / 2;
104 		SetDrawingMode(B_OP_ALPHA);
105 		DrawBitmap(fIconBitmap, BPoint(left, r.top + B_LARGE_ICON / 2));
106 	}
107 
108 	SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR));
109 	r.left = r.right;
110 	FillRect(r);
111 }
112 
113 
114 status_t
115 InfoView::SetIcon(const PlaylistItem* item)
116 {
117 	return item->GetIcon(fIconBitmap, B_LARGE_ICON);
118 }
119 
120 
121 status_t
122 InfoView::SetIcon(const char* mimeTypeString)
123 {
124 	if (!mimeTypeString)
125 		return B_BAD_VALUE;
126 
127 	// get type icon
128 	BMimeType mimeType(mimeTypeString);
129 	status_t status = mimeType.GetIcon(fIconBitmap, B_LARGE_ICON);
130 
131 	// get supertype icon
132 	if (status != B_OK) {
133 		BMimeType superType;
134 		status = mimeType.GetSupertype(&superType);
135 		if (status == B_OK)
136 			status = superType.GetIcon(fIconBitmap, B_LARGE_ICON);
137 	}
138 
139 	return status;
140 }
141 
142 
143 void
144 InfoView::SetGenericIcon()
145 {
146 	// get default icon
147 	BMimeType genericType(B_FILE_MIME_TYPE);
148 	if (genericType.GetIcon(fIconBitmap, B_LARGE_ICON) != B_OK) {
149 		// clear bitmap
150 		uint8 transparent = 0;
151 		if (fIconBitmap->ColorSpace() == B_CMAP8)
152 			transparent = B_TRANSPARENT_MAGIC_CMAP8;
153 
154 		memset(fIconBitmap->Bits(), transparent, fIconBitmap->BitsLength());
155 	}
156 }
157 
158 
159 // #pragma mark -
160 
161 
162 InfoWin::InfoWin(BPoint leftTop, Controller* controller)
163 	:
164 	BWindow(BRect(leftTop.x, leftTop.y, leftTop.x + MIN_WIDTH - 1,
165 		leftTop.y + 300), B_TRANSLATE(NAME), B_TITLED_WINDOW,
166 		B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE | B_NOT_ZOOMABLE),
167 	fController(controller),
168 	fControllerObserver(new ControllerObserver(this,
169 		OBSERVE_FILE_CHANGES | OBSERVE_TRACK_CHANGES | OBSERVE_STAT_CHANGES))
170 {
171 	BRect rect = Bounds();
172 
173 	// accomodate for big fonts
174 	float div = max_c(2 * 32, be_plain_font->StringWidth(
175 		B_TRANSLATE("Display Mode")) + 10);
176 
177 	fInfoView = new InfoView(rect, "background", div);
178 	fInfoView->SetViewColor(ui_color(B_DOCUMENT_BACKGROUND_COLOR));
179 	AddChild(fInfoView);
180 
181 	BFont bigFont(be_plain_font);
182 	bigFont.SetSize(bigFont.Size() + 6);
183 	font_height fh;
184 	bigFont.GetHeight(&fh);
185 	fFilenameView = new BStringView(
186 		BRect(div + 10, 20, rect.right - 10, 20 + fh.ascent + 5),
187 		"filename", "");
188 	AddChild(fFilenameView);
189 	fFilenameView->SetFont(&bigFont);
190 	fFilenameView->SetViewColor(fInfoView->ViewColor());
191 	fFilenameView->SetLowColor(fInfoView->ViewColor());
192 #ifdef B_BEOS_VERSION_DANO /* maybe we should support that as well ? */
193 	fFilenameView->SetTruncation(B_TRUNCATE_END);
194 #endif
195 
196 	rect.top = BASE_HEIGHT;
197 
198 	BRect lr(rect);
199 	BRect cr(rect);
200 	lr.right = div - 1;
201 	cr.left = div + 1;
202 	BRect tr;
203 	tr = lr.OffsetToCopy(0, 0).InsetByCopy(5, 1);
204 	fLabelsView = new BTextView(lr, "labels", tr, B_FOLLOW_BOTTOM);
205 	fLabelsView->SetViewColor(kGreen);
206 	fLabelsView->SetAlignment(B_ALIGN_RIGHT);
207 	fLabelsView->SetWordWrap(false);
208 	AddChild(fLabelsView);
209 	tr = cr.OffsetToCopy(0, 0).InsetByCopy(10, 1);
210 	fContentsView = new BTextView(cr, "contents", tr, B_FOLLOW_BOTTOM);
211 	fContentsView->SetWordWrap(false);
212 	AddChild(fContentsView);
213 
214 	fLabelsView->MakeSelectable();
215 	fContentsView->MakeSelectable();
216 
217 	fController->AddListener(fControllerObserver);
218 	Update();
219 
220 	Show();
221 }
222 
223 
224 InfoWin::~InfoWin()
225 {
226 	fController->RemoveListener(fControllerObserver);
227 	delete fControllerObserver;
228 }
229 
230 
231 // #pragma mark -
232 
233 
234 void
235 InfoWin::FrameResized(float newWidth, float newHeight)
236 {
237 }
238 
239 
240 void
241 InfoWin::MessageReceived(BMessage* msg)
242 {
243 	switch (msg->what) {
244 		case MSG_CONTROLLER_FILE_FINISHED:
245 			break;
246 		case MSG_CONTROLLER_FILE_CHANGED:
247 			Update(INFO_ALL);
248 			break;
249 		case MSG_CONTROLLER_VIDEO_TRACK_CHANGED:
250 			Update(/*INFO_VIDEO | INFO_STATS*/INFO_ALL);
251 			break;
252 		case MSG_CONTROLLER_AUDIO_TRACK_CHANGED:
253 			Update(/*INFO_AUDIO | INFO_STATS*/INFO_ALL);
254 			break;
255 		case MSG_CONTROLLER_VIDEO_STATS_CHANGED:
256 		case MSG_CONTROLLER_AUDIO_STATS_CHANGED:
257 			Update(/*INFO_STATS*/INFO_ALL);
258 			break;
259 		default:
260 			BWindow::MessageReceived(msg);
261 			break;
262 	}
263 }
264 
265 
266 bool
267 InfoWin::QuitRequested()
268 {
269 	Hide();
270 	return false;
271 }
272 
273 
274 void
275 InfoWin::Pulse()
276 {
277 	if (IsHidden())
278 		return;
279 	Update(INFO_STATS);
280 }
281 
282 
283 // #pragma mark -
284 
285 
286 void
287 InfoWin::ResizeToPreferred()
288 {
289 }
290 
291 
292 void
293 InfoWin::Update(uint32 which)
294 {
295 printf("InfoWin::Update(0x%08lx)\n", which);
296 	fLabelsView->SetText("");
297 	fContentsView->SetText("");
298 	fLabelsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kBlue);
299 	fLabelsView->Insert(" ");
300 	fContentsView->SetFontAndColor(be_plain_font, B_FONT_ALL);
301 //	fContentsView->Insert("");
302 
303 	if (!fController->Lock())
304 		return;
305 
306 	fLabelsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kRed);
307 
308 	status_t err;
309 	// video track format information
310 	if ((which & INFO_VIDEO) && fController->VideoTrackCount() > 0) {
311 		BString label = B_TRANSLATE("Video");
312 		fLabelsView->Insert(label << "\n\n\n");
313 		BString s;
314 		media_format format;
315 		media_raw_video_format videoFormat;
316 		err = fController->GetEncodedVideoFormat(&format);
317 		if (err < B_OK) {
318 			s << "(" << strerror(err) << ")\n";
319 		} else if (format.type == B_MEDIA_ENCODED_VIDEO) {
320 			videoFormat = format.u.encoded_video.output;
321 			media_codec_info mci;
322 			err = fController->GetVideoCodecInfo(&mci);
323 			if (err < B_OK) {
324 				s << B_TRANSLATE("Haiku Media Kit: ") << strerror(err);
325 				if (format.user_data_type == B_CODEC_TYPE_INFO) {
326 					s << (char *)format.user_data << " "
327 						<< B_TRANSLATE("(not supported)");
328 				}
329 			} else
330 				s << mci.pretty_name; //<< "(" << mci.short_name << ")";
331 		} else if (format.type == B_MEDIA_RAW_VIDEO) {
332 			videoFormat = format.u.raw_video;
333 			s << B_TRANSLATE("raw video");
334 		} else
335 			s << B_TRANSLATE("unknown format");
336 		s << "\n";
337 		s << format.Width() << " x " << format.Height();
338 		// encoded has output as 1st field...
339 		char fpsString[20];
340 		snprintf(fpsString, sizeof(fpsString), B_TRANSLATE("%.3f fps"),
341 			videoFormat.field_rate);
342 		s << ", " << fpsString << "\n\n";
343 		fContentsView->Insert(s.String());
344 	}
345 
346 	// audio track format information
347 	if ((which & INFO_AUDIO) && fController->AudioTrackCount() > 0) {
348 		BString label = B_TRANSLATE("Audio");
349 		fLabelsView->Insert(label << "\n\n\n");
350 		BString s;
351 		media_format format;
352 		media_raw_audio_format audioFormat;
353 		err = fController->GetEncodedAudioFormat(&format);
354 		//string_for_format(format, buf, sizeof(buf));
355 		//printf("%s\n", buf);
356 		if (err < 0) {
357 			s << "(" << strerror(err) << ")\n";
358 		} else if (format.type == B_MEDIA_ENCODED_AUDIO) {
359 			audioFormat = format.u.encoded_audio.output;
360 			media_codec_info mci;
361 			err = fController->GetAudioCodecInfo(&mci);
362 			if (err < 0) {
363 				s << B_TRANSLATE("Haiku Media Kit: ") << strerror(err);
364 				if (format.user_data_type == B_CODEC_TYPE_INFO) {
365 					s << (char *)format.user_data << " "
366 						<< B_TRANSLATE("(not supported)");
367 				}
368 			} else
369 				s << mci.pretty_name; //<< "(" << mci.short_name << ")";
370 		} else if (format.type == B_MEDIA_RAW_AUDIO) {
371 			audioFormat = format.u.raw_audio;
372 			s << B_TRANSLATE("raw audio");
373 		} else
374 			s << B_TRANSLATE("unknown format");
375 		s << "\n";
376 		uint32 bitsPerSample = 8 * (audioFormat.format
377 			& media_raw_audio_format::B_AUDIO_SIZE_MASK);
378 		uint32 channelCount = audioFormat.channel_count;
379 		float sr = audioFormat.frame_rate;
380 
381 		if (bitsPerSample > 0) {
382 			char bitString[20];
383 			snprintf(bitString, sizeof(bitString), B_TRANSLATE("%d Bit"),
384 				bitsPerSample);
385 			s << bitString << " ";
386 		}
387 		if (channelCount == 1)
388 			s << B_TRANSLATE("Mono");
389 		else if (channelCount == 2)
390 			s << B_TRANSLATE("Stereo");
391 		else {
392 			char channelString[20];
393 			snprintf(channelString, sizeof(channelString),
394 				B_TRANSLATE("%d Channels"), channelCount);
395 			s << channelString;
396 		}
397 		s << ", ";
398 		if (sr > 0.0) {
399 			char rateString[20];
400 			snprintf(rateString, sizeof(rateString),
401 				B_TRANSLATE("%.3f kHz"), sr / 1000);
402 			s << rateString;
403 		} else {
404 			BString rateString = B_TRANSLATE("%d kHz");
405 			rateString.ReplaceFirst("%d", "??");
406 			s << rateString;
407 		}
408 		s << "\n\n";
409 		fContentsView->Insert(s.String());
410 	}
411 
412 	// statistics
413 	if ((which & INFO_STATS) && fController->HasFile()) {
414 		BString label = B_TRANSLATE("Duration");
415 		fLabelsView->Insert(label << "\n");
416 		BString s;
417 		bigtime_t d = fController->TimeDuration();
418 		bigtime_t v;
419 
420 		//s << d << "µs; ";
421 
422 		d /= 1000;
423 
424 		v = d / (3600 * 1000);
425 		d = d % (3600 * 1000);
426 		bool hours = v > 0;
427 		if (hours)
428 			s << v << ":";
429 		v = d / (60 * 1000);
430 		d = d % (60 * 1000);
431 		s << v << ":";
432 		v = d / 1000;
433 		s << v;
434 		if (hours)
435 			s << " " << B_TRANSLATE_COMMENT("h", "Hours");
436 		else
437 			s << " " << B_TRANSLATE_COMMENT("min", "Minutes");
438 		s << "\n";
439 		fContentsView->Insert(s.String());
440 		// TODO: demux/video/audio/... perfs (Kb/s)
441 
442 		BString content = B_TRANSLATE("Display mode");
443 		fLabelsView->Insert(content << "\n");
444 		if (fController->IsOverlayActive()) {
445 			content = B_TRANSLATE("Overlay");
446 			fContentsView->Insert(content << "\n");
447 		} else {
448 			content = B_TRANSLATE("DrawBitmap");
449 			fContentsView->Insert(content << "\n");
450 		}
451 
452 		fLabelsView->Insert("\n");
453 		fContentsView->Insert("\n");
454 	}
455 
456 	if (which & INFO_TRANSPORT) {
457 		// Transport protocol info (file, http, rtsp, ...)
458 	}
459 
460 	if (which & INFO_FILE) {
461 		bool iconSet = false;
462 		if (fController->HasFile()) {
463 			const PlaylistItem* item = fController->Item();
464 			iconSet = fInfoView->SetIcon(item) == B_OK;
465 			media_file_format fileFormat;
466 			BString s;
467 			if (fController->GetFileFormatInfo(&fileFormat) == B_OK) {
468 				BString label = B_TRANSLATE("Container");
469 				fLabelsView->Insert(label << "\n");
470 				s << fileFormat.pretty_name;
471 				s << "\n";
472 				fContentsView->Insert(s.String());
473 				if (!iconSet)
474 					iconSet = fInfoView->SetIcon(fileFormat.mime_type) == B_OK;
475 			} else
476 				fContentsView->Insert("\n");
477 			BString label = B_TRANSLATE("Location");
478 			fLabelsView->Insert(label << "\n");
479 			if (fController->GetLocation(&s) < B_OK)
480 				s = B_TRANSLATE("<unknown>");
481 			s << "\n";
482 			fContentsView->Insert(s.String());
483 			if (fController->GetName(&s) < B_OK)
484 				s = B_TRANSLATE("<unnamed media>");
485 			fFilenameView->SetText(s.String());
486 		} else {
487 			fFilenameView->SetText(B_TRANSLATE("<no media>"));
488 		}
489 		if (!iconSet)
490 			fInfoView->SetGenericIcon();
491 	}
492 
493 	if ((which & INFO_COPYRIGHT) && fController->HasFile()) {
494 		BString s;
495 		if (fController->GetCopyright(&s) == B_OK && s.Length() > 0) {
496 			BString label = B_TRANSLATE("Copyright");
497 			fLabelsView->Insert(label << "\n\n");
498 			s << "\n\n";
499 			fContentsView->Insert(s.String());
500 		}
501 	}
502 
503 	fController->Unlock();
504 
505 	ResizeToPreferred();
506 }
507