0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于MM32F5和MindSDK使用輕量級(jí)圖像解碼器TJpgDec

冬至子 ? 來源:靈動(dòng)MM32 MCU ? 作者:靈動(dòng)MM32 MCU ? 2023-11-03 15:27 ? 次閱讀

TJpgDec簡(jiǎn)介

TJpgDec是一個(gè)為小型嵌入式系統(tǒng)高度優(yōu)化的創(chuàng)建JPEG圖像的解碼軟件。它工作時(shí)占用的內(nèi)存非常低,以便它可以集成到微控芯片,如AVR, 8051, PIC, Z80, Cortex-M0等。不依賴于具體的硬件平臺(tái),使用ANSI-C編寫,易于使用的操作模式,完全可重入的體系結(jié)構(gòu),非常小的內(nèi)存占用(獨(dú)立于圖像尺寸的3KB SRAM。3.5-8.5KB的代碼空間)。輸出格式可以是縮放比例為1/1、1/2、1/4或1/8可選,像素格式可以是RGB888或RGB565。

TJpgDec組件是一個(gè)免費(fèi)開放的軟件,可用于教育、科研和商業(yè)開發(fā)。用戶可以在包含TJpgDec的個(gè)人項(xiàng)目和商業(yè)產(chǎn)品中改寫和重新發(fā)布該組件。

TJpgDec組件在用戶的應(yīng)用中僅需要調(diào)用2個(gè)API。

jd_prepare() - 準(zhǔn)備解碼JPEG圖像

jd_prepare 分析JPEG數(shù)據(jù)并創(chuàng)建一個(gè)解碼對(duì)象用于隨后的解碼過程。

jd_prepare函數(shù)是JPEG解碼過程的第一階段。它接收用戶傳入的數(shù)據(jù)流(需要通過傳入的回調(diào)函數(shù)操作數(shù)據(jù)流),分析JPEG圖像和創(chuàng)建解碼參數(shù)表。函數(shù)成功后,會(huì)話準(zhǔn)備好在jd_decomp函數(shù)解碼JPEG圖像。應(yīng)用程序可以參考JPEG解碼對(duì)象中存儲(chǔ)的尺寸大小。這個(gè)信息將用于在后續(xù)的解碼階段配置輸出設(shè)備和參數(shù)。

JRESULT jd_prepare (
            JDEC* jdec,            /* Pointer to blank decompression object */
            UINT(*infunc)(JDEC*,BYTE*,UINT), /* Pointer to input function */
            void* work,            /* Pointer to work area */
            UINT sz_work,          /* Size of the work area */
            void* device           /* Device identifier for the session */
            );

輸入?yún)?shù):

  • jdec - 輸出,一個(gè)空的JDEC結(jié)構(gòu)體對(duì)象,初始化一個(gè)解碼對(duì)象。需要用戶先創(chuàng)建JPEC對(duì)象的內(nèi)存,然后本函數(shù)在執(zhí)行過程中會(huì)向其中填充有效信息,這個(gè)解碼對(duì)象也將用于后續(xù)的解碼操作。
  • infunc - 輸入,指定一個(gè)為解碼算法提供輸入數(shù)據(jù)的回調(diào)函數(shù)。實(shí)際上,這個(gè)方法也是關(guān)聯(lián)具體平臺(tái)的,不僅僅是提供一個(gè)讀數(shù)的方法,更確切是提供一個(gè)具體的數(shù)據(jù)流。這個(gè)infunc函數(shù)也是需要在具體平臺(tái)適配過程中需要用戶自行實(shí)現(xiàn)的。具體寫法可以看原作者給的應(yīng)用說明,也可以參見本文中的基于具體微控制器平臺(tái)的實(shí)現(xiàn)。
  • work - 輸入,指定一個(gè)內(nèi)存塊,給解碼器內(nèi)部運(yùn)行算法的工作空間。
  • sz_work - 輸入,指定work參數(shù)指定工作空間的 size,以字節(jié)為單位。TJpgDec至多需要3092字節(jié)的工作區(qū)域,這依賴于JPEG圖像的內(nèi)置參數(shù)表。通常情況下是3092字節(jié)工作區(qū)域。
  • device - 輸入,指定用戶自定義的會(huì)話設(shè)備標(biāo)識(shí)。它保存在解碼對(duì)象jdec的字段device中。它可以用于I/O函數(shù)去識(shí)別當(dāng)前會(huì)話。當(dāng)I/O device固定在project或者不需要這個(gè)功能,設(shè)置為NULL并忽略它。device參數(shù)可以作為回調(diào)函數(shù)中訪問綁定硬件的傳參。

返回值:

  • JDR_OK - 函數(shù)執(zhí)行成功,且編碼對(duì)象是有效的。
  • JDR_INP - 一個(gè)錯(cuò)誤發(fā)生在input函數(shù),由于硬件錯(cuò)誤或者流終止。
  • JDR_MEM1 - 工作空間不足解碼這個(gè)JPEG圖像。
  • JDR_MEM2 - 工作空間不足解碼這個(gè)JPEG圖像??赡芨 ?/li>
  • JDR_PAR - 參數(shù)錯(cuò)誤。傳入工作空間的指針為NULL。
  • JDR_FMT1 - 數(shù)據(jù)格式錯(cuò)誤。JPEG數(shù)據(jù)損壞。
  • JDR_FMT2 - 格式正確,但不支持。也許是一個(gè)灰度圖像。
  • JDR_FMT3 - 不支持JPEG標(biāo)準(zhǔn),也許是一個(gè)后續(xù)版本的JPEG圖像。

