summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild/make/gen_msvs_proj.sh8
-rwxr-xr-xbuild/make/gen_msvs_vcxproj.sh8
-rw-r--r--examples/twopass_encoder.c201
-rw-r--r--test/datarate_test.cc40
-rw-r--r--test/svc_test.cc182
-rwxr-xr-xtest/vpxenc.sh164
-rw-r--r--vp8/encoder/denoising.c1
-rw-r--r--vp9/common/vp9_mv.h8
-rw-r--r--vp9/encoder/vp9_bitstream.c11
-rw-r--r--vp9/encoder/vp9_encodeframe.c31
-rw-r--r--vp9/encoder/vp9_encoder.c97
-rw-r--r--vp9/encoder/vp9_encoder.h7
-rw-r--r--vp9/encoder/vp9_firstpass.c71
-rw-r--r--vp9/encoder/vp9_firstpass.h2
-rw-r--r--vp9/encoder/vp9_rd.c4
-rw-r--r--vp9/encoder/vp9_rdopt.c9
-rw-r--r--vp9/encoder/vp9_speed_features.c35
-rw-r--r--vp9/encoder/vp9_svc_layercontext.c1
-rw-r--r--vp9/encoder/vp9_svc_layercontext.h1
-rw-r--r--vp9/vp9_cx_iface.c16
-rw-r--r--vpx/src/svc_encodeframe.c11
-rw-r--r--vpx/src/vpx_decoder.c2
-rw-r--r--vpx/src/vpx_encoder.c2
-rw-r--r--vpx/vpx_codec.h8
-rw-r--r--vpx/vpx_decoder.h2
-rw-r--r--vpx/vpx_encoder.h2
-rw-r--r--vpxdec.c2
27 files changed, 599 insertions, 327 deletions
diff --git a/build/make/gen_msvs_proj.sh b/build/make/gen_msvs_proj.sh
index 3653309ed..790722593 100755
--- a/build/make/gen_msvs_proj.sh
+++ b/build/make/gen_msvs_proj.sh
@@ -245,13 +245,13 @@ esac
case "$target" in
x86_64*)
platforms[0]="x64"
- asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "\$(InputPath)""
- asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "\$(InputPath)""
+ asm_Debug_cmdline="yasm -Xvc -g cv8 -f win64 ${yasmincs} "\$(InputPath)""
+ asm_Release_cmdline="yasm -Xvc -f win64 ${yasmincs} "\$(InputPath)""
;;
x86*)
platforms[0]="Win32"
- asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "\$(InputPath)""
- asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "\$(InputPath)""
+ asm_Debug_cmdline="yasm -Xvc -g cv8 -f win32 ${yasmincs} "\$(InputPath)""
+ asm_Release_cmdline="yasm -Xvc -f win32 ${yasmincs} "\$(InputPath)""
;;
*) die "Unsupported target $target!"
;;
diff --git a/build/make/gen_msvs_vcxproj.sh b/build/make/gen_msvs_vcxproj.sh
index 23ef6a320..56b9a3b50 100755
--- a/build/make/gen_msvs_vcxproj.sh
+++ b/build/make/gen_msvs_vcxproj.sh
@@ -253,13 +253,13 @@ libs=${libs// /;}
case "$target" in
x86_64*)
platforms[0]="x64"
- asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "%(FullPath)""
- asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "%(FullPath)""
+ asm_Debug_cmdline="yasm -Xvc -g cv8 -f win64 ${yasmincs} "%(FullPath)""
+ asm_Release_cmdline="yasm -Xvc -f win64 ${yasmincs} "%(FullPath)""
;;
x86*)
platforms[0]="Win32"
- asm_Debug_cmdline="yasm -Xvc -g cv8 -f \$(PlatformName) ${yasmincs} "%(FullPath)""
- asm_Release_cmdline="yasm -Xvc -f \$(PlatformName) ${yasmincs} "%(FullPath)""
+ asm_Debug_cmdline="yasm -Xvc -g cv8 -f win32 ${yasmincs} "%(FullPath)""
+ asm_Release_cmdline="yasm -Xvc -f win32 ${yasmincs} "%(FullPath)""
;;
arm*)
asm_Debug_cmdline="armasm -nologo "%(FullPath)""
diff --git a/examples/twopass_encoder.c b/examples/twopass_encoder.c
index 369b1d890..76d5a2816 100644
--- a/examples/twopass_encoder.c
+++ b/examples/twopass_encoder.c
@@ -66,13 +66,14 @@ void usage_exit() {
exit(EXIT_FAILURE);
}
-static void get_frame_stats(vpx_codec_ctx_t *ctx,
- const vpx_image_t *img,
- vpx_codec_pts_t pts,
- unsigned int duration,
- vpx_enc_frame_flags_t flags,
- unsigned int deadline,
- vpx_fixed_buf_t *stats) {
+static int get_frame_stats(vpx_codec_ctx_t *ctx,
+ const vpx_image_t *img,
+ vpx_codec_pts_t pts,
+ unsigned int duration,
+ vpx_enc_frame_flags_t flags,
+ unsigned int deadline,
+ vpx_fixed_buf_t *stats) {
+ int got_pkts = 0;
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL;
const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
@@ -81,6 +82,8 @@ static void get_frame_stats(vpx_codec_ctx_t *ctx,
die_codec(ctx, "Failed to get frame stats.");
while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
+ got_pkts = 1;
+
if (pkt->kind == VPX_CODEC_STATS_PKT) {
const uint8_t *const pkt_buf = pkt->data.twopass_stats.buf;
const size_t pkt_size = pkt->data.twopass_stats.sz;
@@ -89,15 +92,18 @@ static void get_frame_stats(vpx_codec_ctx_t *ctx,
stats->sz += pkt_size;
}
}
+
+ return got_pkts;
}
-static void encode_frame(vpx_codec_ctx_t *ctx,
- const vpx_image_t *img,
- vpx_codec_pts_t pts,
- unsigned int duration,
- vpx_enc_frame_flags_t flags,
- unsigned int deadline,
- VpxVideoWriter *writer) {
+static int encode_frame(vpx_codec_ctx_t *ctx,
+ const vpx_image_t *img,
+ vpx_codec_pts_t pts,
+ unsigned int duration,
+ vpx_enc_frame_flags_t flags,
+ unsigned int deadline,
+ VpxVideoWriter *writer) {
+ int got_pkts = 0;
vpx_codec_iter_t iter = NULL;
const vpx_codec_cx_pkt_t *pkt = NULL;
const vpx_codec_err_t res = vpx_codec_encode(ctx, img, pts, duration, flags,
@@ -106,6 +112,7 @@ static void encode_frame(vpx_codec_ctx_t *ctx,
die_codec(ctx, "Failed to encode frame.");
while ((pkt = vpx_codec_get_cx_data(ctx, &iter)) != NULL) {
+ got_pkts = 1;
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
const int keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
@@ -117,19 +124,90 @@ static void encode_frame(vpx_codec_ctx_t *ctx,
fflush(stdout);
}
}
+
+ return got_pkts;
+}
+
+static vpx_fixed_buf_t pass0(vpx_image_t *raw,
+ FILE *infile,
+ const VpxInterface *encoder,
+ const vpx_codec_enc_cfg_t *cfg) {
+ vpx_codec_ctx_t codec;
+ int frame_count = 0;
+ vpx_fixed_buf_t stats = {NULL, 0};
+
+ if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0))
+ die_codec(&codec, "Failed to initialize encoder");
+
+ // Calculate frame statistics.
+ while (vpx_img_read(raw, infile)) {
+ ++frame_count;
+ get_frame_stats(&codec, raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
+ &stats);
+ }
+
+ // Flush encoder.
+ while (get_frame_stats(&codec, NULL, frame_count, 1, 0,
+ VPX_DL_BEST_QUALITY, &stats)) {}
+
+ printf("Pass 0 complete. Processed %d frames.\n", frame_count);
+ if (vpx_codec_destroy(&codec))
+ die_codec(&codec, "Failed to destroy codec.");
+
+ return stats;
+}
+
+static void pass1(vpx_image_t *raw,
+ FILE *infile,
+ const char *outfile_name,
+ const VpxInterface *encoder,
+ const vpx_codec_enc_cfg_t *cfg) {
+ VpxVideoInfo info = {
+ encoder->fourcc,
+ cfg->g_w,
+ cfg->g_h,
+ {cfg->g_timebase.num, cfg->g_timebase.den}
+ };
+ VpxVideoWriter *writer = NULL;
+ vpx_codec_ctx_t codec;
+ int frame_count = 0;
+
+ writer = vpx_video_writer_open(outfile_name, kContainerIVF, &info);
+ if (!writer)
+ die("Failed to open %s for writing", outfile_name);
+
+ if (vpx_codec_enc_init(&codec, encoder->codec_interface(), cfg, 0))
+ die_codec(&codec, "Failed to initialize encoder");
+
+ // Encode frames.
+ while (vpx_img_read(raw, infile)) {
+ ++frame_count;
+ encode_frame(&codec, raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY, writer);
+ }
+
+ // Flush encoder.
+ while (encode_frame(&codec, NULL, -1, 1, 0, VPX_DL_BEST_QUALITY, writer)) {}
+
+ printf("\n");
+
+ if (vpx_codec_destroy(&codec))
+ die_codec(&codec, "Failed to destroy codec.");
+
+ vpx_video_writer_close(writer);
+
+ printf("Pass 1 complete. Processed %d frames.\n", frame_count);
}
int main(int argc, char **argv) {
FILE *infile = NULL;
- VpxVideoWriter *writer = NULL;
+ int w, h;
vpx_codec_ctx_t codec;
vpx_codec_enc_cfg_t cfg;
vpx_image_t raw;
vpx_codec_err_t res;
- vpx_fixed_buf_t stats = {0};
- VpxVideoInfo info = {0};
+ vpx_fixed_buf_t stats;
+
const VpxInterface *encoder = NULL;
- int pass;
const int fps = 30; // TODO(dkovalev) add command line argument
const int bitrate = 200; // kbit/s TODO(dkovalev) add command line argument
const char *const codec_arg = argv[1];
@@ -146,85 +224,44 @@ int main(int argc, char **argv) {
if (!encoder)
die("Unsupported codec.");
- info.codec_fourcc = encoder->fourcc;
- info.time_base.numerator = 1;
- info.time_base.denominator = fps;
- info.frame_width = strtol(width_arg, NULL, 0);
- info.frame_height = strtol(height_arg, NULL, 0);
-
- if (info.frame_width <= 0 ||
- info.frame_height <= 0 ||
- (info.frame_width % 2) != 0 ||
- (info.frame_height % 2) != 0) {
- die("Invalid frame size: %dx%d", info.frame_width, info.frame_height);
- }
+ w = strtol(width_arg, NULL, 0);
+ h = strtol(height_arg, NULL, 0);
- if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, info.frame_width,
- info.frame_height, 1)) {
- die("Failed to allocate image", info.frame_width, info.frame_height);
- }
+ if (w <= 0 || h <= 0 || (w % 2) != 0 || (h % 2) != 0)
+ die("Invalid frame size: %dx%d", w, h);
- writer = vpx_video_writer_open(outfile_arg, kContainerIVF, &info);
- if (!writer)
- die("Failed to open %s for writing", outfile_arg);
+ if (!vpx_img_alloc(&raw, VPX_IMG_FMT_I420, w, h, 1))
+ die("Failed to allocate image", w, h);
printf("Using %s\n", vpx_codec_iface_name(encoder->codec_interface()));
+ // Configuration
res = vpx_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res)
die_codec(&codec, "Failed to get default codec config.");
- cfg.g_w = info.frame_width;
- cfg.g_h = info.frame_height;
- cfg.g_timebase.num = info.time_base.numerator;
- cfg.g_timebase.den = info.time_base.denominator;
+ cfg.g_w = w;
+ cfg.g_h = h;
+ cfg.g_timebase.num = 1;
+ cfg.g_timebase.den = fps;
cfg.rc_target_bitrate = bitrate;
- for (pass = 0; pass < 2; ++pass) {
- int frame_count = 0;
-
- if (pass == 0) {
- cfg.g_pass = VPX_RC_FIRST_PASS;
- } else {
- cfg.g_pass = VPX_RC_LAST_PASS;
- cfg.rc_twopass_stats_in = stats;
- }
-
- if (!(infile = fopen(infile_arg, "rb")))
- die("Failed to open %s for reading", infile_arg);
-
- if (vpx_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
- die_codec(&codec, "Failed to initialize encoder");
-
- while (vpx_img_read(&raw, infile)) {
- ++frame_count;
+ if (!(infile = fopen(infile_arg, "rb")))
+ die("Failed to open %s for reading", infile_arg);
- if (pass == 0) {
- get_frame_stats(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
- &stats);
- } else {
- encode_frame(&codec, &raw, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
- writer);
- }
- }
-
- if (pass == 0) {
- get_frame_stats(&codec, NULL, frame_count, 1, 0, VPX_DL_BEST_QUALITY,
- &stats);
- } else {
- printf("\n");
- }
+ // Pass 0
+ cfg.g_pass = VPX_RC_FIRST_PASS;
+ stats = pass0(&raw, infile, encoder, &cfg);
- fclose(infile);
- printf("Pass %d complete. Processed %d frames.\n", pass + 1, frame_count);
- if (vpx_codec_destroy(&codec))
- die_codec(&codec, "Failed to destroy codec.");
- }
-
- vpx_img_free(&raw);
+ // Pass 1
+ rewind(infile);
+ cfg.g_pass = VPX_RC_LAST_PASS;
+ cfg.rc_twopass_stats_in = stats;
+ pass1(&raw, infile, outfile_arg, encoder, &cfg);
free(stats.buf);
- vpx_video_writer_close(writer);
+ vpx_img_free(&raw);
+ fclose(infile);
return EXIT_SUCCESS;
}
diff --git a/test/datarate_test.cc b/test/datarate_test.cc
index a8d8d4250..e8cbfbea0 100644
--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -41,7 +41,10 @@ class DatarateTestLarge : public ::libvpx_test::EncoderTest,
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
- ::libvpx_test::Encoder* /*encoder*/) {
+ ::libvpx_test::Encoder *encoder) {
+ if (video->frame() == 1) {
+ encoder->Control(VP8E_SET_NOISE_SENSITIVITY, denoiser_on_);
+ }
const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0;
@@ -120,9 +123,43 @@ class DatarateTestLarge : public ::libvpx_test::EncoderTest,
double file_datarate_;
double effective_datarate_;
size_t bits_in_last_frame_;
+ int denoiser_on_;
};
+TEST_P(DatarateTestLarge, BasicBufferModelDenoiserOff) {
+ denoiser_on_ = 0;
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_dropframe_thresh = 1;
+ cfg_.rc_max_quantizer = 56;
+ cfg_.rc_end_usage = VPX_CBR;
+ // 2 pass cbr datarate control has a bug hidden by the small # of
+ // frames selected in this encode. The problem is that even if the buffer is
+ // negative we produce a keyframe on a cutscene. Ignoring datarate
+ // constraints
+ // TODO(jimbankoski): ( Fix when issue
+ // http://code.google.com/p/webm/issues/detail?id=495 is addressed. )
+ ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
+ 30, 1, 0, 140);
+
+ // There is an issue for low bitrates in real-time mode, where the
+ // effective_datarate slightly overshoots the target bitrate.
+ // This is same the issue as noted about (#495).
+ // TODO(jimbankoski/marpan): Update test to run for lower bitrates (< 100),
+ // when the issue is resolved.
+ for (int i = 100; i < 800; i += 200) {
+ cfg_.rc_target_bitrate = i;
+ ResetModel();
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.95)
+ << " The datarate for the file exceeds the target!";
+
+ ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.3)
+ << " The datarate for the file missed the target!";
+ }
+}
+
TEST_P(DatarateTestLarge, BasicBufferModel) {
+ denoiser_on_ = 1;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_max_quantizer = 56;
@@ -154,6 +191,7 @@ TEST_P(DatarateTestLarge, BasicBufferModel) {
}
TEST_P(DatarateTestLarge, ChangingDropFrameThresh) {
+ denoiser_on_ = 1;
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_max_quantizer = 36;
cfg_.rc_end_usage = VPX_CBR;
diff --git a/test/svc_test.cc b/test/svc_test.cc
index 23e727a32..e219488b0 100644
--- a/test/svc_test.cc
+++ b/test/svc_test.cc
@@ -112,7 +112,7 @@ class SvcTest : public ::testing::Test {
video.Next();
}
- // Flush encoder and test EOS packet
+ // Flush encoder and test EOS packet.
res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_);
@@ -135,7 +135,7 @@ class SvcTest : public ::testing::Test {
EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
}
- outputs[*frame_received].buf = malloc(frame_size);
+ outputs[*frame_received].buf = malloc(frame_size + 16);
ASSERT_TRUE(outputs[*frame_received].buf != NULL);
memcpy(outputs[*frame_received].buf, vpx_svc_get_buffer(&svc_),
frame_size);
@@ -176,13 +176,13 @@ class SvcTest : public ::testing::Test {
video.Next();
}
- // Flush Encoder
+ // Flush encoder.
res = vpx_svc_encode(&svc_, &codec_, NULL, 0,
video.duration(), VPX_DL_GOOD_QUALITY);
EXPECT_EQ(VPX_CODEC_OK, res);
StoreFrames(n, outputs, &frame_received);
- EXPECT_EQ(frame_received, (size_t)n);
+ EXPECT_EQ(frame_received, static_cast<size_t>(n));
ReleaseEncoder();
}
@@ -204,7 +204,7 @@ class SvcTest : public ::testing::Test {
++decoded_frames;
DxDataIterator dec_iter = decoder_->GetDxData();
- while (dec_iter.Next()) {
+ while (dec_iter.Next() != NULL) {
++received_frames;
}
}
@@ -214,7 +214,8 @@ class SvcTest : public ::testing::Test {
void DropEnhancementLayers(struct vpx_fixed_buf *const inputs,
const int num_super_frames,
- const int remained_layers) {
+ const int remained_layers,
+ const bool is_multiple_frame_context) {
ASSERT_TRUE(inputs != NULL);
ASSERT_GT(num_super_frames, 0);
ASSERT_GT(remained_layers, 0);
@@ -236,7 +237,7 @@ class SvcTest : public ::testing::Test {
uint8_t *frame_data = static_cast<uint8_t *>(inputs[i].buf);
uint8_t *frame_start = frame_data;
for (frame = 0; frame < frame_count; ++frame) {
- // Looking for a visible frame
+ // Looking for a visible frame.
if (frame_data[0] & 0x02) {
++frames_found;
if (frames_found == remained_layers)
@@ -244,11 +245,17 @@ class SvcTest : public ::testing::Test {
}
frame_data += frame_sizes[frame];
}
- ASSERT_LT(frame, frame_count);
- if (frame == frame_count - 1)
+ ASSERT_LT(frame, frame_count) << "Couldn't find a visible frame. "
+ << "remaining_layers: " << remained_layers
+ << " super_frame: " << i
+ << " is_multiple_frame_context: " << is_multiple_frame_context;
+ if (frame == frame_count - 1 && !is_multiple_frame_context)
continue;
frame_data += frame_sizes[frame];
+ // We need to add one more frame for multiple frame context.
+ if (is_multiple_frame_context)
+ ++frame;
uint8_t marker =
static_cast<const uint8_t *>(inputs[i].buf)[inputs[i].sz - 1];
const uint32_t mag = ((marker >> 3) & 0x3) + 1;
@@ -256,11 +263,37 @@ class SvcTest : public ::testing::Test {
const size_t new_index_sz = 2 + mag * (frame + 1);
marker &= 0x0f8;
marker |= frame;
+
+ // Copy existing frame sizes.
+ memmove(frame_data + (is_multiple_frame_context ? 2 : 1),
+ frame_start + inputs[i].sz - index_sz + 1, new_index_sz - 2);
+ if (is_multiple_frame_context) {
+ // Add a one byte frame with flag show_existing frame.
+ *frame_data++ = 0x88 | (remained_layers - 1);
+ }
+ // New marker.
frame_data[0] = marker;
- memcpy(frame_data + 1, frame_start + inputs[i].sz - index_sz + 1,
- new_index_sz - 2);
- frame_data[new_index_sz - 1] = marker;
- inputs[i].sz = frame_data - frame_start + new_index_sz;
+ frame_data += (mag * (frame + 1) + 1);
+
+ if (is_multiple_frame_context) {
+ // Write the frame size for the one byte frame.
+ frame_data -= mag;
+ *frame_data++ = 1;
+ for (uint32_t j = 1; j < mag; ++j) {
+ *frame_data++ = 0;
+ }
+ }
+
+ *frame_data++ = marker;
+ inputs[i].sz = frame_data - frame_start;
+
+ if (is_multiple_frame_context) {
+ // Change the show frame flag to 0 for all frames.
+ for (int j = 0; j < frame; ++j) {
+ frame_start[0] &= ~2;
+ frame_start += frame_sizes[j];
+ }
+ }
}
}
@@ -507,7 +540,7 @@ TEST_F(SvcTest, TwoPassEncode2LayersDecodeBaseLayerOnly) {
vpx_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
- DropEnhancementLayers(&outputs[0], 10, 1);
+ DropEnhancementLayers(&outputs[0], 10, 1, false);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
@@ -525,13 +558,13 @@ TEST_F(SvcTest, TwoPassEncode5LayersDecode54321Layers) {
Pass2EncodeNFrames(&stats_buf, 10, 5, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
- DropEnhancementLayers(&outputs[0], 10, 4);
+ DropEnhancementLayers(&outputs[0], 10, 4, false);
DecodeNFrames(&outputs[0], 10);
- DropEnhancementLayers(&outputs[0], 10, 3);
+ DropEnhancementLayers(&outputs[0], 10, 3, false);
DecodeNFrames(&outputs[0], 10);
- DropEnhancementLayers(&outputs[0], 10, 2);
+ DropEnhancementLayers(&outputs[0], 10, 2, false);
DecodeNFrames(&outputs[0], 10);
- DropEnhancementLayers(&outputs[0], 10, 1);
+ DropEnhancementLayers(&outputs[0], 10, 1, false);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
@@ -568,12 +601,121 @@ TEST_F(SvcTest, TwoPassEncode3SNRLayersDecode321Layers) {
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 20, 3, &outputs[0]);
DecodeNFrames(&outputs[0], 20);
- DropEnhancementLayers(&outputs[0], 20, 2);
+ DropEnhancementLayers(&outputs[0], 20, 2, false);
DecodeNFrames(&outputs[0], 20);
- DropEnhancementLayers(&outputs[0], 20, 1);
+ DropEnhancementLayers(&outputs[0], 20, 1, false);
DecodeNFrames(&outputs[0], 20);
FreeBitstreamBuffers(&outputs[0], 20);
}
+TEST_F(SvcTest, SetMultipleFrameContextOption) {
+ svc_.spatial_layers = 5;
+ vpx_codec_err_t res =
+ vpx_svc_set_options(&svc_, "multi-frame-contexts=1");
+ EXPECT_EQ(VPX_CODEC_OK, res);
+ res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
+ EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
+
+ svc_.spatial_layers = 2;
+ res = vpx_svc_set_options(&svc_, "multi-frame-contexts=1");
+ InitializeEncoder();
+}
+
+TEST_F(SvcTest, TwoPassEncode2LayersWithMultipleFrameContext) {
+ // First pass encode
+ std::string stats_buf;
+ Pass1EncodeNFrames(10, 2, &stats_buf);
+
+ // Second pass encode
+ codec_enc_.g_pass = VPX_RC_LAST_PASS;
+ codec_enc_.g_error_resilient = 0;
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
+ vpx_fixed_buf outputs[10];
+ memset(&outputs[0], 0, sizeof(outputs));
+ Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
+ DropEnhancementLayers(&outputs[0], 10, 2, true);
+ DecodeNFrames(&outputs[0], 10);
+ FreeBitstreamBuffers(&outputs[0], 10);
+}
+
+TEST_F(SvcTest, TwoPassEncode2LayersWithMultipleFrameContextDecodeBaselayer) {
+ // First pass encode
+ std::string stats_buf;
+ Pass1EncodeNFrames(10, 2, &stats_buf);
+
+ // Second pass encode
+ codec_enc_.g_pass = VPX_RC_LAST_PASS;
+ codec_enc_.g_error_resilient = 0;
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
+ vpx_fixed_buf outputs[10];
+ memset(&outputs[0], 0, sizeof(outputs));
+ Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
+ DropEnhancementLayers(&outputs[0], 10, 1, true);
+ DecodeNFrames(&outputs[0], 10);
+ FreeBitstreamBuffers(&outputs[0], 10);
+}
+
+TEST_F(SvcTest, TwoPassEncode2SNRLayersWithMultipleFrameContext) {
+ // First pass encode
+ std::string stats_buf;
+ vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1");
+ Pass1EncodeNFrames(10, 2, &stats_buf);
+
+ // Second pass encode
+ codec_enc_.g_pass = VPX_RC_LAST_PASS;
+ codec_enc_.g_error_resilient = 0;
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 scale-factors=1/1,1/1 "
+ "multi-frame-contexts=1");
+ vpx_fixed_buf outputs[10];
+ memset(&outputs[0], 0, sizeof(outputs));
+ Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
+ DropEnhancementLayers(&outputs[0], 10, 2, true);
+ DecodeNFrames(&outputs[0], 10);
+ FreeBitstreamBuffers(&outputs[0], 10);
+}
+
+TEST_F(SvcTest, TwoPassEncode3SNRLayersWithMultipleFrameContextDecode321Layer) {
+ // First pass encode
+ std::string stats_buf;
+ vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1");
+ Pass1EncodeNFrames(10, 3, &stats_buf);
+
+ // Second pass encode
+ codec_enc_.g_pass = VPX_RC_LAST_PASS;
+ codec_enc_.g_error_resilient = 0;
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1 "
+ "multi-frame-contexts=1");
+ vpx_fixed_buf outputs[10];
+ memset(&outputs[0], 0, sizeof(outputs));
+ Pass2EncodeNFrames(&stats_buf, 10, 3, &outputs[0]);
+
+ vpx_fixed_buf outputs_new[10];
+ for (int i = 0; i < 10; ++i) {
+ outputs_new[i].buf = malloc(outputs[i].sz + 16);
+ ASSERT_TRUE(outputs_new[i].buf != NULL);
+ memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
+ outputs_new[i].sz = outputs[i].sz;
+ }
+ DropEnhancementLayers(&outputs_new[0], 10, 3, true);
+ DecodeNFrames(&outputs_new[0], 10);
+
+ for (int i = 0; i < 10; ++i) {
+ memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
+ outputs_new[i].sz = outputs[i].sz;
+ }
+ DropEnhancementLayers(&outputs_new[0], 10, 2, true);
+ DecodeNFrames(&outputs_new[0], 10);
+
+ for (int i = 0; i < 10; ++i) {
+ memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz);
+ outputs_new[i].sz = outputs[i].sz;
+ }
+ DropEnhancementLayers(&outputs_new[0], 10, 1, true);
+ DecodeNFrames(&outputs_new[0], 10);
+
+ FreeBitstreamBuffers(&outputs[0], 10);
+ FreeBitstreamBuffers(&outputs_new[0], 10);
+}
+
} // namespace
diff --git a/test/vpxenc.sh b/test/vpxenc.sh
index b6482c603..9674bdce0 100755
--- a/test/vpxenc.sh
+++ b/test/vpxenc.sh
@@ -41,6 +41,40 @@ vpxenc_can_encode_vp9() {
fi
}
+# Echo vpxenc command line parameters allowing use of
+# hantro_collage_w352h288.yuv as input.
+yuv_input_hantro_collage() {
+ echo ""${YUV_RAW_INPUT}"
+ --width="${YUV_RAW_INPUT_WIDTH}"
+ --height="${YUV_RAW_INPUT_HEIGHT}""
+}
+
+# Echo default vpxenc real time encoding params. $1 is the codec, which defaults
+# to vp8 if unspecified.
+vpxenc_rt_params() {
+ local readonly codec="${1:-vp8}"
+ echo "--codec=${codec}
+ --buf-initial-sz=500
+ --buf-optimal-sz=600
+ --buf-sz=1000
+ --cpu-used=-5
+ --end-usage=cbr
+ --error-resilient=1
+ --kf-max-dist=90000
+ --lag-in-frames=0
+ --max-intra-rate=300
+ --max-q=56
+ --min-q=2
+ --noise-sensitivity=0
+ --overshoot-pct=50
+ --passes=1
+ --profile=0
+ --resize-allowed=0
+ --rt
+ --static-thresh=0
+ --undershoot-pct=50"
+}
+
# Wrapper function for running vpxenc with pipe input. Requires that
# LIBVPX_BIN_PATH points to the directory containing vpxenc. $1 is used as the
# input file path and shifted away. All remaining parameters are passed through
@@ -59,9 +93,9 @@ vpxenc_pipe() {
# shifted away. All remaining parameters are passed through to vpxenc.
vpxenc() {
local readonly encoder="$(vpx_tool_path vpxenc)"
- local readonly input="${1}"
+ local readonly input="$1"
shift
- eval "${VPX_TEST_PREFIX}" "${encoder}" "$input" \
+ eval "${VPX_TEST_PREFIX}" "${encoder}" "${input}" \
--test-decode=fatal \
"$@" ${devnull}
}
@@ -69,13 +103,11 @@ vpxenc() {
vpxenc_vp8_ivf() {
if [ "$(vpxenc_can_encode_vp8)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8.ivf"
- vpxenc --codec=vp8 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp8 \
--limit="${TEST_FRAMES}" \
--ivf \
- --output="${output}" \
- "${YUV_RAW_INPUT}"
+ --output="${output}"
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -88,12 +120,10 @@ vpxenc_vp8_webm() {
if [ "$(vpxenc_can_encode_vp8)" = "yes" ] && \
[ "$(webm_io_available)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8.webm"
- vpxenc --codec=vp8 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp8 \
--limit="${TEST_FRAMES}" \
- --output="${output}" \
- "${YUV_RAW_INPUT}"
+ --output="${output}"
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -102,17 +132,29 @@ vpxenc_vp8_webm() {
fi
}
+vpxenc_vp8_webm_rt() {
+ if [ "$(vpxenc_can_encode_vp8)" = "yes" ] && \
+ [ "$(webm_io_available)" = "yes" ]; then
+ local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8_rt.webm"
+ vpxenc $(yuv_input_hantro_collage) \
+ $(vpxenc_rt_params vp8) \
+ --output="${output}"
+ if [ ! -e "${output}" ]; then
+ elog "Output file does not exist."
+ return 1
+ fi
+ fi
+}
+
vpxenc_vp8_webm_2pass() {
if [ "$(vpxenc_can_encode_vp8)" = "yes" ] && \
[ "$(webm_io_available)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8.webm"
- vpxenc --codec=vp8 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp8 \
--limit="${TEST_FRAMES}" \
--output="${output}" \
- --passes=2 \
- "${YUV_RAW_INPUT}"
+ --passes=2
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -127,15 +169,13 @@ vpxenc_vp8_webm_lag10_frames20() {
local readonly lag_total_frames=20
local readonly lag_frames=10
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8_lag10_frames20.webm"
- vpxenc --codec=vp8 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp8 \
--limit="${lag_total_frames}" \
--lag-in-frames="${lag_frames}" \
--output="${output}" \
--auto-alt-ref=1 \
- --passes=2 \
- "${YUV_RAW_INPUT}"
+ --passes=2
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -147,14 +187,11 @@ vpxenc_vp8_webm_lag10_frames20() {
vpxenc_vp8_ivf_piped_input() {
if [ "$(vpxenc_can_encode_vp8)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp8_piped_input.ivf"
- cat "${YUV_RAW_INPUT}" \
- | vpxenc --codec=vp8 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
- --limit="${TEST_FRAMES}" \
- --ivf \
- --output="${output}" \
- -
+ vpxenc_pipe $(yuv_input_hantro_collage) \
+ --codec=vp8 \
+ --limit="${TEST_FRAMES}" \
+ --ivf \
+ --output="${output}"
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -166,13 +203,11 @@ vpxenc_vp8_ivf_piped_input() {
vpxenc_vp9_ivf() {
if [ "$(vpxenc_can_encode_vp9)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9.ivf"
- vpxenc --codec=vp9 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp9 \
--limit="${TEST_FRAMES}" \
--ivf \
- --output="${output}" \
- "${YUV_RAW_INPUT}"
+ --output="${output}"
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -185,12 +220,25 @@ vpxenc_vp9_webm() {
if [ "$(vpxenc_can_encode_vp9)" = "yes" ] && \
[ "$(webm_io_available)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9.webm"
- vpxenc --codec=vp9 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp9 \
--limit="${TEST_FRAMES}" \
- --output="${output}" \
- "${YUV_RAW_INPUT}"
+ --output="${output}"
+
+ if [ ! -e "${output}" ]; then
+ elog "Output file does not exist."
+ return 1
+ fi
+ fi
+}
+
+vpxenc_vp9_webm_rt() {
+ if [ "$(vpxenc_can_encode_vp9)" = "yes" ] && \
+ [ "$(webm_io_available)" = "yes" ]; then
+ local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9_rt.webm"
+ vpxenc $(yuv_input_hantro_collage) \
+ $(vpxenc_rt_params vp9) \
+ --output="${output}"
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -203,14 +251,11 @@ vpxenc_vp9_webm_2pass() {
if [ "$(vpxenc_can_encode_vp9)" = "yes" ] && \
[ "$(webm_io_available)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9.webm"
- vpxenc --codec=vp9 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp9 \
--limit="${TEST_FRAMES}" \
- --test-decode=fatal \
--output="${output}" \
- --passes=2 \
- "${YUV_RAW_INPUT}"
+ --passes=2
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -222,14 +267,12 @@ vpxenc_vp9_webm_2pass() {
vpxenc_vp9_ivf_lossless() {
if [ "$(vpxenc_can_encode_vp9)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9_lossless.ivf"
- vpxenc --codec=vp9 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp9 \
--limit="${TEST_FRAMES}" \
--ivf \
--output="${output}" \
- --lossless=1 \
- "${YUV_RAW_INPUT}"
+ --lossless=1
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -241,15 +284,13 @@ vpxenc_vp9_ivf_lossless() {
vpxenc_vp9_ivf_minq0_maxq0() {
if [ "$(vpxenc_can_encode_vp9)" = "yes" ]; then
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9_lossless_minq0_maxq0.ivf"
- vpxenc --codec=vp9 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp9 \
--limit="${TEST_FRAMES}" \
--ivf \
--output="${output}" \
--min-q=0 \
- --max-q=0 \
- "${YUV_RAW_INPUT}"
+ --max-q=0
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -264,16 +305,13 @@ vpxenc_vp9_webm_lag10_frames20() {
local readonly lag_total_frames=20
local readonly lag_frames=10
local readonly output="${VPX_TEST_OUTPUT_DIR}/vp9_lag10_frames20.webm"
- vpxenc --codec=vp9 \
- --width="${YUV_RAW_INPUT_WIDTH}" \
- --height="${YUV_RAW_INPUT_HEIGHT}" \
+ vpxenc $(yuv_input_hantro_collage) \
+ --codec=vp9 \
--limit="${lag_total_frames}" \
--lag-in-frames="${lag_frames}" \
--output="${output}" \
- --test-decode=fatal \
--passes=2 \
- --auto-alt-ref=1 \
- "${YUV_RAW_INPUT}"
+ --auto-alt-ref=1
if [ ! -e "${output}" ]; then
elog "Output file does not exist."
@@ -284,11 +322,13 @@ vpxenc_vp9_webm_lag10_frames20() {
vpxenc_tests="vpxenc_vp8_ivf
vpxenc_vp8_webm
+ vpxenc_vp8_webm_rt
vpxenc_vp8_webm_2pass
vpxenc_vp8_webm_lag10_frames20
vpxenc_vp8_ivf_piped_input
vpxenc_vp9_ivf
vpxenc_vp9_webm
+ vpxenc_vp9_webm_rt
vpxenc_vp9_webm_2pass
vpxenc_vp9_ivf_lossless
vpxenc_vp9_ivf_minq0_maxq0
diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c
index 4621d13e2..2da0d8c0e 100644
--- a/vp8/encoder/denoising.c
+++ b/vp8/encoder/denoising.c
@@ -430,6 +430,7 @@ void vp8_denoiser_free(VP8_DENOISER *denoiser)
vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]);
}
vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg);
+ vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_last_source);
vpx_free(denoiser->denoise_state);
}
diff --git a/vp9/common/vp9_mv.h b/vp9/common/vp9_mv.h
index 3eb7f9d61..5d89da8c2 100644
--- a/vp9/common/vp9_mv.h
+++ b/vp9/common/vp9_mv.h
@@ -34,6 +34,14 @@ typedef struct mv32 {
int32_t col;
} MV32;
+static INLINE int is_zero_mv(const MV *mv) {
+ return *((const uint32_t *)mv) == 0;
+}
+
+static INLINE int is_equal_mv(const MV *a, const MV *b) {
+ return *((const uint32_t *)a) == *((const uint32_t *)b);
+}
+
static INLINE void clamp_mv(MV *mv, int min_col, int max_col,
int min_row, int max_row) {
mv->col = clamp(mv->col, min_col, max_col);
diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c
index 9fcb33ca9..5c304462a 100644
--- a/vp9/encoder/vp9_bitstream.c
+++ b/vp9/encoder/vp9_bitstream.c
@@ -1084,7 +1084,16 @@ static void write_uncompressed_header(VP9_COMP *cpi,
write_bitdepth_colorspace_sampling(cm, wb);
write_frame_size(cm, wb);
} else {
- if (!cm->show_frame)
+ // In spatial svc if it's not error_resilient_mode then we need to code all
+ // visible frames as invisible. But we need to keep the show_frame flag so
+ // that the publisher could know whether it is supposed to be visible.
+ // So we will code the show_frame flag as it is. Then code the intra_only
+ // bit here. This will make the bitstream incompatible. In the player we
+ // will change to show_frame flag to 0, then add an one byte frame with
+ // show_existing_frame flag which tells the decoder which frame we want to
+ // show.
+ if (!cm->show_frame ||
+ (is_spatial_svc(cpi) && cm->error_resilient_mode == 0))
vp9_wb_write_bit(wb, cm->intra_only);
if (!cm->error_resilient_mode)
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 711354b7f..950a6c8bb 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -1232,30 +1232,23 @@ static void set_source_var_based_partition(VP9_COMP *cpi,
}
}
-static int is_background(VP9_COMP *cpi, const TileInfo *const tile,
+static int is_background(const VP9_COMP *cpi, const TileInfo *const tile,
int mi_row, int mi_col) {
- MACROBLOCK *x = &cpi->mb;
- uint8_t *src, *pre;
- int src_stride, pre_stride;
-
+ // This assumes the input source frames are of the same dimension.
const int row8x8_remaining = tile->mi_row_end - mi_row;
const int col8x8_remaining = tile->mi_col_end - mi_col;
-
+ const int x = mi_col * MI_SIZE;
+ const int y = mi_row * MI_SIZE;
+ const int src_stride = cpi->Source->y_stride;
+ const uint8_t *const src = &cpi->Source->y_buffer[y * src_stride + x];
+ const int pre_stride = cpi->Last_Source->y_stride;
+ const uint8_t *const pre = &cpi->Last_Source->y_buffer[y * pre_stride + x];
int this_sad = 0;
int threshold = 0;
- // This assumes the input source frames are of the same dimension.
- src_stride = cpi->Source->y_stride;
- src = cpi->Source->y_buffer + (mi_row * MI_SIZE) * src_stride +
- (mi_col * MI_SIZE);
- pre_stride = cpi->Last_Source->y_stride;
- pre = cpi->Last_Source->y_buffer + (mi_row * MI_SIZE) * pre_stride +
- (mi_col * MI_SIZE);
-
if (row8x8_remaining >= MI_BLOCK_SIZE &&
col8x8_remaining >= MI_BLOCK_SIZE) {
- this_sad = cpi->fn_ptr[BLOCK_64X64].sdf(src, src_stride,
- pre, pre_stride);
+ this_sad = cpi->fn_ptr[BLOCK_64X64].sdf(src, src_stride, pre, pre_stride);
threshold = (1 << 12);
} else {
int r, c;
@@ -1266,8 +1259,7 @@ static int is_background(VP9_COMP *cpi, const TileInfo *const tile,
threshold = (row8x8_remaining * col8x8_remaining) << 6;
}
- x->in_static_area = (this_sad < 2 * threshold);
- return x->in_static_area;
+ return this_sad < 2 * threshold;
}
static int sb_has_motion(const VP9_COMMON *cm, MODE_INFO **prev_mi_8x8,
@@ -3119,7 +3111,7 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi, const TileInfo *const tile,
break;
case REFERENCE_PARTITION:
if (sf->partition_check ||
- !is_background(cpi, tile, mi_row, mi_col)) {
+ !(x->in_static_area = is_background(cpi, tile, mi_row, mi_col))) {
set_modeinfo_offsets(cm, xd, mi_row, mi_col);
auto_partition_range(cpi, tile, mi_row, mi_col,
&sf->min_partition_size,
@@ -3297,7 +3289,6 @@ static void encode_frame_internal(VP9_COMP *cpi) {
vp9_zero(cm->counts);
vp9_zero(cpi->coef_counts);
- vp9_zero(cpi->tx_stepdown_count);
vp9_zero(rd_opt->comp_pred_diff);
vp9_zero(rd_opt->filter_diff);
vp9_zero(rd_opt->tx_select_diff);
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 9f12d664c..8464882ea 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -2106,6 +2106,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
uint8_t *dest,
unsigned int *frame_flags) {
VP9_COMMON *const cm = &cpi->common;
+ const VP9EncoderConfig *const oxcf = &cpi->oxcf;
struct segmentation *const seg = &cm->seg;
TX_SIZE t;
int q;
@@ -2159,9 +2160,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
// The alternate reference frame cannot be active for a key frame.
cpi->rc.source_alt_ref_active = 0;
- cm->error_resilient_mode = (cpi->oxcf.error_resilient_mode != 0);
- cm->frame_parallel_decoding_mode =
- (cpi->oxcf.frame_parallel_decoding_mode != 0);
+ cm->error_resilient_mode = oxcf->error_resilient_mode;
// By default, encoder assumes decoder can use prev_mi.
if (cm->error_resilient_mode) {
@@ -2169,29 +2168,43 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
cm->reset_frame_context = 0;
cm->refresh_frame_context = 0;
} else if (cm->intra_only) {
+ cm->frame_parallel_decoding_mode = oxcf->frame_parallel_decoding_mode;
// Only reset the current context.
cm->reset_frame_context = 2;
}
}
+ if (is_spatial_svc(cpi) && cm->error_resilient_mode == 0) {
+ cm->frame_context_idx = cpi->svc.spatial_layer_id;
+
+ // The probs will be updated based on the frame type of its previous
+ // frame if frame_parallel_decoding_mode is 0. The type may vary for
+ // the frame after a key frame in base layer since we may drop enhancement
+ // layers. So set frame_parallel_decoding_mode to 1 in this case.
+ if (cpi->svc.spatial_layer_id == 0 &&
+ cpi->svc.layer_context[0].last_frame_type == KEY_FRAME)
+ cm->frame_parallel_decoding_mode = 1;
+ else
+ cm->frame_parallel_decoding_mode = 0;
+ }
// Configure experimental use of segmentation for enhanced coding of
// static regions if indicated.
// Only allowed in second pass of two pass (as requires lagged coding)
// and if the relevant speed feature flag is set.
- if (cpi->oxcf.pass == 2 && cpi->sf.static_segmentation)
+ if (oxcf->pass == 2 && cpi->sf.static_segmentation)
configure_static_seg_features(cpi);
// Check if the current frame is skippable for the partition search in the
// second pass according to the first pass stats
- if (cpi->oxcf.pass == 2 &&
+ if (oxcf->pass == 2 &&
(!cpi->use_svc || is_spatial_svc(cpi))) {
configure_skippable_frame(cpi);
}
// For 1 pass CBR, check if we are dropping this frame.
// Never drop on key frame.
- if (cpi->oxcf.pass == 0 &&
- cpi->oxcf.rc_mode == VPX_CBR &&
+ if (oxcf->pass == 0 &&
+ oxcf->rc_mode == VPX_CBR &&
cm->frame_type != KEY_FRAME) {
if (vp9_rc_drop_frame(cpi)) {
vp9_rc_postencode_update_drop_frame(cpi);
@@ -2203,9 +2216,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
vp9_clear_system_state();
#if CONFIG_VP9_POSTPROC
- if (cpi->oxcf.noise_sensitivity > 0) {
+ if (oxcf->noise_sensitivity > 0) {
int l = 0;
- switch (cpi->oxcf.noise_sensitivity) {
+ switch (oxcf->noise_sensitivity) {
case 1:
l = 20;
break;
@@ -2246,7 +2259,7 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
#if CONFIG_VP9_TEMPORAL_DENOISING
#ifdef OUTPUT_YUV_DENOISED
- if (cpi->oxcf.noise_sensitivity > 0) {
+ if (oxcf->noise_sensitivity > 0) {
vp9_write_yuv_frame_420(&cpi->denoiser.running_avg_y[INTRA_FRAME],
yuv_denoised_file);
}
@@ -2348,8 +2361,12 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
cm->last_height = cm->height;
// reset to normal state now that we are done.
- if (!cm->show_existing_frame)
- cm->last_show_frame = cm->show_frame;
+ if (!cm->show_existing_frame) {
+ if (is_spatial_svc(cpi) && cm->error_resilient_mode == 0)
+ cm->last_show_frame = 0;
+ else
+ cm->last_show_frame = cm->show_frame;
+ }
if (cm->show_frame) {
vp9_swap_mi_and_prev_mi(cm);
@@ -2360,6 +2377,10 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
if (cpi->use_svc)
vp9_inc_frame_in_layer(&cpi->svc);
}
+
+ if (is_spatial_svc(cpi))
+ cpi->svc.layer_context[cpi->svc.spatial_layer_id].last_frame_type =
+ cm->frame_type;
}
static void SvcEncode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
@@ -2474,8 +2495,8 @@ static int frame_is_reference(const VP9_COMP *cpi) {
cm->seg.update_data;
}
-void adjust_frame_rate(VP9_COMP *cpi) {
- const struct lookahead_entry *const source = cpi->source;
+void adjust_frame_rate(VP9_COMP *cpi,
+ const struct lookahead_entry *source) {
int64_t this_duration;
int step = 0;
@@ -2531,7 +2552,8 @@ static int get_arf_src_index(VP9_COMP *cpi) {
return arf_src_index;
}
-static void check_src_altref(VP9_COMP *cpi) {
+static void check_src_altref(VP9_COMP *cpi,
+ const struct lookahead_entry *source) {
RATE_CONTROL *const rc = &cpi->rc;
if (cpi->oxcf.pass == 2) {
@@ -2540,7 +2562,7 @@ static void check_src_altref(VP9_COMP *cpi) {
(gf_group->update_type[gf_group->index] == OVERLAY_UPDATE);
} else {
rc->is_src_frame_alt_ref = cpi->alt_ref_source &&
- (cpi->source == cpi->alt_ref_source);
+ (source == cpi->alt_ref_source);
}
if (rc->is_src_frame_alt_ref) {
@@ -2563,6 +2585,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
struct vpx_usec_timer cmptimer;
YV12_BUFFER_CONFIG *force_src_buffer = NULL;
struct lookahead_entry *last_source = NULL;
+ struct lookahead_entry *source = NULL;
MV_REFERENCE_FRAME ref_frame;
int arf_src_index;
@@ -2575,8 +2598,6 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
vpx_usec_timer_start(&cmptimer);
- cpi->source = NULL;
-
vp9_set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV);
// Normal defaults
@@ -2593,13 +2614,12 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
#if CONFIG_SPATIAL_SVC
if (is_spatial_svc(cpi))
- cpi->source = vp9_svc_lookahead_peek(cpi, cpi->lookahead,
- arf_src_index, 0);
+ source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, arf_src_index, 0);
else
#endif
- cpi->source = vp9_lookahead_peek(cpi->lookahead, arf_src_index);
- if (cpi->source != NULL) {
- cpi->alt_ref_source = cpi->source;
+ source = vp9_lookahead_peek(cpi->lookahead, arf_src_index);
+ if (source != NULL) {
+ cpi->alt_ref_source = source;
#if CONFIG_SPATIAL_SVC
if (is_spatial_svc(cpi) && cpi->svc.spatial_layer_id > 0) {
@@ -2633,7 +2653,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
}
}
- if (!cpi->source) {
+ if (!source) {
// Get last frame source.
if (cm->current_video_frame > 0) {
#if CONFIG_SPATIAL_SVC
@@ -2649,29 +2669,28 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
// Read in the source frame.
#if CONFIG_SPATIAL_SVC
if (is_spatial_svc(cpi))
- cpi->source = vp9_svc_lookahead_pop(cpi, cpi->lookahead, flush);
+ source = vp9_svc_lookahead_pop(cpi, cpi->lookahead, flush);
else
#endif
- cpi->source = vp9_lookahead_pop(cpi->lookahead, flush);
- if (cpi->source != NULL) {
+ source = vp9_lookahead_pop(cpi->lookahead, flush);
+ if (source != NULL) {
cm->show_frame = 1;
cm->intra_only = 0;
// Check to see if the frame should be encoded as an arf overlay.
- check_src_altref(cpi);
+ check_src_altref(cpi, source);
}
}
- if (cpi->source) {
+ if (source) {
cpi->un_scaled_source = cpi->Source = force_src_buffer ? force_src_buffer
- : &cpi->source->img;
+ : &source->img;
cpi->unscaled_last_source = last_source != NULL ? &last_source->img : NULL;
- *time_stamp = cpi->source->ts_start;
- *time_end = cpi->source->ts_end;
- *frame_flags =
- (cpi->source->flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
+ *time_stamp = source->ts_start;
+ *time_end = source->ts_end;
+ *frame_flags = (source->flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
} else {
*size = 0;
@@ -2682,9 +2701,9 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
return -1;
}
- if (cpi->source->ts_start < cpi->first_time_stamp_ever) {
- cpi->first_time_stamp_ever = cpi->source->ts_start;
- cpi->last_end_time_stamp_seen = cpi->source->ts_start;
+ if (source->ts_start < cpi->first_time_stamp_ever) {
+ cpi->first_time_stamp_ever = source->ts_start;
+ cpi->last_end_time_stamp_seen = source->ts_start;
}
// Clear down mmx registers
@@ -2692,7 +2711,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
// adjust frame rates based on timestamps given
if (cm->show_frame) {
- adjust_frame_rate(cpi);
+ adjust_frame_rate(cpi, source);
}
if (cpi->svc.number_temporal_layers > 1 &&
@@ -2764,7 +2783,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
const int lossless = is_lossless_requested(oxcf);
cpi->mb.fwd_txm4x4 = lossless ? vp9_fwht4x4 : vp9_fdct4x4;
cpi->mb.itxm_add = lossless ? vp9_iwht4x4_add : vp9_idct4x4_add;
- vp9_first_pass(cpi);
+ vp9_first_pass(cpi, source);
} else if (oxcf->pass == 2 &&
(!cpi->use_svc || is_spatial_svc(cpi))) {
Pass2Encode(cpi, size, dest, frame_flags);
diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h
index 71fc4decd..2dba67c54 100644
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -223,17 +223,12 @@ static INLINE int is_lossless_requested(const VP9EncoderConfig *cfg) {
return cfg->best_allowed_q == 0 && cfg->worst_allowed_q == 0;
}
-static INLINE int is_best_mode(MODE mode) {
- return mode == BEST;
-}
-
typedef struct VP9_COMP {
QUANTS quants;
MACROBLOCK mb;
VP9_COMMON common;
VP9EncoderConfig oxcf;
struct lookahead_ctx *lookahead;
- struct lookahead_entry *source;
struct lookahead_entry *alt_ref_source;
YV12_BUFFER_CONFIG *Source;
@@ -378,8 +373,6 @@ typedef struct VP9_COMP {
int dummy_packing; /* flag to indicate if packing is dummy */
- unsigned int tx_stepdown_count[TX_SIZES];
-
int initial_width;
int initial_height;
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index 94bbe9c69..7867dc244 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -396,7 +396,7 @@ static void set_first_pass_params(VP9_COMP *cpi) {
cpi->rc.frames_to_key = INT_MAX;
}
-void vp9_first_pass(VP9_COMP *cpi) {
+void vp9_first_pass(VP9_COMP *cpi, const struct lookahead_entry *source) {
int mb_row, mb_col;
MACROBLOCK *const x = &cpi->mb;
VP9_COMMON *const cm = &cpi->common;
@@ -428,7 +428,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
int neutral_count = 0;
int new_mv_count = 0;
int sum_in_vectors = 0;
- uint32_t lastmv_as_int = 0;
+ MV lastmv = {0, 0};
TWO_PASS *twopass = &cpi->twopass;
const MV zero_mv = {0, 0};
const YV12_BUFFER_CONFIG *first_ref_buf = lst_yv12;
@@ -512,9 +512,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
vp9_tile_init(&tile, cm, 0, 0);
for (mb_row = 0; mb_row < cm->mb_rows; ++mb_row) {
- int_mv best_ref_mv;
-
- best_ref_mv.as_int = 0;
+ MV best_ref_mv = {0, 0};
// Reset above block coeffs.
xd->up_available = (mb_row != 0);
@@ -594,14 +592,13 @@ void vp9_first_pass(VP9_COMP *cpi) {
// Other than for the first frame do a motion search.
if (cm->current_video_frame > 0) {
int tmp_err, motion_error, raw_motion_error;
- int_mv mv, tmp_mv;
+ // Assume 0,0 motion with no mv overhead.
+ MV mv = {0, 0} , tmp_mv = {0, 0};
struct buf_2d unscaled_last_source_buf_2d;
xd->plane[0].pre[0].buf = first_ref_buf->y_buffer + recon_yoffset;
motion_error = get_prediction_error(bsize, &x->plane[0].src,
&xd->plane[0].pre[0]);
- // Assume 0,0 motion with no mv overhead.
- mv.as_int = tmp_mv.as_int = 0;
// Compute the motion error of the 0,0 motion using the last source
// frame as the reference. Skip the further motion search on
@@ -617,8 +614,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
if (raw_motion_error > 25 || lc != NULL) {
// Test last reference frame using the previous best mv as the
// starting point (best reference) for the search.
- first_pass_motion_search(cpi, x, &best_ref_mv.as_mv, &mv.as_mv,
- &motion_error);
+ first_pass_motion_search(cpi, x, &best_ref_mv, &mv, &motion_error);
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
vp9_clear_system_state();
motion_error = (int)(motion_error * error_weight);
@@ -626,9 +622,9 @@ void vp9_first_pass(VP9_COMP *cpi) {
// If the current best reference mv is not centered on 0,0 then do a
// 0,0 based search as well.
- if (best_ref_mv.as_int) {
+ if (!is_zero_mv(&best_ref_mv)) {
tmp_err = INT_MAX;
- first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv.as_mv, &tmp_err);
+ first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv, &tmp_err);
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
vp9_clear_system_state();
tmp_err = (int)(tmp_err * error_weight);
@@ -636,7 +632,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
if (tmp_err < motion_error) {
motion_error = tmp_err;
- mv.as_int = tmp_mv.as_int;
+ mv = tmp_mv;
}
}
@@ -649,7 +645,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
gf_motion_error = get_prediction_error(bsize, &x->plane[0].src,
&xd->plane[0].pre[0]);
- first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv.as_mv,
+ first_pass_motion_search(cpi, x, &zero_mv, &tmp_mv,
&gf_motion_error);
if (cpi->oxcf.aq_mode == VARIANCE_AQ) {
vp9_clear_system_state();
@@ -680,7 +676,8 @@ void vp9_first_pass(VP9_COMP *cpi) {
}
// Start by assuming that intra mode is best.
- best_ref_mv.as_int = 0;
+ best_ref_mv.row = 0;
+ best_ref_mv.col = 0;
#if CONFIG_FP_MB_STATS
if (cpi->use_fp_mb_stats) {
@@ -704,25 +701,25 @@ void vp9_first_pass(VP9_COMP *cpi) {
this_error < 2 * intrapenalty)
++neutral_count;
- mv.as_mv.row *= 8;
- mv.as_mv.col *= 8;
+ mv.row *= 8;
+ mv.col *= 8;
this_error = motion_error;
xd->mi[0]->mbmi.mode = NEWMV;
- xd->mi[0]->mbmi.mv[0] = mv;
+ xd->mi[0]->mbmi.mv[0].as_mv = mv;
xd->mi[0]->mbmi.tx_size = TX_4X4;
xd->mi[0]->mbmi.ref_frame[0] = LAST_FRAME;
xd->mi[0]->mbmi.ref_frame[1] = NONE;
vp9_build_inter_predictors_sby(xd, mb_row << 1, mb_col << 1, bsize);
vp9_encode_sby_pass1(x, bsize);
- sum_mvr += mv.as_mv.row;
- sum_mvr_abs += abs(mv.as_mv.row);
- sum_mvc += mv.as_mv.col;
- sum_mvc_abs += abs(mv.as_mv.col);
- sum_mvrs += mv.as_mv.row * mv.as_mv.row;
- sum_mvcs += mv.as_mv.col * mv.as_mv.col;
+ sum_mvr += mv.row;
+ sum_mvr_abs += abs(mv.row);
+ sum_mvc += mv.col;
+ sum_mvc_abs += abs(mv.col);
+ sum_mvrs += mv.row * mv.row;
+ sum_mvcs += mv.col * mv.col;
++intercount;
- best_ref_mv.as_int = mv.as_int;
+ best_ref_mv = mv;
#if CONFIG_FP_MB_STATS
if (cpi->use_fp_mb_stats) {
@@ -740,7 +737,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
}
#endif
- if (mv.as_int) {
+ if (!is_zero_mv(&mv)) {
++mvcount;
#if CONFIG_FP_MB_STATS
@@ -771,33 +768,33 @@ void vp9_first_pass(VP9_COMP *cpi) {
#endif
// Non-zero vector, was it different from the last non zero vector?
- if (mv.as_int != lastmv_as_int)
+ if (!is_equal_mv(&mv, &lastmv))
++new_mv_count;
- lastmv_as_int = mv.as_int;
+ lastmv = mv;
// Does the row vector point inwards or outwards?
if (mb_row < cm->mb_rows / 2) {
- if (mv.as_mv.row > 0)
+ if (mv.row > 0)
--sum_in_vectors;
- else if (mv.as_mv.row < 0)
+ else if (mv.row < 0)
++sum_in_vectors;
} else if (mb_row > cm->mb_rows / 2) {
- if (mv.as_mv.row > 0)
+ if (mv.row > 0)
++sum_in_vectors;
- else if (mv.as_mv.row < 0)
+ else if (mv.row < 0)
--sum_in_vectors;
}
// Does the col vector point inwards or outwards?
if (mb_col < cm->mb_cols / 2) {
- if (mv.as_mv.col > 0)
+ if (mv.col > 0)
--sum_in_vectors;
- else if (mv.as_mv.col < 0)
+ else if (mv.col < 0)
++sum_in_vectors;
} else if (mb_col > cm->mb_cols / 2) {
- if (mv.as_mv.col > 0)
+ if (mv.col > 0)
++sum_in_vectors;
- else if (mv.as_mv.col < 0)
+ else if (mv.col < 0)
--sum_in_vectors;
}
}
@@ -865,7 +862,7 @@ void vp9_first_pass(VP9_COMP *cpi) {
// TODO(paulwilkins): Handle the case when duration is set to 0, or
// something less than the full time between subsequent values of
// cpi->source_time_stamp.
- fps.duration = (double)(cpi->source->ts_end - cpi->source->ts_start);
+ fps.duration = (double)(source->ts_end - source->ts_start);
// Don't want to do output stats with a stack variable!
twopass->this_frame_stats = fps;
diff --git a/vp9/encoder/vp9_firstpass.h b/vp9/encoder/vp9_firstpass.h
index bf8c9fd96..aaa6b0311 100644
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -121,7 +121,7 @@ struct VP9_COMP;
void vp9_init_first_pass(struct VP9_COMP *cpi);
void vp9_rc_get_first_pass_params(struct VP9_COMP *cpi);
-void vp9_first_pass(struct VP9_COMP *cpi);
+void vp9_first_pass(struct VP9_COMP *cpi, const struct lookahead_entry *source);
void vp9_end_first_pass(struct VP9_COMP *cpi);
void vp9_init_second_pass(struct VP9_COMP *cpi);
diff --git a/vp9/encoder/vp9_rd.c b/vp9/encoder/vp9_rd.c
index 4fc3e9e08..2841efabe 100644
--- a/vp9/encoder/vp9_rd.c
+++ b/vp9/encoder/vp9_rd.c
@@ -462,7 +462,7 @@ void vp9_set_rd_speed_thresholds(VP9_COMP *cpi) {
// Set baseline threshold values.
for (i = 0; i < MAX_MODES; ++i)
- rd->thresh_mult[i] = is_best_mode(cpi->oxcf.mode) ? -500 : 0;
+ rd->thresh_mult[i] = cpi->oxcf.mode == BEST ? -500 : 0;
rd->thresh_mult[THR_NEARESTMV] = 0;
rd->thresh_mult[THR_NEARESTG] = 0;
@@ -548,7 +548,7 @@ void vp9_set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) {
int i;
for (i = 0; i < MAX_REFS; ++i)
- rd->thresh_mult_sub8x8[i] = is_best_mode(cpi->oxcf.mode) ? -500 : 0;
+ rd->thresh_mult_sub8x8[i] = cpi->oxcf.mode == BEST ? -500 : 0;
rd->thresh_mult_sub8x8[THR_LAST] += 2500;
rd->thresh_mult_sub8x8[THR_GOLD] += 2500;
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 063eb4b56..5f1b0a515 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -468,7 +468,6 @@ static void choose_largest_tx_size(VP9_COMP *cpi, MACROBLOCK *x,
txfm_rd_in_plane(x, rate, distortion, skip,
sse, ref_best_rd, 0, bs,
mbmi->tx_size, cpi->sf.use_fast_coef_costing);
- cpi->tx_stepdown_count[0]++;
}
static void choose_tx_size_from_rd(VP9_COMP *cpi, MACROBLOCK *x,
@@ -551,16 +550,12 @@ static void choose_tx_size_from_rd(VP9_COMP *cpi, MACROBLOCK *x,
if (max_tx_size == TX_32X32 && best_tx == TX_32X32) {
tx_cache[TX_MODE_SELECT] = rd[TX_32X32][1];
- cpi->tx_stepdown_count[0]++;
} else if (max_tx_size >= TX_16X16 && best_tx == TX_16X16) {
tx_cache[TX_MODE_SELECT] = rd[TX_16X16][1];
- cpi->tx_stepdown_count[max_tx_size - TX_16X16]++;
} else if (rd[TX_8X8][1] < rd[TX_4X4][1]) {
tx_cache[TX_MODE_SELECT] = rd[TX_8X8][1];
- cpi->tx_stepdown_count[max_tx_size - TX_8X8]++;
} else {
tx_cache[TX_MODE_SELECT] = rd[TX_4X4][1];
- cpi->tx_stepdown_count[max_tx_size - TX_4X4]++;
}
}
@@ -1371,7 +1366,7 @@ static int64_t rd_pick_best_sub8x8_mode(VP9_COMP *cpi, MACROBLOCK *x,
if (best_rd < label_mv_thresh)
break;
- if (!is_best_mode(cpi->oxcf.mode)) {
+ if (cpi->oxcf.mode != BEST) {
// use previous block's result as next block's MV predictor.
if (i > 0) {
bsi->mvp.as_int = mi->bmi[i - 1].as_mv[0].as_int;
@@ -1413,7 +1408,7 @@ static int64_t rd_pick_best_sub8x8_mode(VP9_COMP *cpi, MACROBLOCK *x,
INT_MAX, 1);
// Should we do a full search (best quality only)
- if (is_best_mode(cpi->oxcf.mode)) {
+ if (cpi->oxcf.mode == BEST) {
int_mv *const best_mv = &mi->bmi[i].as_mv[0];
/* Check if mvp_full is within the range. */
clamp_mv(&mvp_full, x->mv_col_min, x->mv_col_max,
diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c
index a9d9400b2..879c83c08 100644
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -181,8 +181,8 @@ static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm,
static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf,
int speed, vp9e_tune_content content) {
VP9_COMMON *const cm = &cpi->common;
- const int frames_since_key =
- cm->frame_type == KEY_FRAME ? 0 : cpi->rc.frames_since_key;
+ const int is_keyframe = cm->frame_type == KEY_FRAME;
+ const int frames_since_key = is_keyframe ? 0 : cpi->rc.frames_since_key;
sf->static_segmentation = 0;
sf->adaptive_rd_thresh = 1;
sf->use_fast_coef_costing = 1;
@@ -278,17 +278,16 @@ static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf,
}
if (speed >= 5) {
- sf->use_quant_fp = cm->frame_type == KEY_FRAME ? 0 : 1;
- sf->auto_min_max_partition_size = (cm->frame_type == KEY_FRAME) ?
- RELAXED_NEIGHBORING_MIN_MAX : STRICT_NEIGHBORING_MIN_MAX;
+ sf->use_quant_fp = !is_keyframe;
+ sf->auto_min_max_partition_size = is_keyframe ? RELAXED_NEIGHBORING_MIN_MAX
+ : STRICT_NEIGHBORING_MIN_MAX;
sf->max_partition_size = BLOCK_32X32;
sf->min_partition_size = BLOCK_8X8;
sf->partition_check =
(frames_since_key % sf->last_partitioning_redo_frequency == 1);
- sf->force_frame_boost = cm->frame_type == KEY_FRAME ||
- (frames_since_key %
- (sf->last_partitioning_redo_frequency << 1) == 1);
- sf->max_delta_qindex = (cm->frame_type == KEY_FRAME) ? 20 : 15;
+ sf->force_frame_boost = is_keyframe ||
+ (frames_since_key % (sf->last_partitioning_redo_frequency << 1) == 1);
+ sf->max_delta_qindex = is_keyframe ? 20 : 15;
sf->partition_search_type = REFERENCE_PARTITION;
sf->use_nonrd_pick_mode = 1;
sf->allow_skip_recode = 0;
@@ -306,8 +305,7 @@ static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf,
sf->partition_search_type = SOURCE_VAR_BASED_PARTITION;
sf->search_type_check_frequency = 50;
- sf->tx_size_search_method = (cm->frame_type == KEY_FRAME) ?
- USE_LARGESTALL : USE_TX_8X8;
+ sf->tx_size_search_method = is_keyframe ? USE_LARGESTALL : USE_TX_8X8;
// This feature is only enabled when partition search is disabled.
sf->reuse_inter_pred_sby = 1;
@@ -317,6 +315,7 @@ static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf,
sf->mv.reduce_first_step_size = 1;
}
+
if (speed >= 7) {
sf->mv.search_method = FAST_DIAMOND;
sf->mv.fullpel_search_step_param = 10;
@@ -325,10 +324,12 @@ static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf,
800 : 300;
sf->elevate_newmv_thresh = 2500;
}
+
if (speed >= 12) {
sf->elevate_newmv_thresh = 4000;
sf->mv.subpel_force_stop = 2;
}
+
if (speed >= 13) {
int i;
sf->max_intra_bsize = BLOCK_32X32;
@@ -411,16 +412,14 @@ void vp9_set_speed_features(VP9_COMP *cpi) {
sf->default_interp_filter = SWITCHABLE;
sf->tx_size_search_breakout = 0;
- if (oxcf->mode == REALTIME) {
+ if (oxcf->mode == REALTIME)
set_rt_speed_feature(cpi, sf, oxcf->speed, oxcf->content);
- } else {
- if (!is_best_mode(oxcf->mode))
- set_good_speed_feature(cpi, cm, sf, oxcf->speed);
- }
+ else if (oxcf->mode == GOOD)
+ set_good_speed_feature(cpi, cm, sf, oxcf->speed);
cpi->full_search_sad = vp9_full_search_sad;
- cpi->diamond_search_sad = is_best_mode(oxcf->mode) ? vp9_full_range_search
- : vp9_diamond_search_sad;
+ cpi->diamond_search_sad = oxcf->mode == BEST ? vp9_full_range_search
+ : vp9_diamond_search_sad;
cpi->refining_search_sad = vp9_refining_search_sad;
diff --git a/vp9/encoder/vp9_svc_layercontext.c b/vp9/encoder/vp9_svc_layercontext.c
index fb52d1ab7..9bd9792bd 100644
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -36,6 +36,7 @@ void vp9_init_layer_context(VP9_COMP *const cpi) {
int i;
lc->current_video_frame_in_layer = 0;
lc->layer_size = 0;
+ lc->last_frame_type = FRAME_TYPES;
lrc->ni_av_qi = oxcf->worst_allowed_q;
lrc->total_actual_bits = 0;
lrc->total_target_vs_actual = 0;
diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h
index 0857e39cd..d475d5fcd 100644
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -28,6 +28,7 @@ typedef struct {
vpx_fixed_buf_t rc_twopass_stats_in;
unsigned int current_video_frame_in_layer;
int is_key_frame;
+ FRAME_TYPE last_frame_type;
vpx_svc_parameters_t svc_params_received;
struct lookahead_entry *alt_ref_source;
int alt_ref_idx;
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index 83f8abb16..5ff02d882 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -176,6 +176,8 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
if (alt_ref_sum > REF_FRAMES - cfg->ss_number_layers)
ERROR("Not enough ref buffers for svc alt ref frames");
}
+ if (cfg->ss_number_layers > 3 && cfg->g_error_resilient == 0)
+ ERROR("Multiple frame contexts are not supported for more than 3 layers");
#endif
RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
@@ -910,7 +912,7 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
#endif
// Pack invisible frames with the next visible frame
- if (cpi->common.show_frame == 0
+ if (!cpi->common.show_frame
#if CONFIG_SPATIAL_SVC
|| (is_spatial_svc(cpi) &&
cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
@@ -942,18 +944,6 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
)
pkt.data.frame.flags |= VPX_FRAME_IS_KEY;
- if (cpi->common.show_frame == 0) {
- pkt.data.frame.flags |= VPX_FRAME_IS_INVISIBLE;
-
- // This timestamp should be as close as possible to the
- // prior PTS so that if a decoder uses pts to schedule when
- // to do this, we start right after last frame was decoded.
- // Invisible frames have no duration.
- pkt.data.frame.pts =
- ticks_to_timebase_units(timebase, cpi->last_time_stamp_seen) + 1;
- pkt.data.frame.duration = 0;
- }
-
if (cpi->droppable)
pkt.data.frame.flags |= VPX_FRAME_IS_DROPPABLE;
diff --git a/vpx/src/svc_encodeframe.c b/vpx/src/svc_encodeframe.c
index 7828615b2..45b0dca5c 100644
--- a/vpx/src/svc_encodeframe.c
+++ b/vpx/src/svc_encodeframe.c
@@ -86,6 +86,7 @@ typedef struct SvcInternal {
int layers;
int layer;
int is_keyframe;
+ int use_multiple_frame_contexts;
FrameData *frame_list;
FrameData *frame_temp;
@@ -366,6 +367,7 @@ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
char *option_name;
char *option_value;
char *input_ptr;
+ SvcInternal *const si = get_svc_internal(svc_ctx);
vpx_codec_err_t res = VPX_CODEC_OK;
if (options == NULL) return VPX_CODEC_OK;
@@ -393,6 +395,8 @@ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
} else if (strcmp("auto-alt-refs", option_name) == 0) {
res = parse_auto_alt_ref(svc_ctx, option_value);
if (res != VPX_CODEC_OK) break;
+ } else if (strcmp("multi-frame-contexts", option_name) == 0) {
+ si->use_multiple_frame_contexts = atoi(option_value);
} else {
svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
res = VPX_CODEC_INVALID_PARAM;
@@ -401,6 +405,10 @@ static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
option_name = strtok_r(NULL, "=", &input_ptr);
}
free(input_string);
+
+ if (si->use_multiple_frame_contexts && svc_ctx->spatial_layers > 3)
+ res = VPX_CODEC_INVALID_PARAM;
+
return res;
}
@@ -534,7 +542,8 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
enc_cfg->rc_buf_initial_sz = 500;
enc_cfg->rc_buf_optimal_sz = 600;
enc_cfg->rc_buf_sz = 1000;
- enc_cfg->g_error_resilient = 1;
+ if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0)
+ enc_cfg->g_error_resilient = 1;
// Initialize codec
res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR);
diff --git a/vpx/src/vpx_decoder.c b/vpx/src/vpx_decoder.c
index b19c4409f..fdcc9c1b1 100644
--- a/vpx/src/vpx_decoder.c
+++ b/vpx/src/vpx_decoder.c
@@ -20,7 +20,7 @@
vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx,
vpx_codec_iface_t *iface,
- vpx_codec_dec_cfg_t *cfg,
+ const vpx_codec_dec_cfg_t *cfg,
vpx_codec_flags_t flags,
int ver) {
vpx_codec_err_t res;
diff --git a/vpx/src/vpx_encoder.c b/vpx/src/vpx_encoder.c
index 577345535..736a8daa2 100644
--- a/vpx/src/vpx_encoder.c
+++ b/vpx/src/vpx_encoder.c
@@ -22,7 +22,7 @@
vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t *ctx,
vpx_codec_iface_t *iface,
- vpx_codec_enc_cfg_t *cfg,
+ const vpx_codec_enc_cfg_t *cfg,
vpx_codec_flags_t flags,
int ver) {
vpx_codec_err_t res;
diff --git a/vpx/vpx_codec.h b/vpx/vpx_codec.h
index 07df72a78..91fc532b5 100644
--- a/vpx/vpx_codec.h
+++ b/vpx/vpx_codec.h
@@ -203,9 +203,11 @@ extern "C" {
const char *err_detail; /**< Detailed info, if available */
vpx_codec_flags_t init_flags; /**< Flags passed at init time */
union {
- struct vpx_codec_dec_cfg *dec; /**< Decoder Configuration Pointer */
- struct vpx_codec_enc_cfg *enc; /**< Encoder Configuration Pointer */
- void *raw;
+ /**< Decoder Configuration Pointer */
+ const struct vpx_codec_dec_cfg *dec;
+ /**< Encoder Configuration Pointer */
+ const struct vpx_codec_enc_cfg *enc;
+ const void *raw;
} config; /**< Configuration pointer aliasing union */
vpx_codec_priv_t *priv; /**< Algorithm private storage */
} vpx_codec_ctx_t;
diff --git a/vpx/vpx_decoder.h b/vpx/vpx_decoder.h
index 10b89fa0f..62fd91975 100644
--- a/vpx/vpx_decoder.h
+++ b/vpx/vpx_decoder.h
@@ -135,7 +135,7 @@ extern "C" {
*/
vpx_codec_err_t vpx_codec_dec_init_ver(vpx_codec_ctx_t *ctx,
vpx_codec_iface_t *iface,
- vpx_codec_dec_cfg_t *cfg,
+ const vpx_codec_dec_cfg_t *cfg,
vpx_codec_flags_t flags,
int ver);
diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h
index 58acf18a8..75d3a47b1 100644
--- a/vpx/vpx_encoder.h
+++ b/vpx/vpx_encoder.h
@@ -715,7 +715,7 @@ extern "C" {
*/
vpx_codec_err_t vpx_codec_enc_init_ver(vpx_codec_ctx_t *ctx,
vpx_codec_iface_t *iface,
- vpx_codec_enc_cfg_t *cfg,
+ const vpx_codec_enc_cfg_t *cfg,
vpx_codec_flags_t flags,
int ver);
diff --git a/vpxdec.c b/vpxdec.c
index 6efbc5b68..412504409 100644
--- a/vpxdec.c
+++ b/vpxdec.c
@@ -887,7 +887,7 @@ int main_loop(int argc, const char **argv_) {
display_height = display_size[1];
}
}
- scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, display_width,
+ scaled_img = vpx_img_alloc(NULL, img->fmt, display_width,
display_height, 16);
scaled_img->bit_depth = img->bit_depth;
}