155714Skris/* 255714Skris * Copyright �� 2000-2004 Ingo Weinhold <ingo_weinhold@gmx.de> 355714Skris * Copyright �� 2006-2008 Stephan A��mus <superstippi@gmx.de> 455714Skris * All rights reserved. Distributed under the terms of the MIT License. 555714Skris */ 655714Skris#include "MediaTrackAudioSupplier.h" 755714Skris 855714Skris#include <new> 955714Skris#include <algorithm> 1055714Skris#include <stdio.h> 1155714Skris#include <string.h> 1255714Skris 1355714Skris#include <MediaFile.h> 1455714Skris#include <MediaTrack.h> 1555714Skris 1655714Skrisusing namespace std; 1755714Skris 1855714Skris//#define TRACE_AUDIO_SUPPLIER 1955714Skris#ifdef TRACE_AUDIO_SUPPLIER 2055714Skris# define TRACE(x...) printf("MediaTrackAudioSupplier::" x) 2155714Skris#else 2255714Skris# define TRACE(x...) 2355714Skris#endif 2455714Skris 2555714Skris 2655714Skris// #pragma mark - Buffer 2755714Skris 2855714Skris 2955714Skrisstruct MediaTrackAudioSupplier::Buffer { 3055714Skris void* data; 3155714Skris int64 offset; 3255714Skris int64 size; 3355714Skris bigtime_t time_stamp; 3455714Skris 3555714Skris static int CompareOffset(const void* a, const void* b); 3655714Skris}; 3755714Skris 3855714Skris 3955714Skrisint 4055714SkrisMediaTrackAudioSupplier::Buffer::CompareOffset(const void* a, const void* b) 4155714Skris{ 4255714Skris const Buffer* buffer1 = *(const Buffer**)a; 4355714Skris const Buffer* buffer2 = *(const Buffer**)b; 4455714Skris int result = 0; 4555714Skris if (buffer1->offset < buffer2->offset) 4655714Skris result = -1; 4755714Skris else if (buffer1->offset > buffer2->offset) 4855714Skris result = 1; 4955714Skris return result; 5055714Skris} 5155714Skris 5255714Skris 5355714Skris// #pragma mark - MediaTrackAudioSupplier 5455714Skris 5555714Skris 5655714SkrisMediaTrackAudioSupplier::MediaTrackAudioSupplier(BMediaTrack* mediaTrack, 5755714Skris int32 trackIndex) 5855714Skris : 59109998Smarkm AudioTrackSupplier(), 6055714Skris fMediaTrack(mediaTrack), 6155714Skris fBuffer(NULL), 6255714Skris fBufferOffset(0), 6355714Skris fBufferSize(0), 6455714Skris fBuffers(10), 6555714Skris fHasKeyFrames(false), 6655714Skris fCountFrames(0), 67109998Smarkm fReportSeekError(true), 68109998Smarkm fTrackIndex(trackIndex) 69109998Smarkm{ 70109998Smarkm _InitFromTrack(); 71109998Smarkm} 72109998Smarkm 7368651Skris 7468651SkrisMediaTrackAudioSupplier::~MediaTrackAudioSupplier() 7568651Skris{ 7668651Skris _FreeBuffers(); 7755714Skris delete[] fBuffer; 7855714Skris} 7955714Skris 8055714Skris 8155714Skrisconst media_format& 8255714SkrisMediaTrackAudioSupplier::Format() const 8355714Skris{ 8455714Skris return AudioReader::Format(); 8555714Skris} 8655714Skris 8755714Skris 8855714Skrisstatus_t 8955714SkrisMediaTrackAudioSupplier::GetEncodedFormat(media_format* format) const 9055714Skris{ 9155714Skris if (!fMediaTrack) 9259191Skris return B_NO_INIT; 9355714Skris return fMediaTrack->EncodedFormat(format); 9455714Skris} 9555714Skris 9655714Skris 9755714Skrisstatus_t 9855714SkrisMediaTrackAudioSupplier::GetCodecInfo(media_codec_info* info) const 9955714Skris{ 10055714Skris if (!fMediaTrack) 10155714Skris return B_NO_INIT; 10255714Skris return fMediaTrack->GetCodecInfo(info); 10355714Skris} 10455714Skris 10555714Skris 10655714Skrisbigtime_t 10755714SkrisMediaTrackAudioSupplier::Duration() const 10855714Skris{ 10955714Skris if (!fMediaTrack) 11055714Skris return 0; 11155714Skris 11255714Skris return fMediaTrack->Duration(); 11355714Skris} 11455714Skris 11555714Skris 11655714Skris// #pragma mark - AudioReader 11755714Skris 11855714Skris 11955714Skrisbigtime_t 12055714SkrisMediaTrackAudioSupplier::InitialLatency() const 12155714Skris{ 12255714Skris // TODO: this is just a wild guess, and not really founded on anything. 12355714Skris return 100000; 12455714Skris} 12555714Skris 12659191Skris 12755714Skrisstatus_t 12855714SkrisMediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames) 12955714Skris{ 13055714Skris TRACE("Read(%p, %lld, %lld)\n", buffer, pos, 13155714Skris frames); 13255714Skris TRACE(" this: %p, fOutOffset: %lld\n", this, fOutOffset); 13355714Skris 13455714Skris//printf("MediaTrackAudioSupplier::Read(%p, %lld, %lld)\n", buffer, pos, frames); 13555714Skris 13655714Skris status_t error = InitCheck(); 13755714Skris if (error != B_OK) { 13855714Skris TRACE("Read() InitCheck failed\n"); 13955714Skris return error; 14055714Skris } 14155714Skris 14255714Skris // convert pos according to our offset 14355714Skris pos += fOutOffset; 14455714Skris // Fill the frames after the end of the track with silence. 14555714Skris if (fCountFrames > 0 && pos + frames > fCountFrames) { 14655714Skris int64 size = max(0LL, fCountFrames - pos); 14755714Skris ReadSilence(SkipFrames(buffer, size), frames - size); 14855714Skris frames = size; 14955714Skris } 15055714Skris 15155714Skris TRACE(" after eliminating the frames after the track end: %p, %lld, %lld\n", 15268651Skris buffer, pos, frames); 15355714Skris 15455714Skris#if 0 15555714Skris const media_format& format = Format(); 15655714Skris int64 size = format.u.raw_audio.buffer_size; 15755714Skris uint32 bytesPerFrame = format.u.raw_audio.channel_count 15855714Skris * (format.u.raw_audio.format 15955714Skris & media_raw_audio_format::B_AUDIO_SIZE_MASK); 16055714Skris uint32 framesPerBuffer = size / bytesPerFrame; 16155714Skris 16255714Skris if (fMediaTrack->CurrentFrame() != pos) { 16355714Skrisprintf(" needing to seek: %lld (%lld)\n", pos, 16455714Skris fMediaTrack->CurrentFrame()); 16555714Skris 16655714Skris int64 keyFrame = pos; 16768651Skris error = fMediaTrack->FindKeyFrameForFrame(&keyFrame, 16855714Skris B_MEDIA_SEEK_CLOSEST_BACKWARD); 16955714Skris if (error == B_OK) { 17055714Skris error = fMediaTrack->SeekToFrame(&keyFrame, 17155714Skris B_MEDIA_SEEK_CLOSEST_BACKWARD); 17255714Skris } 17355714Skris if (error != B_OK) { 17455714Skrisprintf(" error seeking to position: %lld (%lld)\n", pos, 17555714Skris fMediaTrack->CurrentFrame()); 17655714Skris 17755714Skris return error; 17855714Skris } 17955714Skris 18055714Skris if (keyFrame < pos) { 18155714Skrisprintf(" need to skip %lld frames\n", pos - keyFrame); 18255714Skris uint8 dummyBuffer[size]; 18355714Skris while (pos - keyFrame >= framesPerBuffer) { 18455714Skrisprintf(" skipped %lu frames (full buffer)\n", framesPerBuffer); 18555714Skris int64 sizeToRead = size; 18655714Skris fMediaTrack->ReadFrames(dummyBuffer, &sizeToRead); 18755714Skris keyFrame += framesPerBuffer; 18855714Skris } 18955714Skris int64 restSize = pos - keyFrame; 19055714Skris if (restSize > 0) { 19155714Skrisprintf(" skipped %lu frames (rest)\n", framesPerBuffer); 19255714Skris fMediaTrack->ReadFrames(dummyBuffer, &restSize); 19355714Skris } 19455714Skris } 19555714Skris } 19655714Skris while (frames > 0) { 19755714Skrisprintf(" reading %lu frames (full buffer)\n", framesPerBuffer); 19855714Skris int64 sizeToRead = min_c(size, frames * bytesPerFrame); 19955714Skris fMediaTrack->ReadFrames(buffer, &sizeToRead); 20055714Skris buffer = (uint8*)buffer + sizeToRead; 20155714Skris frames -= framesPerBuffer; 20255714Skris } 20355714Skrisprintf(" done\n\n"); 20455714Skris 20555714Skris#else 20655714Skris // read the cached frames 20755714Skris bigtime_t time = system_time(); 20855714Skris if (frames > 0) 20955714Skris _ReadCachedFrames(buffer, pos, frames, time); 21055714Skris 21155714Skris TRACE(" after reading from cache: %p, %lld, %lld\n", buffer, pos, frames); 21255714Skris 21355714Skris // read the remaining (uncached) frames 21455714Skris if (frames > 0) 21555714Skris _ReadUncachedFrames(buffer, pos, frames, time); 21655714Skris 21755714Skris#endif 21855714Skris TRACE("Read() done\n"); 21955714Skris 22068651Skris return B_OK; 22155714Skris} 22255714Skris 22355714Skris// InitCheck 22455714Skrisstatus_t 22555714SkrisMediaTrackAudioSupplier::InitCheck() const 22655714Skris{ 22755714Skris status_t error = AudioReader::InitCheck(); 22855714Skris if (error == B_OK && (!fMediaTrack || !fBuffer)) 22955714Skris error = B_NO_INIT; 23055714Skris return error; 23155714Skris} 23255714Skris 23355714Skris// #pragma mark - 23455714Skris 23555714Skris// _InitFromTrack 23655714Skrisvoid 237109998SmarkmMediaTrackAudioSupplier::_InitFromTrack() 23855714Skris{ 23955714Skris TRACE("_InitFromTrack()\n"); 24055714Skris // Try to suggest a big buffer size, we do a lot of caching... 24155714Skris fFormat.u.raw_audio.buffer_size = 16384; 24255714Skris if (fMediaTrack == NULL || fMediaTrack->DecodedFormat(&fFormat) != B_OK 24355714Skris || fFormat.type != B_MEDIA_RAW_AUDIO) { 24455714Skris fMediaTrack = NULL; 24555714Skris return; 24655714Skris } 24755714Skris 24855714Skris #ifdef TRACE_AUDIO_SUPPLIER 24955714Skris char formatString[256]; 25055714Skris string_for_format(fFormat, formatString, 256); 251109998Smarkm TRACE("_InitFromTrack(): format is: %s\n", formatString); 25255714Skris TRACE("_InitFromTrack(): buffer size: %ld\n", 25355714Skris fFormat.u.raw_audio.buffer_size); 25455714Skris #endif 25555714Skris 25655714Skris fBuffer = new (nothrow) char[fFormat.u.raw_audio.buffer_size]; 25755714Skris _AllocateBuffers(); 25855714Skris 25955714Skris // Find out, if the track has key frames: as a heuristic we 26055714Skris // check, if the first and the second frame have the same backward 26155714Skris // key frame. 26255714Skris // Note: It shouldn't harm that much, if we're wrong and the 26355714Skris // track has key frame although we found out that it has not. 26455714Skris#if 0 26555714Skris int64 keyFrame0 = 0; 26655714Skris int64 keyFrame1 = 1; 26755714Skris fMediaTrack->FindKeyFrameForFrame(&keyFrame0, 26855714Skris B_MEDIA_SEEK_CLOSEST_BACKWARD); 26955714Skris fMediaTrack->FindKeyFrameForFrame(&keyFrame1, 27055714Skris B_MEDIA_SEEK_CLOSEST_BACKWARD); 27155714Skris fHasKeyFrames = (keyFrame0 == keyFrame1); 27255714Skris#else 27355714Skris fHasKeyFrames = true; 27455714Skris#endif 27555714Skris 27655714Skris // get the length of the track 27755714Skris fCountFrames = fMediaTrack->CountFrames(); 27855714Skris 27955714Skris TRACE("_InitFromTrack(): keyframes: %d, frame count: %lld\n", 28055714Skris fHasKeyFrames, fCountFrames); 28155714Skris printf("_InitFromTrack(): keyframes: %d, frame count: %lld\n", 28255714Skris fHasKeyFrames, fCountFrames); 28355714Skris} 28455714Skris 28555714Skris// _FramesPerBuffer 28655714Skrisint64 28755714SkrisMediaTrackAudioSupplier::_FramesPerBuffer() const 28855714Skris{ 28955714Skris int64 sampleSize = fFormat.u.raw_audio.format 29055714Skris & media_raw_audio_format::B_AUDIO_SIZE_MASK; 29155714Skris int64 frameSize = sampleSize * fFormat.u.raw_audio.channel_count; 29255714Skris return fFormat.u.raw_audio.buffer_size / frameSize; 29355714Skris} 29455714Skris 29555714Skris// _CopyFrames 29655714Skris// 29755714Skris// Given two buffers starting at different frame offsets, this function 29855714Skris// copies /frames/ frames at position /position/ from the source to the 29955714Skris// target buffer. 30055714Skris// Note that no range checking is done. 30155714Skrisvoid 30255714SkrisMediaTrackAudioSupplier::_CopyFrames(void* source, int64 sourceOffset, 30355714Skris void* target, int64 targetOffset, 30455714Skris int64 position, int64 frames) const 30555714Skris{ 306 int64 sampleSize = fFormat.u.raw_audio.format 307 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 308 int64 frameSize = sampleSize * fFormat.u.raw_audio.channel_count; 309 source = (char*)source + frameSize * (position - sourceOffset); 310 target = (char*)target + frameSize * (position - targetOffset); 311 memcpy(target, source, frames * frameSize); 312} 313 314// _CopyFrames 315// 316// Given two buffers starting at different frame offsets, this function 317// copies /frames/ frames at position /position/ from the source to the 318// target buffer. This version expects a cache buffer as source. 319// Note that no range checking is done. 320void 321MediaTrackAudioSupplier::_CopyFrames(Buffer* buffer, 322 void* target, int64 targetOffset, 323 int64 position, int64 frames) const 324{ 325 _CopyFrames(buffer->data, buffer->offset, target, targetOffset, position, 326 frames); 327} 328 329// _AllocateBuffers 330// 331// Allocates a set of buffers. 332void 333MediaTrackAudioSupplier::_AllocateBuffers() 334{ 335 int32 count = 10; 336 _FreeBuffers(); 337 int32 bufferSize = fFormat.u.raw_audio.buffer_size; 338 char* data = new (nothrow) char[bufferSize * count]; 339 for (; count > 0; count--) { 340 Buffer* buffer = new (nothrow) Buffer; 341 if (!buffer || !fBuffers.AddItem(buffer)) { 342 delete buffer; 343 if (fBuffers.CountItems() == 0) 344 delete[] data; 345 return; 346 } 347 buffer->data = data; 348 data += bufferSize; 349 buffer->offset = 0; 350 buffer->size = 0; 351 buffer->time_stamp = 0; 352 } 353} 354 355// _FreeBuffers 356// 357// Frees the allocated buffers. 358void 359MediaTrackAudioSupplier::_FreeBuffers() 360{ 361 if (fBuffers.CountItems() > 0) { 362 delete[] (char*)_BufferAt(0)->data; 363 for (int32 i = 0; Buffer* buffer = _BufferAt(i); i++) 364 delete buffer; 365 fBuffers.MakeEmpty(); 366 } 367} 368 369// _BufferAt 370// 371// Returns the buffer at index /index/. 372MediaTrackAudioSupplier::Buffer* 373MediaTrackAudioSupplier::_BufferAt(int32 index) const 374{ 375 return (Buffer*)fBuffers.ItemAt(index); 376} 377 378// _FindBufferAtFrame 379// 380// If any buffer starts at offset /frame/, it is returned, NULL otherwise. 381MediaTrackAudioSupplier::Buffer* 382MediaTrackAudioSupplier::_FindBufferAtFrame(int64 frame) const 383{ 384 Buffer* buffer = NULL; 385 for (int32 i = 0; 386 ((buffer = _BufferAt(i))) && buffer->offset != frame; 387 i++); 388 return buffer; 389} 390 391// _FindUnusedBuffer 392// 393// Returns the first unused buffer or NULL if all buffers are used. 394MediaTrackAudioSupplier::Buffer* 395MediaTrackAudioSupplier::_FindUnusedBuffer() const 396{ 397 Buffer* buffer = NULL; 398 for (int32 i = 0; ((buffer = _BufferAt(i))) && buffer->size != 0; i++) 399 ; 400 return buffer; 401} 402 403// _FindUsableBuffer 404// 405// Returns either an unused buffer or, if all buffers are used, the least 406// recently used buffer. 407// In every case a buffer is returned. 408MediaTrackAudioSupplier::Buffer* 409MediaTrackAudioSupplier::_FindUsableBuffer() const 410{ 411 Buffer* result = _FindUnusedBuffer(); 412 if (!result) { 413 // find the least recently used buffer. 414 result = _BufferAt(0); 415 for (int32 i = 1; Buffer* buffer = _BufferAt(i); i++) { 416 if (buffer->time_stamp < result->time_stamp) 417 result = buffer; 418 } 419 } 420 return result; 421} 422 423// _FindUsableBufferFor 424// 425// In case there already exists a buffer that starts at position this 426// one is returned. Otherwise the function returns either an unused 427// buffer or, if all buffers are used, the least recently used buffer. 428// In every case a buffer is returned. 429MediaTrackAudioSupplier::Buffer* 430MediaTrackAudioSupplier::_FindUsableBufferFor(int64 position) const 431{ 432 Buffer* buffer = _FindBufferAtFrame(position); 433 if (buffer == NULL) 434 buffer = _FindUsableBuffer(); 435 return buffer; 436} 437 438// _GetBuffersFor 439// 440// Adds pointers to all buffers to the list that contain data of the 441// supplied interval. 442void 443MediaTrackAudioSupplier::_GetBuffersFor(BList& buffers, int64 position, 444 int64 frames) const 445{ 446 buffers.MakeEmpty(); 447 for (int32 i = 0; Buffer* buffer = _BufferAt(i); i++) { 448 // Calculate the intersecting interval and add the buffer if it is 449 // not empty. 450 int32 startFrame = max(position, buffer->offset); 451 int32 endFrame = min(position + frames, buffer->offset + buffer->size); 452 if (startFrame < endFrame) 453 buffers.AddItem(buffer); 454 } 455} 456 457// _TouchBuffer 458// 459// Sets a buffer's time stamp to the current system time. 460void 461MediaTrackAudioSupplier::_TouchBuffer(Buffer* buffer) 462{ 463 buffer->time_stamp = system_time(); 464} 465 466// _ReadBuffer 467// 468// Read a buffer from the current position (which is supplied in /position/) 469// into /buffer/. The buffer's time stamp is set to the current system time. 470status_t 471MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position) 472{ 473 return _ReadBuffer(buffer, position, system_time()); 474} 475 476// _ReadBuffer 477// 478// Read a buffer from the current position (which is supplied in /position/) 479// into /buffer/. The buffer's time stamp is set to the supplied time. 480status_t 481MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position, 482 bigtime_t time) 483{ 484 status_t error = fMediaTrack->ReadFrames(buffer->data, &buffer->size); 485 486 TRACE("_ReadBuffer(%p, %lld): %s\n", buffer->data, buffer->size, 487 strerror(error)); 488 489 buffer->offset = position; 490 buffer->time_stamp = time; 491 if (error != B_OK) 492 buffer->size = 0; 493 return error; 494} 495 496// _ReadCachedFrames 497// 498// Tries to read as much as possible data from the cache. The supplied 499// buffer pointer as well as position and number of frames are adjusted 500// accordingly. The used cache buffers are stamped with the supplied 501// time. 502void 503MediaTrackAudioSupplier::_ReadCachedFrames(void*& dest, int64& pos, 504 int64& frames, bigtime_t time) 505{ 506 // Get a list of all cache buffers that contain data of the interval, 507 // and sort it. 508 BList buffers(10); 509 _GetBuffersFor(buffers, pos, frames); 510 buffers.SortItems(Buffer::CompareOffset); 511 // Step forward through the list of cache buffers and try to read as 512 // much data from the beginning as possible. 513 for (int32 i = 0; Buffer* buffer = (Buffer*)buffers.ItemAt(i); i++) { 514 if (buffer->offset <= pos && buffer->offset + buffer->size > pos) { 515 // read from the beginning 516 int64 size = min(frames, buffer->offset + buffer->size - pos); 517 _CopyFrames(buffer->data, buffer->offset, dest, pos, pos, size); 518 pos += size; 519 frames -= size; 520 dest = SkipFrames(dest, size); 521 buffer->time_stamp = time; 522 } 523 } 524 // Step backward through the list of cache buffers and try to read as 525 // much data from the end as possible. 526 for (int32 i = buffers.CountItems() - 1; 527 Buffer* buffer = (Buffer*)buffers.ItemAt(i); 528 i++) { 529 if (buffer->offset < pos + frames 530 && buffer->offset + buffer->size >= pos + frames) { 531 // read from the end 532 int64 size = min(frames, pos + frames - buffer->offset); 533 _CopyFrames(buffer->data, buffer->offset, dest, pos, 534 pos + frames - size, size); 535 frames -= size; 536 buffer->time_stamp = time; 537 } 538 } 539} 540 541 542/*! Reads /frames/ frames from /position/ into /buffer/. The frames are not 543 read from the cache, but read frames are cached, if possible. 544 New cache buffers are stamped with the supplied time. 545 If an error occurs, the untouched part of the buffer is set to 0. 546*/ 547status_t 548MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position, 549 int64 frames, bigtime_t time) 550{ 551 TRACE("_ReadUncachedFrames()\n"); 552 status_t error = B_OK; 553 // seek to the position 554 int64 currentPos = position; 555 if (frames > 0) { 556 error = _SeekToKeyFrameBackward(currentPos); 557 TRACE("_ReadUncachedFrames() - seeked to position: %lld\n", currentPos); 558// if (position - currentPos > 100000) 559// printf("MediaTrackAudioSupplier::_ReadUncachedFrames() - " 560// "keyframe was far away: %lld -> %lld\n", position, currentPos); 561 } 562 // read the frames 563 // TODO: Calculate timeout, 0.25 times duration of "frames" seems good. 564 bigtime_t timeout = 10000; 565 while (error == B_OK && frames > 0) { 566 Buffer* cacheBuffer = _FindUsableBufferFor(currentPos); 567 TRACE("_ReadUncachedFrames() - usable buffer found: %p, " 568 "position: %lld/%lld\n", cacheBuffer, currentPos, position); 569 error = _ReadBuffer(cacheBuffer, currentPos, time); 570 if (error == B_OK) { 571 int64 size = min(position + frames, 572 cacheBuffer->offset + cacheBuffer->size) - position; 573 if (size > 0) { 574 _CopyFrames(cacheBuffer, buffer, position, position, size); 575 buffer = SkipFrames(buffer, size); 576 position += size; 577 frames -= size; 578 } 579 currentPos += cacheBuffer->size; 580 } 581 if (system_time() - time > timeout) { 582 error = B_TIMED_OUT; 583 break; 584 } 585 } 586 587#if 0 588 // Ensure that all frames up to the next key frame are cached. 589 // This avoids, that each read reaches the BMediaTrack. 590 if (error == B_OK) { 591 int64 nextKeyFrame = currentPos; 592 if (_FindKeyFrameForward(nextKeyFrame) == B_OK) { 593 while (currentPos < nextKeyFrame) { 594 // Check, if data at this position are cache. 595 // If not read it. 596 Buffer* cacheBuffer = _FindBufferAtFrame(currentPos); 597 if (!cacheBuffer || cacheBuffer->size == 0) { 598 cacheBuffer = _FindUsableBufferFor(currentPos); 599 if (_ReadBuffer(cacheBuffer, currentPos, time) != B_OK) 600 break; 601 } 602 if (cacheBuffer) 603 currentPos += cacheBuffer->size; 604 } 605 } 606 } 607#endif 608 609 // on error fill up the buffer with silence 610 if (error != B_OK && frames > 0) 611 ReadSilence(buffer, frames); 612 return error; 613} 614 615// _FindKeyFrameForward 616status_t 617MediaTrackAudioSupplier::_FindKeyFrameForward(int64& position) 618{ 619 status_t error = B_OK; 620 if (fHasKeyFrames) { 621 error = fMediaTrack->FindKeyFrameForFrame( 622 &position, B_MEDIA_SEEK_CLOSEST_FORWARD); 623 } else { 624 int64 framesPerBuffer = _FramesPerBuffer(); 625 position += framesPerBuffer - 1; 626 position = position % framesPerBuffer; 627 } 628 return error; 629} 630 631// _FindKeyFrameBackward 632status_t 633MediaTrackAudioSupplier::_FindKeyFrameBackward(int64& position) 634{ 635 status_t error = B_OK; 636 if (fHasKeyFrames) { 637 error = fMediaTrack->FindKeyFrameForFrame( 638 &position, B_MEDIA_SEEK_CLOSEST_BACKWARD); 639 } else 640 position -= position % _FramesPerBuffer(); 641 return error; 642} 643 644#if 0 645// _SeekToKeyFrameForward 646status_t 647MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position) 648{ 649 if (position == fMediaTrack->CurrentFrame()) 650 return B_OK; 651 652 status_t error = B_OK; 653 if (fHasKeyFrames) { 654 #ifdef TRACE_AUDIO_SUPPLIER 655 int64 oldPosition = position; 656 #endif 657 error = fMediaTrack->SeekToFrame(&position, 658 B_MEDIA_SEEK_CLOSEST_FORWARD); 659 TRACE("_SeekToKeyFrameForward() - seek to key frame forward: " 660 "%lld -> %lld (%lld)\n", oldPosition, position, 661 fMediaTrack->CurrentFrame()); 662 } else { 663 _FindKeyFrameForward(position); 664 error = fMediaTrack->SeekToFrame(&position); 665 } 666 return error; 667} 668#endif 669 670// _SeekToKeyFrameBackward 671status_t 672MediaTrackAudioSupplier::_SeekToKeyFrameBackward(int64& position) 673{ 674 int64 currentPosition = fMediaTrack->CurrentFrame(); 675 if (position == currentPosition) 676 return B_OK; 677 678 status_t error = B_OK; 679 if (fHasKeyFrames) { 680 int64 wantedPosition = position; 681 error = fMediaTrack->FindKeyFrameForFrame(&position, 682 B_MEDIA_SEEK_CLOSEST_BACKWARD); 683 if (error == B_OK && currentPosition > position 684 && currentPosition < wantedPosition) { 685 // The current position is before the wanted position, 686 // but later than the keyframe, so seeking is worse. 687 position = currentPosition; 688 return B_OK; 689 } 690 if (error == B_OK && position > wantedPosition) { 691 // We asked to seek backwards, but the extractor seeked 692 // forwards! Returning an error here will cause silence 693 // to be produced. 694 return B_ERROR; 695 } 696 if (error == B_OK) 697 error = fMediaTrack->SeekToFrame(&position, 0); 698 if (error != B_OK) { 699 position = fMediaTrack->CurrentFrame(); 700// if (fReportSeekError) { 701 printf(" seek to key frame backward: %lld -> %lld (%lld) " 702 "- %s\n", wantedPosition, position, 703 fMediaTrack->CurrentFrame(), strerror(error)); 704 fReportSeekError = false; 705// } 706 } else { 707 fReportSeekError = true; 708 } 709 } else { 710 _FindKeyFrameBackward(position); 711 error = fMediaTrack->SeekToFrame(&position); 712 } 713 return error; 714} 715 716