Beispiel #1
0
bool
read_files (struct file_data filevec[], bool pretend_binary)
{
  int i;
  bool skip_test = text | pretend_binary;
  bool appears_binary = pretend_binary | sip (&filevec[0], skip_test);

  if (filevec[0].desc != filevec[1].desc)
    appears_binary |= sip (&filevec[1], skip_test | appears_binary);
  else
    {
      filevec[1].buffer = filevec[0].buffer;
      filevec[1].bufsize = filevec[0].bufsize;
      filevec[1].buffered = filevec[0].buffered;
    }
  if (appears_binary)
    {
      set_binary_mode (filevec[0].desc, true);
      set_binary_mode (filevec[1].desc, true);
      return true;
    }

  find_identical_ends (filevec);

  equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1;
  if (PTRDIFF_MAX / sizeof *equivs <= equivs_alloc)
    xalloc_die ();
  equivs = xmalloc (equivs_alloc * sizeof *equivs);
  /* Equivalence class 0 is permanently safe for lines that were not
     hashed.  Real equivalence classes start at 1.  */
  equivs_index = 1;

  /* Allocate (one plus) a prime number of hash buckets.  Use a prime
     number between 1/3 and 2/3 of the value of equiv_allocs,
     approximately.  */
  for (i = 9; (size_t) 1 << i < equivs_alloc / 3; i++)
    continue;
  nbuckets = ((size_t) 1 << i) - prime_offset[i];
  if (PTRDIFF_MAX / sizeof *buckets <= nbuckets)
    xalloc_die ();
  buckets = zalloc ((nbuckets + 1) * sizeof *buckets);
  buckets++;

  for (i = 0; i < 2; i++)
    find_and_hash_each_line (&filevec[i]);

  filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;

  free (equivs);
  free (buckets - 1);

  return false;
}
Beispiel #2
0
static bool
sip (struct file_data *current, bool skip_test)
{
  /* If we have a nonexistent file at this stage, treat it as empty.  */
  if (current->desc < 0)
    {
      /* Leave room for a sentinel.  */
      current->bufsize = sizeof (word);
      current->buffer = xmalloc (current->bufsize);
    }
  else
    {
      current->bufsize = buffer_lcm (sizeof (word),
				     STAT_BLOCKSIZE (current->stat),
				     PTRDIFF_MAX - 2 * sizeof (word));
      current->buffer = xmalloc (current->bufsize);

#ifdef __KLIBC__
      /* Skip test if seek is not possible */
      skip_test = skip_test
		  || (lseek (current->desc, 0, SEEK_CUR) < 0
		      && errno == ESPIPE);
#endif

      if (! skip_test)
	{
	  /* Check first part of file to see if it's a binary file.  */

	  int prev_mode = set_binary_mode (current->desc, O_BINARY);
	  off_t buffered;
	  file_block_read (current, current->bufsize);
	  buffered = current->buffered;

	  if (prev_mode != O_BINARY)
	    {
	      /* Revert to text mode and seek back to the start to reread
		 the file.  Use relative seek, since file descriptors
		 like stdin might not start at offset zero.  */
	      if (lseek (current->desc, - buffered, SEEK_CUR) < 0)
		pfatal_with_name (current->name);
	      set_binary_mode (current->desc, prev_mode);
	      current->buffered = 0;
	      current->eof = false;
	    }

	  return binary_file_p (current->buffer, buffered);
	}
    }

  current->buffered = 0;
  current->eof = false;
  return false;
}
Beispiel #3
0
static bool
sip (struct file_data *current, bool skip_test)
{
  /* If we have a nonexistent file at this stage, treat it as empty.  */
  if (current->desc < 0)
    {
      /* Leave room for a sentinel.  */
      current->bufsize = sizeof (word);
      current->buffer = xmalloc (current->bufsize);
    }
  else
    {
      current->bufsize = buffer_lcm (sizeof (word),
				     STAT_BLOCKSIZE (current->stat),
				     PTRDIFF_MAX - 2 * sizeof (word));
      current->buffer = xmalloc (current->bufsize);

      if (! skip_test)
	{
	  /* Check first part of file to see if it's a binary file.  */

	  bool was_binary = set_binary_mode (current->desc, true);
	  off_t buffered;
	  file_block_read (current, current->bufsize);
	  buffered = current->buffered;

	  if (! was_binary)
	    {
	      /* Revert to text mode and seek back to the beginning to
		 reread the file.  Use relative seek, since file
		 descriptors like stdin might not start at offset
		 zero.  */

	      if (lseek (current->desc, - buffered, SEEK_CUR) == -1)
		pfatal_with_name (current->name);
	      set_binary_mode (current->desc, false);
	      current->buffered = 0;
	      current->eof = false;
	    }

	  return binary_file_p (current->buffer, buffered);
	}
    }

  current->buffered = 0;
  current->eof = false;
  return false;
}
pngquant_error read_image(const char *filename, int using_stdin, read_info *input_image_p)
{
    FILE *infile;

    if (using_stdin) {
        set_binary_mode(stdin);
        infile = stdin;
    } else if ((infile = fopen(filename, "rb")) == NULL) {
        fprintf(stderr, "  error:  cannot open %s for reading\n", filename);
        return READ_ERROR;
    }

    /*
     ** Step 1: read in the alpha-channel image.
     */
    /* GRR:  returns RGBA (4 channels), 8 bps */
    pngquant_error retval = rwpng_read_image(infile, input_image_p);

    if (!using_stdin)
        fclose(infile);

    if (retval) {
        fprintf(stderr, "  rwpng_read_image() error\n");
        return retval;
    }

    return SUCCESS;
}
Beispiel #5
0
static FILE *open_outfile(const char *name) {
  if (strcmp("-", name) == 0) {
    set_binary_mode(stdout);
    return stdout;
  } else {
    FILE *file = fopen(name, "wb");
    if (!file) fatal("Failed to open output file '%s'", name);
    return file;
  }
}
Beispiel #6
0
static pngquant_error write_image(png8_image *output_image, png24_image *output_image24, const char *outname, struct pngquant_options *options)
{
    FILE *outfile;
    if (options->using_stdin) {
        set_binary_mode(stdout);
        outfile = stdout;

        if (output_image) {
            verbose_printf(options, "  writing %d-color image to stdout", output_image->num_palette);
        } else {
            verbose_printf(options, "  writing truecolor image to stdout");
        }
    } else {

        if ((outfile = fopen(outname, "wb")) == NULL) {
            fprintf(stderr, "  error:  cannot open %s for writing\n", outname);
            return CANT_WRITE_ERROR;
        }

        const char *outfilename = strrchr(outname, '/');
        if (outfilename) {
            outfilename++;
        } else {
            outfilename = outname;
        }

        if (output_image) {
            verbose_printf(options, "  writing %d-color image as %s", output_image->num_palette, outfilename);
        } else {
            verbose_printf(options, "  writing truecolor image as %s", outfilename);
        }
    }

    pngquant_error retval;
    #pragma omp critical (libpng)
    {
        if (output_image) {
            retval = rwpng_write_image8(outfile, output_image);
        } else {
            retval = rwpng_write_image24(outfile, output_image24);
        }
    }

    if (retval && retval != TOO_LARGE_FILE) {
        fprintf(stderr, "  error: failed writing image to %s\n", outname);
    }

    if (!options->using_stdin) {
        fclose(outfile);
    }

    return retval;
}
Beispiel #7
0
void
Geomview_stream::pickplane(const Bbox_3 &bbox)
{
    bool bin_bak = set_binary_mode();
    (*this) << "(geometry pickplane {QUAD BINARY\n"
            << 1
    // here are the four corners
            << bbox.xmin() << bbox.ymin() << bbox.zmin()
            << bbox.xmin() << bbox.ymax() << bbox.zmin()
            << bbox.xmax() << bbox.ymax() << bbox.zmin()
            << bbox.xmax() << bbox.ymin() << bbox.zmin()

    // close the text bracket
            << "}) (pickable pickplane no)";
    set_ascii_mode(bin_bak);
}
Beispiel #8
0
static pngquant_error read_image(liq_attr *options, const char *filename, int using_stdin, png24_image *input_image_p, liq_image **liq_image_p, bool keep_input_pixels, bool verbose)
{
    FILE *infile;

    if (using_stdin) {
        set_binary_mode(stdin);
        infile = stdin;
    } else if ((infile = fopen(filename, "rb")) == NULL) {
        fprintf(stderr, "  error: cannot open %s for reading\n", filename);
        return READ_ERROR;
    }

    pngquant_error retval;
    #pragma omp critical (libpng)
    {
        retval = rwpng_read_image24(infile, input_image_p, verbose);
    }

    if (!using_stdin) {
        fclose(infile);
    }

    if (retval) {
        fprintf(stderr, "  error: cannot decode image %s\n", using_stdin ? "from stdin" : filename_part(filename));
        return retval;
    }

    *liq_image_p = liq_image_create_rgba_rows(options, (void**)input_image_p->row_pointers, input_image_p->width, input_image_p->height, input_image_p->gamma);

    if (!*liq_image_p) {
        return OUT_OF_MEMORY_ERROR;
    }

    if (!keep_input_pixels) {
        if (LIQ_OK != liq_image_set_memory_ownership(*liq_image_p, LIQ_OWN_ROWS | LIQ_OWN_PIXELS)) {
            return OUT_OF_MEMORY_ERROR;
        }
        input_image_p->row_pointers = NULL;
        input_image_p->rgba_data = NULL;
    }

    return SUCCESS;
}
pngquant_error write_image(write_info *output_image,const char *filename,const char *newext,int force,int using_stdin)
{
    FILE *outfile;
    if (using_stdin) {
        set_binary_mode(stdout);
        outfile = stdout;
    } else {
        char *outname = add_filename_extension(filename,newext);

        if (!force) {
            if ((outfile = fopen(outname, "rb")) != NULL) {
                fprintf(stderr, "  error:  %s exists; not overwriting\n", outname);
                fclose(outfile);
                free(outname);
                return NOT_OVERWRITING_ERROR;
            }
        }
        if ((outfile = fopen(outname, "wb")) == NULL) {
            fprintf(stderr, "  error:  cannot open %s for writing\n", outname);
            free(outname);
            return CANT_WRITE_ERROR;
        }
        free(outname);
    }

    pngquant_error retval = rwpng_write_image_init(outfile, output_image);
    if (retval) {
        fprintf(stderr, "  rwpng_write_image_init() error\n");
        if (!using_stdin)
            fclose(outfile);
        return retval;
    }

    /* write entire interlaced palette PNG */
    retval = rwpng_write_image_whole(output_image);

    if (!using_stdin)
        fclose(outfile);

    /* now we're done with the OUTPUT data and row_pointers, too */
    return retval;
}
void *out_open(const char *out_fn, int do_md5) {
  void *out = NULL;

  if (do_md5) {
#if CONFIG_MD5
    MD5Context *md5_ctx = out = malloc(sizeof(MD5Context));
    (void)out_fn;
    MD5Init(md5_ctx);
#endif
  } else {
    FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb")
                          : set_binary_mode(stdout);

    if (!outfile) {
      fprintf(stderr, "Failed to output file");
      exit(EXIT_FAILURE);
    }
  }

  return out;
}
Beispiel #11
0
int
main (int argc, char *argv[])
{
  /* Test the O_BINARY macro.  */
  {
    int fd =
      open ("t-bin-out0.tmp", O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0600);
    if (write (fd, "Hello\n", 6) < 0)
      exit (1);
    close (fd);
  }
  {
    struct stat statbuf;
    if (stat ("t-bin-out0.tmp", &statbuf) < 0)
      exit (1);
    ASSERT (statbuf.st_size == 6);
  }

  switch (argv[1][0])
    {
    case '1':
      /* Test the set_binary_mode() function.  */
      set_binary_mode (1, O_BINARY);
      fputs ("Hello\n", stdout);
      break;

    case '2':
      /* Test the SET_BINARY macro.  */
      SET_BINARY (1);
      fputs ("Hello\n", stdout);
      break;

    default:
      break;
    }

  return 0;
}
Beispiel #12
0
int
pipe2 (int fd[2], int flags)
{
  /* Mingw _pipe() corrupts fd on failure; also, if we succeed at
     creating the pipe but later fail at changing fcntl, we want
     to leave fd unchanged: http://austingroupbugs.net/view.php?id=467  */
  int tmp[2];
  tmp[0] = fd[0];
  tmp[1] = fd[1];

#if HAVE_PIPE2
# undef pipe2
  /* Try the system call first, if it exists.  (We may be running with a glibc
     that has the function but with an older kernel that lacks it.)  */
  {
    /* Cache the information whether the system call really exists.  */
    static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */
    if (have_pipe2_really >= 0)
      {
        int result = pipe2 (fd, flags);
        if (!(result < 0 && errno == ENOSYS))
          {
            have_pipe2_really = 1;
            return result;
          }
        have_pipe2_really = -1;
      }
  }
#endif

  /* Check the supported flags.  */
  if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0)
    {
      errno = EINVAL;
      return -1;
    }

