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