本文轉自公眾號,歡迎關注
使用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文章
5299瀏覽量
126636 -
編解碼
+關注
關注
1文章
140瀏覽量
19617 -
Turbo
+關注
關注
1文章
57瀏覽量
18960 -
uvc
+關注
關注
1文章
127瀏覽量
14530
發布評論請先 登錄
相關推薦
評論