int audioFormat, int bufferSizeInBytes, int mode, int sessionId)
*   streamType,Android手机上提供音频管理策略,按下音量键我们会发现由媒体声音管理,闹铃声音管理,通话声音管理等等,当系统有多个进程需要播放音频的时候,管理策略会决定最终的呈现效果,该参数的可选值将以常量的形式定义在类AudioManager中,主要包括以下内容:· STREAM\_VOCIE\_CALL:电话声音· STREAM\_SYSTEM:系统声音· STREAM\_RING:铃声· STREAM\_MUSCI:音乐声· STREAM\_ALARM:警告声· STREAM\_NOTIFICATION:通知声因为这里是播放音频,所以我们选择`STREAM_MUSCI`。*   sampleRateInHz,采样率,即播放的音频每秒钟会有多少次采样,可选用的采样频率列表为:8000、16000、22050、24000、32000、44100、48000等,一般采用人能听到最大音频的2倍,也就是44100Hz。*   channelConfig,声道数的配置,可选值以常量的形式配置在类AudioFormat中,常用的是CHANNEL\_IN\_MONO(单声道)、CHANNEL\_IN\_STEREO(立体双声道)*   audioFormat,采样格式,可选值以常量的形式定义在类AudioFormat中,分别为ENCODING\_PCM\_16BIT(16bit)、ENCODING\_PCM\_8BIT(8bit),一般采用16bit。*   bufferSizeInBytes,其配置的是AudioTrack内部的音频缓冲区的大小,可能会因为生产厂家的不同而有所不同,为了方便AudioTrack提供了一个获取该值最小缓冲区大小的方法`getMinBufferSize`。*   mode,播放模式,AudioTrack提供了两种播放模式,可选的值以常量的形式定义在类AudioTrack中,一个是MODE\_STATIC,需要一次性将所有的数据都写入播放缓冲区中,简单高效,通常用于播放铃声、系统提醒的音频片段;另一个是MODE\_STREAM,需要按照一定的时间间隔不间断地写入音频数据,理论上它可以应用于任何音频播放的场景。*   sessionId,AudioTrack都需要关联一个会话Id,在创建AudioTrack时可直接使用`AudioManager.AUDIO_SESSION_ID_GENERATE`,或者在构造之前通过`AudioManager.generateAudioSessionId`获取。上面这种构造方法已经被弃用了,现在基本使用如下构造(最小skd 版本需要>=21),参数内容与上基本一致:

public AudioTrack (AudioAttributes attributes,

            AudioFormat format, int bufferSizeInBytes, int mode, int sessionId)
通过`AudioAttributes.Builder`设置参数streamType

var audioAttributes = AudioAttributes.Builder()

.setLegacyStreamType(AudioManager.STREAM_MUSIC).build()
通过`AudioFormat.Builder`设置channelConfig,sampleRateInHz,audioFormat参数

var mAudioFormat = AudioFormat.Builder()

.setChannelMask(channel).setEncoding(audioFormat).setSampleRate(sampleRate).build()
### [](https://blog.csdn.net/u012165769/article/details/109730722)切换播放状态首先通过调用`getState`判断AudioRecord是否初始化成功,然后通过`play`切换成录播放状态

if (null!=audioTrack && audioTrack?.state != AudioTrack.STATE_UNINITIALIZED){

audioTrack?.play()

}

### [](https://blog.csdn.net/u012165769/article/details/109730722)开启播放线程开启播放线程

thread= Thread(Runnable {

readDataFromFile()

})

thread?.start()

将数据不断的送入缓存区并通过AudioTrack播放

private fun readDataFromFile() {

val byteArray = ByteArray(bufferSizeInBytes)val file = File(externalCacheDir?.absolutePath + File.separator + filename)if (!file.exists()) {Toast.makeText(this, "请先进行录制PCM音频", Toast.LENGTH_SHORT).show()return}val fis = FileInputStream(file)var read: Intstatus = Status.STARTINGwhile ({ read = fis.read(byteArray);read }() > 0) {var ret = audioTrack?.write(byteArray, 0, bufferSizeInBytes)!!if (ret == AudioTrack.ERROR_BAD_VALUE || ret == AudioTrack.ERROR_INVALID_OPERATION || ret == AudioManager.ERROR_DEAD_OBJECT) {break}}fis.close()

}

