深入理解FFmpeg--软/硬件解码流程
FFmpeg是一款强大的多媒体处理工具,支持软件和硬件解码。软件解码利用CPU执行解码过程,适用于各种平台,但可能对性能要求较高。硬件解码则利用GPU或其他专用硬件加速解码,能显著降低CPU负载,提升解码效率和能效。FFmpeg结合这两种解码方式,提供了灵活的多媒体解决方案,适合于视频处理、流媒体和多媒体应用开发。
1、FFmpeg支持多种硬件加速类型,用于编解码视频,以提升性能和效率。以下是FFmpeg支持的主要硬件加速类型:
- NVIDIA NVENC/NVDEC:利用NVIDIA显卡进行视频编码(NVENC)和解码(NVDEC)。
- Intel Quick Sync Video (QSV):利用Intel处理器中的集成图形进行视频加速。
- AMD Video Coding Engine (VCE)和Video Decoding Acceleration (VDA):利用AMD显卡进行视频编码和解码。
- VAAPI (Video Acceleration API):适用于Intel和AMD硬件,通过通用的API接口进行硬件加速。
- VDPAU (Video Decode and Presentation API for Unix):主要用于NVIDIA显卡的硬件解码加速。
- DXVA2 (DirectX Video Acceleration):适用于Windows平台,利用DirectX进行视频加速。
- OpenMAX IL (Open Media Acceleration Integration Layer):用于移动设备和嵌入式系统的视频加速。
- Vulkan:一种跨平台的图形和计算API,也可以用于视频加速。
这些硬件加速类型使FFmpeg在处理高分辨率视频时更加高效,减少了CPU负载,提高了多媒体处理的整体性能。
2、硬件解码流程图(软解流程比起硬解少一些步骤,就不单独画了):

