Resolve issue 3491

BUG=aomedia:3491

Change-Id: I54916846c9dadc7263826c4d0dc8601880bab4fb
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index a3bd682..fe195f3 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -3126,8 +3126,10 @@
     if (ppi->p_mt_info.prev_num_enc_workers < num_enc_workers &&
         num_enc_workers <= ppi->p_mt_info.num_workers) {
       free_thread_data(ppi);
-      for (int j = 0; j < ppi->num_fp_contexts; j++)
+      for (int j = 0; j < ppi->num_fp_contexts; j++) {
         aom_free(ppi->parallel_cpi[j]->td.tctx);
+        ppi->parallel_cpi[j]->td.tctx = NULL;
+      }
       av1_init_tile_thread_data(ppi, cpi->oxcf.pass == AOM_RC_FIRST_PASS);
     }
 
diff --git a/av1/common/thread_common.c b/av1/common/thread_common.c
index 54d78f7..c215ee7 100644
--- a/av1/common/thread_common.c
+++ b/av1/common/thread_common.c
@@ -631,7 +631,7 @@
 }
 
 // Deallocate loop restoration synchronization related mutex and data
-void av1_loop_restoration_dealloc(AV1LrSync *lr_sync, int num_workers) {
+void av1_loop_restoration_dealloc(AV1LrSync *lr_sync) {
   if (lr_sync != NULL) {
     int j;
 #if CONFIG_MULTITHREAD
@@ -662,7 +662,8 @@
     aom_free(lr_sync->job_queue);
 
     if (lr_sync->lrworkerdata) {
-      for (int worker_idx = 0; worker_idx < num_workers - 1; worker_idx++) {
+      for (int worker_idx = 0; worker_idx < lr_sync->num_workers - 1;
+           worker_idx++) {
         LRWorkerData *const workerdata_data =
             lr_sync->lrworkerdata + worker_idx;
 
@@ -856,7 +857,7 @@
 
   if (!lr_sync->sync_range || num_rows_lr > lr_sync->rows ||
       num_workers > lr_sync->num_workers || num_planes > lr_sync->num_planes) {
-    av1_loop_restoration_dealloc(lr_sync, num_workers);
+    av1_loop_restoration_dealloc(lr_sync);
     av1_loop_restoration_alloc(lr_sync, cm, num_workers, num_rows_lr,
                                num_planes, cm->width);
   }
diff --git a/av1/common/thread_common.h b/av1/common/thread_common.h
index e38b9a8..cfbdc2f 100644
--- a/av1/common/thread_common.h
+++ b/av1/common/thread_common.h
@@ -186,7 +186,7 @@
                                           int optimized_lr, AVxWorker *workers,
                                           int num_workers, AV1LrSync *lr_sync,
                                           void *lr_ctxt, int do_extend_border);
-void av1_loop_restoration_dealloc(AV1LrSync *lr_sync, int num_workers);
+void av1_loop_restoration_dealloc(AV1LrSync *lr_sync);
 void av1_loop_restoration_alloc(AV1LrSync *lr_sync, AV1_COMMON *cm,
                                 int num_workers, int num_rows_lr,
                                 int num_planes, int width);
diff --git a/av1/decoder/decoder.c b/av1/decoder/decoder.c
index 4559dc6..33554a6 100644
--- a/av1/decoder/decoder.c
+++ b/av1/decoder/decoder.c
@@ -217,7 +217,7 @@
 
   if (pbi->num_workers > 0) {
     av1_loop_filter_dealloc(&pbi->lf_row_sync);
-    av1_loop_restoration_dealloc(&pbi->lr_row_sync, pbi->num_workers);
+    av1_loop_restoration_dealloc(&pbi->lr_row_sync);
     av1_dealloc_dec_jobs(&pbi->tile_mt_info);
   }
 
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 3d2e8f8..9bb9482 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1728,9 +1728,7 @@
     av1_loop_filter_dealloc(&mt_info->lf_row_sync);
     av1_cdef_mt_dealloc(&mt_info->cdef_sync);
 #if !CONFIG_REALTIME_ONLY
-    int num_lr_workers =
-        av1_get_num_mod_workers_for_alloc(&cpi->ppi->p_mt_info, MOD_LR);
-    av1_loop_restoration_dealloc(&mt_info->lr_row_sync, num_lr_workers);
+    av1_loop_restoration_dealloc(&mt_info->lr_row_sync);
     av1_tf_mt_dealloc(&mt_info->tf_sync);
 #endif
   }
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index fb9b85a..6f3cbd7 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -896,7 +896,7 @@
       if (!lr_sync->sync_range || num_rows_lr > lr_sync->rows ||
           num_lr_workers > lr_sync->num_workers ||
           MAX_MB_PLANE > lr_sync->num_planes) {
-        av1_loop_restoration_dealloc(lr_sync, num_lr_workers);
+        av1_loop_restoration_dealloc(lr_sync);
         av1_loop_restoration_alloc(lr_sync, cm, num_lr_workers, num_rows_lr,
                                    MAX_MB_PLANE, cm->width);
       }
@@ -3273,7 +3273,8 @@
   return AOMMIN(num_mb_rows, cpi->oxcf.max_threads);
 }
 
-int compute_num_mod_workers(AV1_COMP *cpi, MULTI_THREADED_MODULES mod_name) {
+static int compute_num_mod_workers(AV1_COMP *cpi,
+                                   MULTI_THREADED_MODULES mod_name) {
   int num_mod_workers = 0;
   switch (mod_name) {
     case MOD_FP:
@@ -3313,7 +3314,8 @@
 }
 // Computes the number of workers for each MT modules in the encoder
 void av1_compute_num_workers_for_mt(AV1_COMP *cpi) {
-  for (int i = MOD_FP; i < NUM_MT_MODULES; i++)
+  for (int i = MOD_FP; i < NUM_MT_MODULES; i++) {
     cpi->ppi->p_mt_info.num_mod_workers[i] =
         compute_num_mod_workers(cpi, (MULTI_THREADED_MODULES)i);
+  }
 }
diff --git a/test/resize_test.cc b/test/resize_test.cc
index dbfabe0..8083163 100644
--- a/test/resize_test.cc
+++ b/test/resize_test.cc
@@ -1054,4 +1054,91 @@
   EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
 }
 
+TEST(ResizeSimpleTest, TemporarySmallerFrameSizeMultiThread) {
+  constexpr int kWidth = 512;
+  constexpr int kHeight = 512;
+  constexpr int kFirstWidth = 256;
+  constexpr int kFirstHeight = 256;
+  // Buffer of zero samples.
+  constexpr size_t kBufferSize = 3 * kWidth * kHeight;
+  std::vector<unsigned char> buffer(kBufferSize, static_cast<unsigned char>(0));
+
+  aom_image_t img1;
+  EXPECT_EQ(&img1, aom_img_wrap(&img1, AOM_IMG_FMT_I420, kFirstWidth,
+                                kFirstHeight, 1, buffer.data()));
+
+  aom_image_t img2;
+  EXPECT_EQ(&img2, aom_img_wrap(&img2, AOM_IMG_FMT_I420, kWidth, kHeight, 1,
+                                buffer.data()));
+
+  aom_codec_iface_t *iface = aom_codec_av1_cx();
+  aom_codec_enc_cfg_t cfg;
+  EXPECT_EQ(AOM_CODEC_OK,
+            aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY));
+  cfg.g_threads = 4;
+  cfg.g_lag_in_frames = 1;
+  cfg.g_w = kFirstWidth;
+  cfg.g_h = kFirstHeight;
+  cfg.g_forced_max_frame_width = kWidth;
+  cfg.g_forced_max_frame_height = kHeight;
+  aom_codec_ctx_t enc;
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6));
+
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img1, 0, 1, 0));
+
+  cfg.g_w = kWidth;
+  cfg.g_h = kHeight;
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg));
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img2, 1, 1, 0));
+
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 0, 0));
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
+}
+
+// This test differs from "TemporarySmallerFrameSizeMultiThread" in that
+// it changes the number of threads from 4 to 2 before coding the second frame.
+TEST(ResizeSimpleTest, TemporarySmallerFrameSizeMultiThread2) {
+  constexpr int kWidth = 512;
+  constexpr int kHeight = 512;
+  constexpr int kFirstWidth = 256;
+  constexpr int kFirstHeight = 256;
+  // Buffer of zero samples.
+  constexpr size_t kBufferSize = 3 * kWidth * kHeight;
+  std::vector<unsigned char> buffer(kBufferSize, static_cast<unsigned char>(0));
+
+  aom_image_t img1;
+  EXPECT_EQ(&img1, aom_img_wrap(&img1, AOM_IMG_FMT_I420, kFirstWidth,
+                                kFirstHeight, 1, buffer.data()));
+
+  aom_image_t img2;
+  EXPECT_EQ(&img2, aom_img_wrap(&img2, AOM_IMG_FMT_I420, kWidth, kHeight, 1,
+                                buffer.data()));
+
+  aom_codec_iface_t *iface = aom_codec_av1_cx();
+  aom_codec_enc_cfg_t cfg;
+  EXPECT_EQ(AOM_CODEC_OK,
+            aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_GOOD_QUALITY));
+  cfg.g_threads = 4;
+  cfg.g_lag_in_frames = 1;
+  cfg.g_w = kFirstWidth;
+  cfg.g_h = kFirstHeight;
+  cfg.g_forced_max_frame_width = kWidth;
+  cfg.g_forced_max_frame_height = kHeight;
+  aom_codec_ctx_t enc;
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0));
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 6));
+
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img1, 0, 1, 0));
+
+  cfg.g_threads = 2;
+  cfg.g_w = kWidth;
+  cfg.g_h = kHeight;
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg));
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img2, 1, 1, 0));
+
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 0, 0));
+  EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc));
+}
+
 }  // namespace