### [](https://blog.csdn.net/u012165769/article/details/109730722)释放资源首先停止播放

if (audioTrack != null && audioTrack?.state != AudioTrack.STATE_UNINITIALIZED) {

audioTrack?.stop()

}

然后停止线程

if (thread!=null){

thread?.join()thread =null

}

最后释放AudioTrack

if (audioTrack != null) {

audioTrack?.release()audioTrack = null

}

经过这样几个步骤,我们就可以听到刚刚我们录制的PCM数据声音啦!这就是使用Android提供的`AudioRecord`和`AudioTrack`对PCM数据进行操作。但是仅仅这样是不够的,因为我们生活中肯定不是使用PCM进行音乐播放,那么怎么才能让音频在主流播放器上播放呢?这就需要我们进行压缩编码了,比如mp3或aac压缩编码格式。[](https://blog.csdn.net/u012165769/article/details/109730722)MediaCodec编码AAC-----------------------------------------------------------------------------`AAC`压缩编码是一种高压缩比的音频压缩算法,AAC压缩比通常为18:1;采样率范围通常是8KHz~96KHz,这个范围比MP3更广一些(MP3的范围一般是:16KHz~48KHz),所以在16bit的采样格式上比MP3更精细。方便我们处理AAC编码,Android SDK中提供了`MediaCodec`API,可以将PCM数据编码成AAC数据。大概需要以下几个步骤:*   创建`MediaCodec`*   为`MediaCodec`配置音频参数*   启动线程,循环往缓冲区送入数据*   通过`MediaCodec`将缓冲区的数据进行编码并写入文件*   释放资源### [](https://blog.csdn.net/u012165769/article/details/109730722)创建MediaCodec通过`MediaCodec.createEncoderByType`创建编码MediaCodec

mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC)

### [](https://blog.csdn.net/u012165769/article/details/109730722)配置音频参数

// 配置采样率和声道数

mediaFormat = MediaFormat.createAudioFormat(MINE_TYPE,sampleRate,channel)

// 配置比特率

mediaFormat?.setInteger(MediaFormat.KEY_BIT_RATE,bitRate)

// 配置PROFILE,其中属AAC-LC兼容性最好

mediaFormat?.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC)

// 最大输入大小

mediaFormat?.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 10 * 1024)

mediaCodec!!.configure(mediaFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE)

mediaCodec?.start()

inputBuffers = mediaCodec?.inputBuffers

outputBuffers = mediaCodec?.outputBuffers

### [](https://blog.csdn.net/u012165769/article/details/109730722)启动线程启动线程,循环读取PCM数据送入缓冲区

thread = Thread(Runnable {

val fis = FileInputStream(pcmFile)fos = FileOutputStream(aacFile)var read: Intwhile ({ read = fis.read(byteArray);read }() > 0) {encode(byteArray)}

})

thread?.start()

### [](https://blog.csdn.net/u012165769/article/details/109730722)AAC编码将送入的PCM数据通过`MediaCodec`进行编码,大致流程如下:*   通过可用缓存去索引,获取可用输入缓冲区*   将pcm数据放入输入缓冲区并提交*   根据输出缓冲区索引,获取输出缓冲区*   创建输出数据`data`,并添加ADTS头部信息(有7byte)*   将`outputBuffer`编码后数据写入`data`(data有7byte偏移)*   将编码数据`data`写入文件*   重复以上过程

