Android 本地视频播放器开发 —— ffmpeg解码视频文件中的音频

116 篇文章 0 订阅

  在上一章中Android本地视频播放器开发--NDK编译FFmpeg能够获取编译出来的ffmpeg库,接下来就是调用ffmpeg来实现解码,这里我们先解码音频,然后在播放音频,同时为了适应性我会用不同的方法进行播放例如使用Android提供的AudioTrack,SDL、OpengAL,OpenSL ES,最终合入视频播放器的是OpenSL ES,这样可以减少CPU的利用率。接下来在这一章中,先简单的介绍如何解码音频,在下一章中,实现音频的播放。

  首先就是编写调用ffmpeg的文件这里命名为:Decodec_Audio.c
  1. #include <stdio.h>  
  2. #include <stdlib.h>  

  3. #include <android/log.h>  

  4. #include "VideoPlayerDecode.h"  
  5. #include "../ffmpeg/libavutil/avutil.h"  
  6. #include "../ffmpeg/libavcodec/avcodec.h"  
  7. #include "../ffmpeg/libavformat/avformat.h"  

  8. #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "graduation", __VA_ARGS__))  

  9. AVFormatContext *pFormatCtx = NULL;  
  10. int             audioStream, delay_time, videoFlag = 0;  
  11. AVCodecContext  *aCodecCtx;  
  12. AVCodec         *aCodec;  
  13. AVFrame         *aFrame;  
  14. AVPacket        packet;  
  15. int  frameFinished = 0;  

  16.     JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayer  
  17. (JNIEnv *env, jclass clz, jstring fileName)  
  18. {  
  19.     const char* local_title = (*env)->GetStringUTFChars(env, fileName, NULL);  
  20.     av_register_all();//注册所有支持的文件格式以及编解码器  
  21.     /* 
  22.      *只读取文件头,并不会填充流信息 
  23.      */  
  24.     if(avformat_open_input(&pFormatCtx, local_title, NULL, NULL) != 0)  
  25.         return -1;  
  26.     /* 
  27.      *获取文件中的流信息,此函数会读取packet,并确定文件中所有流信息, 
  28.      *设置pFormatCtx->streams指向文件中的流,但此函数并不会改变文件指针, 
  29.      *读取的packet会给后面的解码进行处理。 
  30.      */  
  31.     if(avformat_find_stream_info(pFormatCtx, NULL) < 0)  
  32.         return -1;  
  33.     /* 
  34.      *输出文件的信息,也就是我们在使用ffmpeg时能够看到的文件详细信息, 
  35.      *第二个参数指定输出哪条流的信息,-1代表ffmpeg自己选择。最后一个参数用于 
  36.      *指定dump的是不是输出文件,我们的dump是输入文件,因此一定要为0 
  37.      */  
  38.     av_dump_format(pFormatCtx, -1, local_title, 0);  
  39.     int i = 0;  
  40.     for(i=0; i< pFormatCtx->nb_streams; i++)  
  41.     {  
  42.         if(pFormatCtx->streams->codec->codec_type == AVMEDIA_TYPE_AUDIO){  
  43.             audioStream = i;  
  44.             break;  
  45.         }  
  46.     }  

  47.     if(audioStream < 0)return -1;  
  48.     aCodecCtx = pFormatCtx->streams[audioStream]->codec;  
  49.     aCodec = avcodec_find_decoder(aCodecCtx->codec_id);  
  50.     if(avcodec_open2(aCodecCtx, aCodec, NULL) < 0)return -1;  
  51.     aFrame = avcodec_alloc_frame();  
  52.     if(aFrame == NULL)return -1;  
  53.     int ret;  
  54.     while(videoFlag != -1)  
  55.     {  
  56.         if(av_read_frame(pFormatCtx, &packet) < 0)break;  
  57.         if(packet.stream_index == audioStream)  
  58.         {  
  59.             ret = avcodec_decode_audio4(aCodecCtx, aFrame, &frameFinished, &packet);  
  60.             if(ret > 0 && frameFinished)  
  61.             {  
  62.                 int data_size = av_samples_get_buffer_size(  
  63.                         aFrame->linesize,aCodecCtx->channels,  
  64.                         aFrame->nb_samples,aCodecCtx->sample_fmt, 0);  
  65.                 LOGI("audioDecodec  :%d",data_size);  
  66.             }  

  67.         }  
  68.         usleep(50000);  
  69.         while(videoFlag != 0)  
  70.         {  
  71.             if(videoFlag == 1)//暂停  
  72.             {  
  73.                 sleep(1);  
  74.             }else if(videoFlag == -1) //停止  
  75.             {  
  76.                 break;  
  77.             }  
  78.         }  
  79.         av_free_packet(&packet);  
  80.     }  
  81.     av_free(aFrame);  
  82.     avcodec_close(aCodecCtx);  
  83.     avformat_close_input(&pFormatCtx);  
  84.     (*env)->ReleaseStringUTFChars(env, fileName, local_title);  
  85. }  

  86. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerPauseOrPlay  
  87.   (JNIEnv *env, jclass clz)  
  88. {  
  89.         if(videoFlag == 1)  
  90.         {  
  91.                 videoFlag = 0;  
  92.         }else if(videoFlag == 0){  
  93.                 videoFlag = 1;  
  94.         }  
  95.         return videoFlag;  
  96. }  

  97. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerStop  
  98.   (JNIEnv *env, jclass clz)  
  99. {  
  100.         videoFlag = -1;  
  101. }  
