音视频开发之旅——音频基础概念、交叉编译原理和实践(LAME的交叉编译)(Android)

这篇具有很好参考价值的文章主要介绍了音视频开发之旅——音频基础概念、交叉编译原理和实践(LAME的交叉编译)(Android)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文章已授权微信公众号郭霖(guolin_blog)转载。

本文主要讲解的是音频基础概念交叉编译原理和实践(LAME的交叉编译),是基于Android平台,示例代码如下所示:

AndroidAudioDemo

另外,iOS平台也有相关的文章,如下所示:

音视频开发之旅——音频基础概念、交叉编译原理和实践(LAME的交叉编译)(iOS)

音频基础概念

在进行音频开发的之前,了解声学的基础还是很有必要的。

声音的物理性质

在初中物理的时候学过,声音是由三要素组成:音调响度音色

音调

声音的高低叫做音调。物体振动得越快,发出声音的音调就越高;物体振动得越慢,发出的音调越低。频率过零率,指信号的符号变化的比率)决定了音调,频率越高,波长越短,声音更容易绕过障碍物,也就是能量衰减越小,反之得到相反的结论。

响度

声音的强弱叫做响度。我们可以一般用分贝(dB)来描述响度,分贝越大,声音响度越大,反之得到相反的结论。

音色

声音的品质叫做音色,它反映了每个物体发出的声音特有的品质。例如在同样的音调和响度下,吉他和钢琴的声音听起来是不同的,也就是音色是不同的。波的形状决定声音的音色,吉他和钢琴音色不同就是因为它们介质产生的波形不同。

业界来说,人耳能够听到频率范围大约为20Hz20kHz**,对**3kHz4kHz频率范围内的声音比较敏感,对于较低或者较高频率的声音,人耳的敏感度会减弱;在分贝较低时,听觉的频率特性会很不均匀,反之就会较为均匀。一个频率范围较宽的音乐,最佳的分贝范围为80dB~90dB超过90dB就会损害人耳,105dB是人耳的极限。

声音在不同的介质传播的速度也会不一样,在空气中的传播速度为340m/s,不过在真空是无法传播的。

有时候我们在空旷的地方或者高山大喊的时候,会听到回声(echo),产生回声的原因是声音在传播的过程中遇到障碍物后反弹回来后再次让我们听到,但是如果这两种声音传回到我们耳朵的时差小于80毫秒的话,我们就无法分辨这两种声音。

音频数字化

将声音模拟信号转换为数字信号的过程称之为音频数字化,这里需要经过三个步骤:采样量化编码

采样

