[FFmpeg学习]windows环境sdl播放音频试验

2024-06-17 06:28

本文主要是介绍[FFmpeg学习]windows环境sdl播放音频试验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考资料:

FFmpeg和SDL2播放mp4_sdl 播放mp4 声音-CSDN博客

SimplePlayer/SimplePlayer.c at master · David1840/SimplePlayer · GitHub

在前面的学习中,通过获得的AVFrame进行了播放画面,

[FFmpeg学习]初级的SDL播放mp4测试-CSDN博客

播放音频原理类似,也是获取AVFrame的信息,


extern "C" {
#include <libavutil/log.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
}
// Simplest FFmpeg Sync Player.cpp : 定义控制台应用程序的入口点。
//#include <stdio.h>
#include <SDL_types.h>
#include "SDL.h"static Uint8* audio_chunk;
static Uint32 audio_len;
static Uint8* audio_pos;#define MAX_AUDIO_FRAME_SIZE 19200//音频设备需要更多数据的时候会调用该回调函数
void read_audio_data(void* udata, Uint8* stream, int len) {fprintf(stderr, "stream addr:%p, audio_len:%d, len:%d\n",stream,audio_len,len);//首先使用SDL_memset()将stream中的数据设置为0SDL_memset(stream, 0, len);if (audio_len == 0)return;len = (len > audio_len ? audio_len : len);SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);audio_pos += len;audio_len -= len;
}#undef main
int main(int argc, char* argv[]) {const char* file = "test.mp4";AVFormatContext* pFormatCtx = NULL; //for opening multi-media fileint i, audioStream = -1;AVCodecParameters* pCodecParameters = NULL; //codec contextAVCodecContext* pCodecCtx = NULL;const AVCodec* pCodec = NULL; // the codecerAVFrame* pFrame = NULL;AVPacket* packet;uint8_t* out_buffer;int64_t in_channel_layout;struct SwrContext* au_convert_ctx;if (avformat_open_input(&pFormatCtx, file, NULL, NULL) != 0) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open video file!");return -1; // Couldn't open file}audioStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if (audioStream == -1) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Din't find a video stream!");return -1;// Didn't find a video stream}// Get a pointer to the codec context for the video streampCodecParameters = pFormatCtx->streams[audioStream]->codecpar;// Find the decoder for the video streampCodec = avcodec_find_decoder(pCodecParameters->codec_id);if (pCodec == NULL) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported codec!\n");return -1; // Codec not found}// Copy contextpCodecCtx = avcodec_alloc_context3(pCodec);if (avcodec_parameters_to_context(pCodecCtx, pCodecParameters) != 0) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't copy codec context");return -1;// Error copying codec context}// Open codecif (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open decoder!\n");return -1; // Could not open codec}packet = (AVPacket*)av_malloc(sizeof(AVPacket));av_init_packet(packet);pFrame = av_frame_alloc();uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;//输出声道int out_nb_samples = 1024;enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;//输出格式S16int out_sample_rate = 44100;int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);out_buffer = (uint8_t*)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);//Initif (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)) {printf("Could not initialize SDL - %s\n", SDL_GetError());return -1;}SDL_AudioSpec spec;spec.freq = out_sample_rate;spec.format = AUDIO_S16SYS;spec.channels = out_channels;spec.silence = 0;spec.samples = out_nb_samples;spec.callback = read_audio_data;spec.userdata = pCodecCtx;if (SDL_OpenAudio(&spec, NULL) < 0) {printf("can't open audio.\n");return -1;}in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);printf("in_channel_layout --->%d\n", in_channel_layout);au_convert_ctx = swr_alloc();au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,in_channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);swr_init(au_convert_ctx);SDL_PauseAudio(0);while (av_read_frame(pFormatCtx, packet) >= 0) {if (packet->stream_index == audioStream) {avcodec_send_packet(pCodecCtx, packet);while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t**)pFrame->data,pFrame->nb_samples); // 转换音频}audio_chunk = (Uint8*)out_buffer;audio_len = out_buffer_size;audio_pos = audio_chunk;while (audio_len > 0) {SDL_Delay(1);//延迟播放}}av_packet_unref(packet);}swr_free(&au_convert_ctx);SDL_Quit();return 0;
}

在windows上,如果有方法废弃的错误,

错误    C4996    'AVCodecContext::channels': 被声明为已否决    

可以设置SDL检查为否,来解决

代码流程里,需要注意一下audio_callback是怎么回调的,

audio_callback函数是由SDL音频系统在需要更多音频数据以填充音频缓冲区时自动调用的。当SDL音频系统开始播放音频时,它会周期性地调用音频回调函数以获取新的音频数据。音频回调函数的调用频率取决于音频采样率和缓冲区大小。

