Browse Source

Merge from mv

Suren A. Chilingaryan 11 years ago
parent
commit
e343c95b90
4 changed files with 259 additions and 149 deletions
  1. 2 2
      CMakeLists.txt
  2. 13 4
      NEWS
  3. 64 96
      src/ufodecode.c
  4. 180 47
      test/ipedec.c

+ 2 - 2
CMakeLists.txt

@@ -5,7 +5,7 @@ set(LIBUFODECODE_API_VERSION "0.2")
 set(LIBUFODECODE_ABI_VERSION "0.2")
 set(LIBUFODECODE_ABI_MAJOR_VERSION "0")
 
-set(PACKAGE_VERSION "0.2.1")
+set(PACKAGE_VERSION "0.2.2")
 set(PACKAGE_NAME "${TARNAME}")
 set(PACKAGE_TARNAME "${TARNAME}")
 set(PACKAGE_STRING "${PACKAGE_NAME}-${PACKAGE_VERSION}")
@@ -24,7 +24,7 @@ if(NOT DEFINED LIB_INSTALL_DIR)
 endif(NOT DEFINED LIB_INSTALL_DIR)
 
 if(NOT DEFINED INCLUDE_INSTALL_DIR)
-    set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/")
+    set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include")
 endif(NOT DEFINED INCLUDE_INSTALL_DIR)
 
 if(NOT DEFINED LOCALE_INSTALL_DIR)

+ 13 - 4
NEWS

@@ -1,13 +1,22 @@
+Changes in ufodecode 0.2.2
+==========================
+
+This is a bugfix release:
+
+- Fix 10 bit decoding that shows wrong output when ADCs are almost saturated
+- Fix 12 bit decoding that capped some output channels at 10 bits
+- `ipedec` returns error code different from 0 when an error occurred
+- `ipedec` reports the frame rate again with the `--frame-rate` switch set
+
+
 Changes in ufodecode 0.2.1
 ==========================
 
-This is a bugfix release.
+This is a bugfix release:
 
-Minor changes
--------------
 - Fix 12 bit decoding according to CMOSIS specs
 - Fix command line input of `ipedec`
-- Trunace so-Version to major.minor
+- Truncate so-Version to major.minor
 
 
 Changes in ufodecode 0.2.0

+ 64 - 96
src/ufodecode.c