#if defined _WIN32 && ! defined __CYGWIN__
/* Native Windows API.  */

  if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0)
    {
      fd[0] = tmp[0];
      fd[1] = tmp[1];
      return -1;
    }

  /* O_NONBLOCK handling.
     On native Windows platforms, O_NONBLOCK is defined by gnulib.  Use the
     functions defined by the gnulib module 'nonblocking'.  */
# if GNULIB_defined_O_NONBLOCK
  if (flags & O_NONBLOCK)
    {
      if (set_nonblocking_flag (fd[0], true) != 0
          || set_nonblocking_flag (fd[1], true) != 0)
        goto fail;
    }
# else
  {
    verify (O_NONBLOCK == 0);
  }
# endif

  return 0;

#else
/* Unix API.  */

  if (pipe (fd) < 0)
    return -1;

  /* POSIX <http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html>
     says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on
     both fd[0] and fd[1].  */

  /* O_NONBLOCK handling.
     On Unix platforms, O_NONBLOCK is defined by the system.  Use fcntl().  */
  if (flags & O_NONBLOCK)
    {
      int fcntl_flags;

      if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0
          || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1
          || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0
          || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1)
        goto fail;
    }

  if (flags & O_CLOEXEC)
    {
      int fcntl_flags;

      if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0
          || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1
          || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0
          || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
        goto fail;
    }

# if O_BINARY
  if (flags & O_BINARY)
    {
      set_binary_mode (fd[1], O_BINARY);
      set_binary_mode (fd[0], O_BINARY);
    }
  else if (flags & O_TEXT)
    {
      set_binary_mode (fd[1], O_TEXT);
      set_binary_mode (fd[0], O_TEXT);
    }
# endif

  return 0;

#endif

#if GNULIB_defined_O_NONBLOCK || !(defined _WIN32 && ! defined __CYGWIN__)
 fail:
  {
    int saved_errno = errno;
    close (fd[0]);
    close (fd[1]);
    fd[0] = tmp[0];
    fd[1] = tmp[1];
    errno = saved_errno;
    return -1;
  }
#endif
}
Beispiel #13
0
static int main_loop(int argc, const char **argv_) {
  aom_codec_ctx_t decoder;
  char *fn = NULL;
  int i;
  int ret = EXIT_FAILURE;
  uint8_t *buf = NULL;
  size_t bytes_in_buffer = 0, buffer_size = 0;
  FILE *infile;
  int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
  int do_md5 = 0, progress = 0;
  int stop_after = 0, postproc = 0, summary = 0, quiet = 1;
  int arg_skip = 0;
  int keep_going = 0;
  const AvxInterface *interface = NULL;
  const AvxInterface *fourcc_interface = NULL;
  uint64_t dx_time = 0;
  struct arg arg;
  char **argv, **argi, **argj;

  int single_file;
  int use_y4m = 1;
  int opt_yv12 = 0;
  int opt_i420 = 0;
  int opt_raw = 0;
  aom_codec_dec_cfg_t cfg = { 0, 0, 0, CONFIG_LOWBITDEPTH, { 1 } };
  unsigned int fixed_output_bit_depth = 0;
  unsigned int is_annexb = 0;
  int frames_corrupted = 0;
  int dec_flags = 0;
  int do_scale = 0;
  int operating_point = 0;
  int output_all_layers = 0;
  int skip_film_grain = 0;
  aom_image_t *scaled_img = NULL;
  aom_image_t *img_shifted = NULL;
  int frame_avail, got_data, flush_decoder = 0;
  int num_external_frame_buffers = 0;
  struct ExternalFrameBufferList ext_fb_list = { 0, NULL };

  const char *outfile_pattern = NULL;
  char outfile_name[PATH_MAX] = { 0 };
  FILE *outfile = NULL;

  FILE *framestats_file = NULL;

  MD5Context md5_ctx;
  unsigned char md5_digest[16];

  struct AvxDecInputContext input = { NULL, NULL, NULL };
  struct AvxInputContext aom_input_ctx;
  memset(&aom_input_ctx, 0, sizeof(aom_input_ctx));
#if CONFIG_WEBM_IO
  struct WebmInputContext webm_ctx;
  memset(&webm_ctx, 0, sizeof(webm_ctx));
  input.webm_ctx = &webm_ctx;
#endif
  struct ObuDecInputContext obu_ctx = { NULL, NULL, 0, 0, 0 };

  obu_ctx.avx_ctx = &aom_input_ctx;
  input.obu_ctx = &obu_ctx;
  input.aom_input_ctx = &aom_input_ctx;

  /* Parse command line */
  exec_name = argv_[0];
  argv = argv_dup(argc - 1, argv_ + 1);

  for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
    memset(&arg, 0, sizeof(arg));
    arg.argv_step = 1;

    if (arg_match(&arg, &help, argi)) {
      show_help(stdout, 0);
      exit(EXIT_SUCCESS);
    } else if (arg_match(&arg, &codecarg, argi)) {
      interface = get_aom_decoder_by_name(arg.val);
      if (!interface)
        die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
    } else if (arg_match(&arg, &looparg, argi)) {
      // no-op
    } else if (arg_match(&arg, &outputfile, argi)) {
      outfile_pattern = arg.val;
    } else if (arg_match(&arg, &use_yv12, argi)) {
      use_y4m = 0;
      flipuv = 1;
      opt_yv12 = 1;
      opt_i420 = 0;
      opt_raw = 0;
    } else if (arg_match(&arg, &use_i420, argi)) {
      use_y4m = 0;
      flipuv = 0;
      opt_yv12 = 0;
      opt_i420 = 1;
      opt_raw = 0;
    } else if (arg_match(&arg, &rawvideo, argi)) {
      use_y4m = 0;
      opt_yv12 = 0;
      opt_i420 = 0;
      opt_raw = 1;
    } else if (arg_match(&arg, &flipuvarg, argi)) {
      flipuv = 1;
    } else if (arg_match(&arg, &noblitarg, argi)) {
      noblit = 1;
    } else if (arg_match(&arg, &progressarg, argi)) {
      progress = 1;
    } else if (arg_match(&arg, &limitarg, argi)) {
      stop_after = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &skiparg, argi)) {
      arg_skip = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &postprocarg, argi)) {
      postproc = 1;
    } else if (arg_match(&arg, &md5arg, argi)) {
      do_md5 = 1;
    } else if (arg_match(&arg, &framestatsarg, argi)) {
      framestats_file = fopen(arg.val, "w");
      if (!framestats_file) {
        die("Error: Could not open --framestats file (%s) for writing.\n",
            arg.val);
      }
    } else if (arg_match(&arg, &summaryarg, argi)) {
      summary = 1;
    } else if (arg_match(&arg, &threadsarg, argi)) {
      cfg.threads = arg_parse_uint(&arg);
#if !CONFIG_MULTITHREAD
      if (cfg.threads > 1) {
        die("Error: --threads=%d is not supported when CONFIG_MULTITHREAD = "
            "0.\n",
            cfg.threads);
      }
#endif
    } else if (arg_match(&arg, &verbosearg, argi)) {
      quiet = 0;
    } else if (arg_match(&arg, &scalearg, argi)) {
      do_scale = 1;
    } else if (arg_match(&arg, &fb_arg, argi)) {
      num_external_frame_buffers = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &continuearg, argi)) {
      keep_going = 1;
    } else if (arg_match(&arg, &outbitdeptharg, argi)) {
      fixed_output_bit_depth = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &isannexb, argi)) {
      is_annexb = 1;
      input.obu_ctx->is_annexb = 1;
    } else if (arg_match(&arg, &oppointarg, argi)) {
      operating_point = arg_parse_int(&arg);
    } else if (arg_match(&arg, &outallarg, argi)) {
      output_all_layers = 1;
    } else if (arg_match(&arg, &skipfilmgrain, argi)) {
      skip_film_grain = 1;
    } else {
      argj++;
    }
  }

  /* Check for unrecognized options */
  for (argi = argv; *argi; argi++)
    if (argi[0][0] == '-' && strlen(argi[0]) > 1)
      die("Error: Unrecognized option %s\n", *argi);

  /* Handle non-option arguments */
  fn = argv[0];

  if (!fn) {
    free(argv);
    fprintf(stderr, "No input file specified!\n");
    usage_exit();
  }
  /* Open file */
  infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);

  if (!infile) {
    fatal("Failed to open input file '%s'", strcmp(fn, "-") ? fn : "stdin");
  }
#if CONFIG_OS_SUPPORT
  /* Make sure we don't dump to the terminal, unless forced to with -o - */
  if (!outfile_pattern && isatty(STDOUT_FILENO) && !do_md5 && !noblit) {
    fprintf(stderr,
            "Not dumping raw video to your terminal. Use '-o -' to "
            "override.\n");
    return EXIT_FAILURE;
  }