main函数中,我们初始化SDL音频系统并设置了音频回调函数audio_callback

if (SDL_Init(SDL_INIT_AUDIO) < 0) {fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());exit(1);
}// 设置音频回调函数
SDL_AudioSpec desired;
desired.freq = audioCodecContext->sample_rate;
desired.format = AUDIO_S16SYS; // 使用16位有符号小端字节序样本
desired.channels = audioCodecContext->channels;
desired.samples = 4096; // 音频缓冲区大小,可以根据需要调整
desired.callback = audio_callback;
desired.userdata = NULL;// 打开音频设备
SDL_AudioDeviceID deviceId = SDL_OpenAudioDevice(NULL, 0, &desired, NULL, SDL_AUDIO_ALLOW_ANY_CHANGE);
if (deviceId <= 0) {fprintf(stderr, "Failed to open audio device: %s\n", SDL_GetError());return -1;
}// 开始播放音频
SDL_PauseAudioDevice(deviceId, 0);

当我们调用SDL_OpenAudioDevice函数时,SDL音频系统会注册音频回调函数audio_callback。当我们调用SDL_PauseAudioDevice(deviceId, 0)开始播放音频时,SDL音频系统会根据音频参数(如采样率、通道数和缓冲区大小)定期调用audio_callback函数。

audio_callback函数中,我们需要根据音频缓冲区的需求提供音频数据。这通常涉及从文件或实时流中解码音频数据,并将其传递给SDL音频系统。在我们的示例中,我们从全局变量audio_buffer中读取音频数据,该变量由swr_convert函数填充。

总之,audio_callback函数是由SDL音频系统在需要更多音频数据以填充音频缓冲区时自动触发的。您无需手动调用此函数,SDL音频系统会负责调用它。只需确保在回调函数中提供正确的音频数据即可。

这篇关于[FFmpeg学习]windows环境sdl播放音频试验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1068695

相关文章

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

Windows设置nginx启动端口的方法

《Windows设置nginx启动端口的方法》在服务器配置与开发过程中,nginx作为一款高效的HTTP和反向代理服务器,被广泛应用,而在Windows系统中,合理设置nginx的启动端口,是确保其正... 目录一、为什么要设置 nginx 启动端口二、设置步骤三、常见问题及解决一、为什么要设置 nginx

Python实现多路视频多窗口播放功能

《Python实现多路视频多窗口播放功能》这篇文章主要为大家详细介绍了Python实现多路视频多窗口播放功能的相关知识,文中的示例代码讲解详细,有需要的小伙伴可以跟随小编一起学习一下... 目录一、python实现多路视频播放功能二、代码实现三、打包代码实现总结一、python实现多路视频播放功能服务端开

Python实现视频转换为音频的方法详解

《Python实现视频转换为音频的方法详解》这篇文章主要为大家详细Python如何将视频转换为音频并将音频文件保存到特定文件夹下,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5. 注意事项

在Mysql环境下对数据进行增删改查的操作方法

《在Mysql环境下对数据进行增删改查的操作方法》本文介绍了在MySQL环境下对数据进行增删改查的基本操作,包括插入数据、修改数据、删除数据、数据查询(基本查询、连接查询、聚合函数查询、子查询)等,并... 目录一、插入数据:二、修改数据:三、删除数据:1、delete from 表名;2、truncate

在 Windows 上安装 DeepSeek 的完整指南(最新推荐)

《在Windows上安装DeepSeek的完整指南(最新推荐)》在Windows上安装DeepSeek的完整指南,包括下载和安装Ollama、下载DeepSeekRXNUMX模型、运行Deep... 目录在www.chinasem.cn Windows 上安装 DeepSeek 的完整指南步骤 1:下载并安装

VScode连接远程Linux服务器环境配置图文教程

《VScode连接远程Linux服务器环境配置图文教程》:本文主要介绍如何安装和配置VSCode,包括安装步骤、环境配置(如汉化包、远程SSH连接)、语言包安装(如C/C++插件)等,文中给出了详... 目录一、安装vscode二、环境配置1.中文汉化包2.安装remote-ssh,用于远程连接2.1安装2

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

windows系统下shutdown重启关机命令超详细教程

《windows系统下shutdown重启关机命令超详细教程》shutdown命令是一个强大的工具,允许你通过命令行快速完成关机、重启或注销操作,本文将为你详细解析shutdown命令的使用方法,并提... 目录一、shutdown 命令简介二、shutdown 命令的基本用法三、远程关机与重启四、实际应用