S3C6410 裸机硬件JPEG解码
扫描二维码
随时随地手机看文章
2012年12月25日,晚上我找到问题所在了,JPEG解码源图像地址必须是16字节(128位)对齐的,也就是最低4位必须为0,这个害的我好久,还好终于解决了。
修复了已知的bug;
这个是我实验用的原图,用工具把他变成了数组后直接放在程序里面了.
解码后的图片
附上代码
/************************************************************************************************************* * 文件名 : JpegCodec.c * 功能 : S3C6410 JPEG解码底层驱动函数 * 作者 : cp1300@139.com * 创建时间 : 2012年9月20日20:59 * 最后修改时间 : 2012年12月02日 * 详细 : JPEG硬解码 * 通过S3C6410 DATASHEETV1.2版以及官方WINCE的JPEG驱动的分析,得出结论,S3C6410的JPEG解码模块不支持硬件控制自动解码 * 只能使用软件控制解码模式 * 20121202:修复连续解码BUG,目前有少数jpeg420,jpeg444会解码出错,就像windows也有可能有不支持的jpeg图片一样,少数图片硬解码 * 失败可以尝试使用软解码即可。 * 20121225:发现JPEG必须16字节(128位)地址对齐,否则可能会出现解码失败问题。 * 20130113:增加尺寸非8或16倍数的jpeg图片解码功能 * 20130113:将程序外部依赖降低,目前只依赖外部的数据类型定义(高类聚,低耦合),打印调试也依赖外部,不用可以修改宏,JPEG_DBUG=0来取消,方便移植。 *************************************************************************************************************/ #include "JpegCodec.h" #include "jpeg_tables.h" //调试宏开关 #define JPEG_DBUG 0 #if JPEG_DBUG #include "system.h" #define jpeg_debug(format,...) uart_printf(format,##__VA_ARGS__) #else #define jpeg_debug(format,...) / / #endif //JPEG_DBUG //jpeg编解码模式配置 #define COEF1_RGB_2_YUV 0x4d971e #define COEF2_RGB_2_YUV 0x2c5783 #define COEF3_RGB_2_YUV 0x836e13 #define ENABLE_MOTION_ENC (0x1<<3) //使能动态编码 #define DISABLE_MOTION_ENC (0x0<<3) #define ENABLE_HW_DEC (0x1<<2) #define DISABLE_HW_DEC (0x0<<2) #define ENABLE_MOTION_DEC (0x1<<0) //使能动态解码 #define DISABLE_MOTION_DEC (0x0<<0) #define INCREMENTAL_DEC (0x1<<3) //增量解码模式 #define NORMAL_DEC (0x0<<3) //正常解码模式 #define YCBCR_MEMORY (0x1<<5) #define ENABLE_IRQ (0xf<<3) //等待超时定义 #define WaitTimeOut 0xffffff //等待超时计数器 //定义最大图像宽高度 #define MAX_JPG_WIDTH 4096 #define MAX_JPG_HEIGHT 4096 //JPEG寄存器结构定义 typedef struct { u32 Mode; //模式寄存器 u32 Status; //状态寄存器 u32 QTblNo; u32 RSTPos; u32 Vertical; //垂直分辨率 u32 Horizontal; //水平分辨率 u32 DataSize; //压缩数据字节数 u32 IRQ; //中断设置寄存器 u32 IRQStatus; //中断状态寄存器 0x20 u32 Reserved0[247]; u32 QTBL0[64]; //0x400 u32 QTBL1[64]; u32 QTBL2[64]; u32 QTBL3[64]; u32 HDCTBL0[16]; //0x800 u32 HDCTBLG0[12]; u32 Reserved1[4]; u32 HACTBL0[16]; u32 HACTBLG0[162]; //0x8c0 u32 Reserved2[46]; u32 HDCTBL1[16]; //0xc00 u32 HDCTBLG1[12]; u32 Reserved3[4]; u32 HACTBL1[16]; u32 HACTBLG1[162]; //0xcc0 u32 Reserved4[46]; u32 ImageAddr0; //目的图像地址1 u32 ImageAddr1; //目的图像地址2 u32 JpegAddr0; //源JPEG图像地址1 u32 JpegAddr1; //源JPEG图像地址2 u32 Start; //JPEG解码开始 u32 ReStart; //重新开始JPEG解码 u32 SofReset; //JPEG复位 u32 Cntl; //控制寄存器 u32 COEF1; u32 COEF2; u32 COEF3; u32 Misc; //杂项寄存器 u32 FramIntv; }JPEG_TypeDef; //定义JPEG文件标记 enum { UNKNOWN, BASELINE = 0xC0, EXTENDED_SEQ = 0xC1, PROGRESSIVE = 0xC2 }JPG_SOF_MARKER; //S3C6410 jpeg编解码器基址 #define JPEG_BASE 0x78800000 //寄存器结构指针 #define JPEG ((JPEG_TypeDef *)JPEG_BASE) //内部静态函数声明 static void JPEG_Reset(void); //JPEG解码器软件复位 static JPEG_TYPE JPEG_GetJpegType(void); //获取JPEG采样模式 static void JPEG_GetWidthHeight(u16* width, u16* height);//获取图像大小 static JPEG_ERROR JPEG_WaitForIRQ(void); //等待中断,并返回状态 static bool JPEG_CorrectHeader(JPEG_TYPE jpegType, u16 *width, u16 *height); static void JPEG_WriteHeader(u32 JpgAddr, u32 fileSize, u16 width, u16 height); static void JPEG_WriteYUV(u32 ImageAddr, u16 width, u16 orgwidth, u16 height, u16 orgheight); static void JPEG_MemMove(u8* dest, u8* src,u32 count); /************************************************************************************************************************* *函数 : void JPEG_Init(void) *功能 : JPEG解码初始化 *参数 : 无 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 20120923 *说明 : 无 *************************************************************************************************************************/ void JPEG_Init(void) { //rCLK_DIV0 |= 0x03 << 24; //Set_GateClk(SCLK_JPEG,ENABLE); //使能JPEG模块时钟 } /************************************************************************************************************************* *函数 : static void JPEG_Reset(void) *功能 : JPEG解码器软件复位 *参数 : 无 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 2010113 *说明 : 无 *************************************************************************************************************************/ static void JPEG_Reset(void) { JPEG->SofReset = 0; } /************************************************************************************************************************* *函数 : static JPEG_TYPE JPEG_Reset(void) *功能 : 获取JPEG采样模式 *参数 : 无 *返回 : JPEG类型,见定义 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 2010113 *说明 : 编码模式只有0x1,0x2两种模式 *************************************************************************************************************************/ static JPEG_TYPE JPEG_GetJpegType(void) { switch (JPEG->Mode & 0x07) //通过判断0-2BIT { case 0 : return TYPE_JPEG_444; //色度4:4:4格式 case 1 : return TYPE_JPEG_422; //色度4:2:2格式 case 2 : return TYPE_JPEG_420; //色度4:2:0格式 case 3 : return TYPE_JPEG_400; //灰色格式(单一组成) case 6 : return TYPE_JPEG_411; //色度4:1:1格式 default : return TYPE_JPEG_UNKNOWN; } } /************************************************************************************************************************* *函数 : static void JPEG_GetWidthHeight(u16* width, u16* height) *功能 : 获取图像尺寸大小 *参数 : HSize:图像宽度缓冲区指针;VSize:图像高度缓冲区指针 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 2010113 *说明 : 16BIT *************************************************************************************************************************/ static void JPEG_GetWidthHeight(u16* width, u16* height) { *width = JPEG->Horizontal; //在水平方向上定义图像大小的值 *height = JPEG->Vertical; //在垂直方向上定义图像大小的值 } /************************************************************************************************************************* *函数 : u32 JPEG_GetYUVSize(JPEG_TYPE jpegType,u16 width, u16 height) *功能 : 获取解码后数据大小 *参数 : jpegType:jpeg图像类型,width,height:图像尺寸 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 2010113 *最后修改时间 : 2010113 *说明 : 无 *************************************************************************************************************************/ u32 JPEG_GetYUVSize(JPEG_TYPE jpegType,u16 width, u16 height) { switch(jpegType) { case TYPE_JPEG_444 : return(width*height*3); case TYPE_JPEG_422 : return(width*height*2); case TYPE_JPEG_420 : case TYPE_JPEG_411 : return((width*height) + (width*height>>1)); case TYPE_JPEG_400 : return(width*height); default : return(0); } } /************************************************************************************************************************* *函数 : void JPEG_ReadClearStatus(u8* Status, u8* IrqStatus) *功能 : 读取并清除JPEG状态 *参数 : Status:解码器状态缓冲区指针;IrqStatus:中断状态缓冲区指针 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 2010113 *说明 : JPGSTS和JPGIRQ;JPGIRQ读取后自动清除 * JPGIRQ: BIT6结果状态 0:不正常的处理结束; 1:正常的处理完成 * BIT4位流的错误状态。只有在解压缩期间有效。0:在被压缩的文件上,没有语法错误。1:在被压缩的文件上,有语法错误。 * BIT3标题状态。只有在解压缩期间有效。0:图像大小和取样因素值不可读。1:图像大小和取样因素值可读。 *************************************************************************************************************************/ void JPEG_ReadClearStatus(u8* Status, u8* IrqStatus) { *Status = JPEG->Status; *IrqStatus = JPEG->IRQStatus & ((1<<6)|(1<<4)|(1<IRQStatus; //读取中断状态寄存器,并消除状态 TimeOut --; //计数器自减 } while((IRQStatus == 0) && TimeOut); //当发生中断或者计数器为0时退出等待 IRQStatus &= ((1<<6)|(1<<4)|(1<Status; return error; } /************************************************************************************************************************* *函数 : static void JPEG_DecodeHeader(u32 JpegAddr) *功能 : 开始解码JPEG头部信息(软件控制解码) *参数 : JpegAddr: jpeg图像地址 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 2010113 *说明 : 用于软件解码的第一步,用于获取JPEG分辨率以及采样模式信息 *************************************************************************************************************************/ static void JPEG_DecodeHeader(u32 JpegAddr) { JPEG->JpegAddr0 = JpegAddr; JPEG->JpegAddr1 = JpegAddr; //jpeg图片数据地址 JPEG->Mode = 0x8; //设置为解码模式 JPEG->IRQ = ENABLE_IRQ; //使能中断 JPEG->Cntl = DISABLE_HW_DEC; //解码JPEG头部 JPEG->Misc = (NORMAL_DEC | YCBCR_MEMORY); JPEG->Start = 1; //开始JPEG处理 } /************************************************************************************************************************* *函数 : static void JPEG_DecodeBody(u32 ImageAddr) *功能 : 开始JPEG主体解码(软件控制解码) *参数 : ImageAddr: 解码后图像地址 *返回 : 无 *依赖 : 底层宏定义 *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 2010113 *说明 : 软件控制解码的第二步,一定要先调用JPEG_StartParsingHeader *************************************************************************************************************************/ static void JPEG_DecodeBody(u32 ImageAddr) { JPEG->ImageAddr0 = ImageAddr; JPEG->ImageAddr1 = ImageAddr; //解码数据缓冲器地址 JPEG->Cntl = 0; //解码JPEG头部 JPEG->Misc = 0; JPEG->ReStart = 1; //开始主解码处理 } /************************************************************************************************************************* *函数 : JPEG_ERROR JPEG_DecodeOneFrame(u32 JpgAddr, u32 ImageAddr, u32 jpegSize, JPEG_INFO *JpegInfo) *功能 : 开始解码一帧JPEG *参数 : JpegAddr: jpeg图像地址 * ImageAddr: 解码后图像地址 * jpegSize: 图片数据大小 * JpegInfo: 图像信息结构指针 *返回 : JPEG_ERROR *依赖 : JPEG_StartParsingHeader;JPEG_StartDecodingBody *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 2010113 *说明 : 软件控制解码模式 * 修改源图像地址128位对齐bug * 20120113:增加尺寸非8或16倍数的jpeg图片解码功能,需要传递一个参数,即图片大小,通过FileSize传递 * 非对齐的jpeg解码效率将低于对齐的图片,由于解码前需要先改写数据。 *************************************************************************************************************************/ JPEG_ERROR JPEG_DecodeOneFrame(u32 JpgAddr, u32 ImageAddr, u32 jpegSize, JPEG_INFO *JpegInfo) { JPEG_ERROR status; u16 width,height; bool headerFixed = FALSE; #if JPEG_DBUG const char *JpegType[6] = {"JPEG 4:4:4","JPEG 4:2:2","JPEG 4:2:0","JPEG 4:0:0","JPEG 4:1:1","JPEG UNKNOWN"}; #endif if(JpgAddr % 16) //源地址一定要是16字节(128位)对齐的,否则会出现各种意想不到的问题,这个问题困扰了我5个多月。 { jpeg_debug("jpeg addr errorrn"); return JPEG_OTHER_ERROR; } JpegInfo->FileSize = jpegSize; //存储图片大小 jpeg_debug("rn"); jpeg_debug("start jpeg decoding...rn"); JPEG_Reset(); JPEG_DecodeHeader(JpgAddr); //分析JPEG文信息 status = JPEG_WaitForIRQ(); //等待完成 if(status != JPEG_HEADER_OK) //图像分析错误 { return status; } JpegInfo->Type = JPEG_GetJpegType(); //获取图片类型 jpeg_debug("Jpeg Mod:%srn",JpegType[JpegInfo->Type]); if(JpegInfo->Type == TYPE_JPEG_UNKNOWN) //未定义类型 { return JPEG_TYPE_ERROR; } JPEG_GetWidthHeight(&(JpegInfo->Width),&(JpegInfo->Height)); //获取图片分辨率 width = JpegInfo->Width; height = JpegInfo->Height; if(!JPEG_CorrectHeader(JpegInfo->Type, &(JpegInfo->Width), &(JpegInfo->Height))) { JPEG_WriteHeader(JpgAddr,jpegSize,JpegInfo->Width, JpegInfo->Height); headerFixed = TRUE; } jpeg_debug("jpeg image size %d*%drn",JpegInfo->Width,JpegInfo->Height); if(JpegInfo->Width Width > MAX_JPG_WIDTH || JpegInfo->Height Height > MAX_JPG_HEIGHT) { return JPEG_SIZE_ERROR; } if(headerFixed == TRUE) { JPEG_Reset(); JPEG_DecodeHeader(JpgAddr); //分析JPEG文信息 status = JPEG_WaitForIRQ(); //等待完成 if(status != JPEG_HEADER_OK) //图像分析错误 { return status; } JPEG_DecodeBody(ImageAddr); //解码JPEG status = JPEG_WaitForIRQ(); //等待完成 if(status == JPEG_OK) { jpeg_debug("Jpeg decode OK(%d)rn",status); //JPEG_GetStreamLen(&(JpegInfo->DataSize)); //获取解码后图像大小 } else { jpeg_debug("Jpeg decode error(%d)rn",status); return status; } // for post processor, discard pixel if(width % 4 != 0) width = (width/4)*4; if(height % 2 != 0) height = (height/2)*2; JPEG_WriteYUV(ImageAddr,JpegInfo->Width,width,JpegInfo->Height,height); JpegInfo->Width = width; JpegInfo->Height = height; } else { JPEG_DecodeBody(ImageAddr); //解码JPEG status = JPEG_WaitForIRQ(); //等待完成 if(status == JPEG_OK) { jpeg_debug("Jpeg decode OK(%d)rn",status); } else { jpeg_debug("Jpeg decode error(%d)rn",status); return status; } } JpegInfo->DataSize = JPEG_GetYUVSize(JpegInfo->Type,JpegInfo->Width,JpegInfo->Height); return status; //返回错误 } /************************************************************************************************************************* *函数 : JPEG_ERROR JPEG_EncodeOneFrame(u32 JpgAddr, u32 ImageAddr, JPEG_INFO *JpegInfo) *功能 : 压缩一张JPEG *参数 : JpegAddr: jpeg图像地址 * ImageAddr: 解码后图像地址 * JpegInfo: 图像信息结构指针 *返回 : JPEG_ERROR *依赖 : 无 *作者 : cp1300@139.com *时间 : 20130114 *最后修改时间 : 201310114 *说明 : 只支持YCbCr4:2:2,YCbCr4:2:0的输入格式 * 只测试了编码,能成功,但是没有生成jpeg文件进行测试,如果要生成jpeg文件应该还需要添加相应的文件头和尾部。 *************************************************************************************************************************/ JPEG_ERROR JPEG_EncodeOneFrame(u32 JpgAddr, u32 ImageAddr, JPEG_QUALITY_TYPE jpegQuality, JPEG_INFO *JpegInfo) { JPEG_ERROR status = JPEG_OK; u32 i; if(JpegInfo->Width Width > MAX_JPG_WIDTH || JpegInfo->Height Height > MAX_JPG_HEIGHT) { return JPEG_SIZE_ERROR; } JPEG_Reset(); JPEG->Mode = (JpegInfo->Type == TYPE_JPEG_422) ? (0x01 << 0) : (0x02 << 0); //亚抽样模式 JPEG->RSTPos = 2; // MCU inserts RST marker JPEG->QTblNo = (1 << 12) | (1 << 14); JPEG->Horizontal = JpegInfo->Width; JPEG->Vertical = JpegInfo->Height; JPEG->ImageAddr0 = ImageAddr; JPEG->ImageAddr1 = ImageAddr; JPEG->JpegAddr0 = JpgAddr; JPEG->JpegAddr1 = JpgAddr; JPEG->COEF1 = COEF1_RGB_2_YUV; // Coefficient value 1 for RGB to YCbCr JPEG->COEF2 = COEF2_RGB_2_YUV; // Coefficient value 2 for RGB to YCbCr JPEG->COEF3 = COEF3_RGB_2_YUV; // Coefficient value 3 for RGB to YCbCr JPEG->Misc = (1<<5) | (0<Cntl = DISABLE_MOTION_ENC; // Quantiazation and Huffman Table setting for (i=0; iQTBL0[i] = (u32)QTBL_Luminance[jpegQuality][i]; for (i=0; iQTBL1[i] = (u32)QTBL_Chrominance[jpegQuality][i]; for (i=0; iHDCTBL0[i] = (u32)HDCTBL0[i]; for (i=0; iHDCTBLG0[i] = (u32)HDCTBLG0[i]; for (i=0; iHACTBL0[i] = (u32)HACTBL0[i]; for (i=0; iHACTBLG0[i] = (u32)HACTBLG0[i]; JPEG->Start = 0; status = JPEG_WaitForIRQ(); if(status == JPEG_OK) { jpeg_debug("Jpeg encode OK!(%d)rn",status); JpegInfo->FileSize = JPEG->DataSize; } else { JpegInfo->FileSize = 0; jpeg_debug("Jpeg encode error!(%d)rn",status); } return status; } /************************************************************************************************************************* *函数 : static bool JPEG_CorrectHeader(JPEG_TYPE jpegType, u16 *width, u16 *height) *功能 : 检查图像的宽高时候满足要求 *参数 : jpegType: jpeg类型,见JPEG_TYPE * width: 图像宽度 * height: 图像高度 *返回 : TRUE:需要重写宽度,高度 * FALSE:无需重写宽度,高度 *依赖 : 无 *作者 : cp1300@139.com *时间 : 20130113 *最后修改时间 : 20130113 *说明 : 直接由S3C6410官方代码移植而来 * 如果不满足要求,将计算最接近的满足要求的分辨率,JPEG分辨率需要能被8或者16整除,具体可以查阅相关资料 *************************************************************************************************************************/ static bool JPEG_CorrectHeader(JPEG_TYPE jpegType, u16 *width, u16 *height) { bool result = FALSE; switch(jpegType){ case TYPE_JPEG_400 : case TYPE_JPEG_444 : { if((*width % 8 == 0) && (*height % 8 == 0)) result = TRUE; if(*width % 8 != 0) *width += 8 - (*width % 8); if(*height % 8 != 0) *height += 8 - (*height % 8); }break; case TYPE_JPEG_422 : { if((*width % 16 == 0) && (*height % 8 == 0)) result = TRUE; if(*width % 16 != 0) *width += 16 - (*width % 16); if(*height % 8 != 0) *height += 8 - (*height % 8); }break; case TYPE_JPEG_420 : case TYPE_JPEG_411 : { if((*width % 16 == 0) && (*height % 16 == 0)) result = TRUE; if(*width % 16 != 0) *width += 16 - (*width % 16); if(*height % 16 != 0) *height += 16 - (*height % 16); }break; default : break; } return(result); } /************************************************************************************************************************* *函数 : static void JPEG_WriteHeader(u32 JpgAddr, u32 fileSize, u16 width, u16 height) *功能 : 重写jpeg头部信息 *参数 : JpgAddr: jpeg文件的起始指针 * fileSize: jpeg文件大小 * width: jpeg文件宽度,需要重写的宽度 * height: jpeg文件高度,需要重写的宽度 *返回 : 无 *依赖 : 无 *作者 : cp1300@139.com *时间 : 20130113 *最后修改时间 : 20130113 *说明 : 重写的只是内存中的数据 *************************************************************************************************************************/ static void JPEG_WriteHeader(u32 JpgAddr, u32 fileSize, u16 width, u16 height) { u32 i; u8 *ptr = (u8 *)(JpgAddr + fileSize); u8 *ptr2; u8 *SOF1; u8 *header; jpeg_debug("DD::Header is not multiple of MCUrn"); for(i=0; i < fileSize; i++) { ptr--; if(*ptr == 0xFF) { ptr2 = ptr+1; if((*ptr2 == BASELINE) || (*ptr2 == EXTENDED_SEQ) || (*ptr2 == PROGRESSIVE)) { jpeg_debug("jpeg match FFC0(i : %d)rn", i); SOF1 = ptr2+1; break; } } } jpeg_debug("jpeg start header correctionrn"); if(i >8) & 0xFF; *header++; *header = height & 0xFF; *header++; *header = (width>>8) & 0xFF; *header++; *header = width & 0xFF; } } /************************************************************************************************************************* *函数 : static void JPEG_MemMove(u8* dest, u8* src,u32 count) *功能 : 由src所指内存区域复制count个字节到dest所指内存区域 *参数 : src: 源地址 * dest: 目标地址 * count: 数据数量 *返回 : 无 *依赖 : 无 *作者 : cp1300@139.com *时间 : 2013014 *最后修改时间 : 2013114 *说明 : 内存复制,8bit对齐,为了减少外部函数的依赖 *************************************************************************************************************************/ static void JPEG_MemMove(u8* dest, u8* src,u32 count) { u32 i; for(i = 0;i < count;i ++) { dest[i] = src[i]; } } /************************************************************************************************************************* *函数 : static void JPEG_WriteYUV(u32 ImageAddr, u16 width, u16 orgwidth, u16 height, u16 orgheight) *功能 : 重写YUV数据,将数据对齐 *参数 : ImageAddr: 解码后图像地址 * width: 图像对齐后的宽度 * orgwidth: 图像原始宽度 * height: 图像对齐后的高度 * orgheight: 图像原始高度 *返回 : 无 *依赖 : 无 *作者 : cp1300@139.com *时间 : 20120920 *最后修改时间 : 2010113 *说明 : 无 *************************************************************************************************************************/ static void JPEG_WriteYUV(u32 ImageAddr, u16 width, u16 orgwidth, u16 height, u16 orgheight) { u32 src, dst; u32 i; u8 *streamPtr; streamPtr = (u8 *)ImageAddr; src = 2*width; dst = 2*orgwidth; for(i = 1; i < orgheight; i++) { JPEG_MemMove(&streamPtr[dst], &streamPtr[src], 2*orgwidth); src += 2*width; dst += 2*orgwidth; } }
/************************************************************************************************************* * 文件名 : JpegCodec.H * 功能 : S3C6410 JPEG解码底层驱动函数 * 作者 : cp1300@139.com * 创建时间 : 2012年9月20日20:59 * 最后修改时间 : 2012年12月02日 * 详细 : JPEG硬解码 * 通过S3C6410 DATASHEETV1.2版以及官方WINCE的JPEG驱动的分析,得出结论,S3C6410的JPEG解码模块不支持硬件控制自动解码 * 只能使用软件控制解码模式 * 20121202:修复连续解码BUG,目前有少数jpeg420,jpeg444会解码出错,就像windows也有可能有不支持的jpeg图片一样,少数图片硬解码 * 失败可以尝试使用软解码即可。 * 20121225:发现JPEG必须16字节(128位)地址对齐,否则可能会出现解码失败问题。 * 20130113:增加尺寸非8或16倍数的jpeg图片解码功能 * 20130113:将程序外部依赖降低,目前只依赖外部的数据类型定义,打印调试也依赖外部,不用可以修改宏,JPEG_DBUG=0来取消,方便移植。 *************************************************************************************************************/ #ifndef __JPEGCODEC_H__ #define __JPEGCODEC_H__ #include "sys_types.h" //数据类型定义 //JPEG类型定义 typedef enum { TYPE_JPEG_444 = 0, //JPEG 444 TYPE_JPEG_422 = 1, //JPEG 422 TYPE_JPEG_420 = 2, //JPEG 420 TYPE_JPEG_400 = 3, //JPEG 400 (Gray) TYPE_JPEG_411 = 4, //JPEG 411 TYPE_JPEG_UNKNOWN = 5 //未知 } JPEG_TYPE; //JPEG DEC模式 typedef enum { DEC_HEADER = 0, //只解码头部信息 DEC_BODY = 1, //只解码主体 } JPEG_DEC_MODE; //JPEG DEC模式 typedef enum { JPEG_OK = 0, //正常处理完成 JPEG_HEADER_OK = 1, //图像大小和取样因素值可读。 JPEG_BITSTRE_ERROR= 2, //在被压缩的文件上,有语法错误 JPEG_WAIT_TIME_OUT= 3, //等待超时 JPEG_TYPE_ERROR = 4, //不支持的图像类型,图像类型错误 JPEG_SIZE_ERROR = 5, //图像大小错误,图像分辨率为0,或超出范围 JPEG_OTHER_ERROR= 6 //其它未知错误,一般是地址未16字节对齐 } JPEG_ERROR; //JPEG 文件信息 typedef struct { u16 Width; //图像宽度 u16 Height; //图像高度 u32 FileSize; //JPEG图片大小 u32 DataSize; //图像解码后数据大小 JPEG_TYPE Type; //图像类型定义 } JPEG_INFO; //图像压缩质量等级 typedef enum { JPEG_QUALITY_LEVEL_1 = 0, //高质量 JPEG_QUALITY_LEVEL_2 = 1, JPEG_QUALITY_LEVEL_3 = 2, JPEG_QUALITY_LEVEL_4 = 3 //低质量 }JPEG_QUALITY_TYPE; //相关函数声明 void JPEG_Init(void); //JPEG解码初始化 void JPEG_ReadClearStatus(u8* Status, u8* IrqStatus);//读取并清除JPEG状态 u32 JPEG_GetYUVSize(JPEG_TYPE jpegType,u16 width, u16 height); //获取解码后数据大小 JPEG_ERROR JPEG_DecodeOneFrame(u32 JpgAddr, u32 ImageAddr, u32 jpegSize, JPEG_INFO *JpegInfo);//开始解码一帧JPEG JPEG_ERROR JPEG_EncodeOneFrame(u32 JpgAddr, u32 ImageAddr, JPEG_QUALITY_TYPE jpegQuality, JPEG_INFO *JpegInfo); //开始编码一张JPEG #endif // __JPEGCODEC_H__
/************************************************************************************************************* * 文件名: jpeg_tables.h * 功能: S3C6410 jpeg编码表 * 作者: cp1300@139.com * 创建时间: 2013年01月14日 * 最后修改时间:2013年01月14日 * 详细: 直接使用的官方的代码 *************************************************************************************************************/ #ifndef __JPEG_TABLES_H__ #define __JPEG_TABLES_H__ const unsigned char QTBL_Luminance[4][64]= { // level 1 - high quality { 8, 6, 6, 8, 12, 14, 16, 17, 6, 6, 6, 8, 10, 13, 12, 15, 6, 6, 7, 8, 13, 14, 18, 24, 8, 8, 8, 14, 13, 19, 24, 35, 12, 10, 13, 13, 20, 26, 34, 39, 14, 13, 14, 19, 26, 34, 39, 39, 16, 12, 18, 24, 34, 39, 39, 39, 17, 15, 24, 35, 39, 39, 39, 39 }, // level 2 { 12, 8, 8, 12, 17, 21, 24, 23, 8, 9, 9, 11, 15, 19, 18, 23, 8, 9, 10, 12, 19, 20, 27, 36, 12, 11, 12, 21, 20, 28, 36, 53, 17, 15, 19, 20, 30, 39, 51, 59, 21, 19, 20, 28, 39, 51, 59, 59, 24, 18, 27, 36, 51, 59, 59, 59, 23, 23, 36, 53, 59, 59, 59, 59 }, // level 3 { 16, 11, 11, 16, 23, 27, 31, 30, 11, 12, 12, 15, 20, 23, 23, 30, 11, 12, 13, 16, 23, 26, 35, 47, 16, 15, 16, 23, 26, 37, 47, 64, 23, 20, 23, 26, 39, 51, 64, 64, 27, 23, 26, 37, 51, 64, 64, 64, 31, 23, 35, 47, 64, 64, 64, 64, 30, 30, 47, 64, 64, 64, 64, 64 }, // level 4 - low quality { 20, 16, 25, 39, 50, 46, 62, 68, 16, 18, 23, 38, 38, 53, 65, 68, 25, 23, 31, 38, 53, 65, 68, 68, 39, 38, 38, 53, 65, 68, 68, 68, 50, 38, 53, 65, 68, 68, 68, 68, 46, 53, 65, 68, 68, 68, 68, 68, 62, 65, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68 } }; const unsigned char QTBL_Chrominance[4][64]= { // level 1 - high quality { 9, 8, 9, 11, 14, 17, 19, 24, 8, 10, 9, 11, 14, 13, 17, 22, 9, 9, 13, 14, 13, 15, 23, 26, 11, 11, 14, 14, 15, 20, 26, 33, 14, 14, 13, 15, 20, 24, 33, 39, 17, 13, 15, 20, 24, 32, 39, 39, 19, 17, 23, 26, 33, 39, 39, 39, 24, 22, 26, 33, 39, 39, 39, 39 }, // level 2 { 13, 11, 13, 16, 20, 20, 29, 37, 11, 14, 14, 14, 16, 20, 26, 32, 13, 14, 15, 17, 20, 23, 35, 40, 16, 14, 17, 21, 23, 30, 40, 50, 20, 16, 20, 23, 30, 37, 50, 59, 20, 20, 23, 30, 37, 48, 59, 59, 29, 26, 35, 40, 50, 59, 59, 59, 37, 32, 40, 50, 59, 59, 59, 59 }, // level 3 { 17, 15, 17, 21, 20, 26, 38, 48, 15, 19, 18, 17, 20, 26, 35, 43, 17, 18, 20, 22, 26, 30, 46, 53, 21, 17, 22, 28, 30, 39, 53, 64, 20, 20, 26, 30, 39, 48, 64, 64, 26, 26, 30, 39, 48, 63, 64, 64, 38, 35, 46, 53, 64, 64, 64, 64, 48, 43, 53, 64, 64, 64, 64, 64 }, // level 4 - low quality { 21, 25, 32, 38, 54, 68, 68, 68, 25, 28, 24, 38, 54, 68, 68, 68, 32, 24, 32, 43, 66, 68, 68, 68, 38, 38, 43, 53, 68, 68, 68, 68, 54, 54, 66, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68 } }; const unsigned char QTBL0[64]= { #if 1 0x10, 0x0B, 0x0A, 0x10, 0x18, 0x28, 0x33, 0x3D, 0x0C, 0x0C, 0x0E, 0x13, 0x1A, 0x3A, 0x3C, 0x37, 0x0E, 0x0D, 0x10, 0x18, 0x28, 0x39, 0x45, 0x38, 0x0E, 0x11, 0x16, 0x1D, 0x33, 0x57, 0x50, 0x3E, 0x12, 0x16, 0x25, 0x38, 0x44, 0x6D, 0x67, 0x4D, 0x18, 0x23, 0x37, 0x40, 0x51, 0x68, 0x71, 0x5C, 0x31, 0x40, 0x4E, 0x57, 0x67, 0x79, 0x78, 0x65, 0x48, 0x5C, 0x5F, 0x62, 0x70, 0x64, 0x67, 0x63 #else 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 #endif }; //Added Quantization Table const unsigned char std_chrominance_quant_tbl_plus[64]= { 0x11, 0x12, 0x18, 0x2F, 0x63, 0x63, 0x63, 0x63, 0x12, 0x15, 0x1A, 0x42, 0x63, 0x63, 0x63, 0x63, 0x18, 0x1A, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63, 0x2F, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 }; //Quantization Table0 unsigned char std_luminance_quant_tbl[64] = { 1, 1, 2, 1, 1, 2, 2, 2, 2, 3, 2, 2, 3, 3, 6, 4, 3, 3, 3, 3, 7, 5, 8, 4, 6, 8, 8, 10, 9, 8, 7, 11, 8, 10, 14, 13, 11, 10, 10, 12, 10, 8, 8, 11, 16, 12, 12, 13, 15, 15, 15, 15, 9, 11, 16, 17, 15, 14, 17, 13, 14, 14, 14, 1 }; //Quantization Table1 unsigned char std_chrominance_quant_tbl[64] = { 4, 4, 4, 5, 4, 5, 9, 5, 5, 9, 15, 10, 8, 10, 15, 26, 19, 9, 9, 19, 26, 26, 26, 26, 13, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26 }; //Huffman Table unsigned char HDCTBL0[16] = {0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}; unsigned char HDCTBLG0[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb}; unsigned char HACTBL0[16]= {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d}; const unsigned char HACTBLG0[162]= { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa }; //Huffman Table0 unsigned char len_dc_luminance[16] ={ 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; unsigned char val_dc_luminance[12] ={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; unsigned char len_ac_luminance[16] ={ 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; unsigned char val_ac_luminance[162] = { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0