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