CWG-F015: M-AVM: A Reference Software for Multi-layered Video Coding - implementation on AVM research-v9.0.0
A software implementation of multilayer coding extensions that include:
(i) basic multilayer coding capabilities, and
(ii) allows extending the size of the decoded frame buffer (DPB).
This software implementation is released for further multilayered/multiview video coding standardization development as a branch for AVM.
diff --git a/README.md b/README.md
index 64caea8..82fd7da 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,23 @@
-# AVM
+# Multiview-AVM (M-AVM) v1.0.0
-[TOC]
+M-AVM is the multilayer/multiview extension of the AVM reference software.
+
+After building and compiling *aomenc* and *aomdec* binaries as instructed below, the following command line entries for *aomenc* will compress of multiple input views from separate raw video files.
+
+For example, two views stored in `Raw_video_view0.yuv` and `Raw_video_view1.yuv` files can be compressed using *aomenc* with the following command line arguments:
+~~~
+aomenc <Raw_video_view0.yuv> <Raw_video_view1.yuv> --num-views=2 -o bitstream.avm [*additional command arguments for AVM]
+~~~
+This will generate a single M-AVM bitstream in `bitstream.avm`. The following sample command can be used to decode using the *aomdec* binary.
+~~~
+aomdec bitstream.avm --output=Recon_video.yuv --progress --output-bit-depth=8 --rawvideo
+~~~
+This command will decode and output two files `Recon_video_view0.yuv` and `Recon_video_view1.yuv` for each view.
+
+The current version software allows up to encoding and decoding of 256 views. For more `N` views the encoder the following encoder command can be used:
+~~~
+aomenc <Raw_video_view0.yuv> <Raw_video_view1.yuv> ... <Raw_video_view{N-1}.yuv> --num-views=N -o bitstream.avm [*additional command arguments for AVM]
+~~~
## Building
diff --git a/aom/aom_decoder.h b/aom/aom_decoder.h
index 072a9ca..8d1bc43 100644
--- a/aom/aom_decoder.h
+++ b/aom/aom_decoder.h
@@ -76,7 +76,10 @@
unsigned int is_kf; /**< Current frame is a keyframe */
unsigned int number_spatial_layers; /**< Number of spatial layers */
unsigned int number_temporal_layers; /**< Number of temporal layers */
- unsigned int is_annexb; /**< Is Bitstream in Annex-B format */
+#if CONFIG_MULTIVIEW_CORE
+ unsigned int number_views; /**< Number of views */
+#endif
+ unsigned int is_annexb; /**< Is Bitstream in Annex-B format */
} aom_codec_stream_info_t;
/* REQUIRED FUNCTIONS
diff --git a/aom/aom_encoder.h b/aom/aom_encoder.h
index 60a495a..2575982 100644
--- a/aom/aom_encoder.h
+++ b/aom/aom_encoder.h
@@ -747,7 +747,13 @@
* height written in write_sequence_header().
*/
unsigned int g_forced_max_frame_height;
-
+#if CONFIG_MULTIVIEW_CORE
+ /*!\brief Number of views
+ *
+ *
+ */
+ unsigned int g_num_views;
+#endif
/*!\brief Bit-depth of the codec
*
* This value identifies the bit_depth of the codec,
diff --git a/aom/aom_frame_buffer.h b/aom/aom_frame_buffer.h
index 7f5b6b9..12796b6 100644
--- a/aom/aom_frame_buffer.h
+++ b/aom/aom_frame_buffer.h
@@ -22,17 +22,25 @@
#endif
#include "aom/aom_integer.h"
+#include "config/aom_config.h"
/*!\brief The maximum number of work buffers used by libaom.
* Support maximum 4 threads to decode video in parallel.
* Each thread will use one work buffer.
* TODO(hkuang): Add support to set number of worker threads dynamically.
*/
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+#define AOM_MAXIMUM_WORK_BUFFERS 16
+#else
#define AOM_MAXIMUM_WORK_BUFFERS 8
-
+#endif
/*!\brief The maximum number of reference buffers that a AV1 encoder may use.
*/
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+#define AOM_MAXIMUM_REF_BUFFERS 16
+#else
#define AOM_MAXIMUM_REF_BUFFERS 8
+#endif
/*!\brief External frame buffer
*
diff --git a/aom/aom_image.h b/aom/aom_image.h
index bd8c045..4048264 100644
--- a/aom/aom_image.h
+++ b/aom/aom_image.h
@@ -21,6 +21,7 @@
extern "C" {
#endif
+#include "config/aom_config.h"
#include "aom/aom_integer.h"
/*!\brief Current ABI version number
@@ -210,7 +211,10 @@
int temporal_id; /**< Temporal layer Id of image */
int spatial_id; /**< Spatial layer Id of image */
-
+#if CONFIG_MULTIVIEW_CORE
+ int view_id; /**< View layer id of image */
+ int display_order_hint; /**< display order of image */
+#endif
/*!\brief The following member may be set by the application to associate
* data with this image.
*/
diff --git a/aom/src/aom_decoder.c b/aom/src/aom_decoder.c
index 3f2db00..ff3756d 100644
--- a/aom/src/aom_decoder.c
+++ b/aom/src/aom_decoder.c
@@ -66,7 +66,9 @@
/* Set default/unknown values */
si->w = 0;
si->h = 0;
-
+#if CONFIG_MULTIVIEW_CORE
+ si->number_views = 1;
+#endif
res = iface->dec.peek_si(data, data_sz, si);
}
@@ -85,7 +87,9 @@
/* Set default/unknown values */
si->w = 0;
si->h = 0;
-
+#if CONFIG_MULTIVIEW_CORE
+ si->number_views = 0;
+#endif
res = ctx->iface->dec.get_si(get_alg_priv(ctx), si);
}
diff --git a/apps/aomdec.c b/apps/aomdec.c
index 059c296..cfea2d9 100644
--- a/apps/aomdec.c
+++ b/apps/aomdec.c
@@ -246,18 +246,32 @@
static int read_frame(struct AvxDecInputContext *input, uint8_t **buf,
size_t *bytes_in_buffer, size_t *buffer_size) {
+#if CONFIG_MULTIVIEW_CORE
+ switch (input->aom_input_ctx->file_type[0]) {
+#else
switch (input->aom_input_ctx->file_type) {
+#endif
#if CONFIG_WEBM_IO
case FILE_TYPE_WEBM:
return webm_read_frame(input->webm_ctx, buf, bytes_in_buffer,
buffer_size);
#endif
case FILE_TYPE_RAW:
+#if CONFIG_MULTIVIEW_CORE
+ return raw_read_frame(input->aom_input_ctx->file[0], buf, bytes_in_buffer,
+ buffer_size);
+#else
return raw_read_frame(input->aom_input_ctx->file, buf, bytes_in_buffer,
buffer_size);
+#endif
case FILE_TYPE_IVF:
+#if CONFIG_MULTIVIEW_CORE
+ return ivf_read_frame(input->aom_input_ctx->file[0], buf, bytes_in_buffer,
+ buffer_size, NULL);
+#else
return ivf_read_frame(input->aom_input_ctx->file, buf, bytes_in_buffer,
buffer_size, NULL);
+#endif
case FILE_TYPE_OBU:
return obudec_read_temporal_unit(input->obu_ctx, buf, bytes_in_buffer,
buffer_size);
@@ -271,7 +285,11 @@
aom_codec_stream_info_t si;
memset(&si, 0, sizeof(si));
+#if CONFIG_MULTIVIEW_CORE
+ if (fread(buf, 1, 32, input->file[0]) == 32) {
+#else
if (fread(buf, 1, 32, input->file) == 32) {
+#endif
int i;
if (mem_get_le32(buf) < 256 * 1024 * 1024) {
@@ -289,10 +307,23 @@
}
}
}
-
+#if CONFIG_MULTIVIEW_CORE
+ rewind(input->file[0]);
+#else
rewind(input->file);
+#endif
return is_raw;
}
+#if CONFIG_MULTIVIEW_CORE
+static void show_progress_multiview(int frame_in, int frame_out, int view_id,
+ int frame_out_per_view, uint64_t dx_time) {
+ fprintf(stderr,
+ "%d decoded frames/%d showed frames (view_id=%d, frame_per_view=%d) "
+ "in %" PRId64 " us (%.2f fps)\r",
+ frame_in, frame_out, view_id, frame_out_per_view, dx_time,
+ (double)frame_out * 1000000.0 / (double)dx_time);
+}
+#endif
static void show_progress(int frame_in, int frame_out, uint64_t dx_time) {
fprintf(stderr,
@@ -528,6 +559,26 @@
}
}
+#if CONFIG_MULTIVIEW_CORE
+static void open_multiple_output_files_perview(
+ const char *outfile_name, const struct AvxInputContext aom_input_ctx,
+ FILE **outfile) {
+ for (int view_id = 0; view_id < aom_input_ctx.num_views; view_id++) {
+ char output_filename[PATH_MAX];
+ char extension[6];
+ char suffix[16];
+ sprintf(suffix, "_view%0d", view_id);
+ strcpy(output_filename, outfile_name);
+ char *ptr_extension = strrchr(output_filename, '.');
+ strcpy(extension, ptr_extension);
+ if (ptr_extension != NULL) *ptr_extension = '\0';
+ strcat(output_filename, suffix);
+ strcat(output_filename, extension);
+ outfile[view_id] = open_outfile(output_filename);
+ }
+}
+#endif
+
static int main_loop(int argc, const char **argv_) {
aom_codec_ctx_t decoder;
char *fn = NULL;
@@ -568,7 +619,11 @@
const char *outfile_pattern = NULL;
char outfile_name[PATH_MAX] = { 0 };
+#if CONFIG_MULTIVIEW_CORE
+ FILE *outfile[NUM_LAYERS_MAX] = { NULL };
+#else
FILE *outfile = NULL;
+#endif
FILE *framestats_file = NULL;
@@ -728,20 +783,41 @@
return EXIT_FAILURE;
}
#endif
+#if CONFIG_MULTIVIEW_CORE
+ input.aom_input_ctx->filename[0] = fn;
+ input.aom_input_ctx->file[0] = infile;
+#else
input.aom_input_ctx->filename = fn;
input.aom_input_ctx->file = infile;
+#endif
if (file_is_ivf(input.aom_input_ctx)) {
+#if CONFIG_MULTIVIEW_CORE
+ input.aom_input_ctx->file_type[0] = FILE_TYPE_IVF;
+#else
input.aom_input_ctx->file_type = FILE_TYPE_IVF;
+#endif
is_ivf = 1;
}
#if CONFIG_WEBM_IO
else if (file_is_webm(input.webm_ctx, input.aom_input_ctx))
+#if CONFIG_MULTIVIEW_CORE
+ input.aom_input_ctx->file_type[0] = FILE_TYPE_WEBM;
+#else
input.aom_input_ctx->file_type = FILE_TYPE_WEBM;
#endif
+#endif
else if (file_is_obu(&obu_ctx))
+#if CONFIG_MULTIVIEW_CORE
+ input.aom_input_ctx->file_type[0] = FILE_TYPE_OBU;
+#else
input.aom_input_ctx->file_type = FILE_TYPE_OBU;
+#endif
else if (file_is_raw(input.aom_input_ctx))
+#if CONFIG_MULTIVIEW_CORE
+ input.aom_input_ctx->file_type[0] = FILE_TYPE_RAW;
+#else
input.aom_input_ctx->file_type = FILE_TYPE_RAW;
+#endif
else {
fprintf(stderr, "Unrecognized input file type.\n");
#if !CONFIG_WEBM_IO
@@ -753,7 +829,7 @@
outfile_pattern = outfile_pattern ? outfile_pattern : "-";
single_file = is_single_file(outfile_pattern);
-
+#if !CONFIG_MULTIVIEW_CORE
if (!noblit && single_file) {
generate_filename(outfile_pattern, outfile_name, PATH_MAX,
aom_input_ctx.width, aom_input_ctx.height, 0);
@@ -762,7 +838,7 @@
else
outfile = open_outfile(outfile_name);
}
-
+#endif
if (use_y4m && !noblit) {
if (!single_file) {
fprintf(stderr,
@@ -772,7 +848,11 @@
}
#if CONFIG_WEBM_IO
+#if CONFIG_MULTIVIEW_CORE
+ if (aom_input_ctx.file_type[0] == FILE_TYPE_WEBM) {
+#else
if (aom_input_ctx.file_type == FILE_TYPE_WEBM) {
+#endif
if (webm_guess_framerate(input.webm_ctx, input.aom_input_ctx)) {
fprintf(stderr,
"Failed to guess framerate -- error parsing "
@@ -872,18 +952,32 @@
if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
frame_avail = 1;
frame_in++;
-
aom_usec_timer_start(&timer);
-
if (aom_codec_decode(&decoder, buf, bytes_in_buffer, NULL)) {
const char *detail = aom_codec_error_detail(&decoder);
warn("Failed to decode frame %d: %s", frame_in,
aom_codec_error(&decoder));
-
if (detail) warn("Additional information: %s", detail);
if (!keep_going) goto fail;
}
+#if CONFIG_MULTIVIEW_CORE
+ if (frame_in == 1) {
+ if (!noblit && single_file) {
+ generate_filename(outfile_pattern, outfile_name, PATH_MAX,
+ aom_input_ctx.width, aom_input_ctx.height, 0);
+ if (do_md5)
+ MD5Init(&md5_ctx);
+ else {
+ aom_codec_stream_info_t si;
+ aom_codec_get_stream_info(&decoder, &si);
+ aom_input_ctx.num_views = si.number_views;
+ open_multiple_output_files_perview(outfile_name, aom_input_ctx,
+ outfile);
+ }
+ }
+ }
+#endif
if (framestats_file) {
int qp;
if (AOM_CODEC_CONTROL_TYPECHECKED(&decoder, AOMD_GET_LAST_QUANTIZER,
@@ -917,7 +1011,15 @@
dx_time += aom_usec_timer_elapsed(&timer);
got_data = 0;
+#if CONFIG_MULTIVIEW_CORE
while ((img = aom_codec_get_frame(&decoder, &iter))) {
+#else
+ while ((img = aom_codec_get_frame(&decoder, &iter))) {
+#endif
+#if CONFIG_MULTIVIEW_CORE
+ const int view_id = img->view_id;
+ const int frame_per_view = frame_out / aom_input_ctx.num_views;
+#endif
++frame_out;
if (frame_in < frame_out) { // No OBUs for show_existing_frame.
frame_in = frame_out;
@@ -931,7 +1033,13 @@
}
frames_corrupted += corrupted;
+#if CONFIG_MULTIVIEW_CORE
+ if (progress)
+ show_progress_multiview(frame_in, frame_out, view_id, frame_per_view,
+ dx_time);
+#else
if (progress) show_progress(frame_in, frame_out, dx_time);
+#endif
if (do_verify) {
if (check_decoded_frame_hash(&decoder, img, frame_out,
@@ -1006,7 +1114,12 @@
if (use_y4m) {
char y4m_buf[Y4M_BUFFER_SIZE] = { 0 };
size_t len = 0;
+#if CONFIG_MULTIVIEW_CORE
+ if (frame_out == 1 ||
+ ((frame_out - 1) / aom_input_ctx.num_views) < 1) {
+#else
if (frame_out == 1) {
+#endif
// Y4M file header
len = y4m_write_file_header(
y4m_buf, sizeof(y4m_buf), aom_input_ctx.width,
@@ -1021,7 +1134,11 @@
if (do_md5) {
MD5Update(&md5_ctx, (md5byte *)y4m_buf, (unsigned int)len);
} else {
+#if CONFIG_MULTIVIEW_CORE
+ fputs(y4m_buf, outfile[view_id]);
+#else
fputs(y4m_buf, outfile);
+#endif
}
}
@@ -1031,8 +1148,13 @@
MD5Update(&md5_ctx, (md5byte *)y4m_buf, (unsigned int)len);
y4m_update_image_md5(img, planes, &md5_ctx);
} else {
+#if CONFIG_MULTIVIEW_CORE
+ fputs(y4m_buf, outfile[view_id]);
+ y4m_write_image_file(img, planes, outfile[view_id]);
+#else
fputs(y4m_buf, outfile);
y4m_write_image_file(img, planes, outfile);
+#endif
}
} else {
if (frame_out == 1) {
@@ -1059,7 +1181,11 @@
if (do_md5) {
raw_update_image_md5(img, planes, num_planes, &md5_ctx);
} else {
+#if CONFIG_MULTIVIEW_CORE
+ raw_write_image_file(img, planes, num_planes, outfile[view_id]);
+#else
raw_write_image_file(img, planes, num_planes, outfile);
+#endif
}
}
} else {
@@ -1075,6 +1201,15 @@
MD5Final(md5_digest, &md5_ctx);
print_md5(md5_digest, outfile_name);
} else {
+#if CONFIG_MULTIVIEW_CORE
+ outfile[0] = open_outfile(outfile_name);
+ if (use_y4m) {
+ y4m_write_image_file(img, planes, outfile[0]);
+ } else {
+ raw_write_image_file(img, planes, num_planes, outfile[0]);
+ }
+ fclose(outfile[0]);
+#else
outfile = open_outfile(outfile_name);
if (use_y4m) {
y4m_write_image_file(img, planes, outfile);
@@ -1082,6 +1217,7 @@
raw_write_image_file(img, planes, num_planes, outfile);
}
fclose(outfile);
+#endif
}
}
}
@@ -1113,19 +1249,36 @@
MD5Final(md5_digest, &md5_ctx);
print_md5(md5_digest, outfile_name);
} else {
+#if CONFIG_MULTIVIEW_CORE
+ for (int view_id = 0; view_id < aom_input_ctx.num_views; view_id++) {
+ fclose(outfile[view_id]);
+ }
+#else
fclose(outfile);
+#endif
}
}
#if CONFIG_WEBM_IO
+#if CONFIG_MULTIVIEW_CORE
+ if (input.aom_input_ctx->file_type[0] == FILE_TYPE_WEBM)
+#else
if (input.aom_input_ctx->file_type == FILE_TYPE_WEBM)
+#endif
webm_free(input.webm_ctx);
#endif
+#if CONFIG_MULTIVIEW_CORE
+ if (input.aom_input_ctx->file_type[0] == FILE_TYPE_OBU)
+#else
if (input.aom_input_ctx->file_type == FILE_TYPE_OBU)
+#endif
obudec_free(input.obu_ctx);
+#if CONFIG_MULTIVIEW_CORE
+ if (input.aom_input_ctx->file_type[0] != FILE_TYPE_WEBM) free(buf);
+#else
if (input.aom_input_ctx->file_type != FILE_TYPE_WEBM) free(buf);
-
+#endif
if (scaled_img) aom_img_free(scaled_img);
if (img_shifted) aom_img_free(img_shifted);
diff --git a/apps/aomenc.c b/apps/aomenc.c
index 399e419..b02850c 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -274,6 +274,9 @@
#if CONFIG_WEBM_IO
&g_av1_codec_arg_defs.stereo_mode,
#endif
+#if CONFIG_MULTIVIEW_CORE
+ &g_av1_codec_arg_defs.num_views,
+#endif
&g_av1_codec_arg_defs.timebase,
&g_av1_codec_arg_defs.framerate,
&g_av1_codec_arg_defs.global_error_resilient,
@@ -802,6 +805,9 @@
global->csp = AOM_CSP_UNKNOWN;
global->show_psnr = 0;
global->step_frames = 1;
+#if CONFIG_MULTIVIEW_CORE
+ global->num_views = 1;
+#endif
int cfg_included = 0;
init_config(&global->encoder_config);
@@ -864,6 +870,10 @@
global->show_psnr = arg_parse_int(&arg);
else
global->show_psnr = 2;
+#if CONFIG_MULTIVIEW_CORE
+ } else if (arg_match(&arg, &g_av1_codec_arg_defs.num_views, argi)) {
+ global->num_views = arg_parse_uint(&arg);
+#endif
} else if (arg_match(&arg, &g_av1_codec_arg_defs.recontest, argi)) {
global->test_decode = arg_parse_enum_or_int(&arg);
} else if (arg_match(&arg, &g_av1_codec_arg_defs.framerate, argi)) {
@@ -905,6 +915,57 @@
static void open_input_file(struct AvxInputContext *input,
aom_chroma_sample_position_t csp) {
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 0; i < input->num_views; i++) {
+ /* Parse certain options from the input file, if possible */
+ input->file[i] = strcmp(input->filename[i], "-")
+ ? fopen(input->filename[i], "rb")
+ : set_binary_mode(stdin);
+
+ if (!input->file[i]) fatal("Failed to open input file");
+
+ if (!fseeko(input->file[i], 0, SEEK_END)) {
+ /* Input file is seekable. Figure out how long it is, so we can get
+ * progress info.
+ */
+ input->length = ftello(input->file[i]);
+ rewind(input->file[i]);
+ }
+
+ /* Default to 1:1 pixel aspect ratio. */
+ input->pixel_aspect_ratio.numerator = 1;
+ input->pixel_aspect_ratio.denominator = 1;
+
+ /* For RAW input sources, these bytes will applied on the first frame
+ * in read_frame().
+ */
+ input->detect[i].buf_read =
+ fread(input->detect[i].buf, 1, 4, input->file[i]);
+ input->detect[i].position = 0;
+
+ if (input->detect[i].buf_read == 4 && file_is_y4m(input->detect[i].buf)) {
+ if (y4m_input_open(&input->y4m[i], input->file[i], input->detect[i].buf,
+ 4, csp, input->only_i420) >= 0) {
+ input->file_type[i] = FILE_TYPE_Y4M;
+ input->width = input->y4m[i].pic_w;
+ input->height = input->y4m[i].pic_h;
+ input->pixel_aspect_ratio.numerator = input->y4m[i].par_n;
+ input->pixel_aspect_ratio.denominator = input->y4m[i].par_d;
+ input->framerate.numerator = input->y4m[i].fps_n;
+ input->framerate.denominator = input->y4m[i].fps_d;
+ input->fmt = input->y4m[i].aom_fmt;
+ input->bit_depth = input->y4m[i].bit_depth;
+ input->color_range = input->y4m[i].color_range;
+ } else
+ fatal("Unsupported Y4M stream.");
+ } else if (input->detect[i].buf_read == 4 &&
+ fourcc_is_ivf(input->detect[i].buf)) {
+ fatal("IVF is not supported as input.");
+ } else {
+ input->file_type[i] = FILE_TYPE_RAW;
+ }
+ }
+#else
/* Parse certain options from the input file, if possible */
input->file = strcmp(input->filename, "-") ? fopen(input->filename, "rb")
: set_binary_mode(stdin);
@@ -949,11 +1010,19 @@
} else {
input->file_type = FILE_TYPE_RAW;
}
+#endif
}
static void close_input_file(struct AvxInputContext *input) {
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 0; i < input->num_views; i++) {
+ fclose(input->file[i]);
+ if (input->file_type[i] == FILE_TYPE_Y4M) y4m_input_close(&input->y4m[i]);
+ }
+#else
fclose(input->file);
if (input->file_type == FILE_TYPE_Y4M) y4m_input_close(&input->y4m);
+#endif
}
static struct stream_state *new_stream(struct AvxEncoderConfig *global,
@@ -1219,6 +1288,10 @@
} else if (arg_match(&arg, &g_av1_codec_arg_defs.stereo_mode, argi)) {
config->stereo_fmt = arg_parse_enum_or_int(&arg);
#endif
+#if CONFIG_MULTIVIEW_CORE
+ } else if (arg_match(&arg, &g_av1_codec_arg_defs.num_views, argi)) {
+ config->cfg.g_num_views = arg_parse_uint(&arg);
+#endif
} else if (arg_match(&arg, &g_av1_codec_arg_defs.timebase, argi)) {
config->cfg.g_timebase = arg_parse_rational(&arg);
validate_positive_rational(arg.name, &config->cfg.g_timebase);
@@ -1485,12 +1558,24 @@
fprintf(stdout, "Codec : %s\n",
aom_codec_iface_name(global->codec));
fprintf(stdout, "Executable : aomenc %s\n", ENV_BITS);
+#if CONFIG_MULTIVIEW_CORE
+ fprintf(stdout, "Number of views : %d \n", cfg->g_num_views);
+ for (int i = 0; i < input->num_views; i++) {
+ fprintf(stdout, "Input file%2d : %s\n", i,
+ input->filename[i]);
+ }
+#else
fprintf(stdout, "Input file : %s\n", input->filename);
+#endif
fprintf(stdout, "Output file : %s\n",
stream->config.out_fn);
fprintf(stdout,
"Input format : %s, %s, %dx%d, %3.1f FPS, %d bit\n",
+#if CONFIG_MULTIVIEW_CORE
+ file_type_to_string(input->file_type[0]),
+#else
file_type_to_string(input->file_type),
+#endif
image_format_to_string(input->fmt), input->width, input->height,
(double)global->framerate.num / (double)global->framerate.den,
input->bit_depth);
@@ -1498,6 +1583,18 @@
print_frames_to_code(stdout, stream, global);
fprintf(stdout, "Operating bit depth : %d\n", cfg->g_bit_depth);
fprintf(stdout, "Num of coding passes : %d\n", global->passes);
+#if CONFIG_MULTIVIEW_CORE
+ fprintf(stdout, "Lag in frames : %d\n",
+ cfg->g_lag_in_frames / cfg->g_num_views);
+ if (cfg->kf_min_dist != cfg->kf_max_dist) {
+ fprintf(stdout, "Key frame distance : %d - %d\n",
+ cfg->kf_min_dist / cfg->g_num_views,
+ cfg->kf_max_dist / cfg->g_num_views);
+ } else {
+ fprintf(stdout, "Key frame distance : %d\n",
+ cfg->kf_min_dist / cfg->g_num_views);
+ }
+#else
fprintf(stdout, "Lag in frames : %d\n",
cfg->g_lag_in_frames);
if (cfg->kf_min_dist != cfg->kf_max_dist) {
@@ -1506,6 +1603,7 @@
} else {
fprintf(stdout, "Key frame distance : %d\n", cfg->kf_min_dist);
}
+#endif
if (encoder_cfg->superblock_size != 0) {
fprintf(stdout, "Super block size : %d\n",
encoder_cfg->superblock_size);
@@ -1907,7 +2005,6 @@
aom_codec_pts_t frame_start, next_frame_start;
struct aom_codec_enc_cfg *cfg = &stream->config.cfg;
struct aom_usec_timer timer;
-
frame_start =
(cfg->g_timebase.den * (int64_t)(frames_in - 1) * global->framerate.den) /
cfg->g_timebase.num / global->framerate.num;
@@ -2225,8 +2322,25 @@
die("only support ivf output format while large-scale-tile=1\n");
}
+#if CONFIG_MULTIVIEW_CORE
+ /* read filenames for each view */
+ input.num_views = global.num_views;
+ for (int i = 0; i < input.num_views; i++) {
+ input.filename[i] = argv[i];
+ printf("Filename inputted : %s \n", input.filename[i]);
+ }
+ FOREACH_STREAM(stream, streams) {
+ stream->config.cfg.g_num_views = input.num_views;
+ stream->config.cfg.g_lag_in_frames *= input.num_views;
+ stream->config.cfg.kf_min_dist *= input.num_views;
+ stream->config.cfg.kf_max_dist *= input.num_views;
+ if (stream->config.cfg.kf_min_dist == 1) stream->config.cfg.kf_min_dist = 0;
+ if (stream->config.cfg.kf_max_dist == 1) stream->config.cfg.kf_max_dist = 0;
+ }
+#else
/* Handle non-option arguments */
input.filename = argv[0];
+#endif
FOREACH_STREAM(stream, streams) {
if (stream->config.recon_fn != NULL) {
@@ -2235,10 +2349,20 @@
}
}
+#if CONFIG_MULTIVIEW_CORE
+ /* check input files for each view */
+ for (int i = 0; i < input.num_views; i++) {
+ if (!input.filename[i]) {
+ fprintf(stderr, "No input file specified!\n");
+ usage_exit();
+ }
+ }
+#else
if (!input.filename) {
fprintf(stderr, "No input file specified!\n");
usage_exit();
}
+#endif
/* Decide if other chroma subsamplings than 4:2:0 are supported */
if (get_fourcc_by_aom_encoder(global.codec) == AV1_FOURCC)
@@ -2317,6 +2441,37 @@
}
break;
case 2:
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 0; i < input.num_views; i++) {
+ if (input.bit_depth < 12 && (input.fmt == AOM_IMG_FMT_I444 ||
+ input.fmt == AOM_IMG_FMT_I44416)) {
+ stream->config.cfg.g_profile = 1;
+ profile_updated = 1;
+ } else if (input.bit_depth < 12 &&
+ (input.fmt == AOM_IMG_FMT_I420 ||
+ input.fmt == AOM_IMG_FMT_I42016)) {
+ stream->config.cfg.g_profile = 0;
+ profile_updated = 1;
+ } else if (input.bit_depth == 12 &&
+ input.file_type[i] == FILE_TYPE_Y4M) {
+ // Note that here the input file values for chroma subsampling
+ // are used instead of those from the command line.
+ AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
+ AV1E_SET_CHROMA_SUBSAMPLING_X,
+ input.y4m[i].dst_c_dec_h >> 1);
+ AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
+ AV1E_SET_CHROMA_SUBSAMPLING_Y,
+ input.y4m[i].dst_c_dec_v >> 1);
+ } else if (input.bit_depth == 12 &&
+ input.file_type[i] == FILE_TYPE_RAW) {
+ AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
+ AV1E_SET_CHROMA_SUBSAMPLING_X,
+ stream->chroma_subsampling_x);
+ AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
+ AV1E_SET_CHROMA_SUBSAMPLING_Y,
+ stream->chroma_subsampling_y);
+ }
+#else
if (input.bit_depth < 12 && (input.fmt == AOM_IMG_FMT_I444 ||
input.fmt == AOM_IMG_FMT_I44416)) {
stream->config.cfg.g_profile = 1;
@@ -2344,6 +2499,7 @@
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
AV1E_SET_CHROMA_SUBSAMPLING_Y,
stream->chroma_subsampling_y);
+#endif
}
break;
default: break;
@@ -2425,6 +2581,17 @@
stream->config.cfg.g_timebase.num = global.framerate.den;
}
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 0; i < input.num_views; i++) {
+ if (input.file_type[i] == FILE_TYPE_Y4M)
+ /*The Y4M reader does its own allocation.
+ Just initialize this here to avoid problems if we never read any
+ frames.*/
+ memset(&raw, 0, sizeof(raw));
+ else
+ aom_img_alloc(&raw, input.fmt, input.width, input.height, 32);
+ }
+#else
if (input.file_type == FILE_TYPE_Y4M)
/*The Y4M reader does its own allocation.
Just initialize this here to avoid problems if we never read any
@@ -2432,7 +2599,7 @@
memset(&raw, 0, sizeof(raw));
else
aom_img_alloc(&raw, input.fmt, input.width, input.height, 32);
-
+#endif
FOREACH_STREAM(stream, streams) {
stream->rate_hist =
init_rate_histogram(&stream->config.cfg, &global.framerate);
@@ -2458,8 +2625,14 @@
// that test frameworks should use, when they want deterministic output
// from the container format).
if (stream->config.write_webm && !stream->webm_ctx.debug) {
+#if CONFIG_MULTIVIEW_CORE
+ const int i = 0;
+ encoder_settings = extract_encoder_settings(
+ aom_codec_version_str(), argv_, argc, input.filename[i]);
+#else
encoder_settings = extract_encoder_settings(
aom_codec_version_str(), argv_, argc, input.filename);
+#endif
if (encoder_settings == NULL) {
fprintf(
stderr,
@@ -2505,8 +2678,19 @@
// The limit iterator will stop returning frames after the N-th.
StreamIter limit_stream;
+#if CONFIG_MULTIVIEW_CORE
+ int limit = global.limit * input.num_views;
+ limit_stream_iter_init(&limit_stream, &step_stream, limit);
+ int view_id = 0;
+#else
limit_stream_iter_init(&limit_stream, &step_stream, global.limit);
+#endif
while (frame_avail || got_data) {
+#if CONFIG_MULTIVIEW_CORE
+ view_id = seen_frames % input.num_views;
+ orig_stream.view_id = view_id;
+ limit_stream.view_id = view_id;
+#endif
frame_avail = read_stream_iter(&limit_stream, &raw);
if (frame_avail) {
seen_frames++;
@@ -2528,6 +2712,9 @@
frame_to_encode = &raw;
}
assert(frame_to_encode->fmt & AOM_IMG_FMT_HIGHBITDEPTH);
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" frame_avail:%d seen_frames=%d \n", frame_avail, seen_frames);
+#endif
FOREACH_STREAM(stream, streams) {
encode_frame(stream, &global, frame_avail ? frame_to_encode : NULL,
seen_frames);
diff --git a/apps/aomenc.h b/apps/aomenc.h
index f243891..57f7397 100644
--- a/apps/aomenc.h
+++ b/apps/aomenc.h
@@ -40,6 +40,9 @@
int limit;
int skip_frames;
int step_frames;
+#if CONFIG_MULTIVIEW_CORE
+ int num_views;
+#endif
int show_psnr;
enum TestDecodeFatality test_decode;
int have_framerate;
diff --git a/av1/arg_defs.c b/av1/arg_defs.c
index 85b3081..17a7f71 100644
--- a/av1/arg_defs.c
+++ b/av1/arg_defs.c
@@ -219,6 +219,10 @@
.stereo_mode = ARG_DEF_ENUM(NULL, "stereo-mode", 1, "Stereo 3D video format",
stereo_mode_enum),
#endif
+#if CONFIG_MULTIVIEW_CORE
+ .num_views =
+ ARG_DEF(NULL, "num-views", 1, "Number of views for multi-layered coding"),
+#endif
.timebase = ARG_DEF(NULL, "timebase", 1,
"Output timestamp precision (fractional seconds)"),
.global_error_resilient = ARG_DEF(NULL, "global-error-resilient", 1,
diff --git a/av1/arg_defs.h b/av1/arg_defs.h
index 8f6006a..44481e4 100644
--- a/av1/arg_defs.h
+++ b/av1/arg_defs.h
@@ -77,6 +77,9 @@
#if CONFIG_WEBM_IO
arg_def_t stereo_mode;
#endif
+#if CONFIG_MULTIVIEW_CORE
+ arg_def_t num_views;
+#endif
arg_def_t timebase;
arg_def_t global_error_resilient;
arg_def_t lag_in_frames;
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 4c5b8c5..e2b1787 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -36,6 +36,10 @@
#include "aom_dsp/psnr.h"
#include "aom_ports/aom_timer.h"
+#if CONFIG_MULTIVIEW_CORE
+#include "common/tools_common.h"
+#endif
+
#define MAG_SIZE (4)
struct av1_extracfg {
@@ -707,7 +711,9 @@
RANGE_CHECK(cfg, g_timebase.den, 1, 1000000000);
RANGE_CHECK(cfg, g_timebase.num, 1, cfg->g_timebase.den);
RANGE_CHECK_HI(cfg, g_profile, MAX_PROFILES - 1);
-
+#if CONFIG_MULTIVIEW_CORE
+ RANGE_CHECK(cfg, g_num_views, 1, NUM_LAYERS_MAX);
+#endif
RANGE_CHECK(cfg, g_bit_depth, AOM_BITS_8, AOM_BITS_12);
RANGE_CHECK(cfg, g_input_bit_depth, AOM_BITS_8, AOM_BITS_12);
@@ -1350,6 +1356,11 @@
frm_dim_cfg->render_width = extra_cfg->render_width;
frm_dim_cfg->render_height = extra_cfg->render_height;
+#if CONFIG_MULTIVIEW_CORE
+ // Set number of views
+ input_cfg->num_views = cfg->g_num_views;
+#endif
+
// Set input video related configuration.
input_cfg->input_bit_depth = cfg->g_input_bit_depth;
// guess a frame rate if out of whack, use 30
@@ -1600,6 +1611,9 @@
} else { // auto-selected qp offset
q_cfg->fixed_qp_offsets[i] = get_modeled_qp_offset(
rc_cfg->qp, i, tool_cfg->bit_depth, q_cfg->q_based_qp_offsets);
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" qp-offset[%d]=%2.2f\n", i, q_cfg->fixed_qp_offsets[i]);
+#endif
}
} else {
q_cfg->fixed_qp_offsets[i] = -1.0;
@@ -2028,7 +2042,6 @@
const SubGOPCfg *const subgop_cfg = gf_group->subgop_cfg;
subgop_info->gf_interval = cpi->rc.baseline_gf_interval;
subgop_info->frames_to_key = cpi->rc.frames_to_key;
-
// As key frame is not part of sub-gop configuration,
// parameters are assigned separately.
if (cpi->common.current_frame.frame_type == KEY_FRAME) {
@@ -3054,23 +3067,38 @@
if (!cm->show_existing_frame) {
// Get reference frame information
int ref_poc[INTER_REFS_PER_FRAME];
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ int ref_view[INTER_REFS_PER_FRAME];
+#endif
for (int ref_frame = 0; ref_frame < INTER_REFS_PER_FRAME; ++ref_frame) {
const int ref_idx = ref_frame;
const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ ref_view[ref_idx] = buf ? (int)buf->view_id : -1;
+ ref_poc[ref_idx] = buf ? (int)buf->display_order_hint : -1;
+#else
ref_poc[ref_idx] = buf ? (int)buf->absolute_poc : -1;
ref_poc[ref_idx] = (ref_poc[ref_idx] == (int)cm->cur_frame->absolute_poc)
? -1
: ref_poc[ref_idx];
+#endif
}
if (cpi->b_calculate_psnr >= 1) {
const bool use_hbd_psnr = (cpi->b_calculate_psnr == 2);
fprintf(stdout,
+#if CONFIG_MULTIVIEW_CORE
+ "POC:%6d, DOH:%3d, View:%2d [%s][Level:%d][Q:%3d]: %10" PRIu64
+#else
"POC:%6d [%s][Level:%d][Q:%3d]: %10" PRIu64
+#endif
" Bytes, "
"%6.1fms, %2.4f dB(Y), %2.4f dB(U), "
"%2.4f dB(V), "
"%2.4f dB(Avg)",
cm->cur_frame->absolute_poc,
+#if CONFIG_MULTIVIEW_CORE
+ cm->cur_frame->display_order_hint, cm->cur_frame->view_id,
+#endif
frameType[cm->current_frame.frame_type],
cm->cur_frame->pyramid_level, base_qindex, (uint64_t)frame_size,
cx_time / 1000.0, use_hbd_psnr ? psnr.psnr_hbd[1] : psnr.psnr[1],
@@ -3090,7 +3118,11 @@
fprintf(stdout, " [");
for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ++ref_idx) {
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ fprintf(stdout, "(%d,%d)", ref_poc[ref_idx], ref_view[ref_idx]);
+#else
fprintf(stdout, "%3d,", ref_poc[ref_idx]);
+#endif
}
fprintf(stdout, "]\n");
}
@@ -4509,11 +4541,14 @@
0, // g_threads
0, // g_profile
- 320, // g_w
- 240, // g_h
- 0, // g_limit
- 0, // g_forced_max_frame_width
- 0, // g_forced_max_frame_height
+ 320, // g_w
+ 240, // g_h
+ 0, // g_limit
+ 0, // g_forced_max_frame_width
+ 0, // g_forced_max_frame_height
+#if CONFIG_MULTIVIEW_CORE
+ 1, // g_num_views
+#endif
AOM_BITS_8, // g_bit_depth
8, // g_input_bit_depth
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index c6dae1c..f391769 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -385,6 +385,9 @@
si->w = 0;
si->h = 0;
si->is_kf = 0; // is_kf indicates whether the current packet contains a RAP
+#if CONFIG_MULTIVIEW_CORE
+ si->number_views = 0;
+#endif
ObuHeader obu_header;
memset(&obu_header, 0, sizeof(obu_header));
@@ -420,6 +423,12 @@
BITSTREAM_PROFILE profile = av1_read_profile(&rb); // profile
+#if CONFIG_MULTIVIEW_CORE
+ si->number_views =
+ aom_rb_read_literal(&rb, 8) + 1; // TODO: @hegilmez redesign later
+ // or change where this is signaled
+#endif
+
int num_bits_width = aom_rb_read_literal(&rb, 4) + 1;
int num_bits_height = aom_rb_read_literal(&rb, 4) + 1;
int max_frame_width = aom_rb_read_literal(&rb, num_bits_width) + 1;
@@ -820,15 +829,27 @@
// show_existing_frame
if (pbi->common.seq_params.order_hint_info.enable_order_hint &&
pbi->common.seq_params.enable_frame_output_order) {
+#if !CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
if (!pbi->common.show_existing_frame ||
pbi->common.current_frame.frame_type == KEY_FRAME)
decrease_ref_count(pbi->output_frames[0], pool);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
} else {
for (size_t j = 0; j < pbi->num_output_frames; j++) {
decrease_ref_count(pbi->output_frames[j], pool);
}
}
pbi->num_output_frames = 0;
+#if CONFIG_MULTIVIEW_CORE
+ for (size_t j = 0; j < REF_FRAMES; j++) {
+ pbi->output_view_ids[j] = -1;
+ }
+#endif
+#if CONFIG_MULTIVIEW_CORE
+ for (size_t j = 0; j < REF_FRAMES; j++) {
+ pbi->display_order_hint_ids[j] = -1;
+ }
+#endif
unlock_buffer_pool(pool);
for (size_t j = 0; j < ctx->num_grain_image_frame_buffers; j++) {
pool->release_fb_cb(pool->cb_priv, &ctx->grain_image_frame_buffers[j]);
@@ -1021,6 +1042,7 @@
AV1Decoder *const pbi = frame_worker_data->pbi;
AV1_COMMON *const cm = &pbi->common;
CommonTileParams *const tiles = &cm->tiles;
+
// Wait for the frame from worker thread.
if (winterface->sync(worker)) {
// Check if worker has received any frames.
@@ -1033,6 +1055,11 @@
if (av1_get_raw_frame(frame_worker_data->pbi, *index, &sd,
&grain_params) == 0) {
RefCntBuffer *const output_frame_buf = pbi->output_frames[*index];
+#if CONFIG_MULTIVIEW_CORE
+ int view_id_ctx = pbi->output_view_ids[*index];
+ ctx->img.view_id = view_id_ctx;
+ ctx->img.display_order_hint = pbi->display_order_hint_ids[*index];
+#endif
ctx->last_show_frame = output_frame_buf;
if (ctx->need_resync) return NULL;
aom_img_remove_metadata(&ctx->img);
@@ -1091,6 +1118,7 @@
img = &ctx->img;
img->temporal_id = cm->temporal_layer_id;
img->spatial_id = cm->spatial_layer_id;
+
if (pbi->skip_film_grain) grain_params->apply_grain = 0;
aom_image_t *res =
add_grain_if_needed(ctx, img, &ctx->image_with_grain, grain_params);
diff --git a/av1/common/av1_common_int.h b/av1/common/av1_common_int.h
index 074d946..c995dae 100644
--- a/av1/common/av1_common_int.h
+++ b/av1/common/av1_common_int.h
@@ -316,6 +316,10 @@
unsigned int order_hint;
int ref_order_hints[INTER_REFS_PER_FRAME];
int ref_display_order_hint[INTER_REFS_PER_FRAME];
+#if CONFIG_MULTIVIEW_CORE
+ int view_id;
+ int ref_view_ids[INTER_REFS_PER_FRAME];
+#endif
// These variables are used only in encoder and compare the absolute
// display order hint to compute the relative distance and overcome
@@ -325,6 +329,9 @@
unsigned int absolute_poc;
// Frame's level within the hierarchical structure
unsigned int pyramid_level;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ unsigned int temporal_layer_id;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
#if CONFIG_IMPROVED_GLOBAL_MOTION
// How many ref frames did this frame use?
@@ -392,8 +399,14 @@
typedef struct {
FRAME_TYPE frame_type;
int pyr_level;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ int temporal_layer_id;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
int disp_order;
int base_qindex;
+#if CONFIG_MULTIVIEW_CORE
+ int view_id;
+#endif
} RefFrameMapPair;
#endif // CONFIG_PRIMARY_REF_FRAME_OPT
@@ -671,6 +684,9 @@
// Operating point info.
int operating_points_cnt_minus_1;
int operating_point_idc[MAX_NUM_OPERATING_POINTS];
+#if CONFIG_MULTIVIEW_CORE
+ int num_views; // for multiview support
+#endif
int timing_info_present;
aom_timing_info_t timing_info;
uint8_t decoder_model_info_present_flag;
@@ -700,9 +716,15 @@
unsigned int display_order_hint;
// Frame's level within the hierarchical structure
unsigned int pyramid_level;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ unsigned int temporal_layer_id;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
unsigned int absolute_poc;
unsigned int key_frame_number;
unsigned int frame_number;
+#if CONFIG_MULTIVIEW_CORE
+ int view_id;
+#endif
SkipModeInfo skip_mode_info;
int refresh_frame_flags; // Which ref frames are overwritten by this frame
} CurrentFrame;
@@ -1866,6 +1888,17 @@
*/
int spatial_layer_id;
+#if CONFIG_MULTIVIEW_CORE
+ /*!
+ * Number of multiple layers
+ */
+ unsigned int number_layers;
+ /*!
+ * Multi-layer ID of this frame
+ * (in the range 0 ... (number_layers - 1)).
+ */
+ int layer_id;
+#endif
/*!
* Weights for IBP of directional modes.
*/
@@ -1897,6 +1930,11 @@
FILE *fDecCoeffLog;
#endif
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ FILE *fEncMultiviewLog;
+ FILE *fDecMultiviewLog;
+#endif
+
#if CONFIG_PARAKIT_COLLECT_DATA
ProbModelInfo prob_models[MAX_NUM_CTX_GROUPS];
#endif
@@ -2091,6 +2129,19 @@
++rhs_ptr->ref_count;
}
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+static INLINE void set_frame_buffer_invalid(RefCntBuffer **lhs_ptr) {
+ RefCntBuffer *const old_ptr = *lhs_ptr;
+ if (old_ptr != NULL) {
+ assert(old_ptr->ref_count > 0);
+ // One less reference to the buffer at 'old_ptr', so decrease ref count.
+ --old_ptr->ref_count;
+ }
+
+ *lhs_ptr = NULL;
+}
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+
static INLINE int frame_is_intra_only(const AV1_COMMON *const cm) {
return cm->current_frame.frame_type == KEY_FRAME ||
cm->current_frame.frame_type == INTRA_ONLY_FRAME;
@@ -2126,6 +2177,156 @@
return (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : NULL;
}
+#if CONFIG_MULTIVIEW_DEBUG
+static INLINE void debug_print_multiview_curr_frame(
+ const AV1_COMMON *const cm) {
+ const CurrentFrame *const cf = &cm->current_frame;
+ const char frame_type_str[4][25] = { "KEY_FRAME", "INTER_FRAME",
+ "INTRA_ONLY_FRAME", "S_FRAME" };
+ const char ref_mode_str[4][50] = { "SINGLE_REFERENCE", "COMPOUND_REFERENCE",
+ "REFERENCE_MODE_SELECT",
+ "REFERENCE_MODES" };
+ printf("frame_type=%s,", frame_type_str[cf->frame_type]);
+ // printf("reference_mode=%s,", ref_mode_str[cf->reference_mode]);
+ printf("order_hint=%2d, ", cf->order_hint);
+ printf("display_order_hint=%2d, ", cf->display_order_hint);
+ // printf("pyramid_level=%2d, ", cf->pyramid_level); // encoder only
+ // printf("absolute_poc=%2d, ", cf->absolute_poc); // encoder only
+ // printf("key_frame_number=%2d, ", cf->key_frame_number);
+ // printf("frame_number=%2d, ", cf->frame_number);
+ printf("view_id=%2d, ", cf->view_id);
+ printf("refresh_frame_flags=%2d,", cf->refresh_frame_flags);
+ printf("num_total_refs=%2d,", cm->ref_frames_info.num_total_refs);
+ printf("num_cur_refs=%2d,", cm->ref_frames_info.num_cur_refs);
+ printf("num_past_refs=%2d,", cm->ref_frames_info.num_past_refs);
+ printf("num_future_refs=%2d", cm->ref_frames_info.num_future_refs);
+
+ printf("\n");
+}
+
+static INLINE void debug_print_buffer_state(const AV1_COMMON *const cm) {
+ printf(" [ ");
+ for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) {
+ RefCntBuffer *const buf = cm->ref_frame_map[ref_idx];
+ if (buf == NULL)
+ printf("%d:(**,**,**) ", ref_idx);
+ else
+ printf("%d:(%d,%d,%d) ", ref_idx, buf->view_id, buf->pyramid_level,
+ buf->display_order_hint);
+ }
+ printf("]\n");
+}
+
+static INLINE void debug_print_multiview_buf_refs(const AV1_COMMON *const cm) {
+ const RefCntBuffer *const cf = cm->cur_frame;
+ MV_REFERENCE_FRAME ref_frame;
+ printf("(View,OH,DOH):(%2d,%2d,%2d) ", cf->view_id, cf->order_hint,
+ cf->display_order_hint);
+ printf(" num_ref_frames/ref_frames_info.num_total_refs=%d/%d ",
+ cf->num_ref_frames, cm->ref_frames_info.num_total_refs);
+ printf("[");
+ for (ref_frame = 0; ref_frame < INTER_REFS_PER_FRAME; ++ref_frame) {
+ const int map_idx = get_ref_frame_map_idx(cm, ref_frame);
+ printf("%2d:", map_idx);
+ printf("(%2d,", cf->ref_view_ids[ref_frame]);
+ printf("%2d,", cf->ref_order_hints[ref_frame]);
+ printf("%2d) ", cf->ref_display_order_hint[ref_frame]);
+ }
+ printf("]\n");
+}
+
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+static INLINE void logfile_multiview_curr_frame(const AV1_COMMON *const cm,
+ FILE *const file) {
+ const CurrentFrame *const cf = &cm->current_frame;
+ const char frame_type_str[4][25] = { "KEY_FRAME", "INTER_FRAME",
+ "INTRA_ONLY_FRAME", "S_FRAME" };
+ const char ref_mode_str[4][50] = { "SINGLE_REFERENCE", "COMPOUND_REFERENCE",
+ "REFERENCE_MODE_SELECT",
+ "REFERENCE_MODES" };
+ fprintf(file, "frame_type=%s,", frame_type_str[cf->frame_type]);
+ // fprintf(file,"reference_mode=%s,", ref_mode_str[cf->reference_mode]);
+ fprintf(file, "order_hint=%2d, ", cf->order_hint);
+ fprintf(file, "display_order_hint=%2d, ", cf->display_order_hint);
+ // fprintf(file,"pyramid_level=%2d, ", cf->pyramid_level); // encoder only
+ // fprintf(file,"absolute_poc=%2d, ", cf->absolute_poc); // encoder only
+ // fprintf(file,"key_frame_number=%2d, ", cf->key_frame_number);
+ // fprintf(file,"frame_number=%2d, ", cf->frame_number);
+ fprintf(file, "view_id=%2d, ", cf->view_id);
+ fprintf(file, "refresh_frame_flags=%2d,", cf->refresh_frame_flags);
+ fprintf(file, "num_total_refs=%2d,", cm->ref_frames_info.num_total_refs);
+ fprintf(file, "num_cur_refs=%2d,", cm->ref_frames_info.num_cur_refs);
+ fprintf(file, "num_past_refs=%2d,", cm->ref_frames_info.num_past_refs);
+ fprintf(file, "num_future_refs=%2d", cm->ref_frames_info.num_future_refs);
+ fprintf(file, "\n");
+}
+
+static INLINE void logfile_multiview_buf_refs(const AV1_COMMON *const cm,
+ FILE *const file) {
+ const RefCntBuffer *const cf = cm->cur_frame;
+ MV_REFERENCE_FRAME ref_frame;
+ fprintf(file, "(View,OH,DOH):(%2d,%2d,%2d) ", cf->view_id, cf->order_hint,
+ cf->display_order_hint);
+ fprintf(file, " num_ref_frames/ref_frames_info.num_total_refs=%d/%d ",
+ cf->num_ref_frames, cm->ref_frames_info.num_total_refs);
+ fprintf(file, "[");
+ for (ref_frame = 0; ref_frame < INTER_REFS_PER_FRAME; ++ref_frame) {
+ const int map_idx = get_ref_frame_map_idx(cm, ref_frame);
+ fprintf(file, "%2d:", map_idx);
+ fprintf(file, "(%2d,", cf->ref_view_ids[ref_frame]);
+ fprintf(file, "%2d,", cf->ref_order_hints[ref_frame]);
+ fprintf(file, "%2d) ", cf->ref_display_order_hint[ref_frame]);
+ }
+ fprintf(file, "]\n");
+}
+
+static INLINE void logfile_buffer_state(const AV1_COMMON *const cm,
+ FILE *const file) {
+ fprintf(file, " [ ");
+ for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) {
+ RefCntBuffer *const buf = cm->ref_frame_map[ref_idx];
+ if (buf == NULL)
+ fprintf(file, "%d:(**,**,**) ", ref_idx);
+ else
+ fprintf(file, "%d:(%d,%d,%d) ", ref_idx, buf->view_id, buf->order_hint,
+ buf->display_order_hint);
+ }
+ fprintf(file, "]\n");
+}
+
+static INLINE void logfile_primary_ref_info(const AV1_COMMON *const cm,
+ FILE *const file) {
+ const int idx = cm->features.primary_ref_frame;
+ const int map_idx = get_ref_frame_map_idx(cm, idx);
+ const RefCntBuffer *const ref_buf = cm->ref_frame_map[map_idx];
+ if (ref_buf == NULL)
+ fprintf(file,
+ " Primary Reference Info. : [idx,map_idx]:[%2d,%2d] --> "
+ "(N/A,N/A,N/A) \n ",
+ idx, map_idx);
+ else
+ fprintf(file,
+ " Primary Reference Info. : [idx,map_idx]:[%2d,%2d] --> "
+ "(%2d,%2d,%3d) \n ",
+ idx, map_idx, ref_buf->view_id, ref_buf->order_hint,
+ ref_buf->display_order_hint);
+}
+
+// static INLINE void logfile_show_existing_frame(const AV1_COMMON *const cm,
+// FILE *const file) {
+// int show_existing_frame = cm->show_existing_frame;
+// if (show_existing_frame)
+// fprintf(file," Show existing frame : [idx,map_idx]:[%2d,%2d] -->
+// (%2d,%2d,%3d) \n ", idx, map_idx, ref_buf->view_id, ref_buf->order_hint,
+// ref_buf->display_order_hint );
+//
+// RefCntBuffer *const frame_to_show =
+// cm->ref_frame_map[cpi->existing_fb_idx_to_show];
+// }
+#endif
+
+#endif
+
// Both const and non-const versions of this function are provided so that it
// can be used with a const AV1_COMMON if needed.
static INLINE const struct scale_factors *get_ref_scale_factors_const(
diff --git a/av1/common/enums.h b/av1/common/enums.h
index 90dc0e6..58a004e 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -1254,7 +1254,13 @@
#define WARP_EXTEND_CTX 3
#endif // CONFIG_OPTIMIZE_CTX_TIP_WARP
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+#define EXTENDED_INTER_REFS_PER_FRAME 8
+#define INTER_REFS_PER_FRAME (EXTENDED_INTER_REFS_PER_FRAME + 7)
+#define EXTENDED_INTER_REFS_CONTEXT 6
+#else
#define INTER_REFS_PER_FRAME 7
+#endif
#define REF_FRAMES (INTER_REFS_PER_FRAME + 1)
// NOTE: A limited number of unidirectional reference pairs can be signalled for
// compound prediction. The use of skip mode, on the other hand, makes it
@@ -1285,7 +1291,11 @@
#define NONE_FRAME INVALID_IDX
#define AOM_REFFRAME_ALL ((1 << INTER_REFS_PER_FRAME) - 1)
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+#define REF_FRAMES_LOG2 4
+#else
#define REF_FRAMES_LOG2 3
+#endif
#define REFRESH_FRAME_ALL ((1 << REF_FRAMES) - 1)
// REF_FRAMES for the cm->ref_frame_map array, 1 scratch frame for the new
@@ -1308,7 +1318,7 @@
// Note: It includes single and compound references. So, it can take values from
// NONE_FRAME to (MODE_CTX_REF_FRAMES - 1). Hence, it is not defined as an enum.
-typedef int8_t MV_REFERENCE_FRAME;
+typedef int16_t MV_REFERENCE_FRAME;
#define MAX_LR_FLEX_SWITCHABLE_BITS 4
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index b2417eb..bd0edcc 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -3945,6 +3945,13 @@
cm->cur_frame->display_order_hint = cm->current_frame.display_order_hint;
cm->cur_frame->absolute_poc = cm->current_frame.absolute_poc;
cm->cur_frame->pyramid_level = cm->current_frame.pyramid_level;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ cm->cur_frame->temporal_layer_id = cm->current_frame.temporal_layer_id;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+
+#if CONFIG_MULTIVIEW_CORE
+ cm->cur_frame->view_id = cm->current_frame.view_id;
+#endif
MV_REFERENCE_FRAME ref_frame;
for (ref_frame = 0; ref_frame < INTER_REFS_PER_FRAME; ++ref_frame) {
@@ -3953,9 +3960,15 @@
cm->cur_frame->ref_order_hints[ref_frame] = buf->order_hint;
cm->cur_frame->ref_display_order_hint[ref_frame] =
buf->display_order_hint;
+#if CONFIG_MULTIVIEW_CORE
+ cm->cur_frame->ref_view_ids[ref_frame] = buf->view_id;
+#endif
} else {
cm->cur_frame->ref_order_hints[ref_frame] = -1;
cm->cur_frame->ref_display_order_hint[ref_frame] = -1;
+#if CONFIG_MULTIVIEW_CORE
+ cm->cur_frame->ref_view_ids[ref_frame] = -1;
+#endif
}
}
}
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index cec4f3e..f019872 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -371,10 +371,10 @@
// (2, 2), (2, 3), ..., (2, n-1),
// ...
// (n-1, n-1)
-static INLINE int8_t single2comb(int n, const int8_t *const rf) {
+static INLINE int16_t single2comb(int n, const int16_t *const rf) {
assert(rf[0] < n && rf[1] < n);
- int8_t rfr[2] = { rf[0], rf[1] };
+ int16_t rfr[2] = { rf[0], rf[1] };
if (rf[1] < rf[0]) {
rfr[0] = rf[1];
rfr[1] = rf[0];
@@ -389,7 +389,7 @@
// Converts a combined index in [0, n*(n+1)/2] to a pair of single
// ref indices (rf) each in [0, n-1]. See comment above for order
// of the combined indexing.
-static INLINE void comb2single(int n, int8_t combindex, int8_t *rf) {
+static INLINE void comb2single(int n, int16_t combindex, int16_t *rf) {
assert(combindex < n * (n + 1) / 2);
int i = n, j = n;
rf[0] = 0;
@@ -444,7 +444,7 @@
}
#endif // CONFIG_SAME_REF_COMPOUND
-static INLINE int8_t av1_ref_frame_type(const MV_REFERENCE_FRAME *const rf) {
+static INLINE int16_t av1_ref_frame_type(const MV_REFERENCE_FRAME *const rf) {
if (!is_inter_ref_frame(rf[0])) {
// Intra or invalid
return rf[0];
@@ -507,13 +507,13 @@
static INLINE int16_t av1_mode_context_pristine(
const int16_t *const mode_context, const MV_REFERENCE_FRAME *const rf) {
- const int8_t ref_frame = av1_ref_frame_type(rf);
+ const int16_t ref_frame = av1_ref_frame_type(rf);
return mode_context[ref_frame];
}
static INLINE int16_t av1_mode_context_analyzer(
const int16_t *const mode_context, const MV_REFERENCE_FRAME *const rf) {
- const int8_t ref_frame = av1_ref_frame_type(rf);
+ const int16_t ref_frame = av1_ref_frame_type(rf);
#if CONFIG_OPT_INTER_MODE_CTX
return mode_context[ref_frame];
diff --git a/av1/common/pred_common.c b/av1/common/pred_common.c
index 0725e2b..5e4f29e 100644
--- a/av1/common/pred_common.c
+++ b/av1/common/pred_common.c
@@ -42,10 +42,19 @@
// Checks to see if a particular reference frame is already in the reference
// frame map
-static int is_in_ref_score(RefScoreData *map, int disp_order, int score,
- int n_frames) {
+static int is_in_ref_score(RefScoreData *map, int disp_order,
+#if CONFIG_MULTIVIEW_CORE
+ int view_id,
+#endif
+ int score, int n_frames) {
for (int i = 0; i < n_frames; i++) {
+#if CONFIG_MULTIVIEW_CORE
+ if (disp_order == map[i].disp_order && view_id == map[i].view_id &&
+ score == map[i].score)
+ return 1;
+#else
if (disp_order == map[i].disp_order && score == map[i].score) return 1;
+#endif
}
return 0;
}
@@ -147,24 +156,42 @@
if (cur_ref.disp_order == -1) continue;
max_disp = AOMMAX(max_disp, cur_ref.disp_order);
}
-
// Compute a score for each reference buffer
for (int i = 0; i < REF_FRAMES; i++) {
// Get reference frame buffer
RefFrameMapPair cur_ref = ref_frame_map_pairs[i];
if (cur_ref.disp_order == -1) continue;
const int ref_disp = cur_ref.disp_order;
+#if CONFIG_MULTIVIEW_CORE
+ const int ref_view_id = cur_ref.view_id;
+#endif
// In error resilient mode, ref mapping must be independent of the
// base_qindex to ensure decoding independency
const int ref_base_qindex = cur_ref.base_qindex;
+#if CONFIG_MULTIVIEW_CORE
+ const int layer_diff = cm->current_frame.view_id - cur_ref.view_id;
+ const int disp_diff = cur_frame_disp - ref_disp + layer_diff;
+#else
const int disp_diff = cur_frame_disp - ref_disp;
+#endif
int tdist = abs(disp_diff);
+#if CONFIG_MULTIVIEW_CORE
+ // if (tdist == 0 && layer_diff != 0) {
+ // tdist = abs(layer_diff);
+ // disp_diff += layer_diff;
+ // }
+#endif
const int score =
max_disp > cur_frame_disp
? ((tdist << DIST_WEIGHT_BITS) + ref_base_qindex)
: temp_dist_score_lookup[AOMMIN(tdist, DECAY_DIST_CAP)] +
AOMMAX(tdist - DECAY_DIST_CAP, 0) + ref_base_qindex;
- if (is_in_ref_score(scores, ref_disp, score, n_ranked)) continue;
+ if (is_in_ref_score(scores, ref_disp,
+#if CONFIG_MULTIVIEW_CORE
+ ref_view_id,
+#endif
+ score, n_ranked))
+ continue;
scores[n_ranked].index = i;
scores[n_ranked].score = score;
@@ -200,7 +227,12 @@
// Fill any slots that are empty (should only happen for the first 7 frames)
for (int i = 0; i < REF_FRAMES; i++) {
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ if (cm->remapped_ref_idx[i] == INVALID_IDX)
+ cm->remapped_ref_idx[i] = scores[0].index;
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
if (cm->remapped_ref_idx[i] == INVALID_IDX) cm->remapped_ref_idx[i] = 0;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
}
return n_ranked;
}
@@ -210,6 +242,9 @@
int idx;
int disp_order;
int base_qindex;
+#if CONFIG_MULTIVIEW_CORE
+ int view_id;
+#endif
} PrimaryRefCand;
// Check if one reference frame is better based on its distance to the current
@@ -334,10 +369,18 @@
const RefFrameMapPair *ref_frame_map_pairs = cm->ref_frame_map_pairs;
const int cur_frame_disp = cm->current_frame.display_order_hint;
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ const int curr_view_id = cm->current_frame.view_id;
+#endif
int i;
+#if CONFIG_MULTIVIEW_CORE
+ PrimaryRefCand cand_lower_qp = { -1, -1, -1, -1 };
+ PrimaryRefCand cand_higher_qp = { -1, -1, INT32_MAX, -1 };
+#else
PrimaryRefCand cand_lower_qp = { -1, -1, -1 };
PrimaryRefCand cand_higher_qp = { -1, -1, INT32_MAX };
+#endif
const OrderHintInfo *oh = &cm->seq_params.order_hint_info;
for (i = 0; i < n_refs; i++) {
@@ -345,7 +388,20 @@
RefFrameMapPair cur_ref = ref_frame_map_pairs[get_ref_frame_map_idx(cm, i)];
if (cur_ref.disp_order == -1) continue;
if (cur_ref.frame_type != INTER_FRAME) continue;
-
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ const int ref_view_id = cur_ref.view_id;
+ if (ref_view_id > curr_view_id) continue;
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ const CurrentFrame *const cf = &cm->current_frame;
+ if (ref_view_id > curr_view_id) {
+ printf("Breaking view dependency: \n");
+ printf("(index=%d): (View,Level,OH,DOH):(%d,%d,%d,%d) \n", i, cf->view_id,
+ cf->pyramid_level, cf->order_hint, cf->display_order_hint);
+ printf("Current reference-buffer =");
+ debug_print_buffer_state(cm);
+ }
+#endif
+#endif
const int ref_base_qindex = cur_ref.base_qindex;
if (ref_base_qindex > cm->quant_params.base_qindex) {
@@ -356,6 +412,9 @@
cand_higher_qp.idx = i;
cand_higher_qp.base_qindex = ref_base_qindex;
cand_higher_qp.disp_order = cur_ref.disp_order;
+#if CONFIG_MULTIVIEW_CORE
+ cand_higher_qp.view_id = cur_ref.view_id;
+#endif
}
} else {
if ((ref_base_qindex > cand_lower_qp.base_qindex) ||
@@ -365,6 +424,9 @@
cand_lower_qp.idx = i;
cand_lower_qp.base_qindex = ref_base_qindex;
cand_lower_qp.disp_order = cur_ref.disp_order;
+#if CONFIG_MULTIVIEW_CORE
+ cand_lower_qp.view_id = cur_ref.view_id;
+#endif
}
}
}
diff --git a/av1/common/pred_common.h b/av1/common/pred_common.h
index 77d189d..4a004c4 100644
--- a/av1/common/pred_common.h
+++ b/av1/common/pred_common.h
@@ -25,6 +25,9 @@
#if !CONFIG_PRIMARY_REF_FRAME_OPT
typedef struct {
int pyr_level;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ int temporal_layer_id;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
int disp_order;
int base_qindex;
} RefFrameMapPair;
@@ -42,10 +45,31 @@
// Get reference frame buffer
const RefCntBuffer *const buf = cm->ref_frame_map[map_idx];
if (ref_frame_map_pairs[map_idx].disp_order == -1) continue;
- if (buf == NULL) {
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ // If the temporal_layer_id of the reference frame is greater than
+ // the temporal_layer_id of the current frame, the reference frame
+ // is not included into the list of ref_frame_map_pairs[].
+ if (buf == NULL ||
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ buf->view_id > cm->current_frame.view_id ||
+#endif
+ buf->temporal_layer_id > cm->current_frame.temporal_layer_id) {
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ if (buf == NULL
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ || buf->view_id > cm->current_frame.view_id
+#endif
+ ) {
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
ref_frame_map_pairs[map_idx].disp_order = -1;
ref_frame_map_pairs[map_idx].pyr_level = -1;
ref_frame_map_pairs[map_idx].base_qindex = -1;
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ ref_frame_map_pairs[map_idx].view_id = -1;
+#endif
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ ref_frame_map_pairs[map_idx].temporal_layer_id = -1;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
continue;
} else if (buf->ref_count > 1) {
// Once the keyframe is coded, the slots in ref_frame_map will all
@@ -59,12 +83,24 @@
ref_frame_map_pairs[idx2].disp_order = -1;
ref_frame_map_pairs[idx2].pyr_level = -1;
ref_frame_map_pairs[idx2].base_qindex = -1;
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ ref_frame_map_pairs[idx2].view_id = -1;
+#endif
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ ref_frame_map_pairs[map_idx].temporal_layer_id = -1;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
}
}
}
ref_frame_map_pairs[map_idx].disp_order = (int)buf->display_order_hint;
ref_frame_map_pairs[map_idx].pyr_level = buf->pyramid_level;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ ref_frame_map_pairs[map_idx].temporal_layer_id = buf->temporal_layer_id;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
ref_frame_map_pairs[map_idx].base_qindex = buf->base_qindex;
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ ref_frame_map_pairs[map_idx].view_id = buf->view_id;
+#endif
#if CONFIG_PRIMARY_REF_FRAME_OPT
ref_frame_map_pairs[map_idx].frame_type = buf->frame_type;
#endif // CONFIG_PRIMARY_REF_FRAME_OPT
@@ -84,6 +120,9 @@
int disp_order;
// Quality of the reference frame
int base_qindex;
+#if CONFIG_MULTIVIEW_CORE
+ int view_id;
+#endif
} RefScoreData;
/*!\endcond */
@@ -548,8 +587,13 @@
MV_REFERENCE_FRAME ref,
int num_total_refs) {
assert((ref + 1) < num_total_refs);
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+ return xd->tile_ctx->single_ref_cdf[av1_get_ref_pred_context(
+ xd, ref, num_total_refs)][clamp(ref, 0, EXTENDED_INTER_REFS_CONTEXT - 1)];
+#else
return xd->tile_ctx
->single_ref_cdf[av1_get_ref_pred_context(xd, ref, num_total_refs)][ref];
+#endif
}
// This function checks whether the previously coded reference frame is on the
@@ -578,13 +622,27 @@
assert(bit_type < COMPREF_BIT_TYPES);
assert(IMPLIES(n_bits == 0, ref < RANKED_REF0_TO_PRUNE - 1));
#endif // CONFIG_SAME_REF_COMPOUND
- return n_bits == 0 ? xd->tile_ctx->comp_ref0_cdf[av1_get_ref_pred_context(
- xd, ref, num_total_refs)][ref]
- : xd->tile_ctx->comp_ref1_cdf[av1_get_ref_pred_context(
-#if CONFIG_SAME_REF_COMPOUND
- xd, ref, num_total_refs)][bit_type][ref];
+ return n_bits == 0
+ ? xd->tile_ctx->comp_ref0_cdf[av1_get_ref_pred_context(
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+ xd, ref,
+ num_total_refs)][clamp(ref, 0,
+ EXTENDED_INTER_REFS_CONTEXT - 1)]
#else
- xd, ref, num_total_refs)][bit_type][ref - 1];
+ xd, ref, num_total_refs)][ref]
+#endif
+ : xd->tile_ctx
+ ->comp_ref1_cdf[av1_get_ref_pred_context(
+#if CONFIG_SAME_REF_COMPOUND
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+ xd, ref, num_total_refs)][bit_type]
+ [clamp(ref, 0,
+ EXTENDED_INTER_REFS_CONTEXT - 1)];
+#else
+ xd, ref, num_total_refs)][bit_type][ref];
+#endif
+#else
+ xd, ref, num_total_refs)][bit_type][ref - 1];
#endif // CONFIG_SAME_REF_COMPOUND
}
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 97b67d0..64b56da 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -4173,8 +4173,9 @@
tip_frame_buf, cm->width, cm->height, seq_params->subsampling_x,
seq_params->subsampling_y, AOM_DEC_BORDER_IN_PIXELS,
cm->features.byte_alignment, NULL, NULL, NULL, false)) {
- aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
- "Failed to allocate frame buffer");
+ aom_internal_error(
+ &cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate frame buffer: setup_tip_frame_size 0");
}
if (tip_frame_buf) {
@@ -4196,8 +4197,9 @@
tip_frame_buf, cm->width, cm->height, seq_params->subsampling_x,
seq_params->subsampling_y, AOM_DEC_BORDER_IN_PIXELS,
cm->features.byte_alignment, NULL, NULL, NULL, false)) {
- aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
- "Failed to allocate frame buffer");
+ aom_internal_error(
+ &cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate frame buffer: setup_tip_frame_size 1");
}
if (tip_frame_buf) {
@@ -4227,7 +4229,7 @@
pool->get_fb_cb, pool->cb_priv, false)) {
unlock_buffer_pool(pool);
aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
- "Failed to allocate frame buffer");
+ "Failed to allocate frame buffer: setup_buffer_pool");
}
unlock_buffer_pool(pool);
@@ -7085,7 +7087,11 @@
BufferPool *const pool = cm->buffer_pool;
for (int i = 0; i < REF_FRAMES; i++) {
- decrease_ref_count(cm->ref_frame_map[i], pool);
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ set_ref_count_zero(cm->ref_frame_map[i], pool);
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ decrease_ref_count(cm->ref_frame_map[i], pool);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
cm->ref_frame_map[i] = NULL;
}
}
@@ -7602,9 +7608,25 @@
current_frame->order_hint = aom_rb_read_literal(
rb, seq_params->order_hint_info.order_hint_bits_minus_1 + 1);
+#if CONFIG_MULTIVIEW_CORE
+ current_frame->view_id = aom_rb_read_literal(rb, 8);
+ cm->layer_id = current_frame->view_id;
+#endif
+
current_frame->display_order_hint = get_disp_order_hint(cm);
current_frame->frame_number = current_frame->order_hint;
+#if CONFIG_MULTIVIEW_CORE
+ current_frame->frame_number =
+ current_frame->order_hint * cm->number_layers + current_frame->view_id;
+#endif
+
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- decode bitstream: show_frame=%d, frame_number=%d -- ",
+ cm->show_existing_frame, current_frame->frame_number);
+ debug_print_multiview_curr_frame(cm);
+#endif
+
if (!features->error_resilient_mode && !frame_is_intra_only(cm)) {
#if CONFIG_PRIMARY_REF_FRAME_OPT
signal_primary_ref_frame = aom_rb_read_literal(rb, 1);
@@ -7748,7 +7770,11 @@
if (buf == NULL || order_hint != buf->order_hint) {
if (buf != NULL) {
lock_buffer_pool(pool);
- decrease_ref_count(buf, pool);
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ set_ref_count_zero(buf, pool);
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ decrease_ref_count(buf, pool);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
unlock_buffer_pool(pool);
cm->ref_frame_map[ref_idx] = NULL;
}
@@ -7767,10 +7793,15 @@
seq_params->subsampling_y, AOM_BORDER_IN_PIXELS,
features->byte_alignment, &buf->raw_frame_buffer,
pool->get_fb_cb, pool->cb_priv, false)) {
- decrease_ref_count(buf, pool);
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ set_ref_count_zero(buf, pool);
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ decrease_ref_count(buf, pool);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
unlock_buffer_pool(pool);
- aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
- "Failed to allocate frame buffer");
+ aom_internal_error(
+ &cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to allocate frame buffer: read_uncompressed_header");
}
unlock_buffer_pool(pool);
// According to the specification, valid bitstreams are required to
@@ -7818,6 +7849,9 @@
#endif // CONFIG_LF_SUB_PU
if (current_frame->frame_type == KEY_FRAME) {
cm->current_frame.pyramid_level = 1;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ cm->current_frame.temporal_layer_id = cm->temporal_layer_id;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
features->tip_frame_mode = TIP_FRAME_DISABLED;
setup_frame_size(cm, frame_size_override_flag, rb);
#if CONFIG_FRAME_HEADER_SIGNAL_OPT
@@ -7857,6 +7891,9 @@
cm->cur_frame->num_ref_frames = 0;
#endif // CONFIG_IMPROVED_GLOBAL_MOTION
} else {
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ cm->current_frame.temporal_layer_id = cm->temporal_layer_id;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
features->allow_ref_frame_mvs = 0;
features->tip_frame_mode = TIP_FRAME_DISABLED;
if (current_frame->frame_type == INTRA_ONLY_FRAME) {
@@ -8003,6 +8040,12 @@
(int)ref_frame_map_pairs[ref].disp_order)
#endif // CONFIG_PRIMARY_REF_FRAME_OPT
: 1;
+#if CONFIG_MULTIVIEW_CORE
+ if (scores[i].distance == 0 &&
+ current_frame->view_id != cm->ref_frame_map_pairs[ref].view_id) {
+ scores[i].distance = 1;
+ }
+#endif
cm->ref_frames_info.ref_frame_distance[i] = scores[i].distance;
}
av1_get_past_future_cur_ref_lists(cm, scores);
diff --git a/av1/decoder/decoder.c b/av1/decoder/decoder.c
index 427b50b..b9b64d6 100644
--- a/av1/decoder/decoder.c
+++ b/av1/decoder/decoder.c
@@ -260,6 +260,10 @@
cm->fDecCoeffLog = fopen("DecCoeffLog.txt", "wt");
#endif
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ cm->fDecMultiviewLog = fopen("/tmp/DecMultilayerLog.txt", "wt");
+#endif
+
#if CONFIG_PARAKIT_COLLECT_DATA
#include "av1/common/entropy_inits_coeffs.h"
#include "av1/common/entropy_inits_modes.h"
@@ -448,6 +452,12 @@
}
#endif
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ if (pbi->common.fDecMultiviewLog != NULL) {
+ fclose(pbi->common.fDecMultiviewLog);
+ }
+#endif
+
#if CONFIG_PARAKIT_COLLECT_DATA
for (int f = 0; f < MAX_NUM_CTX_GROUPS; f++) {
if (pbi->common.prob_models[f].fDataCollect != NULL) {
@@ -570,9 +580,14 @@
AV1_COMMON *const cm = &pbi->common;
BufferPool *const pool = cm->buffer_pool;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ lock_buffer_pool(pool);
+ set_ref_count_zero(cm->cur_frame, pool);
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
cm->cur_frame->buf.corrupted = 1;
lock_buffer_pool(pool);
decrease_ref_count(cm->cur_frame, pool);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
unlock_buffer_pool(pool);
cm->cur_frame = NULL;
}
@@ -589,6 +604,9 @@
AV1_COMMON *const cm = &pbi->common;
RefCntBuffer *trigger_frame = NULL;
RefCntBuffer *output_candidate = NULL;
+#if CONFIG_MULTIVIEW_CORE
+ const unsigned int num_layers = cm->number_layers;
+#endif
// Determine if the triggering frame is the current frame or a frame
// already stored in the refrence buffer.
@@ -600,12 +618,24 @@
output_candidate = trigger_frame;
for (int i = 0; i < REF_FRAMES; i++) {
if (is_frame_eligible_for_output(cm->ref_frame_map[i]) &&
+#if CONFIG_MULTIVIEW_CORE
+ (cm->ref_frame_map[i]->display_order_hint * num_layers +
+ cm->ref_frame_map[i]->view_id) <
+ (output_candidate->display_order_hint * num_layers +
+ output_candidate->view_id)) {
+#else
cm->ref_frame_map[i]->display_order_hint <
output_candidate->display_order_hint) {
+#endif
output_candidate = cm->ref_frame_map[i];
}
}
if (output_candidate != trigger_frame) {
+#if CONFIG_MULTIVIEW_CORE
+ pbi->output_view_ids[pbi->num_output_frames] = output_candidate->view_id;
+ pbi->display_order_hint_ids[pbi->num_output_frames] =
+ output_candidate->display_order_hint;
+#endif
pbi->output_frames[pbi->num_output_frames++] = output_candidate;
output_candidate->frame_output_done = 1;
#if CONFIG_BITSTREAM_DEBUG
@@ -619,6 +649,11 @@
#endif // CONFIG_OUTPUT_FRAME_BASED_ON_ORDER_HINT_ENHANCEMENT
// Add the output triggering frame into the output queue.
+#if CONFIG_MULTIVIEW_CORE
+ pbi->output_view_ids[pbi->num_output_frames] = trigger_frame->view_id;
+ pbi->display_order_hint_ids[pbi->num_output_frames] =
+ trigger_frame->display_order_hint;
+#endif
pbi->output_frames[pbi->num_output_frames++] = trigger_frame;
trigger_frame->frame_output_done = 1;
#if CONFIG_BITSTREAM_DEBUG
@@ -630,15 +665,32 @@
if (trigger_frame->display_order_hint != cm->cur_frame->display_order_hint)
mismatch_move_frame_idx_r(0);
#endif // CONFIG_MISMATCH_DEBUG
-
// Add the next frames (showable_frame == 1) into the output queue.
int successive_output = 1;
for (int k = 1; k <= REF_FRAMES && successive_output > 0; k++) {
+#if CONFIG_MULTIVIEW_CORE
+ unsigned int next_disp_order =
+ (trigger_frame->display_order_hint * num_layers +
+ trigger_frame->view_id) +
+ k;
+#else
unsigned int next_disp_order = trigger_frame->display_order_hint + k;
+#endif
successive_output = 0;
for (int i = 0; i < REF_FRAMES; i++) {
if (is_frame_eligible_for_output(cm->ref_frame_map[i]) &&
+#if CONFIG_MULTIVIEW_CORE
+ (cm->ref_frame_map[i]->display_order_hint * num_layers +
+ cm->ref_frame_map[i]->view_id) == next_disp_order) {
+#else
cm->ref_frame_map[i]->display_order_hint == next_disp_order) {
+#endif
+#if CONFIG_MULTIVIEW_CORE
+ pbi->output_view_ids[pbi->num_output_frames] =
+ cm->ref_frame_map[i]->view_id;
+ pbi->display_order_hint_ids[pbi->num_output_frames] =
+ cm->ref_frame_map[i]->display_order_hint;
+#endif
pbi->output_frames[pbi->num_output_frames++] = cm->ref_frame_map[i];
cm->ref_frame_map[i]->frame_output_done = 1;
successive_output++;
@@ -668,7 +720,9 @@
lock_buffer_pool(pool);
#if CONFIG_OUTPUT_FRAME_BASED_ON_ORDER_HINT_ENHANCEMENT
- if (cm->seq_params.enable_frame_output_order) pbi->num_output_frames = 0;
+ if (cm->seq_params.enable_frame_output_order) {
+ pbi->num_output_frames = 0;
+ }
#endif // CONFIG_OUTPUT_FRAME_BASED_ON_ORDER_HINT_ENHANCEMENT
// In ext-tile decoding, the camera frame header is only decoded once. So,
// we don't update the references here.
@@ -683,9 +737,22 @@
is_frame_eligible_for_output(cm->ref_frame_map[ref_index]))
output_frame_buffers(pbi, ref_index);
#endif // CONFIG_OUTPUT_FRAME_BASED_ON_ORDER_HINT_ENHANCEMENT
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ set_ref_count_zero(cm->ref_frame_map[ref_index], pool);
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
decrease_ref_count(cm->ref_frame_map[ref_index], pool);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ if (cm->current_frame.frame_type == KEY_FRAME && ref_index > 0) {
+ cm->ref_frame_map[ref_index] = NULL;
+ } else {
+ cm->ref_frame_map[ref_index] = cm->cur_frame;
+ //++cm->cur_frame->ref_count;
+ }
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
cm->ref_frame_map[ref_index] = cm->cur_frame;
++cm->cur_frame->ref_count;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
}
++ref_index;
}
@@ -706,31 +773,50 @@
// We can't store the new frame anywhere, so drop it and return an
// error
cm->cur_frame->buf.corrupted = 1;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ set_ref_count_zero(cm->cur_frame, pool);
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
decrease_ref_count(cm->cur_frame, pool);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
} else {
+#if CONFIG_MULTIVIEW_CORE
+ pbi->output_view_ids[pbi->num_output_frames] = cm->cur_frame->view_id;
+ pbi->display_order_hint_ids[pbi->num_output_frames] =
+ cm->cur_frame->display_order_hint;
+#endif
pbi->output_frames[pbi->num_output_frames] = cm->cur_frame;
pbi->num_output_frames++;
}
} else {
// Replace any existing output frame
+#if !CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
assert(pbi->num_output_frames == 0 || pbi->num_output_frames == 1);
if (pbi->num_output_frames > 0) {
decrease_ref_count(pbi->output_frames[0], pool);
}
+#endif // !CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+#if CONFIG_MULTIVIEW_CORE
+ pbi->output_view_ids[0] = cm->cur_frame->view_id;
+ pbi->display_order_hint_ids[0] = cm->cur_frame->display_order_hint;
+#endif
pbi->output_frames[0] = cm->cur_frame;
pbi->num_output_frames = 1;
}
- } else {
+ }
+#if !CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ else {
decrease_ref_count(cm->cur_frame, pool);
}
-
+#endif // !CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
unlock_buffer_pool(pool);
} else {
+#if !CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
// Nothing was decoded, so just drop this frame buffer
lock_buffer_pool(pool);
decrease_ref_count(cm->cur_frame, pool);
unlock_buffer_pool(pool);
+#endif // !CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
}
cm->cur_frame = NULL;
@@ -760,9 +846,17 @@
// thing to do here.
const int last_frame = get_closest_pastcur_ref_index(cm);
RefCntBuffer *ref_buf = get_ref_frame_buf(cm, last_frame);
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ if (ref_buf != NULL) printf("\nref_buf->buf.corrupted = 1\n");
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
if (ref_buf != NULL) ref_buf->buf.corrupted = 1;
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
}
-
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ if (cm->cur_frame != NULL) {
+ release_current_frame(pbi);
+ }
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
if (assign_cur_frame_new_fb(cm) == NULL) {
cm->error.error_code = AOM_CODEC_MEM_ERROR;
return 1;
@@ -793,6 +887,11 @@
int frame_decoded =
aom_decode_frame_from_obus(pbi, source, source + size, psource);
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ if (frame_decoded == 0) {
+ release_current_frame(pbi);
+ }
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
#if CONFIG_INSPECTION
if (cm->features.tip_frame_mode == TIP_FRAME_AS_OUTPUT) {
if (pbi->inspect_tip_cb != NULL) {
diff --git a/av1/decoder/decoder.h b/av1/decoder/decoder.h
index d338133..3052416 100644
--- a/av1/decoder/decoder.h
+++ b/av1/decoder/decoder.h
@@ -294,6 +294,11 @@
size_t output_frames_offset; // Use only for single layer
size_t num_output_frames; // How many frames are queued up so far?
+#if CONFIG_MULTIVIEW_CORE
+ int output_view_ids[REF_FRAMES];
+ int display_order_hint_ids[REF_FRAMES];
+#endif
+
// In order to properly support random-access decoding, we need
// to behave slightly differently for the very first frame we decode.
// So we track whether this is the first frame or not.
@@ -439,6 +444,28 @@
}
}
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+static INLINE void set_ref_count_zero(RefCntBuffer *const buf,
+ BufferPool *const pool) {
+ if (buf != NULL) {
+ buf->ref_count = 0;
+ // Reference counts should never become negative. If this assertion fails,
+ // there is a bug in our reference count management.
+ assert(buf->ref_count >= 0);
+ // A worker may only get a free framebuffer index when calling get_free_fb.
+ // But the raw frame buffer is not set up until we finish decoding header.
+ // So if any error happens during decoding header, frame_bufs[idx] will not
+ // have a valid raw frame buffer.
+ if (buf->ref_count == 0 && buf->raw_frame_buffer.data) {
+ pool->release_fb_cb(pool->cb_priv, &buf->raw_frame_buffer);
+ buf->raw_frame_buffer.data = NULL;
+ buf->raw_frame_buffer.size = 0;
+ buf->raw_frame_buffer.priv = NULL;
+ }
+ }
+}
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+
#if CONFIG_OUTPUT_FRAME_BASED_ON_ORDER_HINT_ENHANCEMENT
// Check whether the frame is ready to output or not.
static INLINE bool is_frame_eligible_for_output(RefCntBuffer *const buf) {
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c
index fc726d1..9c2b566 100644
--- a/av1/decoder/obu.c
+++ b/av1/decoder/obu.c
@@ -120,6 +120,12 @@
return 0;
}
+#if CONFIG_MULTIVIEW_CORE
+ cm->number_layers =
+ aom_rb_read_literal(rb, 8) +
+ 1; // TODO: (@hegilmez) redesign later or change where this is signaled
+#endif
+
const int num_bits_width = aom_rb_read_literal(rb, 4) + 1;
const int num_bits_height = aom_rb_read_literal(rb, 4) + 1;
const int max_frame_width = aom_rb_read_literal(rb, num_bits_width) + 1;
@@ -1103,6 +1109,14 @@
data += payload_size;
}
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ FILE *const logfile = cm->fDecMultiviewLog;
+ logfile_multiview_curr_frame(cm, logfile);
+ logfile_multiview_buf_refs(cm, logfile);
+ logfile_buffer_state(cm, logfile);
+ // logfile_primary_ref_info(cm, logfile);
+#endif
+
if (cm->error.error_code != AOM_CODEC_OK) return -1;
return frame_decoding_finished;
}
diff --git a/av1/encoder/av1_quantize.c b/av1/encoder/av1_quantize.c
index 3060d8c..8083a95 100644
--- a/av1/encoder/av1_quantize.c
+++ b/av1/encoder/av1_quantize.c
@@ -571,11 +571,12 @@
*v_dc_delta_q = 0;
*u_ac_delta_q = 0;
*v_ac_delta_q = 0;
-
+#if !CONFIG_MULTIVIEW_CORE
if (frame_is_intra_only(cm)) {
*y_dc_delta_q = 0;
*u_dc_delta_q = *v_dc_delta_q = -4;
}
+#endif
}
void av1_set_quantizer(AV1_COMMON *const cm, int min_qmlevel, int max_qmlevel,
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 623ee03..538dc0c 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2323,7 +2323,7 @@
const MB_MODE_INFO *mbmi
#endif // CONFIG_SEP_COMP_DRL
) {
- const int8_t ref_frame_type = av1_ref_frame_type(ref_frame);
+ const int16_t ref_frame_type = av1_ref_frame_type(ref_frame);
#if CONFIG_SEP_COMP_DRL
const CANDIDATE_MV *curr_ref_mv_stack =
has_second_drl(mbmi) ? mbmi_ext_frame->ref_mv_stack[ref_idx]
@@ -5048,7 +5048,6 @@
aom_wb_write_literal(
wb, quant_params->base_qindex,
bit_depth == AOM_BITS_8 ? QINDEX_BITS_UNEXT : QINDEX_BITS);
-
write_delta_q(wb, quant_params->y_dc_delta_q);
if (num_planes > 1) {
int diff_uv_delta =
@@ -6141,6 +6140,15 @@
wb, current_frame->order_hint,
seq_params->order_hint_info.order_hint_bits_minus_1 + 1);
+#if CONFIG_MULTIVIEW_CORE
+ aom_wb_write_literal(wb, current_frame->view_id, 8);
+#endif
+
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- write bitstream: view_id=%d --- ", current_frame->view_id);
+ debug_print_multiview_curr_frame(cm);
+#endif
+
if (!features->error_resilient_mode && !frame_is_intra_only(cm)) {
#if CONFIG_PRIMARY_REF_FRAME_OPT
aom_wb_write_literal(wb, cpi->signal_primary_ref_frame, 1);
@@ -6223,19 +6231,43 @@
if (features->error_resilient_mode &&
seq_params->order_hint_info.enable_order_hint) {
for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) {
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST_FIX_ERROR_RES
+ int idx = ref_idx;
+ if (cm->ref_frame_map[ref_idx] == NULL) {
+ idx = 0;
+ // idx = cm->remapped_ref_idx[0];
+ }
aom_wb_write_literal(
- wb, cm->ref_frame_map[ref_idx]->order_hint,
+ wb, cm->ref_frame_map[idx]->order_hint,
seq_params->order_hint_info.order_hint_bits_minus_1 + 1);
+
+#else
+ aom_wb_write_literal(
+ wb, cm->ref_frame_map[ref_idx]->order_hint,
+ seq_params->order_hint_info.order_hint_bits_minus_1 + 1);
+#endif
}
}
// Write all ref frame base_qindex if error_resilient_mode == 1. This is
// required by reference mapping.
if (features->error_resilient_mode) {
for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) {
- aom_wb_write_literal(wb, cm->ref_frame_map[ref_idx]->base_qindex,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST_FIX_ERROR_RES
+ int idx = ref_idx;
+ if (cm->ref_frame_map[ref_idx] == NULL) {
+ idx = 0;
+ // idx = cm->remapped_ref_idx[0];
+ }
+ aom_wb_write_literal(wb, cm->ref_frame_map[idx]->base_qindex,
cm->seq_params.bit_depth == AOM_BITS_8
? QINDEX_BITS_UNEXT
: QINDEX_BITS);
+#else
+ aom_wb_write_literal(wb, cm->ref_frame_map[ref_idx]->base_qindex,
+ cm->seq_params.bit_depth == AOM_BITS_8
+ ? QINDEX_BITS_UNEXT
+ : QINDEX_BITS);
+#endif
}
}
}
@@ -6844,6 +6876,12 @@
write_profile(seq_params->profile, &wb);
+#if CONFIG_MULTIVIEW_CORE
+ aom_wb_write_literal(
+ &wb, seq_params->num_views - 1,
+ 8); // TODO: (@hegilmez) redesign later or change where this is signaled
+#endif
+
aom_wb_write_literal(&wb, seq_params->num_bits_width - 1, 4);
aom_wb_write_literal(&wb, seq_params->num_bits_height - 1, 4);
aom_wb_write_literal(&wb, seq_params->max_frame_width - 1,
@@ -6909,6 +6947,7 @@
}
}
}
+
write_sequence_header(seq_params, &wb);
aom_wb_write_bit(&wb, seq_params->film_grain_params_present);
@@ -7461,6 +7500,9 @@
uint32_t obu_header_size = 0;
uint32_t obu_payload_size = 0;
FrameHeaderInfo fh_info = { NULL, 0, 0 };
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ // printf("\ncm->temporal_layer_id: %d\n", cm->temporal_layer_id);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
const uint8_t obu_extension_header =
cm->temporal_layer_id << 5 | cm->spatial_layer_id << 3 | 0;
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 768104d..5df0b0e 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -159,6 +159,9 @@
}
static void update_rc_counts(AV1_COMP *cpi) {
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("*** update_counters \n");
+#endif
update_keyframe_counters(cpi);
update_frames_till_gf_update(cpi);
update_gf_group_index(cpi);
@@ -254,8 +257,14 @@
GF_GROUP gf_group = cpi->gf_group;
// The current display index stored has not yet been updated. We must add
// The order offset to get the correct value here.
+#if CONFIG_MULTIVIEW_CORE
+ const int cur_frame_disp =
+ (cpi->common.current_frame.frame_number + order_offset) /
+ cpi->common.number_layers;
+#else
const int cur_frame_disp =
cpi->common.current_frame.frame_number + order_offset;
+#endif
const SubGOPStepCfg *step_gop_cfg =
get_subgop_step(&gf_group, gf_group.index);
@@ -618,13 +627,77 @@
return 1;
}
-static int get_free_ref_map_index(RefFrameMapPair ref_map_pairs[REF_FRAMES]) {
+static int get_free_ref_map_index(RefFrameMapPair ref_map_pairs[REF_FRAMES]
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ ,
+ int cur_temporal_layer_id
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ ,
+ int current_view_id, int num_views
+#endif
+) {
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER || \
+ CONFIG_MULTIVIEW_SEPARATE_DPB
+ int start_idx = 0;
+ int end_idx = REF_FRAMES - 1;
+#endif
+
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ // Allocate ref map slot(s) to each temporal layer
+ // to avoid the case that a higher layer frame
+ // flushes out a lower layer frame from a ref map slot
+
+ if (cur_temporal_layer_id == 1) {
+ start_idx = 0;
+ end_idx = 1;
+ } else if (cur_temporal_layer_id == 2) {
+ start_idx = 2;
+ end_idx = 2;
+ } else if (cur_temporal_layer_id == 3) {
+ start_idx = 3;
+ end_idx = 4;
+ } else if (cur_temporal_layer_id == 4) {
+ start_idx = 5;
+ end_idx = 6;
+ } else if (cur_temporal_layer_id == 5) {
+ start_idx = 7;
+ end_idx = 7;
+ }
+#endif
+
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ int idx_offset = REF_FRAMES / num_views;
+ if (current_view_id == 0) {
+ start_idx = 0;
+ end_idx = idx_offset;
+ } else if (current_view_id > 0) {
+ start_idx = idx_offset + 1;
+ end_idx = REF_FRAMES - 1;
+ } else // current_view_id == -1
+ {
+ start_idx = 0;
+ end_idx = REF_FRAMES - 1;
+ }
+#endif
+
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER || \
+ CONFIG_MULTIVIEW_SEPARATE_DPB
+ for (int idx = start_idx; idx <= end_idx; idx++)
+#else
for (int idx = 0; idx < REF_FRAMES; ++idx)
+#endif
if (ref_map_pairs[idx].disp_order == -1) return idx;
return INVALID_IDX;
}
static int get_refresh_idx(int update_arf, int refresh_level,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ int cur_temporal_layer_id,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ int current_view_id, int num_views,
+#endif
int cur_frame_disp,
RefFrameMapPair ref_frame_map_pairs[REF_FRAMES]) {
int arf_count = 0;
@@ -637,7 +710,56 @@
int oldest_ref_level_order = INT32_MAX;
int oldest_ref_level_idx = -1;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER || \
+ CONFIG_MULTIVIEW_SEPARATE_DPB
+ int start_idx = 0;
+ int end_idx = REF_FRAMES - 1;
+#endif
+
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ // Allocate ref map slot(s) to each temporal layer
+ // to avoid the case that a higher layer frame
+ // flushes out a lower layer frame from a ref map slot
+
+ if (cur_temporal_layer_id == 1) {
+ start_idx = 0;
+ end_idx = 1;
+ } else if (cur_temporal_layer_id == 2) {
+ start_idx = 2;
+ end_idx = 2;
+ } else if (cur_temporal_layer_id == 3) {
+ start_idx = 3;
+ end_idx = 4;
+ } else if (cur_temporal_layer_id == 4) {
+ start_idx = 5;
+ end_idx = 6;
+ } else if (cur_temporal_layer_id == 5) {
+ start_idx = 7;
+ end_idx = 7;
+ }
+#endif
+
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ int idx_offset = REF_FRAMES / num_views;
+ if (current_view_id == 0) {
+ start_idx = 0;
+ end_idx = idx_offset;
+ } else if (current_view_id > 0) {
+ start_idx = idx_offset + 1;
+ end_idx = REF_FRAMES - 1;
+ } else // current_view_id == -1
+ {
+ start_idx = 0;
+ end_idx = REF_FRAMES - 1;
+ }
+#endif
+
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER || \
+ CONFIG_MULTIVIEW_SEPARATE_DPB
+ for (int map_idx = start_idx; map_idx <= end_idx; map_idx++) {
+#else
for (int map_idx = 0; map_idx < REF_FRAMES; map_idx++) {
+#endif
RefFrameMapPair ref_pair = ref_frame_map_pairs[map_idx];
if (ref_pair.disp_order == -1) continue;
const int frame_order = ref_pair.disp_order;
@@ -677,14 +799,48 @@
if (update_arf && arf_count > 2) return oldest_arf_idx;
if (oldest_idx >= 0) return oldest_idx;
if (oldest_arf_idx >= 0) return oldest_arf_idx;
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ // Allocate ref map slot(s) to each temporal layer
+ // to avoid the case that a higher layer frame
+ // flushes out a lower layer frame from a ref map slot
+ if (cur_temporal_layer_id == 1) {
+ return 1;
+ } else if (cur_temporal_layer_id == 2) {
+ return 2;
+ } else if (cur_temporal_layer_id == 3) {
+ return 4;
+ } else if (cur_temporal_layer_id == 4) {
+ return 5;
+ } else if (cur_temporal_layer_id == 5) {
+ return 7;
+ }
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ int idx_refresh = 1;
+ if (current_view_id == 0) {
+ return idx_refresh;
+ } else if (current_view_id > 0) {
+ idx_refresh += idx_offset;
+ return start_idx;
+ } else // current_view_id == -1
+ {
+ // do nothing
+ }
+#endif
assert(0 && "No valid refresh index found");
return -1;
}
static int get_refresh_frame_flags_subgop_cfg(
- const AV1_COMP *const cpi, int gf_index, int cur_disp_order,
- RefFrameMapPair ref_frame_map_pairs[REF_FRAMES], int refresh_mask,
- int free_fb_index) {
+ const AV1_COMP *const cpi, int gf_index,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ int cur_temporal_layer_id,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ int current_view_id, int num_views,
+#endif
+ int cur_disp_order, RefFrameMapPair ref_frame_map_pairs[REF_FRAMES],
+ int refresh_mask, int free_fb_index) {
const SubGOPStepCfg *step_gop_cfg = get_subgop_step(&cpi->gf_group, gf_index);
assert(step_gop_cfg != NULL);
const int pyr_level = step_gop_cfg->pyr_level;
@@ -704,14 +860,33 @@
const int update_arf = type_code == FRAME_TYPE_OOO_FILTERED && pyr_level == 1;
const int refresh_idx = get_refresh_idx(update_arf, refresh_level,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ cur_temporal_layer_id,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ current_view_id, num_views,
+#endif
cur_disp_order, ref_frame_map_pairs);
+#if CONFIG_MULTIVIEW_DEBUG_PROMPT
+ const CurrentFrame *const cf = &cpi->common.current_frame; // cm->cur_frame;
+ printf("In - get_refresh_idx: (View,Level,OH,DOH):(%d,%d,%d,%d) \n",
+ cf->view_id, cf->pyramid_level, cf->order_hint,
+ cf->display_order_hint);
+ printf("Out - get_refresh_idx: %d \n", refresh_idx);
+#endif
return 1 << refresh_idx;
}
int av1_get_refresh_frame_flags(
const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params,
- FRAME_UPDATE_TYPE frame_update_type, int gf_index, int cur_disp_order,
- RefFrameMapPair ref_frame_map_pairs[REF_FRAMES]) {
+ FRAME_UPDATE_TYPE frame_update_type, int gf_index,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ int cur_temporal_layer_id,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ int current_view_id, int num_views,
+#endif
+ int cur_disp_order, RefFrameMapPair ref_frame_map_pairs[REF_FRAMES]) {
// Switch frames and shown key-frames overwrite all reference slots
if ((frame_params->frame_type == KEY_FRAME && !cpi->no_show_fwd_kf) ||
frame_params->frame_type == S_FRAME) {
@@ -737,12 +912,33 @@
}
// Search for the open slot to store the current frame.
- int free_fb_index = get_free_ref_map_index(ref_frame_map_pairs);
-
+ int free_fb_index = get_free_ref_map_index(ref_frame_map_pairs
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ ,
+ cur_temporal_layer_id
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ ,
+ current_view_id, num_views
+#endif
+ );
+#if CONFIG_MULTIVIEW_DEBUG_PROMPT
+ const CurrentFrame *const cf = &cpi->common.current_frame; // cm->cur_frame;
+ printf("In - get_free_ref_map_index: (View,Level,OH,DOH):(%d,%d,%d,%d) \n",
+ cf->view_id, cf->pyramid_level, cf->order_hint,
+ cf->display_order_hint);
+ printf("Out - get_free_ref_map_index: %d \n", free_fb_index);
+#endif
if (use_subgop_cfg(&cpi->gf_group, gf_index)) {
const int mask = get_refresh_frame_flags_subgop_cfg(
- cpi, gf_index, cur_disp_order, ref_frame_map_pairs, refresh_mask,
- free_fb_index);
+ cpi, gf_index,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ cur_temporal_layer_id,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ current_view_id, num_views,
+#endif
+ cur_disp_order, ref_frame_map_pairs, refresh_mask, free_fb_index);
return mask;
}
@@ -759,8 +955,20 @@
}
const int update_arf = frame_update_type == ARF_UPDATE;
- const int refresh_idx =
- get_refresh_idx(update_arf, -1, cur_disp_order, ref_frame_map_pairs);
+ const int refresh_idx = get_refresh_idx(update_arf, -1,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ cur_temporal_layer_id,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ current_view_id, num_views,
+#endif
+ cur_disp_order, ref_frame_map_pairs);
+#if CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("In - get_refresh_idx: (View,Level,OH,DOH):(%d,%d,%d,%d) \n",
+ cf->view_id, cf->pyramid_level, cf->order_hint,
+ cf->display_order_hint);
+ printf("Out - get_refresh_idx: %d \n", refresh_idx);
+#endif
return 1 << refresh_idx;
}
@@ -1077,7 +1285,15 @@
frame_update_type != KFFLT_OVERLAY_UPDATE &&
frame_update_type != INTNL_OVERLAY_UPDATE) {
frame_params.frame_type = KEY_FRAME;
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- set1 frame type to KEY_FRAME: ");
+ debug_print_multiview_curr_frame(cm);
+#endif
} else {
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- set1 frame type to INTER_FRAME: ");
+ debug_print_multiview_curr_frame(cm);
+#endif
frame_params.frame_type = INTER_FRAME;
}
} else if (is_stat_consumption_stage(cpi)) {
@@ -1113,8 +1329,63 @@
av1_configure_buffer_updates(cpi, frame_update_type);
const int order_offset = gf_group->arf_src_offset[gf_group->index];
+
+#if CONFIG_MULTIVIEW_CORE
+ int cur_frame_disp = cpi->common.current_frame.frame_number + order_offset;
+#else
const int cur_frame_disp =
cpi->common.current_frame.frame_number + order_offset;
+#endif
+
+#if CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("encode_startegy: cur_frame_disp=%2d, order_offset[%d]=%2d\n",
+ cur_frame_disp, gf_group->index, order_offset);
+#endif
+
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ // Here, ff temporal_layer_id is set to a non-zero value (pry_level),
+ // temporal_layer_id is siganled in obu extension,
+ // and affect reference list construction in both encoder and decoder.
+ // Otherwise (if temporal_layer_id is set to 0), temporal_layer_id is
+ // not signaled and does not change the reference frame list construction.
+#if CONFIG_MULTIVIEW_CORE
+ cm->current_frame.view_id = cur_frame_disp % cm->number_layers;
+ cm->current_frame.order_hint = cur_frame_disp / cm->number_layers;
+ cm->current_frame.display_order_hint = cur_frame_disp / cm->number_layers;
+ cur_frame_disp = cur_frame_disp / cm->number_layers;
+#else
+ cm->current_frame.order_hint = cur_frame_disp;
+ cm->current_frame.display_order_hint = cur_frame_disp;
+#endif
+ cm->current_frame.pyramid_level =
+ get_true_pyr_level(cpi->gf_group.layer_depth[cpi->gf_group.index],
+ cur_frame_disp, cpi->gf_group.max_layer_depth);
+
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ cm->temporal_layer_id = cm->current_frame.pyramid_level;
+ cm->current_frame.temporal_layer_id = cm->temporal_layer_id;
+#else
+ cm->temporal_layer_id = 0;
+ cm->current_frame.temporal_layer_id = cm->temporal_layer_id;
+#endif
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+
+#if CONFIG_MULTIVIEW_DEBUG_PROMPT
+ const CurrentFrame *const cf = &cm->current_frame;
+ printf(
+ "Encode startegy before init: "
+ "(View,Level,OH,DOH,order_offset):(%d,%d,%d,%d,%d) \n",
+ cf->view_id, cf->pyramid_level, cf->order_hint, cf->display_order_hint,
+ order_offset);
+ printf("Encoder side ref-buffer before init =");
+ debug_print_buffer_state(cm);
+#endif
+
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- encode_strategy: ");
+ debug_print_multiview_curr_frame(cm);
+#endif
+
#if CONFIG_PRIMARY_REF_FRAME_OPT
init_ref_map_pair(&cpi->common, cm->ref_frame_map_pairs,
gf_group->update_type[gf_group->index] == KF_UPDATE);
@@ -1169,6 +1440,15 @@
frame_params.refresh_frame_flags = av1_get_refresh_frame_flags(
cpi, &frame_params, frame_update_type, cpi->gf_group.index,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ cm->seq_params.explicit_ref_frame_map
+ ? 0
+ : cm->current_frame.temporal_layer_id,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ cm->seq_params.explicit_ref_frame_map ? -1 : cm->current_frame.view_id,
+ cm->number_layers,
+#endif
#if CONFIG_PRIMARY_REF_FRAME_OPT
cur_frame_disp, cm->ref_frame_map_pairs);
#else
@@ -1185,6 +1465,21 @@
if (frame_order == cur_frame_disp)
frame_params.existing_fb_idx_to_show = frame;
}
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ if (frame_params.existing_fb_idx_to_show < 0) {
+ frame_params.show_existing_frame = 0;
+ }
+#endif
+#if CONFIG_MULTIVIEW_DEBUG_PROMPT
+ if (frame_params.existing_fb_idx_to_show < 0) {
+ printf(
+ "Warning (show_existing_frame): existing_fb_idx_to_show=%d -- "
+ "(View,Level,OH,DOH):(%d,%d,%d,%d) \n",
+ frame_params.existing_fb_idx_to_show, cf->view_id,
+ cf->pyramid_level, cf->order_hint, cf->display_order_hint);
+ frame_params.show_existing_frame = 0;
+ }
+#endif
}
}
diff --git a/av1/encoder/encode_strategy.h b/av1/encoder/encode_strategy.h
index 414548a..ca05a24 100644
--- a/av1/encoder/encode_strategy.h
+++ b/av1/encoder/encode_strategy.h
@@ -70,8 +70,14 @@
int av1_get_refresh_frame_flags(
const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params,
- FRAME_UPDATE_TYPE frame_update_type, int gf_index, int cur_frame_disp,
- RefFrameMapPair ref_frame_map_pairs[REF_FRAMES]);
+ FRAME_UPDATE_TYPE frame_update_type, int gf_index,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ int cur_temporal_layer_id,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ int current_view_id, int num_views,
+#endif
+ int cur_frame_disp, RefFrameMapPair ref_frame_map_pairs[REF_FRAMES]);
int av1_get_refresh_ref_frame_map(AV1_COMMON *cm, int refresh_frame_flags);
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index d4394fc..0e19b0b 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1794,7 +1794,6 @@
// Indicates whether or not to use a default reduced set for ext-tx
// rather than the potential full set of 16 transforms
features->reduced_tx_set_used = cpi->oxcf.txfm_cfg.reduced_tx_type_set;
-
// Make sure segment_id is no larger than last_active_segid.
if (cm->seg.enabled && cm->seg.update_map) {
const int mi_rows = cm->mi_params.mi_rows;
@@ -1880,3 +1879,23 @@
encode_frame_internal(cpi);
}
}
+
+#if CONFIG_MULTIVIEW_DEBUG
+void debug_print_buf_refs_enc(const AV1_COMMON *const cm) {
+ const RefCntBuffer *const cf = cm->cur_frame;
+ MV_REFERENCE_FRAME ref_frame;
+ printf("(View,OH,DOH):(%2d,%2d,%2d) ", cf->view_id, cf->order_hint,
+ cf->display_order_hint);
+ printf(" num_ref_frames/ref_frames_info.num_total_refs=%d/%d ",
+ cf->num_ref_frames, cm->ref_frames_info.num_total_refs);
+ printf("[");
+ for (ref_frame = 0; ref_frame < INTER_REFS_PER_FRAME; ++ref_frame) {
+ const int map_idx = get_ref_frame_map_idx(cm, ref_frame);
+ printf("%2d:", map_idx);
+ printf("(%2d,", cf->ref_view_ids[ref_frame]);
+ printf("%2d,", cf->ref_order_hints[ref_frame]);
+ printf("%2d) ", cf->ref_display_order_hint[ref_frame]);
+ }
+ printf("]\n");
+}
+#endif
diff --git a/av1/encoder/encodeframe.h b/av1/encoder/encodeframe.h
index 598190d..cfbfc3e 100644
--- a/av1/encoder/encodeframe.h
+++ b/av1/encoder/encodeframe.h
@@ -39,7 +39,9 @@
const CHROMA_REF_INFO *chroma_ref_info);
void av1_encode_frame(struct AV1_COMP *cpi);
-
+#if CONFIG_MULTIVIEW_DEBUG
+void debug_print_buf_refs_enc(const AV1_COMMON *const cm);
+#endif
void av1_alloc_tile_data(struct AV1_COMP *cpi);
void av1_init_tile_data(struct AV1_COMP *cpi);
void av1_encode_tile(struct AV1_COMP *cpi, struct ThreadData *td, int tile_row,
diff --git a/av1/encoder/encodemv.c b/av1/encoder/encodemv.c
index f7e5ef6..3663adf 100644
--- a/av1/encoder/encodemv.c
+++ b/av1/encoder/encodemv.c
@@ -1165,7 +1165,7 @@
const MB_MODE_INFO *mbmi
#endif // CONFIG_SEP_COMP_DRL
) {
- const int8_t ref_frame_type = av1_ref_frame_type(ref_frame);
+ const int16_t ref_frame_type = av1_ref_frame_type(ref_frame);
#if CONFIG_SEP_COMP_DRL
const CANDIDATE_MV *curr_ref_mv_stack =
has_second_drl(mbmi) ? mbmi_ext->ref_mv_stack[ref_frame[ref_idx]]
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 2882e20..053b231 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -362,6 +362,10 @@
seq->still_picture =
(tool_cfg->force_video_mode == 0) && (oxcf->input_cfg.limit == 1);
+#if CONFIG_MULTIVIEW_CORE
+ assert(oxcf->input_cfg.num_views > 0);
+ seq->still_picture &= oxcf->input_cfg.num_views == 1;
+#endif
seq->reduced_still_picture_hdr = seq->still_picture;
seq->reduced_still_picture_hdr &= !tool_cfg->full_still_picture_hdr;
seq->force_screen_content_tools = 2;
@@ -389,6 +393,10 @@
seq->num_same_ref_compound = SAME_REF_COMPOUND_PRUNE;
#endif // CONFIG_SAME_REF_COMPOUND
+#if CONFIG_MULTIVIEW_CORE
+ seq->num_views = oxcf->input_cfg.num_views;
+#endif
+
seq->max_frame_width = frm_dim_cfg->forced_max_frame_width
? frm_dim_cfg->forced_max_frame_width
: frm_dim_cfg->width;
@@ -644,6 +652,10 @@
cm->spatial_layer_id = 0;
cm->temporal_layer_id = 0;
+#if CONFIG_MULTIVIEW_CORE
+ cm->number_layers = oxcf->input_cfg.num_views;
+#endif
+
// change includes all joint functionality
av1_change_config(cpi, oxcf);
@@ -1104,6 +1116,9 @@
#if DEBUG_EXTQUANT
cm->fEncCoeffLog = fopen("EncCoeffLog.txt", "wt");
#endif
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ cm->fEncMultiviewLog = fopen("/tmp/EncMultilayerLog.txt", "wt");
+#endif
cm->error.setjmp = 1;
cpi->lap_enabled = num_lap_buffers > 0;
@@ -1140,6 +1155,10 @@
}
cpi->frames_left = cpi->oxcf.input_cfg.limit;
+#if CONFIG_MULTIVIEW_CORE
+ cpi->frames_left *= cm->number_layers;
+ assert(cm->number_layers > 0);
+#endif
av1_rc_init(&cpi->oxcf, 0, &cpi->rc);
@@ -1598,6 +1617,12 @@
}
#endif
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ if (cpi->common.fEncMultiviewLog != NULL) {
+ fclose(cpi->common.fEncMultiviewLog);
+ }
+#endif
+
aom_free(cpi->subgop_config_str);
aom_free(cpi->subgop_config_path);
aom_free(cpi);
@@ -3702,6 +3727,20 @@
cpi->last_encoded_frame_order_hint = cm->current_frame.display_order_hint;
#endif // CONFIG_PRIMARY_REF_FRAME_OPT
+#if CONFIG_MULTIVIEW_DEBUG
+#if CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("Encoder - ");
+ debug_print_multiview_buf_refs(cm);
+ debug_print_multiview_curr_frame(cm);
+#endif
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ FILE *const logfile = cm->fEncMultiviewLog;
+ logfile_multiview_curr_frame(cm, logfile);
+ logfile_multiview_buf_refs(cm, logfile);
+ logfile_buffer_state(cm, logfile);
+#endif
+#endif
+
return AOM_CODEC_OK;
}
@@ -4068,13 +4107,16 @@
realloc_and_scale_source(cpi, cm->cur_frame->buf.y_crop_width,
cm->cur_frame->buf.y_crop_height);
}
-
// current_frame->frame_number is incremented already for
// keyframe overlays.
if (!av1_check_keyframe_overlay(cpi->gf_group.index, &cpi->gf_group,
- cpi->rc.frames_since_key))
+ cpi->rc.frames_since_key)) {
++current_frame->frame_number;
-
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("Frame number increment 1 : %d --> %d \n",
+ current_frame->frame_number - 1, current_frame->frame_number);
+#endif
+ }
return AOM_CODEC_OK;
}
@@ -4331,6 +4373,11 @@
++current_frame->frame_number;
}
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("Frame number increment 2 : %d --> %d \n",
+ current_frame->frame_number - 1, current_frame->frame_number);
+#endif
+
return AOM_CODEC_OK;
}
@@ -4368,16 +4415,74 @@
current_frame->order_hint =
current_frame->frame_number + frame_params->order_offset;
current_frame->display_order_hint = current_frame->order_hint;
+#if CONFIG_MULTIVIEW_CORE
+ current_frame->absolute_poc =
+ current_frame->key_frame_number + current_frame->display_order_hint;
+ current_frame->view_id =
+ current_frame->display_order_hint % cm->number_layers;
+ current_frame->order_hint = current_frame->order_hint / cm->number_layers;
+ current_frame->display_order_hint =
+ current_frame->display_order_hint / cm->number_layers;
+#endif
+
current_frame->pyramid_level = get_true_pyr_level(
cpi->gf_group.layer_depth[cpi->gf_group.index],
current_frame->display_order_hint, cpi->gf_group.max_layer_depth);
+#if !CONFIG_MULTIVIEW_CORE
current_frame->absolute_poc =
current_frame->key_frame_number + current_frame->display_order_hint;
+#endif
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ cm->temporal_layer_id = current_frame->pyramid_level;
+ current_frame->temporal_layer_id = cm->temporal_layer_id;
+#else
+ cm->temporal_layer_id = 0;
+ current_frame->temporal_layer_id = cm->temporal_layer_id;
+#endif
+
+ const int order_offset = cpi->gf_group.arf_src_offset[cpi->gf_group.index];
+#if CONFIG_MULTIVIEW_CORE
+ const int cur_frame_disp =
+ (cpi->common.current_frame.frame_number + order_offset) /
+ cm->number_layers;
+#else
+ const int cur_frame_disp =
+ cpi->common.current_frame.frame_number + order_offset;
+#endif
+
+#if CONFIG_PRIMARY_REF_FRAME_OPT
+ init_ref_map_pair(
+ &cpi->common, cm->ref_frame_map_pairs,
+ cpi->gf_group.update_type[cpi->gf_group.index] == KF_UPDATE);
+#else
+ RefFrameMapPair ref_frame_map_pairs[REF_FRAMES];
+ init_ref_map_pair(
+ &cpi->common, ref_frame_map_pairs,
+ cpi->gf_group.update_type[cpi->gf_group.index] == KF_UPDATE);
+#endif // CONFIG_PRIMARY_REF_FRAME_OPT
+#if CONFIG_PRIMARY_REF_FRAME_OPT
+ if (cm->seq_params.explicit_ref_frame_map)
+ av1_get_ref_frames_enc(cm, cur_frame_disp, cm->ref_frame_map_pairs);
+ else
+ av1_get_ref_frames(cm, cur_frame_disp, cm->ref_frame_map_pairs);
+#else
+ if (cm->seq_params.explicit_ref_frame_map)
+ av1_get_ref_frames_enc(cm, cur_frame_disp, ref_frame_map_pairs);
+ else
+ av1_get_ref_frames(cm, cur_frame_disp, ref_frame_map_pairs);
+#endif // CONFIG_PRIMARY_REF_FRAME_OPT
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
current_frame->order_hint %=
(1 << (cm->seq_params.order_hint_info.order_hint_bits_minus_1 + 1));
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- encoder: ");
+ debug_print_multiview_curr_frame(cm);
+#endif
+
if (is_stat_generation_stage(cpi)) {
av1_first_pass(cpi, frame_input->ts_duration);
} else {
@@ -4388,6 +4493,22 @@
aom_bitstream_queue_set_frame_write(cm->current_frame.order_hint * 2 +
cm->show_frame);
#endif // CONFIG_BITSTREAM_DEBUG
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ cm->show_existing_frame = frame_params->show_existing_frame;
+ cpi->existing_fb_idx_to_show = frame_params->existing_fb_idx_to_show;
+ if (cm->show_existing_frame != 0 && cpi->existing_fb_idx_to_show < 0) {
+ FILE *const logfile = cm->fEncMultiviewLog;
+ fprintf(logfile,
+ " -- Encoder show existing frame may fail (flag=%d, "
+ "fb_idx_to_show=%d): \n ",
+ cm->show_existing_frame, cpi->existing_fb_idx_to_show);
+ logfile_multiview_curr_frame(cm, logfile);
+ logfile_multiview_buf_refs(cm, logfile);
+ logfile_buffer_state(cm, logfile);
+ logfile_primary_ref_info(cm, logfile);
+ fprintf(logfile, " -- End show existing frame --- \n ");
+ }
+#endif
if (encode_frame_to_data_rate(cpi, &frame_results->size, dest) !=
AOM_CODEC_OK) {
return AOM_CODEC_ERROR;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index c6fec27..ca85b45 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -753,6 +753,10 @@
unsigned int chroma_subsampling_x;
// Indicates the chrome subsampling y value.
unsigned int chroma_subsampling_y;
+#if CONFIG_MULTIVIEW_CORE
+ // Indicates number of input views.
+ unsigned int num_views;
+#endif
} InputCfg;
typedef struct {
diff --git a/av1/encoder/encoder_utils.c b/av1/encoder/encoder_utils.c
index 64a0cf8..7a60c94 100644
--- a/av1/encoder/encoder_utils.c
+++ b/av1/encoder/encoder_utils.c
@@ -1124,6 +1124,48 @@
(encode_show_existing_frame(cm) || cm->show_existing_frame)) {
RefCntBuffer *const frame_to_show =
cm->ref_frame_map[cpi->existing_fb_idx_to_show];
+#if CONFIG_MULTIVIEW_DEBUG
+ const CurrentFrame *const cf = &cpi->common.current_frame;
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ FILE *const logfile = cm->fEncMultiviewLog;
+#endif
+ if (frame_to_show == NULL || cpi->existing_fb_idx_to_show < 0) {
+#if CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(
+ "Frame to show - does not exist (index=%d): "
+ "(View,Level,OH,DOH):(%d,%d,%d,%d) \n",
+ cpi->existing_fb_idx_to_show, cf->view_id, cf->pyramid_level,
+ cf->order_hint, cf->display_order_hint);
+ fflush(stdout);
+#endif
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ fprintf(logfile,
+ "Frame to show - does not exist (index=%d): "
+ "(View,Level,OH,DOH):(%d,%d,%d,%d) \n",
+ cpi->existing_fb_idx_to_show, cf->view_id, cf->pyramid_level,
+ cf->order_hint, cf->display_order_hint);
+#endif
+ } else {
+ // printf("Frame to show - exists (index=%d):
+ // (View,Level,OH,DOH):(%d,%d,%d,%d) \n", cpi->existing_fb_idx_to_show,
+ // cf->view_id, cf->pyramid_level, cf->order_hint,
+ // cf->display_order_hint);
+
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+ // fprintf(logfile, "Frame to show - exists (index=%d):
+ // (View,Level,OH,DOH):(%d,%d,%d,%d) \n", cpi->existing_fb_idx_to_show,
+ // cf->view_id, cf->pyramid_level, cf->order_hint,
+ // cf->display_order_hint);
+#endif
+ }
+#if CONFIG_MULTIVIEW_DEBUG_LOGFILES
+// logfile_multiview_curr_frame(cm, logfile);
+// logfile_multiview_buf_refs(cm, logfile);
+// logfile_buffer_state(cm, logfile);
+// logfile_primary_ref_info(cm, logfile);
+// fflush(logfile);
+#endif
+#endif
if (frame_to_show == NULL) {
aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
diff --git a/av1/encoder/encoder_utils.h b/av1/encoder/encoder_utils.h
index 6432bb4..64adb9a 100644
--- a/av1/encoder/encoder_utils.h
+++ b/av1/encoder/encoder_utils.h
@@ -1145,7 +1145,14 @@
// All buffers are refreshed for shown keyframes and S-frames.
for (int ref_frame = 0; ref_frame < REF_FRAMES; ref_frame++) {
if (((cm->current_frame.refresh_frame_flags >> ref_frame) & 1) == 1) {
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ if (cm->current_frame.frame_type == KEY_FRAME && ref_frame > 0)
+ set_frame_buffer_invalid(&cm->ref_frame_map[ref_frame]);
+ else
+ assign_frame_buffer_p(&cm->ref_frame_map[ref_frame], cm->cur_frame);
+#else // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
assign_frame_buffer_p(&cm->ref_frame_map[ref_frame], cm->cur_frame);
+#endif // CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
}
}
}
diff --git a/av1/encoder/gop_structure.c b/av1/encoder/gop_structure.c
index 8bf8234..85b79e0 100644
--- a/av1/encoder/gop_structure.c
+++ b/av1/encoder/gop_structure.c
@@ -32,57 +32,128 @@
GF_GROUP *const gf_group, RATE_CONTROL *rc,
FRAME_INFO *frame_info, int start, int end,
int *cur_frame_idx, int *frame_ind,
- int layer_depth) {
- const int num_frames_to_process = end - start;
+ int layer_depth
+#if CONFIG_MULTIVIEW_CORE
+ ,
+ const int num_views
+#endif
+) {
+ const int num_frames_to_process = end - start;
// Either we are at the last level of the pyramid, or we don't have enough
// frames between 'l' and 'r' to create one more level.
if (layer_depth > gf_group->max_layer_depth_allowed ||
num_frames_to_process < 3) {
// Leaf nodes.
while (start < end) {
+ gf_group->max_layer_depth =
+ AOMMAX(gf_group->max_layer_depth, layer_depth);
gf_group->update_type[*frame_ind] = LF_UPDATE;
gf_group->arf_src_offset[*frame_ind] = 0;
+#if CONFIG_MULTIVIEW_CORE
+ gf_group->cur_frame_idx[*frame_ind] = num_views * (*cur_frame_idx);
+#else
gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx;
+#endif
gf_group->layer_depth[*frame_ind] = MAX_ARF_LAYERS;
gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
twopass, rc, frame_info, start, end - start, 0, NULL, NULL);
- gf_group->max_layer_depth =
- AOMMAX(gf_group->max_layer_depth, layer_depth);
++(*frame_ind);
++(*cur_frame_idx);
++start;
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 1; i < num_views; i++) {
+ const int prev_frame_ind = (*frame_ind) - 1;
+ assert(prev_frame_ind >= 0);
+ gf_group->update_type[*frame_ind] = LF_UPDATE;
+ gf_group->arf_src_offset[*frame_ind] = 0;
+ gf_group->cur_frame_idx[*frame_ind] =
+ gf_group->cur_frame_idx[prev_frame_ind] + 1;
+ gf_group->layer_depth[*frame_ind] = MAX_ARF_LAYERS;
+ gf_group->arf_boost[*frame_ind] = gf_group->arf_boost[prev_frame_ind];
+ ++(*frame_ind);
+ }
+#endif
}
} else {
const int m = (start + end - 1) / 2;
// Internal ARF.
gf_group->update_type[*frame_ind] = INTNL_ARF_UPDATE;
+#if CONFIG_MULTIVIEW_CORE
+ gf_group->arf_src_offset[*frame_ind] = num_views * (m - start);
+ gf_group->cur_frame_idx[*frame_ind] = num_views * (*cur_frame_idx);
+#else
gf_group->arf_src_offset[*frame_ind] = m - start;
gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx;
+#endif
gf_group->layer_depth[*frame_ind] = layer_depth;
// Get the boost factor for intermediate ARF frames.
gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
twopass, rc, frame_info, m, end - m, m - start, NULL, NULL);
++(*frame_ind);
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 1; i < num_views; i++) {
+ // Internal ARF per-view.
+ const int prev_frame_ind = (*frame_ind) - 1;
+ assert(prev_frame_ind >= 0);
+ gf_group->update_type[*frame_ind] = INTNL_ARF_UPDATE;
+ gf_group->arf_src_offset[*frame_ind] =
+ gf_group->arf_src_offset[prev_frame_ind] + 1;
+ gf_group->cur_frame_idx[*frame_ind] =
+ gf_group->cur_frame_idx[prev_frame_ind];
+ gf_group->layer_depth[*frame_ind] = layer_depth;
+ gf_group->arf_boost[*frame_ind] = gf_group->arf_boost[prev_frame_ind];
+ ++(*frame_ind);
+ }
+#endif
// Frames displayed before this internal ARF.
set_multi_layer_params(twopass, gf_group, rc, frame_info, start, m,
- cur_frame_idx, frame_ind, layer_depth + 1);
+ cur_frame_idx, frame_ind, layer_depth + 1
+#if CONFIG_MULTIVIEW_CORE
+ ,
+ num_views
+#endif
+ );
// Overlay for internal ARF.
gf_group->update_type[*frame_ind] = INTNL_OVERLAY_UPDATE;
gf_group->arf_src_offset[*frame_ind] = 0;
+#if CONFIG_MULTIVIEW_CORE
+ gf_group->cur_frame_idx[*frame_ind] = num_views * (*cur_frame_idx);
+#else
gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx;
+#endif
gf_group->arf_boost[*frame_ind] = 0;
gf_group->layer_depth[*frame_ind] = layer_depth;
++(*frame_ind);
++(*cur_frame_idx);
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 1; i < num_views; i++) {
+ // Overlay for internal ARF per-view.
+ const int prev_frame_ind = (*frame_ind) - 1;
+ assert(prev_frame_ind >= 0);
+ gf_group->update_type[*frame_ind] = INTNL_OVERLAY_UPDATE;
+ gf_group->arf_src_offset[*frame_ind] =
+ gf_group->arf_src_offset[prev_frame_ind];
+ gf_group->cur_frame_idx[*frame_ind] =
+ gf_group->cur_frame_idx[prev_frame_ind] + 1;
+ gf_group->arf_boost[*frame_ind] = 0;
+ gf_group->layer_depth[*frame_ind] = layer_depth;
+ ++(*frame_ind);
+ }
+#endif
// Frames displayed after this internal ARF.
set_multi_layer_params(twopass, gf_group, rc, frame_info, m + 1, end,
- cur_frame_idx, frame_ind, layer_depth + 1);
+ cur_frame_idx, frame_ind, layer_depth + 1
+#if CONFIG_MULTIVIEW_CORE
+ ,
+ num_views
+#endif
+ );
}
}
@@ -124,7 +195,12 @@
int *cur_frame_idx, int *frame_index, int is_ld_map_first_gop) {
int last_shown_frame = 0;
int min_pyr_level = MAX_ARF_LAYERS;
-
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(
+ " ml-subgop: subgop_cfg->num_steps=%d "
+ "(cur_frame_idx=%d,frame_index=%d)\n",
+ subgop_cfg->num_steps, *cur_frame_idx, *frame_index);
+#endif
for (int idx = 0; idx < subgop_cfg->num_steps; ++idx) {
const SubGOPStepCfg *frame = &subgop_cfg->step[idx];
@@ -219,12 +295,23 @@
return NULL;
}
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+static const char frame_update_type[FRAME_UPDATE_TYPES][50] = {
+ "KF_UPDATE", "LF_UPDATE", "GF_UPDATE",
+ "ARF_UPDATE", "OVERLAY_UPDATE", "INTNL_OVERLAY_UPDATE",
+ "INTNL_ARF_UPDATE", "KFFLT_UPDATE", "KFFLT_OVERLAY_UPDATE",
+};
+#endif
+
static int construct_multi_layer_gf_structure(
AV1_COMP *cpi, TWO_PASS *twopass, GF_GROUP *const gf_group,
RATE_CONTROL *rc, FRAME_INFO *const frame_info, int gf_interval,
FRAME_UPDATE_TYPE first_frame_update_type) {
int frame_index = 0;
int cur_frame_index = 0;
+#if CONFIG_MULTIVIEW_CORE
+ const int num_views = cpi->common.number_layers;
+#endif
assert(first_frame_update_type == KF_UPDATE ||
first_frame_update_type == ARF_UPDATE ||
@@ -240,7 +327,12 @@
subgop_cfg_set, gf_interval, rc->frames_to_key <= gf_interval + 2,
first_frame_update_type == KF_UPDATE, use_altref, &is_ld_map);
int is_ld_map_first_gop = is_ld_map && first_frame_update_type == KF_UPDATE;
-
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" 1: frame_index=%d, cur_frame_index=%d\n", frame_index,
+ cur_frame_index);
+ printf("-- first_frame_update_type = %s\n",
+ frame_update_type[first_frame_update_type]);
+#endif
if (first_frame_update_type == KF_UPDATE &&
cpi->oxcf.kf_cfg.enable_keyframe_filtering > 1) {
gf_group->has_overlay_for_key_frame = 1;
@@ -266,9 +358,26 @@
gf_group->layer_depth[frame_index] = 0;
gf_group->max_layer_depth = 0;
++frame_index;
- ++cur_frame_index;
+ cur_frame_index++;
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 1; i < num_views; i++) {
+ // arf update
+ const int prev_frame_ind = frame_index - 1;
+ assert(prev_frame_ind >= 0);
+ gf_group->update_type[frame_index] = LF_UPDATE;
+ gf_group->arf_src_offset[frame_index] = 0;
+ gf_group->cur_frame_idx[frame_index] =
+ gf_group->cur_frame_idx[prev_frame_ind] + 1;
+ gf_group->layer_depth[frame_index] = 0;
+ gf_group->max_layer_depth = 0;
+ ++frame_index;
+ }
+#endif
}
-
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" 2: frame_index=%d, cur_frame_index=%d\n", frame_index,
+ cur_frame_index);
+#endif
if (subgop_cfg) {
gf_group->subgop_cfg = subgop_cfg;
gf_group->is_user_specified = 1;
@@ -277,43 +386,117 @@
&frame_index, is_ld_map_first_gop);
frame_index++;
} else {
+#if CONFIG_MULTIVIEW_CORE
+ if (num_views == 1) {
+ if (first_frame_update_type == KF_UPDATE) gf_interval++;
+ }
+#else
if (first_frame_update_type == KF_UPDATE) gf_interval++;
+#endif
// ALTREF.
if (use_altref) {
gf_group->update_type[frame_index] = ARF_UPDATE;
+#if CONFIG_MULTIVIEW_CORE
+ gf_group->arf_src_offset[frame_index] =
+ num_views * (gf_interval - cur_frame_index - 1);
+ gf_group->cur_frame_idx[frame_index] = num_views * cur_frame_index;
+#else
gf_group->arf_src_offset[frame_index] = gf_interval - cur_frame_index - 1;
gf_group->cur_frame_idx[frame_index] = cur_frame_index;
+#endif
gf_group->layer_depth[frame_index] = 1;
gf_group->arf_boost[frame_index] = cpi->rc.gfu_boost;
gf_group->max_layer_depth = 1;
gf_group->arf_index = frame_index;
++frame_index;
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 1; i < num_views; i++) {
+ const int prev_frame_ind = frame_index - 1;
+ assert(prev_frame_ind >= 0);
+ gf_group->update_type[frame_index] = ARF_UPDATE;
+ gf_group->arf_src_offset[frame_index] =
+ gf_group->arf_src_offset[prev_frame_ind] + 1;
+ gf_group->cur_frame_idx[frame_index] =
+ gf_group->cur_frame_idx[prev_frame_ind];
+
+ gf_group->layer_depth[frame_index] = 1;
+ gf_group->arf_boost[frame_index] = cpi->rc.gfu_boost;
+ gf_group->max_layer_depth = 1;
+ gf_group->arf_index = frame_index;
+ ++frame_index;
+ }
+#endif
} else {
gf_group->arf_index = -1;
}
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" frame_index=%d, cur_frame_index=%d\n", frame_index,
+ cur_frame_index);
+#endif
set_multi_layer_params(twopass, gf_group, rc, frame_info, cur_frame_index,
gf_interval - 1, &cur_frame_index, &frame_index,
- use_altref + 1);
+ use_altref + 1
+#if CONFIG_MULTIVIEW_CORE
+ ,
+ num_views
+#endif
+ );
if (use_altref) {
- gf_group->update_type[frame_index] = OVERLAY_UPDATE;
+ gf_group->update_type[frame_index] =
+ INTNL_OVERLAY_UPDATE; // OVERLAY_UPDATE;
gf_group->arf_src_offset[frame_index] = 0;
+#if CONFIG_MULTIVIEW_CORE
+ gf_group->cur_frame_idx[frame_index] = num_views * cur_frame_index;
+#else
gf_group->cur_frame_idx[frame_index] = cur_frame_index;
+#endif
gf_group->layer_depth[frame_index] = MAX_ARF_LAYERS;
gf_group->arf_boost[frame_index] = NORMAL_BOOST;
++frame_index;
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 1; i < num_views; i++) {
+ const int prev_frame_ind = frame_index - 1;
+ assert(prev_frame_ind >= 0);
+ gf_group->update_type[frame_index] =
+ (i == (num_views - 1)) ? OVERLAY_UPDATE : INTNL_OVERLAY_UPDATE;
+ gf_group->arf_src_offset[frame_index] = 0;
+ gf_group->cur_frame_idx[frame_index] =
+ gf_group->cur_frame_idx[prev_frame_ind] + 1;
+ gf_group->layer_depth[frame_index] = MAX_ARF_LAYERS;
+ gf_group->arf_boost[frame_index] = NORMAL_BOOST;
+ ++frame_index;
+ }
+#endif
} else {
for (; cur_frame_index < gf_interval; ++cur_frame_index) {
gf_group->update_type[frame_index] = LF_UPDATE;
gf_group->arf_src_offset[frame_index] = 0;
+#if CONFIG_MULTIVIEW_CORE
+ gf_group->cur_frame_idx[frame_index] = cur_frame_index * num_views;
+#else
gf_group->cur_frame_idx[frame_index] = cur_frame_index;
+#endif
gf_group->layer_depth[frame_index] = MAX_ARF_LAYERS;
gf_group->arf_boost[frame_index] = NORMAL_BOOST;
gf_group->max_layer_depth = AOMMAX(gf_group->max_layer_depth, 2);
++frame_index;
+#if CONFIG_MULTIVIEW_CORE
+ for (int i = 1; i < num_views; i++) {
+ const int prev_frame_ind = frame_index - 1;
+ assert(prev_frame_ind >= 0);
+ gf_group->update_type[frame_index] = LF_UPDATE;
+ gf_group->arf_src_offset[frame_index] = 1;
+ gf_group->cur_frame_idx[frame_index] =
+ gf_group->cur_frame_idx[prev_frame_ind];
+ gf_group->layer_depth[frame_index] = MAX_ARF_LAYERS;
+ gf_group->arf_boost[frame_index] = NORMAL_BOOST;
+ gf_group->max_layer_depth = AOMMAX(gf_group->max_layer_depth, 2);
+ ++frame_index;
+ }
+#endif
}
}
}
-
return frame_index;
}
diff --git a/av1/encoder/mv_prec.c b/av1/encoder/mv_prec.c
index 61db6e6..24d679b 100644
--- a/av1/encoder/mv_prec.c
+++ b/av1/encoder/mv_prec.c
@@ -33,7 +33,7 @@
has_second_ref(mbmi)));
const MV_REFERENCE_FRAME *ref_frames = mbmi->ref_frame;
- const int8_t ref_frame_type = av1_ref_frame_type(ref_frames);
+ const int16_t ref_frame_type = av1_ref_frame_type(ref_frames);
#if CONFIG_SEP_COMP_DRL
const CANDIDATE_MV *curr_ref_mv_stack =
has_second_drl(mbmi) ? mbmi_ext_frame->ref_mv_stack[ref_idx]
diff --git a/av1/encoder/partition_search.c b/av1/encoder/partition_search.c
index 3982479..a294fde 100644
--- a/av1/encoder/partition_search.c
+++ b/av1/encoder/partition_search.c
@@ -5904,10 +5904,10 @@
#endif // CONFIG_EXTENDED_SDP
) {
#if CONFIG_EXTENDED_SDP
- const int ref_type = av1_ref_frame_type(
+ const int16_t ref_type = av1_ref_frame_type(
pc_tree->none[pc_tree->region_type]->mic.ref_frame);
#else
- const int ref_type = av1_ref_frame_type(pc_tree->none->mic.ref_frame);
+ const int16_t ref_type = av1_ref_frame_type(pc_tree->none->mic.ref_frame);
#endif // CONFIG_EXTENDED_SDP
av1_update_picked_ref_frames_mask(x, ref_type, bsize, cm->mib_size,
mi_row, mi_col);
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 1ec40a0..6040b5a 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -2236,6 +2236,10 @@
break;
}
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" frames_to_key=%d, frames_since_key=%d \n", frames_to_key,
+ frames_since_key);
+#endif
// Step on to the next frame.
++frames_to_key;
++frames_since_key;
@@ -2430,7 +2434,6 @@
const FIRSTPASS_STATS first_frame = *this_frame;
FIRSTPASS_STATS next_frame;
av1_zero(next_frame);
-
rc->frames_since_key = 0;
// Use arfs if possible.
rc->use_arf_in_this_kf_group = is_altref_enabled(
@@ -2796,8 +2799,16 @@
if (cpi->no_show_fwd_kf) {
assert(update_type == ARF_UPDATE || update_type == KFFLT_UPDATE);
frame_params->frame_type = KEY_FRAME;
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- set2 frame type to KEY_FRAME: ");
+ debug_print_multiview_curr_frame(&cpi->common);
+#endif
} else {
frame_params->frame_type = INTER_FRAME;
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- set2 frame type to INTER_FRAME: ");
+ debug_print_multiview_curr_frame(&cpi->common);
+#endif
}
if (frame_params->frame_type != KEY_FRAME)
@@ -2835,12 +2846,20 @@
rc->active_worst_quality = oxcf->rc_cfg.qp;
}
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" frames_to_key= %d, current_frame.view_id=%d\n", rc->frames_to_key,
+ cpi->common.current_frame.view_id);
+#endif
// Keyframe and section processing.
if (rc->frames_to_key <= 0) {
assert(rc->frames_to_key >= -1);
FIRSTPASS_STATS this_frame_copy;
this_frame_copy = this_frame;
frame_params->frame_type = KEY_FRAME;
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- set3 frame type to KEY_FRAME: ");
+ debug_print_multiview_curr_frame(&cpi->common);
+#endif
// Define next KF group and assign bits to it.
find_next_key_frame(cpi, &this_frame);
this_frame = this_frame_copy;
@@ -2935,6 +2954,10 @@
if (cpi->no_show_fwd_kf) {
assert(update_type == ARF_UPDATE || update_type == KFFLT_UPDATE);
frame_params->frame_type = KEY_FRAME;
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf("--- set4 frame type to KEY_FRAME: ");
+ debug_print_multiview_curr_frame(&cpi->common);
+#endif
} else {
frame_params->frame_type =
rc->frames_since_key == 0 ? KEY_FRAME : INTER_FRAME;
@@ -3042,6 +3065,9 @@
// Update the active best quality pyramid.
if (!rc->is_src_frame_alt_ref) {
const int pyramid_level = cpi->gf_group.layer_depth[cpi->gf_group.index];
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" pyramid level = %d \n", pyramid_level);
+#endif
int i;
for (i = pyramid_level; i <= MAX_ARF_LAYERS; ++i) {
rc->active_best_quality[i] = cpi->common.quant_params.base_qindex;
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 268611c..94dc7f4 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1043,13 +1043,14 @@
oxcf->q_cfg.use_fixed_qp_offsets == 2);
assert(oxcf->rc_cfg.mode == AOM_Q);
const FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_index];
-
int offset_idx = -1;
if (update_type == KF_UPDATE) {
+#if !CONFIG_MULTIVIEW_CORE
if (rc->frames_to_key <= 1) {
// Image / intra-only coding: ignore offsets.
return qp;
}
+#endif
offset_idx = 0;
} else if (update_type == ARF_UPDATE || update_type == GF_UPDATE ||
update_type == INTNL_ARF_UPDATE || update_type == LF_UPDATE ||
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index 8063f5e..1035a7d 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -548,7 +548,11 @@
#endif // CONFIG_OPTIMIZE_CTX_TIP_WARP
for (i = 0; i < REF_CONTEXTS; ++i) {
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+ for (j = 0; j < EXTENDED_INTER_REFS_CONTEXT; ++j) {
+#else
for (j = 0; j < INTER_REFS_PER_FRAME - 1; ++j) {
+#endif
av1_cost_tokens_from_cdf(mode_costs->single_ref_cost[i][j],
fc->single_ref_cdf[i][j], NULL);
}
@@ -556,7 +560,11 @@
for (i = 0; i < REF_CONTEXTS; ++i) {
#if CONFIG_SAME_REF_COMPOUND
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+ for (j = 0; j < EXTENDED_INTER_REFS_CONTEXT; ++j) {
+#else
for (j = 0; j < INTER_REFS_PER_FRAME - 1; ++j) {
+#endif
#else
for (j = 0; j < INTER_REFS_PER_FRAME - 2; ++j) {
#endif // CONFIG_SAME_REF_COMPOUND
@@ -567,7 +575,11 @@
for (i = 0; i < REF_CONTEXTS; ++i) {
for (j = 0; j < COMPREF_BIT_TYPES; j++) {
#if CONFIG_SAME_REF_COMPOUND
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+ for (int k = 0; k < EXTENDED_INTER_REFS_CONTEXT; ++k) {
+#else
for (int k = 0; k < INTER_REFS_PER_FRAME - 1; ++k) {
+#endif
#else
for (int k = 0; k < INTER_REFS_PER_FRAME - 2; ++k) {
#endif // CONFIG_SAME_REF_COMPOUND
@@ -952,6 +964,7 @@
int av1_compute_rd_mult(const AV1_COMP *cpi, int qindex) {
int64_t rdmult = av1_compute_rd_mult_based_on_qindex(cpi, qindex);
+#if !CONFIG_MULTIVIEW_CORE
if (is_stat_consumption_stage(cpi) &&
(cpi->common.current_frame.frame_type != KEY_FRAME)) {
const GF_GROUP *const gf_group = &cpi->gf_group;
@@ -961,6 +974,7 @@
rdmult = (rdmult * rd_layer_depth_factor[layer_depth]) >> 7;
rdmult += ((rdmult * rd_boost_factor[boost_index]) >> 7);
}
+#endif
return (int)rdmult;
}
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index dea90a1..c1507c9 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -921,7 +921,7 @@
if (!(this_mode == GLOBALMV || this_mode == NEARMV)) {
return 0;
}
- const uint8_t ref_frame_type = av1_ref_frame_type(ref_frames);
+ const uint16_t ref_frame_type = av1_ref_frame_type(ref_frames);
const MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
const int ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type];
if (ref_mv_count > 1) {
@@ -3621,11 +3621,11 @@
assert(single_mode == NEARMV);
const int ref_mv_offset = ref_mv_idx;
#if CONFIG_SEP_COMP_DRL
- const int8_t ref_frame_type = has_second_drl_by_mode(this_mode, ref_frame)
- ? ref_frame[ref_idx]
- : av1_ref_frame_type(ref_frame);
+ const int16_t ref_frame_type = has_second_drl_by_mode(this_mode, ref_frame)
+ ? ref_frame[ref_idx]
+ : av1_ref_frame_type(ref_frame);
#else
- const int8_t ref_frame_type = av1_ref_frame_type(ref_frame);
+ const int16_t ref_frame_type = av1_ref_frame_type(ref_frame);
#endif
if (ref_frame_type > NONE_FRAME &&
ref_mv_offset < mbmi_ext->ref_mv_count[ref_frame_type]) {
@@ -3732,7 +3732,7 @@
if (!ret) return 0;
const PREDICTION_MODE single_mode = get_single_mode(this_mode, i);
if (single_mode == NEWMV) {
- const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+ const uint16_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
#if CONFIG_SEP_COMP_DRL
if (has_second_drl(mbmi))
cur_mv[i] =
@@ -3905,7 +3905,7 @@
}
#endif
- const int8_t ref_frame_type = av1_ref_frame_type(ref_frame);
+ const int16_t ref_frame_type = av1_ref_frame_type(ref_frame);
int ref_mv_count =
ref_frame_type > NONE_FRAME ? mbmi_ext->ref_mv_count[ref_frame_type] : 0;
@@ -3943,7 +3943,7 @@
#if !CONFIG_CWG_E099_DRL_WRL_SIMPLIFY
const AV1_COMMON *const cm = &cpi->common;
const SPEED_FEATURES *const sf = &cpi->sf;
- const int8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+ const int16_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
#if CONFIG_SEP_COMP_DRL
if (sf->inter_sf.reduce_inter_modes &&
(ref_mv_idx[0] > 0 || ref_mv_idx[1] > 0)) {
@@ -4178,7 +4178,7 @@
mbmi->ref_mv_idx > 0) {
#endif
const int is_comp_pred = has_second_ref(mbmi);
- const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+ const uint16_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
int_mv this_refmv[2];
this_refmv[0].as_int = 0;
this_refmv[1].as_int = 0;
@@ -7990,7 +7990,7 @@
#endif // CONFIG_MORPH_PRED
#if !CONFIG_SKIP_MODE_ENHANCEMENT
- const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+ const uint16_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
if (x->mbmi_ext->ref_mv_count[ref_frame_type] == UINT8_MAX) {
if (x->mbmi_ext->ref_mv_count[ref_frame] == UINT8_MAX ||
x->mbmi_ext->ref_mv_count[second_ref_frame] == UINT8_MAX) {
@@ -8104,7 +8104,7 @@
setup_buffer_ref_mvs_inter(cpi, x, rf_idx, bsize, yv12_mb);
}
- const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+ const uint16_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
av1_find_mv_refs(cm, xd, mbmi, ref_frame_type, mbmi_ext->ref_mv_count,
xd->ref_mv_stack, xd->weight, NULL, mbmi_ext->global_mvs
@@ -8450,7 +8450,7 @@
#if CONFIG_IBC_SR_EXT
mbmi->use_intrabc[xd->tree_type == CHROMA_PART] = 0;
#endif // CONFIG_IBC_SR_EXT
- const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+ const int16_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
if (x->mbmi_ext->ref_mv_count[ref_frame_type] == UINT8_MAX) {
if (x->mbmi_ext->ref_mv_count[ref_frame] == UINT8_MAX ||
x->mbmi_ext->ref_mv_count[second_ref_frame] == UINT8_MAX) {
@@ -9425,9 +9425,9 @@
return 1;
}
#if CONFIG_SAME_REF_COMPOUND
- const uint8_t ref_type = av1_ref_frame_type(ref_frame);
+ const uint16_t ref_type = av1_ref_frame_type(ref_frame);
#else
- const int ref_type = av1_ref_frame_type(ref_frame);
+ const int16_t ref_type = av1_ref_frame_type(ref_frame);
#endif // CONFIG_SAME_REF_COMPOUND
if (prune_ref_frame(cpi, x, ref_type)) return 1;
@@ -10702,10 +10702,17 @@
// Note that the 0-th element will contain a cut-off that is later used
// to determine if we should skip a compound mode.
+#if CONFIG_MULTIVIEW_EXTENDED_DPB
+ int64_t ref_frame_rd[SINGLE_REF_FRAMES] = {
+ INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX,
+ INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX,
+ INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX, INT64_MAX
+ };
+#else
int64_t ref_frame_rd[SINGLE_REF_FRAMES] = { INT64_MAX, INT64_MAX, INT64_MAX,
INT64_MAX, INT64_MAX, INT64_MAX,
INT64_MAX, INT64_MAX, INT64_MAX };
-
+#endif
// Prepared stats used later to check if we could skip intra mode eval.
int64_t inter_cost = -1;
int64_t intra_cost = -1;
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 52843d8..86a92db 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -1039,7 +1039,6 @@
int anc_frame_offset = gf_group->cur_frame_idx[cur_frame_idx];
int process_frame_count = 0;
const int gop_length = get_gop_length(gf_group);
-
for (gf_index = cur_frame_idx; gf_index < gop_length; ++gf_index) {
TplDepFrame *tpl_frame = &tpl_data->tpl_frame[gf_index];
FRAME_UPDATE_TYPE frame_update_type = gf_group->update_type[gf_index];
@@ -1100,9 +1099,15 @@
av1_get_ref_frames_enc(cm, true_disp, ref_frame_map_pairs);
else
av1_get_ref_frames(cm, true_disp, ref_frame_map_pairs);
- int refresh_mask =
- av1_get_refresh_frame_flags(cpi, &frame_params, frame_update_type,
- gf_index, true_disp, ref_frame_map_pairs);
+ int refresh_mask = av1_get_refresh_frame_flags(
+ cpi, &frame_params, frame_update_type, gf_index,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ 0,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ -1, cm->number_layers,
+#endif
+ true_disp, ref_frame_map_pairs);
int refresh_frame_map_index =
av1_get_refresh_ref_frame_map(cm, refresh_mask);
@@ -1148,7 +1153,6 @@
MAX_TPL_EXTEND, cpi->rc.frames_to_key - cpi->rc.baseline_gf_interval);
int frame_display_index = gf_group->cur_frame_idx[gop_length - 1] +
gf_group->arf_src_offset[gop_length - 1] + 1;
-
for (;
gf_index < MAX_TPL_FRAME_IDX && extend_frame_count < extend_frame_length;
++gf_index) {
@@ -1185,6 +1189,9 @@
gf_group->update_type[gf_index] = LF_UPDATE;
gf_group->q_val[gf_index] = *pframe_qindex;
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" init_gop_frames_for_tpl: pframe_qindex=%2d\n", *pframe_qindex);
+#endif
const int true_disp =
(int)(tpl_frame->frame_display_index) -
@@ -1199,6 +1206,12 @@
// frame_update_type.
int refresh_mask =
av1_get_refresh_frame_flags(cpi, &frame_params, frame_update_type, -1,
+#if CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ 0,
+#endif
+#if CONFIG_MULTIVIEW_SEPARATE_DPB
+ -1, cm->number_layers,
+#endif
true_disp, ref_frame_map_pairs);
int refresh_frame_map_index =
av1_get_refresh_ref_frame_map(cm, refresh_mask);
@@ -1278,7 +1291,10 @@
gf_group->q_val[gf_index] =
av1_rc_pick_q_and_bounds(cpi, &cpi->rc, cm->width, cm->height, gf_index,
&bottom_index, &top_index);
-
+#if CONFIG_MULTIVIEW_CORE && CONFIG_MULTIVIEW_DEBUG_PROMPT
+ printf(" av1_tpl_setup_stats: q_val[%d]=%2d\n", gf_index,
+ gf_group->q_val[gf_index]);
+#endif
cm->current_frame.frame_type = INTER_FRAME;
}
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index 9a0b17b..d54453b 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -143,6 +143,38 @@
set_aom_config_var(CONFIG_ZERO_OFFSET_BITUPSHIFT 1
"Use zero offset for non-normative bit upshift")
+set_aom_config_var(CONFIG_MULTIVIEW_CORE 0
+ "Core changes in the codebase for multiview coding support.")
+set_aom_config_var(CONFIG_MULTIVIEW_SEPARATE_DPB 0
+ "separate dpb support for multiview.")
+set_aom_config_var(CONFIG_MULTIVIEW_EXTENDED_DPB 0
+ "extended dpb support for multiview.")
+
+set_aom_config_var(CONFIG_MULTIVIEW_DEBUG 0
+ "Debug functionality macro for multiview coding.")
+set_aom_config_var(CONFIG_MULTIVIEW_DEBUG_PROMPT 0
+ "Debug macro for prompting on display.")
+set_aom_config_var(CONFIG_MULTIVIEW_DEBUG_LOGFILES 0
+ "Debug create logfiles for encode and decode.")
+
+set_aom_config_var(
+ CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+ 0
+ "Enable temporal scalability using the implicit reference frame list construction"
+)
+set_aom_config_var(
+ CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_ENCODER
+ 0
+ "Enable temporal scalability encoding with ref map slot allocation and frame drop"
+)
+# Bugfix for error resilience case for
+# CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST
+set_aom_config_var(
+ CONFIG_MULTILAYER_TEMPORAL_SCALABILITY_REFLIST_FIX_ERROR_RES
+ 0
+ "Enable temporal scalability using the implicit reference frame list construction"
+)
+
set_aom_config_var(CONFIG_PARAKIT_COLLECT_DATA 0
"enables data collection for ParaKit training.")
diff --git a/build/cmake/aom_experiment_deps.cmake b/build/cmake/aom_experiment_deps.cmake
index 2e348ca..a74c5ea 100644
--- a/build/cmake/aom_experiment_deps.cmake
+++ b/build/cmake/aom_experiment_deps.cmake
@@ -61,6 +61,11 @@
change_config_and_warn(CONFIG_ENABLE_MHCCP 0 !CONFIG_EXT_RECUR_PARTITIONS)
endif()
+ # CONFIG_MULTIVIEW_SEPARATE_DPB is depdendent on CONFIG_MULTIVIEW_CORE
+ if(NOT CONFIG_MULTIVIEW_CORE AND CONFIG_MULTIVIEW_SEPARATE_DPB)
+ change_config_and_warn(CONFIG_MULTIVIEW_SEPARATE_DPB 0
+ !CONFIG_MULTIVIEW_CORE)
+ endif()
# CONFIG_CB1TO4_SPLIT is dependent on CONFIG_EXT_RECUR_PARTITIONS.
if(NOT CONFIG_EXT_RECUR_PARTITIONS AND CONFIG_CB1TO4_SPLIT)
change_config_and_warn(CONFIG_CB1TO4_SPLIT 0 !CONFIG_EXT_RECUR_PARTITIONS)
diff --git a/common/ivfdec.c b/common/ivfdec.c
index 7eee07f..6437d6e 100644
--- a/common/ivfdec.c
+++ b/common/ivfdec.c
@@ -32,8 +32,11 @@
int file_is_ivf(struct AvxInputContext *input_ctx) {
char raw_hdr[32];
int is_ivf = 0;
-
+#if CONFIG_MULTIVIEW_CORE
+ if (fread(raw_hdr, 1, 32, input_ctx->file[0]) == 32) {
+#else
if (fread(raw_hdr, 1, 32, input_ctx->file) == 32) {
+#endif
if (memcmp(IVF_SIGNATURE, raw_hdr, 4) == 0) {
is_ivf = 1;
@@ -54,10 +57,19 @@
}
if (!is_ivf) {
+#if CONFIG_MULTIVIEW_CORE
+ rewind(input_ctx->file[0]);
+ input_ctx->detect[0].buf_read = 0;
+#else
rewind(input_ctx->file);
input_ctx->detect.buf_read = 0;
+#endif
} else {
+#if CONFIG_MULTIVIEW_CORE
+ input_ctx->detect[0].position = 4;
+#else
input_ctx->detect.position = 4;
+#endif
}
return is_ivf;
}
diff --git a/common/obudec.c b/common/obudec.c
index 4826f92..1ac8079 100644
--- a/common/obudec.c
+++ b/common/obudec.c
@@ -276,7 +276,11 @@
struct AvxInputContext *avx_ctx = obu_ctx->avx_ctx;
uint8_t detect_buf[OBU_DETECTION_SIZE] = { 0 };
const int is_annexb = obu_ctx->is_annexb;
+#if CONFIG_MULTIVIEW_CORE
+ FILE *f = avx_ctx->file[0];
+#else
FILE *f = avx_ctx->file;
+#endif
size_t payload_length = 0;
ObuHeader obu_header;
memset(&obu_header, 0, sizeof(obu_header));
@@ -369,7 +373,11 @@
int obudec_read_temporal_unit(struct ObuDecInputContext *obu_ctx,
uint8_t **buffer, size_t *bytes_read,
size_t *buffer_size) {
+#if CONFIG_MULTIVIEW_CORE
+ FILE *f = obu_ctx->avx_ctx->file[0];
+#else
FILE *f = obu_ctx->avx_ctx->file;
+#endif
if (!f) return -1;
*buffer_size = 0;
diff --git a/common/stream_iter.c b/common/stream_iter.c
index 078be62..fe1230d 100644
--- a/common/stream_iter.c
+++ b/common/stream_iter.c
@@ -18,15 +18,31 @@
#include "common/y4minput.h"
static int copy_reader(StreamIter *iter, aom_image_t *img) {
+#if CONFIG_MULTIVIEW_CORE
+ const int view_id = iter->view_id;
+#endif
struct AvxInputContext *input_ctx = iter->input.avx;
+#if CONFIG_MULTIVIEW_CORE
+ FILE *f = input_ctx->file[view_id];
+ y4m_input *y4m = &input_ctx->y4m[view_id];
+#else
FILE *f = input_ctx->file;
y4m_input *y4m = &input_ctx->y4m;
+#endif
int shortread = 0;
+#if CONFIG_MULTIVIEW_CORE
+ if (input_ctx->file_type[view_id] == FILE_TYPE_Y4M) {
+#else
if (input_ctx->file_type == FILE_TYPE_Y4M) {
+#endif
if (y4m_input_fetch_frame(y4m, f, img) < 1) return 0;
} else {
+#if CONFIG_MULTIVIEW_CORE
+ shortread = read_yuv_frame(input_ctx, img, view_id);
+#else
shortread = read_yuv_frame(input_ctx, img);
+#endif
}
return !shortread;
}
@@ -34,6 +50,9 @@
void copy_stream_iter_init(StreamIter *iter, struct AvxInputContext *input) {
iter->input.avx = input;
iter->reader = copy_reader;
+#if CONFIG_MULTIVIEW_CORE
+ iter->view_id = 0;
+#endif
}
static int skip_reader(StreamIter *iter, aom_image_t *raw) {
@@ -96,6 +115,9 @@
assert(limit >= 0);
iter->input.stream = input;
iter->current = 0;
+#if CONFIG_MULTIVIEW_CORE
+ iter->view_id = 0;
+#endif
iter->n = limit;
iter->reader = limit_reader;
}
diff --git a/common/stream_iter.h b/common/stream_iter.h
index 73781c7..751f356 100644
--- a/common/stream_iter.h
+++ b/common/stream_iter.h
@@ -36,6 +36,9 @@
// iterator, do not use either field.
int current;
int n;
+#if CONFIG_MULTIVIEW_CORE
+ int view_id;
+#endif
// Pointer to the function that performs the read. Returns whether a frame
// is available. If a frame is returned, it is written into *raw.
int (*reader)(struct StreamIter *iter, aom_image_t *raw);
diff --git a/common/tools_common.c b/common/tools_common.c
index 0e4db53..a80a5af 100644
--- a/common/tools_common.c
+++ b/common/tools_common.c
@@ -77,10 +77,17 @@
if (detail) printf(" %s\n", detail);
exit(EXIT_FAILURE);
}
-
+#if CONFIG_MULTIVIEW_CORE
+int read_yuv_frame(struct AvxInputContext *input_ctx, aom_image_t *yuv_frame,
+ int view_id) {
+ assert(view_id >= 0);
+ FILE *f = input_ctx->file[view_id];
+ struct FileTypeDetectionBuffer *detect = &input_ctx->detect[view_id];
+#else
int read_yuv_frame(struct AvxInputContext *input_ctx, aom_image_t *yuv_frame) {
FILE *f = input_ctx->file;
struct FileTypeDetectionBuffer *detect = &input_ctx->detect;
+#endif
int plane = 0;
int shortread = 0;
const int bytespp = (yuv_frame->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
diff --git a/common/tools_common.h b/common/tools_common.h
index 34368dc..d34af53 100644
--- a/common/tools_common.h
+++ b/common/tools_common.h
@@ -71,6 +71,10 @@
#define AV1_FOURCC 0x31305641
+#if CONFIG_MULTIVIEW_CORE
+#define NUM_LAYERS_MAX 256 // maximum number of layers supported
+#endif
+
enum VideoFileType {
FILE_TYPE_OBU,
FILE_TYPE_RAW,
@@ -101,11 +105,22 @@
};
struct AvxInputContext {
+#if CONFIG_MULTIVIEW_CORE
+ const char *filename[NUM_LAYERS_MAX];
+ FILE *file[NUM_LAYERS_MAX];
+ int num_views;
+#else
const char *filename;
FILE *file;
+#endif
int64_t length;
+#if CONFIG_MULTIVIEW_CORE
+ struct FileTypeDetectionBuffer detect[NUM_LAYERS_MAX];
+ enum VideoFileType file_type[NUM_LAYERS_MAX];
+#else
struct FileTypeDetectionBuffer detect;
enum VideoFileType file_type;
+#endif
uint32_t width;
uint32_t height;
struct AvxRational pixel_aspect_ratio;
@@ -115,8 +130,12 @@
uint32_t fourcc;
struct AvxRational framerate;
#if CONFIG_AV1_ENCODER
+#if CONFIG_MULTIVIEW_CORE
+ y4m_input y4m[NUM_LAYERS_MAX];
+#else
y4m_input y4m;
#endif
+#endif
aom_color_range_t color_range;
};
@@ -163,7 +182,12 @@
// If the interface is unknown, returns 0.
uint32_t get_fourcc_by_aom_decoder(aom_codec_iface_t *iface);
+#if CONFIG_MULTIVIEW_CORE
+int read_yuv_frame(struct AvxInputContext *input_ctx, aom_image_t *yuv_frame,
+ int view_id);
+#else
int read_yuv_frame(struct AvxInputContext *input_ctx, aom_image_t *yuv_frame);
+#endif
void aom_img_write(const aom_image_t *img, FILE *file);
int aom_img_read(aom_image_t *img, FILE *file);
diff --git a/common/video_reader.c b/common/video_reader.c
index 2cb653e..546e171 100644
--- a/common/video_reader.c
+++ b/common/video_reader.c
@@ -42,24 +42,41 @@
return NULL; // Can't allocate AvxVideoReader
}
+#if CONFIG_MULTIVIEW_CORE
+ reader->input_ctx.filename[0] = filename;
+ reader->input_ctx.file[0] = file;
+#else
reader->input_ctx.filename = filename;
reader->input_ctx.file = file;
+#endif
reader->obu_ctx.avx_ctx = &reader->input_ctx;
if (file_is_ivf(&reader->input_ctx)) {
+#if CONFIG_MULTIVIEW_CORE
+ reader->input_ctx.file_type[0] = FILE_TYPE_IVF;
+#else
reader->input_ctx.file_type = FILE_TYPE_IVF;
+#endif
reader->info.codec_fourcc = reader->input_ctx.fourcc;
reader->info.frame_width = reader->input_ctx.width;
reader->info.frame_height = reader->input_ctx.height;
#if CONFIG_WEBM_IO
} else if (file_is_webm(&reader->webm_ctx, &reader->input_ctx)) {
+#if CONFIG_MULTIVIEW_CORE
+ reader->input_ctx.file_type[0] = FILE_TYPE_WEBM;
+#else
reader->input_ctx.file_type = FILE_TYPE_WEBM;
+#endif
reader->info.codec_fourcc = reader->input_ctx.fourcc;
reader->info.frame_width = reader->input_ctx.width;
reader->info.frame_height = reader->input_ctx.height;
#endif
} else if (file_is_obu(&reader->obu_ctx)) {
+#if CONFIG_MULTIVIEW_CORE
+ reader->input_ctx.file_type[0] = FILE_TYPE_OBU;
+#else
reader->input_ctx.file_type = FILE_TYPE_OBU;
+#endif
// assume AV1
reader->info.codec_fourcc = AV1_FOURCC;
reader->info.is_annexb = reader->obu_ctx.is_annexb;
@@ -74,8 +91,13 @@
void aom_video_reader_close(AvxVideoReader *reader) {
if (reader) {
+#if CONFIG_MULTIVIEW_CORE
+ fclose(reader->input_ctx.file[0]);
+ if (reader->input_ctx.file_type[0] == FILE_TYPE_OBU) {
+#else
fclose(reader->input_ctx.file);
if (reader->input_ctx.file_type == FILE_TYPE_OBU) {
+#endif
obudec_free(&reader->obu_ctx);
}
free(reader->buffer);
@@ -84,16 +106,29 @@
}
int aom_video_reader_read_frame(AvxVideoReader *reader) {
+#if CONFIG_MULTIVIEW_CORE
+ if (reader->input_ctx.file_type[0] == FILE_TYPE_IVF) {
+ return !ivf_read_frame(reader->input_ctx.file[0], &reader->buffer,
+#else
if (reader->input_ctx.file_type == FILE_TYPE_IVF) {
return !ivf_read_frame(reader->input_ctx.file, &reader->buffer,
+#endif
&reader->frame_size, &reader->buffer_size,
&reader->pts);
+#if CONFIG_MULTIVIEW_CORE
+ } else if (reader->input_ctx.file_type[0] == FILE_TYPE_OBU) {
+#else
} else if (reader->input_ctx.file_type == FILE_TYPE_OBU) {
+#endif
return !obudec_read_temporal_unit(&reader->obu_ctx, &reader->buffer,
&reader->frame_size,
&reader->buffer_size);
#if CONFIG_WEBM_IO
+#if CONFIG_MULTIVIEW_CORE
+ } else if (reader->input_ctx.file_type[0] == FILE_TYPE_WEBM) {
+#else
} else if (reader->input_ctx.file_type == FILE_TYPE_WEBM) {
+#endif
return !webm_read_frame(&reader->webm_ctx, &reader->buffer,
&reader->frame_size, &reader->buffer_size);
#endif
@@ -115,7 +150,11 @@
}
FILE *aom_video_reader_get_file(AvxVideoReader *reader) {
+#if CONFIG_MULTIVIEW_CORE
+ return reader->input_ctx.file[0];
+#else
return reader->input_ctx.file;
+#endif
}
const AvxVideoInfo *aom_video_reader_get_info(AvxVideoReader *reader) {
diff --git a/common/webmdec.cc b/common/webmdec.cc
index b3601d4..ae96f24 100644
--- a/common/webmdec.cc
+++ b/common/webmdec.cc
@@ -56,7 +56,11 @@
void rewind_and_reset(struct WebmInputContext *const webm_ctx,
struct AvxInputContext *const aom_ctx) {
+#if CONFIG_MULTIVIEW_CORE
+ rewind(aom_ctx->file[0]);
+#else
rewind(aom_ctx->file);
+#endif
reset(webm_ctx);
}
@@ -64,7 +68,12 @@
int file_is_webm(struct WebmInputContext *webm_ctx,
struct AvxInputContext *aom_ctx) {
+#if CONFIG_MULTIVIEW_CORE
+ mkvparser::MkvReader *const reader =
+ new mkvparser::MkvReader(aom_ctx->file[0]);
+#else
mkvparser::MkvReader *const reader = new mkvparser::MkvReader(aom_ctx->file);
+#endif
webm_ctx->reader = reader;
webm_ctx->reached_eos = 0;
diff --git a/examples/scalable_decoder.c b/examples/scalable_decoder.c
index 5e95732..117fbd4 100644
--- a/examples/scalable_decoder.c
+++ b/examples/scalable_decoder.c
@@ -110,8 +110,13 @@
if (!(inputfile = fopen(argv[1], "rb")))
die("Failed to open %s for read.", argv[1]);
+#if CONFIG_MULTIVIEW_CORE
+ obu_ctx.avx_ctx->file[0] = inputfile;
+ obu_ctx.avx_ctx->filename[0] = argv[1];
+#else
obu_ctx.avx_ctx->file = inputfile;
obu_ctx.avx_ctx->filename = argv[1];
+#endif
aom_codec_iface_t *decoder = get_aom_decoder_by_index(0);
printf("Using %s\n", aom_codec_iface_name(decoder));
diff --git a/test/webm_video_source.h b/test/webm_video_source.h
index 0f4755a..1f330d2 100644
--- a/test/webm_video_source.h
+++ b/test/webm_video_source.h
@@ -32,7 +32,11 @@
frame_number_(0), end_of_file_(false) {}
virtual ~WebMVideoSource() {
+#if CONFIG_MULTIVIEW_CORE
+ if (aom_ctx_->file[0] != NULL) fclose(aom_ctx_->file[0]);
+#else
if (aom_ctx_->file != NULL) fclose(aom_ctx_->file);
+#endif
webm_free(webm_ctx_);
delete aom_ctx_;
delete webm_ctx_;
@@ -41,9 +45,15 @@
virtual void Init() {}
virtual void Begin() {
+#if CONFIG_MULTIVIEW_CORE
+ aom_ctx_->file[0] = OpenTestDataFile(file_name_);
+ ASSERT_TRUE(aom_ctx_->file[0] != NULL)
+ << "Input file open failed. Filename: " << file_name_;
+#else
aom_ctx_->file = OpenTestDataFile(file_name_);
ASSERT_TRUE(aom_ctx_->file != NULL)
<< "Input file open failed. Filename: " << file_name_;
+#endif
ASSERT_EQ(file_is_webm(webm_ctx_, aom_ctx_), 1) << "file is not WebM";
@@ -56,7 +66,11 @@
}
void FillFrame() {
+#if CONFIG_MULTIVIEW_CORE
+ ASSERT_TRUE(aom_ctx_->file[0] != NULL);
+#else
ASSERT_TRUE(aom_ctx_->file != NULL);
+#endif
const int status = webm_read_frame(webm_ctx_, &buf_, &frame_sz_, &buf_sz_);
ASSERT_GE(status, 0) << "webm_read_frame failed";
if (status == 1) {
@@ -65,7 +79,11 @@
}
void SeekToNextKeyFrame() {
+#if CONFIG_MULTIVIEW_CORE
+ ASSERT_TRUE(aom_ctx_->file[0] != NULL);
+#else
ASSERT_TRUE(aom_ctx_->file != NULL);
+#endif
do {
const int status =
webm_read_frame(webm_ctx_, &buf_, &frame_sz_, &buf_sz_);
diff --git a/tools/dump_obu.cc b/tools/dump_obu.cc
index 755e5f1..e6956bf 100644
--- a/tools/dump_obu.cc
+++ b/tools/dump_obu.cc
@@ -64,10 +64,18 @@
}
bool ReadTemporalUnit(InputContext *ctx, size_t *unit_size) {
+#if CONFIG_MULTIVIEW_CORE
+ const VideoFileType file_type = ctx->avx_ctx->file_type[0];
+#else
const VideoFileType file_type = ctx->avx_ctx->file_type;
+#endif
switch (file_type) {
case FILE_TYPE_IVF: {
+#if CONFIG_MULTIVIEW_CORE
+ if (ivf_read_frame(ctx->avx_ctx->file[0], &ctx->unit_buffer, unit_size,
+#else
if (ivf_read_frame(ctx->avx_ctx->file, &ctx->unit_buffer, unit_size,
+#endif
&ctx->unit_buffer_size, NULL)) {
return false;
}
@@ -130,8 +138,13 @@
#endif
input_ctx.Init();
+#if CONFIG_MULTIVIEW_CORE
+ avx_ctx.file[0] = input_file.get();
+ avx_ctx.file_type[0] = GetFileType(&input_ctx);
+#else
avx_ctx.file = input_file.get();
avx_ctx.file_type = GetFileType(&input_ctx);
+#endif
// Note: the reader utilities will realloc the buffer using realloc() etc.
// Can't have nice things like unique_ptr wrappers with that type of