From: Steinar H. Gunderson Date: Sat, 3 Jan 2009 15:27:32 +0000 (+0100) Subject: Add a decoding driver. X-Git-Url: https://git.sesse.net/?p=fjl;a=commitdiff_plain;h=823f82d1e860f1260c483ef544c4e9532132c7e8 Add a decoding driver. --- diff --git a/driver.c b/driver.c new file mode 100644 index 0000000..08b684a --- /dev/null +++ b/driver.c @@ -0,0 +1,219 @@ +#include +#include + +#include "bytesource.h" +#include "choice.h" +#include "dehuff.h" +#include "input.h" + +struct jpeg_image { + unsigned precision; + unsigned width, height; + unsigned num_components; + unsigned hsample[256], vsample[256], qtable[256]; +}; + +ssize_t stdio_read(void* userdata, uint8_t* buf, size_t count) +{ + return fread(buf, 1, count, (FILE*)userdata); +} + +void read_sof(struct byte_source* source, struct jpeg_image* image) +{ + unsigned len = read_uint16(byte_source_input_func, source); + assert(len >= 8); + image->precision = read_uint8(byte_source_input_func, source); + assert(image->precision == 8); + image->width = read_uint16(byte_source_input_func, source); + image->height = read_uint16(byte_source_input_func, source); + image->num_components = read_uint8(byte_source_input_func, source); + len -= 8; + + fprintf(stderr, "%u-bit %ux%u JPEG with %u components\n", + image->precision, image->width, image->height, image->num_components); + + for (unsigned i = 0; i < image->num_components; ++i) { + assert(len >= 3); + unsigned c = read_uint8(byte_source_input_func, source); + unsigned sampling_factors = read_uint8(byte_source_input_func, source); + image->hsample[c] = sampling_factors >> 4; + image->vsample[c] = sampling_factors & 0x0f; + image->qtable[c] = read_uint8(byte_source_input_func, source); + len -= 3; + + fprintf(stderr, "Component %u: sampling factors %u x %x, quantization table %u\n", + c, image->hsample[c], image->vsample[c], image->qtable[c]); + } +} + +void read_scan(struct byte_source* source, struct jpeg_image* image, huffman_tables_t* tables) +{ + unsigned len = read_uint16(byte_source_input_func, source); + assert(len >= 2); + len -= 2; + + assert(len >= 1); + unsigned num_components = read_uint8(byte_source_input_func, source); + --len; + + unsigned component_num[256]; + unsigned dc_huffman_table[256], ac_huffman_table[256]; + unsigned ss, se, ah_al; + int last_dc[256]; + + for (unsigned i = 0; i < num_components; ++i) { + unsigned char td_ta; + assert(len >= 2); + component_num[i] = read_uint8(byte_source_input_func, source); + td_ta = read_uint8(byte_source_input_func, source); + len -= 2; + dc_huffman_table[i] = td_ta >> 4; + ac_huffman_table[i] = td_ta & 0x0f; + last_dc[i] = 0; + } + + assert(len >= 3); + ss = read_uint8(byte_source_input_func, source); + se = read_uint8(byte_source_input_func, source); + ah_al = read_uint8(byte_source_input_func, source); + len -= 3; + + if (len != 0) { + fprintf(stderr, "Error: %u unused bytes at end of SOS segment\n", len); + } + + struct bit_source bits; + init_bit_source(&bits, byte_source_input_func, source); + + for ( ;; ) { + for (unsigned c = 0; c < num_components; ++c) { + unsigned cn = component_num[c]; + unsigned nc = image->vsample[cn] * image->hsample[cn]; + for (unsigned n = 0; n < nc; ++n) { + const struct huffman_table* dc_table = &((*tables)[DC_CLASS][dc_huffman_table[c]]); + const struct huffman_table* ac_table = &((*tables)[AC_CLASS][ac_huffman_table[c]]); + + // decode DC component + unsigned dc_category = read_huffman_symbol(dc_table, &bits); + possibly_refill(&bits, dc_category); + last_dc[c] += extend(read_bits(&bits, dc_category), dc_category); + + // printf("dc=%d ac=", last_dc[c]); + putchar(last_dc[c]); + + // decode AC components + int zz[63] = { 0 }; + for (unsigned i = 0; i < 63; ++i) { + unsigned rs = read_huffman_symbol(ac_table, &bits); + unsigned r = rs >> 4; + unsigned s = rs & 0xf; + + if (rs == 0x00) { + /* end of block */ + break; + } + if (rs == 0xf0) { + /* 16 zero coefficients */ + i += 15; + continue; + } + + possibly_refill(&bits, s); + + i += r; + zz[i] = extend(read_bits(&bits, s), s); + } + + for (unsigned i = 0; i < 63; ++i) { + putchar(zz[i]); + //printf("%d ", zz[i]); + } + //printf("\n"); + } + } + } + if (len != 0) { + fprintf(stderr, "Error: %u unused bytes at end of SOS segment\n", len); + } +} + +void skip_segment(struct byte_source* source) +{ + uint8_t buf[4096]; + for ( ;; ) { + ssize_t ret = byte_source_input_func(source, buf, 4096); + if (ret == -1) { + fprintf(stderr, "Input error!\n"); + exit(1); + } + if (ret == 0) { + return; + } + } +} + +int main(void) +{ + struct jpeg_image jpeg; + init_choices(); + + struct byte_source source; + init_byte_source(&source, stdio_read, stdin); + + huffman_tables_t tables; + + for ( ;; ) { + uint8_t m2 = byte_source_read_marker(&source); + assert(m2 != 0x00); + + fprintf(stderr, "Marker 0x%02x, at position %ld\n", m2, ftell(stdin) - source.bytes_available); + + switch (m2) { + case 0xe0: + case 0xe1: + case 0xe2: + case 0xe3: + case 0xe4: + case 0xe5: + case 0xe6: + case 0xe7: + case 0xe8: + case 0xe9: + case 0xea: + case 0xeb: + case 0xec: + case 0xed: + case 0xee: + case 0xef: + /* APP0 through APPF */ + case 0xfc: + /* some EXIF stuff */ + case 0xfe: + /* comment */ + case 0xff: + /* ignore */ + case 0xdb: + /* DQT */ + skip_segment(&source); + break; + case 0xc0: + /* SOF0 (baseline DCT, Huffman encoded) */ + read_sof(&source, &jpeg); + break; + case 0xd8: + /* SOI */ + break; + case 0xc4: + /* DHT (define Huffman tables) */ + read_huffman_tables(&tables, byte_source_input_func, &source); + break; + case 0xda: + /* SOS (start of scan) */ + read_scan(&source, &jpeg, &tables); + break; + default: + fprintf(stderr, "Error: Unknown marker 0x%02x\n", m2); + exit(1); + } + } +}