diff options
Diffstat (limited to 'Src/mp3-mpg123/flv_mp3_decoder.cpp')
-rw-r--r-- | Src/mp3-mpg123/flv_mp3_decoder.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/Src/mp3-mpg123/flv_mp3_decoder.cpp b/Src/mp3-mpg123/flv_mp3_decoder.cpp new file mode 100644 index 00000000..b6147904 --- /dev/null +++ b/Src/mp3-mpg123/flv_mp3_decoder.cpp @@ -0,0 +1,194 @@ +#include "flv_mp3_decoder.h" +#include "../nsutil/pcm.h" + +int FLVDecoderCreator::CreateAudioDecoder(int stereo, int bits, int sample_rate, int format_type, ifc_flvaudiodecoder **decoder) +{ + if (format_type == FLV::AUDIO_FORMAT_MP3 || format_type == FLV::AUDIO_FORMAT_MP3_8KHZ) + { + 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 (!stereo) { + flags |= MPG123_FORCE_MONO; + } + mpg123_param(ctx, MPG123_FLAGS, flags, 0); + mpg123_param(ctx, MPG123_RVA, MPG123_RVA_OFF, 0); + + *decoder = new FLVMP3(ctx); + return CREATEDECODER_SUCCESS; + } + return CREATEDECODER_NOT_MINE; +} + +int FLVDecoderCreator::HandlesAudio(int format_type) +{ + if (format_type == FLV::AUDIO_FORMAT_MP3 || format_type == FLV::AUDIO_FORMAT_MP3_8KHZ) + { + return CREATEDECODER_SUCCESS; + } + return CREATEDECODER_NOT_MINE; +} + +#define CBCLASS FLVDecoderCreator +START_DISPATCH; +CB(CREATE_AUDIO_DECODER, CreateAudioDecoder) +CB(HANDLES_AUDIO, HandlesAudio) +END_DISPATCH; +#undef CBCLASS + +/* --- */ +#define FHG_DELAY 529 +FLVMP3::FLVMP3(mpg123_handle *mp3) : mp3(mp3) +{ + mpg123_open_feed(mp3); + bits = 16; + pregap = FHG_DELAY; + max_channels = 2; + channels = 0; + decode_buffer = 0; + decode_buffer_length = 0; +} + +FLVMP3::~FLVMP3() +{ + if (mp3) { + mpg123_delete(mp3); + mp3 = 0; + } + free(decode_buffer); +} + +int FLVMP3::GetOutputFormat(unsigned int *sample_rate, unsigned int *_channels, unsigned int *_bits) +{ + mpg123_frameinfo frameInfo; + if (mpg123_info(mp3, &frameInfo) == MPG123_OK) + { + *sample_rate = frameInfo.rate; + channels = (frameInfo.mode == MPG123_M_MONO)?1:2; + *_channels = channels; + *_bits = bits; + return FLV_AUDIO_SUCCESS; + } + else + { + return FLV_AUDIO_FAILURE; + } +} + +int FLVMP3::DecodeSample(const void *input_buffer, size_t input_buffer_bytes, void *samples, size_t *samples_size_bytes, double *bitrate) +{ + if (!mp3) + return FLV_AUDIO_FAILURE; + + mpg123_feed(mp3, (unsigned char *)input_buffer, input_buffer_bytes); + + *samples_size_bytes = 0; + *bitrate = 0; + + for (;;) { + if (!decode_buffer) { + int channels = 2; + long sample_rate; + int encoding; + if (mpg123_getformat(mp3, &sample_rate, &channels, &encoding) == MPG123_OK) { + this->channels = channels; + decode_buffer_length = sizeof(float) * channels * mpg123_spf(mp3); + decode_buffer = (float *)malloc(decode_buffer_length); + if (!decode_buffer) { + return FLV_AUDIO_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 (!channels) { + long sample_rate = 44100; + int channels = 2; + int encoding = 0; + if (mpg123_getformat(mp3, &sample_rate, &channels, &encoding) == MPG123_OK) { + this->channels = channels; + } else { + return FLV_AUDIO_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(samples, pcm_buf, bits, numSamples); + + *samples_size_bytes += numSamples * bits / 8; + samples = (char *)samples + numSamples * bits / 8; + + mpg123_frameinfo frameInfo; + if (mpg123_info(mp3, &frameInfo) == MPG123_OK) { + *bitrate = frameInfo.bitrate; + } + return FLV_AUDIO_SUCCESS; + } else if (err == MPG123_NEED_MORE) { + *samples_size_bytes = 0; + return FLV_AUDIO_NEEDS_MORE_INPUT; + } else if (err == MPG123_NEW_FORMAT) { + continue; + } else if (err == MPG123_OK) { + continue; + } + else + return FLV_AUDIO_FAILURE; + } + return FLV_AUDIO_SUCCESS; +} + +void FLVMP3::Flush() +{ + mpg123_open_feed(mp3); + pregap = FHG_DELAY; +} + +void FLVMP3::Close() +{ + if (mp3) { + mpg123_delete(mp3); + mp3 = 0; + } + delete this; +} + +void FLVMP3::SetPreferences(unsigned int _max_channels, unsigned int preferred_bits) +{ + if (preferred_bits) + bits = preferred_bits; + + if (max_channels > _max_channels) + max_channels = _max_channels; + + 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(mp3, MPG123_FLAGS, flags, 0); + mpg123_param(mp3, MPG123_RVA, MPG123_RVA_OFF, 0); + +} + +#define CBCLASS FLVMP3 +START_DISPATCH; +CB(FLV_AUDIO_GETOUTPUTFORMAT, GetOutputFormat) +CB(FLV_AUDIO_DECODE, DecodeSample) +VCB(FLV_AUDIO_FLUSH, Flush) +VCB(FLV_AUDIO_CLOSE, Close) +VCB(FLV_AUDIO_SETPREFERENCES, SetPreferences) +END_DISPATCH; +#undef CBCLASS |