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