jd_decomp() - 執(zhí)行解碼JPEG圖像

jd_decomp()函數(shù)解碼JPEG圖像并輸出RGB數(shù)據(jù)。

jd_decomp()是JPEG解碼過程的第二階段。它進(jìn)一步執(zhí)行解碼JPEG圖像的過程,并通過用戶定義的輸出函數(shù)輸出數(shù)據(jù),但同時(shí)也繼續(xù)使用在jd_prepare()傳入的輸入數(shù)據(jù)流的函數(shù)。在它之后,解碼對(duì)象將不在有效。

在解碼時(shí)指定的比例因子,它將JPEG圖像按1/2、1/4或1/8比例縮放尺寸。例如,當(dāng)解碼一個(gè)1024x768大小JPEG圖像在1/4比例,它將輸出256x192大小。相比不縮放,1/2和1/4的縮放由于求均值,解碼速度略有下降。但是1/8縮放相比不縮放是2-3倍的速度輸出,因?yàn)槊總€(gè)塊IDCT和求均值可以跳過,這一特點(diǎn)適合創(chuàng)建縮略圖。

JRESULT jd_decomp (
            JDEC* jdec,             /* Pointer to valid decompressor object */
            UINT(*outfunc)(JDEC*,void*,JRECT*), /* Pointer to output function */
            BYTE scale              /* Scaling factor */
            );

輸入?yún)?shù):

  • jdec - 輸入,指定有效的解碼對(duì)象。其實(shí)就是之前在jd_prepare()函數(shù)中準(zhǔn)備好的JDEC對(duì)象。
  • outfunc - 輸入,指定用戶定義的JPEG解碼過程輸出數(shù)據(jù)流的回調(diào)函數(shù)。jd_decomp()調(diào)用這個(gè)函數(shù)去輸出解碼JPEG圖像的RGB形式數(shù)據(jù)流。具體寫法可以看原作者給的應(yīng)用說明,也可以參見本文中的基于具體微控制器平臺(tái)的實(shí)現(xiàn)。
  • scale - 輸入,指定輸出縮放值N。輸出圖像的縮小比例為1/2^N(N = 0 to 3)。當(dāng)不使用縮放功能時(shí)(JD_USE_SCALE == 0),可以指定為0。

返回值

  • JDR_OK - 函數(shù)執(zhí)行成功。
  • JDR_INTR - 解碼過程在輸出函數(shù)中斷。
  • JDR_INP - 一個(gè)錯(cuò)誤發(fā)生在input函數(shù),由于硬件錯(cuò)誤或者流終止。
  • JDR_PAR - 參數(shù)錯(cuò)誤。給定的縮放值無效。
  • JDR_FMT1 - 數(shù)據(jù)格式錯(cuò)誤。JPEG數(shù)據(jù)損壞。

tjpgdcnf.h - 配置文件

早期版本的TjpgDec源碼中并沒有tjpgdcnf.h文件。我試著找了一下tjpgdec項(xiàng)目的changelog,沒有直接找到關(guān)于版本更新的詳情內(nèi)容,但是遍歷了到目前為止tjpgd所有發(fā)布版本的軟件包,確定了tjpgdcnf.h首次出現(xiàn)的版本是2021年5月8日發(fā)布的R0.02版本。在這個(gè)文件中,更細(xì)化地提取了一些對(duì)TJpgDec軟件配置和裁剪的一些選項(xiàng),在當(dāng)前最新的R0.03版本中源碼如下(原作者非常貼心地注釋了可用的選項(xiàng)和對(duì)應(yīng)的解釋):

/*----------------------------------------------*/
/* TJpgDec System Configurations R0.03          */
/*----------------------------------------------*/

#define    JD_SZBUF        512
/* 指定在輸入數(shù)據(jù)流中每次讀取的字節(jié)數(shù),512、1024、2048等等均可。*/

#define JD_FORMAT        0
/* Specifies output pixel format.
/  0: RGB888 (24-bit/pix)
/  1: RGB565 (16-bit/pix)
/  2: Grayscale (8-bit/pix)
*/

#define    JD_USE_SCALE    1
/* Switches output descaling feature.
/  0: Disable
/  1: Enable
*/

#define JD_TBLCLIP        1
/* Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size.
/  0: Disable
/  1: Enable
*/

#define JD_FASTDECODE    0
/* Optimization level
/  0: Basic optimization. Suitable for 8/16-bit MCUs.
/  1: + 32-bit barrel shifter. Suitable for 32-bit MCUs.
/  2: + Table conversion for huffman decoding (wants 6 < < HUFF_BIT bytes of RAM)
*/

