aboutsummaryrefslogtreecommitdiff
path: root/Src/mp3-mpg123/flv_mp3_decoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/mp3-mpg123/flv_mp3_decoder.cpp')
-rw-r--r--Src/mp3-mpg123/flv_mp3_decoder.cpp194
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