[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

相关文章

Redis在windows环境下如何启动

《Redis在windows环境下如何启动》:本文主要介绍Redis在windows环境下如何启动的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Redis在Windows环境下启动1.在redis的安装目录下2.输入·redis-server.exe

Pytest多环境切换的常见方法介绍

《Pytest多环境切换的常见方法介绍》Pytest作为自动化测试的主力框架,如何实现本地、测试、预发、生产环境的灵活切换,本文总结了通过pytest框架实现自由环境切换的几种方法,大家可以根据需要进... 目录1.pytest-base-url2.hooks函数3.yml和fixture结论你是否也遇到过

浅谈配置MMCV环境,解决报错,版本不匹配问题

《浅谈配置MMCV环境,解决报错,版本不匹配问题》:本文主要介绍浅谈配置MMCV环境,解决报错,版本不匹配问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录配置MMCV环境,解决报错,版本不匹配错误示例正确示例总结配置MMCV环境,解决报错,版本不匹配在col

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

使用Python实现文本转语音(TTS)并播放音频

《使用Python实现文本转语音(TTS)并播放音频》在开发涉及语音交互或需要语音提示的应用时,文本转语音(TTS)技术是一个非常实用的工具,下面我们来看看如何使用gTTS和playsound库将文本... 目录什么是 gTTS 和 playsound安装依赖库实现步骤 1. 导入库2. 定义文本和语言 3

Windows Server服务器上配置FileZilla后,FTP连接不上?

《WindowsServer服务器上配置FileZilla后,FTP连接不上?》WindowsServer服务器上配置FileZilla后,FTP连接错误和操作超时的问题,应该如何解决?首先,通过... 目录在Windohttp://www.chinasem.cnws防火墙开启的情况下,遇到的错误如下:无法与

Centos环境下Tomcat虚拟主机配置详细教程

《Centos环境下Tomcat虚拟主机配置详细教程》这篇文章主要讲的是在CentOS系统上,如何一步步配置Tomcat的虚拟主机,内容很简单,从目录准备到配置文件修改,再到重启和测试,手把手带你搞定... 目录1. 准备虚拟主机的目录和内容创建目录添加测试文件2. 修改 Tomcat 的 server.X

Python解析器安装指南分享(Mac/Windows/Linux)

《Python解析器安装指南分享(Mac/Windows/Linux)》:本文主要介绍Python解析器安装指南(Mac/Windows/Linux),具有很好的参考价值,希望对大家有所帮助,如有... 目NMNkN录1js. 安装包下载1.1 python 下载官网2.核心安装方式3. MACOS 系统安