**一、交叉編譯libjpeg**
~~~
# tar -xzvf libjpeg-turbo-1.2.1.tar.gz?
#cd libjpeg-turbo-1.2.1
#mkdir tmp
# ./configure --prefix=$PWD/tmp --host=arm-linux
#make
#make install ? ? ? ? ? ? ? ?/* 會安裝在當前目錄下面tmp目錄里面 */?
~~~
**二、交叉編譯jpg2rgb.c**
方法一:編譯器后面直接跟上頭文件,庫文件。路徑是我們開始編譯出來的路徑。
arm-linux-gcc -o jpg2rgb jpg2rgb.c -I /home/book/workspace/project/libjpeg-turbo-1.2.1/tmp/include? -L /home/book/workspace/project/libjpeg-turbo-1.2.1/tmp/lib ?-ljpeg
cp jpg2rgb /work/nfs_root/fs_mini_mdev_new
cp libjpeg-turbo-1.2.1/tmp/lib/*so* /work/nfs_root/fs_mini_mdev_new/lib/ -d
方法二:把庫文件,頭文件放在交叉編譯里面庫文件,頭文件的路徑下面。
把編譯出來的頭文件應該放入:/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
cd ?/home/book/workspace/project/libjpeg-turbo-1.2.1/tmp/include
cp ?* ? /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
把編譯出來的庫文件應該放入:/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
cd ?/home/book/workspace/project/libjpeg-turbo-1.2.1/tmp/lib
cp *so* ?-d ? /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib
?cp *so* /work/nfs_root/ ? ? ?/* 把庫文件復制到開發板lib目錄下,我們用的是動態庫所以需要拷貝 */
arm-linux-gcc -o jpg2rgb jpg2rgb.c -ljpeg ? ? ?/* 要指定jpeg庫,數學庫則指定m */
?jpg2rgb.c文件如下:
~~~
#include <stdio.h>
#include "jpeglib.h"
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <string.h>
#include <stdlib.h>
#define FB_DEVICE_NAME "/dev/fb0" ? /* 指定lcd驅動自動創建的設別節點名 */
#define DBG_PRINTF ?printf ? ? ? ? ? ? ? ?/* 方便調試打印 */
static int g_fd;
static struct fb_var_screeninfo g_tFBVar; ? ?/* lcd相關的參數,在這篇文章中重點是libjpeg */
static struct fb_fix_screeninfo g_tFBFix;
static unsigned char *g_pucFBMem;
static unsigned int g_dwScreenSize;
static unsigned int g_dwLineWidth;
static unsigned int g_dwPixelWidth;
static int FBDeviceInit(void)
{
int ret;
g_fd = open(FB_DEVICE_NAME, O_RDWR);
if (0 > g_fd)
{
DBG_PRINTF("can't open %s\n", FB_DEVICE_NAME);
}
ret = ioctl(g_fd, FBIOGET_VSCREENINFO, &g_tFBVar);
if (ret < 0)
{
DBG_PRINTF("can't get fb's var\n");
return -1;
}
ret = ioctl(g_fd, FBIOGET_FSCREENINFO, &g_tFBFix);
if (ret < 0)
{
DBG_PRINTF("can't get fb's fix\n");
return -1;
}
g_dwScreenSize = g_tFBVar.xres * g_tFBVar.yres * g_tFBVar.bits_per_pixel / 8;
g_pucFBMem = (unsigned char *)mmap(NULL , g_dwScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, g_fd, 0);
if (0 > g_pucFBMem)
{
DBG_PRINTF("can't mmap\n");
return -1;
}
g_dwLineWidth ?= g_tFBVar.xres * g_tFBVar.bits_per_pixel / 8;
g_dwPixelWidth = g_tFBVar.bits_per_pixel / 8;
return 0;
}
static int FBShowPixel(int iX, int iY, unsigned int dwColor)
{
unsigned char *pucFB;
unsigned short *pwFB16bpp;
unsigned int *pdwFB32bpp;
unsigned short wColor16bpp; /* 565 */
int iRed;
int iGreen;
int iBlue;
if ((iX >= g_tFBVar.xres) || (iY >= g_tFBVar.yres))
{
DBG_PRINTF("out of region\n");
return -1;
}
pucFB ? ? ?= g_pucFBMem + g_dwLineWidth * iY + g_dwPixelWidth * iX;
pwFB16bpp ?= (unsigned short *)pucFB;
pdwFB32bpp = (unsigned int *)pucFB;
switch (g_tFBVar.bits_per_pixel)
{
case 8:
{
*pucFB = (unsigned char)dwColor;
break;
}
case 16:
{
iRed ? = (dwColor >> (16+3)) & 0x1f;
iGreen = (dwColor >> (8+2)) & 0x3f;
iBlue ?= (dwColor >> 3) & 0x1f;
wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;
*pwFB16bpp= wColor16bpp;
break;
}
case 32:
{
*pdwFB32bpp = dwColor;
break;
}
default :
{
DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel);
return -1;
}
}
return 0;
}
static int FBCleanScreen(unsigned int dwBackColor)
{
unsigned char *pucFB;
unsigned short *pwFB16bpp;
unsigned int *pdwFB32bpp;
unsigned short wColor16bpp; /* 565 */
int iRed;
int iGreen;
int iBlue;
int i = 0;
pucFB ? ? ?= g_pucFBMem;
pwFB16bpp ?= (unsigned short *)pucFB;
pdwFB32bpp = (unsigned int *)pucFB;
switch (g_tFBVar.bits_per_pixel)
{
case 8:
{
memset(g_pucFBMem, dwBackColor, g_dwScreenSize);
break;
}
case 16:
{
iRed ? = (dwBackColor >> (16+3)) & 0x1f;
iGreen = (dwBackColor >> (8+2)) & 0x3f;
iBlue ?= (dwBackColor >> 3) & 0x1f;
wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;
while (i < g_dwScreenSize)
{
*pwFB16bpp= wColor16bpp;
pwFB16bpp++;
i += 2;
}
break;
}
case 32:
{
while (i < g_dwScreenSize)
{
*pdwFB32bpp= dwBackColor;
pdwFB32bpp++;
i += 4;
}
break;
}
default :
{
DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel);
return -1;
}
}
return 0;
}
static int FBShowLine(int iXStart, int iXEnd, int iY, unsigned char *pucRGBArray)
{
int i = iXStart * 3;
int iX;
unsigned int dwColor;
if (iY >= g_tFBVar.yres)
return -1;
if (iXStart >= g_tFBVar.xres)
return -1;
if (iXEnd >= g_tFBVar.xres)
{
iXEnd = g_tFBVar.xres;
}
for (iX = iXStart; iX < iXEnd; iX++)
{
/* 0xRRGGBB */
dwColor = (pucRGBArray[i]<<16) + (pucRGBArray[i+1]<<8) + (pucRGBArray[i+2]<<0);
i += 3;
FBShowPixel(iX, iY, dwColor);
}
return 0;
}
/* 下面才是本文的重點 */
/*
Allocate and initialize a JPEG decompression object ? ?// 分配和初始化一個decompression結構體
Specify the source of the compressed data (eg, a file) // 指定源文件
Call jpeg_read_header() to obtain image info? // 用jpeg_read_header獲得jpg信息
Set parameters for decompression? // 設置解壓參數,比如放大、縮小
jpeg_start_decompress(...); ? // 啟動解壓:jpeg_start_decompress
while (scan lines remain to be read)
jpeg_read_scanlines(...);? // 循環調用jpeg_read_scanlines
jpeg_finish_decompress(...);? // jpeg_finish_decompress
Release the JPEG decompression object? // 釋放decompression結構體
*/
/* Uage: jpg2rgb <jpg_file>
?*/
int main(int argc, char **argv)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * infile;
int row_stride;
unsigned char *buffer;
if (argc != 2)
{
printf("Usage: \n");
printf("%s <jpg_file>\n", argv[0]);
return -1;
}
if (FBDeviceInit()) ? ? /* 初始化Lcd */
{
return -1;
}
FBCleanScreen(0); ? ? ?/* 清屏lcd */
// 分配和初始化一個decompression結構體
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
// 指定源文件
if ((infile = fopen(argv[1], "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", argv[1]);
return -1;
}
jpeg_stdio_src(&cinfo, infile);
// 用jpeg_read_header獲得jpg信息
jpeg_read_header(&cinfo, TRUE);
/* 源信息 */
printf("image_width = %d\n", cinfo.image_width);
printf("image_height = %d\n", cinfo.image_height);
printf("num_components = %d\n", cinfo.num_components);
// 設置解壓參數,比如放大、縮小
printf("enter scale M/N:\n");
scanf("%d/%d", &cinfo.scale_num, &cinfo.scale_denom);
printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);
// 啟動解壓:jpeg_start_decompress
jpeg_start_decompress(&cinfo);
/* 輸出的圖象的信息 */
printf("output_width = %d\n", cinfo.output_width);
printf("output_height = %d\n", cinfo.output_height);
printf("output_components = %d\n", cinfo.output_components);
// 一行的數據長度
row_stride = cinfo.output_width * cinfo.output_components;
buffer = malloc(row_stride);
// 循環調用jpeg_read_scanlines來一行一行地獲得解壓的數據
while (cinfo.output_scanline < cinfo.output_height)?
{
(void) jpeg_read_scanlines(&cinfo, &buffer, 1);
// 寫到LCD去
FBShowLine(0, cinfo.output_width, cinfo.output_scanline, buffer);
}
free(buffer);
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return 0;
}
~~~
上文中紅色以下的才是本文的重點,lcd驅動才以前驅動部分已經講得很明白了。