針對(duì)使用ARM Cortex-MC1處理器內(nèi)核和FSMC驅(qū)動(dòng)的16位并口屏幕的MM32F5微控制器,這里需要改寫:

#define JD_FORMAT     1 /* 1: RGB565 (16-bit/pix) */
#define JD_FASTDECODE 1 /* 1: + 32-bit barrel shifter. Suitable for 32-bit MCUs. */

注意,這里似乎還藏了一個(gè)彩蛋。同時(shí)支持RGB888、RGB565和灰度圖像,這意味著TJpgDec軟件內(nèi)部的源碼內(nèi)部包含了原始RGB888轉(zhuǎn)RGB565和灰度圖像的算式,這個(gè)在純輸出的GUI應(yīng)用開發(fā)中講會(huì)用到,屆時(shí)可以直接復(fù)制驗(yàn)證過的代碼片段,而不用我們?cè)僮孕芯帉懻{(diào)試?yán)病?/p>

關(guān)于TJpgDec的軟件許可證

這是一份包含在源代碼TJpgDec中的許可聲明。

/*----------------------------------------------------------------------------/
/ TJpgDec - Tiny JPEG Decompressor R0.xx                       (C)ChaN, 20xx
/-----------------------------------------------------------------------------/
/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems.
/ This is a free software that opened for education, research and commercial
/  developments under license policy of following terms.
/
/  Copyright (C) 20xx, ChaN, all right reserved.
/
/ * The TJpgDec module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/----------------------------------------------------------------------------*/

TJpgDec許可是BSD風(fēng)格的,但存在一些差異。因?yàn)門JpgDec是嵌入式項(xiàng)目,對(duì)以二進(jìn)制形式的分發(fā),如嵌入式代碼,hex文件或二進(jìn)制庫,未指定以增加其可用性。分發(fā)的文檔不強(qiáng)制包含關(guān)于tjpgdec及其授權(quán)文件。TJpgDec是基于GNU GPL兼容的項(xiàng)目。當(dāng)有任何修改下重新分發(fā),許可證也可以改為GNU GPL或BSD許可證。

應(yīng)用接口解析

TJpgDec組件的移植過程僅需要實(shí)現(xiàn)兩個(gè)函數(shù),輸入數(shù)據(jù)和輸出數(shù)據(jù)。但從嚴(yán)格意義上講,這兩個(gè)函數(shù)都只是以約定的方式將數(shù)據(jù)流傳入到TJpgDec組件,或者從TJpgDec組件中傳出到指定存儲(chǔ)空間,因?yàn)橥耆莾?nèi)存到內(nèi)存的操作,不涉及到任何與具體硬件平臺(tái)相關(guān)綁定關(guān)系,所以也算不上移植。甚至在原作者的用戶使用文檔中,也是以應(yīng)用筆記(TJpgDec Application Note)作為文檔的名字,而不是移植指南。

原作者在《TJpgDec Module Application Note》中講述了在應(yīng)用中使用TJpgDec組件的操作步驟。建議用戶先試著構(gòu)建和運(yùn)行原作者提供的示例程序。

解碼會(huì)話分為兩個(gè)階段。第一階段是分析JPEG圖像,第二階段是解碼。

  1. 初始化輸入流。(例如打開一個(gè)文件)
  2. 分配JPEG解碼對(duì)象和工作區(qū)域。
  3. 調(diào)用jd_prepare()指定輸入數(shù)據(jù)流,并執(zhí)行分析和準(zhǔn)備壓縮的JPEG圖像。
  4. 使用解碼對(duì)象中的圖像信息初始化輸出設(shè)備。
  5. 調(diào)用jd_decomp()指定輸出數(shù)據(jù)流,解碼JPEG圖像并輸出。

image.png

圖x 在應(yīng)用中使用TJpgDec組件的調(diào)用關(guān)系圖

這是原作者提供的一段參考源碼,描述了如何使用TJpgDec模塊。

/*------------------------------------------------*/
/* TJpgDec Quick Evaluation Program for PCs       */
/*------------------------------------------------*/
#include < stdio.h >
#include < string.h >
#include "tjpgd.h"

/* 用戶定義設(shè)備標(biāo)識(shí) */
typedefstruct {
    FILE *fp;      /* 用于輸入函數(shù)的文件指針 */
    BYTE *fbuf;    /* 用于輸出函數(shù)的幀緩沖區(qū)的指針 */
    UINT wfbuf;    /* 幀緩沖區(qū)的圖像寬度[像素] */
} IODEV;

/*------------------------------*/
/*      用戶定義input funciton  */
/*------------------------------*/
UINT in_func (JDEC* jd, BYTE* buff, UINT nbyte)
{
    IODEV *dev = (IODEV*)jd- >device; /* Device identifier for the session (5th argument of jd_prepare function) */

    if (buff) {
        /* 從輸入流讀取一字節(jié) */
        return (UINT)fread(buff, 1, nbyte, dev- >fp);
    } else {
        /* 從輸入流移除一字節(jié) */
        return fseek(dev- >fp, nbyte, SEEK_CUR) ? 0 : nbyte;
    }
}

