2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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.
19 #include "common/tools_common.h"
21 #if CONFIG_AV1_ENCODER
22 #include "aom/aomcx.h"
25 #if CONFIG_AV1_DECODER
26 #include "aom/aomdx.h"
29 #if defined(_WIN32) || defined(__OS2__)
34 #define _setmode setmode
35 #define _fileno fileno
36 #define _O_BINARY O_BINARY
40 #define LOG_ERROR(label) \
42 const char *l = label; \
45 if (l) fprintf(stderr, "%s: ", l); \
46 vfprintf(stderr, fmt, ap); \
47 fprintf(stderr, "\n"); \
51 FILE *set_binary_mode(FILE *stream
) {
53 #if defined(_WIN32) || defined(__OS2__)
54 _setmode(_fileno(stream
), _O_BINARY
);
59 void die(const char *fmt
, ...) {
64 void fatal(const char *fmt
, ...) {
69 void aom_tools_warn(const char *fmt
, ...) { LOG_ERROR("Warning"); }
71 void die_codec(aom_codec_ctx_t
*ctx
, const char *s
) {
72 const char *detail
= aom_codec_error_detail(ctx
);
74 printf("%s: %s\n", s
, aom_codec_error(ctx
));
75 if (detail
) printf(" %s\n", detail
);
79 int read_yuv_frame(struct AvxInputContext
*input_ctx
, aom_image_t
*yuv_frame
) {
80 FILE *f
= input_ctx
->file
;
81 struct FileTypeDetectionBuffer
*detect
= &input_ctx
->detect
;
84 const int bytespp
= (yuv_frame
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) ? 2 : 1;
86 for (plane
= 0; plane
< 3; ++plane
) {
88 const int w
= aom_img_plane_width(yuv_frame
, plane
);
89 const int h
= aom_img_plane_height(yuv_frame
, plane
);
92 /* Determine the correct plane based on the image format. The for-loop
93 * always counts in Y,U,V order, but this may not match the order of
99 yuv_frame
->planes
[yuv_frame
->fmt
== AOM_IMG_FMT_YV12
? AOM_PLANE_V
104 yuv_frame
->planes
[yuv_frame
->fmt
== AOM_IMG_FMT_YV12
? AOM_PLANE_U
107 default: ptr
= yuv_frame
->planes
[plane
];
110 for (r
= 0; r
< h
; ++r
) {
111 size_t needed
= w
* bytespp
;
112 size_t buf_position
= 0;
113 const size_t left
= detect
->buf_read
- detect
->position
;
115 const size_t more
= (left
< needed
) ? left
: needed
;
116 memcpy(ptr
, detect
->buf
+ detect
->position
, more
);
119 detect
->position
+= more
;
122 shortread
|= (fread(ptr
+ buf_position
, 1, needed
, f
) < needed
);
125 ptr
+= yuv_frame
->stride
[plane
];
133 // Pointer to a function of zero arguments that returns an aom_codec_iface_t.
134 aom_codec_iface_t
*(*const interface
)();
139 #if CONFIG_AV1_ENCODER
140 static const struct CodecInfo aom_encoders
[] = {
141 { &aom_codec_av1_cx
, "av1", AV1_FOURCC
},
144 int get_aom_encoder_count(void) {
145 return sizeof(aom_encoders
) / sizeof(aom_encoders
[0]);
148 aom_codec_iface_t
*get_aom_encoder_by_index(int i
) {
149 assert(i
>= 0 && i
< get_aom_encoder_count());
150 return aom_encoders
[i
].interface();
153 aom_codec_iface_t
*get_aom_encoder_by_short_name(const char *name
) {
154 for (int i
= 0; i
< get_aom_encoder_count(); ++i
) {
155 const struct CodecInfo
*info
= &aom_encoders
[i
];
156 if (strcmp(info
->short_name
, name
) == 0) return info
->interface();
161 uint32_t get_fourcc_by_aom_encoder(aom_codec_iface_t
*iface
) {
162 for (int i
= 0; i
< get_aom_encoder_count(); ++i
) {
163 const struct CodecInfo
*info
= &aom_encoders
[i
];
164 if (info
->interface() == iface
) {
171 const char *get_short_name_by_aom_encoder(aom_codec_iface_t
*iface
) {
172 for (int i
= 0; i
< get_aom_encoder_count(); ++i
) {
173 const struct CodecInfo
*info
= &aom_encoders
[i
];
174 if (info
->interface() == iface
) {
175 return info
->short_name
;
181 #endif // CONFIG_AV1_ENCODER
183 #if CONFIG_AV1_DECODER
184 static const struct CodecInfo aom_decoders
[] = {
185 { &aom_codec_av1_dx
, "av1", AV1_FOURCC
},
188 int get_aom_decoder_count(void) {
189 return sizeof(aom_decoders
) / sizeof(aom_decoders
[0]);
192 aom_codec_iface_t
*get_aom_decoder_by_index(int i
) {
193 assert(i
>= 0 && i
< get_aom_decoder_count());
194 return aom_decoders
[i
].interface();
197 aom_codec_iface_t
*get_aom_decoder_by_short_name(const char *name
) {
198 for (int i
= 0; i
< get_aom_decoder_count(); ++i
) {
199 const struct CodecInfo
*info
= &aom_decoders
[i
];
200 if (strcmp(info
->short_name
, name
) == 0) return info
->interface();
205 aom_codec_iface_t
*get_aom_decoder_by_fourcc(uint32_t fourcc
) {
206 for (int i
= 0; i
< get_aom_decoder_count(); ++i
) {
207 const struct CodecInfo
*info
= &aom_decoders
[i
];
208 if (info
->fourcc
== fourcc
) return info
->interface();
213 const char *get_short_name_by_aom_decoder(aom_codec_iface_t
*iface
) {
214 for (int i
= 0; i
< get_aom_decoder_count(); ++i
) {
215 const struct CodecInfo
*info
= &aom_decoders
[i
];
216 if (info
->interface() == iface
) {
217 return info
->short_name
;
223 uint32_t get_fourcc_by_aom_decoder(aom_codec_iface_t
*iface
) {
224 for (int i
= 0; i
< get_aom_decoder_count(); ++i
) {
225 const struct CodecInfo
*info
= &aom_decoders
[i
];
226 if (info
->interface() == iface
) {
233 #endif // CONFIG_AV1_DECODER
235 void aom_img_write(const aom_image_t
*img
, FILE *file
) {
238 for (plane
= 0; plane
< 3; ++plane
) {
239 const unsigned char *buf
= img
->planes
[plane
];
240 const int stride
= img
->stride
[plane
];
241 const int w
= aom_img_plane_width(img
, plane
) *
242 ((img
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) ? 2 : 1);
243 const int h
= aom_img_plane_height(img
, plane
);
246 for (y
= 0; y
< h
; ++y
) {
247 fwrite(buf
, 1, w
, file
);
253 int aom_img_read(aom_image_t
*img
, FILE *file
) {
256 for (plane
= 0; plane
< 3; ++plane
) {
257 unsigned char *buf
= img
->planes
[plane
];
258 const int stride
= img
->stride
[plane
];
259 const int w
= aom_img_plane_width(img
, plane
) *
260 ((img
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) ? 2 : 1);
261 const int h
= aom_img_plane_height(img
, plane
);
264 for (y
= 0; y
< h
; ++y
) {
265 if (fread(buf
, 1, w
, file
) != (size_t)w
) return 0;
273 // TODO(dkovalev) change sse_to_psnr signature: double -> int64_t
274 double sse_to_psnr(double samples
, double peak
, double sse
) {
275 static const double kMaxPSNR
= 100.0;
278 const double psnr
= 10.0 * log10(samples
* peak
* peak
/ sse
);
279 return psnr
> kMaxPSNR
? kMaxPSNR
: psnr
;
285 // TODO(debargha): Consolidate the functions below into a separate file.
286 static void highbd_img_upshift(aom_image_t
*dst
, const aom_image_t
*src
,
288 // Note the offset is 1 less than half.
289 const int offset
= input_shift
> 0 ? (1 << (input_shift
- 1)) - 1 : 0;
291 if (dst
->d_w
!= src
->d_w
|| dst
->d_h
!= src
->d_h
||
292 dst
->x_chroma_shift
!= src
->x_chroma_shift
||
293 dst
->y_chroma_shift
!= src
->y_chroma_shift
|| dst
->fmt
!= src
->fmt
||
295 fatal("Unsupported image conversion");
298 case AOM_IMG_FMT_I42016
:
299 case AOM_IMG_FMT_I42216
:
300 case AOM_IMG_FMT_I44416
: break;
301 default: fatal("Unsupported image conversion"); break;
303 for (plane
= 0; plane
< 3; plane
++) {
308 w
= (w
+ src
->x_chroma_shift
) >> src
->x_chroma_shift
;
309 h
= (h
+ src
->y_chroma_shift
) >> src
->y_chroma_shift
;
311 for (y
= 0; y
< h
; y
++) {
312 const uint16_t *p_src
=
313 (const uint16_t *)(src
->planes
[plane
] + y
* src
->stride
[plane
]);
315 (uint16_t *)(dst
->planes
[plane
] + y
* dst
->stride
[plane
]);
316 for (x
= 0; x
< w
; x
++) *p_dst
++ = (*p_src
++ << input_shift
) + offset
;
321 static void lowbd_img_upshift(aom_image_t
*dst
, const aom_image_t
*src
,
323 // Note the offset is 1 less than half.
324 const int offset
= input_shift
> 0 ? (1 << (input_shift
- 1)) - 1 : 0;
326 if (dst
->d_w
!= src
->d_w
|| dst
->d_h
!= src
->d_h
||
327 dst
->x_chroma_shift
!= src
->x_chroma_shift
||
328 dst
->y_chroma_shift
!= src
->y_chroma_shift
||
329 dst
->fmt
!= src
->fmt
+ AOM_IMG_FMT_HIGHBITDEPTH
|| input_shift
< 0) {
330 fatal("Unsupported image conversion");
333 case AOM_IMG_FMT_YV12
:
334 case AOM_IMG_FMT_I420
:
335 case AOM_IMG_FMT_I422
:
336 case AOM_IMG_FMT_I444
: break;
337 default: fatal("Unsupported image conversion"); break;
339 for (plane
= 0; plane
< 3; plane
++) {
344 w
= (w
+ src
->x_chroma_shift
) >> src
->x_chroma_shift
;
345 h
= (h
+ src
->y_chroma_shift
) >> src
->y_chroma_shift
;
347 for (y
= 0; y
< h
; y
++) {
348 const uint8_t *p_src
= src
->planes
[plane
] + y
* src
->stride
[plane
];
350 (uint16_t *)(dst
->planes
[plane
] + y
* dst
->stride
[plane
]);
351 for (x
= 0; x
< w
; x
++) {
352 *p_dst
++ = (*p_src
++ << input_shift
) + offset
;
358 void aom_img_upshift(aom_image_t
*dst
, const aom_image_t
*src
,
360 if (src
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) {
361 highbd_img_upshift(dst
, src
, input_shift
);
363 lowbd_img_upshift(dst
, src
, input_shift
);
367 void aom_img_truncate_16_to_8(aom_image_t
*dst
, const aom_image_t
*src
) {
369 if (dst
->fmt
+ AOM_IMG_FMT_HIGHBITDEPTH
!= src
->fmt
|| dst
->d_w
!= src
->d_w
||
370 dst
->d_h
!= src
->d_h
|| dst
->x_chroma_shift
!= src
->x_chroma_shift
||
371 dst
->y_chroma_shift
!= src
->y_chroma_shift
) {
372 fatal("Unsupported image conversion");
375 case AOM_IMG_FMT_I420
:
376 case AOM_IMG_FMT_I422
:
377 case AOM_IMG_FMT_I444
: break;
378 default: fatal("Unsupported image conversion"); break;
380 for (plane
= 0; plane
< 3; plane
++) {
385 w
= (w
+ src
->x_chroma_shift
) >> src
->x_chroma_shift
;
386 h
= (h
+ src
->y_chroma_shift
) >> src
->y_chroma_shift
;
388 for (y
= 0; y
< h
; y
++) {
389 const uint16_t *p_src
=
390 (const uint16_t *)(src
->planes
[plane
] + y
* src
->stride
[plane
]);
391 uint8_t *p_dst
= dst
->planes
[plane
] + y
* dst
->stride
[plane
];
392 for (x
= 0; x
< w
; x
++) {
393 *p_dst
++ = (uint8_t)(*p_src
++);
399 static void highbd_img_downshift(aom_image_t
*dst
, const aom_image_t
*src
,
402 if (dst
->d_w
!= src
->d_w
|| dst
->d_h
!= src
->d_h
||
403 dst
->x_chroma_shift
!= src
->x_chroma_shift
||
404 dst
->y_chroma_shift
!= src
->y_chroma_shift
|| dst
->fmt
!= src
->fmt
||
406 fatal("Unsupported image conversion");
409 case AOM_IMG_FMT_I42016
:
410 case AOM_IMG_FMT_I42216
:
411 case AOM_IMG_FMT_I44416
: break;
412 default: fatal("Unsupported image conversion"); break;
414 for (plane
= 0; plane
< 3; plane
++) {
419 w
= (w
+ src
->x_chroma_shift
) >> src
->x_chroma_shift
;
420 h
= (h
+ src
->y_chroma_shift
) >> src
->y_chroma_shift
;
422 for (y
= 0; y
< h
; y
++) {
423 const uint16_t *p_src
=
424 (const uint16_t *)(src
->planes
[plane
] + y
* src
->stride
[plane
]);
426 (uint16_t *)(dst
->planes
[plane
] + y
* dst
->stride
[plane
]);
427 for (x
= 0; x
< w
; x
++) *p_dst
++ = *p_src
++ >> down_shift
;
432 static void lowbd_img_downshift(aom_image_t
*dst
, const aom_image_t
*src
,
435 if (dst
->d_w
!= src
->d_w
|| dst
->d_h
!= src
->d_h
||
436 dst
->x_chroma_shift
!= src
->x_chroma_shift
||
437 dst
->y_chroma_shift
!= src
->y_chroma_shift
||
438 src
->fmt
!= dst
->fmt
+ AOM_IMG_FMT_HIGHBITDEPTH
|| down_shift
< 0) {
439 fatal("Unsupported image conversion");
442 case AOM_IMG_FMT_I420
:
443 case AOM_IMG_FMT_I422
:
444 case AOM_IMG_FMT_I444
: break;
445 default: fatal("Unsupported image conversion"); break;
447 for (plane
= 0; plane
< 3; plane
++) {
452 w
= (w
+ src
->x_chroma_shift
) >> src
->x_chroma_shift
;
453 h
= (h
+ src
->y_chroma_shift
) >> src
->y_chroma_shift
;
455 for (y
= 0; y
< h
; y
++) {
456 const uint16_t *p_src
=
457 (const uint16_t *)(src
->planes
[plane
] + y
* src
->stride
[plane
]);
458 uint8_t *p_dst
= dst
->planes
[plane
] + y
* dst
->stride
[plane
];
459 for (x
= 0; x
< w
; x
++) {
460 *p_dst
++ = *p_src
++ >> down_shift
;
466 void aom_img_downshift(aom_image_t
*dst
, const aom_image_t
*src
,
468 if (dst
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) {
469 highbd_img_downshift(dst
, src
, down_shift
);
471 lowbd_img_downshift(dst
, src
, down_shift
);
475 static int img_shifted_realloc_required(const aom_image_t
*img
,
476 const aom_image_t
*shifted
,
477 aom_img_fmt_t required_fmt
) {
478 return img
->d_w
!= shifted
->d_w
|| img
->d_h
!= shifted
->d_h
||
479 required_fmt
!= shifted
->fmt
;
482 void aom_shift_img(unsigned int output_bit_depth
, aom_image_t
**img_ptr
,
483 aom_image_t
**img_shifted_ptr
) {
484 aom_image_t
*img
= *img_ptr
;
485 aom_image_t
*img_shifted
= *img_shifted_ptr
;
487 const aom_img_fmt_t shifted_fmt
= output_bit_depth
== 8
488 ? img
->fmt
& ~AOM_IMG_FMT_HIGHBITDEPTH
489 : img
->fmt
| AOM_IMG_FMT_HIGHBITDEPTH
;
491 if (shifted_fmt
!= img
->fmt
|| output_bit_depth
!= img
->bit_depth
) {
493 img_shifted_realloc_required(img
, img_shifted
, shifted_fmt
)) {
494 aom_img_free(img_shifted
);
498 img_shifted
->monochrome
= img
->monochrome
;
501 img_shifted
= aom_img_alloc(NULL
, shifted_fmt
, img
->d_w
, img
->d_h
, 16);
502 img_shifted
->bit_depth
= output_bit_depth
;
503 img_shifted
->monochrome
= img
->monochrome
;
504 img_shifted
->csp
= img
->csp
;
506 if (output_bit_depth
> img
->bit_depth
) {
507 aom_img_upshift(img_shifted
, img
, output_bit_depth
- img
->bit_depth
);
509 aom_img_downshift(img_shifted
, img
, img
->bit_depth
- output_bit_depth
);
511 *img_shifted_ptr
= img_shifted
;
512 *img_ptr
= img_shifted
;
516 // Related to I420, NV12 format has one luma "luminance" plane Y and one plane
517 // with U and V values interleaved.
518 void aom_img_write_nv12(const aom_image_t
*img
, FILE *file
) {
520 const unsigned char *buf
= img
->planes
[0];
521 int stride
= img
->stride
[0];
522 int w
= aom_img_plane_width(img
, 0) *
523 ((img
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) ? 2 : 1);
524 int h
= aom_img_plane_height(img
, 0);
527 for (y
= 0; y
< h
; ++y
) {
528 fwrite(buf
, 1, w
, file
);
532 // Interleaved U and V plane
533 const unsigned char *ubuf
= img
->planes
[1];
534 const unsigned char *vbuf
= img
->planes
[2];
535 const size_t size
= (img
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) ? 2 : 1;
536 stride
= img
->stride
[1];
537 w
= aom_img_plane_width(img
, 1);
538 h
= aom_img_plane_height(img
, 1);
540 for (y
= 0; y
< h
; ++y
) {
541 for (x
= 0; x
< w
; ++x
) {
542 fwrite(ubuf
, size
, 1, file
);
543 fwrite(vbuf
, size
, 1, file
);
547 ubuf
+= (stride
- w
* size
);
548 vbuf
+= (stride
- w
* size
);