ffplay音频的波谱图及频谱图源码分析

当ffplay指定启动参数-showmode [0/1/2]时,值为0,正常播放(默认);值为1,显示波形;值为2,显示频谱图。

在ffplay中由show_mode变量控制显示方式取值分别为:SHOW_MODE_VIDEO/SHOW_MODE_WAVES/SHOW_MODE_RDFT

在函数video_display(…)中判断是否有音频流并且show_mode不等于SHOW_MODE_VIDEO,如果成立调用函数video_audio_display(…)
进行波谱或频谱显示

下面详细分析video_audio_display(…)

static void video_audio_display(VideoState *s)
{int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;int ch, channels, h, h2;int64_t time_diff;int rdft_bits, nb_freq;//计算离散傅里叶变换输入数组的长度log2的值,绘制频谱时使用双通道,并且填充显示区域高度for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++);nb_freq = 1 << (rdft_bits - 1);/* compute display index : center on currently output samples */channels = s->audio_tgt.channels;nb_display_channels = channels;if (!s->paused) {//该语句块计算当前波/频谱图显示音频数据的开始索引int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);n = 2 * channels;delay = s->audio_write_buf_size;delay /= n;/* to be more precise, we take into account the time spent sincethe last buffer computation */if (audio_callback_time) {time_diff = av_gettime_relative() - audio_callback_time;delay -= (time_diff * s->audio_tgt.freq) / 1000000;}delay += 2 * data_used;if (delay < data_used)delay = data_used;i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);if (s->show_mode == SHOW_MODE_WAVES) {//如果为波谱图查找振幅变化最大的音频部分数据的索引h = INT_MIN;for (i = 0; i < 1000; i += channels) {int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;int a = s->sample_array[idx];int b = s->sample_array[(idx + 4 * channels) % SAMPLE_ARRAY_SIZE];int c = s->sample_array[(idx + 5 * channels) % SAMPLE_ARRAY_SIZE];int d = s->sample_array[(idx + 9 * channels) % SAMPLE_ARRAY_SIZE];int score = a - d;if (h < score && (b ^ c) < 0) {h = score;i_start = idx;}}}s->last_i_start = i_start;} else {i_start = s->last_i_start;}if (s->show_mode == SHOW_MODE_WAVES) {//设置颜色为白色SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);/* total height for one channel */h = s->height / nb_display_channels;//每一个通道波谱显示区域占有的高度/* graph height / 2 */h2 = (h * 9) / 20;for (ch = 0; ch < nb_display_channels; ch++) {i = i_start + ch;y1 = s->ytop + ch * h + (h / 2); /* position of center line */for (x = 0; x < s->width; x++) {y = (s->sample_array[i] * h2) >> 15;//y的绝对值一定小于hif (y < 0) {y = -y;ys = y1 - y;} else {ys = y1;}fill_rectangle(s->xleft + x, ys, 1, y);//绘制高度为1的矩形i += channels;if (i >= SAMPLE_ARRAY_SIZE)i -= SAMPLE_ARRAY_SIZE;}}SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);//绘制不同声道波谱图的分割线for (ch = 1; ch < nb_display_channels; ch++) {y = s->ytop + ch * h;fill_rectangle(s->xleft, y, s->width, 1);}} else {if (realloc_texture(&s->vis_texture, SDL_PIXELFORMAT_ARGB8888, s->width, s->height, SDL_BLENDMODE_NONE, 1) < 0)return;nb_display_channels= FFMIN(nb_display_channels, 2);//显示最多2声道的频谱图if (rdft_bits != s->rdft_bits) {av_rdft_end(s->rdft);av_free(s->rdft_data);s->rdft = av_rdft_init(rdft_bits, DFT_R2C);//初始化离散傅里叶变换的Contexts->rdft_bits = rdft_bits;s->rdft_data = av_malloc_array(nb_freq, 4 *sizeof(*s->rdft_data));//双声道,每一通道的输入数组大小为2*nb_freq}if (!s->rdft || !s->rdft_data){av_log(NULL, AV_LOG_ERROR, "Failed to allocate buffers for RDFT, switching to waves display\n");s->show_mode = SHOW_MODE_WAVES;} else {FFTSample *data[2];SDL_Rect rect = {.x = s->xpos, .y = 0, .w = 1, .h = s->height};uint32_t *pixels;int pitch;for (ch = 0; ch < nb_display_channels; ch++) {data[ch] = s->rdft_data + 2 * nb_freq * ch;i = i_start + ch;for (x = 0; x < 2 * nb_freq; x++) {double w = (x-nb_freq) * (1.0 / nb_freq);data[ch][x] = s->sample_array[i] * (1.0 - w * w);//减小了音频值,为何这样处理??i += channels;if (i >= SAMPLE_ARRAY_SIZE)i -= SAMPLE_ARRAY_SIZE;}av_rdft_calc(s->rdft, data[ch]);//进行离散傅里叶变换}/* Least efficient way to do this, we should of course* directly access it but it is more than fast enough. */if (!SDL_LockTexture(s->vis_texture, &rect, (void **)&pixels, &pitch)) {pitch >>= 2;//每一个像素4字节,pixels为uint32_t指针pixels += pitch * s->height;//for循环填充每一个像素for (y = 0; y < s->height; y++) {double w = 1 / sqrt(nb_freq);//声道1频率值转换为颜色值,显示为红色int a = sqrt(w * sqrt(data[0][2 * y + 0] * data[0][2 * y + 0] + data[0][2 * y + 1] * data[0][2 * y + 1]));//声道2频率值转换为颜色值,显示为绿色int b = (nb_display_channels == 2 ) ? sqrt(w * hypot(data[1][2 * y + 0], data[1][2 * y + 1])): a;a = FFMIN(a, 255);b = FFMIN(b, 255);pixels -= pitch;//上一行*pixels = (a << 16) + (b << 8) + ((a+b) >> 1);}SDL_UnlockTexture(s->vis_texture);}SDL_RenderCopy(renderer, s->vis_texture, NULL, NULL);}if (!s->paused)s->xpos++;if (s->xpos >= s->width)s->xpos= s->xleft;}
}

