用LAME这个开源的MP3编码库在iOS平台和Android平台上将一个PCM文件编码为MP3文件,最终将编码后的MP3文件发送到电脑上即可进行播放

在iOS上如何搭建一个基础项目

xcode 选择Single View Application模板,看到Xcode默认是以Story board的形式构建的界面部分,由于我们不希望使用这种形式来构建界面,而是希望使用xib的形式来构建界面,所以要在Main Interface选项中删除其中的内容。

接下来,再建立一个界面文件作为应用的第一个界面,而在iOS中一个界面就是一个xib文件,iOS程序运行的时候其入口是main.m,但是苹果公司不希望开发者修改该文件,而是要求开发者去修改应用的入口——AppDelgate.m文件。

开发者仅需要把引用C++的OC类的后缀名改为.mm(OC类的正常后缀名是.m),就可以和C++一块编译了。所以开发者仅需要把ViewController的后缀名改为.mm,再包含进Mp3Encoder.h头文件,

Mp3Encoder* encoder = new Mp3Encoder();

encoder->encode ();
delete encoder;

在Android上如何搭建一个基础项目

jni 项目

交叉编译的原理与实践

无论是自行安装PC上的编译器,还是下载其他平台(Android或者iOS)的交叉工具编译链,它们都会提供以下几个工具:CC、AS、AR、LD、NM、GDB。那么,这几个工具到底是做什么用的呢?下面就来逐一解释一下。
·CC:编译器,对C源文件进行编译处理,生成汇编文件。
·AS:将汇编文件生成目标文件(汇编文件使用的是指令助记符,AS将它翻译成机器码)。
·AR:打包器,用于库操作,可以通过该工具从一个库中删除或者增加目标代码模块。
·LD:链接器,为前面生成的目标代码分配地址空间,将多个目标文件链接成一个库或者是可执行文件。

·GDB:调试工具,可以对运行过程中的程序进行代码调试工作。
·STRIP:以最终生成的可执行文件或者库文件作为输入,然后消除掉其中的源码。
·NM:查看静态库文件中的符号表。
·Objdump:查看静态库或者动态库的方法签名。
了解了这些之后,当读者再进行交叉编译或者使用交叉编译工具链提供的工具时,就不会感到陌生了,接下来将会在iOS平台和Android平台分别演示如何交叉编译出几个常用的音视频开源库。
编译器对比
正常编译一个程序的过程如下:
编译:gcc-c main.cpp./libmad/mad_decoder.cpp-I./libmad/include
打包:ar cr../prebuilt/libmedia.a mad_decoder.o
链接:g++-o main main.o-L../prebuilt-l mdedia
在这个过程中,gcc、ar、g++是我们用到的三个编译工具,在这里没有用到的ranlib、gdb、nm、strip等都会包含在PC的编译器中,同样其他平台提供的交叉工具编译链中也会包含这些命令行工具,比如Android提供的NDK,其交叉工具编译链中的prebuilt/darwin-x86_64/bin中,就包含了对应的gcc、ar、g++、gdb、strip、nm、ranlib等工具。

iOS平台交叉编译的实践

前面提到的目标平台虽然都基于ARM平台,但是随着时间的推移,平台也在不断地演进,就像armv5到armv6、armv7以及到现在的arm64

·armv6:iPhone、iPhone 2、iPhone 3G

armv7:iPhone 4、iPhone 4S
·armv7s:iPhone 5、iPhone 5S
·arm64:iPhone 5S、iPhone 6(P)、iPhone 6S(P)、iPhone 7(P)

机器对指令集的支持是向下兼容的,因此armv7的指令集是可以运行在iPhone 5S中的,只是效率没那么高而已。借此机会,先来讨论一下iOS项目文件中的一项配置,即Build Settings里面的Architectures选项。Architectures指的是该App支持的指令集,一般情况下,在Xcode中新建一个项目,其默认的Architectures选项值是Standard architectures(armv7、arm64),表示该App仅支持armv7和arm64的指令集;Valid architectures选项指即将编译的指令集,一般设置为armv7、armv7s、arm64,表示一般会编译这三个指令集;Build Active Architecture Only选项表示是否只编译当前适用的指令集,一般情况下在Debug的时候设置为YES,以便可以更加快速、高效地调试程序,而在Release的情况下设置为NO,以便App在各个机器上都能够以最高效率运行,因为Valid architectures选择的对应指令集是armv7、armv7s和arm64,在Release下会为各个指令集编译对应的代码,因此最后的ipa体积基本上翻了3倍。
         基于上面的描述,以及设备与指令集平台的对比,大多数情况下,我们在实际的交叉编译过程中只编译armv7与arm64这两个指令集平台下的库,因为armv7s设备的数量比较少,有armv7来保底完全是可以运行的,并且armv7到armv7s指令集的变动又比较少,而arm64的变动则比较大,设备数量也比较多,所以需要单独编译出来,以保证这一批设备可以享受到最优质的运行状况。

LAME的交叉编译

https://sourceforge.net/projects/lame/files/lame/3.99/

编写一个build_armv7.sh脚本,用于编译armv7指令集下的版本,以支持iPhone 5S及以下的设备

./configure \
——disable-shared \
——disable-frontend \
——host=arm-apple-darwin \
——prefix="./thin/armv7" \
CC="xcrun -sdk iphoneos clang -arch armv7" \
CFLAGS="-arch armv7 -fembed-bitcode -miphoneos-version-min=7.0" \
LDFLAGS="-arch armv7 -fembed-bitcode -miphoneos-version-min=7.0"
make clean
make -j8
make install

·——prefix:指定将编译好的库放到哪个目录下,这是GNU大部分库的标准配置。
·——host:指定最终库要运行的平台。
·CC:指定交叉工具编译链的路径,其实这里就是指定gcc的路径。
·CFLAGS:指定编译时所带的参数。Shell脚本中指定-march是armv7平台,代表编译的库运行的目标平台是armv7平台;另外Shell脚本中也指定了打开bitcode选项,这使得使用编译出来的这个库的工程,可以将enable-bitcode选项设置为YES,如果没有打开该选项,那么其在Xcode中只能设置为NO,而这对于最终App的运行性能会有一定的影响。Shell脚本中同时也指定了编译出来的这个库所支持的最低iOS版本是7.0,如果不配置该参数的话,则默认是iOS 9.0版本,而所使用的编译出来的这个库的工程,若所支持的最低iOS版本不是9.0的话,Xcode就会给出警告。
·LDFLAGS:指定链接过程中的参数,同样也要带上bitcode的选项以及开发者期望App支持的最低iOS版本的选项参数。
·——disable-shared:通常是GNU标准中关闭动态链接库的选项,一般是在编译出命令行工具的时候,期望命令行工具可以单独使用而不需要动态链接库的配置。
·——disable-frontend:不编译出LAME的可执行文件。
bitcode模式是表明当开发者提交应用(App)到App Store上的时候,Xcode会将程序编译为一个中间表现形式(bitcode)。App Store会将该bitcode中间表现形式的代码进行编译优化,链接为64位或者32位的程序。如果程序中用到了第三方静态库,则必须在编译第三方静态库的时候也开启bitcode,否则在Xcode的Build Setting中必须要关闭bitcode,这对于App来讲可能会造成性能的降低。

建立build_arm64.sh文件

./configure \
——disable-shared \
——disable-frontend \
——host=arm-apple-darwin \
——prefix="./thin/arm64" \
CC="xcrun -sdk iphoneos clang -arch arm64" \
CFLAGS="-arch arm64 -fembed-bitcode -miphoneos-version-min=7.0" \
LDFLAGS="-arch arm64 -fembed-bitcode -miphoneos-version-min=7.0"
make clean
make -j8
make install

如果想在模拟器上运行,那么就需要编译出i386架构下的静态库,而编译i386平台的Shell脚本也与此类似,仅仅是改变平台架构。