首先对模拟信号进行采样,采样是指在时间轴(横轴)对信号进行数字化,根据奎斯特定理(采样定理,我们要按比声音最高音频高两倍以上的频率对声音进行采样,这个过程也称为AD转换。上面提过的人耳能够听到的频率为20Hz~20kHz,所以一般采样频率为44.1kHz,也就是说1秒会采样44100次

量化

上面提到的,具体每个采样需要怎样处理呢?这就需要量化,量化是指在幅度轴(纵轴)上对信号进行数字化,要注意的是,和上面提到的采样形成平面直角坐标系,举个例子:用16bit的二进制信号表示这个声音的一个采样,16bit等于一个short,表示范围为[-32768, 32767],也就是说有65536个可能取值,所以在幅度上分为65536层。

编码

最后一步就是要将采样的数据进行存储,也就是是需要进行编码,编码就是按照一定的格式记录采样和量化后的数据数据,例如:顺序存储压缩存储等等。常用的格式为音频的裸数据格式,也就是脉冲编码调制(Pulse Code Modulation,简称PCM)。描述一段PCM的数据需要这几个概念:采样率(sampleRate)量化格式(sampleFormat,也称为位深度)声道数(channel)比特率用于衡量音频数据单位时间内的容量大小,也就是一秒时间内的比特数目,我们以常见的CD格式和DVD-Audio格式为例子:

CD格式的采样率为44100Hz,量化格式为16bit(2byte),声道数为2,那么它的比特率为:

44100 * 16 * 2 = 1411200bps

转换可得1411200bps / 1024 = 1378.125Kibps

DVD-Audio格式的采样率为96000Hz,量化格式为24bit(3byte),声道数为6.那么它的比特率为:

96000 * 24 * 6 = 13824000bps

转换可得13824000bps / 1024 = 13500Kibps,再转换可得13500Kibps / 1024 ≈ 13.18Mibps

一般来说一首歌曲的时间大概在4分钟左右,那我们算下CD格式和DVD-Audio格式会占用多大的存储空间,如下所示:

CD格式:1411200bps * 4 * 60 = 338688000b,转换可得338688000b / 8 / 1024 / 1024 ≈ 40.37MiB

DVD-Audio格式:13824000bps * 4 * 60 = 3317760000b,转换可得3317760000b / 8 / 1024 / 1024 = 395.51MiB

由数据可得,DVD-Audio格式一秒时间内的比特数目大于CD格式,因此它的音质会更好,当然所占的储存空间也会相应得大。

压缩编码

由上面可以看到一首歌如果仅仅是已CD格式去存储的已经占用了40.37MiB,如果只是存储在存储设备上(例如:硬盘或者光盘)那还可以接受,但是如果在网络上实时在线传输的话,这样的大小实在是太大了,所以我们需要对其进行压缩编码,压缩编码里有个指标叫做压缩比,压缩比是小于1,压缩比越小(越接近0),丢失的信息就越多,反之得出相反的结论。压缩算法有两种:无损压缩有损压缩。无损压缩是指解压后的数据能够复原;有损压缩是指解压后的数据不能够复原,压缩导致的丢失得越多,还原的失真就越大。

有如下常用的压缩编码格式:

WAV编码

WAV(Waveform Audio File Format)是微软专门为Windows开发的一种编码格式,它会在PCM数据格式的前面加上44字节,分别用来描述该PCM数据的采样率、声道数、量化格式。

优点:音质非常好,有大量软件支持。

缺点:占用的存储空间较大。

适用场合:多媒体开发的中间文件、音乐和音效素材。

MP3编码

MP3(MPEG-1或者MPEG-2 Audio Layer III)是一种有损压缩的编码格式,它通过舍弃PCM数据人类听觉不重要的部分,已达到压缩成较小文件的目的,对于大多数用户来说,它的音质和不压缩的音频没有明显的下降。我们常用LAME编码MP3文件,下面会讲解到。

优点:音质在**高码率(≥128Kbit/s)**表现不错,同时压缩比也比较高;有大量硬件和软件支持,兼容性不错。

适用场合:高码率(≥128Kbit/s)的音频。并且需要比较好的兼容性。

AAC编码

AAC(Advanced Audio Coding,高级音频编码)是一种高压缩比的编码格式,由于采用多声道和使用低复杂性的描述方式,使其比几乎所有的传统编码方式在同规格的情况下更胜一筹。目前衍生出LC-AACHE-AAC v1HE-AAC v2三种主要的编码格式。LC-AAC是比较传统的AAC,主要编码中高码率(≥80Kbit/s)的音频;HE-AAC v1是高效AAC,是对AAC的扩展,它使用频段复制(SBR)提高频域的压缩效率,适用于中低码率(≤80Kbit/s);HE-AAC v2结合使用了**频段复制(SBR)参数立体声(PS)提高立体声信号的压缩效率,进一步降低了对码率的需要(接近于50%),主要编码低码率(≤48Kbit/s)**的音质。大部分编码器都设置为≤48Kbit/s自动启用PS,>48Kbit/s就关闭PS,箱单与HE-AAC v1。

优点:音质在**中低码率(<128Kbit/s)**表现优异,多用于视频中音频轨的编码。

适用场合:中低码率(<128Kbit/s)的音频,多用于视频中音频轨的编码。

Ogg编码

Ogg在各种码率下都有优秀的表现,尤其在中低码率的场景表现不错,同时它不收到软件专利的限制,完全免费。Ogg有着非常出的的算法,可以用更小的码率编码出更好的音质,举个例子:128Kbit/s的Ogg音质甚至比192Kbit甚至更高的MP3还要好。

优点:可以用更小的码率编码出更好的音质,在各种码率下都变现优异。

缺点:目前兼容性不够好,流媒体特性不支持。

适用场合:语音聊天的音频消息。

Android平台增加C和C++支持

Android提供了一种编译框架,叫做JNI(Java Native Interface),用于允许运行于JVM的Java或者Kotlin代码去调用本地代码(C、C++、汇编语言)。大概步骤为将相关的C/C++代码放在项目模块的cpp目录下,在构建项目的时候,Gradle会将这些代码和应用的代码一起打包到原生库,然后Java或者Kotlin代码就可以通过JNI去调用原生库中的函数。什么时候需要用到JNI呢?有以下几种情况:

  • 应用程序需要一些平台的特性支持,但是Java层没有提供相应的API支持,例如:OpenSL ES的使用)

  • 调用一些已经存在并且已是成熟方案的C/C++库,例如:使用LAME编码MP3文件、使用FFmpeg处理音频或者视频、使用OpenGL ES处理视频特效。

  • 应用程序对部分逻辑的运行速度有较高的要求,那么这部分就可以用C/C++实现,再通过JNI向Java层提供访问接口。

