上一节我们讲了如何基于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.
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

接下来我们要实现相应的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

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

close:


av_frame_free(&pFrame);
avcodec_close(pComponent->pCodecCtx);
avcodec_free_context(&pCodecCtx);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

对于其它格式的音频算法,只要在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

我们这里需要把之前编译出来的静态库链接起来,生成一个动态库。其中,静态库lib文件和头文件分别放在/aacdec/lib/ 和 /aacdec/include/ 下。

接下来,cd到jni目录,执行ndk-build,如果顺利的话,我们要的动态库文件就会生成。

整个项目源码见Github

EasyDarwin开源音频解码项目EasyAudioDecoder:EasyPlayer Android音频解码库(第二部分,封装解码器接口)的更多相关文章

  1. EasyDarwin开源音频解码项目EasyAudioDecoder:基于ffmpeg的安卓音频(AAC、G726)解码库(第一部分,ffmpeg-android的编译)

    ffmpeg是一套开源的,完整的流媒体解决方案.基于它可以很轻松构建一些强大的应用程序.对于流媒体这个行业,ffmpeg就像圣经一样的存在.为了表达敬意,在这里把ffmpeg官网的一段简介搬过来,ff ...

  2. android调用第三方库——第二篇——编写库android程序直接调用第三方库libhello.so (转载)

    转自:http://blog.csdn.net/jiuyueguang/article/details/9449737 版权声明:本文为博主原创文章,未经博主允许不得转载. 0:前言 1:本文主要作为 ...

  3. EasyDarwin开源流媒体云平台中boost Base64编解码后与源长度不匹配的bug

    本文转自EasyDarwin团队Alex的博客:http://blog.csdn.net/cai6811376 EasyDarwin云平台中部分协议使用了Base64编码昨晚报文通信的载体.比如在对摄 ...

  4. EasyDarwin开源流媒体服务器提供的RTMP直播推送库

    EasyRTMP EasyRTMP是什么? EasyRTMP是一个EasyDarwin配套使用,也可以单独使用的RTMP推送库,通过EasyRTMP我们就可以避免接触到稍显复杂的RTMP推送流程,只需 ...

  5. Android 网络请求库volley的封装,让请求更方便

    首先封装一下volley 请求 public class CustomRequest extends StringRequest { private static final String TAG = ...

  6. EasyCamera Android安卓移动视频监控单兵设备接入EasyDarwin开源流媒体云平台

    前言 随着Android系统的不断更新和发展,现在越来越多的硬件产品选择用安卓系统作为运行环境,电视机,机顶盒.门禁.行车记录仪.车载系统.单兵设备等等,Android系统底层还是Linux,但对上层 ...

  7. EasyDarwin开源流媒体server将select改为epoll的方法

    本文来自EasyDarwin团队Fantasy(fantasy(at)easydarwin.org) 一. EasyDarwin网络模型介绍 EventContext负责监听全部网络读写事件.Even ...

  8. EasyDarwin开源流媒体服务器将select改为epoll的方法

    本文来自EasyDarwin团队Fantasy(fantasy(at)easydarwin.org) 一. EasyDarwin网络模型介绍 EventContext负责监听所有网络读写事件,Even ...

  9. EasyDarwin开源团队招募开发组成员

    EasyDarwin开源流媒体服务器项目招募开发组成员,共同更新和维护EasyDarwin流媒体服务器,决策EasyDarwin后续开发方向: 加入要求: 1.对开源流媒体项目有浓厚兴趣: 2.有一定 ...

随机推荐

  1. 求N维前缀和

    转载自http://blog.csdn.net/jzhang1/article/details/50528549#comments 膜拜 #include <iostream> #incl ...

  2. 标准C程序设计七---54

    Linux应用             编程深入            语言编程 标准C程序设计七---经典C11程序设计    以下内容为阅读:    <标准C程序设计>(第7版) 作者 ...

  3. idea http请求的插件(测试接口方便)

    http://blog.csdn.net/winter_chen001/article/details/77249029

  4. HDU 1394:Minimum Inversion Number(树状数组,线段树)[水]

    题意:有0~n-1这n个数,以一定的排列.这个排列可以循环,就是可以把第一个拿到最后,然后形成新的排列.问这些排列中的逆序对最小值. 思路: 最后的循环,拿走一个之后,新的逆序对数 newsum = ...

  5. Unity3D Shader 入门之简单案例的实现(通过法线实现颜色变化)

    在没有接触Unity3D  Shader 之前,总感觉shader特别神奇,因为听说是对渲染流水线进行编程,就是对GPU进行编程.听着特别高大上.这不,最近刚刚接触Shader,学了几个小案例,然后本 ...

  6. Hdoj 3506 Monkey Party

    Discription Far away from our world, there is a banana forest. And many lovely monkeys live there. O ...

  7. 在eclipse使用map reduce编写word count程序生成jar包并在虚拟机运行的步骤

    ---恢复内容开始--- 1.首先准备一个需要统计的单词文件 word.txt,我们的单词是以空格分开的,统计时按照空格分隔即可 hello hadoop hello yarnhello zookee ...

  8. Mac下安装和使用GunPG(GPG)

    GPG是加解密的工具,亦可以用于签名.非对称加解密.需要公钥和私钥. mac下安装:brew install gpg 使用gpg工具校验下载文件的完整性,从官网下载KEYS和asc文件:gpg --i ...

  9. VS中的 MD/MT设置 【转】

    VS系列工具作为目前微软主打的集成开发环境,在历经了近20多年的发展后,到如今已经可以 说是Windows平台上各种IDE环境中的翘楚了.很多别的开发工具已经难望其项背了,如今VS2010也已经面市很 ...

  10. SSH 原理和公匙私匙

    先主要介绍了Telnet.SSH 的通信原理,分析了其通信时的工作流程. Telnet 无论Telnet协议连接的是什么类型终端,都会转换为NVT(Net Virtual Terminal)格式进行通 ...