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 25BMediaFile::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 34BMediaFile::BMediaFile(BDataIO* source) 35{ 36 CALLED(); 37 _Init(); 38 _InitReader(source); 39} 40 41 42BMediaFile::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 51BMediaFile::BMediaFile(BDataIO* source, int32 flags) 52{ 53 CALLED(); 54 _Init(); 55 _InitReader(source, NULL, flags); 56} 57 58 59BMediaFile::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 70BMediaFile::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() 80BMediaFile::BMediaFile(const media_file_format* mfi, int32 flags) 81{ 82 debugger("BMediaFile::BMediaFile not implemented"); 83} 84 85 86BMediaFile::BMediaFile(const BUrl& url) 87{ 88 CALLED(); 89 _Init(); 90 fDeleteSource = true; 91 _InitReader(NULL, &url); 92} 93 94 95BMediaFile::BMediaFile(const BUrl& url, int32 flags) 96{ 97 CALLED(); 98 _Init(); 99 fDeleteSource = true; 100 _InitReader(NULL, &url, flags); 101} 102 103 104BMediaFile::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 118status_t 119BMediaFile::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 134status_t 135BMediaFile::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 149status_t 150BMediaFile::SetTo(const BUrl& url) 151{ 152 CALLED(); 153 154 _UnInit(); 155 _InitReader(NULL, &url); 156 157 return fErr; 158} 159 160 161BMediaFile::~BMediaFile() 162{ 163 CALLED(); 164 165 _UnInit(); 166} 167 168 169status_t 170BMediaFile::InitCheck() const 171{ 172 CALLED(); 173 return fErr; 174} 175 176 177status_t 178BMediaFile::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 190status_t 191BMediaFile::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 204const char* 205BMediaFile::Copyright() const 206{ 207 return fExtractor->Copyright(); 208} 209 210 211int32 212BMediaFile::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. 220BMediaTrack* 221BMediaFile::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. 242status_t 243BMediaFile::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 262status_t 263BMediaFile::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 281BMediaTrack* 282BMediaFile::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) 312BMediaTrack* 313BMediaFile::CreateTrack(media_format* mf, uint32 flags) 314{ 315 return CreateTrack(mf, NULL, flags); 316} 317 318 319// For BeOS R5 compatibility 320extern "C" BMediaTrack* 321CreateTrack__10BMediaFileP12media_formatPC16media_codec_info( 322 BMediaFile* self, media_format* mf, const media_codec_info* mci); 323BMediaTrack* 324CreateTrack__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 332extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format( 333 BMediaFile* self, media_format* mf); 334BMediaTrack* 335CreateTrack__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 342status_t 343BMediaFile::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) 353status_t 354BMediaFile::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 362status_t 363BMediaFile::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 373status_t 374BMediaFile::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 385status_t 386BMediaFile::GetParameterWeb(BParameterWeb** outWeb) 387{ 388 UNIMPLEMENTED(); 389 return B_ERROR; 390} 391 392 393// deprecated BeOS R5 API 394BParameterWeb* 395BMediaFile::Web() 396{ 397 UNIMPLEMENTED(); 398 return 0; 399} 400 401 402status_t 403BMediaFile::GetParameterValue(int32 id, void* value, size_t* size) 404{ 405 UNIMPLEMENTED(); 406 return B_OK; 407} 408 409 410status_t 411BMediaFile::SetParameterValue(int32 id, const void* value, size_t size) 412{ 413 UNIMPLEMENTED(); 414 return B_OK; 415} 416 417 418BView* 419BMediaFile::GetParameterView() 420{ 421 UNIMPLEMENTED(); 422 return 0; 423} 424 425 426status_t 427BMediaFile::Perform(int32 selector, void* data) 428{ 429 UNIMPLEMENTED(); 430 return B_OK; 431} 432 433 434status_t 435BMediaFile::ControlFile(int32 selector, void* ioData, size_t size) 436{ 437 UNIMPLEMENTED(); 438 return B_ERROR; 439} 440 441 442// #pragma mark - private 443 444 445void 446BMediaFile::_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 467void 468BMediaFile::_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 498void 499BMediaFile::_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 539void 540BMediaFile::_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 578void 579BMediaFile::_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 597BMediaFile::BMediaFile(); 598BMediaFile::BMediaFile(const BMediaFile&); 599 BMediaFile::BMediaFile& operator=(const BMediaFile&); 600*/ 601 602status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; } 603status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; } 604status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; } 605status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; } 606status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; } 607status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; } 608status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; } 609status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; } 610status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; } 611status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; } 612status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; } 613status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; } 614status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; } 615status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; } 616status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; } 617status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; } 618status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; } 619status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; } 620status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; } 621status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; } 622status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; } 623status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; } 624status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; } 625status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; } 626status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; } 627status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; } 628status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; } 629status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; } 630status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; } 631status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; } 632status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; } 633status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; } 634status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; } 635status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; } 636status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; } 637status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; } 638status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; } 639status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; } 640status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; } 641status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; } 642status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; } 643status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; } 644status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; } 645status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; } 646status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; } 647status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; } 648status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; } 649status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; } 650 651