FFMpeg 4.1 音频检测

前言

网络上各种 FFMPEG,尤其是雷大神的一些样例,很好,但是一堆 deprecated 的API,编译看着是真心很烦。所以自己写了一个针对各种格式的输入音频,然后,也没复杂的功能,就是进行音频内部的一些检测。

说一说音频格式

关键的参数:

1. 采样率

2. 位深(说白了也就是精度)

现实生活中的声音其实是连续的,而到电脑,手机等设备中的音频是数字的,离散的。连续的数据是如何变成离散的呢,就是录音,就是采样过程。这么说太抽象了,假设一个例子:

我们现在来测一天的温度。怎么测?

第一:多久测一次?第二:温度计用什么样子的?刻度需要到什么样的精细程度?

假设:一个小时测量一次,温度计能够精确到0.1度。那么采样率就是 1 次/小时,当然,次不是个物理的计量单位,小时是时间计量单位,物理里面针对这种情况,引入了一个特别的单位,就是赫兹。1 小时负一次方,转换成秒的负一次方,就是具有标准单位的采样单位,赫兹了。精度,如果是精确到度,那么比如32度,31度,跟精确到0.1度,33.1度,31.3度,影响的就是存储数据的空间大小了,8bit长度的数字,16bit长度甚至是32bit长度的数字,能够表达的精度,是不一样的。这就是位深。

采样率是不是越高越好呢?测量温度为例:一分钟测一次,甚至一秒钟测量一次,是否有必要呢?其实完全没有必要,因为气温的变化,太慢,一分钟一次,完全没有必要,很可能很多时候测量的数据都是一样的。还有就是精度,精度太细,有没有必要呢?对于人体而言,低于0.1度的气温,人体根本感受不到。测量精细了有什么用呢?甚至到0.5度精度就足矣了。当然也不能太粗,那测量出来,跟没有温度计的估计是一样的效果,精度如果是10读,测量下来,20度,30度,20度,30度,也没啥特别的作用。

所以,对于音频,也一样,不同需求下的声音的录制,根据场景需要来进行采样的。

比如人声,也就是所谓的语音。语音录制,一般场景下,回放出来,只要能听懂,就OK。满足这种要求的情况下,8K的采样率一般足矣了,甚至个别场景下,采用6k的采样率。为什么是6k或者8k?因为人体说话的声音的固有震动频率一般都是3到4k之间。而且大多数人都是在3k左右,到4k的一般都很少。可想,画成波形,那么采样之后的数据回放,如何让人能够听懂呢?至少能尽量“恢复”成原来的样子呢?直观而言,至少在波峰处取一个点,波谷处取一个点,这样才能还原吧。当然,这种直观是不靠谱的。其实,如果了解傅里叶变换,知道频域时域这些知识,理论上是可以证明:4k固有震动频率的波形,采样必须要在4k*2的采样率以上,其实就是香农采样定理。还有就是位深,采样精度,跟温度精度其实也是类似的。

好,这下我们就知道了音频数据最关键的两个数据了,采样率跟位深。

对于语音,一般8k采样率,8bit采样位深也就足够了。但是为了更好的品质呢,一般都采用8k16bit的采样率跟位深。这样采集来的数据,就是所谓的PCM,也就是没有经过压缩的数据。其实WAV格式的音频,内部的数据,一般就是这样的数据,加了个格式头而已。

为什么会有所谓的44100采样率?因为前文说的是语音,就是人说话,那唱歌呢?乐器呢?经过反复试验,发现采样率到了44100的时候,再往上,不好意思,放出来的声音,人耳朵已经分辨不出其中的差距了。所以,一般的44100就是音频采样的最高频率了。

3. 布局,以及跟随着布局相关的声道信息。对于语音而言,单声道就可以,但是针对各种音乐,那就很复杂了,左右布局的双声道,环绕声,5.2,甚至7.1,还有甚至所谓的杜比什么的,比较复杂。虽然都是音频,其实玩语音的是比较幸福的,不用考虑太多,做声卡,音响设备的,那就不一样了。

一般的音乐,44100的采样率,16bit的位深,加上左右双声道,足矣。其实一个声道,就相当于一个麦克风,就是一路独立的数据。

4. 编码,按照前面说的44100的采样率,16bit位深,双声道,那么1秒钟下来,音频文件有多大呢?

44100 * 16bit * 2 = 44100 * 2B * 2 = 176400B = 172 KB。如果是3分钟的音频的 172KB * 3 * 60 = 30960KB = 30 MB

3分钟音乐,30兆!见过么?真的很少见。所以,总得压缩一下,这种压缩,也就是编码,直接就搞出了各种各样的音频格式出来。

5. 跟时间相关的额外的东西,就是frame。处理数据,总得攒上一笔缓存。音频一般都是以 frame 为单位进行处理,压缩而言,总不能压缩一个采样数据。一般的一个frame 就是10毫秒的音频数据。那么他的大小,根据不同的采样率,位深,编码方式,其大小就是可以计算的了。

FFMPEG 对音频的处理,也就是这些东西了。

环境搭建:

FFMPEG版本4.1。到官网下载,windows版本即可。