/*------------------------------*/
/*      用戶定義output funciton */
/*------------------------------*/
UINT out_func (JDEC* jd, void* bitmap, JRECT* rect)
{
    IODEV *dev = (IODEV*)jd- >device;
    BYTE *src, *dst;
    UINT y, bws, bwd;

    /* 輸出進(jìn)度 */
    if (rect- >left == 0) {
        printf("r%lu%%", (rect- >top < < jd- >scale) * 100UL / jd- >height);
    }

    /* 拷貝解碼的RGB矩形范圍到幀緩沖區(qū)(假設(shè)RGB888配置) */
    src = (BYTE*)bitmap;
    dst = dev- >fbuf + 3 * (rect- >top * dev- >wfbuf + rect- >left);  /* 目標(biāo)矩形的左上 */
    bws = 3 * (rect- >right - rect- >left + 1);     /* 源矩形的寬度[字節(jié)] */
    bwd = 3 * dev- >wfbuf;                         /* 幀緩沖區(qū)寬度[字節(jié)] */
    for (y = rect- >top; y <= rect- >bottom; y++) {
        memcpy(dst, src, bws);   /* 拷貝一行 */
        src += bws; dst += bwd;  /* 定位下一行 */
    }

    return1;    /* 繼續(xù)解碼 */
}

/*------------------------------*/
/*        主程序                */
/*------------------------------*/
int main (int argc, char* argv[])
{
    void *work;       /* 指向解碼工作區(qū)域 */
    JDEC jdec;        /* 解碼對(duì)象 */
    JRESULT res;      /* TJpgDec API的返回值 */
    IODEV devid;      /* 用戶定義設(shè)備標(biāo)識(shí) */

    /* 打開一個(gè)JPEG文件 */
    if (argc < 2) return-1;
    devid.fp = fopen(argv[1], "rb");
    if (!devid.fp) return-1;

    /* 分配一個(gè)用于TJpgDec的工作區(qū)域 */
    work = malloc(3500);

    /* 準(zhǔn)備解碼 */
    res = jd_prepare(&jdec, in_func, work, 3500, &devid);
    if (res == JDR_OK) {
        /* 準(zhǔn)備好解碼。圖像信息有效 */
        printf("Image dimensions: %u by %u. %u bytes used.n", jdec.width, jdec.height, 3100 - jdec.sz_pool);

        devid.fbuf = malloc(3 * jdec.width * jdec.height); /* 輸出圖像的幀緩沖區(qū)(假設(shè)RGB888配置) */
        devid.wfbuf = jdec.width;

        res = jd_decomp(&jdec, out_func, 0);   /* 開始1/1縮放解碼 */
        if (res == JDR_OK) {
            /* 解碼成功。你在這里已經(jīng)解碼圖像到幀緩沖區(qū) */
            printf("rOK  n");
        } else {
            printf("Failed to decompress: rc=%dn", res);
        }
        free(devid.fbuf);    /* 釋放幀緩沖區(qū) */
    } else {
        printf("Failed to prepare: rc=%dn", res);
    }

    free(work);             /* 釋放工作區(qū)域 */
    fclose(devid.fp);       /* 關(guān)閉JPEG文件 */

    return res;
}

這里詳細(xì)說明兩個(gè)回調(diào)函數(shù)的寫法。

in_func() - 輸入數(shù)據(jù)流回調(diào)函數(shù)

用戶需要在輸入數(shù)據(jù)流的回調(diào)函數(shù)in_func()中讀取JPEG數(shù)據(jù)存入傳參指針buff中。在jd_prepare()函數(shù)中傳入數(shù)據(jù)流到TJpgDec模塊。

UINT in_func (
            JDEC* jdec,    /* Pointer to the decompression object */
            BYTE* buff,    /* Pointer to buffer to store the read data */
            UINT ndata     /* Number of bytes to read */
            );

輸入?yún)?shù):

  • jdec - 輸入,當(dāng)前服務(wù)的jdec對(duì)象的handler。通過這個(gè)handler可以訪問到當(dāng)前服務(wù)的jdec對(duì)象的所有資源。
  • buff - 輸出,一塊內(nèi)存區(qū),從介質(zhì)中讀取指定數(shù)量的字節(jié)數(shù)據(jù)后,存放到這塊內(nèi)存區(qū),交給調(diào)用者。但如果buff的值為NULL,就表示跳過ndata參數(shù)指定數(shù)量的數(shù)據(jù)。
  • ndata - 輸入,調(diào)用者希望從輸入數(shù)據(jù)流中讀到的字節(jié)數(shù)量,即buff的大小?;蛘弋?dāng)buff的值為NULL時(shí),此處參數(shù)指定為需要在輸入數(shù)據(jù)流中跳過讀取的字節(jié)數(shù)量。

實(shí)際上,這里還有一個(gè)隱形的參數(shù),即出現(xiàn)在tjpgdcnf.h文件中的JD_SZBUF,它約定的應(yīng)該是每次從輸入流讀取的最大字節(jié)數(shù)量,即ndata的最大值。

返回值:

  • 返回實(shí)際讀取或移除的字節(jié)數(shù)。若返回0,jd_prepare()jd_decomp()函數(shù)將終止并返回JDR_INP

