本文转自公众号,欢迎关注
使用libjpeg-turbo进行JPG编解码-YUV422P转JPG为例 (qq.com)
一.前言
在UVC项目中需要测试MJPEG的传输, 通常JPG使用的是YUV420采样压缩,恰好有个UVC的显示设备不支持YUV420采样压缩,只支持YUV422采样压缩,所以需要生成YUV422采样压缩的JPG文件用于测试。于是使用libjpeg代码库生成。这里使用libjpeg-turbo,相对官方的libjpeg,其使用了SIMD进行了速度优化,并且进一步封装了接口,接口更简洁更方便使用。
关于YUV422和YUV420采样的JPG,以下文章有更详细的说明,总的来说YUV420更常见,毕竟都有损压缩了,使用YUV422带来的质量提升已经没什么意义了,使用YUV420空间更小,质量差异不大。https://calendar.perfplanet.com/2015/why-arent-your-images-using-chroma-subsampling/
项目见: https://github.com/libjpeg-turbo/libjpeg-turbo.git
https://libjpeg-turbo.org/
libjpeg见:http://www.ijg.org/files/
以下基于WSL+Ubuntu环境进行。
二.下载代码
lhj@lhj:~$ git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git
Cloning into 'libjpeg-turbo'...
remote: Enumerating objects: 19401, done.
remote: Counting objects: 100% (432/432), done.
remote: Compressing objects: 100% (199/199), done.
remote: Total 19401 (delta 259), reused 325 (delta 219), pack-reused 18969
Receiving objects: 100% (19401/19401), 17.02 MiB | 10.70 MiB/s, done.
Resolving deltas: 100% (14372/14372), done.
进入目录查看文件如下
lhj@lhj:~$ cd libjpeg-turbo/
lhj@lhj:~/libjpeg-turbo$ ls
BUILDING.md fuzz jconfig.txt jdhuff.c jfdctfst.c jstdhuff.c tjexampletest.in
CMakeLists.txt jaricom.c jconfigint.h.in jdhuff.h jfdctint.c jutils.c tjunittest.c
ChangeLog.md java jcparam.c jdicc.c jidctflt.c jversion.h.in tjutil.c
LICENSE.md jcapimin.c jcphuff.c jdinput.c jidctfst.c libjpeg.map.in tjutil.h
README.ijg jcapistd.c jcprepct.c jdlhuff.c jidctint.c libjpeg.txt transupp.c
README.md jcarith.c jcsample.c jdlossls.c jidctred.c md5 transupp.h
appveyor.yml jccoefct.c jcstest.c jdmainct.c jinclude.h rdbmp.c turbojpeg-jni.c
cderror.h jccolext.c jctrans.c jdmainct.h jlossls.h rdcolmap.c turbojpeg-mapfile
cdjpeg.c jccolor.c jdapimin.c jdmarker.c jmemmgr.c rdgif.c turbojpeg-mapfile.jni
cdjpeg.h jcdctmgr.c jdapistd.c jdmaster.c jmemnobs.c rdjpgcom.1 turbojpeg-mp.c
change.log jcdiffct.c jdarith.c jdmaster.h jmemsys.h rdjpgcom.c turbojpeg.c
cjpeg.1 jchuff.c jdatadst-tj.c jdmerge.c jmorecfg.h rdppm.c turbojpeg.h
cjpeg.c jchuff.h jdatadst.c jdmerge.h jpeg_nbits_table.h rdswitch.c usage.txt
doxygen-extra.css jcmaster.h jdct.h jerror.c jsamplecomp.h tjbench.c wrtarga.c
doxygen.config jcomapi.c jddctmgr.c jerror.h jsimd.h tjbenchtest.in
example.c jconfig.h.in jddiffct.c jfdctflt.c jsimddct.h tjexample.c
lhj@lhj:~/libjpeg-turbo$ code .
三.安装nasm
lhj@lhj:~/libjpeg-turbo$ sudo apt install nasm
[sudo] password for lhj:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
nasm
0 upgraded, 1 newly installed, 0 to remove and 224 not upgraded.
Need to get 362 kB of archives.
After this operation, 3374 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu focal/universe amd64 nasm amd64 2.14.02-1 [362 kB]
Fetched 362 kB in 2s (185 kB/s)
Selecting previously unselected package nasm.
(Reading database ... 131163 files and directories currently installed.)
Preparing to unpack .../nasm_2.14.02-1_amd64.deb ...
Unpacking nasm (2.14.02-1) ...
Setting up nasm (2.14.02-1) ...
Processing triggers for man-db (2.9.1-1) ...
四.编译
lhj@lhj:~/libjpeg-turbo$ mkdir build
lhj@lhj:~/libjpeg-turbo$ cd build
lhj@lhj:~/libjpeg-turbo/build$ cmake ../
-- The C compiler identification is GNU 9.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- CMAKE_BUILD_TYPE = Release
-- VERSION = 3.0.1, BUILD = 20230810
-- 64-bit build (x86_64)
-- CMAKE_INSTALL_PREFIX = /opt/libjpeg-turbo
-- CMAKE_INSTALL_BINDIR = bin (/opt/libjpeg-turbo/bin)
-- CMAKE_INSTALL_DATAROOTDIR = (/opt/libjpeg-turbo)
-- CMAKE_INSTALL_DOCDIR = doc (/opt/libjpeg-turbo/doc)
-- CMAKE_INSTALL_INCLUDEDIR = include (/opt/libjpeg-turbo/include)
-- CMAKE_INSTALL_LIBDIR = lib64 (/opt/libjpeg-turbo/lib64)
-- CMAKE_INSTALL_MANDIR = man (/opt/libjpeg-turbo/man)
-- Shared libraries enabled (ENABLE_SHARED = 1)
-- Static libraries enabled (ENABLE_STATIC = 1)
-- Arithmetic decoding support enabled (WITH_ARITH_DEC = 1)
-- Arithmetic encoding support enabled (WITH_ARITH_ENC = 1)
-- TurboJPEG API library enabled (WITH_TURBOJPEG = 1)
-- TurboJPEG Java wrapper disabled (WITH_JAVA = 0)
-- Emulating libjpeg API/ABI v6.2 (WITH_JPEG7 = 0, WITH_JPEG8 = 0)
-- libjpeg API shared library version = 62.4.0
-- Compiler flags = -O3 -DNDEBUG
-- Linker flags =
-- Looking for sys/types.h
-- Looking for sys/types.h - found
-- Looking for stdint.h
-- Looking for stdint.h - found
-- Looking for stddef.h
-- Looking for stddef.h - found
-- Check size of size_t
-- Check size of size_t - done
-- Check size of unsigned long
-- Check size of unsigned long - done
-- Performing Test HAVE_BUILTIN_CTZL
-- Performing Test HAVE_BUILTIN_CTZL - Success
-- Performing Test RIGHT_SHIFT_IS_UNSIGNED
-- Performing Test RIGHT_SHIFT_IS_UNSIGNED - Failed
-- Performing Test INLINE_WORKS
-- Performing Test INLINE_WORKS - Success
-- INLINE = __inline__ __attribute__((always_inline)) (FORCE_INLINE = 1)
-- Performing Test HAVE_THREAD_LOCAL
-- Performing Test HAVE_THREAD_LOCAL - Success
-- THREAD_LOCAL = __thread
-- Performing Test HAVE_VERSION_SCRIPT
-- Performing Test HAVE_VERSION_SCRIPT - Success
-- Linker supports GNU-style version scripts
-- CMAKE_EXECUTABLE_SUFFIX =
-- Looking for a ASM_NASM compiler
-- Looking for a ASM_NASM compiler - /usr/bin/nasm
-- The ASM_NASM compiler identification is NASM
-- Found assembler: /usr/bin/nasm
-- CMAKE_ASM_NASM_COMPILER = /usr/bin/nasm
-- CMAKE_ASM_NASM_OBJECT_FORMAT = elf64
-- CMAKE_ASM_NASM_FLAGS = -DELF -D__x86_64__ -DPIC
-- SIMD extensions: x86_64 (WITH_SIMD = 1)
-- FLOATTEST8 = sse
-- FLOATTEST12 = no-fp-contract
-- RPM architecture = x86_64, DEB architecture = amd64
-- Configuring done
-- Generating done
-- Build files have been written to: /home/lhj/libjpeg-turbo/build
lhj@lhj:~/libjpeg-turbo/build$ make
Scanning dependencies of target simd
[ 0%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jsimdcpu.asm.o
[ 0%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jfdctflt-sse.asm.o
[ 0%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jccolor-sse2.asm.o
[ 0%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jcgray-sse2.asm.o
[ 1%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jchuff-sse2.asm.o
[ 1%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jcphuff-sse2.asm.o
[ 1%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jcsample-sse2.asm.o
[ 1%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jdcolor-sse2.asm.o
[ 1%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jdmerge-sse2.asm.o
[ 2%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jdsample-sse2.asm.o
[ 2%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jfdctfst-sse2.asm.o
[ 2%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jfdctint-sse2.asm.o
[ 2%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jidctflt-sse2.asm.o
[ 3%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jidctfst-sse2.asm.o
[ 3%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jidctint-sse2.asm.o
[ 3%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jidctred-sse2.asm.o
[ 3%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jquantf-sse2.asm.o
[ 3%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jquanti-sse2.asm.o
[ 4%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jccolor-avx2.asm.o
[ 4%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jcgray-avx2.asm.o
[ 4%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jcsample-avx2.asm.o
[ 4%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jdcolor-avx2.asm.o
[ 5%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jdmerge-avx2.asm.o
[ 5%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jdsample-avx2.asm.o
[ 5%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jfdctint-avx2.asm.o
[ 5%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jidctint-avx2.asm.o
[ 5%] Building ASM_NASM object simd/CMakeFiles/simd.dir/x86_64/jquanti-avx2.asm.o
[ 6%] Building C object simd/CMakeFiles/simd.dir/x86_64/jsimd.c.o
[ 6%] Built target simd
Scanning dependencies of target turbojpeg12
.......
Scanning dependencies of target md5cmp
[ 99%] Building C object md5/CMakeFiles/md5cmp.dir/md5cmp.c.o
[100%] Building C object md5/CMakeFiles/md5cmp.dir/md5.c.o
[100%] Building C object md5/CMakeFiles/md5cmp.dir/md5hl.c.o
[100%] Linking C executable md5cmp
[100%] Built target md5cmp
生成文件如下
lhj@lhj:~/libjpeg-turbo/build$ ls
CMakeCache.txt cmake_uninstall.cmake jconfigint.h libjpeg.so md5 tjbench-static
CMakeFiles croptest jcstest libjpeg.so.62 pkgscripts tjbenchtest
CTestTestfile.cmake djpeg jpegtran libjpeg.so.62.4.0 rdjpgcom tjexample
Makefile djpeg-static jpegtran-static libturbojpeg.a sharedlib tjexampletest
cjpeg example jversion.h libturbojpeg.so simd tjunittest
cjpeg-static example-static libjpeg.a libturbojpeg.so.0 strtest tjunittest-static
cmake_install.cmake jconfig.h libjpeg.map libturbojpeg.so.0.3.0 tjbench wrjpgcom
五.安装
lhj@lhj:~/libjpeg-turbo/build$ sudo make install
安装于/opt/libjpeg-turbo/lib64
[sudo] password for lhj:
[ 6%] Built target simd
[ 7%] Built target turbojpeg12
[ 10%] Built target jpeg16
[ 16%] Built target jpeg12
[ 17%] Built target turbojpeg16
[ 31%] Built target turbojpeg
[ 31%] Built target turbojpeg12-static
[ 34%] Built target jpeg16-static
[ 40%] Built target jpeg12-static
[ 53%] Built target jpeg-static
[ 54%] Built target djpeg12-static
[ 54%] Built target djpeg16-static
[ 56%] Built target djpeg-static
[ 56%] Built target example-static
[ 57%] Built target tjexample
[ 57%] Built target turbojpeg16-static
[ 71%] Built target turbojpeg-static
[ 72%] Built target jpegtran-static
[ 73%] Built target tjunittest-static
[ 74%] Built target rdjpgcom
[ 75%] Built target tjunittest
[ 75%] Built target tjbench-static
[ 76%] Built target cjpeg16-static
[ 76%] Built target strtest
[ 77%] Built target cjpeg12-static
[ 79%] Built target cjpeg-static
[ 80%] Built target wrjpgcom
[ 81%] Built target tjbench
[ 81%] Built target cjpeg12
[ 81%] Built target cjpeg16
[ 93%] Built target jpeg
[ 94%] Built target cjpeg
[ 94%] Built target djpeg16
[ 94%] Built target djpeg12
[ 96%] Built target djpeg
[ 97%] Built target jpegtran
[ 98%] Built target example
[ 99%] Built target jcstest
[100%] Built target md5cmp
Install the project...
-- Install configuration: "Release"
-- Installing: /opt/libjpeg-turbo/lib64/libturbojpeg.so.0.3.0
-- Installing: /opt/libjpeg-turbo/lib64/libturbojpeg.so.0
-- Set runtime path of "/opt/libjpeg-turbo/lib64/libturbojpeg.so.0.3.0" to "/opt/libjpeg-turbo/lib64"
-- Installing: /opt/libjpeg-turbo/lib64/libturbojpeg.so
-- Installing: /opt/libjpeg-turbo/bin/tjbench
-- Set runtime path of "/opt/libjpeg-turbo/bin/tjbench" to "/opt/libjpeg-turbo/lib64"
-- Installing: /opt/libjpeg-turbo/lib64/libturbojpeg.a
-- Installing: /opt/libjpeg-turbo/include/turbojpeg.h
-- Installing: /opt/libjpeg-turbo/lib64/libjpeg.a
-- Installing: /opt/libjpeg-turbo/bin/rdjpgcom
-- Set runtime path of "/opt/libjpeg-turbo/bin/rdjpgcom" to "/opt/libjpeg-turbo/lib64"
-- Installing: /opt/libjpeg-turbo/bin/wrjpgcom
-- Set runtime path of "/opt/libjpeg-turbo/bin/wrjpgcom" to "/opt/libjpeg-turbo/lib64"
-- Installing: /opt/libjpeg-turbo/doc/README.ijg
-- Installing: /opt/libjpeg-turbo/doc/README.md
-- Installing: /opt/libjpeg-turbo/doc/example.c
-- Installing: /opt/libjpeg-turbo/doc/tjexample.c
-- Installing: /opt/libjpeg-turbo/doc/libjpeg.txt
-- Installing: /opt/libjpeg-turbo/doc/structure.txt
-- Installing: /opt/libjpeg-turbo/doc/usage.txt
-- Installing: /opt/libjpeg-turbo/doc/wizard.txt
-- Installing: /opt/libjpeg-turbo/doc/LICENSE.md
-- Installing: /opt/libjpeg-turbo/man/man1/cjpeg.1
-- Installing: /opt/libjpeg-turbo/man/man1/djpeg.1
-- Installing: /opt/libjpeg-turbo/man/man1/jpegtran.1
-- Installing: /opt/libjpeg-turbo/man/man1/rdjpgcom.1
-- Installing: /opt/libjpeg-turbo/man/man1/wrjpgcom.1
-- Installing: /opt/libjpeg-turbo/lib64/pkgconfig/libjpeg.pc
-- Installing: /opt/libjpeg-turbo/lib64/pkgconfig/libturbojpeg.pc
-- Installing: /opt/libjpeg-turbo/lib64/cmake/libjpeg-turbo/libjpeg-turboConfig.cmake
-- Installing: /opt/libjpeg-turbo/lib64/cmake/libjpeg-turbo/libjpeg-turboConfigVersion.cmake
-- Installing: /opt/libjpeg-turbo/lib64/cmake/libjpeg-turbo/libjpeg-turboTargets.cmake
-- Installing: /opt/libjpeg-turbo/lib64/cmake/libjpeg-turbo/libjpeg-turboTargets-release.cmake
-- Installing: /opt/libjpeg-turbo/include/jconfig.h
-- Installing: /opt/libjpeg-turbo/include/jerror.h
-- Installing: /opt/libjpeg-turbo/include/jmorecfg.h
-- Installing: /opt/libjpeg-turbo/include/jpeglib.h
-- Installing: /opt/libjpeg-turbo/lib64/libjpeg.so.62.4.0
-- Installing: /opt/libjpeg-turbo/lib64/libjpeg.so.62
-- Set runtime path of "/opt/libjpeg-turbo/lib64/libjpeg.so.62.4.0" to "/opt/libjpeg-turbo/lib64"
-- Installing: /opt/libjpeg-turbo/lib64/libjpeg.so
-- Installing: /opt/libjpeg-turbo/bin/cjpeg
-- Set runtime path of "/opt/libjpeg-turbo/bin/cjpeg" to "/opt/libjpeg-turbo/lib64"
-- Installing: /opt/libjpeg-turbo/bin/djpeg
-- Set runtime path of "/opt/libjpeg-turbo/bin/djpeg" to "/opt/libjpeg-turbo/lib64"
-- Installing: /opt/libjpeg-turbo/bin/jpegtran
-- Set runtime path of "/opt/libjpeg-turbo/bin/jpegtran" to "/opt/libjpeg-turbo/lib64"
六.测试
lhj@lhj:~/libjpeg-turbo/build$ sudo make test
Running tests...
Test project /home/lhj/libjpeg-turbo/build
Start 1: tjunittest-shared
1/590 Test #1: tjunittest-shared ................................... Passed 3.48 sec
Start 2: tjunittest-shared-alloc
2/590 Test #2: tjunittest-shared-alloc ............................. Passed 3.48 sec
......
Start 590: example-12bit-static-decompress-cmp
590/590 Test #590: example-12bit-static-decompress-cmp ................. Passed 0.00 sec
100% tests passed, 0 tests failed out of 590
Total Test time (real) = 79.40 sec
七.YUV422P转JPG
代码
#include < stdio.h >
#include < stdlib.h >
#include < stdint.h >
#include < sys/time.h >
#include < unistd.h >
#include < sys/stat.h >
#include < turbojpeg.h >
/*
Y = 0.298R + 0.612G + 0.117B; [13,235]
U = -0.168R - 0.330G + 0.498B + 128; [16,239]
V = 0.449R - 0.435G - 0.083B + 128; [16,239]
*/
uint8_t* yuv422p(uint32_t w, uint32_t h, uint32_t color)
{
uint8_t* p = (uint8_t*)malloc(w*h*2);
uint8_t* ret = p;
if(p == NULL)
{
return NULL;
}
int y = 0;
int u = 0;
int v = 0;
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
r = (color > > 16) & 0xFF;
g = (color > > 8) & 0xFF;
b = (color > > 0) & 0xFF;
y = (0.298*r + 0.612*g + 0.117*b);
u = (-0.168*r - 0.330*g + 0.498*b + 128);
v = (0.449*r - 0.435*g - 0.083*b + 128);
if(y >235)
{
y=235;
}
if(y< 16)
{
y=16;
}
if(u >239)
{
u=239;
}
if(u< 16)
{
u=16;
}
if(v >239)
{
v=239;
}
if(v< 16)
{
v=16;
}
for(int i=0;i< w*h;i++)
{
*p++ = y;
}
for(int i=0;i< w*h/2;i++)
{
*p++ = u;
}
for(int i=0;i< w*h/2;i++)
{
*p++ = v;
}
return ret;
}
/*写内存到文件*/
void write_buffer2file(char *filename, uint8_t *buffer, int size)
{
FILE *fd = fopen(filename,"wb");
if (NULL == fd) {
return;
}
fwrite(buffer,1,size,fd);
fclose(fd);
}
int tyuv2jpeg(unsigned char* yuv_buffer, int yuv_size, int width, int height, int subsample, unsigned char** jpeg_buffer, unsigned long* jpeg_size, int quality,char *name)
{
tjhandle handle = NULL;
int flags = 0;
int padding = 16; // 1或4均可,但不能是0
int need_size = 0;
int ret = 0;
handle = tjInitCompress();
flags |= 0;
need_size = tjBufSizeYUV2(width, padding, height, subsample);
if (need_size != yuv_size)
{
printf("we detect yuv size: %d, but you give: %d, check again.n", need_size, yuv_size);
return 0;
}
ret = tjCompressFromYUV(handle, yuv_buffer, width, padding, height, subsample, jpeg_buffer, jpeg_size, quality, flags);
if (ret < 0)
{
printf("compress to jpeg failed: %sn", tjGetErrorStr());
}
write_buffer2file(name,*jpeg_buffer,*jpeg_size);
tjDestroy(handle);
return ret;
}
int main()
{
unsigned long jpeg_size;
unsigned char* yuv_buffer;
unsigned char* jpeg_buffer;
yuv_buffer = yuv422p(800, 480, 0xFFFF00);
tyuv2jpeg(yuv_buffer, 800*480*2, 800, 480, TJSAMP_422, &jpeg_buffer, &jpeg_size, 90, "out.jpg");
free(yuv_buffer);
}
编译
gcc test.c -o test -lturbojpeg -I/opt/libjpeg-turbo/include -L/opt/libjpeg-turbo/lib64
运行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/libjpeg-turbo/lib64 && ./test
生成out.jpg
八. 总结
以上使用libjpeg实现了YUV422P转JPG,可以导入自己项目用于UVC的MJPEG测试。后面再单独讲将其移植到MCU以实现软jpg的编解码。
审核编辑 黄宇
-
测试
+关注
关注
8文章
5148浏览量
126436 -
编解码
+关注
关注
1文章
140浏览量
19594 -
Turbo
+关注
关注
1文章
57浏览量
18921 -
uvc
+关注
关注
1文章
126浏览量
14501
发布评论请先 登录
相关推荐
评论