zynq7000平台交叉编译libjpeg-turbo库,并对YUV420P图像编码传输

参考资料:

    《 IMX6平台交叉编译libjpeg-turbo》    来自https://blog.csdn.net/lang523493505/article/details/81104404

    《嵌入式平台使用libjpeg-turbo将YUV420SP保存为jpg》  来自

    《libjpeg-turbo使用实例(编解码jpeg、jpg转bmp、bmp转jpg代码)》 来自

 

 

主要内容:

1.  本ADAS项目采用usb虚拟串口将图像数据上传到PC实时显示;

2.  由于usb2.0接口带宽限制,不能实时传输1280*720*15帧的YUV420P原图数据,需要采用jpeg编码压缩数据才能传输。

3.  因此采用libjpeg-turbo库,将YUV420P原图编码成JPEG压缩图传输。

 

 

开发环境:

          window7 + VMware12中安装(ubuntu16.04.3     +  SDX2017.4)

运行环境:   

         硬件环境:  zynq7020   + SD  +  usb2.0虚拟串口传输数据;

        软件环境:   linux-xlnx-xilinx-v2017.4 (kernel 4.9)

 

1、下载libjpeg-turbo库

        参考《 IMX6平台交叉编译libjpeg-turbo》    来自https://blog.csdn.net/lang523493505/article/details/81104404

 

2、配置、编译、安装

    2.1  libjpeg-turbo-1.5.3编译

       解压进入libjpeg-turbo-1.5.3目录,执行如下配置编译命令:

export PWD=`pwd`

export CFLAGS="-march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard  -D__ARM_HAVE_NEON -D__ARM_NEON__" 

./configure --host=arm-linux-gnueabihf  --prefix=${PWD}/_install CC="arm-linux-gnueabihf-gcc -O3" 	

make  V=1

make  install

安装后在 _install/目录下生成如下目录

 ../lib/                  库文件目录,将静态库libturbojpeg.a、libjpeg.a添加到项目

../include/           头文件目录, 将全部copy到项目。

 

2.2  libjpeg-turbo-2.0.1编译

    只能采用cmake编译, 编译脚本如下:  注意:  只在window7 + msys2 + sdx2017.4的环境下编译成功(ubuntu16.04 + sdx2017.4编译不过)

#!/bin/bash

# Set these variables to suit your needs
BUILD_PLATFORM="linux-x86_64"
TOOLCHAIN_VERSION="4.9"
ROOT_PWD=$(pwd)
PREFIX=$(pwd)/../_install
cd ${ROOT_PWD}


# It should not be necessary to modify the rest
export HOST=arm-linux-gnueabihf
export CFLAGS="-march=armv7-a -mfloat-abi=hard -mfpu=neon -mtune=cortex-a7"
export LDFLAGS=-pie
export TOOLCHAIN=/opt/Xilinx_SDx_2017.4-final/SDK/2017.4/gnu/aarch32/lin/gcc-arm-linux-gnueabi


cat <toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER ${TOOLCHAIN}/bin/${HOST}-gcc)
set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN}/${HOST})
EOF

cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -DCMAKE_POSITION_INDEPENDENT_CODE=1 -DCMAKE_INSTALL_PREFIX=${PREFIX} 	${ROOT_PWD}
 
make clean
make
make install

 

 

3. 使用方案一:

     3.1  将YUV420P编码为JPEG格式:

        


#include "turbojpeg.h"   


///  二进制数据写入文件
static size_t Write2File(char *filename, uint8_t *buf, int size)
{
	size_t ret;
	
	FILE *fJpg = fopen(filename, "wb");
    if(fJpg == NULL){
        printf("Cannot open file %s, %s\n", filename, strerror(errno));
        return -1;
    }
	ret = fwrite(buf, 1, size, fJpg);
	fclose(fJpg);

	return ret;
}


/*************************************************************************************//**
*\n 函数名称: tyuv2jpeg1()
*\n 功能描述:
*\n            YUV420P转jpeg格式
*\n 输入参数:
*\n            unsigned char* yuv_buffer    : yuv数据
*\n            int width                    : 宽*高
*\n            int height                   
*\n            int subsample                : TJSAMP_420, TJSAMP_422,TJSAMP_GRAY, etc
*\n 输出参数: 
*\n            unsigned char** jpeg_buffer  : 函数内部malloc生成缓冲,外部需要free()
*\n            unsigned long* jpeg_size     : jpeg大小
*\n            
*\n 返 回 值: 
*\n           =0: 成功   
*\n           <0: 失败(错误码)      
*\n           
*\n -----------------------------------------------------------------------------------
*\n  版本:   修改人:       修改日期:        描述:
*\n  V0.1   
*****************************************************************************************/
static int tyuv2jpeg(unsigned char* yuv_buffer,  int width, int height, int subsample, 
					 unsigned char** jpeg_buffer, unsigned long* jpeg_size)
{
    tjhandle handle = NULL;
    int flags = 0;
    int padding = 1; // 1或4均可,但不能是0
    int need_size = 0;
    int ret = 0;

	int yuv_size = width * height * 3/2;
    handle = tjInitCompress();
    need_size = tjBufSizeYUV2(width, padding, height, subsample);
    if (need_size != yuv_size)
    {
		tjDestroy(handle);
        printf("we detect yuv size: %d, but you give: %d, check again.\n", need_size, yuv_size);
        return -1;
    }
 
	int quality = 80; // 压缩率(1 ~ 100)
    ret = tjCompressFromYUV(handle, yuv_buffer, width, padding, height, 
    						subsample, jpeg_buffer, jpeg_size, quality, flags);
    if (ret < 0)
    {
        printf("compress to jpeg failed: %s\n", tjGetErrorStr());
    }
    tjDestroy(handle);
    return ret;
}



