FFmpeg硬件解码

使用FFmpeg进行硬件解码时,通常需要结合FFmpeg的API和硬件加速API(如CUDA、VAAPI、DXVA2等)。以下是一个简单的C++代码示例,展示如何使用FFmpeg进行硬件解码。这个示例使用了CUDA作为硬件加速的后端。

1. 安装FFmpeg和CUDA

确保你已经安装了FFmpeg和CUDA,并且在编译时链接了相关的库。

2. 示例代码

cpp 复制代码
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,并且它们的库和头文件在标准路径中,你可以使用以下命令编译代码:

bash 复制代码
g++ -o hw_decode hw_decode.cpp -lavcodec -lavformat -lavutil -lavdevice -lswscale -lavfilter -lavresample -lcuda

4. 运行

编译成功后,你可以运行生成的可执行文件,并传入一个视频文件作为参数:

bash 复制代码
./hw_decode input.mp4

5. 注意事项

  • 这个示例使用了CUDA作为硬件加速的后端。如果你使用其他硬件加速API(如VAAPI、DXVA2等),你需要相应地修改代码。

  • 确保你的系统支持所选的硬件加速API,并且已经正确安装了相关的驱动和库。

  • 这个示例仅展示了基本的硬件解码流程,实际应用中可能需要处理更多的细节,例如帧格式转换、错误处理等。

最后展示是一个qt的demo

https://download.csdn.net/download/qq_42805085/90262623

相关推荐
iummature6 小时前
FFmpeg命令
ffmpeg
渔舟唱晚@8 小时前
FFmpeg+WebSocket+JsMpeg实时视频流实现方案
websocket·网络协议·ffmpeg
xcg3401231 天前
关于视频抽帧调用虹软人脸识别的BufferedImage读取优化策略
ffmpeg·音视频·视频抽帧
繁依Fanyi1 天前
使用 FFmpeg 剪辑视频指南
java·服务器·开发语言·ffmpeg·音视频
deadknight92 天前
定期自动统计大表执行情况
ffmpeg
cuijiecheng20184 天前
音视频入门基础:RTP专题(9)——FFmpeg接收RTP流的原理和内部实现
ffmpeg·音视频
偶是老李头4 天前
Ubuntu虚拟机NDK编译ffmpeg
linux·ubuntu·ffmpeg·android ndk
lucky-billy4 天前
Qt 中使用 ffmpeg 获取采集卡数据录制视频
qt·ffmpeg·音视频
cuijiecheng20185 天前
FFmpeg源码:url_find_protocol函数分析
ffmpeg
大懒猫软件5 天前
使用 Python 爬虫和 FFmpeg 爬取 B 站高清视频
爬虫·python·ffmpeg