1 /* 2 * Copyright © 2000-2004 Ingo Weinhold <ingo_weinhold@gmx.de> 3 * Copyright © 2006-2008 Stephan Aßmus <superstippi@gmx.de> 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 #include "MediaTrackAudioSupplier.h" 7 8 #include <new> 9 #include <algorithm> 10 #include <stdio.h> 11 #include <string.h> 12 13 #include <MediaFile.h> 14 #include <MediaTrack.h> 15 16 using namespace std; 17 18 //#define TRACE_AUDIO_SUPPLIER 19 #ifdef TRACE_AUDIO_SUPPLIER 20 # define TRACE(x...) printf("MediaTrackAudioSupplier::" x) 21 #else 22 # define TRACE(x...) 23 #endif 24 25 26 // #pragma mark - Buffer 27 28 29 struct MediaTrackAudioSupplier::Buffer { 30 void* data; 31 int64 offset; 32 int64 size; 33 bigtime_t time_stamp; 34 35 static int CompareOffset(const void* a, const void* b); 36 }; 37 38 39 int 40 MediaTrackAudioSupplier::Buffer::CompareOffset(const void* a, const void* b) 41 { 42 const Buffer* buffer1 = *(const Buffer**)a; 43 const Buffer* buffer2 = *(const Buffer**)b; 44 int result = 0; 45 if (buffer1->offset < buffer2->offset) 46 result = -1; 47 else if (buffer1->offset > buffer2->offset) 48 result = 1; 49 return result; 50 } 51 52 53 // #pragma mark - MediaTrackAudioSupplier 54 55 56 MediaTrackAudioSupplier::MediaTrackAudioSupplier(BMediaTrack* mediaTrack, 57 int32 trackIndex) 58 : AudioTrackSupplier(), 59 fMediaTrack(mediaTrack), 60 fBuffer(NULL), 61 fBufferOffset(0), 62 fBufferSize(0), 63 fBuffers(10), 64 fHasKeyFrames(false), 65 fCountFrames(0), 66 fReportSeekError(true), 67 fTrackIndex(trackIndex) 68 { 69 _InitFromTrack(); 70 } 71 72 73 MediaTrackAudioSupplier::~MediaTrackAudioSupplier() 74 { 75 _FreeBuffers(); 76 delete[] fBuffer; 77 } 78 79 80 const media_format& 81 MediaTrackAudioSupplier::Format() const 82 { 83 return AudioReader::Format(); 84 } 85 86 87 status_t 88 MediaTrackAudioSupplier::GetEncodedFormat(media_format* format) const 89 { 90 if (!fMediaTrack) 91 return B_NO_INIT; 92 return fMediaTrack->EncodedFormat(format); 93 } 94 95 96 status_t 97 MediaTrackAudioSupplier::GetCodecInfo(media_codec_info* info) const 98 { 99 if (!fMediaTrack) 100 return B_NO_INIT; 101 return fMediaTrack->GetCodecInfo(info); 102 } 103 104 105 bigtime_t 106 MediaTrackAudioSupplier::Duration() const 107 { 108 if (!fMediaTrack) 109 return 0; 110 111 return fMediaTrack->Duration(); 112 } 113 114 115 // #pragma mark - AudioReader 116 117 118 bigtime_t 119 MediaTrackAudioSupplier::InitialLatency() const 120 { 121 // TODO: this is just a wild guess, and not really founded on anything. 122 return 100000; 123 } 124 125 126 status_t 127 MediaTrackAudioSupplier::Read(void* buffer, int64 pos, int64 frames) 128 { 129 TRACE("Read(%p, %lld, %lld)\n", buffer, pos, 130 frames); 131 TRACE(" this: %p, fOutOffset: %lld\n", this, fOutOffset); 132 133 //printf("MediaTrackAudioSupplier::Read(%p, %lld, %lld)\n", buffer, pos, frames); 134 135 status_t error = InitCheck(); 136 if (error != B_OK) { 137 TRACE("Read() InitCheck failed\n"); 138 return error; 139 } 140 141 // convert pos according to our offset 142 pos += fOutOffset; 143 // Fill the frames after the end of the track with silence. 144 if (fCountFrames > 0 && pos + frames > fCountFrames) { 145 int64 size = max(0LL, fCountFrames - pos); 146 ReadSilence(SkipFrames(buffer, size), frames - size); 147 frames = size; 148 } 149 150 TRACE(" after eliminating the frames after the track end: %p, %lld, %lld\n", 151 buffer, pos, frames); 152 153 #if 0 154 const media_format& format = Format(); 155 int64 size = format.u.raw_audio.buffer_size; 156 uint32 bytesPerFrame = format.u.raw_audio.channel_count 157 * (format.u.raw_audio.format 158 & media_raw_audio_format::B_AUDIO_SIZE_MASK); 159 uint32 framesPerBuffer = size / bytesPerFrame; 160 161 if (fMediaTrack->CurrentFrame() != pos) { 162 printf(" needing to seek: %lld (%lld)\n", pos, 163 fMediaTrack->CurrentFrame()); 164 165 int64 keyFrame = pos; 166 error = fMediaTrack->FindKeyFrameForFrame(&keyFrame, 167 B_MEDIA_SEEK_CLOSEST_BACKWARD); 168 if (error == B_OK) { 169 error = fMediaTrack->SeekToFrame(&keyFrame, 170 B_MEDIA_SEEK_CLOSEST_BACKWARD); 171 } 172 if (error != B_OK) { 173 printf(" error seeking to position: %lld (%lld)\n", pos, 174 fMediaTrack->CurrentFrame()); 175 176 return error; 177 } 178 179 if (keyFrame < pos) { 180 printf(" need to skip %lld frames\n", pos - keyFrame); 181 uint8 dummyBuffer[size]; 182 while (pos - keyFrame >= framesPerBuffer) { 183 printf(" skipped %lu frames (full buffer)\n", framesPerBuffer); 184 int64 sizeToRead = size; 185 fMediaTrack->ReadFrames(dummyBuffer, &sizeToRead); 186 keyFrame += framesPerBuffer; 187 } 188 int64 restSize = pos - keyFrame; 189 if (restSize > 0) { 190 printf(" skipped %lu frames (rest)\n", framesPerBuffer); 191 fMediaTrack->ReadFrames(dummyBuffer, &restSize); 192 } 193 } 194 } 195 while (frames > 0) { 196 printf(" reading %lu frames (full buffer)\n", framesPerBuffer); 197 int64 sizeToRead = min_c(size, frames * bytesPerFrame); 198 fMediaTrack->ReadFrames(buffer, &sizeToRead); 199 buffer = (uint8*)buffer + sizeToRead; 200 frames -= framesPerBuffer; 201 } 202 printf(" done\n\n"); 203 204 #else 205 // read the cached frames 206 bigtime_t time = system_time(); 207 if (frames > 0) 208 _ReadCachedFrames(buffer, pos, frames, time); 209 210 TRACE(" after reading from cache: %p, %lld, %lld\n", buffer, pos, frames); 211 212 // read the remaining (uncached) frames 213 if (frames > 0) 214 _ReadUncachedFrames(buffer, pos, frames, time); 215 216 #endif 217 TRACE("Read() done\n"); 218 219 return B_OK; 220 } 221 222 // InitCheck 223 status_t 224 MediaTrackAudioSupplier::InitCheck() const 225 { 226 status_t error = AudioReader::InitCheck(); 227 if (error == B_OK && (!fMediaTrack || !fBuffer)) 228 error = B_NO_INIT; 229 return error; 230 } 231 232 // #pragma mark - 233 234 // _InitFromTrack 235 void 236 MediaTrackAudioSupplier::_InitFromTrack() 237 { 238 if (fMediaTrack && fMediaTrack->DecodedFormat(&fFormat) == B_OK 239 && fFormat.type == B_MEDIA_RAW_AUDIO) { 240 241 #ifdef TRACE_AUDIO_SUPPLIER 242 char formatString[256]; 243 string_for_format(fFormat, formatString, 256); 244 TRACE("MediaTrackAudioSupplier: format is: %s\n", formatString); 245 #endif 246 247 fBuffer = new (nothrow) char[fFormat.u.raw_audio.buffer_size]; 248 _AllocateBuffers(); 249 250 // Find out, if the track has key frames: as a heuristic we 251 // check, if the first and the second frame have the same backward 252 // key frame. 253 // Note: It shouldn't harm that much, if we're wrong and the 254 // track has key frame although we found out that it has not. 255 int64 keyFrame0 = 0; 256 int64 keyFrame1 = 1; 257 fMediaTrack->FindKeyFrameForFrame(&keyFrame0, 258 B_MEDIA_SEEK_CLOSEST_BACKWARD); 259 fMediaTrack->FindKeyFrameForFrame(&keyFrame1, 260 B_MEDIA_SEEK_CLOSEST_BACKWARD); 261 fHasKeyFrames = (keyFrame0 == keyFrame1); 262 263 // get the length of the track 264 fCountFrames = fMediaTrack->CountFrames(); 265 266 TRACE("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n", 267 fHasKeyFrames, fCountFrames); 268 printf("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n", 269 fHasKeyFrames, fCountFrames); 270 } else 271 fMediaTrack = NULL; 272 } 273 274 // _FramesPerBuffer 275 int64 276 MediaTrackAudioSupplier::_FramesPerBuffer() const 277 { 278 int64 sampleSize = fFormat.u.raw_audio.format 279 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 280 int64 frameSize = sampleSize * fFormat.u.raw_audio.channel_count; 281 return fFormat.u.raw_audio.buffer_size / frameSize; 282 } 283 284 // _CopyFrames 285 // 286 // Given two buffers starting at different frame offsets, this function 287 // copies /frames/ frames at position /position/ from the source to the 288 // target buffer. 289 // Note that no range checking is done. 290 void 291 MediaTrackAudioSupplier::_CopyFrames(void* source, int64 sourceOffset, 292 void* target, int64 targetOffset, 293 int64 position, int64 frames) const 294 { 295 int64 sampleSize = fFormat.u.raw_audio.format 296 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 297 int64 frameSize = sampleSize * fFormat.u.raw_audio.channel_count; 298 source = (char*)source + frameSize * (position - sourceOffset); 299 target = (char*)target + frameSize * (position - targetOffset); 300 memcpy(target, source, frames * frameSize); 301 } 302 303 // _CopyFrames 304 // 305 // Given two buffers starting at different frame offsets, this function 306 // copies /frames/ frames at position /position/ from the source to the 307 // target buffer. This version expects a cache buffer as source. 308 // Note that no range checking is done. 309 void 310 MediaTrackAudioSupplier::_CopyFrames(Buffer* buffer, 311 void* target, int64 targetOffset, 312 int64 position, int64 frames) const 313 { 314 _CopyFrames(buffer->data, buffer->offset, target, targetOffset, position, 315 frames); 316 } 317 318 // _AllocateBuffers 319 // 320 // Allocates a set of buffers. 321 void 322 MediaTrackAudioSupplier::_AllocateBuffers() 323 { 324 int32 count = 10; 325 _FreeBuffers(); 326 int32 bufferSize = fFormat.u.raw_audio.buffer_size; 327 char* data = new (nothrow) char[bufferSize * count]; 328 for (; count > 0; count--) { 329 Buffer* buffer = new (nothrow) Buffer; 330 if (!buffer || !fBuffers.AddItem(buffer)) { 331 delete buffer; 332 if (fBuffers.CountItems() == 0) 333 delete[] data; 334 return; 335 } 336 buffer->data = data; 337 data += bufferSize; 338 buffer->offset = 0; 339 buffer->size = 0; 340 buffer->time_stamp = 0; 341 } 342 } 343 344 // _FreeBuffers 345 // 346 // Frees the allocated buffers. 347 void 348 MediaTrackAudioSupplier::_FreeBuffers() 349 { 350 if (fBuffers.CountItems() > 0) { 351 delete[] (char*)_BufferAt(0)->data; 352 for (int32 i = 0; Buffer* buffer = _BufferAt(i); i++) 353 delete buffer; 354 fBuffers.MakeEmpty(); 355 } 356 } 357 358 // _BufferAt 359 // 360 // Returns the buffer at index /index/. 361 MediaTrackAudioSupplier::Buffer* 362 MediaTrackAudioSupplier::_BufferAt(int32 index) const 363 { 364 return (Buffer*)fBuffers.ItemAt(index); 365 } 366 367 // _FindBufferAtFrame 368 // 369 // If any buffer starts at offset /frame/, it is returned, NULL otherwise. 370 MediaTrackAudioSupplier::Buffer* 371 MediaTrackAudioSupplier::_FindBufferAtFrame(int64 frame) const 372 { 373 Buffer* buffer = NULL; 374 for (int32 i = 0; 375 ((buffer = _BufferAt(i))) && buffer->offset != frame; 376 i++); 377 return buffer; 378 } 379 380 // _FindUnusedBuffer 381 // 382 // Returns the first unused buffer or NULL if all buffers are used. 383 MediaTrackAudioSupplier::Buffer* 384 MediaTrackAudioSupplier::_FindUnusedBuffer() const 385 { 386 Buffer* buffer = NULL; 387 for (int32 i = 0; ((buffer = _BufferAt(i))) && buffer->size != 0; i++); 388 return buffer; 389 } 390 391 // _FindUsableBuffer 392 // 393 // Returns either an unused buffer or, if all buffers are used, the least 394 // recently used buffer. 395 // In every case a buffer is returned. 396 MediaTrackAudioSupplier::Buffer* 397 MediaTrackAudioSupplier::_FindUsableBuffer() const 398 { 399 Buffer* result = _FindUnusedBuffer(); 400 if (!result) { 401 // find the least recently used buffer. 402 result = _BufferAt(0); 403 for (int32 i = 1; Buffer* buffer = _BufferAt(i); i++) { 404 if (buffer->time_stamp < result->time_stamp) 405 result = buffer; 406 } 407 } 408 return result; 409 } 410 411 // _FindUsableBufferFor 412 // 413 // In case there already exists a buffer that starts at position this 414 // one is returned. Otherwise the function returns either an unused 415 // buffer or, if all buffers are used, the least recently used buffer. 416 // In every case a buffer is returned. 417 MediaTrackAudioSupplier::Buffer* 418 MediaTrackAudioSupplier::_FindUsableBufferFor(int64 position) const 419 { 420 Buffer* buffer = _FindBufferAtFrame(position); 421 if (!buffer) 422 buffer = _FindUsableBuffer(); 423 return buffer; 424 } 425 426 // _GetBuffersFor 427 // 428 // Adds pointers to all buffers to the list that contain data of the 429 // supplied interval. 430 void 431 MediaTrackAudioSupplier::_GetBuffersFor(BList& buffers, int64 position, 432 int64 frames) const 433 { 434 buffers.MakeEmpty(); 435 for (int32 i = 0; Buffer* buffer = _BufferAt(i); i++) { 436 // Calculate the intersecting interval and add the buffer if it is 437 // not empty. 438 int32 startFrame = max(position, buffer->offset); 439 int32 endFrame = min(position + frames, buffer->offset + buffer->size); 440 if (startFrame < endFrame) 441 buffers.AddItem(buffer); 442 } 443 } 444 445 // _TouchBuffer 446 // 447 // Sets a buffer's time stamp to the current system time. 448 void 449 MediaTrackAudioSupplier::_TouchBuffer(Buffer* buffer) 450 { 451 buffer->time_stamp = system_time(); 452 } 453 454 // _ReadBuffer 455 // 456 // Read a buffer from the current position (which is supplied in /position/) 457 // into /buffer/. The buffer's time stamp is set to the current system time. 458 status_t 459 MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position) 460 { 461 return _ReadBuffer(buffer, position, system_time()); 462 } 463 464 // _ReadBuffer 465 // 466 // Read a buffer from the current position (which is supplied in /position/) 467 // into /buffer/. The buffer's time stamp is set to the supplied time. 468 status_t 469 MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position, 470 bigtime_t time) 471 { 472 status_t error = fMediaTrack->ReadFrames(buffer->data, &buffer->size); 473 474 TRACE("Read(%p, %lld): %s\n", buffer->data, buffer->size, strerror(error)); 475 476 buffer->offset = position; 477 buffer->time_stamp = time; 478 if (error != B_OK) 479 buffer->size = 0; 480 return error; 481 } 482 483 // _ReadCachedFrames 484 // 485 // Tries to read as much as possible data from the cache. The supplied 486 // buffer pointer as well as position and number of frames are adjusted 487 // accordingly. The used cache buffers are stamped with the supplied 488 // time. 489 void 490 MediaTrackAudioSupplier::_ReadCachedFrames(void*& dest, int64& pos, 491 int64& frames, bigtime_t time) 492 { 493 // Get a list of all cache buffers that contain data of the interval, 494 // and sort it. 495 BList buffers(10); 496 _GetBuffersFor(buffers, pos, frames); 497 buffers.SortItems(Buffer::CompareOffset); 498 // Step forward through the list of cache buffers and try to read as 499 // much data from the beginning as possible. 500 for (int32 i = 0; Buffer* buffer = (Buffer*)buffers.ItemAt(i); i++) { 501 if (buffer->offset <= pos && buffer->offset + buffer->size > pos) { 502 // read from the beginning 503 int64 size = min(frames, buffer->offset + buffer->size - pos); 504 _CopyFrames(buffer->data, buffer->offset, dest, pos, pos, size); 505 pos += size; 506 frames -= size; 507 dest = SkipFrames(dest, size); 508 buffer->time_stamp = time; 509 } 510 } 511 // Step backward through the list of cache buffers and try to read as 512 // much data from the end as possible. 513 for (int32 i = buffers.CountItems() - 1; 514 Buffer* buffer = (Buffer*)buffers.ItemAt(i); 515 i++) { 516 if (buffer->offset < pos + frames 517 && buffer->offset + buffer->size >= pos + frames) { 518 // read from the end 519 int64 size = min(frames, pos + frames - buffer->offset); 520 _CopyFrames(buffer->data, buffer->offset, dest, pos, 521 pos + frames - size, size); 522 frames -= size; 523 buffer->time_stamp = time; 524 } 525 } 526 } 527 528 529 /*! Reads /frames/ frames from /position/ into /buffer/. The frames are not 530 read from the cache, but read frames are cached, if possible. 531 New cache buffers are stamped with the supplied time. 532 If an error occurs, the untouched part of the buffer is set to 0. 533 */ 534 status_t 535 MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position, 536 int64 frames, bigtime_t time) 537 { 538 TRACE("_ReadUncachedFrames()\n"); 539 status_t error = B_OK; 540 // seek to the position 541 int64 currentPos = position; 542 if (frames > 0) { 543 error = _SeekToKeyFrameBackward(currentPos); 544 TRACE("_ReadUncachedFrames() - seeked to position: %lld\n", currentPos); 545 } 546 // read the frames 547 while (error == B_OK && frames > 0) { 548 Buffer* cacheBuffer = _FindUsableBufferFor(currentPos); 549 TRACE("_ReadUncachedFrames() - usable buffer found: %p\n", cacheBuffer); 550 error = _ReadBuffer(cacheBuffer, currentPos, time); 551 if (error == B_OK) { 552 int64 size = min(position + frames, 553 cacheBuffer->offset + cacheBuffer->size) 554 - position; 555 if (size > 0) { 556 _CopyFrames(cacheBuffer, buffer, position, position, size); 557 buffer = SkipFrames(buffer, size); 558 position += size; 559 frames -= size; 560 } 561 currentPos += cacheBuffer->size; 562 } 563 } 564 565 #if 1 566 // Ensure that all frames up to the next key frame are cached. 567 // This avoids, that each read reaches the BMediaTrack. 568 if (error == B_OK) { 569 int64 nextKeyFrame = currentPos; 570 if (_FindKeyFrameForward(nextKeyFrame) == B_OK) { 571 while (currentPos < nextKeyFrame) { 572 // Check, if data at this position are cache. 573 // If not read it. 574 Buffer* cacheBuffer = _FindBufferAtFrame(currentPos); 575 if (!cacheBuffer || cacheBuffer->size == 0) { 576 cacheBuffer = _FindUsableBufferFor(currentPos); 577 if (_ReadBuffer(cacheBuffer, currentPos, time) != B_OK) 578 break; 579 } 580 if (cacheBuffer) 581 currentPos += cacheBuffer->size; 582 } 583 } 584 } 585 #endif 586 587 // on error fill up the buffer with silence 588 if (error != B_OK && frames > 0) 589 ReadSilence(buffer, frames); 590 return error; 591 } 592 593 // _FindKeyFrameForward 594 status_t 595 MediaTrackAudioSupplier::_FindKeyFrameForward(int64& position) 596 { 597 status_t error = B_OK; 598 #ifdef __HAIKU__ 599 if (fHasKeyFrames) { 600 error = fMediaTrack->FindKeyFrameForFrame( 601 &position, B_MEDIA_SEEK_CLOSEST_FORWARD); 602 } else 603 #endif 604 { 605 int64 framesPerBuffer = _FramesPerBuffer(); 606 position += framesPerBuffer - 1; 607 position = position % framesPerBuffer; 608 } 609 return error; 610 } 611 612 // _FindKeyFrameBackward 613 status_t 614 MediaTrackAudioSupplier::_FindKeyFrameBackward(int64& position) 615 { 616 status_t error = B_OK; 617 if (fHasKeyFrames) { 618 error = fMediaTrack->FindKeyFrameForFrame( 619 &position, B_MEDIA_SEEK_CLOSEST_BACKWARD); 620 } else 621 position -= position % _FramesPerBuffer(); 622 return error; 623 } 624 625 #if 0 626 // _SeekToKeyFrameForward 627 status_t 628 MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position) 629 { 630 if (position == fMediaTrack->CurrentFrame()) 631 return B_OK; 632 633 status_t error = B_OK; 634 if (fHasKeyFrames) { 635 #ifdef TRACE_AUDIO_SUPPLIER 636 int64 oldPosition = position; 637 #endif 638 error = fMediaTrack->SeekToFrame(&position, 639 B_MEDIA_SEEK_CLOSEST_FORWARD); 640 TRACE("_SeekToKeyFrameForward() - seek to key frame forward: " 641 "%lld -> %lld (%lld)\n", oldPosition, position, 642 fMediaTrack->CurrentFrame()); 643 } else { 644 _FindKeyFrameForward(position); 645 error = fMediaTrack->SeekToFrame(&position); 646 } 647 return error; 648 } 649 #endif 650 651 // _SeekToKeyFrameBackward 652 status_t 653 MediaTrackAudioSupplier::_SeekToKeyFrameBackward(int64& position) 654 { 655 if (position == fMediaTrack->CurrentFrame()) 656 return B_OK; 657 658 status_t error = B_OK; 659 if (fHasKeyFrames) { 660 int64 oldPosition = position; 661 error = fMediaTrack->FindKeyFrameForFrame(&position, 662 B_MEDIA_SEEK_CLOSEST_BACKWARD); 663 if (error == B_OK) 664 error = fMediaTrack->SeekToFrame(&position, 0); 665 if (error != B_OK) { 666 position = fMediaTrack->CurrentFrame(); 667 // if (fReportSeekError) { 668 printf(" seek to key frame backward: %lld -> %lld (%lld) " 669 "- %s\n", oldPosition, position, 670 fMediaTrack->CurrentFrame(), strerror(error)); 671 fReportSeekError = false; 672 // } 673 } else { 674 fReportSeekError = true; 675 } 676 } else { 677 _FindKeyFrameBackward(position); 678 error = fMediaTrack->SeekToFrame(&position); 679 } 680 return error; 681 } 682 683