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.
5 #ifndef CONTENT_COMMON_GPU_MEDIA_DXVA_VIDEO_DECODE_ACCELERATOR_H_
6 #define CONTENT_COMMON_GPU_MEDIA_DXVA_VIDEO_DECODE_ACCELERATOR_H_
10 // Work around bug in this header by disabling the relevant warning for it.
11 // https://connect.microsoft.com/VisualStudio/feedback/details/911260/dxva2api-h-in-win8-sdk-triggers-c4201-with-w4
13 #pragma warning(disable:4201)
21 #include "base/compiler_specific.h"
22 #include "base/memory/linked_ptr.h"
23 #include "base/memory/weak_ptr.h"
24 #include "base/synchronization/lock.h"
25 #include "base/threading/non_thread_safe.h"
26 #include "base/threading/thread.h"
27 #include "base/win/scoped_comptr.h"
28 #include "content/common/content_export.h"
29 #include "media/video/video_decode_accelerator.h"
32 interface IDirect3DSurface9
;
38 typedef HRESULT (WINAPI
* CreateDXGIDeviceManager
)(
40 IMFDXGIDeviceManager
** device_manager
);
44 // Class to provide a DXVA 2.0 based accelerator using the Microsoft Media
45 // foundation APIs via the VideoDecodeAccelerator interface.
46 // This class lives on a single thread and DCHECKs that it is never accessed
48 class CONTENT_EXPORT DXVAVideoDecodeAccelerator
49 : public media::VideoDecodeAccelerator
{
52 kUninitialized
, // un-initialized.
53 kNormal
, // normal playing state.
54 kResetting
, // upon received Reset(), before ResetDone()
55 kStopped
, // upon output EOS received.
56 kFlushing
, // upon flush request received.
59 // Does not take ownership of |client| which must outlive |*this|.
60 explicit DXVAVideoDecodeAccelerator(
61 const base::Callback
<bool(void)>& make_context_current
,
62 gfx::GLContext
* gl_context
);
63 ~DXVAVideoDecodeAccelerator() override
;
65 // media::VideoDecodeAccelerator implementation.
66 bool Initialize(media::VideoCodecProfile profile
,
67 Client
* client
) override
;
68 void Decode(const media::BitstreamBuffer
& bitstream_buffer
) override
;
69 void AssignPictureBuffers(
70 const std::vector
<media::PictureBuffer
>& buffers
) override
;
71 void ReusePictureBuffer(int32 picture_buffer_id
) override
;
72 void Flush() override
;
73 void Reset() override
;
74 void Destroy() override
;
75 bool CanDecodeOnIOThread() override
;
76 GLenum
GetSurfaceInternalFormat() const override
;
78 static media::VideoDecodeAccelerator::SupportedProfiles
79 GetSupportedProfiles();
82 typedef void* EGLConfig
;
83 typedef void* EGLSurface
;
85 // Creates and initializes an instance of the D3D device and the
86 // corresponding device manager. The device manager instance is eventually
87 // passed to the IMFTransform interface implemented by the decoder.
88 bool CreateD3DDevManager();
90 // Creates and initializes an instance of the DX11 device and the
91 // corresponding device manager. The device manager instance is eventually
92 // passed to the IMFTransform interface implemented by the decoder.
93 bool CreateDX11DevManager();
95 // Creates, initializes and sets the media codec types for the decoder.
96 bool InitDecoder(media::VideoCodecProfile profile
);
98 // Validates whether the decoder supports hardware video acceleration.
99 bool CheckDecoderDxvaSupport();
101 // Returns information about the input and output streams. This includes
102 // alignment information, decoder support flags, minimum sample size, etc.
103 bool GetStreamsInfoAndBufferReqs();
105 // Registers the input and output media types on the decoder. This includes
106 // the expected input and output formats.
107 bool SetDecoderMediaTypes();
109 // Registers the input media type for the decoder.
110 bool SetDecoderInputMediaType();
112 // Registers the output media type for the decoder.
113 bool SetDecoderOutputMediaType(const GUID
& subtype
);
115 // Passes a command message to the decoder. This includes commands like
116 // start of stream, end of stream, flush, drain the decoder, etc.
117 bool SendMFTMessage(MFT_MESSAGE_TYPE msg
, int32 param
);
119 // The bulk of the decoding happens here. This function handles errors,
120 // format changes and processes decoded output.
123 // Invoked when we have a valid decoded output sample. Retrieves the D3D
124 // surface and maintains a copy of it which is passed eventually to the
125 // client when we have a picture buffer to copy the surface contents to.
126 bool ProcessOutputSample(IMFSample
* sample
);
128 // Processes pending output samples by copying them to available picture
130 void ProcessPendingSamples();
132 // Helper function to notify the accelerator client about the error.
133 void StopOnError(media::VideoDecodeAccelerator::Error error
);
135 // Transitions the decoder to the uninitialized state. The decoder will stop
136 // accepting requests in this state.
139 // Notifies the client that the input buffer identifed by input_buffer_id has
141 void NotifyInputBufferRead(int input_buffer_id
);
143 // Notifies the client that the decoder was flushed.
144 void NotifyFlushDone();
146 // Notifies the client that the decoder was reset.
147 void NotifyResetDone();
149 // Requests picture buffers from the client.
150 void RequestPictureBuffers(int width
, int height
);
152 // Notifies the client about the availability of a picture.
153 void NotifyPictureReady(int picture_buffer_id
,
155 const gfx::Rect
& picture_buffer_size
);
157 // Sends pending input buffer processed acks to the client if we don't have
158 // output samples waiting to be processed.
159 void NotifyInputBuffersDropped();
161 // Decodes pending input buffers.
162 void DecodePendingInputBuffers();
164 // Helper for handling the Flush operation.
165 void FlushInternal();
167 // Helper for handling the Decode operation.
168 void DecodeInternal(const base::win::ScopedComPtr
<IMFSample
>& input_sample
);
170 // Handles mid stream resolution changes.
171 void HandleResolutionChanged(int width
, int height
);
173 struct DXVAPictureBuffer
;
174 typedef std::map
<int32
, linked_ptr
<DXVAPictureBuffer
> > OutputBuffers
;
176 // Tells the client to dismiss the stale picture buffers passed in.
177 void DismissStaleBuffers();
179 // Called after the client indicates we can recycle a stale picture buffer.
180 void DeferredDismissStaleBuffer(int32 picture_buffer_id
);
182 // Sets the state of the decoder. Called from the main thread and the decoder
183 // thread. The state is changed on the main thread.
184 void SetState(State state
);
186 // Gets the state of the decoder. Can be called from the main thread and
187 // the decoder thread. Thread safe.
190 // Worker function for the Decoder Reset functionality. Executes on the
191 // decoder thread and queues tasks on the main thread as needed.
194 // Starts the thread used for decoding.
195 void StartDecoderThread();
197 // Returns if we have output samples waiting to be processed. We only
198 // allow one output sample to be present in the output queue at any given
200 bool OutputSamplesPresent();
202 // Copies the source surface |src_surface| to the destination |dest_surface|.
203 // The copying is done on the decoder thread.
204 void CopySurface(IDirect3DSurface9
* src_surface
,
205 IDirect3DSurface9
* dest_surface
,
206 int picture_buffer_id
,
207 int input_buffer_id
);
209 // This is a notification that the source surface |src_surface| was copied to
210 // the destination |dest_surface|. Received on the main thread.
211 void CopySurfaceComplete(IDirect3DSurface9
* src_surface
,
212 IDirect3DSurface9
* dest_surface
,
213 int picture_buffer_id
,
214 int input_buffer_id
);
216 // Copies the source texture |src_texture| to the destination |dest_texture|.
217 // The copying is done on the decoder thread. The |video_frame| parameter
218 // is the sample containing the frame to be copied.
219 void CopyTexture(ID3D11Texture2D
* src_texture
,
220 ID3D11Texture2D
* dest_texture
,
221 IMFSample
* video_frame
,
222 int picture_buffer_id
,
223 int input_buffer_id
);
225 // Flushes the decoder device to ensure that the decoded surface is copied
226 // to the target surface. |iterations| helps to maintain an upper limit on
227 // the number of times we try to complete the flush operation.
228 void FlushDecoder(int iterations
,
229 IDirect3DSurface9
* src_surface
,
230 IDirect3DSurface9
* dest_surface
,
231 int picture_buffer_id
,
232 int input_buffer_id
);
234 // Initializes the DX11 Video format converter media types.
235 // Returns true on success.
236 bool InitializeDX11VideoFormatConverterMediaType(int width
, int height
);
238 // Returns the output video frame dimensions (width, height).
239 // |sample| :- This is the output sample containing the video frame.
240 // |width| :- The width is returned here.
241 // |height| :- The height is returned here.
242 // Returns true on success.
243 bool GetVideoFrameDimensions(IMFSample
* sample
, int* width
, int* height
);
245 // To expose client callbacks from VideoDecodeAccelerator.
246 media::VideoDecodeAccelerator::Client
* client_
;
248 base::win::ScopedComPtr
<IMFTransform
> decoder_
;
249 base::win::ScopedComPtr
<IMFTransform
> video_format_converter_mft_
;
251 base::win::ScopedComPtr
<IDirect3D9Ex
> d3d9_
;
252 base::win::ScopedComPtr
<IDirect3DDevice9Ex
> d3d9_device_ex_
;
253 base::win::ScopedComPtr
<IDirect3DDeviceManager9
> device_manager_
;
254 base::win::ScopedComPtr
<IDirect3DQuery9
> query_
;
256 base::win::ScopedComPtr
<ID3D11DeviceContext
> d3d11_device_context_
;
257 base::win::ScopedComPtr
<ID3D11Device
> d3d11_device_
;
258 base::win::ScopedComPtr
<IMFDXGIDeviceManager
> d3d11_device_manager_
;
259 base::win::ScopedComPtr
<ID3D11Query
> d3d11_query_
;
261 // Ideally the reset token would be a stack variable which is used while
262 // creating the device manager. However it seems that the device manager
263 // holds onto the token and attempts to access it if the underlying device
265 // TODO(ananta): This needs to be verified.
266 uint32 dev_manager_reset_token_
;
268 // Reset token for the DX11 device manager.
269 uint32 dx11_dev_manager_reset_token_
;
271 uint32 dx11_dev_manager_reset_token_format_conversion_
;
273 // The EGL config to use for decoded frames.
274 EGLConfig egl_config_
;
276 // Current state of the decoder.
277 volatile State state_
;
279 MFT_INPUT_STREAM_INFO input_stream_info_
;
280 MFT_OUTPUT_STREAM_INFO output_stream_info_
;
282 // Contains information about a decoded sample.
283 struct PendingSampleInfo
{
284 PendingSampleInfo(int32 buffer_id
, IMFSample
* sample
);
285 ~PendingSampleInfo();
287 int32 input_buffer_id
;
289 // The target picture buffer id where the frame would be copied to.
291 int picture_buffer_id
;
293 base::win::ScopedComPtr
<IMFSample
> output_sample
;
296 typedef std::list
<PendingSampleInfo
> PendingOutputSamples
;
298 // List of decoded output samples. Protected by |decoder_lock_|.
299 PendingOutputSamples pending_output_samples_
;
301 // This map maintains the picture buffers passed the client for decoding.
302 // The key is the picture buffer id.
303 OutputBuffers output_picture_buffers_
;
305 // After a resolution change there may be a few output buffers which have yet
306 // to be displayed so they cannot be dismissed immediately. We move them from
307 // |output_picture_buffers_| to this map so they may be dismissed once they
309 OutputBuffers stale_output_picture_buffers_
;
311 // Set to true if we requested picture slots from the client.
312 bool pictures_requested_
;
314 // Counter which holds the number of input packets before a successful
316 int inputs_before_decode_
;
318 // Set to true when the drain message is sent to the decoder during a flush
319 // operation. Used to ensure the message is only sent once after
320 // |pending_input_buffers_| is drained. Protected by |decoder_lock_|.
321 bool sent_drain_message_
;
323 // List of input samples waiting to be processed.
324 typedef std::list
<base::win::ScopedComPtr
<IMFSample
>> PendingInputs
;
325 PendingInputs pending_input_buffers_
;
327 // Callback to set the correct gl context.
328 base::Callback
<bool(void)> make_context_current_
;
330 // Which codec we are decoding with hardware acceleration.
331 media::VideoCodec codec_
;
332 // Thread on which the decoder operations like passing input frames,
333 // getting output frames are performed. One instance of this thread
334 // is created per decoder instance.
335 base::Thread decoder_thread_
;
337 // Task runner to be used for posting tasks to the decoder thread.
338 scoped_refptr
<base::SingleThreadTaskRunner
> decoder_thread_task_runner_
;
340 // Task runner to be used for posting tasks to the main thread.
341 scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_task_runner_
;
343 // Used to synchronize access between the decoder thread and the main thread.
344 base::Lock decoder_lock_
;
346 // Disallow rebinding WeakReference ownership to a different thread by
347 // keeping a persistent reference. This avoids problems with the
348 // thread safety of reaching into this class from multiple threads to
350 base::WeakPtr
<DXVAVideoDecodeAccelerator
> weak_ptr_
;
352 // Set to true if we are in the context of a Flush operation. Used to prevent
353 // multiple flush done notifications being sent out.
356 // Defaults to false. Indicates if we should use D3D or DX11 interfaces for
360 // Set to true if the DX11 video format converter input media types need to
361 // be initialized. Defaults to true.
362 bool dx11_video_format_converter_media_type_needs_init_
;
364 // The GLContext to be used by the decoder.
365 scoped_refptr
<gfx::GLContext
> gl_context_
;
367 // WeakPtrFactory for posting tasks back to |this|.
368 base::WeakPtrFactory
<DXVAVideoDecodeAccelerator
> weak_this_factory_
;
370 // Function pointer for the MFCreateDXGIDeviceManager API.
371 static CreateDXGIDeviceManager create_dxgi_device_manager_
;
374 } // namespace content
376 #endif // CONTENT_COMMON_GPU_MEDIA_DXVA_VIDEO_DECODE_ACCELERATOR_H_