FFMPEG+SDL2播放音频-1(音频知识和代码)

       为了快速掌握音频开发知识,秉承实用主义,我计划以下面思维导图方式介绍音频开发知识,以求最快速让开发者听到文件的声音。

f428ae8fdf764e9db93ddca9fafc06ec.png

概述

开发者基础

在计算机平台下,二进制数据可用十六进制显示,文件数据可视化工具软件为为UltraEdit。

开发者收获

1 Qt播放音频文件Demo。

2 基于C、C++语言

   使用ffmpeg 解码压缩音频数据;

   使用SDL      播放原始音频数据;

   使用winmm 播放原始音频数据;

   音频播放控制,响度增大和音调不改变实现倍速播放。

知识目录

1 声音是什么?

        声音(sound)是由物体振动产生的声波。是通过介质(空气或固体、液体)传播并能被人或动物听觉器官所感知的波动现象。最初发出振动(震动)的物体叫声源。声音以波的形式振动(震动)传播。声音是声波通过任何介质传播形成的运动。声音是一种波。可以被人耳识别的声(频率在20 Hz~20000 Hz之间),我们称之为声音。

2 声音和音频有什么关系?

        音频是个专业术语,音频一词已用作一般性描述音频范围内和声音有关的设备及其作用。

        1.Audio,指人耳可以听到声音的声波,称为音频。

        2.指存储声音内容的文件。

        3.在某些方面能指作为滤波的振动。 

3 声音怎么被我们听到?

        声音是一种压力波:当演奏乐器、拍打一扇门或者敲击桌面时,他们的振动会引起介质——空气分子有节奏的振动,使周围的空气产生疏密变化,形成疏密相间的纵波,这就产生了声波,这种现象会一直延续到振动消失为止。

        声音作为波的一种,频率和振幅就成了描述波的重要属性,频率的大小与我们通常所说的音高对应,而振幅影响声音的大小。声音可以被分解为不同频率不同强度正弦波的叠加。这种变换(或分解)的过程,称为傅里叶变换(Fourier Transform)。

        因此,一般的声音总是包含一定的频率范围。人耳可以听到的声音的频率范围在20到2万赫兹之间。高于这个范围的波动称为超声波,而低于这一范围的称为次声波。狗和蝙蝠等动物可以听得到高达16万赫兹的声音。鲸和大象则可以产生频率在15到35赫兹范围内的声音。

4 不同的声音有什么区别?

  1. 响度(loudness):人主观上感觉声音的大小(俗称音量),由“振幅”(amplitude)和人离声源的距离决定,振幅越大响度越大,人和声源的距离越小,响度越大。(单位:分贝dB)

  2. 音调(pitch):声音的高低(高音、低音),由“频率”(frequency)决定,频率越高音调越高(频率单位Hz(hertz),赫兹,人耳听觉范围20~20000Hz。20Hz以下称为次声波,20000Hz以上称为超声波)例如,低音端的声音或更高的声音,如细弦声。

  3. 音色(Timbre):又称音品,波形决定了声音的音色。声音因物体材料的特性而不同,音色本身是一种抽象的东西,但波形是把这个抽象直观的表现。波形不同,音色则不同。不同的音色,通过波形,完全可以分辨的。

  4. 音调,响度,音色是乐音的三个主要特征,人们就是根据他们来区分声音.

  5. 当两个物体碰撞后振动产生声音时,若两者振动频率比为不可化简的复杂比,如:201:388,那么我们分辨出来会觉得这个声音刺耳;相反,若两者振动频率比为可化简的简单比,如:3:7,那么我们分辨出来会觉得很动听。(毕达哥拉斯发现)

5 声音怎么被存储下来?

        要在计算机内播放或是处理音频文件,也就是要对声音文件进行数、模转换,这个过程同样由采样和量化构成,人耳所能听到的声音,最低的频率是从20Hz起一直到最高频率20KHZ,20KHz以上人耳是听不到的,因此音频的最大带宽是20KHZ,故而采样速率需要介于40~50KHZ之间,而且对每个样本需要更多的量化比特数。音频数字化的标准是每个样本16位(16bit,即96dB)的信噪比,采用线性脉冲编码调制PCM,每一量化步长都具有相等的长度。在音频文件的制作中,正是采用这一标准。

