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 46enum { 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 61class RawDecoderChunkProvider : public ChunkProvider { 62public: 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 71private: 72 Decoder* fDecoder; 73 void* fBuffer; 74 int fBufferSize; 75 int fFrameSize; 76}; 77 78 79/************************************************************* 80 * protected BMediaTrack 81 *************************************************************/ 82 83BMediaTrack::~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 96status_t 97BMediaTrack::InitCheck() const 98{ 99 CALLED(); 100 101 return fInitStatus; 102} 103 104 105status_t 106BMediaTrack::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 121status_t 122BMediaTrack::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 145extern "C" status_t DecodedFormat__11BMediaTrackP12media_format( 146 BMediaTrack* self, media_format* _format); 147 148status_t DecodedFormat__11BMediaTrackP12media_format(BMediaTrack* self, 149 media_format* _format) 150{ 151 return self->DecodedFormat(_format, 0); 152} 153 154 155status_t 156BMediaTrack::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 291status_t 292BMediaTrack::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 308int64 309BMediaTrack::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 319bigtime_t 320BMediaTrack::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 330int64 331BMediaTrack::CurrentFrame() const 332{ 333 return fCurrentFrame; 334} 335 336 337bigtime_t 338BMediaTrack::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 347extern "C" status_t 348ReadFrames__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 356status_t 357BMediaTrack::ReadFrames(void* buffer, int64* _frameCount, media_header* header) 358{ 359 return ReadFrames(buffer, _frameCount, header, NULL); 360} 361 362 363status_t 364BMediaTrack::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 418status_t 419BMediaTrack::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 432status_t 433BMediaTrack::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 481status_t 482BMediaTrack::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 530status_t 531BMediaTrack::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 556status_t 557BMediaTrack::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 582status_t 583BMediaTrack::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 623status_t 624BMediaTrack::AddCopyright(const char* copyright) 625{ 626 if (fWriter == NULL) 627 return B_NO_INIT; 628 629 return fWriter->SetCopyright(fStream, copyright); 630} 631 632 633status_t 634BMediaTrack::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 644status_t 645BMediaTrack::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 654status_t 655BMediaTrack::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 665status_t 666BMediaTrack::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 675status_t 676BMediaTrack::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 685status_t 686BMediaTrack::Flush() 687{ 688 if (fWriter == NULL) 689 return B_NO_INIT; 690 691 return fWriter->Flush(); 692} 693 694 695// deprecated BeOS R5 API 696BParameterWeb* 697BMediaTrack::Web() 698{ 699 BParameterWeb* web; 700 if (GetParameterWeb(&web) == B_OK) 701 return web; 702 703 return NULL; 704} 705 706 707status_t 708BMediaTrack::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 727status_t 728BMediaTrack::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 740status_t 741BMediaTrack::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 753BView* 754BMediaTrack::GetParameterView() 755{ 756 if (fEncoder == NULL) 757 return NULL; 758 759 return fEncoder->ParameterView(); 760} 761 762 763status_t 764BMediaTrack::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 780status_t 781BMediaTrack::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 800status_t 801BMediaTrack::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 813status_t 814BMediaTrack::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 826status_t 827BMediaTrack::Perform(int32 selector, void* data) 828{ 829 return B_OK; 830} 831 832// #pragma mark - private 833 834 835BMediaTrack::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 867BMediaTrack::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 909status_t 910BMediaTrack::ControlCodec(int32 selector, void* io_data, size_t size) 911{ 912 return B_ERROR; 913} 914 915 916void 917BMediaTrack::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 943bool 944BMediaTrack::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 1002error: 1003 gPluginManager.DestroyDecoder(fRawDecoder); 1004 fRawDecoder = NULL; 1005 return false; 1006} 1007 1008 1009double 1010BMediaTrack::_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 1028BMediaTrack::BMediaTrack() 1029BMediaTrack::BMediaTrack(const BMediaTrack &) 1030BMediaTrack &BMediaTrack::operator=(const BMediaTrack &) 1031#endif 1032 1033status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; } 1034status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; } 1035status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; } 1036status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; } 1037status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; } 1038status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; } 1039status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; } 1040status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; } 1041status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; } 1042status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; } 1043status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; } 1044status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; } 1045status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; } 1046status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; } 1047status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; } 1048status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; } 1049status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; } 1050status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; } 1051status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; } 1052status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; } 1053status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; } 1054status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; } 1055status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; } 1056status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; } 1057status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; } 1058status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; } 1059status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; } 1060status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; } 1061status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; } 1062status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; } 1063status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; } 1064status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; } 1065status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; } 1066status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; } 1067status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; } 1068status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; } 1069status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; } 1070status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; } 1071status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; } 1072status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; } 1073status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; } 1074status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; } 1075status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; } 1076status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; } 1077status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; } 1078status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; } 1079status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; } 1080status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; } 1081 1082 1083RawDecoderChunkProvider::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 1095RawDecoderChunkProvider::~RawDecoderChunkProvider() 1096{ 1097 free(fBuffer); 1098} 1099 1100 1101status_t 1102RawDecoderChunkProvider::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