一、前语

本系列文章是对音视频技能入门常识的整理和复习,为进一步深化体系研究音视频技能巩固根底。文章列表:

  • 01-音视频技能中心常识|了解音频技能【移动通讯技能的发展、声响的实质、深化了解音频】
  • 02-音视频技能中心常识|树立开发环境【FFmpeg与Qt、Windows开发环境树立、Mac开发环境树立、Qt开发根底】
  • 03-音视频技能中心常识|Qt开发根底【.pro文件的装备、Qt控件根底、信号与槽】
  • 04-音视频技能中心常识|音频录制【命令行、C++编程】
  • 05-音视频技能中心常识|音频播映【播映PCM、WAV、PCM转WAV、PCM转WAV、播映WAV】
  • 06-音视频技能中心常识|音频重采样【音频重采样简介、用命令行进行重采样、经过编程重采样】
  • 07-音视频技能中心常识|AAC编码【AAC编码器解码器、编译FFmpeg、AAC编码实战、AAC解码实战】
  • 08-音视频技能中心常识|成像技能【重识图片、详解YUV、视频录制、显现BMP图片、显现YUV图片】
  • 09-音视频技能中心常识|视频编码解码【了解H.264编码、H.264编码、H.264编码解码】
  • 10-音视频技能中心常识|RTMP服务器树立【流媒体、服务器环境】

二、.pro文件的装备

1. 跨渠道装备

之前咱们别离在Windows、Mac环境的Qt项目中集成了FFmpeg。

能够发现在 .pro 文件的装备中,FFmpeg库在Mac、Windows上的位置是有所差异的。这样就会导致 .pro 文件无法跨渠道运用。

# windows
INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
# mac
INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include

为了完成跨渠道装备,能够在装备前面加上渠道标识的前缀,表示这个装备只会在对应的渠道生效。

# windows
win32:INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
win32:LIBS += -LF:/Dev/ffmpeg-4.3.2/lib \
              -lavcodec \
              -lavdevice \
              -lavfilter \
              -lavformat \
              -lavutil \
              -lpostproc \
              -lswscale \
              -lswresample
# mac
macx:INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
macx:LIBS += -L/usr/local/Cellar/ffmpeg/4.3.2/lib \
            -lavcodec \
            -lavdevice \
            -lavfilter \
            -lavformat \
            -lavutil \
            -lpostproc \
            -lswscale \
            -lswresample \
            -lavresample
# linux
# linux:INCLUDEPATH += ...
# linux:LIBS += ...

以后针对每个渠道的装备可能会比较多,能够运用大括号来简化。

# windows
win32 {
    INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
    LIBS += -LF:/Dev/ffmpeg-4.3.2/lib \
            -lavcodec \
            -lavdevice \
            -lavfilter \
            -lavformat \
            -lavutil \
            -lpostproc \
            -lswscale \
            -lswresample
}
# mac
macx {
    INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
    LIBS += -L/usr/local/Cellar/ffmpeg/4.3.2/lib \
            -lavcodec \
            -lavdevice \
            -lavfilter \
            -lavformat \
            -lavutil \
            -lpostproc \
            -lswscale \
            -lswresample \
            -lavresample
}

2. 自定义变量

能够将公共的信息抽取成变量,然后运用 $${} 去拜访。

# mac
macx {
    FFMPEG_HOME = /usr/local/Cellar/ffmpeg/4.3.2
    INCLUDEPATH += $${FFMPEG_HOME}/include
    LIBS += -L$${FFMPEG_HOME}/lib \
            -lavcodec \
            -lavdevice \
            -lavfilter \
            -lavformat \
            -lavutil \
            -lpostproc \
            -lswscale \
            -lswresample \
            -lavresample
}

3. 读取体系环境变量

也能够经过 $$()读取体系的环境变量。比方,我的Windows中有个叫做JAVA_HOME的环境变量。

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

# 运用message打印环境变量JAVA_HOME的值
message($$(JAVA_HOME))

