Files
player/Project/Src/MJPEG/mjpeg.c

224 lines
6.2 KiB
C
Raw Permalink Normal View History

2025-06-27 00:32:57 +08:00
#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;
}