您的位置:首页 > 移动开发 > Android开发

android 使用libmad 生成MP3左右声道的PCM文件

2016-07-29 10:55 423 查看
首先我们需要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 <stdio.h>
#include <jni.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/types.h>
#include "mad.h"

#include <android/log.h>
#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,"<init>","(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;
}


最后在Activity调用
static {
System.loadLibrary("mad");
System.loadLibrary("usemad");
}

public native int decodeMp3(String filepath,String datapath,String rightpath,String leftpath);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: