本文轉(zhuǎn)自公眾號(hào),歡迎關(guān)注
使用libjpeg-turbo進(jìn)行JPG編解碼-YUV422P轉(zhuǎn)JPG為例 (qq.com)
一.前言
在UVC項(xiàng)目中需要測試MJPEG的傳輸, 通常JPG使用的是YUV420采樣壓縮,恰好有個(gè)UVC的顯示設(shè)備不支持YUV420采樣壓縮,只支持YUV422采樣壓縮,所以需要生成YUV422采樣壓縮的JPG文件用于測試。于是使用libjpeg代碼庫生成。這里使用libjpeg-turbo,相對官方的libjpeg,其使用了SIMD進(jìn)行了速度優(yōu)化,并且進(jìn)一步封裝了接口,接口更簡潔更方便使用。
關(guān)于YUV422和YUV420采樣的JPG,以下文章有更詳細(xì)的說明,總的來說YUV420更常見,畢竟都有損壓縮了,使用YUV422帶來的質(zhì)量提升已經(jīng)沒什么意義了,使用YUV420空間更小,質(zhì)量差異不大。https://calendar.perfplanet.com/2015/why-arent-your-images-using-chroma-subsampling/
項(xiàng)目見: https://github.com/libjpeg-turbo/libjpeg-turbo.git
https://libjpeg-turbo.org/
libjpeg見:http://www.ijg.org/files/
以下基于WSL+Ubuntu環(huán)境進(jìn)行。
二.下載代碼
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.
進(jìn)入目錄查看文件如下
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轉(zhuǎn)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;
}
/*寫內(nèi)存到文件*/
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
運(yùn)行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/libjpeg-turbo/lib64 && ./test
生成out.jpg
八. 總結(jié)
以上使用libjpeg實(shí)現(xiàn)了YUV422P轉(zhuǎn)JPG,可以導(dǎo)入自己項(xiàng)目用于UVC的MJPEG測試。后面再單獨(dú)講將其移植到MCU以實(shí)現(xiàn)軟jpg的編解碼。
審核編輯 黃宇
-
測試
+關(guān)注
關(guān)注
8文章
5269瀏覽量
126596 -
編解碼
+關(guān)注
關(guān)注
1文章
140瀏覽量
19612 -
Turbo
+關(guān)注
關(guān)注
1文章
57瀏覽量
18954 -
uvc
+關(guān)注
關(guān)注
1文章
127瀏覽量
14527
發(fā)布評論請先 登錄
相關(guān)推薦
評論