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