#endif
  input.aom_input_ctx->filename = fn;
  input.aom_input_ctx->file = infile;
  if (file_is_ivf(input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_IVF;
#if CONFIG_WEBM_IO
  else if (file_is_webm(input.webm_ctx, input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_WEBM;
#endif
  else if (file_is_obu(&obu_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_OBU;
  else if (file_is_raw(input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_RAW;
  else {
    fprintf(stderr, "Unrecognized input file type.\n");
#if !CONFIG_WEBM_IO
    fprintf(stderr, "aomdec was built without WebM container support.\n");
#endif
    return EXIT_FAILURE;
  }

  outfile_pattern = outfile_pattern ? outfile_pattern : "-";
  single_file = is_single_file(outfile_pattern);

  if (!noblit && single_file) {
    generate_filename(outfile_pattern, outfile_name, PATH_MAX,
                      aom_input_ctx.width, aom_input_ctx.height, 0);
    if (do_md5)
      MD5Init(&md5_ctx);
    else
      outfile = open_outfile(outfile_name);
  }

  if (use_y4m && !noblit) {
    if (!single_file) {
      fprintf(stderr,
              "YUV4MPEG2 not supported with output patterns,"
              " try --i420 or --yv12 or --rawvideo.\n");
      return EXIT_FAILURE;
    }

#if CONFIG_WEBM_IO
    if (aom_input_ctx.file_type == FILE_TYPE_WEBM) {
      if (webm_guess_framerate(input.webm_ctx, input.aom_input_ctx)) {
        fprintf(stderr,
                "Failed to guess framerate -- error parsing "
                "webm file?\n");
        return EXIT_FAILURE;
      }
    }
#endif
  }

  fourcc_interface = get_aom_decoder_by_fourcc(aom_input_ctx.fourcc);
  if (interface && fourcc_interface && interface != fourcc_interface)
    warn("Header indicates codec: %s\n", fourcc_interface->name);
  else
    interface = fourcc_interface;

  if (!interface) interface = get_aom_decoder_by_index(0);

  dec_flags = (postproc ? AOM_CODEC_USE_POSTPROC : 0);
  if (aom_codec_dec_init(&decoder, interface->codec_interface(), &cfg,
                         dec_flags)) {
    fprintf(stderr, "Failed to initialize decoder: %s\n",
            aom_codec_error(&decoder));
    goto fail2;
  }

  if (!quiet) fprintf(stderr, "%s\n", decoder.name);

  if (aom_codec_control(&decoder, AV1D_SET_IS_ANNEXB, is_annexb)) {
    fprintf(stderr, "Failed to set is_annexb: %s\n", aom_codec_error(&decoder));
    goto fail;
  }

  if (aom_codec_control(&decoder, AV1D_SET_OPERATING_POINT, operating_point)) {
    fprintf(stderr, "Failed to set operating_point: %s\n",
            aom_codec_error(&decoder));
    goto fail;
  }

  if (aom_codec_control(&decoder, AV1D_SET_OUTPUT_ALL_LAYERS,
                        output_all_layers)) {
    fprintf(stderr, "Failed to set output_all_layers: %s\n",
            aom_codec_error(&decoder));
    goto fail;
  }

  if (aom_codec_control(&decoder, AV1D_SET_SKIP_FILM_GRAIN, skip_film_grain)) {
    fprintf(stderr, "Failed to set skip_film_grain: %s\n",
            aom_codec_error(&decoder));
    goto fail;
  }

  if (arg_skip) fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
  while (arg_skip) {
    if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) break;
    arg_skip--;
  }

  if (num_external_frame_buffers > 0) {
    ext_fb_list.num_external_frame_buffers = num_external_frame_buffers;
    ext_fb_list.ext_fb = (struct ExternalFrameBuffer *)calloc(
        num_external_frame_buffers, sizeof(*ext_fb_list.ext_fb));
    if (aom_codec_set_frame_buffer_functions(&decoder, get_av1_frame_buffer,
                                             release_av1_frame_buffer,
                                             &ext_fb_list)) {
      fprintf(stderr, "Failed to configure external frame buffers: %s\n",
              aom_codec_error(&decoder));
      goto fail;
    }
  }

  frame_avail = 1;
  got_data = 0;

  if (framestats_file) fprintf(framestats_file, "bytes,qp\r\n");

  /* Decode file */
  while (frame_avail || got_data) {
    aom_codec_iter_t iter = NULL;
    aom_image_t *img;
    struct aom_usec_timer timer;
    int corrupted = 0;

    frame_avail = 0;
    if (!stop_after || frame_in < stop_after) {
      if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
        frame_avail = 1;
        frame_in++;

        aom_usec_timer_start(&timer);

        if (aom_codec_decode(&decoder, buf, bytes_in_buffer, NULL)) {
          const char *detail = aom_codec_error_detail(&decoder);
          warn("Failed to decode frame %d: %s", frame_in,
               aom_codec_error(&decoder));

          if (detail) warn("Additional information: %s", detail);
          if (!keep_going) goto fail;
        }

        if (framestats_file) {
          int qp;
          if (aom_codec_control(&decoder, AOMD_GET_LAST_QUANTIZER, &qp)) {
            warn("Failed AOMD_GET_LAST_QUANTIZER: %s",
                 aom_codec_error(&decoder));
            if (!keep_going) goto fail;
          }
          fprintf(framestats_file, "%d,%d\r\n", (int)bytes_in_buffer, qp);
        }

        aom_usec_timer_mark(&timer);
        dx_time += aom_usec_timer_elapsed(&timer);
      } else {
        flush_decoder = 1;
      }
    } else {
      flush_decoder = 1;
    }

    aom_usec_timer_start(&timer);

    if (flush_decoder) {
      // Flush the decoder.
      if (aom_codec_decode(&decoder, NULL, 0, NULL)) {
        warn("Failed to flush decoder: %s", aom_codec_error(&decoder));
      }
    }

    aom_usec_timer_mark(&timer);
    dx_time += aom_usec_timer_elapsed(&timer);

    got_data = 0;
    while ((img = aom_codec_get_frame(&decoder, &iter))) {
      ++frame_out;
      got_data = 1;

      if (aom_codec_control(&decoder, AOMD_GET_FRAME_CORRUPTED, &corrupted)) {
        warn("Failed AOM_GET_FRAME_CORRUPTED: %s", aom_codec_error(&decoder));
        if (!keep_going) goto fail;
      }
      frames_corrupted += corrupted;

      if (progress) show_progress(frame_in, frame_out, dx_time);

      if (!noblit) {
        const int PLANES_YUV[] = { AOM_PLANE_Y, AOM_PLANE_U, AOM_PLANE_V };
        const int PLANES_YVU[] = { AOM_PLANE_Y, AOM_PLANE_V, AOM_PLANE_U };
        const int *planes = flipuv ? PLANES_YVU : PLANES_YUV;

        if (do_scale) {
          if (frame_out == 1) {
            // If the output frames are to be scaled to a fixed display size
            // then use the width and height specified in the container. If
            // either of these is set to 0, use the display size set in the
            // first frame header. If that is unavailable, use the raw decoded
            // size of the first decoded frame.
            int render_width = aom_input_ctx.width;
            int render_height = aom_input_ctx.height;
            if (!render_width || !render_height) {
              int render_size[2];
              if (aom_codec_control(&decoder, AV1D_GET_DISPLAY_SIZE,
                                    render_size)) {
                // As last resort use size of first frame as display size.
                render_width = img->d_w;
                render_height = img->d_h;
              } else {
                render_width = render_size[0];
                render_height = render_size[1];
              }
            }
            scaled_img =
                aom_img_alloc(NULL, img->fmt, render_width, render_height, 16);
            scaled_img->bit_depth = img->bit_depth;
            scaled_img->monochrome = img->monochrome;
            scaled_img->csp = img->csp;
          }

          if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) {
#if CONFIG_LIBYUV
            libyuv_scale(img, scaled_img, kFilterBox);
            img = scaled_img;
#else
            fprintf(
                stderr,
                "Failed to scale output frame: %s.\n"
                "libyuv is required for scaling but is currently disabled.\n"
                "Be sure to specify -DCONFIG_LIBYUV=1 when running cmake.\n",
                aom_codec_error(&decoder));
            goto fail;
#endif
          }
        }
        // Default to codec bit depth if output bit depth not set
        unsigned int output_bit_depth;
        if (!fixed_output_bit_depth && single_file && !do_md5) {
          output_bit_depth = img->bit_depth;
        } else {
          output_bit_depth = fixed_output_bit_depth;
        }
        // Shift up or down if necessary
        if (output_bit_depth != 0)
          aom_shift_img(output_bit_depth, &img, &img_shifted);

        aom_input_ctx.width = img->d_w;
        aom_input_ctx.height = img->d_h;

        int num_planes = (opt_raw && img->monochrome) ? 1 : 3;
        if (single_file) {
          if (use_y4m) {
            char y4m_buf[Y4M_BUFFER_SIZE] = { 0 };
            size_t len = 0;
            if (frame_out == 1) {
              // Y4M file header
              len = y4m_write_file_header(
                  y4m_buf, sizeof(y4m_buf), aom_input_ctx.width,
                  aom_input_ctx.height, &aom_input_ctx.framerate,
                  img->monochrome, img->csp, img->fmt, img->bit_depth);
              if (img->csp == AOM_CSP_COLOCATED) {
                fprintf(stderr,
                        "Warning: Y4M lacks a colorspace for colocated "
                        "chroma. Using a placeholder.\n");
              }
              if (do_md5) {
                MD5Update(&md5_ctx, (md5byte *)y4m_buf, (unsigned int)len);
              } else {
                fputs(y4m_buf, outfile);
              }
            }

            // Y4M frame header
            len = y4m_write_frame_header(y4m_buf, sizeof(y4m_buf));
            if (do_md5) {
              MD5Update(&md5_ctx, (md5byte *)y4m_buf, (unsigned int)len);
              y4m_update_image_md5(img, planes, &md5_ctx);
            } else {
              fputs(y4m_buf, outfile);
              y4m_write_image_file(img, planes, outfile);
            }
          } else {
            if (frame_out == 1) {
              // Check if --yv12 or --i420 options are consistent with the
              // bit-stream decoded
              if (opt_i420) {
                if (img->fmt != AOM_IMG_FMT_I420 &&
                    img->fmt != AOM_IMG_FMT_I42016) {
                  fprintf(stderr,
                          "Cannot produce i420 output for bit-stream.\n");
                  goto fail;
                }
              }
              if (opt_yv12) {
                if ((img->fmt != AOM_IMG_FMT_I420 &&
                     img->fmt != AOM_IMG_FMT_YV12) ||
                    img->bit_depth != 8) {
                  fprintf(stderr,
                          "Cannot produce yv12 output for bit-stream.\n");
                  goto fail;
                }
              }
            }
            if (do_md5) {
              raw_update_image_md5(img, planes, num_planes, &md5_ctx);
            } else {
              raw_write_image_file(img, planes, num_planes, outfile);
            }
          }
        } else {
          generate_filename(outfile_pattern, outfile_name, PATH_MAX, img->d_w,
                            img->d_h, frame_in);
          if (do_md5) {
            MD5Init(&md5_ctx);
            if (use_y4m) {
              y4m_update_image_md5(img, planes, &md5_ctx);
            } else {
              raw_update_image_md5(img, planes, num_planes, &md5_ctx);
            }
            MD5Final(md5_digest, &md5_ctx);
            print_md5(md5_digest, outfile_name);
          } else {
            outfile = open_outfile(outfile_name);
            if (use_y4m) {
              y4m_write_image_file(img, planes, outfile);
            } else {
              raw_write_image_file(img, planes, num_planes, outfile);
            }
            fclose(outfile);
          }
        }
      }
    }
  }

  if (summary || progress) {
    show_progress(frame_in, frame_out, dx_time);
    fprintf(stderr, "\n");
  }

  if (frames_corrupted) {
    fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted);
  } else {
    ret = EXIT_SUCCESS;
  }

fail:

  if (aom_codec_destroy(&decoder)) {
    fprintf(stderr, "Failed to destroy decoder: %s\n",
            aom_codec_error(&decoder));
  }

fail2:

  if (!noblit && single_file) {
    if (do_md5) {
      MD5Final(md5_digest, &md5_ctx);
      print_md5(md5_digest, outfile_name);
    } else {
      fclose(outfile);
    }
  }

#if CONFIG_WEBM_IO
  if (input.aom_input_ctx->file_type == FILE_TYPE_WEBM)
    webm_free(input.webm_ctx);
#endif
  if (input.aom_input_ctx->file_type == FILE_TYPE_OBU)
    obudec_free(input.obu_ctx);

  if (input.aom_input_ctx->file_type != FILE_TYPE_WEBM) free(buf);

  if (scaled_img) aom_img_free(scaled_img);
  if (img_shifted) aom_img_free(img_shifted);

  for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) {
    free(ext_fb_list.ext_fb[i].data);
  }
  free(ext_fb_list.ext_fb);

  fclose(infile);
  if (framestats_file) fclose(framestats_file);

  free(argv);

  return ret;
}
Beispiel #14
0
int main_loop(int argc, const char **argv_) {
  vpx_codec_ctx_t       decoder;
  char                  *fn = NULL;
  int                    i;
  uint8_t               *buf = NULL;
  size_t                 bytes_in_buffer = 0, buffer_size = 0;
  FILE                  *infile;
  int                    frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
  int                    do_md5 = 0, progress = 0;
  int                    stop_after = 0, postproc = 0, summary = 0, quiet = 1;
  int                    arg_skip = 0;
  int                    ec_enabled = 0;
  const VpxInterface *interface = NULL;
  const VpxInterface *fourcc_interface = NULL;
  uint64_t dx_time = 0;
  struct arg               arg;
  char                   **argv, **argi, **argj;

  int                     single_file;
  int                     use_y4m = 1;
  vpx_codec_dec_cfg_t     cfg = {0};
#if CONFIG_VP8_DECODER
  vp8_postproc_cfg_t      vp8_pp_cfg = {0};
  int                     vp8_dbg_color_ref_frame = 0;
  int                     vp8_dbg_color_mb_modes = 0;
  int                     vp8_dbg_color_b_modes = 0;
  int                     vp8_dbg_display_mv = 0;
#endif
  int                     frames_corrupted = 0;
  int                     dec_flags = 0;
  int                     do_scale = 0;
  vpx_image_t             *scaled_img = NULL;
  int                     frame_avail, got_data;
  int                     num_external_frame_buffers = 0;
  struct ExternalFrameBufferList ext_fb_list = {0};

  const char *outfile_pattern = NULL;
  char outfile_name[PATH_MAX] = {0};
  FILE *outfile = NULL;

  MD5Context md5_ctx;
  unsigned char md5_digest[16];

  struct VpxDecInputContext input = {0};
  struct VpxInputContext vpx_input_ctx = {0};
  struct WebmInputContext webm_ctx = {0};
  input.vpx_input_ctx = &vpx_input_ctx;
  input.webm_ctx = &webm_ctx;

  /* Parse command line */
  exec_name = argv_[0];
  argv = argv_dup(argc - 1, argv_ + 1);

  for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
    memset(&arg, 0, sizeof(arg));
    arg.argv_step = 1;

    if (arg_match(&arg, &codecarg, argi)) {
      interface = get_vpx_decoder_by_name(arg.val);
      if (!interface)
        die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
    } else if (arg_match(&arg, &looparg, argi)) {
      // no-op
    } else if (arg_match(&arg, &outputfile, argi))
      outfile_pattern = arg.val;
    else if (arg_match(&arg, &use_yv12, argi)) {
      use_y4m = 0;
      flipuv = 1;
    } else if (arg_match(&arg, &use_i420, argi)) {
      use_y4m = 0;
      flipuv = 0;
    } else if (arg_match(&arg, &flipuvarg, argi))
      flipuv = 1;
    else if (arg_match(&arg, &noblitarg, argi))
      noblit = 1;
    else if (arg_match(&arg, &progressarg, argi))
      progress = 1;
    else if (arg_match(&arg, &limitarg, argi))
      stop_after = arg_parse_uint(&arg);
    else if (arg_match(&arg, &skiparg, argi))
      arg_skip = arg_parse_uint(&arg);
    else if (arg_match(&arg, &postprocarg, argi))
      postproc = 1;
    else if (arg_match(&arg, &md5arg, argi))
      do_md5 = 1;
    else if (arg_match(&arg, &summaryarg, argi))
      summary = 1;
    else if (arg_match(&arg, &threadsarg, argi))
      cfg.threads = arg_parse_uint(&arg);
    else if (arg_match(&arg, &verbosearg, argi))
      quiet = 0;
    else if (arg_match(&arg, &scalearg, argi))
      do_scale = 1;
    else if (arg_match(&arg, &fb_arg, argi))
      num_external_frame_buffers = arg_parse_uint(&arg);

#if CONFIG_VP8_DECODER
    else if (arg_match(&arg, &addnoise_level, argi)) {
      postproc = 1;
      vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
      vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &demacroblock_level, argi)) {
      postproc = 1;
      vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
      vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &deblock, argi)) {
      postproc = 1;
      vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
    } else if (arg_match(&arg, &mfqe, argi)) {
      postproc = 1;
      vp8_pp_cfg.post_proc_flag |= VP8_MFQE;
    } else if (arg_match(&arg, &pp_debug_info, argi)) {
      unsigned int level = arg_parse_uint(&arg);

      postproc = 1;
      vp8_pp_cfg.post_proc_flag &= ~0x7;

      if (level)
        vp8_pp_cfg.post_proc_flag |= level;
    } else if (arg_match(&arg, &pp_disp_ref_frame, argi)) {
      unsigned int flags = arg_parse_int(&arg);
      if (flags) {
        postproc = 1;
        vp8_dbg_color_ref_frame = flags;
      }
    } else if (arg_match(&arg, &pp_disp_mb_modes, argi)) {
      unsigned int flags = arg_parse_int(&arg);
      if (flags) {
        postproc = 1;
        vp8_dbg_color_mb_modes = flags;
      }
    } else if (arg_match(&arg, &pp_disp_b_modes, argi)) {
      unsigned int flags = arg_parse_int(&arg);
      if (flags) {
        postproc = 1;
        vp8_dbg_color_b_modes = flags;
      }
    } else if (arg_match(&arg, &pp_disp_mvs, argi)) {
      unsigned int flags = arg_parse_int(&arg);
      if (flags) {
        postproc = 1;
        vp8_dbg_display_mv = flags;
      }
    } else if (arg_match(&arg, &error_concealment, argi)) {
      ec_enabled = 1;
    }

#endif
    else
      argj++;
  }

  /* Check for unrecognized options */
  for (argi = argv; *argi; argi++)
    if (argi[0][0] == '-' && strlen(argi[0]) > 1)
      die("Error: Unrecognized option %s\n", *argi);

  /* Handle non-option arguments */
  fn = argv[0];

  if (!fn)
    usage_exit();

  /* Open file */
  infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);

  if (!infile) {
    fprintf(stderr, "Failed to open file '%s'", strcmp(fn, "-") ? fn : "stdin");
    return EXIT_FAILURE;
  }
