首先我们需要libmad.so
修改Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mad
LOCAL_SRC_FILES := libmad.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := usemad
LOCAL_SRC_FILES := usemad.cpp
LOCAL_SHARED_LIBRARIES := mad
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)
新建我们的CPP文件 usemad.cpp
#include
#include
#include
#include
#include
#include
#include "mad.h"
#include
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native", __VA_ARGS__))
#ifdef Test
#define T_LOG(FORMAT,...) \
{ __android_log_print(ANDROID_LOG_DEBUG, "t", FORMAT, ##__VA_ARGS__); }
#else
#define T_LOG(FORMAT,...) /*\
{ __android_log_print(ANDROID_LOG_DEBUG, "t", FORMAT, ##__VA_ARGS__); }*/
#endif
struct buffer {
unsigned char const *start;
unsigned long flen; /*file length*/
};
typedef struct buffer mp3_file;
int decode(unsigned char const *, unsigned long);
inline signed int scale(mad_fixed_t sample);
enum mad_flow input(void *data, struct mad_stream *stream);
enum mad_flow output(void *data, struct mad_header const *header,struct mad_pcm *pcm);
enum mad_flow error(void *data,struct mad_stream *stream,struct mad_frame *frame);
FILE *outfile;
FILE *RightFile;
FILE *LeftFile;
//int samplerate = 0;
//int pcm_channels = 0;
//int pcm_length = 0;
jstring pcm_path;
jobject at_obj;
jclass at_clazz;
JNIEnv* m_env;
extern "C"{
jint Java_com_example_libmadtest_MainActivity_decodeMp3(JNIEnv* env,jclass clazz,jstring filepath,jstring datapath
,jstring rightpath,jstring leftpath);
}
JNIEXPORT jint JNICALL Java_com_example_libmadtest_MainActivity_decodeMp3(JNIEnv* env,jclass clazz,jstring filepath,jstring datapath
,jstring rightpath,jstring leftpath)
{
m_env = env;
pcm_path = datapath;
struct stat stat;
void *fdm;
int fd = open(env->GetStringUTFChars(filepath,0),O_RDONLY);
if(fstat(fd,&stat) == -1 || stat.st_size == 0)
return -1;
fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);//将文件内容拷贝到内存里面
if (fdm == MAP_FAILED)
return -1;
outfile = fopen(env->GetStringUTFChars(datapath,0),"w+");
RightFile = fopen(env->GetStringUTFChars(rightpath,0),"w+");
LeftFile = fopen(env->GetStringUTFChars(leftpath,0),"w+");
const char* classname = "android/media/AudioTrack";
at_clazz = env->FindClass(classname);
jmethodID getMinSize_id = env->GetStaticMethodID(at_clazz,"getMinBufferSize","(III)I");
jvalue* size_args = new jvalue[3];
size_args[0].i = 44100;
size_args[1].i = 12;
size_args[2].i = 2;
jint size = env->CallStaticIntMethodA(at_clazz,getMinSize_id,size_args);
delete size_args;
jmethodID id = env->GetMethodID(at_clazz,"","(IIIIII)V");
jvalue* args = new jvalue[6];
args[0].i = 3; //AudioManager.STREAM_MUSIC
args[1].i = 44100; //sampleRateInHz
args[2].i = 12; //AudioFormat.CHANNEL_OUT_STEREO
args[3].i = 2; //AudioFormat.ENCODING_PCM_16BIT
args[4].i = size;
args[5].i = 1;//MODE_STREAM
at_obj = env->NewObjectA(at_clazz,id,args);
jmethodID play_id = env->GetMethodID(at_clazz,"play","()V");
env->CallVoidMethod(at_obj,play_id);
delete args;
decode((const unsigned char*)fdm,stat.st_size);
fclose(outfile);
if (munmap (fdm, stat.st_size) == -1)
return -1;
return 0;
}
int decode(unsigned char const *start,unsigned long length)
{
struct buffer buffer;
struct mad_decoder decoder;
int result;
buffer.start = start;
buffer.flen = length;
/* configure input, output, and error functions */
mad_decoder_init(&decoder, &buffer,input, 0 /* header */, 0 /* filter */, output,error, 0 /* message */);
mad_decoder_options(&decoder, 0);
/* start decoding */
result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
/* release the decoder */
mad_decoder_finish(&decoder);
return result;
}
enum mad_flow input(void *data, struct mad_stream *stream)
{
struct buffer *buffer = (struct buffer*)data;
if(!buffer->flen)
return MAD_FLOW_STOP;
mad_stream_buffer(stream, buffer->start, buffer->flen);
buffer->flen = 0;
return MAD_FLOW_CONTINUE;
}
/*
* The following utility routine performs simple rounding, clipping, and
* scaling of MAD's high-resolution samples down to 16 bits. It does not
* perform any dithering or noise shaping, which would be recommended to
* obtain any exceptional audio quality. It is therefore not recommended to
* use this routine if high-quality output is desired.
*/
inline signed int scale(mad_fixed_t sample)
{
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
/*
* This is the output callback function. It is called after each frame of
* MPEG audio data has been completely decoded. The purpose of this callback
* is to output (or play) the decoded PCM audio.
*/
enum mad_flow output(void *data, struct mad_header const *header,struct mad_pcm *pcm)
{
unsigned int nchannels, nsamples,n;
mad_fixed_t const *left_ch, *right_ch;
jbyte Output[6912], *OutputPtr;
int fmt, wrote, speed, exact_rate, err, dir;
nchannels = pcm->channels;
n = nsamples = pcm->length;
left_ch = pcm->samples[0];
right_ch = pcm->samples[1];
// samplerate = pcm->samplerate;
// pcm_channels = pcm->channels;
// pcm_length = pcm->length;
// fmt = AFMT_S16_LE;
// speed = pcm->samplerate * 2; /*播放速度是采样率的两倍 */
// unsigned char Left[3456],*Outleftptr;
// unsigned char Right[3456],*Outrightptr;
// Outleftptr = Left;
// Outrightptr = Right;
OutputPtr = Output;//将OutputPtr指向Output
while (nsamples--)
{
signed int sample;
sample = scale (*left_ch++);
*(OutputPtr++) = sample >> 0;
*(OutputPtr++) = sample >> 8;
// *(Outleftptr++) = sample >> 0;
// *(Outleftptr++) = sample >> 8;
if (nchannels == 2)
{
sample = scale (*right_ch++);
*(OutputPtr++) = sample >> 0;
*(OutputPtr++) = sample >> 8;
// *(Outrightptr++) = sample >> 0;
// *(Outrightptr++) = sample >> 8;
}
}
OutputPtr = Output;//由于之前的操作将OutputPtr的指针指向了最后,这时需要将其指针移动到最前面
// Outleftptr = Left;
// Outrightptr = Right;
jbyteArray outdata = m_env->NewByteArray(n*2*nchannels);
m_env->SetByteArrayRegion(outdata,0,n*2*nchannels,OutputPtr);
jmethodID id = m_env->GetMethodID(at_clazz,"write","([BII)I");
m_env->CallIntMethod(at_obj,id,outdata,0,n*2*nchannels);
m_env->DeleteLocalRef(outdata);
// fwrite(OutputPtr, 1, n*2*nchannels, outfile);
// fwrite(Outrightptr, 1, n*2, RightFile);
// fwrite(Outleftptr, 1, n*2, LeftFile);
// snd_pcm_writei (pcm_handle, OutputPtr, n);
OutputPtr = Output;//写完文件后,OutputPtr的指针也移动到了最后,这时需要将其指针移动到最前面
return MAD_FLOW_CONTINUE;
}
/*
* This is the error callback function. It is called whenever a decoding
* error occurs. The error is indicated by stream->error; the list of
* possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
* header file.
*/
enum mad_flow error(void *data,struct mad_stream *stream,struct mad_frame *frame)
{
mp3_file *mp3fp = (mp3_file*)data;
/* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
return MAD_FLOW_CONTINUE;
}
static {
System.loadLibrary("mad");
System.loadLibrary("usemad");
}
public native int decodeMp3(String filepath,String datapath,String rightpath,String leftpath);