EasyDarwin开源音频解码项目EasyAudioDecoder:EasyPlayer Android音频解码库(第二部分,封装解码器接口)
2016-09-17 14:42
1036 查看
上一节我们讲了如何基于ffmpeg-Android工程编译安卓上的支持音频的ffmpeg静态库:http://blog.csdn.net/xiejiashu/article/details/52524099,这篇文章我们将介绍如何封装安卓的解码器。
首先,为了能让我们的app调用调用,我们需要定义一套Java的native接口,解码器主要有三个接口:
create 创建解码器,参数分别为:
codec:音频编码格式,参考EasyTypes.h里面的EASY_SDK_AUDIO_CODEC_*宏定义;
sample_rate:采样率,通常为8000、44000等等;
channels:通道数,1、2分别表示单通道、双通道;
sample_bit:采样精度,通常为16bit;
返回解码器句柄,即后续接口里面用到的handle
decode 解码,参数为:
handle :解码器句柄
buffer:要解码的buffer(编码后的音频数据)
offset:编码数据在buffer里的起始位置
length:编码数据的长度
pcm:解码后的pcm数据
outLen 长度至少为1的int数组,如果解码成功,那outLen[0]被置为pcm的数据长度
close 关闭解码器,参数为解码器的句柄。关闭后句柄无效,应该置为0.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[/code]接下来我们要实现相应的native接口,头文件可通过调用javah命令(这里不再详述)来生成。以AAC解码来说明,create代码片段如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[/code]decode:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[/code]close:
2
3
4
1
2
3
4
[/code]对于其它格式的音频算法,只要在avcodec_find_decoder时传入不同的算法ID即可。
接下来,我们需要使用NDK编译出ANDROID上可以使用的动态库,为此我们需要编辑Android.mk文件,其内容如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
[/code]我们这里需要把之前编译出来的静态库链接起来,生成一个动态库。其中,静态库lib文件和头文件分别放在/aacdec/lib/ 和 /aacdec/include/ 下。
接下来,cd到jni目录,执行ndk-build,如果顺利的话,我们要的动态库文件就会生成。
整个项目源码见Github
首先,为了能让我们的app调用调用,我们需要定义一套Java的native接口,解码器主要有三个接口:
create 创建解码器,参数分别为:
codec:音频编码格式,参考EasyTypes.h里面的EASY_SDK_AUDIO_CODEC_*宏定义;
sample_rate:采样率,通常为8000、44000等等;
channels:通道数,1、2分别表示单通道、双通道;
sample_bit:采样精度,通常为16bit;
返回解码器句柄,即后续接口里面用到的handle
decode 解码,参数为:
handle :解码器句柄
buffer:要解码的buffer(编码后的音频数据)
offset:编码数据在buffer里的起始位置
length:编码数据的长度
pcm:解码后的pcm数据
outLen 长度至少为1的int数组,如果解码成功,那outLen[0]被置为pcm的数据长度
close 关闭解码器,参数为解码器的句柄。关闭后句柄无效,应该置为0.
package org.easydarwin.audio; /** * Created by John on 2016/3/18. */ public class AudioCodec { static { System.loadLibrary("AudioCodecer"); } public static native int create(int codec, int sample_rate, int channels, int sample_bit); public static native int decode(int handle, byte[] buffer, int offset, int length, byte[] pcm, int[] outLen); public static native void close(int handle); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[/code]接下来我们要实现相应的native接口,头文件可通过调用javah命令(这里不再详述)来生成。以AAC解码来说明,create代码片段如下:
// 创建获取解码器 AVCodec *pCodec = avcodec_find_decoder(AV_CODEC_ID_AAC); if (pCodec == NULL) { LOGI("find aac decoder error"); printf("find aac decoder error\r\n"); return 0; } // 创建解码Context并open解码器 pCodecCtx = avcodec_alloc_context3(pCodec); pCodecCtx->channels = channels; pCodecCtx->sample_rate = sample_rate; pCodecCtx->bit_rate = bit_rate; if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { printf("open codec error\r\n"); return 0; } // 分配内存,存放解码后的数据 pFrame = av_frame_alloc();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[/code]decode:
// 源码流赋值 packet.size = length; packet.data = buffer; int got_frame = 0; // 解码、数据拷贝 while (pkt_pos < nLen) { // pkt_pos = 0; int got_frame = 0; src_len = avcodec_decode_audio4(pAACD->pCodecCtx, pAACD->pFrame, &got_frame, &packet); if (src_len < 0) { return -3; } data_len += src_len if (got_frame) { memcpy(pAACD->pFrame, pAACD->audio_buf, len); dst_len += len; } pkt_pos += src_len; packet.data = pData + pkt_pos; packet.size = nLen - pkt_pos; } if (NULL != outLen) *outLen = dst_len; // 释放 av_free_packet(&packet);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[/code]close:
av_frame_free(&pFrame); avcodec_close(pComponent->pCodecCtx); avcodec_free_context(&pCodecCtx);1
2
3
4
1
2
3
4
[/code]对于其它格式的音频算法,只要在avcodec_find_decoder时传入不同的算法ID即可。
接下来,我们需要使用NDK编译出ANDROID上可以使用的动态库,为此我们需要编辑Android.mk文件,其内容如下:
# Copyright (C) 2009 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # LOCAL_PATH:= $(call my-dir) SRC_ROOT_PATH := $(call my-dir) LOCAL_INCLUDE := $(LOCAL_PATH)/aacdec/include # 加载预编译的静态库 include $(CLEAR_VARS) LOCAL_MODULE := libavcodec LOCAL_SRC_FILES := $(LOCAL_PATH)/aacdec/lib/libavcodec.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libavdevice LOCAL_SRC_FILES := $(LOCAL_PATH)/aacdec/lib/libavdevice.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libavfilter LOCAL_SRC_FILES := $(LOCAL_PATH)/aacdec/lib/libavfilter.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libavformat LOCAL_SRC_FILES := $(LOCAL_PATH)/aacdec/lib/libavformat.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libavutil LOCAL_SRC_FILES := $(LOCAL_PATH)/aacdec/lib/libavutil.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libswresample LOCAL_SRC_FILES := $(LOCAL_PATH)/aacdec/lib/libswresample.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libswscale LOCAL_SRC_FILES := $(LOCAL_PATH)/aacdec/lib/libswscale.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_C_INCLUDES += $(LOCAL_PATH) LOCAL_C_INCLUDES += $(LOCAL_INCLUDE) PROJECT_FILES := $(wildcard $(SRC_ROOT_PATH)/*.cpp) PROJECT_FILES += $(wildcard $(SRC_ROOT_PATH)/*.c) PROJECT_FILES += $(wildcard $(SRC_ROOT_PATH)/aacdec/*.cpp) $(warning $(PROJECT_FILES)) PROJECT_FILES := $(PROJECT_FILES:$(LOCAL_PATH)/%=%) $(warning $(PROJECT_FILES)) LOCAL_SRC_FILES := $(PROJECT_FILES) LOCAL_CFLAGS := -D__unix__ -DANDROID_OS -D__arm__ -D__STDC_CONSTANT_MACROS LOCAL_MODULE := AudioCodecer LOCAL_LDLIBS += -L$(LOCAL_PATH)/aacdec/lib -lavcodec -lswscale -lswresample -lavutil -lavformat -lavfilter -lavdevice -llog -lz CFLAGS += -mfpu=neon LOCAL_STATIC_LIBRARIES := libavcodec libswscale libswresample libavutil libavformat libavfilter libavdevice include $(BUILD_SHARED_LIBRARY)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
[/code]我们这里需要把之前编译出来的静态库链接起来,生成一个动态库。其中,静态库lib文件和头文件分别放在/aacdec/lib/ 和 /aacdec/include/ 下。
接下来,cd到jni目录,执行ndk-build,如果顺利的话,我们要的动态库文件就会生成。
整个项目源码见Github
相关文章推荐
- Android 简易音乐动态相册(多种动画)
- NumberPicker制作省市选择器/时间选择器
- Android下拉刷新代码完全解析,完全解读大神代码,解决两个小bug
- 判断AccessibilityService服务是否已经启动
- android里,addContentView()动态增加view控件,并实现控件的顶部,中间,底部布局
- Android 利用addView 动态给Activity添加View组件
- Android拓展系列(5)--CyanogenMod源码下载和编译(Android ROM定制基础篇)
- 简单的自定义View-仿SlideMenu
- android开发之Notification(一)
- Android 第三方ROM CyanogenMod 源码下载,编译,刷机
- Android菜单选项
- 给 Android 开发者的 RxJava 详解
- Android,底部导航+viewpager+fragment+drawerlayout+toolbar+recyclerview
- android:launchMode 启动模式
- 使Eclipse或AndroidStudio的代码模板自动生成类名和方法名
- androidstudio无法真机运行
- Android开发之数据持久化存储
- 作为一个Android开发者,你所需要掌握的东西
- Android Studio 个性化设置
- Android集成极光推送 的异常