Revert "Enable H.264 hardware MFT encoder on Windows"

This reverts commit 2f702ab180c3ae6811682ba416750eae9bb8f720.

Reason for revert: https://crbug.com/1058627 https://crbug.com/1058583

Original change's description:
> Enable H.264 hardware MFT encoder on Windows
> 
> Currently Microsoft H.264 encoder MFT is always used as WebRTC external
> encoder without hardware acceleration. This change enables H.264
> hardware MFT encoder on Windows.
> 
> Bug: 982799
> Change-Id: Ia33812508034daa99dd3dc1fb64b83cb1d7c8465
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1777521
> Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
> Reviewed-by: Tommi <tommi@chromium.org>
> Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#745539}

TBR=tommi@chromium.org,dalecurtis@chromium.org,sprang@chromium.org,chunbo.hua@intel.com

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: 982799
Change-Id: Iab66c1936f27901889e371901642b72f80eff733
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2088733
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747051}
diff --git a/AUTHORS b/AUTHORS
index 2f966b7..17cdbe2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -187,7 +187,6 @@
 Chris Vasselli <clindsay@gmail.com>
 Christophe Dumez <ch.dumez@samsung.com>
 Christopher Dale <chrelad@gmail.com>
-Chunbo Hua <chunbo.hua@intel.com>
 Claudio DeSouza <claudiomdsjr@gmail.com>
 Clemens Fruhwirth <clemens@endorphin.org>
 Clement Scheelfeldt Skau <clementskau@gmail.com>
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
index 53a2edfb..4188bf95 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.cc
@@ -40,8 +40,9 @@
 const size_t kMaxResolutionHeight = 1088;
 const size_t kNumInputBuffers = 3;
 // Media Foundation uses 100 nanosecond units for time, see
-// https://msdn.microsoft.com/en-us/library/windows/desktop/ms697282(v=vs.85).aspx.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms697282(v=vs.85).aspx
 const size_t kOneMicrosecondInMFSampleTimeUnits = 10;
+const size_t kOutputSampleBufferSizeRatio = 4;
 
 constexpr const wchar_t* const kMediaFoundationVideoEncoderDLLs[] = {
     L"mf.dll", L"mfplat.dll",
@@ -107,10 +108,8 @@
 MediaFoundationVideoEncodeAccelerator::MediaFoundationVideoEncodeAccelerator(
     bool compatible_with_win7)
     : compatible_with_win7_(compatible_with_win7),
-      input_required_(false),
       main_client_task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      encoder_thread_("MFEncoderThread"),
-      encoder_task_weak_factory_(this) {}
+      encoder_thread_("MFEncoderThread") {}
 
 MediaFoundationVideoEncodeAccelerator::
     ~MediaFoundationVideoEncodeAccelerator() {
@@ -133,20 +132,18 @@
   frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator;
   input_visible_size_ = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight);
   if (!CreateHardwareEncoderMFT() || !SetEncoderModes() ||
-      !InitializeInputOutputParameters(H264PROFILE_BASELINE)) {
+      !InitializeInputOutputSamples(H264PROFILE_BASELINE)) {
     ReleaseEncoderResources();
     DVLOG(1)
         << "Hardware encode acceleration is not available on this platform.";
-
     return profiles;
   }
 
   gfx::Size highest_supported_resolution = input_visible_size_;
   for (const auto& resolution : kOptionalMaxResolutions) {
     DCHECK_GT(resolution.GetArea(), highest_supported_resolution.GetArea());
-    if (!IsResolutionSupported(resolution)) {
+    if (!IsResolutionSupported(resolution))
       break;
-    }
     highest_supported_resolution = resolution;
   }
   ReleaseEncoderResources();
@@ -203,13 +200,27 @@
   frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator;
   target_bitrate_ = config.initial_bitrate;
   bitstream_buffer_size_ = config.input_visible_size.GetArea();
+  u_plane_offset_ =
+      VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kYPlane,
+                            input_visible_size_)
+          .GetArea();
+  v_plane_offset_ = u_plane_offset_ + VideoFrame::PlaneSize(PIXEL_FORMAT_I420,
+                                                            VideoFrame::kUPlane,
+                                                            input_visible_size_)
+                                          .GetArea();
+  y_stride_ = VideoFrame::RowBytes(VideoFrame::kYPlane, PIXEL_FORMAT_I420,
+                                   input_visible_size_.width());
+  u_stride_ = VideoFrame::RowBytes(VideoFrame::kUPlane, PIXEL_FORMAT_I420,
+                                   input_visible_size_.width());
+  v_stride_ = VideoFrame::RowBytes(VideoFrame::kVPlane, PIXEL_FORMAT_I420,
+                                   input_visible_size_.width());
 
   if (!SetEncoderModes()) {
     DLOG(ERROR) << "Failed setting encoder parameters.";
     return false;
   }
 