@@ -157,9 +157,9 @@ ufo_decode_frame_channels_v0(UfoDecoder     *decoder,
         int pixels = (info >> 20) & 0xFF;
 
 #ifdef CHECKS
-        int err = 0;
         int header = (info >> 30) & 0x03;
         const int bpp = (info >> 16) & 0x0F;
+        int err;
         CHECK_FLAG("raw header magick", header == 2, header);
         CHECK_FLAG("row number, only %i rows requested", row < num_rows, row, num_rows);
         CHECK_FLAG("pixel size, only 10 bits are supported", bpp == 10, bpp);
@@ -299,10 +299,6 @@ ufo_decode_frame_channels_v4(UfoDecoder     *decoder,
         int header = (info >> 30) & 0x03;
         const int bpp = (info >> 16) & 0x0F;
         CHECK_FLAG("raw header magick", header == 2, header);
-
-        /* XXX: rows are numbered absolutely so this becomes unnecessary */
-        /* CHECK_FLAG("row number, only %i rows requested", row < num_rows, row, num_rows); */
-
         CHECK_FLAG("pixel size, only 10 bits are supported", bpp == 10, bpp);
         CHECK_FLAG("channel, limited by %zu output channels", channel < channels_per_row, channel, channels_per_row);
 #endif
@@ -398,18 +394,18 @@ static int
 ufo_decode_frame_channels_v5(UfoDecoder     *decoder,
                              uint16_t       *pixel_buffer,
                              uint32_t       *raw,
-                             size_t          num_words,
                              size_t          num_rows,
                              size_t         *offset,
                              uint8_t         output_mode)
 {
     payload_header_v5 *header;
     size_t base = 0, index = 0;
-    int off = 0;
 
     header = (payload_header_v5 *) &raw[base];
 
     if (output_mode == IPECAMERA_MODE_4_CHAN_IO) {
+        size_t off = 0;
+
         while (raw[base] != 0xAAAAAAA) {
             header = (payload_header_v5 *) &raw[base];
             index = header->row_number * IPECAMERA_WIDTH + header->pixel_number;
@@ -433,69 +429,41 @@ ufo_decode_frame_channels_v5(UfoDecoder     *decoder,
             base += 6;
         }
     }
-    else { /*if (output_mode == IPECAMERA_MODE_16_CHAN_IO)*/
+    else {
         while (raw[base] != 0xAAAAAAA) {
             header = (payload_header_v5 *) &raw[base];
             index = header->row_number * IPECAMERA_WIDTH + header->pixel_number;
 
             /* Skip header + two zero-filled words */
-            /*
-                        base += 3;
-                        pixel_buffer[index + 15*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base] >> 22);
-                        pixel_buffer[index + 13*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base] >> 12);
-                        pixel_buffer[index + 14*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base] >> 2);
-                        pixel_buffer[index + 12*IPECAMERA_PIXELS_PER_CHANNEL] = ((0x3 & raw[base]) << 8) | (0x3ff & (raw[base+1] >> 24));
-                        pixel_buffer[index + 10*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+1] >> 14);
-                        pixel_buffer[index +  8*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+1] >> 4);
-                        pixel_buffer[index + 11*IPECAMERA_PIXELS_PER_CHANNEL] = ((0xf & raw[base+1]) << 6) | (0x3ff & (raw[base+2] >> 26));
-                        pixel_buffer[index +  7*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+2] >> 16);
-                        pixel_buffer[index +  9*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+2] >> 6);
-                        pixel_buffer[index +  6*IPECAMERA_PIXELS_PER_CHANNEL] = ((0x3f & raw[base+2]) << 4) | (0x3ff & (raw[base+3] >> 28));
-                        pixel_buffer[index +  5*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+3] >> 18);
-                        pixel_buffer[index +  2*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+3] >> 8);
-                        pixel_buffer[index +  4*IPECAMERA_PIXELS_PER_CHANNEL] = ((0xff & raw[base+3]) << 2) | (0x3ff & (raw[base+4] >> 30));
-                        pixel_buffer[index +  3*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+4] >> 20);
-                        pixel_buffer[index +  0*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+4] >> 10);
-                        pixel_buffer[index +  1*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & raw[base+4];
-                        base += 5;
-            */
-
             base += 2;
 
             if (header->magic != 0xc0) {
                 pixel_buffer[index + 15*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base] >> 20);
                 pixel_buffer[index + 13*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base] >> 8);
-                pixel_buffer[index + 14*IPECAMERA_PIXELS_PER_CHANNEL] = (0xff & raw[base]) << 4 | (raw[base+1] >> 28);
+                pixel_buffer[index + 14*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (((0xff & raw[base]) << 4) | (raw[base+1] >> 28));
                 pixel_buffer[index + 12*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+1] >> 16);
                 pixel_buffer[index + 10*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+1] >> 4);
-                pixel_buffer[index +  8*IPECAMERA_PIXELS_PER_CHANNEL] = ((0xf & raw[base+1]) << 8) | (raw[base+2] >> 24);
+                pixel_buffer[index +  8*IPECAMERA_PIXELS_PER_CHANNEL] = ((0x3 & raw[base+1]) << 8) | (raw[base+2] >> 24);
                 pixel_buffer[index + 11*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+2] >> 12);
                 pixel_buffer[index +  7*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & raw[base+2];
                 pixel_buffer[index +  9*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+3] >> 20);
                 pixel_buffer[index +  6*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+3] >> 8);
-                pixel_buffer[index +  5*IPECAMERA_PIXELS_PER_CHANNEL] = (0xff & raw[base+3]) << 4 | (raw[base+4] >> 28);
+                pixel_buffer[index +  5*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (((0xff & raw[base+3]) << 4) | (raw[base+4] >> 28));
                 pixel_buffer[index +  2*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+4] >> 16);
                 pixel_buffer[index +  4*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+4] >> 4);
-                pixel_buffer[index +  3*IPECAMERA_PIXELS_PER_CHANNEL] = ((0xf & raw[base+4]) << 8) | (raw[base+5] >> 24);
+                pixel_buffer[index +  3*IPECAMERA_PIXELS_PER_CHANNEL] = ((0x3 & raw[base+4]) << 8) | (raw[base+5] >> 24);
                 pixel_buffer[index +  0*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & (raw[base+5] >> 12);
                 pixel_buffer[index +  1*IPECAMERA_PIXELS_PER_CHANNEL] = 0x3ff & raw[base+5];
             }
-            else {
-                off++;
-
-                if (header->magic == 0xc0)
-                    off = 0;
-            }
 
             base += 6;
-
         }
     }
 
