1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18 #ifndef PVMF_MEDIA_FRAG_GROUP_H_INCLUDED
19 #define PVMF_MEDIA_FRAG_GROUP_H_INCLUDED
20
21 #ifndef PVMF_MEDIA_DATA_IMPL_H_INCLUDED
22 #include "pvmf_media_data_impl.h"
23 #endif
24
25 #ifndef OSCL_SHARED_PTR_H_INCLUDED
26 #include "oscl_shared_ptr.h"
27 #endif
28
29 #ifndef OSCL_VECTOR_H_INCLUDED
30 #include "oscl_vector.h"
31 #endif
32
33 #ifndef OSCL_MEM_H_INCLUDED
34 #include "oscl_mem.h"
35 #endif
36
37 #ifndef OSCL_MEM_MEMPOOL_H_INCLUDED
38 #include "oscl_mem_mempool.h"
39 #endif
40
41 // constants
42 const uint PVMF_MEDIA_FRAG_GROUP_DEFAULT_CAPACITY = 10;
43
44 class MediaDataEntry
45 {
46 public:
MediaDataEntry()47 MediaDataEntry() : next(NULL) {}
~MediaDataEntry()48 ~MediaDataEntry()
49 {
50 mediaDataImpl.Unbind();
51 }
52 OsclSharedPtr<PVMFMediaDataImpl> mediaDataImpl;
53 MediaDataEntry* next;
54 };
55
56 /**
57 * The PVMFMediaFragGroup class is a MediaDataImpl implementation that
58 * stores multiple OsclRefCounterMemFrag which have been separately allocated.
59 * It takes an allocator as a templatized parameter to allow the user to determine
60 * how memory for storing the fragments internally is allocated.
61 * The PVMFMediaFragGroup is created with a fixed capacity that is passed in at
62 * construction time.
63 */
64 template<class Alloc>
65 class PVMFMediaFragGroup : public PVMFMediaDataImpl
66 {
67
68 public:
69 virtual uint32 getMarkerInfo();
70 virtual bool isRandomAccessPoint();
71 virtual uint32 getErrorsFlag();
72 virtual uint32 getNumFragments();
73 virtual bool getMediaFragment(uint32 index, OsclRefCounterMemFrag& memfrag);
74 virtual bool getMediaFragmentSize(uint32 index, uint32& size);
75 virtual uint32 getFilledSize();
76 virtual uint32 getCapacity();
77
78 virtual void setCapacity(uint32 aCapacity);
79 virtual bool setMediaFragFilledLen(uint32 index, uint32 len);
80 virtual bool setMarkerInfo(uint32 marker);
81 virtual bool setRandomAccessPoint(bool flag);
82 virtual bool setErrorsFlag(uint32 flag);
83
84 virtual bool appendMediaFragment(OsclRefCounterMemFrag& memfrag);
85 virtual bool clearMediaFragments();
86
87 /* NOTE!!: The constructor assumes the refcnt has already been incremented
88 * to reflect this class holding a reference to the buffer. Increment it
89 * externally if you aren't simply passing ownership of a reference
90 */
91 PVMFMediaFragGroup(uint32 capacity = PVMF_MEDIA_FRAG_GROUP_DEFAULT_CAPACITY);
92
93 virtual ~PVMFMediaFragGroup();
94
95 private:
96 uint32 marker_info;
97 bool random_access_point;
98 uint32 errors_flag;
99 Oscl_Vector<OsclRefCounterMemFrag, Alloc> iFragments;
100 uint32 capacity;
101 uint32 filled_size;
102 };
103
104
105 /**
106 * The PVMFMediaFragGroupCombinedAlloc allocator class
107 * takes care of allocating the refcounter, PVMFMediaFragGroup container,
108 * and the actual buffer space in a single block of memory.
109 */
110 template<class Alloc>
111 class PVMFMediaFragGroupCombinedAlloc : public OsclDestructDealloc
112 {
113
114 public:
115 PVMFMediaFragGroupCombinedAlloc(uint in_capacity, uint in_fragment_capacity,
116 Oscl_DefAlloc* opt_gen_alloc = 0)
capacity(in_capacity)117 : capacity(in_capacity)
118 , fragment_capacity(in_fragment_capacity)
119 , gen_alloc(opt_gen_alloc)
120 , available_mfgs(NULL)
121 , num_available_mfgs(0)
122 , iRefCnt(0)
123 , iDestroy(false)
124 , iCheckNextAvailableFreeChunk(false)
125 , iObserver(NULL)
126 , iNextAvailableContextData(NULL)
127 {
128 addRef();
129 };
130 virtual ~PVMFMediaFragGroupCombinedAlloc();
131 void create();
132 void destroy();
133 void addRef();
134 void removeRef();
135 void do_allocate(uint32 requested_fragment_capacity = 0);
136 OsclSharedPtr<PVMFMediaDataImpl> allocate(uint32 requested_fragment_capacity = 0);
137 void destruct_and_dealloc(OsclAny* ptr);
IsMsgAvailable()138 bool IsMsgAvailable()
139 {
140 if (available_mfgs == NULL)
141 {
142 return false;
143 }
144 return true;
145 }
146
147 void notifyfreechunkavailable(OsclMemPoolFixedChunkAllocatorObserver& obs, OsclAny* aContextData = NULL)
148 {
149 iCheckNextAvailableFreeChunk = true;
150 iObserver = &obs;
151 iNextAvailableContextData = aContextData;
152 }
153
CancelFreeChunkAvailableCallback()154 void CancelFreeChunkAvailableCallback()
155 {
156 iCheckNextAvailableFreeChunk = false;
157 iObserver = NULL;
158 iNextAvailableContextData = NULL;
159 }
160
NumMsgAvail()161 unsigned NumMsgAvail()
162 {
163 return num_available_mfgs;
164 }
165
166 protected:
167 void append(OsclSharedPtr<PVMFMediaDataImpl> & media_data);
168 void append(uint8* my_ptr);
169
170 uint capacity;
171 uint fragment_capacity;
172 Oscl_DefAlloc* gen_alloc;
173 MediaDataEntry* available_mfgs;
174 unsigned num_available_mfgs;
175 OsclMemPoolFixedChunkAllocator* media_data_entry_alloc;
176 int32 iRefCnt;
177 bool iDestroy;
178 bool iCheckNextAvailableFreeChunk;
179 OsclMemPoolFixedChunkAllocatorObserver* iObserver;
180 OsclAny* iNextAvailableContextData;
181 };
182
183
184 template<class Alloc>
~PVMFMediaFragGroup()185 PVMFMediaFragGroup<Alloc>::~PVMFMediaFragGroup()
186 {
187 // clear all the fragments
188 iFragments.clear();
189 }
190
191 template<class Alloc>
getMarkerInfo()192 uint32 PVMFMediaFragGroup<Alloc>::getMarkerInfo()
193 {
194 return marker_info;
195 }
196
197 template<class Alloc>
isRandomAccessPoint()198 bool PVMFMediaFragGroup<Alloc>::isRandomAccessPoint()
199 {
200 return random_access_point;
201 }
202
203 template<class Alloc>
getErrorsFlag()204 uint32 PVMFMediaFragGroup<Alloc>::getErrorsFlag()
205 {
206 return errors_flag;
207 }
208
209 template<class Alloc>
getNumFragments()210 uint32 PVMFMediaFragGroup<Alloc>::getNumFragments()
211 {
212 return iFragments.size();
213 }
214
215 template<class Alloc>
getMediaFragment(uint32 index,OsclRefCounterMemFrag & memfrag)216 bool PVMFMediaFragGroup<Alloc>::getMediaFragment(uint32 index, OsclRefCounterMemFrag& memfrag)
217 {
218 if (index >= iFragments.size())
219 {
220 return false;
221 }
222
223 memfrag = OsclRefCounterMemFrag(iFragments[index]);
224
225 return true;
226 }
227
228 template<class Alloc>
getMediaFragmentSize(uint32 index,uint32 & size)229 bool PVMFMediaFragGroup<Alloc>::getMediaFragmentSize(uint32 index, uint32& size)
230 {
231 size = 0;
232 if (index >= iFragments.size())
233 {
234 return false;
235 }
236
237 size = iFragments[index].getMemFrag().len;
238
239 return true;
240 }
241
242 template<class Alloc>
getFilledSize()243 uint32 PVMFMediaFragGroup<Alloc>::getFilledSize()
244 {
245 return filled_size;
246 }
247
248 template<class Alloc>
getCapacity()249 uint32 PVMFMediaFragGroup<Alloc>::getCapacity()
250 {
251 return capacity;
252 }
253
254 template<class Alloc>
setCapacity(uint32 aCapacity)255 void PVMFMediaFragGroup<Alloc>::setCapacity(uint32 aCapacity)
256 {
257 capacity = aCapacity;
258 return;
259 }
260
261 template<class Alloc>
setMediaFragFilledLen(uint32 index,uint32 len)262 bool PVMFMediaFragGroup<Alloc>::setMediaFragFilledLen(uint32 index, uint32 len)
263 {
264 if (index >= iFragments.size())
265 {
266 return false;
267 }
268
269 if (len > iFragments[index].getCapacity())
270 {
271 return false;
272 }
273
274 filled_size -= iFragments[index].getMemFrag().len;
275 iFragments[index].getMemFrag().len = len;
276 filled_size += len;
277 return true;
278 }
279
280 template<class Alloc>
setMarkerInfo(uint32 in_marker)281 bool PVMFMediaFragGroup<Alloc>::setMarkerInfo(uint32 in_marker)
282 {
283 marker_info = in_marker;
284 return true;
285 }
286
287 template<class Alloc>
setRandomAccessPoint(bool flag)288 bool PVMFMediaFragGroup<Alloc>::setRandomAccessPoint(bool flag)
289 {
290 random_access_point = flag;
291 return true;
292 }
293
294 template<class Alloc>
setErrorsFlag(uint32 flag)295 bool PVMFMediaFragGroup<Alloc>::setErrorsFlag(uint32 flag)
296 {
297 errors_flag = flag;
298 return true;
299 }
300
301 template<class Alloc>
PVMFMediaFragGroup(uint32 in_capacity)302 PVMFMediaFragGroup<Alloc>::PVMFMediaFragGroup(uint32 in_capacity) :
303 marker_info(0), random_access_point(false), errors_flag(0)
304 {
305 iFragments.reserve(in_capacity);
306 capacity = 0;
307 filled_size = 0;
308 }
309
310 template<class Alloc>
appendMediaFragment(OsclRefCounterMemFrag & memfrag)311 bool PVMFMediaFragGroup<Alloc>::appendMediaFragment(OsclRefCounterMemFrag& memfrag)
312 {
313 iFragments.push_back(memfrag);
314 capacity += memfrag.getCapacity();
315 filled_size += memfrag.getMemFrag().len;
316 return true;
317 }
318
319 template<class Alloc>
clearMediaFragments()320 bool PVMFMediaFragGroup<Alloc>::clearMediaFragments()
321 {
322 iFragments.clear();
323 capacity = 0;
324 filled_size = 0;
325 return true;
326 }
327
328 template<class Alloc>
~PVMFMediaFragGroupCombinedAlloc()329 PVMFMediaFragGroupCombinedAlloc<Alloc>::~PVMFMediaFragGroupCombinedAlloc()
330 {
331 removeRef();
332 }
333
334 template<class Alloc>
addRef()335 void PVMFMediaFragGroupCombinedAlloc<Alloc>::addRef()
336 {
337 iRefCnt++;
338 }
339
340 template<class Alloc>
removeRef()341 void PVMFMediaFragGroupCombinedAlloc<Alloc>::removeRef()
342 {
343 //we need to make sure that this allocator persists as long as
344 //all buffers allocated it have been released. Therefore we need
345 //a notion of reference count for the allocator itself. iRefCnt
346 //is incremented in addRef and is set decremented here.
347 iRefCnt--;
348 if ((iRefCnt == 0) &&
349 (num_available_mfgs == capacity))
350 {
351 //implies that all messages are have been returned
352 //if not, wait for all messages to return
353 //this allocator needs to live till all messages allocated by
354 //it have been released
355 destroy();
356 }
357 }
358
359 template<class Alloc>
create()360 void PVMFMediaFragGroupCombinedAlloc<Alloc>::create()
361 {
362 media_data_entry_alloc = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (capacity));
363 for (uint num = 0; num < capacity; num++)
364 {
365 do_allocate(fragment_capacity);
366 }
367 }
368
369 template<class Alloc>
do_allocate(uint32 requested_size)370 void PVMFMediaFragGroupCombinedAlloc<Alloc>::do_allocate(uint32 requested_size)
371 {
372 if (requested_size == 0)
373 {
374 requested_size = PVMF_MEDIA_FRAG_GROUP_DEFAULT_CAPACITY;
375 }
376
377 uint aligned_class_size = oscl_mem_aligned_size(sizeof(PVMFMediaFragGroup<Alloc>));
378 OsclRefCounter* my_refcnt = NULL;
379 uint8* my_ptr = NULL;
380
381 uint aligned_refcnt_size = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
382 my_ptr = (uint8*) gen_alloc->ALLOCATE(aligned_refcnt_size + aligned_class_size);
383 // create the recounter after the cleanup object
384 my_refcnt = OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterDA(my_ptr, this));
385 my_ptr += aligned_refcnt_size;
386
387 PVMFMediaDataImpl* media_data_ptr = OSCL_PLACEMENT_NEW(my_ptr, PVMFMediaFragGroup<Alloc>(requested_size));
388
389 OsclSharedPtr<PVMFMediaDataImpl> shared_media_data(media_data_ptr, my_refcnt);
390 append(shared_media_data);
391 }
392
393 template<class Alloc>
append(OsclSharedPtr<PVMFMediaDataImpl> & media_data)394 void PVMFMediaFragGroupCombinedAlloc<Alloc>::append(OsclSharedPtr<PVMFMediaDataImpl> & media_data)
395 {
396 void* memory_for_entry = media_data_entry_alloc->ALLOCATE(sizeof(MediaDataEntry));
397 MediaDataEntry* entry = OSCL_PLACEMENT_NEW(memory_for_entry, MediaDataEntry());
398 entry->mediaDataImpl = media_data;
399
400 MediaDataEntry* first = entry;
401 if (available_mfgs)
402 {
403 first = available_mfgs->next;
404 available_mfgs->next = entry;
405 }
406 available_mfgs = entry;
407 entry->next = first;
408 num_available_mfgs++;
409 }
410
411 template<class Alloc>
append(uint8 * my_ptr)412 void PVMFMediaFragGroupCombinedAlloc<Alloc>::append(uint8* my_ptr)
413 {
414 uint aligned_refcnt_size = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
415 PVMFMediaDataImpl* media_data_ptr = (PVMFMediaDataImpl*)(my_ptr + aligned_refcnt_size);
416 OsclRefCounter* my_refcnt = OSCL_PLACEMENT_NEW(my_ptr, OsclRefCounterDA(my_ptr, this));
417 void* memory_for_entry = media_data_entry_alloc->ALLOCATE(sizeof(MediaDataEntry));
418 MediaDataEntry* entry = OSCL_PLACEMENT_NEW(memory_for_entry, MediaDataEntry());
419 entry->mediaDataImpl.Bind(media_data_ptr, my_refcnt);
420
421 MediaDataEntry* first = entry;
422 if (available_mfgs)
423 {
424 first = available_mfgs->next;
425 available_mfgs->next = entry;
426 }
427 available_mfgs = entry;
428 entry->next = first;
429 num_available_mfgs++;
430 if ((iRefCnt == 0) && (num_available_mfgs == capacity))
431 {
432 //iRefCnt of zero implies that owner of PVMFMediaFragGroupCombinedAlloc
433 //has given up ownership (meaning no more allocations)
434 //But we need to wait for all msgs to be released before we can destroy
435 //the allocators.
436 destroy();
437 }
438 }
439
440 template<class Alloc>
allocate(uint32 requested_size)441 OsclSharedPtr<PVMFMediaDataImpl> PVMFMediaFragGroupCombinedAlloc<Alloc>::allocate(uint32 requested_size)
442 {
443 OsclSharedPtr<PVMFMediaDataImpl> media_data;
444
445 if (requested_size > fragment_capacity)
446 {
447 OSCL_LEAVE(OSCL_BAD_ALLOC_EXCEPTION_CODE);
448 }
449
450 if (available_mfgs == NULL)
451 {
452 //all required memory must have been allocated in "do_allocate"
453 //which is called as part of "create". any exception in either of
454 //these methods means that the allocator could not be created, but
455 //upon successful creation if "available_mfgs" is NULL then it means
456 //we are temporarily out of memory, and there is no need to throw
457 //an exception in this case
458 return media_data;
459 }
460
461 MediaDataEntry* first = available_mfgs->next;
462 media_data = first->mediaDataImpl;
463
464 if (first == available_mfgs)
465 {
466 available_mfgs = NULL;
467 }
468 else
469 {
470 available_mfgs->next = first->next;
471 }
472 first->~MediaDataEntry();
473 media_data_entry_alloc->deallocate(first);
474 num_available_mfgs--;
475 return media_data;
476 }
477
478 template<class Alloc>
destroy()479 void PVMFMediaFragGroupCombinedAlloc<Alloc>::destroy()
480 {
481 iDestroy = true;
482 MediaDataEntry* first = NULL;
483 if (available_mfgs)
484 {
485 first = available_mfgs->next;
486 available_mfgs->next = NULL;
487 }
488
489 while (first)
490 {
491 MediaDataEntry* cur = first;
492 first = first->next;
493 cur->~MediaDataEntry();
494 media_data_entry_alloc->deallocate(cur);
495 }
496
497 if (media_data_entry_alloc)
498 {
499 OSCL_DELETE(media_data_entry_alloc);
500 }
501 OSCL_DELETE(this);
502 }
503
504
505 template<class Alloc>
destruct_and_dealloc(OsclAny * ptr)506 void PVMFMediaFragGroupCombinedAlloc<Alloc>::destruct_and_dealloc(OsclAny* ptr)
507 {
508 uint8* my_ptr = (uint8*)ptr;
509 uint aligned_refcnt_size = oscl_mem_aligned_size(sizeof(OsclRefCounterDA));
510 PVMFMediaDataImpl* media_data_ptr = (PVMFMediaDataImpl*)(my_ptr + aligned_refcnt_size);
511 media_data_ptr->clearMediaFragments();
512
513 if (!iDestroy)
514 {
515 if (iCheckNextAvailableFreeChunk == true)
516 {
517 iCheckNextAvailableFreeChunk = false;
518 if (iObserver)
519 {
520 iObserver->freechunkavailable(iNextAvailableContextData);
521 }
522 }
523 append(my_ptr);
524 }
525 else
526 {
527 media_data_ptr->~PVMFMediaDataImpl();
528 gen_alloc->deallocate(ptr);
529 }
530 }
531
532 #endif
533
534