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

来源:互联网 发布:淘宝买衣服哪家店好 编辑:程序博客网 时间:2024/05/22 02:00

首先我们需要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__); }*/#endifstruct 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_MUSICargs[1].i = 44100; //sampleRateInHzargs[2].i = 12; //AudioFormat.CHANNEL_OUT_STEREOargs[3].i = 2; //AudioFormat.ENCODING_PCM_16BITargs[4].i = size;args[5].i = 1;//MODE_STREAMat_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);



0 0