OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/dxva_video_decode_accelerator_win.h" | 5 #include "media/gpu/dxva_video_decode_accelerator_win.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #if !defined(OS_WIN) | 9 #if !defined(OS_WIN) |
10 #error This file should only be built on Windows. | 10 #error This file should only be built on Windows. |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "base/memory/shared_memory.h" | 32 #include "base/memory/shared_memory.h" |
33 #include "base/path_service.h" | 33 #include "base/path_service.h" |
34 #include "base/single_thread_task_runner.h" | 34 #include "base/single_thread_task_runner.h" |
35 #include "base/stl_util.h" | 35 #include "base/stl_util.h" |
36 #include "base/threading/thread_task_runner_handle.h" | 36 #include "base/threading/thread_task_runner_handle.h" |
37 #include "base/trace_event/trace_event.h" | 37 #include "base/trace_event/trace_event.h" |
38 #include "base/win/windows_version.h" | 38 #include "base/win/windows_version.h" |
39 #include "build/build_config.h" | 39 #include "build/build_config.h" |
40 #include "gpu/command_buffer/service/gpu_preferences.h" | 40 #include "gpu/command_buffer/service/gpu_preferences.h" |
41 #include "gpu/config/gpu_driver_bug_workarounds.h" | 41 #include "gpu/config/gpu_driver_bug_workarounds.h" |
42 #include "media/base/win/mf_helpers.h" | |
43 #include "media/base/win/mf_initializer.h" | 42 #include "media/base/win/mf_initializer.h" |
44 #include "media/gpu/dxva_picture_buffer_win.h" | 43 #include "media/gpu/dxva_picture_buffer_win.h" |
45 #include "media/video/video_decode_accelerator.h" | 44 #include "media/video/video_decode_accelerator.h" |
46 #include "third_party/angle/include/EGL/egl.h" | 45 #include "third_party/angle/include/EGL/egl.h" |
47 #include "third_party/angle/include/EGL/eglext.h" | 46 #include "third_party/angle/include/EGL/eglext.h" |
48 #include "ui/gl/gl_bindings.h" | 47 #include "ui/gl/gl_bindings.h" |
49 #include "ui/gl/gl_context.h" | 48 #include "ui/gl/gl_context.h" |
50 #include "ui/gl/gl_fence.h" | 49 #include "ui/gl/gl_fence.h" |
51 #include "ui/gl/gl_surface_egl.h" | 50 #include "ui/gl/gl_surface_egl.h" |
52 | 51 |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, | 180 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, |
182 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4, | 181 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4, |
183 }; | 182 }; |
184 | 183 |
185 // Legacy Intel GPUs (Second generation) which have trouble with resolutions | 184 // Legacy Intel GPUs (Second generation) which have trouble with resolutions |
186 // higher than 1920 x 1088 | 185 // higher than 1920 x 1088 |
187 static const DWORD g_IntelLegacyGPUList[] = { | 186 static const DWORD g_IntelLegacyGPUList[] = { |
188 0x102, 0x106, 0x116, 0x126, | 187 0x102, 0x106, 0x116, 0x126, |
189 }; | 188 }; |
190 | 189 |
| 190 // Provides scoped access to the underlying buffer in an IMFMediaBuffer |
| 191 // instance. |
| 192 class MediaBufferScopedPointer { |
| 193 public: |
| 194 explicit MediaBufferScopedPointer(IMFMediaBuffer* media_buffer) |
| 195 : media_buffer_(media_buffer), |
| 196 buffer_(nullptr), |
| 197 max_length_(0), |
| 198 current_length_(0) { |
| 199 HRESULT hr = media_buffer_->Lock(&buffer_, &max_length_, ¤t_length_); |
| 200 CHECK(SUCCEEDED(hr)); |
| 201 } |
| 202 |
| 203 ~MediaBufferScopedPointer() { |
| 204 HRESULT hr = media_buffer_->Unlock(); |
| 205 CHECK(SUCCEEDED(hr)); |
| 206 } |
| 207 |
| 208 uint8_t* get() { return buffer_; } |
| 209 |
| 210 DWORD current_length() const { return current_length_; } |
| 211 |
| 212 private: |
| 213 base::win::ScopedComPtr<IMFMediaBuffer> media_buffer_; |
| 214 uint8_t* buffer_; |
| 215 DWORD max_length_; |
| 216 DWORD current_length_; |
| 217 |
| 218 DISALLOW_COPY_AND_ASSIGN(MediaBufferScopedPointer); |
| 219 }; |
| 220 |
| 221 void LogDXVAError(int line) { |
| 222 LOG(ERROR) << "Error in dxva_video_decode_accelerator_win.cc on line " |
| 223 << line; |
| 224 } |
| 225 |
191 } // namespace | 226 } // namespace |
192 | 227 |
193 namespace media { | 228 namespace media { |
194 | 229 |
195 static const VideoCodecProfile kSupportedProfiles[] = { | 230 static const VideoCodecProfile kSupportedProfiles[] = { |
196 H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH, | 231 H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH, |
197 VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE1, | 232 VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE1, |
198 VP9PROFILE_PROFILE2, VP9PROFILE_PROFILE3}; | 233 VP9PROFILE_PROFILE2, VP9PROFILE_PROFILE3}; |
199 | 234 |
200 CreateDXGIDeviceManager | 235 CreateDXGIDeviceManager |
201 DXVAVideoDecodeAccelerator::create_dxgi_device_manager_ = NULL; | 236 DXVAVideoDecodeAccelerator::create_dxgi_device_manager_ = NULL; |
202 | 237 |
| 238 #define RETURN_ON_FAILURE(result, log, ret) \ |
| 239 do { \ |
| 240 if (!(result)) { \ |
| 241 DLOG(ERROR) << log; \ |
| 242 LogDXVAError(__LINE__); \ |
| 243 return ret; \ |
| 244 } \ |
| 245 } while (0) |
| 246 |
| 247 #define RETURN_ON_HR_FAILURE(result, log, ret) \ |
| 248 RETURN_ON_FAILURE(SUCCEEDED(result), \ |
| 249 log << ", HRESULT: 0x" << std::hex << result, ret); |
| 250 |
| 251 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ |
| 252 do { \ |
| 253 if (!(result)) { \ |
| 254 DVLOG(1) << log; \ |
| 255 LogDXVAError(__LINE__); \ |
| 256 StopOnError(error_code); \ |
| 257 return ret; \ |
| 258 } \ |
| 259 } while (0) |
| 260 |
| 261 #define RETURN_AND_NOTIFY_ON_HR_FAILURE(result, log, error_code, ret) \ |
| 262 RETURN_AND_NOTIFY_ON_FAILURE(SUCCEEDED(result), \ |
| 263 log << ", HRESULT: 0x" << std::hex << result, \ |
| 264 error_code, ret); |
| 265 |
203 enum { | 266 enum { |
204 // Maximum number of iterations we allow before aborting the attempt to flush | 267 // Maximum number of iterations we allow before aborting the attempt to flush |
205 // the batched queries to the driver and allow torn/corrupt frames to be | 268 // the batched queries to the driver and allow torn/corrupt frames to be |
206 // rendered. | 269 // rendered. |
207 kFlushDecoderSurfaceTimeoutMs = 1, | 270 kFlushDecoderSurfaceTimeoutMs = 1, |
208 // Maximum iterations where we try to flush the d3d device. | 271 // Maximum iterations where we try to flush the d3d device. |
209 kMaxIterationsForD3DFlush = 4, | 272 kMaxIterationsForD3DFlush = 4, |
210 // Maximum iterations where we try to flush the ANGLE device before reusing | 273 // Maximum iterations where we try to flush the ANGLE device before reusing |
211 // the texture. | 274 // the texture. |
212 kMaxIterationsForANGLEReuseFlush = 16, | 275 kMaxIterationsForANGLEReuseFlush = 16, |
213 // We only request 5 picture buffers from the client which are used to hold | 276 // We only request 5 picture buffers from the client which are used to hold |
214 // the decoded samples. These buffers are then reused when the client tells | 277 // the decoded samples. These buffers are then reused when the client tells |
215 // us that it is done with the buffer. | 278 // us that it is done with the buffer. |
216 kNumPictureBuffers = 5, | 279 kNumPictureBuffers = 5, |
217 // The keyed mutex should always be released before the other thread | 280 // The keyed mutex should always be released before the other thread |
218 // attempts to acquire it, so AcquireSync should always return immediately. | 281 // attempts to acquire it, so AcquireSync should always return immediately. |
219 kAcquireSyncWaitMs = 0, | 282 kAcquireSyncWaitMs = 0, |
220 }; | 283 }; |
221 | 284 |
| 285 static IMFSample* CreateEmptySample() { |
| 286 base::win::ScopedComPtr<IMFSample> sample; |
| 287 HRESULT hr = MFCreateSample(sample.Receive()); |
| 288 RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL); |
| 289 return sample.Detach(); |
| 290 } |
| 291 |
| 292 // Creates a Media Foundation sample with one buffer of length |buffer_length| |
| 293 // on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0. |
| 294 static IMFSample* CreateEmptySampleWithBuffer(uint32_t buffer_length, |
| 295 int align) { |
| 296 CHECK_GT(buffer_length, 0U); |
| 297 |
| 298 base::win::ScopedComPtr<IMFSample> sample; |
| 299 sample.Attach(CreateEmptySample()); |
| 300 |
| 301 base::win::ScopedComPtr<IMFMediaBuffer> buffer; |
| 302 HRESULT hr = E_FAIL; |
| 303 if (align == 0) { |
| 304 // Note that MFCreateMemoryBuffer is same as MFCreateAlignedMemoryBuffer |
| 305 // with the align argument being 0. |
| 306 hr = MFCreateMemoryBuffer(buffer_length, buffer.Receive()); |
| 307 } else { |
| 308 hr = |
| 309 MFCreateAlignedMemoryBuffer(buffer_length, align - 1, buffer.Receive()); |
| 310 } |
| 311 RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", NULL); |
| 312 |
| 313 hr = sample->AddBuffer(buffer.get()); |
| 314 RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL); |
| 315 |
| 316 buffer->SetCurrentLength(0); |
| 317 return sample.Detach(); |
| 318 } |
| 319 |
222 // Creates a Media Foundation sample with one buffer containing a copy of the | 320 // Creates a Media Foundation sample with one buffer containing a copy of the |
223 // given Annex B stream data. | 321 // given Annex B stream data. |
224 // If duration and sample time are not known, provide 0. | 322 // If duration and sample time are not known, provide 0. |
225 // |min_size| specifies the minimum size of the buffer (might be required by | 323 // |min_size| specifies the minimum size of the buffer (might be required by |
226 // the decoder for input). If no alignment is required, provide 0. | 324 // the decoder for input). If no alignment is required, provide 0. |
227 static IMFSample* CreateInputSample(const uint8_t* stream, | 325 static IMFSample* CreateInputSample(const uint8_t* stream, |
228 uint32_t size, | 326 uint32_t size, |
229 uint32_t min_size, | 327 uint32_t min_size, |
230 int alignment) { | 328 int alignment) { |
231 CHECK(stream); | 329 CHECK(stream); |
232 CHECK_GT(size, 0U); | 330 CHECK_GT(size, 0U); |
233 base::win::ScopedComPtr<IMFSample> sample; | 331 base::win::ScopedComPtr<IMFSample> sample; |
234 sample.Attach( | 332 sample.Attach( |
235 mf::CreateEmptySampleWithBuffer(std::max(min_size, size), alignment)); | 333 CreateEmptySampleWithBuffer(std::max(min_size, size), alignment)); |
236 RETURN_ON_FAILURE(sample.get(), "Failed to create empty sample", NULL); | 334 RETURN_ON_FAILURE(sample.get(), "Failed to create empty sample", NULL); |
237 | 335 |
238 base::win::ScopedComPtr<IMFMediaBuffer> buffer; | 336 base::win::ScopedComPtr<IMFMediaBuffer> buffer; |
239 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); | 337 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); |
240 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", NULL); | 338 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", NULL); |
241 | 339 |
242 DWORD max_length = 0; | 340 DWORD max_length = 0; |
243 DWORD current_length = 0; | 341 DWORD current_length = 0; |
244 uint8_t* destination = NULL; | 342 uint8_t* destination = NULL; |
245 hr = buffer->Lock(&destination, &max_length, ¤t_length); | 343 hr = buffer->Lock(&destination, &max_length, ¤t_length); |
(...skipping 2400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2646 | 2744 |
2647 HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged(IMFSample* sample, | 2745 HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged(IMFSample* sample, |
2648 bool* config_changed) { | 2746 bool* config_changed) { |
2649 if (codec_ != kCodecH264) | 2747 if (codec_ != kCodecH264) |
2650 return S_FALSE; | 2748 return S_FALSE; |
2651 | 2749 |
2652 base::win::ScopedComPtr<IMFMediaBuffer> buffer; | 2750 base::win::ScopedComPtr<IMFMediaBuffer> buffer; |
2653 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); | 2751 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); |
2654 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from input sample", hr); | 2752 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from input sample", hr); |
2655 | 2753 |
2656 mf::MediaBufferScopedPointer scoped_media_buffer(buffer.get()); | 2754 MediaBufferScopedPointer scoped_media_buffer(buffer.get()); |
2657 | 2755 |
2658 if (!config_change_detector_->DetectConfig( | 2756 if (!config_change_detector_->DetectConfig( |
2659 scoped_media_buffer.get(), scoped_media_buffer.current_length())) { | 2757 scoped_media_buffer.get(), scoped_media_buffer.current_length())) { |
2660 RETURN_ON_HR_FAILURE(E_FAIL, "Failed to detect H.264 stream config", | 2758 RETURN_ON_HR_FAILURE(E_FAIL, "Failed to detect H.264 stream config", |
2661 E_FAIL); | 2759 E_FAIL); |
2662 } | 2760 } |
2663 *config_changed = config_change_detector_->config_changed(); | 2761 *config_changed = config_change_detector_->config_changed(); |
2664 return S_OK; | 2762 return S_OK; |
2665 } | 2763 } |
2666 | 2764 |
2667 void DXVAVideoDecodeAccelerator::ConfigChanged(const Config& config) { | 2765 void DXVAVideoDecodeAccelerator::ConfigChanged(const Config& config) { |
2668 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); | 2766 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
2669 | 2767 |
2670 SetState(kConfigChange); | 2768 SetState(kConfigChange); |
2671 Invalidate(); | 2769 Invalidate(); |
2672 Initialize(config_, client_); | 2770 Initialize(config_, client_); |
2673 decoder_thread_task_runner_->PostTask( | 2771 decoder_thread_task_runner_->PostTask( |
2674 FROM_HERE, | 2772 FROM_HERE, |
2675 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 2773 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
2676 base::Unretained(this))); | 2774 base::Unretained(this))); |
2677 } | 2775 } |
2678 | 2776 |
2679 } // namespace media | 2777 } // namespace media |
OLD | NEW |