cancel
Showing results for 
Search instead for 
Did you mean: 

How to use LibJPEG on STM32?

Charlie CHEN
Associate II

Hi all,

I build a project with STM32CubeMX and using LibJPEG to decode the JPEG file from SDCard.

And now I face a problem ,when it goes to the step 5 - start to decompress, it will stock in that function with no reason and the hardfault descripe like down below.

0690X00000AqkGJQAZ.png

Step 5 : Start decompressor

0690X00000AqkFzQAJ.png

Is there anyone have that experience about LibJPEG?

Hope someone can help!

Thank you!

4 REPLIES 4

So you're going to need a more effective Hard Fault handler that can identify the faulting instructions/registers.

Likely you are overflowing an input or output buffer, or a malloc() is failing. If the code needs to allocate memory dynamically, make sure you actual have some heap space for it to use.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Charlie CHEN
Associate II

Hi @Community member​ ,

Thanks for your reply.

Do you mean the Hard Fault is not clear to know where it wrong,so I should to build a Hard Fault function to recognized it?

The Heap size has been increase,but the same problem.

I mean have the routine provide some actionable data rather than spin in a while(1) loop with nothing identifying the fault. The debug view you have screen shot really doesn't clearly identify the failure point and the registers.

This needs some output via a USART or SWV, but illustrates what the hard fault routines should be doing for any real field analysis or debugging to occur.

https://community.st.com/s/question/0D50X0000Az372YSQQ/stm32l412-hardfault-while-using-minimal-cubeide-example

Determine where the code actually faults, and look at the disassembly of the code there, and immediately preceding. Likely acting on a memory pointer, or call-back, which are invalid.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
MKing
Associate III

Hi,

i guess i had the same problem. Reason was that the picture I wanted to compress was too big for the buffers of libjpeg.

So I do not use a while loop and changed it to a switch. That means I repead the same case as long as I get new data in the buffer. Then I extract the data and clear the buffer.

 

Header:

 

/*
 * LIBJPEG_RGBtoJPG.h
 *
 *  Created on: 05.01.2024
 *      Author: MK
 */
#ifndef __LIBJPEG_RGBtoJPG_H
#define __LIBJPEG_RGBtoJPG_H

#ifdef __cplusplus
extern "C" {
#endif

//-----------------------------------------------------------------------------------------------------------------------------
#include "main.h"

//#define RGB_HEIGHT 480
//#define RGB_WIDTH 640

#define RGB_HEIGHT 800
#define RGB_WIDTH 1280

//-----------------------------------------------------------------------------------------------------------------------------
typedef enum
{
 ERR_JPEG_OK = 0,
 ERR_JPEG_BUSY = -1,
 ERR_JPEG_FINISH_COMPRESSLINE = -2,
 ERR_JPEG_NOT_ALLOWED_VALUE = -3,
}eRetValJPEG;
typedef struct
{

uint32_t JpegNewData;
uint8_t *ptrStartJpeg;
uint8_t *ptrEndJpeg;
uint8_t JpegCompressVal;
uint8_t *pJpegSrc;
uint8_t *pJpegDst;
uint8_t *pJpegImageData;
uint32_t JpegImageData_size;
}_sJPEG;
extern _sJPEG sJPEG;

//-----------------------------------------------------------------------------------------------------------------------------
extern eRetValJPEG JPEG_CompressStart(JDIMENSION image_width, JDIMENSION image_height, uint8_t input_components, J_COLOR_SPACE in_color_space, uint8_t quality, uint8_t **dest_buffer, uint32_t *newdatacnt);
extern void JPEG_CompressClearBuffer(void);
extern eRetValJPEG JPEG_CompressLine(uint8_t *src_linebuffer, uint8_t **dest_buffer, uint32_t *newdatacnt);
extern void JPEG_CompressFinish(uint8_t **dest_buffer, uint32_t *newdatacnt);
extern void JPEG_CompressDestroy(void);

//-----------------------------------------------------------------------------------------------------------------------------
#ifdef __cplusplus
}
#endif

#endif

 

 

C-Code:

 

/*
 * LIBJPEG_RGBtoJPG.c
 *
 *  Created on: 05.01.2024
 *      Author: MK
 */
#include "jpeglib.h"
#include "LIBJPEG_RGBtoJPG.h"

//-----------------------------------------------------------------------------------------------------------------------------
#ifdef JPEGTEST

//-----------------------------------------------------------------------------------------------------------------------------
uint8_t const  oneline[1280];

//-----------------------------------------------------------------------------------------------------------------------------
_sJPEG sJPEG;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
struct jpeg_compress_struct const prs_cinfo;
uint8_t StartImageTransfer, Flag_StartImageTransfer;

//-----------------------------------------------------------------------------------------------------------------------------
/**
 * @brief prepare everything to start a compression. creates the first jepeg data
 *
 * @retval ERR_JPEG_OK when no ongoing comression is active
 */
