mfplay: Implement GetCharacteristics().
[wine/zf.git] / dlls / qcap / filewriter.c
blob4ea1460bb26662e7e16826279b28da944f44d3a4
1 /*
2 * File writer filter
4 * Copyright (C) 2020 Zebediah Figura
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "qcap_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
25 struct file_writer
27 struct strmbase_filter filter;
28 IAMFilterMiscFlags IAMFilterMiscFlags_iface;
29 IFileSinkFilter IFileSinkFilter_iface;
31 struct strmbase_sink sink;
33 WCHAR *filename;
34 HANDLE file;
36 BOOL eos;
39 static inline struct file_writer *impl_from_strmbase_pin(struct strmbase_pin *iface)
41 return CONTAINING_RECORD(iface, struct file_writer, sink.pin);
44 static HRESULT file_writer_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
46 struct file_writer *filter = impl_from_strmbase_pin(iface);
48 if (IsEqualGUID(iid, &IID_IMemInputPin))
49 *out = &filter->sink.IMemInputPin_iface;
50 else
51 return E_NOINTERFACE;
53 IUnknown_AddRef((IUnknown *)*out);
54 return S_OK;
57 static HRESULT file_writer_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
59 struct file_writer *filter = impl_from_strmbase_pin(iface);
61 if (filter->filename && !IsEqualGUID(&mt->majortype, &MEDIATYPE_Stream))
62 return S_FALSE;
63 return S_OK;
66 static HRESULT WINAPI file_writer_sink_receive(struct strmbase_sink *iface, IMediaSample *sample)
68 struct file_writer *filter = impl_from_strmbase_pin(&iface->pin);
69 REFERENCE_TIME start, stop;
70 LARGE_INTEGER offset;
71 HRESULT hr;
72 DWORD size;
73 BYTE *data;
75 if ((hr = IMediaSample_GetTime(sample, &start, &stop)) != S_OK)
76 ERR("Failed to get sample time, hr %#x.\n", hr);
78 if ((hr = IMediaSample_GetPointer(sample, &data)) != S_OK)
79 ERR("Failed to get sample pointer, hr %#x.\n", hr);
81 offset.QuadPart = start;
82 if (!SetFilePointerEx(filter->file, offset, NULL, FILE_BEGIN)
83 || !WriteFile(filter->file, data, stop - start, &size, NULL))
85 ERR("Failed to write file, error %u.\n", GetLastError());
86 return HRESULT_FROM_WIN32(hr);
89 if (size != stop - start)
90 ERR("Short write, %u/%u.\n", size, (DWORD)(stop - start));
92 return S_OK;
95 static void deliver_ec_complete(struct file_writer *filter)
97 IMediaEventSink *event_sink;
99 if (SUCCEEDED(IFilterGraph_QueryInterface(filter->filter.graph,
100 &IID_IMediaEventSink, (void **)&event_sink)))
102 IMediaEventSink_Notify(event_sink, EC_COMPLETE, S_OK,
103 (LONG_PTR)&filter->filter.IBaseFilter_iface);
104 IMediaEventSink_Release(event_sink);
108 static HRESULT file_writer_sink_eos(struct strmbase_sink *iface)
110 struct file_writer *filter = impl_from_strmbase_pin(&iface->pin);
112 EnterCriticalSection(&filter->filter.filter_cs);
114 if (filter->filter.state == State_Running)
115 deliver_ec_complete(filter);
116 else
117 filter->eos = TRUE;
119 LeaveCriticalSection(&filter->filter.filter_cs);
120 return S_OK;
123 static const struct strmbase_sink_ops sink_ops =
125 .base.pin_query_interface = file_writer_sink_query_interface,
126 .base.pin_query_accept = file_writer_sink_query_accept,
127 .pfnReceive = file_writer_sink_receive,
128 .sink_eos = file_writer_sink_eos,
131 static inline struct file_writer *impl_from_strmbase_filter(struct strmbase_filter *iface)
133 return CONTAINING_RECORD(iface, struct file_writer, filter);
136 static HRESULT file_writer_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
138 struct file_writer *filter = impl_from_strmbase_filter(iface);
140 if (IsEqualGUID(iid, &IID_IAMFilterMiscFlags))
141 *out = &filter->IAMFilterMiscFlags_iface;
142 else if (IsEqualGUID(iid, &IID_IFileSinkFilter))
143 *out = &filter->IFileSinkFilter_iface;
144 else
145 return E_NOINTERFACE;
147 IUnknown_AddRef((IUnknown *)*out);
148 return S_OK;
151 static struct strmbase_pin *file_writer_get_pin(struct strmbase_filter *iface, unsigned int index)
153 struct file_writer *filter = impl_from_strmbase_filter(iface);
155 if (!index)
156 return &filter->sink.pin;
157 return NULL;
160 static void file_writer_destroy(struct strmbase_filter *iface)
162 struct file_writer *filter = impl_from_strmbase_filter(iface);
164 free(filter->filename);
165 strmbase_sink_cleanup(&filter->sink);
166 strmbase_filter_cleanup(&filter->filter);
167 free(filter);
170 static HRESULT file_writer_init_stream(struct strmbase_filter *iface)
172 struct file_writer *filter = impl_from_strmbase_filter(iface);
173 HANDLE file;
175 if ((file = CreateFileW(filter->filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
176 NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
178 ERR("Failed to create %s, error %u.\n", debugstr_w(filter->filename), GetLastError());
179 return HRESULT_FROM_WIN32(GetLastError());
181 filter->file = file;
182 return S_OK;
185 static HRESULT file_writer_start_stream(struct strmbase_filter *iface, REFERENCE_TIME start)
187 struct file_writer *filter = impl_from_strmbase_filter(iface);
189 if (filter->eos)
190 deliver_ec_complete(filter);
191 filter->eos = FALSE;
192 return S_OK;
195 static HRESULT file_writer_cleanup_stream(struct strmbase_filter *iface)
197 struct file_writer *filter = impl_from_strmbase_filter(iface);
199 CloseHandle(filter->file);
200 return S_OK;
203 static struct strmbase_filter_ops filter_ops =
205 .filter_query_interface = file_writer_query_interface,
206 .filter_get_pin = file_writer_get_pin,
207 .filter_destroy = file_writer_destroy,
208 .filter_init_stream = file_writer_init_stream,
209 .filter_start_stream = file_writer_start_stream,
210 .filter_cleanup_stream = file_writer_cleanup_stream,
213 static inline struct file_writer *impl_from_IFileSinkFilter(IFileSinkFilter *iface)
215 return CONTAINING_RECORD(iface, struct file_writer, IFileSinkFilter_iface);
218 static HRESULT WINAPI filesinkfilter_QueryInterface(IFileSinkFilter *iface, REFIID iid, void **out)
220 struct file_writer *filter = impl_from_IFileSinkFilter(iface);
221 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
224 static ULONG WINAPI filesinkfilter_AddRef(IFileSinkFilter *iface)
226 struct file_writer *filter = impl_from_IFileSinkFilter(iface);
227 return IUnknown_AddRef(filter->filter.outer_unk);
230 static ULONG WINAPI filesinkfilter_Release(IFileSinkFilter *iface)
232 struct file_writer *filter = impl_from_IFileSinkFilter(iface);
233 return IUnknown_Release(filter->filter.outer_unk);
236 static HRESULT WINAPI filesinkfilter_SetFileName(IFileSinkFilter *iface,
237 LPCOLESTR filename, const AM_MEDIA_TYPE *mt)
239 struct file_writer *filter = impl_from_IFileSinkFilter(iface);
240 WCHAR *new_filename;
242 TRACE("filter %p, filename %s, mt %p.\n", filter, debugstr_w(filename), mt);
243 strmbase_dump_media_type(mt);
245 if (mt)
246 FIXME("Ignoring media type %p.\n", mt);
248 if (!(new_filename = wcsdup(filename)))
249 return E_OUTOFMEMORY;
251 free(filter->filename);
252 filter->filename = new_filename;
253 return S_OK;
256 static HRESULT WINAPI filesinkfilter_GetCurFile(IFileSinkFilter *iface,
257 LPOLESTR *filename, AM_MEDIA_TYPE *mt)
259 struct file_writer *filter = impl_from_IFileSinkFilter(iface);
261 FIXME("filter %p, filename %p, mt %p, stub!\n", filter, filename, mt);
263 return E_NOTIMPL;
266 static const IFileSinkFilterVtbl filesinkfilter_vtbl =
268 filesinkfilter_QueryInterface,
269 filesinkfilter_AddRef,
270 filesinkfilter_Release,
271 filesinkfilter_SetFileName,
272 filesinkfilter_GetCurFile,
275 static inline struct file_writer *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
277 return CONTAINING_RECORD(iface, struct file_writer, IAMFilterMiscFlags_iface);
280 static HRESULT WINAPI misc_flags_QueryInterface(IAMFilterMiscFlags *iface, REFIID iid, void **out)
282 struct file_writer *filter = impl_from_IAMFilterMiscFlags(iface);
283 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
286 static ULONG WINAPI misc_flags_AddRef(IAMFilterMiscFlags *iface)
288 struct file_writer *filter = impl_from_IAMFilterMiscFlags(iface);
289 return IUnknown_AddRef(filter->filter.outer_unk);
292 static ULONG WINAPI misc_flags_Release(IAMFilterMiscFlags *iface)
294 struct file_writer *filter = impl_from_IAMFilterMiscFlags(iface);
295 return IUnknown_Release(filter->filter.outer_unk);
298 static ULONG WINAPI misc_flags_GetMiscFlags(IAMFilterMiscFlags *iface)
300 struct file_writer *filter = impl_from_IAMFilterMiscFlags(iface);
302 TRACE("filter %p.\n", filter);
304 return AM_FILTER_MISC_FLAGS_IS_RENDERER;
307 static const IAMFilterMiscFlagsVtbl misc_flags_vtbl =
309 misc_flags_QueryInterface,
310 misc_flags_AddRef,
311 misc_flags_Release,
312 misc_flags_GetMiscFlags,
315 HRESULT file_writer_create(IUnknown *outer, IUnknown **out)
317 struct file_writer *object;
319 if (!(object = calloc(1, sizeof(*object))))
320 return E_OUTOFMEMORY;
322 strmbase_filter_init(&object->filter, outer, &CLSID_FileWriter, &filter_ops);
323 object->IFileSinkFilter_iface.lpVtbl = &filesinkfilter_vtbl;
324 object->IAMFilterMiscFlags_iface.lpVtbl = &misc_flags_vtbl;
326 strmbase_sink_init(&object->sink, &object->filter, L"in", &sink_ops, NULL);
328 TRACE("Created file writer %p.\n", object);
329 *out = &object->filter.IUnknown_inner;
330 return S_OK;