当前位置: 首页 > news >正文

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博客 

相关文章:

SDL2 播放音频(MP4)

1.简介 这里引入FFmpeg库&#xff0c;获取音频流数据&#xff0c;然后通过FFmpeg将视频流解码成pcm原始数据&#xff0c;再将pcm数据送入到SDL库中实现音频播放。 2.FFmpeg的操作流程 注册API&#xff1a;av_register_all()构建输入AVFormatContext上下文&#xff1a;avform…...

WMS仓库管理系统库位功能

后端 &#xfeff;using Infrastructure.Attribute; using Model.Dto.WarehouseManagement; using Model.Page; using Model.WarehouseManagement; using Repository; using Service.Interface.WarehouseManagement; using SqlSugar;namespace Service.WarehouseManagement {[…...

vue2组件通信中的一些拓展(props,emit,ref父子双向传参)

说明 我上一篇文章中基本对vue所有的数据通信方法进行了一个整理归纳。 其实我并没有像传统的那样去罗列,比如父传子有props,ref,子传父为emit,兄弟用$bus等等。 因为在我的实际练习和业务开发中,props,emit,ref等可以实现父子数据互传,这里就涉及一个比较重要的编程思维,函…...

Flink1.17 DataStream API

目录 一.执行环境&#xff08;Execution Environment&#xff09; 1.1 创建执行环境 1.2 执行模式 1.3 触发程序执行 二.源算子&#xff08;Source&#xff09; 2.1 从集合中读取数据 2.2 从文件读取数据 2.3 从 RabbitMQ 中读取数据 2.4 从数据生成器读取数据 2.5 …...

数据结构中树、森林 与 二叉树的转换

1 树转换为 二叉树 将树转换成二叉树的步骤是&#xff1a; 加线。在所有的兄弟结点之间加一条线。去线。对于树中的每个结点&#xff0c;只保留它与第一个孩子结点的连线&#xff0c;删除该结点其他孩子结点之间的连线。调整。以树的根结点为轴心&#xff0c;将整个树顺时针旋…...

力扣labuladong——一刷day43

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣257. 二叉树的所有路径二、力扣129. 求根节点到叶节点数字之和三、力扣199. 二叉树的右视图四、力扣662. 二叉树最大宽度 前言 一般来说&#xff0c;如…...

MapApp 地图应用

1. 简述 1.1 重点 1&#xff09;更好地理解 MVVM 架构 2&#xff09;更轻松地使用 SwiftUI 框架、对齐、动画和转换 1.2 资源下载地址: Swiftful-Thinking:https://www.swiftful-thinking.com/downloads 1.3 项目结构图: 1.4 图片、颜色资源文件图: 1.5 启动图片配置图: 2. Mo…...

Java之反射获取和赋值字段

在Java中&#xff0c;反射能够使得代码更加通用&#xff0c;往往用于工具类中。 但常常我们在获取或者赋值反射的属性时&#xff0c;会出现没有赋值成功的结果&#xff0c;往往是由于这个属性在父级中而导致的&#xff0c;这个时候我们就不能用getDeclaredField方法单独获取字段…...

ckplayer自己定义风格播放器的开发记录

CKplayer是一款基于Flash和HTML5技术的开源视频播放器&#xff0c;支持多种格式的音视频播放&#xff0c;并且具有优秀的兼容性和扩展性。 它不仅可以在网页上播放本地或者网络上的视频&#xff0c;还可以通过代码嵌入到网页中&#xff0c;实现更加个性化的播放效果。CKplayer…...

全网最全Django面试题整理(一)

Django 中的 MTV 是什么意思&#xff1f; 在Django中&#xff0c;MTV指的是“Model-Template-View”&#xff0c;而不是常见的MVC&#xff08;Model-View-Controller&#xff09;架构。Django的设计理念是基于MTV的 Model&#xff08;模型&#xff09; 模型代表数据存取层&am…...

vue统一登录