-
     *offset = base;
     return 0;
 }
+
 /**
  * \brief Deinterlace by interpolating between two rows
  *
@@ -584,78 +552,78 @@ size_t ufo_decoder_decode_frame(UfoDecoder      *decoder,
     CHECK_VALUE(raw[pos++], 0x55555555);
 
     switch (version) {
-    case 0:
-        CHECK_VALUE(raw[pos++], 0x56666666);
-        CHECK_VALUE(raw[pos] >> 28, 0x5);
-        meta->frame_number = raw[pos++] & 0xFFFFFFF;
-        CHECK_VALUE(raw[pos] >> 28, 0x5);
-        meta->time_stamp = raw[pos++] & 0xFFFFFFF;
-        break;
-
-    case 4:
-    case 5:
-        CHECK_VALUE(raw[pos] >> 28, 0x5);
-        meta->cmosis_start_address = (raw[pos] >> 21) & 0x1FF;
-        meta->n_skipped_rows = (raw[pos] >> 15) & 0x3F;
-        meta->n_rows = rows_per_frame = raw[pos] & 0x7FF;
-        pos++;
+        case 0:
+            CHECK_VALUE(raw[pos++], 0x56666666);
+            CHECK_VALUE(raw[pos] >> 28, 0x5);
+            meta->frame_number = raw[pos++] & 0xFFFFFFF;
+            CHECK_VALUE(raw[pos] >> 28, 0x5);
+            meta->time_stamp = raw[pos++] & 0xFFFFFFF;
+            break;
+
+        case 4:
+        case 5:
+            CHECK_VALUE(raw[pos] >> 28, 0x5);
+            meta->cmosis_start_address = (raw[pos] >> 21) & 0x1FF;
+            meta->n_skipped_rows = (raw[pos] >> 15) & 0x3F;
+            meta->n_rows = rows_per_frame = raw[pos] & 0x7FF;
+            pos++;
 
-        meta->frame_number = raw[pos++] & 0x1FFFFFF;
-        CHECK_VALUE(raw[pos] >> 28, 0x5);
-        meta->time_stamp = raw[pos] & 0xFFFFFF;
-        meta->output_mode = (raw[pos] >> 24) & 0x3;
-        meta->adc_resolution = (raw[pos] >> 26) & 0x3;
-        pos++;
+            meta->frame_number = raw[pos++] & 0x1FFFFFF;
+            CHECK_VALUE(raw[pos] >> 28, 0x5);
+            meta->time_stamp = raw[pos] & 0xFFFFFF;
+            meta->output_mode = (raw[pos] >> 24) & 0x3;
+            meta->adc_resolution = (raw[pos] >> 26) & 0x3;
+            pos++;
 
-        if ((meta->output_mode != IPECAMERA_MODE_4_CHAN_IO)&&(meta->output_mode != IPECAMERA_MODE_16_CHAN_IO)) {
+            if ((meta->output_mode != IPECAMERA_MODE_4_CHAN_IO) && (meta->output_mode != IPECAMERA_MODE_16_CHAN_IO)) {
 #ifdef DEBUG
-            fprintf(stderr, "Output mode 0x%lx is not supported\n", meta->output_mode);
+                fprintf(stderr, "Output mode 0x%x is not supported\n", meta->output_mode);
 #endif
-            return EILSEQ;
-        }
-        break;
+                return EILSEQ;
+            }
+            break;
 
-    default:
-        fprintf(stderr, "Unsupported data format detected\n");
-        return 0;
+        default:
+            fprintf(stderr, "Unsupported data format version %i detected\n", version);
+            return 0;
     }
 
     if (err)
         return 0;
 #else
     switch (version) {
-    case 0:
-        meta->frame_number = raw[pos + 6] & 0xFFFFFFF;
-        meta->time_stamp = raw[pos + 7] & 0xFFFFFFF;
-        break;
-    case 4:
-    case 5:
-        meta->frame_number = raw[pos + 6] & 0x1FFFFFF;
-        meta->time_stamp = raw[pos + 7] & 0xFFFFFF;
-        meta->output_mode = (raw[pos + 7] >> 24) & 0x3;
-        meta->adc_resolution = (raw[pos + 7] >> 26) & 0x3;
-
-        break;
-    default:
-        fprintf(stderr, "Unsupported data format detected\n");
-        return 0;
+        case 0:
+            meta->frame_number = raw[pos + 6] & 0xFFFFFFF;
+            meta->time_stamp = raw[pos + 7] & 0xFFFFFFF;
+            break;
+        case 4:
+        case 5:
+            meta->frame_number = raw[pos + 6] & 0x1FFFFFF;
+            meta->time_stamp = raw[pos + 7] & 0xFFFFFF;
+            meta->output_mode = (raw[pos + 7] >> 24) & 0x3;
+            meta->adc_resolution = (raw[pos + 7] >> 26) & 0x3;
+
+            break;
+        default:
+            fprintf(stderr, "Unsupported data format detected\n");
+            return 0;
     }
 
     pos += 8;
 #endif
 
     switch (version) {
-    case 0:
-        err = ufo_decode_frame_channels_v0(decoder, pixels, raw + pos, num_words - pos - 8, &advance);
-        break;
-    case 4:
-        err = ufo_decode_frame_channels_v4(decoder, pixels, raw + pos, num_words - pos - 8, rows_per_frame, &advance);
-        break;
-    case 5:
-        err = ufo_decode_frame_channels_v5(decoder, pixels, raw + pos, num_words - pos - 8, rows_per_frame, &advance, meta->output_mode);
-        break;
-    default:
-        break;
+        case 0:
+            err = ufo_decode_frame_channels_v0(decoder, pixels, raw + pos, num_words - pos - 8, &advance);
+            break;
+        case 4:
+            err = ufo_decode_frame_channels_v4(decoder, pixels, raw + pos, num_words - pos - 8, rows_per_frame, &advance);
+            break;
+        case 5:
+            err = ufo_decode_frame_channels_v5(decoder, pixels, raw + pos, rows_per_frame, &advance, meta->output_mode);
+            break;
+        default:
+            break;
     }
 
     if (err)

+ 180 - 47
test/ipedec.c

@@ -8,10 +8,21 @@
 #include <getopt.h>
 #include <ufodecode.h>
 
+typedef struct {
+    int clear_frame;
+    int dry_run;
+    int verbose;
+    int rows;
+    int print_frame_rate;
+    int print_num_rows;
+    int cont;
+    int superimpose;
+} Options;
+
 static int
 read_raw_file(const char *filename, char **buffer, size_t *length)
 {
-    FILE *fp = fopen(filename, "rb"); 
+    FILE *fp = fopen(filename, "rb");
     if (fp == NULL)
         return ENOENT;
 
@@ -38,12 +49,17 @@ read_raw_file(const char *filename, char **buffer, size_t *length)
 static void
 usage(void)
 {
-    printf("usage: ipedec [--num-rows=ROWS] [--clear-frame] FILE [FILE ...]\n\
+    printf("usage: ipedec [OPTION]... FILE [FILE ...]\n\
 Options:\n\
-  -h, --help         Show this help message and exit\n\
-  -v, --verbose      Print additional information on STDOUT\n\
-  -r, --num-rows=N   N rows that are contained in the file\n\
-  -c, --clear-frame  Clear the frame for each iteration\n");
+  -h, --help                Show this help message and exit\n\
+  -v, --verbose             Print additional information on STDOUT\n\
+  -r, --num-rows=N          N rows that are contained in the file\n\
+  -c, --clear-frame         Clear the frame for each iteration\n\
+  -d, --dry-run             Do not save the frames\n\
+  -s, --superimpose=C       Superimpose frames on top of the first with color C as borders\n\
+  -f, --print-frame-rate    Print frame rate on STDOUT\n\
+      --print-num-rows      Print number of rows on STDOUT\n\
+      --continue            Continue decoding frames even when errors occur\n");
 }
 
 static void
@@ -122,111 +138,224 @@ timer_stop (Timer *t)
 }
 
 static void
-process_file(const char *filename, int rows, int clear_frame, int verbose)
+superimpose_on_top (uint16_t *top, uint16_t *bottom, uint16_t color)
+{
+    int x, y;
+    int in_void = top[0] == 0;
+
+    for (y = 0; y < 1088; y++) {
+        int offset = y * 2048;
+
+        if ((in_void && top[offset] != 0) ||
+            (!in_void && top[offset] == 0)) {
+            in_void = 1 - in_void;
+
+            for (x = 0; x < 2048; x++)
+                top[offset++] = color;
+        } 
+        else {
+            for (x = 0; x < 2048; x++, offset++) {
+                if (top[offset] == 0) 
+                    top[offset] = bottom[offset];
+            }
+        }
+    }
+}
+
+static int
+process_file(const char *filename, Options *opts)
 {
     UfoDecoder      *decoder;
     UfoDecoderMeta   meta = {0};
     Timer           *timer;
     char            *buffer;
     size_t           num_bytes;
-    int              error;
+    size_t           frame_size;
+    uint16_t        *orig;
     uint16_t        *pixels;
     uint32_t         time_stamp, old_time_stamp;
-    int              n_frames = 0;
+    int              n_frames;
+    int              error = 0;
     FILE            *fp;
     char             output_name[256];
-    
+    float            mtime;
+
+    frame_size = 2048 * 1088 * sizeof(uint16_t);
     error = read_raw_file(filename, &buffer, &num_bytes);
 
     if (error) {
         fprintf(stderr, "Error reading %s: %s\n", filename, strerror(error));
-        return;
+        return error;
     }
 
-    decoder = ufo_decoder_new(rows, 2048, (uint32_t *) buffer, num_bytes);
+    decoder = ufo_decoder_new(opts->rows, 2048, (uint32_t *) buffer, num_bytes);
 
     if (decoder == NULL) {
         fprintf(stderr, "Failed to initialize decoder\n");
-        return;
+        return 1;
     }
 
-    snprintf(output_name, 256, "%s.raw", filename);
-    fp = fopen(output_name, "wb");
+    if (!opts->dry_run) {
+        snprintf(output_name, 256, "%s.raw", filename);
+        fp = fopen(output_name, "wb");
 
-    if (!fp) {
-        fprintf(stderr, "Failed to open file for writing\n");
-        return;
+        if (!fp) {
+            fprintf(stderr, "Failed to open file for writing\n");
+            return 1;
+        }
     }
 
+    if (opts->superimpose)
+        orig = (uint16_t *) malloc(frame_size);
+
+    pixels = (uint16_t *) malloc(frame_size);
+
     timer = timer_new ();
-    pixels = (uint16_t *) malloc(2048 * 1088 * sizeof(uint16_t));
     n_frames = 0;
+    old_time_stamp = 0;
 
     while (error != EIO) {
-        if (clear_frame)
-            memset(pixels, 0, 2048 * 1088 * sizeof(uint16_t));
+        if (opts->clear_frame || opts->superimpose)
+            memset(pixels, 0, frame_size);
 
         timer_start (timer);
         error = ufo_decoder_get_next_frame(decoder, &pixels, &meta);
         timer_stop (timer);
+        n_frames++;
+
+        if (opts->superimpose && n_frames == 1)
+            memcpy (orig, pixels, frame_size);
 
         if (!error) {
-            if (verbose) {
+            if (opts->verbose) {
                 printf("Status for frame %i\n", n_frames);
                 print_meta_data (&meta);
             }
 
-            n_frames++;
-            fwrite(pixels, sizeof(uint16_t), 2048 * 1088, fp);
+            if (opts->print_frame_rate) {
+                uint32_t diff = 80 * (meta.time_stamp - old_time_stamp);
+
+                printf("%-6d", 1000000000 / diff);
+                old_time_stamp = meta.time_stamp;
+            }
+
+            if (opts->print_num_rows)
+                printf("%d", meta.n_rows); 
+
+            if (opts->print_frame_rate || opts->print_num_rows)
+                printf("\n");
+
+            if (opts->superimpose)
+                superimpose_on_top (pixels, orig, opts->superimpose);
+
+            if (!opts->dry_run)
+                fwrite(pixels, sizeof(uint16_t), 2048 * 1088, fp);
+        }
+        else if (error != EIO) {
+            fprintf(stderr, "Failed to decode frame %i\n", n_frames);
+
+            if (opts->cont) {
+                /* Save the frame even though we know it is corrupted */
+                if (!opts->dry_run)
+                    fwrite(pixels, sizeof(uint16_t), 2048 * 1088, fp);
+            }
+            else
+                break;
         }