我们需要以下组件:

  • Android原生开发套件(NDK):这是一套可以让开发者使用C/C++的工具。

  • ndk-build脚本或者CMake:用于构建原生库。

  • LLDB:Android Studio用于调试原生代码的程序,默认情况下,它会随同Android Studio的安装而安装。

这里讲解下ndk-build脚本CMake的区别,在讲解之前,我们要了解下下面的内容:

GNU、GCC、gcc、g++

  • GNU:它是一个完全自由的操作系统,起源于GNU计划。

  • GCC:GNU Compiler Collection(GNU编译器套件)的缩写,它是一组GNU操作系统中的编译器集合,可以用于编译C、C++、Java、Go等语言。

  • gcc:GCC中的GNU C Compiler(C编译器)。

  • g++:GCC中的GNU C++ Compiler(C++编译器)。

对于.c文件和.cpp文件,gcc会分别当作c文件和cpp文件编译,而g++会统一当作cpp文件编译。

编译C/C++的四个步骤

接下来我们要了解一下使用gcc(GNU Compiler Collection,GNU编译器套件)生成可执行二进制文件的大概过程:

预处理(Preprocess)

预处理(Preprocess):预处理会处理一些编译前的准备工作,把一些#define的宏定义完成文本替换,然后将#include里的文件复制到.cpp文件,如果.h文件里还有.h文件,那么就会递归展开,要注意的是,在这一步中,代码注释会被忽略。通过g++ -E命令将.c文件预处理为.i文件,它是文本文件。

编译(Compile)

编译(Compile):编译是把代码转换成汇编代码,同时检查词法规则和语法规则,如果没有出现语法错误,那么不管逻辑是否错误都不会报错。通过g++ -S命令将.i文件转换为.s文件,它是文本文件。

汇编(Assemble)

汇编(Assemble):汇编是把汇编代码(.s文件)转换为机器码。通过g++ -c命令将.s文件转换为.o文件(目标文件),它是二进制格式。

链接(Link)

C/C++代码经过汇编后生成的.o文件(目标文件),它是二进制文件,但是它不是最终可执行的,需要和系统组件(例如:标准库、动态链接库)链接起来才能得到可执行的二进制文件(Executable File),完成这个过程的组件叫做链接器(Linker)。链接分为静态链接动态链接,生成的文件叫做静态库动态库

静态库

静态库在Linux下为.a文件,在Windows下为.lib文件。之所以称之为静态库,是因为在链接阶段会将.o文件和引用到的库一起链接打包到可执行文件中,它有如下特点:

  • 会在编译时期完成静态库对函数库的链接。

  • 程序在运行的时候与函数无关,方便移植。

  • 会浪费一定的空间和资源,因为所有目标文件和涉及到的函数库被链接合成一个可执行文件。

动态库

动态库在Linux下为.so文件,在Windows下为.dll文件。动态库在程序编译时不会被链接到目标文件,而是在程序运行时才被载入,它有如下特点:

  • 把对一些库函数的链接载入推迟到程序运行的时期。

  • 不同的应用程序如果调用相同的库,那么在内存中只需要有一份该共享库的实例,可以实现进程之间的资源共享,节省了空间。

  • 由于动态库是在程序运行的时候才载入,因此解决了静态库对程序的更新、部署和发布带来的麻烦,只需要更新动态库就可以了,即增量更新

  • 开发者可以在程序代码中控制链接载入,即显示调用

Make

Make其实是一个批量处理的工具,它是通过调用Makefile文件中开发者指定的命令来进行编译链接,例如调用gcc或者其他编译器的命令。上面提的ndk-build脚本就是使用NDK基于Make来构建项目。

CMake

如果是简单的工程Makefile文件手写起来还是比较轻松的,但是如果复杂的工程手写起来就比较麻烦了,换平台还要重新修改,所以就有上面提到的CMake。CMake是一个开源的跨平台自动化建构系统,它可以根据CMakeList.txt文件自动生成Makefile文件来给上面的Make工具使用。它也是目前Android Studio编译NDK默认构建工具,当然也可以使用上面提到的ndk-build脚本,官方也是支持的。

本机编译

我们要在PC上运行一个二进制的程序(要注意的是,是以源码的方式进行编译,而不是以包管理器的方式去安装)会经过如下步骤:

  1. 得到这段程序的源代码,它可以是自己编写的源代码,也可以是从第三方开源网站上下载的源代码。

  2. 在PC上编译链接这些源代码生成可执行文件。

  3. 在终端(Terminal)下执行该可执行文件。

总结就是使用本机器的编译器和链接器,将源代码编译链接成一个可以在本机器运行的程序,这个编译过程叫做本机编译,它是正常的编译过程。

交叉编译

了解完本机编译后,交叉编译就好理解了,它就是一个平台(例如:PC)上生成另外一个平台(例如:Android、iOS、其他嵌入式设备)可执行的程序。这里的编译机器是PC,所以编译器是安装在PC上,并且运行在PC上的,而这个编译器叫做交叉工具编译链。那其实为啥需要交叉编译呢?因为运行程序的目标平台运算能力和存储能力都是有限的,尽管现在iOS和Android设备的性能越来越强劲,但是和PC还是有一定的距离,而且ARM平台下的编译工具和整个编译过程异常繁琐,所以PC是最佳选择。目前大部分的嵌入式开发平台都提供本身平台交叉编译所需要运行在PC上的交叉工具编译链。

在所有的编译器中,包括自行安装在PC上的编译器和嵌入式平台的交叉工具编译链,都包含以下这几个工具:

  • CC:编译器,作用是对C或者C++源文件编译成汇编文件。

  • AS:将汇编文件翻译成机器码,生成目标文件,汇编文件使用的是指令助记符。

  • AR:打包器,它可以从一个库增加或者删除目标代码模块。

  • LD:链接器,作用是为前面生成的目标代码分配地址空间,将多个目标文件链接成一个库或者可执行文件。

  • GDB:调试工具,它可以对正在运行的程序进行代码调试。

  • STRIP:消除最终生成的库文件或者可执行文件其中的源码。

  • NM:查看静态库文件中符号表。

  • Objdump:查看静态库或者动态库的方法签名。

在Android的NDK提供的交叉工具编译链就在开发者用到的ndk下的prebuilt/darwin-x86_64/bin路径中,它提供了上面这些工具。我的路径如下所示:

/Users/tanjiajun/Library/Android/sdk/ndk/26.1.10909125/prebuilt/darwin-x86_64/bin

LAME的交叉编译

我们了解完交叉编译后,以LAME库为例进行实践。

先介绍一下LAME库,它是目前最优秀也是最常用的MP3编码引擎。当码率达到320Kbit/s以上的时候,LAME编码出来的音频质量几乎可以和CD音质媲美,并且还能保证其文件体积非常小,因此如果要在移动端编码MP3文件,使用LAME是唯一选择。

下面来讲解下,在Android平台下如何交叉编译LAME库,并且打印LAME版本。

Android Studio准备工作