待两个脚本执行完毕之后,就可以去thin-lame目录下寻找对应的armv7与arm64目录,并且在这两个目录下会看到bin、lib、include、share这四个目录。由于在配置的时候裁剪掉了可执行文件,所以bin目录下不会有内容;在lib目录下则是链接过程中需要链接的libmp3lame.a静态库文件;在include目录下则是编译过程所需要引用的头文件。
       至此已经编译出了两个指令集平台下的静态库文件与include文件目录,其实这两个include文件的目录是一样的,随便使用哪一份都可以,但是对于静态库文件,应该如何用呢?这里就会涉及如何合并静态库的知识,合并静态库应该使用lipo命令,在终端下切换到thin-lame目录下键入:
lipo -create ./arm64/lib/libmp3lame.a ./armv7/lib/libmp3lame.a -output
libmp3lame.a
           这行命令会把两个平台架构下的静态库文件合并到一个libmp3lame.a的静态库文件中,现在来验证一下最终的libmp3lame.a是否包含armv7与arm64这两个平台架构的静态库,在命令行键入:
file libmp3lame.a
如果看到如下信息,则说明编译成功了:

libmp3lame.a:Mach-O universal binary with 2 architectures:[arm_v7:current ar
archive][arm64:current ar archive]
libmp3lame.a (for architecture armv7): current ar archive
libmp3lame.a (for architecture arm64): current ar archive

如果在开发过程中编译的第三方库比较多,而同时编译的指令集平台也比较多,则每次都需要新建几个脚本文件,然后编译出各个平台的静态库,最终再用lipo命令进行合并,将会非常麻烦。而软件工程师就是要把重复性的东西做成工具,让工作变得更加简单,所以后续在代码仓库中会有完整的编译脚本,可以编译出所有架构平台下的静态库,并且也已经用 lipo 命令把所有指令集平台下的静态库合并到了一个静态库文件中

Android平台交叉编译的实践

Android原生开发包(NDK)可用于Android平台上的C++开发,NDK不仅仅是一个单一功能的工具,还是一个包含了API、交叉编译器、链接程序、调试器、构建工具等的综合工具集。
下面大致列举了一下经常会用到的组件。

  • ·ARM、x86的交叉编译器
  • ·构建系统
  • ·Java原生接口头文件
  • ·C库
  • ·Math库
  • ·最小的C++库
  • ·ZLib压缩库
  • ·POSIX线程
  • ·Android日志库
  • ·Android原生应用API
  • ·OpenGL ES(包括EGL)库
  • ·OpenSL ES库

下面来看一下Android所提供的NDK根目录下的结构。

  • ·ndk-build:该Shell脚本是Android NDK构建系统的起始点,一般在项目中仅仅执行这一个命令就可以编译出对应的动态链接库了,后面会有详细的介绍。
  • ·ndk-gdb:该Shell脚本允许用GUN调试器调试Native代码,并且可以配置到Eclipse的IDE中,可以做到像调试Java代码一样调试Native的代码。
  • ·ndk-stack:该Shell脚本可以帮助分析Native代码崩溃时的堆栈信息,后续会针对Native代码的崩溃进行详细的分析。
  • ·build:该目录包含NDK构建系统的所有模块。
  • ·platforms:该目录包含支持不同Android目标版本的头文件和库文件,NDK构建系统会根据具体的配置来引用指定平台下的头文件和库文件。
  • ·toolchains:该目录包含目前NDK所支持的不同平台下的交叉编译器——ARM、x86、MIPS,其中比较常用的是ARM和x86。构建系统会根据具体的配置选择不同的交叉编译器。

