SDL2 播放音频(MP4)

1.简介

这里引入FFmpeg库,获取音频流数据,然后通过FFmpeg将视频流解码成pcm原始数据,再将pcm数据送入到SDL库中实现音频播放。

2.FFmpeg的操作流程

  • 注册API:av_register_all()
  • 构建输入AVFormatContext上下文:avformat_open_input()
  • 查找音视频流信息:avformat_find_stream_info()
  • 查找解码器:avcodec_find_decoder()
  • 打开解码器:avcodec_open2()
  • 然后通过while循环,不停的读取数据:av_read_frame()
  • 帧解码:avcodec_send_packet()和avcodec_receive_frame()
  • 重采样:swr_convert()

3.SDL音频播放流程

SDL播放音频的流程如下:

  • 初始化音频子系统:SDL_Init()。
  • 设置音频参数:SDL_AudioSpec。
  • 设置回调函数:SDL_AudioCallback。
  • 打开音频设备:SDL_OpenAudio()。
  • 打开pcm文件,读取数据。
  • 开始播放:SDL_PauseAudio()。

4.示例

#include <stdio.h>
#include <SDL.h>
#include <memory>extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "libswresample/swresample.h"
};static  Uint8  *audio_chunk;
static  Uint32  audio_len;
static  Uint8  *audio_pos;void  fill_audio(void *udata, Uint8 *stream, int len)
{//SDL 2.0SDL_memset(stream, 0, len);if (audio_len == 0)		/*  Only  play  if  we  have  data  left  */return;len = (len > audio_len ? audio_len : len);	/*  Mix  as  much  data  as  possible  */SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME/2);audio_pos += len;audio_len -= len;	
}AVFrame *recv(AVCodecContext *codecCtx)
{if (!codecCtx){return NULL;}AVFrame *frame = av_frame_alloc();int ret = avcodec_receive_frame(codecCtx, frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){av_frame_free(&frame);return NULL;}else if (ret < 0){av_frame_free(&frame);return NULL;}return frame;
}#undef main
int main(int argc, char* argv[])
{av_register_all();///ffmpegavformat_network_init();AVFormatContext* pFormatCtx = NULL;const char* inputUrl = "./2.mp4";///打开输入的流int ret = avformat_open_input(&pFormatCtx, inputUrl, NULL, NULL);if (ret != 0){printf("Couldn't open input stream.\n");return -1;}//查找流信息if (avformat_find_stream_info(pFormatCtx, NULL) < 0){printf("Couldn't find stream information.\n");return -1;}//找到音频流索引int audio_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);AVStream* st = pFormatCtx->streams[audio_index];AVCodec* codec = nullptr;//找到解码器codec = avcodec_find_decoder(st->codecpar->codec_id);if (!codec){fprintf(stderr, "Codec not found\n");return -1;}//申请AVCodecContextAVCodecContext* pCodecCtx = avcodec_alloc_context3(codec);if (!pCodecCtx){return -1;}avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[audio_index]->codecpar);//打开解码器if ((ret = avcodec_open2(pCodecCtx, codec, NULL) < 0)){return -1;}AVPacket* pkt = av_packet_alloc();//------------SDL----------------//Output Info-----------------------------printf("---------------- File Information ---------------\n");av_dump_format(pFormatCtx, 0, inputUrl, 0);printf("-------------------------------------------------\n");SwrContext *swrContext = swr_alloc();if (!swrContext){return -1;}swrContext = swr_alloc_set_opts(NULL,													//ctxAV_CH_LAYOUT_STEREO,																	//输出channel布局AV_SAMPLE_FMT_S16,																		 //输出的采样格式44100,																									//采样率av_get_default_channel_layout(pCodecCtx->channels),						//输入channel布局pCodecCtx->sample_fmt,																	//输入的采样格式pCodecCtx->sample_rate,																	//输入的采样率0, NULL);// 初始化重采样上下文if (swr_init(swrContext) < 0){swr_free(&swrContext);return -1;}if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){printf("Could not initialize SDL - %s\n", SDL_GetError());return -1;}//SDL_AudioSpecSDL_AudioSpec wanted_spec;wanted_spec.freq = 44100;wanted_spec.format = AUDIO_S16SYS;wanted_spec.channels = 2;wanted_spec.silence = 0;wanted_spec.samples = 1024;wanted_spec.callback = fill_audio;wanted_spec.userdata = pCodecCtx;if (SDL_OpenAudio(&wanted_spec, NULL) < 0){printf("can't open audio.\n");return -1;}//PlaySDL_PauseAudio(0);// 分配输出音频数据uint8_t	 *out_buffer = nullptr;while (av_read_frame(pFormatCtx, pkt) >= 0){if (pkt->stream_index == audio_index){//一次send 多次recvint ret = avcodec_send_packet(pCodecCtx, pkt);if (ret < 0)continue;//释放资源av_packet_unref(pkt);while (1){AVFrame *frame = recv(pCodecCtx);if (!frame)break;//输入的样本数int in_nb_samples = frame->nb_samples;//1024int out_linesize;int dst_nb_samples = av_rescale_rnd(in_nb_samples, 44100, frame->sample_rate, AV_ROUND_UP);//输出的样本数int out_buffer_size = av_samples_get_buffer_size(NULL, 2, dst_nb_samples, AV_SAMPLE_FMT_S16, 0);if(!out_buffer)out_buffer = (uint8_t *)av_malloc(out_buffer_size);//返回每个通道输出的样本数,错误时为负值int sampleCount = swr_convert(swrContext, &out_buffer, dst_nb_samples,(const uint8_t**)frame->data, in_nb_samples);if (sampleCount <= 0){av_frame_free(&frame);break;}int outSize = sampleCount * 2 * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);while (audio_len > 0)//Wait until finishSDL_Delay(1);//Set audio buffer (PCM data)audio_chunk = (Uint8 *)out_buffer;//Audio buffer lengthaudio_len = outSize;audio_pos = audio_chunk;av_frame_free(&frame);}}else{//释放资源av_packet_unref(pkt);}}//--------------av_free(out_buffer);av_packet_free(&pkt);swr_close(swrContext);swr_free(&swrContext);avcodec_close(pCodecCtx);avcodec_free_context(&pCodecCtx);avformat_close_input(&pFormatCtx);SDL_CloseAudio();SDL_Quit();
}

 5.相关推荐