首先我们的Android Studio要下载好NDK,然后新建一个Android项目,右键模块点击“Add C++ to Module”,上面也提及过,Android Studio编译NDK的默认构建工具是CMake,所以我们会看到添加完毕后会有相关的代码和文件生成,例如生成了cpp文件夹和里面相关的cpp文件和CMakeList.txt文件。

下载LAME库并解压,复制到项目中

然后在SourceForge下载最新版本的LAME库,目前为3.100,点击下面文本即可下载:

lame-3.100.tar.gz

下载完成后,解压文件得到lame-3.100文件夹,然后找到libmp3lame文件夹,把里面的.c和.h文件全部复制到Android Studio项目生成的cpp文件夹下,我这边会新建一个lame的文件夹来存放这些文件,这样看起来目录会整洁点,我这边写了个的Python脚本用于把文件夹里的.c和.h文件复制到指定的目录,同时还会打印复制后的绝对路径。我已经把它push到示例代码中,文件名为CopySpecifiedFiles.py,代码如下所示:

import os
import shutil

oldDir = '/Users/tanjiajun/lame-3.100/libmp3lame'
newDir = '/Users/tanjiajun/StudioProjects/AndroidAudioDemo/app/src/main/cpp/lame'
cExtension = '.c'
hExtension = '.h'

if not os.path.exists(newDir):
    os.makedirs(newDir)
for file in os.listdir(oldDir):
    extension = os.path.splitext(file)[-1]
    if extension == cExtension or extension == hExtension:
        shutil.copy(os.path.join(oldDir, file), newDir)
        print(os.path.join(newDir, file))

然后再找到上面提到的lame-3.100文件夹下的include文件夹,把里面的lame.h文件同样复制到Android Studio的lame文件夹。

编译项目

接下来,我们需要修改CMakeList.txt文件,利用上面脚本打印的绝对路径,修改后代码如下所示:

cmake_minimum_required(VERSION 3.22.1)

project("audiodemo")

add_library(
        ${CMAKE_PROJECT_NAME}
        SHARED
        audiodemo.cpp
        lame/reservoir.c
        lame/mpglib_interface.c
        lame/machine.h
        lame/fft.h
        lame/set_get.c
        lame/quantize_pvt.h
        lame/psymodel.h
        lame/newmdct.c
        lame/id3tag.h
        lame/lame-analysis.h
        lame/id3tag.c
        lame/reservoir.h
        lame/lameerror.h
        lame/set_get.h
        lame/quantize.c
        lame/fft.c
        lame/l3side.h
        lame/newmdct.h
        lame/quantize.h
        lame/gain_analysis.c
        lame/encoder.c
        lame/lame.c
        lame/bitstream.c
        lame/quantize_pvt.c
        lame/presets.c
        lame/bitstream.h
        lame/encoder.h
        lame/gain_analysis.h
        lame/lame_global_flags.h
        lame/psymodel.c
        lame/lame.h
        lame/tables.c
        lame/tables.h
        lame/takehiro.c
        lame/util.c
        lame/util.h
        lame/vbrquantize.c
        lame/vbrquantize.h
        lame/VbrTag.c
        lame/VbrTag.h
        lame/version.c
        lame/version.h
)

target_link_libraries(
        ${CMAKE_PROJECT_NAME}
        android
        log
)

然后我们make project,build完后以下文件会报错,这里列出解决的办法:

util.h

在570行,如图所示:

android 开发 lame,Kotlin,Android,前端,android,音视频

解决办法:

extern float fast_log2(float x);

fft.c

在47行,如图所示:

android 开发 lame,Kotlin,Android,前端,android,音视频

解决办法:删除该行代码。

set_get.h

在24行,如图所示:

android 开发 lame,Kotlin,Android,前端,android,音视频

解决办法:

#include "lame.h"

其他错误

如图所示:

android 开发 lame,Kotlin,Android,前端,android,音视频

解决办法:修改app模块中的build.gradle.kts文件,在android函数中增加如下代码:

android {
    ...

    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cFlags("-DSTDC_HEADERS")
            }
        }
    }

    ...
}