c8bc7865bd9b42958ca2ff6b0dea5002.png

6 Winmm 是什么?

        DLL 文件是winmm 或者 winmm.dll,DLL 名称为Windows Multimedia, API描述是winmm.dll是Windows多媒体相关应用程序接口,用于低档的音频和游戏手柄。 系统文件winmm.dll是存放在Windows系统文件夹中的重要文件,通常情况下是在安装操作系统过程中自动创建的,对于系统正常运行来说至关重要。下为微软官方解释:

网站: User-Mode WDM Audio Components - Windows drivers | Microsoft Learn

81280a30285d4183a7839b8a0f2c83ba.png

7 SDL是什么?

        SDL(Simple DirectMedia Layer)是一套开放源代码跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。现SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。

 网站: Simple DirectMedia Layer - Homepage (libsdl.org)

8ed493e5527a4d9ba017c9e26e81a8b7.png

8 ffmpeg 是什么?

        FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPLGPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。

FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括WindowsMac OS X等。这个项目最早由Fabrice Bellard发起,2004年至2015年间由Michael Niedermayer主要负责维护。许多FFmpeg的开发人员都来自MPlayer项目,而且当前FFmpeg也是放在MPlayer项目组的服务器上。项目的名称来自MPEG视频编码标准,前面的"FF"代表"Fast Forward"。 [1]FFmpeg编码库可以使用GPU加速。

官网:FFmpeg

b785c1b548db461d889b80cec6cbf415.png

================================开始编程啦=================================

9 声音怎么被计算机播放出来?

        思路:获得一份音频文件时,通过windows  I/O 函数,将音频文件读取到系统内存,如果是非压缩文件或者RAW文件,可以将内存数据传入至配置好的SDL 播放器中,直接播放;如果是压缩文件,需要将内存数据传入至配置好的FFMPEG音频解码器中,随后送入配置好的SDL 播放器中播放。SDL 播放器亦可换成WINMM。

1. 在上述官网分别下载FFMPEG/SDL库,WINMM 为系统内置,无需下载。

2.将头文件和LIB库分别加入到工程中。

SDL 播放PCM 代码部分

// audio_play.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include "SDL.h"

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



unsigned char* audio_chunk;
unsigned int   audio_len;
unsigned char* audio_pos;

const static uint32_t PCM_BUFFER_SIZE = 4096;

//数据到来的回调函数
void read_audio_data_cb(void* udata, Uint8* stream, int len)
{
	SDL_memset(stream, 0, len);
	if (audio_len == 0)
		return;
	len = std::min(len, static_cast<int>(audio_len));

	SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
	audio_pos += len;
	audio_len -= len;
}
#undef main
int main(int argc , char *argv[])
{
	SDL_Init(SDL_INIT_AUDIO);   //init

	SDL_AudioSpec spec;
	spec.freq = 44100;
	spec.format = AUDIO_S16SYS;
	spec.channels = 2;
	spec.samples = 1024;
	spec.callback = read_audio_data_cb;
	spec.userdata = NULL;
	//根据参数,打开音频设备
	if (SDL_OpenAudio(&spec, NULL) < 0)
		return -1;

	//打开文件
	FILE *f = fopen("yinpin.pcm", "rb+");
	if (f == nullptr) return -1;
	char* pcm_buffer = (char*)malloc(PCM_BUFFER_SIZE);
	//开始播放
	SDL_PauseAudio(0);
	int ret = 0;
	while (true)
	{
		ret = fread(pcm_buffer, 1, PCM_BUFFER_SIZE, f);
		if (ret == 0) break;

		audio_chunk = reinterpret_cast<Uint8*>(pcm_buffer);
		audio_len = ret;                           //读取到的字节数
		audio_pos = audio_chunk;
		std::cout << "play " << audio_len << " data" << std::endl;
		while (audio_len > 0)       //等待audio_len长度的数据播放完成  
			SDL_Delay(1);
	}

	free(pcm_buffer);
	SDL_Quit();
	return 0;
}

