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