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 return fExtractor->GetMetaData(_data); 201 } 202 203 204 const char* 205 BMediaFile::Copyright() const 206 { 207 return fExtractor->Copyright(); 208 } 209 210 211 int32 212 BMediaFile::CountTracks() const 213 { 214 return fTrackNum; 215 } 216 217 218 // Can be called multiple times with the same index. You must call 219 // ReleaseTrack() when you're done with a track. 220 BMediaTrack* 221 BMediaFile::TrackAt(int32 index) 222 { 223 CALLED(); 224 if (fTrackList == NULL || fExtractor == NULL 225 || index < 0 || index >= fTrackNum) { 226 return NULL; 227 } 228 if (fTrackList[index] == NULL) { 229 TRACE("BMediaFile::TrackAt, creating new track for index %" 230 B_PRId32 "\n", index); 231 fTrackList[index] = new(std::nothrow) BMediaTrack(fExtractor, index); 232 TRACE("BMediaFile::TrackAt, new track is %p\n", fTrackList[index]); 233 } 234 return fTrackList[index]; 235 } 236 237 238 // Release the resource used by a given BMediaTrack object, to reduce 239 // the memory usage of your application. The specific 'track' object 240 // can no longer be used, but you can create another one by calling 241 // TrackAt() with the same track index. 242 status_t 243 BMediaFile::ReleaseTrack(BMediaTrack* track) 244 { 245 CALLED(); 246 if (!fTrackList || !track) 247 return B_ERROR; 248 for (int32 i = 0; i < fTrackNum; i++) { 249 if (fTrackList[i] == track) { 250 TRACE("BMediaFile::ReleaseTrack, releasing track %p with index " 251 "%" B_PRId32 "\n", track, i); 252 delete track; 253 fTrackList[i] = NULL; 254 return B_OK; 255 } 256 } 257 fprintf(stderr, "BMediaFile::ReleaseTrack track %p not found\n", track); 258 return B_ERROR; 259 } 260 261 262 status_t 263 BMediaFile::ReleaseAllTracks() 264 { 265 CALLED(); 266 if (!fTrackList) 267 return B_ERROR; 268 for (int32 i = 0; i < fTrackNum; i++) { 269 if (fTrackList[i]) { 270 TRACE("BMediaFile::ReleaseAllTracks, releasing track %p with " 271 "index %" B_PRId32 "\n", fTrackList[i], i); 272 delete fTrackList[i]; 273 fTrackList[i] = NULL; 274 } 275 } 276 return B_OK; 277 } 278 279 280 // Create and add a track to the media file 281 BMediaTrack* 282 BMediaFile::CreateTrack(media_format* mediaFormat, 283 const media_codec_info* codecInfo, uint32 flags) 284 { 285 if (mediaFormat == NULL) 286 return NULL; 287 288 // NOTE: It is allowed to pass NULL for codecInfo. In that case, the 289 // track won't have an Encoder and you can only use WriteChunk() with 290 // already encoded data. 291 292 // Make room for the new track. 293 BMediaTrack** trackList = (BMediaTrack**)realloc(fTrackList, 294 (fTrackNum + 1) * sizeof(BMediaTrack*)); 295 if (trackList == NULL) 296 return NULL; 297 298 int32 streamIndex = fTrackNum; 299 fTrackList = trackList; 300 fTrackNum += 1; 301 302 BMediaTrack* track = new(std::nothrow) BMediaTrack(fWriter, streamIndex, 303 mediaFormat, codecInfo); 304 305 fTrackList[streamIndex] = track; 306 307 return track; 308 } 309 310 311 // Create and add a raw track to the media file (it has no encoder) 312 BMediaTrack* 313 BMediaFile::CreateTrack(media_format* mf, uint32 flags) 314 { 315 return CreateTrack(mf, NULL, flags); 316 } 317 318 319 // For BeOS R5 compatibility 320 extern "C" BMediaTrack* 321 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info( 322 BMediaFile* self, media_format* mf, const media_codec_info* mci); 323 BMediaTrack* 324 CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(BMediaFile* self, 325 media_format* mf, const media_codec_info* mci) 326 { 327 return self->CreateTrack(mf, mci, 0); 328 } 329 330 331 // For BeOS R5 compatibility 332 extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format( 333 BMediaFile* self, media_format* mf); 334 BMediaTrack* 335 CreateTrack__10BMediaFileP12media_format(BMediaFile* self, media_format* mf) 336 { 337 return self->CreateTrack(mf, NULL, 0); 338 } 339 340 341 // Lets you set the copyright info for the entire file 342 status_t 343 BMediaFile::AddCopyright(const char* copyright) 344 { 345 if (fWriter == NULL) 346 return B_NO_INIT; 347 348 return fWriter->SetCopyright(copyright); 349 } 350 351 352 // Call this to add user-defined chunks to a file (if they're supported) 353 status_t 354 BMediaFile::AddChunk(int32 type, const void* data, size_t size) 355 { 356 UNIMPLEMENTED(); 357 return B_OK; 358 } 359 360 361 // After you have added all the tracks you want, call this 362 status_t 363 BMediaFile::CommitHeader() 364 { 365 if (fWriter == NULL) 366 return B_NO_INIT; 367 368 return fWriter->CommitHeader(); 369 } 370 371 372 // After you have written all the data to the track objects, call this 373 status_t 374 BMediaFile::CloseFile() 375 { 376 if (fWriter == NULL) 377 return B_NO_INIT; 378 379 return fWriter->Close(); 380 } 381 382 // This is for controlling file format parameters 383 384 // returns a copy of the parameter web 385 status_t 386 BMediaFile::GetParameterWeb(BParameterWeb** outWeb) 387 { 388 UNIMPLEMENTED(); 389 return B_ERROR; 390 } 391 392 393 // deprecated BeOS R5 API 394 BParameterWeb* 395 BMediaFile::Web() 396 { 397 UNIMPLEMENTED(); 398 return 0; 399 } 400 401 402 status_t 403 BMediaFile::GetParameterValue(int32 id, void* value, size_t* size) 404 { 405 UNIMPLEMENTED(); 406 return B_OK; 407 } 408 409 410 status_t 411 BMediaFile::SetParameterValue(int32 id, const void* value, size_t size) 412 { 413 UNIMPLEMENTED(); 414 return B_OK; 415 } 416 417 418 BView* 419 BMediaFile::GetParameterView() 420 { 421 UNIMPLEMENTED(); 422 return 0; 423 } 424 425 426 status_t 427 BMediaFile::Perform(int32 selector, void* data) 428 { 429 UNIMPLEMENTED(); 430 return B_OK; 431 } 432 433 434 status_t 435 BMediaFile::ControlFile(int32 selector, void* ioData, size_t size) 436 { 437 UNIMPLEMENTED(); 438 return B_ERROR; 439 } 440 441 442 // #pragma mark - private 443 444 445 void 446 BMediaFile::_Init() 447 { 448 CALLED(); 449 450 fSource = NULL; 451 fTrackNum = 0; 452 fTrackList = NULL; 453 fExtractor = NULL; 454 fStreamer = NULL; 455 fWriter = NULL; 456 fWriterID = 0; 457 fErr = B_OK; 458 fDeleteSource = false; 459 460 // not used so far: 461 fEncoderMgr = NULL; 462 fWriterMgr = NULL; 463 fFileClosed = false; 464 } 465 466 467 void 468 BMediaFile::_UnInit() 469 { 470 ReleaseAllTracks(); 471 free(fTrackList); 472 fTrackList = NULL; 473 fTrackNum = 0; 474 475 // Tells the extractor to stop its asynchronous processing 476 // before deleting its source 477 if (fExtractor != NULL) 478 fExtractor->StopProcessing(); 479 480 if (fDeleteSource) { 481 delete fSource; 482 fDeleteSource = false; 483 } 484 fSource = NULL; 485 486 // Deleting the extractor or writer can cause unloading of the plugins. 487 // The source must be deleted before that, because it can come from a 488 // plugin (for example the http_streamer) 489 delete fExtractor; 490 fExtractor = NULL; 491 delete fWriter; 492 fWriter = NULL; 493 delete fStreamer; 494 fStreamer = NULL; 495 } 496 497 498 void 499 BMediaFile::_InitReader(BDataIO* source, const BUrl* url, int32 flags) 500 { 501 CALLED(); 502 503 if (source == NULL && url == NULL) { 504 fErr = B_NO_MEMORY; 505 return; 506 } 507 508 if (source == NULL) 509 _InitStreamer(*url, &source); 510 else if (BFile* file = dynamic_cast<BFile*>(source)) 511 fErr = file->InitCheck(); 512 513 if (fErr != B_OK) 514 return; 515 516 fExtractor = new(std::nothrow) MediaExtractor(source, flags); 517 518 if (fExtractor == NULL) 519 fErr = B_NO_MEMORY; 520 else 521 fErr = fExtractor->InitCheck(); 522 523 if (fErr != B_OK) 524 return; 525 526 fSource = source; 527 528 fExtractor->GetFileFormatInfo(&fMFI); 529 fTrackNum = fExtractor->StreamCount(); 530 fTrackList = (BMediaTrack**)malloc(fTrackNum * sizeof(BMediaTrack*)); 531 if (fTrackList == NULL) { 532 fErr = B_NO_MEMORY; 533 return; 534 } 535 memset(fTrackList, 0, fTrackNum * sizeof(BMediaTrack*)); 536 } 537 538 539 void 540 BMediaFile::_InitWriter(BDataIO* target, const BUrl* url, 541 const media_file_format* fileFormat, int32 flags) 542 { 543 CALLED(); 544 545 if (fileFormat == NULL) { 546 fErr = B_BAD_VALUE; 547 return; 548 } 549 550 if (target == NULL && url == NULL) { 551 fErr = B_NO_MEMORY; 552 return; 553 } 554 555 fMFI = *fileFormat; 556 557 if (target == NULL) { 558 _InitStreamer(*url, &target); 559 if (fErr != B_OK) 560 return; 561 } 562 563 fWriter = new(std::nothrow) MediaWriter(target, fMFI); 564 565 if (fWriter == NULL) 566 fErr = B_NO_MEMORY; 567 else 568 fErr = fWriter->InitCheck(); 569 if (fErr != B_OK) 570 return; 571 572 // Get the actual source from the writer 573 fSource = fWriter->Target(); 574 fTrackNum = 0; 575 } 576 577 578 void 579 BMediaFile::_InitStreamer(const BUrl& url, BDataIO** adapter) 580 { 581 if (fStreamer != NULL) 582 delete fStreamer; 583 584 TRACE(url.UrlString()); 585 586 fStreamer = new(std::nothrow) MediaStreamer(url); 587 if (fStreamer == NULL) { 588 fErr = B_NO_MEMORY; 589 return; 590 } 591 592 fErr = fStreamer->CreateAdapter(adapter); 593 } 594 595 /* 596 //unimplemented 597 BMediaFile::BMediaFile(); 598 BMediaFile::BMediaFile(const BMediaFile&); 599 BMediaFile::BMediaFile& operator=(const BMediaFile&); 600 */ 601 602 status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; } 603 status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; } 604 status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; } 605 status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; } 606 status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; } 607 status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; } 608 status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; } 609 status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; } 610 status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; } 611 status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; } 612 status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; } 613 status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; } 614 status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; } 615 status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; } 616 status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; } 617 status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; } 618 status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; } 619 status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; } 620 status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; } 621 status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; } 622 status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; } 623 status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; } 624 status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; } 625 status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; } 626 status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; } 627 status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; } 628 status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; } 629 status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; } 630 status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; } 631 status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; } 632 status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; } 633 status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; } 634 status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; } 635 status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; } 636 status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; } 637 status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; } 638 status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; } 639 status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; } 640 status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; } 641 status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; } 642 status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; } 643 status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; } 644 status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; } 645 status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; } 646 status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; } 647 status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; } 648 status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; } 649 status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; } 650 651