// 测试代码, 将YUV420P图像编码为jpeg图像,并写入文件
int wirt2file(void *yuv_buffer, int width, int height)
{
		unsigned char *jpeg_buf = NULL;
		unsigned long jpeg_size = 0;
		
		int ret = tyuv2jpeg(src, width, height, TJSAMP_420,  &jpeg_buf, &jpeg_size); //函数分配jpeg内存
		if (ret < 0) 
		{
			printf("tyuv2jpeg() error");
			goto exit1;
		}		
		Write2File("/cam.jpg", jpeg_buf, jpeg_size);
		printf("write /cam.jpg,");

	exit1:
		free(jpeg_buf);  // 用户释放内存
		return 0;	
}

  3.2 测试:

          经过测试 JPEG编码时间为:    40毫秒

 

 

4. 使用方案二:

     4.1  将YUV420P编码为JPEG格式:

     

/*************************************************************************************//**
*\n 函数名称: tyuv2jpeg()
*\n 功能描述:
*\n            YUV420P转jpeg格式 
*\n 输入参数:
*\n            JSAMPLE *pYUVBuffer   : yuv数据
*\n            int width             : 宽 x 高
*\n            int height            
*\n            size_t *dest_size     : jpeg缓冲大小
*\n 输出参数: 
*\n            uint8_t *jpeg_buffer  : jpeg图像
*\n            size_t *dest_size     : jpeg大小
*\n            
*\n 返 回 值: 
*\n           =0: 成功           
*\n           <0: 失败(错误码)
*\n
*\n -----------------------------------------------------------------------------------
*\n  版本:	 修改人:       修改日期:       	 描述:
*\n  V0.1    罗先能        2018.12.12        创建
*****************************************************************************************/
static int tyuv2jpeg(/*OUT*/uint8_t *jpeg_buffer,  /*INOUT*/ size_t *dest_size,
	JSAMPLE *pYUVBuffer, int width, int height)
{
    JSAMPROW row_pointer[1];
    int row_stride;
    int i = 0, j = 0;
    unsigned char yuvbuf[width * 3];
    unsigned char *pY, *pU, *pV;
    int ulen;

    if(pYUVBuffer == NULL){
        printf("pBGRBuffer is NULL!\n");
        return -1;
    }

	struct jpeg_error_mgr jerr;
	struct jpeg_compress_struct cinfo;
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
	jpeg_mem_dest(&cinfo, &jpeg_buffer, (unsigned long*)dest_size);

    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_YCbCr;
    cinfo.dct_method = JDCT_ISLOW;
    jpeg_set_defaults(&cinfo);

    jpeg_set_quality(&cinfo, 80, TRUE);
    jpeg_start_compress(&cinfo, TRUE);
    row_stride = cinfo.image_width * 3; 
    
	ulen = width * height / 4;
    pY = pYUVBuffer;
    pU = pYUVBuffer + width*height;
    pV = pYUVBuffer + width*height + ulen;
    j = 1;
    while (cinfo.next_scanline < cinfo.image_height) {
        if(j % 2 == 1 && j > 1){
            pU = pYUVBuffer + width*height + width / 2 * (j / 2);
            pV = pYUVBuffer + width*height * 5 / 4 + width / 2 *(j / 2);
        }
        for(i = 0; i < width; i += 2){
            yuvbuf[i*3] = *pY++;
            yuvbuf[i*3 + 1] = *pU;
            yuvbuf[i*3 + 2] = *pV;

            yuvbuf[i*3 + 3] = *pY++;
            yuvbuf[i*3 + 4] = *pU++;
            yuvbuf[i*3 + 5] = *pV++;
        }

        row_pointer[0] = yuvbuf;
        (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
        j++;
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    return 0;
}

 

   4.2 测试:

          经过测试 JPEG编码时间为:    99mS

 

5. 结论:

          方案一,效率高。

 

 

 

你可能感兴趣的:(Xilinx,Zynq7000开发)