diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/mp3-mpg123/mkv_mp3_decoder.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/mp3-mpg123/mkv_mp3_decoder.cpp')
-rw-r--r-- | Src/mp3-mpg123/mkv_mp3_decoder.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/Src/mp3-mpg123/mkv_mp3_decoder.cpp b/Src/mp3-mpg123/mkv_mp3_decoder.cpp new file mode 100644 index 00000000..3574f635 --- /dev/null +++ b/Src/mp3-mpg123/mkv_mp3_decoder.cpp @@ -0,0 +1,169 @@ +#include "mkv_mp3_decoder.h" +#include "../nsutil/pcm.h" + +int MKVDecoder::CreateAudioDecoder(const char *codec_id, const nsmkv::TrackEntryData *track_entry_data, const nsmkv::AudioData *audio_data, unsigned int preferred_bits, unsigned int max_channels,bool floating_point, ifc_mkvaudiodecoder **decoder) +{ + if (!strcmp(codec_id, "A_MPEG/L3") + || !strcmp(codec_id, "A_MPEG/L2") + || !strcmp(codec_id, "A_MPEG/L1")) + { + mpg123_handle *ctx = mpg123_new(NULL, NULL); + if (!ctx) + return CREATEDECODER_FAILURE; + + long flags = MPG123_QUIET|MPG123_FORCE_FLOAT|MPG123_SKIP_ID3V2|MPG123_IGNORE_STREAMLENGTH|MPG123_IGNORE_INFOFRAME; + if (max_channels == 1) { + flags |= MPG123_FORCE_MONO; + } + mpg123_param(ctx, MPG123_FLAGS, flags, 0); + mpg123_param(ctx, MPG123_RVA, MPG123_RVA_OFF, 0); + + *decoder = new MKVMP3Decoder(ctx, preferred_bits, max_channels, floating_point); + return CREATEDECODER_SUCCESS; + } + + return CREATEDECODER_NOT_MINE; +} + +#define CBCLASS MKVDecoder +START_DISPATCH; +CB(CREATE_AUDIO_DECODER, CreateAudioDecoder) +END_DISPATCH; +#undef CBCLASS + +#define FHG_DELAY 529 +MKVMP3Decoder::MKVMP3Decoder(mpg123_handle *mp3, unsigned int bps, unsigned max_channels, bool floating_point) +: mp3(mp3), bits(bps?bps:16), max_channels(max_channels?max_channels:2), floating_point(floating_point) +{ + decode_buffer=0; + decode_buffer_length=0; + sample_rate = 0; + channels = 0; + pregap = FHG_DELAY; + mpg123_open_feed(mp3); +} + +MKVMP3Decoder::~MKVMP3Decoder() +{ + if (mp3) { + mpg123_delete(mp3); + mp3 = 0; + } + free(decode_buffer); +} + +bool MKVMP3Decoder::_UpdateProperties() +{ + if (mp3 && (!channels || !sample_rate)) { + long sample_rate = 44100; + int channels = 2; + int encoding = 0; + if (mpg123_getformat(mp3, &sample_rate, &channels, &encoding) == MPG123_OK) { + this->channels = channels; + this->sample_rate = sample_rate; + } + } + + return channels && sample_rate; +} + +int MKVMP3Decoder::OutputFrameSize(size_t *frame_size) +{ + if (_UpdateProperties()) { + *frame_size = (bits/8) * channels * mpg123_spf(mp3); + return MKV_SUCCESS; + } else { + return MKV_FAILURE; + } +} + +int MKVMP3Decoder::GetOutputProperties(unsigned int *sampleRate, unsigned int *channels, unsigned int *bitsPerSample, bool *isFloat) +{ + if (_UpdateProperties()) { + *sampleRate = this->sample_rate; + *channels = this->channels; + *bitsPerSample = bits; + *isFloat = floating_point; + return MKV_SUCCESS; + } + else + { + return MKV_FAILURE; + } +} + +int MKVMP3Decoder::DecodeBlock(void *inputBuffer, size_t inputBufferBytes, void *outputBuffer, size_t *outputBufferBytes) +{ + if (!mp3) + return MKV_FAILURE; + + *outputBufferBytes = 0; + mpg123_feed(mp3, (unsigned char *)inputBuffer, inputBufferBytes); + + for (;;) { + if (!decode_buffer) { + if (_UpdateProperties()) { + decode_buffer_length = sizeof(float) * channels * mpg123_spf(mp3); + decode_buffer = (float *)malloc(decode_buffer_length); + if (!decode_buffer) { + return MKV_FAILURE; + } + } + } + // get the decoded data out + size_t pcm_buf_used=0; + int err = mpg123_read(mp3, (unsigned char *)decode_buffer, decode_buffer_length, &pcm_buf_used); + + if (pcm_buf_used) { + if (!_UpdateProperties()) { + return MKV_FAILURE; + } + // deal with pregap + size_t numSamples = pcm_buf_used / sizeof(float); + size_t offset = min(numSamples, pregap * channels); + numSamples -= offset; + pregap -= (int)offset / channels; + float *pcm_buf = decode_buffer + offset; + + // convert to destination sample format + + nsutil_pcm_FloatToInt_Interleaved(outputBuffer, pcm_buf, bits, numSamples); + + *outputBufferBytes += numSamples * bits / 8; + outputBuffer = (char *)outputBuffer + numSamples * bits / 8; + + return MKV_SUCCESS; + } else if (err == MPG123_NEED_MORE) { + *outputBufferBytes = 0; + return MKV_NEED_MORE_INPUT; + } else if (err == MPG123_NEW_FORMAT) { + continue; + } else if (err == MPG123_OK) { + continue; + } + else + return MKV_FAILURE; + } + return MKV_SUCCESS; +} + +void MKVMP3Decoder::Flush() +{ + mpg123_open_feed(mp3); + pregap = FHG_DELAY; +} + +void MKVMP3Decoder::Close() +{ + delete this; +} + +#define CBCLASS MKVMP3Decoder +START_DISPATCH; +CB(OUTPUT_FRAME_SIZE, OutputFrameSize) +CB(GET_OUTPUT_PROPERTIES, GetOutputProperties) +CB(DECODE_BLOCK, DecodeBlock) +VCB(FLUSH, Flush) +VCB(CLOSE, Close) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file |