zoukankan      html  css  js  c++  java
  • EasyDarwin开源音频解码项目EasyAudioDecoder:EasyPlayer Android音频解码库(第二部分,封装解码器接口)

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

  • 相关阅读:
    数据类型装换
    变量及数据类型
    27 网络通信协议 udp tcp
    26 socket简单操作
    26 socket简单操作
    14 内置函数 递归 二分法查找
    15 装饰器 开闭原则 代参装饰器 多个装饰器同一函数应用
    12 生成器和生成器函数以及各种推导式
    13 内置函数 匿名函数 eval,exec,compile
    10 函数进阶 动态传参 作用域和名称空间 函数的嵌套 全局变量
  • 原文地址:https://www.cnblogs.com/babosa/p/9217892.html
Copyright © 2011-2022 走看看