| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/gpu/media_foundation_video_encode_accelerator_win.h" | 5 #include "media/gpu/media_foundation_video_encode_accelerator_win.h" |
| 6 | 6 |
| 7 #pragma warning(push) | 7 #pragma warning(push) |
| 8 #pragma warning(disable : 4800) // Disable warning for added padding. | 8 #pragma warning(disable : 4800) // Disable warning for added padding. |
| 9 | 9 |
| 10 #include <codecapi.h> | 10 #include <codecapi.h> |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 using base::win::ScopedComPtr; | 27 using base::win::ScopedComPtr; |
| 28 using media::mf::MediaBufferScopedPointer; | 28 using media::mf::MediaBufferScopedPointer; |
| 29 | 29 |
| 30 namespace media { | 30 namespace media { |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 | 33 |
| 34 const int32_t kDefaultTargetBitrate = 5000000; | 34 const int32_t kDefaultTargetBitrate = 5000000; |
| 35 const size_t kMaxFrameRateNumerator = 30; | 35 const size_t kMaxFrameRateNumerator = 30; |
| 36 const size_t kMaxFrameRateDenominator = 1; | 36 const size_t kMaxFrameRateDenominator = 1; |
| 37 const size_t kMaxResolutionWidth = 1920; | 37 const size_t kMaxResolutionWidth = 3840; |
| 38 const size_t kMaxResolutionHeight = 1088; | 38 const size_t kMaxResolutionHeight = 2176; |
| 39 const size_t kNumInputBuffers = 3; | 39 const size_t kNumInputBuffers = 3; |
| 40 // Media Foundation uses 100 nanosecond units for time, see | 40 // Media Foundation uses 100 nanosecond units for time, see |
| 41 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms697282(v=vs.85).as
px | 41 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms697282(v=vs.85).as
px |
| 42 const size_t kOneMicrosecondInMFSampleTimeUnits = 10; | 42 const size_t kOneMicrosecondInMFSampleTimeUnits = 10; |
| 43 const size_t kOneSecondInMFSampleTimeUnits = 10000000; | |
| 44 const size_t kOutputSampleBufferSizeRatio = 4; | 43 const size_t kOutputSampleBufferSizeRatio = 4; |
| 45 | 44 |
| 46 constexpr const wchar_t* const kMediaFoundationVideoEncoderDLLs[] = { | 45 constexpr const wchar_t* const kMediaFoundationVideoEncoderDLLs[] = { |
| 47 L"mf.dll", L"mfplat.dll", | 46 L"mf.dll", L"mfplat.dll", |
| 48 }; | 47 }; |
| 49 | 48 |
| 50 } // namespace | 49 } // namespace |
| 51 | 50 |
| 52 class MediaFoundationVideoEncodeAccelerator::EncodeOutput { | 51 class MediaFoundationVideoEncodeAccelerator::EncodeOutput { |
| 53 public: | 52 public: |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 u_plane_offset_ = | 169 u_plane_offset_ = |
| 171 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kYPlane, | 170 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kYPlane, |
| 172 input_visible_size_) | 171 input_visible_size_) |
| 173 .GetArea(); | 172 .GetArea(); |
| 174 v_plane_offset_ = | 173 v_plane_offset_ = |
| 175 u_plane_offset_ + | 174 u_plane_offset_ + |
| 176 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kUPlane, | 175 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kUPlane, |
| 177 input_visible_size_) | 176 input_visible_size_) |
| 178 .GetArea(); | 177 .GetArea(); |
| 179 | 178 |
| 180 | |
| 181 if (!SetEncoderModes()) { | 179 if (!SetEncoderModes()) { |
| 182 DLOG(ERROR) << "Failed setting encoder parameters."; | 180 DLOG(ERROR) << "Failed setting encoder parameters."; |
| 183 return false; | 181 return false; |
| 184 } | 182 } |
| 185 | 183 |
| 186 if (!InitializeInputOutputSamples()) { | 184 if (!InitializeInputOutputSamples()) { |
| 187 DLOG(ERROR) << "Failed initializing input-output samples."; | 185 DLOG(ERROR) << "Failed initializing input-output samples."; |
| 188 return false; | 186 return false; |
| 189 } | 187 } |
| 188 |
| 189 MFT_INPUT_STREAM_INFO input_stream_info; |
| 190 HRESULT hr = |
| 191 encoder_->GetInputStreamInfo(input_stream_id_, &input_stream_info); |
| 192 RETURN_ON_HR_FAILURE(hr, "Couldn't get input stream info", false); |
| 190 input_sample_.Attach(mf::CreateEmptySampleWithBuffer( | 193 input_sample_.Attach(mf::CreateEmptySampleWithBuffer( |
| 191 VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size_), 2)); | 194 input_stream_info.cbSize |
| 195 ? input_stream_info.cbSize |
| 196 : VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size_), |
| 197 input_stream_info.cbAlignment)); |
| 198 |
| 199 MFT_OUTPUT_STREAM_INFO output_stream_info; |
| 200 hr = encoder_->GetOutputStreamInfo(output_stream_id_, &output_stream_info); |
| 201 RETURN_ON_HR_FAILURE(hr, "Couldn't get output stream info", false); |
| 192 output_sample_.Attach(mf::CreateEmptySampleWithBuffer( | 202 output_sample_.Attach(mf::CreateEmptySampleWithBuffer( |
| 193 bitstream_buffer_size_ * kOutputSampleBufferSizeRatio, 2)); | 203 output_stream_info.cbSize |
| 204 ? output_stream_info.cbSize |
| 205 : bitstream_buffer_size_ * kOutputSampleBufferSizeRatio, |
| 206 output_stream_info.cbAlignment)); |
| 194 | 207 |
| 195 HRESULT hr = | 208 hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL); |
| 196 encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL); | |
| 197 RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false); | 209 RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false); |
| 198 | 210 |
| 199 // Pin all client callbacks to the main task runner initially. It can be | 211 // Pin all client callbacks to the main task runner initially. It can be |
| 200 // reassigned by TryToSetupEncodeOnSeparateThread(). | 212 // reassigned by TryToSetupEncodeOnSeparateThread(). |
| 201 if (!encode_client_task_runner_) { | 213 if (!encode_client_task_runner_) { |
| 202 encode_client_task_runner_ = main_client_task_runner_; | 214 encode_client_task_runner_ = main_client_task_runner_; |
| 203 encode_client_ = main_client_; | 215 encode_client_ = main_client_; |
| 204 } | 216 } |
| 205 | 217 |
| 206 main_client_task_runner_->PostTask( | 218 main_client_task_runner_->PostTask( |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 RETURN_ON_FAILURE((count > 0), "No HW encoder found", false); | 345 RETURN_ON_FAILURE((count > 0), "No HW encoder found", false); |
| 334 DVLOG(3) << "HW encoder(s) found: " << count; | 346 DVLOG(3) << "HW encoder(s) found: " << count; |
| 335 hr = encoder_.CreateInstance(CLSIDs[0]); | 347 hr = encoder_.CreateInstance(CLSIDs[0]); |
| 336 RETURN_ON_HR_FAILURE(hr, "Couldn't activate hardware encoder", false); | 348 RETURN_ON_HR_FAILURE(hr, "Couldn't activate hardware encoder", false); |
| 337 return true; | 349 return true; |
| 338 } | 350 } |
| 339 | 351 |
| 340 bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputSamples() { | 352 bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputSamples() { |
| 341 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); | 353 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 342 | 354 |
| 355 DWORD input_count = 0; |
| 356 DWORD output_count = 0; |
| 357 HRESULT hr = encoder_->GetStreamCount(&input_count, &output_count); |
| 358 RETURN_ON_HR_FAILURE(hr, "Couldn't get stream count", false); |
| 359 if (input_count < 1 || output_count < 1) { |
| 360 LOG(ERROR) << "Stream count too few: input " << input_count << ", output " |
| 361 << output_count; |
| 362 return false; |
| 363 } |
| 364 |
| 365 std::vector<DWORD> input_ids(input_count, 0); |
| 366 std::vector<DWORD> output_ids(output_count, 0); |
| 367 hr = encoder_->GetStreamIDs(input_count, input_ids.data(), output_count, |
| 368 output_ids.data()); |
| 369 if (hr == S_OK) { |
| 370 input_stream_id_ = input_ids[0]; |
| 371 output_stream_id_ = output_ids[0]; |
| 372 } else if (hr == E_NOTIMPL) { |
| 373 input_stream_id_ = 0; |
| 374 output_stream_id_ = 0; |
| 375 } else { |
| 376 LOG(ERROR) << "Couldn't find stream ids."; |
| 377 return false; |
| 378 } |
| 379 |
| 343 // Initialize output parameters. | 380 // Initialize output parameters. |
| 344 HRESULT hr = MFCreateMediaType(imf_output_media_type_.Receive()); | 381 hr = MFCreateMediaType(imf_output_media_type_.Receive()); |
| 345 RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false); | 382 RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false); |
| 346 hr = imf_output_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); | 383 hr = imf_output_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); |
| 347 RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false); | 384 RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false); |
| 348 hr = imf_output_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); | 385 hr = imf_output_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); |
| 349 RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false); | 386 RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false); |
| 350 hr = imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); | 387 hr = imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); |
| 351 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); | 388 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); |
| 352 hr = MFSetAttributeRatio(imf_output_media_type_.get(), MF_MT_FRAME_RATE, | 389 hr = MFSetAttributeRatio(imf_output_media_type_.get(), MF_MT_FRAME_RATE, |
| 353 frame_rate_, kMaxFrameRateDenominator); | 390 frame_rate_, 1); |
| 354 RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate", false); | 391 RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate", false); |
| 355 hr = MFSetAttributeSize(imf_output_media_type_.get(), MF_MT_FRAME_SIZE, | 392 hr = MFSetAttributeSize(imf_output_media_type_.get(), MF_MT_FRAME_SIZE, |
| 356 input_visible_size_.width(), | 393 input_visible_size_.width(), |
| 357 input_visible_size_.height()); | 394 input_visible_size_.height()); |
| 358 RETURN_ON_HR_FAILURE(hr, "Couldn't set frame size", false); | 395 RETURN_ON_HR_FAILURE(hr, "Couldn't set frame size", false); |
| 359 hr = imf_output_media_type_->SetUINT32(MF_MT_INTERLACE_MODE, | 396 hr = imf_output_media_type_->SetUINT32(MF_MT_INTERLACE_MODE, |
| 360 MFVideoInterlace_Progressive); | 397 MFVideoInterlace_Progressive); |
| 361 RETURN_ON_HR_FAILURE(hr, "Couldn't set interlace mode", false); | 398 RETURN_ON_HR_FAILURE(hr, "Couldn't set interlace mode", false); |
| 362 hr = imf_output_media_type_->SetUINT32(MF_MT_MPEG2_PROFILE, | 399 hr = imf_output_media_type_->SetUINT32(MF_MT_MPEG2_PROFILE, |
| 363 eAVEncH264VProfile_Base); | 400 eAVEncH264VProfile_Base); |
| 364 RETURN_ON_HR_FAILURE(hr, "Couldn't set codec profile", false); | 401 RETURN_ON_HR_FAILURE(hr, "Couldn't set codec profile", false); |
| 365 hr = encoder_->SetOutputType(0, imf_output_media_type_.get(), 0); | 402 hr = encoder_->SetOutputType(output_stream_id_, imf_output_media_type_.get(), |
| 403 0); |
| 366 RETURN_ON_HR_FAILURE(hr, "Couldn't set output media type", false); | 404 RETURN_ON_HR_FAILURE(hr, "Couldn't set output media type", false); |
| 367 | 405 |
| 368 // Initialize input parameters. | 406 // Initialize input parameters. |
| 369 hr = MFCreateMediaType(imf_input_media_type_.Receive()); | 407 hr = MFCreateMediaType(imf_input_media_type_.Receive()); |
| 370 RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false); | 408 RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false); |
| 371 hr = imf_input_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); | 409 hr = imf_input_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); |
| 372 RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false); | 410 RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false); |
| 373 hr = imf_input_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12); | 411 hr = imf_input_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_YV12); |
| 374 RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false); | 412 RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false); |
| 375 hr = MFSetAttributeRatio(imf_input_media_type_.get(), MF_MT_FRAME_RATE, | 413 hr = MFSetAttributeRatio(imf_input_media_type_.get(), MF_MT_FRAME_RATE, |
| 376 frame_rate_, kMaxFrameRateDenominator); | 414 frame_rate_, 1); |
| 377 RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate", false); | 415 RETURN_ON_HR_FAILURE(hr, "Couldn't set frame rate", false); |
| 378 hr = MFSetAttributeSize(imf_input_media_type_.get(), MF_MT_FRAME_SIZE, | 416 hr = MFSetAttributeSize(imf_input_media_type_.get(), MF_MT_FRAME_SIZE, |
| 379 input_visible_size_.width(), | 417 input_visible_size_.width(), |
| 380 input_visible_size_.height()); | 418 input_visible_size_.height()); |
| 381 RETURN_ON_HR_FAILURE(hr, "Couldn't set frame size", false); | 419 RETURN_ON_HR_FAILURE(hr, "Couldn't set frame size", false); |
| 382 hr = imf_input_media_type_->SetUINT32(MF_MT_INTERLACE_MODE, | 420 hr = imf_input_media_type_->SetUINT32(MF_MT_INTERLACE_MODE, |
| 383 MFVideoInterlace_Progressive); | 421 MFVideoInterlace_Progressive); |
| 384 RETURN_ON_HR_FAILURE(hr, "Couldn't set interlace mode", false); | 422 RETURN_ON_HR_FAILURE(hr, "Couldn't set interlace mode", false); |
| 385 hr = encoder_->SetInputType(0, imf_input_media_type_.get(), 0); | 423 hr = encoder_->SetInputType(input_stream_id_, imf_input_media_type_.get(), 0); |
| 386 RETURN_ON_HR_FAILURE(hr, "Couldn't set input media type", false); | 424 RETURN_ON_HR_FAILURE(hr, "Couldn't set input media type", false); |
| 387 | 425 |
| 388 return SUCCEEDED(hr); | 426 return SUCCEEDED(hr); |
| 389 } | 427 } |
| 390 | 428 |
| 391 bool MediaFoundationVideoEncodeAccelerator::SetEncoderModes() { | 429 bool MediaFoundationVideoEncodeAccelerator::SetEncoderModes() { |
| 392 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); | 430 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 393 | 431 |
| 394 HRESULT hr = encoder_.QueryInterface(IID_ICodecAPI, codec_api_.ReceiveVoid()); | 432 HRESULT hr = encoder_.QueryInterface(IID_ICodecAPI, codec_api_.ReceiveVoid()); |
| 395 RETURN_ON_HR_FAILURE(hr, "Couldn't get ICodecAPI", false); | 433 RETURN_ON_HR_FAILURE(hr, "Couldn't get ICodecAPI", false); |
| 396 VARIANT var; | 434 VARIANT var; |
| 397 var.vt = VT_UI4; | 435 var.vt = VT_UI4; |
| 398 var.ulVal = eAVEncCommonRateControlMode_CBR; | 436 var.ulVal = eAVEncCommonRateControlMode_CBR; |
| 399 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonRateControlMode, &var); | 437 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonRateControlMode, &var); |
| 400 RETURN_ON_HR_FAILURE(hr, "Couldn't set CommonRateControlMode", false); | 438 RETURN_ON_HR_FAILURE(hr, "Couldn't set CommonRateControlMode", false); |
| 401 var.ulVal = target_bitrate_; | 439 var.ulVal = target_bitrate_; |
| 402 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); | 440 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); |
| 403 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); | 441 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); |
| 404 var.ulVal = eAVEncAdaptiveMode_FrameRate; | 442 var.ulVal = eAVEncAdaptiveMode_Resolution; |
| 405 hr = codec_api_->SetValue(&CODECAPI_AVEncAdaptiveMode, &var); | 443 hr = codec_api_->SetValue(&CODECAPI_AVEncAdaptiveMode, &var); |
| 406 RETURN_ON_HR_FAILURE(hr, "Couldn't set FrameRate", false); | 444 RETURN_ON_HR_FAILURE(hr, "Couldn't set FrameRate", false); |
| 407 var.vt = VT_BOOL; | 445 var.vt = VT_BOOL; |
| 408 var.boolVal = VARIANT_TRUE; | 446 var.boolVal = VARIANT_TRUE; |
| 409 hr = codec_api_->SetValue(&CODECAPI_AVLowLatencyMode, &var); | 447 hr = codec_api_->SetValue(&CODECAPI_AVLowLatencyMode, &var); |
| 410 RETURN_ON_HR_FAILURE(hr, "Couldn't set LowLatencyMode", false); | 448 RETURN_ON_HR_FAILURE(hr, "Couldn't set LowLatencyMode", false); |
| 411 return SUCCEEDED(hr); | 449 return SUCCEEDED(hr); |
| 412 } | 450 } |
| 413 | 451 |
| 414 void MediaFoundationVideoEncodeAccelerator::NotifyError( | 452 void MediaFoundationVideoEncodeAccelerator::NotifyError( |
| (...skipping 24 matching lines...) Expand all Loading... |
| 439 frame->stride(VideoFrame::kYPlane), | 477 frame->stride(VideoFrame::kYPlane), |
| 440 scoped_buffer.get() + u_plane_offset_, | 478 scoped_buffer.get() + u_plane_offset_, |
| 441 frame->stride(VideoFrame::kUPlane), | 479 frame->stride(VideoFrame::kUPlane), |
| 442 scoped_buffer.get() + v_plane_offset_, | 480 scoped_buffer.get() + v_plane_offset_, |
| 443 frame->stride(VideoFrame::kVPlane), | 481 frame->stride(VideoFrame::kVPlane), |
| 444 input_visible_size_.width(), input_visible_size_.height()); | 482 input_visible_size_.width(), input_visible_size_.height()); |
| 445 } | 483 } |
| 446 | 484 |
| 447 input_sample_->SetSampleTime(frame->timestamp().InMicroseconds() * | 485 input_sample_->SetSampleTime(frame->timestamp().InMicroseconds() * |
| 448 kOneMicrosecondInMFSampleTimeUnits); | 486 kOneMicrosecondInMFSampleTimeUnits); |
| 449 input_sample_->SetSampleDuration(kOneSecondInMFSampleTimeUnits / frame_rate_); | 487 UINT64 sample_duration = 1; |
| 488 HRESULT hr = |
| 489 MFFrameRateToAverageTimePerFrame(frame_rate_, 1, &sample_duration); |
| 490 RETURN_ON_HR_FAILURE(hr, "Couldn't calculate sample duration", ); |
| 491 input_sample_->SetSampleDuration(sample_duration); |
| 450 | 492 |
| 451 // Release frame after input is copied. | 493 // Release frame after input is copied. |
| 452 frame = nullptr; | 494 frame = nullptr; |
| 453 | 495 |
| 454 HRESULT hr = encoder_->ProcessInput(0, input_sample_.get(), 0); | 496 hr = encoder_->ProcessInput(input_stream_id_, input_sample_.get(), 0); |
| 455 // According to MSDN, if encoder returns MF_E_NOTACCEPTING, we need to try | 497 // According to MSDN, if encoder returns MF_E_NOTACCEPTING, we need to try |
| 456 // processing the output. This error indicates that encoder does not accept | 498 // processing the output. This error indicates that encoder does not accept |
| 457 // any more input data. | 499 // any more input data. |
| 458 if (hr == MF_E_NOTACCEPTING) { | 500 if (hr == MF_E_NOTACCEPTING) { |
| 459 DVLOG(3) << "MF_E_NOTACCEPTING"; | 501 DVLOG(3) << "MF_E_NOTACCEPTING"; |
| 460 ProcessOutput(); | 502 ProcessOutput(); |
| 461 hr = encoder_->ProcessInput(0, input_sample_.get(), 0); | 503 hr = encoder_->ProcessInput(input_stream_id_, input_sample_.get(), 0); |
| 462 if (!SUCCEEDED(hr)) { | 504 if (!SUCCEEDED(hr)) { |
| 463 NotifyError(kPlatformFailureError); | 505 NotifyError(kPlatformFailureError); |
| 464 RETURN_ON_HR_FAILURE(hr, "Couldn't encode", ); | 506 RETURN_ON_HR_FAILURE(hr, "Couldn't encode", ); |
| 465 } | 507 } |
| 466 } else if (!SUCCEEDED(hr)) { | 508 } else if (!SUCCEEDED(hr)) { |
| 467 NotifyError(kPlatformFailureError); | 509 NotifyError(kPlatformFailureError); |
| 468 RETURN_ON_HR_FAILURE(hr, "Couldn't encode", ); | 510 RETURN_ON_HR_FAILURE(hr, "Couldn't encode", ); |
| 469 } | 511 } |
| 470 DVLOG(3) << "Sent for encode " << hr; | 512 DVLOG(3) << "Sent for encode " << hr; |
| 471 | 513 |
| 472 ProcessOutput(); | 514 ProcessOutput(); |
| 473 } | 515 } |
| 474 | 516 |
| 475 void MediaFoundationVideoEncodeAccelerator::ProcessOutput() { | 517 void MediaFoundationVideoEncodeAccelerator::ProcessOutput() { |
| 476 DVLOG(3) << __func__; | 518 DVLOG(3) << __func__; |
| 477 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 519 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 478 | 520 |
| 521 DWORD output_status = 0; |
| 522 HRESULT hr = encoder_->GetOutputStatus(&output_status); |
| 523 RETURN_ON_HR_FAILURE(hr, "Couldn't get output status", ); |
| 524 if (output_status != MFT_OUTPUT_STATUS_SAMPLE_READY) { |
| 525 DVLOG(3) << "Output isnt ready"; |
| 526 return; |
| 527 } |
| 528 |
| 479 MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; | 529 MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; |
| 480 output_data_buffer.dwStreamID = 0; | 530 output_data_buffer.dwStreamID = 0; |
| 481 output_data_buffer.dwStatus = 0; | 531 output_data_buffer.dwStatus = 0; |
| 482 output_data_buffer.pEvents = NULL; | 532 output_data_buffer.pEvents = NULL; |
| 483 output_data_buffer.pSample = output_sample_.get(); | 533 output_data_buffer.pSample = output_sample_.get(); |
| 484 DWORD status = 0; | 534 DWORD status = 0; |
| 485 HRESULT hr = encoder_->ProcessOutput(0, 1, &output_data_buffer, &status); | 535 hr = encoder_->ProcessOutput(output_stream_id_, 1, &output_data_buffer, |
| 536 &status); |
| 486 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { | 537 if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { |
| 487 DVLOG(3) << "MF_E_TRANSFORM_NEED_MORE_INPUT"; | 538 DVLOG(3) << "MF_E_TRANSFORM_NEED_MORE_INPUT" << status; |
| 488 return; | 539 return; |
| 489 } | 540 } |
| 490 RETURN_ON_HR_FAILURE(hr, "Couldn't get encoded data", ); | 541 RETURN_ON_HR_FAILURE(hr, "Couldn't get encoded data", ); |
| 491 DVLOG(3) << "Got encoded data " << hr; | 542 DVLOG(3) << "Got encoded data " << hr; |
| 492 | 543 |
| 493 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | 544 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; |
| 494 hr = output_sample_->GetBufferByIndex(0, output_buffer.Receive()); | 545 hr = output_sample_->GetBufferByIndex(0, output_buffer.Receive()); |
| 495 RETURN_ON_HR_FAILURE(hr, "Couldn't get buffer by index", ); | 546 RETURN_ON_HR_FAILURE(hr, "Couldn't get buffer by index", ); |
| 496 DWORD size = 0; | 547 DWORD size = 0; |
| 497 hr = output_buffer->GetCurrentLength(&size); | 548 hr = output_buffer->GetCurrentLength(&size); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 encode_output->size(), encode_output->keyframe, | 624 encode_output->size(), encode_output->keyframe, |
| 574 encode_output->capture_timestamp)); | 625 encode_output->capture_timestamp)); |
| 575 } | 626 } |
| 576 | 627 |
| 577 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChangeTask( | 628 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChangeTask( |
| 578 uint32_t bitrate, | 629 uint32_t bitrate, |
| 579 uint32_t framerate) { | 630 uint32_t framerate) { |
| 580 DVLOG(3) << __func__; | 631 DVLOG(3) << __func__; |
| 581 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 632 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 582 | 633 |
| 583 frame_rate_ = framerate ? framerate : 1; | 634 frame_rate_ = |
| 584 target_bitrate_ = bitrate ? bitrate : 1; | 635 framerate |
| 636 ? std::min(framerate, static_cast<uint32_t>(kMaxFrameRateNumerator)) |
| 637 : 1; |
| 585 | 638 |
| 586 VARIANT var; | 639 if (target_bitrate_ != bitrate) { |
| 587 var.vt = VT_UI4; | 640 target_bitrate_ = bitrate ? bitrate : 1; |
| 588 var.ulVal = target_bitrate_; | 641 VARIANT var; |
| 589 HRESULT hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); | 642 var.vt = VT_UI4; |
| 590 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", ); | 643 var.ulVal = target_bitrate_; |
| 591 | 644 HRESULT hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); |
| 592 hr = imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); | 645 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", ); |
| 593 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", ); | 646 } |
| 594 hr = MFSetAttributeRatio(imf_output_media_type_.get(), MF_MT_FRAME_RATE, | |
| 595 frame_rate_, kMaxFrameRateDenominator); | |
| 596 RETURN_ON_HR_FAILURE(hr, "Couldn't set output type params", ); | |
| 597 } | 647 } |
| 598 | 648 |
| 599 void MediaFoundationVideoEncodeAccelerator::DestroyTask() { | 649 void MediaFoundationVideoEncodeAccelerator::DestroyTask() { |
| 600 DVLOG(3) << __func__; | 650 DVLOG(3) << __func__; |
| 601 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 651 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 602 | 652 |
| 603 // Cancel all encoder thread callbacks. | 653 // Cancel all encoder thread callbacks. |
| 604 encoder_task_weak_factory_.InvalidateWeakPtrs(); | 654 encoder_task_weak_factory_.InvalidateWeakPtrs(); |
| 605 | 655 |
| 606 ReleaseEncoderResources(); | 656 ReleaseEncoderResources(); |
| 607 } | 657 } |
| 608 | 658 |
| 609 void MediaFoundationVideoEncodeAccelerator::ReleaseEncoderResources() { | 659 void MediaFoundationVideoEncodeAccelerator::ReleaseEncoderResources() { |
| 610 encoder_.Release(); | 660 encoder_.Release(); |
| 611 codec_api_.Release(); | 661 codec_api_.Release(); |
| 612 imf_input_media_type_.Release(); | 662 imf_input_media_type_.Release(); |
| 613 imf_output_media_type_.Release(); | 663 imf_output_media_type_.Release(); |
| 614 input_sample_.Release(); | 664 input_sample_.Release(); |
| 615 output_sample_.Release(); | 665 output_sample_.Release(); |
| 616 } | 666 } |
| 617 | 667 |
| 618 } // namespace content | 668 } // namespace content |
| OLD | NEW |