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

Side by Side Diff: content/common/gpu/media/dxva_video_decode_accelerator_win.h

Issue 1882373004: Migrate content/common/gpu/media code to media/gpu (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix several more bot-identified build issues Created 4 years, 8 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #ifndef CONTENT_COMMON_GPU_MEDIA_DXVA_VIDEO_DECODE_ACCELERATOR_H_
6 #define CONTENT_COMMON_GPU_MEDIA_DXVA_VIDEO_DECODE_ACCELERATOR_H_
7
8 #include <d3d11.h>
9 #include <d3d9.h>
10 #include <initguid.h>
11 #include <stdint.h>
12 // Work around bug in this header by disabling the relevant warning for it.
13 // https://connect.microsoft.com/VisualStudio/feedback/details/911260/dxva2api-h -in-win8-sdk-triggers-c4201-with-w4
14 #pragma warning(push)
15 #pragma warning(disable:4201)
16 #include <dxva2api.h>
17 #pragma warning(pop)
18 #include <mfidl.h>
19
20 #include <list>
21 #include <map>
22 #include <vector>
23
24 #include "base/compiler_specific.h"
25 #include "base/macros.h"
26 #include "base/memory/linked_ptr.h"
27 #include "base/memory/weak_ptr.h"
28 #include "base/synchronization/lock.h"
29 #include "base/threading/non_thread_safe.h"
30 #include "base/threading/thread.h"
31 #include "base/win/scoped_comptr.h"
32 #include "content/common/content_export.h"
33 #include "content/common/gpu/media/gpu_video_decode_accelerator_helpers.h"
34 #include "media/filters/h264_parser.h"
35 #include "media/video/video_decode_accelerator.h"
36
37 interface IMFSample;
38 interface IDirect3DSurface9;
39
40 namespace gfx {
41 class GLContext;
42 }
43
44 typedef HRESULT (WINAPI* CreateDXGIDeviceManager)(
45 UINT* reset_token,
46 IMFDXGIDeviceManager** device_manager);
47
48 namespace content {
49
50 // Provides functionality to detect H.264 stream configuration changes.
51 // TODO(ananta)
52 // Move this to a common place so that all VDA's can use this.
53 class H264ConfigChangeDetector {
54 public:
55 H264ConfigChangeDetector();
56 ~H264ConfigChangeDetector();
57
58 // Detects stream configuration changes.
59 // Returns false on failure.
60 bool DetectConfig(const uint8_t* stream, unsigned int size);
61
62 bool config_changed() const {
63 return config_changed_;
64 }
65
66 private:
67 // These fields are used to track the SPS/PPS in the H.264 bitstream and
68 // are eventually compared against the SPS/PPS in the bitstream to detect
69 // a change.
70 int last_sps_id_;
71 std::vector<uint8_t> last_sps_;
72 int last_pps_id_;
73 std::vector<uint8_t> last_pps_;
74 // Set to true if we detect a stream configuration change.
75 bool config_changed_;
76 // We want to indicate configuration changes only after we see IDR slices.
77 // This flag tracks that we potentially have a configuration change which
78 // we want to honor after we see an IDR slice.
79 bool pending_config_changed_;
80
81 std::unique_ptr<media::H264Parser> parser_;
82
83 DISALLOW_COPY_AND_ASSIGN(H264ConfigChangeDetector);
84 };
85
86
87 // Class to provide a DXVA 2.0 based accelerator using the Microsoft Media
88 // foundation APIs via the VideoDecodeAccelerator interface.
89 // This class lives on a single thread and DCHECKs that it is never accessed
90 // from any other.
91 class CONTENT_EXPORT DXVAVideoDecodeAccelerator
92 : public media::VideoDecodeAccelerator {
93 public:
94 enum State {
95 kUninitialized, // un-initialized.
96 kNormal, // normal playing state.
97 kResetting, // upon received Reset(), before ResetDone()
98 kStopped, // upon output EOS received.
99 kFlushing, // upon flush request received.
100 kConfigChange, // stream configuration change detected.
101 };
102
103 // Does not take ownership of |client| which must outlive |*this|.
104 DXVAVideoDecodeAccelerator(
105 const GetGLContextCallback& get_gl_context_cb,
106 const MakeGLContextCurrentCallback& make_context_current_cb,
107 bool enable_accelerated_vpx_decode);
108 ~DXVAVideoDecodeAccelerator() override;
109
110 // media::VideoDecodeAccelerator implementation.
111 bool Initialize(const Config& config, Client* client) override;
112 void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
113 void AssignPictureBuffers(
114 const std::vector<media::PictureBuffer>& buffers) override;
115 void ReusePictureBuffer(int32_t picture_buffer_id) override;
116 void Flush() override;
117 void Reset() override;
118 void Destroy() override;
119 bool TryToSetupDecodeOnSeparateThread(
120 const base::WeakPtr<Client>& decode_client,
121 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner)
122 override;
123 GLenum GetSurfaceInternalFormat() const override;
124
125 static media::VideoDecodeAccelerator::SupportedProfiles
126 GetSupportedProfiles();
127
128 // Preload dlls required for decoding.
129 static void PreSandboxInitialization();
130
131 private:
132 typedef void* EGLConfig;
133 typedef void* EGLSurface;
134
135 // Returns the minimum resolution for the |profile| passed in.
136 static std::pair<int, int> GetMinResolution(
137 const media::VideoCodecProfile profile);
138
139 // Returns the maximum resolution for the |profile| passed in.
140 static std::pair<int, int> GetMaxResolution(
141 const media::VideoCodecProfile profile);
142
143 // Returns the maximum resolution for H264 video.
144 static std::pair<int, int> GetMaxH264Resolution();
145
146 // Certain AMD GPU drivers like R600, R700, Evergreen and Cayman and
147 // some second generation Intel GPU drivers crash if we create a video
148 // device with a resolution higher then 1920 x 1088. This function
149 // checks if the GPU is in this list and if yes returns true.
150 static bool IsLegacyGPU(ID3D11Device* device);
151
152 // Creates and initializes an instance of the D3D device and the
153 // corresponding device manager. The device manager instance is eventually
154 // passed to the IMFTransform interface implemented by the decoder.
155 bool CreateD3DDevManager();
156
157 // Creates and initializes an instance of the DX11 device and the
158 // corresponding device manager. The device manager instance is eventually
159 // passed to the IMFTransform interface implemented by the decoder.
160 bool CreateDX11DevManager();
161
162 // Creates, initializes and sets the media codec types for the decoder.
163 bool InitDecoder(media::VideoCodecProfile profile);
164
165 // Validates whether the decoder supports hardware video acceleration.
166 bool CheckDecoderDxvaSupport();
167
168 // Returns information about the input and output streams. This includes
169 // alignment information, decoder support flags, minimum sample size, etc.
170 bool GetStreamsInfoAndBufferReqs();
171
172 // Registers the input and output media types on the decoder. This includes
173 // the expected input and output formats.
174 bool SetDecoderMediaTypes();
175
176 // Registers the input media type for the decoder.
177 bool SetDecoderInputMediaType();
178
179 // Registers the output media type for the decoder.
180 bool SetDecoderOutputMediaType(const GUID& subtype);
181
182 // Passes a command message to the decoder. This includes commands like
183 // start of stream, end of stream, flush, drain the decoder, etc.
184 bool SendMFTMessage(MFT_MESSAGE_TYPE msg, int32_t param);
185
186 // The bulk of the decoding happens here. This function handles errors,
187 // format changes and processes decoded output.
188 void DoDecode();
189
190 // Invoked when we have a valid decoded output sample. Retrieves the D3D
191 // surface and maintains a copy of it which is passed eventually to the
192 // client when we have a picture buffer to copy the surface contents to.
193 bool ProcessOutputSample(IMFSample* sample);
194
195 // Processes pending output samples by copying them to available picture
196 // slots.
197 void ProcessPendingSamples();
198
199 // Helper function to notify the accelerator client about the error.
200 void StopOnError(media::VideoDecodeAccelerator::Error error);
201
202 // Transitions the decoder to the uninitialized state. The decoder will stop
203 // accepting requests in this state.
204 void Invalidate();
205
206 // Notifies the client that the input buffer identifed by input_buffer_id has
207 // been processed.
208 void NotifyInputBufferRead(int input_buffer_id);
209
210 // Notifies the client that the decoder was flushed.
211 void NotifyFlushDone();
212
213 // Notifies the client that the decoder was reset.
214 void NotifyResetDone();
215
216 // Requests picture buffers from the client.
217 void RequestPictureBuffers(int width, int height);
218
219 // Notifies the client about the availability of a picture.
220 void NotifyPictureReady(int picture_buffer_id,
221 int input_buffer_id);
222
223 // Sends pending input buffer processed acks to the client if we don't have
224 // output samples waiting to be processed.
225 void NotifyInputBuffersDropped();
226
227 // Decodes pending input buffers.
228 void DecodePendingInputBuffers();
229
230 // Helper for handling the Flush operation.
231 void FlushInternal();
232
233 // Helper for handling the Decode operation.
234 void DecodeInternal(const base::win::ScopedComPtr<IMFSample>& input_sample);
235
236 // Handles mid stream resolution changes.
237 void HandleResolutionChanged(int width, int height);
238
239 struct DXVAPictureBuffer;
240 typedef std::map<int32_t, linked_ptr<DXVAPictureBuffer>> OutputBuffers;
241
242 // Tells the client to dismiss the stale picture buffers passed in.
243 void DismissStaleBuffers(bool force);
244
245 // Called after the client indicates we can recycle a stale picture buffer.
246 void DeferredDismissStaleBuffer(int32_t picture_buffer_id);
247
248 // Sets the state of the decoder. Called from the main thread and the decoder
249 // thread. The state is changed on the main thread.
250 void SetState(State state);
251
252 // Gets the state of the decoder. Can be called from the main thread and
253 // the decoder thread. Thread safe.
254 State GetState();
255
256 // Starts the thread used for decoding.
257 void StartDecoderThread();
258
259 // Returns if we have output samples waiting to be processed. We only
260 // allow one output sample to be present in the output queue at any given
261 // time.
262 bool OutputSamplesPresent();
263
264 // Copies the source surface |src_surface| to the destination |dest_surface|.
265 // The copying is done on the decoder thread.
266 void CopySurface(IDirect3DSurface9* src_surface,
267 IDirect3DSurface9* dest_surface,
268 int picture_buffer_id,
269 int input_buffer_id);
270
271 // This is a notification that the source surface |src_surface| was copied to
272 // the destination |dest_surface|. Received on the main thread.
273 void CopySurfaceComplete(IDirect3DSurface9* src_surface,
274 IDirect3DSurface9* dest_surface,
275 int picture_buffer_id,
276 int input_buffer_id);
277
278 // Copies the source texture |src_texture| to the destination |dest_texture|.
279 // The copying is done on the decoder thread. The |video_frame| parameter
280 // is the sample containing the frame to be copied.
281 void CopyTexture(ID3D11Texture2D* src_texture,
282 ID3D11Texture2D* dest_texture,
283 base::win::ScopedComPtr<IDXGIKeyedMutex> dest_keyed_mutex,
284 uint64_t keyed_mutex_value,
285 IMFSample* video_frame,
286 int picture_buffer_id,
287 int input_buffer_id);
288
289 // Flushes the decoder device to ensure that the decoded surface is copied
290 // to the target surface. |iterations| helps to maintain an upper limit on
291 // the number of times we try to complete the flush operation.
292 void FlushDecoder(int iterations,
293 IDirect3DSurface9* src_surface,
294 IDirect3DSurface9* dest_surface,
295 int picture_buffer_id,
296 int input_buffer_id);
297
298 // Polls to wait for GPU commands to be finished on the picture buffer
299 // before reusing it.
300 void WaitForOutputBuffer(int32_t picture_buffer_id, int count);
301
302 // Initializes the DX11 Video format converter media types.
303 // Returns true on success.
304 bool InitializeDX11VideoFormatConverterMediaType(int width, int height);
305
306 // Returns the output video frame dimensions (width, height).
307 // |sample| :- This is the output sample containing the video frame.
308 // |width| :- The width is returned here.
309 // |height| :- The height is returned here.
310 // Returns true on success.
311 bool GetVideoFrameDimensions(IMFSample* sample, int* width, int* height);
312
313 // Sets the output type on the |transform| to the GUID identified by the
314 // the |output_type| parameter. The GUID can be MFVideoFormat_RGB32,
315 // MFVideoFormat_ARGB32, MFVideoFormat_NV12, etc.
316 // Additionally if the |width| and |height| parameters are non zero, then
317 // this function also sets the MF_MT_FRAME_SIZE attribute on the type.
318 // Returns true on success.
319 bool SetTransformOutputType(IMFTransform* transform,
320 const GUID& output_type,
321 int width,
322 int height);
323
324 // Checks if the resolution, bitrate etc of the stream changed. We do this
325 // by keeping track of the SPS/PPS frames and if they change we assume
326 // that the configuration changed.
327 // Returns S_OK or S_FALSE on succcess.
328 // The |config_changed| parameter is set to true if we detect a change in the
329 // stream.
330 HRESULT CheckConfigChanged(IMFSample* sample, bool* config_changed);
331
332 // Called when we detect a stream configuration change. We reinitialize the
333 // decoder here.
334 void ConfigChanged(const Config& config);
335
336 // To expose client callbacks from VideoDecodeAccelerator.
337 media::VideoDecodeAccelerator::Client* client_;
338
339 base::win::ScopedComPtr<IMFTransform> decoder_;
340 base::win::ScopedComPtr<IMFTransform> video_format_converter_mft_;
341
342 base::win::ScopedComPtr<IDirect3D9Ex> d3d9_;
343 base::win::ScopedComPtr<IDirect3DDevice9Ex> d3d9_device_ex_;
344 base::win::ScopedComPtr<IDirect3DDeviceManager9> device_manager_;
345 base::win::ScopedComPtr<IDirect3DQuery9> query_;
346
347 base::win::ScopedComPtr<ID3D11Device > d3d11_device_;
348 base::win::ScopedComPtr<IMFDXGIDeviceManager> d3d11_device_manager_;
349 base::win::ScopedComPtr<ID3D10Multithread> multi_threaded_;
350 base::win::ScopedComPtr<ID3D11DeviceContext> d3d11_device_context_;
351 base::win::ScopedComPtr<ID3D11Query> d3d11_query_;
352
353 // Ideally the reset token would be a stack variable which is used while
354 // creating the device manager. However it seems that the device manager
355 // holds onto the token and attempts to access it if the underlying device
356 // changes.
357 // TODO(ananta): This needs to be verified.
358 uint32_t dev_manager_reset_token_;
359
360 // Reset token for the DX11 device manager.
361 uint32_t dx11_dev_manager_reset_token_;
362
363 uint32_t dx11_dev_manager_reset_token_format_conversion_;
364
365 // The EGL config to use for decoded frames.
366 EGLConfig egl_config_;
367
368 // Current state of the decoder.
369 volatile State state_;
370
371 MFT_INPUT_STREAM_INFO input_stream_info_;
372 MFT_OUTPUT_STREAM_INFO output_stream_info_;
373
374 // Contains information about a decoded sample.
375 struct PendingSampleInfo {
376 PendingSampleInfo(int32_t buffer_id, IMFSample* sample);
377 PendingSampleInfo(const PendingSampleInfo& other);
378 ~PendingSampleInfo();
379
380 int32_t input_buffer_id;
381
382 // The target picture buffer id where the frame would be copied to.
383 // Defaults to -1.
384 int picture_buffer_id;
385
386 base::win::ScopedComPtr<IMFSample> output_sample;
387 };
388
389 typedef std::list<PendingSampleInfo> PendingOutputSamples;
390
391 // List of decoded output samples. Protected by |decoder_lock_|.
392 PendingOutputSamples pending_output_samples_;
393
394 // This map maintains the picture buffers passed the client for decoding.
395 // The key is the picture buffer id.
396 OutputBuffers output_picture_buffers_;
397
398 // After a resolution change there may be a few output buffers which have yet
399 // to be displayed so they cannot be dismissed immediately. We move them from
400 // |output_picture_buffers_| to this map so they may be dismissed once they
401 // become available.
402 OutputBuffers stale_output_picture_buffers_;
403
404 // Set to true if we requested picture slots from the client.
405 bool pictures_requested_;
406
407 // Counter which holds the number of input packets before a successful
408 // decode.
409 int inputs_before_decode_;
410
411 // Set to true when the drain message is sent to the decoder during a flush
412 // operation. Used to ensure the message is only sent once after
413 // |pending_input_buffers_| is drained. Protected by |decoder_lock_|.
414 bool sent_drain_message_;
415
416 // List of input samples waiting to be processed.
417 typedef std::list<base::win::ScopedComPtr<IMFSample>> PendingInputs;
418 PendingInputs pending_input_buffers_;
419
420 // Callback to get current GLContext.
421 GetGLContextCallback get_gl_context_cb_;
422 // Callback to set the correct gl context.
423 MakeGLContextCurrentCallback make_context_current_cb_;
424
425 // Which codec we are decoding with hardware acceleration.
426 media::VideoCodec codec_;
427 // Thread on which the decoder operations like passing input frames,
428 // getting output frames are performed. One instance of this thread
429 // is created per decoder instance.
430 base::Thread decoder_thread_;
431
432 // Task runner to be used for posting tasks to the decoder thread.
433 scoped_refptr<base::SingleThreadTaskRunner> decoder_thread_task_runner_;
434
435 // Task runner to be used for posting tasks to the main thread.
436 scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
437
438 // Used to synchronize access between the decoder thread and the main thread.
439 base::Lock decoder_lock_;
440
441 // Disallow rebinding WeakReference ownership to a different thread by
442 // keeping a persistent reference. This avoids problems with the
443 // thread safety of reaching into this class from multiple threads to
444 // attain a WeakPtr.
445 base::WeakPtr<DXVAVideoDecodeAccelerator> weak_ptr_;
446
447 // Set to true if we are in the context of a Flush operation. Used to prevent
448 // multiple flush done notifications being sent out.
449 bool pending_flush_;
450
451 // Defaults to false. Indicates if we should use D3D or DX11 interfaces for
452 // H/W decoding.
453 bool use_dx11_;
454
455 // True if we should use DXGI keyed mutexes to synchronize between the two
456 // contexts.
457 bool use_keyed_mutex_;
458
459 // Set to true if the DX11 video format converter input media types need to
460 // be initialized. Defaults to true.
461 bool dx11_video_format_converter_media_type_needs_init_;
462
463 // Set to true if we are sharing ANGLE's device.
464 bool using_angle_device_;
465
466 // Enables experimental hardware acceleration for VP8/VP9 video decoding.
467 const bool enable_accelerated_vpx_decode_;
468
469 // The media foundation H.264 decoder has problems handling changes like
470 // resolution change, bitrate change etc. If we reinitialize the decoder
471 // when these changes occur then, the decoder works fine. The
472 // H264ConfigChangeDetector class provides functionality to check if the
473 // stream configuration changed.
474 std::unique_ptr<H264ConfigChangeDetector> config_change_detector_;
475
476 // Contains the initialization parameters for the video.
477 Config config_;
478
479 // WeakPtrFactory for posting tasks back to |this|.
480 base::WeakPtrFactory<DXVAVideoDecodeAccelerator> weak_this_factory_;
481
482 // Function pointer for the MFCreateDXGIDeviceManager API.
483 static CreateDXGIDeviceManager create_dxgi_device_manager_;
484
485 DISALLOW_COPY_AND_ASSIGN(DXVAVideoDecodeAccelerator);
486 };
487
488 } // namespace content
489
490 #endif // CONTENT_COMMON_GPU_MEDIA_DXVA_VIDEO_DECODE_ACCELERATOR_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698