FFmpeg6.0 硬解码 qt demo
时间: 2025-06-03 10:18:01 浏览: 31
### FFmpeg 6.0 硬解码结合 Qt 示例代码及教程
以下内容详细介绍了如何在 FFmpeg 6.0 中结合 Qt 使用硬解码功能。硬解码通过利用硬件加速(如 NVIDIA CUDA 或 Intel QSV)来提升视频解码性能,尤其是在处理高分辨率或复杂编码格式时。
---
#### 1. 环境准备
在开始之前,确保已安装以下依赖项:
- FFmpeg 6.0(支持硬件加速的版本)
- Qt 5 或更高版本
- 目标硬件驱动程序(如 NVIDIA CUDA 驱动)
---
#### 2. 示例代码:使用 Qt 和 FFmpeg 实现硬解码
以下是一个完整的示例代码,展示如何在 Qt 中集成 FFmpeg 的硬解码功能。
```cpp
#include <QApplication>
#include <QMainWindow>
#include <QImage>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
class VideoDecoder : public QObject {
Q_OBJECT
public:
explicit VideoDecoder(QObject *parent = nullptr) : QObject(parent) {}
void decodeVideo(const QString &filePath) {
AVFormatContext *pFormatCtx = nullptr;
if (avformat_open_input(&pFormatCtx, filePath.toStdString().c_str(), nullptr, nullptr) != 0) {
qWarning() << "Could not open input file";
return;
}
if (avformat_find_stream_info(pFormatCtx, nullptr) < 0) {
qWarning() << "Failed to retrieve input stream information";
avformat_close_input(&pFormatCtx);
return;
}
int videoStreamIndex = -1;
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
qWarning() << "Did not find a video stream";
avformat_close_input(&pFormatCtx);
return;
}
AVCodecParameters *codecParams = pFormatCtx->streams[videoStreamIndex]->codecpar;
const AVCodec *codec = avcodec_find_decoder_by_name("h264_cuvid"); // 使用 CUDA 硬解码
if (!codec) {
qWarning() << "Codec not found";
avformat_close_input(&pFormatCtx);
return;
}
AVCodecContext *codecContext = avcodec_alloc_context3(codec);
if (!codecContext) {
qWarning() << "Failed to allocate codec context";
avformat_close_input(&pFormatCtx);
return;
}
if (avcodec_parameters_to_context(codecContext, codecParams) < 0) {
qWarning() << "Failed to copy codec parameters to codec context";
avcodec_free_context(&codecContext);
avformat_close_input(&pFormatCtx);
return;
}
if (avcodec_open2(codecContext, codec, nullptr) < 0) {
qWarning() << "Failed to open codec";
avcodec_free_context(&codecContext);
avformat_close_input(&pFormatCtx);
return;
}
AVPacket packet;
av_init_packet(&packet);
AVFrame *frame = av_frame_alloc();
if (!frame) {
qWarning() << "Failed to allocate frame";
avcodec_free_context(&codecContext);
avformat_close_input(&pFormatCtx);
return;
}
SwsContext *sws_ctx = sws_getContext(
codecContext->width, codecContext->height, codecContext->pix_fmt,
codecContext->width, codecContext->height, AV_PIX_FMT_RGB32,
SWS_BILINEAR, nullptr, nullptr, nullptr
);
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
int ret = avcodec_send_packet(codecContext, &packet);
if (ret < 0) {
qWarning() << "Error sending a packet for decoding";
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codecContext, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
qWarning() << "Error during decoding";
break;
}
uint8_t *data[4] = {nullptr};
int linesize[4] = {0};
av_image_alloc(data, linesize, codecContext->width, codecContext->height, AV_PIX_FMT_RGB32, 16);
sws_scale(sws_ctx, frame->data, frame->linesize, 0, codecContext->height, data, linesize);
QImage image(data[0], codecContext->width, codecContext->height, linesize[0], QImage::Format_RGBA8888);
emit frameDecoded(image); // 发送解码后的帧给 UI
av_freep(&data[0]);
}
}
av_packet_unref(&packet);
}
av_frame_free(&frame);
sws_freeContext(sws_ctx);
avcodec_free_context(&codecContext);
avformat_close_input(&pFormatCtx);
}
signals:
void frameDecoded(QImage image);
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QMainWindow window;
QLabel label(&window);
label.setScaledContents(true);
label.setGeometry(0, 0, 800, 600);
VideoDecoder decoder;
QObject::connect(&decoder, &VideoDecoder::frameDecoded, [&label](const QImage &image) {
label.setPixmap(QPixmap::fromImage(image));
});
decoder.decodeVideo("input.mp4");
window.show();
return app.exec();
}
#include "main.moc"
```
---
#### 3. 关键点解析
1. **硬解码器选择**
在示例中,`h264_cuvid` 是 NVIDIA CUDA 硬解码器的名称。根据目标硬件,可以选择其他硬解码器,例如 `h264_vdpau` 或 `h264_qsv`[^4]。
2. **Qt 与 FFmpeg 的集成**
使用 `QImage` 将解码后的帧转换为 Qt 图像格式,并通过信号槽机制将图像传递到 UI 层进行显示。
3. **硬件加速支持**
硬解码需要目标设备支持相应的硬件加速技术。例如,CUDA 只能在 NVIDIA 显卡上使用[^4]。
4. **错误处理**
FFmpeg 提供了丰富的错误码机制,确保在解码过程中捕获并处理潜在问题。
5. **资源释放**
解码完成后,必须正确释放所有分配的资源,包括 `AVPacket`、`AVFrame` 和 `AVCodecContext`。
---
#### 4. 注意事项
- 硬解码依赖于硬件支持,确保目标设备驱动程序已正确安装。
- 根据目标平台选择合适的硬解码器名称。
- 在多线程环境中使用 FFmpeg 时,需注意线程安全问题。
---
###
阅读全文
相关推荐

