说明&#xff1a; 统一登录其实就是前端去判断Url地址的token 之后如果有token未过期就直接跳转到首页。 说到浏览器输入url地址&#xff0c;那从浏览器输入地址一共发生了几件事大致如下&#xff1a; DNS解析域名&#xff0c;获取IP地址 --》 建立TCP连接&#xff08;三次握…...

MVSNet论文笔记

MVSNet论文笔记 摘要1 引言2 相关基础2.1 多视图立体视觉重建&#xff08;MVS Reconstruction&#xff09;2.2 基于学习的立体视觉&#xff08;Learned Stereo&#xff09;2.3 基于学习的多视图的立体视觉&#xff08;Learned MVS&#xff09; 3 MVSNet3.1 网络架构3.2 提取图片…...

大型 APP 的性能优化思路

做客户端开发都基本都做过性能优化&#xff0c;比如提升自己所负责的业务的速度或流畅性&#xff0c;优化内存占用等等。但是大部分开发者所做的性能优化可能都是针对中小型 APP 的&#xff0c;大型 APP 的性能优化经验并不会太多&#xff0c;毕竟大型 APP 就只有那么几个&…...

K8S配置资源管理

这里写目录标题 K8S配置资源管理一.Secret1.介绍2.Secret 有四种类型3.创建 Secret4.使用方式 二.ConfigMap1.介绍2.创建 ConfigMap3.Pod 中使用 ConfigMap4.用 ConfigMap 设置命令行参数5.通过数据卷插件使用ConfigMap6.ConfigMap 的热更新7.ConfigMap 更新后滚动更新 Pod K8S…...

Redis 的集群模式实现高可用

来源&#xff1a;Redis高可用&#xff1a;武林秘籍存在集群里&#xff0c;那稳了~ (qq.com) 1. 引言 前面我们已经聊过 Redis 的主从同步&#xff08;复制&#xff09;和哨兵机制&#xff0c;这期我们来聊 Redis 的集群模式。 但是在超大规模的互联网应用中&#xff0c;业务规…...

21、嵌套路由实战操作

1、创建内嵌子路由&#xff0c;你需要添加一个vue文件&#xff0c;同时添加一个与该文件同名的目录用来存放子视图组件。 2、在父组件&#xff08;.vue&#xff09;内增加用于显示子视图内容 新建文件 pages\index_id.vue 生成的对应路由 {path: "/",component: _…...

WPF 控件的缩放和移动

WPF 控件的缩放和移动 1.页面代码 <ContentControl ClipToBounds"True" Cursor"SizeAll"><Viewboxx:Name"viewbox"MouseDown"viewbox_MouseDown"MouseMove"viewbox_MouseMove"MouseWheel"Viewbox_MouseWhee…...

Python and和or的优先级实例比较

Python and和or的优先级 and和or都是Python的逻辑运算符&#xff0c;都为保留字。通常情况下&#xff0c;在没有括号影响&#xff0c;and和or的优先级中and在代码的逻辑运算过程中会相对优先一些&#xff0c;及在同一行的Python代码中&#xff0c;and会优先与or执行。下面将通…...

数据结构与算法编程题2

逆置线性表&#xff0c;使空间复杂度为 O(1) #include <iostream> using namespace std;typedef int ElemType; #define Maxsize 100 #define OK 1 #define ERROR 0 typedef struct SqList {ElemType data[Maxsize];int length; }SqList;void Init_SqList(SqList& …...

Java开发者的Python快速进修指南:控制之if-else和循环技巧

简单介绍 在我们今天的学习中&#xff0c;让我们简要了解一下Python的控制流程。考虑到我们作为有着丰富Java开发经验的程序员&#xff0c;我们将跳过一些基础概念&#xff0c;如变量和数据类型。如果遇到不熟悉的内容&#xff0c;可以随时查阅文档。但在编写程序或逻辑时&…...

智能提取B站字幕:告别手动抄录的高效开源工具

智能提取B站字幕&#xff1a;告别手动抄录的高效开源工具 【免费下载链接】BiliBiliCCSubtitle 一个用于下载B站(哔哩哔哩)CC字幕及转换的工具; 项目地址: https://gitcode.com/gh_mirrors/bi/BiliBiliCCSubtitle 还在为手动记录B站视频字幕而烦恼&#xff1f;BiliBiliC…...