devel 的要下载(头文件以及lib),shared 也要下载(包含dll文件)。

个人的习惯:

筛选器跟目录一一对应。如下:

项目的一些配置:

然后还有就是附件包含目录,附加库目录等等。

配置起来确实比较麻烦。

bin以及lib中分x86跟x64,然后分别把相关的lib,dll copy进去。引入库,就采用

#pragma comment(lib, "xxx.lib")

去导入。

main.c代码如下:(注意是.c,否则include FFMPEG头文件 需要extern C)

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <string.h>

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/samplefmt.h"


#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")

void audio_detect(const char* url);

int main()
{
	int argc = 3;
	char* argv[] = {"xxx", "out.wav", "decode_audio_out.mp3"};
	// decode_audio(argc, argv);
	// mp3_2_wav();
	char* url[] = {"input.mp3", "input.wav", "input.wma",
		"8k8bitpcm.wav", "8k16bitpcm.wav", "8kmp38.wav",
		"8kmp316.wav", "8kulaw.wav", "11k8bitpcm.wav",
		"11k16bitpcm.wav", "11kulaw.wav"};
	int i = 0; 
	for (; i < sizeof(url) / sizeof(char*); i++)
	{
		printf("=========================================\nFile in: %s\n", url[i]);
		audio_detect(url[i]);
	}
	return 0;
}

void audio_detect(const char* url)
{
	AVFormatContext	*pFormatCtx = NULL;
	int ret = avformat_open_input(&pFormatCtx, url, NULL, NULL);
	if (ret != 0)
	{
		printf("avformat_open_input error: %d\n", ret);
		return;
	}

	unsigned int nb = pFormatCtx->nb_streams;
	AVCodecContext *codecCtx = avcodec_alloc_context3(NULL);

	int i = 0;
	for (; i < nb; i++)
	{
		if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			break;
		}
	}
	if (i >= nb)
	{
		printf("There is no AUDIO stream\n");
		return;
	}
	// Retrieve stream information
	// 读取部分数据,进行探测,用以自动识别输入文件的格式。。。。
	ret = avformat_find_stream_info(pFormatCtx, NULL);
	if (ret < 0)
	{
		printf("Couldn't find stream information.\n");
		return;
	}
	ret = avcodec_parameters_to_context(codecCtx, pFormatCtx->streams[i]->codecpar);

	AVCodec * codec = avcodec_find_decoder(codecCtx->codec_id);
	if (codec == NULL)
	{
		printf("Codec not found.\n");
		return;
	}
	ret = avcodec_open2(codecCtx, codec, NULL);
	if (ret < 0)
	{
		printf("Could not open codec.\n");
		return;
	}

	enum AVSampleFormat in_fmt = codecCtx->sample_fmt;
	int in_rate = codecCtx->sample_rate;
	int in_ch = codecCtx->channels;

	printf("Input audio fmt: %s(%d), rate: %d, channels: %d\n", av_get_sample_fmt_name(in_fmt), in_fmt, in_rate, in_ch);
	printf("codec name: %s, id: 0X%X, type: %d\n", codec->name, codec->id, codec->type);
	avcodec_close(codecCtx);
	avformat_close_input(&pFormatCtx);
}

=========================================
File in: input.mp3
Input audio fmt: fltp(8), rate: 44100, channels: 2
codec name: mp3float, id: 0X15001, type: 1
=========================================
File in: input.wav
Input audio fmt: s16(1), rate: 44100, channels: 2
codec name: pcm_s16le, id: 0X10000, type: 1
=========================================
File in: input.wma
Input audio fmt: fltp(8), rate: 44100, channels: 2
codec name: wmav2, id: 0X15008, type: 1
=========================================
File in: 8k8bitpcm.wav
Input audio fmt: u8(0), rate: 8000, channels: 1
codec name: pcm_u8, id: 0X10005, type: 1
=========================================
File in: 8k16bitpcm.wav
Input audio fmt: s16(1), rate: 8000, channels: 1
codec name: pcm_s16le, id: 0X10000, type: 1
=========================================
File in: 8kmp38.wav
Input audio fmt: fltp(8), rate: 8000, channels: 1
codec name: mp3float, id: 0X15001, type: 1
=========================================
File in: 8kmp316.wav
Input audio fmt: fltp(8), rate: 8000, channels: 1
codec name: mp3float, id: 0X15001, type: 1
=========================================
File in: 8kulaw.wav
Input audio fmt: s16(1), rate: 8000, channels: 1
codec name: pcm_mulaw, id: 0X10006, type: 1
=========================================
File in: 11k8bitpcm.wav
Input audio fmt: u8(0), rate: 11025, channels: 1
codec name: pcm_u8, id: 0X10005, type: 1
=========================================
File in: 11k16bitpcm.wav
Input audio fmt: s16(1), rate: 11025, channels: 1
codec name: pcm_s16le, id: 0X10000, type: 1
=========================================
File in: 11kulaw.wav
Input audio fmt: s16(1), rate: 11025, channels: 1
codec name: pcm_mulaw, id: 0X10006, type: 1

示例音频:

不知道该怎么传了。。。。。

自己去下载吧。然后改一下文件名即可。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值