#include "mjpeg.h" #include "mymem.h" #include "ff.h" #include "lcd_rgb.h" ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32F407开发板 //MJPEG视频处理 代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //创建日期:2014/7/20 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights reserved //******************************************************************************* //修改信息 //无 ////////////////////////////////////////////////////////////////////////////////// struct jpeg_decompress_struct *cinfo; struct my_error_mgr *jerr; u8 *jpegbuf; //jpeg数据缓存指针 u32 jbufsize; //jpeg buf大小 u16 imgoffx,imgoffy; //图像在x,y方向的偏移量 //////////////////////////////////////////////////////////////////////////////// //简单快速的内存分配,以提高速度 #define MJPEG_MAX_MALLOC_SIZE 38*1024 //最大可以分配38K字节 u8 *jmembuf; //mjpeg解码的 内存池 u32 jmempos; //内存池指针 //mjpeg申请内存 void* mjpeg_malloc(u32 num) { u32 curpos=jmempos; //此次分配的起始地址 jmempos+=num; //下一次分配的起始地址 if(jmempos>MJPEG_MAX_MALLOC_SIZE) { printf("mem error:%d,%d",curpos,num); } return (void *)&jmembuf[curpos]; //返回申请到的内存首地址 } //////////////////////////////////////////////////////////////////////////////// //错误退出 static void my_error_exit(j_common_ptr cinfo) { my_error_ptr myerr=(my_error_ptr) cinfo->err; (*cinfo->err->output_message) (cinfo); longjmp(myerr->setjmp_buffer, 1); } METHODDEF(void) my_emit_message(j_common_ptr cinfo, int msg_level) { my_error_ptr myerr=(my_error_ptr) cinfo->err; if(msg_level<0) { printf("emit msg:%d\r\n",msg_level); longjmp(myerr->setjmp_buffer, 1); } } //初始化资源,不执行任何操作 static void init_source(j_decompress_ptr cinfo) { //不需要做任何事情. return; } //填充输入缓冲区,一次性读取整帧数据 static boolean fill_input_buffer(j_decompress_ptr cinfo) { if(jbufsize==0)//结束了 { //printf("jd read off\r\n"); //填充结束符 jpegbuf[0] = (u8) 0xFF; jpegbuf[1] = (u8) JPEG_EOI; cinfo->src->next_input_byte =jpegbuf; cinfo->src->bytes_in_buffer = 2; }else { cinfo->src->next_input_byte =jpegbuf; cinfo->src->bytes_in_buffer = jbufsize; jbufsize-=jbufsize; } return TRUE; } //在文件里面,跳过num_bytes个数据 static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { /* Just a dumb implementation for now. Could use fseek() except * it doesn't work on pipes. Not clear that being smart is worth * any trouble anyway --- large skips are infrequent. */ if (num_bytes > 0) { while(num_bytes>(long) cinfo->src->bytes_in_buffer) { num_bytes-=(long)cinfo->src->bytes_in_buffer; (void)cinfo->src->fill_input_buffer(cinfo); /* note we assume that fill_input_buffer will never * return FALSE, so suspension need not be handled. */ } cinfo->src->next_input_byte += (size_t) num_bytes; cinfo->src->bytes_in_buffer -= (size_t) num_bytes; } } //在解码结束后,被jpeg_finish_decompress函数调用 static void term_source(j_decompress_ptr cinfo) { //不做任何处理 return; } //初始化jpeg解码数据源 static void jpeg_filerw_src_init(j_decompress_ptr cinfo) { if (cinfo->src == NULL) /* first time for this JPEG object? */ { cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr)); } cinfo->src->init_source = init_source; cinfo->src->fill_input_buffer = fill_input_buffer; cinfo->src->skip_input_data = skip_input_data; cinfo->src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ cinfo->src->term_source = term_source; cinfo->src->bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ cinfo->src->next_input_byte = NULL; /* until buffer loaded */ } //mjpeg 解码初始化 //offx,offy:x,y方向的偏移 //返回值:0,成功; // 1,失败 u8 mjpegdec_init(u16 offx,u16 offy) { cinfo=mymalloc(sizeof(struct jpeg_decompress_struct)); jerr=mymalloc(sizeof(struct my_error_mgr)); //分配sram区的内存以提高解码速度--2020.6.2 jmembuf=mymalloc_fast(MJPEG_MAX_MALLOC_SIZE);//MJPEG解码内存池申请 if(cinfo==0||jerr==0||jmembuf==0) { mjpegdec_free(); return 1; } //保存图像在x,y方向的偏移量 imgoffx=offx; imgoffy=offy; return 0; } //mjpeg结束,释放内存 void mjpegdec_free(void) { myfree(cinfo); myfree(jerr); myfree(jmembuf); } //解码一副JPEG图片 //buf:jpeg数据流数组 //bsize:数组大小 //返回值:0,成功 // 其他,错误 u8 mjpegdec_decode(u8* buf,u32 bsize) { JSAMPARRAY buffer; if(bsize==0)return 1; jpegbuf=buf; jbufsize=bsize; jmempos=0;//MJEPG解码,重新从0开始分配内存 cinfo->err=jpeg_std_error(&jerr->pub); jerr->pub.error_exit = my_error_exit; jerr->pub.emit_message = my_emit_message; //if(bsize>20*1024)printf("s:%d\r\n",bsize); if (setjmp(jerr->setjmp_buffer)) //错误处理 { jpeg_abort_decompress(cinfo); jpeg_destroy_decompress(cinfo); return 2; } jpeg_create_decompress(cinfo); jpeg_filerw_src_init(cinfo); jpeg_read_header(cinfo, TRUE); cinfo->dct_method = JDCT_IFAST; cinfo->do_fancy_upsampling = 0; jpeg_start_decompress(cinfo); extern void jdmerge_setlcdaddr (unsigned short *addr); unsigned short *lcd_addr=(unsigned short *)LCD_GetDrawAddr(); // lcd_addr+=LCD_GetLcdSizeX()*LCD_GetLcdSizeY()-1-(imgoffx+imgoffy*LCD_GetLcdSizeX()); jdmerge_setlcdaddr(lcd_addr);//设置显示位置 while (cinfo->output_scanline < cinfo->output_height) { jpeg_read_scanlines(cinfo, buffer, 1); } jpeg_finish_decompress(cinfo); jpeg_destroy_decompress(cinfo); return 0; }