buildroot下libjpeg-turbo的使用
libjpeg-turbo是一种JPEG图像编解码器的库,它使用SIMD指令(MMX、SSE2、AVX2、NEON、AltiVec)来加速x86、x86-64、ARM和PowerPC系统上的基线JPEG压缩和解压缩。libjpeg库使用的更广泛,不过它是使用纯c语言编写的,所以编解码速度慢。 libjpeg-turbo的速度通常是libjpeg的2-6倍。
libjpeg-turbo支持rgba图像数据转jpeg,或者yuv格式的图像数据转jpeg。反之亦然。
主要功能
libjpeg-turbo包含两种API,一种是libjpeg-turbo,另一种是libjpeg。当两种API都用于执行类似的操作时,这两种API没有显著的性能优势。具体的api使用方法可以参考 doc/index.html 网页的Modules下面的TurboJPEG链接的内容。
libjpeg-turbo 使用起来更简单。
libjpeg API 的存在是为了与API/ABI兼容,又与libjpeg v6b在数学上兼容。它还可以可选地配置为与libjpeg v7和v8兼容的API/ABI。
libjpeg-turbo库提供的功能主要分为4类,包括编码,解码,格式转换,和读写bmp文件。
-
编码
将一个rgb图像编码为jpeg文件
将一个yuv图像编码为jpeg文件 -
解码
获取jpeg文件宽高,采样率,色彩空间等信息
将一个jpeg文件解码为rgb图像
将一个jpeg文件解码为yuv图像 -
格式转换
rgb图像转为yuv图像
yuv图像转rgb图像 -
bmp
读取一个bmp文件到内存
将图像数据保存为bmp文件
编译库
-
查看cpu是否支持simd指令。
通产cpu的数据手册会提示你有没有simd指令,如neon指令。也可以在linux板子上执行cat /proc/cpuinfo
查看cpu信息。 -
检查buildroot是否已经配置了simd指令,如neon指令。
检查buildroot的output文件夹下面的某个项目里的.config文件,里面是否有 BR2_ARM_CPU_HAS_NEON=y这个配置,没有的话,编译库的时候要加上。 -
可以参考BUILDING.md文件编译这个库。
使用buildroot方式编译时,不需要参考这个md文件,只要在configs配置文件中添加 BR2_PACKAGE_JPEG=y 即可。这个配置包括两个配置选项,一个是jpeg库,另一个是jpegturbo库,所以,当cpu支持simd指令时,buildroot不会编译jpeg库,而是会编译jpegturbo库。编译完成后,会生成最重要的libturbojpeg.so文件和turbojpeg.h文件。
测试
编译成功后,会产生一些可执行程序,将它们和生成的.so库文件一起拷到开发板上,便可开始测试。
-
tjexample
主要用于把一个bmp文件转为jpeg,或者将一个jpeg文件转为bmp文件。
bmp转jpeg:./tjexample input.bmp output.jpg
jpeg转bmp./tjexample input.jpg output.bmp
-
tjbench
测试编码或者解码性能
测试编码性能:./tjbench cif.bmp 90
// 90为编码质量,范围为[1, 100]
测试解码性能:./tjbench cif.jpg
以下是rv1126_1109芯片所测的数据,测试的图片大小为1280x720,使用arm neon指令,4核Cortex-A7 1.5Ghz,测试时cpu大概占用25%。
示例
以下代码会生成一个红色图片的jpg文件,保存在 /tmp/123.jpg 文件上。文章来源:https://uudwc.com/A/VR6o
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <turbojpeg.h>
#define _throw(action, message) { \
printf("ERROR in line %d while %s:\n%s\n", __LINE__, action, message); \
retval = -1; goto bailout; \
}
#define _throwtj(action) _throw(action, tjGetErrorStr2(tjInstance))
void encode_jpeg_by_cpu(const void *input, int width, int height, int pixelFormat, void *output, unsigned long *size)
{
int retval = 0;
tjhandle tjInstance = NULL; // 句柄
unsigned char *jpegBuf = NULL;
// pixelFormat = { TJPF_RGB, TJPF_BGR, TJPF_BGRX, TJPF_BGRX, TJPF_XRGB, TJPF_GRAY, TJPF_RGBA,
// TJPF_BGRA, TJPF_ABGR, TJPF_ARGB, TJPF_CMYK, TJPF_UNKNOWN};
*size = 0;
if ((tjInstance = tjInitCompress()) == NULL) // 创建一个TurboJPEG编码器实例
_throwtj("initializing compressor");
if (tjCompress2(tjInstance, (const unsigned char *)input, width, 0, height, pixelFormat, // 将图像编码为jpeg文件
&jpegBuf, size, TJSAMP_444, 90, 0) < 0) // 编码质量为90,取值范围为[1,100],超过95会导致性能下降严重。
_throwtj("compressing image");
tjDestroy(tjInstance); tjInstance = NULL; // 销毁一个TurboJPEG编码器实例
memcpy(output, jpegBuf, *size);
tjFree(jpegBuf); jpegBuf = NULL;
bailout:
if (tjInstance) tjDestroy(tjInstance);
if (jpegBuf) tjFree(jpegBuf);
}
int main(int argc, char *argv[])
{
unsigned long size;
int *red = malloc(640 * 480 * 4);
int *jpeg = malloc(640 * 480 * 4);
// 1. 生成红色图像
for (int i = 0; i < 480; i++)
for (int j = 0; j < 640; j++)
red[i * 640 + j] = 0xffff0000;
// 2.编码
encode_jpeg_by_cpu(red, 640, 480, TJPF_BGRA, jpeg, &size);
// 3.写入文件
FILE *file = fopen("/tmp/123.jpg", "wb+");
fwrite(jpeg, size, 1, file);
fclose(file);
printf("generate red picture to /tmp/123.jpg success!\n");
}
将源文件保存为red.c,则编译命令为:arm-linux-gnueabihf-gcc red.c -o red -lturbojpeg
,输出应用程序red。运行前需把red和libturbojpeg.so一起拷贝到开发板上。文章来源地址https://uudwc.com/A/VR6o