编程进阶网 编程进阶网
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机的原理
  • 操作系统原理
  • 网络协议原理
  • 数据库的原理
  • 序卷导读
  • 数据本质
  • 运行模型
  • 并发设计
  • 内存真相
  • 交互系统
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 技能之旅
  • 体系建设
  • 代码品质
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 性能优化
  • 数据结构导论
  • 线性结构详解
  • 树哈希结构论
  • 容器设计实战
  • 经典算法思想
  • 工程案例剖析
  • 算法题库精练
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript案例
  • JavaScript高级
  • Kotlin精通
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 毛选解读
  • 自我精进
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机的原理
  • 操作系统原理
  • 网络协议原理
  • 数据库的原理
  • 序卷导读
  • 数据本质
  • 运行模型
  • 并发设计
  • 内存真相
  • 交互系统
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 技能之旅
  • 体系建设
  • 代码品质
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 性能优化
  • 数据结构导论
  • 线性结构详解
  • 树哈希结构论
  • 容器设计实战
  • 经典算法思想
  • 工程案例剖析
  • 算法题库精练
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript案例
  • JavaScript高级
  • Kotlin精通
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 毛选解读
  • 自我精进
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

  • Web开发和进阶

  • Linux应用开发

    • Linux应用开发
    • QML基础入门

    • QT核心库实践

      • QT核心库实践
      • 核心功能基础
      • 并发与多线程
      • 文件与IO系统
      • 日期与时间处理
      • 网络与序列化
      • QT事件系统
      • 信号与槽机制
      • 多媒体的应用
        • 8.1 多媒体介绍
          • 8.1.1 多媒体支持
          • 8.1.2 多媒体模块概述
        • 8.2 音频播放
          • 8.2.1 QMediaPlayer介绍
          • 8.2.2 QMediaPlayer功能
          • 8.2.3 QMediaPlayer作用
          • 8.2.4 核心方法API
          • 8.2.5 QMediaPlayer原理
          • 8.2.6 QMediaPlayer信号槽
          • 8.2.7 综合播放案例
          • 8.2.8 音频效果处理
        • 8.3 音频录制
          • 8.3.1 QAudioRecorder介绍
        • 8.4 视频播放
          • 8.4.1 视频播放案例
          • 8.4.2 视频录制
        • 8.5 QCamera
          • 8.5.1 QCamera介绍
          • 8.5.2 图像捕捉
        • 8.6 Qt 6 多媒体架构
          • 8.6.1 Qt 5 vs Qt 6 多媒体模块变革
          • 8.6.2 QMediaCaptureSession 综合使用
          • 8.6.3 后端实现原理
        • 8.7 音频设备与编解码
          • 8.7.1 QAudioDevice / QMediaDevices
          • 8.7.2 QAudioSink 低级音频输出
          • 8.7.3 支持的编解码格式
        • 8.8 嵌入式多媒体实战
          • 8.8.1 硬件加速
          • 8.8.2 QVideoSink ——直接访问视频帧
          • 8.8.3 低延迟视频预览
        • 8.9 综合案例
          • 案例:嵌入式视频监控与抓拍
        • 8.10 速查表
      • 容器类和算法
      • 高级编程技巧
    • Linux系统编程

    • 综合项目实战

  • IoT智能硬件开发

  • Apps
  • Linux应用开发
  • QT核心库实践
杨充
2025-09-08
目录

多媒体的应用

# 08.多媒体的应用

# 目录介绍

  • 8.1 多媒体介绍
    • 8.1.1 多媒体支持
    • 8.1.2 多媒体模块概述
  • 8.2 音频播放
    • 8.2.1 QMediaPlayer介绍
    • 8.2.2 QMediaPlayer功能
    • 8.2.3 QMediaPlayer作用
    • 8.2.4 核心方法API
    • 8.2.5 QMediaPlayer原理
    • 8.2.6 QMediaPlayer信号槽
    • 8.2.7 综合播放案例
    • 8.2.8 音频效果处理
  • 8.3 音频录制
    • 8.3.1 QAudioRecorder介绍
  • 8.4 视频播放
    • 8.4.1 视频播放案例
    • 8.4.2 视频录制
  • 8.5 QCamera
    • 8.5.1 QCamera介绍
    • 8.5.2 图像捕捉

