jpg解码库移植过程详解

Posted 正在起飞的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jpg解码库移植过程详解相关的知识,希望对你有一定的参考价值。

1、jpg解码库的源码获取

(1)可以从网站下载:http://www.photopost.com/jpegsrc.v6b.tar.gz;
(2)我下面的移植过程是根据jpegsrc.v6b.tar.gz版本的jpg解码库移植的,如果是其他版本的jpg解码库,配置编译过程可能会有所差异,需要自行解决,如果没什么特别的需求,v6b版本的jpg解码库完全是 够用的;
(3)如果想直接要源码,可以私信我;

2、jpg解码库的编译

解压源码:
	tar -zxvf jpegsrc.v6b.tar.gz

第一步:
	./configure --prefix=/opt/libdecode --exec-prefix=/opt/libdecode --enable-shared --enable-static -build=i386 -host=arm 
	
	--prefix=/opt/libdecode:指定生成的jpg库的安装目录 
	--exec-prefix=/opt/libdecode:指定生成的二进制文件的存放目录,一般和"--prefix"选项一致
	--enable-shared:要生成动态库
	--enable-static:要生成静态库
	-build=i386:编译源码所在的环境是i386体系的机器
	-host=arm:编译得到的库要在arm架构的机器上运行
	
第二步:
	CC=gcc 		改为 	CC=arm-linux-gcc
	AR=ar rc 	改为 	AR=arm-linux-ar rc
	AR2=ranlib 	改为 	AR2=arm-linux-ranlib
第三步:
	mkdir /opt/libdecode/lib
	mkdir /opt/libdecode/include
第四步:
	make
第五步:
	make install-lib

(1)jpg解码库源码的配置文件是configure,Makefile刚解压时是没有的,需要调用configure文件去生成Makefile,会根据调用configure文件时指定的参数去生成特定的Makefile,比如Makefile中可以找到你传入的安装路径;
(2)嵌入式开发要根据平台去选择适配的交叉编译工具链,所以对生成的Makefile要修改编译工具;
(3)在指定的安装目录中,需要提前创建lib和include目录,其中lib是用来存放生成的动态库、静态库的,include是用来存放头文件的;
(4)最后就是编译和安装,在指定的安装目录的lib中有生成的动态库,在include目录下生成头文件;

3、jpg解码库编译后的产物

(1)在指定的安装目录中,include目录下是头文件,lib目录下是生成的动态库;
(2)在lib目录下有动态库和链接文件,真正的jpg解码库是libjpeg.so.62;

4、jpg解码库的移植

(1)将编译得到的include目录下的头文件,和lib目录下动态库添加到你的代码工程中,并且动态库还需要部署到可执行程序的运行环境中;
(2)编写调用jpg解码库去编解码jpg图片的函数,

5、jpg解码库的API调用

(1)想要使用编译得到的libjpg.so库去编解码jpg文件,需要去结合include目录下得到的头文件的jpg解码库里的example.c文件;
(2)examle.c文件里是示例代码,里面有jpg图片的各种操作函数,结合include目录下的头文件对API接口描述去理解;
(3)还想了解更仔细可以去阅读jpg源码目录下的libjpg.doc文件,里面有对jpg解码库更详细的介绍,不过都是英文,英文不是很6就别去看了;

6、jpg解码库的使用示例

// 结构体用来封装一个图片的各种信息
typedef struct pic_info

	char *pathname;			// 图片在文件系统中的路径名+文件名
	unsigned int width;		// 图片分辨率之宽
	unsigned int height;	// 图片分辨率之高
	unsigned int bpp;		// 图片bpp
	char *pData;			// 指向图片有效数据存储的buf数据
pic_info;


typedef struct my_error_mgr 
  
	struct jpeg_error_mgr pub;	/* "public" fields */  
//	jmp_buf setjmp_buffer;	/* for return to caller */
*my_error_ptr;

// 函数功能: 判断一个图片文件是不是jpg图片
// 函数参数: path是图片文件的pathname
// 返回值:   如果是jpg则返回0,不是则返回1,错误返回-1
int is_jpg(const char *path)

	FILE *file = NULL;
	char buf[2] = 0;
	// 打开文件
	file = fopen(path, "rb");
	if (NULL == file)
	
		fprintf(stderr, "fopen %s error.\\n", path);
		fclose(file);
		return -1;
	
	// 读出前2个字节
	fread(buf, 1, 2, file);
	debug("read: 0x%x%x\\n", buf[0], buf[1]);
	// 判断是不是0xffd8
	if (!((buf[0] == 0xff) && (buf[1] == 0xd8)))
	
		fclose(file);
		return 1;		// 不是jpg图片
	
	// 是0xffd8开头,就继续
	// 文件指针移动到倒数2个字符的位置
	fseek(file, -2, SEEK_END);
	// 读出2个字节
	fread(buf, 1, 2, file);
	debug("read: 0x%x%x\\n", buf[0], buf[1]);
	// 判断是不是0xffd9
	if (!((buf[0] == 0xff) && (buf[1] == 0xd9)))
	
		fclose(file);
		return 1;		// 不是jpg图片
	

	fclose(file);
	
	return 0;