[总结]FFMPEG视音频编解码零基础学习方法_零基础ffmpeg 雷霄骅-CSDN博客 

FFmpeg 音频解码(秒懂)-CSDN博客

SDL2 播放音频数据(PCM)-CSDN博客

SDL2 消息循环和事件响应-CSDN博客 

SDL2 播放视频文件(MP4)-CSDN博客 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/197019.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pytorch torch.dot、torch.mv、torch.mm、torch.norm的用法详解

torch.dot的用法&#xff1a; 使用numpy求点积&#xff0c;对于二维的且一个二维的维数为1 torch.mv的用法&#xff1a; torch.mm的用法 torch.norm 名词解释&#xff1a;L2范数也就是向量的模&#xff0c;L1范数就是各个元素的绝对值之和例如&#xff1a;

报道 | 2023年12月-2024年2月国际运筹优化会议汇总

2023年12月-2024年2月召开会议汇总&#xff1a; The 16th Annual International Conference on Combinatorial Optimization and Applications (COCOA 2023) Location: Virtual Important dates: Conference: December 11, 2023 (Start) - December 13, 2023 (End) Details…

Java中如何通过路径表达式找值:XPath和JsonPath以及SpEL详解及对比

大家好&#xff0c;我是G探险者。 我们编程时&#xff0c;在前后端数据交互和传输过程中&#xff0c;往往需要对报文中的某个字段或者某个标签的值进行解析读取&#xff0c;报文通常是以json或者xml作为数据交换格式&#xff0c;而json和xml这两种格式的报文结构都是具备一定的…

基于SSM+Vue的校园共享单车管理系统

基于SSMVue的校园共享单车管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringMyBatisSpringMVC工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 登录界面 管理员界面 用户界面 摘要 随着城市交通的不断发展和人们出…

cesium 重点区域大屏展示效果(加载行政区划)

cesium 重点区域大屏展示效果(配色不太好看,主要看思路和方法) 1、实现思路(文张最后有**源码 **) 1、第一步将cesium背景调成透明关掉光照大气等效果相关属性都在“viewer.scene”中 2、第二步添加背景图片此背景图片直接用html加css就可以完成 3、第三步添加蒙版效果也…

Redis(哈希Hash和发布订阅模式)

哈希是一个字符类型字段和值的映射表。 在Redis中&#xff0c;哈希是一种数据结构&#xff0c;用于存储键值对的集合。哈希可以理解为一个键值对的集合&#xff0c;其中每个键都对应一个值。哈希在Redis中的作用主要有以下几点&#xff1a; 1. 存储对象&#xff1a;哈希可以用…

大模型之十二十-中英双语开源大语言模型选型

从ChatGPT火爆出圈到现在纷纷开源的大语言模型&#xff0c;众多出入门的学习者以及跃跃欲试的公司不得不面临的是开源大语言模型的选型问题。 基于开源商业许可的开源大语言模型可以极大的节省成本和加速业务迭代。 当前&#xff08;2023年11月17日)开源的大语言模型如下&#…

vue3+webpack+elementplus+国际化+axios封装+pinia

文章目录 创建项目 eslint prettier切换pinia&#xff08;后补上&#xff09;创建项目eslint prettier注意 自动格式化 element plus注意 element plus icon注意&#xff1a; 国际化注意 axios 封装 最近菜鸟自己搭建一个项目&#xff0c;想着 vue3 都出来这么久了&#xff…

