Android本地视频播放器开发--ffmpeg解码视频文件中的音频(2)


Android本地视频播放器开发--ffmpeg解码视频文件中的音频(1)中我们从视频文件中解码出音频,这一章中将使用OpenSL ES来播放解码的音频数据,首先关于OpenSL ES这里暂不介绍,可以查看官网以及NDK中samples下面的native-audio里面的文件,这里我也是扣取了其中的代码,我们播放音频的部分在上一章的基础上进行添加的,代码如下:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4.   
  5. #include <assert.h>  
  6. #include <android/log.h>  
  7.   
  8. // for native audio  
  9. #include <SLES/OpenSLES.h>  
  10. #include <SLES/OpenSLES_Android.h>  
  11.   
  12. #include "VideoPlayerDecode.h"  
  13. #include "../ffmpeg/libavutil/avutil.h"  
  14. #include "../ffmpeg/libavcodec/avcodec.h"  
  15. #include "../ffmpeg/libavformat/avformat.h"  
  16.   
  17. #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "graduation", __VA_ARGS__))  
  18.   
  19. AVFormatContext *pFormatCtx = NULL;  
  20. int             audioStream, delay_time, videoFlag = 0;  
  21. AVCodecContext  *aCodecCtx;  
  22. AVCodec         *aCodec;  
  23. AVFrame         *aFrame;  
  24. AVPacket        packet;  
  25. int  frameFinished = 0;  
  26.   
  27. // engine interfaces  
  28. static SLObjectItf engineObject = NULL;  
  29. static SLEngineItf engineEngine;  
  30.   
  31. // output mix interfaces  
  32. static SLObjectItf outputMixObject = NULL;  
  33. static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;  
  34.   
  35. // buffer queue player interfaces  
  36. static SLObjectItf bqPlayerObject = NULL;  
  37. static SLPlayItf bqPlayerPlay;  
  38. static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;  
  39. static SLEffectSendItf bqPlayerEffectSend;  
  40. static SLMuteSoloItf bqPlayerMuteSolo;  
  41. static SLVolumeItf bqPlayerVolume;  
  42.   
  43. // aux effect on the output mix, used by the buffer queue player  
  44. static const SLEnvironmentalReverbSettings reverbSettings =  
  45.     SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;  
  46.   
  47. // file descriptor player interfaces  
  48. static SLObjectItf fdPlayerObject = NULL;  
  49. static SLPlayItf fdPlayerPlay;  
  50. static SLSeekItf fdPlayerSeek;  
  51. static SLMuteSoloItf fdPlayerMuteSolo;  
  52. static SLVolumeItf fdPlayerVolume;  
  53.   
  54. // pointer and size of the next player buffer to enqueue, and number of remaining buffers  
  55. static short *nextBuffer;  
  56. static unsigned nextSize;  
  57. static int nextCount;  
  58.   
  59. // this callback handler is called every time a buffer finishes playing  
  60. void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)  
  61. {  
  62.     assert(bq == bqPlayerBufferQueue);  
  63.     assert(NULL == context);  
  64.     // for streaming playback, replace this test by logic to find and fill the next buffer  
  65.     if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) {  
  66.         SLresult result;  
  67.         // enqueue another buffer  
  68.         result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);  
  69.         // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,  
  70.         // which for this code example would indicate a programming error  
  71.         assert(SL_RESULT_SUCCESS == result);  
  72.     }  
  73. }  
  74.   
  75.   
  76. void createEngine(JNIEnv* env, jclass clazz)  
  77. {  
  78.     SLresult result;  
  79.   
  80.     // create engine  
  81.     result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);  
  82.     assert(SL_RESULT_SUCCESS == result);  
  83.   
  84.     // realize the engine  
  85.     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);  
  86.     assert(SL_RESULT_SUCCESS == result);  
  87.   
  88.     // get the engine interface, which is needed in order to create other objects  
  89.     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);  
  90.     assert(SL_RESULT_SUCCESS == result);  
  91.   
  92.     // create output mix, with environmental reverb specified as a non-required interface  
  93.     const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};  
  94.     const SLboolean req[1] = {SL_BOOLEAN_FALSE};  
  95.     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);  
  96.     assert(SL_RESULT_SUCCESS == result);  
  97.   
  98.     // realize the output mix  
  99.     result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);  
  100.     assert(SL_RESULT_SUCCESS == result);  
  101.   
  102.     // get the environmental reverb interface  
  103.     // this could fail if the environmental reverb effect is not available,  
  104.     // either because the feature is not present, excessive CPU load, or  
  105.     // the required MODIFY_AUDIO_SETTINGS permission was not requested and granted  
  106.     result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,  
  107.             &outputMixEnvironmentalReverb);  
  108.     if (SL_RESULT_SUCCESS == result) {  
  109.         result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(  
  110.                 outputMixEnvironmentalReverb, &reverbSettings);  
  111.     }  
  112.     // ignore unsuccessful result codes for environmental reverb, as it is optional for this example  
  113. }  
  114.   
  115. void createBufferQueueAudioPlayer(JNIEnv* env, jclass clazz, int rate, int channel,int bitsPerSample)  
  116. {  
  117.     SLresult result;  
  118.   
  119.     // configure audio source  
  120.     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};  
  121. //    SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_16,  
  122. //        SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,  
  123. //        SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN};  
  124.    SLDataFormat_PCM format_pcm;  
  125.    format_pcm.formatType = SL_DATAFORMAT_PCM;  
  126. format_pcm.numChannels = channel;  
  127. format_pcm.samplesPerSec = rate * 1000;  
  128.  format_pcm.bitsPerSample = bitsPerSample;  
  129.  format_pcm.containerSize = 16;  
  130. if(channel == 2)  
  131. format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;  
  132. else  
  133. format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;  
  134. format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;  
  135.     SLDataSource audioSrc = {&loc_bufq, &format_pcm};  
  136.   
  137.     // configure audio sink  
  138.     SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};  
  139.     SLDataSink audioSnk = {&loc_outmix, NULL};  
  140.   
  141.     // create audio player  
  142.     const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND,  
  143.             /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME};  
  144.     const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,  
  145.             /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE};  
  146.     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,  
  147.             3, ids, req);  
  148.     assert(SL_RESULT_SUCCESS == result);  
  149. // realize the player  
  150.     result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);  
  151.     assert(SL_RESULT_SUCCESS == result);  
  152.   
  153.     // get the play interface  
  154.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);  
  155.     assert(SL_RESULT_SUCCESS == result);  
  156.   
  157.     // get the buffer queue interface  
  158.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,  
  159.             &bqPlayerBufferQueue);  
  160.     assert(SL_RESULT_SUCCESS == result);  
  161.   
  162.     // register callback on the buffer queue  
  163.     result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);  
  164.     assert(SL_RESULT_SUCCESS == result);  
  165.   
  166.     // get the effect send interface  
  167.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,  
  168.             &bqPlayerEffectSend);  
  169.     assert(SL_RESULT_SUCCESS == result);  
  170.   
  171. #if 0   // mute/solo is not supported for sources that are known to be mono, as this is  
  172.     // get the mute/solo interface  
  173.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);  
  174.     assert(SL_RESULT_SUCCESS == result);  
  175. #endif  
  176.   
  177.     // get the volume interface  
  178.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);  
  179.     assert(SL_RESULT_SUCCESS == result);  
  180.   
  181. // set the player's state to playing  
  182.     result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);  
  183.     assert(SL_RESULT_SUCCESS == result);  
  184.   
  185. }  
  186.   
  187. void AudioWrite(const void*buffer, int size)  
  188. {  
  189.     (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer, size);  
  190. }  
  191.   
  192.     JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayer  
  193. (JNIEnv *env, jclass clz, jstring fileName)  
  194. {  
  195.     const char* local_title = (*env)->GetStringUTFChars(env, fileName, NULL);  
  196.     av_register_all();//注册所有支持的文件格式以及编解码器  
  197.     /* 
  198.      *只读取文件头,并不会填充流信息 
  199.      */  
  200.     if(avformat_open_input(&pFormatCtx, local_title, NULL, NULL) != 0)  
  201.         return -1;  
  202.     /* 
  203.      *获取文件中的流信息,此函数会读取packet,并确定文件中所有流信息, 
  204.      *设置pFormatCtx->streams指向文件中的流,但此函数并不会改变文件指针, 
  205.      *读取的packet会给后面的解码进行处理。 
  206.      */  
  207.     if(avformat_find_stream_info(pFormatCtx, NULL) < 0)  
  208.         return -1;  
  209.     /* 
  210.      *输出文件的信息,也就是我们在使用ffmpeg时能够看到的文件详细信息, 
  211.      *第二个参数指定输出哪条流的信息,-1代表ffmpeg自己选择。最后一个参数用于 
  212.      *指定dump的是不是输出文件,我们的dump是输入文件,因此一定要为0 
  213.      */  
  214.     av_dump_format(pFormatCtx, -1, local_title, 0);  
  215.     int i = 0;  
  216.     for(i=0; i< pFormatCtx->nb_streams; i++)  
  217.     {  
  218.         if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){  
  219.             audioStream = i;  
  220.             break;  
  221.         }  
  222.     }  
  223.   
  224.     if(audioStream < 0)return -1;  
  225.     aCodecCtx = pFormatCtx->streams[audioStream]->codec;  
  226.     aCodec = avcodec_find_decoder(aCodecCtx->codec_id);  
  227.     if(avcodec_open2(aCodecCtx, aCodec, NULL) < 0)return -1;  
  228.     aFrame = avcodec_alloc_frame();  
  229.     if(aFrame == NULL)return -1;  
  230.     int ret;  
  231.     createEngine(env, clz);  
  232.     int flag_start = 0;  
  233.     while(videoFlag != -1)  
  234.     {  
  235.         if(av_read_frame(pFormatCtx, &packet) < 0)break;  
  236.         if(packet.stream_index == audioStream)  
  237.         {  
  238.             ret = avcodec_decode_audio4(aCodecCtx, aFrame, &frameFinished, &packet);  
  239.             if(ret > 0 && frameFinished)  
  240.             {  
  241.                 if(flag_start == 0)  
  242.                 {  
  243.                     flag_start = 1;  
  244.                     createBufferQueueAudioPlayer(env, clz, aCodecCtx->sample_rate, aCodecCtx->channels, SL_PCMSAMPLEFORMAT_FIXED_16);  
  245.                 }  
  246.                 int data_size = av_samples_get_buffer_size(  
  247.                         aFrame->linesize,aCodecCtx->channels,  
  248.                         aFrame->nb_samples,aCodecCtx->sample_fmt, 1);  
  249.                 LOGI("audioDecodec  :%d : %d, :%d    :%d",data_size,aCodecCtx->channels,aFrame->nb_samples,aCodecCtx->sample_rate);  
  250.                 (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, aFrame->data[0], data_size);  
  251.             }  
  252.   
  253.         }  
  254.         usleep(5000);  
  255.         while(videoFlag != 0)  
  256.         {  
  257.             if(videoFlag == 1)//暂停  
  258.             {  
  259.                 sleep(1);  
  260.             }else if(videoFlag == -1) //停止  
  261.             {  
  262.                 break;  
  263.             }  
  264.         }  
  265.         av_free_packet(&packet);  
  266.     }  
  267.     av_free(aFrame);  
  268.     avcodec_close(aCodecCtx);  
  269.     avformat_close_input(&pFormatCtx);  
  270.     (*env)->ReleaseStringUTFChars(env, fileName, local_title);  
  271. }  
  272.   
  273. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerPauseOrPlay  
  274.   (JNIEnv *env, jclass clz)  
  275. {  
  276.         if(videoFlag == 1)  
  277.         {  
  278.                 videoFlag = 0;  
  279.         }else if(videoFlag == 0){  
  280.                 videoFlag = 1;  
  281.         }  
  282.         return videoFlag;  
  283. }  
  284.   
  285. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerStop  
  286.   (JNIEnv *env, jclass clz)  
  287. {  
  288.         videoFlag = -1;  
  289. }  

