1 // Copyright (c) 1998-99, Be Incorporated, All Rights Reserved. 2 // SMS 3 // VideoConsumer.cpp 4 5 #include <View.h> 6 #include <stdio.h> 7 #include <fcntl.h> 8 #include <Buffer.h> 9 #include <unistd.h> 10 #include <string.h> 11 #include <NodeInfo.h> 12 #include <scheduler.h> 13 #include <TimeSource.h> 14 #include <StringView.h> 15 #include <MediaRoster.h> 16 #include <Application.h> 17 #include <BufferGroup.h> 18 19 #include "FtpClient.h" 20 #include "VideoConsumer.h" 21 22 #define M1 ((double)1000000.0) 23 #define JITTER 20000 24 25 #define FUNCTION printf 26 #define ERROR printf 27 #define PROGRESS printf 28 #define LOOP printf 29 30 static status_t SetFileType(BFile * file, int32 translator, uint32 type); 31 32 const media_raw_video_format vid_format = { 29.97,1,0,239,B_VIDEO_TOP_LEFT_RIGHT,1,1,{B_RGB16,320,240,320*4,0,0}}; 33 34 //--------------------------------------------------------------- 35 36 VideoConsumer::VideoConsumer( 37 const char * name, 38 BView *view, 39 BStringView * statusLine, 40 BMediaAddOn *addon, 41 const uint32 internal_id) : 42 43 BMediaNode(name), 44 BMediaEventLooper(), 45 BBufferConsumer(B_MEDIA_RAW_VIDEO), 46 mStatusLine(statusLine), 47 mInternalID(internal_id), 48 mAddOn(addon), 49 mConnectionActive(false), 50 mMyLatency(20000), 51 mWindow(NULL), 52 mView(view), 53 mOurBuffers(false), 54 mBuffers(NULL), 55 mTimeToFtp(false), 56 mFtpComplete(true), 57 mRate(1000000), 58 mImageFormat(0), 59 mTranslator(0), 60 mPassiveFtp(true) 61 { 62 FUNCTION("VideoConsumer::VideoConsumer\n"); 63 64 AddNodeKind(B_PHYSICAL_OUTPUT); 65 SetEventLatency(0); 66 mWindow = mView->Window(); 67 68 for (uint32 j = 0; j < 3; j++) 69 { 70 mBitmap[j] = NULL; 71 mBufferMap[j] = 0; 72 } 73 74 strcpy(mFileNameText, ""); 75 strcpy(mServerText, ""); 76 strcpy(mLoginText, ""); 77 strcpy(mPasswordText, ""); 78 strcpy(mDirectoryText, ""); 79 80 SetPriority(B_DISPLAY_PRIORITY); 81 } 82 83 //--------------------------------------------------------------- 84 85 VideoConsumer::~VideoConsumer() 86 { 87 FUNCTION("VideoConsumer::~VideoConsumer\n"); 88 89 Quit(); 90 91 if (mWindow) 92 { 93 printf("Locking the window\n"); 94 if (mWindow->Lock()) 95 { 96 printf("Closing the window\n"); 97 mWindow->Close(); 98 mWindow = 0; 99 } 100 } 101 102 // clean up ftp thread 103 // wait up to 30 seconds if ftp is in progress 104 int32 count = 0; 105 while (!mFtpComplete && (count < 30)) 106 { 107 snooze(1000000); 108 count++; 109 } 110 111 if(count == 30) 112 kill_thread(mFtpThread); 113 114 DeleteBuffers(); 115 116 117 } 118 119 /******************************** 120 From BMediaNode 121 ********************************/ 122 123 //--------------------------------------------------------------- 124 125 BMediaAddOn * 126 VideoConsumer::AddOn(long *cookie) const 127 { 128 FUNCTION("VideoConsumer::AddOn\n"); 129 // do the right thing if we're ever used with an add-on 130 *cookie = mInternalID; 131 return mAddOn; 132 } 133 134 //--------------------------------------------------------------- 135 136 // This implementation is required to get around a bug in 137 // the ppc compiler. 138 139 void 140 VideoConsumer::Start(bigtime_t performance_time) 141 { 142 BMediaEventLooper::Start(performance_time); 143 } 144 145 void 146 VideoConsumer::Stop(bigtime_t performance_time, bool immediate) 147 { 148 BMediaEventLooper::Stop(performance_time, immediate); 149 } 150 151 void 152 VideoConsumer::Seek(bigtime_t media_time, bigtime_t performance_time) 153 { 154 BMediaEventLooper::Seek(media_time, performance_time); 155 } 156 157 void 158 VideoConsumer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time) 159 { 160 BMediaEventLooper::TimeWarp(at_real_time, to_performance_time); 161 } 162 163 status_t 164 VideoConsumer::DeleteHook(BMediaNode *node) 165 { 166 return BMediaEventLooper::DeleteHook(node); 167 } 168 169 //--------------------------------------------------------------- 170 171 void 172 VideoConsumer::NodeRegistered() 173 { 174 FUNCTION("VideoConsumer::NodeRegistered\n"); 175 mIn.destination.port = ControlPort(); 176 mIn.destination.id = 0; 177 mIn.source = media_source::null; 178 mIn.format.type = B_MEDIA_RAW_VIDEO; 179 mIn.format.u.raw_video = vid_format; 180 181 Run(); 182 } 183 184 //--------------------------------------------------------------- 185 186 status_t 187 VideoConsumer::RequestCompleted(const media_request_info & info) 188 { 189 FUNCTION("VideoConsumer::RequestCompleted\n"); 190 switch(info.what) 191 { 192 case media_request_info::B_SET_OUTPUT_BUFFERS_FOR: 193 { 194 if (info.status != B_OK) 195 ERROR("VideoConsumer::RequestCompleted: Not using our buffers!\n"); 196 } 197 break; 198 default: 199 ERROR("VideoConsumer::RequestCompleted: Invalid argument\n"); 200 break; 201 } 202 return B_OK; 203 } 204 205 //--------------------------------------------------------------- 206 207 status_t 208 VideoConsumer::HandleMessage(int32 message, const void * data, size_t size) 209 { 210 //FUNCTION("VideoConsumer::HandleMessage\n"); 211 ftp_msg_info *info = (ftp_msg_info *)data; 212 status_t status = B_OK; 213 214 switch (message) 215 { 216 case FTP_INFO: 217 PROGRESS("VideoConsumer::HandleMessage - FTP_INFO message\n"); 218 mRate = info->rate; 219 mImageFormat = info->imageFormat; 220 mTranslator = info->translator; 221 mPassiveFtp = info->passiveFtp; 222 strcpy(mFileNameText, info->fileNameText); 223 strcpy(mServerText, info->serverText); 224 strcpy(mLoginText, info->loginText); 225 strcpy(mPasswordText, info->passwordText); 226 strcpy(mDirectoryText, info->directoryText); 227 // remove old user events 228 EventQueue()->FlushEvents(TimeSource()->Now(), BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_USER_EVENT); 229 if (mRate != B_INFINITE_TIMEOUT) { 230 // if rate is not "Never," push an event to restart captures 5 seconds from now 231 media_timed_event event(TimeSource()->Now() + 5000000, BTimedEventQueue::B_USER_EVENT); 232 EventQueue()->AddEvent(event); 233 } 234 break; 235 } 236 237 return status; 238 } 239 240 //--------------------------------------------------------------- 241 242 void 243 VideoConsumer::BufferReceived(BBuffer * buffer) 244 { 245 LOOP("VideoConsumer::Buffer #%ld received\n", buffer->ID()); 246 247 if (RunState() == B_STOPPED) 248 { 249 buffer->Recycle(); 250 return; 251 } 252 253 media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER, 254 buffer, BTimedEventQueue::B_RECYCLE_BUFFER); 255 EventQueue()->AddEvent(event); 256 } 257 258 259 //--------------------------------------------------------------- 260 261 void 262 VideoConsumer::ProducerDataStatus( 263 const media_destination &for_whom, 264 int32 status, 265 bigtime_t at_media_time) 266 { 267 FUNCTION("VideoConsumer::ProducerDataStatus\n"); 268 269 if (for_whom != mIn.destination) 270 return; 271 } 272 273 //--------------------------------------------------------------- 274 275 status_t 276 VideoConsumer::CreateBuffers( 277 const media_format & with_format) 278 { 279 FUNCTION("VideoConsumer::CreateBuffers\n"); 280 281 // delete any old buffers 282 DeleteBuffers(); 283 284 status_t status = B_OK; 285 286 // create a buffer group 287 uint32 mXSize = with_format.u.raw_video.display.line_width; 288 uint32 mYSize = with_format.u.raw_video.display.line_count; 289 color_space mColorspace = with_format.u.raw_video.display.format; 290 PROGRESS("VideoConsumer::CreateBuffers - Colorspace = %d\n", mColorspace); 291 292 mBuffers = new BBufferGroup(); 293 status = mBuffers->InitCheck(); 294 if (B_OK != status) 295 { 296 ERROR("VideoConsumer::CreateBuffers - ERROR CREATING BUFFER GROUP\n"); 297 return status; 298 } 299 // and attach the bitmaps to the buffer group 300 for (uint32 j=0; j < 3; j++) 301 { 302 mBitmap[j] = new BBitmap(BRect(0, 0, (mXSize-1), (mYSize - 1)), mColorspace, false, true); 303 if (mBitmap[j]->IsValid()) 304 { 305 buffer_clone_info info; 306 if ((info.area = area_for(mBitmap[j]->Bits())) == B_ERROR) 307 ERROR("VideoConsumer::CreateBuffers - ERROR IN AREA_FOR\n");; 308 info.offset = 0; 309 info.size = (size_t)mBitmap[j]->BitsLength(); 310 info.flags = j; 311 info.buffer = 0; 312 313 if ((status = mBuffers->AddBuffer(info)) != B_OK) 314 { 315 ERROR("VideoConsumer::CreateBuffers - ERROR ADDING BUFFER TO GROUP\n"); 316 return status; 317 } else PROGRESS("VideoConsumer::CreateBuffers - SUCCESSFUL ADD BUFFER TO GROUP\n"); 318 } 319 else 320 { 321 ERROR("VideoConsumer::CreateBuffers - ERROR CREATING VIDEO RING BUFFER: %08lx\n", status); 322 return B_ERROR; 323 } 324 } 325 326 BBuffer ** buffList = new BBuffer * [3]; 327 for (int j = 0; j < 3; j++) buffList[j] = 0; 328 329 if ((status = mBuffers->GetBufferList(3, buffList)) == B_OK) 330 for (int j = 0; j < 3; j++) 331 if (buffList[j] != NULL) 332 { 333 mBufferMap[j] = (uint32) buffList[j]; 334 PROGRESS(" j = %d buffer = %08lx\n", j, mBufferMap[j]); 335 } 336 else 337 { 338 ERROR("VideoConsumer::CreateBuffers ERROR MAPPING RING BUFFER\n"); 339 return B_ERROR; 340 } 341 else 342 ERROR("VideoConsumer::CreateBuffers ERROR IN GET BUFFER LIST\n"); 343 344 FUNCTION("VideoConsumer::CreateBuffers - EXIT\n"); 345 return status; 346 } 347 348 //--------------------------------------------------------------- 349 350 void 351 VideoConsumer::DeleteBuffers() 352 { 353 FUNCTION("VideoConsumer::DeleteBuffers\n"); 354 355 if (mBuffers) 356 { 357 delete mBuffers; 358 mBuffers = NULL; 359 360 for (uint32 j = 0; j < 3; j++) 361 if (mBitmap[j]->IsValid()) 362 { 363 delete mBitmap[j]; 364 mBitmap[j] = NULL; 365 } 366 } 367 FUNCTION("VideoConsumer::DeleteBuffers - EXIT\n"); 368 } 369 370 //--------------------------------------------------------------- 371 372 status_t 373 VideoConsumer::Connected( 374 const media_source & producer, 375 const media_destination & where, 376 const media_format & with_format, 377 media_input * out_input) 378 { 379 FUNCTION("VideoConsumer::Connected\n"); 380 381 mIn.source = producer; 382 mIn.format = with_format; 383 mIn.node = Node(); 384 sprintf(mIn.name, "Video Consumer"); 385 *out_input = mIn; 386 387 uint32 user_data = 0; 388 int32 change_tag = 1; 389 if (CreateBuffers(with_format) == B_OK) 390 BBufferConsumer::SetOutputBuffersFor(producer, mDestination, 391 mBuffers, (void *)&user_data, &change_tag, true); 392 else 393 { 394 ERROR("VideoConsumer::Connected - COULDN'T CREATE BUFFERS\n"); 395 return B_ERROR; 396 } 397 398 mFtpBitmap = new BBitmap(BRect(0, 0, 320-1, 240-1), B_RGB32, false, false); 399 mConnectionActive = true; 400 401 FUNCTION("VideoConsumer::Connected - EXIT\n"); 402 return B_OK; 403 } 404 405 //--------------------------------------------------------------- 406 407 void 408 VideoConsumer::Disconnected( 409 const media_source & producer, 410 const media_destination & where) 411 { 412 FUNCTION("VideoConsumer::Disconnected\n"); 413 414 if (where == mIn.destination && producer == mIn.source) 415 { 416 // disconnect the connection 417 mIn.source = media_source::null; 418 delete mFtpBitmap; 419 mConnectionActive = false; 420 } 421 422 } 423 424 //--------------------------------------------------------------- 425 426 status_t 427 VideoConsumer::AcceptFormat( 428 const media_destination & dest, 429 media_format * format) 430 { 431 FUNCTION("VideoConsumer::AcceptFormat\n"); 432 433 if (dest != mIn.destination) 434 { 435 ERROR("VideoConsumer::AcceptFormat - BAD DESTINATION\n"); 436 return B_MEDIA_BAD_DESTINATION; 437 } 438 439 if (format->type == B_MEDIA_NO_TYPE) 440 format->type = B_MEDIA_RAW_VIDEO; 441 442 if (format->type != B_MEDIA_RAW_VIDEO) 443 { 444 ERROR("VideoConsumer::AcceptFormat - BAD FORMAT\n"); 445 return B_MEDIA_BAD_FORMAT; 446 } 447 448 if (format->u.raw_video.display.format != B_RGB32 && 449 format->u.raw_video.display.format != B_RGB16 && 450 format->u.raw_video.display.format != B_RGB15 && 451 format->u.raw_video.display.format != B_GRAY8 && 452 format->u.raw_video.display.format != media_raw_video_format::wildcard.display.format) 453 { 454 ERROR("AcceptFormat - not a format we know about!\n"); 455 return B_MEDIA_BAD_FORMAT; 456 } 457 458 if (format->u.raw_video.display.format == media_raw_video_format::wildcard.display.format) 459 { 460 format->u.raw_video.display.format = B_RGB16; 461 } 462 463 char format_string[256]; 464 string_for_format(*format, format_string, 256); 465 FUNCTION("VideoConsumer::AcceptFormat: %s\n", format_string); 466 467 return B_OK; 468 } 469 470 //--------------------------------------------------------------- 471 472 status_t 473 VideoConsumer::GetNextInput( 474 int32 * cookie, 475 media_input * out_input) 476 { 477 FUNCTION("VideoConsumer::GetNextInput\n"); 478 479 // custom build a destination for this connection 480 // put connection number in id 481 482 if (*cookie < 1) 483 { 484 mIn.node = Node(); 485 mIn.destination.id = *cookie; 486 sprintf(mIn.name, "Video Consumer"); 487 *out_input = mIn; 488 (*cookie)++; 489 return B_OK; 490 } 491 else 492 { 493 ERROR("VideoConsumer::GetNextInput - - BAD INDEX\n"); 494 return B_MEDIA_BAD_DESTINATION; 495 } 496 } 497 498 //--------------------------------------------------------------- 499 500 void 501 VideoConsumer::DisposeInputCookie(int32 /*cookie*/) 502 { 503 } 504 505 //--------------------------------------------------------------- 506 507 status_t 508 VideoConsumer::GetLatencyFor( 509 const media_destination &for_whom, 510 bigtime_t * out_latency, 511 media_node_id * out_timesource) 512 { 513 FUNCTION("VideoConsumer::GetLatencyFor\n"); 514 515 if (for_whom != mIn.destination) 516 return B_MEDIA_BAD_DESTINATION; 517 518 *out_latency = mMyLatency; 519 *out_timesource = TimeSource()->ID(); 520 return B_OK; 521 } 522 523 524 //--------------------------------------------------------------- 525 526 status_t 527 VideoConsumer::FormatChanged( 528 const media_source & producer, 529 const media_destination & consumer, 530 int32 from_change_count, 531 const media_format &format) 532 { 533 FUNCTION("VideoConsumer::FormatChanged\n"); 534 535 if (consumer != mIn.destination) 536 return B_MEDIA_BAD_DESTINATION; 537 538 if (producer != mIn.source) 539 return B_MEDIA_BAD_SOURCE; 540 541 mIn.format = format; 542 543 return CreateBuffers(format); 544 } 545 546 //--------------------------------------------------------------- 547 548 void 549 VideoConsumer::HandleEvent( 550 const media_timed_event *event, 551 bigtime_t lateness, 552 bool realTimeEvent) 553 554 { 555 LOOP("VideoConsumer::HandleEvent\n"); 556 557 BBuffer *buffer; 558 559 switch (event->type) 560 { 561 case BTimedEventQueue::B_START: 562 PROGRESS("VideoConsumer::HandleEvent - START\n"); 563 break; 564 case BTimedEventQueue::B_STOP: 565 PROGRESS("VideoConsumer::HandleEvent - STOP\n"); 566 EventQueue()->FlushEvents(event->event_time, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); 567 break; 568 case BTimedEventQueue::B_USER_EVENT: 569 PROGRESS("VideoConsumer::HandleEvent - USER EVENT\n"); 570 if (RunState() == B_STARTED) 571 { 572 mTimeToFtp = true; 573 PROGRESS("Pushing user event for %.4f, time now %.4f\n", (event->event_time + mRate)/M1, event->event_time/M1); 574 media_timed_event newEvent(event->event_time + mRate, BTimedEventQueue::B_USER_EVENT); 575 EventQueue()->AddEvent(newEvent); 576 } 577 break; 578 case BTimedEventQueue::B_HANDLE_BUFFER: 579 LOOP("VideoConsumer::HandleEvent - HANDLE BUFFER\n"); 580 buffer = (BBuffer *) event->pointer; 581 if (RunState() == B_STARTED && mConnectionActive) 582 { 583 // see if this is one of our buffers 584 uint32 index = 0; 585 mOurBuffers = true; 586 while(index < 3) 587 if ((uint32)buffer == mBufferMap[index]) 588 break; 589 else 590 index++; 591 592 if (index == 3) 593 { 594 // no, buffers belong to consumer 595 mOurBuffers = false; 596 index = 0; 597 } 598 599 if (mFtpComplete && mTimeToFtp) 600 { 601 PROGRESS("VidConsumer::HandleEvent - SPAWNING FTP THREAD\n"); 602 mTimeToFtp = false; 603 mFtpComplete = false; 604 memcpy(mFtpBitmap->Bits(), buffer->Data(),mFtpBitmap->BitsLength()); 605 mFtpThread = spawn_thread(FtpRun, "Video Window Ftp", B_NORMAL_PRIORITY, this); 606 resume_thread(mFtpThread); 607 } 608 609 if ( (RunMode() == B_OFFLINE) || 610 ((TimeSource()->Now() > (buffer->Header()->start_time - JITTER)) && 611 (TimeSource()->Now() < (buffer->Header()->start_time + JITTER))) ) 612 { 613 if (!mOurBuffers) 614 // not our buffers, so we need to copy 615 memcpy(mBitmap[index]->Bits(), buffer->Data(),mBitmap[index]->BitsLength()); 616 617 if (mWindow->Lock()) 618 { 619 uint32 flags; 620 if ((mBitmap[index]->ColorSpace() == B_GRAY8) && 621 !bitmaps_support_space(mBitmap[index]->ColorSpace(), &flags)) 622 { 623 // handle mapping of GRAY8 until app server knows how 624 uint32 *start = (uint32 *)mBitmap[index]->Bits(); 625 int32 size = mBitmap[index]->BitsLength(); 626 uint32 *end = start + size/4; 627 for (uint32 *p = start; p < end; p++) 628 *p = (*p >> 3) & 0x1f1f1f1f; 629 } 630 631 mView->DrawBitmap(mBitmap[index]); 632 mWindow->Unlock(); 633 } 634 } 635 else 636 PROGRESS("VidConsumer::HandleEvent - DROPPED FRAME\n"); 637 buffer->Recycle(); 638 } 639 else 640 buffer->Recycle(); 641 break; 642 default: 643 ERROR("VideoConsumer::HandleEvent - BAD EVENT\n"); 644 break; 645 } 646 } 647 648 //--------------------------------------------------------------- 649 650 status_t 651 VideoConsumer::FtpRun(void * data) 652 { 653 FUNCTION("VideoConsumer::FtpRun\n"); 654 655 ((VideoConsumer *)data)->FtpThread(); 656 657 return 0; 658 } 659 660 //--------------------------------------------------------------- 661 662 663 void 664 VideoConsumer::FtpThread() 665 { 666 FUNCTION("VideoConsumer::FtpThread\n"); 667 668 if (LocalSave(mFileNameText, mFtpBitmap) == B_OK) 669 FtpSave(mFileNameText); 670 671 #if 0 672 // save a small version, too 673 BBitmap * b = new BBitmap(BRect(0,0,159,119), B_RGB32, true, false); 674 BView * v = new BView(BRect(0,0,159,119), "SmallView 1", 0, B_WILL_DRAW); 675 b->AddChild(v); 676 677 b->Lock(); 678 v->DrawBitmap(mFtpBitmap, v->Frame()); 679 v->Sync(); 680 b->Unlock(); 681 682 if (LocalSave("small.jpg", b) == B_OK) 683 FtpSave("small.jpg"); 684 685 delete b; 686 #endif 687 688 mFtpComplete = true; 689 } 690 691 //--------------------------------------------------------------- 692 693 void 694 VideoConsumer::UpdateFtpStatus(char *status) 695 { 696 printf("FTP STATUS: %s\n",status); 697 if (mView->Window()->Lock()) 698 { 699 mStatusLine->SetText(status); 700 mView->Window()->Unlock(); 701 } 702 } 703 704 //--------------------------------------------------------------- 705 706 status_t 707 VideoConsumer::LocalSave(char *filename, BBitmap *bitmap) 708 { 709 BFile *output; 710 711 UpdateFtpStatus("Capturing Image ..."); 712 713 /* save a local copy of the image in the requested format */ 714 output =new BFile(); 715 if (output->SetTo(filename, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE) == B_NO_ERROR) 716 { 717 BBitmapStream input(bitmap); 718 status_t err = BTranslatorRoster::Default()->Translate(&input, NULL, NULL, output, mImageFormat); 719 if (err == B_OK) 720 { 721 err = SetFileType(output, mTranslator, mImageFormat); 722 if (err != B_OK) 723 UpdateFtpStatus("Error setting type of output file"); 724 } 725 else 726 { 727 UpdateFtpStatus("Error writing output file"); 728 } 729 input.DetachBitmap(&bitmap); 730 output->Unset(); 731 delete output; 732 return B_OK; 733 } 734 else 735 { 736 UpdateFtpStatus("Error creating output file"); 737 return B_ERROR; 738 } 739 } 740 741 //--------------------------------------------------------------- 742 743 status_t 744 VideoConsumer::FtpSave(char *filename) 745 { 746 FtpClient ftp; 747 748 /* ftp the local file to our web site */ 749 ftp.setPassive(mPassiveFtp); 750 751 UpdateFtpStatus("Logging in ..."); 752 if (ftp.connect((string)mServerText, (string)mLoginText, (string)mPasswordText)) // connect to server 753 { 754 UpdateFtpStatus("Connected ..."); 755 if (ftp.cd((string)mDirectoryText)) 756 { // cd to the desired directory 757 UpdateFtpStatus("Transmitting ..."); 758 if (ftp.putFile((string)filename, (string)"temp")) // send the file to the server 759 { 760 UpdateFtpStatus("Renaming ..."); 761 if (ftp.moveFile((string)"temp",(string)filename)) // change to the desired name 762 { 763 uint32 time = real_time_clock(); 764 char s[80]; 765 strcpy(s,"Last Capture: "); 766 strcat(s,ctime((const long *)&time)); 767 s[strlen(s)-1] = 0; 768 UpdateFtpStatus(s); 769 return B_OK; 770 } else UpdateFtpStatus("Rename failed"); 771 } else UpdateFtpStatus("File transmission failed"); 772 } else UpdateFtpStatus("Couldn't find requested directory on server"); 773 } else UpdateFtpStatus("Server login failed"); 774 return B_ERROR; 775 } 776 777 //--------------------------------------------------------------- 778 779 status_t 780 SetFileType(BFile * file, int32 translator, uint32 type) 781 { 782 translation_format * formats; 783 int32 count; 784 785 status_t err = BTranslatorRoster::Default()->GetOutputFormats(translator, (const translation_format **) &formats, &count); 786 if (err < B_OK) return err; 787 const char * mime = NULL; 788 for (int ix=0; ix<count; ix++) 789 { 790 if (formats[ix].type == type) 791 { 792 mime = formats[ix].MIME; 793 break; 794 } 795 } 796 if (mime == NULL) 797 { /* this should not happen, but being defensive might be prudent */ 798 return B_ERROR; 799 } 800 801 /* use BNodeInfo to set the file type */ 802 BNodeInfo ninfo(file); 803 return ninfo.SetType(mime); 804 } 805 806 //--------------------------------------------------------------- 807 808 809