media/libyuv/util/convert.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/libyuv/util/convert.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,365 @@
     1.4 +/*
     1.5 + *  Copyright 2013 The LibYuv Project Authors. All rights reserved.
     1.6 + *
     1.7 + *  Use of this source code is governed by a BSD-style license
     1.8 + *  that can be found in the LICENSE file in the root of the source
     1.9 + *  tree. An additional intellectual property rights grant can be found
    1.10 + *  in the file PATENTS. All contributing project authors may
    1.11 + *  be found in the AUTHORS file in the root of the source tree.
    1.12 + */
    1.13 +
    1.14 +// Convert an ARGB image to YUV.
    1.15 +// Usage: convert src_argb.raw dst_yuv.raw
    1.16 +
    1.17 +#ifndef _CRT_SECURE_NO_WARNINGS
    1.18 +#define _CRT_SECURE_NO_WARNINGS
    1.19 +#endif
    1.20 +
    1.21 +#include <stddef.h>
    1.22 +#include <stdio.h>
    1.23 +#include <stdlib.h>
    1.24 +#include <string.h>
    1.25 +
    1.26 +#include "libyuv/convert.h"
    1.27 +#include "libyuv/planar_functions.h"
    1.28 +#include "libyuv/scale_argb.h"
    1.29 +
    1.30 +// options
    1.31 +bool verbose = false;
    1.32 +bool attenuate = false;
    1.33 +bool unattenuate = false;
    1.34 +int image_width = 0, image_height = 0;  // original width and height
    1.35 +int dst_width = 0, dst_height = 0;  // new width and height
    1.36 +int fileindex_org = 0;  // argv argument contains the original file name.
    1.37 +int fileindex_rec = 0;  // argv argument contains the reconstructed file name.
    1.38 +int num_rec = 0;  // Number of reconstructed images.
    1.39 +int num_skip_org = 0;  // Number of frames to skip in original.
    1.40 +int num_frames = 0;  // Number of frames to convert.
    1.41 +int filter = 1;  // Bilinear filter for scaling.
    1.42 +
    1.43 +static __inline uint32 Abs(int32 v) {
    1.44 +  return v >= 0 ? v : -v;
    1.45 +}
    1.46 +
    1.47 +// Parse PYUV format. ie name.1920x800_24Hz_P420.yuv
    1.48 +bool ExtractResolutionFromFilename(const char* name,
    1.49 +                                   int* width_ptr,
    1.50 +                                   int* height_ptr) {
    1.51 +  // Isolate the .width_height. section of the filename by searching for a
    1.52 +  // dot or underscore followed by a digit.
    1.53 +  for (int i = 0; name[i]; ++i) {
    1.54 +    if ((name[i] == '.' || name[i] == '_') &&
    1.55 +        name[i + 1] >= '0' && name[i + 1] <= '9') {
    1.56 +      int n = sscanf(name + i + 1, "%dx%d", width_ptr, height_ptr);  // NOLINT
    1.57 +      if (2 == n) {
    1.58 +        return true;
    1.59 +      }
    1.60 +    }
    1.61 +  }
    1.62 +  return false;
    1.63 +}
    1.64 +
    1.65 +void PrintHelp(const char * program) {
    1.66 +  printf("%s [-options] src_argb.raw dst_yuv.raw\n", program);
    1.67 +  printf(" -s <width> <height> .... specify source resolution.  "
    1.68 +         "Optional if name contains\n"
    1.69 +         "                          resolution (ie. "
    1.70 +         "name.1920x800_24Hz_P420.yuv)\n"
    1.71 +         "                          Negative value mirrors.\n");
    1.72 +  printf(" -d <width> <height> .... specify destination resolution.\n");
    1.73 +  printf(" -f <filter> ............ 0 = point, 1 = bilinear (default).\n");
    1.74 +  printf(" -skip <src_argb> ....... Number of frame to skip of src_argb\n");
    1.75 +  printf(" -frames <num> .......... Number of frames to convert\n");
    1.76 +  printf(" -attenuate ............. Attenuate the ARGB image\n");
    1.77 +  printf(" -unattenuate ........... Unattenuate the ARGB image\n");
    1.78 +  printf(" -v ..................... verbose\n");
    1.79 +  printf(" -h ..................... this help\n");
    1.80 +  exit(0);
    1.81 +}
    1.82 +
    1.83 +void ParseOptions(int argc, const char* argv[]) {
    1.84 +  if (argc <= 1) PrintHelp(argv[0]);
    1.85 +  for (int c = 1; c < argc; ++c) {
    1.86 +    if (!strcmp(argv[c], "-v")) {
    1.87 +      verbose = true;
    1.88 +    } else if (!strcmp(argv[c], "-attenuate")) {
    1.89 +      attenuate = true;
    1.90 +    } else if (!strcmp(argv[c], "-unattenuate")) {
    1.91 +      unattenuate = true;
    1.92 +    } else if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
    1.93 +      PrintHelp(argv[0]);
    1.94 +    } else if (!strcmp(argv[c], "-s") && c + 2 < argc) {
    1.95 +      image_width = atoi(argv[++c]);    // NOLINT
    1.96 +      image_height = atoi(argv[++c]);   // NOLINT
    1.97 +    } else if (!strcmp(argv[c], "-d") && c + 2 < argc) {
    1.98 +      dst_width = atoi(argv[++c]);    // NOLINT
    1.99 +      dst_height = atoi(argv[++c]);   // NOLINT
   1.100 +    } else if (!strcmp(argv[c], "-skip") && c + 1 < argc) {
   1.101 +      num_skip_org = atoi(argv[++c]);   // NOLINT
   1.102 +    } else if (!strcmp(argv[c], "-frames") && c + 1 < argc) {
   1.103 +      num_frames = atoi(argv[++c]);     // NOLINT
   1.104 +    } else if (!strcmp(argv[c], "-f") && c + 1 < argc) {
   1.105 +      filter = atoi(argv[++c]);     // NOLINT
   1.106 +    } else if (argv[c][0] == '-') {
   1.107 +      fprintf(stderr, "Unknown option. %s\n", argv[c]);
   1.108 +    } else if (fileindex_org == 0) {
   1.109 +      fileindex_org = c;
   1.110 +    } else if (fileindex_rec == 0) {
   1.111 +      fileindex_rec = c;
   1.112 +      num_rec = 1;
   1.113 +    } else {
   1.114 +      ++num_rec;
   1.115 +    }
   1.116 +  }
   1.117 +  if (fileindex_org == 0 || fileindex_rec == 0) {
   1.118 +    fprintf(stderr, "Missing filenames\n");
   1.119 +    PrintHelp(argv[0]);
   1.120 +  }
   1.121 +  if (num_skip_org < 0) {
   1.122 +    fprintf(stderr, "Skipped frames incorrect\n");
   1.123 +    PrintHelp(argv[0]);
   1.124 +  }
   1.125 +  if (num_frames < 0) {
   1.126 +    fprintf(stderr, "Number of frames incorrect\n");
   1.127 +    PrintHelp(argv[0]);
   1.128 +  }
   1.129 +
   1.130 +  int org_width, org_height;
   1.131 +  int rec_width, rec_height;
   1.132 +  bool org_res_avail = ExtractResolutionFromFilename(argv[fileindex_org],
   1.133 +                                                     &org_width,
   1.134 +                                                     &org_height);
   1.135 +  bool rec_res_avail = ExtractResolutionFromFilename(argv[fileindex_rec],
   1.136 +                                                     &rec_width,
   1.137 +                                                     &rec_height);
   1.138 +  if (image_width == 0 || image_height == 0) {
   1.139 +    if (org_res_avail) {
   1.140 +      image_width = org_width;
   1.141 +      image_height = org_height;
   1.142 +    } else if (rec_res_avail) {
   1.143 +      image_width = rec_width;
   1.144 +      image_height = rec_height;
   1.145 +    } else {
   1.146 +      fprintf(stderr, "Missing dimensions.\n");
   1.147 +      PrintHelp(argv[0]);
   1.148 +    }
   1.149 +  }
   1.150 +  if (dst_width == 0 || dst_height == 0) {
   1.151 +    if (rec_res_avail) {
   1.152 +      dst_width = rec_width;
   1.153 +      dst_height = rec_height;
   1.154 +    } else {
   1.155 +      dst_width = Abs(image_width);
   1.156 +      dst_height = Abs(image_height);
   1.157 +    }
   1.158 +  }
   1.159 +}
   1.160 +
   1.161 +static const int kTileX = 32;
   1.162 +static const int kTileY = 32;
   1.163 +
   1.164 +static int TileARGBScale(const uint8* src_argb, int src_stride_argb,
   1.165 +                         int src_width, int src_height,
   1.166 +                         uint8* dst_argb, int dst_stride_argb,
   1.167 +                         int dst_width, int dst_height,
   1.168 +                         libyuv::FilterMode filtering) {
   1.169 +  for (int y = 0; y < dst_height; y += kTileY) {
   1.170 +    for (int x = 0; x < dst_width; x += kTileX) {
   1.171 +      int clip_width = kTileX;
   1.172 +      if (x + clip_width > dst_width) {
   1.173 +        clip_width = dst_width - x;
   1.174 +      }
   1.175 +      int clip_height = kTileY;
   1.176 +      if (y + clip_height > dst_height) {
   1.177 +        clip_height = dst_height - y;
   1.178 +      }
   1.179 +      int r = libyuv::ARGBScaleClip(src_argb, src_stride_argb,
   1.180 +                                    src_width, src_height,
   1.181 +                                    dst_argb, dst_stride_argb,
   1.182 +                                    dst_width, dst_height,
   1.183 +                                    x, y, clip_width, clip_height, filtering);
   1.184 +      if (r) {
   1.185 +        return r;
   1.186 +      }
   1.187 +    }
   1.188 +  }
   1.189 +  return 0;
   1.190 +}
   1.191 +
   1.192 +int main(int argc, const char* argv[]) {
   1.193 +  ParseOptions(argc, argv);
   1.194 +
   1.195 +  // Open original file (first file argument)
   1.196 +  FILE* const file_org = fopen(argv[fileindex_org], "rb");
   1.197 +  if (file_org == NULL) {
   1.198 +    fprintf(stderr, "Cannot open %s\n", argv[fileindex_org]);
   1.199 +    exit(1);
   1.200 +  }
   1.201 +
   1.202 +  // Open all files to convert to
   1.203 +  FILE** file_rec = new FILE* [num_rec];
   1.204 +  memset(file_rec, 0, num_rec * sizeof(FILE*)); // NOLINT
   1.205 +  for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   1.206 +    file_rec[cur_rec] = fopen(argv[fileindex_rec + cur_rec], "wb");
   1.207 +    if (file_rec[cur_rec] == NULL) {
   1.208 +      fprintf(stderr, "Cannot open %s\n", argv[fileindex_rec + cur_rec]);
   1.209 +      fclose(file_org);
   1.210 +      for (int i = 0; i < cur_rec; ++i) {
   1.211 +        fclose(file_rec[i]);
   1.212 +      }
   1.213 +      delete[] file_rec;
   1.214 +      exit(1);
   1.215 +    }
   1.216 +  }
   1.217 +
   1.218 +  bool org_is_yuv = strstr(argv[fileindex_org], "_P420.") != NULL;
   1.219 +  bool org_is_argb = strstr(argv[fileindex_org], "_ARGB.") != NULL;
   1.220 +  if (!org_is_yuv && !org_is_argb) {
   1.221 +    fprintf(stderr, "Original format unknown %s\n", argv[fileindex_org]);
   1.222 +    exit(1);
   1.223 +  }
   1.224 +  int org_size = Abs(image_width) * Abs(image_height) * 4;  // ARGB
   1.225 +  // Input is YUV
   1.226 +  if (org_is_yuv) {
   1.227 +    const int y_size = Abs(image_width) * Abs(image_height);
   1.228 +    const int uv_size = ((Abs(image_width) + 1) / 2) *
   1.229 +        ((Abs(image_height) + 1) / 2);
   1.230 +    org_size = y_size + 2 * uv_size;  // YUV original.
   1.231 +  }
   1.232 +
   1.233 +  const int dst_size = dst_width * dst_height * 4;  // ARGB scaled
   1.234 +  const int y_size = dst_width * dst_height;
   1.235 +  const int uv_size = ((dst_width + 1) / 2) * ((dst_height + 1) / 2);
   1.236 +  const size_t total_size = y_size + 2 * uv_size;
   1.237 +#if defined(_MSC_VER)
   1.238 +  _fseeki64(file_org,
   1.239 +            static_cast<__int64>(num_skip_org) *
   1.240 +            static_cast<__int64>(org_size), SEEK_SET);
   1.241 +#else
   1.242 +  fseek(file_org, num_skip_org * total_size, SEEK_SET);
   1.243 +#endif
   1.244 +
   1.245 +  uint8* const ch_org = new uint8[org_size];
   1.246 +  uint8* const ch_dst = new uint8[dst_size];
   1.247 +  uint8* const ch_rec = new uint8[total_size];
   1.248 +  if (ch_org == NULL || ch_rec == NULL) {
   1.249 +    fprintf(stderr, "No memory available\n");
   1.250 +    fclose(file_org);
   1.251 +    for (int i = 0; i < num_rec; ++i) {
   1.252 +      fclose(file_rec[i]);
   1.253 +    }
   1.254 +    delete[] ch_org;
   1.255 +    delete[] ch_dst;
   1.256 +    delete[] ch_rec;
   1.257 +    delete[] file_rec;
   1.258 +    exit(1);
   1.259 +  }
   1.260 +
   1.261 +  if (verbose) {
   1.262 +    printf("Size: %dx%d to %dx%d\n", image_width, image_height,
   1.263 +           dst_width, dst_height);
   1.264 +  }
   1.265 +
   1.266 +  int number_of_frames;
   1.267 +  for (number_of_frames = 0; ; ++number_of_frames) {
   1.268 +    if (num_frames && number_of_frames >= num_frames)
   1.269 +      break;
   1.270 +
   1.271 +    // Load original YUV or ARGB frame.
   1.272 +    size_t bytes_org = fread(ch_org, sizeof(uint8),
   1.273 +                             static_cast<size_t>(org_size), file_org);
   1.274 +    if (bytes_org < static_cast<size_t>(org_size))
   1.275 +      break;
   1.276 +
   1.277 +    // TODO(fbarchard): Attenuate doesnt need to know dimensions.
   1.278 +    // ARGB attenuate frame
   1.279 +    if (org_is_argb && attenuate) {
   1.280 +      libyuv::ARGBAttenuate(ch_org, 0, ch_org, 0, org_size / 4, 1);
   1.281 +    }
   1.282 +    // ARGB unattenuate frame
   1.283 +    if (org_is_argb && unattenuate) {
   1.284 +      libyuv::ARGBUnattenuate(ch_org, 0, ch_org, 0, org_size / 4, 1);
   1.285 +    }
   1.286 +
   1.287 +    for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   1.288 +      // Scale YUV or ARGB frame.
   1.289 +      if (org_is_yuv) {
   1.290 +        int src_width = Abs(image_width);
   1.291 +        int src_height = Abs(image_height);
   1.292 +        int half_src_width = (src_width + 1) / 2;
   1.293 +        int half_src_height = (src_height + 1) / 2;
   1.294 +        int half_dst_width = (dst_width + 1) / 2;
   1.295 +        int half_dst_height = (dst_height + 1) / 2;
   1.296 +        I420Scale(ch_org, src_width,
   1.297 +                  ch_org + src_width * src_height, half_src_width,
   1.298 +                  ch_org + src_width * src_height +
   1.299 +                      half_src_width * half_src_height,  half_src_width,
   1.300 +                  image_width, image_height,
   1.301 +                  ch_rec, dst_width,
   1.302 +                  ch_rec + dst_width * dst_height, half_dst_width,
   1.303 +                  ch_rec + dst_width * dst_height +
   1.304 +                      half_dst_width * half_dst_height,  half_dst_width,
   1.305 +                  dst_width, dst_height,
   1.306 +                      static_cast<libyuv::FilterMode>(filter));
   1.307 +      } else {
   1.308 +        TileARGBScale(ch_org, Abs(image_width) * 4,
   1.309 +                      image_width, image_height,
   1.310 +                      ch_dst, dst_width * 4,
   1.311 +                      dst_width, dst_height,
   1.312 +                      static_cast<libyuv::FilterMode>(filter));
   1.313 +      }
   1.314 +      bool rec_is_yuv = strstr(argv[fileindex_rec + cur_rec], "_P420.") != NULL;
   1.315 +      bool rec_is_argb =
   1.316 +          strstr(argv[fileindex_rec + cur_rec], "_ARGB.") != NULL;
   1.317 +      if (!rec_is_yuv && !rec_is_argb) {
   1.318 +        fprintf(stderr, "Output format unknown %s\n",
   1.319 +                argv[fileindex_rec + cur_rec]);
   1.320 +        continue;  // Advance to next file.
   1.321 +      }
   1.322 +
   1.323 +      // Convert ARGB to YUV.
   1.324 +      if (!org_is_yuv && rec_is_yuv) {
   1.325 +        int half_width = (dst_width + 1) / 2;
   1.326 +        int half_height = (dst_height + 1) / 2;
   1.327 +        libyuv::ARGBToI420(ch_dst, dst_width * 4,
   1.328 +                           ch_rec, dst_width,
   1.329 +                           ch_rec + dst_width * dst_height, half_width,
   1.330 +                           ch_rec + dst_width * dst_height +
   1.331 +                               half_width * half_height,  half_width,
   1.332 +                           dst_width, dst_height);
   1.333 +      }
   1.334 +
   1.335 +      // Output YUV or ARGB frame.
   1.336 +      if (rec_is_yuv) {
   1.337 +        size_t bytes_rec = fwrite(ch_rec, sizeof(uint8),
   1.338 +                                  static_cast<size_t>(total_size),
   1.339 +                                  file_rec[cur_rec]);
   1.340 +        if (bytes_rec < static_cast<size_t>(total_size))
   1.341 +          break;
   1.342 +      } else {
   1.343 +        size_t bytes_rec = fwrite(ch_dst, sizeof(uint8),
   1.344 +                                  static_cast<size_t>(dst_size),
   1.345 +                                  file_rec[cur_rec]);
   1.346 +        if (bytes_rec < static_cast<size_t>(dst_size))
   1.347 +          break;
   1.348 +      }
   1.349 +      if (verbose) {
   1.350 +        printf("%5d", number_of_frames);
   1.351 +      }
   1.352 +      if (verbose) {
   1.353 +        printf("\t%s", argv[fileindex_rec + cur_rec]);
   1.354 +        printf("\n");
   1.355 +      }
   1.356 +    }
   1.357 +  }
   1.358 +
   1.359 +  fclose(file_org);
   1.360 +  for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
   1.361 +    fclose(file_rec[cur_rec]);
   1.362 +  }
   1.363 +  delete[] ch_org;
   1.364 +  delete[] ch_dst;
   1.365 +  delete[] ch_rec;
   1.366 +  delete[] file_rec;
   1.367 +  return 0;
   1.368 +}

mercurial