Merge pull request #1263 from abidrahmank:pyCLAHE_24
[profile/ivi/opencv.git] / samples / winrt / ImageManipulations / MediaExtensions / Common / OpQueue.h
1 //////////////////////////////////////////////////////////////////////////
2 //
3 // OpQueue.h
4 // Async operation queue.
5 //
6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
7 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
9 // PARTICULAR PURPOSE.
10 //
11 // Copyright (c) Microsoft Corporation. All rights reserved.
12 //
13 //////////////////////////////////////////////////////////////////////////
14
15 #pragma once
16
17 #pragma warning( push )
18 #pragma warning( disable : 4355 )  // 'this' used in base member initializer list
19
20 /*
21     This header file defines an object to help queue and serialize
22     asynchronous operations.
23
24     Background:
25
26     To perform an operation asynchronously in Media Foundation, an object
27     does one of the following:
28
29         1. Calls MFPutWorkItem(Ex), using either a standard work queue
30            identifier or a caller-allocated work queue. The work-queue
31            thread invokes the object's callback.
32
33         2. Creates an async result object (IMFAsyncResult) and calls
34            MFInvokeCallback to invoke the object's callback.
35
36     Ultimately, either of these cause the object's callback to be invoked
37     from a work-queue thread. The object can then complete the operation
38     inside the callback.
39
40     However, the Media Foundation platform may dispatch async callbacks in
41     parallel on several threads. Putting an item on a work queue does NOT
42     guarantee that one operation will complete before the next one starts,
43     or even that work items will be dispatched in the same order they were
44     called.
45
46     To serialize async operations that should not overlap, an object should
47     use a queue. While one operation is pending, subsequent operations are
48     put on the queue, and only dispatched after the previous operation is
49     complete.
50
51     The granularity of a single "operation" depends on the requirements of
52     that particular object. A single operation might involve several
53     asynchronous calls before the object dispatches the next operation on
54     the queue.
55
56
57 */
58
59
60
61 //-------------------------------------------------------------------
62 // OpQueue class template
63 //
64 // Base class for an async operation queue.
65 //
66 // TOperation: The class used to describe operations. This class must
67 //          implement IUnknown.
68 //
69 // The OpQueue class is an abstract class. The derived class must
70 // implement the following pure-virtual methods:
71 //
72 // - IUnknown methods (AddRef, Release, QI)
73 //
74 // - DispatchOperation:
75 //
76 //      Performs the asynchronous operation specified by pOp.
77 //
78 //      At the end of each operation, the derived class must call
79 //      ProcessQueue to process the next operation in the queue.
80 //
81 //      NOTE: An operation is not required to complete inside the
82 //      DispatchOperation method. A single operation might consist
83 //      of several asynchronous method calls.
84 //
85 // - ValidateOperation:
86 //
87 //      Checks whether the object can perform the operation specified
88 //      by pOp at this time.
89 //
90 //      If the object cannot perform the operation now (e.g., because
91 //      another operation is still in progress) the method should
92 //      return MF_E_NOTACCEPTING.
93 //
94 //-------------------------------------------------------------------
95 #include "linklist.h"
96 #include "AsyncCB.h"
97
98 template <class T, class TOperation>
99 class OpQueue //: public IUnknown
100 {
101 public:
102
103     typedef ComPtrList<TOperation>   OpList;
104
105     HRESULT QueueOperation(TOperation *pOp);
106
107 protected:
108
109     HRESULT ProcessQueue();
110     HRESULT ProcessQueueAsync(IMFAsyncResult *pResult);
111
112     virtual HRESULT DispatchOperation(TOperation *pOp) = 0;
113     virtual HRESULT ValidateOperation(TOperation *pOp) = 0;
114
115     OpQueue(CRITICAL_SECTION& critsec)
116         : m_OnProcessQueue(static_cast<T *>(this), &OpQueue::ProcessQueueAsync),
117           m_critsec(critsec)
118     {
119     }
120
121     virtual ~OpQueue()
122     {
123     }
124
125 protected:
126     OpList                  m_OpQueue;         // Queue of operations.
127     CRITICAL_SECTION&       m_critsec;         // Protects the queue state.
128     AsyncCallback<T>  m_OnProcessQueue;  // ProcessQueueAsync callback.
129 };
130
131
132
133 //-------------------------------------------------------------------
134 // Place an operation on the queue.
135 // Public method.
136 //-------------------------------------------------------------------
137
138 template <class T, class TOperation>
139 HRESULT OpQueue<T, TOperation>::QueueOperation(TOperation *pOp)
140 {
141     HRESULT hr = S_OK;
142
143     EnterCriticalSection(&m_critsec);
144
145     hr = m_OpQueue.InsertBack(pOp);
146     if (SUCCEEDED(hr))
147     {
148         hr = ProcessQueue();
149     }
150
151     LeaveCriticalSection(&m_critsec);
152     return hr;
153 }
154
155
156 //-------------------------------------------------------------------
157 // Process the next operation on the queue.
158 // Protected method.
159 //
160 // Note: This method dispatches the operation to a work queue.
161 //-------------------------------------------------------------------
162
163 template <class T, class TOperation>
164 HRESULT OpQueue<T, TOperation>::ProcessQueue()
165 {
166     HRESULT hr = S_OK;
167     if (m_OpQueue.GetCount() > 0)
168     {
169         hr = MFPutWorkItem2(
170             MFASYNC_CALLBACK_QUEUE_STANDARD,    // Use the standard work queue.
171             0,                                  // Default priority
172             &m_OnProcessQueue,                  // Callback method.
173             nullptr                             // State object.
174             );
175     }
176     return hr;
177 }
178
179
180 //-------------------------------------------------------------------
181 // Process the next operation on the queue.
182 // Protected method.
183 //
184 // Note: This method is called from a work-queue thread.
185 //-------------------------------------------------------------------
186
187 template <class T, class TOperation>
188 HRESULT OpQueue<T, TOperation>::ProcessQueueAsync(IMFAsyncResult *pResult)
189 {
190     HRESULT hr = S_OK;
191     TOperation *pOp = nullptr;
192
193     EnterCriticalSection(&m_critsec);
194
195     if (m_OpQueue.GetCount() > 0)
196     {
197         hr = m_OpQueue.GetFront(&pOp);
198
199         if (SUCCEEDED(hr))
200         {
201             hr = ValidateOperation(pOp);
202         }
203         if (SUCCEEDED(hr))
204         {
205             hr = m_OpQueue.RemoveFront(nullptr);
206         }
207         if (SUCCEEDED(hr))
208         {
209             (void)DispatchOperation(pOp);
210         }
211     }
212
213     if (pOp != nullptr)
214     {
215         pOp->Release();
216     }
217
218     LeaveCriticalSection(&m_critsec);
219     return hr;
220 }
221
222 #pragma warning( pop )