#if CONFIG_OS_SUPPORT
  /* Make sure we don't dump to the terminal, unless forced to with -o - */
  if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) {
    fprintf(stderr,
            "Not dumping raw video to your terminal. Use '-o -' to "
            "override.\n");
    return EXIT_FAILURE;
  }
#endif
  input.vpx_input_ctx->file = infile;
  if (file_is_ivf(input.vpx_input_ctx))
    input.vpx_input_ctx->file_type = FILE_TYPE_IVF;
#if CONFIG_WEBM_IO
  else if (file_is_webm(input.webm_ctx, input.vpx_input_ctx))
    input.vpx_input_ctx->file_type = FILE_TYPE_WEBM;
#endif
  else if (file_is_raw(input.vpx_input_ctx))
    input.vpx_input_ctx->file_type = FILE_TYPE_RAW;
  else {
    fprintf(stderr, "Unrecognized input file type.\n");
#if !CONFIG_WEBM_IO
    fprintf(stderr, "vpxdec was built without WebM container support.\n");
#endif
    return EXIT_FAILURE;
  }

  outfile_pattern = outfile_pattern ? outfile_pattern : "-";
  single_file = is_single_file(outfile_pattern);

  if (!noblit && single_file) {
    generate_filename(outfile_pattern, outfile_name, PATH_MAX,
                      vpx_input_ctx.width, vpx_input_ctx.height, 0);
    if (do_md5)
      MD5Init(&md5_ctx);
    else
      outfile = open_outfile(outfile_name);
  }

  if (use_y4m && !noblit) {
    if (!single_file) {
      fprintf(stderr, "YUV4MPEG2 not supported with output patterns,"
              " try --i420 or --yv12.\n");
      return EXIT_FAILURE;
    }

#if CONFIG_WEBM_IO
    if (vpx_input_ctx.file_type == FILE_TYPE_WEBM) {
      if (webm_guess_framerate(input.webm_ctx, input.vpx_input_ctx)) {
        fprintf(stderr, "Failed to guess framerate -- error parsing "
                "webm file?\n");
        return EXIT_FAILURE;
      }
    }
#endif
  }

  fourcc_interface = get_vpx_decoder_by_fourcc(vpx_input_ctx.fourcc);
  if (interface && fourcc_interface && interface != fourcc_interface)
    warn("Header indicates codec: %s\n", fourcc_interface->name);
  else
    interface = fourcc_interface;

  if (!interface)
    interface = get_vpx_decoder_by_index(0);

  dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) |
              (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0);
  if (vpx_codec_dec_init(&decoder, interface->interface(), &cfg, dec_flags)) {
    fprintf(stderr, "Failed to initialize decoder: %s\n",
            vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (!quiet)
    fprintf(stderr, "%s\n", decoder.name);

#if CONFIG_VP8_DECODER

  if (vp8_pp_cfg.post_proc_flag
      && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) {
    fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (vp8_dbg_color_ref_frame
      && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) {
    fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (vp8_dbg_color_mb_modes
      && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) {
    fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (vp8_dbg_color_b_modes
      && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) {
    fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (vp8_dbg_display_mv
      && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) {
    fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }
#endif


  if (arg_skip)
    fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
  while (arg_skip) {
    if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size))
      break;
    arg_skip--;
  }

  if (num_external_frame_buffers > 0) {
    ext_fb_list.num_external_frame_buffers = num_external_frame_buffers;
    ext_fb_list.ext_fb = (struct ExternalFrameBuffer *)calloc(
        num_external_frame_buffers, sizeof(*ext_fb_list.ext_fb));
    if (vpx_codec_set_frame_buffer_functions(
            &decoder, get_vp9_frame_buffer, release_vp9_frame_buffer,
            &ext_fb_list)) {
      fprintf(stderr, "Failed to configure external frame buffers: %s\n",
              vpx_codec_error(&decoder));
      return EXIT_FAILURE;
    }
  }

  frame_avail = 1;
  got_data = 0;

  /* Decode file */
  while (frame_avail || got_data) {
    vpx_codec_iter_t  iter = NULL;
    vpx_image_t    *img;
    struct vpx_usec_timer timer;
    int                   corrupted;

    frame_avail = 0;
    if (!stop_after || frame_in < stop_after) {
      if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
        frame_avail = 1;
        frame_in++;

        vpx_usec_timer_start(&timer);

        if (vpx_codec_decode(&decoder, buf, (unsigned int)bytes_in_buffer,
                             NULL, 0)) {
          const char *detail = vpx_codec_error_detail(&decoder);
          warn("Failed to decode frame %d: %s",
               frame_in, vpx_codec_error(&decoder));

          if (detail)
            warn("Additional information: %s", detail);
          goto fail;
        }

        vpx_usec_timer_mark(&timer);
        dx_time += vpx_usec_timer_elapsed(&timer);
      }
    }

    vpx_usec_timer_start(&timer);

    got_data = 0;
    if ((img = vpx_codec_get_frame(&decoder, &iter))) {
      ++frame_out;
      got_data = 1;
    }

    vpx_usec_timer_mark(&timer);
    dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);

    if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
      warn("Failed VP8_GET_FRAME_CORRUPTED: %s", vpx_codec_error(&decoder));
      goto fail;
    }
    frames_corrupted += corrupted;

    if (progress)
      show_progress(frame_in, frame_out, dx_time);

    if (!noblit && img) {
      const int PLANES_YUV[] = {VPX_PLANE_Y, VPX_PLANE_U, VPX_PLANE_V};
      const int PLANES_YVU[] = {VPX_PLANE_Y, VPX_PLANE_V, VPX_PLANE_U};
      const int *planes = flipuv ? PLANES_YVU : PLANES_YUV;

      if (do_scale) {
        if (frame_out == 1) {
          // If the output frames are to be scaled to a fixed display size then
          // use the width and height specified in the container. If either of
          // these is set to 0, use the display size set in the first frame
          // header. If that is unavailable, use the raw decoded size of the
          // first decoded frame.
          int display_width = vpx_input_ctx.width;
          int display_height = vpx_input_ctx.height;
          if (!display_width || !display_height) {
            int display_size[2];
            if (vpx_codec_control(&decoder, VP9D_GET_DISPLAY_SIZE,
                                  display_size)) {
              // As last resort use size of first frame as display size.
              display_width = img->d_w;
              display_height = img->d_h;
            } else {
              display_width = display_size[0];
              display_height = display_size[1];
            }
          }
          scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, display_width,
                                     display_height, 16);
        }

        if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) {
          vpx_image_scale(img, scaled_img, kFilterBox);
          img = scaled_img;
        }
      }

      if (single_file) {
        if (use_y4m) {
          char buf[Y4M_BUFFER_SIZE] = {0};
          size_t len = 0;
          if (frame_out == 1) {
            // Y4M file header
            len = y4m_write_file_header(buf, sizeof(buf),
                                        vpx_input_ctx.width,
                                        vpx_input_ctx.height,
                                        &vpx_input_ctx.framerate, img->fmt);
            if (do_md5) {
              MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
            } else {
              fputs(buf, outfile);
            }
          }

          // Y4M frame header
          len = y4m_write_frame_header(buf, sizeof(buf));
          if (do_md5) {
            MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
          } else {
            fputs(buf, outfile);
          }
        }

        if (do_md5) {
          update_image_md5(img, planes, &md5_ctx);
        } else {
          write_image_file(img, planes, outfile);
        }
      } else {
        generate_filename(outfile_pattern, outfile_name, PATH_MAX,
                          img->d_w, img->d_h, frame_in);
        if (do_md5) {
          MD5Init(&md5_ctx);
          update_image_md5(img, planes, &md5_ctx);
          MD5Final(md5_digest, &md5_ctx);
          print_md5(md5_digest, outfile_name);
        } else {
          outfile = open_outfile(outfile_name);
          write_image_file(img, planes, outfile);
          fclose(outfile);
        }
      }
    }

    if (stop_after && frame_in >= stop_after)
      break;
  }

  if (summary || progress) {
    show_progress(frame_in, frame_out, dx_time);
    fprintf(stderr, "\n");
  }

  if (frames_corrupted)
    fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted);