复制代码

  接下来就是编写Android.mk:
  1. #######################################################  
  2. ##########              ffmpeg-prebuilt         #######  
  3. #######################################################  
  4. #declare the prebuilt library  
  5. include $(CLEAR_VARS)  
  6. LOCAL_MODULE := ffmpeg-prebuilt  
  7. LOCAL_SRC_FILES := ffmpeg/android/armv7-a/libffmpeg-neon.so  
  8. LOCAL_EXPORT_C_INCLUDES := ffmpeg/android/armv7-a/include  
  9. LOCAL_EXPORT_LDLIBS := ffmpeg/android/armv7-a/libffmpeg-neon.so  
  10. LOCAL_PRELINK_MODULE := true  
  11. include $(PREBUILT_SHARED_LIBRARY)  

  12. ########################################################  
  13. ##              ffmpeg-test-neno.so             ########  
  14. ########################################################  
  15. include $(CLEAR_VARS)  
  16. TARGET_ARCH_ABI=armeabi-v7a  
  17. LOCAL_ARM_MODE=arm  
  18. LOCAL_ARM_NEON=true  
  19. LOCAL_ALLOW_UNDEFINED_SYMBOLS=false  
  20. LOCAL_MODULE := ffmpeg-test-neon  
  21. LOCAL_SRC_FILES := jniffmpeg/Decodec_Audio.c  

  22. LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/android/armv7-a/include \  
  23.                     $(LOCAL_PATH)/ffmpeg \  
  24.                     $(LOCAL_PATH)/ffmpeg/libavutil \  
  25.                     $(LOCAL_PATH)/ffmpeg/libavcodec \  
  26.                     $(LOCAL_PATH)/ffmpeg/libavformat \  
  27.                     $(LOCAL_PATH)/ffmpeg/libavcodec \  
  28.                     $(LOCAL_PATH)/ffmpeg/libswscale \  
  29.                     $(LOCAL_PATH)/jniffmpeg \  
  30.                     $(LOCAL_PATH)  
  31. LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt  
  32. LOCAL_LDLIBS    := -llog -ljnigraphics -lz -lm $(LOCAL_PATH)/ffmpeg/android/armv7-a/libffmpeg-neon.so  
  33. include $(BUILD_SHARED_LIBRARY)  
复制代码

  然后在终端运行ndk-build,运行结果如下:
  1. root@zhangjie:/Graduation/jni# ndk-build  
  2. Install        : libffmpeg-neon.so => libs/armeabi/libffmpeg-neon.so  
  3. Compile arm    : ffmpeg-test-neon <= Decodec_Audio.c  
  4. SharedLibrary  : libffmpeg-test-neon.so  
  5. Install        : libffmpeg-test-neon.so => libs/armeabi/libffmpeg-test-neon.so  
