Move lpf thread data init to lpf_pipeline_mt_init()

Add unit tests that trigger heap overflow.

Bug: aomedia:3429

Change-Id: I6db5be04a2f961c96e6115e982beec50b345d087
(cherry picked from commit 826ce59b303ece48f1b0e8aff1f54998e445e32b)
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index c0b0e30..209636d 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -1314,16 +1314,10 @@
                                            int num_workers) {
   MultiThreadInfo *const mt_info = &cpi->mt_info;
   AV1_COMMON *const cm = &cpi->common;
-  MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
   for (int i = num_workers - 1; i >= 0; i--) {
     AVxWorker *const worker = &mt_info->workers[i];
     EncWorkerData *const thread_data = &mt_info->tile_thr_data[i];
 
-    // Initialize loopfilter data
-    thread_data->lf_sync = &mt_info->lf_row_sync;
-    thread_data->lf_data = &thread_data->lf_sync->lfdata[i];
-    loop_filter_data_reset(thread_data->lf_data, &cm->cur_frame->buf, cm, xd);
-
     worker->hook = hook;
     worker->data1 = thread_data;
     worker->data2 = NULL;
@@ -1613,7 +1607,7 @@
 }
 #endif
 
-static void lpf_pipeline_mt_init(AV1_COMP *cpi) {
+static void lpf_pipeline_mt_init(AV1_COMP *cpi, int num_workers) {
   // Pipelining of loop-filtering after encoding is enabled when loop-filter
   // level is chosen based on quantizer and frame type. It is disabled in case
   // of 'LOOPFILTER_SELECTIVELY' as the stats collected during encoding stage
@@ -1624,18 +1618,20 @@
   const int use_superres = av1_superres_scaled(cm);
   const int use_cdef = is_cdef_used(cm);
   const int use_restoration = is_restoration_used(cm);
+  MultiThreadInfo *const mt_info = &cpi->mt_info;
+  MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
 
   const unsigned int skip_apply_postproc_filters =
       derive_skip_apply_postproc_filters(cpi, use_loopfilter, use_cdef,
                                          use_superres, use_restoration);
-  cpi->mt_info.pipeline_lpf_mt_with_enc =
+  mt_info->pipeline_lpf_mt_with_enc =
       (cpi->oxcf.mode == REALTIME) && (cpi->oxcf.speed >= 5) &&
       (cpi->sf.lpf_sf.lpf_pick == LPF_PICK_FROM_Q) &&
       (cpi->oxcf.algo_cfg.loopfilter_control != LOOPFILTER_SELECTIVELY) &&
       !cpi->ppi->rtc_ref.non_reference_frame && !cm->features.allow_intrabc &&
       ((skip_apply_postproc_filters & SKIP_APPLY_LOOPFILTER) == 0);
 
-  if (!cpi->mt_info.pipeline_lpf_mt_with_enc) return;
+  if (!mt_info->pipeline_lpf_mt_with_enc) return;
 
   set_postproc_filter_default_params(cm);
 
@@ -1661,12 +1657,20 @@
 
     av1_loop_filter_frame_init(cm, plane_start, plane_end);
 
-    assert(cpi->mt_info.num_mod_workers[MOD_ENC] ==
-           cpi->mt_info.num_mod_workers[MOD_LPF]);
+    assert(mt_info->num_mod_workers[MOD_ENC] ==
+           mt_info->num_mod_workers[MOD_LPF]);
     loop_filter_frame_mt_init(cm, start_mi_row, end_mi_row, planes_to_lf,
-                              cpi->mt_info.num_mod_workers[MOD_LPF],
-                              &cpi->mt_info.lf_row_sync, lpf_opt_level,
+                              mt_info->num_mod_workers[MOD_LPF],
+                              &mt_info->lf_row_sync, lpf_opt_level,
                               cm->seq_params->mib_size_log2);
+
+    for (int i = num_workers - 1; i >= 0; i--) {
+      EncWorkerData *const thread_data = &mt_info->tile_thr_data[i];
+      // Initialize loopfilter data
+      thread_data->lf_sync = &mt_info->lf_row_sync;
+      thread_data->lf_data = &thread_data->lf_sync->lfdata[i];
+      loop_filter_data_reset(thread_data->lf_data, &cm->cur_frame->buf, cm, xd);
+    }
   }
 }
 
@@ -1701,7 +1705,9 @@
                      cpi->oxcf.algo_cfg.cdf_update_mode);
   }
 
-  lpf_pipeline_mt_init(cpi);
+  num_workers = AOMMIN(num_workers, mt_info->num_workers);
+
+  lpf_pipeline_mt_init(cpi, num_workers);
 
   av1_init_tile_data(cpi);
 
@@ -1731,8 +1737,6 @@
     }
   }
 
-  num_workers = AOMMIN(num_workers, mt_info->num_workers);
-
   assign_tile_to_thread(thread_id_to_tile_id, tile_cols * tile_rows,
                         num_workers);
   prepare_enc_workers(cpi, enc_row_mt_worker_hook, num_workers);
diff --git a/test/resize_test.cc b/test/resize_test.cc
index d015ff0..e21f4bf 100644
--- a/test/resize_test.cc
+++ b/test/resize_test.cc
@@ -377,13 +377,15 @@
                            ::testing::Values(::libaom_test::kOnePassGood));
 #endif
 
+// Parameters: test mode, speed, threads
 class ResizeRealtimeTest
-    : public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode, int>,
+    : public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode, int,
+                                                 int>,
       public ::libaom_test::EncoderTest {
  protected:
   ResizeRealtimeTest()
-      : EncoderTest(GET_PARAM(0)), set_scale_mode_(false),
-        set_scale_mode2_(false) {}
+      : EncoderTest(GET_PARAM(0)), num_threads_(GET_PARAM(3)),
+        set_scale_mode_(false), set_scale_mode2_(false) {}
   virtual ~ResizeRealtimeTest() {}
 
   virtual void PreEncodeFrameHook(libaom_test::VideoSource *video,
@@ -457,6 +459,7 @@
     cfg_.rc_dropframe_thresh = 1;
     // Disable error_resilience mode.
     cfg_.g_error_resilient = 0;
+    cfg_.g_threads = num_threads_;
     // Run at low bitrate.
     cfg_.rc_target_bitrate = 200;
     // We use max(kInitialWidth, kInitialHeight) because during the test
@@ -472,6 +475,7 @@
 
   std::vector<FrameInfo> frame_info_list_;
   int set_cpu_used_;
+  int num_threads_;
   bool change_bitrate_;
   unsigned int frame_change_bitrate_;
   double mismatch_psnr_;
@@ -864,7 +868,7 @@
                            ::testing::Values(::libaom_test::kRealTime));
 AV1_INSTANTIATE_TEST_SUITE(ResizeRealtimeTest,
                            ::testing::Values(::libaom_test::kRealTime),
-                           ::testing::Range(6, 10));
+                           ::testing::Range(6, 10), ::testing::Values(1, 2, 4));
 AV1_INSTANTIATE_TEST_SUITE(ResizeCspTest,
                            ::testing::Values(::libaom_test::kRealTime));