Qt源码-Qt多媒体音频框架

news2024/12/27 1:49:01

Qt 多媒体音频框架

  • 一、概述
  • 二、音频设计
    • 1. ALSA 基础
    • 2. Qt 音频类
      • 1. 接口实现
      • 2. alsa 插件实现

一、概述

环境详细
Qt版本Qt 5.15
操作系统Deepin v23
代码工具Visual Code
源码https://github.com/qt/qtmultimedia/tree/5.15

这里记录一下在Linux下Qt 的 Qt Multimedia 模块的设计,我目前先记录与音频相关的库的设计。不同Qt版本的设计有些不一样,需要看对应版本的源码设计。

二、音频设计

1. ALSA 基础

ALSA是 Advanced Linux Sound Architecture的缩写,即高级Linux声音架构。在Linux 2.6的内核版本后,ALSA目前已经成为了Linux的主流音频体系结构。
在这里插入图片描述

2. Qt 音频类

1. 接口实现

最重要的就是 QAudioInput和QAudioOutput两个类,作为音频输入输出的类。
在这里插入图片描述
这个类的源码位置在

src/multimedia/audio/qaudioinput.cpp

那我们开始看 QAudioInput 类的关键实现吧,在 qaudioinput.cpp 中都是使用的 qaudioinput.h 头文件中 QAbstractAudioInput 类型的 d 的成员方法。

如 QAudioInput::start() 实际使用的是 d->start();

// qaudioinput.h
private:
    QAbstractAudioInput* d;
// qaudioinput.cpp
void QAudioInput::start(QIODevice* device)
{
    d->start(device);
}
....
QAudioFormat QAudioInput::format() const
{
    return d->format();
}

在 QAudioInput 构造函数中,得知是d 是由工厂类 QAudioDeviceFactory 创建的

src/multimedia/audio/qaudiodevicefactory.cpp
QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent):
    QObject(parent)
{
    d = QAudioDeviceFactory::createDefaultInputDevice(format);
    ...
}

QAudioDeviceFactory 工厂通过 createDefaultInputDevice() ⇒ \Rightarrow createInputDevice() 函数调用。所以具体就看 createInputDevice() 函数实现 就可以了。

QAbstractAudioInput* QAudioDeviceFactory::createDefaultInputDevice(QAudioFormat const &format)
{
    return createInputDevice(defaultDevice(QAudio::AudioInput), format);
}
QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceInfo const& deviceInfo, QAudioFormat const &format)
{
    if (deviceInfo.isNull())
        return new QNullInputDevice();

#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
    QAudioSystemFactoryInterface* plugin =
        qobject_cast<QAudioSystemFactoryInterface*>(
        	audioLoader()->instance(deviceInfo.realm())
        );
        
    if (plugin) {
        QAbstractAudioInput* p = plugin->createInput(deviceInfo.handle());
        if (p) p->setFormat(format);
        return p;
    }
#endif

    return new QNullInputDevice();
}

上面 createInputDevice 中 QAbstractAudioInput *p 就是 通过 audioLoader 加载的插件 plugin 创建出的。这样不同系统可以实现不同的插件,根据系统做到跨平台性。

QAudioSystemFactoryInterface* plugin 就是插件的接口父类。

在创建失败的时候,QAudioDeviceFactory 工厂也通过定义 QNullInputDevice 类。保证插件系统正常运行。

让我们看看QNullInputDevice 在 qaudiodevicefactory.cpp 的定义

