| 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> |
| 11 #include <mferror.h> | 11 #include <mferror.h> |
| 12 #include <mftransform.h> | 12 #include <mftransform.h> |
| 13 | 13 |
| 14 #include <iterator> | 14 #include <iterator> |
| 15 #include <utility> | 15 #include <utility> |
| 16 #include <vector> | 16 #include <vector> |
| 17 | 17 |
| 18 #include "base/threading/sequenced_task_runner_handle.h" | 18 #include "base/threading/thread_task_runner_handle.h" |
| 19 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
| 20 #include "base/win/scoped_co_mem.h" | 20 #include "base/win/scoped_co_mem.h" |
| 21 #include "base/win/scoped_variant.h" | 21 #include "base/win/scoped_variant.h" |
| 22 #include "base/win/windows_version.h" | 22 #include "base/win/windows_version.h" |
| 23 #include "media/base/win/mf_helpers.h" | 23 #include "media/base/win/mf_helpers.h" |
| 24 #include "media/base/win/mf_initializer.h" | 24 #include "media/base/win/mf_initializer.h" |
| 25 #include "third_party/libyuv/include/libyuv.h" | 25 #include "third_party/libyuv/include/libyuv.h" |
| 26 | 26 |
| 27 using base::win::ScopedComPtr; | 27 using base::win::ScopedComPtr; |
| 28 using media::mf::MediaBufferScopedPointer; | 28 using media::mf::MediaBufferScopedPointer; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 : id(id), shm(std::move(shm)), size(size) {} | 74 : id(id), shm(std::move(shm)), size(size) {} |
| 75 const int32_t id; | 75 const int32_t id; |
| 76 const std::unique_ptr<base::SharedMemory> shm; | 76 const std::unique_ptr<base::SharedMemory> shm; |
| 77 const size_t size; | 77 const size_t size; |
| 78 | 78 |
| 79 private: | 79 private: |
| 80 DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef); | 80 DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef); |
| 81 }; | 81 }; |
| 82 | 82 |
| 83 MediaFoundationVideoEncodeAccelerator::MediaFoundationVideoEncodeAccelerator() | 83 MediaFoundationVideoEncodeAccelerator::MediaFoundationVideoEncodeAccelerator() |
| 84 : client_task_runner_(base::SequencedTaskRunnerHandle::Get()), | 84 : main_client_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 85 encoder_thread_("MFEncoderThread"), | 85 encoder_thread_("MFEncoderThread"), |
| 86 encoder_task_weak_factory_(this) {} | 86 encoder_task_weak_factory_(this) {} |
| 87 | 87 |
| 88 MediaFoundationVideoEncodeAccelerator:: | 88 MediaFoundationVideoEncodeAccelerator:: |
| 89 ~MediaFoundationVideoEncodeAccelerator() { | 89 ~MediaFoundationVideoEncodeAccelerator() { |
| 90 DVLOG(3) << __func__; | 90 DVLOG(3) << __func__; |
| 91 DCHECK(sequence_checker_.CalledOnValidSequence()); | 91 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 92 | 92 |
| 93 DCHECK(!encoder_thread_.IsRunning()); | 93 DCHECK(!encoder_thread_.IsRunning()); |
| 94 DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); | 94 DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); |
| 95 } | 95 } |
| 96 | 96 |
| 97 VideoEncodeAccelerator::SupportedProfiles | 97 VideoEncodeAccelerator::SupportedProfiles |
| 98 MediaFoundationVideoEncodeAccelerator::GetSupportedProfiles() { | 98 MediaFoundationVideoEncodeAccelerator::GetSupportedProfiles() { |
| 99 TRACE_EVENT0("gpu,startup", | 99 TRACE_EVENT0("gpu,startup", |
| 100 "MediaFoundationVideoEncodeAccelerator::GetSupportedProfiles"); | 100 "MediaFoundationVideoEncodeAccelerator::GetSupportedProfiles"); |
| 101 DVLOG(3) << __func__; | 101 DVLOG(3) << __func__; |
| 102 DCHECK(sequence_checker_.CalledOnValidSequence()); | 102 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 103 | 103 |
| 104 SupportedProfiles profiles; | 104 SupportedProfiles profiles; |
| 105 | 105 |
| 106 target_bitrate_ = kDefaultTargetBitrate; | 106 target_bitrate_ = kDefaultTargetBitrate; |
| 107 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; | 107 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; |
| 108 input_visible_size_ = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight); | 108 input_visible_size_ = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight); |
| 109 if (!CreateHardwareEncoderMFT() || !SetEncoderModes() || | 109 if (!CreateHardwareEncoderMFT() || !SetEncoderModes() || |
| 110 !InitializeInputOutputSamples()) { | 110 !InitializeInputOutputSamples()) { |
| 111 ReleaseEncoderResources(); | 111 ReleaseEncoderResources(); |
| 112 DVLOG(1) | 112 DVLOG(1) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 129 bool MediaFoundationVideoEncodeAccelerator::Initialize( | 129 bool MediaFoundationVideoEncodeAccelerator::Initialize( |
| 130 VideoPixelFormat format, | 130 VideoPixelFormat format, |
| 131 const gfx::Size& input_visible_size, | 131 const gfx::Size& input_visible_size, |
| 132 VideoCodecProfile output_profile, | 132 VideoCodecProfile output_profile, |
| 133 uint32_t initial_bitrate, | 133 uint32_t initial_bitrate, |
| 134 Client* client) { | 134 Client* client) { |
| 135 DVLOG(3) << __func__ << ": input_format=" << VideoPixelFormatToString(format) | 135 DVLOG(3) << __func__ << ": input_format=" << VideoPixelFormatToString(format) |
| 136 << ", input_visible_size=" << input_visible_size.ToString() | 136 << ", input_visible_size=" << input_visible_size.ToString() |
| 137 << ", output_profile=" << output_profile | 137 << ", output_profile=" << output_profile |
| 138 << ", initial_bitrate=" << initial_bitrate; | 138 << ", initial_bitrate=" << initial_bitrate; |
| 139 DCHECK(sequence_checker_.CalledOnValidSequence()); | 139 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 140 | 140 |
| 141 if (PIXEL_FORMAT_I420 != format) { | 141 if (PIXEL_FORMAT_I420 != format) { |
| 142 DLOG(ERROR) << "Input format not supported= " | 142 DLOG(ERROR) << "Input format not supported= " |
| 143 << VideoPixelFormatToString(format); | 143 << VideoPixelFormatToString(format); |
| 144 return false; | 144 return false; |
| 145 } | 145 } |
| 146 | 146 |
| 147 if (H264PROFILE_BASELINE != output_profile) { | 147 if (H264PROFILE_BASELINE != output_profile) { |
| 148 DLOG(ERROR) << "Output profile not supported= " << output_profile; | 148 DLOG(ERROR) << "Output profile not supported= " << output_profile; |
| 149 return false; | 149 return false; |
| 150 } | 150 } |
| 151 | 151 |
| 152 encoder_thread_.init_com_with_mta(false); | 152 encoder_thread_.init_com_with_mta(false); |
| 153 if (!encoder_thread_.Start()) { | 153 if (!encoder_thread_.Start()) { |
| 154 DLOG(ERROR) << "Failed spawning encoder thread."; | 154 DLOG(ERROR) << "Failed spawning encoder thread."; |
| 155 return false; | 155 return false; |
| 156 } | 156 } |
| 157 encoder_thread_task_runner_ = encoder_thread_.task_runner(); | 157 encoder_thread_task_runner_ = encoder_thread_.task_runner(); |
| 158 | 158 |
| 159 if (!CreateHardwareEncoderMFT()) { | 159 if (!CreateHardwareEncoderMFT()) { |
| 160 DLOG(ERROR) << "Failed creating a hardware encoder MFT."; | 160 DLOG(ERROR) << "Failed creating a hardware encoder MFT."; |
| 161 return false; | 161 return false; |
| 162 } | 162 } |
| 163 | 163 |
| 164 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 164 main_client_weak_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
| 165 client_ = client_ptr_factory_->GetWeakPtr(); | 165 main_client_ = main_client_weak_factory_->GetWeakPtr(); |
| 166 input_visible_size_ = input_visible_size; | 166 input_visible_size_ = input_visible_size; |
| 167 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; | 167 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; |
| 168 target_bitrate_ = initial_bitrate; | 168 target_bitrate_ = initial_bitrate; |
| 169 bitstream_buffer_size_ = input_visible_size.GetArea(); | 169 bitstream_buffer_size_ = input_visible_size.GetArea(); |
| 170 u_plane_offset_ = | 170 u_plane_offset_ = |
| 171 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kYPlane, | 171 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, VideoFrame::kYPlane, |
| 172 input_visible_size_) | 172 input_visible_size_) |
| 173 .GetArea(); | 173 .GetArea(); |
| 174 v_plane_offset_ = | 174 v_plane_offset_ = |
| 175 u_plane_offset_ + | 175 u_plane_offset_ + |
| (...skipping 13 matching lines...) Expand all Loading... |
| 189 } | 189 } |
| 190 input_sample_.Attach(mf::CreateEmptySampleWithBuffer( | 190 input_sample_.Attach(mf::CreateEmptySampleWithBuffer( |
| 191 VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size_), 2)); | 191 VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size_), 2)); |
| 192 output_sample_.Attach(mf::CreateEmptySampleWithBuffer( | 192 output_sample_.Attach(mf::CreateEmptySampleWithBuffer( |
| 193 bitstream_buffer_size_ * kOutputSampleBufferSizeRatio, 2)); | 193 bitstream_buffer_size_ * kOutputSampleBufferSizeRatio, 2)); |
| 194 | 194 |
| 195 HRESULT hr = | 195 HRESULT hr = |
| 196 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); | 197 RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false); |
| 198 | 198 |
| 199 client_task_runner_->PostTask( | 199 // Pin all client callbacks to the main task runner initially. It can be |
| 200 FROM_HERE, | 200 // reassigned by TryToSetupEncodeOnSeparateThread(). |
| 201 base::Bind(&Client::RequireBitstreamBuffers, client_, kNumInputBuffers, | 201 if (!encode_client_task_runner_) { |
| 202 input_visible_size_, bitstream_buffer_size_)); | 202 encode_client_task_runner_ = main_client_task_runner_; |
| 203 encode_client_ = main_client_; |
| 204 } |
| 205 |
| 206 main_client_task_runner_->PostTask( |
| 207 FROM_HERE, base::Bind(&Client::RequireBitstreamBuffers, main_client_, |
| 208 kNumInputBuffers, input_visible_size_, |
| 209 bitstream_buffer_size_)); |
| 203 return SUCCEEDED(hr); | 210 return SUCCEEDED(hr); |
| 204 } | 211 } |
| 205 | 212 |
| 206 void MediaFoundationVideoEncodeAccelerator::Encode( | 213 void MediaFoundationVideoEncodeAccelerator::Encode( |
| 207 const scoped_refptr<VideoFrame>& frame, | 214 const scoped_refptr<VideoFrame>& frame, |
| 208 bool force_keyframe) { | 215 bool force_keyframe) { |
| 209 DVLOG(3) << __func__; | 216 DVLOG(3) << __func__; |
| 210 DCHECK(sequence_checker_.CalledOnValidSequence()); | 217 DCHECK(encode_client_task_runner_->BelongsToCurrentThread()); |
| 211 | 218 |
| 212 encoder_thread_task_runner_->PostTask( | 219 encoder_thread_task_runner_->PostTask( |
| 213 FROM_HERE, base::Bind(&MediaFoundationVideoEncodeAccelerator::EncodeTask, | 220 FROM_HERE, base::Bind(&MediaFoundationVideoEncodeAccelerator::EncodeTask, |
| 214 encoder_task_weak_factory_.GetWeakPtr(), frame, | 221 encoder_task_weak_factory_.GetWeakPtr(), frame, |
| 215 force_keyframe)); | 222 force_keyframe)); |
| 216 } | 223 } |
| 217 | 224 |
| 218 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBuffer( | 225 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBuffer( |
| 219 const BitstreamBuffer& buffer) { | 226 const BitstreamBuffer& buffer) { |
| 220 DVLOG(3) << __func__ << ": buffer size=" << buffer.size(); | 227 DVLOG(3) << __func__ << ": buffer size=" << buffer.size(); |
| 221 DCHECK(sequence_checker_.CalledOnValidSequence()); | 228 DCHECK(encode_client_task_runner_->BelongsToCurrentThread()); |
| 222 | 229 |
| 223 if (buffer.size() < bitstream_buffer_size_) { | 230 if (buffer.size() < bitstream_buffer_size_) { |
| 224 DLOG(ERROR) << "Output BitstreamBuffer isn't big enough: " << buffer.size() | 231 DLOG(ERROR) << "Output BitstreamBuffer isn't big enough: " << buffer.size() |
| 225 << " vs. " << bitstream_buffer_size_; | 232 << " vs. " << bitstream_buffer_size_; |
| 226 client_->NotifyError(kInvalidArgumentError); | 233 NotifyError(kInvalidArgumentError); |
| 227 return; | 234 return; |
| 228 } | 235 } |
| 229 | 236 |
| 230 std::unique_ptr<base::SharedMemory> shm( | 237 std::unique_ptr<base::SharedMemory> shm( |
| 231 new base::SharedMemory(buffer.handle(), false)); | 238 new base::SharedMemory(buffer.handle(), false)); |
| 232 if (!shm->Map(buffer.size())) { | 239 if (!shm->Map(buffer.size())) { |
| 233 DLOG(ERROR) << "Failed mapping shared memory."; | 240 DLOG(ERROR) << "Failed mapping shared memory."; |
| 234 client_->NotifyError(kPlatformFailureError); | 241 NotifyError(kPlatformFailureError); |
| 235 return; | 242 return; |
| 236 } | 243 } |
| 237 | 244 |
| 238 std::unique_ptr<BitstreamBufferRef> buffer_ref( | 245 std::unique_ptr<BitstreamBufferRef> buffer_ref( |
| 239 new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size())); | 246 new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size())); |
| 240 encoder_thread_task_runner_->PostTask( | 247 encoder_thread_task_runner_->PostTask( |
| 241 FROM_HERE, | 248 FROM_HERE, |
| 242 base::Bind( | 249 base::Bind( |
| 243 &MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask, | 250 &MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask, |
| 244 encoder_task_weak_factory_.GetWeakPtr(), base::Passed(&buffer_ref))); | 251 encoder_task_weak_factory_.GetWeakPtr(), base::Passed(&buffer_ref))); |
| 245 } | 252 } |
| 246 | 253 |
| 247 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChange( | 254 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChange( |
| 248 uint32_t bitrate, | 255 uint32_t bitrate, |
| 249 uint32_t framerate) { | 256 uint32_t framerate) { |
| 250 DVLOG(3) << __func__ << ": bitrate=" << bitrate | 257 DVLOG(3) << __func__ << ": bitrate=" << bitrate |
| 251 << ": framerate=" << framerate; | 258 << ": framerate=" << framerate; |
| 252 DCHECK(sequence_checker_.CalledOnValidSequence()); | 259 DCHECK(encode_client_task_runner_->BelongsToCurrentThread()); |
| 253 | 260 |
| 254 encoder_thread_task_runner_->PostTask( | 261 encoder_thread_task_runner_->PostTask( |
| 255 FROM_HERE, | 262 FROM_HERE, |
| 256 base::Bind(&MediaFoundationVideoEncodeAccelerator:: | 263 base::Bind(&MediaFoundationVideoEncodeAccelerator:: |
| 257 RequestEncodingParametersChangeTask, | 264 RequestEncodingParametersChangeTask, |
| 258 encoder_task_weak_factory_.GetWeakPtr(), bitrate, framerate)); | 265 encoder_task_weak_factory_.GetWeakPtr(), bitrate, framerate)); |
| 259 } | 266 } |
| 260 | 267 |
| 261 void MediaFoundationVideoEncodeAccelerator::Destroy() { | 268 void MediaFoundationVideoEncodeAccelerator::Destroy() { |
| 262 DVLOG(3) << __func__; | 269 DVLOG(3) << __func__; |
| 263 DCHECK(sequence_checker_.CalledOnValidSequence()); | 270 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 264 | 271 |
| 265 // Cancel all callbacks. | 272 // Cancel all callbacks. |
| 266 client_ptr_factory_.reset(); | 273 main_client_weak_factory_.reset(); |
| 267 | 274 |
| 268 if (encoder_thread_.IsRunning()) { | 275 if (encoder_thread_.IsRunning()) { |
| 269 encoder_thread_task_runner_->PostTask( | 276 encoder_thread_task_runner_->PostTask( |
| 270 FROM_HERE, | 277 FROM_HERE, |
| 271 base::Bind(&MediaFoundationVideoEncodeAccelerator::DestroyTask, | 278 base::Bind(&MediaFoundationVideoEncodeAccelerator::DestroyTask, |
| 272 encoder_task_weak_factory_.GetWeakPtr())); | 279 encoder_task_weak_factory_.GetWeakPtr())); |
| 273 encoder_thread_.Stop(); | 280 encoder_thread_.Stop(); |
| 274 } | 281 } |
| 275 | 282 |
| 276 delete this; | 283 delete this; |
| 277 } | 284 } |
| 278 | 285 |
| 286 bool MediaFoundationVideoEncodeAccelerator::TryToSetupEncodeOnSeparateThread( |
| 287 const base::WeakPtr<Client>& encode_client, |
| 288 const scoped_refptr<base::SingleThreadTaskRunner>& encode_task_runner) { |
| 289 DVLOG(3) << __func__; |
| 290 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 291 encode_client_ = encode_client; |
| 292 encode_client_task_runner_ = encode_task_runner; |
| 293 return true; |
| 294 } |
| 295 |
| 279 // static | 296 // static |
| 280 void MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization() { | 297 void MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization() { |
| 281 for (const wchar_t* mfdll : kMediaFoundationVideoEncoderDLLs) | 298 for (const wchar_t* mfdll : kMediaFoundationVideoEncoderDLLs) |
| 282 ::LoadLibrary(mfdll); | 299 ::LoadLibrary(mfdll); |
| 283 } | 300 } |
| 284 | 301 |
| 285 bool MediaFoundationVideoEncodeAccelerator::CreateHardwareEncoderMFT() { | 302 bool MediaFoundationVideoEncodeAccelerator::CreateHardwareEncoderMFT() { |
| 286 DVLOG(3) << __func__; | 303 DVLOG(3) << __func__; |
| 287 DCHECK(sequence_checker_.CalledOnValidSequence()); | 304 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 288 | 305 |
| 289 if (base::win::GetVersion() < base::win::VERSION_WIN8) { | 306 if (base::win::GetVersion() < base::win::VERSION_WIN8) { |
| 290 DVLOG(ERROR) << "Windows versions earlier than 8 are not supported."; | 307 DVLOG(ERROR) << "Windows versions earlier than 8 are not supported."; |
| 291 return false; | 308 return false; |
| 292 } | 309 } |
| 293 | 310 |
| 294 for (const wchar_t* mfdll : kMediaFoundationVideoEncoderDLLs) { | 311 for (const wchar_t* mfdll : kMediaFoundationVideoEncoderDLLs) { |
| 295 if (!::GetModuleHandle(mfdll)) { | 312 if (!::GetModuleHandle(mfdll)) { |
| 296 DVLOG(ERROR) << mfdll << " is required for encoding"; | 313 DVLOG(ERROR) << mfdll << " is required for encoding"; |
| 297 return false; | 314 return false; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 314 &output_info, NULL, &CLSIDs, &count); | 331 &output_info, NULL, &CLSIDs, &count); |
| 315 RETURN_ON_HR_FAILURE(hr, "Couldn't enumerate hardware encoder", false); | 332 RETURN_ON_HR_FAILURE(hr, "Couldn't enumerate hardware encoder", false); |
| 316 RETURN_ON_FAILURE((count > 0), "No HW encoder found", false); | 333 RETURN_ON_FAILURE((count > 0), "No HW encoder found", false); |
| 317 DVLOG(3) << "HW encoder(s) found: " << count; | 334 DVLOG(3) << "HW encoder(s) found: " << count; |
| 318 hr = encoder_.CreateInstance(CLSIDs[0]); | 335 hr = encoder_.CreateInstance(CLSIDs[0]); |
| 319 RETURN_ON_HR_FAILURE(hr, "Couldn't activate hardware encoder", false); | 336 RETURN_ON_HR_FAILURE(hr, "Couldn't activate hardware encoder", false); |
| 320 return true; | 337 return true; |
| 321 } | 338 } |
| 322 | 339 |
| 323 bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputSamples() { | 340 bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputSamples() { |
| 324 DCHECK(sequence_checker_.CalledOnValidSequence()); | 341 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 325 | 342 |
| 326 // Initialize output parameters. | 343 // Initialize output parameters. |
| 327 HRESULT hr = MFCreateMediaType(imf_output_media_type_.Receive()); | 344 HRESULT hr = MFCreateMediaType(imf_output_media_type_.Receive()); |
| 328 RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false); | 345 RETURN_ON_HR_FAILURE(hr, "Couldn't create media type", false); |
| 329 hr = imf_output_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); | 346 hr = imf_output_media_type_->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); |
| 330 RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false); | 347 RETURN_ON_HR_FAILURE(hr, "Couldn't set media type", false); |
| 331 hr = imf_output_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); | 348 hr = imf_output_media_type_->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); |
| 332 RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false); | 349 RETURN_ON_HR_FAILURE(hr, "Couldn't set video format", false); |
| 333 hr = imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); | 350 hr = imf_output_media_type_->SetUINT32(MF_MT_AVG_BITRATE, target_bitrate_); |
| 334 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); | 351 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 365 hr = imf_input_media_type_->SetUINT32(MF_MT_INTERLACE_MODE, | 382 hr = imf_input_media_type_->SetUINT32(MF_MT_INTERLACE_MODE, |
| 366 MFVideoInterlace_Progressive); | 383 MFVideoInterlace_Progressive); |
| 367 RETURN_ON_HR_FAILURE(hr, "Couldn't set interlace mode", false); | 384 RETURN_ON_HR_FAILURE(hr, "Couldn't set interlace mode", false); |
| 368 hr = encoder_->SetInputType(0, imf_input_media_type_.get(), 0); | 385 hr = encoder_->SetInputType(0, imf_input_media_type_.get(), 0); |
| 369 RETURN_ON_HR_FAILURE(hr, "Couldn't set input media type", false); | 386 RETURN_ON_HR_FAILURE(hr, "Couldn't set input media type", false); |
| 370 | 387 |
| 371 return SUCCEEDED(hr); | 388 return SUCCEEDED(hr); |
| 372 } | 389 } |
| 373 | 390 |
| 374 bool MediaFoundationVideoEncodeAccelerator::SetEncoderModes() { | 391 bool MediaFoundationVideoEncodeAccelerator::SetEncoderModes() { |
| 375 DCHECK(sequence_checker_.CalledOnValidSequence()); | 392 DCHECK(main_client_task_runner_->BelongsToCurrentThread()); |
| 376 | 393 |
| 377 HRESULT hr = encoder_.QueryInterface(IID_ICodecAPI, codec_api_.ReceiveVoid()); | 394 HRESULT hr = encoder_.QueryInterface(IID_ICodecAPI, codec_api_.ReceiveVoid()); |
| 378 RETURN_ON_HR_FAILURE(hr, "Couldn't get ICodecAPI", false); | 395 RETURN_ON_HR_FAILURE(hr, "Couldn't get ICodecAPI", false); |
| 379 VARIANT var; | 396 VARIANT var; |
| 380 var.vt = VT_UI4; | 397 var.vt = VT_UI4; |
| 381 var.ulVal = eAVEncCommonRateControlMode_CBR; | 398 var.ulVal = eAVEncCommonRateControlMode_CBR; |
| 382 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonRateControlMode, &var); | 399 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonRateControlMode, &var); |
| 383 RETURN_ON_HR_FAILURE(hr, "Couldn't set CommonRateControlMode", false); | 400 RETURN_ON_HR_FAILURE(hr, "Couldn't set CommonRateControlMode", false); |
| 384 var.ulVal = target_bitrate_; | 401 var.ulVal = target_bitrate_; |
| 385 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); | 402 hr = codec_api_->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var); |
| 386 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); | 403 RETURN_ON_HR_FAILURE(hr, "Couldn't set bitrate", false); |
| 387 var.ulVal = eAVEncAdaptiveMode_FrameRate; | 404 var.ulVal = eAVEncAdaptiveMode_FrameRate; |
| 388 hr = codec_api_->SetValue(&CODECAPI_AVEncAdaptiveMode, &var); | 405 hr = codec_api_->SetValue(&CODECAPI_AVEncAdaptiveMode, &var); |
| 389 RETURN_ON_HR_FAILURE(hr, "Couldn't set FrameRate", false); | 406 RETURN_ON_HR_FAILURE(hr, "Couldn't set FrameRate", false); |
| 390 var.vt = VT_BOOL; | 407 var.vt = VT_BOOL; |
| 391 var.boolVal = VARIANT_TRUE; | 408 var.boolVal = VARIANT_TRUE; |
| 392 hr = codec_api_->SetValue(&CODECAPI_AVLowLatencyMode, &var); | 409 hr = codec_api_->SetValue(&CODECAPI_AVLowLatencyMode, &var); |
| 393 RETURN_ON_HR_FAILURE(hr, "Couldn't set LowLatencyMode", false); | 410 RETURN_ON_HR_FAILURE(hr, "Couldn't set LowLatencyMode", false); |
| 394 return SUCCEEDED(hr); | 411 return SUCCEEDED(hr); |
| 395 } | 412 } |
| 396 | 413 |
| 397 void MediaFoundationVideoEncodeAccelerator::NotifyError( | 414 void MediaFoundationVideoEncodeAccelerator::NotifyError( |
| 398 VideoEncodeAccelerator::Error error) { | 415 VideoEncodeAccelerator::Error error) { |
| 399 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 416 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 400 client_task_runner_->PostTask( | 417 main_client_task_runner_->PostTask( |
| 401 FROM_HERE, base::Bind(&Client::NotifyError, client_, error)); | 418 FROM_HERE, base::Bind(&Client::NotifyError, main_client_, error)); |
| 402 } | 419 } |
| 403 | 420 |
| 404 void MediaFoundationVideoEncodeAccelerator::EncodeTask( | 421 void MediaFoundationVideoEncodeAccelerator::EncodeTask( |
| 405 scoped_refptr<VideoFrame> frame, | 422 scoped_refptr<VideoFrame> frame, |
| 406 bool force_keyframe) { | 423 bool force_keyframe) { |
| 407 DVLOG(3) << __func__; | 424 DVLOG(3) << __func__; |
| 408 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 425 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 409 | 426 |
| 410 base::win::ScopedComPtr<IMFMediaBuffer> input_buffer; | 427 base::win::ScopedComPtr<IMFMediaBuffer> input_buffer; |
| 411 input_sample_->GetBufferByIndex(0, input_buffer.Receive()); | 428 input_sample_->GetBufferByIndex(0, input_buffer.Receive()); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 | 525 |
| 509 std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef> | 526 std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef> |
| 510 buffer_ref = std::move(bitstream_buffer_queue_.front()); | 527 buffer_ref = std::move(bitstream_buffer_queue_.front()); |
| 511 bitstream_buffer_queue_.pop_front(); | 528 bitstream_buffer_queue_.pop_front(); |
| 512 | 529 |
| 513 { | 530 { |
| 514 MediaBufferScopedPointer scoped_buffer(output_buffer.get()); | 531 MediaBufferScopedPointer scoped_buffer(output_buffer.get()); |
| 515 memcpy(buffer_ref->shm->memory(), scoped_buffer.get(), size); | 532 memcpy(buffer_ref->shm->memory(), scoped_buffer.get(), size); |
| 516 } | 533 } |
| 517 | 534 |
| 518 client_task_runner_->PostTask( | 535 encode_client_task_runner_->PostTask( |
| 519 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, | 536 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, encode_client_, |
| 520 buffer_ref->id, size, keyframe, timestamp)); | 537 buffer_ref->id, size, keyframe, timestamp)); |
| 521 | 538 |
| 522 // Keep calling ProcessOutput recursively until MF_E_TRANSFORM_NEED_MORE_INPUT | 539 // Keep calling ProcessOutput recursively until MF_E_TRANSFORM_NEED_MORE_INPUT |
| 523 // is returned to flush out all the output. | 540 // is returned to flush out all the output. |
| 524 ProcessOutput(); | 541 ProcessOutput(); |
| 525 } | 542 } |
| 526 | 543 |
| 527 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask( | 544 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask( |
| 528 std::unique_ptr<BitstreamBufferRef> buffer_ref) { | 545 std::unique_ptr<BitstreamBufferRef> buffer_ref) { |
| 529 DVLOG(3) << __func__; | 546 DVLOG(3) << __func__; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 543 | 560 |
| 544 void MediaFoundationVideoEncodeAccelerator::ReturnBitstreamBuffer( | 561 void MediaFoundationVideoEncodeAccelerator::ReturnBitstreamBuffer( |
| 545 std::unique_ptr<EncodeOutput> encode_output, | 562 std::unique_ptr<EncodeOutput> encode_output, |
| 546 std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef> | 563 std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef> |
| 547 buffer_ref) { | 564 buffer_ref) { |
| 548 DVLOG(3) << __func__; | 565 DVLOG(3) << __func__; |
| 549 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 566 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 550 | 567 |
| 551 memcpy(buffer_ref->shm->memory(), encode_output->memory(), | 568 memcpy(buffer_ref->shm->memory(), encode_output->memory(), |
| 552 encode_output->size()); | 569 encode_output->size()); |
| 553 client_task_runner_->PostTask( | 570 encode_client_task_runner_->PostTask( |
| 554 FROM_HERE, | 571 FROM_HERE, |
| 555 base::Bind(&Client::BitstreamBufferReady, client_, buffer_ref->id, | 572 base::Bind(&Client::BitstreamBufferReady, encode_client_, buffer_ref->id, |
| 556 encode_output->size(), encode_output->keyframe, | 573 encode_output->size(), encode_output->keyframe, |
| 557 encode_output->capture_timestamp)); | 574 encode_output->capture_timestamp)); |
| 558 } | 575 } |
| 559 | 576 |
| 560 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChangeTask( | 577 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChangeTask( |
| 561 uint32_t bitrate, | 578 uint32_t bitrate, |
| 562 uint32_t framerate) { | 579 uint32_t framerate) { |
| 563 DVLOG(3) << __func__; | 580 DVLOG(3) << __func__; |
| 564 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 581 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 565 | 582 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 592 void MediaFoundationVideoEncodeAccelerator::ReleaseEncoderResources() { | 609 void MediaFoundationVideoEncodeAccelerator::ReleaseEncoderResources() { |
| 593 encoder_.Release(); | 610 encoder_.Release(); |
| 594 codec_api_.Release(); | 611 codec_api_.Release(); |
| 595 imf_input_media_type_.Release(); | 612 imf_input_media_type_.Release(); |
| 596 imf_output_media_type_.Release(); | 613 imf_output_media_type_.Release(); |
| 597 input_sample_.Release(); | 614 input_sample_.Release(); |
| 598 output_sample_.Release(); | 615 output_sample_.Release(); |
| 599 } | 616 } |
| 600 | 617 |
| 601 } // namespace content | 618 } // namespace content |
| OLD | NEW |