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

        isXing = (memcmp(xing, "ng\0\0", 4) == 0) || (memcmp(xing, "fo\0\0", 4) == 0);
        if(isXing)
        {
            pTrack->vf.fileoffset -= 2;
        }
    }
    if(isXing)
    {
        const uint8_t *flagsBytes;
        const blockvf_error xingFlagsError = blockvf_read_view(&pTrack->vf, 4, &flagsBytes, &pReturnData->needed_offset);
        if(xingFlagsError != BLOCKVF_SUCCESS)
        {
            return mhfs_cl_error_from_blockvf_error(xingFlagsError);
        }
        const uint32_t xingFlags = unaligned_beu32_to_native(flagsBytes);
        if(xingFlags & 0x1)
        {
            const uint8_t *framesBytes;
            const blockvf_error framesError = blockvf_read_view(&pTrack->vf, 4, &framesBytes, &pReturnData->needed_offset);
            if(framesError != BLOCKVF_SUCCESS)
            {
                return mhfs_cl_error_from_blockvf_error(framesError);
            }
            const uint32_t frames = unaligned_beu32_to_native(framesBytes);
            MHFSCLTR_PRINT("xing frames %u\n", frames);
            // FIX ME FIX ME we add 1 to mp3frames because the decoder will currently (foolishly) decode the xing mp3frame
            mhfs_cl_track_meta_audioinfo_init(&pTrack->meta, (frames + 1) * 1152, sampleRate, channels, MCT_MAI_FLD_BITRATE, 0, bitrate);
            if(on_metablock != NULL)
            {
                on_metablock(context, MHFS_CL_TRACK_M_AUDIOINFO, &pTrack->meta);
            }
            pTrack->meta_initialized = true;
            return MHFS_CL_SUCCESS;
        }
        return MHFS_CL_ERROR;
    }

    // check for VBRI
    const blockvf_error seekVBRI = blockvf_seek(&pTrack->vf, startoffset+36, blockvf_seek_origin_start);
    if(seekVBRI != BLOCKVF_SUCCESS)
    {
        return mhfs_cl_error_from_blockvf_error(seekVBRI);
    }
    const uint8_t *vbriMagic;
    const blockvf_error vbriMagicError = blockvf_read_view(&pTrack->vf, 4, &vbriMagic, &pReturnData->needed_offset);
    if(vbriMagicError != BLOCKVF_SUCCESS)
    {
        return mhfs_cl_error_from_blockvf_error(vbriMagicError);
    }
    if(memcmp(vbriMagic, "VBRI", 4) == 0)
    {
        MHFSCLTR_PRINT("VBRI found\n");
        const uint8_t *vbriFields;
        const blockvf_error vbriFieldsError = blockvf_read_view(&pTrack->vf, 22, &vbriFields, &pReturnData->needed_offset);
        if(vbriFieldsError != BLOCKVF_SUCCESS)
        {
            return mhfs_cl_error_from_blockvf_error(vbriFieldsError);
        }
        const uint32_t frames = unaligned_beu32_to_native(&vbriFields[10]);
        MHFSCLTR_PRINT("vbri frames %u\n", frames);
        // FIX ME FIX ME need to verify pcmframes  calculation
        mhfs_cl_track_meta_audioinfo_init(&pTrack->meta, (frames + 1) * 1152, sampleRate, channels, MCT_MAI_FLD_BITRATE, 0, bitrate);
        if(on_metablock != NULL)
        {
            on_metablock(context, MHFS_CL_TRACK_M_AUDIOINFO, &pTrack->meta);
        }
        pTrack->meta_initialized = true;
        return MHFS_CL_SUCCESS;
    }

    // TODO

    // ID3 TLEN?



    //estimate from bitrate?

    return MHFS_CL_ERROR;
}

typedef enum {
MCT_WAVE_FORMAT_PCM          = 0x1,
MCT_WAVE_FORMAT_ADPCM        = 0x2,
MCT_WAVE_FORMAT_IEEE_FLOAT   = 0x3,
MCT_WAVE_FORMAT_ALAW         = 0x6,
MCT_WAVE_FORMAT_MULAW        = 0x7,
MCT_WAVE_FORMAT_DVI_ADPCM    = 0x11,
MCT_WAVE_FORMAT_EXTENSIBLE   = 0xFFFE
} mhfs_cl_wav_format;

typedef enum {
    MCT_WAVE_CHUNK_FMT = 'f' | ('m' << 8) | ('t' << 16) | (' ' << 24),
    MCT_WAVE_CHUNK_DATA = 'd' | ('a' << 8) | ('t' << 16) | ('a' << 24)
} mhfs_cl_riff_chunk_type;

static inline mhfs_cl_error mhfs_cl_wav_read_chunk_header(blockvf *pBlockvf, uint32_t *pNeededOffset, mhfs_cl_riff_chunk_type *pChunkType, uint32_t *pChunkSize)
{
    const uint8_t *chunkHeader;
    const blockvf_error chunkHeaderError = blockvf_read_view(pBlockvf, 8, &chunkHeader, pNeededOffset);
    if(chunkHeaderError != BLOCKVF_SUCCESS)
    {
        return mhfs_cl_error_from_blockvf_error(chunkHeaderError);
    }
    *pChunkType = unaligned_leu32_to_native(&chunkHeader[0]);
    *pChunkSize = unaligned_leu32_to_native(&chunkHeader[4]);
    return MHFS_CL_SUCCESS;
}

static mhfs_cl_error mhfs_cl_track_load_metadata_wav(mhfs_cl_track *pTrack, mhfs_cl_track_return_data *pReturnData, const mhfs_cl_track_on_metablock on_metablock, void *context)
{
    {
    const uint8_t *wavHeader;
    const blockvf_error wavHeaderError = blockvf_read_view(&pTrack->vf, 12, &wavHeader, &pReturnData->needed_offset);
    if(wavHeaderError != BLOCKVF_SUCCESS)
    {
        return mhfs_cl_error_from_blockvf_error(wavHeaderError);
    }

    if(memcmp(&wavHeader[0], "RIFF", 4) != 0)
    {

share/public_html/static/music_worklet_inprogress/decoder/src/mhfs_cl_track.h  view on Meta::CPAN

    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



( run in 1.029 second using v1.01-cache-2.11-cpan-e1769b4cff6 )