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