【AVD】简述 C++ 解码 HEIF HEIC 图片

21 篇文章 0 订阅

随着软硬件技术的不断升级,相机像素越来越高、人们对照片细节的要求越来越多,高压缩率、低损失率的编码格式,heic 越来越多地出现在人们的生活中,现在 iOS 相机已经默认保存 heic 格式的图片了。而通常情况下,FFmpeg 是不支持对 heif 解析的。

无法解析 heic 格式的 FFmpeg

当第一次遇到 HEIC 格式的图片时,遇到了 FFmpeg 的报错,av_format_open_input() 这个接口的调用就失败了,也就是说,FFmpeg 对 HEIC 这种封装格式没法解析。

简单了解了一下 HEIC 相关的知识点,它是使用 hevc,也就是 h265 编码格式压缩的。因此,解码其实并不是问题的所在,heic 的封装格式才是。

自带示例 demo 的 libheif

通过查资料发现,一个比较常见的 C++ 解析解码 heic 格式图片的开源库是 libheif,而这个库对 h265 的解码过程又依赖于另一个开源 C++ 库 libde265

同时从 github 上下载了这两个开源库。根据 github 上两个库 readme.md 的内容,依次编译通过 libde265 和 libheif 之后,就可以参考 libheif/examples/heif_convert.cc 来完成一个简单的对 HEIC 格式图片的解析、解码的过程。主要调用的函数如下:

#include <libheif/heif.h>
bool decodeheif(string filename) {
  	// 类似于 ffmpeg AVFormatContext,heif 也需要一个上下文环境
  	heif_context* heif_ctx_ = heif_context_alloc();
  	if (!heif_ctx_) return false;
	// 读取文件
	heif_error error = heif_context_read_from_file(heif_ctx_, filename.c_str(), nullptr);
  	if (error.code != heif_error_Ok) return false;
  	// 获取图片句柄(handle),这里,primary 可以理解为主图片。因为 heif 格式是支持将图片的原始图片(主图片)和不同等级的缩略图一起放在同一个文件里的。因此,如非需要,我们主要获取其主图片即可。再注意,这里传入的是指针的指针,即 heif_image_handle**
  	heif_image_handle *heif_handle_ = nullptr;
  	error = heif_context_get_primary_image_handle(heif_ctx_, &heif_handle_);
  	if (error.code != heif_error_Ok) return false;
  	// 获取图片宽高,注意,由于之前我们是获取的是主图片的句柄,因此这里获取的是当前句柄下图片的宽高
  	width_ = heif_image_handle_get_width(heif_handle_);
  	height_ = heif_image_handle_get_height(heif_handle_);
  	// 解码,注意,这里需要再申请一个 heif_image 的指针变量,并将其地址传入该函数,即作为传出参数使用。
  	// 此外,这里的 heif_colorspace_RGB 也可以用 heif_colorspace_YCbCr,
  	// 同样地,后面的 heif_chroma_interleaved_RGBA 也可以用 heif_chroma_420 代替,
  	// 来获取 YUV 420 的图像数据,可能解码效率上会快很多
  	heif_image* heif_img_ = nullptr;
	error = heif_decode_image(heif_handle_, &heif_img_, heif_colorspace_RGB, heif_chroma_interleaved_RGBA, nullptr);
  	if (error.code != heif_error_Ok) return false;
  	int stride;
  	// 解码完成之后,还需要调用下面的方法来获取解码数据的只读地址。拿到地址后如何使用,则看自己的了。
  	// 我通常是直接 memcpy 到一个内存去使用,当然,也可以直接直接 glTexture2D 到 GPU 显存中去
  	const uint8_t *data = heif_image_get_plane_readonly(heif_img_, heif_channel_interleaved, &stride);
  	if (data == nullptr) return false;
}

对 libheif 相关环境变量内存的释放也很简单:

  if (heif_ctx_) {
    heif_context_free(heif_ctx_);
    heif_ctx_ = nullptr;
  }
  if (heif_handle_) {
    heif_image_handle_release(heif_handle_);
    heif_handle_ = nullptr;
  }
  if (heif_img_) {
    heif_image_release(heif_img_);
    heif_img_ = nullptr;
  }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深海Enoch

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值