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

  • 相关阅读:
    jquery学习以及下载链接
    iOS:进度条控件的详细使用
    iOS: 工具栏控件UIToolBar和工具栏按钮控件UIBarButtonItem的使用
    iOS:分段控件UISegmentedControl的详细使用
    iOS:分页控件UIPageControl的使用
    iOS:提示框(警告框)控件UIActionSheet的详解
    iOS:风火轮活动刷新视图控件UIActivityIndicatorView的详细使用
    iOS:UIPageViewController翻页控制器控件详细介绍
    iOS:提示框(警告框)控件UIAlertView的详解
    iOS:网络编程的第三方框架:AFNetworking、SDWebImage
  • 原文地址:https://www.cnblogs.com/babosa/p/5904606.html
Copyright © 2011-2022 走看看