fail:

  if (vpx_codec_destroy(&decoder)) {
    fprintf(stderr, "Failed to destroy decoder: %s\n",
            vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (!noblit && single_file) {
    if (do_md5) {
      MD5Final(md5_digest, &md5_ctx);
      print_md5(md5_digest, outfile_name);
    } else {
      fclose(outfile);
    }
  }

#if CONFIG_WEBM_IO
  if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM)
    webm_free(input.webm_ctx);
#endif

  if (input.vpx_input_ctx->file_type != FILE_TYPE_WEBM)
    free(buf);

  if (scaled_img) vpx_img_free(scaled_img);

  for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) {
    free(ext_fb_list.ext_fb[i].data);
  }
  free(ext_fb_list.ext_fb);

  fclose(infile);
  free(argv);

  return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS;
}
int
accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
{
  int fd;

#if HAVE_ACCEPT4
# undef accept4
  /* Try the system call first, if it exists.  (We may be running with a glibc
     that has the function but with an older kernel that lacks it.)  */
  {
    /* Cache the information whether the system call really exists.  */
    static int have_accept4_really; /* 0 = unknown, 1 = yes, -1 = no */
    if (have_accept4_really >= 0)
      {
        int result = accept4 (sockfd, addr, addrlen, flags);
        if (!(result < 0 && errno == ENOSYS))
          {
            have_accept4_really = 1;
            return result;
          }
        have_accept4_really = -1;
      }
  }
#endif

  /* Check the supported flags.  */
  if ((flags & ~(SOCK_CLOEXEC | O_TEXT | O_BINARY)) != 0)
    {
      errno = EINVAL;
      return -1;
    }

  fd = accept (sockfd, addr, addrlen);
  if (fd < 0)
    return -1;

#if SOCK_CLOEXEC
# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
/* Native Windows API.  */
  if (flags & SOCK_CLOEXEC)
    {
      HANDLE curr_process = GetCurrentProcess ();
      HANDLE old_handle = (HANDLE) _get_osfhandle (fd);
      HANDLE new_handle;
      int nfd;

      if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
                            old_handle,             /* SourceHandle */
                            curr_process,           /* TargetProcessHandle */
                            (PHANDLE) &new_handle,  /* TargetHandle */
                            (DWORD) 0,              /* DesiredAccess */
                            FALSE,                  /* InheritHandle */
                            DUPLICATE_SAME_ACCESS)) /* Options */
        {
          close (fd);
          errno = EBADF; /* arbitrary */
          return -1;
        }

      /* Closing fd before allocating the new fd ensures that the new fd will
         have the minimum possible value.  */
      close (fd);
      nfd = _open_osfhandle ((intptr_t) new_handle,
                             O_NOINHERIT | (flags & (O_TEXT | O_BINARY)));
      if (nfd < 0)
        {
          CloseHandle (new_handle);
          return -1;
        }
      return nfd;
    }
# else
/* Unix API.  */
  if (flags & SOCK_CLOEXEC)
    {
      int fcntl_flags;

      if ((fcntl_flags = fcntl (fd, F_GETFD, 0)) < 0
          || fcntl (fd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
        {
          int saved_errno = errno;
          close (fd);
          errno = saved_errno;
          return -1;
        }
    }
# endif
#endif

#if O_BINARY
  if (flags & O_BINARY)
    set_binary_mode (fd, O_BINARY);
  else if (flags & O_TEXT)
    set_binary_mode (fd, O_TEXT);
#endif

  return fd;
}
Beispiel #16
0
int
main (int argc, char **argv)
{
  int i;

  progname = argv[0];

  /* If first two args are -o FILE, output to FILE.  */
  i = 1;
  if (argc > i + 1 && !strcmp (argv[i], "-o"))
    {
      if (! freopen (argv[i + 1], "w", stdout))
	{
	  perror (argv[i + 1]);
	  return EXIT_FAILURE;
	}
      i += 2;
    }
  if (argc > i + 1 && !strcmp (argv[i], "-a"))
    {
      if (! freopen (argv[i + 1], "a", stdout))
	{
	  perror (argv[i + 1]);
	  return EXIT_FAILURE;
	}
      i += 2;
    }
  if (argc > i + 1 && !strcmp (argv[i], "-d"))
    {
      if (chdir (argv[i + 1]) != 0)
	{
	  perror (argv[i + 1]);
	  return EXIT_FAILURE;
	}
      i += 2;
    }
  if (argc > i && !strcmp (argv[i], "-g"))
    {
      generate_globals = true;
      ++i;
    }

  set_binary_mode (fileno (stdout), O_BINARY);

  if (generate_globals)
    start_globals ();

  if (argc <= i)
    scan_c_stream (stdin);
  else
    {
      int first_infile = i;
      for (; i < argc; i++)
	{
	  int j;
	  /* Don't process one file twice.  */
	  for (j = first_infile; j < i; j++)
	    if (strcmp (argv[i], argv[j]) == 0)
	      break;
	  if (j == i)
	    scan_file (argv[i]);
	}
    }

  if (generate_globals)
    write_globals ();

  if (ferror (stdout) || fclose (stdout) != 0)
    fatal ("write error");

  return EXIT_SUCCESS;
}
Beispiel #17
0
int
main (int argc, char **argv)
{
  int status = EXIT_SUCCESS;
  int DEFAULT_GROUPING = 0x01;
  int group_by = DEFAULT_GROUPING;
  bool un_flag = false, iso_flag = false;
  progname = *argv++;

  /*
   ** -hex		hex dump
   ** -group-by-8-bits
   ** -group-by-16-bits
   ** -group-by-32-bits
   ** -group-by-64-bits
   ** -iso		iso character set.
   ** -un || -de	from hexl format to binary.
   ** --		End switch list.
   ** <filename>	dump filename
   ** -		(as filename == stdin)
   */

  for (; *argv && *argv[0] == '-' && (*argv)[1]; argv++)
    {
      /* A switch! */
      if (!strcmp (*argv, "--"))
	{
	  argv++;
	  break;
	}
      else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de"))
	{
	  un_flag = true;
	  set_binary_mode (fileno (stdout), O_BINARY);
	}
      else if (!strcmp (*argv, "-hex"))
	/* Hex is the default and is only base supported.  */;
      else if (!strcmp (*argv, "-iso"))
	iso_flag = true;
      else if (!strcmp (*argv, "-group-by-8-bits"))
	group_by = 0x00;
      else if (!strcmp (*argv, "-group-by-16-bits"))
	group_by = 0x01;
      else if (!strcmp (*argv, "-group-by-32-bits"))
	group_by = 0x03;
      else if (!strcmp (*argv, "-group-by-64-bits"))
	group_by = 0x07;
      else
	{
	  fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname,
		   *argv);
	  fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
	  return EXIT_FAILURE;
	}
    }

  char const *filename = *argv ? *argv++ : "-";

  do
    {
      FILE *fp;

      if (!strcmp (filename, "-"))
	{
	  fp = stdin;
	  if (!un_flag)
	    set_binary_mode (fileno (stdin), O_BINARY);
	}
      else
	{
	  fp = fopen (filename, un_flag ? "r" : "rb");
	  if (!fp)
	    {
	      perror (filename);
	      status = EXIT_FAILURE;
	      continue;
	    }
	}

      if (un_flag)
	{
	  for (int c; 0 <= (c = getc (fp)); )
	    {
	      /* Skip address at start of line.  */
	      if (c != ' ')
		continue;

	      for (int i = 0; i < 16; i++)
		{
		  c = getc (fp);
		  if (c < 0 || c == ' ')
		    break;

		  int hc = hexchar (c);
		  c = getc (fp);
		  if (c < 0)
		    break;
		  putchar (hc * 0x10 + hexchar (c));

		  if ((i & group_by) == group_by)
		    {
		      c = getc (fp);
		      if (c < 0)
			break;
		    }
		}

	      while (0 <= c && c != '\n')
		c = getc (fp);
	      if (c < 0)
		break;
	      if (ferror (stdout))
		output_error ();
	    }
	}
      else
	{
	  int c = 0;
	  char string[18];
	  string[0] = ' ';
	  string[17] = '\0';
	  for (uintmax_t address = 0; 0 <= c; address += 0x10)
	    {
	      int i;
	      for (i = 0; i < 16; i++)
		{
		  if (0 <= c)
		    c = getc (fp);
		  if (c < 0)
		    {
		      if (!i)
			break;

		      fputs ("  ", stdout);
		      string[i + 1] = '\0';
		    }
		  else
		    {
		      if (!i)
			printf ("%08"PRIxMAX": ", address);

		      string[i + 1]
			= (c < 0x20 || (0x7F <= c && (!iso_flag || c < 0xa0))
			   ? '.' : c);

		      printf ("%02x", c + 0u);
		    }

		  if ((i & group_by) == group_by)
		    putchar (' ');
		}

	      if (i)
		puts (string);

	      if (ferror (stdout))
		output_error ();
	    }
	}

      bool trouble = ferror (fp) != 0;
      trouble |= fp != stdin && fclose (fp) != 0;
      if (trouble)
	{
	  fprintf (stderr, "%s: read error\n", progname);
	  status = EXIT_FAILURE;
	}

      filename = *argv++;
    }
  while (filename);

  if (ferror (stdout) || fclose (stdout) != 0)
    output_error ();
  return status;
}
Beispiel #18
0
static pngquant_error write_image(png8_image *output_image, png24_image *output_image24, const char *outname, struct pngquant_options *options)
{
    FILE *outfile;
    char *tempname = NULL;

    if (options->using_stdout) {
        set_binary_mode(stdout);
        outfile = stdout;

        if (output_image) {
            verbose_printf(options, "  writing %d-color image to stdout", output_image->num_palette);
        } else {
            verbose_printf(options, "  writing truecolor image to stdout");
        }
    } else {
        tempname = temp_filename(outname);
        if (!tempname) return OUT_OF_MEMORY_ERROR;

        if ((outfile = fopen(tempname, "wb")) == NULL) {
            fprintf(stderr, "  error: cannot open '%s' for writing\n", tempname);
            free(tempname);
            return CANT_WRITE_ERROR;
        }

        if (output_image) {
            verbose_printf(options, "  writing %d-color image as %s", output_image->num_palette, filename_part(outname));
        } else {
            verbose_printf(options, "  writing truecolor image as %s", filename_part(outname));
        }
    }

    pngquant_error retval;
    #pragma omp critical (libpng)
    {
        if (output_image) {
            retval = rwpng_write_image8(outfile, output_image);
        } else {
            retval = rwpng_write_image24(outfile, output_image24);
        }
    }

    if (!options->using_stdout) {
        fclose(outfile);

        if (SUCCESS == retval) {
            // Image has been written to a temporary file and then moved over destination.
            // This makes replacement atomic and avoids damaging destination file on write error.
            if (!replace_file(tempname, outname, options->force)) {
                retval = CANT_WRITE_ERROR;
            }
        }

        if (retval) {
            unlink(tempname);
        }
    }
    free(tempname);

    if (retval && retval != TOO_LARGE_FILE) {
        fprintf(stderr, "  error: failed writing image to %s\n", outname);
    }

    return retval;
}
Beispiel #19
0
static int main_loop(int argc, const char **argv_) {
  aom_codec_ctx_t decoder;
  char *fn = NULL;
  int i;
  int ret = EXIT_FAILURE;
  uint8_t *buf = NULL;
  size_t bytes_in_buffer = 0, buffer_size = 0;
  FILE *infile;
  int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
  int do_md5 = 0, progress = 0, frame_parallel = 0;
  int stop_after = 0, postproc = 0, summary = 0, quiet = 1;
  int arg_skip = 0;
  int ec_enabled = 0;
  int keep_going = 0;
  const AvxInterface *interface = NULL;
  const AvxInterface *fourcc_interface = NULL;
  uint64_t dx_time = 0;
  struct arg arg;
  char **argv, **argi, **argj;

  int single_file;
  int use_y4m = 1;
  int opt_yv12 = 0;
  int opt_i420 = 0;
  aom_codec_dec_cfg_t cfg = { 0, 0, 0 };
#if CONFIG_AOM_HIGHBITDEPTH
  unsigned int output_bit_depth = 0;
#endif
#if CONFIG_EXT_TILE
  int tile_row = -1;
  int tile_col = -1;
#endif  // CONFIG_EXT_TILE
  int frames_corrupted = 0;
  int dec_flags = 0;
  int do_scale = 0;
  aom_image_t *scaled_img = NULL;
#if CONFIG_AOM_HIGHBITDEPTH
  aom_image_t *img_shifted = NULL;
#endif
  int frame_avail, got_data, flush_decoder = 0;
  int num_external_frame_buffers = 0;
  struct ExternalFrameBufferList ext_fb_list = { 0, NULL };

  const char *outfile_pattern = NULL;
  char outfile_name[PATH_MAX] = { 0 };
  FILE *outfile = NULL;

  FILE *framestats_file = NULL;

  MD5Context md5_ctx;
  unsigned char md5_digest[16];

  struct AvxDecInputContext input = { NULL, NULL };
  struct AvxInputContext aom_input_ctx;
#if CONFIG_WEBM_IO
  struct WebmInputContext webm_ctx;
  memset(&(webm_ctx), 0, sizeof(webm_ctx));
  input.webm_ctx = &webm_ctx;
#endif
  input.aom_input_ctx = &aom_input_ctx;

  /* Parse command line */
  exec_name = argv_[0];
  argv = argv_dup(argc - 1, argv_ + 1);

  for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
    memset(&arg, 0, sizeof(arg));
    arg.argv_step = 1;

    if (arg_match(&arg, &codecarg, argi)) {
      interface = get_aom_decoder_by_name(arg.val);
      if (!interface)
        die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
    } else if (arg_match(&arg, &looparg, argi)) {
      // no-op
    } else if (arg_match(&arg, &outputfile, argi)) {
      outfile_pattern = arg.val;
    } else if (arg_match(&arg, &use_yv12, argi)) {
      use_y4m = 0;
      flipuv = 1;
      opt_yv12 = 1;
    } else if (arg_match(&arg, &use_i420, argi)) {
      use_y4m = 0;
      flipuv = 0;
      opt_i420 = 1;
    } else if (arg_match(&arg, &rawvideo, argi)) {
      use_y4m = 0;
    } else if (arg_match(&arg, &flipuvarg, argi)) {
      flipuv = 1;
    } else if (arg_match(&arg, &noblitarg, argi)) {
      noblit = 1;
    } else if (arg_match(&arg, &progressarg, argi)) {
      progress = 1;
    } else if (arg_match(&arg, &limitarg, argi)) {
      stop_after = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &skiparg, argi)) {
      arg_skip = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &postprocarg, argi)) {
      postproc = 1;
    } else if (arg_match(&arg, &md5arg, argi)) {
      do_md5 = 1;
    } else if (arg_match(&arg, &framestatsarg, argi)) {
      framestats_file = fopen(arg.val, "w");
      if (!framestats_file) {
        die("Error: Could not open --framestats file (%s) for writing.\n",
            arg.val);
      }
    } else if (arg_match(&arg, &summaryarg, argi)) {
      summary = 1;
    } else if (arg_match(&arg, &threadsarg, argi)) {
      cfg.threads = arg_parse_uint(&arg);
    }