-  if (!InitializeInputOutputParameters(config.output_profile)) {
+  if (!InitializeInputOutputSamples(config.output_profile)) {
     DLOG(ERROR) << "Failed initializing input-output samples.";
     return false;
   }
@@ -221,28 +232,25 @@
   input_sample_ = CreateEmptySampleWithBuffer(
       input_stream_info.cbSize
           ? input_stream_info.cbSize
-          : VideoFrame::AllocationSize(PIXEL_FORMAT_NV12, input_visible_size_),
+          : VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size_),
       input_stream_info.cbAlignment);
 
+  MFT_OUTPUT_STREAM_INFO output_stream_info;
+  hr = encoder_->GetOutputStreamInfo(output_stream_id_, &output_stream_info);
+  RETURN_ON_HR_FAILURE(hr, "Couldn't get output stream info", false);
+  output_sample_ = CreateEmptySampleWithBuffer(
+      output_stream_info.cbSize
+          ? output_stream_info.cbSize
+          : bitstream_buffer_size_ * kOutputSampleBufferSizeRatio,
+      output_stream_info.cbAlignment);
+
+  hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
+  RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false);
+
   main_client_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&Client::RequireBitstreamBuffers, main_client_,
                                 kNumInputBuffers, input_visible_size_,
                                 bitstream_buffer_size_));
-
-  hr = encoder_->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
-  RETURN_ON_HR_FAILURE(
-      hr, "Couldn't set ProcessMessage MFT_MESSAGE_COMMAND_FLUSH", false);
-  hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
-  RETURN_ON_HR_FAILURE(
-      hr, "Couldn't set ProcessMessage MFT_MESSAGE_NOTIFY_BEGIN_STREAMING",
-      false);
-  hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
-  RETURN_ON_HR_FAILURE(
-      hr, "Couldn't set ProcessMessage MFT_MESSAGE_NOTIFY_START_OF_STREAM",
-      false);
-  hr = encoder_->QueryInterface(IID_PPV_ARGS(&event_generator_));
-  RETURN_ON_HR_FAILURE(hr, "Couldn't get event generator", false);
-
   return SUCCEEDED(hr);
 }
 
@@ -351,9 +359,8 @@
     }
   }
 
-  if (!(session_ = InitializeMediaFoundation())) {
+  if (!(session_ = InitializeMediaFoundation()))
     return false;
-  }
 
   uint32_t flags = MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;
   MFT_REGISTER_TYPE_INFO input_info;
@@ -363,97 +370,32 @@
   output_info.guidMajorType = MFMediaType_Video;
   output_info.guidSubtype = MFVideoFormat_H264;
 
+  base::win::ScopedCoMem<CLSID> CLSIDs;
   uint32_t count = 0;
-  base::win::ScopedCoMem<IMFActivate*> pp_activate;
-  HRESULT hr = MFTEnumEx(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info,
-                         &output_info, &pp_activate, &count);
+  HRESULT hr = MFTEnum(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info,
+                       &output_info, NULL, &CLSIDs, &count);
   RETURN_ON_HR_FAILURE(hr, "Couldn't enumerate hardware encoder", false);
