老调重弹之ffmpeg解码音频

接着之前的视频解码,在之前的基础上加上音频解码,还是使用SDL。

  1. 首先找到音频流 与找视频流时一样,在avformat_find_stream_info之后,遍历一下AVFormatContext中的streams,找到codecpar->codec_typeAVMEDIA_TYPE_AUDIO的索引。
else if(pformatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
audioStream = i;
}
  1. 打开解码器 与视频流时一样,创建一个AVCodecContext
paudiocodecContext = avcodec_alloc_context3(nullptr);
avcodec_parameters_to_context(paudiocodecContext, pformatContext->streams[audioStream]->codecpar);
paudiocodec = avcodec_find_decoder(paudiocodecContext->codec_id);
avcodec_open2(paudiocodecContext, paudiocodec, &opts);
  1. SDL打开音频 SDL打开音频设备时,需要提供一些关于音频的参数,如采样率、采样格式、通道数等。 但SDL实际使用时的参数可能与指定的不一样,因此需要把打开音频设备时返回的实际使用的参数保存下来,当解码出来的音频参数与设备使用的参数不一致时,需要进行转换。 另外,还需要提供一下回调函数,但SDL需要音频数据时,就会调用这个回调函数来获取数据。只是为了解码音频,所以简单地使用一个缓冲区直接顺序保存解码得到的音频数据,当SDL通过回调函数来取时,直接从这个缓冲区中读取。

  2. 解码音频数据 与视频时一样,通过av_read_frame从文件中读取packet后,通过packet中的stream_index可知道是音频还是视频。 当时音频时,通过函数avcodec_send_packet把packet发到解码器,通过avcodec_receive_frame读取解码的frame。对于音频,一个packet可能包含多个frame,因此需要多次调用avcodec_receive_frame

  3. 音频数据格式转换 音频流中的格式可能与需要的不一致,就要进行转换。 通过swr_alloc_set_opts分配一个转换时需要的上下文,然后swr_init进行初始化,再使用swr_convert进行转换。 尽可能简单,把转换后的数据直接放入缓冲区,等SDL通过回调来读取。

  4. 播放音频数据 SDL通过回调函数获得音频数据。直接从音频解码后放入的缓冲区中读取数据给SDL。