7个实用技巧让Continue AI编程助手提升开发效率

7个实用技巧让Continue AI编程助手提升开发效率 【免费下载链接】continue ⏩ Source-controlled AI checks, enforceable in CI. Powered by the open-source Continue CLI 项目地址: https://gitcode.com/GitHub_Trending/co/continue 在当今快节奏的开发环境中&#…...

肿瘤免疫微环境解析:8大免疫浸润工具实战指南

1. 肿瘤免疫微环境分析的核心价值 当你拿到一份肿瘤样本的转录组数据时&#xff0c;最令人兴奋的莫过于揭开它的免疫面纱——那些隐藏在肿瘤组织中的免疫细胞究竟在做什么&#xff1f;这就是免疫浸润分析的价值所在。想象一下&#xff0c;肿瘤组织就像一座复杂的城市&#xff0…...

耦合详解-模块

耦合详解 耦合(Coupling)是衡量软件模块之间相互依赖程度的指标。低耦合是优秀软件设计的核心目标之一,它使系统更易于维护、测试和扩展。 1. 耦合的本质 耦合描述的是两个模块(类、组件、服务)之间的依赖关系强度。当修改一个模块时,需要修改其他模块的程度越高,耦合…...

避开生产计划大坑:不懂MPS和MRP的区别,你的SAP PP模块白学了

避开生产计划大坑&#xff1a;不懂MPS和MRP的区别&#xff0c;你的SAP PP模块白学了 在制造业数字化转型的浪潮中&#xff0c;SAP PP模块作为生产计划的核心枢纽&#xff0c;常常成为企业运营的"隐形战场"。许多实施顾问和计划专员在MD41和MD02这两个相似的事务码前陷…...

如何将笔记从 iCloud 传输到 iPhone:分步指南

iPhone 上的“备忘录”应用是一款便捷的工具&#xff0c;可以用来记录待办事项、日记、想法等等。它能帮助我们追踪需要完成的事情。借助 iCloud 的自动同步功能&#xff0c;你的备忘录可以安全地存储在云端&#xff0c;并可通过任何 Apple 设备甚至电脑访问。将笔记从 iPhone …...

Git从入门到精通:完整学习路线图,全面详细一次过

Git超详细使用教程&#xff1a;从入门到高级&#xff08;全面详解&#xff5c;目录结构&#xff5c;口语化专业双轨&#xff5c;长文警告&#xff09; ⚠️ 长文警告&#xff1a;全文共 6218 字&#xff0c;覆盖 Git 全生命周期操作&#xff0c;含 18 个核心章节、7 张结构化对…...

为什么选全屋定制,不买成品柜

1&#xff09;为什么选全屋定制&#xff0c;不买成品柜&#xff1f;​ 成品柜尺寸固定&#xff0c;苏州很多户型飘窗、梁位、管道多&#xff0c;放进去丑、浪费空间&#xff01;我们定制严丝合缝&#xff0c;顶天立地&#xff0c;收纳多 30%&#xff0c;颜值统一&#xff0c;和…...

Intv_AI_MK11嵌入式开发实战:在WSL2中部署AI模型并集成Keil5

Intv_AI_MK11嵌入式开发实战&#xff1a;在WSL2中部署AI模型并集成Keil5 1. 为什么选择WSL2进行嵌入式AI开发 对于嵌入式开发者来说&#xff0c;传统AI模型开发面临一个典型困境&#xff1a;训练环境通常基于Linux系统&#xff0c;而嵌入式开发工具链&#xff08;如Keil MDK&…...

DriverStore Explorer:突破Windows驱动管理瓶颈,释放系统空间提升80%存储效率

DriverStore Explorer&#xff1a;突破Windows驱动管理瓶颈&#xff0c;释放系统空间提升80%存储效率 【免费下载链接】DriverStoreExplorer Driver Store Explorer [RAPR] 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 诊断存储异常&#xff1a;设…...