-  RETURN_ON_FAILURE((count > 0), "No hardware encoder found", false);
-  DVLOG(3) << "Hardware encoder(s) found: " << count;
-
-  // Try to create the encoder with priority according to merit value.
-  hr = E_FAIL;
-  for (UINT32 i = 0; i < count; i++) {
-    if (FAILED(hr)) {
-      DCHECK(!encoder_);
-      DCHECK(!activate_);
-      hr = pp_activate[i]->ActivateObject(IID_PPV_ARGS(&encoder_));
-      if (encoder_.Get() != nullptr) {
-        DCHECK(SUCCEEDED(hr));
-
-        activate_ = pp_activate[i];
-        pp_activate[i] = nullptr;
-
-        // Print the friendly name.
-        base::win::ScopedCoMem<WCHAR> friendly_name;
-        UINT32 name_length;
-        activate_->GetAllocatedString(MFT_FRIENDLY_NAME_Attribute,
-                                      &friendly_name, &name_length);
-        DVLOG(3) << "Selected hardware encoder's friendly name: "
-                 << friendly_name;
-      } else {
-        DCHECK(FAILED(hr));
-
-        // The component that calls ActivateObject is
-        // responsible for calling ShutdownObject,
-        // https://docs.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfactivate-shutdownobject.
-        pp_activate[i]->ShutdownObject();
-      }
-    }
-
-    // Release the enumerated instances. According to Windows Dev Center,
-    // https://docs.microsoft.com/en-us/windows/win32/api/mfapi/nf-mfapi-mftenumex
-    // The caller must release the pointers.
-    if (pp_activate[i]) {
-      pp_activate[i]->Release();
-      pp_activate[i] = nullptr;
-    }
-  }
-
+  RETURN_ON_FAILURE((count > 0), "No HW encoder found", false);
+  DVLOG(3) << "HW encoder(s) found: " << count;
+  hr = ::CoCreateInstance(CLSIDs[0], nullptr, CLSCTX_ALL,
+                          IID_PPV_ARGS(&encoder_));
   RETURN_ON_HR_FAILURE(hr, "Couldn't activate hardware encoder", false);
   RETURN_ON_FAILURE((encoder_.Get() != nullptr),
-                    "No hardware encoder instance created", false);
-
-  Microsoft::WRL::ComPtr<IMFAttributes> all_attributes;
-  hr = encoder_->GetAttributes(&all_attributes);
-  if (SUCCEEDED(hr)) {
-    // An asynchronous MFT must support dynamic format changes,
-    // https://docs.microsoft.com/en-us/windows/win32/medfound/asynchronous-mfts#format-changes.
-    UINT32 dynamic = FALSE;
-    hr = all_attributes->GetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, &dynamic);
-    if (!dynamic) {
-      DLOG(ERROR) << "Couldn't support dynamic format change.";
-      return false;
-    }
-
-    // Unlock the selected asynchronous MFTs,
-    // https://docs.microsoft.com/en-us/windows/win32/medfound/asynchronous-mfts#unlocking-asynchronous-mfts.
-    UINT32 async = FALSE;
-    hr = all_attributes->GetUINT32(MF_TRANSFORM_ASYNC, &async);
-    if (!async) {
-      DLOG(ERROR) << "MFT encoder is not asynchronous.";
-      return false;
-    }
-
-    hr = all_attributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
-    RETURN_ON_HR_FAILURE(hr, "Couldn't unlock transform async", false);
-  }
-
+                    "No HW encoder instance created", false);
   return true;
 }
 
-bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputParameters(
+bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputSamples(
     VideoCodecProfile output_profile) {
   DCHECK(main_client_task_runner_->BelongsToCurrentThread());
-  DCHECK(encoder_);
 
   DWORD input_count = 0;
   DWORD output_count = 0;
   HRESULT hr = encoder_->GetStreamCount(&input_count, &output_count);
   RETURN_ON_HR_FAILURE(hr, "Couldn't get stream count", false);
   if (input_count < 1 || output_count < 1) {
-    DLOG(ERROR) << "Stream count too few: input " << input_count << ", output "
-                << output_count;
+    LOG(ERROR) << "Stream count too few: input " << input_count << ", output "
+               << output_count;
     return false;
   }
 
@@ -468,13 +410,13 @@
     input_stream_id_ = 0;
     output_stream_id_ = 0;
   } else {
-    DLOG(ERROR) << "Couldn't find stream ids from hardware encoder.";
+    LOG(ERROR) << "Couldn't find stream ids.";
     return false;
   }
 
   // Initialize output parameters.
   hr = MFCreateMediaType(&imf_output_media_type_);
-  RETURN_ON_HR_FAILURE(hr, "Couldn't create output media type", false);
+  RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false);
   hr = imf_output_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false);
   hr = imf_output_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264);
@@ -500,10 +442,10 @@
 
   // Initialize input parameters.
   hr = MFCreateMediaType(&imf_input_media_type_);
-  RETURN_ON_HR_FAILURE(hr, "Couldn't create input media type", false);
+  RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false);
   hr = imf_input_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false);