修改后,再次make project后编译成功,CMake会帮我们自动生成libaudiodemo.so文件,过程上面也提过了,这里就不再赘述。

打印LAME库的版本

新建MainActivity,这里我使用Compose写界面,并且在AndroidManifest.xml添加相关的代码,AndroidManifest.xml的代码我就不贴了,详细可查看该demo。调用getLameVersion函数就能获取当前LAME版本,要注意的是,需要调用**System.loadLibrary(“audiodemo”)**把生成的动态库加载进来。代码如下所示:

/**
 * Created by TanJiaJun on 2023/12/13.
 */
class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ContentView()
        }
    }

    @Composable
    private fun ContentView() {
        ConstraintLayout(modifier = Modifier.fillMaxSize()) {
            val (topBox, lameVersionText) = createRefs()
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(45.dp)
                    .background(Purple80)
                    .constrainAs(topBox) {
                        start.linkTo(parent.start)
                        top.linkTo(parent.top)
                        end.linkTo(parent.end)
                    }
            ) {
                Text(
                    modifier = Modifier.align(Alignment.Center),
                    text = packageManager.getApplicationLabel(applicationInfo).toString(),
                    fontSize = 18.sp,
                    color = White
                )
            }
            Text(
                modifier = Modifier.constrainAs(lameVersionText) {
                    start.linkTo(parent.start)
                    top.linkTo(topBox.bottom)
                    end.linkTo(parent.end)
                    bottom.linkTo(parent.bottom)
                },
                text = getLameVersion(),
                fontSize = 16.sp,
                color = Black
            )
        }
    }

    /**
     * 获取当前LAME版本
     *
     * @return 当前LAME版本
     */
    private external fun getLameVersion(): String

    private companion object {
        init {
            System.loadLibrary("androidaudiodemo")
        }
    }

}

运行后,我们就可以看到界面有个居中的3.100文本,这就是目前编译的LAME版本,代表我们编译LAME库成功。

我的GitHub:TanJiaJunBeyond

Android通用框架:Android通用框架

我的掘金:谭嘉俊

我的简书:谭嘉俊

我的CSDN:谭嘉俊文章来源地址https://www.toymoban.com/news/detail-857425.html

