huffmancode to decode in real-time for motion-jpeg
Dependents: BaseJpegDecode_example SimpleJpegDecode_example Dumb_box_rev2
example code:
Import programBaseJpegDecode_example
BaseJpegDeocde exampe program
Import programSimpleJpegDecode_example
convert JPEG stream data to bitmap, BaseJpegDecode example program
Revision 1:bfbc18000cca, committed 2012-10-25
- Comitter:
- va009039
- Date:
- Thu Oct 25 11:00:05 2012 +0000
- Parent:
- 0:417b7ae90eff
- Child:
- 2:5b1dd4e34857
- Commit message:
- support DQT
Changed in this revision
--- a/BaseJpefDecode.cpp Mon Oct 22 13:55:09 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -#include "mbed.h" -#include "BaseJpegDecode.h" - -#if 0 -#define DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0); -#define DBG_WAIT(A) wait_ms(A) -#else -#define DBG(...) -#define DBG_WAIT(A) -#endif - -#if 1 -#define DBG_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; -#else -#define DBG_ASSERT(A) -#endif - -#define MARK_SOF 0xc0 -#define MARK_DHT 0xc4 -#define MARK_RST0 0xd0 -#define MARK_RST7 0xd7 -#define MARK_SOI 0xd8 -#define MARK_EOI 0xd9 -#define MARK_SOS 0xda -#define MARK_DQT 0xdb -#define MARK_DRI 0xdd -#define MARK_APP 0xe0 - -#define SEQ_INIT 0 -#define SEQ_MARK 1 -#define SEQ_LEN 2 -#define SEQ_LEN2 3 -#define SEQ_SKIP 4 -#define SEQ_SOS 5 -#define SEQ_SOS2 6 - -#define HT_DC 0 -#define HT_AC 1 - -BaseJpegDecode::BaseJpegDecode() -{ - m_yblocks = JPEG_MCU_YBLOCKS; // 2 or 4 - clear(); - pHD = new HuffmanDecode; -} - -void BaseJpegDecode::clear() -{ - m_seq = SEQ_INIT; -} - -void BaseJpegDecode::input(uint8_t* buf, int len) -{ - for(int i = 0; i < len; i++) { - input(buf[i]); - } -} - -void BaseJpegDecode::restart() -{ - m_block = 0; - m_scan = 0; - m_old_DC_value[0] = 0; - m_old_DC_value[1] = 0; - m_bitpat.clear(); - m_huff = NULL; -} - -void BaseJpegDecode::input(uint8_t c) -{ - switch(m_seq) { - case SEQ_INIT: - if (c == 0xff) { - m_seq = SEQ_MARK; - } - break; - case SEQ_MARK: - outputMARK(c); - if (c == MARK_SOI || c == MARK_EOI) { - m_seq = SEQ_INIT; - break; - } - m_mark = c; - m_seq = SEQ_LEN; - break; - case SEQ_LEN: - m_skip = c; - m_seq = SEQ_LEN2; - break; - case SEQ_LEN2: - m_skip <<= 8; - m_skip |= c; - m_skip -= 2; - m_seq = SEQ_SKIP; - break; - case SEQ_SKIP: - if (--m_skip > 0) { - break; - } - if (m_mark == MARK_SOS) { - m_seq = SEQ_SOS; - m_mcu = 0; - restart(); - break; - } - m_seq = SEQ_INIT; - break; - case SEQ_SOS: - if (c == 0xff) { - m_seq = SEQ_SOS2; - break; - } - inputScan(c); - break; - case SEQ_SOS2: - if (c == 0x00) { - inputScan(0xff); - m_seq = SEQ_SOS; - break; - } else if (c >= MARK_RST0 && c <= MARK_RST7) { - restart(); - m_seq = SEQ_SOS; - break; - } - outputMARK(c); - m_seq = SEQ_INIT; - break; - default: - break; - } -} - -void BaseJpegDecode::inputScan(uint8_t c) -{ - m_bitpat += c; - while(m_bitpat.size() > 0) { - int tc = (m_scan == 0) ? HT_DC : HT_AC; - int th = (m_block < m_yblocks) ? 0 : 1; - DBG("%d %d %08x %d\n", tc, th, m_bitpat.peek(32), m_bitpat.size()); - if (m_huff == NULL) { - m_huff = pHD->Lookup(tc, th, &m_bitpat); - if (m_huff == NULL) { - break; - } - m_bitpat.get(m_huff->code_size); // skip code - } - if (m_huff->value_size > m_bitpat.size()) { - break; - } - DBG("%d %d %d %02x\n", m_huff->run, m_huff->value_size, m_huff->code_size, m_huff->code); - int value = pHD->getValue(m_huff, &m_bitpat); - if (tc == HT_DC) { - value += m_old_DC_value[th]; - outputDC(m_mcu, m_block, value); - m_old_DC_value[th] = value; - m_scan++; - } else { // AC - if (m_huff->value_size == 0 && m_huff->run == 0) { // EOB - DBG("AC EOB\n"); - m_scan = 64; - } else { - for(int i = 0; i < m_huff->run; i++) { - outputAC(m_mcu, m_block, m_scan, 0); - m_scan++; - } - outputAC(m_mcu, m_block, m_scan, value); - m_scan++; - } - if (m_scan >= 64) { - m_scan = 0; - if (++m_block >= (m_yblocks+2)) { - m_block = 0; - m_mcu++; - } - } - } - m_huff = NULL; - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BaseJpegDecode.cpp Thu Oct 25 11:00:05 2012 +0000 @@ -0,0 +1,234 @@ +#include "mbed.h" +#include "BaseJpegDecode.h" + +#if 0 +#define DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0); +#define DBG_WAIT(A) wait_ms(A) +#else +#define DBG(...) +#define DBG_WAIT(A) +#endif + +#if 1 +#define DBG_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; +#else +#define DBG_ASSERT(A) +#endif + +#ifdef JPEG_USE_REPORT_CODE +#define REPORT_CODE(A) (A) +#else +#define REPORT_CODE(A) +#endif + +#define MARK_SOF0 0xc0 +#define MARK_DHT 0xc4 +#define MARK_RST0 0xd0 +#define MARK_RST7 0xd7 +#define MARK_SOI 0xd8 +#define MARK_EOI 0xd9 +#define MARK_SOS 0xda +#define MARK_DQT 0xdb +#define MARK_DRI 0xdd +#define MARK_APP 0xe0 + +#define SEQ_INIT 0 +#define SEQ_MARK 1 +#define SEQ_SEG_LEN 2 +#define SEQ_SEG_LEN2 3 +#define SEQ_SEG_BODY 4 +#define SEQ_SOS 5 +#define SEQ_SOS2 6 + +#define HT_DC 0 +#define HT_AC 1 + +BaseJpegDecode::BaseJpegDecode() +{ + m_yblocks = JPEG_MCU_YBLOCKS; // 2 or 4 + clear(); + pHD = new HuffmanDecode; + DBG_ASSERT(pHD); + qt[0] = new uint8_t[64]; + qt[1] = new uint8_t[64]; + DBG_ASSERT(qt[0]); + DBG_ASSERT(qt[1]); +} + +void BaseJpegDecode::clear() +{ + m_seq = SEQ_INIT; +} + +void BaseJpegDecode::input(uint8_t* buf, int len) +{ + for(int i = 0; i < len; i++) { + input(buf[i]); + } +} + +void BaseJpegDecode::restart() +{ + m_block = 0; + m_scan = 0; + m_old_DC_value[0] = 0; + m_old_DC_value[1] = 0; + m_bitpat.clear(); + m_huff = NULL; +} + +void BaseJpegDecode::inputDQT(uint8_t c, int pos, int len) +{ + if (pos == 0 || pos == 65) { + m_param1 = c; + DBG_ASSERT(m_param1 == 0 || m_param1 == 1); + } else { + qt[m_param1][(pos%65)-1] = c; + } +} + +void BaseJpegDecode::inputSOF(uint8_t c, int pos, int len) +{ + switch(pos) { + case 1: + case 3: + m_param1 = c<<8; + break; + case 2: + width = m_param1 | c; + break; + case 4: + height = m_param1 | c; + break; + case 7: + if (c == 0x22) { + m_yblocks = 4; + } else if (c == 0x21) { + m_yblocks = 2; + } else { + DBG_ASSERT(c == 0x22 || c == 0x21); + } + break; + } +} + +void BaseJpegDecode::input(uint8_t c) +{ + switch(m_seq) { + case SEQ_INIT: + if (c == 0xff) { + m_seq = SEQ_MARK; + } + break; + case SEQ_MARK: + outputMARK(c); + if (c == MARK_SOI || c == MARK_EOI) { + m_seq = SEQ_INIT; + break; + } + m_mark = c; + m_seq = SEQ_SEG_LEN; + break; + case SEQ_SEG_LEN: + m_seg_len = c; + m_seq = SEQ_SEG_LEN2; + break; + case SEQ_SEG_LEN2: + m_seg_len <<= 8; + m_seg_len |= c; + m_seg_len -= 2; + m_seg_pos = 0; + m_seq = SEQ_SEG_BODY; + break; + case SEQ_SEG_BODY: + if (m_mark == MARK_DQT) { + inputDQT(c, m_seg_pos, m_seg_len); + } else if (m_mark == MARK_SOF0) { + inputSOF(c, m_seg_pos, m_seg_len); + } + if (++m_seg_pos < m_seg_len) { + break; + } + if (m_mark == MARK_SOS) { + m_seq = SEQ_SOS; + m_mcu = 0; + restart(); + break; + } + m_seq = SEQ_INIT; + break; + case SEQ_SOS: + if (c == 0xff) { + m_seq = SEQ_SOS2; + break; + } + inputScan(c); + break; + case SEQ_SOS2: + if (c == 0x00) { + inputScan(0xff); + m_seq = SEQ_SOS; + break; + } else if (c >= MARK_RST0 && c <= MARK_RST7) { + restart(); + m_seq = SEQ_SOS; + break; + } + outputMARK(c); + m_seq = SEQ_INIT; + break; + default: + break; + } +} + +void BaseJpegDecode::inputScan(uint8_t c) +{ + m_bitpat += c; + while(m_bitpat.size() > 0) { + int tc = (m_scan == 0) ? HT_DC : HT_AC; + int th = (m_block < m_yblocks) ? 0 : 1; + DBG("%d %d %08x %d\n", tc, th, m_bitpat.peek(32), m_bitpat.size()); + if (m_huff == NULL) { + m_huff = pHD->Lookup(tc, th, &m_bitpat); + if (m_huff == NULL) { + break; + } + m_bitpat.get(m_huff->code_size); // skip code + } + if (m_huff->value_size > m_bitpat.size()) { + break; + } + DBG("%d %d %d %02x\n", m_huff->run, m_huff->value_size, m_huff->code_size, m_huff->code); + int value = pHD->getValue(m_huff, &m_bitpat); + if (tc == HT_DC) { + value += m_old_DC_value[th]; + outputDC(m_mcu, m_block, value); + m_old_DC_value[th] = value; + m_scan++; + REPORT_CODE(report_scan_dc_count++); + } else { // AC + if (m_huff->value_size == 0 && m_huff->run == 0) { // EOB + DBG("AC EOB\n"); + m_scan = 64; + } else { + for(int i = 0; i < m_huff->run; i++) { + outputAC(m_mcu, m_block, m_scan, 0); + m_scan++; + } + outputAC(m_mcu, m_block, m_scan, value); + m_scan++; + } + if (m_scan >= 64) { + m_scan = 0; + if (++m_block >= (m_yblocks+2)) { + m_block = 0; + m_mcu++; + } + } + REPORT_CODE(report_scan_ac_count++); + } + m_huff = NULL; + REPORT_CODE(report_scan_count++); + } +}
--- a/BaseJpegDecode.h Mon Oct 22 13:55:09 2012 +0000 +++ b/BaseJpegDecode.h Thu Oct 25 11:00:05 2012 +0000 @@ -4,7 +4,6 @@ #include "HuffmanDecode.h" #include "BitPattern.h" - class BaseJpegDecode { public: BaseJpegDecode(); @@ -14,7 +13,18 @@ virtual void outputDC(int mcu, int block, int value) = 0; virtual void outputAC(int mcu, int block, int scan, int value) = 0; virtual void outputMARK(uint8_t c) = 0; + uint8_t* qt[2]; + int width; + int height; + int m_yblocks; +#ifdef JPEG_USE_REPORT_CODE + int report_scan_count; + int report_scan_dc_count; + int report_scan_ac_count; +#endif //JPEG_USE_REPORT private: + void inputDQT(uint8_t c, int pos, int len); + void inputSOF(uint8_t c, int pos, int len); void inputScan(uint8_t c); void restart(); protected: @@ -25,9 +35,10 @@ Huff* m_huff; int m_old_DC_value[2]; BitPattern m_bitpat; - int m_skip; uint8_t m_mark; HuffmanDecode* pHD; - int m_yblocks; + int m_seg_pos; + int m_seg_len; + int m_param1; }; #endif // BASE_JPEG_DECODE_H
--- a/bjd_config.h Mon Oct 22 13:55:09 2012 +0000 +++ b/bjd_config.h Thu Oct 25 11:00:05 2012 +0000 @@ -2,6 +2,8 @@ #define BJE_CONFIG_H #define JPEG_MCU_YBLOCKS 2 + #define JPEG_USE_HUFFMAN_TABLE +#define JPEG_USE_REPORT_CODE #endif // BJE_CONFIG_H