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