mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 20:45:46 -04:00
Initial community commit
This commit is contained in:
194
Src/mp3-mpg123/flv_mp3_decoder.cpp
Normal file
194
Src/mp3-mpg123/flv_mp3_decoder.cpp
Normal file
@ -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
|
Reference in New Issue
Block a user