==============歇了,有时间继续=============================================

未完成: ffmpeg 解码  winmm 播放

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用FFmpegSDL实现音频播放,您可以按照以下步骤进行操作: 1. 首先,确保您已经安装了FFmpegSDL库。 2. 创建一个C/C++源文件,并包含必要的头文件: ```c #include <stdio.h> #include <SDL2/SDL.h> #include <libavformat/avformat.h> #include <libavutil/opt.h> #include <libswresample/swresample.h> ``` 3. 初始化FFmpegSDL库: ```c av_register_all(); avformat_network_init(); SDL_Init(SDL_INIT_AUDIO); ``` 4. 打开音频文件并解码音频流: ```c AVFormatContext *formatCtx = NULL; if (avformat_open_input(&formatCtx, "audio.mp3", NULL, NULL) != 0) { // 处理打开文件失败的情况 return -1; } if (avformat_find_stream_info(formatCtx, NULL) < 0) { // 处理获取流信息失败的情况 return -1; } int audioStreamIndex = -1; for (int i = 0; i < formatCtx->nb_streams; i++) { if (formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { audioStreamIndex = i; break; } } if (audioStreamIndex == -1) { // 处理没有找到音频流的情况 return -1; } AVCodecParameters *codecPar = formatCtx->streams[audioStreamIndex]->codecpar; AVCodec *codec = avcodec_find_decoder(codecPar->codec_id); if (codec == NULL) { // 处理找不到解码器的情况 return -1; } AVCodecContext *codecCtx = avcodec_alloc_context3(codec); if (avcodec_parameters_to_context(codecCtx, codecPar) < 0) { // 处理解码器参数设置失败的情况 return -1; } if (avcodec_open2(codecCtx, codec, NULL) < 0) { // 处理打开解码器失败的情况 return -1; } ``` 5. 配置SDL音频参数: ```c SDL_AudioSpec wantedSpec, obtainedSpec; wantedSpec.freq = codecCtx->sample_rate; wantedSpec.format = AUDIO_S16SYS; wantedSpec.channels = codecCtx->channels; wantedSpec.silence = 0; wantedSpec.samples = 1024;wantedSpec.callback = audio_callback; wantedSpec.userdata = codecCtx; SDL_OpenAudio(&wantedSpec, &obtainedSpec); SDL_PauseAudio(0); ``` 6. 实现SDL音频回调函数: ```c void audio_callback(void *userdata, Uint8 *stream, int len) { AVCodecContext *codecCtx = (AVCodecContext *)userdata; AVPacket packet; static uint8_t audio_buffer[(192000 * 3) / 2]; static unsigned int audio_buffer_size = 0; static unsigned int audio_buffer_index = 0; while (len > 0) { if (audio_buffer_index >= audio_buffer_size) { int ret = av_read_frame(formatCtx, &packet); if (ret < 0) { // 处理读取音频帧失败的情况 break; } if (packet.stream_index == audioStreamIndex) { ret = avcodec_send_packet(codecCtx, &packet); if (ret < 0) { // 处理发送音频帧给解码器失败的情况 break; } ret = avcodec_receive_frame(codecCtx, &frame); if (ret < 0) { // 处理接收解码后的音频帧失败的情况 break; } int data_size = av_samples_get_buffer_size(NULL, codecCtx->channels, frame->nb_samples, codecCtx->sample_fmt, 1); memcpy(audio_buffer, frame->data[0], data_size); audio_buffer_size = data_size; audio_buffer_index = 0; } av_packet_unref(&packet); } int remaining = audio_buffer_size - audio_buffer_index; int to_copy = len > remaining ? remaining : len; memcpy(stream, audio_buffer + audio_buffer_index, to_copy); len -= to_copy; stream += to_copy; audio_buffer_index += to_copy; } } ``` 7. 清理资源并关闭SDLFFmpeg库: ```c SDL_CloseAudio(); SDL_Quit(); avformat_close_input(&formatCtx); avcodec_free_context(&codecCtx); return 0; ``` 以上是一个简单的示例,演示了如何使用FFmpegSDL实现音频播放。您可以根据自己的需求进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sinat_37898310

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值