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

libjpeg-turbo编译

libjpeg-turbo可以看成是libjpeg的优化加速版,从理论上来说,它所耗费的时间只有libjpeg的1/3。

编译:

tar -zxvf libjpeg-turbo-1.4.3.tar.gz

cd libjpeg-turbo-1.4.3

./configure --prefix=安装目录 --host=编译平台  //我用的是海思平台 arm-hisiv500-linux

make

make install


将YUV420P保存为jpg

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)  
{  
    tjhandle handle = NULL;  
    int flags = 0;  
    int padding = 1; //must be 1 or 4  
    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: %s\n", tjGetErrorStr());  
    }  
  
    tjDestroy(handle);  
  
    return ret;  
}
unsigned char *jpeg_buf = NULL;
unsigned long jpeg_size = 0;
unsigned char *picture = (unsigned char *)malloc(yuv_size+1);
if(picture == NULL)
{
printf("lpr_jpeg_save malloc failed\n");
return -1;
}
yuv420sp_to_yuv420p(yuv_buffer, picture, width, height);

tyuv2jpeg(picture, yuv_size, width, height, TJSAMP_420, &jpeg_buf, &jpeg_size, 50); //50:quality

width:图像宽度

height:图像高度

yuv_size:yuv大小,等于width*height*3/2

quality:转换后的图像质量(1~100)

subsample:

enum TJSAMP
{
  /**
   * 4:4:4 chrominance subsampling (no chrominance subsampling).  The JPEG or
   * YUV image will contain one chrominance component for every pixel in the
   * source image.
   */
  TJSAMP_444=0,
  /**
   * 4:2:2 chrominance subsampling.  The JPEG or YUV image will contain one
   * chrominance component for every 2x1 block of pixels in the source image.
   */
  TJSAMP_422,
  /**
   * 4:2:0 chrominance subsampling.  The JPEG or YUV image will contain one
   * chrominance component for every 2x2 block of pixels in the source image.
   */
  TJSAMP_420,
  /**
   * Grayscale.  The JPEG or YUV image will contain no chrominance components.
   */
  TJSAMP_GRAY,
  /**
   * 4:4:0 chrominance subsampling.  The JPEG or YUV image will contain one
   * chrominance component for every 1x2 block of pixels in the source image.
   *
   * @note 4:4:0 subsampling is not fully accelerated in libjpeg-turbo.
   */
  TJSAMP_440,
  /**
   * 4:1:1 chrominance subsampling.  The JPEG or YUV image will contain one
   * chrominance component for every 4x1 block of pixels in the source image.
   * JPEG images compressed with 4:1:1 subsampling will be almost exactly the
   * same size as those compressed with 4:2:0 subsampling, and in the
   * aggregate, both subsampling methods produce approximately the same
   * perceptual quality.  However, 4:1:1 is better able to reproduce sharp
   * horizontal features.
   *
   * @note 4:1:1 subsampling is not fully accelerated in libjpeg-turbo.
   */
  TJSAMP_411
};


将YUV420SP转为YUV420P

在TJSAMP中并没有看到420sp的相关信息,因此,如果我们的数据是420sp的话,就需要转换成420p后再进行保存。

YUV420p:先保存Y,再保存U,最后是V

YUV420sp:先保存Y,然后UV交叉保存。又分为NV12和NV21,区别就在于U和V哪个在前哪个在后

图1为420p,图2为420sp(NV12)



//NV21->YUV420P
void yuv420sp_to_yuv420p(unsigned char* yuv420sp, unsigned char* yuv420p, int width, int height)  
{  
    int i, j;  
    int y_size = width * height;  
  
    unsigned char* y = yuv420sp;  
    unsigned char* uv = yuv420sp + y_size;  
  
    unsigned char* y_tmp = yuv420p;  
    unsigned char* u_tmp = yuv420p + y_size;  
    unsigned char* v_tmp = yuv420p + y_size * 5 / 4;  
  
    // y  
    memcpy(y_tmp, y, y_size);  
  
    // u  
    for (j = 0, i = 0; j < y_size/2; j+=2, i++)  
    {  
        v_tmp[i] = uv[j];  
        u_tmp[i] = uv[j+1];  
    }  
}

裁剪YUV数据

有时候我们还需要一些截图功能,就需要裁剪YUV数据,然后再保存成jpeg

int tailor_yuv(unsigned char* srcframe,unsigned char *dstframe,int startX,int startY,int normal_width,int normal_height,int tailor_width,int tailor_height)
{
	if(!srcframe || !dstframe)
		return -1;
	int i = 0;
	int j = 0;
	int k = 0;
	if(startX % 2 != 0)
		startX++;
	if(startY % 2 != 0)
		startY++;
  	unsigned char *tmpY = (unsigned char *)malloc(tailor_width*tailor_height);  
    unsigned char *tmpUV = (unsigned char *)malloc(tailor_width*tailor_height/2);
	if(!tmpY || !tmpUV)
		return -1;
	for(i = startY;i < startY + tailor_height;i++)
	{
		//copy Y
		memcpy(tmpY+j*tailor_width,srcframe + i * normal_width + startX,tailor_width);
		j++;	//current height num
	}
	for(i = startY/2;i < (startY + tailor_height)/2;i++)
	{
		//copy UV
		memcpy(tmpUV+k*tailor_width,srcframe + (normal_width * normal_height) + i * normal_width + startX,tailor_width);
		k++;	//current height num
	}
	memcpy(dstframe, tmpY, tailor_width*tailor_height);
	memcpy(dstframe+tailor_width*tailor_height, tmpUV, tailor_width*tailor_height/2);
	free(tmpY);  
	free(tmpUV);
	return 0;
}

startX,startY:裁剪的起始点

normal_width,normal_height:未裁剪前的尺寸

tailor_width,tailor_height:裁剪后的尺寸

原理:先保存Y分量,再保存uv分量,根据起始点和尺寸进行裁剪。

猜你喜欢

转载自blog.csdn.net/zouwm12/article/details/79856741