1 #include "allocator.h"
2 #include "com.h"
3 #include "../wine/winerror.h"
4 #include <stdio.h>
5 #include <stdlib.h>
6 
7 static int AllocatorKeeper = 0;
8 
9 struct _avm_list_t
10 {
11     struct _avm_list_t* next;
12     struct _avm_list_t* prev;
13     void* member;
14 };
15 
avm_list_size(avm_list_t * head)16 static inline int avm_list_size(avm_list_t* head)
17 {
18     avm_list_t* it = head;
19     int i = 0;
20     if (it)
21     {
22 	for (;;)
23 	{
24             i++;
25 	    it = it->next;
26 	    if (it == head)
27                 break;
28 	}
29     }
30     return i;
31 }
32 
avm_list_print(avm_list_t * head)33 static inline int avm_list_print(avm_list_t* head)
34 {
35     avm_list_t* it = head;
36     int i = 0;
37     printf("Head: %p\n", head);
38     if (it)
39     {
40 	for (;;)
41 	{
42 	    i++;
43 	    printf("%d:  member: %p    next: %p  prev: %p\n",
44 		   i, it->member, it->next, it->prev);
45 	    it = it->next;
46 	    if (it == head)
47                 break;
48 	}
49     }
50     return i;
51 }
52 
avm_list_add_head(avm_list_t * head,void * member)53 static inline avm_list_t* avm_list_add_head(avm_list_t* head, void* member)
54 {
55     avm_list_t* n = (avm_list_t*) malloc(sizeof(avm_list_t));
56     n->member = member;
57 
58     if (!head)
59     {
60 	head = n;
61         head->prev = head;
62     }
63 
64     n->prev = head->prev;
65     head->prev = n;
66     n->next = head;
67 
68     return n;
69 }
70 
avm_list_add_tail(avm_list_t * head,void * member)71 static inline avm_list_t* avm_list_add_tail(avm_list_t* head, void* member)
72 {
73     avm_list_t* n = avm_list_add_head(head, member);
74     return (!head) ? n : head;
75 }
76 
avm_list_del_head(avm_list_t * head)77 static inline avm_list_t* avm_list_del_head(avm_list_t* head)
78 {
79     avm_list_t* n = 0;
80 
81     if (head)
82     {
83 	if (head->next != head)
84 	{
85 	    n = head->next;
86 	    head->prev->next = head->next;
87 	    head->next->prev = head->prev;
88 	}
89 	free(head);
90     }
91     return n;
92 }
93 
avm_list_find(avm_list_t * head,void * member)94 static inline avm_list_t* avm_list_find(avm_list_t* head, void* member)
95 {
96     avm_list_t* it = head;
97     if (it)
98     {
99 	for (;;)
100 	{
101 	    if (it->member == member)
102 		return it;
103 	    it = it->next;
104 	    if (it == head)
105                 break;
106 	}
107     }
108     return NULL;
109 }
110 
MemAllocator_CreateAllocator(GUID * clsid,const GUID * iid,void ** ppv)111 static long MemAllocator_CreateAllocator(GUID* clsid, const GUID* iid, void** ppv)
112 {
113     IMemAllocator* p;
114     int result;
115     if (!ppv)
116 	return -1;
117     *ppv = 0;
118     if (memcmp(clsid, &CLSID_MemoryAllocator, sizeof(GUID)))
119 	return -1;
120 
121     p = (IMemAllocator*) MemAllocatorCreate();
122     result = p->vt->QueryInterface((IUnknown*)p, iid, ppv);
123     p->vt->Release((IUnknown*)p);
124 
125     return result;
126 }
127 
MemAllocator_SetProperties(IMemAllocator * This,ALLOCATOR_PROPERTIES * pRequest,ALLOCATOR_PROPERTIES * pActual)128 static HRESULT STDCALL MemAllocator_SetProperties(IMemAllocator * This,
129 						  /* [in] */ ALLOCATOR_PROPERTIES *pRequest,
130 						  /* [out] */ ALLOCATOR_PROPERTIES *pActual)
131 {
132     MemAllocator* me = (MemAllocator*)This;
133     Debug printf("MemAllocator_SetProperties(%p) called\n", This);
134     if (!pRequest || !pActual)
135 	return E_INVALIDARG;
136     if (pRequest->cBuffers<=0 || pRequest->cbBuffer<=0)
137 	return E_FAIL;
138     if (me->used_list != 0 || me->free_list != 0)
139 	return E_FAIL;
140 
141     *pActual = *pRequest;
142     //if (pActual->cbBuffer == 2)
143     //    pActual->cbBuffer = 576;
144 
145     me->props = *pActual;
146 
147     return 0;
148 }
149 
MemAllocator_GetProperties(IMemAllocator * This,ALLOCATOR_PROPERTIES * pProps)150 static HRESULT STDCALL MemAllocator_GetProperties(IMemAllocator * This,
151 						  /* [out] */ ALLOCATOR_PROPERTIES *pProps)
152 {
153     Debug printf("MemAllocator_GetProperties(%p) called\n", This);
154     if (!pProps)
155 	return E_INVALIDARG;
156     if (((MemAllocator*)This)->props.cbBuffer<0)
157 	return E_FAIL;
158     *pProps=((MemAllocator*)This)->props;
159 
160     return 0;
161 }
162 
MemAllocator_Commit(IMemAllocator * This)163 static HRESULT STDCALL MemAllocator_Commit(IMemAllocator * This)
164 {
165     MemAllocator* me = (MemAllocator*)This;
166     int i;
167     Debug printf("MemAllocator_Commit(%p) called\n", This);
168     if (((MemAllocator*)This)->props.cbBuffer < 0)
169 	return E_FAIL;
170     if (me->used_list || me->free_list)
171 	return E_INVALIDARG;
172     for (i = 0; i < me->props.cBuffers; i++)
173     {
174 	CMediaSample* sample = CMediaSampleCreate((IMemAllocator*)me,
175 						  me->props.cbBuffer);
176 	if (!sample)
177             return E_OUTOFMEMORY;
178 	//printf("FREEEEEEEEEEEE ADDED %p\n", sample);
179 	me->free_list = avm_list_add_tail(me->free_list, sample);
180 	//avm_list_print(me->free_list);
181     }
182 
183     //printf("Added mem %p: lsz: %d  %d  size: %d\n", me, avm_list_size(me->free_list), me->props.cBuffers, me->props.cbBuffer);
184     return 0;
185 }
186 
MemAllocator_Decommit(IMemAllocator * This)187 static HRESULT STDCALL MemAllocator_Decommit(IMemAllocator * This)
188 {
189     MemAllocator* me=(MemAllocator*)This;
190     Debug printf("MemAllocator_Decommit(%p) called\n", This);
191     //printf("Deleted mem %p: %d  %d\n", me, me->free_list.size(), me->used_list.size());
192     while (me->used_list)
193     {
194 	me->free_list = avm_list_add_tail(me->free_list,
195 					  (CMediaSample*) me->used_list->member);
196 	me->used_list = avm_list_del_head(me->used_list);
197     }
198 
199     while (me->free_list)
200     {
201         CMediaSample* sample = (CMediaSample*) me->free_list->member;
202 	//printf("****************** Decommiting FREE %p\n", sample);
203 	//sample->vt->Release((IUnknown*)sample);
204 	CMediaSample_Destroy((CMediaSample*)sample);
205 	me->free_list = avm_list_del_head(me->free_list);
206     }
207 
208     return 0;
209 }
210 
MemAllocator_GetBuffer(IMemAllocator * This,IMediaSample ** ppBuffer,REFERENCE_TIME * pStartTime,REFERENCE_TIME * pEndTime,DWORD dwFlags)211 static HRESULT STDCALL MemAllocator_GetBuffer(IMemAllocator * This,
212 					      /* [out] */ IMediaSample **ppBuffer,
213 					      /* [in] */ REFERENCE_TIME *pStartTime,
214 					      /* [in] */ REFERENCE_TIME *pEndTime,
215 					      /* [in] */ DWORD dwFlags)
216 {
217     MemAllocator* me = (MemAllocator*)This;
218     CMediaSample* sample;
219     (void)pStartTime;
220     (void)pEndTime;
221     (void)dwFlags;
222     Debug printf("MemAllocator_ReleaseBuffer(%p) called   %d  %d\n", This,
223 		 avm_list_size(me->used_list), avm_list_size(me->free_list));
224 
225     if (!me->free_list)
226     {
227 	Debug printf("No samples available\n");
228 	return E_FAIL;//should block here if no samples are available
229     }
230 
231     sample = (CMediaSample*) me->free_list->member;
232     me->free_list = avm_list_del_head(me->free_list);
233     me->used_list = avm_list_add_tail(me->used_list, sample);
234 
235     *ppBuffer = (IMediaSample*) sample;
236     sample->vt->AddRef((IUnknown*) sample);
237     if (me->new_pointer)
238     {
239 	if (me->modified_sample)
240 	    me->modified_sample->ResetPointer(me->modified_sample);
241 	sample->SetPointer(sample, me->new_pointer);
242 	me->modified_sample = sample;
243 	me->new_pointer = 0;
244     }
245     return 0;
246 }
247 
MemAllocator_ReleaseBuffer(IMemAllocator * This,IMediaSample * pBuffer)248 static HRESULT STDCALL MemAllocator_ReleaseBuffer(IMemAllocator* This,
249 						  /* [in] */ IMediaSample* pBuffer)
250 {
251     avm_list_t* l;
252     MemAllocator* me = (MemAllocator*)This;
253     Debug printf("MemAllocator_ReleaseBuffer(%p) called   %d  %d\n", This,
254 		 avm_list_size(me->used_list), avm_list_size(me->free_list));
255 
256     l = avm_list_find(me->used_list, pBuffer);
257     if (l)
258     {
259 	CMediaSample* sample = (CMediaSample*) l->member;
260 	if (me->modified_sample == sample)
261 	{
262 	    me->modified_sample->ResetPointer(me->modified_sample);
263 	    me->modified_sample = 0;
264 	}
265 	me->used_list = avm_list_del_head(me->used_list);
266 	me->free_list = avm_list_add_head(me->free_list, sample);
267 	//printf("****************** RELEASED OK %p  %p\n", me->used_list, me->free_list);
268 	return 0;
269     }
270     Debug printf("MemAllocator_ReleaseBuffer(%p) releasing unknown buffer!!!! %p\n", This, pBuffer);
271     return E_FAIL;
272 }
273 
274 
MemAllocator_SetPointer(MemAllocator * This,char * pointer)275 static void MemAllocator_SetPointer(MemAllocator* This, char* pointer)
276 {
277     This->new_pointer = pointer;
278 }
279 
MemAllocator_ResetPointer(MemAllocator * This)280 static void MemAllocator_ResetPointer(MemAllocator* This)
281 {
282     if (This->modified_sample)
283     {
284 	This->modified_sample->ResetPointer(This->modified_sample);
285 	This->modified_sample = 0;
286     }
287 }
288 
MemAllocator_Destroy(MemAllocator * This)289 static void MemAllocator_Destroy(MemAllocator* This)
290 {
291     Debug printf("MemAllocator_Destroy(%p) called  (%d, %d)\n", This, This->refcount, AllocatorKeeper);
292     if (--AllocatorKeeper == 0)
293 	UnregisterComClass(&CLSID_MemoryAllocator, MemAllocator_CreateAllocator);
294     free(This->vt);
295     free(This);
296 }
297 
IMPLEMENT_IUNKNOWN(MemAllocator)298 IMPLEMENT_IUNKNOWN(MemAllocator)
299 
300 MemAllocator* MemAllocatorCreate()
301 {
302     MemAllocator* This = (MemAllocator*) malloc(sizeof(MemAllocator));
303 
304     if (!This)
305         return NULL;
306 
307     Debug printf("MemAllocatorCreate() called -> %p\n", This);
308 
309     This->refcount = 1;
310     This->props.cBuffers = 1;
311     This->props.cbBuffer = 65536; /* :/ */
312     This->props.cbAlign = This->props.cbPrefix = 0;
313 
314     This->vt = (IMemAllocator_vt*) malloc(sizeof(IMemAllocator_vt));
315 
316     if (!This->vt)
317     {
318         free(This);
319 	return NULL;
320     }
321 
322     This->vt->QueryInterface = MemAllocator_QueryInterface;
323     This->vt->AddRef = MemAllocator_AddRef;
324     This->vt->Release = MemAllocator_Release;
325     This->vt->SetProperties = MemAllocator_SetProperties;
326     This->vt->GetProperties = MemAllocator_GetProperties;
327     This->vt->Commit = MemAllocator_Commit;
328     This->vt->Decommit = MemAllocator_Decommit;
329     This->vt->GetBuffer = MemAllocator_GetBuffer;
330     This->vt->ReleaseBuffer = MemAllocator_ReleaseBuffer;
331 
332     This->SetPointer = MemAllocator_SetPointer;
333     This->ResetPointer = MemAllocator_ResetPointer;
334 
335     This->modified_sample = 0;
336     This->new_pointer = 0;
337     This->used_list = 0;
338     This->free_list = 0;
339 
340     This->interfaces[0]=IID_IUnknown;
341     This->interfaces[1]=IID_IMemAllocator;
342 
343     if (AllocatorKeeper++ == 0)
344 	RegisterComClass(&CLSID_MemoryAllocator, MemAllocator_CreateAllocator);
345 
346     return This;
347 }
348