#if CONFIG_AV1_DECODER
    else if (arg_match(&arg, &frameparallelarg, argi))
      frame_parallel = 1;
#endif
    else if (arg_match(&arg, &verbosearg, argi))
      quiet = 0;
    else if (arg_match(&arg, &scalearg, argi))
      do_scale = 1;
    else if (arg_match(&arg, &fb_arg, argi))
      num_external_frame_buffers = arg_parse_uint(&arg);
    else if (arg_match(&arg, &continuearg, argi))
      keep_going = 1;
#if CONFIG_AOM_HIGHBITDEPTH
    else if (arg_match(&arg, &outbitdeptharg, argi)) {
      output_bit_depth = arg_parse_uint(&arg);
    }
#endif
#if CONFIG_EXT_TILE
    else if (arg_match(&arg, &tiler, argi))
      tile_row = arg_parse_int(&arg);
    else if (arg_match(&arg, &tilec, argi))
      tile_col = arg_parse_int(&arg);
#endif  // CONFIG_EXT_TILE
    else
      argj++;
  }

  /* Check for unrecognized options */
  for (argi = argv; *argi; argi++)
    if (argi[0][0] == '-' && strlen(argi[0]) > 1)
      die("Error: Unrecognized option %s\n", *argi);

  /* Handle non-option arguments */
  fn = argv[0];

  if (!fn) {
    free(argv);
    usage_exit();
  }
  /* Open file */
  infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);

  if (!infile) {
    fatal("Failed to open input file '%s'", strcmp(fn, "-") ? fn : "stdin");
  }
#if CONFIG_OS_SUPPORT
  /* Make sure we don't dump to the terminal, unless forced to with -o - */
  if (!outfile_pattern && isatty(STDOUT_FILENO) && !do_md5 && !noblit) {
    fprintf(stderr,
            "Not dumping raw video to your terminal. Use '-o -' to "
            "override.\n");
    return EXIT_FAILURE;
  }
