2 * InfoWin.cpp - Media Player for the Haiku Operating System
4 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5 * Copyright 2015 Axel Dörfler <axeld@pinc-software.de>
7 * Released under the terms of the MIT license.
19 #include <ControlLook.h>
21 #include <LayoutBuilder.h>
22 #include <MediaDefs.h>
23 #include <MessageFormat.h>
28 #include <StringForRate.h>
29 #include <StringView.h>
32 #include "Controller.h"
33 #include "ControllerObserver.h"
34 #include "PlaylistItem.h"
40 #undef B_TRANSLATION_CONTEXT
41 #define B_TRANSLATION_CONTEXT "MediaPlayer-InfoWin"
44 class IconView
: public BView
{
46 IconView(const char* name
, int32 iconSize
);
49 status_t
SetIcon(const PlaylistItem
* item
);
50 status_t
SetIcon(const char* mimeType
);
51 void SetGenericIcon();
53 virtual void GetPreferredSize(float* _width
, float* _height
);
54 virtual void AttachedToWindow();
55 virtual void Draw(BRect updateRect
);
62 IconView::IconView(const char* name
, int32 iconSize
)
64 BView(name
, B_WILL_DRAW
| B_FULL_UPDATE_ON_RESIZE
),
67 fIconBitmap
= new BBitmap(BRect(0, 0, iconSize
- 1, iconSize
- 1),
69 SetExplicitMaxSize(PreferredSize());
80 IconView::SetIcon(const PlaylistItem
* item
)
82 return item
->GetIcon(fIconBitmap
, B_LARGE_ICON
);
87 IconView::SetIcon(const char* mimeTypeString
)
93 BMimeType
mimeType(mimeTypeString
);
94 status_t status
= mimeType
.GetIcon(fIconBitmap
, B_LARGE_ICON
);
99 status
= mimeType
.GetSupertype(&superType
);
101 status
= superType
.GetIcon(fIconBitmap
, B_LARGE_ICON
);
109 IconView::SetGenericIcon()
112 BMimeType
genericType(B_FILE_MIME_TYPE
);
113 if (genericType
.GetIcon(fIconBitmap
, B_LARGE_ICON
) != B_OK
) {
115 uint8 transparent
= 0;
116 if (fIconBitmap
->ColorSpace() == B_CMAP8
)
117 transparent
= B_TRANSPARENT_MAGIC_CMAP8
;
119 memset(fIconBitmap
->Bits(), transparent
, fIconBitmap
->BitsLength());
125 IconView::GetPreferredSize(float* _width
, float* _height
)
127 if (_width
!= NULL
) {
128 *_width
= fIconBitmap
->Bounds().Width()
129 + 2 * be_control_look
->DefaultItemSpacing();
131 if (_height
!= NULL
) {
132 *_height
= fIconBitmap
->Bounds().Height()
133 + 2 * be_control_look
->DefaultItemSpacing();
139 IconView::AttachedToWindow()
141 if (Parent() != NULL
)
142 SetViewColor(Parent()->ViewColor());
144 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
149 IconView::Draw(BRect updateRect
)
151 BRect
rect(Bounds());
153 if (fIconBitmap
!= NULL
) {
154 // Draw bitmap centered within the view
155 SetDrawingMode(B_OP_ALPHA
);
156 DrawBitmap(fIconBitmap
, BPoint(rect
.left
157 + (rect
.Width() - fIconBitmap
->Bounds().Width()) / 2,
158 rect
.top
+ (rect
.Height() - fIconBitmap
->Bounds().Height()) / 2));
166 InfoWin::InfoWin(BPoint leftTop
, Controller
* controller
)
168 BWindow(BRect(leftTop
.x
, leftTop
.y
, leftTop
.x
+ MIN_WIDTH
- 1,
169 leftTop
.y
+ 300), B_TRANSLATE("File info"), B_TITLED_WINDOW
,
170 B_ASYNCHRONOUS_CONTROLS
| B_AUTO_UPDATE_SIZE_LIMITS
| B_NOT_ZOOMABLE
),
171 fController(controller
),
172 fControllerObserver(new ControllerObserver(this,
173 OBSERVE_FILE_CHANGES
| OBSERVE_TRACK_CHANGES
| OBSERVE_STAT_CHANGES
))
175 fIconView
= new IconView("background", B_LARGE_ICON
);
177 fFilenameView
= _CreateInfo("filename");
178 BFont
bigFont(be_plain_font
);
179 bigFont
.SetSize(bigFont
.Size() * 1.5f
);
180 fFilenameView
->SetFont(&bigFont
);
184 BStringView
* containerLabel
= _CreateLabel("containerLabel",
185 B_TRANSLATE("Container"));
186 fContainerInfo
= _CreateInfo("container");
188 fVideoSeparator
= _CreateSeparator();
189 fVideoLabel
= _CreateLabel("videoLabel", B_TRANSLATE("Video"));
190 fVideoFormatInfo
= _CreateInfo("videoFormat");
191 fVideoConfigInfo
= _CreateInfo("videoConfig");
192 fDisplayModeLabel
= _CreateLabel("displayModeLabel",
193 B_TRANSLATE("Display mode"));
194 fDisplayModeInfo
= _CreateInfo("displayMode");
196 fAudioSeparator
= _CreateSeparator();
197 fAudioLabel
= _CreateLabel("audioLabel", B_TRANSLATE("Audio"));
198 fAudioFormatInfo
= _CreateInfo("audioFormat");
199 fAudioConfigInfo
= _CreateInfo("audioConfig");
201 BStringView
* durationLabel
= _CreateLabel("durationLabel",
202 B_TRANSLATE("Duration"));
203 fDurationInfo
= _CreateInfo("duration");
205 BStringView
* locationLabel
= _CreateLabel("locationLabel",
206 B_TRANSLATE("Location"));
207 fLocationInfo
= _CreateInfo("location");
209 fCopyrightSeparator
= _CreateSeparator();
210 fCopyrightLabel
= _CreateLabel("copyrightLabel", B_TRANSLATE("Copyright"));
211 fCopyrightInfo
= _CreateInfo("copyright");
213 BLayoutBuilder::Group
<>(this, B_VERTICAL
)
214 .SetInsets(B_USE_DEFAULT_SPACING
)
215 .AddGroup(B_HORIZONTAL
)
217 .Add(fFilenameView
, 1)
220 .Add(containerLabel
, 0, 0)
221 .Add(fContainerInfo
, 1, 0)
222 .Add(fVideoSeparator
, 0, 1)
223 .Add(fVideoLabel
, 0, 2)
224 .Add(fVideoFormatInfo
, 1, 2)
225 .Add(fVideoConfigInfo
, 1, 3)
226 .Add(fDisplayModeLabel
, 0, 4)
227 .Add(fDisplayModeInfo
, 1, 4)
228 .Add(fAudioSeparator
, 0, 5)
229 .Add(fAudioLabel
, 0, 6)
230 .Add(fAudioFormatInfo
, 1, 6)
231 .Add(fAudioConfigInfo
, 1, 7)
232 .Add(_CreateSeparator(), 0, 8)
233 .Add(durationLabel
, 0, 9)
234 .Add(fDurationInfo
, 1, 9)
235 .Add(_CreateSeparator(), 0, 10)
236 .Add(locationLabel
, 0, 11)
237 .Add(fLocationInfo
, 1, 11)
238 .Add(fCopyrightSeparator
, 0, 12)
239 .Add(fCopyrightLabel
, 0, 12)
240 .Add(fCopyrightInfo
, 1, 12)
241 .SetColumnWeight(0, 0)
242 .SetColumnWeight(1, 1)
243 .SetSpacing(B_USE_DEFAULT_SPACING
, 0)
244 .SetExplicitMinSize(BSize(MIN_WIDTH
, B_SIZE_UNSET
));
246 fController
->AddListener(fControllerObserver
);
251 // Move window on screen if needed
252 BScreen
screen(this);
253 if (screen
.Frame().bottom
< Frame().bottom
)
254 MoveBy(0, screen
.Frame().bottom
- Frame().bottom
);
255 if (screen
.Frame().right
< Frame().right
)
256 MoveBy(0, screen
.Frame().right
- Frame().right
);
264 fController
->RemoveListener(fControllerObserver
);
265 delete fControllerObserver
;
270 InfoWin::MessageReceived(BMessage
* msg
)
273 case MSG_CONTROLLER_FILE_FINISHED
:
275 case MSG_CONTROLLER_FILE_CHANGED
:
278 case MSG_CONTROLLER_VIDEO_TRACK_CHANGED
:
279 Update(INFO_VIDEO
| INFO_STATS
);
281 case MSG_CONTROLLER_AUDIO_TRACK_CHANGED
:
282 Update(INFO_AUDIO
| INFO_STATS
);
284 case MSG_CONTROLLER_VIDEO_STATS_CHANGED
:
285 case MSG_CONTROLLER_AUDIO_STATS_CHANGED
:
289 BWindow::MessageReceived(msg
);
296 InfoWin::QuitRequested()
316 InfoWin::Update(uint32 which
)
318 if (!fController
->Lock())
321 if ((which
& INFO_FILE
) != 0)
324 // video track format information
325 if ((which
& INFO_VIDEO
) != 0)
328 // audio track format information
329 if ((which
& INFO_AUDIO
) != 0)
333 if ((which
& INFO_STATS
) != 0) {
335 // TODO: demux/video/audio/... perfs (Kb/info)
338 if ((which
& INFO_TRANSPORT
) != 0) {
339 // Transport protocol info (file, http, rtsp, ...)
342 if ((which
& INFO_COPYRIGHT
)!=0)
345 fController
->Unlock();
350 InfoWin::_UpdateFile()
352 bool iconSet
= false;
353 if (fController
->HasFile()) {
354 const PlaylistItem
* item
= fController
->Item();
355 iconSet
= fIconView
->SetIcon(item
) == B_OK
;
356 media_file_format fileFormat
;
357 status_t status
= fController
->GetFileFormatInfo(&fileFormat
);
358 if (status
== B_OK
) {
359 fContainerInfo
->SetText(fileFormat
.pretty_name
);
361 iconSet
= fIconView
->SetIcon(fileFormat
.mime_type
) == B_OK
;
363 fContainerInfo
->SetText(strerror(status
));
366 if (fController
->GetLocation(&info
) != B_OK
)
367 info
= B_TRANSLATE("<unknown>");
368 fLocationInfo
->SetText(info
.String());
369 fLocationInfo
->SetToolTip(info
.String());
371 if (fController
->GetName(&info
) != B_OK
|| info
.IsEmpty())
372 info
= B_TRANSLATE("<unnamed media>");
373 fFilenameView
->SetText(info
.String());
374 fFilenameView
->SetToolTip(info
.String());
376 fFilenameView
->SetText(B_TRANSLATE("<no media>"));
377 fContainerInfo
->SetText("-");
378 fLocationInfo
->SetText("-");
382 fIconView
->SetGenericIcon();
387 InfoWin::_UpdateVideo()
389 bool visible
= fController
->VideoTrackCount() > 0;
393 media_raw_video_format videoFormat
= {};
394 status_t status
= fController
->GetEncodedVideoFormat(&format
);
395 if (status
!= B_OK
) {
396 info
<< "(" << strerror(status
) << ")\n";
397 } else if (format
.type
== B_MEDIA_ENCODED_VIDEO
) {
398 videoFormat
= format
.u
.encoded_video
.output
;
399 media_codec_info mci
;
400 status
= fController
->GetVideoCodecInfo(&mci
);
401 if (status
!= B_OK
) {
402 if (format
.user_data_type
== B_CODEC_TYPE_INFO
) {
403 info
<< (char *)format
.user_data
<< " "
404 << B_TRANSLATE("(not supported)");
406 info
= strerror(status
);
408 info
<< mci
.pretty_name
; //<< "(" << mci.short_name << ")";
409 } else if (format
.type
== B_MEDIA_RAW_VIDEO
) {
410 videoFormat
= format
.u
.raw_video
;
411 info
<< B_TRANSLATE("raw video");
413 info
<< B_TRANSLATE("unknown format");
415 fVideoFormatInfo
->SetText(info
.String());
417 info
.SetToFormat("%" B_PRIu32
" x %" B_PRIu32
, format
.Width(),
420 // encoded has output as 1st field...
422 snprintf(fpsString
, sizeof(fpsString
), B_TRANSLATE("%.3f fps"),
423 videoFormat
.field_rate
);
424 info
<< ", " << fpsString
;
426 fVideoConfigInfo
->SetText(info
.String());
428 if (fController
->IsOverlayActive())
429 fDisplayModeInfo
->SetText(B_TRANSLATE("Overlay"));
431 fDisplayModeInfo
->SetText(B_TRANSLATE("DrawBitmap"));
434 fVideoSeparator
->SetVisible(visible
);
435 _SetVisible(fVideoLabel
, visible
);
436 _SetVisible(fVideoFormatInfo
, visible
);
437 _SetVisible(fVideoConfigInfo
, visible
);
438 _SetVisible(fDisplayModeLabel
, visible
);
439 _SetVisible(fDisplayModeInfo
, visible
);
444 InfoWin::_UpdateAudio()
446 bool visible
= fController
->AudioTrackCount() > 0;
450 media_raw_audio_format audioFormat
= {};
452 status_t status
= fController
->GetEncodedAudioFormat(&format
);
453 if (status
!= B_OK
) {
454 info
<< "(" << strerror(status
) << ")\n";
455 } else if (format
.type
== B_MEDIA_ENCODED_AUDIO
) {
456 audioFormat
= format
.u
.encoded_audio
.output
;
457 media_codec_info mci
;
458 status
= fController
->GetAudioCodecInfo(&mci
);
459 if (status
!= B_OK
) {
460 if (format
.user_data_type
== B_CODEC_TYPE_INFO
) {
461 info
<< (char *)format
.user_data
<< " "
462 << B_TRANSLATE("(not supported)");
464 info
= strerror(status
);
466 info
= mci
.pretty_name
;
467 } else if (format
.type
== B_MEDIA_RAW_AUDIO
) {
468 audioFormat
= format
.u
.raw_audio
;
469 info
= B_TRANSLATE("raw audio");
471 info
= B_TRANSLATE("unknown format");
473 fAudioFormatInfo
->SetText(info
.String());
475 uint32 bitsPerSample
= 8 * (audioFormat
.format
476 & media_raw_audio_format::B_AUDIO_SIZE_MASK
);
477 uint32 channelCount
= audioFormat
.channel_count
;
478 float sr
= audioFormat
.frame_rate
;
482 if (bitsPerSample
> 0) {
484 snprintf(bitString
, sizeof(bitString
), B_TRANSLATE("%d Bit"),
486 info
<< bitString
<< " ";
489 static BMessageFormat
channelFormat(B_TRANSLATE(
490 "{0, plural, =1{Mono} =2{Stereo} other{# Channels}}"));
491 channelFormat
.Format(info
, channelCount
);
496 snprintf(rateString
, sizeof(rateString
),
497 B_TRANSLATE("%.3f kHz"), sr
/ 1000);
500 BString rateString
= B_TRANSLATE("%d kHz");
501 rateString
.ReplaceFirst("%d", "??");
504 if (format
.type
== B_MEDIA_ENCODED_AUDIO
) {
505 float br
= format
.u
.encoded_audio
.bit_rate
;
506 char string
[20] = "";
508 info
<< ", " << string_for_rate(br
, string
, sizeof(string
));
511 fAudioConfigInfo
->SetText(info
.String());
514 fAudioSeparator
->SetVisible(visible
);
515 _SetVisible(fAudioLabel
, visible
);
516 _SetVisible(fAudioFormatInfo
, visible
);
517 _SetVisible(fAudioConfigInfo
, visible
);
522 InfoWin::_UpdateDuration()
524 if (!fController
->HasFile()) {
525 fDurationInfo
->SetText("-");
531 bigtime_t d
= fController
->TimeDuration() / 1000;
532 bigtime_t v
= d
/ (3600 * 1000);
533 d
= d
% (3600 * 1000);
545 info
<< " " << B_TRANSLATE_COMMENT("h", "Hours");
547 info
<< " " << B_TRANSLATE_COMMENT("min", "Minutes");
549 fDurationInfo
->SetText(info
.String());
554 InfoWin::_UpdateCopyright()
558 bool visible
= fController
->HasFile()
559 && fController
->GetCopyright(&info
) == B_OK
&& !info
.IsEmpty();
561 fCopyrightInfo
->SetText(info
.String());
563 fCopyrightSeparator
->SetVisible(visible
);
564 _SetVisible(fCopyrightLabel
, visible
);
565 _SetVisible(fCopyrightInfo
, visible
);
573 InfoWin::_CreateLabel(const char* name
, const char* label
)
575 static const rgb_color kLabelColor
= tint_color(
576 ui_color(B_PANEL_BACKGROUND_COLOR
), B_DARKEN_3_TINT
);
578 BStringView
* view
= new BStringView(name
, label
);
579 view
->SetAlignment(B_ALIGN_RIGHT
);
580 view
->SetHighColor(kLabelColor
);
587 InfoWin::_CreateInfo(const char* name
)
589 BStringView
* view
= new BStringView(name
, "");
590 view
->SetExplicitMinSize(BSize(200, B_SIZE_UNSET
));
591 view
->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
592 view
->SetTruncation(B_TRUNCATE_SMART
);
599 InfoWin::_CreateSeparator()
601 return BSpaceLayoutItem::CreateVerticalStrut(
602 be_control_look
->ComposeSpacing(B_USE_HALF_ITEM_SPACING
));
607 InfoWin::_SetVisible(BView
* view
, bool visible
)
609 bool hidden
= view
->IsHidden(view
);
610 if (hidden
&& visible
)
612 else if (!hidden
&& !visible
)