-  hr = imf_input_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12);
+  hr = imf_input_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false);
   hr = MFSetAttributeRatio(imf_input_media_type_.Get(), MF_MT_FRAME_RATE,
                            frame_rate_, 1);
@@ -523,11 +465,11 @@
 
 bool MediaFoundationVideoEncodeAccelerator::SetEncoderModes() {
   DCHECK(main_client_task_runner_->BelongsToCurrentThread());
-  DCHECK(encoder_);
+  RETURN_ON_FAILURE((encoder_.Get() != nullptr),
+                    "No HW encoder instance created", false);
 
   HRESULT hr = encoder_.As(&codec_api_);
   RETURN_ON_HR_FAILURE(hr, "Couldn't get ICodecAPI", false);
-
   VARIANT var;
   var.vt = VT_UI4;
   var.ulVal = eAVEncCommonRateControlMode_CBR;
@@ -539,37 +481,21 @@
     // setting it on Windows 7 returns error.
     RETURN_ON_HR_FAILURE(hr, "Couldn't set CommonRateControlMode", false);
   }
-
-  if (S_OK ==
-      codec_api_->IsModifiable(&CODECAPI_AVEncVideoTemporalLayerCount)) {
-    var.ulVal = 1;
-    hr = codec_api_->SetValue(&CODECAPI_AVEncVideoTemporalLayerCount, &var);
-    if (!compatible_with_win7_) {
-      RETURN_ON_HR_FAILURE(hr, "Couldn't set temporal layer count", false);
-    }
-  }
-
   var.ulVal = target_bitrate_;
   hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var);
   if (!compatible_with_win7_) {
     RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false);
   }