在了解了NDK的目录结构之后,接下来详细了解一下NDK的编译脚本语法——Android.mk和Application.mk。
Android.mk是在Android平台上构建一个C或者C++语言编写的程序系统的Makefile文件,不同的是,Android提供了一系列的内置变量来提供更加方便的构建语法规则。 Application.mk文件实际上是对应用程序本身进行描述的文件,它描述了应用程序要针对哪些CPU架构打包动态so包、要构建的是release包还是debug包以及一些编译和链接参数等。
(1)Android.mk
Android.mk分为以下几部分。

  • ·LOCAL_PATH:=$(call my-dir),返回当前文件在系统中的路径,Android.mk文件开始时必须定义该变量。
  • ·include$(CLEAR_VARS),表明清除上一次构建过程的所有全局变量,因为在一个Makefile编译脚本中,会使用大量的全局变量,使用这行脚本表明需要清除掉所有的全局变量。
  • ·LOCAL_SRC_FILES,要编译的C或者Cpp的文件,注意这里不需要列举头文件,构建系统会自动帮助开发者依赖这些文件。
  • ·LOCAL_STATIC_LIBRARIES,所依赖的静态库文件。
  • ·LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib-llog-lOpenSLES-lGLESv2-lEGL-lz,指定编译过程所依赖的NDK提供的动态与静态库,SYSROOT变量代表的是NDK_ROOT下面的目录$NDK_ROOT/platforms/android-18/arch-arm,而在这个目录的usr/lib/目录下有很多对应的so的动态库以及.a的静态库。
  • ·LOCAL_CFLAGS,编译C或者Cpp的编译标志,在实际编译的时候会发送给编译器。比如常用的实例是加上-DAUTO_TEST,然后在代码中就可以利用条件判断#ifdef AUTO_TEST来做一些与自动化测试相关的事情。
  • ·LOCAL_LDFLAGS,链接标志的可选列表,当对目标文件进行链接以生成输出文件的时候,将这些标志带给链接器。该指令与LOCAL_LDLIBS有些类似,一般情况下,该选项会用于指定第三方编译的静态库,LOCAL_LDLIBS经常用于指定系统的库(比如log、OpenGL ES、EGL等)。
  • ·LOCAL_MODULE,该模块的编译的目标名,用于区分各个模块,名字必须是唯一并且不包含空格的,如果编译目标是so库,那么该so库的名字就是lib项目名.so。
  • ·include$(BUILD_SHARED_LIBRARY),其实类似的include还有很多,都是构建系统提供的内置变量,该变量的意义是构建动态库,其他的内置变量还包括如下几种。
  • ·——BUILD_STATIC_LIBRARY:构建静态库。
  • ·——PREBUILT_STATIC_LIBRARY:对已有的静态库进行包装,使其成为一个模块。
  • ·——PREBUILT_SHARED_LIBRARY:对已有的动态库进行包装,使其成为一个模块。
  • ·——BUILD_EXECUTABLE:构建可执行文件。

构建系统提供的这些内置变量在哪里能够看到呢?它们都在$NDK_ROOT/build/core/目录下,这里面会有所有预先定义好的Makefile,开发者include一个变量,实际上就是把对应的Makefile包含到Android.mk中,包括前面提到的CLEAR_VARS,其也是该目录下面的一个Makefile。

  • ·include$(call all-makefiles-under,$(LOCAL_PATH)),也是构建系统提供的变量,该命令会返回该目录下所有子目录的Android.mk列表。

上面已经清楚地讲解了Android.mk里的基本语法规则,那么,在输入命令ndk-build之后,系统到底会使用哪些编译器以及打包器和链接器来编译我们的程序呢?
      会使用$NDK_ROOT/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/目录(以Mac平台为例)下面的gcc、g++、ar、ld等工具。同样在该目录下的strip工具将会用于清除so包里面的源码,nm工具可以供开发者查看静态库下的符号表。
      那么进行gcc编译的时候,头文件将放在哪里呢?
     $NDK_ROOT/platforms/android-18/arch-arm/usr/include/目录下会存放编译过程所依赖的头文件。
    那么在链接过程中,经常使用的log或者OpenSL ES以及OpenGL ES等库又将放在哪里呢?

