Bug Fix: Fix minimp3 streaming support
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run

The streaming support was breaking because initial packet detection was
failing due to bit reservoir errors. Instead, detect consecutive sync
frames in the initial read buffer, then attempt to sync to a decodable
frame in the first block of data, otherwise give up.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2025-03-24 08:16:37 -07:00
parent 2237863f08
commit 18d3f76152
2 changed files with 27 additions and 15 deletions

View file

@ -15,11 +15,11 @@
#import "Plugin.h" #import "Plugin.h"
#define INPUT_BUFFER_SIZE 16 * 1024 //#define INPUT_BUFFER_SIZE 16 * 1024 // superceded by MINIMP3_BUF_SIZE, which has been altered
@interface MP3Decoder : NSObject <CogDecoder> { @interface MP3Decoder : NSObject <CogDecoder> {
BOOL seekable; BOOL seekable;
unsigned char _decoder_buffer[INPUT_BUFFER_SIZE]; unsigned char _decoder_buffer[MINIMP3_BUF_SIZE];
size_t _decoder_buffer_filled; size_t _decoder_buffer_filled;
mp3dec_ex_t _decoder_ex; mp3dec_ex_t _decoder_ex;

View file

@ -161,20 +161,28 @@ static int mp3_seek_callback(uint64_t position, void *user_data) {
} }
bitrate = (double)((_fileSize - id3_length) * 8) / ((double)totalFrames / (double)_decoder_info.hz) / 1000.0; bitrate = (double)((_fileSize - id3_length) * 8) / ((double)totalFrames / (double)_decoder_info.hz) / 1000.0;
} else { } else {
_decoder_buffer_filled = [source read:_decoder_buffer amount:INPUT_BUFFER_SIZE]; _decoder_buffer_filled = [source read:_decoder_buffer amount:MINIMP3_BUF_SIZE];
inputEOF = _decoder_buffer_filled < INPUT_BUFFER_SIZE; inputEOF = _decoder_buffer_filled < MINIMP3_BUF_SIZE;
mp3dec_init(&_decoder_ex.mp3d); mp3dec_init(&_decoder_ex.mp3d);
int samples = mp3dec_decode_frame(&_decoder_ex.mp3d, _decoder_buffer, (int)_decoder_buffer_filled, &_decoder_buffer_output[0], &_decoder_info); int error = mp3dec_detect_buf(_decoder_buffer, _decoder_buffer_filled);
if(!samples) if(error)
return NO; return NO;
size_t bytes_read = _decoder_info.frame_bytes;
if(bytes_read >= _decoder_buffer_filled) { for(;;) {
_decoder_buffer_filled = 0; error = mp3dec_decode_frame(&_decoder_ex.mp3d, _decoder_buffer, (int)_decoder_buffer_filled, &_decoder_buffer_output[0], &_decoder_info);
} else { if(_decoder_info.frame_bytes > _decoder_buffer_filled) {
_decoder_buffer_filled -= bytes_read; break;
memmove(&_decoder_buffer[0], &_decoder_buffer[bytes_read], _decoder_buffer_filled);
} }
samples_filled = samples; _decoder_buffer_filled -= _decoder_info.frame_bytes;
memmove(&_decoder_buffer[0], &_decoder_buffer[_decoder_info.frame_bytes], _decoder_buffer_filled);
if(error) {
break;
}
}
if(!error) {
return NO;
}
samples_filled = error;
bitrate = _decoder_info.bitrate_kbps; bitrate = _decoder_info.bitrate_kbps;
} }
@ -243,7 +251,7 @@ static int mp3_seek_callback(uint64_t position, void *user_data) {
inputEOF = YES; inputEOF = YES;
} }
} else { } else {
size_t bytesRemain = INPUT_BUFFER_SIZE - _decoder_buffer_filled; size_t bytesRemain = MINIMP3_BUF_SIZE - _decoder_buffer_filled;
ssize_t bytesRead = [_source read:&_decoder_buffer[_decoder_buffer_filled] amount:bytesRemain]; ssize_t bytesRead = [_source read:&_decoder_buffer[_decoder_buffer_filled] amount:bytesRemain];
if(bytesRead < 0 || bytesRead < bytesRemain) { if(bytesRead < 0 || bytesRead < bytesRemain) {
inputEOF = YES; inputEOF = YES;
@ -254,8 +262,12 @@ static int mp3_seek_callback(uint64_t position, void *user_data) {
int samples = mp3dec_decode_frame(&_decoder_ex.mp3d, &_decoder_buffer[0], (int)_decoder_buffer_filled, &_decoder_buffer_output[0], &_decoder_info); int samples = mp3dec_decode_frame(&_decoder_ex.mp3d, &_decoder_buffer[0], (int)_decoder_buffer_filled, &_decoder_buffer_output[0], &_decoder_info);
if(samples > 0) { if(samples > 0) {
samples_filled = samples; samples_filled = samples;
} else { }
if(_decoder_info.frame_bytes > _decoder_buffer_filled) {
inputEOF = YES; inputEOF = YES;
} else {
_decoder_buffer_filled -= _decoder_info.frame_bytes;
memmove(&_decoder_buffer[0], &_decoder_buffer[_decoder_info.frame_bytes], _decoder_buffer_filled);
} }
} }