// 自己定义的错误处理函数
METHODDEF(void)my_error_exit (j_common_ptr cinfo)
  
	//my_error_ptr myerr = (my_error_ptr) cinfo->err;  
	//(*cinfo->err->output_message) (cinfo);    
	fprintf(stderr, "my_error_exit\\n");
	//longjmp(myerr->setjmp_buffer, 1);


/*
 * 函数功能: 解码jpg图片,并将解码出来的数据存储
 * 函数参数: pPIC,记录源jpg图片,解码出来的图片宽高、图片数据缓冲区等信息
 * 返回值  : 成功解码则返回0,失败则返回-1
 */
 
int jpg_analyze(struct pic_info *pPic)

	struct jpeg_decompress_struct cinfo;		// cinfo贯穿整个解码过程的信息记录和传递的数据结构
	struct my_error_mgr jerr;					// 错误处理的	
	//JSAMPARRAY buffer = NULL;					// 指向解码行数据的指针
	char * buffer = NULL;
	FILE * infile;								// 指向fopen打开源jpg图片文件的指针
	int row_stride, ret;						// 解码出来的一行图片信息的字节数

	// 第一步: 检测给的图片是不是jpg图片
	ret = is_jpg(pPic->pathname);
	if (ret != 0)
	
		debug("%s not jpg picture!\\n", pPic->pathname);
		return -1;
	

	if ((infile = fopen(pPic->pathname, "rb")) == NULL) 
	    
		fprintf(stderr, "can't open %s\\n", pPic->pathname);    
		return -1;  
	

	// 第1步: 错误处理函数部分的绑定
	cinfo.err = jpeg_std_error(&jerr.pub);	
	jerr.pub.error_exit = my_error_exit;
	// 给解码器做必要的内存分配和数据结构的初始化
	jpeg_create_decompress(&cinfo);

	// 第2步: 将fopen打开的源jpg图片和解码器相关联
	jpeg_stdio_src(&cinfo, infile);

	// 第3步: 读jpg文件头
	jpeg_read_header(&cinfo, TRUE);

	// 第4步: 启动解码器
	jpeg_start_decompress(&cinfo);

	debug("image resolution: %d * %d, bpp/8=%d.\\n", 
		cinfo.output_width, cinfo.output_height, cinfo.output_components);
	// 解码出来的数据一行的字节数
	row_stride = cinfo.output_width * cinfo.output_components;
	//buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
	buffer = (char *)malloc(row_stride);
	if (NULL == buffer)
	
		fprintf(stderr, "cinfo.mem->alloc_sarray error.\\n");
		return -1;
	

	// 第5步: 逐行解码,并将解码出的数据丢到事先准备好的缓冲区去
	while (cinfo.output_scanline < cinfo.output_height) 
		 
		// 解码一行信息,并且丢到buffer中
		//jpeg_read_scanlines(&cinfo, buffer, 1);
		jpeg_read_scanlines(&cinfo, &buffer, 1);	 

		// 将buffer中这一行数据移走到别的地方去暂存或者使用,总之是要腾出buffer空间
		// 来给循环的下一次解码一行来使用
		memcpy(pPic->pData + (cinfo.output_scanline-1) * row_stride, buffer, row_stride);
	

	// 第6步: 解码完了,做各种清理工作
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);
	fclose(infile);


	// jpg图片的数据记录下来
	pPic->width = cinfo.output_width;
	pPic->height = cinfo.output_height;
	pPic->bpp = cinfo.output_components * 8;


	return 0;

(1)上面的代码是从jpg图片中提取RGB数据的函数,也是参考example.c文件修改得到,可以直接移植;
(2)想要学习jpg解码库在实际项目中的应用,参考博客:;

7、参考资源

《朱友鹏——嵌入式核心课程》

以上是关于jpg解码库移植过程详解的主要内容,如果未能解决你的问题,请参考以下文章

Linux下GIF库移植与运用

FFmpeg移植Android编译生成单个库

FFmpeg移植Android编译生成多库

FFmpeg解码H264及swscale缩放详解

wasm 视频解码渲染实现

wasm 视频解码渲染实现