使用libjpeg-turbo进行JPG编解码-YUV422P转JPG为例

描述

本文转自公众号,欢迎关注
使用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的编解码。

编解码

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分