ffmpeg 硬件解码 264 265 各个平台

一.命令行介绍

FFmpeg 支持多种平台的硬件解码,包括 H.264 (AVC) 和 H.265 (HEVC) 编解码器。以下是在不同平台上使用 FFmpeg 进行硬件解码的概述:

1. NVIDIA GPU (NVDEC)

适用于 Windows、Linux 和 macOS(较旧的 Mac 设备)。

- H.264: `-c:v h264_cuvid`
- H.265: `-c:v hevc_cuvid`

示例:
```
ffmpeg -hwaccel cuvid -c:v h264_cuvid -i input.mp4 -c:v h264_nvenc output.mp4
```

2. Intel Quick Sync Video

适用于 Windows 和 Linux,支持搭载 Intel 集成显卡的处理器。

- H.264: `-c:v h264_qsv`
- H.265: `-c:v hevc_qsv`

示例:
```
ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -c:v h264_qsv output.mp4
```

3. AMD GPU (AMD AMF)

主要适用于 Windows。

- H.264: `-c:v h264_amf`
- H.265: `-c:v hevc_amf`

示例:
```
ffmpeg -hwaccel amf -c:v h264_amf -i input.mp4 -c:v h264_amf output.mp4
```

4. Apple Video Toolbox

适用于 macOS 和 iOS 设备。

- H.264: `-c:v h264_videotoolbox`
- H.265: `-c:v hevc_videotoolbox`

示例:
```
ffmpeg -hwaccel videotoolbox -c:v h264_videotoolbox -i input.mp4 -c:v h264_videotoolbox output.mp4
```

5. VAAPI (Video Acceleration API)

主要用于 Linux 系统。

- H.264: `-c:v h264_vaapi`
- H.265: `-c:v hevc_vaapi`

示例:
```
ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -i input.mp4 -c:v h264_vaapi output.mp4
```

6. DXVA2 (DirectX Video Acceleration)

适用于 Windows 系统。

使用 `-hwaccel dxva2` 选项。

示例:
```
ffmpeg -hwaccel dxva2 -i input.mp4 -c:v h264_nvenc output.mp4
```

注意事项:

1. 确保你的 FFmpeg 版本支持所需的硬件加速。可以使用 `ffmpeg -hwaccels` 命令查看支持的硬件加速方法。

2. 某些硬件加速可能需要特定的驱动程序或额外的库。

3. 不同的 GPU 和驱动版本可能支持不同的功能,请查阅相关文档以获取特定配置的详细信息。

4. 在某些情况下,可能需要同时指定 `-hwaccel` 和 `-c:v` 选项以获得最佳性能。

5. 硬件解码的效果可能因具体的硬件和视频内容而异,建议进行测试以确定最佳配置。

使用硬件加速可以显著提高解码性能,特别是对于高分辨率或高帧率的视频。然而,输出质量可能会略有不同,因此在对质量要求极高的场景中,可能仍需要使用软件解码。
 

二.相关代码

以下是在不同平台上使用 FFmpeg 进行 H.264 和 H.265 硬件解码的 C++ 示例。这些示例使用 FFmpeg 的 C API,并假设你已经正确安装和链接了 FFmpeg 库。

首先,这里是一个通用的函数框架,我们将在每个平台特定的示例中使用:

```cpp
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/hwcontext.h>
#include <libavutil/opt.h>
}

#include <iostream>
#include <stdexcept>

void decode_video(const char* filename, enum AVHWDeviceType type) {
    AVFormatContext *input_ctx = nullptr;
    AVCodecContext *decoder_ctx = nullptr;
    AVStream *video = nullptr;
    const AVCodec *decoder = nullptr;
    AVPacket *packet = nullptr;
    AVFrame *frame = nullptr;

    int video_stream, ret;
    
    // 打开输入文件
    if (avformat_open_input(&input_ctx, filename, nullptr, nullptr) < 0) {
        throw std::runtime_error("Could not open input file");
    }

    if (avformat_find_stream_info(input_ctx, nullptr) < 0) {
        throw std::runtime_error("Could not find stream information");
    }

    // 找到视频流
    video_stream = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
    if (video_stream < 0) {
        throw std::runtime_error("Could not find video stream");
    }
    video = input_ctx->streams[video_stream];

    // 根据视频流的编解码器ID找到合适的解码器
    decoder = avcodec_find_decoder(video->codecpar->codec_id);
    if (!decoder) {
        throw std::runtime_error("Failed to find decoder");
    }

    // 分配解码器上下文
    decoder_ctx = avcodec_alloc_context3(decoder);
    if (!decoder_ctx) {
        throw std::runtime_error("Failed to allocate decoder context");
    }

    if (avcodec_parameters_to_context(decoder_ctx, video->codecpar) < 0) {
        throw std::runtime_error("Failed to copy codec parameters to decoder context");
    }

    // 设置硬件加速
    if (hw_decoder_init(decoder_ctx, type) < 0) {
        throw std::runtime_error("Failed to initialize hardware decoder");
    }

    if (avcodec_open2(decoder_ctx, decoder, nullptr) < 0) {
        throw std::runtime_error("Failed to open codec");
    }

    // 分配数据包和帧
    packet = av_packet_alloc();
    if (!packet) {
        throw std::runtime_error("Failed to allocate packet");
    }

    frame = av_frame_alloc();
    if (!frame) {
        throw std::runtime_error("Failed to allocate frame");
    }

    // 读取数据包并解码
    while (av_read_frame(input_ctx, packet) >= 0) {
        if (packet->stream_index == video_stream) {
            ret = avcodec_send_packet(decoder_ctx, packet);
            if (ret < 0) {
                throw std::runtime_error("Error sending packet for decoding");
            }
            
            while (ret >= 0) {
                ret = avcodec_receive_frame(decoder_ctx, frame);
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                    break;
                } else if (ret < 0) {
                    throw std::runtime_error("Error during decoding");
                }
                
                // 处理解码后的帧
                process_frame(frame);
            }
        }
        av_packet_unref(packet);
    }

    // 清理资源
    avformat_close_input(&input_ctx);
    av_frame_free(&frame);
    av_packet_free(&packet);
    avcodec_free_context(&decoder_ctx);
}

// 处理解码后的帧(这里只是打印一些信息)
void process_frame(AVFrame *frame) {
    std::cout << "Processed frame: " << frame->pts << std::endl;
}
```

