[vaapi] Fix fuzzer error

If buffer allocation fails during a mid stream buffer reallocation then
the method CoreCodecMidStreamOutputBufferReConfigFinish() will never be
called and instead CoreCodecStopStream() will be called. Ensure that we
stop waiting if either is called. Also if output_re_config_required is
false when onCoreCodecMidStreamOutputConstraintsChange() is called then
the buffers are not reallocated, meaning that we should not wait since
CoreCodecMidStreamOutputBufferReConfigFinish() will not be called and
instead the new buffer constraints will be sent instead.

Bug: 103142
Change-Id: I260b5a2a9d99eb292534085c73970c3775db85f1
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/693807
Reviewed-by: John Bauman <jbauman@google.com>
Commit-Queue: Stefan Bossbaly <stefanbossbaly@google.com>
diff --git a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.cc b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.cc
index 50a2493..dfd7ec8 100644
--- a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.cc
+++ b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.cc
@@ -700,6 +700,11 @@
   input_queue_.Reset();
   free_output_packets_.Reset(/*keep_data=*/true);
 
+  {
+    std::lock_guard<std::mutex> guard(lock_);
+    is_stream_stopped_ = false;
+  }
+
   // If the stream has initialized then reset
   if (surface_buffer_manager_) {
     surface_buffer_manager_->Reset();
@@ -747,7 +752,8 @@
       // Trigger a mid stream output constraints change
       // TODO(fxbug.dev/102737): We always request a output reconfiguration. This may or may not be
       // needed.
-      events_->onCoreCodecMidStreamOutputConstraintsChange(true);
+      bool output_re_config_required = true;
+      events_->onCoreCodecMidStreamOutputConstraintsChange(output_re_config_required);
 
       gfx::Size pic_size = media_decoder_->GetPicSize();
       VAContextID context_id;
@@ -760,13 +766,20 @@
       }
       context_id_.emplace(context_id);
 
-      // Wait for the stream reconfiguration to finish before continuing to increment the surface
-      // generation value
-      {
+      // Only wait if an output reconfiguration was required. Otherwise the buffers will be kept and
+      // only the new output constraints will be sent.
+      if (output_re_config_required) {
+        // Wait for the stream reconfiguration to finish before continuing to increment the surface
+        // generation value
         std::unique_lock<std::mutex> lock(lock_);
         surface_buffer_manager_cv_.wait(lock, [this]() FXL_REQUIRE(lock_) {
-          return mid_stream_output_buffer_reconfig_finish_;
+          return mid_stream_output_buffer_reconfig_finish_ || is_stream_stopped_;
         });
+
+        // If the stream is stopped, exit immediately
+        if (is_stream_stopped_) {
+          return;
+        }
       }
 
       // Increment surface generation so all existing surfaces will be freed
diff --git a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.h b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.h
index c7df420..e4d92fa 100644
--- a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.h
+++ b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.h
@@ -196,6 +196,14 @@
     input_queue_.StopAllWaits();
     free_output_packets_.StopAllWaits();
 
+    // If we are waiting for a mid stream output buffer reconfiguration, stop.
+    // CoreCodecMidStreamOutputBufferReConfigFinish() will not be called.
+    {
+      std::lock_guard<std::mutex> guard(lock_);
+      is_stream_stopped_ = true;
+    }
+    surface_buffer_manager_cv_.notify_all();
+
     // It is possible a stream was started by no input packets were provided which means that the
     // surface buffer manager was never constructed.
     if (surface_buffer_manager_) {
@@ -611,6 +619,7 @@
   std::unique_ptr<SurfaceBufferManager> surface_buffer_manager_;
   std::condition_variable surface_buffer_manager_cv_;
   bool mid_stream_output_buffer_reconfig_finish_ FXL_GUARDED_BY(lock_) = false;
+  bool is_stream_stopped_ /* FXL_GUARDED_BY(lock_) */ = false;
 
   // Buffers the client has added but that we cannot use until configuration is
   // complete.