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

首先我们需要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;
}


最后在Activity调用

	static {
		System.loadLibrary("mad");
		System.loadLibrary("usemad");
	}
	
	public native int decodeMp3(String filepath,String datapath,String rightpath,String leftpath);



你可能感兴趣的:(android)