-
-  if (S_OK == codec_api_->IsModifiable(&CODECAPI_AVEncAdaptiveMode)) {
-    var.ulVal = eAVEncAdaptiveMode_Resolution;
-    hr = codec_api_->SetValue(&CODECAPI_AVEncAdaptiveMode, &var);
-    if (!compatible_with_win7_) {
-      RETURN_ON_HR_FAILURE(hr, "Couldn't set adaptive mode", false);
-    }
+  var.ulVal = eAVEncAdaptiveMode_Resolution;
+  hr = codec_api_->SetValue(&CODECAPI_AVEncAdaptiveMode, &var);
+  if (!compatible_with_win7_) {
+    RETURN_ON_HR_FAILURE(hr, "Couldn't set FrameRate", false);
   }
-
-  if (S_OK == codec_api_->IsModifiable(&CODECAPI_AVLowLatencyMode)) {
-    var.vt = VT_BOOL;
-    var.boolVal = VARIANT_TRUE;
-    hr = codec_api_->SetValue(&CODECAPI_AVLowLatencyMode, &var);
-    if (!compatible_with_win7_) {
-      RETURN_ON_HR_FAILURE(hr, "Couldn't set low latency mode", false);
-    }
+  var.vt = VT_BOOL;
+  var.boolVal = VARIANT_TRUE;
+  hr = codec_api_->SetValue(&CODECAPI_AVLowLatencyMode, &var);
+  if (!compatible_with_win7_) {
+    RETURN_ON_HR_FAILURE(hr, "Couldn't set LowLatencyMode", false);
   }
 
   return true;
@@ -612,79 +538,27 @@
   DVLOG(3) << __func__;
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
 
-  bool input_delivered = false;
-  if (input_required_) {
-    // HMFT is waiting for this coming input.
-    ProcessInput(frame, force_keyframe);
-    input_delivered = true;
-    input_required_ = false;
-  } else {
-    Microsoft::WRL::ComPtr<IMFMediaEvent> media_event;
-    HRESULT hr =
-        event_generator_->GetEvent(MF_EVENT_FLAG_NO_WAIT, &media_event);
-    if (FAILED(hr)) {
-      DLOG(WARNING) << "Abandoned input frame for video encoder.";
-      return;
-    }
-
-    MediaEventType event_type;
-    hr = media_event->GetType(&event_type);
-    if (FAILED(hr)) {
-      DLOG(ERROR) << "Failed to get the type of media event.";
-      return;
-    }
-
-    // Always deliver the current input into HMFT.
-    if (event_type == METransformNeedInput) {
-      ProcessInput(frame, force_keyframe);
-      input_delivered = true;
-    } else if (event_type == METransformHaveOutput) {
-      ProcessOutput();
-      input_delivered =
-          TryToDeliverInputFrame(std::move(frame), force_keyframe);
-    }
-  }
-
-  if (!input_delivered) {
-    DLOG(ERROR) << "Failed to deliver input frame to video encoder";
-    return;
-  }
-
-  TryToReturnBitstreamBuffer();
-}
-
-void MediaFoundationVideoEncodeAccelerator::ProcessInput(
-    scoped_refptr<VideoFrame> frame,
-    bool force_keyframe) {
-  DVLOG(3) << __func__;
-  DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
-
-  // Convert I420 to NV12 as input.
   Microsoft::WRL::ComPtr<IMFMediaBuffer> input_buffer;
   input_sample_->GetBufferByIndex(0, &input_buffer);
 
   {
     MediaBufferScopedPointer scoped_buffer(input_buffer.Get());
     DCHECK(scoped_buffer.get());
-    int dst_stride_y = frame->stride(VideoFrame::kYPlane);
-    uint8_t* dst_uv =
-        scoped_buffer.get() +
-        frame->stride(VideoFrame::kYPlane) * frame->rows(VideoFrame::kYPlane);
-    int dst_stride_uv = frame->stride(VideoFrame::kUPlane) * 2;
-    libyuv::I420ToNV12(frame->visible_data(VideoFrame::kYPlane),
-                       frame->stride(VideoFrame::kYPlane),
-                       frame->visible_data(VideoFrame::kUPlane),
-                       frame->stride(VideoFrame::kUPlane),
-                       frame->visible_data(VideoFrame::kVPlane),
-                       frame->stride(VideoFrame::kVPlane), scoped_buffer.get(),
-                       dst_stride_y, dst_uv, dst_stride_uv,
-                       input_visible_size_.width(),
-                       input_visible_size_.height());
+    libyuv::I420Copy(frame->visible_data(VideoFrame::kYPlane),
+                     frame->stride(VideoFrame::kYPlane),
+                     frame->visible_data(VideoFrame::kVPlane),
+                     frame->stride(VideoFrame::kVPlane),
+                     frame->visible_data(VideoFrame::kUPlane),
+                     frame->stride(VideoFrame::kUPlane), scoped_buffer.get(),
+                     y_stride_, scoped_buffer.get() + u_plane_offset_,
+                     u_stride_, scoped_buffer.get() + v_plane_offset_,
+                     v_stride_, input_visible_size_.width(),
+                     input_visible_size_.height());
   }
 
   input_sample_->SetSampleTime(frame->timestamp().InMicroseconds() *
                                kOneMicrosecondInMFSampleTimeUnits);
-  UINT64 sample_duration = 0;
+  UINT64 sample_duration = 1;
   HRESULT hr =
       MFFrameRateToAverageTimePerFrame(frame_rate_, 1, &sample_duration);
   RETURN_ON_HR_FAILURE(hr, "Couldn't calculate sample duration", );
@@ -698,70 +572,80 @@
     var.vt = VT_UI4;
     var.ulVal = 1;
     hr = codec_api_->SetValue(&CODECAPI_AVEncVideoForceKeyFrame, &var);
-    if (!compatible_with_win7_ && FAILED(hr)) {
+    if (!compatible_with_win7_ && !SUCCEEDED(hr)) {
       LOG(WARNING) << "Failed to set CODECAPI_AVEncVideoForceKeyFrame, "
                       "HRESULT: 0x" << std::hex << hr;
     }
   }
 
   hr = encoder_->ProcessInput(input_stream_id_, input_sample_.Get(), 0);
-  if (FAILED(hr)) {
+  // According to MSDN, if encoder returns MF_E_NOTACCEPTING, we need to try
+  // processing the output. This error indicates that encoder does not accept
+  // any more input data.
+  if (hr == MF_E_NOTACCEPTING) {
+    DVLOG(3) << "MF_E_NOTACCEPTING";
+    ProcessOutput();
+    hr = encoder_->ProcessInput(input_stream_id_, input_sample_.Get(), 0);
+    if (!SUCCEEDED(hr)) {
+      NotifyError(kPlatformFailureError);
+      RETURN_ON_HR_FAILURE(hr, "Couldn't encode", );
+    }
+  } else if (!SUCCEEDED(hr)) {
     NotifyError(kPlatformFailureError);
     RETURN_ON_HR_FAILURE(hr, "Couldn't encode", );
   }
-
   DVLOG(3) << "Sent for encode " << hr;
+
+  ProcessOutput();
 }
 
 void MediaFoundationVideoEncodeAccelerator::ProcessOutput() {
   DVLOG(3) << __func__;
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
 
-  MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0};
-  output_data_buffer.dwStreamID = output_stream_id_;
-  output_data_buffer.dwStatus = 0;
-  output_data_buffer.pEvents = nullptr;
-  output_data_buffer.pSample = nullptr;
-  DWORD status = 0;
-  HRESULT hr = encoder_->ProcessOutput(0, 1, &output_data_buffer, &status);
-  if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
-    hr = S_OK;
-    Microsoft::WRL::ComPtr<IMFMediaType> media_type;
-    for (DWORD type_index = 0; SUCCEEDED(hr); ++type_index) {
-      hr = encoder_->GetOutputAvailableType(output_stream_id_, type_index,
-                                            &media_type);
-      if (SUCCEEDED(hr)) {
-        break;
-      }
-    }
-    hr = encoder_->SetOutputType(output_stream_id_, media_type.Get(), 0);
+  DWORD output_status = 0;
+  HRESULT hr = encoder_->GetOutputStatus(&output_status);
+  RETURN_ON_HR_FAILURE(hr, "Couldn't get output status", );
+  if (output_status != MFT_OUTPUT_STATUS_SAMPLE_READY) {
+    DVLOG(3) << "Output isnt ready";
     return;
   }
 
+  MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0};
+  output_data_buffer.dwStreamID = 0;
+  output_data_buffer.dwStatus = 0;
+  output_data_buffer.pEvents = NULL;
+  output_data_buffer.pSample = output_sample_.Get();
+  DWORD status = 0;
+  hr = encoder_->ProcessOutput(output_stream_id_, 1, &output_data_buffer,
+                               &status);
+  if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
+    DVLOG(3) << "MF_E_TRANSFORM_NEED_MORE_INPUT" << status;
+    return;
+  }
   RETURN_ON_HR_FAILURE(hr, "Couldn't get encoded data", );
   DVLOG(3) << "Got encoded data " << hr;
 
   Microsoft::WRL::ComPtr<IMFMediaBuffer> output_buffer;