复制代码

  把编译出来的libffmpeg-test-neon.solib ffmpeg-neon.so拷贝到之前android功能下的libs/armeabi目录下面,点击视频,视频文件开始解码音频,当解码成功,则打印出解码音频包的大小:
  1. 06-07 04:51:30.953: I/graduation(7014): audioDecodec  :2048  
  2. 06-07 04:51:31.000: I/graduation(7014): audioDecodec  :2048  
  3. 06-07 04:51:31.109: I/graduation(7014): audioDecodec  :2048  
  4. 06-07 04:51:31.156: I/graduation(7014): audioDecodec  :2048  
  5. 06-07 04:51:31.257: I/graduation(7014): audioDecodec  :2048  
  6. 06-07 04:51:31.304: I/graduation(7014): audioDecodec  :2048  
  7. 06-07 04:51:31.406: I/graduation(7014): audioDecodec  :2048  
  8. 06-07 04:51:31.460: I/graduation(7014): audioDecodec  :2048  
  9. 06-07 04:51:31.554: I/graduation(7014): audioDecodec  :2048  
  10. 06-07 04:51:31.609: I/graduation(7014): audioDecodec  :2048  
  11. 06-07 04:51:31.710: I/graduation(7014): audioDecodec  :2048  
  12. 06-07 04:51:31.757: I/graduation(7014): audioDecodec  :2048  
  13. 06-07 04:51:31.859: I/graduation(7014): audioDecodec  :2048  
  14. 06-07 04:51:31.914: I/graduation(7014): audioDecodec  :2048  
  15. 06-07 04:51:32.015: I/graduation(7014): audioDecodec  :2048  
  16. 06-07 04:51:32.062: I/graduation(7014): audioDecodec  :2048  
  17. 06-07 04:51:32.164: I/graduation(7014): audioDecodec  :2048  
  18. 06-07 04:51:32.210: I/graduation(7014): audioDecodec  :2048  
  19. 06-07 04:51:32.312: I/graduation(7014): audioDecodec  :2048  
  20. 06-07 04:51:32.367: I/graduation(7014): audioDecodec  :2048  
  21. 06-07 04:51:32.468: I/graduation(7014): audioDecodec  :2048  
  22. 06-07 04:51:32.515: I/graduation(7014): audioDecodec  :2048  
  23. 06-07 04:51:32.617: I/graduation(7014): audioDecodec  :2048  
  24. 06-07 04:51:32.671: I/graduation(7014): audioDecodec  :2048  
  25. 06-07 04:51:32.773: I/graduation(7014): audioDecodec  :2048
