Example #1
0
int main(int argc, char*const* argv) {
  int opt, has_consumed_fmt_input;
  unsigned i;
  co_this = argv[0];

  while (-1 != (opt =
#ifdef HAVE_GETOPT_LONG
         getopt_long(argc, argv, short_options, long_options, NULL)
#else
         getopt(argc, argv, short_options)
#endif
  )) {
    switch (opt) {
    case '?':
    case ':':
    case 'h':
      fputs(usage_statement, opt == 'h'? stdout : stderr);
      return (opt == 'h'? 0 : 255);

    case 'V':
      puts("drachencode (" PACKAGE_STRING ")");
      return 0;

    case 'b':
      uint_arg_or_die(&co_block_size, "block-size");
      break;

    case 'd':
      co_is_decoding = 1;
      break;

    case 'D':
      co_dryrun = 1;
      break;

    case 'e':
      co_is_encoding = 1;
      break;

    case 'f':
      co_force = 1;
      break;

    case 'H':
      uint_arg_or_die(&co_image_bh, "img-block-height");
      break;

    case 'W':
      uint_arg_or_die(&co_image_bw, "img-block-width");
      break;

    case 'O':
      uint_arg_or_die(&co_image_off, "img-offset");
      break;

    case 'C':
      uint_arg_or_die(&co_image_nc, "img-num-cols");
      break;

    case 'X':
      uint_arg_or_die(&co_image_comps, "img-num-components");
      break;

    case 'R':
      uint_arg_or_die(&co_image_nr, "img-num-rows");
      break;

    case 'w':
      co_nowarn = 1;
      break;

    case 'N':
      co_base_son_on_output = 1;
      break;

    case 'n':
      co_sequential_output_name = strdup(optarg);
      break;

    case 'u':
      co_allow_unsafe_names = 1;
      break;

    case 'o':
      co_primary_filename = strdup(optarg);
      break;

    case 't':
      co_timing_statistics = 1;
      break;

    case 'v':
      ++co_verbosity;
      break;

    case 'Z':
      co_zero_frames = 1;
      break;

    case 'a':
      uint_arg_or_die(&co_begin, "begin");
      break;

    case 'z':
      uint_arg_or_die(&co_end, "end");
      break;

    case 's':
      uint_arg_or_die(&co_stride, "stride");
      break;

    default:
      fprintf(stderr, "%s: FATAL: Unknown \"known\" option: %c\n",
              co_this, (char)opt);
      exit(255);
    }
  }

  /* Validate options */
  if (!(co_is_decoding ^ co_is_encoding)) {
    l_error("Exactly one of --encode or --decode must be specified.");
    return 255;
  }

  if (co_is_encoding &&
      (co_image_nc || co_image_nr || co_image_bw || co_image_bh ||
       co_image_off || co_image_comps) &&
      !(co_image_nc && co_image_nr && co_image_bw && co_image_bh)) {
    l_error("Either no image options, or at least --img-num-cols,\n"
            "--img-num-rows, --img-block-width, and --img-block-height\n"
            "must be specified.");
    return 255;
  }

  if (co_image_nc && !co_image_comps)
    co_image_comps = 1;

  /* Validate the format string, if given */
  if (co_sequential_output_name) {
    has_consumed_fmt_input = 0;
    for (i = 0; co_sequential_output_name[i]; ++i) {
      if (co_sequential_output_name[i] == '%') {
        ++i;
        if (co_sequential_output_name[i] == '%')
          /* Simple escaped percent sign */
          continue;

        if (has_consumed_fmt_input) {
          l_error("Format string has more than one consuming formatting.");
          return 255;
        }

        has_consumed_fmt_input = 1;

        /* Flags */
        while (co_sequential_output_name[i] == '#' ||
               co_sequential_output_name[i] == '0' ||
               co_sequential_output_name[i] == '-' ||
               co_sequential_output_name[i] == ' ' ||
               co_sequential_output_name[i] == '+')
          ++i;
        /* Width */
        while (co_sequential_output_name[i] >= '0' &&
               co_sequential_output_name[i] <= '9')
          ++i;

        /* Type */
        if (co_sequential_output_name[i] != 'd' &&
            co_sequential_output_name[i] != 'i' &&
            co_sequential_output_name[i] != 'o' &&
            co_sequential_output_name[i] != 'u' &&
            co_sequential_output_name[i] != 'x' &&
            co_sequential_output_name[i] != 'X') {
          l_error("Invalid format string type.");
          return 255;
        }
      }
    }

    if (!has_consumed_fmt_input) {
      l_error("Format string is not variant.");
      return 255;
    }
  }

  if (co_is_encoding && !co_force && !co_primary_filename) {
    l_error("Not implicitly encoding to standard output without --force");
    return 255;
  }

  if (co_image_bh && co_image_nr && co_image_nr % co_image_bh) {
    l_warn("img-block-height does not divide evenly into img-num-rows.");
    l_warn("Actual block height will differ from what you specfied.");
  }
  if (co_image_bw && co_image_nc && co_image_nc % co_image_bw) {
    l_warn("img-block-width does not divide evenly into img-num-cols.");
    l_warn("Actual block height will differ from what you specified.");
  }

  if (co_dryrun && co_is_encoding) {
    l_report("Changing output file to /dev/null to perform dry-run.");
    co_primary_filename = "/dev/null";
  }

  if (co_is_encoding) {
    co_num_encoding_input_files = optind <= argc? argc - optind : 0;
    /* Cast is safe, we won't be modifying anything.
     * (char*const* -> const char*const* is technically "incompatible")
     */
    co_encoding_input_files = (const char*const*)argv+optind;
    if (!co_num_encoding_input_files) {
      l_error("No encoding input files given.");
      return 255;
    }

    return do_encode();
  } else {
    if (optind >= argc) {
      co_primary_filename = "-";
      if (!co_force)
        l_warn("Decoding from standard input.");
    } else if (argc - optind == 1) {
      co_primary_filename = argv[optind];
    } else {
      l_error("Too many input files.");
      return 255;
    }

    return do_decode();
  }
}
Example #2
0
static int do_encode(void) {
  FILE* file = 0, *infile = 0;
  drachen_encoder* enc = NULL;
  struct stat statbuf;
  uint32_t frame_size, amt_read;
  uint32_t* custom_xform = NULL;
  unsigned char* buffer = NULL;
  int status = 0;
  unsigned i;
  clock_t enc_start, enc_end, total_time = 0;
  unsigned long long total_data;
  unsigned data_suffix = 0;
  drachen_block_spec custom_blocks[2];

  if (!co_primary_filename || !strcmp(co_primary_filename, "-"))
    file = stdin;
  else
    file = fopen(co_primary_filename,
                 /* Only allow overwriting if forced, or if writing to the
                  * bitbucket.
                  */
                 co_force || !strcmp(co_primary_filename, "/dev/null")?
                 "wb" : "wbx");

  if (!file) {
    l_sysferr("Could not open output file", co_primary_filename);
    if (errno == EEXIST)
      fprintf(stderr, "Use --force to overwrite it anyway.\n");
    status = 254;
    goto finish;
  }

  /* Get the frame size from the first file */
  if (stat(co_encoding_input_files[0], &statbuf)) {
    l_sysferr("Could not stat first input file", co_encoding_input_files[0]);
    status = 254;
    goto finish;
  }

  if (!statbuf.st_size) {
    l_error("First file appears to be empty (size==0), giving up.");
    status = 254;
    goto finish;
  }

  frame_size = statbuf.st_size;

  l_reportf("Using frame size of %u bytes.\n", (unsigned)frame_size);

  if (co_image_bw) {
    if (frame_size < co_image_off + co_image_comps*co_image_nr*co_image_nc) {
      l_error("Frames are too small for the image parameters you specified.");
      status = 255;
      goto finish;
    }

    if (frame_size > co_image_nc + co_image_comps*co_image_nr*co_image_nc)
      l_warn("Frame size is larger than the space used by the image parms.");

    custom_xform = malloc(sizeof(uint32_t)*frame_size);
    if (!custom_xform) {
      l_syserr("Could not allocate image transform buffer");
      status = 254;
      goto finish;
    }

    /* Initialise the whole thing first in case the image doesn't cover the
     * whole thing.
     */
    for (i = 0; i < frame_size; ++i)
      custom_xform[i] = i;

    drachen_make_image_xform_matrix(custom_xform,
                                    co_image_off,
                                    co_image_nc,
                                    co_image_nr,
                                    co_image_comps,
                                    co_image_bw,
                                    co_image_bh);
  }

  buffer = malloc(frame_size);
  if (!buffer) {
    l_syserr("Could not allocate input buffer");
    status = 254;
    goto finish;
  }

  enc = drachen_create_encoder(file, frame_size, custom_xform);
  if (!enc) {
    l_syserr("Could not allocate encoder");
    status = 254;
    goto finish;
  }

  if (co_block_size) {
    custom_blocks[0].segment_end = 0xFFFFFFFFu;
    custom_blocks[0].block_size = co_block_size;
    drachen_set_block_size(enc, custom_blocks);
  } else if (co_image_bh) {
    if (co_image_off) {
      custom_blocks[0].segment_end = co_image_off;
      custom_blocks[0].block_size = co_image_off;
      custom_blocks[1].segment_end = 0xFFFFFFFFu;
      custom_blocks[1].block_size = co_image_bw/4;
      if (custom_blocks[1].block_size < 16)
        custom_blocks[1].block_size = co_image_bw;
    } else {
      custom_blocks[0].segment_end = 0xFFFFFFFFu;
      custom_blocks[0].block_size = co_image_bw/4;
      if (custom_blocks[0].block_size < 16)
        custom_blocks[0].block_size = co_image_bw;
    }

    drachen_set_block_size(enc, custom_blocks);
  }

  for (i = 0; i < co_num_encoding_input_files; ++i) {
    l_report(co_encoding_input_files[i]);

    infile = fopen(co_encoding_input_files[i], "rb");
    if (!infile) {
      l_sysferr("Could not open input file", co_encoding_input_files[i]);
      status = 254;
      goto finish;
    }

    amt_read = fread(buffer, 1, frame_size, infile);
    if (ferror(infile)) {
      l_sysferr("Could not read from input file", co_encoding_input_files[i]);
      status = 254;
      goto finish;
    }

    if (EOF != fgetc(infile)) {
      l_warns("File is longer than frame size; it will be truncated",
              co_encoding_input_files[i]);
    }

    fclose(infile);
    infile = NULL;

    if (amt_read < frame_size) {
      l_warns("File is shorter than frame size; other bytes assumed zero.",
              co_encoding_input_files[i]);
      memset(buffer+amt_read, 0, frame_size-amt_read);
    }

    enc_start = clock();
    status = drachen_encode(enc, buffer, co_encoding_input_files[i]);
    enc_end = clock();

    if (status) {
      l_errore(co_encoding_input_files[i], enc);
      goto finish;
    }

    total_time += enc_end - enc_start;

    if (co_timing_statistics)
      l_report_extraf("File %s encoded in %u ms\n",
                      co_encoding_input_files[i],
                      (unsigned)((enc_end-enc_start)*1000/CLOCKS_PER_SEC));
  }

  /* If timing statistics were requested, print them */
  if (co_timing_statistics) {
    if (total_time == 0)
      total_time = 1;

    fprintf(stderr, "Encoding rate:\n");
    fprintf(stderr, "  Frames/ms:  %u\n",
            (unsigned)(((unsigned long long)co_num_encoding_input_files) *
                       CLOCKS_PER_SEC / 1000 / total_time));
    fprintf(stderr, "  Frames/sec: %u\n",
            (unsigned)(((unsigned long long)co_num_encoding_input_files) *
                       CLOCKS_PER_SEC / total_time));
    fprintf(stderr, "  Frames/min: %u\n",
            (unsigned)(((unsigned long long)co_num_encoding_input_files) *
                       60 * CLOCKS_PER_SEC / total_time));

    total_data = co_num_encoding_input_files;
    total_data *= frame_size;
    total_data *= CLOCKS_PER_SEC;
    total_data /= total_time;
    while (total_data > 1024*1024) {
      total_data /= 1024;
      ++data_suffix;
    }

    fprintf(stderr, "  Data rate:  %u %s/sec\n",
            (unsigned)total_data, data_suffices[data_suffix]);
  }

  finish:
  if (infile) fclose(infile);
  if (buffer) free(buffer);
  if (custom_xform) free(custom_xform);
  if (enc) {
    drachen_free(enc);
    file = NULL;
  }
  if (file) fclose(file);

  return status;
}
Example #3
0
// Find the matching plugin structure for the section name `section`. If no
// such section exists, a new one is allocated and returned. If the section
// name matches the special name "Global", it is added to the appropriate list.
//
// Returns true on success, false on failure.
static bool find_plugin_section(struct registry *registry,
                                const char *section,
                                struct plugin **plugin)
{
    struct plugin *current;

