summaryrefslogtreecommitdiff
path: root/media/libaom/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'media/libaom/src/common')
-rw-r--r--media/libaom/src/common/args.c90
-rw-r--r--media/libaom/src/common/args.h5
-rw-r--r--media/libaom/src/common/av1_config.c16
-rw-r--r--media/libaom/src/common/ivfdec.h3
-rw-r--r--media/libaom/src/common/obudec.c132
-rw-r--r--media/libaom/src/common/rawenc.c88
-rw-r--r--media/libaom/src/common/tools_common.c83
-rw-r--r--media/libaom/src/common/tools_common.h100
-rw-r--r--media/libaom/src/common/video_reader.c4
-rw-r--r--media/libaom/src/common/video_reader.h3
-rw-r--r--media/libaom/src/common/video_writer.c10
-rw-r--r--media/libaom/src/common/video_writer.h4
-rw-r--r--media/libaom/src/common/webmdec.cc19
-rw-r--r--media/libaom/src/common/webmenc.cc115
-rw-r--r--media/libaom/src/common/webmenc.h24
-rw-r--r--media/libaom/src/common/y4menc.c12
-rw-r--r--media/libaom/src/common/y4minput.c39
-rw-r--r--media/libaom/src/common/y4minput.h8
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);