复制代码

  在logcat里面可以看到解码音频成功,下面我们将解码出来的音频进行播放。

  使用OpenSL ES来播放解码的音频数据,首先关于OpenSL ES这里暂不介绍,可以查看官网以及NDK中samples下面的native-audio里面的文件,这里我也是扣取了其中的代码,我们播放音频的部分在上一章的基础上进行添加的,代码如下:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  

  4. #include <assert.h>  
  5. #include <android/log.h>  

  6. // for native audio  
  7. #include <SLES/OpenSLES.h>  
  8. #include <SLES/OpenSLES_Android.h>  

  9. #include "VideoPlayerDecode.h"  
  10. #include "../ffmpeg/libavutil/avutil.h"  
  11. #include "../ffmpeg/libavcodec/avcodec.h"  
  12. #include "../ffmpeg/libavformat/avformat.h"  

  13. #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "graduation", __VA_ARGS__))  

  14. AVFormatContext *pFormatCtx = NULL;  
  15. int             audioStream, delay_time, videoFlag = 0;  
  16. AVCodecContext  *aCodecCtx;  
  17. AVCodec         *aCodec;  
  18. AVFrame         *aFrame;  
  19. AVPacket        packet;  
  20. int  frameFinished = 0;  

  21. // engine interfaces  
  22. static SLObjectItf engineObject = NULL;  
  23. static SLEngineItf engineEngine;  

  24. // output mix interfaces  
  25. static SLObjectItf outputMixObject = NULL;  
  26. static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;  

  27. // buffer queue player interfaces  
  28. static SLObjectItf bqPlayerObject = NULL;  
  29. static SLPlayItf bqPlayerPlay;  
  30. static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;  
  31. static SLEffectSendItf bqPlayerEffectSend;  
  32. static SLMuteSoloItf bqPlayerMuteSolo;  
  33. static SLVolumeItf bqPlayerVolume;  

  34. // aux effect on the output mix, used by the buffer queue player  
  35. static const SLEnvironmentalReverbSettings reverbSettings =  
  36.     SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;  

  37. // file descriptor player interfaces  
  38. static SLObjectItf fdPlayerObject = NULL;  
  39. static SLPlayItf fdPlayerPlay;  
  40. static SLSeekItf fdPlayerSeek;  
  41. static SLMuteSoloItf fdPlayerMuteSolo;  
  42. static SLVolumeItf fdPlayerVolume;  

  43. // pointer and size of the next player buffer to enqueue, and number of remaining buffers  
  44. static short *nextBuffer;  
  45. static unsigned nextSize;  
  46. static int nextCount;  

  47. // this callback handler is called every time a buffer finishes playing  
  48. void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)  
  49. {  
  50.     assert(bq == bqPlayerBufferQueue);  
  51.     assert(NULL == context);  
  52.     // for streaming playback, replace this test by logic to find and fill the next buffer  
  53.     if (--nextCount > 0 && NULL != nextBuffer && 0 != nextSize) {  
  54.         SLresult result;  
  55.         // enqueue another buffer  
  56.         result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);  
  57.         // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,  
  58.         // which for this code example would indicate a programming error  
  59.         assert(SL_RESULT_SUCCESS == result);  
  60.     }  
  61. }  


  62. void createEngine(JNIEnv* env, jclass clazz)  
  63. {  
  64.     SLresult result;  

  65.     // create engine  
  66.     result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);  
  67.     assert(SL_RESULT_SUCCESS == result);  

  68.     // realize the engine  
  69.     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);  
  70.     assert(SL_RESULT_SUCCESS == result);  

  71.     // get the engine interface, which is needed in order to create other objects  
  72.     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);  
  73.     assert(SL_RESULT_SUCCESS == result);  

  74.     // create output mix, with environmental reverb specified as a non-required interface  
  75.     const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};  
  76.     const SLboolean req[1] = {SL_BOOLEAN_FALSE};  
  77.     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);  
  78.     assert(SL_RESULT_SUCCESS == result);  

  79.     // realize the output mix  
  80.     result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);  
  81.     assert(SL_RESULT_SUCCESS == result);  

  82.     // get the environmental reverb interface  
  83.     // this could fail if the environmental reverb effect is not available,  
  84.     // either because the feature is not present, excessive CPU load, or  
  85.     // the required MODIFY_AUDIO_SETTINGS permission was not requested and granted  
  86.     result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,  
  87.             &outputMixEnvironmentalReverb);  
  88.     if (SL_RESULT_SUCCESS == result) {  
  89.         result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(  
  90.                 outputMixEnvironmentalReverb, &reverbSettings);  
  91.     }  
  92.     // ignore unsuccessful result codes for environmental reverb, as it is optional for this example  
  93. }  

  94. void createBufferQueueAudioPlayer(JNIEnv* env, jclass clazz, int rate, int channel,int bitsPerSample)  
  95. {  
  96.     SLresult result;  

  97.     // configure audio source  
  98.     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};  
  99. //    SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2, SL_SAMPLINGRATE_16,  
  100. //        SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,  
  101. //        SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN};  
  102.    SLDataFormat_PCM format_pcm;  
  103.    format_pcm.formatType = SL_DATAFORMAT_PCM;  
  104. format_pcm.numChannels = channel;  
  105. format_pcm.samplesPerSec = rate * 1000;  
  106. format_pcm.bitsPerSample = bitsPerSample;  
  107. format_pcm.containerSize = 16;  
  108. if(channel == 2)  
  109. format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;  
  110. else  
  111. format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;  
  112. format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;  
  113.     SLDataSource audioSrc = {&loc_bufq, &format_pcm};  

  114.     // configure audio sink  
  115.     SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};  
  116.     SLDataSink audioSnk = {&loc_outmix, NULL};  

  117.     // create audio player  
  118.     const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_EFFECTSEND,  
  119.             /*SL_IID_MUTESOLO,*/ SL_IID_VOLUME};  
  120.     const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,  
  121.             /*SL_BOOLEAN_TRUE,*/ SL_BOOLEAN_TRUE};  
  122.     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,  
  123.             3, ids, req);  
  124.     assert(SL_RESULT_SUCCESS == result);  
  125. // realize the player  
  126.     result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);  
  127.     assert(SL_RESULT_SUCCESS == result);  

  128.     // get the play interface  
  129.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);  
  130.     assert(SL_RESULT_SUCCESS == result);  

  131.     // get the buffer queue interface  
  132.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,  
  133.             &bqPlayerBufferQueue);  
  134.     assert(SL_RESULT_SUCCESS == result);  

  135.     // register callback on the buffer queue  
  136.     result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);  
  137.     assert(SL_RESULT_SUCCESS == result);  

  138.     // get the effect send interface  
  139.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,  
  140.             &bqPlayerEffectSend);  
  141.     assert(SL_RESULT_SUCCESS == result);  

  142. #if 0   // mute/solo is not supported for sources that are known to be mono, as this is  
  143.     // get the mute/solo interface  
  144.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);  
  145.     assert(SL_RESULT_SUCCESS == result);  
  146. #endif  

  147.     // get the volume interface  
  148.     result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);  
  149.     assert(SL_RESULT_SUCCESS == result);  

  150. // set the player's state to playing  
  151.     result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);  
  152.     assert(SL_RESULT_SUCCESS == result);  

  153. }  

  154. void AudioWrite(const void*buffer, int size)  
  155. {  
  156.     (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer, size);  
  157. }  

  158.     JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayer  
  159. (JNIEnv *env, jclass clz, jstring fileName)  
  160. {  
  161.     const char* local_title = (*env)->GetStringUTFChars(env, fileName, NULL);  
  162.     av_register_all();//注册所有支持的文件格式以及编解码器  
  163.     /* 
  164.      *只读取文件头,并不会填充流信息 
  165.      */  
  166.     if(avformat_open_input(&pFormatCtx, local_title, NULL, NULL) != 0)  
  167.         return -1;  
  168.     /* 
  169.      *获取文件中的流信息,此函数会读取packet,并确定文件中所有流信息, 
  170.      *设置pFormatCtx->streams指向文件中的流,但此函数并不会改变文件指针, 
  171.      *读取的packet会给后面的解码进行处理。 
  172.      */  
  173.     if(avformat_find_stream_info(pFormatCtx, NULL) < 0)  
  174.         return -1;  
  175.     /* 
  176.      *输出文件的信息,也就是我们在使用ffmpeg时能够看到的文件详细信息, 
  177.      *第二个参数指定输出哪条流的信息,-1代表ffmpeg自己选择。最后一个参数用于 
  178.      *指定dump的是不是输出文件,我们的dump是输入文件,因此一定要为0 
  179.      */  
  180.     av_dump_format(pFormatCtx, -1, local_title, 0);  
  181.     int i = 0;  
  182.     for(i=0; i< pFormatCtx->nb_streams; i++)  
  183.     {  
  184.         if(pFormatCtx->streams->codec->codec_type == AVMEDIA_TYPE_AUDIO){  
  185.             audioStream = i;  
  186.             break;  
  187.         }  
  188.     }  

  189.     if(audioStream < 0)return -1;  
  190.     aCodecCtx = pFormatCtx->streams[audioStream]->codec;  
  191.     aCodec = avcodec_find_decoder(aCodecCtx->codec_id);  
  192.     if(avcodec_open2(aCodecCtx, aCodec, NULL) < 0)return -1;  
  193.     aFrame = avcodec_alloc_frame();  
  194.     if(aFrame == NULL)return -1;  
  195.     int ret;  
  196.     createEngine(env, clz);  
  197.     int flag_start = 0;  
  198.     while(videoFlag != -1)  
  199.     {  
  200.         if(av_read_frame(pFormatCtx, &packet) < 0)break;  
  201.         if(packet.stream_index == audioStream)  
  202.         {  
  203.             ret = avcodec_decode_audio4(aCodecCtx, aFrame, &frameFinished, &packet);  
  204.             if(ret > 0 && frameFinished)  
  205.             {  
  206.                 if(flag_start == 0)  
  207.                 {  
  208.                     flag_start = 1;  
  209.                     createBufferQueueAudioPlayer(env, clz, aCodecCtx->sample_rate, aCodecCtx->channels, SL_PCMSAMPLEFORMAT_FIXED_16);  
  210.                 }  
  211.                 int data_size = av_samples_get_buffer_size(  
  212.                         aFrame->linesize,aCodecCtx->channels,  
  213.                         aFrame->nb_samples,aCodecCtx->sample_fmt, 1);  
  214.                 LOGI("audioDecodec  :%d : %d, :%d    :%d",data_size,aCodecCtx->channels,aFrame->nb_samples,aCodecCtx->sample_rate);  
  215.                 (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, aFrame->data[0], data_size);  
  216.             }  

  217.         }  
  218.         usleep(5000);  
  219.         while(videoFlag != 0)  
  220.         {  
  221.             if(videoFlag == 1)//暂停  
  222.             {  
  223.                 sleep(1);  
  224.             }else if(videoFlag == -1) //停止  
  225.             {  
  226.                 break;  
  227.             }  
  228.         }  
  229.         av_free_packet(&packet);  
  230.     }  
  231.     av_free(aFrame);  
  232.     avcodec_close(aCodecCtx);  
  233.     avformat_close_input(&pFormatCtx);  
  234.     (*env)->ReleaseStringUTFChars(env, fileName, local_title);  
  235. }  

  236. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerPauseOrPlay  
  237.   (JNIEnv *env, jclass clz)  
  238. {  
  239.         if(videoFlag == 1)  
  240.         {  
  241.                 videoFlag = 0;  
  242.         }else if(videoFlag == 0){  
  243.                 videoFlag = 1;  
  244.         }  
  245.         return videoFlag;  
  246. }  

  247. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerStop  
  248.   (JNIEnv *env, jclass clz)  
  249. {  
  250.         videoFlag = -1;  
  251. }  