然后就是需要在Android.mk中添加OpenSL ES的库支持,代码如下:

[cpp]  view plain copy
  1. LOCAL_PATH := $(call my-dir)  
  2. #######################################################  
  3. ##########      ffmpeg-prebuilt     #######  
  4. #######################################################  
  5. #declare the prebuilt library  
  6. include $(CLEAR_VARS)  
  7. LOCAL_MODULE := ffmpeg-prebuilt  
  8. LOCAL_SRC_FILES := ffmpeg/android/armv7-a/libffmpeg-neon.so  
  9. LOCAL_EXPORT_C_INCLUDES := ffmpeg/android/armv7-a/include  
  10. LOCAL_EXPORT_LDLIBS := ffmpeg/android/armv7-a/libffmpeg-neon.so  
  11. LOCAL_PRELINK_MODULE := true  
  12. include $(PREBUILT_SHARED_LIBRARY)  
  13.   
  14. ########################################################  
  15. ##      ffmpeg-test-neno.so     ########  
  16. ########################################################  
  17. include $(CLEAR_VARS)  
  18. TARGET_ARCH_ABI=armeabi-v7a  
  19. LOCAL_ARM_MODE=arm  
  20. LOCAL_ARM_NEON=true  
  21. LOCAL_ALLOW_UNDEFINED_SYMBOLS=false  
  22. LOCAL_MODULE := ffmpeg-test-neon  
  23. #LOCAL_SRC_FILES := jniffmpeg/VideoPlayerDecode.c  
  24. LOCAL_SRC_FILES := jniffmpeg/Decodec_Audio.c      
  25.   
  26. LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/android/armv7-a/include \  
  27.             $(LOCAL_PATH)/ffmpeg \  
  28.             $(LOCAL_PATH)/ffmpeg/libavutil \  
  29.             $(LOCAL_PATH)/ffmpeg/libavcodec \  
  30.             $(LOCAL_PATH)/ffmpeg/libavformat \  
  31.             $(LOCAL_PATH)/ffmpeg/libavcodec \  
  32.             $(LOCAL_PATH)/ffmpeg/libswscale \  
  33.             $(LOCAL_PATH)/jniffmpeg \  
  34.             $(LOCAL_PATH)  
  35. LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt  
  36. LOCAL_LDLIBS    := -llog -lGLESv2 -ljnigraphics -lz -lm $(LOCAL_PATH)/ffmpeg/android/armv7-a/libffmpeg-neon.so  
  37. LOCAL_LDLIBS    += -lOpenSLES   
  38. include $(BUILD_SHARED_LIBRARY)  

由于OpenSLES最低版本需要9所以要在Application.mk中添加平台

[cpp]  view plain copy
  1. # The ARMv7 is significanly faster due to the use of the hardware FPU  
  2. APP_ABI := armeabi   
  3. APP_PLATFORM := android-9  
  4. APP_STL := stlport_static  
  5. APP_CPPFLAGS += -fno-rtti  
  6. #APP_ABI := armeabi  

最后在终端运行ndk-build,就会将代码添加到
[cpp]  view plain copy
  1. ffmpeg-test-neon.so这个库中  

最后在Android端调用


[cpp]  view plain copy
  1. VideoPlayer这个函数就会自动播放视频的声音,测试发现虽然声音正常但是有杂音,可能采样率设置的不对,获取其他的配置有问题,下一章着重解决这个问题,同时使用队列

出在:

[cpp]  view plain copy
  1. VideoPlayer这个函数就会自动播放视频的声音,测试发现虽然声音正常但是有杂音,可能采样率设置的不对,获取其他的配置有问题,下一章着重解决这个问题,同时使用队列
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值