winegstreamer: Introduce new wg_sample_create_quartz helper for quartz_transform.c.
[wine.git] / dlls / winegstreamer / wg_sample.c
blobdded264b079e48aa70f2aeafa9bf8a8a1f73550d
1 /*
2 * Copyright 2022 RĂ©mi Bernon for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "gst_private.h"
21 #include "wmcodecdsp.h"
22 #include "mfapi.h"
24 #include "wine/debug.h"
25 #include "wine/list.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
28 WINE_DECLARE_DEBUG_CHANNEL(quartz);
30 struct wg_sample_queue
32 CRITICAL_SECTION cs;
33 struct list samples;
36 struct wg_sample_ops
38 void (*destroy)(struct wg_sample *sample);
41 struct sample
43 struct wg_sample wg_sample;
45 const struct wg_sample_ops *ops;
46 struct list entry;
48 union
50 struct
52 IMFSample *sample;
53 IMFMediaBuffer *buffer;
54 } mf;
55 struct
57 IMediaSample *sample;
58 } quartz;
59 } u;
62 static const struct wg_sample_ops mf_sample_ops;
64 static inline struct sample *unsafe_mf_from_wg_sample(struct wg_sample *wg_sample)
66 struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample);
67 if (sample->ops != &mf_sample_ops) return NULL;
68 return sample;
71 static void mf_sample_destroy(struct wg_sample *wg_sample)
73 struct sample *sample = unsafe_mf_from_wg_sample(wg_sample);
75 TRACE_(mfplat)("wg_sample %p.\n", wg_sample);
77 IMFMediaBuffer_Unlock(sample->u.mf.buffer);
78 IMFMediaBuffer_Release(sample->u.mf.buffer);
79 IMFSample_Release(sample->u.mf.sample);
82 static const struct wg_sample_ops mf_sample_ops =
84 mf_sample_destroy,
87 HRESULT wg_sample_create_mf(IMFSample *mf_sample, struct wg_sample **out)
89 DWORD current_length, max_length;
90 struct sample *sample;
91 BYTE *buffer;
92 HRESULT hr;
94 if (!(sample = calloc(1, sizeof(*sample))))
95 return E_OUTOFMEMORY;
96 if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(mf_sample, &sample->u.mf.buffer)))
97 goto fail;
98 if (FAILED(hr = IMFMediaBuffer_Lock(sample->u.mf.buffer, &buffer, &max_length, &current_length)))
99 goto fail;
101 IMFSample_AddRef((sample->u.mf.sample = mf_sample));
102 sample->wg_sample.data = buffer;
103 sample->wg_sample.size = current_length;
104 sample->wg_sample.max_size = max_length;
105 sample->ops = &mf_sample_ops;
107 *out = &sample->wg_sample;
108 TRACE_(mfplat)("Created wg_sample %p for IMFSample %p.\n", *out, mf_sample);
109 return S_OK;
111 fail:
112 if (sample->u.mf.buffer)
113 IMFMediaBuffer_Release(sample->u.mf.buffer);
114 free(sample);
115 return hr;
118 static const struct wg_sample_ops quartz_sample_ops;
120 static inline struct sample *unsafe_quartz_from_wg_sample(struct wg_sample *wg_sample)
122 struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample);
123 if (sample->ops != &quartz_sample_ops) return NULL;
124 return sample;
127 static void quartz_sample_destroy(struct wg_sample *wg_sample)
129 struct sample *sample = unsafe_quartz_from_wg_sample(wg_sample);
131 TRACE_(quartz)("wg_sample %p.\n", wg_sample);
133 IMediaSample_Release(sample->u.quartz.sample);
136 static const struct wg_sample_ops quartz_sample_ops =
138 quartz_sample_destroy,
141 HRESULT wg_sample_create_quartz(IMediaSample *media_sample, struct wg_sample **out)
143 DWORD current_length, max_length;
144 struct sample *sample;
145 BYTE *buffer;
146 HRESULT hr;
148 if (FAILED(hr = IMediaSample_GetPointer(media_sample, &buffer)))
149 return hr;
150 current_length = IMediaSample_GetActualDataLength(media_sample);
151 max_length = IMediaSample_GetSize(media_sample);
153 if (!(sample = calloc(1, sizeof(*sample))))
154 return E_OUTOFMEMORY;
156 IMediaSample_AddRef((sample->u.quartz.sample = media_sample));
157 sample->wg_sample.data = buffer;
158 sample->wg_sample.size = current_length;
159 sample->wg_sample.max_size = max_length;
160 sample->ops = &quartz_sample_ops;
162 TRACE_(quartz)("Created wg_sample %p for IMediaSample %p.\n", &sample->wg_sample, media_sample);
163 *out = &sample->wg_sample;
164 return S_OK;
167 void wg_sample_release(struct wg_sample *wg_sample)
169 struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample);
171 if (InterlockedOr(&wg_sample->refcount, 0))
173 ERR("wg_sample %p is still in use, trouble ahead!\n", wg_sample);
174 return;
177 sample->ops->destroy(wg_sample);
179 free(sample);
182 static void wg_sample_queue_begin_append(struct wg_sample_queue *queue, struct wg_sample *wg_sample)
184 struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample);
186 /* make sure a concurrent wg_sample_queue_flush call won't release the sample until we're done */
187 InterlockedIncrement(&wg_sample->refcount);
188 sample->wg_sample.flags |= WG_SAMPLE_FLAG_HAS_REFCOUNT;
190 EnterCriticalSection(&queue->cs);
191 list_add_tail(&queue->samples, &sample->entry);
192 LeaveCriticalSection(&queue->cs);
195 static void wg_sample_queue_end_append(struct wg_sample_queue *queue, struct wg_sample *wg_sample)
197 /* release temporary ref taken in wg_sample_queue_begin_append */
198 InterlockedDecrement(&wg_sample->refcount);
200 wg_sample_queue_flush(queue, false);
203 void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all)
205 struct sample *sample, *next;
207 EnterCriticalSection(&queue->cs);
209 LIST_FOR_EACH_ENTRY_SAFE(sample, next, &queue->samples, struct sample, entry)
211 if (!InterlockedOr(&sample->wg_sample.refcount, 0) || all)
213 list_remove(&sample->entry);
214 wg_sample_release(&sample->wg_sample);
218 LeaveCriticalSection(&queue->cs);
221 HRESULT wg_sample_queue_create(struct wg_sample_queue **out)
223 struct wg_sample_queue *queue;
225 if (!(queue = calloc(1, sizeof(*queue))))
226 return E_OUTOFMEMORY;
228 InitializeCriticalSection(&queue->cs);
229 queue->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
230 list_init(&queue->samples);
232 TRACE("Created wg_sample_queue %p.\n", queue);
233 *out = queue;
235 return S_OK;
238 void wg_sample_queue_destroy(struct wg_sample_queue *queue)
240 wg_sample_queue_flush(queue, true);
242 queue->cs.DebugInfo->Spare[0] = 0;
243 InitializeCriticalSection(&queue->cs);
245 free(queue);
248 HRESULT wg_transform_push_mf(struct wg_transform *transform, struct wg_sample *wg_sample,
249 struct wg_sample_queue *queue)
251 struct sample *sample = unsafe_mf_from_wg_sample(wg_sample);
252 LONGLONG time, duration;
253 UINT32 value;
254 HRESULT hr;
256 TRACE_(mfplat)("transform %p, wg_sample %p, queue %p.\n", transform, wg_sample, queue);
258 if (SUCCEEDED(IMFSample_GetSampleTime(sample->u.mf.sample, &time)))
260 sample->wg_sample.flags |= WG_SAMPLE_FLAG_HAS_PTS;
261 sample->wg_sample.pts = time;
263 if (SUCCEEDED(IMFSample_GetSampleDuration(sample->u.mf.sample, &duration)))
265 sample->wg_sample.flags |= WG_SAMPLE_FLAG_HAS_DURATION;
266 sample->wg_sample.duration = duration;
268 if (SUCCEEDED(IMFSample_GetUINT32(sample->u.mf.sample, &MFSampleExtension_CleanPoint, &value)) && value)
269 sample->wg_sample.flags |= WG_SAMPLE_FLAG_SYNC_POINT;
271 wg_sample_queue_begin_append(queue, wg_sample);
272 hr = wg_transform_push_data(transform, wg_sample);
273 wg_sample_queue_end_append(queue, wg_sample);
275 return hr;
278 HRESULT wg_transform_read_mf(struct wg_transform *transform, struct wg_sample *wg_sample,
279 struct wg_format *format)
281 struct sample *sample = unsafe_mf_from_wg_sample(wg_sample);
282 HRESULT hr;
284 TRACE_(mfplat)("transform %p, wg_sample %p, format %p.\n", transform, wg_sample, format);
286 if (FAILED(hr = wg_transform_read_data(transform, wg_sample, format)))
287 return hr;
289 if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(sample->u.mf.buffer, wg_sample->size)))
290 return hr;
292 if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_PTS)
293 IMFSample_SetSampleTime(sample->u.mf.sample, wg_sample->pts);
294 if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_DURATION)
295 IMFSample_SetSampleDuration(sample->u.mf.sample, wg_sample->duration);
296 if (wg_sample->flags & WG_SAMPLE_FLAG_SYNC_POINT)
297 IMFSample_SetUINT32(sample->u.mf.sample, &MFSampleExtension_CleanPoint, 1);
299 return S_OK;