out_func() - 輸出數(shù)據(jù)流回調(diào)函數(shù)

用戶可指定解碼出來的像素輸出到具體的存儲(chǔ)區(qū),這個(gè)存儲(chǔ)區(qū)可以是一塊內(nèi)存,或者映射到顯存的地址空間。用戶需要在out_func()函數(shù)內(nèi)部,在rect參數(shù)執(zhí)行的矩形區(qū)域中填充bitmap參數(shù)指定的像素信息。

UINT out_func (
            JDEC* jdec,    /* Pointer to the decompression object */
            void* bitmap,  /* RGB bitmap to be output */
            JRECT* rect    /* Rectangular region to output */
            );

輸入?yún)?shù):

  • jdec - 輸入,當(dāng)前服務(wù)的jdec對(duì)象的handler。通過這個(gè)handler可以訪問到當(dāng)前服務(wù)的jdec對(duì)象的所有資源。
  • bitmap - 像素?cái)?shù)據(jù)流。是按照tjpgdcnf.h文件中JD_FORMAT選項(xiàng)指定的格式組織,可以是3字節(jié)表示的一個(gè)像素的RGB888格式,也可以是2字節(jié)表示一個(gè)像素的RGB565格式等。第一個(gè)像素是rect指定矩形區(qū)域的左上角,從左到右,從上到下,最后一個(gè)像素是右下角的位置。
  • rect - 輸入,執(zhí)行顯示像素區(qū)域的矩形。JRECT類型的結(jié)構(gòu)體中,有Left、Right、Top、Bottom四個(gè)字段,指示當(dāng)前解碼輸出的矩形區(qū)域。實(shí)際上,這個(gè)矩形的大小從1x1到16x16不等,取決于圖像的裁剪、縮放和采樣因子(JPEG信息)。

返回值:

  • 通常返回1,以便TJpgDec繼續(xù)解碼過程。當(dāng)它返回0,jd_decomp函數(shù)終止并返回JDR_INTR

輸入數(shù)據(jù)流可能時(shí)常發(fā)生變化,因?yàn)橐x取不同的jpg圖像文件。輸出數(shù)據(jù)流也是在應(yīng)用中根據(jù)需要變化的,只不過因?yàn)樵诖蠖鄶?shù)微控制器應(yīng)用中,顯示設(shè)備通常只有一個(gè),所以統(tǒng)一輸出到這個(gè)顯示設(shè)備對(duì)應(yīng)的顯存中。有一些對(duì)于輸出體驗(yàn)有要求的場(chǎng)景,需要輸出到特定的存儲(chǔ)空間,為了進(jìn)行二次渲染,或者多緩沖區(qū)的應(yīng)用,此時(shí)就需要在應(yīng)用根據(jù)程序執(zhí)行的情況動(dòng)態(tài)切換輸出了區(qū)域了。

關(guān)于工作區(qū)和幀緩沖區(qū)

在應(yīng)用程序中調(diào)用jd_prepare()函數(shù)時(shí),需要為TJpgDec指定一塊工作區(qū),作為TJpgDec在內(nèi)部運(yùn)行解碼算法的臨時(shí)空間。TJpgDec至少需要3100字節(jié)用于JPEG圖像,這取決于解碼JPEG圖像使用怎樣的參數(shù)。3100字節(jié)是在默認(rèn)輸入緩存(JD_SZBUF == 512)下的最大內(nèi)存需求,并隨JD_SZBUFJD_FASTDECODE的配置值變化。JD_SZBUF定義每次從輸入流中讀取多少字節(jié)。TJpgDec對(duì)齊每個(gè)讀請(qǐng)求緩沖區(qū)大小,512, 1024, 2048... 字節(jié)是從存儲(chǔ)設(shè)備讀取的理想大小。

在樣例代碼中,原作者使用了動(dòng)態(tài)分配的內(nèi)存作為工作區(qū),這對(duì)于擁有海量存儲(chǔ)資源和完善內(nèi)存管理機(jī)制的PC環(huán)境是合適的。但在資源受限的嵌入式系統(tǒng)平臺(tái)上,使用靜態(tài)內(nèi)存會(huì)是更穩(wěn)妥的選擇。

另外,樣例代碼中使用了幀緩沖區(qū)(devid結(jié)構(gòu)體變量中的fbuf指定內(nèi)存區(qū),wfbuf指定寬度),在應(yīng)用程序和out_func回調(diào)函數(shù)之間傳遞像素?cái)?shù)據(jù),但實(shí)際看起來有點(diǎn)莫名其妙。此處了解到以矩形方式傳送像素矩陣的模式之后,用戶也可以自行簡(jiǎn)化代碼。

在MM32F5微控制器上應(yīng)用

在MM32F5微控制器上適配TJpgDec時(shí),我使用了FatFs文件系統(tǒng)作為JPEG圖像文件的來源,使用靜態(tài)內(nèi)存作為工作區(qū),簡(jiǎn)化了對(duì)“幀緩沖區(qū)”的使用,并使用LCD模塊作為輸出設(shè)備。最終實(shí)現(xiàn)在微控制器系統(tǒng)中啟用JPEG圖像解碼器的功能。