    // Check if this is the special "Global" section used to specify default
    // parameters and other special values.
    if (strcmp(section, "Global") == 0) {

        // If this is the first value from the Global section, we need to
        // create it.
        if (registry->global == NULL) {

            // Allocate a new structure.
            if ((*plugin = calloc(1, sizeof(**plugin))) == NULL) {
                l_error("memory allocation failure");
                return false;
            }

            // Install as the global plugin.
            registry->global            = *plugin;
            registry->global->section   = strdup(section);
        }

        // Return pointer to parent.
        *plugin = registry->global;

        // Success.
        return !! registry->global->section;
    } else {
        // This is not the Global section, a regular plugin section.
        current = registry->plugins;

        for (current = registry->plugins; current; current = current->next) {
            // Search to see if we already recognise this section.
            if (strcmp(current->section, section) == 0) {
                // Match found.
                *plugin = current;

                return true;
            }
        }
    }

    // This is the first time we've seen this section, we have to set it up.
    l_debug("new plugin section %s discovered", section);

    // Allocate a new structure.
    if ((*plugin = calloc(1, sizeof(**plugin))) == NULL) {
        l_error("memory allocation failure");
        return false;
    }

    // Check if we have any other plugins registered.
    if (registry->plugins != NULL) {

        // Find the tail of the plugin registry.
        for (current = registry->plugins; current->next; current = current->next)
            ;

        // Add to the list.
        current->next = *plugin;
        current = current->next;
        current->section = strdup(section);
    } else {
        // This is the first plugin structure we've seen, create the list head.
        registry->plugins = *plugin;
        registry->plugins->section = strdup(section);
        current = registry->plugins;
    }

    // Success.
    return !! current->section;
}