Files
player/Project/Src/MJPEG/mjpeg.c
2025-06-27 00:32:57 +08:00

224 lines
6.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}