tools_common.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. /*
  2. * Copyright (c) 2016, Alliance for Open Media. All rights reserved
  3. *
  4. * This source code is subject to the terms of the BSD 2 Clause License and
  5. * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
  6. * was not distributed with this source code in the LICENSE file, you can
  7. * obtain it at www.aomedia.org/license/software. If the Alliance for Open
  8. * Media Patent License 1.0 was not distributed with this source code in the
  9. * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
  10. */
  11. #include <assert.h>
  12. #include <math.h>
  13. #include <stdarg.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "common/tools_common.h"
  18. #if CONFIG_AV1_ENCODER
  19. #include "aom/aomcx.h"
  20. #endif
  21. #if CONFIG_AV1_DECODER
  22. #include "aom/aomdx.h"
  23. #endif
  24. #if defined(_WIN32)
  25. #include <io.h>
  26. #include <fcntl.h>
  27. #endif
  28. #define LOG_ERROR(label) \
  29. do { \
  30. const char *l = label; \
  31. va_list ap; \
  32. va_start(ap, fmt); \
  33. if (l) fprintf(stderr, "%s: ", l); \
  34. vfprintf(stderr, fmt, ap); \
  35. fprintf(stderr, "\n"); \
  36. va_end(ap); \
  37. } while (0)
  38. FILE *set_binary_mode(FILE *stream) {
  39. (void)stream;
  40. #if defined(_WIN32)
  41. _setmode(_fileno(stream), _O_BINARY);
  42. #endif
  43. return stream;
  44. }
  45. void die(const char *fmt, ...) {
  46. LOG_ERROR(NULL);
  47. usage_exit();
  48. }
  49. void fatal(const char *fmt, ...) {
  50. LOG_ERROR("Fatal");
  51. exit(EXIT_FAILURE);
  52. }
  53. void aom_tools_warn(const char *fmt, ...) { LOG_ERROR("Warning"); }
  54. void die_codec(aom_codec_ctx_t *ctx, const char *s) {
  55. const char *detail = aom_codec_error_detail(ctx);
  56. fprintf(stderr, "%s: %s\n", s, aom_codec_error(ctx));
  57. if (detail) fprintf(stderr, " %s\n", detail);
  58. exit(EXIT_FAILURE);
  59. }
  60. const char *image_format_to_string(aom_img_fmt_t fmt) {
  61. switch (fmt) {
  62. case AOM_IMG_FMT_I420: return "I420";
  63. case AOM_IMG_FMT_I422: return "I422";
  64. case AOM_IMG_FMT_I444: return "I444";
  65. case AOM_IMG_FMT_YV12: return "YV12";
  66. case AOM_IMG_FMT_NV12: return "NV12";
  67. case AOM_IMG_FMT_YV1216: return "YV1216";
  68. case AOM_IMG_FMT_I42016: return "I42016";
  69. case AOM_IMG_FMT_I42216: return "I42216";
  70. case AOM_IMG_FMT_I44416: return "I44416";
  71. default: return "Other";
  72. }
  73. }
  74. int read_yuv_frame(struct AvxInputContext *input_ctx, aom_image_t *yuv_frame) {
  75. FILE *f = input_ctx->file;
  76. struct FileTypeDetectionBuffer *detect = &input_ctx->detect;
  77. int plane = 0;
  78. int shortread = 0;
  79. const int bytespp = (yuv_frame->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
  80. for (plane = 0; plane < 3; ++plane) {
  81. uint8_t *ptr;
  82. int w = aom_img_plane_width(yuv_frame, plane);
  83. const int h = aom_img_plane_height(yuv_frame, plane);
  84. int r;
  85. // Assuming that for nv12 we read all chroma data at one time
  86. if (yuv_frame->fmt == AOM_IMG_FMT_NV12 && plane > 1) break;
  87. if (yuv_frame->fmt == AOM_IMG_FMT_NV12 && plane == 1) w *= 2;
  88. /* Determine the correct plane based on the image format. The for-loop
  89. * always counts in Y,U,V order, but this may not match the order of
  90. * the data on disk.
  91. */
  92. switch (plane) {
  93. case 1:
  94. ptr =
  95. yuv_frame->planes[yuv_frame->fmt == AOM_IMG_FMT_YV12 ? AOM_PLANE_V
  96. : AOM_PLANE_U];
  97. break;
  98. case 2:
  99. ptr =
  100. yuv_frame->planes[yuv_frame->fmt == AOM_IMG_FMT_YV12 ? AOM_PLANE_U
  101. : AOM_PLANE_V];
  102. break;
  103. default: ptr = yuv_frame->planes[plane];
  104. }
  105. for (r = 0; r < h; ++r) {
  106. size_t needed = w * bytespp;
  107. size_t buf_position = 0;
  108. const size_t left = detect->buf_read - detect->position;
  109. if (left > 0) {
  110. const size_t more = (left < needed) ? left : needed;
  111. memcpy(ptr, detect->buf + detect->position, more);
  112. buf_position = more;
  113. needed -= more;
  114. detect->position += more;
  115. }
  116. if (needed > 0) {
  117. shortread |= (fread(ptr + buf_position, 1, needed, f) < needed);
  118. }
  119. ptr += yuv_frame->stride[plane];
  120. }
  121. }
  122. return shortread;
  123. }
  124. struct CodecInfo {
  125. // Pointer to a function of zero arguments that returns an aom_codec_iface_t.
  126. aom_codec_iface_t *(*interface)(void);
  127. const char *short_name;
  128. uint32_t fourcc;
  129. };
  130. #if CONFIG_AV1_ENCODER
  131. static const struct CodecInfo aom_encoders[] = {
  132. { &aom_codec_av1_cx, "av1", AV1_FOURCC },
  133. };
  134. int get_aom_encoder_count(void) {
  135. return sizeof(aom_encoders) / sizeof(aom_encoders[0]);
  136. }
  137. aom_codec_iface_t *get_aom_encoder_by_index(int i) {
  138. assert(i >= 0 && i < get_aom_encoder_count());
  139. return aom_encoders[i].interface();
  140. }
  141. aom_codec_iface_t *get_aom_encoder_by_short_name(const char *name) {
  142. for (int i = 0; i < get_aom_encoder_count(); ++i) {
  143. const struct CodecInfo *info = &aom_encoders[i];
  144. if (strcmp(info->short_name, name) == 0) return info->interface();
  145. }
  146. return NULL;
  147. }
  148. uint32_t get_fourcc_by_aom_encoder(aom_codec_iface_t *iface) {
  149. for (int i = 0; i < get_aom_encoder_count(); ++i) {
  150. const struct CodecInfo *info = &aom_encoders[i];
  151. if (info->interface() == iface) {
  152. return info->fourcc;
  153. }
  154. }
  155. return 0;
  156. }
  157. const char *get_short_name_by_aom_encoder(aom_codec_iface_t *iface) {
  158. for (int i = 0; i < get_aom_encoder_count(); ++i) {
  159. const struct CodecInfo *info = &aom_encoders[i];
  160. if (info->interface() == iface) {
  161. return info->short_name;
  162. }
  163. }
  164. return NULL;
  165. }
  166. #endif // CONFIG_AV1_ENCODER
  167. #if CONFIG_AV1_DECODER
  168. static const struct CodecInfo aom_decoders[] = {
  169. { &aom_codec_av1_dx, "av1", AV1_FOURCC },
  170. };
  171. int get_aom_decoder_count(void) {
  172. return sizeof(aom_decoders) / sizeof(aom_decoders[0]);
  173. }
  174. aom_codec_iface_t *get_aom_decoder_by_index(int i) {
  175. assert(i >= 0 && i < get_aom_decoder_count());
  176. return aom_decoders[i].interface();
  177. }
  178. aom_codec_iface_t *get_aom_decoder_by_short_name(const char *name) {
  179. for (int i = 0; i < get_aom_decoder_count(); ++i) {
  180. const struct CodecInfo *info = &aom_decoders[i];
  181. if (strcmp(info->short_name, name) == 0) return info->interface();
  182. }
  183. return NULL;
  184. }
  185. aom_codec_iface_t *get_aom_decoder_by_fourcc(uint32_t fourcc) {
  186. for (int i = 0; i < get_aom_decoder_count(); ++i) {
  187. const struct CodecInfo *info = &aom_decoders[i];
  188. if (info->fourcc == fourcc) return info->interface();
  189. }
  190. return NULL;
  191. }
  192. const char *get_short_name_by_aom_decoder(aom_codec_iface_t *iface) {
  193. for (int i = 0; i < get_aom_decoder_count(); ++i) {
  194. const struct CodecInfo *info = &aom_decoders[i];
  195. if (info->interface() == iface) {
  196. return info->short_name;
  197. }
  198. }
  199. return NULL;
  200. }
  201. uint32_t get_fourcc_by_aom_decoder(aom_codec_iface_t *iface) {
  202. for (int i = 0; i < get_aom_decoder_count(); ++i) {
  203. const struct CodecInfo *info = &aom_decoders[i];
  204. if (info->interface() == iface) {
  205. return info->fourcc;
  206. }
  207. }
  208. return 0;
  209. }
  210. #endif // CONFIG_AV1_DECODER
  211. void aom_img_write(const aom_image_t *img, FILE *file) {
  212. int plane;
  213. for (plane = 0; plane < 3; ++plane) {
  214. const unsigned char *buf = img->planes[plane];
  215. const int stride = img->stride[plane];
  216. const int w = aom_img_plane_width(img, plane) *
  217. ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
  218. const int h = aom_img_plane_height(img, plane);
  219. int y;
  220. for (y = 0; y < h; ++y) {
  221. fwrite(buf, 1, w, file);
  222. buf += stride;
  223. }
  224. }
  225. }
  226. bool aom_img_read(aom_image_t *img, FILE *file) {
  227. int plane;
  228. const int bytespp = (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
  229. for (plane = 0; plane < 3; ++plane) {
  230. unsigned char *buf = img->planes[plane];
  231. const int stride = img->stride[plane];
  232. const int w = aom_img_plane_width(img, plane) * bytespp;
  233. const int h = aom_img_plane_height(img, plane);
  234. int y;
  235. for (y = 0; y < h; ++y) {
  236. if (fread(buf, 1, w, file) != (size_t)w) return false;
  237. buf += stride;
  238. }
  239. }
  240. return true;
  241. }
  242. // TODO(dkovalev) change sse_to_psnr signature: double -> int64_t
  243. double sse_to_psnr(double samples, double peak, double sse) {
  244. static const double kMaxPSNR = 100.0;
  245. if (sse > 0.0) {
  246. const double psnr = 10.0 * log10(samples * peak * peak / sse);
  247. return psnr > kMaxPSNR ? kMaxPSNR : psnr;
  248. } else {
  249. return kMaxPSNR;
  250. }
  251. }
  252. // TODO(debargha): Consolidate the functions below into a separate file.
  253. static void highbd_img_upshift(aom_image_t *dst, const aom_image_t *src,
  254. int input_shift) {
  255. // Note the offset is 1 less than half.
  256. const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
  257. int plane;
  258. if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
  259. dst->x_chroma_shift != src->x_chroma_shift ||
  260. dst->y_chroma_shift != src->y_chroma_shift || dst->fmt != src->fmt ||
  261. input_shift < 0) {
  262. fatal("Unsupported image conversion");
  263. }
  264. switch (src->fmt) {
  265. case AOM_IMG_FMT_I42016:
  266. case AOM_IMG_FMT_I42216:
  267. case AOM_IMG_FMT_I44416: break;
  268. default: fatal("Unsupported image conversion");
  269. }
  270. for (plane = 0; plane < 3; plane++) {
  271. int w = src->d_w;
  272. int h = src->d_h;
  273. int x, y;
  274. if (plane) {
  275. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  276. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  277. }
  278. for (y = 0; y < h; y++) {
  279. const uint16_t *p_src =
  280. (const uint16_t *)(src->planes[plane] + y * src->stride[plane]);
  281. uint16_t *p_dst =
  282. (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
  283. for (x = 0; x < w; x++) *p_dst++ = (*p_src++ << input_shift) + offset;
  284. }
  285. }
  286. }
  287. static void lowbd_img_upshift(aom_image_t *dst, const aom_image_t *src,
  288. int input_shift) {
  289. // Note the offset is 1 less than half.
  290. const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
  291. int plane;
  292. if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
  293. dst->x_chroma_shift != src->x_chroma_shift ||
  294. dst->y_chroma_shift != src->y_chroma_shift ||
  295. dst->fmt != src->fmt + AOM_IMG_FMT_HIGHBITDEPTH || input_shift < 0) {
  296. fatal("Unsupported image conversion");
  297. }
  298. switch (src->fmt) {
  299. case AOM_IMG_FMT_YV12:
  300. case AOM_IMG_FMT_I420:
  301. case AOM_IMG_FMT_I422:
  302. case AOM_IMG_FMT_I444: break;
  303. default: fatal("Unsupported image conversion");
  304. }
  305. for (plane = 0; plane < 3; plane++) {
  306. int w = src->d_w;
  307. int h = src->d_h;
  308. int x, y;
  309. if (plane) {
  310. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  311. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  312. }
  313. for (y = 0; y < h; y++) {
  314. const uint8_t *p_src = src->planes[plane] + y * src->stride[plane];
  315. uint16_t *p_dst =
  316. (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
  317. for (x = 0; x < w; x++) {
  318. *p_dst++ = (*p_src++ << input_shift) + offset;
  319. }
  320. }
  321. }
  322. }
  323. void aom_img_upshift(aom_image_t *dst, const aom_image_t *src,
  324. int input_shift) {
  325. if (src->fmt & AOM_IMG_FMT_HIGHBITDEPTH) {
  326. highbd_img_upshift(dst, src, input_shift);
  327. } else {
  328. lowbd_img_upshift(dst, src, input_shift);
  329. }
  330. }
  331. void aom_img_truncate_16_to_8(aom_image_t *dst, const aom_image_t *src) {
  332. int plane;
  333. if (dst->fmt + AOM_IMG_FMT_HIGHBITDEPTH != src->fmt || dst->d_w != src->d_w ||
  334. dst->d_h != src->d_h || dst->x_chroma_shift != src->x_chroma_shift ||
  335. dst->y_chroma_shift != src->y_chroma_shift) {
  336. fatal("Unsupported image conversion");
  337. }
  338. switch (dst->fmt) {
  339. case AOM_IMG_FMT_I420:
  340. case AOM_IMG_FMT_I422:
  341. case AOM_IMG_FMT_I444: break;
  342. default: fatal("Unsupported image conversion");
  343. }
  344. for (plane = 0; plane < 3; plane++) {
  345. int w = src->d_w;
  346. int h = src->d_h;
  347. int x, y;
  348. if (plane) {
  349. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  350. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  351. }
  352. for (y = 0; y < h; y++) {
  353. const uint16_t *p_src =
  354. (const uint16_t *)(src->planes[plane] + y * src->stride[plane]);
  355. uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane];
  356. for (x = 0; x < w; x++) {
  357. *p_dst++ = (uint8_t)(*p_src++);
  358. }
  359. }
  360. }
  361. }
  362. static void highbd_img_downshift(aom_image_t *dst, const aom_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 || dst->fmt != src->fmt ||
  368. down_shift < 0) {
  369. fatal("Unsupported image conversion");
  370. }
  371. switch (src->fmt) {
  372. case AOM_IMG_FMT_I42016:
  373. case AOM_IMG_FMT_I42216:
  374. case AOM_IMG_FMT_I44416: break;
  375. default: fatal("Unsupported image conversion");
  376. }
  377. for (plane = 0; plane < 3; plane++) {
  378. int w = src->d_w;
  379. int h = src->d_h;
  380. int x, y;
  381. if (plane) {
  382. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  383. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  384. }
  385. for (y = 0; y < h; y++) {
  386. const uint16_t *p_src =
  387. (const uint16_t *)(src->planes[plane] + y * src->stride[plane]);
  388. uint16_t *p_dst =
  389. (uint16_t *)(dst->planes[plane] + y * dst->stride[plane]);
  390. for (x = 0; x < w; x++) *p_dst++ = *p_src++ >> down_shift;
  391. }
  392. }
  393. }
  394. static void lowbd_img_downshift(aom_image_t *dst, const aom_image_t *src,
  395. int down_shift) {
  396. int plane;
  397. if (dst->d_w != src->d_w || dst->d_h != src->d_h ||
  398. dst->x_chroma_shift != src->x_chroma_shift ||
  399. dst->y_chroma_shift != src->y_chroma_shift ||
  400. src->fmt != dst->fmt + AOM_IMG_FMT_HIGHBITDEPTH || down_shift < 0) {
  401. fatal("Unsupported image conversion");
  402. }
  403. switch (dst->fmt) {
  404. case AOM_IMG_FMT_I420:
  405. case AOM_IMG_FMT_I422:
  406. case AOM_IMG_FMT_I444: break;
  407. default: fatal("Unsupported image conversion");
  408. }
  409. for (plane = 0; plane < 3; plane++) {
  410. int w = src->d_w;
  411. int h = src->d_h;
  412. int x, y;
  413. if (plane) {
  414. w = (w + src->x_chroma_shift) >> src->x_chroma_shift;
  415. h = (h + src->y_chroma_shift) >> src->y_chroma_shift;
  416. }
  417. for (y = 0; y < h; y++) {
  418. const uint16_t *p_src =
  419. (const uint16_t *)(src->planes[plane] + y * src->stride[plane]);
  420. uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane];
  421. for (x = 0; x < w; x++) {
  422. *p_dst++ = *p_src++ >> down_shift;
  423. }
  424. }
  425. }
  426. }
  427. void aom_img_downshift(aom_image_t *dst, const aom_image_t *src,
  428. int down_shift) {
  429. if (dst->fmt & AOM_IMG_FMT_HIGHBITDEPTH) {
  430. highbd_img_downshift(dst, src, down_shift);
  431. } else {
  432. lowbd_img_downshift(dst, src, down_shift);
  433. }
  434. }
  435. static int img_shifted_realloc_required(const aom_image_t *img,
  436. const aom_image_t *shifted,
  437. aom_img_fmt_t required_fmt) {
  438. return img->d_w != shifted->d_w || img->d_h != shifted->d_h ||
  439. required_fmt != shifted->fmt;
  440. }
  441. bool aom_shift_img(unsigned int output_bit_depth, aom_image_t **img_ptr,
  442. aom_image_t **img_shifted_ptr) {
  443. aom_image_t *img = *img_ptr;
  444. aom_image_t *img_shifted = *img_shifted_ptr;
  445. const aom_img_fmt_t shifted_fmt = output_bit_depth == 8
  446. ? img->fmt & ~AOM_IMG_FMT_HIGHBITDEPTH
  447. : img->fmt | AOM_IMG_FMT_HIGHBITDEPTH;
  448. if (shifted_fmt != img->fmt || output_bit_depth != img->bit_depth) {
  449. if (img_shifted &&
  450. img_shifted_realloc_required(img, img_shifted, shifted_fmt)) {
  451. aom_img_free(img_shifted);
  452. img_shifted = NULL;
  453. }
  454. if (img_shifted) {
  455. img_shifted->monochrome = img->monochrome;
  456. }
  457. if (!img_shifted) {
  458. img_shifted = aom_img_alloc(NULL, shifted_fmt, img->d_w, img->d_h, 16);
  459. if (!img_shifted) {
  460. *img_shifted_ptr = NULL;
  461. return false;
  462. }
  463. img_shifted->bit_depth = output_bit_depth;
  464. img_shifted->monochrome = img->monochrome;
  465. img_shifted->csp = img->csp;
  466. }
  467. if (output_bit_depth > img->bit_depth) {
  468. aom_img_upshift(img_shifted, img, output_bit_depth - img->bit_depth);
  469. } else {
  470. aom_img_downshift(img_shifted, img, img->bit_depth - output_bit_depth);
  471. }
  472. *img_shifted_ptr = img_shifted;
  473. *img_ptr = img_shifted;
  474. }
  475. return true;
  476. }
  477. // Related to I420, NV12 format has one luma "luminance" plane Y and one plane
  478. // with U and V values interleaved.
  479. void aom_img_write_nv12(const aom_image_t *img, FILE *file) {
  480. // Y plane
  481. const unsigned char *buf = img->planes[0];
  482. int stride = img->stride[0];
  483. int w = aom_img_plane_width(img, 0) *
  484. ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
  485. int h = aom_img_plane_height(img, 0);
  486. int x, y;
  487. for (y = 0; y < h; ++y) {
  488. fwrite(buf, 1, w, file);
  489. buf += stride;
  490. }
  491. // Interleaved U and V plane
  492. const unsigned char *ubuf = img->planes[1];
  493. const unsigned char *vbuf = img->planes[2];
  494. const size_t size = (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
  495. stride = img->stride[1];
  496. w = aom_img_plane_width(img, 1);
  497. h = aom_img_plane_height(img, 1);
  498. for (y = 0; y < h; ++y) {
  499. for (x = 0; x < w; ++x) {
  500. fwrite(ubuf, size, 1, file);
  501. fwrite(vbuf, size, 1, file);
  502. ubuf += size;
  503. vbuf += size;
  504. }
  505. ubuf += (stride - w * size);
  506. vbuf += (stride - w * size);
  507. }
  508. }
  509. size_t read_from_input(struct AvxInputContext *input_ctx, size_t n,
  510. unsigned char *buf) {
  511. const size_t buffered_bytes =
  512. input_ctx->detect.buf_read - input_ctx->detect.position;
  513. size_t read_n;
  514. if (buffered_bytes == 0) {
  515. read_n = fread(buf, 1, n, input_ctx->file);
  516. } else if (n <= buffered_bytes) {
  517. memcpy(buf, input_ctx->detect.buf + input_ctx->detect.position, n);
  518. input_ctx->detect.position += n;
  519. read_n = n;
  520. } else {
  521. memcpy(buf, input_ctx->detect.buf + input_ctx->detect.position,
  522. buffered_bytes);
  523. input_ctx->detect.position += buffered_bytes;
  524. read_n = buffered_bytes;
  525. read_n +=
  526. fread(buf + buffered_bytes, 1, n - buffered_bytes, input_ctx->file);
  527. }
  528. return read_n;
  529. }
  530. size_t input_to_detect_buf(struct AvxInputContext *input_ctx, size_t n) {
  531. if (n + input_ctx->detect.position > DETECT_BUF_SZ) {
  532. die("Failed to store in the detect buffer, maximum size exceeded.");
  533. }
  534. const size_t buffered_bytes =
  535. input_ctx->detect.buf_read - input_ctx->detect.position;
  536. size_t read_n;
  537. if (buffered_bytes == 0) {
  538. read_n = fread(input_ctx->detect.buf + input_ctx->detect.buf_read, 1, n,
  539. input_ctx->file);
  540. input_ctx->detect.buf_read += read_n;
  541. } else if (n <= buffered_bytes) {
  542. // In this case, don't need to do anything as the data is already in
  543. // the detect buffer
  544. read_n = n;
  545. } else {
  546. read_n = fread(input_ctx->detect.buf + input_ctx->detect.buf_read, 1,
  547. n - buffered_bytes, input_ctx->file);
  548. input_ctx->detect.buf_read += read_n;
  549. read_n += buffered_bytes;
  550. }
  551. return read_n;
  552. }
  553. // Read from detect buffer to a buffer. If not enough, read from input and also
  554. // buffer them first.
  555. size_t buffer_input(struct AvxInputContext *input_ctx, size_t n,
  556. unsigned char *buf, bool buffered) {
  557. if (!buffered) {
  558. return read_from_input(input_ctx, n, buf);
  559. }
  560. const size_t buf_n = input_to_detect_buf(input_ctx, n);
  561. if (buf_n < n) {
  562. return buf_n;
  563. }
  564. return read_from_input(input_ctx, n, buf);
  565. }
  566. void rewind_detect(struct AvxInputContext *input_ctx) {
  567. input_ctx->detect.position = 0;
  568. }
  569. bool input_eof(struct AvxInputContext *input_ctx) {
  570. return feof(input_ctx->file) &&
  571. input_ctx->detect.position == input_ctx->detect.buf_read;
  572. }