在MCU上移植使用libjpeg

原创 嵌入式Lee 2024-11-26 17:46

一. 前言

在一些嵌入式项目中可能需要用到jpeg编解码,比如UVCMJPEG显示, 加载JPEG图片显示到TFT屏幕等,而往往很多通用MCU平台不带硬件jpeg编解码,此时就需要软件实现,这时就希望能有一个好用的jpeg编解码库,恰好官方就提供了这么一个c库即libjpeg。网址为https://libjpeg.sourceforge.net/可以方便将该库应用到自己的项目中,当然其实现也是学习jpeg编解码实现的不二之选。我们就来移植使用该项目源码,源码默认输入输出是针对文件的,我这里对其进行了一些可移植性改造,可以用户配置输入输出接口,这样可以针对缓存或者文件都可以,源码分享在了https://github.com/qinyunti/libjpeg_port.git.

二. 准备

这里先进入网站下载源码和相关的资料

进入网址https://libjpeg.sourceforge.net/

点击上述链接进入https://www.ijg.org/files/

最新版是jpegsr9f,上面还有一些pdf资料可以参考。

解压下载的压缩包jpegsr9f.zip

里面提供了VS相关的工程可以按照说明直接构建,但是我们这里是要移植到MCU上,所以只使用其源码,其他很多的图像格式处理相关的文件也暂时不添加以后有需要可以使用。

需要使用的源码如下,即只需要j开头的ch文件。

