FastLED 3.10.8
Loading...
Searching...
No Matches

◆ findAndDecodeFrame()

bool fl::third_party::Mp3StreamDecoderImpl::findAndDecodeFrame ( audio::Sample * out_sample)
private

Definition at line 425 of file mp3.cpp.hpp.

425 {
426 if (!mDecoder) {
427 return false;
428 }
429
430 // Try to decode from current buffer
431 const fl::u8* inptr = mBuffer.get() + mBufferPos;
432 fl::size bytes_left = mBufferFilled - mBufferPos;
433
434 if (bytes_left == 0) {
435 return false;
436 }
437
438 // Find sync word
439 int offset = mDecoder->findSyncWord(inptr, bytes_left);
440 if (offset < 0) {
441 // No sync word found, consume buffer and try again
443 return false;
444 }
445
446 inptr += offset;
447 bytes_left -= offset;
449
450 // Try to decode one frame
451 const fl::u8* decode_ptr = inptr;
452 fl::size decode_bytes = bytes_left;
453
454 /* The first frame may be a Xing/Info/VBRI header rather than audio. It is
455 a complete, valid MPEG frame, so decoding it emits noise before the
456 music; LAME also records how much encoder priming follows it. Inspect
457 before decoding so the frame can be dropped whole (FastLED#4129). */
460 Mp3VbrTag tag;
461 if (Mp3ParseVbrTag(fl::span<const fl::u8>(inptr, bytes_left), &tag) &&
462 tag.present) {
463 mSkipTagFrame = true;
464 mSkipSamples = tag.encoderDelay + MP3D_DECODER_DELAY;
465 }
466 }
467
468 int result = mDecoder->decodeFrame(&decode_ptr, &decode_bytes);
469
470 // Update buffer position based on how many bytes were consumed
471 fl::size consumed = (decode_ptr - inptr);
472 if (result != 0 && consumed == 0 && bytes_left == BUFFER_SIZE) {
473 // A full buffer cannot grow to complete this frame. Drop one byte so
474 // corrupt input cannot pin the streaming decoder on the same sync.
475 consumed = 1;
476 }
477 mBufferPos += consumed;
478 mBytesProcessed += consumed;
479
480 if (result == 0 && mSkipTagFrame) {
481 // The metadata frame itself: consumed above, never emitted.
482 mSkipTagFrame = false;
483 return false;
484 }
485
486 if (result == 0) {
487 // Successfully decoded a frame
488 Mp3Frame frame;
489 frame.pcm = mDecoder->mPcmBuffer.get();
490 frame.samples = mDecoder->mFrameInfo.outputSamps / mDecoder->mFrameInfo.nChans;
491 frame.channels = mDecoder->mFrameInfo.nChans;
492 frame.sample_rate = mDecoder->mFrameInfo.samprate;
493 frame.bitrate = mDecoder->mFrameInfo.bitrate;
494 frame.version = mDecoder->mFrameInfo.version;
495 frame.layer = mDecoder->mFrameInfo.layer;
496
497 // Update stream info on first successful decode
499 mInfo.sampleRate = frame.sample_rate;
500 mInfo.channels = static_cast<fl::u8>(frame.channels);
501 mInfo.bitrate = frame.bitrate;
502 mInfo.version = static_cast<fl::u8>(frame.version);
503 mInfo.layer = static_cast<fl::u8>(frame.layer);
504 mInfo.isValid = true;
506 }
507
508 /* Encoder priming plus the filterbank's own latency: not signal, and
509 audible as a burst at the start of playback if emitted. */
510 int first = 0;
511 if (mSkipSamples > 0) {
512 const fl::u32 available = static_cast<fl::u32>(frame.samples);
513 const fl::u32 drop =
515 first = static_cast<int>(drop);
516 mSkipSamples -= drop;
517 if (first >= frame.samples) {
518 return false; // whole frame was priming
519 }
520 }
521 const int emitted = frame.samples - first;
522
523 // Convert to audio::Sample (convert stereo to mono if needed)
524 if (frame.channels == 2) {
525 fl::vector<fl::i16> mono_pcm;
526 mono_pcm.reserve(emitted);
527
528 for (int i = first; i < frame.samples; i++) {
529 fl::i32 left = frame.pcm[i * 2];
530 fl::i32 right = frame.pcm[i * 2 + 1];
531 fl::i32 avg = (left + right) / 2;
532 mono_pcm.push_back(static_cast<fl::i16>(avg));
533 }
534
535 *out_sample = audio::Sample(mono_pcm);
536 } else {
537 // Mono audio - use directly
538 *out_sample = audio::Sample(
539 fl::span<const fl::i16>(frame.pcm + first, emitted));
540 }
541
542 return true;
543 }
544
545 return false;
546}
fl::unique_ptr< fl::u8[], Mp3MemoryDeleter< fl::u8 > > mBuffer
Definition mp3.cpp.hpp:306
static constexpr fl::size BUFFER_SIZE
Definition mp3.cpp.hpp:282
fl::unique_ptr< Mp3SelectedDecoder > mDecoder
Definition mp3.cpp.hpp:305
void reserve(fl::size n) FL_NO_EXCEPT
Definition vector.h:591
void push_back(const T &value) FL_NO_EXCEPT
Definition vector.h:624
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
bool Mp3ParseVbrTag(fl::span< const fl::u8 > bytes, Mp3VbrTag *out) FL_NO_EXCEPT
Definition mp3_vbr_tag.h:75
static const fl::u32 MP3D_DECODER_DELAY
Metadata carried by an MP3's first frame when an encoder wrote a Xing, Info, or VBRI header there.
Definition mp3_vbr_tag.h:35
unsigned char u8
Definition stdint.h:131
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
int available() FL_NO_EXCEPT

References fl::available(), fl::third_party::Mp3Frame::bitrate, BUFFER_SIZE, fl::third_party::Mp3Frame::channels, fl::third_party::Mp3VbrTag::encoderDelay, fl::FL_NO_EXCEPT, fl::third_party::Mp3Frame::layer, mBuffer, mBufferFilled, mBufferPos, mBytesProcessed, mDecoder, mHasDecodedFirstFrame, mInfo, mInspectedFirstFrame, fl::third_party::MP3D_DECODER_DELAY, fl::third_party::Mp3ParseVbrTag(), mSkipSamples, mSkipTagFrame, offset(), fl::third_party::Mp3Frame::pcm, fl::third_party::Mp3VbrTag::present, fl::vector< T >::push_back(), fl::vector< T >::reserve(), fl::third_party::Mp3Frame::sample_rate, fl::third_party::Mp3Frame::samples, and fl::third_party::Mp3Frame::version.

Referenced by decodeNextFrame().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: