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