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

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: Created 4 years, 6 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 20 matching lines...) Expand all
31 #include "base/macros.h" 31 #include "base/macros.h"
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 "media/base/win/mf_helpers.h"
41 #include "media/base/win/mf_initializer.h" 42 #include "media/base/win/mf_initializer.h"
42 #include "media/gpu/dxva_picture_buffer_win.h" 43 #include "media/gpu/dxva_picture_buffer_win.h"
43 #include "media/video/video_decode_accelerator.h" 44 #include "media/video/video_decode_accelerator.h"
44 #include "third_party/angle/include/EGL/egl.h" 45 #include "third_party/angle/include/EGL/egl.h"
45 #include "third_party/angle/include/EGL/eglext.h" 46 #include "third_party/angle/include/EGL/eglext.h"
46 #include "ui/gl/gl_bindings.h" 47 #include "ui/gl/gl_bindings.h"
47 #include "ui/gl/gl_context.h" 48 #include "ui/gl/gl_context.h"
48 #include "ui/gl/gl_fence.h" 49 #include "ui/gl/gl_fence.h"
49 #include "ui/gl/gl_surface_egl.h" 50 #include "ui/gl/gl_surface_egl.h"
50 51
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, 178 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998,
178 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4, 179 0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4,
179 }; 180 };
180 181
181 // Legacy Intel GPUs (Second generation) which have trouble with resolutions 182 // Legacy Intel GPUs (Second generation) which have trouble with resolutions
182 // higher than 1920 x 1088 183 // higher than 1920 x 1088
183 static const DWORD g_IntelLegacyGPUList[] = { 184 static const DWORD g_IntelLegacyGPUList[] = {
184 0x102, 0x106, 0x116, 0x126, 185 0x102, 0x106, 0x116, 0x126,
185 }; 186 };
186 187
187 // Provides scoped access to the underlying buffer in an IMFMediaBuffer
188 // instance.
189 class MediaBufferScopedPointer {
190 public:
191 MediaBufferScopedPointer(IMFMediaBuffer* media_buffer)
192 : media_buffer_(media_buffer),
193 buffer_(nullptr),
194 max_length_(0),
195 current_length_(0) {
196 HRESULT hr = media_buffer_->Lock(&buffer_, &max_length_, &current_length_);
197 CHECK(SUCCEEDED(hr));
198 }
199
200 ~MediaBufferScopedPointer() {
201 HRESULT hr = media_buffer_->Unlock();
202 CHECK(SUCCEEDED(hr));
203 }
204
205 uint8_t* get() { return buffer_; }
206
207 DWORD current_length() const { return current_length_; }
208
209 private:
210 base::win::ScopedComPtr<IMFMediaBuffer> media_buffer_;
211 uint8_t* buffer_;
212 DWORD max_length_;
213 DWORD current_length_;
214
215 DISALLOW_COPY_AND_ASSIGN(MediaBufferScopedPointer);
216 };
217
218 } // namespace 188 } // namespace
219 189
220 namespace media { 190 namespace media {
221 191
222 static const VideoCodecProfile kSupportedProfiles[] = { 192 static const VideoCodecProfile kSupportedProfiles[] = {
223 H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH, 193 H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH,
224 VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE1, 194 VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE1,
225 VP9PROFILE_PROFILE2, VP9PROFILE_PROFILE3}; 195 VP9PROFILE_PROFILE2, VP9PROFILE_PROFILE3};
226 196
227 CreateDXGIDeviceManager 197 CreateDXGIDeviceManager
228 DXVAVideoDecodeAccelerator::create_dxgi_device_manager_ = NULL; 198 DXVAVideoDecodeAccelerator::create_dxgi_device_manager_ = NULL;
229 199
230 #define RETURN_ON_FAILURE(result, log, ret) \
231 do { \
232 if (!(result)) { \
233 DLOG(ERROR) << log; \
234 return ret; \
235 } \
236 } while (0)
237
238 #define RETURN_ON_HR_FAILURE(result, log, ret) \
239 RETURN_ON_FAILURE(SUCCEEDED(result), \
240 log << ", HRESULT: 0x" << std::hex << result, ret);
241
242 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \
243 do { \
244 if (!(result)) { \
245 DVLOG(1) << log; \
246 StopOnError(error_code); \
247 return ret; \
248 } \
249 } while (0)
250
251 #define RETURN_AND_NOTIFY_ON_HR_FAILURE(result, log, error_code, ret) \
252 RETURN_AND_NOTIFY_ON_FAILURE(SUCCEEDED(result), \
253 log << ", HRESULT: 0x" << std::hex << result, \
254 error_code, ret);
255
256 enum { 200 enum {
257 // Maximum number of iterations we allow before aborting the attempt to flush 201 // Maximum number of iterations we allow before aborting the attempt to flush
258 // the batched queries to the driver and allow torn/corrupt frames to be 202 // the batched queries to the driver and allow torn/corrupt frames to be
259 // rendered. 203 // rendered.
260 kFlushDecoderSurfaceTimeoutMs = 1, 204 kFlushDecoderSurfaceTimeoutMs = 1,
261 // Maximum iterations where we try to flush the d3d device. 205 // Maximum iterations where we try to flush the d3d device.
262 kMaxIterationsForD3DFlush = 4, 206 kMaxIterationsForD3DFlush = 4,
263 // Maximum iterations where we try to flush the ANGLE device before reusing 207 // Maximum iterations where we try to flush the ANGLE device before reusing
264 // the texture. 208 // the texture.
265 kMaxIterationsForANGLEReuseFlush = 16, 209 kMaxIterationsForANGLEReuseFlush = 16,
266 // We only request 5 picture buffers from the client which are used to hold 210 // We only request 5 picture buffers from the client which are used to hold
267 // the decoded samples. These buffers are then reused when the client tells 211 // the decoded samples. These buffers are then reused when the client tells
268 // us that it is done with the buffer. 212 // us that it is done with the buffer.
269 kNumPictureBuffers = 5, 213 kNumPictureBuffers = 5,
270 // The keyed mutex should always be released before the other thread 214 // The keyed mutex should always be released before the other thread
271 // attempts to acquire it, so AcquireSync should always return immediately. 215 // attempts to acquire it, so AcquireSync should always return immediately.
272 kAcquireSyncWaitMs = 0, 216 kAcquireSyncWaitMs = 0,
273 }; 217 };
274 218
275 static IMFSample* CreateEmptySample() {
276 base::win::ScopedComPtr<IMFSample> sample;
277 HRESULT hr = MFCreateSample(sample.Receive());
278 RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL);
279 return sample.Detach();
280 }
281
282 // Creates a Media Foundation sample with one buffer of length |buffer_length|
283 // on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0.
284 static IMFSample* CreateEmptySampleWithBuffer(uint32_t buffer_length,
285 int align) {
286 CHECK_GT(buffer_length, 0U);
287
288 base::win::ScopedComPtr<IMFSample> sample;
289 sample.Attach(CreateEmptySample());
290
291 base::win::ScopedComPtr<IMFMediaBuffer> buffer;
292 HRESULT hr = E_FAIL;
293 if (align == 0) {
294 // Note that MFCreateMemoryBuffer is same as MFCreateAlignedMemoryBuffer
295 // with the align argument being 0.
296 hr = MFCreateMemoryBuffer(buffer_length, buffer.Receive());
297 } else {
298 hr =
299 MFCreateAlignedMemoryBuffer(buffer_length, align - 1, buffer.Receive());
300 }
301 RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", NULL);
302
303 hr = sample->AddBuffer(buffer.get());
304 RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL);
305
306 buffer->SetCurrentLength(0);
307 return sample.Detach();
308 }
309
310 // Creates a Media Foundation sample with one buffer containing a copy of the 219 // Creates a Media Foundation sample with one buffer containing a copy of the
311 // given Annex B stream data. 220 // given Annex B stream data.
312 // If duration and sample time are not known, provide 0. 221 // If duration and sample time are not known, provide 0.
313 // |min_size| specifies the minimum size of the buffer (might be required by 222 // |min_size| specifies the minimum size of the buffer (might be required by
314 // the decoder for input). If no alignment is required, provide 0. 223 // the decoder for input). If no alignment is required, provide 0.
315 static IMFSample* CreateInputSample(const uint8_t* stream, 224 static IMFSample* CreateInputSample(const uint8_t* stream,
316 uint32_t size, 225 uint32_t size,
317 uint32_t min_size, 226 uint32_t min_size,
318 int alignment) { 227 int alignment) {
319 CHECK(stream); 228 CHECK(stream);
320 CHECK_GT(size, 0U); 229 CHECK_GT(size, 0U);
321 base::win::ScopedComPtr<IMFSample> sample; 230 base::win::ScopedComPtr<IMFSample> sample;
322 sample.Attach( 231 sample.Attach(
323 CreateEmptySampleWithBuffer(std::max(min_size, size), alignment)); 232 mf::CreateEmptySampleWithBuffer(std::max(min_size, size), alignment));
324 RETURN_ON_FAILURE(sample.get(), "Failed to create empty sample", NULL); 233 RETURN_ON_FAILURE(sample.get(), "Failed to create empty sample", NULL);
325 234
326 base::win::ScopedComPtr<IMFMediaBuffer> buffer; 235 base::win::ScopedComPtr<IMFMediaBuffer> buffer;
327 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); 236 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive());
328 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", NULL); 237 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", NULL);
329 238
330 DWORD max_length = 0; 239 DWORD max_length = 0;
331 DWORD current_length = 0; 240 DWORD current_length = 0;
332 uint8_t* destination = NULL; 241 uint8_t* destination = NULL;
333 hr = buffer->Lock(&destination, &max_length, &current_length); 242 hr = buffer->Lock(&destination, &max_length, &current_length);
(...skipping 2325 matching lines...) Expand 10 before | Expand all | Expand 10 after
2659 2568
2660 HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged(IMFSample* sample, 2569 HRESULT DXVAVideoDecodeAccelerator::CheckConfigChanged(IMFSample* sample,
2661 bool* config_changed) { 2570 bool* config_changed) {
2662 if (codec_ != kCodecH264) 2571 if (codec_ != kCodecH264)
2663 return S_FALSE; 2572 return S_FALSE;
2664 2573
2665 base::win::ScopedComPtr<IMFMediaBuffer> buffer; 2574 base::win::ScopedComPtr<IMFMediaBuffer> buffer;
2666 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); 2575 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive());
2667 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from input sample", hr); 2576 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from input sample", hr);
2668 2577
2669 MediaBufferScopedPointer scoped_media_buffer(buffer.get()); 2578 mf::MediaBufferScopedPointer scoped_media_buffer(buffer.get());
2670 2579
2671 if (!config_change_detector_->DetectConfig( 2580 if (!config_change_detector_->DetectConfig(
2672 scoped_media_buffer.get(), scoped_media_buffer.current_length())) { 2581 scoped_media_buffer.get(), scoped_media_buffer.current_length())) {
2673 RETURN_ON_HR_FAILURE(E_FAIL, "Failed to detect H.264 stream config", 2582 RETURN_ON_HR_FAILURE(E_FAIL, "Failed to detect H.264 stream config",
2674 E_FAIL); 2583 E_FAIL);
2675 } 2584 }
2676 *config_changed = config_change_detector_->config_changed(); 2585 *config_changed = config_change_detector_->config_changed();
2677 return S_OK; 2586 return S_OK;
2678 } 2587 }
2679 2588
2680 void DXVAVideoDecodeAccelerator::ConfigChanged(const Config& config) { 2589 void DXVAVideoDecodeAccelerator::ConfigChanged(const Config& config) {
2681 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); 2590 DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
2682 2591
2683 SetState(kConfigChange); 2592 SetState(kConfigChange);
2684 Invalidate(); 2593 Invalidate();
2685 Initialize(config_, client_); 2594 Initialize(config_, client_);
2686 decoder_thread_task_runner_->PostTask( 2595 decoder_thread_task_runner_->PostTask(
2687 FROM_HERE, 2596 FROM_HERE,
2688 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, 2597 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
2689 base::Unretained(this))); 2598 base::Unretained(this)));
2690 } 2599 }
2691 2600
2692 } // namespace media 2601 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698