终究能够在概要信息处看到JAVA_HOME的打印成果。

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

三、控件的根本运用

为了更好地学习Qt控件的运用,主张创立项目时先不要生成ui文件。

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

翻开mainwindow.cpp,在MainWindow的结构函数中编写界面的初始化代码。

1. 窗口设置

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent) {
    // 设置窗口标题
    setWindowTitle("主窗口");
    // 设置窗口大小
    // 窗口能够经过拖拽边际进行自在伸缩
//    resize(400, 400);
    // 设置窗口的固定大小
    // 窗口不能经过拖拽边际进行自在伸缩
    setFixedSize(400, 400);
    // 设置窗口的位置
    // 以父控件的左上角为坐标原点
    // 没有父控件,就以屏幕的左上角作为坐标原点
    move(100, 100);
}

Qt坐标系如下图所示。

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

2. 增加子控件

#include <QPushButton>
// 创立按钮
QPushButton *btn = new QPushButton;
// 设置按钮的文字
btn->setText("登录");
// 设置父控件为当时窗口
btn->setParent(this);
// 设置按钮的位置和大小
btn->move(50, 50);
btn->resize(100, 50);
// 创立第2个按钮
new QPushButton("注册", this);

new出来的Qt控件是不需求程序员手动delete的,Qt内部会主动管理内存:当父控件毁掉时,会顺带毁掉子控件。

四、信号与槽

1. 根本运用

  • 信号(Signal):比方点击按钮就会宣布一个点击信号
  • 槽(Slot):一般也叫槽函数,是用来处理信号的函数
  • 官方文档参阅:Signals & Slots

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

上图中的效果是:

  • Object1宣布信号signal1,交给Object2的槽slot1、slot2去处理
    • Object1是信号的发送者,Object2是信号的接收者
  • Object1宣布信号signal2,交给Object4的槽slot1去处理
    • Object1是信号的发送者,Object4是信号的接收者
  • Object3宣布信号signal1,交给Object4的槽slot3去处理
    • Object3是信号的发送者,Object4是信号的接收者
  • 1个信号能够由多个槽进行处理,1个槽能够处理多个信号

经过connect函数能够将信号的发送者信号信号的接收者衔接在一起。

connect(信号的发送者, 信号, 信号的接收者, 槽);
// 比方点击按钮,关闭当时窗口
// btn宣布clicked信号,就会调用this的close函数
connect(btn, &QPushButton::clicked, this, &MainWindow::close);
// 能够经过disconnect断开衔接
disconnect(btn, &QPushButton::clicked, this, &MainWindow::close);

2. 自定义信号与槽

信号的发送者和接收者都有必要承继自QObject,Qt中的控件终究都是承继自QObject,比方QMainWindow、QPushButton等。

3. 信号的发送者

  • sender.h
    • Q_OBJECT用以支持自定义信号和槽
    • 自定义的信号需求写在 signals: 下面
    • 自定义的信号只需求声明,不需求完成
#ifndef SENDER_H
#define SENDER_H
#include <QObject>
class Sender : public QObject {
    Q_OBJECT
public:
    explicit Sender(QObject *parent = nullptr);
    // 自定义信号
signals:
    void exit();
};
#endif // SENDER_H
  • sender.cpp
#include "sender.h"
Sender::Sender(QObject *parent) : QObject(parent) {
}

4. 信号的接收者

  • receiver.h
    • 自定义的槽主张写在 public slots: 下面
#ifndef RECEIVER_H
#define RECEIVER_H
#include <QObject>
class Receiver : public QObject {
    Q_OBJECT
public:
    explicit Receiver(QObject *parent = nullptr);
    // 自定义槽
public slots:
    void handleExit();
};
#endif // RECEIVER_H
  • receiver.cpp
#include "receiver.h"
#include <QDebug>
Receiver::Receiver(QObject *parent) : QObject(parent) {
}
// 完成槽函数,编写处理信号的代码
void Receiver::handleExit() {
    qDebug() << "Receiver::handleExit()";
}

