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