eRetValJPEG JPEG_CompressStart(JDIMENSION image_width, JDIMENSION image_height, uint8_t input_components, J_COLOR_SPACE in_color_space, uint8_t quality, uint8_t **dest_buffer, uint32_t *newdatacnt)
{
	if ( (cinfo.image_height) || (cinfo.image_width) )
		return ERR_JPEG_BUSY;
	if (!image_width)
		return ERR_JPEG_NOT_ALLOWED_VALUE;
	if (!image_height)
		return ERR_JPEG_NOT_ALLOWED_VALUE;
	if (input_components != 3)
		return ERR_JPEG_NOT_ALLOWED_VALUE;
	if (in_color_space != JCS_RGB)
		return ERR_JPEG_NOT_ALLOWED_VALUE;
	if (!quality || quality > 100)
		return ERR_JPEG_NOT_ALLOWED_VALUE;
	if (!dest_buffer)
		return ERR_JPEG_NOT_ALLOWED_VALUE;
	if (!newdatacnt)
		return ERR_JPEG_NOT_ALLOWED_VALUE;

//init all global
	cinfo = prs_cinfo;
	sJPEG.JpegImageData_size = 0;
	sJPEG.pJpegImageData = NULL;

//prepare all
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);

	jpeg_mem_dest(&cinfo, &sJPEG.pJpegImageData, &sJPEG.JpegImageData_size);

	cinfo.image_width = image_width;
	cinfo.image_height = image_height;
	cinfo.input_components = input_components;
	cinfo.in_color_space = in_color_space;

	jpeg_set_defaults( &cinfo );

	jpeg_set_quality(&cinfo, quality, 1 );

	//memset(cinfo.dest->next_output_byte,0,cinfo.dest->free_in_buffer);//not neccessary

	*dest_buffer = cinfo.dest->next_output_byte;

//start compress
	*newdatacnt = cinfo.dest->free_in_buffer;
	jpeg_start_compress(&cinfo, 1);
	*newdatacnt -= cinfo.dest->free_in_buffer;

	return ERR_JPEG_OK;
}

//-----------------------------------------------------------------------------------------------------------------------------
/**
 * @brief need to be done after compressed data is created and handled. Avoid buffer overrun when compressing large images
 *
 * @retval none
 */
void JPEG_CompressClearBuffer(void)
{
	 jpeg_mem_dest(&cinfo, &sJPEG.pJpegImageData, &sJPEG.JpegImageData_size);
}

//-----------------------------------------------------------------------------------------------------------------------------
/**
 * @brief compress one line of the image
 *
 * @retval
 * ERR_JPEG_FINISH_COMPRESSLINE: when last line was compressed
 * ERR_JPEG_OK': when line was compressed
 */
eRetValJPEG JPEG_CompressLine(uint8_t *src_linebuffer, uint8_t **dest_buffer, uint32_t *newdatacnt)
{
	unsigned char* row_pointer[1];

	*dest_buffer = cinfo.dest->next_output_byte;
	*newdatacnt  = cinfo.dest->free_in_buffer;

	  if (cinfo.next_scanline < cinfo.image_height) {
	    row_pointer[0] = src_linebuffer;
	    (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
	  }
	  else
	  {
		  newdatacnt = 0;
		  return ERR_JPEG_FINISH_COMPRESSLINE;
	  }

	  *newdatacnt -= cinfo.dest->free_in_buffer;

	return ERR_JPEG_OK;
}

//-----------------------------------------------------------------------------------------------------------------------------
/**
 * @brief function will finish the compression and prepare the last bytes of the jpeg data
 *
 * @retval none
 */
void JPEG_CompressFinish(uint8_t **dest_buffer, uint32_t *newdatacnt)
{
	*dest_buffer = cinfo.dest->next_output_byte;

	*newdatacnt = cinfo.dest->free_in_buffer;
    jpeg_finish_compress( &cinfo );
	*newdatacnt -= cinfo.dest->free_in_buffer;

}

//-----------------------------------------------------------------------------------------------------------------------------
/**
 * @brief has to be called after last data of JPEG_CompressFinish was handled
 *
 * @retval none
 */
void JPEG_CompressDestroy(void)
{
	jpeg_destroy_compress( &cinfo );

	//init all global for next compression
	cinfo = prs_cinfo;
	sJPEG.JpegImageData_size = 0;
	sJPEG.pJpegImageData = NULL;
}





//-----------------------------------------------------------------------------------------------------------------------------
/**
 * @brief function for sending the image. function call in main loop.
 *
 * @retval none
 */
void JPEG_StartImageTransfer(void)
{
		switch (StartImageTransfer)
		{
		 case 2:
			  sJPEG.pJpegsrc=(uint8_t *)&oneline[0];//one image line 1280px width
		      if (Init_ImageTransfer())//function to send image / ethernet
		      {
		    	  StartImageTransfer = 0;
		      }
		      else
		    	  StartImageTransfer++;
			  break;

		 case 3:
			  JPEG_CompressStart(RGB_WIDTH, RGB_HEIGHT, 3, JCS_RGB, sJPEG.JpegCompressVal, &sJPEG.pJpegDst, &sJPEG.JpegNewData);
			  Flag_StartImageTransfer = ++StartImageTransfer;
			  StartImageTransfer = 10;//send data
			  break;

		 case 4:
			  if (JPEG_CompressLine(&sJPEG.pJpegSrc[0],&sJPEG.pJpegDst,&sJPEG.JpegNewData) == ERR_JPEG_FINISH_COMPRESSLINE)
				StartImageTransfer++;
			  else  if (sJPEG.JpegNewData)
			  {
			   Flag_StartImageTransfer = StartImageTransfer;
			   StartImageTransfer = 10;//send data
			  }
			  break;

		 case 5:
			  JPEG_CompressFinish(&sJPEG.pJpegDst,&sJPEG.JpegNewData);
			  Flag_StartImageTransfer = ++StartImageTransfer;
			   StartImageTransfer = 10;//send data
			  break;

		 case 6:
			  JPEG_CompressDestroy();
			  StartImageTransfer = 20;//all done
			  break;


		 case 10://send data
			if (Cont_ImageTransfer())//function to send image / ethernet
				break;
			JPEG_CompressClearBuffer();
			StartImageTransfer = Flag_StartImageTransfer;
			break;

		 case 20://all done
			SendImageStatus = 0;
			StartImageTransfer = 0;
			break;
		}//sw
}


#endif//JPEGTEST

 

 

Function call in main loop:

 

JPEG_StartImageTransfer();