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 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include <ControlLook.h>
33 #include <LayoutBuilder.h>
34 #include <MediaDefs.h>
35 #include <MessageFormat.h>
40 #include <StringForRate.h>
41 #include <StringView.h>
44 #include "Controller.h"
45 #include "ControllerObserver.h"
46 #include "PlaylistItem.h"
52 #undef B_TRANSLATION_CONTEXT
53 #define B_TRANSLATION_CONTEXT "MediaPlayer-InfoWin"
56 class IconView
: public BView
{
58 IconView(const char* name
, int32 iconSize
);
61 status_t
SetIcon(const PlaylistItem
* item
);
62 status_t
SetIcon(const char* mimeType
);
63 void SetGenericIcon();
65 virtual void GetPreferredSize(float* _width
, float* _height
);
66 virtual void AttachedToWindow();
67 virtual void Draw(BRect updateRect
);
74 IconView::IconView(const char* name
, int32 iconSize
)
76 BView(name
, B_WILL_DRAW
| B_FULL_UPDATE_ON_RESIZE
),
79 fIconBitmap
= new BBitmap(BRect(0, 0, iconSize
- 1, iconSize
- 1),
81 SetExplicitMaxSize(PreferredSize());
92 IconView::SetIcon(const PlaylistItem
* item
)
94 return item
->GetIcon(fIconBitmap
, B_LARGE_ICON
);
99 IconView::SetIcon(const char* mimeTypeString
)
105 BMimeType
mimeType(mimeTypeString
);
106 status_t status
= mimeType
.GetIcon(fIconBitmap
, B_LARGE_ICON
);
108 // get supertype icon
109 if (status
!= B_OK
) {
111 status
= mimeType
.GetSupertype(&superType
);
113 status
= superType
.GetIcon(fIconBitmap
, B_LARGE_ICON
);
121 IconView::SetGenericIcon()
124 BMimeType
genericType(B_FILE_MIME_TYPE
);
125 if (genericType
.GetIcon(fIconBitmap
, B_LARGE_ICON
) != B_OK
) {
127 uint8 transparent
= 0;
128 if (fIconBitmap
->ColorSpace() == B_CMAP8
)
129 transparent
= B_TRANSPARENT_MAGIC_CMAP8
;
131 memset(fIconBitmap
->Bits(), transparent
, fIconBitmap
->BitsLength());
137 IconView::GetPreferredSize(float* _width
, float* _height
)
139 if (_width
!= NULL
) {
140 *_width
= fIconBitmap
->Bounds().Width()
141 + 2 * be_control_look
->DefaultItemSpacing();
143 if (_height
!= NULL
) {
144 *_height
= fIconBitmap
->Bounds().Height()
145 + 2 * be_control_look
->DefaultItemSpacing();
151 IconView::AttachedToWindow()
153 if (Parent() != NULL
)
154 SetViewColor(Parent()->ViewColor());
156 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
161 IconView::Draw(BRect updateRect
)
163 BRect
rect(Bounds());
165 if (fIconBitmap
!= NULL
) {
166 // Draw bitmap centered within the view
167 SetDrawingMode(B_OP_ALPHA
);
168 DrawBitmap(fIconBitmap
, BPoint(rect
.left
169 + (rect
.Width() - fIconBitmap
->Bounds().Width()) / 2,
170 rect
.top
+ (rect
.Height() - fIconBitmap
->Bounds().Height()) / 2));
178 InfoWin::InfoWin(BPoint leftTop
, Controller
* controller
)
180 BWindow(BRect(leftTop
.x
, leftTop
.y
, leftTop
.x
+ MIN_WIDTH
- 1,
181 leftTop
.y
+ 300), B_TRANSLATE("File info"), B_TITLED_WINDOW
,
182 B_ASYNCHRONOUS_CONTROLS
| B_AUTO_UPDATE_SIZE_LIMITS
| B_NOT_ZOOMABLE
),
183 fController(controller
),
184 fControllerObserver(new ControllerObserver(this,
185 OBSERVE_FILE_CHANGES
| OBSERVE_TRACK_CHANGES
| OBSERVE_STAT_CHANGES
))
187 fIconView
= new IconView("background", B_LARGE_ICON
);
189 fFilenameView
= _CreateInfo("filename");
190 BFont
bigFont(be_plain_font
);
191 bigFont
.SetSize(bigFont
.Size() * 1.5f
);
192 fFilenameView
->SetFont(&bigFont
);
196 BStringView
* containerLabel
= _CreateLabel("containerLabel",
197 B_TRANSLATE("Container"));
198 fContainerInfo
= _CreateInfo("container");
200 fVideoSeparator
= _CreateSeparator();
201 fVideoLabel
= _CreateLabel("videoLabel", B_TRANSLATE("Video"));
202 fVideoFormatInfo
= _CreateInfo("videoFormat");
203 fVideoConfigInfo
= _CreateInfo("videoConfig");
204 fDisplayModeLabel
= _CreateLabel("displayModeLabel",
205 B_TRANSLATE("Display mode"));
206 fDisplayModeInfo
= _CreateInfo("displayMode");
208 fAudioSeparator
= _CreateSeparator();
209 fAudioLabel
= _CreateLabel("audioLabel", B_TRANSLATE("Audio"));
210 fAudioFormatInfo
= _CreateInfo("audioFormat");
211 fAudioConfigInfo
= _CreateInfo("audioConfig");
213 BStringView
* durationLabel
= _CreateLabel("durationLabel",
214 B_TRANSLATE("Duration"));
215 fDurationInfo
= _CreateInfo("duration");
217 BStringView
* locationLabel
= _CreateLabel("locationLabel",
218 B_TRANSLATE("Location"));
219 fLocationInfo
= _CreateInfo("location");
221 fCopyrightSeparator
= _CreateSeparator();
222 fCopyrightLabel
= _CreateLabel("copyrightLabel", B_TRANSLATE("Copyright"));
223 fCopyrightInfo
= _CreateInfo("copyright");
225 BLayoutBuilder::Group
<>(this, B_VERTICAL
)
226 .SetInsets(B_USE_DEFAULT_SPACING
)
227 .AddGroup(B_HORIZONTAL
)
229 .Add(fFilenameView
, 1)
232 .Add(containerLabel
, 0, 0)
233 .Add(fContainerInfo
, 1, 0)
234 .Add(fVideoSeparator
, 0, 1)
235 .Add(fVideoLabel
, 0, 2)
236 .Add(fVideoFormatInfo
, 1, 2)
237 .Add(fVideoConfigInfo
, 1, 3)
238 .Add(fDisplayModeLabel
, 0, 4)
239 .Add(fDisplayModeInfo
, 1, 4)
240 .Add(fAudioSeparator
, 0, 5)
241 .Add(fAudioLabel
, 0, 6)
242 .Add(fAudioFormatInfo
, 1, 6)
243 .Add(fAudioConfigInfo
, 1, 7)
244 .Add(_CreateSeparator(), 0, 8)
245 .Add(durationLabel
, 0, 9)
246 .Add(fDurationInfo
, 1, 9)
247 .Add(_CreateSeparator(), 0, 10)
248 .Add(locationLabel
, 0, 11)
249 .Add(fLocationInfo
, 1, 11)
250 .Add(fCopyrightSeparator
, 0, 12)
251 .Add(fCopyrightLabel
, 0, 12)
252 .Add(fCopyrightInfo
, 1, 12)
253 .SetColumnWeight(0, 0)
254 .SetColumnWeight(1, 1)
255 .SetSpacing(B_USE_DEFAULT_SPACING
, 0)
256 .SetExplicitMinSize(BSize(MIN_WIDTH
, B_SIZE_UNSET
));
258 fController
->AddListener(fControllerObserver
);
263 // Move window on screen if needed
264 BScreen
screen(this);
265 if (screen
.Frame().bottom
< Frame().bottom
)
266 MoveBy(0, screen
.Frame().bottom
- Frame().bottom
);
267 if (screen
.Frame().right
< Frame().right
)
268 MoveBy(0, screen
.Frame().right
- Frame().right
);
276 fController
->RemoveListener(fControllerObserver
);
277 delete fControllerObserver
;
282 InfoWin::MessageReceived(BMessage
* msg
)
285 case MSG_CONTROLLER_FILE_FINISHED
:
287 case MSG_CONTROLLER_FILE_CHANGED
:
290 case MSG_CONTROLLER_VIDEO_TRACK_CHANGED
:
291 Update(INFO_VIDEO
| INFO_STATS
);
293 case MSG_CONTROLLER_AUDIO_TRACK_CHANGED
:
294 Update(INFO_AUDIO
| INFO_STATS
);
296 case MSG_CONTROLLER_VIDEO_STATS_CHANGED
:
297 case MSG_CONTROLLER_AUDIO_STATS_CHANGED
:
301 BWindow::MessageReceived(msg
);
308 InfoWin::QuitRequested()
328 InfoWin::Update(uint32 which
)
330 if (!fController
->Lock())
333 if ((which
& INFO_FILE
) != 0)
336 // video track format information
337 if ((which
& INFO_VIDEO
) != 0)
340 // audio track format information
341 if ((which
& INFO_AUDIO
) != 0)
345 if ((which
& INFO_STATS
) != 0) {
347 // TODO: demux/video/audio/... perfs (Kb/info)
350 if ((which
& INFO_TRANSPORT
) != 0) {
351 // Transport protocol info (file, http, rtsp, ...)
354 if ((which
& INFO_COPYRIGHT
)!=0)
357 fController
->Unlock();
362 InfoWin::_UpdateFile()
364 bool iconSet
= false;
365 if (fController
->HasFile()) {
366 const PlaylistItem
* item
= fController
->Item();
367 iconSet
= fIconView
->SetIcon(item
) == B_OK
;
368 media_file_format fileFormat
;
369 status_t status
= fController
->GetFileFormatInfo(&fileFormat
);
370 if (status
== B_OK
) {
371 fContainerInfo
->SetText(fileFormat
.pretty_name
);
373 iconSet
= fIconView
->SetIcon(fileFormat
.mime_type
) == B_OK
;
375 fContainerInfo
->SetText(strerror(status
));
378 if (fController
->GetLocation(&info
) != B_OK
)
379 info
= B_TRANSLATE("<unknown>");
380 fLocationInfo
->SetText(info
.String());
381 fLocationInfo
->SetToolTip(info
.String());
383 if (fController
->GetName(&info
) != B_OK
|| info
.IsEmpty())
384 info
= B_TRANSLATE("<unnamed media>");
385 fFilenameView
->SetText(info
.String());
386 fFilenameView
->SetToolTip(info
.String());
388 fFilenameView
->SetText(B_TRANSLATE("<no media>"));
389 fContainerInfo
->SetText("-");
390 fLocationInfo
->SetText("-");
394 fIconView
->SetGenericIcon();
399 InfoWin::_UpdateVideo()
401 bool visible
= fController
->VideoTrackCount() > 0;
405 media_raw_video_format videoFormat
= {};
406 status_t status
= fController
->GetEncodedVideoFormat(&format
);
407 if (status
!= B_OK
) {
408 info
<< "(" << strerror(status
) << ")\n";
409 } else if (format
.type
== B_MEDIA_ENCODED_VIDEO
) {
410 videoFormat
= format
.u
.encoded_video
.output
;
411 media_codec_info mci
;
412 status
= fController
->GetVideoCodecInfo(&mci
);
413 if (status
!= B_OK
) {
414 if (format
.user_data_type
== B_CODEC_TYPE_INFO
) {
415 info
<< (char *)format
.user_data
<< " "
416 << B_TRANSLATE("(not supported)");
418 info
= strerror(status
);
420 info
<< mci
.pretty_name
; //<< "(" << mci.short_name << ")";
421 } else if (format
.type
== B_MEDIA_RAW_VIDEO
) {
422 videoFormat
= format
.u
.raw_video
;
423 info
<< B_TRANSLATE("raw video");
425 info
<< B_TRANSLATE("unknown format");
427 fVideoFormatInfo
->SetText(info
.String());
429 info
.SetToFormat("%" B_PRIu32
" x %" B_PRIu32
, format
.Width(),
432 // encoded has output as 1st field...
434 snprintf(fpsString
, sizeof(fpsString
), B_TRANSLATE("%.3f fps"),
435 videoFormat
.field_rate
);
436 info
<< ", " << fpsString
;
438 fVideoConfigInfo
->SetText(info
.String());
440 if (fController
->IsOverlayActive())
441 fDisplayModeInfo
->SetText(B_TRANSLATE("Overlay"));
443 fDisplayModeInfo
->SetText(B_TRANSLATE("DrawBitmap"));
446 fVideoSeparator
->SetVisible(visible
);
447 _SetVisible(fVideoLabel
, visible
);
448 _SetVisible(fVideoFormatInfo
, visible
);
449 _SetVisible(fVideoConfigInfo
, visible
);
450 _SetVisible(fDisplayModeLabel
, visible
);
451 _SetVisible(fDisplayModeInfo
, visible
);
456 InfoWin::_UpdateAudio()
458 bool visible
= fController
->AudioTrackCount() > 0;
462 media_raw_audio_format audioFormat
= {};
464 status_t status
= fController
->GetEncodedAudioFormat(&format
);
465 if (status
!= B_OK
) {
466 info
<< "(" << strerror(status
) << ")\n";
467 } else if (format
.type
== B_MEDIA_ENCODED_AUDIO
) {
468 audioFormat
= format
.u
.encoded_audio
.output
;
469 media_codec_info mci
;
470 status
= fController
->GetAudioCodecInfo(&mci
);
471 if (status
!= B_OK
) {
472 if (format
.user_data_type
== B_CODEC_TYPE_INFO
) {
473 info
<< (char *)format
.user_data
<< " "
474 << B_TRANSLATE("(not supported)");
476 info
= strerror(status
);
478 info
= mci
.pretty_name
;
479 } else if (format
.type
== B_MEDIA_RAW_AUDIO
) {
480 audioFormat
= format
.u
.raw_audio
;
481 info
= B_TRANSLATE("raw audio");
483 info
= B_TRANSLATE("unknown format");
485 fAudioFormatInfo
->SetText(info
.String());
487 uint32 bitsPerSample
= 8 * (audioFormat
.format
488 & media_raw_audio_format::B_AUDIO_SIZE_MASK
);
489 uint32 channelCount
= audioFormat
.channel_count
;
490 float sr
= audioFormat
.frame_rate
;
494 if (bitsPerSample
> 0) {
496 snprintf(bitString
, sizeof(bitString
), B_TRANSLATE("%d Bit"),
498 info
<< bitString
<< " ";
501 static BMessageFormat
channelFormat(B_TRANSLATE(
502 "{0, plural, =1{Mono} =2{Stereo} other{# Channels}}"));
503 channelFormat
.Format(info
, channelCount
);
508 snprintf(rateString
, sizeof(rateString
),
509 B_TRANSLATE("%.3f kHz"), sr
/ 1000);
512 BString rateString
= B_TRANSLATE("%d kHz");
513 rateString
.ReplaceFirst("%d", "??");
516 if (format
.type
== B_MEDIA_ENCODED_AUDIO
) {
517 float br
= format
.u
.encoded_audio
.bit_rate
;
518 char string
[20] = "";
520 info
<< ", " << string_for_rate(br
, string
, sizeof(string
));
523 fAudioConfigInfo
->SetText(info
.String());
526 fAudioSeparator
->SetVisible(visible
);
527 _SetVisible(fAudioLabel
, visible
);
528 _SetVisible(fAudioFormatInfo
, visible
);
529 _SetVisible(fAudioConfigInfo
, visible
);
534 InfoWin::_UpdateDuration()
536 if (!fController
->HasFile()) {
537 fDurationInfo
->SetText("-");
543 bigtime_t d
= fController
->TimeDuration() / 1000;
544 bigtime_t v
= d
/ (3600 * 1000);
545 d
= d
% (3600 * 1000);
557 info
<< " " << B_TRANSLATE_COMMENT("h", "Hours");
559 info
<< " " << B_TRANSLATE_COMMENT("min", "Minutes");
561 fDurationInfo
->SetText(info
.String());
566 InfoWin::_UpdateCopyright()
570 bool visible
= fController
->HasFile()
571 && fController
->GetCopyright(&info
) == B_OK
&& !info
.IsEmpty();
573 fCopyrightInfo
->SetText(info
.String());
575 fCopyrightSeparator
->SetVisible(visible
);
576 _SetVisible(fCopyrightLabel
, visible
);
577 _SetVisible(fCopyrightInfo
, visible
);
585 InfoWin::_CreateLabel(const char* name
, const char* label
)
587 static const rgb_color kLabelColor
= tint_color(
588 ui_color(B_PANEL_BACKGROUND_COLOR
), B_DARKEN_3_TINT
);
590 BStringView
* view
= new BStringView(name
, label
);
591 view
->SetAlignment(B_ALIGN_RIGHT
);
592 view
->SetHighColor(kLabelColor
);
599 InfoWin::_CreateInfo(const char* name
)
601 BStringView
* view
= new BStringView(name
, "");
602 view
->SetExplicitMinSize(BSize(200, B_SIZE_UNSET
));
603 view
->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
604 view
->SetTruncation(B_TRUNCATE_SMART
);
611 InfoWin::_CreateSeparator()
613 return BSpaceLayoutItem::CreateVerticalStrut(
614 be_control_look
->ComposeSpacing(B_USE_HALF_ITEM_SPACING
));
619 InfoWin::_SetVisible(BView
* view
, bool visible
)
621 bool hidden
= view
->IsHidden(view
);
622 if (hidden
&& visible
)
624 else if (!hidden
&& !visible
)