#endif
  input.aom_input_ctx->file = infile;
  if (file_is_ivf(input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_IVF;
#if CONFIG_WEBM_IO
  else if (file_is_webm(input.webm_ctx, input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_WEBM;
#endif
  else if (file_is_raw(input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_RAW;
  else {
    fprintf(stderr, "Unrecognized input file type.\n");
#if !CONFIG_WEBM_IO
    fprintf(stderr, "aomdec was built without WebM container support.\n");
#endif
    return EXIT_FAILURE;
  }

  outfile_pattern = outfile_pattern ? outfile_pattern : "-";
  single_file = is_single_file(outfile_pattern);

  if (!noblit && single_file) {
    generate_filename(outfile_pattern, outfile_name, PATH_MAX,
                      aom_input_ctx.width, aom_input_ctx.height, 0);
    if (do_md5)
      MD5Init(&md5_ctx);
    else
      outfile = open_outfile(outfile_name);
  }

  if (use_y4m && !noblit) {
    if (!single_file) {
      fprintf(stderr,
              "YUV4MPEG2 not supported with output patterns,"
              " try --i420 or --yv12 or --rawvideo.\n");
      return EXIT_FAILURE;
    }

#if CONFIG_WEBM_IO
    if (aom_input_ctx.file_type == FILE_TYPE_WEBM) {
      if (webm_guess_framerate(input.webm_ctx, input.aom_input_ctx)) {
        fprintf(stderr,
                "Failed to guess framerate -- error parsing "
                "webm file?\n");
        return EXIT_FAILURE;
      }
    }
#endif
  }

  fourcc_interface = get_aom_decoder_by_fourcc(aom_input_ctx.fourcc);
  if (interface && fourcc_interface && interface != fourcc_interface)
    warn("Header indicates codec: %s\n", fourcc_interface->name);
  else
    interface = fourcc_interface;

  if (!interface) interface = get_aom_decoder_by_index(0);

  dec_flags = (postproc ? AOM_CODEC_USE_POSTPROC : 0) |
              (ec_enabled ? AOM_CODEC_USE_ERROR_CONCEALMENT : 0) |
              (frame_parallel ? AOM_CODEC_USE_FRAME_THREADING : 0);
  if (aom_codec_dec_init(&decoder, interface->codec_interface(), &cfg,
                         dec_flags)) {
    fprintf(stderr, "Failed to initialize decoder: %s\n",
            aom_codec_error(&decoder));
    goto fail2;
  }

  if (!quiet) fprintf(stderr, "%s\n", decoder.name);

#if CONFIG_AV1_DECODER && CONFIG_EXT_TILE
  if (aom_codec_control(&decoder, AV1_SET_DECODE_TILE_ROW, tile_row)) {
    fprintf(stderr, "Failed to set decode_tile_row: %s\n",
            aom_codec_error(&decoder));
    goto fail;
  }

  if (aom_codec_control(&decoder, AV1_SET_DECODE_TILE_COL, tile_col)) {
    fprintf(stderr, "Failed to set decode_tile_col: %s\n",
            aom_codec_error(&decoder));
    goto fail;
  }
#endif

  if (arg_skip) fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
  while (arg_skip) {
    if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) break;
    arg_skip--;
  }

  if (num_external_frame_buffers > 0) {
    ext_fb_list.num_external_frame_buffers = num_external_frame_buffers;
    ext_fb_list.ext_fb = (struct ExternalFrameBuffer *)calloc(
        num_external_frame_buffers, sizeof(*ext_fb_list.ext_fb));
    if (aom_codec_set_frame_buffer_functions(&decoder, get_av1_frame_buffer,
                                             release_av1_frame_buffer,
                                             &ext_fb_list)) {
      fprintf(stderr, "Failed to configure external frame buffers: %s\n",
              aom_codec_error(&decoder));
      goto fail;
    }
  }

  frame_avail = 1;
  got_data = 0;

  if (framestats_file) fprintf(framestats_file, "bytes,qp\r\n");

  /* Decode file */
  while (frame_avail || got_data) {
    aom_codec_iter_t iter = NULL;
    aom_image_t *img;
    struct aom_usec_timer timer;
    int corrupted = 0;

    frame_avail = 0;
    if (!stop_after || frame_in < stop_after) {
      if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
        frame_avail = 1;
        frame_in++;

        aom_usec_timer_start(&timer);

        if (aom_codec_decode(&decoder, buf, (unsigned int)bytes_in_buffer, NULL,
                             0)) {
          const char *detail = aom_codec_error_detail(&decoder);
          warn("Failed to decode frame %d: %s", frame_in,
               aom_codec_error(&decoder));

          if (detail) warn("Additional information: %s", detail);
          if (!keep_going) goto fail;
        }

        if (framestats_file) {
          int qp;
          if (aom_codec_control(&decoder, AOMD_GET_LAST_QUANTIZER, &qp)) {
            warn("Failed AOMD_GET_LAST_QUANTIZER: %s",
                 aom_codec_error(&decoder));
            if (!keep_going) goto fail;
          }
          fprintf(framestats_file, "%d,%d\r\n", (int)bytes_in_buffer, qp);
        }

        aom_usec_timer_mark(&timer);
        dx_time += aom_usec_timer_elapsed(&timer);
      } else {
        flush_decoder = 1;
      }
    } else {
      flush_decoder = 1;
    }

    aom_usec_timer_start(&timer);

    if (flush_decoder) {
      // Flush the decoder in frame parallel decode.
      if (aom_codec_decode(&decoder, NULL, 0, NULL, 0)) {
        warn("Failed to flush decoder: %s", aom_codec_error(&decoder));
      }
    }

    got_data = 0;
    if ((img = aom_codec_get_frame(&decoder, &iter))) {
      ++frame_out;
      got_data = 1;
    }

    aom_usec_timer_mark(&timer);
    dx_time += (unsigned int)aom_usec_timer_elapsed(&timer);

    if (!frame_parallel &&
        aom_codec_control(&decoder, AOMD_GET_FRAME_CORRUPTED, &corrupted)) {
      warn("Failed AOM_GET_FRAME_CORRUPTED: %s", aom_codec_error(&decoder));
      if (!keep_going) goto fail;
    }
    frames_corrupted += corrupted;

    if (progress) show_progress(frame_in, frame_out, dx_time);

    if (!noblit && img) {
      const int PLANES_YUV[] = { AOM_PLANE_Y, AOM_PLANE_U, AOM_PLANE_V };
      const int PLANES_YVU[] = { AOM_PLANE_Y, AOM_PLANE_V, AOM_PLANE_U };
      const int *planes = flipuv ? PLANES_YVU : PLANES_YUV;

      if (do_scale) {
        if (frame_out == 1) {
          // If the output frames are to be scaled to a fixed display size then
          // use the width and height specified in the container. If either of
          // these is set to 0, use the display size set in the first frame
          // header. If that is unavailable, use the raw decoded size of the
          // first decoded frame.
          int render_width = aom_input_ctx.width;
          int render_height = aom_input_ctx.height;
          if (!render_width || !render_height) {
            int render_size[2];
            if (aom_codec_control(&decoder, AV1D_GET_DISPLAY_SIZE,
                                  render_size)) {
              // As last resort use size of first frame as display size.
              render_width = img->d_w;
              render_height = img->d_h;
            } else {
              render_width = render_size[0];
              render_height = render_size[1];
            }
          }
          scaled_img =
              aom_img_alloc(NULL, img->fmt, render_width, render_height, 16);
          scaled_img->bit_depth = img->bit_depth;
        }

        if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) {
#if CONFIG_LIBYUV
          libyuv_scale(img, scaled_img, kFilterBox);
          img = scaled_img;
#else
          fprintf(stderr,
                  "Failed  to scale output frame: %s.\n"
                  "Scaling is disabled in this configuration. "
                  "To enable scaling, configure with --enable-libyuv\n",
                  aom_codec_error(&decoder));
          goto fail;
#endif
        }
      }
#if CONFIG_AOM_HIGHBITDEPTH
      // Default to codec bit depth if output bit depth not set
      if (!output_bit_depth && single_file && !do_md5) {
        output_bit_depth = img->bit_depth;
      }
      // Shift up or down if necessary
      if (output_bit_depth != 0 && output_bit_depth != img->bit_depth) {
        const aom_img_fmt_t shifted_fmt =
            output_bit_depth == 8
                ? img->fmt ^ (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH)
                : img->fmt | AOM_IMG_FMT_HIGHBITDEPTH;
        if (img_shifted &&
            img_shifted_realloc_required(img, img_shifted, shifted_fmt)) {
          aom_img_free(img_shifted);
          img_shifted = NULL;
        }
        if (!img_shifted) {
          img_shifted =
              aom_img_alloc(NULL, shifted_fmt, img->d_w, img->d_h, 16);
          img_shifted->bit_depth = output_bit_depth;
        }
        if (output_bit_depth > img->bit_depth) {
          aom_img_upshift(img_shifted, img, output_bit_depth - img->bit_depth);
        } else {
          aom_img_downshift(img_shifted, img,
                            img->bit_depth - output_bit_depth);
        }
        img = img_shifted;
      }
#endif

#if CONFIG_EXT_TILE
      aom_input_ctx.width = img->d_w;
      aom_input_ctx.height = img->d_h;
#endif  // CONFIG_EXT_TILE

      if (single_file) {
        if (use_y4m) {
          char y4m_buf[Y4M_BUFFER_SIZE] = { 0 };
          size_t len = 0;
          if (img->fmt == AOM_IMG_FMT_I440 || img->fmt == AOM_IMG_FMT_I44016) {
            fprintf(stderr, "Cannot produce y4m output for 440 sampling.\n");
            goto fail;
          }
          if (frame_out == 1) {
            // Y4M file header
            len = y4m_write_file_header(
                y4m_buf, sizeof(y4m_buf), aom_input_ctx.width,
                aom_input_ctx.height, &aom_input_ctx.framerate, img->fmt,
                img->bit_depth);
            if (do_md5) {
              MD5Update(&md5_ctx, (md5byte *)y4m_buf, (unsigned int)len);
            } else {
              fputs(y4m_buf, outfile);
            }
          }

          // Y4M frame header
          len = y4m_write_frame_header(y4m_buf, sizeof(y4m_buf));
          if (do_md5) {
            MD5Update(&md5_ctx, (md5byte *)y4m_buf, (unsigned int)len);
          } else {
            fputs(y4m_buf, outfile);
          }
        } else {
          if (frame_out == 1) {
            // Check if --yv12 or --i420 options are consistent with the
            // bit-stream decoded
            if (opt_i420) {
              if (img->fmt != AOM_IMG_FMT_I420 &&
                  img->fmt != AOM_IMG_FMT_I42016) {
                fprintf(stderr, "Cannot produce i420 output for bit-stream.\n");
                goto fail;
              }
            }
            if (opt_yv12) {
              if ((img->fmt != AOM_IMG_FMT_I420 &&
                   img->fmt != AOM_IMG_FMT_YV12) ||
                  img->bit_depth != 8) {
                fprintf(stderr, "Cannot produce yv12 output for bit-stream.\n");
                goto fail;
              }
            }
          }
        }

        if (do_md5) {
          update_image_md5(img, planes, &md5_ctx);
        } else {
          write_image_file(img, planes, outfile);
        }
      } else {
        generate_filename(outfile_pattern, outfile_name, PATH_MAX, img->d_w,
                          img->d_h, frame_in);
        if (do_md5) {
          MD5Init(&md5_ctx);
          update_image_md5(img, planes, &md5_ctx);
          MD5Final(md5_digest, &md5_ctx);
          print_md5(md5_digest, outfile_name);
        } else {
          outfile = open_outfile(outfile_name);
          write_image_file(img, planes, outfile);
          fclose(outfile);
        }
      }
    }
  }

  if (summary || progress) {
    show_progress(frame_in, frame_out, dx_time);
    fprintf(stderr, "\n");
  }

  if (frames_corrupted) {
    fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted);
  } else {
    ret = EXIT_SUCCESS;
  }

fail:

  if (aom_codec_destroy(&decoder)) {
    fprintf(stderr, "Failed to destroy decoder: %s\n",
            aom_codec_error(&decoder));
  }

fail2:

  if (!noblit && single_file) {
    if (do_md5) {
      MD5Final(md5_digest, &md5_ctx);
      print_md5(md5_digest, outfile_name);
    } else {
      fclose(outfile);
    }
  }

#if CONFIG_WEBM_IO
  if (input.aom_input_ctx->file_type == FILE_TYPE_WEBM)
    webm_free(input.webm_ctx);
#endif

  if (input.aom_input_ctx->file_type != FILE_TYPE_WEBM) free(buf);

  if (scaled_img) aom_img_free(scaled_img);
#if CONFIG_AOM_HIGHBITDEPTH
  if (img_shifted) aom_img_free(img_shifted);
#endif

  for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) {
    free(ext_fb_list.ext_fb[i].data);
  }
  free(ext_fb_list.ext_fb);

  fclose(infile);
  if (framestats_file) fclose(framestats_file);

  free(argv);

  return ret;
}
int main(int argc, char *argv[])
{
    char view_file_type;
    int num_files;
    int i, j;
    char **view_files;
    char dest_file[LINE_BUF_SIZE];
    file_merger_error_t error;
    cb_thread_t exit_thread;
    int status = 0;

    (void) argc;
    (void) argv;

    /*
     * Disable buffering for stdout since file merger messages needs
     * to be immediately available at erlang side
     */
    setvbuf(stdout, (char *) NULL, _IONBF, 0);

    if (set_binary_mode() < 0) {
        fprintf(stderr, "Error setting binary mode\n");
        exit(EXIT_FAILURE);
    }

    if (fscanf(stdin, "%c\n", &view_file_type) != 1) {
        fprintf(stderr, "Error reading view file type.\n");
        exit(EXIT_FAILURE);
    }
    if (view_file_type != 'i' && view_file_type != 'v') {
        fprintf(stderr, "View file type must be 'i' or 'v'.\n");
        exit(EXIT_FAILURE);
    }

    if (fscanf(stdin, "%d\n", &num_files) != 1) {
        fprintf(stderr, "Error reading number of files to merge.\n");
        exit(EXIT_FAILURE);
    }
    if (num_files <= 0) {
        fprintf(stderr, "Number of files to merge is negative or zero.\n");
        exit(EXIT_FAILURE);
    }

    view_files = (char **) malloc(sizeof(char *) * num_files);
    if (view_files == NULL) {
        fprintf(stderr, "Memory allocation failure.\n");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < num_files; ++i) {
        view_files[i] = (char *) malloc(LINE_BUF_SIZE);
        if (view_files[i] == NULL) {
            for (j = 0; j < i; ++j) {
                free(view_files[j]);
            }
            free(view_files);
            fprintf(stderr, "Memory allocation failure.\n");
            exit(EXIT_FAILURE);
        }

        if (couchstore_read_line(stdin, view_files[i], LINE_BUF_SIZE) != view_files[i]) {
            for (j = 0; j <= i; ++j) {
                free(view_files[j]);
            }
            free(view_files);
            fprintf(stderr, "Error reading view file number %d.\n", (i + 1));
            exit(EXIT_FAILURE);
        }
    }

    if (couchstore_read_line(stdin, dest_file, LINE_BUF_SIZE) != dest_file) {
        fprintf(stderr, "Error reading destination file name.\n");
        status = 1;
        goto finished;
    }

    status = start_exit_listener(&exit_thread);
    if (status) {
        fprintf(stderr, "Error starting stdin exit listener thread\n");
        goto finished;
    }

    if (num_files > 1) {
        const char **src_files = (const char **) view_files;
        switch (view_file_type) {
        case 'i':
            error = merge_view_ids_ops_files(src_files, num_files, dest_file);
            break;
        case 'v':
            error = merge_view_kvs_ops_files(src_files, num_files, dest_file);
            break;
        default:
            fprintf(stderr, "Unknown view file type: %c\n", view_file_type);
            status = 1;
            goto finished;
        }

        if (error == FILE_MERGER_SUCCESS) {
            for (i = 0; i < num_files; ++i) {
                /* Ignore failures.
                   Erlang side will eventually delete the files later. */
                remove(view_files[i]);
            }
        } else {
            status = MERGE_ERROR_CODE(error);
            goto finished;
        }
    } else {
        if (rename(view_files[0], dest_file) != 0) {
            fprintf(stderr, "Error renaming file %s to %s: %s\n",
                    view_files[0], dest_file, strerror(errno));
            status = 1;
            goto finished;
        }
    }

 finished:
    for (i = 0; i < num_files; ++i) {
        free(view_files[i]);
    }
    free(view_files);

    return status;
}
Beispiel #21
0
int main (int argc, char **argv)
{
    // Optimize allocation for Tornado (2GB hash allocated after 1GB dictionary)
    AllocTopDown = FALSE;

    // Operation mode
    OPMODE global_mode=AUTO;

    // Record that stores all the info required for ReadWriteCallback
    static Results r;
    r.use_cpu_time = r.quiet_title = r.quiet_header = r.quiet_progress = r.quiet_result = FALSE;

    // Default compression parameters are equivalent to option -5
    r.method = std_Tornado_method [default_Tornado_method];

    // Delete successfully (de)compressed input files
    bool delete_input_files = FALSE;

    // Count of files to process
    int fcount=0;

    // Output path/filename
    const char *output_filename = NULL;

    // Process options until "--"
    // 1. First, process -1..-16 option if any
    for (char **argv_ptr = argv; *++argv_ptr!=NULL; ) {
        char *param = *argv_ptr;
        if (*param == '-') {
            param++;
                 if (strcasecmp(param,"-")==0)   break;   // "--" is a "stop processing" option
            else if (isdigit(*param))            r.method = std_Tornado_method[check_parse_int (param, 1, elements(std_Tornado_method)-1, param-1)];
        }
    }
    // 2. Second, process rest of options
    for (char **argv_ptr = argv; *++argv_ptr!=NULL; ) {
        char *param = *argv_ptr;
        if (param[0] != '-' || param[1]=='\0') {
            fcount++;
        } else { param++;  int error=0;
                 if (strcasecmp(param,"-")==0)      break;
            else if (strcasecmp(param,"") ==0)      continue;
            else if (strcasecmp(param,"z")==0)      global_mode=_COMPRESS;
            else if (strcasecmp(param,"d")==0)      global_mode=_DECOMPRESS;
            else if (strcasecmp(param,"delete")==0) delete_input_files=TRUE;
            else if (strcasecmp(param,"t")==0)      output_filename="";
            else if (strcasecmp(param,"q")==0)      r.quiet_title = r.quiet_header = r.quiet_progress = r.quiet_result = TRUE;
#ifndef FREEARC_NO_TIMING
            else if (strcasecmp(param,"cpu")==0)    r.use_cpu_time=TRUE;
#endif
            else if (strcasecmp(param,"h")==0)      global_mode=HELP;
            else if (strcasecmp(param,"b")==0)      r.method.buffer = MAX_BUFFER_SIZE;         // set buffer size to the maximum supported by LZ coders
            else if (strcasecmp(param,"x")==0)      r.method.caching_finder = CACHING_MF4;
            else if (strcasecmp(param,"xx")==0)     r.method.caching_finder = CYCLED_MF4;
            else if (strcasecmp(param,"x+")==0)     r.method.caching_finder = CACHING_MF4;
            else if (strcasecmp(param,"x-")==0)     r.method.caching_finder = NON_CACHING_MF;
            else if (strcasecmp(param,"t+")==0)     r.method.find_tables = TRUE;
            else if (strcasecmp(param,"t-")==0)     r.method.find_tables = FALSE;
            else if (strcasecmp(param,"t1")==0)     r.method.find_tables = TRUE;
            else if (strcasecmp(param,"t0")==0)     r.method.find_tables = FALSE;
            else if (strcasecmp(param,"s")==0)      r.method.hash3 = 1;
            else if (strcasecmp(param,"ss")==0)     r.method.hash3 = 2;
            else if (strcasecmp(param,"s+")==0)     r.method.hash3 = 1;
            else if (strcasecmp(param,"s-")==0)     r.method.hash3 = 0;
            else if (start_with(param,"fb"))        r.method.fast_bytes = check_parse_int (param+2, MIN_FAST_BYTES, MAX_FAST_BYTES, *argv_ptr);
#ifdef FREEARC_WIN
            else if (strcasecmp(param,"slp-")==0)   DefaultLargePageMode = DISABLE;
            else if (strcasecmp(param,"slp" )==0)   DefaultLargePageMode = TRY;
            else if (strcasecmp(param,"slp+")==0)   DefaultLargePageMode = FORCE;
#endif
            else if (start_with(param,"rem"))       /* ignore option */;
            else if (isdigit(*param))            ; // -1..-16 option is already processed :)
            else switch( tolower(*param++) ) {
                case 'b': r.method.buffer          = check_parse_mem (param, MIN_BUFFER_SIZE, MAX_BUFFER_SIZE,    *argv_ptr);  break;
                case 'h': r.method.hashsize        = check_parse_mem (param, MIN_HASH_SIZE,   MAX_HASH_SIZE,      *argv_ptr);  break;
                case 'l': r.method.hash_row_width  = check_parse_int (param, 1,               MAX_HASH_ROW_WIDTH, *argv_ptr);  break;
                case 'u': r.method.update_step     = check_parse_int (param, 1,               MAX_UPDATE_STEP,    *argv_ptr);  break;
                case 'c': r.method.encoding_method = check_parse_int (param, BYTECODER,       ARICODER,           *argv_ptr);  break;
                case 's': r.method.hash3           = check_parse_int (param, 0,               2,                  *argv_ptr);  break;
                case 'p': r.method.match_parser    = parseInt (param, &error);  break;
                case 'x': r.method.caching_finder  = parseInt (param, &error);  break;
                case 'o': output_filename          = param;                     break;
                case 'q':
#ifndef FREEARC_NO_TIMING
                          r.quiet_title            = strchr (param, 't');
                          r.quiet_progress         = strchr (param, 'p');
#endif
                          r.quiet_header           = strchr (param, 'h');
                          r.quiet_result           = strchr (param, 'r');
                          break;
                case 'a': switch( tolower(*param++) ) {
                            case 'h': r.method.auxhash_size      = check_parse_mem (param, MIN_HASH_SIZE, MAX_HASH_SIZE, *argv_ptr);  goto check_for_errors;
                            case 'l': r.method.auxhash_row_width = check_parse_int (param, 1,        MAX_HASH_ROW_WIDTH, *argv_ptr);  goto check_for_errors;
                          }
                          // 'a' should be the last case!
                default : fprintf (stderr, "ERROR: unknown option '%s'\n", *argv_ptr);
                          exit(FREEARC_EXIT_ERROR);
            }
check_for_errors:
            if (error) {
                fprintf (stderr, "ERROR: bad option format: '%s'\n", *argv_ptr);
                exit(FREEARC_EXIT_ERROR);
            }
            if (!(r.method.match_parser==GREEDY || r.method.match_parser==LAZY  || r.method.match_parser==OPTIMAL)) {
                fprintf (stderr, "ERROR: bad option value: '%s'\n", *argv_ptr);
                exit(FREEARC_EXIT_ERROR);
            }
            int mf = r.method.caching_finder;
            r.method.caching_finder = mf = (mf==CACHING_MF4_DUB? CACHING_MF4 : (mf==CYCLED_MF4_DUB? CYCLED_MF4 : mf));
            if (!(mf==NON_CACHING_MF || (CYCLED_MF4<=mf && mf<=CYCLED_MF7) || (CACHING_MF4<=mf && mf<=CACHING_MF7) || (BT_MF4<=mf && mf<=BT_MF7))) {
                fprintf (stderr, "ERROR: non-existing match finder: '%s'\n", *argv_ptr);
                exit(FREEARC_EXIT_ERROR);
            }
        }
    }

    // No files to compress: read from stdin and write to stdout
    if (global_mode!=HELP && fcount==0 &&
       (global_mode!=AUTO  ||  !isatty(0) && !isatty(1)) ) {

        static char *_argv[] = {argv[0], (char*)"-", NULL};
        argv = _argv;
        fcount = 1;

    } else if (global_mode==HELP || fcount==0) {
        char h[100], ah[100], b[100], MinHashSizeStr[100], MaxHashSizeStr[100], MinBufSizeStr[100], MaxBufSizeStr[100];
        showMem64 (r.method.hashsize, h);
        showMem64 (r.method.auxhash_size, ah);
        showMem64 (r.method.buffer, b);
        showMem64 (MIN_HASH_SIZE, MinHashSizeStr);
        showMem64 (MAX_HASH_SIZE+1, MaxHashSizeStr);
        showMem64 (MIN_BUFFER_SIZE, MinBufSizeStr);
        showMem64 (MAX_BUFFER_SIZE, MaxBufSizeStr);
        printf( "Tornado compressor v0.6  (c) [email protected]  http://freearc.org  2014-03-08\n"
                "\n"
                " Usage: tor [options and files in any order]\n"
                "   -#      -- compression level (1..%d), default %d\n", int(elements(std_Tornado_method))-1, default_Tornado_method);
        printf( "   -z      -- force compression\n"
                "   -d      -- force decompression\n"
                "   -oNAME  -- output filename/directory (default %s/%s)\n", COMPRESS_EXT, DECOMPRESS_EXT);
        printf( "   -t      -- test (de)compression (redirect output to nul)\n"
                "   -delete -- delete successfully (de)compressed input files\n"
#ifdef FREEARC_NO_TIMING
                "   -q      -- be quiet; -q[hr]* disables header/results individually\n"
#else
                "   -q      -- be quiet; -q[thpr]* disables title/header/progress/results individually\n"
                "   -cpu    -- compute raw CPU time (for benchmarking)\n"
#endif
#ifdef FREEARC_WIN
                "   -slp[+/-/]   -- force/disable/try(default) large pages support (2mb/4mb)\n"
#endif
                "   -rem... -- command-line remark\n"
                "   -h      -- display this help\n"
                "   --      -- stop flags processing\n"
                " \"-\" used as filename means stdin/stdout\n"
                "\n"
                " Advanced compression parameters:\n"
                "   -b#     -- buffer size (%s..%s), default %s\n", MinBufSizeStr, MaxBufSizeStr, b);
        printf( "   -h#     -- hash size (%s..%s-1), default %s\n", MinHashSizeStr, MaxHashSizeStr, h);
        printf( "   -l#     -- length of hash row (1..%d), default %d\n", int(MAX_HASH_ROW_WIDTH), r.method.hash_row_width);
        printf( "   -ah#    -- auxiliary hash size (%s..%s-1), default %s\n", MinHashSizeStr, MaxHashSizeStr, ah);
        printf( "   -al#    -- auxiliary hash row length (1..%d), default %d\n", int(MAX_HASH_ROW_WIDTH), r.method.auxhash_row_width);
        printf( "   -u#     -- update step (1..%d), default %d\n", int(MAX_UPDATE_STEP), r.method.update_step);
        printf( "   -c#     -- coder (1-bytes, 2-bits, 3-huf, 4-arith), default %d\n", r.method.encoding_method);
        printf( "   -p#     -- parser (1-greedy, 2-lazy, 4-optimal), default %d\n", r.method.match_parser);
        printf( "   -x#     -- match finder (0: non-caching ht4, 4-7: cycling cached ht4..ht7,\n"
                "                            14-17: shifting cached ht4..ht7, 24-27: bt4..bt7), default %d\n", r.method.caching_finder);
        printf( "   -s#     -- 2/3-byte hash (0-disabled, 1-fast, 2-max), default %d\n", r.method.hash3);
        printf( "   -t#     -- table diffing (0-disabled, 1-enabled), default %d\n", r.method.find_tables);
        printf( "   -fb#    -- fast bytes in the optimal parser (%d..%d), default %d\n", int(MIN_FAST_BYTES), int(MAX_FAST_BYTES), r.method.fast_bytes);
        printf( "\n"
                " Predefined methods:\n");
        for (int i=1; i<elements(std_Tornado_method); i++)
        {
            printf("   %-8d-- %s\n", -i, name(std_Tornado_method[i]));
        }
        exit(EXIT_SUCCESS);
    }



    // (De)compress all files given on cmdline
    bool parse_options=TRUE;  // options will be parsed until "--"
    Install_signal_handler(signal_handler);

    for (char **parameters = argv; *++parameters!=NULL; )
    {
        // If options are still parsed and this argument starts with "-" - it's an option
        if (parse_options && parameters[0][0]=='-' && parameters[0][1]) {
            if (strequ(*parameters,"--"))  parse_options=FALSE;
            continue;
        }

        // Save input filename
        r.filename = *parameters;

        // Select operation mode if it was not specified on cmdline
        r.mode = global_mode != AUTO?                  global_mode :
                 end_with (r.filename, COMPRESS_EXT)?  _DECOMPRESS  :
                                                       _COMPRESS;
        // Extension that should be added to output filenames
        const char *MODE_EXT  =  r.mode==_COMPRESS? COMPRESS_EXT : DECOMPRESS_EXT;

        // Construct output filename
        if (r.mode==BENCHMARK  ||  output_filename && strequ (output_filename, "")) {  // Redirect output to nul
            strcpy (r.outname, "");
        } else if (output_filename) {
            if (strequ(output_filename,"-"))
                strcpy (r.outname, output_filename);
            else if (is_path_char (last_char (output_filename)))
                {sprintf(r.outname, "%s%s", output_filename, drop_dirname(r.filename));  goto add_remove_ext;}
            else if (dir_exists (output_filename))
                {sprintf(r.outname, "%s%c%s", output_filename, PATH_DELIMITER, drop_dirname(r.filename));  goto add_remove_ext;}
            else
                strcpy (r.outname, output_filename);
        } else if (strequ(r.filename,"-")) {
            strcpy (r.outname, r.filename);
        } else {
            // No output filename was given on cmdline:
            //    on compression   - add COMPRESS_EXT
            //    on decompression - remove COMPRESS_EXT (and add DECOMPRESS_EXT if file already exists)
            strcpy (r.outname, r.filename);
add_remove_ext: // Remove COMPRESS_EXT on the end of name or add DECOMPRESS_EXT (unless we are in _COMPRESS mode)
            if (r.mode!=_COMPRESS && end_with (r.outname, COMPRESS_EXT)) {
                r.outname [strlen(r.outname) - strlen(COMPRESS_EXT)] = '\0';
                if (file_exists (r.outname))
                    strcat(r.outname, MODE_EXT);
            } else {
                strcat(r.outname, MODE_EXT);
            }
        }

        // Open input file
        r.fin = strequ (r.filename, "-")? stdin : file_open_read_binary(r.filename);
        if (r.fin == NULL) {
            fprintf (stderr, "\n Can't open %s for read\n", r.filename);
            exit(FREEARC_EXIT_ERROR);
        }
        set_binary_mode (r.fin);

        // Open output file
        if (*r.outname) {
          r.fout = strequ (r.outname, "-")? stdout : file_open_write_binary(r.outname);
          if (r.fout == NULL) {
              fprintf (stderr, "\n Can't open %s for write\n", r.outname);
              exit(FREEARC_EXIT_ERROR);
          }
          set_binary_mode (r.fout);
        } else {
          r.fout = NULL;
        }

        // Prepare to (de)compression
        int result;  char filesize_str[100];
        start_print_stats(r);

        // Perform actual (de)compression
        switch (r.mode) {
        case _COMPRESS: {
            if (!r.quiet_header && r.filesize >= 0)
                fprintf (stderr, "Compressing %s bytes with %s\n", show3(r.filesize,filesize_str), name(r.method));
            PackMethod m = r.method;
            if (r.filesize >= 0)
                m.buffer = mymin (m.buffer, r.filesize+LOOKAHEAD*2);
            result = tor_compress (m, ReadWriteCallback, &r, NULL, -1);
            break; }

        case _DECOMPRESS: {
            //if (!r.quiet_header && !strequ (r.outname, "-"))   fprintf (stderr, "Unpacking %.3lf mb\n", double(r.filesize)/1000/1000);
            result = tor_decompress (ReadWriteCallback, &r, NULL, -1);
            break; }
        }

        // Finish (de)compression
        print_final_stats(r);
        fclose (r.fin);
        if (r.fout)  fclose (r.fout);

        if (result == FREEARC_OK)  {
            if (delete_input_files && !strequ(r.filename,"-"))    delete_file(r.filename);
        } else {
            if (!strequ(r.outname,"-") && !strequ(r.outname,""))  delete_file(r.outname);
            switch (result) {
            case FREEARC_ERRCODE_INVALID_COMPRESSOR:
                fprintf (stderr, "\nThis compression mode isn't supported by small Tornado version, use full version instead!");
                break;
            case FREEARC_ERRCODE_NOT_ENOUGH_MEMORY:
                fprintf (stderr, "\nNot enough memory for (de)compression!");
                break;
            case FREEARC_ERRCODE_READ:
                fprintf (stderr, "\nRead error! Bad media?");
                break;
            case FREEARC_ERRCODE_WRITE:
                fprintf (stderr, "\nWrite error! Disk full?");
                break;
            case FREEARC_ERRCODE_BAD_COMPRESSED_DATA:
                fprintf (stderr, "\nData can't be decompressed!");
                break;
            default:
                fprintf (stderr, "\n(De)compression failed with error code %d!", result);
                break;
            }
            exit(FREEARC_EXIT_ERROR);
        }

        // going to next file...
    }

    return EXIT_SUCCESS;
}