Add a decoding driver.
authorSteinar H. Gunderson <sesse@debian.org>
Sat, 3 Jan 2009 15:27:32 +0000 (16:27 +0100)
committerSteinar H. Gunderson <sesse@debian.org>
Sat, 3 Jan 2009 15:27:32 +0000 (16:27 +0100)
driver.c [new file with mode: 0644]

diff --git a/driver.c b/driver.c
new file mode 100644 (file)
index 0000000..08b684a
--- /dev/null
+++ b/driver.c
@@ -0,0 +1,219 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#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);
+               }
+       }
+}