-  hr = output_data_buffer.pSample->GetBufferByIndex(0, &output_buffer);
+  hr = output_sample_->GetBufferByIndex(0, &output_buffer);
   RETURN_ON_HR_FAILURE(hr, "Couldn't get buffer by index", );
-
   DWORD size = 0;
   hr = output_buffer->GetCurrentLength(&size);
   RETURN_ON_HR_FAILURE(hr, "Couldn't get buffer length", );
 
   base::TimeDelta timestamp;
   LONGLONG sample_time;
-  hr = output_data_buffer.pSample->GetSampleTime(&sample_time);
+  hr = output_sample_->GetSampleTime(&sample_time);
   if (SUCCEEDED(hr)) {
     timestamp = base::TimeDelta::FromMicroseconds(
         sample_time / kOneMicrosecondInMFSampleTimeUnits);
   }
 
   const bool keyframe = MFGetAttributeUINT32(
-      output_data_buffer.pSample, MFSampleExtension_CleanPoint, false);
-  DVLOG(3) << "Encoded data with size:" << size << " keyframe " << keyframe;
+      output_sample_.Get(), MFSampleExtension_CleanPoint, false);
+  DVLOG(3) << "We HAVE encoded data with size:" << size << " keyframe "
+           << keyframe;
 
-  // If no bit stream buffer presents, queue the output first.
   if (bitstream_buffer_queue_.empty()) {
     DVLOG(3) << "No bitstream buffers.";
     // We need to copy the output so that encoding can continue.
@@ -772,12 +656,9 @@
       memcpy(encode_output->memory(), scoped_buffer.get(), size);
     }
     encoder_output_queue_.push_back(std::move(encode_output));
-    output_data_buffer.pSample->Release();
-    output_data_buffer.pSample = nullptr;
     return;
   }
 
-  // Immediately return encoded buffer with BitstreamBuffer to client.
   std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef>
       buffer_ref = std::move(bitstream_buffer_queue_.front());
   bitstream_buffer_queue_.pop_front();
