FFmpeg硬件解码
使用FFmpeg进行硬件解码时,通常需要结合FFmpeg的API和硬件加速API(如CUDA、VAAPI、DXVA2等)。以下是一个简单的C++代码示例,展示如何使用FFmpeg进行硬件解码。这个示例使用了CUDA作为硬件加速的后端。
1. 安装FFmpeg和CUDA
确保你已经安装了FFmpeg和CUDA,并且在编译时链接了相关的库。
2. 示例代码
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/hwcontext.h>
#include <libavutil/hwcontext_cuda.h>
}
#include <iostream>
#include <stdexcept>
void decode(AVCodecContext* codec_ctx, AVPacket* pkt, AVFrame* frame) {
int ret = avcodec_send_packet(codec_ctx, pkt);
if (ret < 0) {
throw std::runtime_error("Error sending a packet for decoding");
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return;
} else if (ret < 0) {
throw std::runtime_error("Error during decoding");
}
// 处理解码后的帧
std::cout << "Frame decoded, width: " << frame->width << ", height: " << frame->height << std::endl;
}
}
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <input file>" << std::endl;
return 1;
}
const char* filename = argv[1];
av_register_all();
avformat_network_init();
AVFormatContext* format_ctx = nullptr;
if (avformat_open_input(&format_ctx, filename, nullptr, nullptr) != 0) {
std::cerr << "Could not open file " << filename << std::endl;
return 1;
}
if (avformat_find_stream_info(format_ctx, nullptr) < 0) {
std::cerr << "Could not find stream information" << std::endl;
return 1;
}
int video_stream_index = -1;
for (unsigned int i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
std::cerr << "Could not find a video stream" << std::endl;
return 1;
}
AVCodecParameters* codecpar = format_ctx->streams[video_stream_index]->codecpar;
AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);
if (!codec) {
std::cerr << "Unsupported codec" << std::endl;
return 1;
}
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
std::cerr << "Could not allocate video codec context" << std::endl;
return 1;
}
if (avcodec_parameters_to_context(codec_ctx, codecpar) < 0) {
std::cerr << "Could not copy codec parameters to codec context" << std::endl;
return 1;
}
// 设置硬件加速
AVBufferRef* hw_device_ctx = nullptr;
if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA, nullptr, nullptr, 0) < 0) {
std::cerr << "Failed to create CUDA hardware device context" << std::endl;
return 1;
}
codec_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
if (avcodec_open2(codec_ctx, codec, nullptr) < 0) {
std::cerr << "Could not open codec" << std::endl;
return 1;
}
AVPacket* pkt = av_packet_alloc();
AVFrame* frame = av_frame_alloc();
if (!pkt || !frame) {
std::cerr << "Could not allocate packet or frame" << std::endl;
return 1;
}
while (av_read_frame(format_ctx, pkt) >= 0) {
if (pkt->stream_index == video_stream_index) {
decode(codec_ctx, pkt, frame);
}
av_packet_unref(pkt);
}
// 刷新解码器
decode(codec_ctx, nullptr, frame);
av_frame_free(&frame);
av_packet_free(&pkt);
avcodec_free_context(&codec_ctx);
avformat_close_input(&format_ctx);
av_buffer_unref(&hw_device_ctx);
return 0;
}
3. 编译命令
假设你已经安装了FFmpeg和CUDA,并且它们的库和头文件在标准路径中,你可以使用以下命令编译代码:
g++ -o hw_decode hw_decode.cpp -lavcodec -lavformat -lavutil -lavdevice -lswscale -lavfilter -lavresample -lcuda
4. 运行
编译成功后,你可以运行生成的可执行文件,并传入一个视频文件作为参数:
./hw_decode input.mp4
5. 注意事项
-
这个示例使用了CUDA作为硬件加速的后端。如果你使用其他硬件加速API(如VAAPI、DXVA2等),你需要相应地修改代码。
-
确保你的系统支持所选的硬件加速API,并且已经正确安装了相关的驱动和库。
-
这个示例仅展示了基本的硬件解码流程,实际应用中可能需要处理更多的细节,例如帧格式转换、错误处理等。
最后展示是一个qt的demo
https://download.csdn.net/download/qq_42805085/90262623