vo_dxr3: Fix validity checks before closing a file descriptor
[mplayer/glamo.git] / loader / dshow / allocator.c
bloba90bd9d3d21e18ccf6721616b7aa6b9095c983cd
1 /*
2 * Modified for use with MPlayer, detailed changelog at
3 * http://svn.mplayerhq.hu/mplayer/trunk/
4 */
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>
13 static int AllocatorKeeper = 0;
15 struct avm_list_t
17 struct avm_list_t* next;
18 struct avm_list_t* prev;
19 void* member;
22 static inline int avm_list_size(avm_list_t* head)
24 avm_list_t* it = head;
25 int i = 0;
26 if (it)
28 for (;;)
30 i++;
31 it = it->next;
32 if (it == head)
33 break;
36 return i;
39 static inline int avm_list_print(avm_list_t* head)
41 avm_list_t* it = head;
42 int i = 0;
43 printf("Head: %p\n", head);
44 if (it)
46 for (;;)
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;
56 return i;
59 static inline avm_list_t* avm_list_add_head(avm_list_t* head, void* member)
61 avm_list_t* n = malloc(sizeof(avm_list_t));
62 n->member = member;
64 if (!head)
66 head = n;
67 head->prev = head;
70 n->prev = head->prev;
71 head->prev = n;
72 n->next = head;
74 return n;
77 static inline avm_list_t* avm_list_add_tail(avm_list_t* head, void* member)
79 avm_list_t* n = avm_list_add_head(head, member);
80 return (!head) ? n : head;
83 static inline avm_list_t* avm_list_del_head(avm_list_t* head)
85 avm_list_t* n = 0;
87 if (head)
89 if (head->next != head)
91 n = head->next;
92 head->prev->next = head->next;
93 head->next->prev = head->prev;
95 free(head);
97 return n;
100 static inline avm_list_t* avm_list_find(avm_list_t* head, void* member)
102 avm_list_t* it = head;
103 if (it)
105 for (;;)
107 if (it->member == member)
108 return it;
109 it = it->next;
110 if (it == head)
111 break;
114 return NULL;
117 static long MemAllocator_CreateAllocator(GUID* clsid, const GUID* iid, void** ppv)
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;
127 p = (IUnknown*) MemAllocatorCreate();
128 result = p->vt->QueryInterface(p, iid, ppv);
129 p->vt->Release(p);
131 return result;
134 static HRESULT STDCALL MemAllocator_SetProperties(IMemAllocator * This,
135 /* [in] */ ALLOCATOR_PROPERTIES *pRequest,
136 /* [out] */ ALLOCATOR_PROPERTIES *pActual)
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;
147 *pActual = *pRequest;
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.
154 if (pActual->cbBuffer == 2)
155 pActual->cbBuffer = 10240; //Enough for WMSP codec
157 me->props = *pActual;
159 return 0;
162 static HRESULT STDCALL MemAllocator_GetProperties(IMemAllocator * This,
163 /* [out] */ ALLOCATOR_PROPERTIES *pProps)
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;
172 return 0;
175 static HRESULT STDCALL MemAllocator_Commit(IMemAllocator * This)
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++)
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);
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;
199 static HRESULT STDCALL MemAllocator_Decommit(IMemAllocator * This)
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)
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);
211 while (me->free_list)
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);
220 return 0;
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)
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));
234 if (!me->free_list)
236 Debug printf("No samples available\n");
237 return E_FAIL;//should block here if no samples are available
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);
244 *ppBuffer = (IMediaSample*) sample;
245 sample->vt->AddRef((IUnknown*) sample);
246 if (me->new_pointer)
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;
254 return 0;
257 static HRESULT STDCALL MemAllocator_ReleaseBuffer(IMemAllocator* This,
258 /* [in] */ IMediaSample* pBuffer)
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));
265 l = avm_list_find(me->used_list, pBuffer);
266 if (l)
268 CMediaSample* sample = (CMediaSample*) l->member;
269 if (me->modified_sample == sample)
271 me->modified_sample->ResetPointer(me->modified_sample);
272 me->modified_sample = 0;
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;
279 Debug printf("MemAllocator_ReleaseBuffer(%p) releasing unknown buffer!!!! %p\n", This, pBuffer);
280 return E_FAIL;
284 static void MemAllocator_SetPointer(MemAllocator* This, char* pointer)
286 This->new_pointer = pointer;
289 static void MemAllocator_ResetPointer(MemAllocator* This)
291 if (This->modified_sample)
293 This->modified_sample->ResetPointer(This->modified_sample);
294 This->modified_sample = 0;
298 static void MemAllocator_Destroy(MemAllocator* This)
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);
309 IMPLEMENT_IUNKNOWN(MemAllocator)
311 MemAllocator* MemAllocatorCreate()
313 MemAllocator* This = malloc(sizeof(MemAllocator));
315 if (!This)
316 return NULL;
318 Debug printf("MemAllocatorCreate() called -> %p\n", This);
320 This->refcount = 1;
321 This->props.cBuffers = 1;
322 This->props.cbBuffer = 65536; /* :/ */
323 This->props.cbAlign = 1;
324 This->props.cbPrefix = 0;
326 This->vt = malloc(sizeof(IMemAllocator_vt));
328 if (!This->vt)
330 free(This);
331 return NULL;
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;
344 This->SetPointer = MemAllocator_SetPointer;
345 This->ResetPointer = MemAllocator_ResetPointer;
347 This->modified_sample = 0;
348 This->new_pointer = 0;
349 This->used_list = 0;
350 This->free_list = 0;
352 This->interfaces[0]=IID_IUnknown;
353 This->interfaces[1]=IID_IMemAllocator;
355 #ifdef WIN32_LOADER
356 if (AllocatorKeeper++ == 0)
357 RegisterComClass(&CLSID_MemoryAllocator, MemAllocator_CreateAllocator);
358 #endif
360 return This;