@@ -787,88 +668,15 @@
     memcpy(buffer_ref->mapping.memory(), scoped_buffer.get(), size);
   }
 
-  output_data_buffer.pSample->Release();
-  output_data_buffer.pSample = nullptr;
-
   main_client_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&Client::BitstreamBufferReady, main_client_,
                      buffer_ref->id,
                      BitstreamBufferMetadata(size, keyframe, timestamp)));
-}
 
-bool MediaFoundationVideoEncodeAccelerator::TryToDeliverInputFrame(
-    scoped_refptr<VideoFrame> frame,
-    bool force_keyframe) {
-  bool input_delivered = false;
-  Microsoft::WRL::ComPtr<IMFMediaEvent> media_event;
-  MediaEventType event_type;
-  do {
-    HRESULT hr =
-        event_generator_->GetEvent(MF_EVENT_FLAG_NO_WAIT, &media_event);
-    if (FAILED(hr)) {
-      break;
-    }
-
-    hr = media_event->GetType(&event_type);
-    if (FAILED(hr)) {
-      DLOG(ERROR) << "Failed to get the type of media event.";
-      break;
-    }
-
-    switch (event_type) {
-      case METransformHaveOutput: {
-        ProcessOutput();
-        continue;
-      }
-      case METransformNeedInput: {
-        ProcessInput(frame, force_keyframe);
-        return true;
-      }
-      default:
-        break;
-    }
-  } while (true);
-
-  return input_delivered;
-}
-
-void MediaFoundationVideoEncodeAccelerator::TryToReturnBitstreamBuffer() {
-  // Try to fetch the encoded frame in time.
-  bool output_processed = false;
-  do {
-    Microsoft::WRL::ComPtr<IMFMediaEvent> media_event;
-    MediaEventType event_type;
-    HRESULT hr =
-        event_generator_->GetEvent(MF_EVENT_FLAG_NO_WAIT, &media_event);
-    if (FAILED(hr)) {
-      if (!output_processed) {
-        continue;
-      } else {
-        break;
-      }
-    }
-
-    hr = media_event->GetType(&event_type);
-    if (FAILED(hr)) {
-      DLOG(ERROR) << "Failed to get the type of media event.";
-      break;
-    }
-
-    switch (event_type) {
-      case METransformHaveOutput: {
-        ProcessOutput();
-        output_processed = true;
-        break;
-      }
-      case METransformNeedInput: {
-        input_required_ = true;
-        continue;
-      }
-      default:
-        break;
-    }
-  } while (true);
+  // Keep calling ProcessOutput recursively until MF_E_TRANSFORM_NEED_MORE_INPUT
+  // is returned to flush out all the output.
+  ProcessOutput();
 }
 
 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
@@ -881,22 +689,31 @@
     std::unique_ptr<MediaFoundationVideoEncodeAccelerator::EncodeOutput>
         encode_output = std::move(encoder_output_queue_.front());
     encoder_output_queue_.pop_front();
-    memcpy(buffer_ref->mapping.memory(), encode_output->memory(),
-           encode_output->size());
-
-    main_client_task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&Client::BitstreamBufferReady, main_client_,
-                       buffer_ref->id,
-                       BitstreamBufferMetadata(
-                           encode_output->size(), encode_output->keyframe,
-                           encode_output->capture_timestamp)));
+    ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref));
     return;
   }
 
   bitstream_buffer_queue_.push_back(std::move(buffer_ref));
 }
 
+void MediaFoundationVideoEncodeAccelerator::ReturnBitstreamBuffer(
+    std::unique_ptr<EncodeOutput> encode_output,
+    std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef>
+        buffer_ref) {
+  DVLOG(3) << __func__;
+  DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
+
+  memcpy(buffer_ref->mapping.memory(), encode_output->memory(),
+         encode_output->size());
+  main_client_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&Client::BitstreamBufferReady, main_client_,
+                     buffer_ref->id,
+                     BitstreamBufferMetadata(
+                         encode_output->size(), encode_output->keyframe,
+                         encode_output->capture_timestamp)));
+}
+
 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
     uint32_t bitrate,
     uint32_t framerate) {
@@ -915,7 +732,7 @@
     var.ulVal = target_bitrate_;
     HRESULT hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var);
     if (!compatible_with_win7_) {
-      RETURN_ON_HR_FAILURE(hr, "Couldn't update bitrate", );
+      RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", );
     }
   }
 }
