Merge "Expand the lossless and datarate tests to cover 4:4:4."
diff --git a/test/resize_test.cc b/test/resize_test.cc
index e8c2c82..1963453 100644
--- a/test/resize_test.cc
+++ b/test/resize_test.cc
@@ -208,7 +208,7 @@
virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
if (!frame0_psnr_)
frame0_psnr_ = pkt->data.psnr.psnr[0];
- EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 1.5);
+ EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 2.0);
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
diff --git a/vp8/encoder/arm/neon/denoising_neon.c b/vp8/encoder/arm/neon/denoising_neon.c
index d517dfa..3f85397 100644
--- a/vp8/encoder/arm/neon/denoising_neon.c
+++ b/vp8/encoder/arm/neon/denoising_neon.c
@@ -119,8 +119,10 @@
v_abs_adjustment);
v_running_avg_y = vqaddq_u8(v_sig, v_pos_adjustment);
v_running_avg_y = vqsubq_u8(v_running_avg_y, v_neg_adjustment);
- v_sum_diff = vqaddq_s8(v_sum_diff, (int8x16_t)v_pos_adjustment);
- v_sum_diff = vqsubq_s8(v_sum_diff, (int8x16_t)v_neg_adjustment);
+ v_sum_diff = vqaddq_s8(v_sum_diff,
+ vreinterpretq_s8_u8(v_pos_adjustment));
+ v_sum_diff = vqsubq_s8(v_sum_diff,
+ vreinterpretq_s8_u8(v_neg_adjustment));
/* Store results. */
vst1q_u8(running_avg_y, v_running_avg_y);
diff --git a/vp9/common/vp9_alloccommon.c b/vp9/common/vp9_alloccommon.c
index ff20553..ca42090 100644
--- a/vp9/common/vp9_alloccommon.c
+++ b/vp9/common/vp9_alloccommon.c
@@ -85,7 +85,7 @@
int mi_size;
if (vp9_realloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y,
- VP9BORDERINPIXELS, NULL, NULL, NULL) < 0)
+ VP9_DEC_BORDER_IN_PIXELS, NULL, NULL, NULL) < 0)
goto fail;
set_mb_mi(cm, aligned_width, aligned_height);
@@ -154,7 +154,7 @@
for (i = 0; i < cm->fb_count; i++) {
cm->fb_idx_ref_cnt[i] = 0;
if (vp9_alloc_frame_buffer(&cm->yv12_fb[i], width, height, ss_x, ss_y,
- VP9BORDERINPIXELS) < 0)
+ VP9_ENC_BORDER_IN_PIXELS) < 0)
goto fail;
}
@@ -167,7 +167,7 @@
}
if (vp9_alloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y,
- VP9BORDERINPIXELS) < 0)
+ VP9_ENC_BORDER_IN_PIXELS) < 0)
goto fail;
set_mb_mi(cm, aligned_width, aligned_height);
diff --git a/vp9/common/vp9_entropy.h b/vp9/common/vp9_entropy.h
index f43a85f..ba162fd 100644
--- a/vp9/common/vp9_entropy.h
+++ b/vp9/common/vp9_entropy.h
@@ -112,8 +112,8 @@
// This macro is currently unused but may be used by certain implementations
#define MAXBAND_INDEX 21
-extern const uint8_t vp9_coefband_trans_8x8plus[1024];
-extern const uint8_t vp9_coefband_trans_4x4[16];
+extern DECLARE_ALIGNED(16, const uint8_t, vp9_coefband_trans_8x8plus[1024]);
+extern DECLARE_ALIGNED(16, const uint8_t, vp9_coefband_trans_4x4[16]);
static const uint8_t *get_band_translate(TX_SIZE tx_size) {
return tx_size == TX_4X4 ? vp9_coefband_trans_4x4
diff --git a/vp9/common/vp9_mvref_common.h b/vp9/common/vp9_mvref_common.h
index 06adbab..cd89390 100644
--- a/vp9/common/vp9_mvref_common.h
+++ b/vp9/common/vp9_mvref_common.h
@@ -32,8 +32,10 @@
mv_ref_list, -1, mi_row, mi_col);
}
-#define LEFT_TOP_MARGIN ((VP9BORDERINPIXELS - VP9_INTERP_EXTEND) << 3)
-#define RIGHT_BOTTOM_MARGIN ((VP9BORDERINPIXELS - VP9_INTERP_EXTEND) << 3)
+#define LEFT_TOP_MARGIN ((VP9_ENC_BORDER_IN_PIXELS \
+ - VP9_INTERP_EXTEND) << 3)
+#define RIGHT_BOTTOM_MARGIN ((VP9_ENC_BORDER_IN_PIXELS \
+ - VP9_INTERP_EXTEND) << 3)
// check a list of motion vectors by sad score using a number rows of pixels
// above and a number cols of pixels in the left to select the one with best
diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c
index 7b856d7..d66ee27 100644
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -704,7 +704,7 @@
if (vp9_realloc_frame_buffer(get_frame_new_buffer(cm),
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS, ext_fb,
+ VP9_DEC_BORDER_IN_PIXELS, ext_fb,
cm->realloc_fb_cb, cm->user_priv)) {
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate external frame buffer");
@@ -712,7 +712,7 @@
} else {
vp9_realloc_frame_buffer(get_frame_new_buffer(cm), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS, NULL, NULL, NULL);
+ VP9_DEC_BORDER_IN_PIXELS, NULL, NULL, NULL);
}
}
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 9966cb6..9d02c8f 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -500,7 +500,7 @@
if (is_inter_block(mbmi) &&
(mbmi->sb_type < BLOCK_8X8 || mbmi->mode == NEWMV)) {
int_mv best_mv[2];
- for (i = 0; i < 2; ++i)
+ for (i = 0; i < 1 + has_second_ref(mbmi); ++i)
best_mv[i].as_int = mbmi->ref_mvs[mbmi->ref_frame[i]][0].as_int;
vp9_update_mv_count(cpi, x, best_mv);
}
diff --git a/vp9/encoder/vp9_lookahead.c b/vp9/encoder/vp9_lookahead.c
index 277bd7d..ee73ff1 100644
--- a/vp9/encoder/vp9_lookahead.c
+++ b/vp9/encoder/vp9_lookahead.c
@@ -73,7 +73,7 @@
for (i = 0; i < depth; i++)
if (vp9_alloc_frame_buffer(&ctx->buf[i].img,
width, height, subsampling_x, subsampling_y,
- VP9BORDERINPIXELS))
+ VP9_ENC_BORDER_IN_PIXELS))
goto bail;
}
return ctx;
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c
index 3e1daca..27531d2 100644
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -36,6 +36,7 @@
#include "vp9/encoder/vp9_segmentation.h"
#include "vp9/encoder/vp9_temporal_filter.h"
#include "vp9/encoder/vp9_vaq.h"
+#include "vp9/encoder/vp9_resize.h"
#include "vpx_ports/vpx_timer.h"
@@ -968,7 +969,7 @@
if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
cpi->oxcf.width, cpi->oxcf.height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS, NULL, NULL, NULL))
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate altref buffer");
}
@@ -983,14 +984,14 @@
if (vp9_alloc_frame_buffer(&cpi->last_frame_uf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS))
+ VP9_ENC_BORDER_IN_PIXELS))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate last frame buffer");
if (vp9_alloc_frame_buffer(&cpi->scaled_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS))
+ VP9_ENC_BORDER_IN_PIXELS))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled source buffer");
@@ -1036,14 +1037,14 @@
if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS, NULL, NULL, NULL))
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate last frame buffer");
if (vp9_realloc_frame_buffer(&cpi->scaled_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS, NULL, NULL, NULL))
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate scaled source buffer");
@@ -2295,6 +2296,42 @@
}
#endif
+static void scale_and_extend_frame_nonnormative(YV12_BUFFER_CONFIG *src_fb,
+ YV12_BUFFER_CONFIG *dst_fb) {
+ const int in_w = src_fb->y_crop_width;
+ const int in_h = src_fb->y_crop_height;
+ const int out_w = dst_fb->y_crop_width;
+ const int out_h = dst_fb->y_crop_height;
+ const int in_w_uv = src_fb->uv_crop_width;
+ const int in_h_uv = src_fb->uv_crop_height;
+ const int out_w_uv = dst_fb->uv_crop_width;
+ const int out_h_uv = dst_fb->uv_crop_height;
+ int i;
+
+ uint8_t *srcs[4] = {src_fb->y_buffer, src_fb->u_buffer, src_fb->v_buffer,
+ src_fb->alpha_buffer};
+ int src_strides[4] = {src_fb->y_stride, src_fb->uv_stride, src_fb->uv_stride,
+ src_fb->alpha_stride};
+
+ uint8_t *dsts[4] = {dst_fb->y_buffer, dst_fb->u_buffer, dst_fb->v_buffer,
+ dst_fb->alpha_buffer};
+ int dst_strides[4] = {dst_fb->y_stride, dst_fb->uv_stride, dst_fb->uv_stride,
+ dst_fb->alpha_stride};
+
+ for (i = 0; i < MAX_MB_PLANE; ++i) {
+ if (i == 0 || i == 3) {
+ // Y and alpha planes
+ vp9_resize_plane(srcs[i], in_h, in_w, src_strides[i],
+ dsts[i], out_h, out_w, dst_strides[i]);
+ } else {
+ // Chroma planes
+ vp9_resize_plane(srcs[i], in_h_uv, in_w_uv, src_strides[i],
+ dsts[i], out_h_uv, out_w_uv, dst_strides[i]);
+ }
+ }
+ vp8_yv12_extend_frame_borders(dst_fb);
+}
+
static void scale_and_extend_frame(YV12_BUFFER_CONFIG *src_fb,
YV12_BUFFER_CONFIG *dst_fb) {
const int in_w = src_fb->y_crop_width;
@@ -2316,7 +2353,7 @@
for (y = 0; y < out_h; y += 16) {
for (x = 0; x < out_w; x += 16) {
for (i = 0; i < MAX_MB_PLANE; ++i) {
- const int factor = i == 0 ? 1 : 2;
+ const int factor = (i == 0 || i == 3 ? 1 : 2);
const int x_q4 = x * (16 / factor) * in_w / out_w;
const int y_q4 = y * (16 / factor) * in_h / out_h;
const int src_stride = src_strides[i];
@@ -2552,7 +2589,7 @@
vp9_realloc_frame_buffer(&cm->yv12_fb[new_fb],
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS, NULL, NULL, NULL);
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
scale_and_extend_frame(ref, &cm->yv12_fb[new_fb]);
cpi->scaled_ref_idx[ref_frame - 1] = new_fb;
} else {
@@ -2924,7 +2961,8 @@
/* Scale the source buffer, if required. */
if (cm->mi_cols * 8 != cpi->un_scaled_source->y_width ||
cm->mi_rows * 8 != cpi->un_scaled_source->y_height) {
- scale_and_extend_frame(cpi->un_scaled_source, &cpi->scaled_source);
+ scale_and_extend_frame_nonnormative(cpi->un_scaled_source,
+ &cpi->scaled_source);
cpi->Source = &cpi->scaled_source;
} else {
cpi->Source = cpi->un_scaled_source;
@@ -3379,7 +3417,6 @@
struct vpx_usec_timer cmptimer;
YV12_BUFFER_CONFIG *force_src_buffer = NULL;
MV_REFERENCE_FRAME ref_frame;
- // FILE *fp_out = fopen("enc_frame_type.txt", "a");
if (!cpi)
return -1;
@@ -3501,8 +3538,6 @@
vp9_end_first_pass(cpi); /* get last stats packet */
cpi->twopass.first_pass_done = 1;
}
-
- // fclose(fp_out);
return -1;
}
@@ -3545,7 +3580,7 @@
vp9_realloc_frame_buffer(get_frame_new_buffer(cm),
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
- VP9BORDERINPIXELS, NULL, NULL, NULL);
+ VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
@@ -3671,7 +3706,6 @@
}
#endif
- // fclose(fp_out);
return 0;
}
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 3c1bd39..242aa87 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -233,8 +233,8 @@
const int q = compute_rd_thresh_factor(qindex);
for (bsize = 0; bsize < BLOCK_SIZES; ++bsize) {
- // Threshold here seem unecessarily harsh but fine given actual
- // range of values used for cpi->sf.thresh_mult[]
+ // Threshold here seems unnecessarily harsh but fine given actual
+ // range of values used for cpi->sf.thresh_mult[].
const int t = q * rd_thresh_block_size_factor[bsize];
const int thresh_max = INT_MAX / t;
diff --git a/vp9/encoder/vp9_resize.c b/vp9/encoder/vp9_resize.c
new file mode 100644
index 0000000..b4eba63
--- /dev/null
+++ b/vp9/encoder/vp9_resize.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2014 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vp9/common/vp9_common.h"
+#include "vp9/encoder/vp9_resize.h"
+
+#define FILTER_BITS 7
+
+#define INTERP_TAPS 8
+#define SUBPEL_BITS 5
+#define SUBPEL_MASK ((1 << SUBPEL_BITS) - 1)
+#define INTERP_PRECISION_BITS 32
+
+#define ROUND_POWER_OF_TWO(value, n) \
+ (((value) + (1 << ((n) - 1))) >> (n))
+
+typedef int16_t interp_kernel[INTERP_TAPS];
+
+// Filters for interpolation - note this also filters integer pels.
+const interp_kernel vp9_filteredinterp_filters[(1 << SUBPEL_BITS)] = {
+ {-1, -8, 33, 80, 33, -8, -1, 0},
+ {-1, -8, 30, 80, 35, -8, -1, 1},
+ {-1, -8, 28, 80, 37, -7, -2, 1},
+ {0, -8, 26, 79, 39, -7, -2, 1},
+ {0, -8, 24, 79, 41, -7, -2, 1},
+ {0, -8, 22, 78, 43, -6, -2, 1},
+ {0, -8, 20, 78, 45, -5, -3, 1},
+ {0, -8, 18, 77, 48, -5, -3, 1},
+ {0, -8, 16, 76, 50, -4, -3, 1},
+ {0, -8, 15, 75, 52, -3, -4, 1},
+ {0, -7, 13, 74, 54, -3, -4, 1},
+ {0, -7, 11, 73, 56, -2, -4, 1},
+ {0, -7, 10, 71, 58, -1, -4, 1},
+ {1, -7, 8, 70, 60, 0, -5, 1},
+ {1, -6, 6, 68, 62, 1, -5, 1},
+ {1, -6, 5, 67, 63, 2, -5, 1},
+ {1, -6, 4, 65, 65, 4, -6, 1},
+ {1, -5, 2, 63, 67, 5, -6, 1},
+ {1, -5, 1, 62, 68, 6, -6, 1},
+ {1, -5, 0, 60, 70, 8, -7, 1},
+ {1, -4, -1, 58, 71, 10, -7, 0},
+ {1, -4, -2, 56, 73, 11, -7, 0},
+ {1, -4, -3, 54, 74, 13, -7, 0},
+ {1, -4, -3, 52, 75, 15, -8, 0},
+ {1, -3, -4, 50, 76, 16, -8, 0},
+ {1, -3, -5, 48, 77, 18, -8, 0},
+ {1, -3, -5, 45, 78, 20, -8, 0},
+ {1, -2, -6, 43, 78, 22, -8, 0},
+ {1, -2, -7, 41, 79, 24, -8, 0},
+ {1, -2, -7, 39, 79, 26, -8, 0},
+ {1, -2, -7, 37, 80, 28, -8, -1},
+ {1, -1, -8, 35, 80, 30, -8, -1},
+};
+
+// Filters for factor of 2 downsampling.
+static const int16_t vp9_down2_symeven_half_filter[] = {56, 12, -3, -1};
+static const int16_t vp9_down2_symodd_half_filter[] = {64, 35, 0, -3};
+
+static void interpolate(const uint8_t *const input, int inlength,
+ uint8_t *output, int outlength) {
+ const int64_t delta = (((uint64_t)inlength << 32) + outlength / 2) /
+ outlength;
+ const int64_t offset = inlength > outlength ?
+ (((int64_t)(inlength - outlength) << 31) + outlength / 2) / outlength :
+ -(((int64_t)(outlength - inlength) << 31) + outlength / 2) / outlength;
+ uint8_t *optr = output;
+ int x, x1, x2, sum, k, int_pel, sub_pel;
+ int64_t y;
+
+ x = 0;
+ y = offset;
+ while ((y >> INTERP_PRECISION_BITS) < (INTERP_TAPS / 2 - 1)) {
+ x++;
+ y += delta;
+ }
+ x1 = x;
+ x = outlength - 1;
+ y = delta * x + offset;
+ while ((y >> INTERP_PRECISION_BITS) +
+ (int64_t)(INTERP_TAPS / 2) >= inlength) {
+ x--;
+ y -= delta;
+ }
+ x2 = x;
+ if (x1 > x2) {
+ for (x = 0, y = offset; x < outlength; ++x, y += delta) {
+ const int16_t *filter;
+ int_pel = y >> INTERP_PRECISION_BITS;
+ sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
+ filter = vp9_filteredinterp_filters[sub_pel];
+ sum = 0;
+ for (k = 0; k < INTERP_TAPS; ++k) {
+ const int pk = int_pel - INTERP_TAPS / 2 + 1 + k;
+ sum += filter[k] * input[(pk < 0 ? 0 :
+ (pk >= inlength ? inlength - 1 : pk))];
+ }
+ *optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
+ }
+ } else {
+ // Initial part.
+ for (x = 0, y = offset; x < x1; ++x, y += delta) {
+ const int16_t *filter;
+ int_pel = y >> INTERP_PRECISION_BITS;
+ sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
+ filter = vp9_filteredinterp_filters[sub_pel];
+ sum = 0;
+ for (k = 0; k < INTERP_TAPS; ++k)
+ sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k < 0 ?
+ 0 :
+ int_pel - INTERP_TAPS / 2 + 1 + k)];
+ *optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
+ }
+ // Middle part.
+ for (; x <= x2; ++x, y += delta) {
+ const int16_t *filter;
+ int_pel = y >> INTERP_PRECISION_BITS;
+ sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
+ filter = vp9_filteredinterp_filters[sub_pel];
+ sum = 0;
+ for (k = 0; k < INTERP_TAPS; ++k)
+ sum += filter[k] * input[int_pel - INTERP_TAPS / 2 + 1 + k];
+ *optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
+ }
+ // End part.
+ for (; x < outlength; ++x, y += delta) {
+ const int16_t *filter;
+ int_pel = y >> INTERP_PRECISION_BITS;
+ sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
+ filter = vp9_filteredinterp_filters[sub_pel];
+ sum = 0;
+ for (k = 0; k < INTERP_TAPS; ++k)
+ sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k >=
+ inlength ? inlength - 1 :
+ int_pel - INTERP_TAPS / 2 + 1 + k)];
+ *optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
+ }
+ }
+}
+
+static void down2_symeven(const uint8_t *const input, int length,
+ uint8_t *output) {
+ // Actual filter len = 2 * filter_len_half.
+ static const int16_t *filter = vp9_down2_symeven_half_filter;
+ const int filter_len_half = sizeof(vp9_down2_symeven_half_filter) / 2;
+ int i, j;
+ uint8_t *optr = output;
+ int l1 = filter_len_half;
+ int l2 = (length - filter_len_half);
+ l1 += (l1 & 1);
+ l2 += (l2 & 1);
+ if (l1 > l2) {
+ // Short input length.
+ for (i = 0; i < length; i += 2) {
+ int sum = (1 << (FILTER_BITS - 1));
+ for (j = 0; j < filter_len_half; ++j) {
+ sum += (input[(i - j < 0 ? 0 : i - j)] +
+ input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
+ filter[j];
+ }
+ sum >>= FILTER_BITS;
+ *optr++ = clip_pixel(sum);
+ }
+ } else {
+ // Initial part.
+ for (i = 0; i < l1; i += 2) {
+ int sum = (1 << (FILTER_BITS - 1));
+ for (j = 0; j < filter_len_half; ++j) {
+ sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + 1 + j]) * filter[j];
+ }
+ sum >>= FILTER_BITS;
+ *optr++ = clip_pixel(sum);
+ }
+ // Middle part.
+ for (; i < l2; i += 2) {
+ int sum = (1 << (FILTER_BITS - 1));
+ for (j = 0; j < filter_len_half; ++j) {
+ sum += (input[i - j] + input[i + 1 + j]) * filter[j];
+ }
+ sum >>= FILTER_BITS;
+ *optr++ = clip_pixel(sum);
+ }
+ // End part.
+ for (; i < length; i += 2) {
+ int sum = (1 << (FILTER_BITS - 1));
+ for (j = 0; j < filter_len_half; ++j) {
+ sum += (input[i - j] +
+ input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
+ filter[j];
+ }
+ sum >>= FILTER_BITS;
+ *optr++ = clip_pixel(sum);
+ }
+ }
+}
+
+static void down2_symodd(const uint8_t *const input, int length,
+ uint8_t *output) {
+ // Actual filter len = 2 * filter_len_half - 1.
+ static const int16_t *filter = vp9_down2_symodd_half_filter;
+ const int filter_len_half = sizeof(vp9_down2_symodd_half_filter) / 2;
+ int i, j;
+ uint8_t *optr = output;
+ int l1 = filter_len_half - 1;
+ int l2 = (length - filter_len_half + 1);
+ l1 += (l1 & 1);
+ l2 += (l2 & 1);
+ if (l1 > l2) {
+ // Short input length.
+ for (i = 0; i < length; i += 2) {
+ int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
+ for (j = 1; j < filter_len_half; ++j) {
+ sum += (input[(i - j < 0 ? 0 : i - j)] +
+ input[(i + j >= length ? length - 1 : i + j)]) *
+ filter[j];
+ }
+ sum >>= FILTER_BITS;
+ *optr++ = clip_pixel(sum);
+ }
+ } else {
+ // Initial part.
+ for (i = 0; i < l1; i += 2) {
+ int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
+ for (j = 1; j < filter_len_half; ++j) {
+ sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + j]) * filter[j];
+ }
+ sum >>= FILTER_BITS;
+ *optr++ = clip_pixel(sum);
+ }
+ // Middle part.
+ for (; i < l2; i += 2) {
+ int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
+ for (j = 1; j < filter_len_half; ++j) {
+ sum += (input[i - j] + input[i + j]) * filter[j];
+ }
+ sum >>= FILTER_BITS;
+ *optr++ = clip_pixel(sum);
+ }
+ // End part.
+ for (; i < length; i += 2) {
+ int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
+ for (j = 1; j < filter_len_half; ++j) {
+ sum += (input[i - j] + input[(i + j >= length ? length - 1 : i + j)]) *
+ filter[j];
+ }
+ sum >>= FILTER_BITS;
+ *optr++ = clip_pixel(sum);
+ }
+ }
+}
+
+static int get_down2_length(int length, int steps) {
+ int s;
+ for (s = 0; s < steps; ++s)
+ length = (length + 1) >> 1;
+ return length;
+}
+
+int get_down2_steps(int in_length, int out_length) {
+ int steps = 0;
+ int proj_in_length;
+ while ((proj_in_length = get_down2_length(in_length, 1)) >= out_length) {
+ ++steps;
+ in_length = proj_in_length;
+ }
+ return steps;
+}
+
+static void resize_multistep(const uint8_t *const input,
+ int length,
+ uint8_t *output,
+ int olength,
+ uint8_t *buf) {
+ int steps;
+ if (length == olength) {
+ memcpy(output, input, sizeof(uint8_t) * length);
+ return;
+ }
+ steps = get_down2_steps(length, olength);
+
+ if (steps > 0) {
+ int s;
+ uint8_t *out = NULL;
+ uint8_t *tmpbuf = NULL;
+ uint8_t *otmp, *otmp2;
+ int filteredlength = length;
+ if (!tmpbuf) {
+ tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) * length);
+ otmp = tmpbuf;
+ } else {
+ otmp = buf;
+ }
+ otmp2 = otmp + get_down2_length(length, 1);
+ for (s = 0; s < steps; ++s) {
+ const int proj_filteredlength = get_down2_length(filteredlength, 1);
+ const uint8_t *const in = (s == 0 ? input : out);
+ if (s == steps - 1 && proj_filteredlength == olength)
+ out = output;
+ else
+ out = (s & 1 ? otmp2 : otmp);
+ if (filteredlength & 1)
+ down2_symodd(in, filteredlength, out);
+ else
+ down2_symeven(in, filteredlength, out);
+ filteredlength = proj_filteredlength;
+ }
+ if (filteredlength != olength) {
+ interpolate(out, filteredlength, output, olength);
+ }
+ if (tmpbuf)
+ free(tmpbuf);
+ } else {
+ interpolate(input, length, output, olength);
+ }
+}
+
+static void fill_col_to_arr(uint8_t *img, int stride, int len, uint8_t *arr) {
+ int i;
+ uint8_t *iptr = img;
+ uint8_t *aptr = arr;
+ for (i = 0; i < len; ++i, iptr += stride) {
+ *aptr++ = *iptr;
+ }
+}
+
+static void fill_arr_to_col(uint8_t *img, int stride, int len, uint8_t *arr) {
+ int i;
+ uint8_t *iptr = img;
+ uint8_t *aptr = arr;
+ for (i = 0; i < len; ++i, iptr += stride) {
+ *iptr = *aptr++;
+ }
+}
+
+void vp9_resize_plane(const uint8_t *const input,
+ int height,
+ int width,
+ int in_stride,
+ uint8_t *output,
+ int height2,
+ int width2,
+ int out_stride) {
+ int i;
+ uint8_t *intbuf = (uint8_t *)malloc(sizeof(uint8_t) * width2 * height);
+ uint8_t *tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) *
+ (width < height ? height : width));
+ uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * (height + height2));
+ for (i = 0; i < height; ++i)
+ resize_multistep(input + in_stride * i, width,
+ intbuf + width2 * i, width2, tmpbuf);
+ for (i = 0; i < width2; ++i) {
+ fill_col_to_arr(intbuf + i, width2, height, arrbuf);
+ resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf);
+ fill_arr_to_col(output + i, out_stride, height2, arrbuf + height);
+ }
+ free(intbuf);
+ free(tmpbuf);
+ free(arrbuf);
+}
+
+void vp9_resize_frame420(const uint8_t *const y,
+ int y_stride,
+ const uint8_t *const u, const uint8_t *const v,
+ int uv_stride,
+ int height, int width,
+ uint8_t *oy, int oy_stride,
+ uint8_t *ou, uint8_t *ov, int ouv_stride,
+ int oheight, int owidth) {
+ vp9_resize_plane(y, height, width, y_stride,
+ oy, oheight, owidth, oy_stride);
+ vp9_resize_plane(u, height / 2, width / 2, uv_stride,
+ ou, oheight / 2, owidth / 2, ouv_stride);
+ vp9_resize_plane(v, height / 2, width / 2, uv_stride,
+ ov, oheight / 2, owidth / 2, ouv_stride);
+}
+
+void vp9_resize_frame422(const uint8_t *const y, int y_stride,
+ const uint8_t *const u, const uint8_t *const v,
+ int uv_stride,
+ int height, int width,
+ uint8_t *oy, int oy_stride,
+ uint8_t *ou, uint8_t *ov, int ouv_stride,
+ int oheight, int owidth) {
+ vp9_resize_plane(y, height, width, y_stride,
+ oy, oheight, owidth, oy_stride);
+ vp9_resize_plane(u, height, width / 2, uv_stride,
+ ou, oheight, owidth / 2, ouv_stride);
+ vp9_resize_plane(v, height, width / 2, uv_stride,
+ ov, oheight, owidth / 2, ouv_stride);
+}
+
+void vp9_resize_frame444(const uint8_t *const y, int y_stride,
+ const uint8_t *const u, const uint8_t *const v,
+ int uv_stride,
+ int height, int width,
+ uint8_t *oy, int oy_stride,
+ uint8_t *ou, uint8_t *ov, int ouv_stride,
+ int oheight, int owidth) {
+ vp9_resize_plane(y, height, width, y_stride,
+ oy, oheight, owidth, oy_stride);
+ vp9_resize_plane(u, height, width, uv_stride,
+ ou, oheight, owidth, ouv_stride);
+ vp9_resize_plane(v, height, width, uv_stride,
+ ov, oheight, owidth, ouv_stride);
+}
diff --git a/vp9/encoder/vp9_resize.h b/vp9/encoder/vp9_resize.h
new file mode 100644
index 0000000..c67595a
--- /dev/null
+++ b/vp9/encoder/vp9_resize.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef VP9_ENCODER_VP9_RESIZE_H_
+#define VP9_ENCODER_VP9_RESIZE_H_
+
+#include <stdio.h>
+
+void vp9_resize_plane(const uint8_t *const input,
+ int height,
+ int width,
+ int in_stride,
+ uint8_t *output,
+ int height2,
+ int width2,
+ int out_stride);
+void vp9_resize_frame420(const uint8_t *const y,
+ int y_stride,
+ const uint8_t *const u,
+ const uint8_t *const v,
+ int uv_stride,
+ int height,
+ int width,
+ uint8_t *oy,
+ int oy_stride,
+ uint8_t *ou,
+ uint8_t *ov,
+ int ouv_stride,
+ int oheight,
+ int owidth);
+void vp9_resize_frame422(const uint8_t *const y,
+ int y_stride,
+ const uint8_t *const u,
+ const uint8_t *const v,
+ int uv_stride,
+ int height,
+ int width,
+ uint8_t *oy,
+ int oy_stride,
+ uint8_t *ou,
+ uint8_t *ov,
+ int ouv_stride,
+ int oheight,
+ int owidth);
+void vp9_resize_frame444(const uint8_t *const y,
+ int y_stride,
+ const uint8_t *const u,
+ const uint8_t *const v,
+ int uv_stride,
+ int height,
+ int width,
+ uint8_t *oy,
+ int oy_stride,
+ uint8_t *ou,
+ uint8_t *ov,
+ int ouv_stride,
+ int oheight,
+ int owidth);
+
+#endif // VP9_ENCODER_VP9_RESIZE_H_
diff --git a/vp9/encoder/vp9_temporal_filter.c b/vp9/encoder/vp9_temporal_filter.c
index 8762192..c2eea0a 100644
--- a/vp9/encoder/vp9_temporal_filter.c
+++ b/vp9/encoder/vp9_temporal_filter.c
@@ -227,7 +227,7 @@
for (mb_row = 0; mb_row < mb_rows; mb_row++) {
#if ALT_REF_MC_ENABLED
// Source frames are extended to 16 pixels. This is different than
- // L/A/G reference frames that have a border of 32 (VP9BORDERINPIXELS)
+ // L/A/G reference frames that have a border of 32 (VP9ENCBORDERINPIXELS)
// A 6/8 tap filter is used for motion search. This requires 2 pixels
// before and 3 pixels after. So the largest Y mv on a border would
// then be 16 - VP9_INTERP_EXTEND. The UV blocks are half the size of the
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index 5c14b2e..897ecd7 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -513,10 +513,8 @@
priv->vp8_cfg = extracfg_map[i].cfg;
priv->vp8_cfg.pkt_list = &priv->pkt_list.head;
- // TODO(agrange) Check the limits set on this buffer, or the check that is
- // applied in vp9e_encode.
+ // Maximum buffer size approximated based on having multiple ARF.
priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 8;
-// priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 2;
if (priv->cx_data_sz < 4096) priv->cx_data_sz = 4096;
@@ -692,7 +690,7 @@
}
}
- /* Initialize the encoder instance on the first frame*/
+ /* Initialize the encoder instance on the first frame. */
if (!res && ctx->cpi) {
unsigned int lib_flags;
YV12_BUFFER_CONFIG sd;
@@ -704,9 +702,6 @@
if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
((VP9_COMP *)ctx->cpi)->b_calculate_psnr = 1;
- // if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION)
- // ((VP9_COMP *)ctx->cpi)->output_partition = 1;
-
/* Convert API flags to internal codec lib flags */
lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
diff --git a/vp9/vp9_iface_common.h b/vp9/vp9_iface_common.h
index ed0122c..58256b2 100644
--- a/vp9/vp9_iface_common.h
+++ b/vp9/vp9_iface_common.h
@@ -29,7 +29,7 @@
img->fmt = VPX_IMG_FMT_I420;
}
img->w = yv12->y_stride;
- img->h = ALIGN_POWER_OF_TWO(yv12->y_height + 2 * VP9BORDERINPIXELS, 3);
+ img->h = ALIGN_POWER_OF_TWO(yv12->y_height + 2 * VP9_ENC_BORDER_IN_PIXELS, 3);
img->d_w = yv12->y_crop_width;
img->d_h = yv12->y_crop_height;
img->x_chroma_shift = yv12->uv_width < yv12->y_width;
@@ -75,7 +75,7 @@
yv12->border = (img->stride[VPX_PLANE_Y] - img->w) / 2;
#if CONFIG_ALPHA
- // For development purposes, force alpha to hold the same data a Y for now.
+ // For development purposes, force alpha to hold the same data as Y for now.
yv12->alpha_buffer = yv12->y_buffer;
yv12->alpha_width = yv12->y_width;
yv12->alpha_height = yv12->y_height;
diff --git a/vp9/vp9cx.mk b/vp9/vp9cx.mk
index dd33099..63003b9 100644
--- a/vp9/vp9cx.mk
+++ b/vp9/vp9cx.mk
@@ -61,6 +61,8 @@
VP9_CX_SRCS-yes += encoder/vp9_segmentation.h
VP9_CX_SRCS-yes += encoder/vp9_subexp.c
VP9_CX_SRCS-yes += encoder/vp9_subexp.h
+VP9_CX_SRCS-yes += encoder/vp9_resize.c
+VP9_CX_SRCS-yes += encoder/vp9_resize.h
VP9_CX_SRCS-$(CONFIG_INTERNAL_STATS) += encoder/vp9_ssim.c
VP9_CX_SRCS-yes += encoder/vp9_tokenize.c
VP9_CX_SRCS-yes += encoder/vp9_treewriter.c
diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h
index bf5fc07..610e7d2 100644
--- a/vpx_scale/yv12config.h
+++ b/vpx_scale/yv12config.h
@@ -18,10 +18,11 @@
#include "vpx/vpx_external_frame_buffer.h"
#include "vpx/vpx_integer.h"
-#define VP8BORDERINPIXELS 32
-#define VP9INNERBORDERINPIXELS 96
-#define VP9BORDERINPIXELS 160
-#define VP9_INTERP_EXTEND 4
+#define VP8BORDERINPIXELS 32
+#define VP9INNERBORDERINPIXELS 96
+#define VP9_INTERP_EXTEND 4
+#define VP9_ENC_BORDER_IN_PIXELS 160
+#define VP9_DEC_BORDER_IN_PIXELS 32
typedef struct yv12_buffer_config {
int y_width;
diff --git a/vpxdec.c b/vpxdec.c
index c067609..fc344a1 100644
--- a/vpxdec.c
+++ b/vpxdec.c
@@ -245,25 +245,6 @@
}
}
-void *out_open(const char *out_fn, int do_md5) {
- void *out = NULL;
-
- if (do_md5) {
- MD5Context *md5_ctx = out = malloc(sizeof(MD5Context));
- (void)out_fn;
- MD5Init(md5_ctx);
- } else {
- FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb")
- : set_binary_mode(stdout);
-
- if (!outfile) {
- fatal("Failed to output file");
- }
- }
-
- return out;
-}
-
static int get_image_plane_width(int plane, const vpx_image_t *img) {
return (plane > 0 && img->x_chroma_shift > 0) ?
(img->d_w + 1) >> img->x_chroma_shift :
@@ -312,23 +293,6 @@
}
}
-void out_close(void *out, const char *out_fn, int do_md5) {
- if (do_md5) {
- uint8_t md5[16];
- int i;
-
- MD5Final(md5, out);
- free(out);
-
- for (i = 0; i < 16; i++)
- printf("%02x", md5[i]);
-
- printf(" %s\n", out_fn);
- } else {
- fclose(out);
- }
-}
-
int file_is_raw(struct VpxInputContext *input) {
uint8_t buf[32];
int is_raw = 0;
@@ -469,6 +433,40 @@
} while (*p);
}
+static int is_single_file(const char *outfile_pattern) {
+ const char *p = outfile_pattern;
+
+ do {
+ p = strchr(p, '%');
+ if (p && p[1] >= '1' && p[1] <= '9')
+ return 0; // pattern contains sequence number, so it's not unique
+ if (p)
+ p++;
+ } while (p);
+
+ return 1;
+}
+
+static void print_md5(unsigned char digest[16], const char *filename) {
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ printf("%02x", digest[i]);
+ printf(" %s\n", filename);
+}
+
+static FILE *open_outfile(const char *name) {
+ if (strcmp("-", name) == 0) {
+ set_binary_mode(stdout);
+ return stdout;
+ } else {
+ FILE *file = fopen(name, "wb");
+ if (!file)
+ fatal("Failed to output file %s", name);
+ return file;
+ }
+}
+
int main_loop(int argc, const char **argv_) {
vpx_codec_ctx_t decoder;
char *fn = NULL;
@@ -485,11 +483,9 @@
unsigned long dx_time = 0;
struct arg arg;
char **argv, **argi, **argj;
- const char *outfile_pattern = 0;
- char outfile[PATH_MAX];
+
int single_file;
int use_y4m = 1;
- void *out = NULL;
vpx_codec_dec_cfg_t cfg = {0};
#if CONFIG_VP8_DECODER
vp8_postproc_cfg_t vp8_pp_cfg = {0};
@@ -507,6 +503,13 @@
int fb_lru_cache = 0;
vpx_codec_frame_buffer_t *frame_buffers = NULL;
+ const char *outfile_pattern = NULL;
+ char outfile_name[PATH_MAX] = {0};
+ FILE *outfile = NULL;
+
+ MD5Context md5_ctx;
+ unsigned char md5_digest[16];
+
struct VpxDecInputContext input = {0};
struct VpxInputContext vpx_input_ctx = {0};
struct WebmInputContext webm_ctx = {0};
@@ -641,8 +644,7 @@
infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);
if (!infile) {
- fprintf(stderr, "Failed to open file '%s'",
- strcmp(fn, "-") ? fn : "stdin");
+ fprintf(stderr, "Failed to open file '%s'", strcmp(fn, "-") ? fn : "stdin");
return EXIT_FAILURE;
}
#if CONFIG_OS_SUPPORT
@@ -666,29 +668,16 @@
return EXIT_FAILURE;
}
- /* If the output file is not set or doesn't have a sequence number in
- * it, then we only open it once.
- */
outfile_pattern = outfile_pattern ? outfile_pattern : "-";
- single_file = 1;
- {
- const char *p = outfile_pattern;
- do {
- p = strchr(p, '%');
- if (p && p[1] >= '1' && p[1] <= '9') {
- /* pattern contains sequence number, so it's not unique. */
- single_file = 0;
- break;
- }
- if (p)
- p++;
- } while (p);
- }
+ single_file = is_single_file(outfile_pattern);
- if (single_file && !noblit) {
- generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1,
+ if (!noblit && single_file) {
+ generate_filename(outfile_pattern, outfile_name, PATH_MAX,
vpx_input_ctx.width, vpx_input_ctx.height, 0);
- out = out_open(outfile, do_md5);
+ if (do_md5)
+ MD5Init(&md5_ctx);
+ else
+ outfile = open_outfile(outfile_name);
}
if (use_y4m && !noblit) {
@@ -851,17 +840,18 @@
show_progress(frame_in, frame_out, dx_time);
if (!noblit) {
- if (frame_out == 1 && img && use_y4m) {
- y4m_write_file_header(out, vpx_input_ctx.width, vpx_input_ctx.height,
+ if (frame_out == 1 && img && single_file && !do_md5 && use_y4m)
+ y4m_write_file_header(outfile,
+ vpx_input_ctx.width, vpx_input_ctx.height,
&vpx_input_ctx.framerate, img->fmt);
- }
if (img && do_scale) {
if (frame_out == 1) {
// If the output frames are to be scaled to a fixed display size then
// use the width and height specified in the container. If either of
// these is set to 0, use the display size set in the first frame
- // header.
+ // header. If that is unavailable, use the raw decoded size of the
+ // first decoded frame.
int display_width = vpx_input_ctx.width;
int display_height = vpx_input_ctx.height;
if (!display_width || !display_height) {
@@ -891,24 +881,29 @@
const int PLANES_YVU[] = {VPX_PLANE_Y, VPX_PLANE_V, VPX_PLANE_U};
const int *planes = flipuv ? PLANES_YVU : PLANES_YUV;
- char out_fn[PATH_MAX];
if (!single_file) {
- generate_filename(outfile_pattern, out_fn, PATH_MAX,
+ generate_filename(outfile_pattern, outfile_name, PATH_MAX,
img->d_w, img->d_h, frame_in);
- out = out_open(out_fn, do_md5);
+ if (do_md5) {
+ MD5Init(&md5_ctx);
+ update_image_md5(img, planes, &md5_ctx);
+ MD5Final(md5_digest, &md5_ctx);
+ print_md5(md5_digest, outfile_name);
+ } else {
+ outfile = open_outfile(outfile_name);
+ write_image_file(img, planes, outfile);
+ fclose(outfile);
+ }
} else {
- if (use_y4m)
- y4m_write_frame_header(out);
+ if (do_md5) {
+ update_image_md5(img, planes, &md5_ctx);
+ } else {
+ if (use_y4m)
+ y4m_write_frame_header(outfile);
+ write_image_file(img, planes, outfile);
+ }
}
-
- if (do_md5)
- update_image_md5(img, planes, out);
- else
- write_image_file(img, planes, out);
-
- if (!single_file)
- out_close(out, out_fn, do_md5);
}
}
@@ -932,8 +927,14 @@
return EXIT_FAILURE;
}
- if (single_file && !noblit)
- out_close(out, outfile, do_md5);
+ if (!noblit && single_file) {
+ if (do_md5) {
+ MD5Final(md5_digest, &md5_ctx);
+ print_md5(md5_digest, outfile_name);
+ } else {
+ fclose(outfile);
+ }
+ }
if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM)
webm_free(input.webm_ctx);