1 /* 2 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de> 3 * Copyright 2002-2004, Marcus Overhagen <marcus@overhagen.de> 4 * All rights reserved. Distributed under the terms of the MIT license. 5 */ 6 7 #include <MediaFile.h> 8 9 #include <new> 10 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <File.h> 15 #include <MediaTrack.h> 16 #include <Url.h> 17 18 #include "MediaDebug.h" 19 20 #include "MediaExtractor.h" 21 #include "MediaStreamer.h" 22 #include "MediaWriter.h" 23 24 25 BMediaFile::BMediaFile(const entry_ref* ref) 26 { 27 CALLED(); 28 _Init(); 29 fDeleteSource = true; 30 _InitReader(new(std::nothrow) BFile(ref, O_RDONLY)); 31 } 32 33 34 BMediaFile::BMediaFile(BDataIO* source) 35 { 36 CALLED(); 37 _Init(); 38 _InitReader(source); 39 } 40 41 42 BMediaFile::BMediaFile(const entry_ref* ref, int32 flags) 43 { 44 CALLED(); 45 _Init(); 46 fDeleteSource = true; 47 _InitReader(new(std::nothrow) BFile(ref, O_RDONLY), NULL, flags); 48 } 49 50 51 BMediaFile::BMediaFile(BDataIO* source, int32 flags) 52 { 53 CALLED(); 54 _Init(); 55 _InitReader(source, NULL, flags); 56 } 57 58 59 BMediaFile::BMediaFile(const entry_ref* ref, const media_file_format* mfi, 60 int32 flags) 61 { 62 CALLED(); 63 _Init(); 64 fDeleteSource = true; 65 _InitWriter(new(std::nothrow) BFile(ref, B_CREATE_FILE | B_ERASE_FILE 66 | B_WRITE_ONLY), NULL, mfi, flags); 67 } 68 69 70 BMediaFile::BMediaFile(BDataIO* destination, const media_file_format* mfi, 71 int32 flags) 72 { 73 CALLED(); 74 _Init(); 75 _InitWriter(destination, NULL, mfi, flags); 76 } 77 78 79 // File will be set later by SetTo() 80 BMediaFile::BMediaFile(const media_file_format* mfi, int32 flags) 81 { 82 debugger("BMediaFile::BMediaFile not implemented"); 83 } 84 85 86 BMediaFile::BMediaFile(const BUrl& url) 87 { 88 CALLED(); 89 _Init(); 90 fDeleteSource = true; 91 _InitReader(NULL, &url); 92 } 93 94 95 BMediaFile::BMediaFile(const BUrl& url, int32 flags) 96 { 97 CALLED(); 98 _Init(); 99 fDeleteSource = true; 100 _InitReader(NULL, &url, flags); 101 } 102 103 104 BMediaFile::BMediaFile(const BUrl& destination, const media_file_format* mfi, 105 int32 flags) 106 { 107 CALLED(); 108 _Init(); 109 fDeleteSource = true; 110 _InitWriter(NULL, &destination, mfi, flags); 111 // TODO: Implement streaming server support, it's 112 // a pretty complex thing compared to client mode 113 // and will require to expand the current BMediaFile 114 // design to be aware of it. 115 } 116 117 118 status_t 119 BMediaFile::SetTo(const entry_ref* ref) 120 { 121 CALLED(); 122 123 if (ref == NULL) 124 return B_BAD_VALUE; 125 126 _UnInit(); 127 fDeleteSource = true; 128 _InitReader(new(std::nothrow) BFile(ref, O_RDONLY)); 129 130 return fErr; 131 } 132 133 134 status_t 135 BMediaFile::SetTo(BDataIO* destination) 136 { 137 CALLED(); 138 139 if (destination == NULL) 140 return B_BAD_VALUE; 141 142 _UnInit(); 143 _InitReader(destination); 144 145 return fErr; 146 } 147 148 149 status_t 150 BMediaFile::SetTo(const BUrl& url) 151 { 152 CALLED(); 153 154 _UnInit(); 155 _InitReader(NULL, &url); 156 157 return fErr; 158 } 159 160 161 BMediaFile::~BMediaFile() 162 { 163 CALLED(); 164 165 _UnInit(); 166 } 167 168 169 status_t 170 BMediaFile::InitCheck() const 171 { 172 CALLED(); 173 return fErr; 174 } 175 176 177 status_t 178 BMediaFile::GetFileFormatInfo(media_file_format* mfi) const 179 { 180 CALLED(); 181 if (mfi == NULL) 182 return B_BAD_VALUE; 183 if (fErr) 184 return B_ERROR; 185 *mfi = fMFI; 186 return B_OK; 187 } 188 189 190 status_t 191 BMediaFile::GetMetaData(BMessage* _data) const 192 { 193 if (fExtractor == NULL) 194 return B_NO_INIT; 195 if (_data == NULL) 196 return B_BAD_VALUE; 197 198 _data->MakeEmpty(); 199 200 BMetaData* metaData = NULL; 201 if (fExtractor->GetMetaData(metaData) == B_OK) { 202 *_data = *metaData->Message(); 203 return B_OK; 204 } 205 206 return B_ERROR; 207 } 208 209 210 const char* 211 BMediaFile::Copyright() const 212 { 213 BMetaData data; 214 BString copyright; 215 if (fExtractor->GetMetaData(&data) == B_OK) 216 data.GetString(kCopyright, ©right); 217 218 return copyright.String(); 219 } 220 221 222 int32 223 BMediaFile::CountTracks() const 224 { 225 return fTrackNum; 226 } 227 228 229 // Can be called multiple times with the same index. You must call 230 // ReleaseTrack() when you're done with a track. 231 BMediaTrack* 232 BMediaFile::TrackAt(int32 index) 233 { 234 CALLED(); 235 if (fTrackList == NULL || fExtractor == NULL 236 || index < 0 || index >= fTrackNum) { 237 return NULL; 238 } 239 if (fTrackList[index] == NULL) { 240 TRACE("BMediaFile::TrackAt, creating new track for index %" 241 B_PRId32 "\n", index); 242 fTrackList[index] = new(std::nothrow) BMediaTrack(fExtractor, index); 243 TRACE("BMediaFile::TrackAt, new track is %p\n", fTrackList[index]); 244 } 245 return fTrackList[index]; 246 } 247 248 249 // Release the resource used by a given BMediaTrack object, to reduce 250 // the memory usage of your application. The specific 'track' object 251 // can no longer be used, but you can create another one by calling 252 // TrackAt() with the same track index. 253 status_t 254 BMediaFile::ReleaseTrack(BMediaTrack* track) 255 { 256 CALLED(); 257 if (!fTrackList || !track) 258 return B_ERROR; 259 for (int32 i = 0; i < fTrackNum; i++) { 260 if (fTrackList[i] == track) { 261 TRACE("BMediaFile::ReleaseTrack, releasing track %p with index " 262 "%" B_PRId32 "\n", track, i); 263 delete track; 264 fTrackList[i] = NULL; 265 return B_OK; 266 } 267 } 268 fprintf(stderr, "BMediaFile::ReleaseTrack track %p not found\n", track); 269 return B_ERROR; 270 } 271 272 273 status_t 274 BMediaFile::ReleaseAllTracks() 275 { 276 CALLED(); 277 if (!fTrackList) 278 return B_ERROR; 279 for (int32 i = 0; i < fTrackNum; i++) { 280 if (fTrackList[i]) { 281 TRACE("BMediaFile::ReleaseAllTracks, releasing track %p with " 282 "index %" B_PRId32 "\n", fTrackList[i], i); 283 delete fTrackList[i]; 284 fTrackList[i] = NULL; 285 } 286 } 287 return B_OK; 288 } 289 290 291 // Create and add a track to the media file 292 BMediaTrack* 293 BMediaFile::CreateTrack(media_format* mediaFormat, 294 const media_codec_info* codecInfo, uint32 flags) 295 { 296 if (mediaFormat == NULL) 297 return NULL; 298 299 // NOTE: It is allowed to pass NULL for codecInfo. In that case, the 300 // track won't have an Encoder and you can only use WriteChunk() with 301 // already encoded data. 302 303 // Make room for the new track. 304 BMediaTrack** trackList = (BMediaTrack**)realloc(fTrackList, 305 (fTrackNum + 1) * sizeof(BMediaTrack*)); 306 if (trackList == NULL) 307 return NULL; 308 309 int32 streamIndex = fTrackNum; 310 fTrackList = trackList; 311 fTrackNum += 1; 312 313 BMediaTrack* track = new(std::nothrow) BMediaTrack(fWriter, streamIndex, 314 mediaFormat, codecInfo); 315 316 fTrackList[streamIndex] = track; 317 318 return track; 319 } 320 321 322 // Create and add a raw track to the media file (it has no encoder) 323 BMediaTrack* 324 BMediaFile::CreateTrack(media_format* mf, uint32 flags) 325 { 326 return CreateTrack(mf, NULL, flags); 327 } 328 329 330 // For BeOS R5 compatibility 331 extern "C" BMediaTrack* 332 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info( 333 BMediaFile* self, media_format* mf, const media_codec_info* mci); 334 BMediaTrack* 335 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(BMediaFile* self, 336 media_format* mf, const media_codec_info* mci) 337 { 338 return self->CreateTrack(mf, mci, 0); 339 } 340 341 342 // For BeOS R5 compatibility 343 extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format( 344 BMediaFile* self, media_format* mf); 345 BMediaTrack* 346 CreateTrack__10BMediaFileP12media_format(BMediaFile* self, media_format* mf) 347 { 348 return self->CreateTrack(mf, NULL, 0); 349 } 350 351 352 // Lets you set the copyright info for the entire file 353 status_t 354 BMediaFile::AddCopyright(const char* copyright) 355 { 356 if (fWriter == NULL) 357 return B_NO_INIT; 358 359 BMetaData* data = new BMetaData(); 360 data->SetString(kCopyright, copyright); 361 return fWriter->SetMetaData(data); 362 } 363 364 365 // Call this to add user-defined chunks to a file (if they're supported) 366 status_t 367 BMediaFile::AddChunk(int32 type, const void* data, size_t size) 368 { 369 UNIMPLEMENTED(); 370 return B_OK; 371 } 372 373 374 // After you have added all the tracks you want, call this 375 status_t 376 BMediaFile::CommitHeader() 377 { 378 if (fWriter == NULL) 379 return B_NO_INIT; 380 381 return fWriter->CommitHeader(); 382 } 383 384 385 // After you have written all the data to the track objects, call this 386 status_t 387 BMediaFile::CloseFile() 388 { 389 if (fWriter == NULL) 390 return B_NO_INIT; 391 392 return fWriter->Close(); 393 } 394 395 // This is for controlling file format parameters 396 397 // returns a copy of the parameter web 398 status_t 399 BMediaFile::GetParameterWeb(BParameterWeb** outWeb) 400 { 401 UNIMPLEMENTED(); 402 return B_ERROR; 403 } 404 405 406 // deprecated BeOS R5 API 407 BParameterWeb* 408 BMediaFile::Web() 409 { 410 UNIMPLEMENTED(); 411 return 0; 412 } 413 414 415 status_t 416 BMediaFile::GetParameterValue(int32 id, void* value, size_t* size) 417 { 418 UNIMPLEMENTED(); 419 return B_OK; 420 } 421 422 423 status_t 424 BMediaFile::SetParameterValue(int32 id, const void* value, size_t size) 425 { 426 UNIMPLEMENTED(); 427 return B_OK; 428 } 429 430 431 BView* 432 BMediaFile::GetParameterView() 433 { 434 UNIMPLEMENTED(); 435 return 0; 436 } 437 438 439 status_t 440 BMediaFile::Perform(int32 selector, void* data) 441 { 442 UNIMPLEMENTED(); 443 return B_OK; 444 } 445 446 447 status_t 448 BMediaFile::ControlFile(int32 selector, void* ioData, size_t size) 449 { 450 UNIMPLEMENTED(); 451 return B_ERROR; 452 } 453 454 455 // #pragma mark - private 456 457 458 void 459 BMediaFile::_Init() 460 { 461 CALLED(); 462 463 fSource = NULL; 464 fTrackNum = 0; 465 fTrackList = NULL; 466 fExtractor = NULL; 467 fStreamer = NULL; 468 fWriter = NULL; 469 fWriterID = 0; 470 fErr = B_OK; 471 fDeleteSource = false; 472 473 // not used so far: 474 fEncoderMgr = NULL; 475 fWriterMgr = NULL; 476 fFileClosed = false; 477 } 478 479 480 void 481 BMediaFile::_UnInit() 482 { 483 ReleaseAllTracks(); 484 free(fTrackList); 485 fTrackList = NULL; 486 fTrackNum = 0; 487 488 // Tells the extractor to stop its asynchronous processing 489 // before deleting its source 490 if (fExtractor != NULL) 491 fExtractor->StopProcessing(); 492 493 if (fDeleteSource) { 494 delete fSource; 495 fSource = NULL; 496 fDeleteSource = false; 497 } 498 499 // Deleting the extractor or writer can cause unloading of the plugins. 500 // The source must be deleted before that, because it can come from a 501 // plugin (for example the http_streamer) 502 delete fExtractor; 503 fExtractor = NULL; 504 delete fWriter; 505 fWriter = NULL; 506 delete fStreamer; 507 fStreamer = NULL; 508 } 509 510 511 void 512 BMediaFile::_InitReader(BDataIO* source, const BUrl* url, int32 flags) 513 { 514 CALLED(); 515 516 if (source == NULL && url == NULL) { 517 fErr = B_NO_MEMORY; 518 return; 519 } 520 521 if (source == NULL) 522 _InitStreamer(*url, &source); 523 else if (BFile* file = dynamic_cast<BFile*>(source)) 524 fErr = file->InitCheck(); 525 526 if (fErr != B_OK) 527 return; 528 529 fExtractor = new(std::nothrow) MediaExtractor(source, flags); 530 531 if (fExtractor == NULL) 532 fErr = B_NO_MEMORY; 533 else 534 fErr = fExtractor->InitCheck(); 535 536 if (fErr != B_OK) 537 return; 538 539 // Get the actual source from the extractor 540 fSource = fExtractor->Source(); 541 542 fExtractor->GetFileFormatInfo(&fMFI); 543 fTrackNum = fExtractor->CountStreams(); 544 fTrackList = (BMediaTrack**)malloc(fTrackNum * sizeof(BMediaTrack*)); 545 if (fTrackList == NULL) { 546 fErr = B_NO_MEMORY; 547 return; 548 } 549 memset(fTrackList, 0, fTrackNum * sizeof(BMediaTrack*)); 550 } 551 552 553 void 554 BMediaFile::_InitWriter(BDataIO* target, const BUrl* url, 555 const media_file_format* fileFormat, int32 flags) 556 { 557 CALLED(); 558 559 if (fileFormat == NULL) { 560 fErr = B_BAD_VALUE; 561 return; 562 } 563 564 if (target == NULL && url == NULL) { 565 fErr = B_NO_MEMORY; 566 return; 567 } 568 569 fMFI = *fileFormat; 570 571 if (target == NULL) { 572 _InitStreamer(*url, &target); 573 if (fErr != B_OK) 574 return; 575 } 576 577 fWriter = new(std::nothrow) MediaWriter(target, fMFI); 578 579 if (fWriter == NULL) 580 fErr = B_NO_MEMORY; 581 else 582 fErr = fWriter->InitCheck(); 583 if (fErr != B_OK) 584 return; 585 586 // Get the actual source from the writer 587 fSource = fWriter->Target(); 588 fTrackNum = 0; 589 } 590 591 592 void 593 BMediaFile::_InitStreamer(const BUrl& url, BDataIO** adapter) 594 { 595 if (fStreamer != NULL) 596 delete fStreamer; 597 598 TRACE(url.UrlString()); 599 600 fStreamer = new(std::nothrow) MediaStreamer(url); 601 if (fStreamer == NULL) { 602 fErr = B_NO_MEMORY; 603 return; 604 } 605 606 fErr = fStreamer->CreateAdapter(adapter); 607 } 608 609 /* 610 //unimplemented 611 BMediaFile::BMediaFile(); 612 BMediaFile::BMediaFile(const BMediaFile&); 613 BMediaFile::BMediaFile& operator=(const BMediaFile&); 614 */ 615 616 status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; } 617 status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; } 618 status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; } 619 status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; } 620 status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; } 621 status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; } 622 status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; } 623 status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; } 624 status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; } 625 status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; } 626 status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; } 627 status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; } 628 status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; } 629 status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; } 630 status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; } 631 status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; } 632 status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; } 633 status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; } 634 status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; } 635 status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; } 636 status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; } 637 status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; } 638 status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; } 639 status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; } 640 status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; } 641 status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; } 642 status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; } 643 status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; } 644 status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; } 645 status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; } 646 status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; } 647 status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; } 648 status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; } 649 status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; } 650 status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; } 651 status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; } 652 status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; } 653 status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; } 654 status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; } 655 status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; } 656 status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; } 657 status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; } 658 status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; } 659 status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; } 660 status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; } 661 status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; } 662 status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; } 663 status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; } 664 665