答案其实已在前文中提到过,$NDK_ROOT/platforms/android-18/arch-arm/usr/lib/目录下会存放链接过程中所依赖的库文件。
(2)Application.mk
Application.mk分为以下几个部分。

  • ·APP_ABI:=XXX,这里的XXX是指不同的平台,可以选填的有x86、mips、armeabi、armeabi-v7a、all等,值得一提的是,若选择all则会构建出所有平台的so,如果不填写该项,那么将默认构建为armeabi平台下的库。由于工作的原因,笔者和Intel的员工打过交道,构建armeabi-v7a平台的so之所以可以运行在Intel x86架构的CPU平台下,是因为Intel针对armeabi做了兼容,但是如果想要应用以最小的能耗、最高的效率运行在Intel x86平台上,则还是要指定构建的so为x86平台。因此,如果想要提高App的运行性能,则还需要编译出x86平台。类似于前面介绍的iOS平台,如果不考虑模拟器的话,则仅需要构建armv7与arm64平台架构,那么对于Android平台呢?对于armv7-a,肯定是要编译的;至于arm64-v8a这个平台,其实已经占到了50%以上,最好也将其单独编译出来;同时armv5这个平台的设备还是存在的,当然不同App在不同架构下的比例也不尽相同,读者可以根据实际场景来决定编译的平台数目。这里需要注意的是,编译arm64-v8a的时候使用的交叉工具编译链与之前的armv7所在的目录有比较大的差异,其目录存在于:
  • ·$NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin
  • ·编译过程中使用的编译工具都存在于上述目录下。
  • ·APP_STL:=gnustl_static,NDK构建系统提供了由Android系统给出的最小C++运行时库(/system/lib/libstdc++.so)的C++头文件。然而,NDK带有另一个C++实现,开发者可以在自己的应用程序中使用或链接它,定义APP_STL可选择它们中的一个,可选项包括:stlport_static、stlport_shared、gnustl_static。
  • ·APP_CPPFLAGS:=-std=gnu++11-fexceptions,指定编译过程的flag,可以在该选项中开启exception rtti等特性,但是为了效率考虑,最好关闭rtti。
  • ·NDK_TOOLCHAIN_VERSION=4.8,指定交叉工具编译链里面的版本号,这里指定使用4.8。
  • ·APP_PLATFORM:=android-9,指定创建的动态库的平台。
  • ·APP_OPTIM:=release,该变量是可选的,用来定义“release”或“debug”,“release”模式是默认的,并且会生成高度优化的二进制代码;“debug”模式生成的是未优化的二进制代码,但是可以检测出很多的BUG,经常用于调试阶段,也相当于在ndk-build指令后边直接加上参数NDK_DEBUG=1。

LAME的交叉编译

在Android的编译中,一般情况下会使用一个Shell脚本文件,指定好编译器里面的各个工具,然后把对应的Configure的命令与选项开关配置好,最后执行该Shell脚本

#!/bin/bash
NDK_ROOT=/Users/apple/soft/android/android-ndk-r9b
PREBUILT=$NDK_ROOT/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64
PLATFORM=$NDK_ROOT/platforms/android-9/arch-arm
export PATH=$PATH:$PREBUILT/bin:$PLATFORM/usr/include:
export LDFLAGS="-L$PLATFORM/usr/lib -L$PREBUILT/arm-linux-androideabi/lib
-march=armv7-a"
export CFLAGS="-I$PLATFORM/usr/include -march=armv7-a -mfloat-abi=softfp -mfpu=vfp
-ffast-math -O2"
export CPPFLAGS="$CFLAGS"
export CFLAGS="$CFLAGS"
export CXXFLAGS="$CFLAGS"
export LDFLAGS="$LDFLAGS"
export AS=$PREBUILT/bin/arm-linux-androideabi-as
export LD=$PREBUILT/bin/arm-linux-androideabi-ld
export CXX="$PREBUILT/bin/arm-linux-androideabi-g++ ——sysroot=${PLATFORM}"
export CC="$PREBUILT/bin/arm-linux-androideabi-gcc ——sysroot=${PLATFORM}
-march=armv7-a "
export NM=$PREBUILT/bin/arm-linux-androideabi-nm
export STRIP=$PREBUILT/bin/arm-linux-androideabi-strip
export RANLIB=$PREBUILT/bin/arm-linux-androideabi-ranlib
export AR=$PREBUILT/bin/arm-linux-androideabi-ar
./configure ——host=arm-linux \
——disable-shared \
——disable-frontend \
——enable-static \
——prefix=./armv7a
make clean
make -j8
make install

