|
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 /** |
|
17 @file |
|
18 @internalComponent |
|
19 */ |
|
20 |
|
21 #include <mmf/devvideo/devvideobase.h> |
|
22 #include "buffermanager.h" |
|
23 #include "videoframebuffer.h" |
|
24 #include "rendererutil.h" |
|
25 |
|
26 /** Constructor for performing 1st stage construction */ |
|
27 CRendererBufferManager::CRendererBufferManager(const RChunk& aChunk, TBool aTimed) |
|
28 : iChunk(aChunk), |
|
29 iTimed(aTimed), |
|
30 iAvailBuffers(TVideoFrameBuffer::iOffset), |
|
31 iWaitingBuffers(TVideoFrameBuffer::iOffset), |
|
32 iWaitingBuffersIter(iWaitingBuffers) |
|
33 {} |
|
34 |
|
35 /** Destructor. */ |
|
36 CRendererBufferManager::~CRendererBufferManager() |
|
37 { |
|
38 if (iTimed) |
|
39 { |
|
40 iMutex.Close(); |
|
41 } |
|
42 iAvailBuffers.Reset(); |
|
43 iWaitingBuffers.Reset(); |
|
44 iBuffers.ResetAndDestroy(); |
|
45 iChunk.Close(); |
|
46 } |
|
47 |
|
48 /** Two-phased constructor. */ |
|
49 CRendererBufferManager* CRendererBufferManager::NewL(const RSurfaceManager::TSurfaceInfoV01& aSurfaceInfo, const RArray<TInt>& aBufferOffsets, const RChunk& aChunk, TBool aTimed) |
|
50 { |
|
51 CRendererBufferManager* self = new (ELeave) CRendererBufferManager(aChunk, aTimed); |
|
52 CleanupStack::PushL(self); |
|
53 self->ConstructL(aSurfaceInfo, aBufferOffsets); |
|
54 CleanupStack::Pop(); // self; |
|
55 return self; |
|
56 } |
|
57 |
|
58 /** Constructor for performing 2nd stage construction */ |
|
59 void CRendererBufferManager::ConstructL(const RSurfaceManager::TSurfaceInfoV01& aSurfaceInfo, const RArray<TInt>& aBufferOffsets) |
|
60 { |
|
61 if (iTimed) |
|
62 { |
|
63 User::LeaveIfError(iMutex.CreateLocal()); |
|
64 } |
|
65 |
|
66 TUncompressedVideoFormat format = VideoRendererUtil::ConvertUidPixelFormatToUncompressedVideoFormatL(aSurfaceInfo.iPixelFormat); |
|
67 |
|
68 TVideoFrameBuffer* buffer = NULL; |
|
69 for (TInt i = 0; i < aSurfaceInfo.iBuffers; ++i) |
|
70 { |
|
71 buffer = new (ELeave) TVideoFrameBuffer(format, aSurfaceInfo.iStride, i, iChunk, aBufferOffsets[i]); |
|
72 buffer->SetBufferStatus(TVideoFrameBuffer::EAvailable); |
|
73 CleanupStack::PushL(buffer); |
|
74 iBuffers.AppendL(buffer); |
|
75 CleanupStack::Pop(buffer); |
|
76 |
|
77 iAvailBuffers.AddLast(*buffer); |
|
78 } |
|
79 } |
|
80 |
|
81 /** Lock buffer table on timed mode */ |
|
82 void CRendererBufferManager::Lock() |
|
83 { |
|
84 if (iTimed) |
|
85 { |
|
86 iMutex.Wait(); |
|
87 } |
|
88 } |
|
89 |
|
90 /** Unlock buffer table on timed mode */ |
|
91 void CRendererBufferManager::Unlock() |
|
92 { |
|
93 if (iTimed) |
|
94 { |
|
95 iMutex.Signal(); |
|
96 } |
|
97 } |
|
98 |
|
99 /** Get the next available buffer */ |
|
100 TVideoFrameBuffer* CRendererBufferManager::NextBuffer() |
|
101 { |
|
102 Lock(); |
|
103 |
|
104 TVideoFrameBuffer* buffer = NULL; |
|
105 if (!iAvailBuffers.IsEmpty()) |
|
106 { |
|
107 buffer = iAvailBuffers.First(); |
|
108 |
|
109 __ASSERT_DEBUG(buffer->BufferStatus() == TVideoFrameBuffer::EAvailable, |
|
110 User::Panic(_L("CRBM::NextBuffer"), KErrCorrupt)); |
|
111 buffer->SetBufferStatus(TVideoFrameBuffer::EUsedByClient); |
|
112 buffer->DblQueLink().Deque(); |
|
113 } |
|
114 |
|
115 Unlock(); |
|
116 return buffer; |
|
117 } |
|
118 |
|
119 /** Check if a buffer was previously sent to client */ |
|
120 TBool CRendererBufferManager::BufferUsedByClient(TVideoFrameBuffer* aBuffer) |
|
121 { |
|
122 TVideoFrameBuffer* buffer = iBuffers[aBuffer->BufferId()]; |
|
123 if (buffer->BufferStatus() == TVideoFrameBuffer::EUsedByClient && aBuffer == buffer) |
|
124 { |
|
125 return ETrue; |
|
126 } |
|
127 return EFalse; |
|
128 } |
|
129 |
|
130 /** Release the buffer for reuse */ |
|
131 TBool CRendererBufferManager::ReleaseBuffer(TVideoFrameBuffer* aBuffer) |
|
132 { |
|
133 TBool released = EFalse; |
|
134 Lock(); |
|
135 |
|
136 if (BufferUsedByClient(aBuffer)) |
|
137 { |
|
138 // release the buffer if it was previously sent to client |
|
139 aBuffer->SetBufferStatus(TVideoFrameBuffer::EAvailable); |
|
140 iAvailBuffers.AddLast(*aBuffer); |
|
141 released = ETrue; |
|
142 } |
|
143 |
|
144 Unlock(); |
|
145 return released; |
|
146 } |
|
147 |
|
148 /** Received notification that buffer become available */ |
|
149 void CRendererBufferManager::BufferAvailable(TInt aBufferId) |
|
150 { |
|
151 Lock(); |
|
152 |
|
153 TVideoFrameBuffer* buffer = iBuffers[aBufferId]; |
|
154 |
|
155 __ASSERT_DEBUG(buffer->BufferStatus() == TVideoFrameBuffer::EWaiting || buffer->BufferStatus() == TVideoFrameBuffer::ESubmitted, |
|
156 User::Panic(_L("CRBM::BufferAvailable"), KErrCorrupt)); |
|
157 |
|
158 buffer->SetBufferStatus(TVideoFrameBuffer::EAvailable); |
|
159 buffer->DblQueLink().Deque(); |
|
160 iAvailBuffers.AddLast(*buffer); |
|
161 |
|
162 Unlock(); |
|
163 } |
|
164 |
|
165 /** Get the next waiting buffer to submit |
|
166 @param aRemoveFromList If true, mark the buffer as submitted and deque from waiting list |
|
167 @param aIsLast ETrue on result if the returned buffer is the last buffer in waiting list |
|
168 */ |
|
169 TVideoFrameBuffer* CRendererBufferManager::WaitingBuffer(TBool aRemoveFromList, TBool& aIsLast) |
|
170 { |
|
171 Lock(); |
|
172 |
|
173 TVideoFrameBuffer* buf = NULL; |
|
174 if (iWaitingBuffers.IsEmpty() == EFalse) |
|
175 { |
|
176 buf = iWaitingBuffers.First(); |
|
177 |
|
178 __ASSERT_DEBUG(buf->BufferStatus() == TVideoFrameBuffer::EWaiting, |
|
179 User::Panic(_L("CRBM::WaitingBuffer"), KErrCorrupt)); |
|
180 aIsLast = iWaitingBuffers.IsLast(buf); |
|
181 |
|
182 if (aRemoveFromList) |
|
183 { |
|
184 buf->SetBufferStatus(TVideoFrameBuffer::ESubmitted); |
|
185 buf->DblQueLink().Deque(); |
|
186 } |
|
187 } |
|
188 |
|
189 Unlock(); |
|
190 return buf; |
|
191 } |
|
192 |
|
193 /** Mark the buffer as submitted and deque from waiting list */ |
|
194 void CRendererBufferManager::BufferSubmitted(TVideoFrameBuffer* aBuffer) |
|
195 { |
|
196 Lock(); |
|
197 |
|
198 __ASSERT_DEBUG(aBuffer->BufferStatus() == TVideoFrameBuffer::EWaiting, |
|
199 User::Panic(_L("CRBM::BufferSubmitted"), KErrArgument)); |
|
200 |
|
201 aBuffer->SetBufferStatus(TVideoFrameBuffer::ESubmitted); |
|
202 aBuffer->DblQueLink().Deque(); |
|
203 |
|
204 Unlock(); |
|
205 } |
|
206 |
|
207 /** Return ETrue if the waiting list is empty */ |
|
208 TBool CRendererBufferManager::WaitingListIsEmpty() |
|
209 { |
|
210 Lock(); |
|
211 |
|
212 TBool ret = iWaitingBuffers.IsEmpty(); |
|
213 |
|
214 Unlock(); |
|
215 return ret; |
|
216 } |
|
217 |
|
218 /** |
|
219 Mark a buffer as waiting for update and add to waiting list, return ETrue |
|
220 if rescheduled is needed (i.e. head of waiting list has changed and the list wasn't empty) */ |
|
221 TBool CRendererBufferManager::UpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aTime) |
|
222 { |
|
223 Lock(); |
|
224 |
|
225 TBool headChanged = EFalse; |
|
226 if (BufferUsedByClient(aBuffer)) |
|
227 { |
|
228 aBuffer->SetBufferStatus(TVideoFrameBuffer::EWaiting); |
|
229 aBuffer->SetPresentationTime(aTime); |
|
230 |
|
231 // add buffer to waiting buffer list according to presentation time |
|
232 if (iWaitingBuffers.IsEmpty()) |
|
233 { |
|
234 iWaitingBuffers.AddLast(*aBuffer); |
|
235 } |
|
236 else |
|
237 { |
|
238 TVideoFrameBuffer* buf = iWaitingBuffers.Last(); |
|
239 if (aTime >= buf->PresentationTime()) |
|
240 { |
|
241 iWaitingBuffers.AddLast(*aBuffer); |
|
242 } |
|
243 else |
|
244 { |
|
245 // client tried to insert a older frame, search for the right position to insert |
|
246 iWaitingBuffersIter.SetToFirst(); |
|
247 while ((buf = iWaitingBuffersIter++) != NULL) |
|
248 { |
|
249 if (aTime < buf->PresentationTime()) |
|
250 { |
|
251 // Found the slot |
|
252 if (iWaitingBuffers.IsFirst(buf)) |
|
253 { |
|
254 iWaitingBuffers.AddFirst(*aBuffer); |
|
255 headChanged = ETrue; |
|
256 } |
|
257 else |
|
258 { |
|
259 aBuffer->DblQueLink().AddBefore(&(buf->DblQueLink())); |
|
260 } |
|
261 } |
|
262 } |
|
263 } |
|
264 } |
|
265 } |
|
266 else |
|
267 { |
|
268 DEBUGPRINT1(_L("CRendererBufferManager::UpdateBuffer receive buffer not usable by client")); |
|
269 __ASSERT_DEBUG(EFalse, User::Panic(_L("CRBM::UpdateBuf"), KErrBadHandle)); |
|
270 } |
|
271 |
|
272 Unlock(); |
|
273 |
|
274 return headChanged; |
|
275 } |