convert JPEG stream data to bitmap, BaseJpegDecode example program
Dependencies: BaseJpegDecode BaseUsbHost FATFileSystem mbed-rtos mbed
JPEGデコードのサンプルプログラムです。
JPEGのMCU単位で逐次デコード出力していますので少ないRAMメモリで動かすことが出来ます。
#include "USBHostMSD.h" #include "SimpleJpegDecode.h" #include "bmp24.h" const char* INPUT_FILE = "/usb/input.jpg"; const char* OUTPUT_FILE = "/usb/output.bmp"; bmp24 bmp; RawSerial pc(USBTX, USBRX); void callbackRGB(int x, int y, uint8_t* rgb) { bmp.point(x, y, rgb); pc.printf("x=%d, y=%d, RGB=(0x%02x,0x%02x,0x%02x)\n", x, y, rgb[0], rgb[1], rgb[2]); } int main() { pc.baud(115200); USBHostMSD* msd = new USBHostMSD("usb"); if (!msd->connect()) { error("USB Flash drive not found.\n"); } SimpleJpegDecode* decode = new SimpleJpegDecode(RGB24); decode->setOnResult(callbackRGB); decode->clear(); pc.printf("input: %s\n", INPUT_FILE); FILE* fp = fopen(INPUT_FILE, "rb"); if (fp == NULL) { error("open error\n"); } while(1) { int c = fgetc(fp); if (c == EOF) { break; } decode->input(c); } fclose(fp); pc.printf("output: %s\n", OUTPUT_FILE); if (!bmp.writeFile(OUTPUT_FILE)) { error("write error\n"); } exit(1); }
SimpleJpegDecode/SimpleJpegDecode.cpp@0:98f918e1d528, 2013-02-02 (annotated)
- Committer:
- va009039
- Date:
- Sat Feb 02 01:25:25 2013 +0000
- Revision:
- 0:98f918e1d528
first commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
va009039 | 0:98f918e1d528 | 1 | #include "SimpleJpegDecode.h" |
va009039 | 0:98f918e1d528 | 2 | |
va009039 | 0:98f918e1d528 | 3 | #define DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0); |
va009039 | 0:98f918e1d528 | 4 | #define ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; |
va009039 | 0:98f918e1d528 | 5 | |
va009039 | 0:98f918e1d528 | 6 | |
va009039 | 0:98f918e1d528 | 7 | #define _1_4020 45 |
va009039 | 0:98f918e1d528 | 8 | #define _0_3441 11 |
va009039 | 0:98f918e1d528 | 9 | #define _0_7139 23 |
va009039 | 0:98f918e1d528 | 10 | #define _1_7718 57 |
va009039 | 0:98f918e1d528 | 11 | #define _0_0012 0 |
va009039 | 0:98f918e1d528 | 12 | |
va009039 | 0:98f918e1d528 | 13 | int adjust(int r) { |
va009039 | 0:98f918e1d528 | 14 | if (r >= 0) { |
va009039 | 0:98f918e1d528 | 15 | if (r <= 255) { |
va009039 | 0:98f918e1d528 | 16 | return r; |
va009039 | 0:98f918e1d528 | 17 | } else { |
va009039 | 0:98f918e1d528 | 18 | return 255; |
va009039 | 0:98f918e1d528 | 19 | } |
va009039 | 0:98f918e1d528 | 20 | } else { |
va009039 | 0:98f918e1d528 | 21 | return 0; |
va009039 | 0:98f918e1d528 | 22 | } |
va009039 | 0:98f918e1d528 | 23 | } |
va009039 | 0:98f918e1d528 | 24 | |
va009039 | 0:98f918e1d528 | 25 | void convYUVtoRGB(uint8_t rgb[], int y, int u, int v) |
va009039 | 0:98f918e1d528 | 26 | { |
va009039 | 0:98f918e1d528 | 27 | rgb[0] = adjust((y*32 + v*_1_4020)/32 + 128); |
va009039 | 0:98f918e1d528 | 28 | rgb[1] = adjust((y*32 - u*_0_3441 - v*_0_7139)/32 + 128); |
va009039 | 0:98f918e1d528 | 29 | rgb[2] = adjust((y*32 + u*_1_7718 - v*_0_0012)/32 + 128); |
va009039 | 0:98f918e1d528 | 30 | } |
va009039 | 0:98f918e1d528 | 31 | |
va009039 | 0:98f918e1d528 | 32 | SimpleJpegDecode::SimpleJpegDecode(uint8_t output_mode) |
va009039 | 0:98f918e1d528 | 33 | { |
va009039 | 0:98f918e1d528 | 34 | m_output_mode = output_mode; |
va009039 | 0:98f918e1d528 | 35 | clearOnResult(); |
va009039 | 0:98f918e1d528 | 36 | } |
va009039 | 0:98f918e1d528 | 37 | |
va009039 | 0:98f918e1d528 | 38 | |
va009039 | 0:98f918e1d528 | 39 | void SimpleJpegDecode::output(int mcu, int block, int scan, int value) |
va009039 | 0:98f918e1d528 | 40 | { |
va009039 | 0:98f918e1d528 | 41 | int sc = (block < yblock) ? 0 : 1; |
va009039 | 0:98f918e1d528 | 42 | inputBLOCK(mcu, block, scan, value * qt[sc][scan]); |
va009039 | 0:98f918e1d528 | 43 | } |
va009039 | 0:98f918e1d528 | 44 | |
va009039 | 0:98f918e1d528 | 45 | void SimpleJpegDecode::outputDC(int mcu, int block, int value) |
va009039 | 0:98f918e1d528 | 46 | { |
va009039 | 0:98f918e1d528 | 47 | output(mcu, block, 0, value); |
va009039 | 0:98f918e1d528 | 48 | DC_count++; |
va009039 | 0:98f918e1d528 | 49 | } |
va009039 | 0:98f918e1d528 | 50 | |
va009039 | 0:98f918e1d528 | 51 | void SimpleJpegDecode::outputAC(int mcu, int block, int scan, int value) |
va009039 | 0:98f918e1d528 | 52 | { |
va009039 | 0:98f918e1d528 | 53 | output(mcu, block, scan, value); |
va009039 | 0:98f918e1d528 | 54 | AC_count++; |
va009039 | 0:98f918e1d528 | 55 | } |
va009039 | 0:98f918e1d528 | 56 | |
va009039 | 0:98f918e1d528 | 57 | void SimpleJpegDecode::outputMARK(uint8_t c) |
va009039 | 0:98f918e1d528 | 58 | { |
va009039 | 0:98f918e1d528 | 59 | } |
va009039 | 0:98f918e1d528 | 60 | |
va009039 | 0:98f918e1d528 | 61 | void SimpleJpegDecode::format_YUV(int mcu, int block, int8_t* values) |
va009039 | 0:98f918e1d528 | 62 | { |
va009039 | 0:98f918e1d528 | 63 | if (block < yblock+1) { |
va009039 | 0:98f918e1d528 | 64 | memcpy(m_block_data[block], values, 64); |
va009039 | 0:98f918e1d528 | 65 | return; |
va009039 | 0:98f918e1d528 | 66 | } |
va009039 | 0:98f918e1d528 | 67 | int mcu_x_count = (width+15)/16; |
va009039 | 0:98f918e1d528 | 68 | int mcu_x = mcu % mcu_x_count; |
va009039 | 0:98f918e1d528 | 69 | int mcu_y = mcu / mcu_x_count; |
va009039 | 0:98f918e1d528 | 70 | uint8_t yuv[3]; |
va009039 | 0:98f918e1d528 | 71 | if (yblock == 2) { |
va009039 | 0:98f918e1d528 | 72 | for(int y = 0; y < 8; y++) { |
va009039 | 0:98f918e1d528 | 73 | for(int x = 0; x < 16; x++) { |
va009039 | 0:98f918e1d528 | 74 | yuv[0] = m_block_data[x/8][y*8+x%8] + 128; |
va009039 | 0:98f918e1d528 | 75 | yuv[1] = m_block_data[2][y*8+x/2] + 128; |
va009039 | 0:98f918e1d528 | 76 | yuv[2] = values[y*8+x/2] + 128; |
va009039 | 0:98f918e1d528 | 77 | onResult(mcu_x * 16 + x, mcu_y * 8 + y, yuv); |
va009039 | 0:98f918e1d528 | 78 | } |
va009039 | 0:98f918e1d528 | 79 | } |
va009039 | 0:98f918e1d528 | 80 | } else if (yblock == 4) { |
va009039 | 0:98f918e1d528 | 81 | for(int y = 0; y < 16; y++) { |
va009039 | 0:98f918e1d528 | 82 | for(int x = 0; x < 16; x++) { |
va009039 | 0:98f918e1d528 | 83 | yuv[0] = m_block_data[(y/8)*2+x/8][(y%8)*8+x%8] + 128; |
va009039 | 0:98f918e1d528 | 84 | yuv[1] = m_block_data[4][(y/2)*8+x/2] + 128; |
va009039 | 0:98f918e1d528 | 85 | yuv[2] = values[(y/2)*8+x/2] + 128; |
va009039 | 0:98f918e1d528 | 86 | onResult(mcu_x * 16 + x, mcu_y * 16 + y, yuv); |
va009039 | 0:98f918e1d528 | 87 | } |
va009039 | 0:98f918e1d528 | 88 | } |
va009039 | 0:98f918e1d528 | 89 | } else { |
va009039 | 0:98f918e1d528 | 90 | ASSERT(yblock == 2 || yblock == 4); |
va009039 | 0:98f918e1d528 | 91 | } |
va009039 | 0:98f918e1d528 | 92 | } |
va009039 | 0:98f918e1d528 | 93 | |
va009039 | 0:98f918e1d528 | 94 | void SimpleJpegDecode::format_RGB24(int mcu, int block, int8_t* values) |
va009039 | 0:98f918e1d528 | 95 | { |
va009039 | 0:98f918e1d528 | 96 | if (block < yblock+1) { |
va009039 | 0:98f918e1d528 | 97 | memcpy(m_block_data[block], values, 64); |
va009039 | 0:98f918e1d528 | 98 | return; |
va009039 | 0:98f918e1d528 | 99 | } |
va009039 | 0:98f918e1d528 | 100 | int mcu_x_count = (width+15)/16; |
va009039 | 0:98f918e1d528 | 101 | int mcu_x = mcu % mcu_x_count; |
va009039 | 0:98f918e1d528 | 102 | int mcu_y = mcu / mcu_x_count; |
va009039 | 0:98f918e1d528 | 103 | uint8_t rgb[3]; |
va009039 | 0:98f918e1d528 | 104 | if (yblock == 2) { |
va009039 | 0:98f918e1d528 | 105 | for(int y = 0; y < 8; y++) { |
va009039 | 0:98f918e1d528 | 106 | for(int x = 0; x < 16; x++) { |
va009039 | 0:98f918e1d528 | 107 | int8_t yuv_y = m_block_data[x/8][y*8+x%8]; |
va009039 | 0:98f918e1d528 | 108 | int8_t yuv_u = m_block_data[2][y*8+x/2]; |
va009039 | 0:98f918e1d528 | 109 | int8_t yuv_v = values[y*8+x/2]; |
va009039 | 0:98f918e1d528 | 110 | convYUVtoRGB(rgb, yuv_y, yuv_u, yuv_v); |
va009039 | 0:98f918e1d528 | 111 | onResult(mcu_x * 16 + x, mcu_y * 8 + y, rgb); |
va009039 | 0:98f918e1d528 | 112 | } |
va009039 | 0:98f918e1d528 | 113 | } |
va009039 | 0:98f918e1d528 | 114 | } else if (yblock == 4) { |
va009039 | 0:98f918e1d528 | 115 | for(int y = 0; y < 16; y++) { |
va009039 | 0:98f918e1d528 | 116 | for(int x = 0; x < 16; x++) { |
va009039 | 0:98f918e1d528 | 117 | int8_t yuv_y = m_block_data[(y/8)*2+x/8][(y%8)*8+x%8]; |
va009039 | 0:98f918e1d528 | 118 | int8_t yuv_u = m_block_data[4][(y/2)*8+x/2]; |
va009039 | 0:98f918e1d528 | 119 | int8_t yuv_v = values[(y/2)*8+x/2]; |
va009039 | 0:98f918e1d528 | 120 | convYUVtoRGB(rgb, yuv_y, yuv_u, yuv_v); |
va009039 | 0:98f918e1d528 | 121 | onResult(mcu_x * 16 + x, mcu_y * 16 + y, rgb); |
va009039 | 0:98f918e1d528 | 122 | } |
va009039 | 0:98f918e1d528 | 123 | } |
va009039 | 0:98f918e1d528 | 124 | } else { |
va009039 | 0:98f918e1d528 | 125 | ASSERT(yblock == 2 || yblock == 4); |
va009039 | 0:98f918e1d528 | 126 | } |
va009039 | 0:98f918e1d528 | 127 | } |
va009039 | 0:98f918e1d528 | 128 | |
va009039 | 0:98f918e1d528 | 129 | void SimpleJpegDecode::outputBLOCK(int mcu, int block, int8_t* values) |
va009039 | 0:98f918e1d528 | 130 | { |
va009039 | 0:98f918e1d528 | 131 | BLOCK_count++; |
va009039 | 0:98f918e1d528 | 132 | if (m_output_mode == YUV) { |
va009039 | 0:98f918e1d528 | 133 | format_YUV(mcu, block, values); |
va009039 | 0:98f918e1d528 | 134 | } else if (m_output_mode == RGB24) { |
va009039 | 0:98f918e1d528 | 135 | format_RGB24(mcu, block, values); |
va009039 | 0:98f918e1d528 | 136 | } else { |
va009039 | 0:98f918e1d528 | 137 | ASSERT(m_output_mode == YUV || m_output_mode == RGB24); |
va009039 | 0:98f918e1d528 | 138 | } |
va009039 | 0:98f918e1d528 | 139 | } |
va009039 | 0:98f918e1d528 | 140 | |
va009039 | 0:98f918e1d528 | 141 | void SimpleJpegDecode::onResult(int x, int y, uint8_t* yuv) |
va009039 | 0:98f918e1d528 | 142 | { |
va009039 | 0:98f918e1d528 | 143 | if(m_pCbItem && m_pCbMeth) |
va009039 | 0:98f918e1d528 | 144 | (m_pCbItem->*m_pCbMeth)(x, y, yuv); |
va009039 | 0:98f918e1d528 | 145 | else if(m_pCb) |
va009039 | 0:98f918e1d528 | 146 | m_pCb(x, y, yuv); |
va009039 | 0:98f918e1d528 | 147 | } |
va009039 | 0:98f918e1d528 | 148 | |
va009039 | 0:98f918e1d528 | 149 | void SimpleJpegDecode::setOnResult( void (*pMethod)(int, int, uint8_t*) ) |
va009039 | 0:98f918e1d528 | 150 | { |
va009039 | 0:98f918e1d528 | 151 | m_pCb = pMethod; |
va009039 | 0:98f918e1d528 | 152 | m_pCbItem = NULL; |
va009039 | 0:98f918e1d528 | 153 | m_pCbMeth = NULL; |
va009039 | 0:98f918e1d528 | 154 | } |
va009039 | 0:98f918e1d528 | 155 | |
va009039 | 0:98f918e1d528 | 156 | void SimpleJpegDecode::clearOnResult() |
va009039 | 0:98f918e1d528 | 157 | { |
va009039 | 0:98f918e1d528 | 158 | m_pCb = NULL; |
va009039 | 0:98f918e1d528 | 159 | m_pCbItem = NULL; |
va009039 | 0:98f918e1d528 | 160 | m_pCbMeth = NULL; |
va009039 | 0:98f918e1d528 | 161 | } |