5. 衔接

  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
};
#endif // MAINWINDOW_H
  • mainwindow.cpp
#include "mainwindow.h"
#include "sender.h"
#include "receiver.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent) {
    // 创立目标
    Sender *sender = new Sender;
    Receiver *receiver = new Receiver;
    // 衔接
    connect(sender,
            &Sender::exit,
            receiver,
            &Receiver::handleExit);
    // 宣布信号
    // 终究会调用Receiver::handleExit函数
    emit sender->exit();
    // 毁掉目标
    delete sender;
    delete receiver;
}
MainWindow::~MainWindow() {
}

6. 参数和返回值

信号与槽都能够有参数和返回值:

  • 发信号时的参数会传递给槽
  • 槽的返回值会返回到发信号的位置
// 自定义信号
signals:
    int exit(int a, int b);
// 自定义槽
public slots:
    int handleExit(int a, int b);
int Receiver::handleExit(int a, int b) {
    // Receiver::handleExit() 10 20
    qDebug() << "Receiver::handleExit()" << a << b;
    return a + b;
}
// 宣布信号
int a = emit sender->exit(10, 20);
// 30
qDebug() << a;

需求注意的是:信号的参数个数有必要大于等于槽的参数个数。比方下面的写法是过错的:

// 自定义信号
signals:
    void exit(int a);
// 自定义槽
public slots:
    void handleExit(int a, int b);

7. 衔接2个信号

比方下图,衔接了Object 1的Signal 1A和Object 2的Signal 2A

  • 当Object 1宣布Signal 1A时,会触发Slot X、Slot Y
  • 当Object 2宣布Signal 2A时,只会触发Slot Y,而不会触发Slot X

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

能够运用connect函数衔接2个信号

  • 当sender宣布exit信号时,sender2会宣布exit2信号
  • 当sender2宣布exit2信号时,sender并不会宣布exit信号
connect(sender,
        &Sender::exit,
        sender2,
        &Sender2::exit2);

8. Lambda

也能够直接运用Lambda处理信号。

connect(sender, &Sender::exit, []() {
    qDebug() << "lambda handle exit";
});

9. ui文件

如果你的控件是经过ui文件生成的,衔接槽函数的步骤会更加简略。

首先主张给按钮们起个有意义的变量名,比方别离叫做:loginButtonregisterButton

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

对着登录按钮右键,选择转为槽

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

选择clicked信号,然后OK

03-音视频技术核心知识|Qt开发基础【`.pro`文件的配置、Qt控件基础、信号与槽】

此刻,Qt Creator现已帮你主动生成了槽函数的声明和完成,当咱们点击登录按钮时,就会调用这个函数。

class MainWindow : public QMainWindow {
    Q_OBJECT
private slots:
    // 槽函数的声明
    void on_loginButton_clicked();
};
// 槽函数的完成
void MainWindow::on_loginButton_clicked() {
    qDebug() << "on_loginButton_clicked";
}	

其实,仔细调查函数名能够发现一个规律,函数名的命名规矩是:on_控件的变量名_事件名

所以,咱们能够测验编写以下代码。

class MainWindow : public QMainWindow {
    Q_OBJECT
private slots:
    // 槽函数的声明
    void on_registerButton_clicked();
};
// 槽函数的完成
void MainWindow::on_registerButton_clicked() {
    qDebug() << "on_registerButton_clicked";
}	

然后,你点击一下注册按钮,会发现成功调用了MainWindow::on_registerButton_clicked函数。

所以得知:ui文件中的控件会主动跟符合命名规矩的槽函数树立衔接

终究,再提示一个常识点:ui文件中的控件能够在代码中经过ui->变量名拜访。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    // 经过ui->拜访ui文件中的2个按钮
    ui->loginButton->setFixedSize(100, 30);
    ui->registerButton->setFixedSize(100, 30);
}