src|-- jaricom.c|-- jcapimin.c|-- jcapistd.c|-- jcarith.c|-- jccoefct.c|-- jccolor.c|-- jcdctmgr.c|-- jchuff.c|-- jcinit.c|-- jcmainct.c|-- jcmarker.c|-- jcmaster.c|-- jcomapi.c|-- jcparam.c|-- jcprepct.c|-- jcsample.c|-- jctrans.c|-- jdapimin.c|-- jdapistd.c|-- jdarith.c|-- jdatadst.c|-- jdatasrc.c|-- jdcoefct.c|-- jdcolor.c|-- jddctmgr.c|-- jdhuff.c|-- jdinput.c|-- jdmainct.c|-- jdmarker.c|-- jdmaster.c|-- jdmerge.c|-- jdpostct.c|-- jdsample.c|-- jdtrans.c|-- jerror.c|-- jfdctflt.c|-- jfdctfst.c|-- jfdctint.c|-- jidctflt.c|-- jidctfst.c|-- jidctint.c|-- jmemmgr.c|-- jquant1.c|-- jquant2.c`-- jutils.c
0 directories, 45 files
inc/|-- jdct.h|-- jerror.h|-- jinclude.h|-- jioport.h|-- jmemsys.h|-- jmorecfg.h|-- jpegint.h|-- jpeglib.h`-- jversion.h
0 directories, 9 files
port/|-- jioport.c|-- jmemansi.c|-- jmemdos.c|-- jmemmac.c|-- jmemname.c|-- jmemnobs.c`-- jmemport.c
0 directories, 7 files

我这里的源码如下

三. 配置

使用jconfig.h进行编译时静态配置

该文件由源码目录下的jconfig.txt生成,我们这里复制该文件手动修改为jconfig.h添加到自己的工程中去。

会有很多warning: unused parameter所以我们直接

添加编译参数-Wno-unused-variable,-Wno-unused-parameter忽略该告警。

3.1适配mem接口

添加jmemport.c

我这里不使用stdlib.hmallocfree所以

jpegsr9f/inc/jconfig.h

删除#define HAVE_STDLIB_H

参考jmemnobs.c新建我们自己的jmemport.c

实现以下接口

jpeg_get_small

jpeg_free_small

jpeg_get_large

jpeg_free_large

jpeg_mem_available

jpeg_open_backing_store

jpeg_mem_init

jpeg_mem_term

#include "FreeRTOS.h"//#ifndef HAVE_STDLIB_H   /*  should declare malloc(),free() *///extern void * malloc JPP((size_t size));//extern void free JPP((void *ptr));//#endif

替换mallocfree为我们自己的实现,我这里使用的是freertos

pvPortMallocvPortFree,如果支持标准cmallocfree则可以使用jmemansi.c

实现如下

/* * jmemport.c * * Copyright (C) 1992-1996, Thomas G. Lane. * Modified 2019 by Guido Vollbeding. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file provides a really simple implementation of the system- * dependent portion of the JPEG memory manager.  This implementation * assumes that no backing-store files are needed: all required space * can be obtained from malloc(). * This is very portable in the sense that it'll compile on almost anything, * but you'd better have lots of main memory (or virtual memory) if you want * to process big images. * Note that the max_memory_to_use option is respected by this implementation. */
#define JPEG_INTERNALS#include "jinclude.h"#include "jpeglib.h"#include "jmemsys.h" /* import the system-dependent declarations */#include "FreeRTOS.h"//#ifndef HAVE_STDLIB_H /* should declare malloc(),free() *///extern void * malloc JPP((size_t size));//extern void free JPP((void *ptr));//#endif

/* * Memory allocation and freeing are controlled by the regular library * routines malloc() and free(). */
GLOBAL(void *)jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject){ void* ret; ret = (void *) pvPortMalloc(sizeofobject); #if JPEG_LOG jprintf("jpeg_get_small %p size:%ld r\n",ret, sizeofobject); #endif return ret;}
GLOBAL(void)jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject){ #if JPEG_LOG jprintf("jpeg_free_small %p \r\n",object); #endif vPortFree(object);}

/* * "Large" objects are treated the same as "small" ones. * NB: although we include FAR keywords in the routine declarations, * this file won't actually work in 80x86 small/medium model; at least, * you probably won't be able to process useful-size images in only 64KB. */
GLOBAL(void FAR *)jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject){ void* ret; ret = (void FAR *) pvPortMalloc(sizeofobject); #if JPEG_LOG jprintf("jpeg_get_small %p size:%ld r\n",ret, sizeofobject); #endif return ret;}
GLOBAL(void)jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject){ #if JPEG_LOG jprintf("jpeg_free_large %p \r\n",object); #endif vPortFree(object);}

/* * This routine computes the total memory space available for allocation. */
GLOBAL(long)jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, long max_bytes_needed, long already_allocated){ if (cinfo->mem->max_memory_to_use) return cinfo->mem->max_memory_to_use - already_allocated;
/* Here we say, "we got all you want bud!" */ return max_bytes_needed;}

/* * Backing store (temporary file) management. * Since jpeg_mem_available always promised the moon, * this should never be called and we can just error out. */
GLOBAL(void)jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, long total_bytes_needed){ ERREXIT(cinfo, JERR_NO_BACKING_STORE);}

/* * These routines take care of any system-dependent initialization and * cleanup required. Here, there isn't any. */
GLOBAL(long)jpeg_mem_init (j_common_ptr cinfo){ return 0; /* just set max_memory_to_use to 0 */}
GLOBAL(void)jpeg_mem_term (j_common_ptr cinfo){ /* no work */}

jdatadst.cmalloc/free替换

jpegsr9f/src/jdatadst.c

#ifndef HAVE_STDLIB_H   /*  should declare malloc(),free() */extern void * malloc JPP((size_t size));extern void free JPP((void *ptr));#endif

不使用stdlib则这里依赖外部实现的mallocfree,这里可移植性不好,这里直接依赖mem接口即。

注释掉

//#ifndef HAVE_STDLIB_H   /*  should declare malloc(),free() *///extern void * malloc JPP((size_t size));//extern void free JPP((void *ptr));//#endif

后面的malloc改为jpeg_get_small

free改为jpeg_free_small

nextbuffer = (JOCTET *) malloc(nextsize);

改为

nextbuffer = (JOCTET *) jpeg_get_small(0,nextsize);

dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE);

改为

dest->newbuffer = *outbuffer = (unsigned char *) jpeg_get_small(0,OUTPUT_BUF_SIZE);

free(dest->newbuffer);

改为

jpeg_free_small(0,dest->newbuffer,0);

jpegsr9f/src/jdatadst.c中需要

#include "jmemsys.h"

3.2不使用getenv

jpegsr9f/src/jmemmgr.c

#ifndef NO_GETENV#ifndef HAVE_STDLIB_H   /*  should declare getenv() */extern char * getenv JPP((const char * name));#endif#endif

我们不使用getenv则需要定义NO_GETENV

jpegsr9f/inc/jconfig.h中添加

#define NO_GETENV

3.3适配IO操作

我们在jpegsr9f/inc/jconfig.h

定义#define JPEG_USE_FILE_IO_CUSTOM

不定义JPEG_HAVE_FILE_IO_CUSTOM

走如下路线

即用户需要实现

jfread
jfwrite
jfflush
jferror

jpegsr9f/inc/jinclude.h中,FILE*改为void*,这样可移植

extern size_t jfread(void * __ptr, size_t __size, size_t __n, FILE * __stream);extern size_t jfwrite(const void * __ptr, size_t __size, size_t __n, FILE * __stream);extern int    jfflush(FILE * __stream);extern int    jferror(FILE * __fp);
改为extern size_t jfread(void * __ptr, size_t __size, size_t __n, void * __stream);extern size_t jfwrite(const void * __ptr, size_t __size, size_t __n, void * __stream);extern int    jfflush(void * __stream);extern int    jferror(void * __fp);

为了可移植性

jdatadst.c

jdatasrc.c,

jmemsys.h

jpeglib.h

FILE改为void

为了方便适配不同的输入输出方式,我这里添加了jioport.c/jioport.h可以用户设置对应的接口

h文件

#ifndef JPEG_IOPORT_H#define JPEG_IOPORT_H
#ifdef __cplusplus extern "C" {#endif
#include #include
typedef struct{  size_t (*read)(void * __ptr, size_t __size, size_t __n, void * __stream);  size_t (*write)(const void * __ptr, size_t __size, size_t __n, void * __stream);  int    (*flush)(void * __stream);  int    (*error)(void * __fp);  size_t infile_len;} jioport_st;
size_t jfread(void * __ptr, size_t __size, size_t __n, void * __stream);size_t jfwrite(const void * __ptr, size_t __size, size_t __n, void * __stream);int    jfflush(void * __stream);int    jferror(void * __fp);
void jioport_set(jioport_st* port);
#ifdef __cplusplus}#endif
#endif

c文件

#include "jconfig.h"#include "jioport.h"
jioport_st* s_jioport = (jioport_st*)0;
size_t jfread(void * __ptr, size_t __size, size_t __n, void * __stream){  #if JPEG_LOG  jprintf("jfread ptr:%p size:%ld n:%ld stream:%p\r\n",__ptr,__size,__n,__stream);  #endif  if((s_jioport != (jioport_st*)0) && (s_jioport->read != 0))  {    return s_jioport->read(__ptr, __size, __n, __stream);  }  return 0;}
size_t jfwrite(const void * __ptr, size_t __size, size_t __n, void * __stream){  #if JPEG_LOG  jprintf("jfwrite ptr:%p size:%ld n:%ld stream:%p\r\n",__ptr,__size,__n,__stream);  #endif  if((s_jioport != (jioport_st*)0) && (s_jioport->write != 0))  {    return s_jioport->write(__ptr, __size, __n, __stream);  }  return 0;}
int    jfflush(void * __stream){  #if JPEG_LOG  jprintf("jfflush stream:%p\r\n",__stream);  #endif  if((s_jioport != (jioport_st*)0) && (s_jioport->flush != 0))  {    return s_jioport->flush(__stream);  }  return 0;}
int    jferror(void * __fp){  #if JPEG_LOG  jprintf("jferror fp:%p\r\n",__fp);  #endif  if((s_jioport != (jioport_st*)0) && (s_jioport->error != 0))  {    return s_jioport->flush(__fp);  }  return 0;}
void jioport_set(jioport_st* port){  s_jioport = port;}

3.4适配打印

jpegsr9f/src/jerror.c

注释掉 //exit(EXIT_FAILURE);

因为一般MCU平台没有exit

fprintf(stderr, "%s\n", buffer);

改为

jprintf("%s\n", buffer);

jpegsr9f/inc/jconfig.h中实现jprintf

#include 
#define jprintf(fmt, arg...) printf(fmt, ##arg)

四. 测试

可以直接在pc上测试,参加git源码

编译

./build.sh

4.1 编码

源码见

jpeg_encode_buffer.c/h

encode_test.c

注意输入bmp图片必须是24位格式,且一行数据量要是4的倍数,widthx34的倍数.

./encode_test testimg.bmp testimg.jpg 320 240 50

生成testimg.jpg如下

4.2解码

源码见

jpeg_decode_buffer.c/h

decode_test.c

./decode_test testimg.jpg testimg.rgb 320

使用YUView软件查看输出文件testimg.rgb

五. 总结

ligjpegTom LaneIJG开发的对jpeg的实现,广泛使用。本文分享了将其进行简单的移植改造适合MCU等任意嵌入式平台使用。

以上测试是在pc上进行,在mcu上比如freertos上则只需要使用jmemport.c,如果不是使用freertos则替换自己的动态分配接口,使用jconfig.h修改#define jprintf(fmt, arg...) printf(fmt, ##arg)宏为自己的打印宏即可。









评论 (0)
  • 引言:工业安全与智能化需求的双重驱动在工业安全、环境保护及家庭安防领域,气体泄漏引发的安全事故始终是重大隐患。随着传感器技术、物联网及语音交互的快速发展,气体检测报警器正朝着智能化、低成本、高可靠的方向演进。WT588F02B-8S语音芯片,以“离在线语音更换+多协议通信”为核心优势,为气体检测报警器提供了一套高效、灵活的低成本语音解决方案,助力开发者快速响应市场需求。产品功能与市场需求1. 核心功能:从监测到预警的全流程覆盖实时气体监测:支持一氧化碳、臭氧、硫化氢等多种气体浓度检测,精度可达p
    广州唯创电子 2025-04-22 09:14 68浏览
  •   电磁干扰抑制系统平台深度解析   一、系统概述   北京华盛恒辉电磁干扰抑制系统在电子技术快速发展、电磁环境愈发复杂的背景下,电磁干扰(EMI)严重影响电子设备性能、稳定性与安全性。电磁干扰抑制系统平台作为综合性解决方案,通过整合多元技术手段,实现对电磁干扰的高效抑制,确保电子设备稳定运行。   应用案例   目前,已有多个电磁干扰抑制系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁干扰抑制系统。这些成功案例为电磁干扰抑制系统的推广和应用提供了有力支持。   二
    华盛恒辉l58ll334744 2025-04-22 15:27 80浏览
  •   电磁兼容故障诊断系统平台深度解析   北京华盛恒辉电磁兼容(EMC)故障诊断系统平台是解决电子设备在复杂电磁环境下性能异常的核心工具。随着电子设备集成度提升与电磁环境复杂化,EMC 问题直接影响设备可靠性与安全性。以下从平台架构、核心功能、技术实现、应用场景及发展趋势展开全面剖析。   应用案例   目前,已有多个电磁兼容故障诊断系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁兼容故障诊断系统。这些成功案例为电磁兼容故障诊断系统的推广和应用提供了有力支持。  
    华盛恒辉l58ll334744 2025-04-22 14:29 82浏览
  • 近期,金融界消息称,江西万年芯微电子有限公司申请一项名为“基于预真空腔体注塑的芯片塑封方法及芯片”的专利。此项创新工艺的申请,标志着万年芯在高端芯片封装领域取得重要突破,为半导体产业链提升注入了新动能。专利摘要显示,本发明公开了一种基于预真空腔体注塑的芯片塑封方法,方法包括将待塑封的大尺寸芯片平铺于下模盒腔体内的基板并将大尺寸芯片的背向表面直接放置于基板上以进行基板吸附;将上模盒盖合于下模盒形成塑封腔,根据基板将塑封腔分为上型腔以及下型腔;将下型腔内壁与大尺寸芯片间的空隙进行树脂填充;通过设置于
    万年芯 2025-04-22 13:28 74浏览
  • 引言:老龄化社会的健康守护需求随着全球老龄化进程加速,老年人的健康管理与生活质量成为社会焦点。记忆衰退、用药混乱、日程遗漏等问题频发,催生了智能健康设备的市场需求。WTR096录音语音芯片,凭借其高度集成的录放音、计时时钟与计划管理功能,为老年人量身打造了一站式健康管理方案,重新定义智能语音时钟的价值。功能亮点:1. 用药安全守护:多维度提醒,拒绝遗忘多时段精准提醒:支持一天内设置多个用药时间(如早、中、晚),适配复杂用药需求。个性化语音定制:家属可录制专属提醒语音(如“上午9点,请服用降压药”
    广州唯创电子 2025-04-22 08:41 94浏览
  • 职场烂摊子,每个人都难免遇上如果你在职场待久了,总会碰到一些让人无奈的情况:比如刚接手的项目混乱不堪、前任同事留下的任务一团乱麻,甚至有时因为自己的疏忽造成麻烦。面对这种烂摊子,烦躁、焦虑、甚至怀疑人生的情绪都会扑面而来。但如果你冷静想想,会发现真正消耗你的,往往不是工作本身,而是持续不断的心理内耗。那么问题来了,如何摆脱内耗,快速有效地“自救”?摆脱内耗,从情绪中抽离我曾经历过一个典型的职场烂摊子:前任项目负责人突然辞职,项目资料缺失严重,进度远远落后,客户抱怨不断。当时接手后的第一反应就是慌
    优思学院 2025-04-21 18:21 45浏览
  • 在汽车行业的变革浪潮中,智界汽车的诞生备受瞩目。作为华为与奇瑞两大巨头携手合作的结晶,智界汽车自孕育之初便承载着众人的期待,被视为融合前沿科技与卓越制造的典范,有望在竞争激烈的新能源汽车市场中开辟出一片新天地。2024年,智界品牌首款车型智界S7正式上市,凭借华为的技术赋能,如先进的鸿蒙智能座舱、强大的HUAWEI ADS高阶智能驾驶辅助系统,以及奇瑞多年积累的深厚造车底蕴,在上市前赚足了眼球。智界S7的亮相,犹如一颗投入平静湖面的石子,激起了层层涟漪,消费者对其充满了好奇与期待,行业内也纷纷将
    用户1742991715177 2025-04-21 20:28 79浏览
  •   北京华盛恒辉基于GIS的电磁态势可视化系统软件是将地理空间信息与电磁态势数据相结合,通过图形化手段直观展示电磁环境态势的系统。这类软件在军事、通信、无线电管理等领域具有广泛应用,能够辅助用户进行电磁频谱分析、干扰监测、态势研判和决策支持。以下是关于此类系统的详细介绍:   应用案例   目前,已有多个电磁态势可视化系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁态势可视化系统。这些成功案例为电磁态势可视化系统的推广和应用提供了有力支持。   一、系统功能   电磁
    华盛恒辉l58ll334744 2025-04-22 11:44 75浏览
  • 在消费金融的赛道上,马上消费曾是备受瞩目的明星企业。自2015年成立以来,它以年均 30% 的净利润增速一路狂奔,成为持牌消费金融公司的标杆,2023年更是斩获19.82亿元净利润,风光无限。然而,2024年却成了马上消费的一道分水岭。2024年上半年,其营收为77.38亿元,同比下降2.11%;净利润更是同比骤降20.66%,仅为10.68亿元,创下历史最大跌幅 。与此同时,不良贷款率攀升至2.5%,不良余额高达16.54亿元,核心资本充足率降至12.72%,融资
    用户1742991715177 2025-04-21 21:29 100浏览
  • 据国际精益六西格玛研究所(ILSSI)成员大卫·哈钦斯(David Hutchins)的回忆,在“六西格玛”名称出现前,摩托罗拉组建了约100个质量改进团队,接受朱兰博士制作的16盘录像带培训,名为《朱兰论质量改进》(Juran on Quality Improvement),为了推广这种严谨的分析方法(朱兰博士视频中的核心内容),摩托罗拉前首席执行官鲍勃·加尔文创造了“六西格玛”这一标签,用以表彰这种“最顶尖"的方法。大卫·哈钦斯(David Hutchins)是朱兰博士的好友,也为他的工作做
    优思学院 2025-04-22 12:03 72浏览
  •   卫星通信效能评估系统平台全面解析   北京华盛恒辉卫星通信效能评估系统平台是衡量卫星通信系统性能、优化资源配置、保障通信服务质量的关键技术工具。随着卫星通信技术的快速发展,特别是低轨卫星星座、高通量卫星和软件定义卫星的广泛应用,效能评估系统平台的重要性日益凸显。以下从技术架构、评估指标、关键技术、应用场景及发展趋势五个维度进行全面解析。   应用案例   目前,已有多个卫星通信效能评估系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润卫星通信效能评估系统。这些成功案例为卫
    华盛恒辉l58ll334744 2025-04-22 16:34 71浏览
  •   北京华盛恒辉机场保障能力评估系统软件深度解析   在航空运输业快速发展的背景下,机场保障任务愈发复杂,传统人工评估方式已无法满足高效精准的管理需求。机场保障能力评估系统软件作为提升机场运行效率、保障飞行安全的关键工具,其重要性日益凸显。   应用案例   目前,已有多个机场保障能力评估系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润机场保障能力评估系统。这些成功案例为机场保障能力评估系统的推广和应用提供了有力支持。   一、系统功能模块   数据采集与整合模块  
    华盛恒辉l58ll334744 2025-04-22 10:28 89浏览
  •   电磁兼容(EMC)故障诊断系统软件解析   北京华盛恒辉电磁兼容故障诊断系统软件是攻克电子设备电磁干扰难题的专业利器。在电子设备复杂度攀升、电磁兼容问题频发的背景下,该软件于研发、测试、生产全流程中占据关键地位。以下为其详细介绍:   应用案例   目前,已有多个电磁兼容故障诊断系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁兼容故障诊断系统。这些成功案例为电磁兼容故障诊断系统的推广和应用提供了有力支持。   一、软件核心功能   干扰与敏感分析:深度剖析电磁干
    华盛恒辉l58ll334744 2025-04-22 14:53 82浏览
  • 4 月 19 日,“增长无界・智领未来” 第十六届牛商大会暨电子商务十大牛商成果报告会在深圳凤凰大厦盛大举行。河南业之峰科技股份有限公司总经理段利强——誉峰变频器强哥凭借在变频器领域的卓越成就,荣膺第十六届电子商务十大牛商,携誉峰变频器品牌惊艳亮相,以十几年如一日的深耕与创新,书写着行业传奇。图 1:誉峰变频器强哥在牛商大会领奖现场,荣耀时刻定格牛商大会现场,誉峰变频器强哥接受了多家媒体的专访。面对镜头,他从容分享了自己在变频器行业二十年的奋斗历程与心路感悟。谈及全域营销战略的成功,誉峰变频器强
    电子与消费 2025-04-22 13:22 99浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