USB摄像头出现“Huffman table 0x00 was not defined”解决办法

时间:2020-12-21 21:16:50

        在韦东山linux第三期视频中,有一节介绍USB摄像头在LCD上显示。我照着视频的讲解,边写程序。usb摄像头是家里一个N年前的摄像头,牌子不明,从程序返回的值中,可以看出是一个MJPEG输出的摄像头。

程序在mjpeg2rgb时,出现“Huffman table 0x00 was not defined”错误,jpeg解码用的是libjpeg库。

       从错误提示可以看出:摄像头数据的每一帧中没有定义huffman表,所以用常规的jpg解码出错。

      一种解决方法是在数据中嵌入标准huffman table,然后在用jpg解码。代码参考https://github.com/joeshang/joycar/blob/master/module/v4l2_camera/decoder_mjpeg.c,修改后果然能正常解码了。

我的源代码如下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include <jpeglib.h>



#include "convert_manager.h"
#include "huffman.h"


typedef struct MyErrorMgr
{
	struct jpeg_error_mgr pub;
	jmp_buf setjmp_buffer;
}T_MyErrorMgr, *PT_MyErrorMgr;


static int isSupportMjpeg2Rgb(int iPixelFormatIn, int iPixelFormatOut);
static int Mjpeg2RgbConvert(PT_VideoBuf ptVideoBufIn, PT_VideoBuf ptVideoBufOut);
static int Mjpeg2RgbConvertExit(PT_VideoBuf ptVideoBufOut);

extern void jpeg_mem_src_tj (j_decompress_ptr cinfo,
	      unsigned char * inbuffer, unsigned long insize);


static T_VideoConvert g_tMjpeg2RgbVideoConvert={
	.name           = "mjpeg2rgb",
	.isSupport	    = isSupportMjpeg2Rgb,
	.Convert        = Mjpeg2RgbConvert,
	.ConvertExit    = Mjpeg2RgbConvertExit,
};


static void MyErrorExit(j_common_ptr ptCInfo)
{
    static char errStr[JMSG_LENGTH_MAX];
    
	PT_MyErrorMgr ptMyErr = (PT_MyErrorMgr)ptCInfo->err;

    /* Create the message */
    (*ptCInfo->err->format_message) (ptCInfo, errStr);
    DBG_PRINTF("%s\n", errStr);
	printf("[JPG]:9\n");

	longjmp(ptMyErr->setjmp_buffer, 1);

}


static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
	unsigned int dwRed;
	unsigned int dwGreen;
	unsigned int dwBlue;
	unsigned int dwColor;

	unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
	unsigned int   *pwDstDatas32bpp = (unsigned int *)pudDstDatas;

	int i;
	int pos = 0;

	if (iSrcBpp != 24)
	{
		return -1;
	}

	if (iDstBpp == 24)
	{
		memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
	}
	else
	{
		for (i = 0; i < iWidth; i++)
		{
			dwRed	= pudSrcDatas[pos++];
			dwGreen = pudSrcDatas[pos++];
			dwBlue	= pudSrcDatas[pos++];
			if (iDstBpp == 32)
			{
				dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
				*pwDstDatas32bpp = dwColor;
				pwDstDatas32bpp++;
			}
			else if (iDstBpp == 16)
			{
				/* 565 */
				dwRed	= dwRed >> 3;
				dwGreen = dwGreen >> 2;
				dwBlue	= dwBlue >> 3;
				dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
				*pwDstDatas16bpp = dwColor;
				pwDstDatas16bpp++;
			}
		}
	}
	return 0;

}




static int isSupportMjpeg2Rgb(int iPixelFormatIn, int iPixelFormatOut)
{
	if(iPixelFormatIn != V4L2_PIX_FMT_MJPEG)
		return 0;
	if((iPixelFormatOut !=V4L2_PIX_FMT_RGB565)&&\
		(iPixelFormatOut !=V4L2_PIX_FMT_RGB32))
	{
		return 0;
	}

	return 1;
}


static int is_huffman(unsigned char *buf)
{
    int i = 0;
    unsigned char *pbuf = buf;

    while (((pbuf[0] << 8) | pbuf[1]) != 0xffda)
    {
        if (i++ > 2048)
        {
            return 0;
        }
        
        if (((pbuf[0] << 8) | pbuf[1]) == 0xffc4)
        {
            return 1;
        }

        pbuf++;
    }

    return 0;
}

