187 lines
5.7 KiB
C
187 lines
5.7 KiB
C
#include "mjpeg.h"
|
||
#include "ff.h"
|
||
#include "lcd_rgb.h"
|
||
#include "mymem.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;
|
||
}
|