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 _plugin_manager.DestroyDecoder(fRawDecoder); 82 _plugin_manager.DestroyDecoder(fDecoder); 83 _plugin_manager.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 _plugin_manager.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 int64 237 BMediaTrack::CountFrames() const 238 { 239 CALLED(); 240 int64 frames = fExtractor ? fExtractor->CountFrames(fStream) : 0; 241 // printf("BMediaTrack::CountFrames: %Ld\n", frames); 242 return frames; 243 } 244 245 246 bigtime_t 247 BMediaTrack::Duration() const 248 { 249 CALLED(); 250 bigtime_t duration = fExtractor ? fExtractor->Duration(fStream) : 0; 251 // printf("BMediaTrack::Duration: %Ld\n", duration); 252 return duration; 253 } 254 255 256 int64 257 BMediaTrack::CurrentFrame() const 258 { 259 return fCurrentFrame; 260 } 261 262 263 bigtime_t 264 BMediaTrack::CurrentTime() const 265 { 266 return fCurrentTime; 267 } 268 269 // BMediaTrack::ReadFrames(char *, long long *, media_header *) 270 // Compatibility for R5 and below. Required by Corum III and Civ:CTP. 271 #if __GNUC__ < 3 272 273 extern "C" status_t 274 ReadFrames__11BMediaTrackPcPxP12media_header(BMediaTrack *self, 275 char *out_buffer, 276 int64 *out_frameCount, 277 media_header *mh) 278 { 279 return self->ReadFrames(out_buffer, out_frameCount, mh, 0); 280 } 281 282 #endif // __GNUC__ < 3 283 284 status_t 285 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount, 286 media_header* mediaHeader) 287 { 288 return ReadFrames(buffer, _frameCount, mediaHeader, NULL); 289 } 290 291 292 status_t 293 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount, 294 media_header* _header, media_decode_info* info) 295 { 296 // CALLED(); 297 if (!fDecoder) 298 return B_NO_INIT; 299 if (!buffer || !_frameCount) 300 return B_BAD_VALUE; 301 302 media_header header; 303 if (_header == NULL) 304 _header = &header; 305 306 // Always clear the header first, as the decoder may not set all fields. 307 memset(_header, 0, sizeof(media_header)); 308 309 status_t result; 310 if (fRawDecoder) 311 result = fRawDecoder->Decode(buffer, _frameCount, _header, info); 312 else 313 result = fDecoder->Decode(buffer, _frameCount, _header, info); 314 if (result == B_OK) { 315 fCurrentFrame += *_frameCount; 316 // TODO: This changes the meaning of fCurrentTime from pointing 317 // to the next chunk start time (i.e. after seeking) to the start time 318 // of the last chunk. Asking the extractor for the current time will 319 // not work so well because of the chunk cache. But providing a 320 // "duration" field in the media_header could be useful. 321 fCurrentTime = fCurrentTime = _header->start_time; 322 } else { 323 ERROR("BMediaTrack::ReadFrames: decoder returned error 0x%08lx (%s)\n", 324 result, strerror(result)); 325 *_frameCount = 0; 326 } 327 328 // PRINT(1, "BMediaTrack::ReadFrames: stream %ld, start-time %5Ld.%06Ld, " 329 // "%Ld frames\n", fStream, _header->start_time / 1000000, 330 // _header->start_time % 1000000, *out_frameCount); 331 332 return result; 333 } 334 335 336 status_t 337 BMediaTrack::ReplaceFrames(const void* inBuffer, int64* inOutFrameCount, 338 const media_header* mediaHeader) 339 { 340 UNIMPLEMENTED(); 341 342 // TODO: Actually, a file is either open for reading or writing at the 343 // moment. Since the chunk size of encoded media data will change, 344 // implementing this call will only be possible for raw media tracks. 345 346 return B_NOT_SUPPORTED; 347 } 348 349 350 status_t 351 BMediaTrack::SeekToTime(bigtime_t* inOutTime, int32 flags) 352 { 353 CALLED(); 354 if (!fDecoder || !fExtractor) 355 return B_NO_INIT; 356 if (!inOutTime) 357 return B_BAD_VALUE; 358 359 uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK) 360 | B_MEDIA_SEEK_TO_TIME; 361 bigtime_t seekTime = *inOutTime; 362 363 int64 frame = 0; 364 bigtime_t time = seekTime; 365 status_t result = fExtractor->Seek(fStream, seekTo, &frame, &time); 366 if (result != B_OK) { 367 ERROR("BMediaTrack::SeekToTime: extractor seek failed\n"); 368 return result; 369 } 370 371 // TODO: Codecs cannot actually "seek" in the stream, all they 372 // can do is "reset" their decoder state, since they are made 373 // aware of the fact that there will be a jump in the data. Maybe 374 // rename the Decoder method? 375 result = fDecoder->Seek(seekTo, 0, &frame, seekTime, &time); 376 if (result != B_OK) { 377 ERROR("BMediaTrack::SeekToTime: decoder seek failed\n"); 378 return result; 379 } 380 381 if (fRawDecoder) { 382 result = fRawDecoder->Seek(seekTo, 0, &frame, seekTime, &time); 383 if (result != B_OK) { 384 ERROR("BMediaTrack::SeekToTime: raw decoder seek failed\n"); 385 return result; 386 } 387 } 388 389 *inOutTime = time; 390 fCurrentFrame = frame; 391 fCurrentTime = time; 392 393 PRINT(1, "BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n", 394 seekTime / 1000000.0, *inOutTime / 1000000.0); 395 396 return B_OK; 397 } 398 399 400 status_t 401 BMediaTrack::SeekToFrame(int64 *inout_frame, int32 flags) 402 { 403 CALLED(); 404 if (!fDecoder || !fExtractor) 405 return B_NO_INIT; 406 if (!inout_frame) 407 return B_BAD_VALUE; 408 409 uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK) 410 | B_MEDIA_SEEK_TO_FRAME; 411 int64 seekFrame = *inout_frame; 412 413 int64 frame = seekFrame; 414 bigtime_t time = 0; 415 status_t result = fExtractor->Seek(fStream, seekTo, &frame, &time); 416 if (result != B_OK) { 417 ERROR("BMediaTrack::SeekToFrame: extractor seek failed\n"); 418 return result; 419 } 420 421 // TODO: Codecs cannot actually "seek" in the stream, all they 422 // can do is "reset" their decoder state, since they are made 423 // aware of the fact that there will be a jump in the data. Maybe 424 // rename the codec method? 425 result = fDecoder->Seek(seekTo, seekFrame, &frame, 0, &time); 426 if (result != B_OK) { 427 ERROR("BMediaTrack::SeekToFrame: decoder seek failed\n"); 428 return result; 429 } 430 431 if (fRawDecoder) { 432 result = fRawDecoder->Seek(seekTo, seekFrame, &frame, 0, &time); 433 if (result != B_OK) { 434 ERROR("BMediaTrack::SeekToFrame: raw decoder seek failed\n"); 435 return result; 436 } 437 } 438 439 *inout_frame = frame; 440 fCurrentFrame = frame; 441 fCurrentTime = time; 442 443 PRINT(1, "BMediaTrack::SeekToTime SeekToFrame, requested %Ld, result %Ld\n", seekFrame, *inout_frame); 444 445 return B_OK; 446 } 447 448 449 status_t 450 BMediaTrack::FindKeyFrameForTime(bigtime_t *inoutTime, int32 flags) const 451 { 452 CALLED(); 453 if (!fExtractor) 454 return B_NO_INIT; 455 if (!inoutTime) 456 return B_BAD_VALUE; 457 458 uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK) 459 | B_MEDIA_SEEK_TO_TIME; 460 461 int64 frame = 0; 462 // dummy frame, will be ignored because of flags 463 status_t result = fExtractor->FindKeyFrame(fStream, seekTo, &frame, 464 inoutTime); 465 if (result != B_OK) { 466 ERROR("BMediaTrack::FindKeyFrameForTime: extractor seek failed: %s\n", 467 strerror(result)); 468 return result; 469 } 470 471 return B_OK; 472 } 473 474 475 status_t 476 BMediaTrack::FindKeyFrameForFrame(int64 *inoutFrame, 477 int32 flags) const 478 { 479 CALLED(); 480 if (!fExtractor) 481 return B_NO_INIT; 482 if (!inoutFrame) 483 return B_BAD_VALUE; 484 485 uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK) 486 | B_MEDIA_SEEK_TO_FRAME; 487 488 bigtime_t time = 0; 489 // dummy time, will be ignored because of flags 490 status_t result = fExtractor->FindKeyFrame(fStream, seekTo, inoutFrame, 491 &time); 492 if (result != B_OK) { 493 ERROR("BMediaTrack::FindKeyFrameForFrame: extractor seek failed: %s\n", 494 strerror(result)); 495 return result; 496 } 497 498 return B_OK; 499 } 500 501 502 status_t 503 BMediaTrack::ReadChunk(char** _buffer, int32* _size, media_header* _header) 504 { 505 CALLED(); 506 if (fExtractor == NULL) 507 return B_NO_INIT; 508 if (_buffer == NULL || _size == NULL) 509 return B_BAD_VALUE; 510 511 media_header header; 512 if (_header == NULL) 513 _header = &header; 514 515 // Always clear the header first, as the extractor may not set all fields. 516 memset(_header, 0, sizeof(media_header)); 517 518 const void* buffer; 519 size_t size; 520 status_t result = fExtractor->GetNextChunk(fStream, &buffer, &size, 521 _header); 522 523 if (result == B_OK) { 524 *_buffer = const_cast<char*>(static_cast<const char*>(buffer)); 525 // TODO: Change the pointer type when we break the API. 526 *_size = size; 527 // TODO: This changes the meaning of fCurrentTime from pointing 528 // to the next chunk start time (i.e. after seeking) to the start time 529 // of the last chunk. Asking the extractor for the current time will 530 // not work so well because of the chunk cache. But providing a 531 // "duration" field in the media_header could be useful. 532 fCurrentTime = fCurrentTime = _header->start_time; 533 fCurrentFrame = fCurrentTime * _FrameRate() / 1000000LL; 534 535 } 536 537 return result; 538 } 539 540 541 status_t 542 BMediaTrack::AddCopyright(const char* copyright) 543 { 544 if (fWriter == NULL) 545 return B_NO_INIT; 546 547 return fWriter->SetCopyright(fStream, copyright); 548 } 549 550 551 status_t 552 BMediaTrack::AddTrackInfo(uint32 code, const void* data, size_t size, 553 uint32 flags) 554 { 555 if (fWriter == NULL) 556 return B_NO_INIT; 557 558 return fWriter->AddTrackInfo(fStream, code, data, size, flags); 559 } 560 561 562 status_t 563 BMediaTrack::WriteFrames(const void* data, int32 frameCount, int32 flags) 564 { 565 media_encode_info encodeInfo; 566 encodeInfo.flags = flags; 567 568 return WriteFrames(data, frameCount, &encodeInfo); 569 } 570 571 572 status_t 573 BMediaTrack::WriteFrames(const void* data, int64 frameCount, 574 media_encode_info* info) 575 { 576 if (fEncoder == NULL) 577 return B_NO_INIT; 578 579 return fEncoder->Encode(data, frameCount, info); 580 } 581 582 583 status_t 584 BMediaTrack::WriteChunk(const void* data, size_t size, uint32 flags) 585 { 586 media_encode_info encodeInfo; 587 encodeInfo.flags = flags; 588 589 return WriteChunk(data, size, &encodeInfo); 590 } 591 592 593 status_t 594 BMediaTrack::WriteChunk(const void* data, size_t size, media_encode_info* info) 595 { 596 if (fWriter == NULL) 597 return B_NO_INIT; 598 599 return fWriter->WriteChunk(fStream, data, size, info); 600 } 601 602 603 status_t 604 BMediaTrack::Flush() 605 { 606 if (fWriter == NULL) 607 return B_NO_INIT; 608 609 return fWriter->Flush(); 610 } 611 612 613 // deprecated BeOS R5 API 614 BParameterWeb* 615 BMediaTrack::Web() 616 { 617 BParameterWeb* web; 618 if (GetParameterWeb(&web) == B_OK) 619 return web; 620 return NULL; 621 } 622 623 624 status_t 625 BMediaTrack::GetParameterWeb(BParameterWeb** outWeb) 626 { 627 if (outWeb == NULL) 628 return B_BAD_VALUE; 629 630 if (fEncoder == NULL) 631 return B_NO_INIT; 632 633 // TODO: This method is new in Haiku. The header mentions it returns a 634 // copy. But how could it even do that? How can one clone a web and make 635 // it point to the same BControllable? 636 *outWeb = fEncoder->ParameterWeb(); 637 if (*outWeb != NULL) 638 return B_OK; 639 640 return B_NOT_SUPPORTED; 641 } 642 643 644 status_t 645 BMediaTrack::GetParameterValue(int32 id, void* value, size_t* size) 646 { 647 if (value == NULL || size == NULL) 648 return B_BAD_VALUE; 649 650 if (fEncoder == NULL) 651 return B_NO_INIT; 652 653 return fEncoder->GetParameterValue(id, value, size); 654 } 655 656 657 status_t 658 BMediaTrack::SetParameterValue(int32 id, const void* value, size_t size) 659 { 660 if (value == NULL || size == 0) 661 return B_BAD_VALUE; 662 663 if (fEncoder == NULL) 664 return B_NO_INIT; 665 666 return fEncoder->SetParameterValue(id, value, size); 667 } 668 669 670 BView* 671 BMediaTrack::GetParameterView() 672 { 673 if (fEncoder == NULL) 674 return NULL; 675 676 return fEncoder->ParameterView(); 677 } 678 679 680 status_t 681 BMediaTrack::GetQuality(float* quality) 682 { 683 if (quality == NULL) 684 return B_BAD_VALUE; 685 686 encode_parameters parameters; 687 status_t ret = GetEncodeParameters(¶meters); 688 if (ret != B_OK) 689 return ret; 690 691 *quality = parameters.quality; 692 693 return B_OK; 694 } 695 696 697 status_t 698 BMediaTrack::SetQuality(float quality) 699 { 700 encode_parameters parameters; 701 status_t ret = GetEncodeParameters(¶meters); 702 if (ret != B_OK) 703 return ret; 704 705 if (quality < 0.0f) 706 quality = 0.0f; 707 if (quality > 1.0f) 708 quality = 1.0f; 709 710 parameters.quality = quality; 711 712 return SetEncodeParameters(¶meters); 713 } 714 715 716 status_t 717 BMediaTrack::GetEncodeParameters(encode_parameters* parameters) const 718 { 719 if (parameters == NULL) 720 return B_BAD_VALUE; 721 722 if (fEncoder == NULL) 723 return B_NO_INIT; 724 725 return fEncoder->GetEncodeParameters(parameters); 726 } 727 728 729 status_t 730 BMediaTrack::SetEncodeParameters(encode_parameters *parameters) 731 { 732 if (parameters == NULL) 733 return B_BAD_VALUE; 734 735 if (fEncoder == NULL) 736 return B_NO_INIT; 737 738 return fEncoder->SetEncodeParameters(parameters); 739 } 740 741 742 status_t 743 BMediaTrack::Perform(int32 selector, void* data) 744 { 745 return B_OK; 746 } 747 748 // #pragma mark - private 749 750 751 BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor* extractor, 752 int32 stream) 753 { 754 CALLED(); 755 fWorkaroundFlags = 0; 756 fDecoder = NULL; 757 fRawDecoder = NULL; 758 fExtractor = extractor; 759 fStream = stream; 760 fInitStatus = B_OK; 761 762 SetupWorkaround(); 763 764 status_t ret = fExtractor->CreateDecoder(fStream, &fDecoder, &fCodecInfo); 765 if (ret != B_OK) { 766 TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: " 767 "%s\n", strerror(ret)); 768 // We do not set fInitStatus here, because ReadChunk should still work. 769 fDecoder = NULL; 770 } 771 772 fCurrentFrame = 0; 773 fCurrentTime = 0; 774 775 // not used: 776 fEncoder = NULL; 777 fEncoderID = 0; 778 fWriter = NULL; 779 } 780 781 782 BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer, 783 int32 streamIndex, const media_format* format, 784 const media_codec_info* codecInfo) 785 { 786 CALLED(); 787 788 fWorkaroundFlags = 0; 789 fEncoder = NULL; 790 fEncoderID = -1; 791 // TODO: Not yet sure what this was needed for... 792 fWriter = writer; 793 fFormat = *format; 794 fStream = streamIndex; 795 fInitStatus = B_OK; 796 797 SetupWorkaround(); 798 799 if (codecInfo != NULL) { 800 status_t ret = fWriter->CreateEncoder(&fEncoder, codecInfo, format); 801 if (ret != B_OK) { 802 TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: " 803 "%s\n", strerror(ret)); 804 // We do not set fInitStatus here, because WriteChunk should still work. 805 fEncoder = NULL; 806 } else { 807 fCodecInfo = *codecInfo; 808 fInitStatus = fEncoder->SetUp(&fFormat); 809 } 810 } 811 812 // not used: 813 fCurrentFrame = 0; 814 fCurrentTime = 0; 815 fDecoder = NULL; 816 fRawDecoder = NULL; 817 fExtractor = NULL; 818 } 819 820 821 // Does nothing, returns B_ERROR, for Zeta compatiblity only 822 status_t 823 BMediaTrack::ControlCodec(int32 selector, void *io_data, size_t size) 824 { 825 return B_ERROR; 826 } 827 828 829 void 830 BMediaTrack::SetupWorkaround() 831 { 832 app_info ainfo; 833 thread_info tinfo; 834 835 get_thread_info(find_thread(0), &tinfo); 836 be_roster->GetRunningAppInfo(tinfo.team, &ainfo); 837 838 if (strcmp(ainfo.signature, "application/x-vnd.marcone-soundplay") == 0) { 839 fWorkaroundFlags = FORCE_RAW_AUDIO | FORCE_RAW_AUDIO_INT16_FORMAT 840 | FORCE_RAW_AUDIO_HOST_ENDIAN; 841 printf("BMediaTrack::SetupWorkaround: SoundPlay workaround active\n"); 842 } 843 if (strcmp(ainfo.signature, "application/x-vnd.Be.MediaPlayer") == 0) { 844 fWorkaroundFlags = IGNORE_ENCODED_AUDIO | IGNORE_ENCODED_VIDEO; 845 printf("BMediaTrack::SetupWorkaround: MediaPlayer workaround active\n"); 846 } 847 848 #if CONVERT_TO_INT32 849 // TODO: Test 850 if (!(fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT)) 851 fWorkaroundFlags |= FORCE_RAW_AUDIO_INT32_FORMAT; 852 #endif 853 } 854 855 856 bool 857 BMediaTrack::SetupFormatTranslation(const media_format &from, media_format *to) 858 { 859 _plugin_manager.DestroyDecoder(fRawDecoder); 860 fRawDecoder = NULL; 861 862 #ifdef TRACE_MEDIA_TRACK 863 char s[200]; 864 string_for_format(from, s, sizeof(s)); 865 printf("BMediaTrack::SetupFormatTranslation: from: %s\n", s); 866 #endif 867 868 status_t res = _plugin_manager.CreateDecoder(&fRawDecoder, from); 869 if (res != B_OK) { 870 ERROR("BMediaTrack::SetupFormatTranslation: CreateDecoder failed\n"); 871 return false; 872 } 873 874 // XXX video? 875 int buffer_size = from.u.raw_audio.buffer_size; 876 int frame_size = (from.u.raw_audio.format & 15) 877 * from.u.raw_audio.channel_count; 878 media_format notconstFrom = from; 879 880 ChunkProvider *chunkProvider 881 = new(std::nothrow) RawDecoderChunkProvider(fDecoder, buffer_size, 882 frame_size); 883 if (!chunkProvider) { 884 ERROR("BMediaTrack::SetupFormatTranslation: can't create chunk " 885 "provider\n"); 886 goto error; 887 } 888 fRawDecoder->SetChunkProvider(chunkProvider); 889 890 res = fRawDecoder->Setup(¬constFrom, 0, 0); 891 if (res != B_OK) { 892 ERROR("BMediaTrack::SetupFormatTranslation: Setup failed\n"); 893 goto error; 894 } 895 896 #ifdef TRACE_MEDIA_TRACK 897 string_for_format(*to, s, sizeof(s)); 898 printf("BMediaTrack::SetupFormatTranslation: to: %s\n", s); 899 #endif 900 901 res = fRawDecoder->NegotiateOutputFormat(to); 902 if (res != B_OK) { 903 ERROR("BMediaTrack::SetupFormatTranslation: NegotiateOutputFormat " 904 "failed\n"); 905 goto error; 906 } 907 908 #ifdef TRACE_MEDIA_TRACK 909 string_for_format(*to, s, sizeof(s)); 910 printf("BMediaTrack::SetupFormatTranslation: res: %s\n", s); 911 #endif 912 913 return true; 914 915 error: 916 _plugin_manager.DestroyDecoder(fRawDecoder); 917 fRawDecoder = NULL; 918 return false; 919 } 920 921 922 double 923 BMediaTrack::_FrameRate() const 924 { 925 switch (fFormat.type) { 926 case B_MEDIA_RAW_VIDEO: 927 return fFormat.u.raw_video.field_rate; 928 case B_MEDIA_ENCODED_VIDEO: 929 return fFormat.u.encoded_video.output.field_rate; 930 case B_MEDIA_RAW_AUDIO: 931 return fFormat.u.raw_audio.frame_rate; 932 case B_MEDIA_ENCODED_AUDIO: 933 return fFormat.u.encoded_audio.output.frame_rate; 934 default: 935 return 1.0; 936 } 937 } 938 939 /* 940 // unimplemented 941 BMediaTrack::BMediaTrack() 942 BMediaTrack::BMediaTrack(const BMediaTrack &) 943 BMediaTrack &BMediaTrack::operator=(const BMediaTrack &) 944 */ 945 946 status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; } 947 status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; } 948 status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; } 949 status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; } 950 status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; } 951 status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; } 952 status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; } 953 status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; } 954 status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; } 955 status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; } 956 status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; } 957 status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; } 958 status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; } 959 status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; } 960 status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; } 961 status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; } 962 status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; } 963 status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; } 964 status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; } 965 status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; } 966 status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; } 967 status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; } 968 status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; } 969 status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; } 970 status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; } 971 status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; } 972 status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; } 973 status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; } 974 status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; } 975 status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; } 976 status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; } 977 status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; } 978 status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; } 979 status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; } 980 status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; } 981 status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; } 982 status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; } 983 status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; } 984 status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; } 985 status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; } 986 status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; } 987 status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; } 988 status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; } 989 status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; } 990 status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; } 991 status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; } 992 status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; } 993 status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; } 994 995 996 RawDecoderChunkProvider::RawDecoderChunkProvider(Decoder *decoder, int buffer_size, int frame_size) 997 { 998 // printf("RawDecoderChunkProvider: buffer_size %d, frame_size %d\n", buffer_size, frame_size); 999 fDecoder = decoder; 1000 fFrameSize = frame_size; 1001 fBufferSize = buffer_size; 1002 fBuffer = malloc(buffer_size); 1003 } 1004 1005 RawDecoderChunkProvider::~RawDecoderChunkProvider() 1006 { 1007 free(fBuffer); 1008 } 1009 1010 status_t 1011 RawDecoderChunkProvider::GetNextChunk(const void **chunkBuffer, size_t *chunkSize, 1012 media_header *mediaHeader) 1013 { 1014 int64 frames; 1015 media_decode_info info; 1016 status_t res = fDecoder->Decode(fBuffer, &frames, mediaHeader, &info); 1017 if (res == B_OK) { 1018 *chunkBuffer = fBuffer; 1019 *chunkSize = frames * fFrameSize; 1020 // printf("RawDecoderChunkProvider::GetNextChunk, %Ld frames, %ld bytes, start-time %Ld\n", frames, *chunkSize, mediaHeader->start_time); 1021 } else { 1022 ERROR("RawDecoderChunkProvider::GetNextChunk failed\n"); 1023 } 1024 return res; 1025 } 1026