专题系列文章

1. 前常识

  • 01-探求iOS底层原理|总述
  • 02-探求iOS底层原理|编译器LLVM项目【Clang、SwiftC、优化器、LLVM】
  • 03-探求iOS底层原理|LLDB
  • 04-探求iOS底层原理|ARM64汇编

2. 根据OC言语探求iOS底层原理

  • 05-探求iOS底层原理|OC的实质
  • 06-探求iOS底层原理|OC目标的实质
  • 07-探求iOS底层原理|几种OC目标【实例目标、类目标、元类】、目标的isa指针、superclass、目标的办法调用、Class的底层实质
  • 08-探求iOS底层原理|Category底层结构、App启动时Class与Category装载过程、load 和 initialize 履行、相关目标
  • 09-探求iOS底层原理|KVO
  • 10-探求iOS底层原理|KVC
  • 11-探求iOS底层原理|探求Block的实质|【Block的数据类型(实质)与内存布局、变量捕获、Block的品种、内存管理、Block的修饰符、循环引证】
  • 12-探求iOS底层原理|Runtime1【isa详解、class的结构、办法缓存cache_t】
  • 13-探求iOS底层原理|Runtime2【音讯处理(发送、转发)&&动态办法解析、super的实质】
  • 14-探求iOS底层原理|Runtime3【Runtime的相关运用】
  • 15-探求iOS底层原理|RunLoop【两种RunloopMode、RunLoopMode中的Source0、Source1、Timer、Observer】
  • 16-探求iOS底层原理|RunLoop的运用
  • 17-探求iOS底层原理|多线程技能的底层原理【GCD源码剖析1:主行列、串行行列&&并行行列、大局并发行列】
  • 18-探求iOS底层原理|多线程技能【GCD源码剖析1:dispatch_get_global_queue与dispatch_(a)sync、单例、线程死锁】
  • 19-探求iOS底层原理|多线程技能【GCD源码剖析2:栅门函数dispatch_barrier_(a)sync、信号量dispatch_semaphore】
  • 20-探求iOS底层原理|多线程技能【GCD源码剖析3:线程调度组dispatch_group、事件源dispatch Source】
  • 21-探求iOS底层原理|多线程技能【线程锁:自旋锁、互斥锁、递归锁】
  • 22-探求iOS底层原理|多线程技能【原子锁atomic、gcd Timer、NSTimer、CADisplayLink】
  • 23-探求iOS底层原理|内存管理【Mach-O文件、Tagged Pointer、目标的内存管理、copy、引证计数、weak指针、autorelease

3. 根据Swift言语探求iOS底层原理

关于函数枚举可选项结构体闭包特点办法swift多态原理StringArrayDictionary引证计数MetaData等Swift根本语法和相关的底层原理文章有如下几篇:

  • 01-Swift5常用中心语法|了解Swift【Swift简介、Swift的版本、Swift编译原理】
  • 02-Swift5常用中心语法|根底语法【Playground、常量与变量、常见数据类型、字面量、元组、流程操控、函数、枚举、可选项、guard语句、区间】
  • 03-Swift5常用中心语法|面向目标【闭包、结构体、类、枚举】
  • 04-Swift5常用中心语法|面向目标【特点、inout、类型特点、单例形式、办法、下标、承继、初始化】
  • 05-Swift5常用中心语法|高档语法【可选链、协议、过错处理、泛型、String与Array、高档运算符、扩展、拜访操控、内存管理、字面量、形式匹配】
  • 06-Swift5常用中心语法|编程范式与Swift源码【从OC到Swift、函数式编程、面向协议编程、响应式编程、Swift源码剖析】

4. C++中心语法

  • 01-C++中心语法|C++概述【C++简介、C++来源、可移植性和规范、为什么C++会成功、从一个简略的程序开始知道C++】
  • 02-C++中心语法|C++对C的扩展【::效果域运算符、姓名操控、struct类型加强、C/C++中的const、引证(reference)、函数】
  • 03-C++中心语法|面向目标1【 C++编程规范、类和目标、面向目标程序设计事例、目标的结构和析构、C++面向目标模型初探】
  • 04-C++中心语法|面向目标2【友元、内部类与局部类、强化训练(数组类封装)、运算符重载、仿函数、模板、类型转换、 C++规范、过错&&反常、智能指针】
  • 05-C++中心语法|面向目标3【 承继和派生、多态、静态成员、const成员、引证类型成员、VS的内存窗口】

5. Vue全家桶

  • 01-Vue全家桶中心常识|Vue根底【Vue概述、Vue根本运用、Vue模板语法、根底事例、Vue常用特性、归纳事例】
  • 02-Vue全家桶中心常识|Vue常用特性【表单操作、自定义指令、核算特点、侦听器、过滤器、生命周期、归纳事例】
  • 03-Vue全家桶中心常识|组件化开发【组件化开发思想、组件注册、Vue调试工具用法、组件间数据交互、组件插槽、根据组件的
  • 04-Vue全家桶中心常识|多线程与网络【前后端交互形式、promise用法、fetch、axios、归纳事例】
  • 05-Vue全家桶中心常识|Vue Router【根本运用、嵌套路由、动态路由匹配、命名路由、编程式导航、根据vue-router的事例】
  • 06-Vue全家桶中心常识|前端工程化【模块化相关规范、webpack、Vue 单文件组件、Vue 脚手架、Element-UI 的根本运用】
  • 07-Vue全家桶中心常识|Vuex【Vuex的根本运用、Vuex中的中心特性、vuex事例】

6. 音视频技能中心常识

  • 01-音视频技能中心常识|了解音频技能【移动通讯技能的发展、声响的实质、深化了解音频】
  • 02-音视频技能中心常识|树立开发环境【FFmpeg与Qt、Windows开发环境树立、Mac开发环境树立、Qt开发根底】
  • 03-音视频技能中心常识|Qt开发根底【.pro文件的装备、Qt控件根底、信号与槽】
  • 04-音视频技能中心常识|音频录制【命令行、C++编程】
  • 05-音视频技能中心常识|音频播映【播映PCM、WAV、PCM转WAV、PCM转WAV、播映WAV】
  • 06-音视频技能中心常识|音频重采样【音频重采样简介、用命令行进行重采样、经过编程重采样】
  • 07-音视频技能中心常识|AAC编码【AAC编码器解码器、编译FFmpeg、AAC编码实战、AAC解码实战】
  • 08-音视频技能中心常识|成像技能【重识图片、详解YUV、视频录制、显现BMP图片、显现YUV图片】
  • 09-音视频技能中心常识|视频编码解码【了解H.264编码、H.264编码、H.264编码解码】
  • 10-音视频技能中心常识|RTMP服务器树立【流媒体、服务器环境】

其它底层原理专题

1. 底层原理相关专题

  • 01-核算机原理|核算机图形烘托原理这篇文章
  • 02-核算机原理|移动终端屏幕成像与卡顿

2. iOS相关专题

  • 01-iOS底层原理|iOS的各个烘托结构以及iOS图层烘托原理
  • 02-iOS底层原理|iOS动画烘托原理
  • 03-iOS底层原理|iOS OffScreen Rendering 离屏烘托原理
  • 04-iOS底层原理|因CPU、GPU资源耗费导致卡顿的原因和解决计划

3. webApp相关专题

  • 01-Web和类RN大前端的烘托原理

4. 跨渠道开发计划相关专题

  • 01-Flutter页面烘托原理

5. 阶段性总结:Native、WebApp、跨渠道开发三种计划功能比较

  • 01-Native、WebApp、跨渠道开发三种计划功能比较

6. Android、HarmonyOS页面烘托专题

  • 01-Android页面烘托原理
  • 02-HarmonyOS页面烘托原理 (待输出)

7. 小程序页面烘托专题

  • 01-小程序结构烘托原理