# 8.1 多媒体介绍

# 8.1.1 多媒体支持

Qt 提供了丰富的多媒体支持,涵盖了音频、视频、摄像头、图像处理等功能。

# 8.1.2 多媒体模块概述

Qt 多媒体模块位于 QtMultimedia 库中,提供了以下功能:

  • 音频播放与录制
  • 视频播放与录制
  • 摄像头访问
  • 图像捕捉与处理
  • 音频效果处理

要使用 Qt 多媒体模块,需要在项目文件(.pro)中添加以下配置:

QT += multimedia

# 8.2 音频播放

# 8.2.1 QMediaPlayer介绍

QMediaPlayer 用于播放音频文件。

#include <QMediaPlayer>
#include <QUrl>
#include <QDebug>

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    // 创建媒体播放器
    QMediaPlayer player;
    // 设置音频文件
    player.setMedia(QUrl::fromLocalFile("/path/to/audio.mp3"));
    // 播放音频
    player.play();
    // 监听播放状态
    QObject::connect(&player, &QMediaPlayer::stateChanged, [](QMediaPlayer::State state) {
        if (state == QMediaPlayer::PlayingState) {
            qDebug() << "Audio is playing!";
        }
    });

    return app.exec();
}

# 8.2.2 QMediaPlayer功能

QMediaPlayer 提供了以下主要功能:

  • (1) 媒体播放:支持播放多种格式的音频和视频文件(如 MP3、WAV、MP4 等)。支持从本地文件、网络流或内存中加载媒体内容。
  • (2) 播放控制:播放/暂停:开始或暂停媒体播放。停止:停止播放并释放资源。跳转:跳转到指定时间点播放。循环播放:设置媒体是否循环播放。
  • (3) 状态和错误处理:提供媒体播放状态(如播放中、暂停、停止、错误等)。捕获并处理播放错误(如文件不存在、格式不支持等)。
  • (4) 元数据访问:获取媒体的元数据(如标题、作者、时长、封面等)。
  • (5) 音量控制:设置和获取播放音量。
  • (6) 视频输出:支持将视频渲染到 QVideoWidget 或自定义的 QAbstractVideoSurface。
  • (7) 信号与槽机制:通过信号与槽机制,实时响应播放状态、位置、音量等变化。

# 8.2.3 QMediaPlayer作用

QMediaPlayer 的主要作用是为 Qt 应用程序提供多媒体播放能力,适用于以下场景:

  • 音频播放:播放背景音乐、提示音、语音等。
  • 视频播放:播放本地或网络视频。
  • 流媒体:支持实时流媒体播放(如网络电台、直播等)。
  • 多媒体应用:用于开发音乐播放器、视频播放器、多媒体演示等应用。

# 8.2.4 核心方法API

以下是 QMediaPlayer 的常用方法:

方法 描述
setMedia(const QMediaContent &media) 设置媒体内容(文件路径或 URL)。
play() 开始播放。
pause() 暂停播放。
stop() 停止播放。
setPosition(qint64 position) 跳转到指定时间点(毫秒)。
setVolume(int volume) 设置音量(0-100)。
state() 获取当前播放状态。
duration() 获取媒体总时长(毫秒)。
position() 获取当前播放位置(毫秒)。
setVideoOutput(QVideoWidget *output) 设置视频输出到 QVideoWidget。

播放状态

  • state():获取当前播放状态(PlayingState、PausedState、StoppedState)。
  • mediaStatus():获取媒体状态(NoMedia、LoadedMedia、BufferingMedia 等)。

# 8.2.5 QMediaPlayer原理

QMediaPlayer 的工作原理基于 Qt 的多媒体模块,其核心流程如下:

(1) 媒体加载:使用 setMedia() 方法加载媒体文件或 URL。媒体内容可以是本地文件、网络资源或内存数据。

(2) 解码与播放:QMediaPlayer 依赖于底层的多媒体框架(如 GStreamer、DirectShow、AVFoundation 等)进行媒体解码。解码后的音频数据通过音频设备输出,视频数据通过 QVideoWidget 或自定义渲染器显示。

(3) 状态管理:QMediaPlayer 维护一个内部状态机,通过 state() 方法获取当前状态。包括以下状态:

  • StoppedState:停止状态。无论是手动调用 stop() 方法,还是播放结束,播放器都会进入 StoppedState。
  • PlayingState:播放中。
  • PausedState:暂停状态。

(4) 信号与槽:QMediaPlayer 通过信号与槽机制通知状态变化和事件,例如:

  • stateChanged(QMediaPlayer::State state):播放状态变化时触发。
  • mediaStatusChanged(QMediaPlayer::MediaStatus status):媒体状态变化时触发。
  • positionChanged(qint64 position):播放位置变化时触发。
  • durationChanged(qint64 duration):媒体总时长变化时触发。
  • error(QMediaPlayer::Error error):发生错误时触发。

(5) 资源管理:播放完成后,调用 stop() 方法释放资源。使用 setMedia(nullptr) 清除当前媒体内容。

# 8.2.6 QMediaPlayer信号槽

以下是 QMediaPlayer 的常用信号:

信号 描述
stateChanged(QMediaPlayer::State state) 播放状态变化时触发。
positionChanged(qint64 position) 播放位置变化时触发。
durationChanged(qint64 duration) 媒体时长变化时触发。
errorOccurred(QMediaPlayer::Error error, const QString &errorString) 播放出错时触发。
mediaStatusChanged(QMediaPlayer::MediaStatus status) 媒体状态变化时触发(如加载中、加载完成等)。
// 监听播放状态
QObject::connect(&player, &QMediaPlayer::stateChanged, [](QMediaPlayer::State state) {
    qDebug() << "State changed:" << state;
});

// 监听媒体状态
QObject::connect(&player, &QMediaPlayer::mediaStatusChanged, [](QMediaPlayer::MediaStatus status) {
    qDebug() << "Media status changed:" << status;
});

// 监听播放位置
QObject::connect(&player, &QMediaPlayer::positionChanged, [](qint64 position) {
    qDebug() << "Position changed:" << position;
});

// 监听错误
QObject::connect(&player, QOverload<QMediaPlayer::Error>::of(&QMediaPlayer::error), [](QMediaPlayer::Error error) {
    qDebug() << "Error occurred:" << error;
});

# 8.2.7 综合播放案例

#include <QCoreApplication>
#include <QMediaPlayer>
#include <QAudioOutput>
#include <QDebug>
#include <QFileInfo>

class AudioPlayer : public QObject {
    Q_OBJECT

public:
    AudioPlayer(const QString &filePath, QObject *parent = nullptr)
        : QObject(parent), m_player(new QMediaPlayer(this)), m_audioOutput(new QAudioOutput(this)) {
        // 设置音频输出
        m_player->setAudioOutput(m_audioOutput);

        // 设置媒体文件
        QFileInfo fileInfo(filePath);
        if (!fileInfo.exists()) {
            qWarning() << "File does not exist:" << filePath;
            QCoreApplication::exit(1);
            return;
        }
        m_player->setSource(QUrl::fromLocalFile(filePath));

        // 连接信号和槽
        connect(m_player, &QMediaPlayer::stateChanged, this, &AudioPlayer::onStateChanged);
        connect(m_player, &QMediaPlayer::mediaStatusChanged, this, &AudioPlayer::onMediaStatusChanged);
        connect(m_player, &QMediaPlayer::errorOccurred, this, &AudioPlayer::onErrorOccurred);

        // 开始播放
        m_player->play();
    }

private slots:
    // 处理播放状态变化
    void onStateChanged(QMediaPlayer::PlaybackState state) {
        switch (state) {
        case QMediaPlayer::StoppedState:
            qDebug() << "State: Stopped";
            break;
        case QMediaPlayer::PlayingState:
            qDebug() << "State: Playing";
            break;
        case QMediaPlayer::PausedState:
            qDebug() << "State: Paused";
            break;
        }
    }

    // 处理媒体状态变化
    void onMediaStatusChanged(QMediaPlayer::MediaStatus status) {
        switch (status) {
        case QMediaPlayer::NoMedia:
            qDebug() << "MediaStatus: No Media";
            break;
        case QMediaPlayer::LoadingMedia:
            qDebug() << "MediaStatus: Loading Media";
            break;
        case QMediaPlayer::LoadedMedia:
            qDebug() << "MediaStatus: Media Loaded";
            break;
        case QMediaPlayer::StalledMedia:
            qDebug() << "MediaStatus: Media Stalled";
            break;
        case QMediaPlayer::BufferingMedia:
            qDebug() << "MediaStatus: Buffering Media";
            break;
        case QMediaPlayer::BufferedMedia:
            qDebug() << "MediaStatus: Media Buffered";
            break;
        case QMediaPlayer::EndOfMedia:
            qDebug() << "MediaStatus: End of Media";
            QCoreApplication::quit(); // 播放结束后退出程序
            break;
        case QMediaPlayer::InvalidMedia:
            qDebug() << "MediaStatus: Invalid Media";
            break;
        }
    }

    // 处理播放错误
    void onErrorOccurred(QMediaPlayer::Error error, const QString &errorString) {
        qWarning() << "Error:" << errorString;
        switch (error) {
        case QMediaPlayer::NoError:
            break;
        case QMediaPlayer::ResourceError:
            qWarning() << "Resource Error: Unable to load media.";
            break;
        case QMediaPlayer::FormatError:
            qWarning() << "Format Error: Unsupported media format.";
            break;
        case QMediaPlayer::NetworkError:
            qWarning() << "Network Error: Network issue occurred.";
            break;
        case QMediaPlayer::AccessDeniedError:
            qWarning() << "Access Denied Error: Permission issue.";
            break;
        default:
            qWarning() << "Unknown Error.";
            break;
        }
        QCoreApplication::exit(1); // 发生错误时退出程序
    }

private:
    QMediaPlayer *m_player;
    QAudioOutput *m_audioOutput;
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    if (argc < 2) {
        qWarning() << "Usage: ./AudioPlayer <audio_file_path>";
        return 1;
    }

    QString filePath = argv[1];
    AudioPlayer player(filePath);

    return app.exec();
}

#include "main.moc"

# 8.2.8 音频效果处理

QAudioEffect 用于处理音频效果,如均衡器、混响等。

#include <QMediaPlayer>
#include <QAudioEffect>
#include <QUrl>

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    // 创建媒体播放器
    QMediaPlayer player;
    player.setMedia(QUrl::fromLocalFile("/path/to/audio.mp3"));

    // 创建音频效果(例如均衡器)
    QAudioEffect *effect = new QAudioEffect(&player);
    effect->setEffectType(QAudioEffect::EqualizerEffect);
    effect->setEnabled(true);

    // 播放音频
    player.play();

    return app.exec();
}

# 8.3 音频录制

# 8.3.1 QAudioRecorder介绍

QAudioRecorder 用于录制音频。

#include <QAudioRecorder>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // 创建音频录制器
    QAudioRecorder recorder;

    // 设置输出文件
    recorder.setOutputLocation(QUrl::fromLocalFile("/path/to/recording.wav"));

    // 开始录制
    recorder.record();

    qDebug() << "Recording started!";

    // 停止录制
    QTimer::singleShot(5000, [&recorder]() {
        recorder.stop();
        qDebug() << "Recording stopped!";
    });

    return app.exec();
}

# 8.4 视频播放

# 8.4.1 视频播放案例

QMediaPlayer 结合 QVideoWidget 可以播放视频。

#include <QApplication>
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QUrl>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建媒体播放器和视频窗口
    QMediaPlayer player;
    QVideoWidget videoWidget;
    // 设置视频文件
    player.setMedia(QUrl::fromLocalFile("/path/to/video.mp4"));
    // 将视频输出到窗口
    player.setVideoOutput(&videoWidget);
    // 显示窗口并播放视频
    videoWidget.show();
    player.play();

    return app.exec();
}

# 8.4.2 视频录制

QCamera 和 QMediaRecorder 用于录制视频。

#include <QApplication>
#include <QCamera>
#include <QMediaRecorder>
#include <QCameraViewfinder>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建摄像头和视图
    QCamera camera;
    QCameraViewfinder viewfinder;

    // 设置摄像头视图
    camera.setViewfinder(&viewfinder);

    // 创建媒体录制器
    QMediaRecorder recorder(&camera);

    // 设置输出文件
    recorder.setOutputLocation(QUrl::fromLocalFile("/path/to/recording.mp4"));

    // 显示摄像头视图
    viewfinder.show();

    // 开始录制
    camera.start();
    recorder.record();

    qDebug() << "Recording started!";

    // 停止录制
    QTimer::singleShot(10000, [&recorder]() {
        recorder.stop();
        qDebug() << "Recording stopped!";
    });

    return app.exec();
}

# 8.5 QCamera

# 8.5.1 QCamera介绍

QCamera 用于访问摄像头并显示实时画面。

#include <QApplication>
#include <QCamera>
#include <QCameraViewfinder>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    // 创建摄像头和视图
    QCamera camera;
    QCameraViewfinder viewfinder;
    // 设置摄像头视图
    camera.setViewfinder(&viewfinder);
    // 显示摄像头视图
    viewfinder.show();
    // 启动摄像头
    camera.start();
    return app.exec();
}

# 8.5.2 图像捕捉

QCameraImageCapture 用于从摄像头捕捉静态图像。

#include <QApplication>
#include <QCamera>
#include <QCameraImageCapture>
#include <QCameraViewfinder>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    // 创建摄像头和视图
    QCamera camera;
    QCameraViewfinder viewfinder;
    camera.setViewfinder(&viewfinder);
    // 创建图像捕捉器
    QCameraImageCapture imageCapture(&camera);
    // 显示摄像头视图
    viewfinder.show();
    // 启动摄像头
    camera.start();
    // 捕捉图像
    imageCapture.capture("/path/to/capture.jpg");
    return app.exec();
}

# 8.6 Qt 6 多媒体架构

# 8.6.1 Qt 5 vs Qt 6 多媒体模块变革

Qt 6 完全重写了多媒体模块——从 QMediaPlayer + QMediaRecorder 变为以 QMediaCaptureSession 为核心:

Qt 5 架构:                          Qt 6 架构:
QMediaPlayer                        QMediaPlayer
  ├── setMedia(url)                   ├── setSource(url)
  ├── setVideoOutput(widget)    →     ├── setVideoOutput(QVideoWidget)
  └── setAudioOutput(widget)          └── setAudioOutput(QAudioOutput)

QMediaRecorder                      QMediaCaptureSession (核心)
  ├── setOutput(url)                   ├── setCamera(QCamera)
  └── record() / stop()                ├── setAudioInput(QAudioInput)
                                       ├── setImageCapture(QImageCapture)
                                       ├── setVideoOutput(QVideoWidget)
                                       └── setRecorder(QMediaRecorder)
                                      QMediaRecorder
                                        └── record() / stop()

# 8.6.2 QMediaCaptureSession 综合使用

// Qt 6 典型的视频录制 + 预览
QMediaCaptureSession session;
QCamera camera;
QMediaRecorder recorder;
QVideoWidget viewfinder;

// 组装管线
session.setCamera(&camera);
session.setVideoOutput(&viewfinder);
session.setRecorder(&recorder);

// 配置录制
QMediaFormat format(QMediaFormat::MPEG4);
format.setVideoCodec(QMediaFormat::VideoCodec::H264);
recorder.setMediaFormat(format);
recorder.setOutputLocation(QUrl::fromLocalFile("/tmp/output.mp4"));

// 开始预览
camera.start();
viewfinder.show();

// 开始录制
recorder.record();
// ...
recorder.stop();

# 8.6.3 后端实现原理

Qt 多媒体在不同平台使用不同后端:

Qt 多媒体模块(Qt Multimedia):
  ├── Linux: GStreamer 管道
  │     QMediaPlayer → playbin
  │     QCamera      → v4l2src → ...
  │
  ├── macOS/iOS: AVFoundation
  │     QMediaPlayer → AVPlayer
  │     QCamera      → AVCaptureSession
  │
  ├── Windows: Windows Media Foundation (Qt 6)
  │     QMediaPlayer → IMFMediaEngine
  │
  └── 嵌入式 Linux: GStreamer + v4l2 + DRM/KMS
        QCamera → v4l2src ! video/x-raw ! ...
        渲染    → appsink → QVideoFrame → QVideoWidget

# 8.7 音频设备与编解码

# 8.7.1 QAudioDevice / QMediaDevices

Qt 6 统一了设备发现 API:

#include <QMediaDevices>

// 列出所有音频输出设备
for (const QAudioDevice& device : QMediaDevices::audioOutputs()) {
    qDebug() << "Output:" << device.description()
             << "channels:" << device.maximumChannelCount();
}

// 列出所有音频输入设备
for (const QAudioDevice& device : QMediaDevices::audioInputs()) {
    qDebug() << "Input:" << device.description();
}

// 列出所有摄像头
for (const QCameraDevice& device : QMediaDevices::videoInputs()) {
    qDebug() << "Camera:" << device.description()
             << "position:" << device.position();
}

// 选择特定设备播放
QAudioOutput output(QMediaDevices::defaultAudioOutput());

// 设备变化通知
connect(&QMediaDevices::instance(), &QMediaDevices::audioOutputsChanged,
        this, [this]() { rescanAudioDevices(); });

# 8.7.2 QAudioSink 低级音频输出

// 低级音频播放——直接推送 PCM 数据
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(2);
format.setSampleFormat(QAudioFormat::Int16);

QAudioDevice device = QMediaDevices::defaultAudioOutput();
if (!device.isFormatSupported(format)) {
    format = device.preferredFormat();
}

QAudioSink* audioSink = new QAudioSink(device, format, this);
QIODevice* stream = audioSink->start();  // 返回可写入的 QIODevice

// 生成并推送 PCM 数据
QByteArray pcmData = generateSineWave(440, 44100, 1000);  // 1 秒 440Hz 正弦波
stream->write(pcmData);

# 8.7.3 支持的编解码格式

类型 常见格式 依赖后端
音频播放 MP3, WAV, OGG, FLAC, AAC GStreamer / AVFoundation
视频播放 MP4, AVI, MKV, WebM GStreamer
视频编码 H.264, H.265, VP8, VP9 硬件编码器
音频编码 AAC, MP3, Opus GStreamer / CoreAudio
图像拍照 JPEG, PNG, BMP 内置

# 8.8 嵌入式多媒体实战

# 8.8.1 硬件加速

嵌入式 ARM 板(如 i.MX8)有硬件编解码器——Qt 通过 GStreamer 调用:

// 启用硬件加速视频解码
// 环境变量:
// GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0
// QT_GSTREAMER_USE_PLAYBIN_VO=1

// GStreamer 管道(Qt 自动构建,这里展示对应关系):
// 软件解码:
//   filesrc ! qtdemux ! h264parse ! avdec_h264 ! videoconvert ! appsink
//
// 硬件解码(i.MX8 VPU):
//   filesrc ! qtdemux ! h264parse ! vpudec ! videoconvert ! appsink

// 在代码中检查是否支持硬件加速
QMediaFormat format(QMediaFormat::MPEG4);
if (format.videoCodec() == QMediaFormat::VideoCodec::H264) {
    qDebug() << "Using H.264 codec";
}

# 8.8.2 QVideoSink ——直接访问视频帧

class VideoProcessor : public QObject {
    Q_OBJECT
public:
    void setPlayer(QMediaPlayer* player) {
        QVideoSink* sink = player->videoSink();
        connect(sink, &QVideoSink::videoFrameChanged,
                this, &VideoProcessor::onFrameChanged);
    }

private:
    void onFrameChanged(const QVideoFrame& frame) {
        if (!frame.isValid()) return;

        // 映射帧到 CPU 可访问内存
        QVideoFrame mappedFrame = frame;
        if (mappedFrame.map(QVideoFrame::ReadOnly)) {
            QImage image = mappedFrame.toImage();
            detectMotion(image);  // 运动检测
            mappedFrame.unmap();
        }
    }
};

# 8.8.3 低延迟视频预览

QCamera camera;
QMediaCaptureSession session;
QVideoWidget viewfinder;

session.setCamera(&camera);
session.setVideoOutput(&viewfinder);

void setupPreview() {
    viewfinder.setAspectRatioMode(Qt::KeepAspectRatio);
    viewfinder.setFullScreen(true);
    viewfinder.show();
    camera.start();

    // 调整相机参数
    camera.setFocusMode(QCamera::FocusModeAuto);
    camera.setWhiteBalanceMode(QCamera::WhiteBalanceAuto);
}

# 8.9 综合案例

# 案例:嵌入式视频监控与抓拍

class SurveillanceSystem : public QObject {
    Q_OBJECT

public:
    SurveillanceSystem() {
        auto cameras = QMediaDevices::videoInputs();
        if (cameras.isEmpty()) {
            qFatal("No camera found!");
            return;
        }
        m_camera.reset(new QCamera(cameras.first()));

        m_session.setCamera(m_camera.get());
        m_session.setVideoOutput(&m_viewfinder);
        m_viewfinder.show();

        m_imageCapture.reset(new QImageCapture);
        m_session.setImageCapture(m_imageCapture.get());

        m_recorder.reset(new QMediaRecorder);
        m_session.setRecorder(m_recorder.get());

        QMediaFormat format(QMediaFormat::MPEG4);
        format.setVideoCodec(QMediaFormat::VideoCodec::H264);
        m_recorder->setMediaFormat(format);

        // 运动检测——每 200ms 检查
        connect(&m_motionTimer, &QTimer::timeout, this, &SurveillanceSystem::checkMotion);
        m_motionTimer.start(200);

        m_camera->start();
    }

    void captureSnapshot(const QString& path) {
        m_imageCapture->captureToFile(path);
    }

    void startRecording(const QString& path) {
        m_recorder->setOutputLocation(QUrl::fromLocalFile(path));
        m_recorder->record();
    }

    void stopRecording() {
        m_recorder->stop();
    }

private:
    void checkMotion() {
        if (motionDetected()) {
            startRecording(generateTimestampedPath());
            QTimer::singleShot(30000, this, [this]() { stopRecording(); });
        }
    }

    QMediaCaptureSession m_session;
    QScopedPointer<QCamera> m_camera;
    QScopedPointer<QImageCapture> m_imageCapture;
    QScopedPointer<QMediaRecorder> m_recorder;
    QVideoWidget m_viewfinder;
    QTimer m_motionTimer;
};

# 8.10 速查表

类(Qt 6) 用途 关键方法
QMediaPlayer 音频/视频播放 setSource(), play(), pause(), stop()
QAudioOutput 音频输出 setVolume(), setMuted()
QMediaCaptureSession 多媒体管线核心 setCamera(), setRecorder(), setImageCapture()
QCamera 摄像头访问 start(), stop(), setFocusMode()
QImageCapture 图像抓拍 captureToFile(), capture()
QMediaRecorder 视频录制 record(), stop(), setMediaFormat()
QVideoWidget 视频预览窗口 show(), setAspectRatioMode()
QVideoSink 视频帧访问 videoFrameChanged()
QMediaDevices 设备发现 audioOutputs(), videoInputs()
QAudioSink 低级音频输出 start()(返回 QIODevice)
QMediaFormat 编解码格式 setVideoCodec(), setAudioCodec()

多媒体铁律:

  1. Qt 5 代码迁移到 Qt 6 需要重写多媒体部分——架构完全不同
  2. 嵌入式必须确保 GStreamer 插件齐全——缺失编解码器时静默失败
  3. QCamera 在启动前检查 isAvailable()——设备可能被占用
  4. 视频处理放到 QVideoSink::videoFrameChanged——不阻塞主线程
  5. 录制时使用 QMediaFormat::H264 硬件编码——CPU 软件编码无法实时
  6. QMediaCaptureSession 是 Qt 6 的核心——它连接所有多媒体组件
上次更新: 2026/07/02, 11:21:43
信号与槽机制
容器类和算法

← 信号与槽机制 容器类和算法→

最近更新
01
audit
07-27
02
C++入门教程全章思考题汇编
07-24
03
12.技术团队建设能力
07-21
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 鄂ICP备2024073355号-1 | 鄂ICP备2024073355号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式