class QNullInputDevice : public QAbstractAudioInput
{
public:
    void start(QIODevice*) override { qWarning()<<"using null input device, none available";}
    QIODevice *start() override { qWarning()<<"using null input device, none available"; return nullptr; 
    void setBufferSize(int ) override {}
    int bufferSize() const override  { return 0; }
...
    void setVolume(qreal) override {}
    qreal volume() const override {return 1.0f;}
};

2. alsa 插件实现

那让我们继续看看音频功能的具体实现,音频插件的源码工程位置在 `

src/pligins/alsa/alsa.pro

在下面我们可以看到,不同平台的不同实现,有Linux、Windows、Android等。在我WIndows电脑的Qt5.14.2 上音频库则是使用的
windowsaudio 工程
在这里插入图片描述

我们找到Linux的alsa工程,从工程文件可以得到这个插件的名字叫 qtaudio_alsa
在这里插入图片描述
这个插件最后生成的名字叫 libqtaudio_alsa.so

在我的系统中安装的位置在

/usr/lib/x86_64-linux-gnu/qt5/plugins/audio/libqtaudio_alsa.so	

在这里插入图片描述

下面继续介绍这个插件

qalsaplugin.cpp:就是生成插件的接口类,对外使用,内部使用了ALSA实现功能

qalsaaudiodeviceinfo.cpp:封装的 音频设备信息,功能QAudioDeviceInfo 功能
qalsaaudioinput.cpp :音频输入类,实际 QAudioInput 的实现
qalsaaudiooutput.cpp:音频输出类,实际的 QAudioOutput 的实现

下面就是 qalsaaudioinput 的open函数实现,可以看到open函数使用了 snd_pcm_open 函数:

bool QAlsaAudioDeviceInfo::open()
{
    int err = 0;
    QString dev;

    if (!availableDevices(mode).contains(device.toLocal8Bit()))
        return false;

#if SND_LIB_VERSION < 0x1000e  // 1.0.14
    if (device.compare(QLatin1String("default")) != 0)
        dev = deviceFromCardName(device);
    else
#endif
        dev = device;

    if(mode == QAudio::AudioOutput) {
        err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
    } else {
        err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
    }
    if(err < 0) {
        handle = 0;
        return false;
    }
    return true;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

性能测试学习6:jmeter安装与基本配置/元件/线程组介绍

一.JDK安装 官网&#xff1a;https://www.oracle.com/ 二.Jmeter安装 官网&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 下载zip包&#xff0c;zip后缀那个才是Windows系统的jmeter 三.Jmeter工作目录介绍 四.Jmeter功能 1&#xff09;修改默认配置-汉化 2&am…

51 单片机最小系统

一、51 单片机最小系统概述 51 单片机最小系统是一个基于 51 单片机的最小化电路系统&#xff0c;它包含了使单片机能够正常工作的最少元件。这个系统主要用于学习和实验目的&#xff0c;帮助学习者在没有复杂电路的情况下快速了解 51 单片机的工作原理&#xff0c;其重要性不…

TryHackMe 第7天 | Web Fundamentals (二)

继续介绍一些 Web hacking 相关的漏洞。 IDOR IDOR (Insecure direct object reference)&#xff0c;不安全的对象直接引用&#xff0c;这是一种访问控制漏洞。 当 Web 服务器接收到用户提供的输入来检索对象时 (包括文件、数据、文档)&#xff0c;如果对用户输入数据过于信…

【可视化大屏】Python Flask框架介绍

为了能显示真实数据&#xff0c;使用flask快速搭建了一个web应用&#xff0c;然后连接数据库&#xff0c;读取数据库里的数据来进行大屏可视化显示&#xff08;btw&#xff1a;数据是从车主之家网站上爬虫爬的&#xff09; 家人们&#xff01;记得使用专业版的pycharm&#xf…

在忘记密码的情况下重新访问手机?5种忘记密码解锁Android手机的方法

无需密码即可访问Android手机。 即使你忘记了密码&#xff0c;你也可以解锁你的Android手机&#xff0c;但你通常需要将手机恢复出厂设置。 您可以通过执行出厂恢复或使用“查找我的设备”网站解锁大多数Android手机。 如果你不再有密码&#xff0c;这里有五种解锁安卓手机的…

sqli-labs less-17密码重置报错注入

密码重置报错植入 来到首页面我们看到页面提示【password reset】&#xff0c;说明这是更改密码的注入&#xff0c;也就是说我们知道一个账户名&#xff0c;修改他的密码&#xff0c;所以我们可以在passwd处进行注入。 闭合方式 添加单引号 有报错 可以知道闭合方式为单引号…

【JavaEE】——初始网络原理

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;局域网 1&#xff1a;概念 二&#xff1a;局域网的连接方式 1&#xff1a;网线直连 …

Qt实现Halcon窗口显示当前图片坐标

一、前言 Halcon加载图片的窗口&#xff0c;不仅能放大和缩小图片&#xff0c;还可以按住Ctrl键显示鼠标下的灰度值&#xff0c;这种方式很方便我们分析缺陷的灰度和对比度。 二、实现方式 ① 创建显示坐标和灰度的widget窗口 下图的是widget部件&#xff0c;使用了4个label控…

前端如何让页面上的文字“立”起来

前言 最近看到了一个很有意思的 CSS 效果&#xff0c;如下图&#xff0c;是一个文字立起来 阴影 的效果&#xff0c;觉得比较有意思&#xff0c;所以分享给大家~ 实现 基础样式 首先我们把基础的文字和样式编写出来&#xff0c;代码如下 效果如下&#xff1a; 伪元素 ->…

香橙派如何连接网络,及wiringOP库

1.使用nmcli dev wifi命令扫描周围的 WiFi热点 2.找到需要连接的WiFi 输入nmcli dev wifi connect wifi_name password wifi_passwd 其中wifi_name是你的WiFi名字&#xff0c;wifi_passwd是WiFi的密码 3.wiringOP库 包含#include <wiringPi.h> 首先使用wiringPiSet…

[OS] 再探Kernel Threads -2

内核线程&#xff08;Kernel Thread&#xff09;创建和执行机制&#xff1a; 在 Linux 内核中&#xff0c;内核线程&#xff08;kthread&#xff09; 是一种特殊类型的线程&#xff0c;专门用于执行内核任务。与用户态的进程和线程不同&#xff0c;内核线程不具有用户空间&…

计算机的错误计算(一百一十六)

摘要 计算机的错误计算&#xff08;一百一十&#xff09;分析了&#xff08;二&#xff09;中例1循环迭代错误计算的原因。应读者建议&#xff0c;本节将用错数讨论其例2的错误计算原因。 例1. 已知 计算 在 的错数&#xff0c;并用实例分析计算过程中的错误数字数量。…

leetcode-哈希篇1

leetcode-217 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 &#xff0c;返回 true &#xff1b;如果数组中每个元素互不相同&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,1] 输出&#xff1a;true 解释&#xff1a; 元素 1 在下标…

电脑操作技巧:如何恢复永久删除的婚礼照片

我们的生活充满了褪色和模糊的快照&#xff0c;是我们记忆的剪贴簿。尽管我们很想记住事情并坚持快乐的回忆&#xff0c;但随着时间的推移&#xff0c;它们会被冲走。为了避免这种情况并记住这些记忆&#xff0c;我们以照片的形式捕捉瞬间。这有助于缓解和分享那些快乐的时刻。…

C语言编译与链接(29)

文章目录 前言一、翻译环境和执行环境二、翻译环境预处理(预编译)编译词法分析语法分析语义分析 汇编链接 三、运行环境总结 前言 本篇同样是一篇修炼内功的文章   很重要&#xff01;它将会让你对程序的构建运行有一个更深的认识 一、翻译环境和执行环境 在ANSI C的任何一种…

[uni-app]小兔鲜-08云开发

uniCloud可以通过JS开发服务端,包含云数据库, 云函数, 云存储等功能, uniCloud可结合 uni-ui 组件库使用 效果展示: <picker>城市选择组件不支持h5端和APP端, 所以我们使用 <uni-data-picker>组件进行兼容处理 <uni-data-picker>的数据使用云数据库的数据 云…

指针(7)

目录 1. sizeof和strlen的对⽐ 1.1 sizeof 1.2 strlen sizeof 和 strlen 总结&#xff1a; 2. 数组和指针 2.1 ⼀维数组 2.2 字符数组 1. sizeof和strlen的对⽐ 1.1 sizeof 计算的是使⽤类型创建的变量所占内存空间的⼤⼩。sizeof不在乎你里面放的什么。sizieof是操作符…

基于springboot人力资源管理系统源码

项目技术&#xff1a;SpringBoot 运行环境&#xff1a;jdk1.8idea/eclipsemaven3mysql5.6 项目描述&#xff1a; 系统包括&#xff0c;员工管理&#xff0c;奖惩管理&#xff0c;合同管理&#xff0c;薪酬管理&#xff0c;培训管理&#xff0c;绩效评估等功能

x++、++x的一些问题

x、x在字面上无非就说一个先前置递增然后再运算&#xff0c;另一个是运算完再递增&#xff0c;是不是有些许模棱两可的感觉&#xff0c;接下来引用一个简单的for循环就能够大致理解&#xff1a; 先是x&#xff1a; int i0,x0;for(i0;(i)<5;){xi;printf("%d\n",x)…

影刀RPA实战:Excel排序、替换与格式

1.实战目标 今天继续介绍影刀RPA操作Excel的指令&#xff0c;内容替换&#xff0c;数据排序与单元格格式设置&#xff0c;这几个功能在日常工作中使用率还是比较频繁的。我们可以使用影刀来处理这些重复繁琐的工作。 2.内容替换 我们手动替换内容时 打开Excel文件&#xff1…