zoukankan      html  css  js  c++  java
  • 音频播放(一)

    音频播放全是噪声。思考: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 }

         

            

  • 相关阅读:
    php 删除指定文件夹
    php 批量进行复制文件
    php 导入/导出 csv 文件
    Java8 Nashorn JavaScript引擎
    Java8 Optional类
    Java8数据流
    Java8默认方法
    异常的其他问题
    package和import语句_5
    继承和权限控制_1
  • 原文地址:https://www.cnblogs.com/wyqfighting/p/2818123.html
Copyright © 2011-2022 走看看