static int decoder_jpeg_decompress(unsigned char *BufIn,int BufSize, PT_VideoBuf ptVideoBufOut)
{
	struct jpeg_decompress_struct tDInfo;
	T_MyErrorMgr tJerr;
	int iRet,i;
	int iRowStride;
    unsigned char *aucLineBuffer = NULL;
	unsigned char *pucDest;

	 PT_PixelDatas ptPixelDatas = &ptVideoBufOut->tPixelDatas;


    tDInfo.err               = jpeg_std_error(&tJerr.pub);
	tJerr.pub.error_exit     = MyErrorExit;
	if(setjmp(tJerr.setjmp_buffer))
	{
		/* 如果程序能运行到这里, 表示JPEG解码出错 */
		
        jpeg_destroy_decompress(&tDInfo);
        if (aucLineBuffer)
        {
            free(aucLineBuffer);
        }
        if (ptPixelDatas->aucPixelDatas)
        {
            free(ptPixelDatas->aucPixelDatas);
        }
		return -1;
	}

	//2.初始化JPEG对象
	jpeg_create_decompress(&tDInfo);
	
	//3.指定目标图像文件
   // jpeg_stdio_src(&tDInfo,ptFileMap->tFp);
	jpeg_mem_src_tj (&tDInfo,BufIn,BufSize);
	

	
     //读取图像信息
    iRet = jpeg_read_header(&tDInfo, TRUE);


	// 设置解压参数,比如放大、缩小
    tDInfo.scale_num = tDInfo.scale_denom = 1;
	//开始解压缩图像

	jpeg_start_decompress(&tDInfo);

	// 一行的数据长度
	iRowStride = tDInfo.output_width * tDInfo.output_components;
	aucLineBuffer = malloc(iRowStride);

    if (NULL == aucLineBuffer)
    {
        return -1;
    }

	ptPixelDatas->iWidth        = tDInfo.output_width;
	ptPixelDatas->iHeight       = tDInfo.output_height;
	//ptPixelDatas->iBpp        = iBpp;
	ptPixelDatas->iLineBytes    = ptPixelDatas->iWidth * ptPixelDatas->iBpp / 8;
	ptPixelDatas->iTotalBytes   = ptPixelDatas->iLineBytes *ptPixelDatas->iHeight;
	ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes);

	pucDest = ptPixelDatas->aucPixelDatas;
	if (NULL == ptPixelDatas->aucPixelDatas)
	{
	return -1;
	}
//	printf("[JPG]:8\n");

	while (tDInfo.output_scanline < tDInfo.output_height)
	{	 
		(void)jpeg_read_scanlines(&tDInfo, &aucLineBuffer, 1);
		
		// 转到ptPixelDatas去
		CovertOneLine(ptPixelDatas->iWidth, 24, ptPixelDatas->iBpp, aucLineBuffer, pucDest);
		pucDest += ptPixelDatas->iLineBytes;
	}



	//释放资源
	free(aucLineBuffer);
	jpeg_finish_decompress(&tDInfo);
	jpeg_destroy_decompress(&tDInfo);

	return 0;
}

#if 1
static int Mjpeg2RgbConvert(PT_VideoBuf ptVideoBufIn, PT_VideoBuf ptVideoBufOut)
{
    int pos = 0;
    int size_start = 0;
	unsigned char *in_buf = ptVideoBufIn->tPixelDatas.aucPixelDatas;
	int buf_size = ptVideoBufIn->tPixelDatas.iTotalBytes;
    unsigned char *pdeb = ptVideoBufIn->tPixelDatas.aucPixelDatas;
    unsigned char *pcur = ptVideoBufIn->tPixelDatas.aucPixelDatas;
    unsigned char *plimit = ptVideoBufIn->tPixelDatas.aucPixelDatas \
		                    + ptVideoBufIn->tPixelDatas.iTotalBytes;
    unsigned char *jpeg_buf;

    if (is_huffman(ptVideoBufIn->tPixelDatas.aucPixelDatas))
    {

       // printf("huffman\n");

        decoder_jpeg_decompress(in_buf,buf_size,ptVideoBufOut);
    }
    else
    {

      //  printf("no huffman\n");


        /* find the SOF0(Start Of Frame 0) of JPEG */
        while ( (((pcur[0] << 8) | pcur[1]) != 0xffc0) && (pcur < plimit) )
        {
            pcur++;
        }

        /* SOF0 of JPEG exist */
        if (pcur < plimit)
        {

           // printf("SOF0 existed at position\n");

            jpeg_buf = malloc(ptVideoBufIn->tPixelDatas.iTotalBytes +\
				              sizeof(dht_data) + 10);

            if (jpeg_buf != NULL)
            {
                /* insert huffman table after SOF0 */
                size_start = pcur - pdeb;
                memcpy(jpeg_buf, in_buf, size_start);
                pos += size_start;

                memcpy(jpeg_buf + pos, dht_data, sizeof(dht_data));
                pos += sizeof(dht_data);

                memcpy(jpeg_buf + pos, pcur, buf_size - size_start);
                pos += buf_size - size_start;

                decoder_jpeg_decompress(jpeg_buf, pos, ptVideoBufOut);

                free(jpeg_buf);
                jpeg_buf = NULL;
            }
        }
    }

}

#endif

static int Mjpeg2RgbConvertExit(PT_VideoBuf ptVideoBufOut)
{
	if(ptVideoBufOut->tPixelDatas.aucPixelDatas)
	{
		free(ptVideoBufOut->tPixelDatas.aucPixelDatas);
		ptVideoBufOut->tPixelDatas.aucPixelDatas = NULL;
	}
	return 0;
}



/* 注册这个结构体 */
int Mjpeg2RgbInit(void)
{
    return RegisterVideoConvrtOpr(&g_tMjpeg2RgbVideoConvert);
}

"huffman.h"

const static unsigned char dht_data[] = {
    0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
    0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03,
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
    0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05,
    0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
    0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22,
    0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15,
    0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17,
    0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36,
    0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
    0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
    0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
    0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95,
    0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
    0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
    0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5,
    0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
    0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
    0xfa, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05,
    0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
    0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
    0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33,
    0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
    0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
    0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
    0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
    0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
    0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
    0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
    0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
    0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
    0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
};