3、代码示例:
Decode.h
#ifndef WINDOWS_FFMPEG_DECODE_H
#define WINDOWS_FFMPEG_DECODE_H
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
};
#include <memory>class Decode {
public:Decode();~Decode();//初始化软解码//IN:AVCodecID, AVPixelFormatint InitSoftDecode(int VideoType, int PixFmt);//初始化硬解码//IN:AVFormatContext输入上下文, 硬解类型名称int InitHardDecode(AVFormatContext* input_ctx, const std::string& HWType);//解码视频数据int DecodePacket(AVPacket* packet, AVFrame* frame);private://解码器上下文的get_format函数static enum AVPixelFormat get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts);//初始化AVBufferRefstatic int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type);private:AVCodecContext* pDecodeCtx_;AVCodecParserContext* pParseCtx_;AVStream* pVStream_;const AVCodec* pCodec_;static enum AVPixelFormat ePixFmt_;static AVBufferRef* pDeviceCtx;bool bHWDecode_;
};#endif //WINDOWS_FFMPEG_DECODE_H
Decode.cpp
#include "Decode.h"
#include <iostream>
using namespace std;enum AVPixelFormat Decode::ePixFmt_;
AVBufferRef* Decode::pDeviceCtx;
Decode::Decode() {}Decode::~Decode() {}enum AVPixelFormat Decode::get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts) {const enum AVPixelFormat *p;for (p = pix_fmts; *p != -1; p++) {if (*p == ePixFmt_)return *p;}fprintf(stderr, "Failed to get HW surface format.\n");return AV_PIX_FMT_NONE;
}int Decode::hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) {int err = 0;if ((err = av_hwdevice_ctx_create(&pDeviceCtx, type,nullptr, nullptr, 0)) < 0) {fprintf(stderr, "Failed to create specified HW device.\n");return err;}ctx->hw_device_ctx = av_buffer_ref(pDeviceCtx);return err;
}int Decode::InitSoftDecode(int VideoType, int PixFmt) {pCodec_ = avcodec_find_decoder((AVCodecID)VideoType);if (!pCodec_) {std::cout<<"avcodec_find_decoder Failed"<<std::endl;return -1;}pParseCtx_ = av_parser_init(pCodec_->id);if (!pParseCtx_) {std::cout<<"av_parser_init Failed"<<std::endl;return -1;}pDecodeCtx_ = avcodec_alloc_context3(pCodec_);if (!pDecodeCtx_) {std::cout<<"avcodec_alloc_context3 Failed"<<std::endl;return -1;}pDecodeCtx_->pix_fmt = (AVPixelFormat)PixFmt;if (avcodec_open2(pDecodeCtx_, pCodec_, nullptr) < 0) {std::cout<<"avcodec_open2 Failed"<<std::endl;return -1;}bHWDecode_ = false;return 0;
}int Decode::InitHardDecode(AVFormatContext* input_ctx, const std::string& HWType) {enum AVHWDeviceType type;type = av_hwdevice_find_type_by_name(HWType.c_str());if (type == AV_HWDEVICE_TYPE_NONE) {std::cout<<"UnKnown HW Device Type"<<std::endl;while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) {std::cout<< type <<std::endl;}return -1;}int video_index = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1 , -1, &pCodec_, 0);if (video_index < 0) {cout<<"Cannot find a video stream in the input file"<<endl;return -1;}for (int i = 0; ; i++) {const AVCodecHWConfig *config = avcodec_get_hw_config(pCodec_, i);if (!config) {cout<<"avcodec_get_hw_config Failed"<<i<<endl;return -1;}if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&config->device_type == type) {ePixFmt_ = config->pix_fmt;break;}}pDecodeCtx_ = avcodec_alloc_context3(pCodec_);if (!pDecodeCtx_) {cout<<"avcodec_alloc_context3 Failed"<<endl;return -1;}pVStream_ = input_ctx->streams[video_index];if (avcodec_parameters_to_context(pDecodeCtx_, pVStream_->codecpar) < 0) {cout<<"avcodec_parameters_to_context Failed"<<endl;return -1;}pDecodeCtx_->get_format = get_hw_format;if (hw_decoder_init(pDecodeCtx_, type) < 0) {return -1;}if (avcodec_open2(pDecodeCtx_, pCodec_, nullptr) < 0) {cout<<"avcodec_open2 Failed"<<endl;return -1;}bHWDecode_ = true;return 0;
}int Decode::DecodePacket(AVPacket* packet, AVFrame* frame) {//软解码if (!bHWDecode_) {int nRet = avcodec_send_packet(pDecodeCtx_, packet); //将AVPacket发送至解码器中if (nRet < 0) {cout<<"Error sending a packet for decoding"<<endl;return -1;}nRet = avcodec_receive_frame(pDecodeCtx_, frame); //从解码器中获取被解码后的帧数据AVFrameif (nRet == AVERROR(EAGAIN) || nRet == AVERROR_EOF)return 0;else if (nRet < 0) {cout<<"Error during decoding"<<endl;return -1;}return 0;} else { //硬解码AVFrame* tmpFrame = nullptr, *swFrame = nullptr;int nRet = avcodec_send_packet(pDecodeCtx_, packet); //将AVPacket发送至解码器中if (nRet < 0) {cout<<"Error sending a packet for decoding"<<endl;av_frame_free(&tmpFrame);av_frame_free(&swFrame);return -1;}if (!(tmpFrame = av_frame_alloc()) || !(swFrame = av_frame_alloc())) {cout<<"Can not alloc frame"<<endl;av_frame_free(&tmpFrame);av_frame_free(&swFrame);nRet = AVERROR(ENOMEM);return -1;}nRet = avcodec_receive_frame(pDecodeCtx_, tmpFrame); //从解码器中获取被解码后的帧数据AVFrameif (nRet == AVERROR(EAGAIN) || nRet == AVERROR_EOF) {av_frame_free(&tmpFrame);av_frame_free(&swFrame);return 0;} else if (nRet < 0) {cout<<"Error while decoding"<<endl;av_frame_free(&tmpFrame);av_frame_free(&swFrame);return -1;}if (frame->format == ePixFmt_) {/* 将GPU中的数据 移交到CPU中*/if (av_hwframe_transfer_data(swFrame, tmpFrame, 0) < 0) {cout<<"Error transferring the data to system memory"<<endl;av_frame_free(&tmpFrame);av_frame_free(&swFrame);return -1;}frame = swFrame;} else {frame = tmpFrame;}av_frame_free(&tmpFrame);av_frame_free(&swFrame);return 0;}
}
代码仅供参考,因为电脑太旧,硬解没识别出来支持的硬件,简单跟着深入理解FFmpeg写的Demo,有问题欢迎指正。
相关文章:
深入理解FFmpeg--软/硬件解码流程
FFmpeg是一款强大的多媒体处理工具,支持软件和硬件解码。软件解码利用CPU执行解码过程,适用于各种平台,但可能对性能要求较高。硬件解码则利用GPU或其他专用硬件加速解码,能显著降低CPU负载,提升解码效率和能效。FFmpe…...
新的铸造厂通过 PROFIBUS 技术实现完全自动化
钢铁生产商某钢以其在厚钢板类别中极高的产品质量而闻名。其原材料(板坯连铸机)在钢铁厂本地生产,该厂最近新建了一座垂直连铸厂。该项目的一个主要目标是从一开始就完全自动化这座新工厂和整个铸造过程,以高成本效率实现最佳产品…...
【UE5.1】NPC人工智能——04 NPC巡逻
效果 步骤 一、准备行为树和黑板 1. 对我们之前创建的AI控制器创建一个子蓝图类 这里命名为“BP_NPC_AIController_Lion”,表示专门用于控制狮子的AI控制器 2. 打开狮子蓝图“Character_Lion” 在类默认值中将“AI控制器类”修改为“BP_NPC_AIController_Lion” 3…...
计算机视觉主流框架及其应用方向
文章目录 前言一、计算机视觉领域的主要框架1、深度学习框架1.1、TensorFlow1.2、PyTorch 2、神经网络模型2.1、卷积神经网络(CNN)2.2、循环神经网络(RNN) 二、框架在计算机视觉任务中的应用1、TensorFlow1.1、概述:1.…...
群晖 搭建alist 记录
docker搭建 使用docker-compose 创建一个 docker-compose.yml version: 3.5services:qbittorrent:image: linuxserver/qbittorrent:latestcontainer_name: qbittorrent# network_mode: hostenvironment:- PUID1000- PGID100- TZAsia/Shanghai- WEBUI_PORT8181 # 将外部端口…...
【北航主办丨本届SPIE独立出版丨已确认ISSN号】第三届智能机械与人机交互技术学术会议(IHCIT 2024,7月27)
由北京航空航天大学指导,北京航空航天大学自动化科学与电气工程学院主办,AEIC学术交流中心承办的第三届智能机械与人机交互技术学术会议(IHCIT 2024)将定于2024年7月27日于中国杭州召开。 大会面向基础与前沿、学科与产业…...
深入浅出WebRTC—NACK
WebRTC 中的 NACK(Negative Acknowledgment)机制是实时通信中处理网络丢包的关键组件。网络丢包是常见的现象,尤其是在无线网络或不稳定连接中。NACK 机制旨在通过请求重传丢失的数据包来减少这种影响,从而保持通信的连续性和质量…...
简单工厂模式、工厂模式和抽象工厂模式的区别
简单工厂模式、工厂模式和抽象工厂模式都是创建型设计模式,它们之间在目的、实现方式和适用场景上存在显著的区别。以下是对这三种模式的详细比较: 一、定义与目的 简单工厂模式(Simple Factory Pattern) 定义: 简单工…...
JVM-垃圾回收与内存分配
目录 垃圾收集器与内存分配策略 引用 对象的访问方式有哪些?(句柄和直接指针) Java的引用有哪些类型? 如何判断对象是否是垃圾? 请列举一些可作为GC Roots的对象? 对象头了解吗? mark word(hashcode、分代、锁标志位)、…...
Jolt路线图
1. 引言 a16z crypto团队2024年7月更新了其Jolt路线图: 主要分为3大维度: 1)链上验证维度: 1.1)Zeromorph:见Aztec Labs团队2023年论文 Zeromorph: Zero-Knowledge Multilinear-Evaluation Proofs from…...
NEEP-EN2-2019-Text4
英二-2019-Text4摘自赫芬顿邮报《The Huffington Post》2018年6月的一篇名为“Let’s Stop Pretending Quitting Straws Will Solve Plastic Pollution”的文章。 以下为个人解析,非官方公开标准资料,可能有误,仅供参考。(单词解释…...
docker 部署wechatbot-webhook 并获取接口实现微信群图片自动保存到chevereto图库等
功能如图: docker部署 version: "3" services:excalidraw:image: dannicool/docker-wechatbot-webhook:latestcontainer_name: wechatbot-webhookdeploy:resources:limits:cpus: 0.15memory: 500Mreservations:cpus: 0.05memory: 80Mrestart: alwayspor…...
OpenWrt安装快速入门指南
在刷新 OpenWrt 固件之前,建议进行以下准备: 1、不要急于安装,慢慢来。如果在安装过程中出现奇怪之处,请先找到答案,然后再继续。 2、准备好设备的精确型号,以便能够选择正确的OpenWrt固件。 3、手上有关…...
AIGC Kolors可图IP-Adapter-Plus风格参考模型使用案例
参考: https://huggingface.co/Kwai-Kolors/Kolors-IP-Adapter-Plus 代码环境安装: git clone https://github.com/Kwai-Kolors/Kolors cd Kolors conda create --name kolors python=3.8 conda activate kolors pip install -r requirements.txt python3 setup.py install…...
从零开始学量化~Ptrade使用教程(七)——期权相关操作
期权交易 可点击证券代码右侧的选,进入期权选择菜单。通过选择标的商品,认购期权和认沽期权中间的选项(包括代码、成交价、幅度%、隐波%、内在价值、时间价值等),以及认购期权或认沽期权,选择所需的期权标的…...
TeamViewer关闭访问密码或固定一组密码不变
TeamViewer的新UI界面变化较大,网上的一些信息已经不再有效,更新后的访问密码在如下图所示: 演示的版本为7.21.4—— 设置每次你的设备访问的密码...
iMazing 3 换手机后苹果游戏数据还有吗 换iPhone怎么转移游戏数据
当你想要更换手机,无论是选择升级到最新款iPhone,或者换到“经典”旧款iPhone,单机游戏数据的转移总是让人发愁。本文将详细介绍换手机后苹果游戏数据还有吗,以及换iPhone怎么转移游戏数据,确保你能无缝继续你的游戏体…...
正则表达式:电子邮件地址的格式详解,及常见正则表达式符号的详细解释和匹配方式
一、第一部分是对该段电子邮件的详解 var Regex /^(?:\w\.?)*\w(?:\w\.)*\w$/; 1.^:这个符号表示匹配输入字符串的开始位置。 2.(?:...):这是一个非捕获组(non-capturing group),用于将正则表达式的一部分组合在…...
AWS全服务历史年表:发布日期、GA和服务概述一览(一)
我一直在尝试从各种角度撰写关于Amazon Web Services(AWS)的信息和魅力。由于我喜欢技术历史,这次我总结了AWS服务发布的历史年表。 虽然AWS官方也通过“Whats New”发布了官方公告,但我一直希望能有一篇文章将公告日期、GA日期&…...
现场可重构CPLD芯片应用案例—蓝牙音箱
我司英尚微提供的高性能数模混合现场可重构IC、通用可配置的模数混合芯片内部集成丰富的模拟资源和数字资源,可轻松替代电路中的各种标准器件,并按照客户要求组合成最优小型ASIC,缩短开发周期,降低成本。下面介绍LS98002现场可重构…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...