下面就来针对该脚本的每一行命令进行详细解释。
第一部分是设置NDK_ROOT,并且声明platform和prebuilt,最终配置可在环境变量中查看。
第二部分主要是声明CFLAGS与LDFLAGS,其目的是在编译和链接阶段找到正确的头文件与链接到正确的库文件。这里需要特别注意的是,在这两个设置的后边都加上了-march=armv7-a,这相当于是让编译器知道要编译的目标平台是armv7-a。
第三部分是声明CC、AS、AR、LD、NM、STRIP等工具,具体每一个工具是做什么用的,前面都已经介绍过了,如果要编译armv5、x86或者arm64-v8a,那么在代码仓库中会提供全量编译的Shell脚本文件。
第四部分就是使用LAME本身的Configure进行编译裁剪。
第五部分就是使用标准的编译链接和安装。
最终执行脚本成功之后,可以看到在指定的Prefix目录下面,包含了lib和include目录,里面分别是静态库文件和头文件,这两个目录的作用在前面已经说过很多遍了,在此不再赘述。

使用LAME编码MP3文件

首先新建两个文件:mp3_encoder.h和mp3_encoder.cpp。

class Mp3Encoder {
private:
FILE* pcmFile;
FILE* mp3File;
lame_t lameClient;
public:
Mp3Encoder();
~Mp3Encoder();
int Init(const char* pcmFilePath,const char *mp3FilePath,int
sampleRate,int channels,int bitRate);
void Encode();
void Destory();
};
int Mp3Encoder:Init(const char* pcmFilePath,const char *
mp3FilePath,int sampleRate,int channels,int bitRate) {
int ret = -1;
pcmFile = fopen(pcmFilePath,"rb");
if(pcmFile) {
mp3File = fopen(mp3FilePath,"wb");
if(mp3File) {
lameClient = lame_init();
lame_set_in_samplerate(lameClient,sampleRate);
lame_set_out_samplerate(lameClient,sampleRate);
lame_set_num_channels(lameClient,channels);
lame_set_brate(lameClient,bitRate / 1000);
lame_init_params(lameClient);
ret = 0;
}
}
return ret;
}
//
void Mp3Encoder:Encode() {
int bufferSize = 1024 * 256;
short* buffer = new short[bufferSize / 2];
short* leftBuffer = new short[bufferSize / 4];
short* rightBuffer = new short[bufferSize / 4];
unsigned char* mp3_buffer = new unsigned char[bufferSize];
size_t readBufferSize = 0;
while ((readBufferSize = fread(buffer,2,bufferSize / 2,pcmFile)) > 0) {
for (int i = 0; i < readBufferSize; i++) {
if (i % 2 == 0) {
leftBuffer[i / 2]= buffer[i];
} else {
rightBuffer[i / 2]= buffer[i];
}
}
size_t wroteSize = lame_encode_buffer(lameClient,(short
int *) leftBuffer,(short int *) rightBuffer,
(int)(readBufferSize / 2),mp3_buffer,bufferSize);
fwrite(mp3_buffer,1,wroteSize,mp3File);
}
delete[]buffer;
delete[]leftBuffer;
delete[]rightBuffer;
delete[]mp3_buffer;
}void Mp3Encoder:Destory() {
if(pcmFile) {
fclose(pcmFile);
}
if(mp3File) {
fclose(mp3File);
lame_close(lameClient);
}
}