-        else if (error != EIO)
-            fprintf(stderr, "Failed to decode frame %i\n", n_frames); 
     }
 
-    fclose(fp);
+    if (!opts->dry_run)
+        fclose(fp);
 
-    float mtime = timer->seconds * 1000.0 + timer->useconds / 1000.0;
-    printf("Decoded %i frames in %.5fms\n", n_frames, mtime);
+    if (opts->verbose) {
+        mtime = timer->seconds * 1000.0 + timer->useconds / 1000.0;
+        printf("Decoded %i frames in %.5fms\n", n_frames, mtime);
+    }
 
     free(pixels);
     free(buffer);
     timer_destroy (timer);
     ufo_decoder_free(decoder);
+
+    return error == EIO ? 0 : error;
 }
 
 int main(int argc, char const* argv[])
 {
     int getopt_ret, index;
 
+    enum {
+        SUPERIMPOSE  = 's',
+        CLEAR_FRAME  = 'c',
+        DRY_RUN      = 'd',
+        FRAME_RATE   = 'f',
+        HELP         = 'h',
+        SET_NUM_ROWS = 'r', 
+        VERBOSE      = 'v',
+        CONTINUE,
+        NUM_ROWS
+    };
+
     static struct option long_options[] = {
-        { "num-rows", required_argument, 0, 'r' },
-        { "clear-frame", no_argument, 0, 'c' },
-        { "verbose", no_argument, 0, 'v' },
-        { "help", no_argument, 0, 'h' },
+        { "num-rows",           required_argument, 0, SET_NUM_ROWS },
+        { "clear-frame",        no_argument, 0, CLEAR_FRAME },
+        { "verbose",            no_argument, 0, VERBOSE },
+        { "help",               no_argument, 0, HELP },
+        { "dry-run",            no_argument, 0, DRY_RUN },
+        { "print-frame-rate",   no_argument, 0, FRAME_RATE },
+        { "continue",           no_argument, 0, CONTINUE },
+        { "print-num-rows",     no_argument, 0, NUM_ROWS },
+        { "superimpose",        required_argument, 0, SUPERIMPOSE },
         { 0, 0, 0, 0 }
     };
 
-    int clear_frame = 0;
-    int verbose = 0;
-    int rows = 1088;
+    static Options opts = {
+        .rows = 1088,
+        .verbose = 0,
+        .dry_run = 0,
+        .clear_frame = 0,
+        .print_frame_rate = 0,
+        .print_num_rows = 0,
+        .cont = 0,
+        .superimpose = 0
+    };
 
-    while ((getopt_ret = getopt_long(argc, (char *const *) argv, "r:cvh", long_options, &index)) != -1) {
+    while ((getopt_ret = getopt_long(argc, (char *const *) argv, "r:s:cvhdf", long_options, &index)) != -1) {
         switch (getopt_ret) {
-            case 'r': 
-                rows = atoi(optarg);
+            case SET_NUM_ROWS:
+                opts.rows = atoi(optarg);
                 break;
-            case 'c':
-                clear_frame = 1;
+            case CLEAR_FRAME:
+                opts.clear_frame = 1;
                 break;
-            case 'v':
-                verbose = 1;
+            case VERBOSE:
+                opts.verbose = 1;
                 break;
-            case 'h':
+            case HELP:
                 usage();
                 return 0;
+            case DRY_RUN:
+                opts.dry_run = 1;
+                break;
+            case FRAME_RATE:
+                opts.print_frame_rate = 1;
+                break;
+            case CONTINUE:
+                opts.cont = 1;
+                break;
+            case NUM_ROWS:
+                opts.print_num_rows = 1;
+            case SUPERIMPOSE:
+                opts.superimpose = atoi(optarg);
+                break;
             default:
                 break;
-        } 
+        }
+    }
+
+    if (opts.clear_frame && opts.superimpose) {
+        fprintf(stderr, "Error: --clear-frame and --superimpose are mutual exclusive\n");
+        return 1;
     }
 
     if (optind == argc) {
@@ -234,8 +363,12 @@ int main(int argc, char const* argv[])
         return 1;
     }
 
-    while (optind < argc)
-        process_file(argv[optind++], rows, clear_frame, verbose);
+    while (optind < argc) {
+        int errcode = process_file(argv[optind++], &opts);
+
+        if (errcode != 0)
+            return errcode;
+    }
 
     return 0;
 }