2
0

tools_common.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #include <math.h>
  11. #include <stdarg.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include "./tools_common.h"
  16. #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
  17. #include "vpx/vp8cx.h"
  18. #endif
  19. #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
  20. #include "vpx/vp8dx.h"
  21. #endif
  22. #if defined(_WIN32) || defined(__OS2__)
  23. #include <io.h>
  24. #include <fcntl.h>
  25. #ifdef __OS2__
  26. #define _setmode setmode
  27. #define _fileno fileno
  28. #define _O_BINARY O_BINARY
  29. #endif
  30. #endif
  31. #define LOG_ERROR(label) \
  32. do { \
  33. const char *l = label; \
  34. va_list ap; \
  35. va_start(ap, fmt); \
  36. if (l) fprintf(stderr, "%s: ", l); \
  37. vfprintf(stderr, fmt, ap); \
  38. fprintf(stderr, "\n"); \
  39. va_end(ap); \
  40. } while (0)
  41. FILE *set_binary_mode(FILE *stream) {
  42. (void)stream;
  43. #if defined(_WIN32) || defined(__OS2__)
  44. _setmode(_fileno(stream), _O_BINARY);
  45. #endif
  46. return stream;
  47. }
  48. void die(const char *fmt, ...) {
  49. LOG_ERROR(NULL);
  50. usage_exit();
  51. }
  52. void fatal(const char *fmt, ...) {
  53. LOG_ERROR("Fatal");
  54. exit(EXIT_FAILURE);
  55. }
  56. void warn(const char *fmt, ...) { LOG_ERROR("Warning"); }
  57. void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
  58. const char *detail = vpx_codec_error_detail(ctx);
  59. printf("%s: %s\n", s, vpx_codec_error(ctx));
  60. if (detail) printf(" %s\n", detail);
  61. exit(EXIT_FAILURE);
  62. }
  63. int read_yuv_frame(struct VpxInputContext *input_ctx, vpx_image_t *yuv_frame) {
  64. FILE *f = input_ctx->file;
  65. struct FileTypeDetectionBuffer *detect = &input_ctx->detect;
  66. int plane = 0;
  67. int shortread = 0;
  68. const int bytespp = (yuv_frame->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
  69. for (plane = 0; plane < 3; ++plane) {
  70. uint8_t *ptr;
  71. const int w = vpx_img_plane_width(yuv_frame, plane);
  72. const int h = vpx_img_plane_height(yuv_frame, plane);
  73. int r;
  74. /* Determine the correct plane based on the image format. The for-loop
  75. * always counts in Y,U,V order, but this may not match the order of
  76. * the data on disk.
  77. */
  78. switch (plane) {
  79. case 1:
  80. ptr =
  81. yuv_frame->planes[yuv_frame->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_V
  82. : VPX_PLANE_U];
  83. break;
  84. case 2:
  85. ptr =
  86. yuv_frame->planes[yuv_frame->fmt == VPX_IMG_FMT_YV12 ? VPX_PLANE_U
  87. : VPX_PLANE_V];
  88. break;
  89. default: ptr = yuv_frame->planes[plane];
  90. }
  91. for (r = 0; r < h; ++r) {
  92. size_t needed = w * bytespp;
  93. size_t buf_position = 0;
  94. const size_t left = detect->buf_read - detect->position;
  95. if (left > 0) {
  96. const size_t more = (left < needed) ? left : needed;
  97. memcpy(ptr, detect->buf + detect->position, more);
  98. buf_position = more;
  99. needed -= more;
  100. detect->position += more;
  101. }
  102. if (needed > 0) {
  103. shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
  104. }
  105. ptr += yuv_frame->stride[plane];
  106. }
  107. }
  108. return shortread;
  109. }
  110. #if CONFIG_ENCODERS
  111. static const VpxInterface vpx_encoders[] = {
  112. #if CONFIG_VP8_ENCODER
  113. { "vp8", VP8_FOURCC, &vpx_codec_vp8_cx },
  114. #endif
  115. #if CONFIG_VP9_ENCODER
  116. { "vp9", VP9_FOURCC, &vpx_codec_vp9_cx },
  117. #endif
  118. };
  119. int get_vpx_encoder_count(void) {
  120. return sizeof(vpx_encoders) / sizeof(vpx_encoders[0]);
  121. }
  122. const VpxInterface *get_vpx_encoder_by_index(int i) { return &vpx_encoders[i]; }
  123. const VpxInterface *get_vpx_encoder_by_name(const char *name) {
  124. int i;
  125. for (i = 0; i < get_vpx_encoder_count(); ++i) {
  126. const VpxInterface *encoder = get_vpx_encoder_by_index(i);
  127. if (strcmp(encoder->name, name) == 0) return encoder;
  128. }
  129. return NULL;
  130. }
  131. #endif // CONFIG_ENCODERS
  132. #if CONFIG_DECODERS
  133. static const VpxInterface vpx_decoders[] = {
  134. #if CONFIG_VP8_DECODER
  135. { "vp8", VP8_FOURCC, &vpx_codec_vp8_dx },
  136. #endif
  137. #if CONFIG_VP9_DECODER
  138. { "vp9", VP9_FOURCC, &vpx_codec_vp9_dx },
  139. #endif
  140. };
  141. int get_vpx_decoder_count(void) {
  142. return sizeof(vpx_decoders) / sizeof(vpx_decoders[0]);
  143. }
  144. const VpxInterface *get_vpx_decoder_by_index(int i) { return &vpx_decoders[i]; }
  145. const VpxInterface *get_vpx_decoder_by_name(const char *name) {
  146. int i;
  147. for (i = 0; i < get_vpx_decoder_count(); ++i) {
  148. const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
  149. if (strcmp(decoder->name, name) == 0) return decoder;
  150. }
  151. return NULL;
  152. }
  153. const VpxInterface *get_vpx_decoder_by_fourcc(uint32_t fourcc) {
  154. int i;
  155. for (i = 0; i < get_vpx_decoder_count(); ++i) {
  156. const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
  157. if (decoder->fourcc == fourcc) return decoder;
  158. }
  159. return NULL;
  160. }
  161. #endif // CONFIG_DECODERS
  162. // TODO(dkovalev): move this function to vpx_image.{c, h}, so it will be part
  163. // of vpx_image_t support
  164. int vpx_img_plane_width(const vpx_image_t *img, int plane) {
  165. if (plane > 0 && img->x_chroma_shift > 0)
  166. return (img->d_w + 1) >> img->x_chroma_shift;
  167. else
  168. return img->d_w;
  169. }
  170. int vpx_img_plane_height(const vpx_image_t *img, int plane) {
  171. if (plane > 0 && img->y_chroma_shift > 0)
  172. return (img->d_h + 1) >> img->y_chroma_shift;
  173. else
  174. return img->d_h;
  175. }
  176. void vpx_img_write(const vpx_image_t *img, FILE *file) {
  177. int plane;
  178. for (plane = 0; plane < 3; ++plane) {
  179. const unsigned char *buf = img->planes[plane];
  180. const int stride = img->stride[plane];
  181. const int w = vpx_img_plane_width(img, plane) *
  182. ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
  183. const int h = vpx_img_plane_height(img, plane);
  184. int y;
  185. for (y = 0; y < h; ++y) {
  186. fwrite(buf, 1, w, file);
  187. buf += stride;
  188. }
  189. }
  190. }
  191. int vpx_img_read(vpx_image_t *img, FILE *file) {
  192. int plane;
  193. for (plane = 0; plane < 3; ++plane) {
  194. unsigned char *buf = img->planes[plane];
  195. const int stride = img->stride[plane];
  196. const int w = vpx_img_plane_width(img, plane) *
  197. ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
  198. const int h = vpx_img_plane_height(img, plane);
  199. int y;
  200. for (y = 0; y < h; ++y) {
  201. if (fread(buf, 1, w, file) != (size_t)w) return 0;
  202. buf += stride;
  203. }
  204. }
  205. return 1;
  206. }
  207. // TODO(dkovalev) change sse_to_psnr signature: double -> int64_t
  208. double sse_to_psnr(double samples, double peak, double sse) {
  209. static const double kMaxPSNR = 100.0;
  210. if (sse > 0.0) {
  211. const double psnr = 10.0 * log10(samples * peak * peak / sse);
  212. return psnr > kMaxPSNR ? kMaxPSNR : psnr;
  213. } else {
  214. return kMaxPSNR;
  215. }
  216. }
  217. // TODO(debargha): Consolidate the functions below into a separate file.
  218. #if CONFIG_VP9_HIGHBITDEPTH
  219. static void highbd_img_upshift(vpx_image_t *dst, vpx_image_t *src,
  220. int input_shift) {
  221. // Note the offset is 1 less than half.
  222. const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
  223. int plane;
  224. if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
  225. dst->x_chroma_shift != src->x_chroma_shift ||
  226. dst->y_chroma_shift != src->y_chroma_shift || dst->fmt != src->fmt ||
  227. input_shift < 0) {
  228. fatal("Unsupported image conversion");
  229. }
  230. switch (src->fmt) {
  231. case VPX_IMG_FMT_I42016:
  232. case VPX_IMG_FMT_I42216:
  233. case VPX_IMG_FMT_I44416:
  234. case VPX_IMG_FMT_I44016: break;
  235. default: fatal("Unsupported image conversion"); break;
  236. }
  237. for (plane = 0; plane < 3; plane++) {
  238. int w = src->d_w;
  239. int h = src->d_h;
  240. int x, y;
  241. if (plane) {
  242. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  243. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  244. }
  245. for (y = 0; y < h; y++) {
  246. uint16_t *p_src =
  247. (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
  248. uint16_t *p_dst =
  249. (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
  250. for (x = 0; x < w; x++) *p_dst++ = (*p_src++ << input_shift) + offset;
  251. }
  252. }
  253. }
  254. static void lowbd_img_upshift(vpx_image_t *dst, vpx_image_t *src,
  255. int input_shift) {
  256. // Note the offset is 1 less than half.
  257. const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
  258. int plane;
  259. if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
  260. dst->x_chroma_shift != src->x_chroma_shift ||
  261. dst->y_chroma_shift != src->y_chroma_shift ||
  262. dst->fmt != src->fmt + VPX_IMG_FMT_HIGHBITDEPTH || input_shift < 0) {
  263. fatal("Unsupported image conversion");
  264. }
  265. switch (src->fmt) {
  266. case VPX_IMG_FMT_I420:
  267. case VPX_IMG_FMT_I422:
  268. case VPX_IMG_FMT_I444:
  269. case VPX_IMG_FMT_I440: break;
  270. default: fatal("Unsupported image conversion"); break;
  271. }
  272. for (plane = 0; plane < 3; plane++) {
  273. int w = src->d_w;
  274. int h = src->d_h;
  275. int x, y;
  276. if (plane) {
  277. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  278. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  279. }
  280. for (y = 0; y < h; y++) {
  281. uint8_t *p_src = src->planes[plane] + y * src->stride[plane];
  282. uint16_t *p_dst =
  283. (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
  284. for (x = 0; x < w; x++) {
  285. *p_dst++ = (*p_src++ << input_shift) + offset;
  286. }
  287. }
  288. }
  289. }
  290. void vpx_img_upshift(vpx_image_t *dst, vpx_image_t *src, int input_shift) {
  291. if (src->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
  292. highbd_img_upshift(dst, src, input_shift);
  293. } else {
  294. lowbd_img_upshift(dst, src, input_shift);
  295. }
  296. }
  297. void vpx_img_truncate_16_to_8(vpx_image_t *dst, vpx_image_t *src) {
  298. int plane;
  299. if (dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH != src->fmt || dst->d_w != src->d_w ||
  300. dst->d_h != src->d_h || dst->x_chroma_shift != src->x_chroma_shift ||
  301. dst->y_chroma_shift != src->y_chroma_shift) {
  302. fatal("Unsupported image conversion");
  303. }
  304. switch (dst->fmt) {
  305. case VPX_IMG_FMT_I420:
  306. case VPX_IMG_FMT_I422:
  307. case VPX_IMG_FMT_I444:
  308. case VPX_IMG_FMT_I440: break;
  309. default: fatal("Unsupported image conversion"); break;
  310. }
  311. for (plane = 0; plane < 3; plane++) {
  312. int w = src->d_w;
  313. int h = src->d_h;
  314. int x, y;
  315. if (plane) {
  316. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  317. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  318. }
  319. for (y = 0; y < h; y++) {
  320. uint16_t *p_src =
  321. (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
  322. uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane];
  323. for (x = 0; x < w; x++) {
  324. *p_dst++ = (uint8_t)(*p_src++);
  325. }
  326. }
  327. }
  328. }
  329. static void highbd_img_downshift(vpx_image_t *dst, vpx_image_t *src,
  330. int down_shift) {
  331. int plane;
  332. if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
  333. dst->x_chroma_shift != src->x_chroma_shift ||
  334. dst->y_chroma_shift != src->y_chroma_shift || dst->fmt != src->fmt ||
  335. down_shift < 0) {
  336. fatal("Unsupported image conversion");
  337. }
  338. switch (src->fmt) {
  339. case VPX_IMG_FMT_I42016:
  340. case VPX_IMG_FMT_I42216:
  341. case VPX_IMG_FMT_I44416:
  342. case VPX_IMG_FMT_I44016: break;
  343. default: fatal("Unsupported image conversion"); break;
  344. }
  345. for (plane = 0; plane < 3; plane++) {
  346. int w = src->d_w;
  347. int h = src->d_h;
  348. int x, y;
  349. if (plane) {
  350. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  351. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  352. }
  353. for (y = 0; y < h; y++) {
  354. uint16_t *p_src =
  355. (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
  356. uint16_t *p_dst =
  357. (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
  358. for (x = 0; x < w; x++) *p_dst++ = *p_src++ >> down_shift;
  359. }
  360. }
  361. }
  362. static void lowbd_img_downshift(vpx_image_t *dst, vpx_image_t *src,
  363. int down_shift) {
  364. int plane;
  365. if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
  366. dst->x_chroma_shift != src->x_chroma_shift ||
  367. dst->y_chroma_shift != src->y_chroma_shift ||
  368. src->fmt != dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH || down_shift < 0) {
  369. fatal("Unsupported image conversion");
  370. }
  371. switch (dst->fmt) {
  372. case VPX_IMG_FMT_I420:
  373. case VPX_IMG_FMT_I422:
  374. case VPX_IMG_FMT_I444:
  375. case VPX_IMG_FMT_I440: break;
  376. default: fatal("Unsupported image conversion"); break;
  377. }
  378. for (plane = 0; plane < 3; plane++) {
  379. int w = src->d_w;
  380. int h = src->d_h;
  381. int x, y;
  382. if (plane) {
  383. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  384. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  385. }
  386. for (y = 0; y < h; y++) {
  387. uint16_t *p_src =
  388. (uint16_t *)(src->planes[plane] + y * src->stride[plane]);
  389. uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane];
  390. for (x = 0; x < w; x++) {
  391. *p_dst++ = *p_src++ >> down_shift;
  392. }
  393. }
  394. }
  395. }
  396. void vpx_img_downshift(vpx_image_t *dst, vpx_image_t *src, int down_shift) {
  397. if (dst->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
  398. highbd_img_downshift(dst, src, down_shift);
  399. } else {
  400. lowbd_img_downshift(dst, src, down_shift);
  401. }
  402. }
  403. #endif // CONFIG_VP9_HIGHBITDEPTH