* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "decode_heif_image.h"
#include <cstring>
#include <hilog/log.h>
#include "common.h"
#include <algorithm>
#include "libheif/heif.h"
extern "C" {
DecodeHEIFImage::DecodeHEIFImage() {}
DecodeHEIFImage::~DecodeHEIFImage() {}
void DecodeHEIFImage::swapRBChannels(uint8_t *pixels, int pixelCount)
{
int32_t two = 2;
int32_t four = 4;
for (int i = 0; i < pixelCount; i++) {
std::swap(pixels[i * four], pixels[i * four + two]);
}
}
DecodeResult *DecodeHEIFImage::decode_heif_image(MemoryStruct chunk)
{
struct heif_context *ctx = heif_context_alloc();
if (!ctx) {
OH_LOG_ERROR(LOG_APP, "分配 heif_context 失败");
return nullptr;
}
heif_error err = heif_context_read_from_memory_without_copy(ctx, chunk.memory, chunk.size, nullptr);
if (err.code != heif_error_Ok) {
OH_LOG_ERROR(LOG_APP, "读取 heif 图片错误: %{public}s", err.message);
heif_context_free(ctx);
return nullptr;
}
heif_image_handle *handle;
err = heif_context_get_primary_image_handle(ctx, &handle);
if (err.code != heif_error_Ok) {
OH_LOG_ERROR(LOG_APP, "获取主图像句柄错误: %{public}s", err.message);
heif_image_handle_release(handle);
heif_context_free(ctx);
return nullptr;
}
heif_image *heif_img;
err = heif_decode_image(handle, &heif_img, heif_colorspace_RGB, heif_chroma_interleaved_RGBA, nullptr);
if (err.code != heif_error_Ok) {
heif_image_handle_release(handle);
heif_context_free(ctx);
return nullptr;
}
int width;
int height;
width = heif_image_get_width(heif_img, heif_channel_interleaved);
height = heif_image_get_height(heif_img, heif_channel_interleaved);
int stride;
uint8_t *data = heif_image_get_plane_readonly(heif_img, heif_channel_interleaved, &stride);
if (data == nullptr) {
OH_LOG_ERROR(LOG_APP, "读取到的图像数据为空");
if (heif_img != nullptr) {
heif_image_release(heif_img);
heif_img = nullptr;
}
if (handle != nullptr) {
heif_image_handle_release(handle);
handle = nullptr;
}
if (ctx != nullptr) {
heif_context_free(ctx);
ctx = nullptr;
}
return nullptr;
}
if (!data) {
OH_LOG_ERROR(LOG_APP, "解码失败或图像数据为空");
return nullptr;
}
const size_t bpp = 4;
const size_t pixel_count = width * height;
const size_t row_bytes = width * bpp;
const size_t total_size = pixel_count * bpp;
uint8_t *new_data = data;
bool needAlignment = stride != row_bytes;
if (needAlignment) {
new_data = new (std::nothrow) uint8_t[total_size];
if (new_data == nullptr) {
OH_LOG_ERROR(LOG_APP, "内存分配失败");
return nullptr;
}
for (int row = 0; row < height; row++) {
errno_t err =
memcpy_s(new_data + row * row_bytes, total_size - row * row_bytes, data + row * stride, row_bytes);
if (err != 0) {
OH_LOG_ERROR(LOG_APP, "字节对齐失败");
}
}
}
if (new_data == nullptr) {
OH_LOG_ERROR(LOG_APP, "图像数据为空,无法进行通道转换");
return nullptr;
}
swapRBChannels(new_data, pixel_count);
DecodeResult *decodeResult = new DecodeResult(new_data, stride, width, height);
return decodeResult;
}
}