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);
};