S3C2416裸機開發(fā)系列二十_Libjpeg的移植
jpeg格式是一種針對相片影像而廣泛使用的一種失真壓縮標準,其壓縮技術十分先進,用有損壓縮方式去除冗余的圖像數(shù)據(jù),在獲得極高壓縮率的同時,能展現(xiàn)十分豐富生動的圖像,能用最少的磁盤空間得到較好的圖像品質。由于其尺寸較小,能夠較快地在網(wǎng)絡上傳輸,因此在數(shù)碼相機、網(wǎng)頁等領域均廣泛應用到jpeg圖像格式。筆者此處就移植libjpeg開源庫來應用jpeg作一個簡單的介紹。
1. 代碼準備libjpeg源碼,libjpeg是一個完全用c語言編寫的庫,包含了被廣泛使用的jpeg編碼、jpeg解碼和其它的jpeg功能的實現(xiàn),這個庫由獨立的jpeg工作組維護。請讀者自行到官網(wǎng)下載最新的源碼。
s3c2416啟動代碼工程,啟動代碼是s3c2416/50/51這系列arm9芯片在運行用戶c代碼main函數(shù)之前必須先運行的代碼,啟動代碼支持sd、Nand啟動,為用戶設置系統(tǒng)時鐘,初始化內(nèi)存,自動識別啟動設備并搬移代碼到RAM,MMU映射,中斷管理等,支持x、ymodem文件傳輸協(xié)議,代碼可直接通過串口下載進RAM執(zhí)行,用戶只需專注于用c開發(fā)其它功能函數(shù)即可。關于啟動代碼以及啟動代碼的實現(xiàn)過程,筆者前面章節(jié)有非常詳細的介紹。此處在MDK下開發(fā),下載”MDK啟動代碼工程應用實例”中的啟動代碼源碼。
用戶代碼,用c開發(fā)的所有功能代碼,其中,用戶代碼入口為main()函數(shù),在這里用libjpeg庫實現(xiàn)在屏上顯示jpeg圖像以及屏幕截圖保存成jpeg圖片。
2. 標準io庫函數(shù)libjpeg由于其開源免費,對桌面操作系統(tǒng)均有良好的支持,因此在linux、windows操作系統(tǒng)下均常用libjpeg來編解碼jpeg圖片。libjpeg以及例程使用了標準io庫函數(shù),如文件操作fopen、fread、fwrite等;輸入、輸出、錯誤流函數(shù)printf、fprintf等。對于嵌入式開發(fā)來說,所有的io操作均是面對特定設備,編譯器的標準c庫是無法統(tǒng)一實現(xiàn)的,應由用戶去實現(xiàn)。在arm編譯器中,是使用一種半主機的模式,當用戶使用了標準io庫函數(shù)時,默認情況下,編譯器是通過一組定義好的軟中斷來把io應用請求傳送至運行調(diào)試器的主機,如用printf和scanf來使用主機的屏幕以及鍵盤,需要jtag的支持。一旦目標板脫離主機,需單獨運行時,在半主機模式下是無法運行,因為io軟中斷請求無法得到處理。因此對于libjpeg移植,我們必須先對所使用到的io庫函數(shù)進行重定向,如把輸入、輸出、錯誤流重定向到串口,把文件操作重定向到對sd卡的文件操作。此處我們在sd卡中采用的是fatfs文件系統(tǒng),關于fatfs的移植,筆者在前面的章節(jié)有詳細的介紹,此處不再詳述。在MDK中,標準io庫函數(shù)最終是通過系統(tǒng)調(diào)用接口來完成實質的io請求,我們必須在這些系統(tǒng)調(diào)用接口上重定向為目標板上特定設備的請求操作。對于linux操作系統(tǒng),標準io庫函數(shù)最終也是通過系統(tǒng)調(diào)用,從用戶態(tài)轉到內(nèi)核態(tài),通過系統(tǒng)api完成實質的io請求操作。在Retarget.c中我們實現(xiàn)所有的標準io庫函數(shù)的重定向,該部分的代碼如下:
#include
#include
#include
#include
#include
#include "ff.h"
#include "diskio.h"
#include "UART0.h"
#pragma import (__use_no_semihosting_swi)
#defineSTDIO 1
/* Standard IO device handles. */
#define STDIN 0x1
#define STDOUT 0x2
#define STDERR 0x3
/* Standard IO device name defines. */
const char __stdin_name[] = "STDIN";
const char __stdout_name[] = "STDOUT";
const char __stderr_name[] = "STDERR";
struct __FILE {int handle; /* Add whatever you need here */ };
#ifdef STDIO
/*-----------------------------------------------------------------------------
Write character to the Serial Port
*----------------------------------------------------------------------------*/
int sendchar(int c) {
if (c == 'n') {
Uart0_SendByte('r');
}
Uart0_SendByte(c);
return (c);
}
/*-----------------------------------------------------------------------------
Read character from the Serial Port
*----------------------------------------------------------------------------*/
int getkey(void) {
int ch = Uart0_ReceiveByte();
if (ch < 0) {
return 0;
}
return ch;
}
#endif
/*---------------------------_ttywrch ---------------------------------------*/
void _ttywrch(int ch) {
#ifdef STDIO
sendchar (ch);
#endif
}
/*---------------------------_sys_open --------------------------------------*/
FILEHANDLE _sys_open (const char *name, int openmode) {
FRESULT Res;
FILEHANDLE fh;
BYTE Mode = FA_READ;
/* Register standard Input Output devices. */
if (strcmp(name, "STDIN") == 0) {
return (STDIN);
}
if (strcmp(name, "STDOUT") == 0) {
return (STDOUT);
}
if (strcmp(name, "STDERR") == 0) {
return (STDERR);
}
if (openmode& OPEN_W) {
Mode|= FA_WRITE | FA_OPEN_ALWAYS;
Mode&= ~FA_READ;
}
if (openmode& OPEN_PLUS) {
Mode|= FA_WRITE | FA_READ;
}
if (openmode & OPEN_A) {
Mode|= FA_OPEN_ALWAYS;
}
fh = (FILEHANDLE)malloc(sizeof(FIL));
if (fh == NULL) {
return -1;
}
Res =f_open((FIL *)fh, name, Mode);
if (Res == RES_OK) {
return fh;
} else {
free((FIL *)fh);
return -1;
}
}
/*---------------------------_sys_close -------------------------------------*/
int _sys_close(FILEHANDLE fh) {
FRESULT Res;
if (fh > 0 && fh < 4) {
return (0);
}
Res = f_close((FIL *)fh);
free((FIL *)fh);
if (Res == RES_OK) {
return 0;
}
return -1;
}
/*---------------------------_sys_write -------------------------------------*/
int _sys_write(FILEHANDLE fh, const uint8_t *buf, uint32_t len, int32_t mode) {
FRESULT Res;
UINT ByteWrite;
#ifdef STDIO
if (fh > 0 && fh < 4) {
if (fh == STDOUT) {
/* Standard Output device. */
for (; len; len--) {
sendchar (*buf++);
}
return (0);
} else {
return (-1);
}
}
#endif
#if!(_FS_READONLY)
Res = f_write((FIL *)fh, buf, len,&ByteWrite);
if (Res == RES_OK) {
if(ByteWrite < len) {
return (len-ByteWrite);
}
return 0;
}
#endif
return -1;
}
/*---------------------------_sys_read --------------------------------------*/
int _sys_read(FILEHANDLE fh, uint8_t *buf, uint32_t len, int32_t mode) {
FRESULT Res;
UINT ByteRead;
#ifdef STDIO
if (fh > 0 && fh < 4) {
if (fh == STDIN) {
/* Standard Input device. */
for (; len; len--) {
*buf++ = getkey ();
}
return (0);
} else {
return (-1);
}
}
#endif
Res = f_read((FIL *)fh, buf, len,&ByteRead);
if (Res == RES_OK) {
if(ByteRead < len) {
return (len-ByteRead);
}
return 0;
}
return -1;
}
/*---------------------------_sys_istty -------------------------------------*/
int _sys_istty(FILEHANDLE fh) {
if (fh > 0 && fh < 4) {
return (1);
}
return (0);
}
/*---------------------------_sys_seek --------------------------------------*/
int _sys_seek(FILEHANDLE fh, long pos) {
FRESULT Res;
if (fh > 0 && fh < 4) {
return (-1);
}
#if_FS_MINIMIZE < 3
Res = f_lseek((FIL *)fh, pos);
if (Res == RES_OK) {
return 0;
}
#endif
return (-1);
}
/*---------------------------_sys_ensure ------------------------------------*/
int _sys_ensure(FILEHANDLE fh) {
FRESULT Res;
if (fh > 0 && fh < 4) {
return (-1);
}
#if!(_FS_READONLY)
Res = f_sync((FIL *)fh);
if (Res == RES_OK) {
return 0;
}
#endif
return -1;
}
/*---------------------------_sys_flen --------------------------------------*/
long _sys_flen(FILEHANDLE fh) {
if (fh > 0 && fh < 4) {
return (0);
}
return f_tell((FIL *)fh);
}
/*---------------------------_sys_tmpnam ------------------------------------*/
int _sys_tmpnam(char *name, int sig, unsigned maxlen) {
return (1);
}
/*----------------