9、ffplay音频的波谱图及频谱图源码分析相关推荐

  1. 一步一步手绘Spring AOP运行时序图(Spring AOP 源码分析)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  2. pyhton 画出音频文件的波形图和频谱图

    pyhton 画出音频文件的波形图和频谱图 # -*- coding:utf-8 -*- import wave import struct import numpy as np import mat ...

  3. FFplay源码分析-音视频同步1

    本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 FFplay 源码分析系列以一条简单的命令开始,ffplay -i a.mp4.a.mp4下载链接:百度网盘,提取 ...

  4. ffplay源码分析4-音视频同步

    ffplay是FFmpeg工程自带的简单播放器,使用FFmpeg提供的解码器和SDL库进行视频播放.本文基于FFmpeg工程4.1版本进行分析,其中ffplay源码清单如下: https://gith ...

  5. 一步步实现windows版ijkplayer系列文章之三——Ijkplayer播放器源码分析之音视频输出——音频篇

    https://www.cnblogs.com/harlanc/p/9693983.html 目录 OpenSL ES & AudioTrack 源码分析 创建播放器音频输出对象 配置并创建音 ...

  6. WebRTC源码分析-呼叫建立过程之四(上)(创建并添加本地音频轨到PeerConnection)

    目录 1. 引言 2. 音频轨创建和添加 2.1 音频源AudioSource的创建 2.1.1 音频源继承树 2.1.2 近端音频源LocalAudioSource 2.1.3 远端音频源Remot ...

  7. java观察者模式类图_设计模式(十八)——观察者模式(JDK Observable源码分析)...

    1 天气预报项目需求,具体要求以下: 1) 气象站能够将天天测量到的温度,湿度,气压等等以公告的形式发布出去(好比发布到本身的网站或第三方).java 2) 须要设计开放型 API,便于其余第三方也能 ...

  8. jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)

    Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图* ...

  9. jdk1.8 源码分析导图

    以下总结全部基于 jdk1.8,详细源码分析见 GitHub 链接:https://github.com/zchen96/jdk1.8-source-code-read 一.非并发 幕布导图链接:ht ...

  10. 【数字信号】基于matlab GUI多音双频(DTMF)拨号音频解码仿真系统【含Matlab源码 1084期】

    ⛄一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[数字信号]基于matlab GUI多音双频(DTMF)拨号音频解码仿真系统[含Matlab源码 1084期] 点击上面蓝色字体,直接付费 ...

最新文章

  1. maven中打包项目为war包的pom.xml配置
  2. AD5933阻抗转换器、网络分析仪初步实验
  3. 计算机网络测试两个主机连通性,计算机网络试卷A
  4. 【linux杂谈】查看centOS系统的版本号和内核号
  5. 数据集转换_为什么LSTM看起来那么复杂,以及如何避免时序数据的处理差异和混乱...
  6. 简评游戏人工智能相关的中文书(补遗)
  7. Session登陆后丢失的解决办法。
  8. 设计模式之抽象工厂模式(Abstract Factory)
  9. zigbee网关数据到json格式
  10. 单层感知机(Single Layer Perceptron)详解
  11. 在线旅游OTA行业调研报告-携程美团同程飞猪booking对比分析
  12. Flutter 实现风车加载动画组件
  13. 计算机基本防范技术教案,电脑病毒处处防 教案(华科版信息技术上册)
  14. 「科技与安全」RK3568J核心板让隔离网闸更强大
  15. 计算机专业mx330够用吗,这款新的HP笔记本电脑配备了MX330图形卡,那么性能如何?...
  16. 使用vs2010生成64位的dll文件
  17. 用jq实现简单的锚点切换
  18. 开源配置管理工具config-toolkit 使用心得
  19. 8、数码相框之libjpeg的使用
  20. Python机器学习库sklearn里利用LR模型进行三分类(多分类)的原理

热门文章

  1. java odbc timesten_TimesTen 使用ODBC连接数据库的程序问题
  2. Vista v12.0 Win32-ISO 1DVD(地震数据处理)
  3. Percona XtraBackup User Manual
  4. 软件测试——集成测试篇
  5. 微信游戏小程序源码-合成大西瓜小游戏(合成版)源码 附带流量主功能
  6. selenium 接管浏览器
  7. 最新数据库可视化工具DataGrip安装教程
  8. LintCode 842: Origami
  9. 宁浩网sql注入工具_国产SQL注入漏洞测试工具 - 超级SQL注入工具(SSQLInjection)...
  10. 520用Java制作一个表白app