diff --git a/media/libvpx/libvpx/examples.mk b/media/libvpx/libvpx/examples.mk --- a/media/libvpx/libvpx/examples.mk +++ b/media/libvpx/libvpx/examples.mk @@ -367,10 +367,17 @@ INSTALL-BINS-$(CONFIG_MSVS) += $(foreach p,$(VS_PLATFORMS),\ $(addprefix bin/$(p)/,$(ALL_EXAMPLES_BASENAME:.c=.exe))) $(foreach proj,$(call enabled,PROJECTS),\ $(eval $(call vcproj_template,$(proj)))) +# Generate a list of all enabled sources, in particular for exporting to gyp +# based build systems. +vpxdec_srcs.txt: + @echo " [CREATE] $@" + @echo $(vpxdec.SRCS) | xargs -n1 echo | LC_ALL=C sort -u > $@ +CLEAN-OBJS += vpxdec_srcs.txt + # # Documentation Rules # %.dox: %.c @echo " [DOXY] $@" diff --git a/media/libvpx/libvpx/test/resize_test.cc b/media/libvpx/libvpx/test/resize_test.cc --- a/media/libvpx/libvpx/test/resize_test.cc +++ b/media/libvpx/libvpx/test/resize_test.cc @@ -91,15 +91,24 @@ }; void ScaleForFrameNumber(unsigned int frame, unsigned int initial_w, unsigned int initial_h, unsigned int *w, unsigned int *h, bool flag_codec, - bool smaller_width_larger_size_) { + bool smaller_width_larger_size, + bool random_input_one_half_only) { *w = initial_w; *h = initial_h; - if (smaller_width_larger_size_) { + if (random_input_one_half_only == 1) { + if (frame < 100) { + return; + } + *w = initial_w / 2; + *h = initial_h / 2; + return; + } + if (smaller_width_larger_size) { if (frame < 30) { return; } *w = initial_w * 7 / 10; *h = initial_h * 16 / 10; @@ -234,29 +243,49 @@ } } class ResizingVideoSource : public ::libvpx_test::DummyVideoSource { public: - ResizingVideoSource() { - SetSize(kInitialWidth, kInitialHeight); + ResizingVideoSource(int width, int height) + : smaller_width_larger_size_(false), random_input_one_half_only_(false), + configured_width_(width), configured_height_(height) { limit_ = 350; - smaller_width_larger_size_ = false; + SetSize(configured_width_, configured_height_); } bool flag_codec_; bool smaller_width_larger_size_; + bool random_input_one_half_only_; + // configured_width_/height_ is the configured resolution when codec is + // created. + int configured_width_; + int configured_height_; ~ResizingVideoSource() override = default; protected: void Next() override { ++frame_; unsigned int width = 0; unsigned int height = 0; - ScaleForFrameNumber(frame_, kInitialWidth, kInitialHeight, &width, &height, - flag_codec_, smaller_width_larger_size_); + ScaleForFrameNumber(frame_, configured_width_, configured_height_, &width, + &height, flag_codec_, smaller_width_larger_size_, + random_input_one_half_only_); SetSize(width, height); FillFrame(); } + + void FillFrame() override { + if (img_) { + memset(img_->img_data, 0, raw_sz_); + if (random_input_one_half_only_) { + libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed()); + unsigned char *image = img_->planes[0]; + for (size_t i = 0; i < raw_sz_; ++i) { + image[i] = rnd.Rand8(); + } + } + } + } }; class ResizeTest : public ::libvpx_test::EncoderTest, public ::libvpx_test::CodecTestWithParam { @@ -294,30 +323,30 @@ std::vector encode_frame_width_; std::vector encode_frame_height_; }; TEST_P(ResizeTest, TestExternalResizeWorks) { - ResizingVideoSource video; + ResizingVideoSource video(kInitialWidth, kInitialHeight); video.flag_codec_ = false; video.smaller_width_larger_size_ = false; cfg_.g_lag_in_frames = 0; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const unsigned int frame = static_cast(info->pts); + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); unsigned int expected_w; unsigned int expected_h; - const size_t idx = info - frame_info_list_.begin(); - ASSERT_EQ(info->w, GetFrameWidth(idx)); - ASSERT_EQ(info->h, GetFrameHeight(idx)); + const size_t idx = &info - &frame_info_list_[0]; + ASSERT_EQ(info.w, GetFrameWidth(idx)); + ASSERT_EQ(info.h, GetFrameHeight(idx)); ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w, &expected_h, video.flag_codec_, - video.smaller_width_larger_size_); - EXPECT_EQ(expected_w, info->w) + video.smaller_width_larger_size_, + /*random_input_one_half_only=*/false); + EXPECT_EQ(expected_w, info.w) << "Frame " << frame << " had unexpected width"; - EXPECT_EQ(expected_h, info->h) + EXPECT_EQ(expected_h, info.h) << "Frame " << frame << " had unexpected height"; } } const unsigned int kStepDownFrame = 3; @@ -417,19 +446,18 @@ // frames to detect mismatch would then not be possible. Set // g_lag_in_frames = 0 to get around this. cfg_.g_lag_in_frames = 0; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const vpx_codec_pts_t pts = info->pts; + for (const auto &info : frame_info_list_) { + const vpx_codec_pts_t pts = info.pts; if (pts >= kStepDownFrame && pts < kStepUpFrame) { - ASSERT_EQ(282U, info->w) << "Frame " << pts << " had unexpected width"; - ASSERT_EQ(173U, info->h) << "Frame " << pts << " had unexpected height"; + ASSERT_EQ(282U, info.w) << "Frame " << pts << " had unexpected width"; + ASSERT_EQ(173U, info.h) << "Frame " << pts << " had unexpected height"; } else { - EXPECT_EQ(352U, info->w) << "Frame " << pts << " had unexpected width"; - EXPECT_EQ(288U, info->h) << "Frame " << pts << " had unexpected height"; + EXPECT_EQ(352U, info.w) << "Frame " << pts << " had unexpected width"; + EXPECT_EQ(288U, info.h) << "Frame " << pts << " had unexpected height"; } } } TEST_P(ResizeInternalTest, TestInternalResizeChangeConfig) { @@ -451,10 +479,14 @@ void PreEncodeFrameHook(libvpx_test::VideoSource *video, libvpx_test::Encoder *encoder) override { if (video->frame() == 0) { encoder->Control(VP9E_SET_AQ_MODE, 3); encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); + if (cfg_.g_threads > 0) { + encoder->Control(VP9E_SET_ROW_MT, 1); + encoder->Control(VP9E_SET_TILE_COLUMNS, cfg_.g_threads >> 1); + } } if (change_bitrate_ && video->frame() == 120) { change_bitrate_ = false; cfg_.rc_target_bitrate = 500; @@ -526,62 +558,95 @@ std::vector encode_frame_width_; std::vector encode_frame_height_; }; TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) { - ResizingVideoSource video; + ResizingVideoSource video(kInitialWidth, kInitialHeight); video.flag_codec_ = true; video.smaller_width_larger_size_ = false; DefaultConfig(); // Disable internal resize for this test. cfg_.rc_resize_allowed = 0; change_bitrate_ = false; mismatch_psnr_ = 0.0; mismatch_nframes_ = 0; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const unsigned int frame = static_cast(info->pts); + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); unsigned int expected_w; unsigned int expected_h; ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w, &expected_h, video.flag_codec_, - video.smaller_width_larger_size_); - EXPECT_EQ(expected_w, info->w) + video.smaller_width_larger_size_, + /*random_input_one_half_only=*/false); + EXPECT_EQ(expected_w, info.w) << "Frame " << frame << " had unexpected width"; - EXPECT_EQ(expected_h, info->h) + EXPECT_EQ(expected_h, info.h) << "Frame " << frame << " had unexpected height"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); + } +} + +// This test uses 4 threads with small keyframe spacing, random input, +// and uses 640x480 as initial resolution. +TEST_P(ResizeRealtimeTest, TestExternalResizeWorks4Threads) { + ResizingVideoSource video(640, 480); + video.flag_codec_ = true; + video.smaller_width_larger_size_ = false; + video.random_input_one_half_only_ = true; + DefaultConfig(); + // Disable internal resize for this test. + cfg_.rc_resize_allowed = 0; + cfg_.g_threads = 4; + cfg_.kf_max_dist = 50; + cfg_.kf_min_dist = 50; + change_bitrate_ = false; + mismatch_psnr_ = 0.0; + mismatch_nframes_ = 0; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); + unsigned int expected_w; + unsigned int expected_h; + ScaleForFrameNumber(frame, 640, 480, &expected_w, &expected_h, + video.flag_codec_, video.smaller_width_larger_size_, + video.random_input_one_half_only_); + EXPECT_EQ(expected_w, info.w) + << "Frame " << frame << " had unexpected width"; + EXPECT_EQ(expected_h, info.h) + << "Frame " << frame << " had unexpected height"; + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); } } TEST_P(ResizeRealtimeTest, TestExternalResizeSmallerWidthBiggerSize) { - ResizingVideoSource video; + ResizingVideoSource video(kInitialWidth, kInitialHeight); video.flag_codec_ = true; video.smaller_width_larger_size_ = true; DefaultConfig(); // Disable internal resize for this test. cfg_.rc_resize_allowed = 0; change_bitrate_ = false; mismatch_psnr_ = 0.0; mismatch_nframes_ = 0; ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const unsigned int frame = static_cast(info->pts); + for (const auto &info : frame_info_list_) { + const unsigned int frame = static_cast(info.pts); unsigned int expected_w; unsigned int expected_h; ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w, &expected_h, video.flag_codec_, - video.smaller_width_larger_size_); - EXPECT_EQ(expected_w, info->w) + video.smaller_width_larger_size_, + /*random_input_one_half_only=*/false); + EXPECT_EQ(expected_w, info.w) << "Frame " << frame << " had unexpected width"; - EXPECT_EQ(expected_h, info->h) + EXPECT_EQ(expected_h, info.h) << "Frame " << frame << " had unexpected height"; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); } } // Verify the dynamic resizer behavior for real time, 1 pass CBR mode. // Run at low bitrate, with resize_allowed = 1, and verify that we get @@ -599,25 +664,24 @@ #if CONFIG_VP9_DECODER unsigned int last_w = cfg_.g_w; unsigned int last_h = cfg_.g_h; int resize_count = 0; - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - if (info->w != last_w || info->h != last_h) { + for (const auto &info : frame_info_list_) { + if (info.w != last_w || info.h != last_h) { // Verify that resize down occurs. - ASSERT_LT(info->w, last_w); - ASSERT_LT(info->h, last_h); - last_w = info->w; - last_h = info->h; + ASSERT_LT(info.w, last_w); + ASSERT_LT(info.h, last_h); + last_w = info.w; + last_h = info.h; resize_count++; } } // Verify that we get 1 resize down event in this test. ASSERT_EQ(1, resize_count) << "Resizing should occur."; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); #else GTEST_SKIP() << "Warning: VP9 decoder unavailable, unable to check resize count!\n"; #endif } @@ -641,35 +705,34 @@ ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); unsigned int last_w = cfg_.g_w; unsigned int last_h = cfg_.g_h; int resize_count = 0; - for (std::vector::const_iterator info = frame_info_list_.begin(); - info != frame_info_list_.end(); ++info) { - const size_t idx = info - frame_info_list_.begin(); - ASSERT_EQ(info->w, GetFrameWidth(idx)); - ASSERT_EQ(info->h, GetFrameHeight(idx)); - if (info->w != last_w || info->h != last_h) { + for (const auto &info : frame_info_list_) { + const size_t idx = &info - &frame_info_list_[0]; + ASSERT_EQ(info.w, GetFrameWidth(idx)); + ASSERT_EQ(info.h, GetFrameHeight(idx)); + if (info.w != last_w || info.h != last_h) { resize_count++; if (resize_count <= 2) { // Verify that resize down occurs. - ASSERT_LT(info->w, last_w); - ASSERT_LT(info->h, last_h); + ASSERT_LT(info.w, last_w); + ASSERT_LT(info.h, last_h); } else if (resize_count > 2) { // Verify that resize up occurs. - ASSERT_GT(info->w, last_w); - ASSERT_GT(info->h, last_h); + ASSERT_GT(info.w, last_w); + ASSERT_GT(info.h, last_h); } - last_w = info->w; - last_h = info->h; + last_w = info.w; + last_h = info.h; } } #if CONFIG_VP9_DECODER // Verify that we get 4 resize events in this test. ASSERT_EQ(resize_count, 4) << "Resizing should occur twice."; - EXPECT_EQ(static_cast(0), GetMismatchFrames()); + EXPECT_EQ(GetMismatchFrames(), static_cast(0)); #else GTEST_SKIP() << "Warning: VP9 decoder unavailable, unable to check resize count!\n"; #endif } diff --git a/media/libvpx/libvpx/test/svc_datarate_test.cc b/media/libvpx/libvpx/test/svc_datarate_test.cc --- a/media/libvpx/libvpx/test/svc_datarate_test.cc +++ b/media/libvpx/libvpx/test/svc_datarate_test.cc @@ -572,11 +572,14 @@ int num_layers_encoded = 0; last_pts_ = pkt->data.frame.pts; const bool key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? true : false; if (external_resize_dynamic_drop_layer_) { - ASSERT_FALSE(key_frame && superframe_cnt_ > 1); + // No key frames expected in stream, except for first. + if (cfg_.kf_max_dist > 1000) { + ASSERT_FALSE(key_frame && superframe_cnt_ > 1); + } } if (key_frame) { // For test that inserts layer sync frames: requesting a layer_sync on // the base layer must force key frame. So if any key frame occurs after // first superframe it must due to layer sync on base spatial layer. @@ -808,25 +811,29 @@ } } class ResizingVideoSource : public ::libvpx_test::DummyVideoSource { public: - ResizingVideoSource() { - SetSize(1280, 720); + ResizingVideoSource(int width, int height) { + top_width_ = width; + top_height_ = height; + SetSize(top_width_, top_height_); limit_ = 300; } int external_resize_pattern_ = 1; int force_zero_source_ = 0; + int top_width_; + int top_height_; ~ResizingVideoSource() override = default; protected: void Next() override { ++frame_; unsigned int width = 0; unsigned int height = 0; libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed()); - ScaleForFrameNumber(frame_, 1280, 720, &width, &height, + ScaleForFrameNumber(frame_, top_width_, top_height_, &width, &height, external_resize_pattern_); SetSize(width, height); FillFrame(); unsigned char *image = img_->planes[0]; for (size_t i = 0; i < raw_sz_; ++i) { @@ -1350,11 +1357,11 @@ cfg_.rc_resize_allowed = 0; cfg_.g_w = 1280; cfg_.g_h = 720; top_sl_width_ = 1280; top_sl_height_ = 720; - ResizingVideoSource video; + ResizingVideoSource video(1280, 720); video.external_resize_pattern_ = 1; video.force_zero_source_ = 0; cfg_.rc_target_bitrate = 1000; ResetModel(); dynamic_drop_layer_ = false; @@ -1391,11 +1398,53 @@ cfg_.rc_resize_allowed = 0; cfg_.g_w = 1280; cfg_.g_h = 720; top_sl_width_ = 1280; top_sl_height_ = 720; - ResizingVideoSource video; + ResizingVideoSource video(1280, 720); + video.external_resize_pattern_ = 2; + video.force_zero_source_ = 0; + cfg_.rc_target_bitrate = 1000; + ResetModel(); + dynamic_drop_layer_ = false; + single_layer_resize_ = false; + denoiser_on_ = 1; + base_speed_setting_ = speed_setting_; + external_resize_dynamic_drop_layer_ = true; + external_resize_pattern_ = video.external_resize_pattern_; + AssignLayerBitrates(); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + +// For 1 pass CBR SVC with 3 spatial and 3 temporal layers with external resize +// and denoiser enabled. The external resizer will resize down and back up, +// setting 0/nonzero bitrate on spatial enhancement layers to disable/enable +// layers. Resizing starts on first frame and the pattern is: +// 1/2 -> 1/4 -> 1 -> 1/2 -> 1/4. This test uses 4 threads with small keyframe +// spacing, and top resolution is 1280x960. +TEST_P(DatarateOnePassCbrSvcSingleBR, + OnePassCbrSvc3SL3TL_DenoiseExternalResizePattern2Key4Threads) { + SetSvcConfig(3, 3); + cfg_.rc_buf_initial_sz = 500; + cfg_.rc_buf_optimal_sz = 500; + cfg_.rc_buf_sz = 1000; + cfg_.rc_min_quantizer = 40; + cfg_.rc_max_quantizer = 63; + cfg_.g_threads = 4; + cfg_.temporal_layering_mode = 3; + cfg_.ts_rate_decimator[0] = 4; + cfg_.ts_rate_decimator[1] = 2; + cfg_.ts_rate_decimator[2] = 1; + cfg_.rc_dropframe_thresh = 1; + cfg_.kf_max_dist = 40; + cfg_.kf_min_dist = 40; + cfg_.rc_resize_allowed = 0; + cfg_.g_w = 1280; + cfg_.g_h = 960; + top_sl_width_ = cfg_.g_w; + top_sl_height_ = cfg_.g_h; + ResizingVideoSource video(1280, 960); video.external_resize_pattern_ = 2; video.force_zero_source_ = 0; cfg_.rc_target_bitrate = 1000; ResetModel(); dynamic_drop_layer_ = false; @@ -1433,11 +1482,11 @@ cfg_.rc_resize_allowed = 0; cfg_.g_w = 1280; cfg_.g_h = 720; top_sl_width_ = 1280; top_sl_height_ = 720; - ResizingVideoSource video; + ResizingVideoSource video(1280, 720); video.external_resize_pattern_ = 1; video.force_zero_source_ = 1; cfg_.rc_target_bitrate = 1000; ResetModel(); dynamic_drop_layer_ = false; diff --git a/media/libvpx/libvpx/vp8/encoder/encodeframe.c b/media/libvpx/libvpx/vp8/encoder/encodeframe.c --- a/media/libvpx/libvpx/vp8/encoder/encodeframe.c +++ b/media/libvpx/libvpx/vp8/encoder/encodeframe.c @@ -745,12 +745,14 @@ } #endif { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer emr_timer; vpx_usec_timer_start(&emr_timer); +#endif #if CONFIG_MULTITHREAD if (vpx_atomic_load_acquire(&cpi->b_multi_threaded)) { int i; @@ -892,12 +894,14 @@ cpi->partition_sz[i + 1] = bc[i].pos; } } #endif +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&emr_timer); cpi->time_encode_mb_row += vpx_usec_timer_elapsed(&emr_timer); +#endif } // Work out the segment probabilities if segmentation is enabled // and needs to be updated if (xd->segmentation_enabled && xd->update_mb_segmentation_map) { diff --git a/media/libvpx/libvpx/vp8/encoder/onyx_if.c b/media/libvpx/libvpx/vp8/encoder/onyx_if.c --- a/media/libvpx/libvpx/vp8/encoder/onyx_if.c +++ b/media/libvpx/libvpx/vp8/encoder/onyx_if.c @@ -3138,15 +3138,19 @@ } if (cm->no_lpf) { cm->filter_level = 0; } else { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer timer; +#endif vpx_clear_system_state(); +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&timer); +#endif if (cpi->sf.auto_filter == 0) { #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity && cm->frame_type != KEY_FRAME) { // Use the denoised buffer for selecting base loop filter level. // Denoised signal for current frame is stored in INTRA_FRAME. @@ -3177,12 +3181,14 @@ if (cm->filter_level > 0) { vp8cx_set_alt_lf_level(cpi, cm->filter_level); } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&timer); cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer); +#endif } #if CONFIG_MULTITHREAD if (vpx_atomic_load_acquire(&cpi->b_multi_threaded)) { /* signal that we have set filter_level */ @@ -4782,14 +4788,18 @@ #endif int vp8_receive_raw_frame(VP8_COMP *cpi, unsigned int frame_flags, YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time) { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer timer; +#endif int res = 0; +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&timer); +#endif /* Reinit the lookahead buffer if the frame size changes */ if (sd->y_width != cpi->oxcf.Width || sd->y_height != cpi->oxcf.Height) { assert(cpi->oxcf.lag_in_frames < 2); dealloc_raw_frame_buffers(cpi); @@ -4798,12 +4808,14 @@ if (vp8_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, frame_flags, cpi->active_map_enabled ? cpi->active_map : NULL)) { res = -1; } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&timer); cpi->time_receive_data += vpx_usec_timer_elapsed(&timer); +#endif return res; } static int frame_is_reference(const VP8_COMP *cpi) { @@ -4822,18 +4834,22 @@ unsigned char *dest_end, int64_t *time_stamp, int64_t *time_end, int flush) { VP8_COMMON *cm; struct vpx_usec_timer tsctimer; struct vpx_usec_timer ticktimer; +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer cmptimer; +#endif YV12_BUFFER_CONFIG *force_src_buffer = NULL; if (!cpi) return -1; cm = &cpi->common; +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&cmptimer); +#endif cpi->source = NULL; #if !CONFIG_REALTIME_ONLY /* Should we code an alternate reference frame */ @@ -5131,12 +5147,14 @@ } /* Save layer specific state */ if (cpi->oxcf.number_of_layers > 1) vp8_save_layer_context(cpi); +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&cmptimer); cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer); +#endif #if CONFIG_MULTITHREAD /* wait for the lpf thread done */ if (vpx_atomic_load_acquire(&cpi->b_multi_threaded) && cpi->b_lpf_running) { vp8_sem_wait(&cpi->h_event_end_lpf); diff --git a/media/libvpx/libvpx/vp8/encoder/onyx_int.h b/media/libvpx/libvpx/vp8/encoder/onyx_int.h --- a/media/libvpx/libvpx/vp8/encoder/onyx_int.h +++ b/media/libvpx/libvpx/vp8/encoder/onyx_int.h @@ -554,14 +554,16 @@ fractional_mv_step_fp *find_fractional_mv_step; vp8_refining_search_fn_t refining_search_sad; vp8_diamond_search_fn_t diamond_search_sad; vp8_variance_fn_ptr_t fn_ptr[BLOCK_MAX_SEGMENTS]; +#if CONFIG_INTERNAL_STATS uint64_t time_receive_data; uint64_t time_compress_data; uint64_t time_pick_lpf; uint64_t time_encode_mb_row; +#endif int base_skip_false_prob[128]; FRAME_CONTEXT lfc_n; /* last frame entropy */ FRAME_CONTEXT lfc_a; /* last alt ref entropy */ diff --git a/media/libvpx/libvpx/vp8/vp8_cx_iface.c b/media/libvpx/libvpx/vp8/vp8_cx_iface.c --- a/media/libvpx/libvpx/vp8/vp8_cx_iface.c +++ b/media/libvpx/libvpx/vp8/vp8_cx_iface.c @@ -992,23 +992,14 @@ dst_end_time_stamp = pts_end * ctx->timestamp_ratio.num / ctx->timestamp_ratio.den; res = image2yuvconfig(img, &sd); - if (sd.y_width != ctx->cfg.g_w || sd.y_height != ctx->cfg.g_h) { - /* from vpx_encoder.h for g_w/g_h: - "Note that the frames passed as input to the encoder must have this - resolution" - */ - ctx->base.err_detail = "Invalid input frame resolution"; - res = VPX_CODEC_INVALID_PARAM; - } else { - if (vp8_receive_raw_frame(ctx->cpi, ctx->next_frame_flag | lib_flags, - &sd, dst_time_stamp, dst_end_time_stamp)) { - VP8_COMP *cpi = (VP8_COMP *)ctx->cpi; - res = update_error_state(ctx, &cpi->common.error); - } + if (vp8_receive_raw_frame(ctx->cpi, ctx->next_frame_flag | lib_flags, &sd, + dst_time_stamp, dst_end_time_stamp)) { + VP8_COMP *cpi = (VP8_COMP *)ctx->cpi; + res = update_error_state(ctx, &cpi->common.error); } /* reset for next frame */ ctx->next_frame_flag = 0; } diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.c b/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_encodeframe.c @@ -6177,12 +6177,14 @@ // Frame segmentation if (cpi->oxcf.aq_mode == PERCEPTUAL_AQ) build_kmeans_segmentation(cpi); { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer emr_timer; vpx_usec_timer_start(&emr_timer); +#endif if (!cpi->row_mt) { cpi->row_mt_sync_read_ptr = vp9_row_mt_sync_read_dummy; cpi->row_mt_sync_write_ptr = vp9_row_mt_sync_write_dummy; // If allowed, encoding tiles in parallel with one thread handling one @@ -6195,12 +6197,14 @@ cpi->row_mt_sync_read_ptr = vp9_row_mt_sync_read; cpi->row_mt_sync_write_ptr = vp9_row_mt_sync_write; vp9_encode_tiles_row_mt(cpi); } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&emr_timer); cpi->time_encode_sb_row += vpx_usec_timer_elapsed(&emr_timer); +#endif } sf->skip_encode_frame = sf->skip_encode_sb ? get_skip_encode_frame(cm, td) : 0; diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_encoder.h b/media/libvpx/libvpx/vp9/encoder/vp9_encoder.h --- a/media/libvpx/libvpx/vp9/encoder/vp9_encoder.h +++ b/media/libvpx/libvpx/vp9/encoder/vp9_encoder.h @@ -865,14 +865,16 @@ fractional_mv_step_fp *find_fractional_mv_step; struct scale_factors me_sf; vp9_diamond_search_fn_t diamond_search_sad; vp9_variance_fn_ptr_t fn_ptr[BLOCK_SIZES]; +#if CONFIG_INTERNAL_STATS uint64_t time_receive_data; uint64_t time_compress_data; uint64_t time_pick_lpf; uint64_t time_encode_sb_row; +#endif TWO_PASS twopass; // Force recalculation of segment_ids for each mode info uint8_t force_update_segmentation; diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_encoder.c b/media/libvpx/libvpx/vp9/encoder/vp9_encoder.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_encoder.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_encoder.c @@ -3498,15 +3498,19 @@ if (xd->lossless) { lf->filter_level = 0; lf->last_filt_level = 0; } else { +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer timer; +#endif vpx_clear_system_state(); +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&timer); +#endif if (!cpi->rc.is_src_frame_alt_ref) { if ((cpi->common.frame_type == KEY_FRAME) && (!cpi->rc.this_key_frame_forced)) { lf->last_filt_level = 0; @@ -3515,12 +3519,14 @@ lf->last_filt_level = lf->filter_level; } else { lf->filter_level = 0; } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&timer); cpi->time_pick_lpf += vpx_usec_timer_elapsed(&timer); +#endif } if (lf->filter_level > 0 && is_reference_frame) { vp9_build_mask_frame(cm, lf->filter_level, 0); @@ -6027,11 +6033,13 @@ int vp9_receive_raw_frame(VP9_COMP *cpi, vpx_enc_frame_flags_t frame_flags, YV12_BUFFER_CONFIG *sd, int64_t time_stamp, int64_t end_time) { VP9_COMMON *const cm = &cpi->common; +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer timer; +#endif int res = 0; const int subsampling_x = sd->subsampling_x; const int subsampling_y = sd->subsampling_y; #if CONFIG_VP9_HIGHBITDEPTH const int use_highbitdepth = (sd->flags & YV12_FLAG_HIGHBITDEPTH) != 0; @@ -6044,17 +6052,21 @@ setup_denoiser_buffer(cpi); #endif alloc_raw_frame_buffers(cpi); +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&timer); +#endif if (vp9_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, use_highbitdepth, frame_flags)) res = -1; +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&timer); cpi->time_receive_data += vpx_usec_timer_elapsed(&timer); +#endif if ((cm->profile == PROFILE_0 || cm->profile == PROFILE_2) && (subsampling_x != 1 || subsampling_y != 1)) { vpx_internal_error(&cm->error, VPX_CODEC_INVALID_PARAM, "Non-4:2:0 color format requires profile 1 or 3"); @@ -6458,11 +6470,13 @@ ENCODE_FRAME_RESULT *encode_frame_result) { const VP9EncoderConfig *const oxcf = &cpi->oxcf; VP9_COMMON *const cm = &cpi->common; BufferPool *const pool = cm->buffer_pool; RATE_CONTROL *const rc = &cpi->rc; +#if CONFIG_INTERNAL_STATS struct vpx_usec_timer cmptimer; +#endif YV12_BUFFER_CONFIG *force_src_buffer = NULL; struct lookahead_entry *last_source = NULL; struct lookahead_entry *source = NULL; int arf_src_index; const int gf_group_index = cpi->twopass.gf_group.index; @@ -6474,11 +6488,13 @@ if (is_one_pass_svc(cpi)) { vp9_one_pass_svc_start_layer(cpi); } +#if CONFIG_INTERNAL_STATS vpx_usec_timer_start(&cmptimer); +#endif vp9_set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV); // Is multi-arf enabled. // Note that at the moment multi_arf is only configured for 2 pass VBR and @@ -6815,12 +6831,14 @@ } if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) cpi->fixed_qp_onepass = 0; +#if CONFIG_INTERNAL_STATS vpx_usec_timer_mark(&cmptimer); cpi->time_compress_data += vpx_usec_timer_elapsed(&cmptimer); +#endif if (cpi->keep_level_stats && oxcf->pass != 1) update_level_info(cpi, size, arf_src_index); #if !CONFIG_REALTIME_ONLY diff --git a/media/libvpx/libvpx/vp9/encoder/vp9_lookahead.c b/media/libvpx/libvpx/vp9/encoder/vp9_lookahead.c --- a/media/libvpx/libvpx/vp9/encoder/vp9_lookahead.c +++ b/media/libvpx/libvpx/vp9/encoder/vp9_lookahead.c @@ -130,20 +130,28 @@ VP9_ENC_BORDER_IN_PIXELS, 0)) return 1; vpx_free_frame_buffer(&buf->img); buf->img = new_img; } else if (new_dimensions) { + int aligned_width = ALIGN_POWER_OF_TWO(width, 3); buf->img.y_width = src->y_width; buf->img.y_height = src->y_height; buf->img.uv_width = src->uv_width; buf->img.uv_height = src->uv_height; buf->img.y_crop_width = src->y_crop_width; buf->img.y_crop_height = src->y_crop_height; buf->img.uv_crop_width = src->uv_crop_width; buf->img.uv_crop_height = src->uv_crop_height; buf->img.subsampling_x = src->subsampling_x; buf->img.subsampling_y = src->subsampling_y; + // Here the new width (src->y_crop_width) is <= the previous width + // (since otherwise it would enter the "larger_dimensions" code), so + // it is safe here to update the stride. + // The stride setting is taken from vpx_alloc_frame_buffer(). + buf->img.y_stride = + ALIGN_POWER_OF_TWO((aligned_width + 2 * buf->img.border), 5); + buf->img.uv_stride = buf->img.y_stride >> subsampling_x; } vp9_copy_and_extend_frame(src, &buf->img); buf->ts_start = ts_start; buf->ts_end = ts_end; diff --git a/media/libvpx/libvpx/vp9/vp9_cx_iface.c b/media/libvpx/libvpx/vp9/vp9_cx_iface.c --- a/media/libvpx/libvpx/vp9/vp9_cx_iface.c +++ b/media/libvpx/libvpx/vp9/vp9_cx_iface.c @@ -1466,26 +1466,17 @@ } const int64_t dst_end_time_stamp = timebase_units_to_ticks(timebase_in_ts, pts_end); res = image2yuvconfig(img, &sd); - if (sd.y_width != ctx->cfg.g_w || sd.y_height != ctx->cfg.g_h) { - /* from vpx_encoder.h for g_w/g_h: - "Note that the frames passed as input to the encoder must have this - resolution" - */ - ctx->base.err_detail = "Invalid input frame resolution"; - res = VPX_CODEC_INVALID_PARAM; - } else { - // Store the original flags in to the frame buffer. Will extract the - // key frame flag when we actually encode this frame. - if (vp9_receive_raw_frame(cpi, flags | ctx->next_frame_flags, &sd, + // Store the original flags in to the frame buffer. Will extract the + // key frame flag when we actually encode this frame. + if (vp9_receive_raw_frame(cpi, flags | ctx->next_frame_flags, &sd, dst_time_stamp, dst_end_time_stamp)) { - res = update_error_state(ctx, &cpi->common.error); - } - ctx->next_frame_flags = 0; + res = update_error_state(ctx, &cpi->common.error); } + ctx->next_frame_flags = 0; } cx_data = ctx->cx_data; cx_data_sz = ctx->cx_data_sz; diff --git a/media/libvpx/libvpx/vpx_ports/aarch64_cpudetect.c b/media/libvpx/libvpx/vpx_ports/aarch64_cpudetect.c --- a/media/libvpx/libvpx/vpx_ports/aarch64_cpudetect.c +++ b/media/libvpx/libvpx/vpx_ports/aarch64_cpudetect.c @@ -14,11 +14,11 @@ #if defined(__APPLE__) #include #endif -#if !CONFIG_RUNTIME_CPU_DETECT || defined(__OpenBSD__) +#if !CONFIG_RUNTIME_CPU_DETECT static int arm_get_cpu_caps(void) { // This function should actually be a no-op. There is no way to adjust any of // these because the RTCD tables do not exist: the functions are called // statically. @@ -27,11 +27,11 @@ flags |= HAS_NEON; #endif // HAVE_NEON return flags; } -#elif defined(__APPLE__) // end !CONFIG_RUNTIME_CPU_DETECT || defined(__OpenBSD__) +#elif defined(__APPLE__) // end !CONFIG_RUNTIME_CPU_DETECT // sysctlbyname() parameter documentation for instruction set characteristics: // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics static INLINE int64_t have_feature(const char *feature) { int64_t feature_present = 0; diff --git a/media/libvpx/libvpx/vpx_ports/vpx_timer.h b/media/libvpx/libvpx/vpx_ports/vpx_timer.h --- a/media/libvpx/libvpx/vpx_ports/vpx_timer.h +++ b/media/libvpx/libvpx/vpx_ports/vpx_timer.h @@ -29,47 +29,51 @@ #include #else /* * POSIX specific includes */ -#include +#include /* timersub is not provided by msys at this time. */ -#ifndef timersub -#define timersub(a, b, result) \ +#ifndef timersub_ns +#define timersub_ns(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ + (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ + if ((result)->tv_nsec < 0) { \ --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ + (result)->tv_nsec += 1000000000; \ } \ } while (0) #endif #endif struct vpx_usec_timer { #if defined(_WIN32) LARGE_INTEGER begin, end; #else - struct timeval begin, end; + struct timespec begin, end; #endif }; static INLINE void vpx_usec_timer_start(struct vpx_usec_timer *t) { #if defined(_WIN32) QueryPerformanceCounter(&t->begin); +#elif defined(CLOCK_MONOTONIC_RAW) + clock_gettime(CLOCK_MONOTONIC_RAW, &t->begin); #else - gettimeofday(&t->begin, NULL); + clock_gettime(CLOCK_MONOTONIC, &t->begin); #endif } static INLINE void vpx_usec_timer_mark(struct vpx_usec_timer *t) { #if defined(_WIN32) QueryPerformanceCounter(&t->end); +#elif defined(CLOCK_MONOTONIC_RAW) + clock_gettime(CLOCK_MONOTONIC_RAW, &t->end); #else - gettimeofday(&t->end, NULL); + clock_gettime(CLOCK_MONOTONIC, &t->end); #endif } static INLINE int64_t vpx_usec_timer_elapsed(struct vpx_usec_timer *t) { #if defined(_WIN32) @@ -78,22 +82,22 @@ diff.QuadPart = t->end.QuadPart - t->begin.QuadPart; QueryPerformanceFrequency(&freq); return diff.QuadPart * 1000000 / freq.QuadPart; #else - struct timeval diff; + struct timespec diff; - timersub(&t->end, &t->begin, &diff); - return (int64_t)diff.tv_sec * 1000000 + diff.tv_usec; + timersub_ns(&t->end, &t->begin, &diff); + return (int64_t)diff.tv_sec * 1000000 + diff.tv_nsec / 1000; #endif } #else /* CONFIG_OS_SUPPORT = 0*/ /* Empty timer functions if CONFIG_OS_SUPPORT = 0 */ -#ifndef timersub -#define timersub(a, b, result) +#ifndef timersub_ns +#define timersub_ns(a, b, result) #endif struct vpx_usec_timer { void *dummy; }; diff --git a/media/libvpx/moz.yaml b/media/libvpx/moz.yaml --- a/media/libvpx/moz.yaml +++ b/media/libvpx/moz.yaml @@ -18,15 +18,15 @@ # Usually different from repository url url: https://chromium.googlesource.com/webm/libvpx # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: 95afae324986797afb19a606f3d95ecdf21e99a7 (Fri Feb 28 04:15:02 2025). + release: 027bbee30a0103b99d86327b48d29567fed11688 (Wed Mar 19 05:15:16 2025). # Revision to pull in # Must be a long or short commit SHA (long preferred) - revision: 95afae324986797afb19a606f3d95ecdf21e99a7 + revision: 027bbee30a0103b99d86327b48d29567fed11688 # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/ # Multiple licenses can be specified (as a YAML list) # A "LICENSE" file must exist containing the full license text