现在,让我们看看如何为不同的平台实现 `hw_decoder_init` 函数:

1. NVIDIA GPU (NVDEC)

```cpp
static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) {
    int err = 0;
    if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type, nullptr, nullptr, 0)) < 0) {
        fprintf(stderr, "Failed to create specified HW device.\n");
        return err;
    }
    ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
    return err;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <input file>" << std::endl;
        return 1;
    }
    try {
        decode_video(argv[1], AV_HWDEVICE_TYPE_CUDA);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
```

2. Intel Quick Sync Video

```cpp
static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) {
    int err = 0;
    if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type, nullptr, nullptr, 0)) < 0) {
        fprintf(stderr, "Failed to create specified HW device.\n");
        return err;
    }
    ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
    return err;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <input file>" << std::endl;
        return 1;
    }
    try {
        decode_video(argv[1], AV_HWDEVICE_TYPE_QSV);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
```

3. AMD GPU (AMD AMF)

```cpp
static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) {
    int err = 0;
    if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type, nullptr, nullptr, 0)) < 0) {
        fprintf(stderr, "Failed to create specified HW device.\n");
        return err;
    }
    ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
    return err;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <input file>" << std::endl;
        return 1;
    }
    try {
        decode_video(argv[1], AV_HWDEVICE_TYPE_DRM);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
```

4. Apple Video Toolbox

```cpp
static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) {
    int err = 0;
    if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type, nullptr, nullptr, 0)) < 0) {
        fprintf(stderr, "Failed to create specified HW device.\n");
        return err;
    }
    ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
    return err;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <input file>" << std::endl;
        return 1;
    }
    try {
        decode_video(argv[1], AV_HWDEVICE_TYPE_VIDEOTOOLBOX);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
```

5. VAAPI (Video Acceleration API)

```cpp
static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) {
    int err = 0;
    if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type, "/dev/dri/renderD128", nullptr, 0)) < 0) {
        fprintf(stderr, "Failed to create specified HW device.\n");
        return err;
    }
    ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
    return err;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <input file>" << std::endl;
        return 1;
    }
    try {
        decode_video(argv[1], AV_HWDEVICE_TYPE_VAAPI);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
```

6. DXVA2 (DirectX Video Acceleration)

```cpp
static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) {
    int err = 0;
    if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type, nullptr, nullptr, 0)) < 0) {
        fprintf(stderr, "Failed to create specified HW device.\n");
        return err;
    }
    ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
    return err;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <input file>" << std::endl;
        return 1;
    }
    try {
        decode_video(argv[1], AV_HWDEVICE_TYPE_DXVA2);
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
```

注意:

1. 这些示例仅展示了基本的硬件解码流程,实际应用中可能需要更多的错误处理和资源管理。

2. 编译时需要链接相应的 FFmpeg 库,例如:
   ```
   g++ -o decoder decoder.cpp -lavformat -lavcodec -lavutil -lswscale
   ```

3. 某些平台可能需要额外的设置或库,请参考 FFmpeg 文档和相应平台的开发指南。

4. 这些示例主要关注解码过程,没有包括视频渲染或其他后续处理步骤。

5. 在使用硬件加速时,可能需要在系统中安装相应的驱动程序和支持库。

通过这些示例,你应该能够在不同平台上使用 FFmpeg 进行 H.264 和 H.265 的硬件解码。根据具体需求,你可能需要进一步优化或扩展这些代码。
 

  • 20
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值