到了这里,关于音视频开发之旅——音频基础概念、交叉编译原理和实践(LAME的交叉编译)(Android)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Android 音视频开发—MediaPlayer音频与视频的播放介绍

    Android 音视频开发—MediaPlayer音频与视频的播放介绍

    Android多媒体中的——MediaPlayer,我们可以通过这个API来播放音频和视频该类是Androd多媒体框架中的一个重要组件,通过该类,我们可以以最小的步骤来获取,解码和播放音视频。 它支持三种不同的媒体来源: 本地资源 内部的URI,比如你可以通过ContentResolver来获取 外部URL(流

    2024年02月10日
    浏览(18)
  • 音视频开发系列(10):基于qt的音频推流

    音视频开发系列(10):基于qt的音频推流

    今天分享一下利用qt录制音频,然后再利用ffmpeg推流到nginx服务器,最后再利用vlc进行拉流的demo。 首先介绍一下如何利用qt来进行音频的录制,qt的音频录制主要利用qt的QAudioFormat先进行音频信息的配置。主要需要配置以下的信息: 然后使用QAudioDeviceInfo来获取是否支持改设置

    2024年02月02日
    浏览(12)
  • 安卓音视频开发(3)—— AudioTrack两种方式播放pcm音频

    前言 之前学习了AudioRecord录制pcm音频,与之对应的就是AudioTrack播放pcm音频(MediaPlayer、SoundPool有其他应用场景),它有两种数据加载模式(MODE_STATIC、MODE_STREAM)。 模式 MODE_STATIC :这种模式下,一次将所有的数据放入一个固定的buffer,然后写入到AudioTrack中,后续就不用继续

    2023年04月22日
    浏览(14)
  • 从数字图像到音视频学习:我的学习之旅

    从数字图像到音视频学习:我的学习之旅

    数字图像是一门广泛应用于计算机视觉、图像处理和计算机图形学等领域的学科,而音视频学习则涵盖了音频和视频的处理、分析和应用。 如果你最开始接触数字图像,可能会学习一些基本概念,例如像素、分辨率、色彩空间和图像处理算法等。这可能涉及到使用编程语言(

    2024年02月11日
    浏览(11)
  • 【FFmpeg】音视频录制 ① ( 查询系统中 ffmpeg 可录制的音视频输入设备 | 使用 ffmpeg 命令录制音视频数据 | 录制视频数据命令 |录制音频数据| 同时录制音频和视频数据命令 )

    【FFmpeg】音视频录制 ① ( 查询系统中 ffmpeg 可录制的音视频输入设备 | 使用 ffmpeg 命令录制音视频数据 | 录制视频数据命令 |录制音频数据| 同时录制音频和视频数据命令 )

    在 Windows 系统中 , 使用 ffmpeg 命令 录制 音视频 , 需要先获取 系统的 音视频设备 信息 , 录制 音视频 本质上是从 系统音视频设备 中获取数据 ; 执行 命令 , 可以获取 系统中 ffmpeg 可用的 DirectShow 音视频输入设备 ; 命令参数解析 : -list_devices true : 列出所有 ffmpeg 的 指定类型的可

    2024年04月25日
    浏览(19)
  • Qt/C++音视频开发69-保存监控pcm音频数据到mp4文件/监控录像/录像存储和回放/264/265/aac/pcm等

    用ffmpeg做音视频保存到mp4文件,都会遇到一个问题,尤其是在视频监控行业,就是监控摄像头设置的音频是PCM/G711A/G711U,解码后对应的格式是pcm_s16be/pcm_alaw/pcm_mulaw,将这个原始的音频流保存到mp4文件是会报错的,在调用avformat_write_header写文件头的时候提示(-22) Invalid argument,

    2024年04月11日
    浏览(22)
  • Android-音视频学习系列-(二)-交叉编译动态库、静态库的入门学习

    Android-音视频学习系列-(二)-交叉编译动态库、静态库的入门学习

    gcc -S test.i -o test.s//-S 的作用是编译结束生成汇编文件。 汇编阶段 汇编阶段把 .S 文件翻译成二进制机器指令文件 .o ,这个阶段接收.c ,.i ,.s 的文件都没有问题。 下面我们通过以下命令生成二进制机器指令文件 .o 文件: gcc -c test.s -o test.o 链接阶段 链接阶段,链接的是函数库。

    2024年04月09日
    浏览(17)
  • 【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装播放流程 )

    【音视频原理】音视频 “ 采样 - 编码 - 封装 过程 “ 和 “ 解封装 - 解码 - 播放 过程 “ 分析 ( 视频采集处理流程 | 音频采集处理流程 | 音视频文件解封装播放流程 )

    本篇文件主要分析 音视频文件 是怎么产生的 , 以及 音视频文件是如何播放的 ; 视频文件从录像到生成文件的全过程 : 采集图像帧 : 摄像头 硬件 负责 采集画面 , 采集的 初始画面 称为 \\\" 图像帧 \\\" , 一秒钟 采集 的 图像帧 数量 称为 \\\" 帧率 \\\" , 如 : 60 帧 就是 一秒钟采集 60 个画

    2024年02月11日
    浏览(56)
  • 【音视频 | AAC】AAC格式音频文件解析

    【音视频 | AAC】AAC格式音频文件解析

    😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭 🤣本文内容🤣:🍭介绍AAC格式音频文件解析🍭 😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭 本文未经允许,不得转发!!

    2024年02月04日
    浏览(13)
  • 音视频基本概念

    音视频基本概念

    充分利用cpu资源的工具  多线程管理问题 资源 有限多个人去抢 有序进行 读写锁 读写分离 自旋锁 等待资源释放(例如) 可重入锁 SDL锁 互斥锁 SDL_CreateMutex/SDL_DestroyMutex SDL_LockMutex/SDL_UnlockMutex 信号量 SDL_CreateCond/SDL_DestroyCond SDL_CondWait/SDL_CondSignal pts:Presentation timestamp  展示音

    2024年01月22日
    浏览(15)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包