复制代码

  然后就是需要在Android.mk中添加OpenSL ES的库支持,代码如下:
  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. ##      ffmpeg-test-neno.so     ########  
  15. ########################################################  
  16. include $(CLEAR_VARS)  
  17. TARGET_ARCH_ABI=armeabi-v7a  
  18. LOCAL_ARM_MODE=arm  
  19. LOCAL_ARM_NEON=true  
  20. LOCAL_ALLOW_UNDEFINED_SYMBOLS=false  
  21. LOCAL_MODULE := ffmpeg-test-neon  
  22. #LOCAL_SRC_FILES := jniffmpeg/VideoPlayerDecode.c  
  23. LOCAL_SRC_FILES := jniffmpeg/Decodec_Audio.c      

  24. LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/android/armv7-a/include \  
  25.             $(LOCAL_PATH)/ffmpeg \  
  26.             $(LOCAL_PATH)/ffmpeg/libavutil \  
  27.             $(LOCAL_PATH)/ffmpeg/libavcodec \  
  28.             $(LOCAL_PATH)/ffmpeg/libavformat \  
  29.             $(LOCAL_PATH)/ffmpeg/libavcodec \  
  30.             $(LOCAL_PATH)/ffmpeg/libswscale \  
  31.             $(LOCAL_PATH)/jniffmpeg \  
  32.             $(LOCAL_PATH)  
  33. LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt  
  34. LOCAL_LDLIBS    := -llog -lGLESv2 -ljnigraphics -lz -lm $(LOCAL_PATH)/ffmpeg/android/armv7-a/libffmpeg-neon.so  
  35. LOCAL_LDLIBS    += -lOpenSLES   
  36. include $(BUILD_SHARED_LIBRARY)  
复制代码

  由于OpenSLES最低版本需要9所以要在Application.mk中添加平台
  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,就会将代码添加到ffmpeg-test-neon.so这个库中  

  最后在Android端调用VideoPlayer这个函数就会自动播放视频的声音,测试发现虽然声音正常但是有杂音,可能采样率设置的不对,获取其他的配置有问题,下一章着重解决这个问题,同时使用队列的方式来从视频中取音频包,然后从音频包队列中取出,然后解码播放。  


  原文地址:
     http://blog.csdn.net/jwzhangjie/article/details/9046427
     http://blog.csdn.net/jwzhangjie/article/details/9056607
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值