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