在包含TJpgDec組件的plus-f5270_image_fatfs_tjpgdec_basic_mdk工程中,我將打開圖像文件并解碼的過程封裝成bool app_fs_display_jpg_file(char * filepath)函數(shù),如此,在主循環(huán)中遍歷到文件系統(tǒng)中的jpg文件后,可以直接使用其文件路徑打開文件并顯示像素信息到LCD屏上。這個(gè)函數(shù)中,就使用到了靜態(tài)內(nèi)存分配的工具區(qū)域app_tjpgdec_work_buff。從代碼中可以看出,代碼的內(nèi)容被簡(jiǎn)化了不少。

#define APP_TJPGDEC_WORK_BUFF_SIZE 3500
uint8_t app_tjpgdec_work_buff[APP_TJPGDEC_WORK_BUFF_SIZE];

/* display a jpg file with its full filepath. */
bool app_fs_display_jpg_file(char * filepath)
{
    JRESULT res;      /* Result code of TJpgDec API */
    JDEC jdec;        /* Decompression object */
    //void *work;       /* Pointer to the work area */
    //size_t sz_work = 3500; /* Size of work area */
    IODEV devid;      /* Session identifier */
    FRESULT fres;
    
    /* Initialize input stream */
    devid.fp = &app_fs_file;
    fres = f_open(devid.fp, filepath, FA_READ);
    if (fres != FR_OK)
    {
        return-1;
    }
    
    /* Prepare to decompress */
    //work = (void*)malloc(sz_work);
    //res = jd_prepare(&jdec, in_func, work, sz_work, &devid);
    res = jd_prepare(&jdec, in_func, app_tjpgdec_work_buff, APP_TJPGDEC_WORK_BUFF_SIZE, &devid);
    if (res == JDR_OK)
    {
        /* It is ready to dcompress and image info is available here */
        //printf("Image size is %u x %u.n%u bytes of work ares is used.n", jdec.width, jdec.height, sz_work - jdec.sz_pool);

        /* Initialize output device */
        //devid.fbuf = (uint8_t*)malloc(N_BPP * jdec.width * jdec.height); /* Create frame buffer for output image */
        //devid.wfbuf = jdec.width;

        res = jd_decomp(&jdec, out_func, 0);   /* Start to decompress with 1/1 scaling */
        if (res == JDR_OK)
        {
            /* Decompression succeeded. You have the decompressed image in the frame buffer here. */
            printf("rDecompression succeeded.n");
        } else {
            printf("jd_decomp() failed (rc=%d)n", res);
        }
        //free(devid.fbuf);    /* Discard frame buffer */
    }
    else
    {
        printf("jd_prepare() failed (rc=%d)n", res);
    }
    //free(work);             /* Discard work area */
    f_close(devid.fp);       /* Close the JPEG file */
    returntrue;
}

同時(shí),在實(shí)現(xiàn)輸入輸出數(shù)據(jù)流的回調(diào)函數(shù)時(shí),也有一些考究。

在實(shí)現(xiàn)輸入數(shù)據(jù)流的回調(diào)函數(shù)的過程中,由于使用了FatFs文件系統(tǒng),其中很多類POSIX的接口同樣例代碼的行為并不完全一致,需要做一些轉(zhuǎn)接的工作。特別FatFs文件系統(tǒng)中的f_lseek()函數(shù)是從文件開始計(jì)算偏移,而不是像通用的f_seek()函數(shù)從當(dāng)前位置算偏移,因此需要使用f_tell()函數(shù)做一個(gè)適配。

size_t in_func (    /* Returns number of bytes read (zero on error) */
    JDEC* jd,       /* Decompression object */
    uint8_t* buff,  /* Pointer to the read buffer (null to remove data) */
    size_t nbyte    /* Number of bytes to read/remove */
)
{
    IODEV *dev = (IODEV*)jd- >device;   /* Session identifier (5th argument of jd_prepare function) */
    UINT br;

    if (buff) /* Read data from imput stream */
    {
        //return fread(dev- >fp, buff, 1, nbyte, dev- >fp);
        return (FR_OK == f_read(dev- >fp, buff, nbyte, &br)) ? br : 0;
    }
    else/* Remove data from input stream */
    {
        //return f_seek(dev- >fp, nbyte, SEEK_CUR) ? 0 : nbyte;
        return (FR_OK == f_lseek(dev- >fp, f_tell(dev- >fp) + nbyte)) ? nbyte : 0;
    }
}

在實(shí)現(xiàn)輸出數(shù)據(jù)流的回調(diào)函數(shù)的過程中,可以直接對(duì)接到開發(fā)板上LCD屏的顯存中,直接顯示像素。

int out_func (      /* Returns 1 to continue, 0 to abort */
    JDEC* jd,       /* Decompression object */
    void* bitmap,   /* Bitmap data to be output */
    JRECT* rect     /* Rectangular region of output image */
)
{
    /* Progress indicator */
    if (rect- >left == 0)
    {
        printf("r%lu%%", (rect- >top < < jd- >scale) * 100UL / jd- >height);
    }
    
    /* 在LCD屏幕上顯示圖像信息. */
    LCD_FillWindow(rect- >left, rect- >top, rect- >right, rect- >bottom, (uint16_t *)bitmap);

    return1;    /* Continue to decompress */
}

