简介

这里实现了一个简单的纯语音播放器,其数据流图如下

图中已经表述的很清楚了,解复用、解码、重采样都通过ffmpeg完成,而播放则由SDL完成。其中解复用、解码和重采样部分可以参看ffmpeg给出的示例文件(解复用和解码可参考demuxing_decoding.c,重采样可参考resampling_audio.c)。

由于SDL并不能完全支持所有的语音数据存储格式,因此这里需要将ffmpeg解码出来的语音数据存储格式通过重采样转化为SDL支持的数据存储格式。


头文件

解复用需要用到libavformat库,解码需要用到libavcodec库,而重采样需要用到libswresamplelibavutil库,播放需要用到SDL库,关于ffmpeg+SDL工程的配置可以参考之前写过的一篇文章 。

由于这里创建了main.cpp源文件,而ffmpeg是用C写的,因此在包含头文件时要做些处理

#include <iostream>#ifdef __cplusplus
extern "C" {
#endif#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libswresample/swresample.h>#ifdef __cplusplus
}
#endif
#include <SDL.h>
using namespace std;

源码

#include <iostream>#ifdef __cplusplus
extern "C" {
#endif#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libswresample/swresample.h>#ifdef __cplusplus
}
#endif
#include <SDL.h>
using namespace std;
#define USER_40MS_FRESH (SDL_USEREVENT + 1)static  Uint8* g_audio_chunk;
static  Uint32 g_audio_len;
static  Uint8* g_audio_pos;//-- 语音播放回调函数
void AudioPlay(void* udata, Uint8* stream, int len) {SDL_memset(stream, 0, len);/*  Only  play  if  we  have  data  left  */if (g_audio_len == 0)return;/*  Mix  as  much  data  as  possible  */len = (len > g_audio_len ? g_audio_len : len);SDL_MixAudio(stream, g_audio_pos, len, SDL_MIX_MAXVOLUME);g_audio_pos += len;g_audio_len -= len;
}
//-- 解码器初始化函数
int InitCodec(AVFormatContext* fmt_ctx, AVMediaType type, AVCodecContext*& dec_ctx, AVStream*& videoStream, int& streamIdx)
{int ret = 0;const AVCodec* dec = NULL;//-- 查找指定媒体流信息streamIdx = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);if (streamIdx < 0){cout << "find stream error!" << endl;return -1;}videoStream = fmt_ctx->streams[streamIdx];//-- 获取解码器dec = avcodec_find_decoder(videoStream->codecpar->codec_id);if (dec == NULL){cout << "find decoder error!" << endl;return -1;}//-- 创建解码器dec_ctx = avcodec_alloc_context3(dec);if (dec_ctx == NULL){cout << "create decoder error!" << endl;return -1;}//-- 配置解码器ret = avcodec_parameters_to_context(dec_ctx, videoStream->codecpar);if (ret < 0){cout << "config decoder failure!" << endl;return -1;}//--- 打开解码器ret = avcodec_open2(dec_ctx, dec, NULL);if (ret != 0){cout << "open decoder error!" << endl;return -1;}return 1;}
int main(int argc, char** argv)
{//-- 解码解复用AVFormatContext* fmt_ctx = NULL;AVCodecContext* audio_dec_ctx = NULL;int audio_stream_id = -1;AVStream* audio_stream = NULL;AVCodec* dec = NULL;AVPacket* pkt = NULL;AVFrame* frame = NULL;//-- 重采样相关SwrContext* resample_context = NULL;int out_linesize;int out_buffer_size;uint8_t* out_buffer = NULL;const char* fileName;if (argc != 2){cout << "The number if input parameter error" << endl;return 1;}fileName = argv[1];//-- 打开文件,并初始化fmt_ctxavformat_open_input(&fmt_ctx, fileName, NULL, NULL);//-- 读取流信息avformat_find_stream_info(fmt_ctx, NULL);//-- 打印流信息av_dump_format(fmt_ctx, 0, fileName, 0);//-- 初始化编码InitCodec(fmt_ctx, AVMEDIA_TYPE_AUDIO, audio_dec_ctx, audio_stream, audio_stream_id);//-- 获取数据存储空间大小out_buffer_size = av_samples_get_buffer_size(&out_linesize, audio_dec_ctx->channels, audio_dec_ctx->frame_size, audio_dec_ctx->sample_fmt, 1);//-- 分配重采样后的数据存储空间out_buffer = new uint8_t[out_buffer_size];//-- 设置重采样参数resample_context = swr_alloc_set_opts(NULL, audio_dec_ctx->channel_layout, AV_SAMPLE_FMT_S16, audio_dec_ctx->sample_rate,audio_dec_ctx->channel_layout, audio_dec_ctx->sample_fmt, audio_dec_ctx->sample_rate, 0, NULL);//-- 初始化重采样对象swr_init(resample_context);//-- 初始化SDLSDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER);//-- 设置SDL语音播放参数SDL_AudioSpec spec;spec.freq = audio_dec_ctx->sample_rate;spec.samples = audio_dec_ctx->frame_size;spec.format = AUDIO_S16SYS;spec.channels = 2;spec.silence = 0;spec.userdata = audio_dec_ctx;spec.callback = AudioPlay; //-- 设置语音播放回调函数,用于SDL读取播放数据//-- 打开SDL语音播放器if (SDL_OpenAudio(&spec, NULL) < 0){return 1;}//-- 分配包空间和帧空间frame = av_frame_alloc();pkt = av_packet_alloc();//-- 主循环while (av_read_frame(fmt_ctx, pkt) >= 0){//-- 筛选语音包if (pkt->stream_index == audio_stream_id){//-- 将语音包发送到解码器avcodec_send_packet(audio_dec_ctx, pkt);//-- 读取解码帧while (avcodec_receive_frame(audio_dec_ctx, frame) >= 0){//-- 语音重采样swr_convert(resample_context, &out_buffer, out_linesize, (const uint8_t**)frame->extended_data, frame->nb_samples);//-- 记录播放数据的长度、记录数据存储的首地址g_audio_chunk = out_buffer;g_audio_len = out_linesize;g_audio_pos = g_audio_chunk;//-- 播放语音SDL_PauseAudio(0);//-- 等待当前帧的语音数据播放完毕while (g_audio_len > 0){SDL_Delay(1);}av_frame_unref(frame);}av_frame_unref(frame);}av_packet_unref(pkt);}//-- 释放资源SDL_CloseAudio(); av_frame_unref(frame);av_packet_unref(pkt);delete[] out_buffer;swr_free(&resample_context);avcodec_free_context(&audio_dec_ctx);avformat_close_input(&fmt_ctx);av_frame_free(&frame);av_packet_free(&pkt);return 0;
}

输入参数配置

FFmpeg+SDL纯语音播放器相关推荐

  1. 最简单的基于FFMPEG+SDL的音频播放器

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  2. 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  3. 最简单的基于FFMPEG SDL的音频播放器

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! ==== ...

  4. 最简单的基于FFMPEG+SDL的音频播放器:拆分-解码器和播放器

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  5. 最简单的基于FFMPEG+SDL的音频播放器 拆分-解码器和播放器

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  6. 如何用FFmpeg编写一个简单播放器详细步骤介绍

    如何用FFmpeg编写一个简单播放器详细步骤介绍(转载) FFMPEG是一个很好的库,可以用来创建视频应用或者生成特定的工具.FFMPEG几乎为你把所有的繁重工作都做了,比如解码.编码.复用和解复用. ...

  7. 如何用 FFmpeg 编写一个简单播放器.pdf

    An ffmpeg and SDL Tutorial.pdf 如何用 FFmpeg 编写一个简单播放器.pdf 中文版

  8. 多功能语音播放器上线啦~

    应广大学生反映,学程序不会读单词,留言问我能不能做个语音播放器,就是能输入英文能读出来的那种!! 为了帮助公众号里面仅有的几百粉丝,我就顺手写一个吧,万一还能增加点粉丝呢? 于是经过一番奋斗,一款名为 ...

  9. HaaS100 云端钉一体智能语音播放器设计

    1.方案介绍 本文主要介绍如何基于HaaS100硬件平台搭建"云端钉一体"(阿里云IoT平台 + HaaS100 + 钉钉小程序)的智能语音播放器(以下简称智能语音播放器).该智能 ...

  10. [模拟拖拽] 模拟将一个文件拖拽到一个软件窗口上,实现拖拽操作(微信语音播放器)...

    "金蛇语音播放器" 是我随便写的一个假名.要实现的功能是: 我在网上下载了一个播放器,在自己公司的软件中使用,用来播放微信的语音. 因为版权问题,我不想让别人知道我用的是金蛇播放器 ...

最新文章

  1. Cocos 物理系统
  2. unity开发小贴士之八 Audio使用心得
  3. 阿里某程序员吐槽:年终奖被金融行业的老婆完爆!自己奖金15万,老婆奖金66万!...
  4. frdora10_a8_linux,在Fedora 10中安装IRAF
  5. 在WinForm应用程序中嵌入WPF控件(转)
  6. 你对博客中提到的评分规则有何意见和建议?
  7. 【BZOJ2118】墨墨的等式【循环节做法】
  8. (转)KMP的next数组模板
  9. 数据可视化课程_在这个由10部分组成的免费数据可视化课程中学习D3
  10. 全球最大地标识别数据集问世:包含200万张图片和3万处地标
  11. 使用pdfbox将多个pdf合成一个pdf
  12. html打印多了空白页,为什么打印Word文档会多打印出一空白页
  13. U盘容量变小了 -恢复U盘实际容量教程(亲试有效)
  14. 青光眼 程序员_青光眼-如何不失明:让我们谈谈治疗方法…
  15. 面对复杂问题时,系统思考助你理解问题本质
  16. java以某个字符串断句_结合 ictclass4j 和 KTDictSeg 写自己的分词器----断句(1)
  17. 一加 Ace Pro怎么样?颜值性能它都有
  18. linux 访问西数网盘,西数不认盘,无法访问固件
  19. 将qq目录下文件写如qq.txt
  20. Opencv学习笔记——视频进度条

热门文章

  1. email英文计算机求职信,求职信_计算机英文求职信
  2. 【SAR综述】复杂场景单通道SAR目标检测与鉴别方法
  3. android 缺半圆形头像,圆形头像设计
  4. Android流媒体播放器介绍
  5. 电脑里强力删除的文件如何恢复?
  6. 数据库程序中按关键字查询代码
  7. JEP 379:将低暂停时间的垃圾收集器Shenandoah推向生产
  8. iFunk翼只换不修强出新高度
  9. OpenGL ES 绘制纹理
  10. Linux修改文件出现错误E45:“readonly” option is set(add ! to override)退出不了vim