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