Keil工程中編譯可執(zhí)行文件,下載到plus-f5270開發(fā)板上,實(shí)物演示如圖x所示。

640.gif

圖x 在plus-f5270開發(fā)板上運(yùn)行TJpgDec

Code Size (-0):

==============================================================================

    Total RO  Size (Code + RO Data)                45096 (  44.04kB)
    Total RW  Size (RW Data + ZI Data)             13032 (  12.73kB)
    Total ROM Size (Code + RO Data + RW Data)      45104 (  44.05kB)

==============================================================================

其中,SRAM占用量是比較少的,總共13032字節(jié),其中系統(tǒng)棧占用4KB,系統(tǒng)堆占用4KB,工作空間占用3500字節(jié),還帶了個(gè)FatFs文件系統(tǒng),這已經(jīng)算是非常經(jīng)濟(jì)的用量了。

一點(diǎn)思考

從實(shí)際演示效果來看,移植的樣例工程能夠完成JPEG解碼功能,驗(yàn)證了TJpgDec組件能夠正常工作,這是非常不錯(cuò)的。但由于從SD卡讀數(shù)、解碼、刷屏這些個(gè)步驟都是一小段一小段執(zhí)行的,因此實(shí)際顯示圖像刷屏的速度不是很快(估計(jì)受讀取SD卡過程的影響較大)。一種改進(jìn)的策略,是將解碼得到的圖像片段搜集到一塊大內(nèi)存中,然后集中刷屏,這樣視覺效果會(huì)好很多。解碼完之后純刷屏的速度很快,解碼之前雖然有等待,但當(dāng)前屏幕上還在放映之前解碼的圖片,參觀者不會(huì)感到無趣。

