diff options
Diffstat (limited to 'media/libaom/src/common')
-rw-r--r-- | media/libaom/src/common/args.c | 90 | ||||
-rw-r--r-- | media/libaom/src/common/args.h | 5 | ||||
-rw-r--r-- | media/libaom/src/common/av1_config.c | 16 | ||||
-rw-r--r-- | media/libaom/src/common/ivfdec.h | 3 | ||||
-rw-r--r-- | media/libaom/src/common/obudec.c | 132 | ||||
-rw-r--r-- | media/libaom/src/common/rawenc.c | 88 | ||||
-rw-r--r-- | media/libaom/src/common/tools_common.c | 83 | ||||
-rw-r--r-- | media/libaom/src/common/tools_common.h | 100 | ||||
-rw-r--r-- | media/libaom/src/common/video_reader.c | 4 | ||||
-rw-r--r-- | media/libaom/src/common/video_reader.h | 3 | ||||
-rw-r--r-- | media/libaom/src/common/video_writer.c | 10 | ||||
-rw-r--r-- | media/libaom/src/common/video_writer.h | 4 | ||||
-rw-r--r-- | media/libaom/src/common/webmdec.cc | 19 | ||||
-rw-r--r-- | media/libaom/src/common/webmenc.cc | 115 | ||||
-rw-r--r-- | media/libaom/src/common/webmenc.h | 24 | ||||
-rw-r--r-- | media/libaom/src/common/y4menc.c | 12 | ||||
-rw-r--r-- | media/libaom/src/common/y4minput.c | 39 | ||||
-rw-r--r-- | media/libaom/src/common/y4minput.h | 8 |
18 files changed, 606 insertions, 149 deletions
diff --git a/media/libaom/src/common/args.c b/media/libaom/src/common/args.c index 7131e24dee..ec2a863534 100644 --- a/media/libaom/src/common/args.c +++ b/media/libaom/src/common/args.c @@ -17,6 +17,7 @@ #include "aom/aom_integer.h" #include "aom_ports/msvc.h" +#include "aom/aom_codec.h" #if defined(__GNUC__) && __GNUC__ extern void die(const char *fmt, ...) __attribute__((noreturn)); @@ -48,20 +49,31 @@ void ignore_end_spaces(char *str) { if (end >= str) end[1] = '\0'; } -int arg_cfg(int *argc, char ***argv, const char *file) { - char **argv_local = (char **)*argv; - char **argv_org = (char **)*argv; +static const char kSbSizeWarningString[] = + "super_block_size has to be 64 or 128."; +static const char kMinpartWarningString[] = + "min_partition_size has to be smaller or equal to max_partition_size."; +static const char kMaxpartWarningString[] = + "max_partition_size has to be smaller or equal to super_block_size."; + +int parse_cfg(const char *file, cfg_options_t *config) { char line[1024 * 10]; FILE *f = fopen(file, "r"); if (!f) return 1; +#define GET_PARAMS(field) \ + if (strcmp(left, #field) == 0) { \ + config->field = atoi(right); \ + continue; \ + } + while (fgets(line, sizeof(line) - 1, f)) { char *actual_line = ignore_front_spaces(line); char *left, *right, *comment; size_t length = strlen(actual_line); if (length == 0 || actual_line[0] == '#') continue; - right = strchr(actual_line, ':'); + right = strchr(actual_line, '='); if (right == NULL) continue; right[0] = '\0'; @@ -74,23 +86,61 @@ int arg_cfg(int *argc, char ***argv, const char *file) { ignore_end_spaces(left); ignore_end_spaces(right); - char **new_args = argv_dup(*argc, (const char **)argv_local); - char *new_line = (char *)malloc(sizeof(*new_line) * 128); - - if (argv_local != argv_org) free(argv_local); - - if (!strcmp(right, "ON")) - snprintf(new_line, sizeof(*new_line) * 128, "--%s", left); - else - snprintf(new_line, sizeof(*new_line) * 128, "--%s=%s", left, right); + GET_PARAMS(super_block_size); + GET_PARAMS(max_partition_size); + GET_PARAMS(min_partition_size); + GET_PARAMS(disable_ab_partition_type); + GET_PARAMS(disable_rect_partition_type); + GET_PARAMS(disable_1to4_partition_type); + GET_PARAMS(disable_flip_idtx); + GET_PARAMS(disable_cdef); + GET_PARAMS(disable_lr); + GET_PARAMS(disable_obmc); + GET_PARAMS(disable_warp_motion); + GET_PARAMS(disable_global_motion); + GET_PARAMS(disable_dist_wtd_comp); + GET_PARAMS(disable_diff_wtd_comp); + GET_PARAMS(disable_inter_intra_comp); + GET_PARAMS(disable_masked_comp); + GET_PARAMS(disable_one_sided_comp); + GET_PARAMS(disable_palette); + GET_PARAMS(disable_intrabc); + GET_PARAMS(disable_cfl); + GET_PARAMS(disable_smooth_intra); + GET_PARAMS(disable_filter_intra); + GET_PARAMS(disable_dual_filter); + GET_PARAMS(disable_intra_angle_delta); + GET_PARAMS(disable_intra_edge_filter); + GET_PARAMS(disable_tx_64x64); + GET_PARAMS(disable_smooth_inter_intra); + GET_PARAMS(disable_inter_inter_wedge); + GET_PARAMS(disable_inter_intra_wedge); + GET_PARAMS(disable_paeth_intra); + GET_PARAMS(disable_trellis_quant); + GET_PARAMS(disable_ref_frame_mv); + GET_PARAMS(reduced_reference_set); + GET_PARAMS(reduced_tx_type_set); + + fprintf(stderr, "\nInvalid parameter: %s", left); + exit(-1); + } - new_args[(*argc) - 1] = new_args[(*argc) - 2]; - new_args[(*argc) - 2] = new_line; - argv_local = new_args; - *argv = new_args; - (*argc)++; + if (config->super_block_size != 128 && config->super_block_size != 64) { + fprintf(stderr, "\n%s", kSbSizeWarningString); + exit(-1); + } + if (config->min_partition_size > config->max_partition_size) { + fprintf(stderr, "\n%s", kMinpartWarningString); + exit(-1); + } + if (config->max_partition_size > config->super_block_size) { + fprintf(stderr, "\n%s", kMaxpartWarningString); + exit(-1); } + fclose(f); + config->init_by_cfg_file = 1; + return 0; } @@ -209,10 +259,6 @@ int arg_parse_int(const struct arg *arg) { return 0; } -struct aom_rational { - int num; /**< fraction numerator */ - int den; /**< fraction denominator */ -}; struct aom_rational arg_parse_rational(const struct arg *arg) { long int rawval; char *endptr; diff --git a/media/libaom/src/common/args.h b/media/libaom/src/common/args.h index 6a26642692..286f7dd1ac 100644 --- a/media/libaom/src/common/args.h +++ b/media/libaom/src/common/args.h @@ -13,6 +13,9 @@ #define AOM_COMMON_ARGS_H_ #include <stdio.h> +#include "aom/aom_codec.h" +#include "aom/aom_encoder.h" + #ifdef __cplusplus extern "C" { #endif @@ -50,7 +53,7 @@ struct arg arg_init(char **argv); int arg_match(struct arg *arg_, const struct arg_def *def, char **argv); char *ignore_front_spaces(const char *str); void ignore_end_spaces(char *str); -int arg_cfg(int *argc, char ***argv, const char *file); +int parse_cfg(const char *file, cfg_options_t *config); const char *arg_next(struct arg *arg); void arg_show_usage(FILE *fp, const struct arg_def *const *defs); char **argv_dup(int argc, const char **argv); diff --git a/media/libaom/src/common/av1_config.c b/media/libaom/src/common/av1_config.c index e8decf76fe..9f5b02015b 100644 --- a/media/libaom/src/common/av1_config.c +++ b/media/libaom/src/common/av1_config.c @@ -237,9 +237,9 @@ static int parse_sequence_header(const uint8_t *const buffer, size_t length, // The reader instance is local to this function, but a pointer to the // reader instance is used within this function and throughout this file to // allow use of the helper macros that reduce parse error checking verbosity. - struct aom_read_bit_buffer reader_instance = { - buffer, buffer + length, 0, &result, bitreader_error_handler - }; + struct aom_read_bit_buffer reader_instance = { buffer, buffer + length, 0, + &result, + bitreader_error_handler }; struct aom_read_bit_buffer *reader = &reader_instance; AV1C_READ_BITS_OR_RETURN_ERROR(seq_profile, 3); @@ -322,7 +322,7 @@ static int parse_sequence_header(const uint8_t *const buffer, size_t length, AV1C_READ_BITS_OR_RETURN_ERROR(max_frame_height_minus_1, frame_height_bits_minus_1 + 1); - int frame_id_numbers_present = 0; + uint8_t frame_id_numbers_present = 0; if (!reduced_still_picture_header) { AV1C_READ_BIT_OR_RETURN_ERROR(frame_id_numbers_present_flag); frame_id_numbers_present = frame_id_numbers_present_flag; @@ -345,7 +345,7 @@ static int parse_sequence_header(const uint8_t *const buffer, size_t length, AV1C_READ_BIT_OR_RETURN_ERROR(enable_order_hint); if (enable_order_hint) { - AV1C_READ_BIT_OR_RETURN_ERROR(enable_jnt_comp); + AV1C_READ_BIT_OR_RETURN_ERROR(enable_dist_wtd_comp); AV1C_READ_BIT_OR_RETURN_ERROR(enable_ref_frame_mvs); } @@ -416,9 +416,9 @@ int read_av1config(const uint8_t *buffer, size_t buffer_length, *bytes_read = 0; int result = 0; - struct aom_read_bit_buffer reader_instance = { - buffer, buffer + buffer_length, 0, &result, bitreader_error_handler - }; + struct aom_read_bit_buffer reader_instance = { buffer, buffer + buffer_length, + 0, &result, + bitreader_error_handler }; struct aom_read_bit_buffer *reader = &reader_instance; memset(config, 0, sizeof(*config)); diff --git a/media/libaom/src/common/ivfdec.h b/media/libaom/src/common/ivfdec.h index ea294faa18..dbc77331f0 100644 --- a/media/libaom/src/common/ivfdec.h +++ b/media/libaom/src/common/ivfdec.h @@ -11,6 +11,7 @@ #ifndef AOM_COMMON_IVFDEC_H_ #define AOM_COMMON_IVFDEC_H_ +#include "aom/aom_codec.h" #include "common/tools_common.h" #ifdef __cplusplus @@ -18,8 +19,6 @@ extern "C" { #endif int file_is_ivf(struct AvxInputContext *input); - -typedef int64_t aom_codec_pts_t; int ivf_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read, size_t *buffer_size, aom_codec_pts_t *pts); diff --git a/media/libaom/src/common/obudec.c b/media/libaom/src/common/obudec.c index acbd12e0c8..650f9973bd 100644 --- a/media/libaom/src/common/obudec.c +++ b/media/libaom/src/common/obudec.c @@ -12,9 +12,11 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <assert.h> #include "common/obudec.h" +#include "aom_dsp/aom_dsp_common.h" #include "aom_ports/mem_ops.h" #include "av1/common/common.h" #include "av1/common/obu_util.h" @@ -24,8 +26,12 @@ #define OBU_HEADER_SIZE 1 #define OBU_EXTENSION_SIZE 1 #define OBU_MAX_LENGTH_FIELD_SIZE 8 + +#define OBU_MAX_HEADER_SIZE \ + (OBU_HEADER_SIZE + OBU_EXTENSION_SIZE + 2 * OBU_MAX_LENGTH_FIELD_SIZE) + #define OBU_DETECTION_SIZE \ - (OBU_HEADER_SIZE + OBU_EXTENSION_SIZE + 3 * OBU_MAX_LENGTH_FIELD_SIZE) + (OBU_HEADER_SIZE + OBU_EXTENSION_SIZE + 4 * OBU_MAX_LENGTH_FIELD_SIZE) // Reads unsigned LEB128 integer and returns 0 upon successful read and decode. // Stores raw bytes in 'value_buffer', length of the number in 'value_length', @@ -117,20 +123,20 @@ static int obudec_read_obu_header_and_size(FILE *f, size_t buffer_capacity, size_t *bytes_read, size_t *payload_length, ObuHeader *obu_header) { - const size_t kMinimumBufferSize = - (OBU_HEADER_SIZE + OBU_EXTENSION_SIZE + OBU_MAX_LENGTH_FIELD_SIZE); + const size_t kMinimumBufferSize = OBU_MAX_HEADER_SIZE; if (!f || !buffer || !bytes_read || !payload_length || !obu_header || buffer_capacity < kMinimumBufferSize) { return -1; } - size_t leb128_length = 0; + size_t leb128_length_obu = 0; + size_t leb128_length_payload = 0; uint64_t obu_size = 0; if (is_annexb) { - if (obudec_read_leb128(f, &buffer[0], &leb128_length, &obu_size) != 0) { + if (obudec_read_leb128(f, &buffer[0], &leb128_length_obu, &obu_size) != 0) { fprintf(stderr, "obudec: Failure reading OBU size length.\n"); return -1; - } else if (leb128_length == 0) { + } else if (leb128_length_obu == 0) { *payload_length = 0; return 0; } @@ -141,8 +147,8 @@ static int obudec_read_obu_header_and_size(FILE *f, size_t buffer_capacity, } size_t header_size = 0; - if (obudec_read_obu_header(f, buffer_capacity - leb128_length, is_annexb, - buffer + leb128_length, obu_header, + if (obudec_read_obu_header(f, buffer_capacity - leb128_length_obu, is_annexb, + buffer + leb128_length_obu, obu_header, &header_size) != 0) { return -1; } else if (header_size == 0) { @@ -150,7 +156,8 @@ static int obudec_read_obu_header_and_size(FILE *f, size_t buffer_capacity, return 0; } - if (is_annexb) { + if (!obu_header->has_size_field) { + assert(is_annexb); if (obu_size < header_size) { fprintf(stderr, "obudec: OBU size is too small.\n"); return -1; @@ -158,8 +165,8 @@ static int obudec_read_obu_header_and_size(FILE *f, size_t buffer_capacity, *payload_length = (size_t)obu_size - header_size; } else { uint64_t u64_payload_length = 0; - if (obudec_read_leb128(f, &buffer[header_size], &leb128_length, - &u64_payload_length) != 0) { + if (obudec_read_leb128(f, &buffer[leb128_length_obu + header_size], + &leb128_length_payload, &u64_payload_length) != 0) { fprintf(stderr, "obudec: Failure reading OBU payload length.\n"); return -1; } @@ -171,7 +178,39 @@ static int obudec_read_obu_header_and_size(FILE *f, size_t buffer_capacity, *payload_length = (size_t)u64_payload_length; } - *bytes_read = leb128_length + header_size; + *bytes_read = leb128_length_obu + header_size + leb128_length_payload; + return 0; +} + +static int obudec_grow_buffer(size_t growth_amount, uint8_t **obu_buffer, + size_t *obu_buffer_capacity) { + if (!*obu_buffer || !obu_buffer_capacity || growth_amount == 0) { + return -1; + } + + const size_t capacity = *obu_buffer_capacity; + if (SIZE_MAX - growth_amount < capacity) { + fprintf(stderr, "obudec: cannot grow buffer, capacity will roll over.\n"); + return -1; + } + + const size_t new_capacity = capacity + growth_amount; + +#if defined AOM_MAX_ALLOCABLE_MEMORY + if (new_capacity > AOM_MAX_ALLOCABLE_MEMORY) { + fprintf(stderr, "obudec: OBU size exceeds max alloc size.\n"); + return -1; + } +#endif + + uint8_t *new_buffer = (uint8_t *)realloc(*obu_buffer, new_capacity); + if (!new_buffer) { + fprintf(stderr, "obudec: Failed to allocate compressed data buffer.\n"); + return -1; + } + + *obu_buffer = new_buffer; + *obu_buffer_capacity = new_capacity; return 0; } @@ -179,12 +218,25 @@ static int obudec_read_one_obu(FILE *f, uint8_t **obu_buffer, size_t obu_bytes_buffered, size_t *obu_buffer_capacity, size_t *obu_length, ObuHeader *obu_header, int is_annexb) { - size_t available_buffer_capacity = *obu_buffer_capacity - obu_bytes_buffered; - - if (!(*obu_buffer)) return -1; + if (!f || !(*obu_buffer) || !obu_buffer_capacity || !obu_length || + !obu_header) { + return -1; + } size_t bytes_read = 0; size_t obu_payload_length = 0; + size_t available_buffer_capacity = *obu_buffer_capacity - obu_bytes_buffered; + + if (available_buffer_capacity < OBU_MAX_HEADER_SIZE) { + if (obudec_grow_buffer(AOMMAX(*obu_buffer_capacity, OBU_MAX_HEADER_SIZE), + obu_buffer, obu_buffer_capacity) != 0) { + *obu_length = bytes_read; + return -1; + } + available_buffer_capacity += + AOMMAX(*obu_buffer_capacity, OBU_MAX_HEADER_SIZE); + } + const int status = obudec_read_obu_header_and_size( f, available_buffer_capacity, is_annexb, *obu_buffer + obu_bytes_buffered, &bytes_read, &obu_payload_length, obu_header); @@ -199,28 +251,11 @@ static int obudec_read_one_obu(FILE *f, uint8_t **obu_buffer, return -1; } - if (bytes_read + obu_payload_length > available_buffer_capacity) { - // TODO(tomfinegan): Add overflow check. - const size_t new_capacity = - obu_bytes_buffered + bytes_read + 2 * obu_payload_length; - -#if defined AOM_MAX_ALLOCABLE_MEMORY - if (new_capacity > AOM_MAX_ALLOCABLE_MEMORY) { - fprintf(stderr, "obudec: OBU size exceeds max alloc size.\n"); - return -1; - } -#endif - - uint8_t *new_buffer = (uint8_t *)realloc(*obu_buffer, new_capacity); - - if (new_buffer) { - *obu_buffer = new_buffer; - *obu_buffer_capacity = new_capacity; - } else { - fprintf(stderr, "obudec: Failed to allocate compressed data buffer\n"); - *obu_length = bytes_read + obu_payload_length; - return -1; - } + if (bytes_read + obu_payload_length > available_buffer_capacity && + obudec_grow_buffer(AOMMAX(*obu_buffer_capacity, obu_payload_length), + obu_buffer, obu_buffer_capacity) != 0) { + *obu_length = bytes_read + obu_payload_length; + return -1; } if (obu_payload_length > 0 && @@ -403,13 +438,15 @@ int obudec_read_temporal_unit(struct ObuDecInputContext *obu_ctx, return -1; } #endif - uint8_t *new_buffer = (uint8_t *)realloc(*buffer, tu_size); - if (!new_buffer) { - free(*buffer); - fprintf(stderr, "obudec: Out of memory.\n"); - return -1; + if (tu_size > 0) { + uint8_t *new_buffer = (uint8_t *)realloc(*buffer, tu_size); + if (!new_buffer) { + free(*buffer); + fprintf(stderr, "obudec: Out of memory.\n"); + return -1; + } + *buffer = new_buffer; } - *buffer = new_buffer; *bytes_read = tu_size; *buffer_size = tu_size; @@ -430,10 +467,11 @@ int obudec_read_temporal_unit(struct ObuDecInputContext *obu_ctx, memcpy(*buffer, &tuheader[0], length_of_temporal_unit_size); offset = length_of_temporal_unit_size; } else { - memcpy(*buffer, obu_ctx->buffer, obu_ctx->bytes_buffered); - offset = obu_ctx->bytes_buffered; - data_size = tu_size - obu_ctx->bytes_buffered; - obu_ctx->bytes_buffered = 0; + const size_t copy_size = AOMMIN(obu_ctx->bytes_buffered, tu_size); + memcpy(*buffer, obu_ctx->buffer, copy_size); + offset = copy_size; + data_size = tu_size - copy_size; + obu_ctx->bytes_buffered -= copy_size; } if (fread(*buffer + offset, 1, data_size, f) != data_size) { diff --git a/media/libaom/src/common/rawenc.c b/media/libaom/src/common/rawenc.c index 5a2731d3ac..b72132c2e9 100644 --- a/media/libaom/src/common/rawenc.c +++ b/media/libaom/src/common/rawenc.c @@ -9,36 +9,88 @@ * PATENTS file, you can obtain it at www.aomedia.org/license/patent. */ +#include <stdbool.h> #include "common/rawenc.h" -void raw_write_image_file(const aom_image_t *img, const int *planes, - const int num_planes, FILE *file) { - const int bytes_per_sample = ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); - for (int i = 0; i < num_planes; ++i) { - const int plane = planes[i]; - const unsigned char *buf = img->planes[plane]; - const int stride = img->stride[plane]; - const int w = aom_img_plane_width(img, plane); - const int h = aom_img_plane_height(img, plane); - for (int y = 0; y < h; ++y) { - fwrite(buf, bytes_per_sample, w, file); - buf += stride; +#define BATCH_SIZE 8 +// When writing greyscale color, batch 8 writes for low bit-depth, 4 writes +// for high bit-depth. +static const uint8_t batched[BATCH_SIZE] = { 128, 128, 128, 128, + 128, 128, 128, 128 }; +static const uint8_t batched_hbd[BATCH_SIZE] = { + 0, 128, 0, 128, 0, 128, 0, 128 +}; + +// Interface to writing to either a file or MD5Context. Takes a pointer to +// either the file or MD5Context, the buffer, the size of each element, and +// number of elements to write. Note that size and nmemb (last two args) must +// be unsigned int, as the interface to MD5Update requires that. +typedef void (*WRITER)(void *, const uint8_t *, unsigned int, unsigned int); + +static void write_file(void *fp, const uint8_t *buffer, unsigned int size, + unsigned int nmemb) { + fwrite(buffer, size, nmemb, (FILE *)fp); +} + +static void write_md5(void *md5, const uint8_t *buffer, unsigned int size, + unsigned int nmemb) { + MD5Update((MD5Context *)md5, buffer, size * nmemb); +} + +// Writes out n greyscale values. +static void write_greyscale(const bool high_bitdepth, int n, WRITER writer_func, + void *file_or_md5) { + const uint8_t *b = batched; + if (high_bitdepth) { + b = batched_hbd; + } + const int num_batched_writes = + high_bitdepth ? n / (BATCH_SIZE / 2) : n / BATCH_SIZE; + for (int i = 0; i < num_batched_writes; ++i) { + writer_func(file_or_md5, b, sizeof(uint8_t), BATCH_SIZE); + } + const int remaining = high_bitdepth ? n % (BATCH_SIZE / 2) : n % BATCH_SIZE; + for (int i = 0; i < remaining; ++i) { + if (high_bitdepth) { + writer_func(file_or_md5, batched_hbd, sizeof(uint8_t), 2); + } else { + writer_func(file_or_md5, batched, sizeof(uint8_t), 1); } } } -void raw_update_image_md5(const aom_image_t *img, const int *planes, - const int num_planes, MD5Context *md5) { +// Encapsulates the logic for writing raw data to either an image file or +// to an MD5 context. +static void raw_write_image_file_or_md5(const aom_image_t *img, + const int *planes, const int num_planes, + void *file_or_md5, WRITER writer_func) { + const bool high_bitdepth = img->fmt & AOM_IMG_FMT_HIGHBITDEPTH; + const int bytes_per_sample = high_bitdepth ? 2 : 1; for (int i = 0; i < num_planes; ++i) { const int plane = planes[i]; + const int w = aom_img_plane_width(img, plane); + const int h = aom_img_plane_height(img, plane); + // If we're on a color plane and the output is monochrome, write a greyscale + // value. Since there are only YUV planes, compare against Y. + if (img->monochrome && plane != AOM_PLANE_Y) { + write_greyscale(high_bitdepth, w * h, writer_func, file_or_md5); + continue; + } const unsigned char *buf = img->planes[plane]; const int stride = img->stride[plane]; - const int w = aom_img_plane_width(img, plane) * - ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); - const int h = aom_img_plane_height(img, plane); for (int y = 0; y < h; ++y) { - MD5Update(md5, buf, w); + writer_func(file_or_md5, buf, bytes_per_sample, w); buf += stride; } } } + +void raw_write_image_file(const aom_image_t *img, const int *planes, + const int num_planes, FILE *file) { + raw_write_image_file_or_md5(img, planes, num_planes, file, write_file); +} + +void raw_update_image_md5(const aom_image_t *img, const int *planes, + const int num_planes, MD5Context *md5) { + raw_write_image_file_or_md5(img, planes, num_planes, md5, write_md5); +} diff --git a/media/libaom/src/common/tools_common.c b/media/libaom/src/common/tools_common.c index 21cd800262..51c1c52a1a 100644 --- a/media/libaom/src/common/tools_common.c +++ b/media/libaom/src/common/tools_common.c @@ -149,6 +149,11 @@ const AvxInterface *get_aom_encoder_by_name(const char *name) { return NULL; } + +// large scale tile encoding +static const AvxInterface aom_lst_encoder = { "av1", LST_FOURCC, + &aom_codec_av1_cx }; +const AvxInterface *get_aom_lst_encoder(void) { return &aom_lst_encoder; } #endif // CONFIG_AV1_ENCODER #if CONFIG_AV1_DECODER @@ -283,6 +288,7 @@ static void lowbd_img_upshift(aom_image_t *dst, const aom_image_t *src, fatal("Unsupported image conversion"); } switch (src->fmt) { + case AOM_IMG_FMT_YV12: case AOM_IMG_FMT_I420: case AOM_IMG_FMT_I422: case AOM_IMG_FMT_I444: break; @@ -423,3 +429,80 @@ void aom_img_downshift(aom_image_t *dst, const aom_image_t *src, lowbd_img_downshift(dst, src, down_shift); } } + +static int img_shifted_realloc_required(const aom_image_t *img, + const aom_image_t *shifted, + aom_img_fmt_t required_fmt) { + return img->d_w != shifted->d_w || img->d_h != shifted->d_h || + required_fmt != shifted->fmt; +} + +void aom_shift_img(unsigned int output_bit_depth, aom_image_t **img_ptr, + aom_image_t **img_shifted_ptr) { + aom_image_t *img = *img_ptr; + aom_image_t *img_shifted = *img_shifted_ptr; + + const aom_img_fmt_t shifted_fmt = output_bit_depth == 8 + ? img->fmt & ~AOM_IMG_FMT_HIGHBITDEPTH + : img->fmt | AOM_IMG_FMT_HIGHBITDEPTH; + + if (shifted_fmt != img->fmt || output_bit_depth != img->bit_depth) { + 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->monochrome = img->monochrome; + } + 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; + img_shifted->monochrome = img->monochrome; + img_shifted->csp = img->csp; + } + 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_shifted_ptr = img_shifted; + *img_ptr = img_shifted; + } +} + +// Related to I420, NV12 format has one luma "luminance" plane Y and one plane +// with U and V values interleaved. +void aom_img_write_nv12(const aom_image_t *img, FILE *file) { + // Y plane + const unsigned char *buf = img->planes[0]; + int stride = img->stride[0]; + int w = aom_img_plane_width(img, 0) * + ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); + int h = aom_img_plane_height(img, 0); + int x, y; + + for (y = 0; y < h; ++y) { + fwrite(buf, 1, w, file); + buf += stride; + } + + // Interleaved U and V plane + const unsigned char *ubuf = img->planes[1]; + const unsigned char *vbuf = img->planes[2]; + const size_t size = (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1; + stride = img->stride[1]; + w = aom_img_plane_width(img, 1); + h = aom_img_plane_height(img, 1); + + for (y = 0; y < h; ++y) { + for (x = 0; x < w; ++x) { + fwrite(ubuf, size, 1, file); + fwrite(vbuf, size, 1, file); + ubuf += size; + vbuf += size; + } + ubuf += (stride - w * size); + vbuf += (stride - w * size); + } +} diff --git a/media/libaom/src/common/tools_common.h b/media/libaom/src/common/tools_common.h index 4e1d12f4a0..1ed004521a 100644 --- a/media/libaom/src/common/tools_common.h +++ b/media/libaom/src/common/tools_common.h @@ -18,6 +18,7 @@ #include "aom/aom_codec.h" #include "aom/aom_image.h" #include "aom/aom_integer.h" +#include "aom_ports/mem.h" #include "aom_ports/msvc.h" #if CONFIG_AV1_ENCODER @@ -77,6 +78,16 @@ enum VideoFileType { FILE_TYPE_WEBM }; +// Used in lightfield example. +enum { + YUV1D, // 1D tile output for conformance test. + YUV, // Tile output in YUV format. + NV12, // Tile output in NV12 format. +} UENUM1BYTE(OUTPUT_FORMAT); + +// The fourcc for large_scale_tile encoding is "LSTC". +#define LST_FOURCC 0x4354534c + struct FileTypeDetectionBuffer { char buf[4]; size_t buf_read; @@ -133,19 +144,103 @@ void usage_exit(void) AOM_NO_RETURN; int read_yuv_frame(struct AvxInputContext *input_ctx, aom_image_t *yuv_frame); +/////////////////////////////////////////////////////////////////////////////// +// A description of the interfaces used to access the AOM codecs +/////////////////////////////////////////////////////////////////////////////// +// +// There are three levels of interfaces used to access the AOM codec: the +// AVXInterface, the aom_codec_iface, and the aom_codec_ctx. Each of these +// is described in detail here. +// +// +// 1. AVXInterface +// (Related files: common/tools_common.c, common/tools_common.h) +// +// The high-level interface to the AVx encoders / decoders. Each AvxInterface +// contains the name of the codec (e.g., "av1"), the four character code +// associated with it, and a function pointer to the actual interface (see the +// documentation on aom_codec_iface_t for more info). This API +// is meant for lookup / iteration over all known codecs. +// +// For the encoder, call get_aom_encoder_by_name(...) if you know the name +// (e.g., "av1"); to iterate over all known encoders, use +// get_aom_encoder_count() and get_aom_encoder_by_index(i). To get the +// encoder specifically for large scale tile encoding, use +// get_aom_lst_encoder(). +// +// For the decoder, similar functions are available. There is also a +// get_aom_decoder_by_fourcc(fourcc) to get the decoder based on the four +// character codes. +// +// The main purpose of the AVXInterface is to get a reference to the +// aom_codec_interface_t, pointed to by its codec_interface variable. +// +// +// 2. aom_codec_iface_t +// (Related files: aom/aom_codec.h, aom/src/aom_codec.c, +// aom/internal/aom_codec_internal.h, av1/av1_cx_iface.c, +// av1/av1_dx_iface.c) +// +// Used to initialize the codec context, which contains the configuration for +// for modifying the encoder/decoder during run-time. See the documentation of +// aom/aom_codec.h for more details. For the most part, users will call the +// helper functions listed there, such as aom_codec_iface_name, +// aom_codec_get_caps, etc., to interact with it. +// +// The main purpose of the aom_codec_iface_t is to provide a way to generate +// a default codec config, find out what capabilities the implementation has, +// and create an aom_codec_ctx_t (which is actually used to interact with the +// codec). +// +// Note that the implementations of the aom_codec_iface_t are located in +// av1/av1_cx_iface.c and av1/av1_dx_iface.c +// +// +// 3. aom_codec_ctx_t +// (Related files: aom/aom_codec.h, av1/av1_cx_iface.c, av1/av1_dx_iface.c, +// aom/aomcx.h, aom/aomdx.h, aom/src/aom_encoder.c, aom/src/aom_decoder.c) +// +// The actual interface between user code and the codec. It stores the name +// of the codec, a pointer back to the aom_codec_iface_t that initialized it, +// initialization flags, a config for either encoder or the decoder, and a +// pointer to internal data. +// +// The codec is configured / queried through calls to aom_codec_control, +// which takes a control code (listed in aomcx.h and aomdx.h) and a parameter. +// In the case of "getter" control codes, the parameter is modified to have +// the requested value; in the case of "setter" control codes, the codec's +// configuration is changed based on the parameter. Note that a aom_codec_err_t +// is returned, which indicates if the operation was successful or not. +// +// Note that for the encoder, the aom_codec_alg_priv_t points to the +// the aom_codec_alg_priv structure in av1/av1_cx_iface.c, and for the decoder, +// the struct in av1/av1_dx_iface.c. Variables such as AV1_COMP cpi are stored +// here and also used in the core algorithm. +// +// At the end, aom_codec_destroy should be called for each initialized +// aom_codec_ctx_t. + typedef struct AvxInterface { const char *const name; const uint32_t fourcc; + // Pointer to a function of zero arguments that returns an aom_codec_iface_t + // pointer. E.g.: + // aom_codec_iface_t *codec = interface->codec_interface(); aom_codec_iface_t *(*const codec_interface)(); } AvxInterface; int get_aom_encoder_count(void); +// Lookup the interface by index -- it must be the case that +// i < get_aom_encoder_count() const AvxInterface *get_aom_encoder_by_index(int i); +// Lookup the interface by name -- returns NULL if no match. const AvxInterface *get_aom_encoder_by_name(const char *name); +const AvxInterface *get_aom_lst_encoder(void); int get_aom_decoder_count(void); const AvxInterface *get_aom_decoder_by_index(int i); const AvxInterface *get_aom_decoder_by_name(const char *name); +// Lookup the interface by the fourcc -- returns NULL if no match. const AvxInterface *get_aom_decoder_by_fourcc(uint32_t fourcc); void aom_img_write(const aom_image_t *img, FILE *file); @@ -155,8 +250,13 @@ double sse_to_psnr(double samples, double peak, double mse); void aom_img_upshift(aom_image_t *dst, const aom_image_t *src, int input_shift); void aom_img_downshift(aom_image_t *dst, const aom_image_t *src, int down_shift); +void aom_shift_img(unsigned int output_bit_depth, aom_image_t **img_ptr, + aom_image_t **img_shifted_ptr); void aom_img_truncate_16_to_8(aom_image_t *dst, const aom_image_t *src); +// Output in NV12 format. +void aom_img_write_nv12(const aom_image_t *img, FILE *file); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/media/libaom/src/common/video_reader.c b/media/libaom/src/common/video_reader.c index 47ad6e1891..7b021bc40f 100644 --- a/media/libaom/src/common/video_reader.c +++ b/media/libaom/src/common/video_reader.c @@ -121,3 +121,7 @@ FILE *aom_video_reader_get_file(AvxVideoReader *reader) { const AvxVideoInfo *aom_video_reader_get_info(AvxVideoReader *reader) { return &reader->info; } + +void aom_video_reader_set_fourcc(AvxVideoReader *reader, uint32_t fourcc) { + reader->info.codec_fourcc = fourcc; +} diff --git a/media/libaom/src/common/video_reader.h b/media/libaom/src/common/video_reader.h index 903deae849..9ab439e8af 100644 --- a/media/libaom/src/common/video_reader.h +++ b/media/libaom/src/common/video_reader.h @@ -50,6 +50,9 @@ FILE *aom_video_reader_get_file(AvxVideoReader *reader); // Fills AvxVideoInfo with information from opened video file. const AvxVideoInfo *aom_video_reader_get_info(AvxVideoReader *reader); +// Set fourcc. +void aom_video_reader_set_fourcc(AvxVideoReader *reader, uint32_t fourcc); + #ifdef __cplusplus } // extern "C" #endif diff --git a/media/libaom/src/common/video_writer.c b/media/libaom/src/common/video_writer.c index a7ec309fc7..1d4328ae1e 100644 --- a/media/libaom/src/common/video_writer.c +++ b/media/libaom/src/common/video_writer.c @@ -41,8 +41,10 @@ AvxVideoWriter *aom_video_writer_open(const char *filename, if (!file) return NULL; writer = malloc(sizeof(*writer)); - if (!writer) return NULL; - + if (!writer) { + fclose(file); + return NULL; + } writer->frame_count = 0; writer->info = *info; writer->file = file; @@ -75,3 +77,7 @@ int aom_video_writer_write_frame(AvxVideoWriter *writer, const uint8_t *buffer, return 1; } + +void aom_video_writer_set_fourcc(AvxVideoWriter *writer, uint32_t fourcc) { + writer->info.codec_fourcc = fourcc; +} diff --git a/media/libaom/src/common/video_writer.h b/media/libaom/src/common/video_writer.h index 3e2b6554b8..8712d47a58 100644 --- a/media/libaom/src/common/video_writer.h +++ b/media/libaom/src/common/video_writer.h @@ -14,7 +14,7 @@ #include "common/video_common.h" -typedef enum { kContainerIVF } AvxContainer; +enum { kContainerIVF } UENUM1BYTE(AvxContainer); struct AvxVideoWriterStruct; typedef struct AvxVideoWriterStruct AvxVideoWriter; @@ -37,6 +37,8 @@ void aom_video_writer_close(AvxVideoWriter *writer); // Writes frame bytes to the file. int aom_video_writer_write_frame(AvxVideoWriter *writer, const uint8_t *buffer, size_t size, int64_t pts); +// Set fourcc. +void aom_video_writer_set_fourcc(AvxVideoWriter *writer, uint32_t fourcc); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/common/webmdec.cc b/media/libaom/src/common/webmdec.cc index 17ac53c930..33bda59021 100644 --- a/media/libaom/src/common/webmdec.cc +++ b/media/libaom/src/common/webmdec.cc @@ -197,6 +197,17 @@ int webm_read_frame(struct WebmInputContext *webm_ctx, uint8_t **buffer, return frame.Read(reader, *buffer) ? -1 : 0; } +// Calculate the greatest common divisor between two numbers. +static int gcd(int a, int b) { + int remainder; + while (b > 0) { + remainder = a % b; + a = b; + b = remainder; + } + return a; +} + int webm_guess_framerate(struct WebmInputContext *webm_ctx, struct AvxInputContext *aom_ctx) { uint32_t i = 0; @@ -213,6 +224,14 @@ int webm_guess_framerate(struct WebmInputContext *webm_ctx, aom_ctx->framerate.numerator = (i - 1) * 1000000; aom_ctx->framerate.denominator = static_cast<int>(webm_ctx->timestamp_ns / 1000); + // Fraction might be represented in large numbers, like 49000000/980000 + // for 50fps. Simplify as much as possible. + int g = gcd(aom_ctx->framerate.numerator, aom_ctx->framerate.denominator); + if (g != 0) { + aom_ctx->framerate.numerator /= g; + aom_ctx->framerate.denominator /= g; + } + delete[] buffer; webm_ctx->buffer = NULL; diff --git a/media/libaom/src/common/webmenc.cc b/media/libaom/src/common/webmenc.cc index 58ab336707..6ae7df646f 100644 --- a/media/libaom/src/common/webmenc.cc +++ b/media/libaom/src/common/webmenc.cc @@ -11,8 +11,11 @@ #include "common/webmenc.h" +#include <stdio.h> + #include <string> +#include "common/av1_config.h" #include "third_party/libwebm/mkvmuxer/mkvmuxer.h" #include "third_party/libwebm/mkvmuxer/mkvmuxerutil.h" #include "third_party/libwebm/mkvmuxer/mkvwriter.h" @@ -22,17 +25,33 @@ const uint64_t kDebugTrackUid = 0xDEADBEEF; const int kVideoTrackNumber = 1; } // namespace -void write_webm_file_header(struct WebmOutputContext *webm_ctx, - const aom_codec_enc_cfg_t *cfg, - stereo_format_t stereo_fmt, unsigned int fourcc, - const struct AvxRational *par) { +int write_webm_file_header(struct WebmOutputContext *webm_ctx, + aom_codec_ctx_t *encoder_ctx, + const aom_codec_enc_cfg_t *cfg, + stereo_format_t stereo_fmt, unsigned int fourcc, + const struct AvxRational *par) { mkvmuxer::MkvWriter *const writer = new mkvmuxer::MkvWriter(webm_ctx->stream); mkvmuxer::Segment *const segment = new mkvmuxer::Segment(); - segment->Init(writer); + if (!writer || !segment) { + fprintf(stderr, "webmenc> mkvmuxer objects alloc failed, out of memory?\n"); + return -1; + } + + bool ok = segment->Init(writer); + if (!ok) { + fprintf(stderr, "webmenc> mkvmuxer Init failed.\n"); + return -1; + } + segment->set_mode(mkvmuxer::Segment::kFile); segment->OutputCues(true); mkvmuxer::SegmentInfo *const info = segment->GetSegmentInfo(); + if (!info) { + fprintf(stderr, "webmenc> Cannot retrieve Segment Info.\n"); + return -1; + } + const uint64_t kTimecodeScale = 1000000; info->set_timecode_scale(kTimecodeScale); std::string version = "aomenc"; @@ -46,13 +65,48 @@ void write_webm_file_header(struct WebmOutputContext *webm_ctx, static_cast<int>(cfg->g_h), kVideoTrackNumber); mkvmuxer::VideoTrack *const video_track = static_cast<mkvmuxer::VideoTrack *>( segment->GetTrackByNumber(video_track_id)); - video_track->SetStereoMode(stereo_fmt); - const char *codec_id; - switch (fourcc) { - case AV1_FOURCC: codec_id = "V_AV1"; break; - default: codec_id = "V_AV1"; break; + + if (!video_track) { + fprintf(stderr, "webmenc> Video track creation failed.\n"); + return -1; + } + + ok = false; + aom_fixed_buf_t *obu_sequence_header = + aom_codec_get_global_headers(encoder_ctx); + if (obu_sequence_header) { + Av1Config av1_config; + if (get_av1config_from_obu( + reinterpret_cast<const uint8_t *>(obu_sequence_header->buf), + obu_sequence_header->sz, false, &av1_config) == 0) { + uint8_t av1_config_buffer[4] = { 0 }; + size_t bytes_written = 0; + if (write_av1config(&av1_config, sizeof(av1_config_buffer), + &bytes_written, av1_config_buffer) == 0) { + ok = video_track->SetCodecPrivate(av1_config_buffer, + sizeof(av1_config_buffer)); + } + } + free(obu_sequence_header->buf); + free(obu_sequence_header); + } + if (!ok) { + fprintf(stderr, "webmenc> Unable to set AV1 config.\n"); + return -1; + } + + ok = video_track->SetStereoMode(stereo_fmt); + if (!ok) { + fprintf(stderr, "webmenc> Unable to set stereo mode.\n"); + return -1; } - video_track->set_codec_id(codec_id); + + if (fourcc != AV1_FOURCC) { + fprintf(stderr, "webmenc> Unsupported codec (unknown 4 CC).\n"); + return -1; + } + video_track->set_codec_id("V_AV1"); + if (par->numerator > 1 || par->denominator > 1) { // TODO(fgalligan): Add support of DisplayUnit, Display Aspect Ratio type // to WebM format. @@ -61,16 +115,24 @@ void write_webm_file_header(struct WebmOutputContext *webm_ctx, video_track->set_display_width(display_width); video_track->set_display_height(cfg->g_h); } + if (webm_ctx->debug) { video_track->set_uid(kDebugTrackUid); } + webm_ctx->writer = writer; webm_ctx->segment = segment; + + return 0; } -void write_webm_block(struct WebmOutputContext *webm_ctx, - const aom_codec_enc_cfg_t *cfg, - const aom_codec_cx_pkt_t *pkt) { +int write_webm_block(struct WebmOutputContext *webm_ctx, + const aom_codec_enc_cfg_t *cfg, + const aom_codec_cx_pkt_t *pkt) { + if (!webm_ctx->segment) { + fprintf(stderr, "webmenc> segment is NULL.\n"); + return -1; + } mkvmuxer::Segment *const segment = reinterpret_cast<mkvmuxer::Segment *>(webm_ctx->segment); int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * cfg->g_timebase.num / @@ -78,19 +140,34 @@ void write_webm_block(struct WebmOutputContext *webm_ctx, if (pts_ns <= webm_ctx->last_pts_ns) pts_ns = webm_ctx->last_pts_ns + 1000000; webm_ctx->last_pts_ns = pts_ns; - segment->AddFrame(static_cast<uint8_t *>(pkt->data.frame.buf), - pkt->data.frame.sz, kVideoTrackNumber, pts_ns, - pkt->data.frame.flags & AOM_FRAME_IS_KEY); + if (!segment->AddFrame(static_cast<uint8_t *>(pkt->data.frame.buf), + pkt->data.frame.sz, kVideoTrackNumber, pts_ns, + pkt->data.frame.flags & AOM_FRAME_IS_KEY)) { + fprintf(stderr, "webmenc> AddFrame failed.\n"); + return -1; + } + return 0; } -void write_webm_file_footer(struct WebmOutputContext *webm_ctx) { +int write_webm_file_footer(struct WebmOutputContext *webm_ctx) { + if (!webm_ctx->writer || !webm_ctx->segment) { + fprintf(stderr, "webmenc> segment or writer NULL.\n"); + return -1; + } mkvmuxer::MkvWriter *const writer = reinterpret_cast<mkvmuxer::MkvWriter *>(webm_ctx->writer); mkvmuxer::Segment *const segment = reinterpret_cast<mkvmuxer::Segment *>(webm_ctx->segment); - segment->Finalize(); + const bool ok = segment->Finalize(); delete segment; delete writer; webm_ctx->writer = NULL; webm_ctx->segment = NULL; + + if (!ok) { + fprintf(stderr, "webmenc> Segment::Finalize failed.\n"); + return -1; + } + + return 0; } diff --git a/media/libaom/src/common/webmenc.h b/media/libaom/src/common/webmenc.h index aa9832fbae..a4aa992b02 100644 --- a/media/libaom/src/common/webmenc.h +++ b/media/libaom/src/common/webmenc.h @@ -30,24 +30,28 @@ struct WebmOutputContext { }; /* Stereo 3D packed frame format */ -typedef enum stereo_format { +enum { STEREO_FORMAT_MONO = 0, STEREO_FORMAT_LEFT_RIGHT = 1, STEREO_FORMAT_BOTTOM_TOP = 2, STEREO_FORMAT_TOP_BOTTOM = 3, STEREO_FORMAT_RIGHT_LEFT = 11 -} stereo_format_t; +} UENUM1BYTE(stereo_format_t); -void write_webm_file_header(struct WebmOutputContext *webm_ctx, - const aom_codec_enc_cfg_t *cfg, - stereo_format_t stereo_fmt, unsigned int fourcc, - const struct AvxRational *par); +// The following functions wrap libwebm's mkvmuxer. All functions return 0 upon +// success, or -1 upon failure. -void write_webm_block(struct WebmOutputContext *webm_ctx, - const aom_codec_enc_cfg_t *cfg, - const aom_codec_cx_pkt_t *pkt); +int write_webm_file_header(struct WebmOutputContext *webm_ctx, + aom_codec_ctx_t *encoder_ctx, + const aom_codec_enc_cfg_t *cfg, + stereo_format_t stereo_fmt, unsigned int fourcc, + const struct AvxRational *par); -void write_webm_file_footer(struct WebmOutputContext *webm_ctx); +int write_webm_block(struct WebmOutputContext *webm_ctx, + const aom_codec_enc_cfg_t *cfg, + const aom_codec_cx_pkt_t *pkt); + +int write_webm_file_footer(struct WebmOutputContext *webm_ctx); #ifdef __cplusplus } // extern "C" diff --git a/media/libaom/src/common/y4menc.c b/media/libaom/src/common/y4menc.c index 585d221976..e3f5d5b387 100644 --- a/media/libaom/src/common/y4menc.c +++ b/media/libaom/src/common/y4menc.c @@ -15,7 +15,7 @@ #include "common/y4menc.h" // Returns the Y4M name associated with the monochrome colorspace. -const char *monochrome_colorspace(unsigned int bit_depth) { +static const char *monochrome_colorspace(unsigned int bit_depth) { switch (bit_depth) { case 8: return "Cmono"; case 9: return "Cmono9"; @@ -30,12 +30,15 @@ const char *monochrome_colorspace(unsigned int bit_depth) { // image format. const char *colorspace8(aom_chroma_sample_position_t csp, aom_img_fmt_t fmt) { switch (fmt) { - case AOM_IMG_FMT_444A: return "C444alpha"; case AOM_IMG_FMT_I444: return "C444"; case AOM_IMG_FMT_I422: return "C422"; default: if (csp == AOM_CSP_VERTICAL) { return "C420mpeg2 XYSCSS=420MPEG2"; + } else if (csp == AOM_CSP_COLOCATED) { + // Note that Y4M does not have a dedicated header for colocated chroma, + // and that FFMPEG interprets C420 as C420jpeg. + return "C420"; } else { return "C420jpeg"; } @@ -43,8 +46,9 @@ const char *colorspace8(aom_chroma_sample_position_t csp, aom_img_fmt_t fmt) { } // Return the Y4M name of the colorspace, given the bit depth and image format. -const char *colorspace(unsigned int bit_depth, aom_chroma_sample_position_t csp, - aom_img_fmt_t fmt) { +static const char *colorspace(unsigned int bit_depth, + aom_chroma_sample_position_t csp, + aom_img_fmt_t fmt) { switch (bit_depth) { case 8: return colorspace8(csp, fmt); case 9: diff --git a/media/libaom/src/common/y4minput.c b/media/libaom/src/common/y4minput.c index eca8b1bbac..f3dfaafc68 100644 --- a/media/libaom/src/common/y4minput.c +++ b/media/libaom/src/common/y4minput.c @@ -16,6 +16,7 @@ #include <string.h> #include "aom/aom_integer.h" +#include "aom_ports/msvc.h" #include "y4minput.h" // Reads 'size' bytes from 'file' into 'buf' with some fault tolerance. @@ -109,7 +110,8 @@ static int y4m_parse_tags(y4m_input *_y4m, char *_tags) { if (!got_par) _y4m->par_n = _y4m->par_d = 0; /*Chroma-type is not specified in older files, e.g., those generated by mplayer.*/ - if (!got_chroma) strcpy(_y4m->chroma_type, "420"); + if (!got_chroma) + snprintf(_y4m->chroma_type, sizeof(_y4m->chroma_type), "420"); return 0; } @@ -778,7 +780,7 @@ static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst, } int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip, - int only_420) { + aom_chroma_sample_position_t csp, int only_420) { char buffer[80] = { 0 }; int ret; int i; @@ -821,6 +823,19 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip, "Only progressive scan handled.\n"); return -1; } + /* Only support vertical chroma sample position if the input format is + * already 420mpeg2. Colocated is not supported in Y4M. + */ + if (csp == AOM_CSP_VERTICAL && strcmp(_y4m->chroma_type, "420mpeg2") != 0) { + fprintf(stderr, + "Vertical chroma sample position only supported " + "for 420mpeg2 input\n"); + return -1; + } + if (csp == AOM_CSP_COLOCATED) { + fprintf(stderr, "Colocated chroma sample position not supported in Y4M\n"); + return -1; + } _y4m->aom_fmt = AOM_IMG_FMT_I420; _y4m->bps = 12; _y4m->bit_depth = 8; @@ -877,7 +892,11 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip, /*Chroma filter required: read into the aux buf first.*/ _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2); - _y4m->convert = y4m_convert_42xmpeg2_42xjpeg; + _y4m->convert = y4m_convert_null; + if (csp != AOM_CSP_VERTICAL) { + _y4m->convert = y4m_convert_42xmpeg2_42xjpeg; + snprintf(_y4m->chroma_type, sizeof(_y4m->chroma_type), "420"); + } } else if (strcmp(_y4m->chroma_type, "420paldv") == 0) { _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v = _y4m->dst_c_dec_v = 2; @@ -1037,14 +1056,8 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip, _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 3 * _y4m->pic_w * _y4m->pic_h; _y4m->convert = y4m_convert_444_420jpeg; } else { - _y4m->aom_fmt = AOM_IMG_FMT_444A; - _y4m->bps = 32; - _y4m->dst_c_dec_h = _y4m->src_c_dec_h; - _y4m->dst_c_dec_v = _y4m->src_c_dec_v; - _y4m->dst_buf_read_sz = 4 * _y4m->pic_w * _y4m->pic_h; - /*Natively supported: no conversion required.*/ - _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0; - _y4m->convert = y4m_convert_null; + fprintf(stderr, "Unsupported format: 444A\n"); + return -1; } } else if (strcmp(_y4m->chroma_type, "mono") == 0) { _y4m->src_c_dec_h = _y4m->src_c_dec_v = 0; @@ -1131,12 +1144,10 @@ int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, aom_image_t *_img) { c_w *= bytes_per_sample; c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v; c_sz = c_w * c_h; - _img->stride[AOM_PLANE_Y] = _img->stride[AOM_PLANE_ALPHA] = - _y4m->pic_w * bytes_per_sample; + _img->stride[AOM_PLANE_Y] = _y4m->pic_w * bytes_per_sample; _img->stride[AOM_PLANE_U] = _img->stride[AOM_PLANE_V] = c_w; _img->planes[AOM_PLANE_Y] = _y4m->dst_buf; _img->planes[AOM_PLANE_U] = _y4m->dst_buf + pic_sz; _img->planes[AOM_PLANE_V] = _y4m->dst_buf + pic_sz + c_sz; - _img->planes[AOM_PLANE_ALPHA] = _y4m->dst_buf + pic_sz + 2 * c_sz; return 1; } diff --git a/media/libaom/src/common/y4minput.h b/media/libaom/src/common/y4minput.h index 01b9ce9726..f6c5a3d3ab 100644 --- a/media/libaom/src/common/y4minput.h +++ b/media/libaom/src/common/y4minput.h @@ -57,8 +57,14 @@ struct y4m_input { unsigned int bit_depth; }; +/** + * Open the input file, treating it as Y4M. y4m_input is filled in after + * reading it. Note that chroma-sample-position should only be set for 420 + * input, and the input chroma is shifted if necessary. The code does not + * support the conversion from co-located to vertical. + */ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip, - int only_420); + aom_chroma_sample_position_t csp, int only_420); void y4m_input_close(y4m_input *_y4m); int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, aom_image_t *img); |