private fun encode(byteArray: ByteArray){

mediaCodec?.run {//返回要用有效数据填充的输入缓冲区的索引, -1 无限期地等待输入缓冲区的可用性val inputIndex = dequeueInputBuffer(-1)if (inputIndex > 0){// 根据索引获取可用输入缓存区val inputBuffer = this@AACEncoder.inputBuffers!![inputIndex]// 清空缓冲区inputBuffer.clear()// 将pcm数据放入缓冲区inputBuffer.put(byteArray)// 提交放入数据缓冲区索引以及大小queueInputBuffer(inputIndex,0,byteArray.size,System.nanoTime(),0)}// 指定编码器缓冲区中有效数据范围val bufferInfo = MediaCodec.BufferInfo()// 获取输出缓冲区索引var outputIndex = dequeueOutputBuffer(bufferInfo,0)while (outputIndex>0){// 根据索引获取可用输出缓存区val outputBuffer =this@AACEncoder.outputBuffers!![outputIndex]// 测量输出缓冲区大小val bufferSize = bufferInfo.size// 输出缓冲区实际大小,ADTS头部长度为7val bufferOutSize = bufferSize+7// 指定输出缓存区偏移位置以及限制大小outputBuffer.position(bufferInfo.offset)outputBuffer.limit(bufferInfo.offset+bufferSize)// 创建输出空数据val data = ByteArray(bufferOutSize)// 向空数据先增加ADTS头部addADTStoPacket(data, bufferOutSize)// 将编码输出数据写入已加入ADTS头部的数据中outputBuffer.get(data,7,bufferInfo.size)// 重新指定输出缓存区偏移outputBuffer.position(bufferInfo.offset)// 将获取的数据写入文件fos?.write(data)// 释放输出缓冲区releaseOutputBuffer(outputIndex,false)// 重新获取输出缓冲区索引outputIndex=dequeueOutputBuffer(bufferInfo,0)}}

}

### [](https://blog.csdn.net/u012165769/article/details/109730722)释放资源编码完成后,一定要释放所有资源,首先关闭输入输出流

fos?.close()

fis.close()

停止编码

if (mediaCodec!=null){

 mediaCodec?.stop()

}

然后就是关闭线程

if (thread!=null){

thread?.join()thread =null

}

最后释放MediaCodec

if (mediaCodec!=null){

mediaCodec?.release()mediaCodec = nullmediaFormat = nullinputBuffers = nulloutputBuffers = null

}

通过以上一个流程,我们就可以得到一个AAC压缩编码的音频文件,可以听一听是不是自己刚刚录制的。我听了一下我自己唱的一首歌,觉得我的还是可以的嘛,也不是那么五音不全~~[](https://blog.csdn.net/u012165769/article/details/109730722)Android NDK-------------------------------------------------------------------------虽然我们通过压缩编码生成了AAC音频文件,但是有个问题:毕竟AAC音频不是主流的音频文件呀,我们最常见的是MP3的嘛,可不可以将PCM编码成MP3呢?当然是可以的,但是Android SDK没有直接提供这样的API,只能使用Android NDK,通过交叉编译其他C或C++库来进行实现。Android NDK 是由Google提供一个工具集,可让您使用 C 和 C++ 等语言实现应用。Android NDK 一般有两个用途,一个是进一步提升设备性能,以降低延迟,或运行计算密集型应用,如游戏或物理模拟;另一个是重复使用您自己或其他开发者的 C 或 C++ 库。当然我们使用最多的应该还是后者。想使用Android NDK调试代码需要以下工具:*   Android 原生开发套件 (NDK):这套工具使您能在 Android 应用中使用 C 和 C++ 代码。*   CMake:一款外部编译工具,可与 Gradle 搭配使用来编译原生库。如果您只计划使用 ndk-build,则不需要此组件。*   LLDB:Android Studio 用于调试原生代码的调试程序。可以进入Tools > SDK Manager > SDK Tools 选择 NDK (Side by side) 和 CMake 应用安装![](https://img-blog.csdnimg.cn/img_convert/50161ea3ff7125562514b0086e4bc58d.png)在应用以上选项之后,我们可以看到SDK的目录中多了一个`ndk-bundle`的文件夹,大致目录结构如下![](https://img-blog.csdnimg.cn/img_convert/70b909d063b4e09af9d2038bdb48b97b.png)*   ndk-build:该Shell脚本是Android NDK构建系统的起始点,一般在项目中仅仅执行这一个命令就可以编译出对应的动态链接库了,后面的编译mp3lame 就会使用到。*   platforms:该目录包含支持不同Android目标版本的头文件和库文件,NDK构建系统会根据具体的配置来引用指定平台下的头文件和库文件。*   toolchains:该目录包含目前NDK所支持的不同平台下的交叉编译器——ARM、x86、MIPS,其中比较常用的是ARM和x86。不论是哪个平台都会提供以下工具:·CC:编译器,对C源文件进行编译处理,生成汇编文件。·AS:将汇编文件生成目标文件(汇编文件使用的是指令助记符,AS将它翻译成机器码)。·AR:打包器,用于库操作,可以通过该工具从一个库中删除或者增加目标代码模块。·LD:链接器,为前面生成的目标代码分配地址空间,将多个目标文件链接成一个库或者是可执行文件。·GDB:调试工具,可以对运行过程中的程序进行代码调试工作。·STRIP:以最终生成的可执行文件或者库文件作为输入,然后消除掉其中的源码。·NM:查看静态库文件中的符号表。·Objdump:查看静态库或者动态库的方法签名。了解Android NDK 之后,就可新建一个支持C/C++ 的Android项目了:*   在向导的 Choose your project 部分中,选择 Native C++ 项目类型。*   点击 Next。*   填写向导下一部分中的所有其他字段。*   点击 Next。*   在向导的 Customize C++ Support 部分中,您可以使用 C++ Standard 字段来自定义项目。使用下拉列表选择您想要使用哪种 C++ 标准化。选择 Toolchain Default 可使用默认的 CMake 设置。*   点击 Finish,同步完成之后会出现如下图所示的目录结构,即表示原生项目创建完成![](https://img-blog.csdnimg.cn/img_convert/402febb7a25d9cb574189eb7f699651b.png)[](https://blog.csdn.net/u012165769/article/details/109730722)编译Lame--------------------------------------------------------------------LAME是一个开源的MP3音频压缩库,当前是公认有损质量MP3中压缩效果最好的编码器,所以我们选择它来进行压缩编码,那如何进行压缩编码呢?主流的由两种方式:*   Cmake*   ndk-build下面就详细讲解这两种方式### [](https://blog.csdn.net/u012165769/article/details/109730722)Cmake编译Lame配置Cmake之后可以直接将Lame代码运行于Android中#### [](https://blog.csdn.net/u012165769/article/details/109730722)准备下载[Lame-3.100]( )并解压大概得到如下目录![](https://img-blog.csdnimg.cn/img_convert/23eb69b598a8eebf09b3ef4c11597c79.png)然后将里面的`libmp3lame`文件夹拷贝到我们上面创建的支持c/c++项目,删除其中的i386和vector文件夹,以及其他非.c 和 .h 后缀的文件![](https://img-blog.csdnimg.cn/img_convert/54322b6c6c6c285422f1be3c408a8cd7.png)需要将以下文件进行修改,否则会报错*   将util.h中570行

extern ieee754_float32_t fast_log2(ieee754_float32_t x)

替换成

extern float fast_log2(float x)

*   在id3tag.c和machine.h两个文件中,将`HAVE_STRCHR`和`HAVE_MEMCPY`注释

#ifdef STDC_HEADERS

include <stddef.h>

include <stdlib.h>

include <string.h>

include <ctype.h>

#else

/*# ifndef HAVE_STRCHR

define strchr index

define strrchr rindex

endif

*/

char *strchr(), *strrchr();

/*# ifndef HAVE_MEMCPY

define memcpy(d, s, n) bcopy ((s), (d), (n))

endif*/

#endif

*   在fft.c中,将47行注释

//#include “vector/lame_intrin.h”

*   将set\_get.h中24行

#include <lame.h>

替换成

#include “lame.h”

#### [](https://blog.csdn.net/u012165769/article/details/109730722)编写Mp3编码器首先在自己的包下(我这里是`com.coder.media`,这个很重要,后面会用到),新建`Mp3Encoder`的文件,大概如下几个方法*   init,将声道,比特率,采样率等信息传入*   encode,根据init中提供的信息进行编码*   destroy,释放资源

class Mp3Encoder {

companion object {init {System.loadLibrary("mp3encoder")}}external fun init(pcmPath: String,channel: Int,bitRate: Int,sampleRate: Int,mp3Path: String): Intexternal fun encode()external fun destroy()

}

在cpp目录下新建两个文件*   mp3-encoder.h*   mp3-encoder.cpp这两个文件中可能会提示错误异常,先不要管它,这是因为我们还没有配置`CMakeList.txt`导致的。在`mp3-encoder.h`中定义三个变量

FILE* pcmFile;

FILE* mp3File;

lame_t lameClient;

然后在`mp3-encoder.c`中分别实现我们在`Mp3Encoder`中定义的三个方法首先导入需要的文件

#include <jni.h>

#include

#include “android/log.h”

#include “libmp3lame/lame.h”

#include “mp3-encoder.h”

#define LOGD(…) __android_log_print(ANDROID_LOG_DEBUG , “mp3-encoder”, VA_ARGS)

然后实现init方法

extern “C” JNIEXPORT jint JNICALL

Java_com_coder_media_Mp3Encoder_init(JNIEnv *env, jobject obj, jstring pcmPathParam, jint channels,

                                 jint bitRate, jint sampleRate, jstring mp3PathParam) {LOGD("encoder init");int ret = -1;const char* pcmPath = env->GetStringUTFChars(pcmPathParam, NULL);const char* mp3Path = env->GetStringUTFChars(mp3PathParam, NULL);pcmFile = fopen(pcmPath,"rb");if (pcmFile){mp3File = fopen(mp3Path,"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);lame_init_params(lameClient);ret = 0;}}env->ReleaseStringUTFChars(mp3PathParam, mp3Path);env->ReleaseStringUTFChars(pcmPathParam, pcmPath);return ret;

}

这个方法的作用就是将我们的音频参数信息送入`lameClient`需要注意我这里的方法`Java_com_coder_media_Mp3Encoder_init`中的`com_coder_media`需要替换成你自己的对应包名,下面的encode和destroy也是如此,切记!!!实现通过`lame`编码encode

extern “C” JNIEXPORT void JNICALL

Java_com_coder_media_Mp3Encoder_encode(JNIEnv *env, jobject obj) {

LOGD("encoder encode");

学习福利

【Android 详细知识点思维脑图(技能树)】

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

CodeChina开源项目:《Android学习PDF+架构视频+面试文档+源码笔记》

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

gUTFChars(mp3PathParam, mp3Path);

env->ReleaseStringUTFChars(pcmPathParam, pcmPath);return ret;

}

这个方法的作用就是将我们的音频参数信息送入`lameClient`需要注意我这里的方法`Java_com_coder_media_Mp3Encoder_init`中的`com_coder_media`需要替换成你自己的对应包名,下面的encode和destroy也是如此,切记!!!实现通过`lame`编码encode

extern “C” JNIEXPORT void JNICALL

Java_com_coder_media_Mp3Encoder_encode(JNIEnv *env, jobject obj) {

LOGD("encoder encode");

学习福利

【Android 详细知识点思维脑图(技能树)】

[外链图片转存中…(img-LbeY1LeP-1630839513088)]

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

[外链图片转存中…(img-rkQfADfD-1630839513090)]

CodeChina开源项目:《Android学习PDF+架构视频+面试文档+源码笔记》

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

Android音视频开发之,全网疯传相关推荐

  1. 迅为RK3399开发板音视频开发之Debian9 多媒体测试

    iTOP3399平台 Debian 系统音视频部分应用层软件采用的是 Gstreamer,支持硬件编解码.本节所有的 示例均是基于 Gstreamer 命令行的形式. iTOP3399 平台内部有一个 ...

  2. WebRTC 音视频开发之路

    早在2014年就通过WebRTC实现了PC客户端的实时视频语音,那时P2P连接的建立使用的WebRTC自带的libjingle库,使用peerconnection的API实现的.后来在做远程桌面,文件 ...

  3. linux mp4转h264工具,Linux音视频开发之二:转换YUY2到I420便于压缩成h264

    在用libx264做h264压缩的时候,我们可以通过命令ffmpeg -h encoder=libx264来查看它所支持的输入格式 Encoder libx264 [libx264 H.264 / A ...

  4. Android音视频学习系列(五) — 掌握音频基础知识并使用AudioTrack、OpenSL ES渲染PCM数据

    系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...

  5. 谈谈对Android音视频开发的探究

    ​ 在日常生活中,视频类应用占据了我们越来越多的时间,各大公司也纷纷杀入这个战场,不管是抖音.快手等短视频类型,虎牙.斗鱼等直播类型,腾讯视频.爱奇艺.优酷等长视频类型,还是Vue.美拍等视频编辑美颜 ...

  6. Android 音视频难学?音视频(流媒体)开发学习也有套路

    我们都知道音视频流媒体开发这块的知识比较纷繁复杂,对新手很不友好,自学难度大,想要们既需要比较扎实的C/C++基础,又需要有很多的工程/项目经验,今天就从音视频开发/开源框架/就业方向分析,为广大开发 ...

  7. Android音视频点/直播模块开发

    前言 随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能,那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式 ...

  8. Android 音视频采集与软编码总结

    请尊重原创,转载请注明出处:http://blog.csdn.net/mabeijianxi/article/details/75807435(本文已在 "任玉刚" 微信公众号发布 ...

  9. Android音视频 - 学习路线概览

    PS 我们上一个系列 - OpenGL ES 暂告一段落,如果你对相机滤镜感兴趣,可以参看之前的文章. 从本篇开始呢,开始记录Android音视频的相关知识. 学习路线概览 Android音视频的基础 ...

最新文章

  1. 2022-2028年中国FNG硅胶行业市场研究及前瞻分析报告
  2. ssh mysql转发_ssh转发代理:ssh-agent用法详解
  3. proteus仿真micropython_[MicroPython]TurniBit开发板DIY自动窗帘模拟系统
  4. .net core编写转发服务(三) 接入Polly
  5. html标签教案,第1章 HTML的基本标签-教案
  6. 获取当前iframe动态加载文档的href
  7. CF 335B. Palindrome(DP)
  8. php 安装rabbitmq扩展无报错版
  9. 静态时序分析——多周期、半周期和伪路径
  10. [css] css中最常用的字体有哪些?你是怎么选择字体的?
  11. 急用物料怎么办???
  12. jQuery的getter和setter
  13. 【C++ 与 STL】集合:set
  14. [黑金原创教程][连载][iBoard 电子学堂][第〇卷 电子基础]第一篇 认识电子元器件...
  15. FabFilter Total Bundle 2021 Mac - 经典音频效果器合集
  16. 第一篇:工作之我见一-----------细节决定成败(1)
  17. python 3d大数据可视化软件_5个最受欢迎的大数据可视化工具!
  18. 云计算基础架构实施要经历三个阶段
  19. 区块链3.0 EOS和TRON
  20. Linux CentOS 重置root密码

热门文章

  1. uniapp小程序发布过程中,图片跟音频资源超过200K无法上传
  2. Error during artifact deployment. See server log for details.解决方法
  3. 【数据结构】常见数据结构类型
  4. mysql查询姓张的同学_Mysql 基础2 (sql查询语句)
  5. 简单粗暴理解支持向量机(SVM)及其MATLAB实例
  6. python3跑通smpl模型_Python smpl-pytorch包_程序模块 - PyPI - Python中文网
  7. python 百度云不限速版_现在各位是怎么应对百度网盘限速的?
  8. apriori算法 python实现
  9. StringBuffer之间的比较、String和StringBuffer的比较
  10. Mysql部门培训-入门篇