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