lame库(iOS 和 Android)相关推荐

  1. android lame音频转换,音视频开发02--使用LAME库转换pcm文件到mp3

    android 使用 AudioRecord 对麦克风进行录音得到的是 pcm 格式的原始音频数据,pcm文件是不能用来播放的,需要进行编码压缩. LAME是目前非常优秀的一种MP3编码引擎,在业界, ...

  2. iOS架构-C/C++lame库在Mac下编译通用静态库.a库(13)

    C/C++ 有很多成熟的库,还有很多特殊功能的库,有时候iOS 平台开发一些比较前沿或者冷门的功能时,iOS并没有提供解决方案,这时候就可以研究C/C++的一些库,为我们使用.但是在Xcode编译C/ ...

  3. Android直播开发之旅(4):MP3编码格式分析与lame库编译封装

    转载请声明出处:http://blog.csdn.net/andrexpert/article/77683776 一.Mp3编码格式分析 MP3,全称MPEG Audio Layer3,是一种高效的计 ...

  4. android边缘模糊效果,iOS和Android算法或库用于羽化图像的边缘,类似于photoshop的

    我正在寻找iOS和Android库(最好)或算法,它可以帮助我像在Photoshop中处理它的方式一样羽化图像的边缘.下图显示了算法的预期效果.我不感兴趣羽化图像的边界,只是alpha边缘.我一直在寻 ...

  5. ios静态库和代码同名_使用一个代码库开始制作NativeScript iOS和Android应用程序

    ios静态库和代码同名 Users can choose whatever operating system they prefer, but every operating system use d ...

  6. ios与android设备即时语音互通的录音格式预研说明

    本文内容都是来自于网络,参考了大家的微博,以及论坛的总结. 在做语音对讲的时候,将会碰到录制语音格式的问题,因为要考虑自己开发设备的支持的格式,还要考虑其他设备操作系统的支持的格式,以及各自平台实现各 ...

  7. 将音频转化为MP3格式(lame库)

    为什么要转化音频格式 最近又在做即时通讯了, 关于语音录制的文件总是那么几个类型的, 但想要与 Android 实现音频互通. 那么就要转化Mp3格式的音频文件或者Amr 格式文件. 当然Amr是最好 ...

  8. ios与android设备即时语音互通的录音格式

    在做iphone开发之前,我(ray)对声音格式了解的相当少.我知道一些"wav"和"mp3"声音格式的差异,但是我肯定不能准确地告诉你"AAC&qu ...

  9. ios编译与android编译区别是什么,为iOS和Android编译C ++代码(XCode)。 这是真的吗?...

    你绝对可以在iOS和Android上使用C ++. 我已经为两者编写了自己的游戏引擎. Xcode是iOS的常规IDE,本身支持"Objective-C ++"开发(编译器支持Ob ...

  10. android lame wav 转 mp3,Android JNI Lame编解码实现wav到MP3的转换

    1.JNI简介 JNI全称为Java Native Interface(JAVA本地调用).从Java1.1开始,JNI成为java平台的一部分,它允许Java代码和其他语言写的代码(如C&C ...

最新文章

  1. 霸气!考 692 分想当程序员,女王式发言:也没见男生考得比我好
  2. Jsp获得Map中map.put(2, bb);此类的value值
  3. 如何在CRM WebClient UI里创建HANA live report
  4. Matlab(R2020a)添加工具箱Toolbox的方法(详细图解)
  5. 【codevs1163】访问艺术馆,圣战の终焉
  6. Java网络编程IO模型 --- BIO、NIO、AIO详解
  7. ska测试软件怎么用,wow伤害测试软件SIMC怎么用?SIMC使用详细攻略
  8. LeetCode罗马数字转整数
  9. 概率论与数理统计(下)
  10. Groovy(二)groovy基础
  11. HDMI转PGA电脑没有声音处理方法
  12. 论一个好翻译的重要性
  13. 读完这篇系列文章,前端offer手到擒来!!!
  14. selenium中键盘操作:Keys类
  15. 计算机实用教学,【实用】计算机教学工作计划3篇
  16. 蚂蚁金服 CTO 程立新加坡演讲:小蚂蚁是如何“爬”上区块链的?
  17. sinon.js的spy、stub和mock
  18. 房产抵押贷款需要的资质有哪些
  19. [RK3588-Android12] 双HDMI+喇叭Speak同音问题
  20. 双边网格学习一:2021cvpr《Ultra-High-Definition Image Dehazing via Multi-Guided Bilateral Learning》

热门文章

  1. qt GraphicsScene添加背景
  2. 有向图和无向图用邻接矩阵储存
  3. grunt_从Grunt测试Grunt插件
  4. Python 将汉字转为拼音
  5. adb 连接方式汇总
  6. Virtual Private Network(虚拟专用网络隧道)详解
  7. ArcGIS中消除两幅卫星影像之间色带问题
  8. Macbook pro 电脑显示连上Wi-Fi但无法上网:解决方案汇总
  9. python常用代码
  10. P5713 【深基3.例5】洛谷团队系统(C语言)