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);     
}
Committer:
va009039
Date:
Sat Feb 02 01:25:25 2013 +0000
Revision:
0:98f918e1d528
first commit

Who changed what in which revision?

UserRevisionLine numberNew 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 }