在上一章中 Android本地视频播放器开发--NDK编译FFmpeg 能够获取编译出来的ffmpeg库,接下来就是调用ffmpeg来实现解码,这里我们先解码音频,然后在播放音频,同时为了适应性我会用不同的方法进行播放例如使用Android提供的AudioTrack,SDL、OpengAL,OpenSL ES,最终合入视频播放器的是OpenSL ES,这样可以减少CPU的利用率。接下来在这一章中,先简单的介绍如何解码音频,在下一章中,实现音频的播放。
首先就是编写调用ffmpeg的文件这里命名为:Decodec_Audio.c
[cpp]
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. #include <android/log.h>
5.
6. #include "VideoPlayerDecode.h"
7. #include "../ffmpeg/libavutil/avutil.h"
8. #include "../ffmpeg/libavcodec/avcodec.h"
9. #include "../ffmpeg/libavformat/avformat.h"
10.
11. #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "graduation", __VA_ARGS__))
12.
13. AVFormatContext *pFormatCtx = NULL;
14. int audioStream, delay_time, videoFlag = 0;
15. AVCodecContext *aCodecCtx;
16. AVCodec *aCodec;
17. AVFrame *aFrame;
18. AVPacket packet;
19. int frameFinished = 0;
20.
21. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayer
22. (JNIEnv *env, jclass clz, jstring fileName)
23. {
24. const char* local_title = (*env)->GetStringUTFChars(env, fileName, NULL);
25. //注册所有支持的文件格式以及编解码器
26. /*
27. *只读取文件头,并不会填充流信息
28. */
29. if(avformat_open_input(&pFormatCtx, local_title, NULL, NULL) != 0)
30. return -1;
31. /*
32. *获取文件中的流信息,此函数会读取packet,并确定文件中所有流信息,
33. *设置pFormatCtx->streams指向文件中的流,但此函数并不会改变文件指针,
34. *读取的packet会给后面的解码进行处理。
35. */
36. if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
37. return -1;
38. /*
39. *输出文件的信息,也就是我们在使用ffmpeg时能够看到的文件详细信息,
40. *第二个参数指定输出哪条流的信息,-1代表ffmpeg自己选择。最后一个参数用于
41. *指定dump的是不是输出文件,我们的dump是输入文件,因此一定要为0
42. */
43. av_dump_format(pFormatCtx, -1, local_title, 0);
44. int i = 0;
45. for(i=0; i< pFormatCtx->nb_streams; i++)
46. {
47. if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){
48. audioStream = i;
49. break;
50. }
51. }
52.
53. if(audioStream < 0)return -1;
54. aCodecCtx = pFormatCtx->streams[audioStream]->codec;
55. aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
56. if(avcodec_open2(aCodecCtx, aCodec, NULL) < 0)return -1;
57. aFrame = avcodec_alloc_frame();
58. if(aFrame == NULL)return -1;
59. int ret;
60. while(videoFlag != -1)
61. {
62. if(av_read_frame(pFormatCtx, &packet) < 0)break;
63. if(packet.stream_index == audioStream)
64. {
65. ret = avcodec_decode_audio4(aCodecCtx, aFrame, &frameFinished, &packet);
66. if(ret > 0 && frameFinished)
67. {
68. int data_size = av_samples_get_buffer_size(
69. aFrame->linesize,aCodecCtx->channels,
70. aFrame->nb_samples,aCodecCtx->sample_fmt, 0);
71. "audioDecodec :%d",data_size);
72. }
73.
74. }
75. usleep(50000);
76. while(videoFlag != 0)
77. {
78. if(videoFlag == 1)//暂停
79. {
80. sleep(1);
81. else if(videoFlag == -1) //停止
82. {
83. break;
84. }
85. }
86. av_free_packet(&packet);
87. }
88. av_free(aFrame);
89. avcodec_close(aCodecCtx);
90. avformat_close_input(&pFormatCtx);
91. (*env)->ReleaseStringUTFChars(env, fileName, local_title);
92. }
93.
94. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerPauseOrPlay
95. (JNIEnv *env, jclass clz)
96. {
97. if(videoFlag == 1)
98. {
99. videoFlag = 0;
100. else if(videoFlag == 0){
101. videoFlag = 1;
102. }
103. return videoFlag;
104. }
105.
106. JNIEXPORT jint JNICALL Java_com_zhangjie_graduation_videopalyer_jni_VideoPlayerDecode_VideoPlayerStop
107. (JNIEnv *env, jclass clz)
108. {
109. videoFlag = -1;
110. }
接下来就是编写Android.mk:
[html]
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. ########################################################
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/Decodec_Audio.c
23.
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 -ljnigraphics -lz -lm $(LOCAL_PATH)/ffmpeg/android/armv7-a/libffmpeg-neon.so
35. include $(BUILD_SHARED_LIBRARY)
然后在终端运行ndk-build,运行结果如下:
[cpp]
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
把编译出来的
[cpp]
1. libffmpeg-test-neon.so<pre name="code" class="cpp" style="font-size: 14px;">libffmpeg-neon.so</pre><p></p>
2. <pre></pre>
3. <p></p>
4. <p><span style="font-size:14px">拷贝到之前android功能下的libs/armeabi目录下面,点击视频,视频文件开始解码音频,当解码成功,则打印出解码音频包的大小:</span></p>
5. <p><span style="font-size:14px"><img src="" alt=""><br>
6. </span></p>
7. <p><span style="font-size:14px"></span></p><pre name="code" class="cpp">06-07 04:51:30.953: I/graduation(7014): audioDecodec :2048
8. 06-07 04:51:31.000: I/graduation(7014): audioDecodec :2048
9. 06-07 04:51:31.109: I/graduation(7014): audioDecodec :2048
10. 06-07 04:51:31.156: I/graduation(7014): audioDecodec :2048
11. 06-07 04:51:31.257: I/graduation(7014): audioDecodec :2048
12. 06-07 04:51:31.304: I/graduation(7014): audioDecodec :2048
13. 06-07 04:51:31.406: I/graduation(7014): audioDecodec :2048
14. 06-07 04:51:31.460: I/graduation(7014): audioDecodec :2048
15. 06-07 04:51:31.554: I/graduation(7014): audioDecodec :2048
16. 06-07 04:51:31.609: I/graduation(7014): audioDecodec :2048
17. 06-07 04:51:31.710: I/graduation(7014): audioDecodec :2048
18. 06-07 04:51:31.757: I/graduation(7014): audioDecodec :2048
19. 06-07 04:51:31.859: I/graduation(7014): audioDecodec :2048
20. 06-07 04:51:31.914: I/graduation(7014): audioDecodec :2048
21. 06-07 04:51:32.015: I/graduation(7014): audioDecodec :2048
22. 06-07 04:51:32.062: I/graduation(7014): audioDecodec :2048
23. 06-07 04:51:32.164: I/graduation(7014): audioDecodec :2048
24. 06-07 04:51:32.210: I/graduation(7014): audioDecodec :2048
25. 06-07 04:51:32.312: I/graduation(7014): audioDecodec :2048
26. 06-07 04:51:32.367: I/graduation(7014): audioDecodec :2048
27. 06-07 04:51:32.468: I/graduation(7014): audioDecodec :2048
28. 06-07 04:51:32.515: I/graduation(7014): audioDecodec :2048
29. 06-07 04:51:32.617: I/graduation(7014): audioDecodec :2048
30. 06-07 04:51:32.671: I/graduation(7014): audioDecodec :2048
31. 06-07 04:51:32.773: I/graduation(7014): audioDecodec :2048</pre><br>
32. 在logcat里面可以看到解码音频成功,下面一章我们将解码出来的音频进行播放。<p></p>
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。