plus-f5270開發(fā)板上的MM32F5270微控制器僅有128KB的SRAM,不夠存放一整張圖(480x320),但是可以存放1/4個(gè)屏幕的圖片數(shù)據(jù)(75KB),可以考慮將屏幕分成四塊小屏來用,每次刷一塊。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 微控制器
    +關(guān)注

    關(guān)注

    48

    文章

    7334

    瀏覽量

    150086
  • 解碼器
    +關(guān)注

    關(guān)注

    9

    文章

    1107

    瀏覽量

    40443
  • RGB
    RGB
    +關(guān)注

    關(guān)注

    4

    文章

    785

    瀏覽量

    58199
  • 回調(diào)函數(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    87

    瀏覽量

    11508
  • SRAM存儲(chǔ)器
    +關(guān)注

    關(guān)注

    0

    文章

    88

    瀏覽量

    13243
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    手工打造基于MM32F5微控制的MicroPython開發(fā)板

    集成(感謝同事Hao的出色工作),使我得以在MM32F5微控制上運(yùn)行的MicroPython項(xiàng)目中,使用基于flash存儲(chǔ)芯片的LittleFS文件系統(tǒng),替換掉基于SD卡的FatFS文件系統(tǒng)。經(jīng)過剛剛過去兩天一夜的編碼和調(diào)試,終于大功告成!
    的頭像 發(fā)表于 06-16 10:57 ?1130次閱讀
    手工打造基于<b class='flag-5'>MM32F5</b>微控制<b class='flag-5'>器</b>的MicroPython開發(fā)板

    基于MM32F5微控制的FSMC接口外接SRAM存儲(chǔ)的用法

    MM32F5微控制基于Arm STAR-MC1微控制,最高主頻可達(dá)120MHz,集成了FPU單元和DSP擴(kuò)展指令集,有不錯(cuò)的算力。
    發(fā)表于 07-17 15:08 ?1272次閱讀
    基于<b class='flag-5'>MM32F5</b>微控制<b class='flag-5'>器</b>的FSMC接口外接SRAM存儲(chǔ)<b class='flag-5'>器</b>的用法

    應(yīng)用AM3358,請(qǐng)問怎樣在硬件設(shè)計(jì)上外部連接解碼器芯片,實(shí)現(xiàn)對(duì)圖像數(shù)據(jù)的解碼?

    本帖最后由 一只耳朵怪 于 2018-6-5 14:46 編輯 圖像數(shù)據(jù)由網(wǎng)口發(fā)送給AM3358,需要解碼,現(xiàn)在想通過外部連接解碼器芯片來實(shí)現(xiàn),可是看了下手冊(cè),不太清楚ARM由哪
    發(fā)表于 06-04 15:35

    10個(gè)輕量級(jí)框架

    這些輕量級(jí)框架使用HTML5和CSS3標(biāo)準(zhǔn)來幫助您快速開發(fā)跨平臺(tái)的Web移動(dòng)應(yīng)用和網(wǎng)站。
    發(fā)表于 07-17 08:25

    基于MM32F5270開發(fā)板對(duì)MindSDK進(jìn)行使用測(cè)評(píng)

    1、MindSDK使用測(cè)評(píng)步驟  Plus-F5270,據(jù)靈動(dòng)微電子市場(chǎng)總監(jiān)王維介紹,MM32F5系列采用Armv8-M Mainline架構(gòu),全系配置安謀科技“星辰”STAR-MC1處理
    發(fā)表于 09-01 17:05

    高清解碼器的作用

    高清解碼器(xunwei)的主要作用在于接收前端高清編碼圖像或網(wǎng)絡(luò)攝像頭信號(hào)并解碼,然后通過自身的各種視頻輸出接口,如HDMI、DVI、SDI、VGA、BNC輸出顯示到顯示設(shè)備上。編碼
    的頭像 發(fā)表于 12-10 15:47 ?1.3w次閱讀
    高清<b class='flag-5'>解碼器</b>的作用

    標(biāo)記圖像文件格式(TIFF)解碼器-下載生產(chǎn)代碼

    標(biāo)記圖像文件格式(TIFF)解碼器-下載生產(chǎn)代碼
    發(fā)表于 03-23 13:30 ?9次下載
    標(biāo)記<b class='flag-5'>圖像</b>文件格式(TIFF)<b class='flag-5'>解碼器</b>-下載生產(chǎn)代碼

    Blackfin下載產(chǎn)品代碼的位圖圖像文件(BMP)解碼器

    Blackfin下載產(chǎn)品代碼的位圖圖像文件(BMP)解碼器
    發(fā)表于 06-08 11:46 ?1次下載
    Blackfin下載產(chǎn)品代碼的位圖<b class='flag-5'>圖像</b>文件(BMP)<b class='flag-5'>解碼器</b>

    靈動(dòng)微電子發(fā)布高性能MM32F5系列MCU產(chǎn)品

    MM32F5作為一個(gè)通用高性能的MCU平臺(tái),對(duì)于不同的應(yīng)用場(chǎng)景和項(xiàng)目需要,客戶可以從中選擇所需的功能接口。同時(shí),靈動(dòng)也提供不同封裝形式如64,100和144pin,以及-40~105℃的擴(kuò)展工業(yè)級(jí)產(chǎn)品選項(xiàng)供客戶選擇。
    的頭像 發(fā)表于 04-15 14:18 ?2476次閱讀

    靈動(dòng)微電子高端MCU產(chǎn)品MM32F5系列正式量產(chǎn)

    日前,上海靈動(dòng)微電子股份有限公司(以下簡(jiǎn)稱“靈動(dòng)微電子”)宣布高端MCU產(chǎn)品MM32F5系列已正式量產(chǎn)。
    的頭像 發(fā)表于 06-17 09:32 ?1931次閱讀

    搭載安謀科技“星辰”STAR-MC1處理MM32F5系列MCU量產(chǎn)

    作為靈動(dòng)微電子高端MCU系列的開局,MM32F5在內(nèi)核性能和資源配置上都較之前產(chǎn)品有很大提升。MM32F5系列產(chǎn)品配置了以太網(wǎng)、USB 和雙FlexCAN 等豐富的通信接口以及多達(dá)14組UART、SPI 和I2C
    的頭像 發(fā)表于 06-17 09:29 ?1207次閱讀

    MM32F5 推廣彩頁:新內(nèi)核,新架構(gòu),"星"平臺(tái)(中文版)

    MM32F5 推廣彩頁:新內(nèi)核,新架構(gòu),"星"平臺(tái)(中文版)
    發(fā)表于 02-23 18:44 ?0次下載
    <b class='flag-5'>MM32F5</b> 推廣彩頁:新內(nèi)核,新架構(gòu),"星"平臺(tái)(中文版)

    MM32F5 推廣彩頁:新內(nèi)核,新架構(gòu),"星"平臺(tái)(英文版)

    MM32F5 推廣彩頁:新內(nèi)核,新架構(gòu),"星"平臺(tái)(英文版)
    發(fā)表于 02-23 18:44 ?0次下載
    <b class='flag-5'>MM32F5</b> 推廣彩頁:新內(nèi)核,新架構(gòu),"星"平臺(tái)(英文版)

    解碼器該怎么選?

    當(dāng)一個(gè)監(jiān)控項(xiàng)目中是有多臺(tái)錄像機(jī)的時(shí)候,每臺(tái)錄像機(jī)是可以接顯示來顯示圖像,但是!它只能顯示自己添加的攝像機(jī)圖像! * **解碼器** **是可以把任意一臺(tái)錄像機(jī)的
    的頭像 發(fā)表于 05-06 11:07 ?3585次閱讀

    MicroPython應(yīng)用基礎(chǔ)-準(zhǔn)備基于MM32F5的MicroPython開發(fā)板

    本文主要面向 **2023年全國(guó)大學(xué)生物聯(lián)網(wǎng)設(shè)計(jì)競(jìng)賽安謀科技命題** ,使用星辰處理的靈動(dòng)MM32F5微控制開發(fā)板,基于MicroPython開發(fā)應(yīng)用系統(tǒng)。
    的頭像 發(fā)表于 10-19 18:27 ?871次閱讀
    MicroPython應(yīng)用基礎(chǔ)-準(zhǔn)備基于<b class='flag-5'>MM32F5</b>的MicroPython開發(fā)板