1 /* 2 * Copyright 2009-2010, Stephan Aßmus <superstippi@gmx.de> 3 * Copyright 2002-2007, Marcus Overhagen <marcus@overhagen.de> 4 * All rights reserved. Distributed under the terms of the MIT license. 5 */ 6 7 8 #include <MediaTrack.h> 9 10 #include <new> 11 12 #include <string.h> 13 #include <stdlib.h> 14 15 #include <Roster.h> 16 17 #include "debug.h" 18 19 #include "MediaExtractor.h" 20 #include "MediaWriter.h" 21 #include "PluginManager.h" 22 23 24 //#define TRACE_MEDIA_TRACK 25 #ifdef TRACE_MEDIA_TRACK 26 # ifndef TRACE 27 # define TRACE printf 28 # endif 29 #else 30 # ifndef TRACE 31 # define TRACE(a...) 32 # endif 33 #endif 34 35 #define ERROR(a...) fprintf(stderr, a) 36 37 38 #define CONVERT_TO_INT32 0 39 // TODO: Test! This triggers a few bugs! 40 41 // flags used for workarounds 42 enum { 43 FORCE_RAW_AUDIO = 0x0001, 44 FORCE_RAW_VIDEO = 0x0002, 45 FORCE_RAW_AUDIO_INT16_FORMAT = 0x0010, 46 FORCE_RAW_AUDIO_INT32_FORMAT = 0x0020, 47 FORCE_RAW_AUDIO_FLOAT_FORMAT = 0x0040, 48 FORCE_RAW_AUDIO_HOST_ENDIAN = 0x0100, 49 IGNORE_ENCODED_AUDIO = 0x1000, 50 IGNORE_ENCODED_VIDEO = 0x2000, 51 }; 52 53 #define B_MEDIA_DISABLE_FORMAT_TRANSLATION 0x4000 54 // TODO: move this (after name change?) to MediaDefs.h 55 56 57 class RawDecoderChunkProvider : public ChunkProvider { 58 public: 59 RawDecoderChunkProvider(Decoder* decoder, int buffer_size, 60 int frame_size); 61 virtual ~RawDecoderChunkProvider(); 62 63 status_t GetNextChunk(const void** chunkBuffer, size_t* chunkSize, 64 media_header* mediaHeader); 65 66 private: 67 Decoder* fDecoder; 68 void* fBuffer; 69 int fBufferSize; 70 int fFrameSize; 71 }; 72 73 74 /************************************************************* 75 * protected BMediaTrack 76 *************************************************************/ 77 78 BMediaTrack::~BMediaTrack() 79 { 80 CALLED(); 81 gPluginManager.DestroyDecoder(fRawDecoder); 82 gPluginManager.DestroyDecoder(fDecoder); 83 gPluginManager.DestroyEncoder(fEncoder); 84 } 85 86 /************************************************************* 87 * public BMediaTrack 88 *************************************************************/ 89 90 status_t 91 BMediaTrack::InitCheck() const 92 { 93 CALLED(); 94 return fInitStatus; 95 } 96 97 98 status_t 99 BMediaTrack::GetCodecInfo(media_codec_info* mci) const 100 { 101 CALLED(); 102 if (!fDecoder) 103 return B_NO_INIT; 104 105 *mci = fCodecInfo; 106 strlcpy(mci->pretty_name, fCodecInfo.pretty_name, sizeof(mci->pretty_name)); 107 108 return B_OK; 109 } 110 111 112 status_t 113 BMediaTrack::EncodedFormat(media_format *out_format) const 114 { 115 CALLED(); 116 if (!out_format) 117 return B_BAD_VALUE; 118 if (!fExtractor) 119 return B_NO_INIT; 120 121 *out_format = *fExtractor->EncodedFormat(fStream); 122 123 #ifdef TRACE_MEDIA_TRACK 124 char s[200]; 125 string_for_format(*out_format, s, sizeof(s)); 126 printf("BMediaTrack::EncodedFormat: %s\n", s); 127 #endif 128 129 return B_OK; 130 } 131 132 133 // for BeOS R5 compatibilitly 134 extern "C" status_t DecodedFormat__11BMediaTrackP12media_format(BMediaTrack *self, media_format *inout_format); 135 status_t DecodedFormat__11BMediaTrackP12media_format(BMediaTrack *self, 136 media_format *inout_format) 137 { 138 return self->DecodedFormat(inout_format, 0); 139 } 140 141 142 status_t 143 BMediaTrack::DecodedFormat(media_format *inout_format, uint32 flags) 144 { 145 CALLED(); 146 if (!inout_format) 147 return B_BAD_VALUE; 148 if (!fExtractor || !fDecoder) 149 return B_NO_INIT; 150 151 gPluginManager.DestroyDecoder(fRawDecoder); 152 fRawDecoder = NULL; 153 154 #ifdef TRACE_MEDIA_TRACK 155 char s[200]; 156 string_for_format(*inout_format, s, sizeof(s)); 157 printf("BMediaTrack::DecodedFormat: req1: %s\n", s); 158 #endif 159 160 if ((fWorkaroundFlags & FORCE_RAW_AUDIO) || ((fWorkaroundFlags & IGNORE_ENCODED_AUDIO) && inout_format->type == B_MEDIA_ENCODED_AUDIO)) { 161 inout_format->type = B_MEDIA_RAW_AUDIO; 162 inout_format->u.raw_audio = media_multi_audio_format::wildcard; 163 } 164 if ((fWorkaroundFlags & FORCE_RAW_VIDEO) || ((fWorkaroundFlags & IGNORE_ENCODED_VIDEO) && inout_format->type == B_MEDIA_ENCODED_VIDEO)) { 165 inout_format->type = B_MEDIA_RAW_VIDEO; 166 inout_format->u.raw_video = media_raw_video_format::wildcard; 167 } 168 if (inout_format->type == B_MEDIA_RAW_AUDIO) { 169 if (fWorkaroundFlags & FORCE_RAW_AUDIO_HOST_ENDIAN) 170 inout_format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 171 if (fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT) 172 inout_format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; 173 if (fWorkaroundFlags & FORCE_RAW_AUDIO_INT32_FORMAT) 174 inout_format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; 175 if (fWorkaroundFlags & FORCE_RAW_AUDIO_FLOAT_FORMAT) 176 inout_format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; 177 } 178 179 #ifdef TRACE_MEDIA_TRACK 180 string_for_format(*inout_format, s, sizeof(s)); 181 printf("BMediaTrack::DecodedFormat: req2: %s\n", s); 182 #endif 183 184 fFormat = *inout_format; 185 186 status_t res; 187 188 res = fDecoder->NegotiateOutputFormat(inout_format); 189 190 #ifdef TRACE_MEDIA_TRACK 191 string_for_format(*inout_format, s, sizeof(s)); 192 printf("BMediaTrack::DecodedFormat: nego: %s\n", s); 193 #endif 194 195 if (inout_format->type == 0) 196 debugger("Decoder didn't set output format type"); 197 if (inout_format->type == B_MEDIA_RAW_AUDIO) { 198 if (inout_format->u.raw_audio.byte_order == 0) 199 debugger("Decoder didn't set raw audio output byte order"); 200 if (inout_format->u.raw_audio.format == 0) 201 debugger("Decoder didn't set raw audio output sample format"); 202 if (inout_format->u.raw_audio.buffer_size <= 0) 203 debugger("Decoder didn't set raw audio output buffer size"); 204 } 205 if (inout_format->type == B_MEDIA_RAW_VIDEO) { 206 if (inout_format->u.raw_video.display.format == 0) 207 debugger("Decoder didn't set raw video output color space"); 208 if (inout_format->u.raw_video.display.line_width == 0) 209 debugger("Decoder didn't set raw video output line_width"); 210 if (inout_format->u.raw_video.display.line_count == 0) 211 debugger("Decoder didn't set raw video output line_count"); 212 if (inout_format->u.raw_video.display.bytes_per_row == 0) 213 debugger("Decoder didn't set raw video output bytes_per_row"); 214 } 215 216 if (0 == (flags & B_MEDIA_DISABLE_FORMAT_TRANSLATION)) { 217 if (fFormat.type == B_MEDIA_RAW_AUDIO 218 && inout_format->type == B_MEDIA_RAW_AUDIO 219 && fFormat.u.raw_audio.format != 0 220 && fFormat.u.raw_audio.format != inout_format->u.raw_audio.format) { 221 if (SetupFormatTranslation(*inout_format, &fFormat)) { 222 *inout_format = fFormat; 223 } 224 } 225 } 226 227 fFormat = *inout_format; 228 229 // string_for_format(*inout_format, s, sizeof(s)); 230 // printf("BMediaTrack::DecodedFormat: res: %s\n", s); 231 232 return res; 233 } 234 235 236 status_t 237 BMediaTrack::GetMetaData(BMessage* _data) const 238 { 239 CALLED(); 240 if (fExtractor == NULL) 241 return B_NO_INIT; 242 if (_data == NULL) 243 return B_BAD_VALUE; 244 245 _data->MakeEmpty(); 246 247 return fExtractor->GetStreamMetaData(fStream, _data); 248 } 249 250 251 int64 252 BMediaTrack::CountFrames() const 253 { 254 CALLED(); 255 int64 frames = fExtractor ? fExtractor->CountFrames(fStream) : 0; 256 // printf("BMediaTrack::CountFrames: %lld\n", frames); 257 return frames; 258 } 259 260 261 bigtime_t 262 BMediaTrack::Duration() const 263 { 264 CALLED(); 265 bigtime_t duration = fExtractor ? fExtractor->Duration(fStream) : 0; 266 // printf("BMediaTrack::Duration: %lld\n", duration); 267 return duration; 268 } 269 270 271 int64 272 BMediaTrack::CurrentFrame() const 273 { 274 return fCurrentFrame; 275 } 276 277 278 bigtime_t 279 BMediaTrack::CurrentTime() const 280 { 281 return fCurrentTime; 282 } 283 284 // BMediaTrack::ReadFrames(char *, long long *, media_header *) 285 // Compatibility for R5 and below. Required by Corum III and Civ:CTP. 286 #if __GNUC__ < 3 287 288 extern "C" status_t 289 ReadFrames__11BMediaTrackPcPxP12media_header(BMediaTrack *self, 290 char *out_buffer, 291 int64 *out_frameCount, 292 media_header *mh) 293 { 294 return self->ReadFrames(out_buffer, out_frameCount, mh, 0); 295 } 296 297 #endif // __GNUC__ < 3 298 299 status_t 300 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount, 301 media_header* mediaHeader) 302 { 303 return ReadFrames(buffer, _frameCount, mediaHeader, NULL); 304 } 305 306 307 status_t 308 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount, 309 media_header* _header, media_decode_info* info) 310 { 311 // CALLED(); 312 if (!fDecoder) 313 return B_NO_INIT; 314 if (!buffer || !_frameCount) 315 return B_BAD_VALUE; 316 317 media_header header; 318 if (_header == NULL) 319 _header = &header; 320 321 // Always clear the header first, as the decoder may not set all fields. 322 memset(_header, 0, sizeof(media_header)); 323 324 status_t result; 325 if (fRawDecoder) 326 result = fRawDecoder->Decode(buffer, _frameCount, _header, info); 327 else 328 result = fDecoder->Decode(buffer, _frameCount, _header, info); 329 if (result == B_OK) { 330 fCurrentFrame += *_frameCount; 331 bigtime_t framesDuration = (bigtime_t)(*_frameCount * 1000000 332 / _FrameRate()); 333 fCurrentTime = _header->start_time + framesDuration; 334 // This debug output shows drift between calculated fCurrentFrame and time-based 335 // current frame, if there is any. 336 //if (fFormat.type == B_MEDIA_RAW_AUDIO) { 337 //printf("current frame: %lld / calculated: %lld (%.2f/%.2f)\r", fCurrentFrame, 338 //int64(fCurrentTime * _FrameRate() / 1000000.0 + 0.5), fCurrentTime / 1000000.0, 339 //(float)fCurrentFrame / _FrameRate()); 340 //fflush(stdout); 341 //} 342 } else { 343 ERROR("BMediaTrack::ReadFrames: decoder returned error %#" B_PRIx32 344 " (%s)\n", result, strerror(result)); 345 *_frameCount = 0; 346 } 347 348 // PRINT(1, "BMediaTrack::ReadFrames: stream %ld, start-time %5Ld.%06Ld, " 349 // "%lld frames\n", fStream, _header->start_time / 1000000, 350 // _header->start_time % 1000000, *out_frameCount); 351 352 return result; 353 } 354 355 356 status_t 357 BMediaTrack::ReplaceFrames(const void* inBuffer, int64* inOutFrameCount, 358 const media_header* mediaHeader) 359 { 360 UNIMPLEMENTED(); 361 362 // TODO: Actually, a file is either open for reading or writing at the 363 // moment. Since the chunk size of encoded media data will change, 364 // implementing this call will only be possible for raw media tracks. 365 366 return B_NOT_SUPPORTED; 367 } 368 369 370 status_t 371 BMediaTrack::SeekToTime(bigtime_t* _time, int32 flags) 372 { 373 CALLED(); 374 if (fDecoder == NULL || fExtractor == NULL) 375 return B_NO_INIT; 376 if (_time == NULL) 377 return B_BAD_VALUE; 378 379 // Make sure flags are valid 380 flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME; 381 382 #if DEBUG 383 bigtime_t requestedTime = *_time; 384 #endif 385 int64 frame = 0; 386 387 status_t result = fExtractor->Seek(fStream, flags, &frame, _time); 388 if (result != B_OK) { 389 ERROR("BMediaTrack::SeekToTime: extractor seek failed\n"); 390 return result; 391 } 392 393 result = fDecoder->SeekedTo(frame, *_time); 394 if (result != B_OK) { 395 ERROR("BMediaTrack::SeekToTime: decoder seek failed\n"); 396 return result; 397 } 398 399 if (fRawDecoder) { 400 result = fRawDecoder->SeekedTo(frame, *_time); 401 if (result != B_OK) { 402 ERROR("BMediaTrack::SeekToTime: raw decoder seek failed\n"); 403 return result; 404 } 405 } 406 407 fCurrentFrame = frame; 408 fCurrentTime = *_time; 409 410 PRINT(1, "BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n", 411 requestedTime / 1000000.0, *_time / 1000000.0); 412 413 return B_OK; 414 } 415 416 417 status_t 418 BMediaTrack::SeekToFrame(int64* _frame, int32 flags) 419 { 420 CALLED(); 421 if (fDecoder == NULL || fExtractor == NULL) 422 return B_NO_INIT; 423 if (_frame == NULL) 424 return B_BAD_VALUE; 425 426 // Make sure flags are valid 427 flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_FRAME; 428 429 #if DEBUG 430 int64 requestedFrame = *_frame; 431 #endif 432 bigtime_t time = 0; 433 434 status_t result = fExtractor->Seek(fStream, flags, _frame, &time); 435 if (result != B_OK) { 436 ERROR("BMediaTrack::SeekToFrame: extractor seek failed\n"); 437 return result; 438 } 439 440 result = fDecoder->SeekedTo(*_frame, time); 441 if (result != B_OK) { 442 ERROR("BMediaTrack::SeekToFrame: decoder seek failed\n"); 443 return result; 444 } 445 446 if (fRawDecoder != NULL) { 447 result = fRawDecoder->SeekedTo(*_frame, time); 448 if (result != B_OK) { 449 ERROR("BMediaTrack::SeekToFrame: raw decoder seek failed\n"); 450 return result; 451 } 452 } 453 454 fCurrentFrame = *_frame; 455 fCurrentTime = time; 456 457 PRINT(1, "BMediaTrack::SeekToTime SeekToFrame, requested %lld, " 458 "result %lld\n", requestedFrame, *_frame); 459 460 return B_OK; 461 } 462 463 464 status_t 465 BMediaTrack::FindKeyFrameForTime(bigtime_t* _time, int32 flags) const 466 { 467 CALLED(); 468 if (fExtractor == NULL) 469 return B_NO_INIT; 470 if (_time == NULL) 471 return B_BAD_VALUE; 472 473 // Make sure flags are valid 474 flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME; 475 476 int64 frame = 0; 477 // dummy frame, will be ignored because of flags 478 status_t result = fExtractor->FindKeyFrame(fStream, flags, &frame, _time); 479 if (result != B_OK) { 480 ERROR("BMediaTrack::FindKeyFrameForTime: extractor seek failed: %s\n", 481 strerror(result)); 482 } 483 484 return result; 485 } 486 487 488 status_t 489 BMediaTrack::FindKeyFrameForFrame(int64* _frame, int32 flags) const 490 { 491 CALLED(); 492 if (fExtractor == NULL) 493 return B_NO_INIT; 494 if (_frame == NULL) 495 return B_BAD_VALUE; 496 497 // Make sure flags are valid 498 flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_FRAME; 499 500 bigtime_t time = 0; 501 // dummy time, will be ignored because of flags 502 status_t result = fExtractor->FindKeyFrame(fStream, flags, _frame, &time); 503 if (result != B_OK) { 504 ERROR("BMediaTrack::FindKeyFrameForFrame: extractor seek failed: %s\n", 505 strerror(result)); 506 } 507 508 return result; 509 } 510 511 512 status_t 513 BMediaTrack::ReadChunk(char** _buffer, int32* _size, media_header* _header) 514 { 515 CALLED(); 516 if (fExtractor == NULL) 517 return B_NO_INIT; 518 if (_buffer == NULL || _size == NULL) 519 return B_BAD_VALUE; 520 521 media_header header; 522 if (_header == NULL) 523 _header = &header; 524 525 // Always clear the header first, as the extractor may not set all fields. 526 memset(_header, 0, sizeof(media_header)); 527 528 const void* buffer; 529 size_t size; 530 status_t result = fExtractor->GetNextChunk(fStream, &buffer, &size, 531 _header); 532 533 if (result == B_OK) { 534 *_buffer = const_cast<char*>(static_cast<const char*>(buffer)); 535 // TODO: Change the pointer type when we break the API. 536 *_size = size; 537 // TODO: This changes the meaning of fCurrentTime from pointing 538 // to the next chunk start time (i.e. after seeking) to the start time 539 // of the last chunk. Asking the extractor for the current time will 540 // not work so well because of the chunk cache. But providing a 541 // "duration" field in the media_header could be useful. 542 fCurrentTime = _header->start_time; 543 fCurrentFrame = (int64)(fCurrentTime * _FrameRate() / 1000000LL); 544 545 } 546 547 return result; 548 } 549 550 551 status_t 552 BMediaTrack::AddCopyright(const char* copyright) 553 { 554 if (fWriter == NULL) 555 return B_NO_INIT; 556 557 return fWriter->SetCopyright(fStream, copyright); 558 } 559 560 561 status_t 562 BMediaTrack::AddTrackInfo(uint32 code, const void* data, size_t size, 563 uint32 flags) 564 { 565 if (fWriter == NULL) 566 return B_NO_INIT; 567 568 return fWriter->AddTrackInfo(fStream, code, data, size, flags); 569 } 570 571 572 status_t 573 BMediaTrack::WriteFrames(const void* data, int32 frameCount, int32 flags) 574 { 575 media_encode_info encodeInfo; 576 encodeInfo.flags = flags; 577 578 return WriteFrames(data, frameCount, &encodeInfo); 579 } 580 581 582 status_t 583 BMediaTrack::WriteFrames(const void* data, int64 frameCount, 584 media_encode_info* info) 585 { 586 if (fEncoder == NULL) 587 return B_NO_INIT; 588 589 return fEncoder->Encode(data, frameCount, info); 590 } 591 592 593 status_t 594 BMediaTrack::WriteChunk(const void* data, size_t size, uint32 flags) 595 { 596 media_encode_info encodeInfo; 597 encodeInfo.flags = flags; 598 599 return WriteChunk(data, size, &encodeInfo); 600 } 601 602 603 status_t 604 BMediaTrack::WriteChunk(const void* data, size_t size, media_encode_info* info) 605 { 606 if (fWriter == NULL) 607 return B_NO_INIT; 608 609 return fWriter->WriteChunk(fStream, data, size, info); 610 } 611 612 613 status_t 614 BMediaTrack::Flush() 615 { 616 if (fWriter == NULL) 617 return B_NO_INIT; 618 619 return fWriter->Flush(); 620 } 621 622 623 // deprecated BeOS R5 API 624 BParameterWeb* 625 BMediaTrack::Web() 626 { 627 BParameterWeb* web; 628 if (GetParameterWeb(&web) == B_OK) 629 return web; 630 return NULL; 631 } 632 633 634 status_t 635 BMediaTrack::GetParameterWeb(BParameterWeb** outWeb) 636 { 637 if (outWeb == NULL) 638 return B_BAD_VALUE; 639 640 if (fEncoder == NULL) 641 return B_NO_INIT; 642 643 // TODO: This method is new in Haiku. The header mentions it returns a 644 // copy. But how could it even do that? How can one clone a web and make 645 // it point to the same BControllable? 646 *outWeb = fEncoder->ParameterWeb(); 647 if (*outWeb != NULL) 648 return B_OK; 649 650 return B_NOT_SUPPORTED; 651 } 652 653 654 status_t 655 BMediaTrack::GetParameterValue(int32 id, void* value, size_t* size) 656 { 657 if (value == NULL || size == NULL) 658 return B_BAD_VALUE; 659 660 if (fEncoder == NULL) 661 return B_NO_INIT; 662 663 return fEncoder->GetParameterValue(id, value, size); 664 } 665 666 667 status_t 668 BMediaTrack::SetParameterValue(int32 id, const void* value, size_t size) 669 { 670 if (value == NULL || size == 0) 671 return B_BAD_VALUE; 672 673 if (fEncoder == NULL) 674 return B_NO_INIT; 675 676 return fEncoder->SetParameterValue(id, value, size); 677 } 678 679 680 BView* 681 BMediaTrack::GetParameterView() 682 { 683 if (fEncoder == NULL) 684 return NULL; 685 686 return fEncoder->ParameterView(); 687 } 688 689 690 status_t 691 BMediaTrack::GetQuality(float* quality) 692 { 693 if (quality == NULL) 694 return B_BAD_VALUE; 695 696 encode_parameters parameters; 697 status_t ret = GetEncodeParameters(¶meters); 698 if (ret != B_OK) 699 return ret; 700 701 *quality = parameters.quality; 702 703 return B_OK; 704 } 705 706 707 status_t 708 BMediaTrack::SetQuality(float quality) 709 { 710 encode_parameters parameters; 711 status_t ret = GetEncodeParameters(¶meters); 712 if (ret != B_OK) 713 return ret; 714 715 if (quality < 0.0f) 716 quality = 0.0f; 717 if (quality > 1.0f) 718 quality = 1.0f; 719 720 parameters.quality = quality; 721 722 return SetEncodeParameters(¶meters); 723 } 724 725 726 status_t 727 BMediaTrack::GetEncodeParameters(encode_parameters* parameters) const 728 { 729 if (parameters == NULL) 730 return B_BAD_VALUE; 731 732 if (fEncoder == NULL) 733 return B_NO_INIT; 734 735 return fEncoder->GetEncodeParameters(parameters); 736 } 737 738 739 status_t 740 BMediaTrack::SetEncodeParameters(encode_parameters *parameters) 741 { 742 if (parameters == NULL) 743 return B_BAD_VALUE; 744 745 if (fEncoder == NULL) 746 return B_NO_INIT; 747 748 return fEncoder->SetEncodeParameters(parameters); 749 } 750 751 752 status_t 753 BMediaTrack::Perform(int32 selector, void* data) 754 { 755 return B_OK; 756 } 757 758 // #pragma mark - private 759 760 761 BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor* extractor, 762 int32 stream) 763 { 764 CALLED(); 765 fWorkaroundFlags = 0; 766 fDecoder = NULL; 767 fRawDecoder = NULL; 768 fExtractor = extractor; 769 fStream = stream; 770 fInitStatus = B_OK; 771 772 SetupWorkaround(); 773 774 status_t ret = fExtractor->CreateDecoder(fStream, &fDecoder, &fCodecInfo); 775 if (ret != B_OK) { 776 TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: " 777 "%s\n", strerror(ret)); 778 // We do not set fInitStatus here, because ReadChunk should still work. 779 fDecoder = NULL; 780 } 781 782 fCurrentFrame = 0; 783 fCurrentTime = 0; 784 785 // not used: 786 fEncoder = NULL; 787 fEncoderID = 0; 788 fWriter = NULL; 789 } 790 791 792 BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer, 793 int32 streamIndex, media_format* format, 794 const media_codec_info* codecInfo) 795 { 796 CALLED(); 797 798 fWorkaroundFlags = 0; 799 fEncoder = NULL; 800 fEncoderID = -1; 801 // TODO: Not yet sure what this was needed for... 802 fWriter = writer; 803 fStream = streamIndex; 804 fInitStatus = B_OK; 805 806 SetupWorkaround(); 807 808 if (codecInfo != NULL) { 809 status_t ret = fWriter->CreateEncoder(&fEncoder, codecInfo, format); 810 if (ret != B_OK) { 811 TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: " 812 "%s\n", strerror(ret)); 813 // We do not set fInitStatus here, because WriteChunk should still 814 // work. 815 fEncoder = NULL; 816 } else { 817 fCodecInfo = *codecInfo; 818 fInitStatus = fEncoder->SetUp(format); 819 } 820 } 821 822 fFormat = *format; 823 824 // not used: 825 fCurrentFrame = 0; 826 fCurrentTime = 0; 827 fDecoder = NULL; 828 fRawDecoder = NULL; 829 fExtractor = NULL; 830 } 831 832 833 // Does nothing, returns B_ERROR, for Zeta compatiblity only 834 status_t 835 BMediaTrack::ControlCodec(int32 selector, void *io_data, size_t size) 836 { 837 return B_ERROR; 838 } 839 840 841 void 842 BMediaTrack::SetupWorkaround() 843 { 844 app_info ainfo; 845 thread_info tinfo; 846 847 get_thread_info(find_thread(0), &tinfo); 848 be_roster->GetRunningAppInfo(tinfo.team, &ainfo); 849 850 if (strcmp(ainfo.signature, "application/x-vnd.marcone-soundplay") == 0) { 851 fWorkaroundFlags = FORCE_RAW_AUDIO | FORCE_RAW_AUDIO_INT16_FORMAT 852 | FORCE_RAW_AUDIO_HOST_ENDIAN; 853 printf("BMediaTrack::SetupWorkaround: SoundPlay workaround active\n"); 854 } 855 if (strcmp(ainfo.signature, "application/x-vnd.Be.MediaPlayer") == 0) { 856 fWorkaroundFlags = IGNORE_ENCODED_AUDIO | IGNORE_ENCODED_VIDEO; 857 printf("BMediaTrack::SetupWorkaround: MediaPlayer workaround active\n"); 858 } 859 860 #if CONVERT_TO_INT32 861 // TODO: Test 862 if (!(fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT)) 863 fWorkaroundFlags |= FORCE_RAW_AUDIO_INT32_FORMAT; 864 #endif 865 } 866 867 868 bool 869 BMediaTrack::SetupFormatTranslation(const media_format &from, media_format *to) 870 { 871 gPluginManager.DestroyDecoder(fRawDecoder); 872 fRawDecoder = NULL; 873 874 #ifdef TRACE_MEDIA_TRACK 875 char s[200]; 876 string_for_format(from, s, sizeof(s)); 877 printf("BMediaTrack::SetupFormatTranslation: from: %s\n", s); 878 #endif 879 880 status_t res = gPluginManager.CreateDecoder(&fRawDecoder, from); 881 if (res != B_OK) { 882 ERROR("BMediaTrack::SetupFormatTranslation: CreateDecoder failed\n"); 883 return false; 884 } 885 886 // XXX video? 887 int buffer_size = from.u.raw_audio.buffer_size; 888 int frame_size = (from.u.raw_audio.format & 15) 889 * from.u.raw_audio.channel_count; 890 media_format notconstFrom = from; 891 892 ChunkProvider *chunkProvider 893 = new(std::nothrow) RawDecoderChunkProvider(fDecoder, buffer_size, 894 frame_size); 895 if (!chunkProvider) { 896 ERROR("BMediaTrack::SetupFormatTranslation: can't create chunk " 897 "provider\n"); 898 goto error; 899 } 900 fRawDecoder->SetChunkProvider(chunkProvider); 901 902 res = fRawDecoder->Setup(¬constFrom, 0, 0); 903 if (res != B_OK) { 904 ERROR("BMediaTrack::SetupFormatTranslation: Setup failed\n"); 905 goto error; 906 } 907 908 #ifdef TRACE_MEDIA_TRACK 909 string_for_format(*to, s, sizeof(s)); 910 printf("BMediaTrack::SetupFormatTranslation: to: %s\n", s); 911 #endif 912 913 res = fRawDecoder->NegotiateOutputFormat(to); 914 if (res != B_OK) { 915 ERROR("BMediaTrack::SetupFormatTranslation: NegotiateOutputFormat " 916 "failed\n"); 917 goto error; 918 } 919 920 #ifdef TRACE_MEDIA_TRACK 921 string_for_format(*to, s, sizeof(s)); 922 printf("BMediaTrack::SetupFormatTranslation: res: %s\n", s); 923 #endif 924 925 return true; 926 927 error: 928 gPluginManager.DestroyDecoder(fRawDecoder); 929 fRawDecoder = NULL; 930 return false; 931 } 932 933 934 double 935 BMediaTrack::_FrameRate() const 936 { 937 switch (fFormat.type) { 938 case B_MEDIA_RAW_VIDEO: 939 return fFormat.u.raw_video.field_rate; 940 case B_MEDIA_ENCODED_VIDEO: 941 return fFormat.u.encoded_video.output.field_rate; 942 case B_MEDIA_RAW_AUDIO: 943 return fFormat.u.raw_audio.frame_rate; 944 case B_MEDIA_ENCODED_AUDIO: 945 return fFormat.u.encoded_audio.output.frame_rate; 946 default: 947 return 1.0; 948 } 949 } 950 951 /* 952 // unimplemented 953 BMediaTrack::BMediaTrack() 954 BMediaTrack::BMediaTrack(const BMediaTrack &) 955 BMediaTrack &BMediaTrack::operator=(const BMediaTrack &) 956 */ 957 958 status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; } 959 status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; } 960 status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; } 961 status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; } 962 status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; } 963 status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; } 964 status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; } 965 status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; } 966 status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; } 967 status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; } 968 status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; } 969 status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; } 970 status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; } 971 status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; } 972 status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; } 973 status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; } 974 status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; } 975 status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; } 976 status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; } 977 status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; } 978 status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; } 979 status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; } 980 status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; } 981 status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; } 982 status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; } 983 status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; } 984 status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; } 985 status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; } 986 status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; } 987 status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; } 988 status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; } 989 status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; } 990 status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; } 991 status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; } 992 status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; } 993 status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; } 994 status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; } 995 status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; } 996 status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; } 997 status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; } 998 status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; } 999 status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; } 1000 status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; } 1001 status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; } 1002 status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; } 1003 status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; } 1004 status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; } 1005 status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; } 1006 1007 1008 RawDecoderChunkProvider::RawDecoderChunkProvider(Decoder *decoder, int buffer_size, int frame_size) 1009 { 1010 // printf("RawDecoderChunkProvider: buffer_size %d, frame_size %d\n", buffer_size, frame_size); 1011 fDecoder = decoder; 1012 fFrameSize = frame_size; 1013 fBufferSize = buffer_size; 1014 fBuffer = malloc(buffer_size); 1015 } 1016 1017 RawDecoderChunkProvider::~RawDecoderChunkProvider() 1018 { 1019 free(fBuffer); 1020 } 1021 1022 status_t 1023 RawDecoderChunkProvider::GetNextChunk(const void **chunkBuffer, size_t *chunkSize, 1024 media_header *mediaHeader) 1025 { 1026 int64 frames; 1027 media_decode_info info; 1028 status_t res = fDecoder->Decode(fBuffer, &frames, mediaHeader, &info); 1029 if (res == B_OK) { 1030 *chunkBuffer = fBuffer; 1031 *chunkSize = frames * fFrameSize; 1032 // printf("RawDecoderChunkProvider::GetNextChunk, %lld frames, %ld bytes, start-time %lld\n", frames, *chunkSize, mediaHeader->start_time); 1033 } else { 1034 ERROR("RawDecoderChunkProvider::GetNextChunk failed\n"); 1035 } 1036 return res; 1037 } 1038