@@ -931,22 +748,12 @@
 }
 
 void MediaFoundationVideoEncodeAccelerator::ReleaseEncoderResources() {
-  while (!bitstream_buffer_queue_.empty())
-    bitstream_buffer_queue_.pop_front();
-  while (!encoder_output_queue_.empty())
-    encoder_output_queue_.pop_front();
-
-  if (activate_.Get() != nullptr) {
-    activate_->ShutdownObject();
-    activate_->Release();
-    activate_.Reset();
-  }
   encoder_.Reset();
   codec_api_.Reset();
-  event_generator_.Reset();
   imf_input_media_type_.Reset();
   imf_output_media_type_.Reset();
   input_sample_.Reset();
+  output_sample_.Reset();
 }
 
-}  // namespace media
+}  // namespace content
diff --git a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
index 228b636..e7f5cff 100644
--- a/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
+++ b/media/gpu/windows/media_foundation_video_encode_accelerator_win.h
@@ -65,8 +65,8 @@
   // Creates an hardware encoder backed IMFTransform instance on |encoder_|.
   bool CreateHardwareEncoderMFT();
 
-  // Initializes and allocates memory for input and output parameters.
-  bool InitializeInputOutputParameters(VideoCodecProfile output_profile);
+  // Initializes and allocates memory for input and output samples.
+  bool InitializeInputOutputSamples(VideoCodecProfile output_profile);
 
   // Initializes encoder parameters for real-time use.
   bool SetEncoderModes();
@@ -82,23 +82,20 @@
   // Encoding tasks to be run on |encoder_thread_|.
   void EncodeTask(scoped_refptr<VideoFrame> frame, bool force_keyframe);
 
-  // Processes the input video frame for the encoder.
-  void ProcessInput(scoped_refptr<VideoFrame> frame, bool force_keyframe);
-
   // Checks for and copies encoded output on |encoder_thread_|.
   void ProcessOutput();
 
-  // Tries to deliver the input frame to the encoder.
-  bool TryToDeliverInputFrame(scoped_refptr<VideoFrame> frame,
-                              bool force_keyframe);
-
-  // Tries to return a bitstream buffer to the client.
-  void TryToReturnBitstreamBuffer();
-
   // Inserts the output buffers for reuse on |encoder_thread_|.
   void UseOutputBitstreamBufferTask(
       std::unique_ptr<BitstreamBufferRef> buffer_ref);
 
+  // Copies EncodeOutput into a BitstreamBuffer and returns it to the
+  // |main_client_|.
+  void ReturnBitstreamBuffer(
+      std::unique_ptr<EncodeOutput> encode_output,
+      std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef>
+          buffer_ref);
+
   // Changes encode parameters on |encoder_thread_|.
   void RequestEncodingParametersChangeTask(uint32_t bitrate,
                                            uint32_t framerate);
@@ -122,11 +119,14 @@
   size_t bitstream_buffer_size_;
   uint32_t frame_rate_;
   uint32_t target_bitrate_;
+  size_t u_plane_offset_;
+  size_t v_plane_offset_;
+  size_t y_stride_;
+  size_t u_stride_;
+  size_t v_stride_;
 
-  Microsoft::WRL::ComPtr<IMFActivate> activate_;
   Microsoft::WRL::ComPtr<IMFTransform> encoder_;
   Microsoft::WRL::ComPtr<ICodecAPI> codec_api_;
-  Microsoft::WRL::ComPtr<IMFMediaEventGenerator> event_generator_;
 
   DWORD input_stream_id_;
   DWORD output_stream_id_;
@@ -134,8 +134,8 @@
   Microsoft::WRL::ComPtr<IMFMediaType> imf_input_media_type_;
   Microsoft::WRL::ComPtr<IMFMediaType> imf_output_media_type_;
 
-  bool input_required_;
   Microsoft::WRL::ComPtr<IMFSample> input_sample_;
+  Microsoft::WRL::ComPtr<IMFSample> output_sample_;
 
   // MediaFoundation session.
   MFSessionLifetime session_;
@@ -155,7 +155,7 @@
   // Declared last to ensure that all weak pointers are invalidated before
   // other destructors run.
   base::WeakPtrFactory<MediaFoundationVideoEncodeAccelerator>
-      encoder_task_weak_factory_;
+      encoder_task_weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MediaFoundationVideoEncodeAccelerator);
 };