音频播放(一)

音频播放全是噪声。思考:1、解码处没有正确解码;2、内存拷贝处地址有问题。

验证:1、解码是否正确

         方法:将解码后的数据写入PCM文件中,再测试

         结果:下载了cool edit这个软件,将PCM文件直接转换为mp3文件,可正常播放,说明不是解码的问题。

        2、内存拷贝处 memcpy(audioBuf,audioBuffer+audio_offset,size);

         仔细分析了一下len=avcodec_decode_audio2(ffmpeg_audio.pCodecCtx,(int16_t *)audioBuffer,&out_size,pktdata,pktsize)这句话,发现自己居然不知道audioBuffer是

这次解码的一段内存,还是所有内存。查阅资料,发现audioBuffer只是一段内存,avcodec_decode_audio2每次只解码audioBuffer大小的数据,所以在内存拷贝处犯了错误。

         解决办法:额,非常复杂。。。

鉴于此,想到换一种思路,在c层直接利用AudioTrack播放。如果直接在底层播放的话,就不需要把这段内存再传给JAVA层,也就是说这段代码多余了,去掉,也节省了相当大的内存空间。

每次解码一个audioBuffer大小的数据,解码完成后,直接传给AudioTrack播放,每次解码就播放一次,不用等到所有解码完成后再播放,延时性大大提高,但是,问题是这样解一段播一段中间会不会有很大的间隙?

先看GetMethodID,最后一个参数是方法的定义,也就是"参数,返回类型"。

直接播放PCM文件,噪声,用cool edit播放,正确。修改cool edit设置的参数:采样率、声道数等,发觉也不能播放,且是相同的噪声,所以,基本断定是由于AudioTrack的初始化参数设置问题。按照cool edit能正常播放的参数来初始化AudioTrack,修改后能正确播放。现在思考:那对任一个音频文件,怎么拿到它的采样率、声道数了?

proccessAudio
 1 void  Java_com_churnlabs_ffmpegsample_MainActivity_processAudio(JNIEnv* env,jobject this){
 2     static jbyteArray buffer;
 3     static jobject audio_track;
 4     static jint buffer_size;
 5     static jmethodID method_write;
 6     //根据FindClass找到AudioTrack这个类
 7     jclass audio_track_cls = (*env)->FindClass(env,"android/media/AudioTrack");
 8     //根据GetStaticMethodID找到类的静态方法
 9     //类定义、方法名称和方法的定义,方法的定义可以用jdk中带的javap工具反编译class文件获取
10     jmethodID min_buff_size_id = (*env)->GetStaticMethodID(
11                                          env,
12                                          audio_track_cls,
13                                         "getMinBufferSize",
14                                         "(III)I");
15     //根据CallStaticIntMethod得到此静态方法的返回值
16     buffer_size = (*env)->CallStaticIntMethod(env,audio_track_cls,min_buff_size_id,
17                 44100,
18                 3,          /*CHANNEL_CONFIGURATION_STEREO*/
19                 2);         /*ENCODING_PCM_16BIT*/
20     LOGI("buffer_size=%i",buffer_size);
21 
22     //在C中新建一个ByteArray数组,名为buffer
23     buffer = (*env)->NewByteArray(env,buffer_size/4);
24 
25     char buf[buffer_size/4];
26 
27     //找到此类的初始化构造方法
28     jmethodID constructor_id = (*env)->GetMethodID(env,audio_track_cls, "<init>",
29             "(IIIIII)V");
30     //新建一个类对象
31     //在AudioFomart这个类里找每个类型的数值
32     audio_track = (*env)->NewObject(env,audio_track_cls,
33             constructor_id,
34             3,            /*AudioManager.STREAM_MUSIC*/
35             44100,        /*sampleRateInHz*/
36             3,            /*CHANNEL_CONFIGURATION_STEREO*/
37             2,            /*ENCODING_PCM_16BIT*/
38             buffer_size,  /*bufferSizeInBytes*/
39             1             /*AudioTrack.MODE_STREAM*/
40     );
41 
42     //setvolume   find是找到该方法,call是调用该方法
43     jmethodID setStereoVolume = (*env)->GetMethodID(env,audio_track_cls,"setStereoVolume","(FF)I");
44     (*env)->CallIntMethod(env,audio_track,setStereoVolume,1.0,1.0);
45 
46     //play
47     jmethodID method_play = (*env)->GetMethodID(env,audio_track_cls, "play", "()V");
48     (*env)->CallVoidMethod(env,audio_track, method_play);
49 
50     //write
51     method_write = (*env)->GetMethodID(env,audio_track_cls,"write","([BII)I");
52 
53    FILE* fp = fopen("/sdcard/result.pcm","rb");
54    LOGE("after open");
55    while(!feof(fp)){
56        //feof()这个函数是用来判断指针是否已经到达文件尾部的。
57        //fread从文件流fp中读取200个元素,每个元素sizeof(char)个字节,读取的数据存入buf中;返回值是200
58        jint read= fread(buf,sizeof(char),200,fp);
59        //将本地类型的buf转换成jbyteArray类型的buffer
60        (*env)->SetByteArrayRegion(env,buffer, 0,read,(jbyte *)buf);
61        //CallIntMethod中Int是方法的返回值,也可能是CallVoidMethod等类型的
62        (*env)->CallIntMethod(env,audio_track,method_write,buffer,0,read);
63    }
64    fclose(fp);
65 }

     

        

原文地址:https://www.cnblogs.com/wyqfighting/p/2818123.html