Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: media/gpu/dxva_video_decode_accelerator_win.cc

Issue 2058413003: H264 HW encode using MediaFoundation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: wuchengli@ and ananta@ comments. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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"
42 #include "media/base/win/mf_initializer.h" 43 #include "media/base/win/mf_initializer.h"
43 #include "media/gpu/dxva_picture_buffer_win.h" 44 #include "media/gpu/dxva_picture_buffer_win.h"
44 #include "media/video/video_decode_accelerator.h" 45 #include "media/video/video_decode_accelerator.h"
45 #include "third_party/angle/include/EGL/egl.h" 46 #include "third_party/angle/include/EGL/egl.h"
46 #include "third_party/angle/include/EGL/eglext.h" 47 #include "third_party/angle/include/EGL/eglext.h"
47 #include "ui/gl/gl_bindings.h" 48 #include "ui/gl/gl_bindings.h"
48 #include "ui/gl/gl_context.h" 49 #include "ui/gl/gl_context.h"
49 #include "ui/gl/gl_fence.h" 50 #include "ui/gl/gl_fence.h"
50 #include "ui/gl/gl_surface_egl.h" 51 #include "ui/gl/gl_surface_egl.h"
51 52
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, 181 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998,
181 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4, 182 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4,
182 }; 183 };
183 184
184 // Legacy Intel GPUs (Second generation) which have trouble with resolutions 185 // Legacy Intel GPUs (Second generation) which have trouble with resolutions
185 // higher than 1920 x 1088 186 // higher than 1920 x 1088
186 static const DWORD g_IntelLegacyGPUList[] = { 187 static const DWORD g_IntelLegacyGPUList[] = {
187 0x102, 0x106, 0x116, 0x126, 188 0x102, 0x106, 0x116, 0x126,
188 }; 189 };
189 190
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_, &current_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
226 } // namespace 191 } // namespace
227 192
228 namespace media { 193 namespace media {
229 194
230 static const VideoCodecProfile kSupportedProfiles[] = { 195 static const VideoCodecProfile kSupportedProfiles[] = {
231 H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH, 196 H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH,
232 VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE1, 197 VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE1,
233 VP9PROFILE_PROFILE2, VP9PROFILE_PROFILE3}; 198 VP9PROFILE_PROFILE2, VP9PROFILE_PROFILE3};
234 199
235 CreateDXGIDeviceManager 200 CreateDXGIDeviceManager
236 DXVAVideoDecodeAccelerator::create_dxgi_device_manager_ = NULL; 201 DXVAVideoDecodeAccelerator::create_dxgi_device_manager_ = NULL;
237 202
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
266 enum { 203 enum {
267 // Maximum number of iterations we allow before aborting the attempt to flush 204 // Maximum number of iterations we allow before aborting the attempt to flush
268 // the batched queries to the driver and allow torn/corrupt frames to be 205 // the batched queries to the driver and allow torn/corrupt frames to be
269 // rendered. 206 // rendered.
270 kFlushDecoderSurfaceTimeoutMs = 1, 207 kFlushDecoderSurfaceTimeoutMs = 1,
271 // Maximum iterations where we try to flush the d3d device. 208 // Maximum iterations where we try to flush the d3d device.
272 kMaxIterationsForD3DFlush = 4, 209 kMaxIterationsForD3DFlush = 4,
273 // Maximum iterations where we try to flush the ANGLE device before reusing 210 // Maximum iterations where we try to flush the ANGLE device before reusing
274 // the texture. 211 // the texture.
275 kMaxIterationsForANGLEReuseFlush = 16, 212 kMaxIterationsForANGLEReuseFlush = 16,
276 // We only request 5 picture buffers from the client which are used to hold 213 // We only request 5 picture buffers from the client which are used to hold
277 // the decoded samples. These buffers are then reused when the client tells 214 // the decoded samples. These buffers are then reused when the client tells
278 // us that it is done with the buffer. 215 // us that it is done with the buffer.
279 kNumPictureBuffers = 5, 216 kNumPictureBuffers = 5,
280 // The keyed mutex should always be released before the other thread 217 // The keyed mutex should always be released before the other thread
281 // attempts to acquire it, so AcquireSync should always return immediately. 218 // attempts to acquire it, so AcquireSync should always return immediately.
282 kAcquireSyncWaitMs = 0, 219 kAcquireSyncWaitMs = 0,
283 }; 220 };
284 221
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
320 // Creates a Media Foundation sample with one buffer containing a copy of the 222 // Creates a Media Foundation sample with one buffer containing a copy of the
321 // given Annex B stream data. 223 // given Annex B stream data.
322 // If duration and sample time are not known, provide 0. 224 // If duration and sample time are not known, provide 0.
323 // |min_size| specifies the minimum size of the buffer (might be required by 225 // |min_size| specifies the minimum size of the buffer (might be required by
324 // the decoder for input). If no alignment is required, provide 0. 226 // the decoder for input). If no alignment is required, provide 0.
325 static IMFSample* CreateInputSample(const uint8_t* stream, 227 static IMFSample* CreateInputSample(const uint8_t* stream,
326 uint32_t size, 228 uint32_t size,
327 uint32_t min_size, 229 uint32_t min_size,
328 int alignment) { 230 int alignment) {
329 CHECK(stream); 231 CHECK(stream);
330 CHECK_GT(size, 0U); 232 CHECK_GT(size, 0U);
331 base::win::ScopedComPtr<IMFSample> sample; 233 base::win::ScopedComPtr<IMFSample> sample;
332 sample.Attach( 234 sample.Attach(
333 CreateEmptySampleWithBuffer(std::max(min_size, size), alignment)); 235 mf::CreateEmptySampleWithBuffer(std::max(min_size, size), alignment));
334 RETURN_ON_FAILURE(sample.get(), "Failed to create empty sample", NULL); 236 RETURN_ON_FAILURE(sample.get(), "Failed to create empty sample", NULL);
335 237
336 base::win::ScopedComPtr<IMFMediaBuffer> buffer; 238 base::win::ScopedComPtr<IMFMediaBuffer> buffer;
337 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); 239 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive());
338 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", NULL); 240 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", NULL);
339 241
340 DWORD max_length = 0; 242 DWORD max_length = 0;
341 DWORD current_length = 0; 243 DWORD current_length = 0;
342 uint8_t* destination = NULL; 244 uint8_t* destination = NULL;
343 hr = buffer->Lock(&destination, &max_length, &current_length); 245 hr = buffer->Lock(&destination, &max_length, &current_length);
(...skipping 2400 matching lines...) Expand 10 before | Expand all | Expand 10 after
2744 2646
2745 HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged(IMFSample* sample, 2647 HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged(IMFSample* sample,
2746 bool* config_changed) { 2648 bool* config_changed) {
2747 if (codec_ != kCodecH264) 2649 if (codec_ != kCodecH264)
2748 return S_FALSE; 2650 return S_FALSE;
2749 2651
2750 base::win::ScopedComPtr<IMFMediaBuffer> buffer; 2652 base::win::ScopedComPtr<IMFMediaBuffer> buffer;
2751 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); 2653 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive());
2752 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from input sample", hr); 2654 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from input sample", hr);
2753 2655
2754 MediaBufferScopedPointer scoped_media_buffer(buffer.get()); 2656 mf::MediaBufferScopedPointer scoped_media_buffer(buffer.get());
2755 2657
2756 if (!config_change_detector_->DetectConfig( 2658 if (!config_change_detector_->DetectConfig(
2757 scoped_media_buffer.get(), scoped_media_buffer.current_length())) { 2659 scoped_media_buffer.get(), scoped_media_buffer.current_length())) {
2758 RETURN_ON_HR_FAILURE(E_FAIL, "Failed to detect H.264 stream config", 2660 RETURN_ON_HR_FAILURE(E_FAIL, "Failed to detect H.264 stream config",
2759 E_FAIL); 2661 E_FAIL);
2760 } 2662 }
2761 *config_changed = config_change_detector_->config_changed(); 2663 *config_changed = config_change_detector_->config_changed();
2762 return S_OK; 2664 return S_OK;
2763 } 2665 }
2764 2666
2765 void DXVAVideoDecodeAccelerator::ConfigChanged(const Config& config) { 2667 void DXVAVideoDecodeAccelerator::ConfigChanged(const Config& config) {
2766 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); 2668 DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
2767 2669
2768 SetState(kConfigChange); 2670 SetState(kConfigChange);
2769 Invalidate(); 2671 Invalidate();
2770 Initialize(config_, client_); 2672 Initialize(config_, client_);
2771 decoder_thread_task_runner_->PostTask( 2673 decoder_thread_task_runner_->PostTask(
2772 FROM_HERE, 2674 FROM_HERE,
2773 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, 2675 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
2774 base::Unretained(this))); 2676 base::Unretained(this)));
2775 } 2677 }
2776 2678
2777 } // namespace media 2679 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698