App-MHFS
view release on metacpan or search on metacpan
share/public_html/static/music_worklet_inprogress/decoder/src/mhfs_cl_track.h view on Meta::CPAN
{
*pNeededOffset = pTrack->vfData.extradata;
if(bRestoreDecoder)
{
mhfs_cl_track_allocs_restore(pTrack);
}
}
return mhfs_cl_error_from_blockvf_error(pTrack->vfData.code);
}
static mhfs_cl_error mhfs_cl_track_open_ma_decoder(mhfs_cl_track *pTrack, uint32_t *pNeededOffset)
{
pTrack->vf.fileoffset = 0;
mhfs_cl_track_blockvf_ma_decoder_call_before(pTrack, false);
const ma_result openRes = ma_decoder_init(&mhfs_cl_track_on_read_ma_decoder, &mhfs_cl_track_on_seek_ma_decoder, pTrack, &pTrack->decoderConfig, &pTrack->decoder);
const mhfs_cl_error openBlockRes = mhfs_cl_track_blockvf_ma_decoder_call_after(pTrack, false, pNeededOffset);
if(openBlockRes != MHFS_CL_SUCCESS)
{
if(openRes == MA_SUCCESS) ma_decoder_uninit(&pTrack->decoder);
return openBlockRes;
}
else if(openRes == MA_SUCCESS)
{
pTrack->dec_initialized = true;
return MHFS_CL_SUCCESS;
}
return MHFS_CL_ERROR;
}
static mhfs_cl_error mhfs_cl_track_load_metadata_ma_decoder(mhfs_cl_track *pTrack, mhfs_cl_track_return_data *pReturnData, const mhfs_cl_track_on_metablock on_metablock, void *context)
{
// open the decoder
mhfs_cl_error retval = mhfs_cl_track_open_ma_decoder(pTrack, &pReturnData->needed_offset);
if(retval != MHFS_CL_SUCCESS)
{
return retval;
}
// read and store the metadata
const unsigned savefileoffset = pTrack->vf.fileoffset;
uint64_t totalPCMFrameCount = pTrack->meta.totalPCMFrameCount;
if(pTrack->decoderConfig.encodingFormat != ma_encoding_format_mp3)
{
ma_decoder_get_length_in_pcm_frames(&pTrack->decoder, &totalPCMFrameCount);
}
MHFSCLTR_PRINT("decoder output samplerate %u\n", pTrack->decoder.outputSampleRate);
mhfs_cl_track_meta_audioinfo_init(&pTrack->meta, totalPCMFrameCount, pTrack->decoder.outputSampleRate, pTrack->decoder.outputChannels, MCT_MAI_FLD_EMPTY, 0, 0);
if(on_metablock != NULL)
{
on_metablock(context, MHFS_CL_TRACK_M_AUDIOINFO, &pTrack->meta);
}
if(retval == MHFS_CL_SUCCESS)
{
pTrack->meta_initialized = true;
}
pTrack->vf.fileoffset = savefileoffset;
return retval;
}
static inline ma_encoding_format mhfs_cl_guess_codec(const uint8_t *id, const char *mime, const char *fullfilename)
{
const size_t namelen = strlen(fullfilename);
const char *lastFourChars = (namelen >= 4) ? (fullfilename + namelen - 4) : "";
const uint32_t uMagic = unaligned_beu32_to_native(id);
if(memcmp(id, "fLaC", 4) == 0)
{
return ma_encoding_format_flac;
}
else if(memcmp(id, "RIFF", 4) == 0)
{
return ma_encoding_format_wav;
}
// check mpeg sync and verify the audio version id isn't reserved
else if(((uMagic & 0xFFE00000) == 0xFFE00000) && ((uMagic & 0x00180000) != 0x80000))
{
return ma_encoding_format_mp3;
}
// fallback, attempt to speed up guesses by mime
else if(strcmp(mime, "audio/flac") == 0)
{
return ma_encoding_format_flac;
}
else if((strcmp(mime, "audio/wave") == 0) || (strcmp(mime, "audio/wav") == 0))
{
return ma_encoding_format_wav;
}
else if(strcmp(mime, "audio/mpeg") == 0)
{
return ma_encoding_format_mp3;
}
// fallback, fallback attempt to speed up guesses with file extension
else if(strcmp(lastFourChars, "flac") == 0)
{
return ma_encoding_format_flac;
}
else if(strcmp(lastFourChars, ".wav") == 0)
{
return ma_encoding_format_wav;
}
else if(strcmp(lastFourChars, ".mp3") == 0)
{
return ma_encoding_format_mp3;
}
else
{
MHFSCLTR_PRINT("warning: unable to guess format\n");
return ma_encoding_format_unknown;
}
}
typedef struct {
bool initialized;
mhfs_cl_error res;
uint32_t neededOffset;
} mhfs_cl_track_io_error;
static inline void mhfs_cl_track_io_error_update(mhfs_cl_track_io_error *ioError, const mhfs_cl_error res, const uint32_t neededOffset)
{
if(res != MHFS_CL_NEED_MORE_DATA) return;
if(!ioError->initialized)
{
ioError->initialized = true;
ioError->res = res;
ioError->neededOffset = neededOffset;
}
}
mhfs_cl_error mhfs_cl_track_load_metadata(mhfs_cl_track *pTrack, mhfs_cl_track_return_data *pReturnData, const char *mime, const char *fullfilename, const uint64_t totalPCMFrameCount, const mhfs_cl_track_on_metablock on_metablock, void *context)
{
mhfs_cl_track_return_data rd;
if(pReturnData == NULL) pReturnData = &rd;
// seek past ID3 tags
pTrack->vf.fileoffset = 0;
const uint8_t *id;
for(;;)
{
const blockvf_error idError = blockvf_read_view(&pTrack->vf, 4, &id, &pReturnData->needed_offset);
if(idError != BLOCKVF_SUCCESS)
{
return mhfs_cl_error_from_blockvf_error(idError);
}
MHFSCLTR_PRINT("uMagic %X %X %X %X @ 0x%X\n", id[0], id[1], id[2], id[3], pTrack->vf.fileoffset-4);
if(memcmp(id, "ID3", 3) != 0) break;
pTrack->vf.fileoffset--;
uint16_t id3version;
uint8_t flags;
uint32_t tagSize;
const mhfs_cl_error parseError = mhfs_cl_parse_id3_header_after_magic(&pTrack->vf, &pReturnData->needed_offset, &id3version, &flags, &tagSize);
if(parseError != MHFS_CL_SUCCESS)
{
return parseError;
}
if(BLOCKVF_SUCCESS != blockvf_seek(&pTrack->vf, tagSize, blockvf_seek_origin_current))
{
return MHFS_CL_ERROR;
}
}
pTrack->afterID3Offset = pTrack->vf.fileoffset - 4;
// attempt to guess the codec to determine what codec to try first
ma_encoding_format encFmt;
if(pTrack->decoderConfig.encodingFormat == ma_encoding_format_unknown)
{
encFmt = mhfs_cl_guess_codec(id, mime, fullfilename);
}
else
{
encFmt = pTrack->decoderConfig.encodingFormat;
}
ma_encoding_format tryorder[] = { ma_encoding_format_flac, ma_encoding_format_mp3, ma_encoding_format_wav};
const unsigned max_try_count = sizeof(tryorder) / sizeof(tryorder[0]);
if(encFmt == ma_encoding_format_mp3)
{
mhfs_cl_track_swap_tryorder(&tryorder[DAF_MP3], &tryorder[0]);
}
else if(encFmt == ma_encoding_format_wav)
{
mhfs_cl_track_swap_tryorder(&tryorder[DAF_WAV], &tryorder[0]);
}
// set this as a fallback
pTrack->meta.totalPCMFrameCount = totalPCMFrameCount;
// try the various codecs
mhfs_cl_track_io_error ioError = {
.initialized = false
};
for(unsigned i = 0; i < max_try_count; i++)
{
pTrack->decoderConfig.encodingFormat = tryorder[i];
pTrack->vf.fileoffset = pTrack->afterID3Offset;
// try loading via our methods
mhfs_cl_track_return_data temprd;
if(pTrack->decoderConfig.encodingFormat == ma_encoding_format_flac)
{
const mhfs_cl_error retval = mhfs_cl_track_load_metadata_flac(pTrack, &temprd, on_metablock, context);
if(retval == MHFS_CL_SUCCESS)
{
return retval;
}
mhfs_cl_track_io_error_update(&ioError, retval, temprd.needed_offset);
}
else if(pTrack->decoderConfig.encodingFormat == ma_encoding_format_wav)
{
const mhfs_cl_error retval = mhfs_cl_track_load_metadata_wav(pTrack, &temprd, on_metablock, context);
if(retval == MHFS_CL_SUCCESS)
{
return retval;
}
mhfs_cl_track_io_error_update(&ioError, retval, temprd.needed_offset);
}
else if(pTrack->decoderConfig.encodingFormat == ma_encoding_format_mp3)
{
const mhfs_cl_error retval = mhfs_cl_track_load_metadata_mp3(pTrack, &temprd, on_metablock, context);
if(retval == MHFS_CL_SUCCESS)
{
return retval;
}
mhfs_cl_track_io_error_update(&ioError, retval, temprd.needed_offset);
}
// try loading via ma_decoder
const mhfs_cl_error retval = mhfs_cl_track_load_metadata_ma_decoder(pTrack, &temprd, on_metablock, context);
( run in 2.627 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )