您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# Qt ffmpeg录像存储实现详解
## 前言
在多媒体应用开发中,音视频录制与存储是核心功能之一。Qt作为跨平台应用框架,结合FFmpeg强大的多媒体处理能力,可以构建高效的录像存储系统。本文将详细介绍在Qt中如何利用FFmpeg实现录像存储功能,涵盖环境配置、核心流程、代码实现及优化策略。
---
## 一、环境准备
### 1.1 开发环境要求
- **Qt版本**:5.15或更高(推荐使用Qt6)
- **FFmpeg版本**:4.x或更高
- **编译器**:MSVC(Windows)、GCC(Linux)、Clang(macOS)
### 1.2 FFmpeg集成
#### Windows平台
1. 下载预编译的FFmpeg开发包(包含`include`、`lib`、`dll`)
2. 在Qt项目文件(.pro)中添加:
```qmake
win32 {
INCLUDEPATH += $$PWD/ffmpeg/include
LIBS += -L$$PWD/ffmpeg/lib -lavcodec -lavformat -lavutil -lswscale
}
# 安装FFmpeg开发包
sudo apt install libavcodec-dev libavformat-dev libavutil-dev # Ubuntu
brew install ffmpeg # macOS
graph TD
A[视频源] --> B[FFmpeg编码]
C[音频源] --> B
B --> D[MP4容器封装]
D --> E[本地存储]
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
#include <QDebug>
#include <QDateTime>
class FFmpegRecorder : public QObject {
Q_OBJECT
public:
explicit FFmpegRecorder(QObject *parent = nullptr);
bool startRecording(const QString &filename, int width, int height);
void stopRecording();
void encodeFrame(AVFrame *frame);
private:
AVFormatContext *m_formatCtx = nullptr;
AVCodecContext *m_videoCodecCtx = nullptr;
AVStream *m_videoStream = nullptr;
bool m_isRecording = false;
};
bool FFmpegRecorder::startRecording(const QString &filename, int width, int height) {
// 1. 分配输出上下文
avformat_alloc_output_context2(&m_formatCtx, nullptr, nullptr,
filename.toLocal8Bit().data());
if (!m_formatCtx) {
qWarning() << "Could not create output context";
return false;
}
// 2. 查找H.264编码器
const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec) {
qWarning() << "H.264 encoder not found";
return false;
}
// 3. 创建视频流
m_videoStream = avformat_new_stream(m_formatCtx, codec);
m_videoCodecCtx = avcodec_alloc_context3(codec);
// 4. 配置编码参数
m_videoCodecCtx->width = width;
m_videoCodecCtx->height = height;
m_videoCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
m_videoCodecCtx->time_base = (AVRational){1, 30}; // 30fps
// 5. 打开编码器
if (avcodec_open2(m_videoCodecCtx, codec, nullptr) < 0) {
qWarning() << "Could not open codec";
return false;
}
// 6. 打开输出文件
if (!(m_formatCtx->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&m_formatCtx->pb, filename.toLocal8Bit().data(),
AVIO_FLAG_WRITE) < 0) {
qWarning() << "Could not open output file";
return false;
}
}
// 7. 写入文件头
avformat_write_header(m_formatCtx, nullptr);
m_isRecording = true;
return true;
}
void FFmpegRecorder::encodeFrame(AVFrame *frame) {
if (!m_isRecording) return;
AVPacket *pkt = av_packet_alloc();
// 发送帧到编码器
if (avcodec_send_frame(m_videoCodecCtx, frame) < 0) {
qWarning() << "Error sending frame to encoder";
return;
}
// 接收编码后的包
while (avcodec_receive_packet(m_videoCodecCtx, pkt) >= 0) {
av_packet_rescale_ts(pkt, m_videoCodecCtx->time_base,
m_videoStream->time_base);
pkt->stream_index = m_videoStream->index;
// 写入文件
av_interleaved_write_frame(m_formatCtx, pkt);
av_packet_unref(pkt);
}
}
void FFmpegRecorder::stopRecording() {
if (!m_isRecording) return;
// 写入文件尾
av_write_trailer(m_formatCtx);
// 关闭编码器
if (m_videoCodecCtx) {
avcodec_close(m_videoCodecCtx);
avcodec_free_context(&m_videoCodecCtx);
}
// 关闭输出文件
if (m_formatCtx && !(m_formatCtx->oformat->flags & AVFMT_NOFILE)) {
avio_close(m_formatCtx->pb);
}
avformat_free_context(m_formatCtx);
m_isRecording = false;
}
// 使用QCamera采集
QCamera *camera = new QCamera(this);
QCameraViewfinder *viewfinder = new QCameraViewfinder(this);
camera->setViewfinder(viewfinder);
camera->start();
// 视频帧捕获
QVideoProbe *probe = new QVideoProbe(this);
if (probe->setSource(camera)) {
connect(probe, &QVideoProbe::videoFrameProbed, [this](const QVideoFrame &frame){
// 转换为AVFrame并编码
AVFrame *avFrame = convertQtFrameToAVFrame(frame);
m_recorder->encodeFrame(avFrame);
});
}
// 使用QAudioInput
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(2);
format.setSampleSize(16);
format.setCodec("audio/pcm");
QAudioInput *audioInput = new QAudioInput(format, this);
audioInput->start(m_recorder->audioDevice());
硬件加速:使用h264_nvenc
(NVIDIA)或h264_qsv
(Intel)编码器
const AVCodec *codec = avcodec_find_encoder_by_name("h264_nvenc");
多线程编码:
m_videoCodecCtx->thread_count = 4; // 使用4个编码线程
// 设置CRF(Constant Rate Factor)
av_opt_set(m_videoCodecCtx->priv_data, "crf", "23", 0);
// 设置预设(preset)
av_opt_set(m_videoCodecCtx->priv_data, "preset", "fast", 0);
// 每5分钟创建新文件
QTimer *splitTimer = new QTimer(this);
connect(splitTimer, &QTimer::timeout, [this](){
stopRecording();
startRecording(generateNewFilename(), width, height);
});
splitTimer->start(5 * 60 * 1000);
tune zerolatency
参数
av_opt_set(m_videoCodecCtx->priv_data, "tune", "zerolatency", 0);
ffprobe
分析文件结构本文详细介绍了Qt+FFmpeg实现录像存储的全流程。实际开发中还需考虑更多细节如错误恢复、跨平台兼容等。建议参考FFmpeg官方文档和Qt Multimedia模块的示例代码进行深入开发。
扩展阅读: - FFmpeg官方文档 - Qt Multimedia示例 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。