HarmonyOS开发Java与ArkTS如何抉择

在“鸿蒙系统实战短视频App 从0到1掌握HarmonyOS”视频课程中&#xff0c;很多学员来问我&#xff0c;在HarmonyOS开发过程中&#xff0c;面对Java与ArkTS&#xff0c;应该选哪样&#xff1f; 本文详细分析Java与ArkTS在HarmonyOS开发过程的区别&#xff0c;力求解答学员的一些…

<MySQL> 什么是JDBC?如何使用JDBC进行编程?

目录 一、JDBC是什么&#xff1f; 二、JDBC常用接口和类 2.1 DataSource 2.2 Connection 2.3 Statement 2.4 ResultSet 三、JDBC的使用 3.1 获得数据库驱动包 3.2 添加到项目依赖 3.3 描述数据库服务器 3.4 建立数据库连接 3.6 执行SQL语句和接收返回数据 3.7 释放…

搭建内部知识库,解决企业内部琐碎信息问题

企业内部面临着大量琐碎的信息&#xff0c;这些信息可能分散在各个部门、员工之间&#xff0c;导致查找和共享变得困难。这种情况下&#xff0c;搭建一个内部知识库可以解决这一问题。通过内部知识库&#xff0c;企业可以将琐碎的信息整理、分类&#xff0c;并提供一个集中存储…

python之使用深度学习创建自己的表情符号

目录 部署项目1、首先运行train.py训练模型2、接下运行gui.py测试 一、使用 CNN 进行面部情绪识别二、GUI 代码和表情符号映射 在这个深度学习项目中&#xff0c;我们将对人类面部表情进行分类&#xff0c;以过滤和映射相应的表情符号或头像。 数据集&#xff08;面部表情识别&…

【ARM Trace32(劳特巴赫) 使用介绍 5 -- Trace32 scan dump 详细介绍】

文章目录 1.1 JTAG 测试逻辑架构1.2 D型扫描触发器1.2.1 全扫描介绍1.3 IR 寄存器1.4 TDR(Test data registers)1.4.1 TDR 的实现1.4.1.1 Bypass Register1.4.1.2 Boundary-scan register1.5 Scan Dump1.5.1 soft fusion1.1 JTAG 测试逻辑架构 图 1-1 片上测试逻辑概念图 如前面…

基于STM32的多组外部中断(EXTI)的优化策略与应用

在某些嵌入式应用中&#xff0c;可能需要同时处理多个外部中断事件。STM32系列微控制器提供了多组外部中断线&#xff08;EXTI Line&#xff09;&#xff0c;可以同时配置和使用多个GPIO引脚作为外部中断触发器。为了有效管理和处理多组外部中断&#xff0c;我们可以采取一些优…

(带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程

源码简介&#xff1a; 1、会员管理&#xff1a; 该系统分为三个级别的会员流程&#xff1a;总站管理员、代理与会员&#xff08;会员有普通会员、中级会员和高级会员三个等级&#xff09;。总站管理员可以添加代理用户并为其充值余额&#xff0c;代理用户可以为普通用户充值余…

zookeperkafka学习

1、why kafka 优点 缺点kafka 吞吐量高&#xff0c;对批处理和异步处理做了大量的设计&#xff0c;因此Kafka可以得到非常高的性能。延迟也会高&#xff0c;不适合电商场景。RabbitMQ 如果有大量消息堆积在队列中&#xff0c;性能会急剧下降每秒处理几万到几十万的消息。如果…

若依框架数据源切换为pg库

一 切换数据源 在ruoyi-admin项目里引入pg数据库驱动 <dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>42.2.18</version> </dependency>修改配置文件里的数据源为pg spring:d…

交通 | 神奇动物在哪里?Operations Research经典文章

论文作者&#xff1a;Robert G. Haight, Charles S. Revelle, Stephanie A. Snyder​ 论文原文&#xff1a;Robert G. Haight, Charles S. Revelle, Stephanie A. Snyder, (2000) An Integer Optimization Approach to a Probabilistic Reserve Site Selection Problem. Operat…

解决java在idea运行正常,但是打成jar包后中文乱码问题

目录 比如&#xff1a; 打包命令使用utf-8编码&#xff1a; 1.当在idea中编写的程序,运行一切正常.但是当被打成jar包时,执行的程序会中文乱码.产生问题的原因和解决方案是什么呢? 一.问题分析 分别使用idea和jar包形式打印出System中所有的jvm参数---代码如下: public static…

H5ke11--1登录界面一直保存--用本地localStorage存储

目录 代码详解 localStage优点 :一直保存着 注意事项: storage属性们 代码详解 ke8学校陈老师H5-CSDN博客文章浏览阅读76次。实现H5中新增的三个元素&#xff1a;forEach的使用方法。https://blog.csdn.net/m0_72735063/article/details/134019012即此之后 当然可以分为按…