paudiocodecContext = avcodec_alloc_context3(nullptr);
avcodec_parameters_to_context(paudiocodecContext, pformatContext->streams[audioStream]->codecpar);
paudiocodec = avcodec_find_decoder(paudiocodecContext->codec_id);
avcodec_open2(paudiocodecContext, paudiocodec, &opts);SDL_AudioSpec wanted_spec, got_spec;
wanted_spec.freq = paudiocodecContext->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = paudiocodecContext->channels;
wanted_spec.silence = 0;
wanted_spec.samples = 1024;
wanted_spec.callback = audio_callback;
wanted_spec.userdata = nullptr;
if(SDL_OpenAudio(&wanted_spec, &got_spec) < 0)
{cerr << "SDL_OpenAudio fail:" << SDL_GetError() << endl;exit(1);
}
AVFrame audio_wanted_frame;
audio_wanted_frame.format = AV_SAMPLE_FMT_S16;
audio_wanted_frame.sample_rate = got_spec.freq;
audio_wanted_frame.channel_layout = av_get_default_channel_layout(got_spec.channels);
audio_wanted_frame.channels = got_spec.channels;SwrContext *pswrcontext = nullptr;uint8_t audio_buff[(192000 * 3) / 2];
uint8_t *paudio_buff = audio_buff;
int audio_buff_size = 0;//解码后的数据直接简单地放入这个buf中
g_audiobuf.cond = SDL_CreateCond();
g_audiobuf.mutex = SDL_CreateMutex();
g_audiobuf.buf.AllocateBuffer(SIZE_16M);SDL_PauseAudio(0);//读取到packet后,
else if(pkt.stream_index == audioStream)
{iret = avcodec_send_packet(paudiocodecContext, &pkt);for(;;){iret = avcodec_receive_frame(paudiocodecContext, pframe);if(iret == 0){pswrcontext = swr_alloc_set_opts(pswrcontext, audio_wanted_frame.channel_layout, (AVSampleFormat)audio_wanted_frame.format, audio_wanted_frame.sample_rate,pframe->channel_layout, (AVSampleFormat)pframe->format, pframe->sample_rate,0, nullptr);if (!pswrcontext || swr_init(pswrcontext) < 0){cerr << "swr_alloc_set_opts | swr_init fail." << endl;continue;}int dst_nb_samples = (int)av_rescale_rnd(swr_get_delay(pswrcontext, pframe->sample_rate) + pframe->nb_samples,audio_wanted_frame.sample_rate, audio_wanted_frame.format, AVRounding(1));int len2 = swr_convert(pswrcontext, &paudio_buff, dst_nb_samples, (const uint8_t**)pframe->data, pframe->nb_samples);audio_buff_size = audio_wanted_frame.channels * len2 * av_get_bytes_per_sample((AVSampleFormat)audio_wanted_frame.format);//放及取数据的这部分烂死for(;;){SDL_LockMutex(g_audiobuf.mutex);uInt32 ifree = g_audiobuf.buf.GetFree();if(ifree < audio_buff_size){SDL_CondSignal(g_audiobuf.cond);SDL_UnlockMutex(g_audiobuf.mutex);continue;}g_audiobuf.buf.Write(paudio_buff, audio_buff_size);SDL_UnlockMutex(g_audiobuf.mutex);break;}}else{break;}}
}
//SDL音频回调函数
static void audio_callback(void *userdata, Uint8* stream, int len)
{memset(stream, 0, len);if(bquit)return;//放及取数据的这部分烂死SDL_LockMutex(g_audiobuf.mutex);while(!bquit){uInt32 idata = g_audiobuf.buf.GetSize();if(idata < len){SDL_CondWait(g_audiobuf.cond, g_audiobuf.mutex);}else{break;}}g_audiobuf.buf.Read(stream, len);SDL_UnlockMutex(g_audiobuf.mutex);
}

转载于:https://my.oschina.net/u/2286208/blog/752948

老调重弹之ffmpeg解码音频相关推荐

  1. ffmpeg 解码音频(aac、mp3)输出pcm文件

    ffmpeg 解码音频(aac.mp3)输出pcm文件 播放pcm可以参考: ffplay -ar 48000 -ac 2 -f f32le out.pcm main.c #include <s ...

  2. 使用ffmpeg解码音频sdl(push)播放

    自定义播放器系列 第一章 视频渲染 第二章 音频(push)播放(本章) 第三章 音频(pull)播放 第四章 实现时钟同步 第五章 实现通用时钟同步 第六章 实现播放器 文章目录 自定义播放器系列 ...

  3. FFmpeg开发笔记(七):ffmpeg解码音频保存为PCM并使用软件播放

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108799279 各位读者,知识无穷而人力有穷 ...

  4. FFmpeg解码音频代码

    工程请访问DecodeTest.用c++写的,使用FFmpeg-4.1.0.比较完善的是OfficalDecodeAudio.cpp,它是我研究了一下ffplay.c的源码得来的.该代码按照统一的44 ...

  5. FFmpeg进行音频的解码和播放

    音频编码 音频数字化主要有压缩与非压缩(pcm)两种方式. 非压缩编码(PCM)PCM音频编码 PCM通过抽样.量化.编码三个步骤将连续变化的模拟信号转换为数字编码. 当采样频率fs.max大于信号中 ...

  6. iOS 音视频开发:Audio Unit播放FFmpeg解码的音频

    本文档描述了iOS播放经FFmpeg解码的音频数据的编程步骤,具体基于Audio Toolbox框架的Audio Session和Audio Unit框架提供的接口实现.在iOS 7及以上平台Audi ...

  7. ffmpeg 找不到bin_FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/109603499 各位读者,知识无穷而人力有穷 ...

  8. FFMPEG视音频编解码学习(1)

    ###开篇 看过了FFMPEG视音频编解码的基础知识,接着还有许多比如制作一个基于FFMPEG的视频播放器等,但是好像比较抽象,而且在公司的mac上很多软件也没有(重点是看的一头雾水), 还是老老实实 ...

  9. [总结]FFMPEG视音频编解码零基础学习方法--转

    ffmpeg编解码学习 目录(?)[-] ffmpeg程序的使用ffmpegexeffplayexeffprobeexe 1 ffmpegexe 2 ffplayexe 3 ffprobeexe ff ...

最新文章

  1. win7 python3环境变量设置_如何配置python3的环境变量
  2. 【CV冬季划】终极进阶,超30个项目实战+3本书+3年知识星球
  3. 設備(IE01/IE02/IE03)客製欄位及BAPI處理
  4. java spring mvc 上传_Java Spring MVC 上传下载文件配置及controller方法详解
  5. 【IT笔试面试题整理】堆栈和队列
  6. 【转】3.2SharePoint服务器端对象模型 之 访问文件和文件夹(Part 2)
  7. AC_Dream 1211 Reactor Cooling
  8. 帝国CMS7.2阿里大于云短信插件(UTF-8)
  9. 记一次由PCI BAR配置不正确引发的硬盘IO调度io_schedule阻塞的经历
  10. 网页ui设计模板素材|液体流动效果!
  11. 奥特曼在银行里下象棋的梗
  12. bootdo 重命名 版本2.0 (适合所有springboot项目)
  13. 初学python------写一个心理测试
  14. 作为iOS开发者,你不可错过的资源
  15. 分析亚洲手机游戏市场现状--中国篇、韩国篇以及日本篇
  16. Redhat最小化安装后安装图形界面步骤
  17. Mapguide配置心得
  18. HBase读数据和写数据流程
  19. 泛目录程序-泛目录站群程序-免费泛目录站群管理工具下载
  20. Windows phone 8 JumpStart--Async

热门文章

  1. 如何将D盘分区为多个磁盘(E盘,F盘等)window 10
  2. 试题 算法训练 车的放置(蓝桥杯c++)
  3. 宏观与微观的一秒改变
  4. 计算机系男生横幅,男生节标语横幅
  5. 卡顿老笔记本换新颜--增加内存条(内存条如何选购终极总结)
  6. 并发编程-25 高并发处理手段之消息队列思路 + 应用拆分思路 + 应用限流思路
  7. 大型C++网络游戏开发视频教程
  8. panda3d 键盘移动场景
  9. 给女朋友写的h5(移动端)小游戏,超简单
  10. 米公益完结项目结项反馈——环保梦想,你我一同点亮