mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / windowscodecs / encoder.c
bloba213e7d14d021b00f8382ead5dfe41274f95b84b
1 /*
2 * Copyright 2020 Esme Povirk
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 <stdarg.h>
21 #define NONAMELESSUNION
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "objbase.h"
28 #include "wincodecs_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
34 static const PROPBAG2 encoder_option_properties[ENCODER_OPTION_END] = {
35 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)L"InterlaceOption" },
36 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)L"FilterOption" },
37 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)L"TiffCompressionMethod" },
38 { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)L"CompressionQuality" },
39 { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)L"ImageQuality" },
40 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)L"BitmapTransform" },
41 { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)L"Luminance" },
42 { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)L"Chrominance" },
43 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)L"JpegYCrCbSubsampling" },
44 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)L"SuppressApp0" }
47 typedef struct CommonEncoder {
48 IWICBitmapEncoder IWICBitmapEncoder_iface;
49 LONG ref;
50 CRITICAL_SECTION lock; /* must be held when stream or encoder is accessed */
51 IStream *stream;
52 struct encoder *encoder;
53 struct encoder_info encoder_info;
54 UINT frame_count;
55 BOOL uncommitted_frame;
56 BOOL committed;
57 } CommonEncoder;
59 typedef struct CommonEncoderFrame {
60 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
61 IWICMetadataBlockWriter IWICMetadataBlockWriter_iface;
62 LONG ref;
63 CommonEncoder *parent;
64 struct encoder_frame encoder_frame;
65 BOOL initialized;
66 BOOL frame_created;
67 UINT lines_written;
68 BOOL committed;
69 } CommonEncoderFrame;
71 static inline CommonEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
73 return CONTAINING_RECORD(iface, CommonEncoder, IWICBitmapEncoder_iface);
76 static inline CommonEncoderFrame *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
78 return CONTAINING_RECORD(iface, CommonEncoderFrame, IWICBitmapFrameEncode_iface);
81 static inline CommonEncoderFrame *impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter *iface)
83 return CONTAINING_RECORD(iface, CommonEncoderFrame, IWICMetadataBlockWriter_iface);
86 static HRESULT WINAPI CommonEncoderFrame_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
87 void **ppv)
89 CommonEncoderFrame *object = impl_from_IWICBitmapFrameEncode(iface);
90 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
92 if (!ppv) return E_INVALIDARG;
94 if (IsEqualIID(&IID_IUnknown, iid) ||
95 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
97 *ppv = &object->IWICBitmapFrameEncode_iface;
99 else if (object->parent->encoder_info.flags & ENCODER_FLAGS_SUPPORTS_METADATA
100 && IsEqualIID(&IID_IWICMetadataBlockWriter, iid))
102 *ppv = &object->IWICMetadataBlockWriter_iface;
104 else
106 *ppv = NULL;
107 return E_NOINTERFACE;
110 IUnknown_AddRef((IUnknown*)*ppv);
111 return S_OK;
114 static ULONG WINAPI CommonEncoderFrame_AddRef(IWICBitmapFrameEncode *iface)
116 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
117 ULONG ref = InterlockedIncrement(&This->ref);
119 TRACE("(%p) refcount=%u\n", iface, ref);
121 return ref;
124 static ULONG WINAPI CommonEncoderFrame_Release(IWICBitmapFrameEncode *iface)
126 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
127 ULONG ref = InterlockedDecrement(&This->ref);
129 TRACE("(%p) refcount=%u\n", iface, ref);
131 if (ref == 0)
133 IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface);
134 HeapFree(GetProcessHeap(), 0, This);
137 return ref;
140 static HRESULT WINAPI CommonEncoderFrame_Initialize(IWICBitmapFrameEncode *iface,
141 IPropertyBag2 *pIEncoderOptions)
143 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
144 HRESULT hr=S_OK;
145 struct encoder_frame options = {{0}};
146 PROPBAG2 opts[7]= {{0}};
147 VARIANT opt_values[7];
148 HRESULT opt_hres[7];
149 DWORD num_opts, i;
151 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
153 if (pIEncoderOptions)
155 for (i=0; This->parent->encoder_info.encoder_options[i] != ENCODER_OPTION_END; i++)
156 opts[i] = encoder_option_properties[This->parent->encoder_info.encoder_options[i]];
157 num_opts = i;
159 hr = IPropertyBag2_Read(pIEncoderOptions, num_opts, opts, NULL, opt_values, opt_hres);
161 if (FAILED(hr))
162 return hr;
164 for (i=0; This->parent->encoder_info.encoder_options[i] != ENCODER_OPTION_END; i++)
166 VARIANT *val = &opt_values[i];
168 switch (This->parent->encoder_info.encoder_options[i])
170 case ENCODER_OPTION_INTERLACE:
171 if (V_VT(val) == VT_EMPTY)
172 options.interlace = FALSE;
173 else
174 options.interlace = (V_BOOL(val) != 0);
175 break;
176 case ENCODER_OPTION_FILTER:
177 options.filter = V_UI1(val);
178 if (options.filter > WICPngFilterAdaptive)
180 WARN("Unrecognized filter option value %u.\n", options.filter);
181 options.filter = WICPngFilterUnspecified;
183 break;
184 default:
185 break;
189 else
191 options.interlace = FALSE;
192 options.filter = WICPngFilterUnspecified;
195 EnterCriticalSection(&This->parent->lock);
197 if (This->initialized)
198 hr = WINCODEC_ERR_WRONGSTATE;
199 else
201 This->encoder_frame = options;
202 This->initialized = TRUE;
205 LeaveCriticalSection(&This->parent->lock);
207 return hr;
210 static HRESULT WINAPI CommonEncoderFrame_SetSize(IWICBitmapFrameEncode *iface,
211 UINT uiWidth, UINT uiHeight)
213 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
214 HRESULT hr;
216 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
218 EnterCriticalSection(&This->parent->lock);
220 if (This->parent->encoder_info.flags & ENCODER_FLAGS_ICNS_SIZE)
222 if (uiWidth != uiHeight)
224 WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight);
225 hr = E_INVALIDARG;
226 goto end;
229 switch (uiWidth)
231 case 16:
232 case 32:
233 case 48:
234 case 128:
235 case 256:
236 case 512:
237 break;
238 default:
239 WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight);
240 hr = E_INVALIDARG;
241 goto end;
245 if (!This->initialized || This->frame_created)
247 hr = WINCODEC_ERR_WRONGSTATE;
249 else
251 This->encoder_frame.width = uiWidth;
252 This->encoder_frame.height = uiHeight;
253 hr = S_OK;
256 end:
257 LeaveCriticalSection(&This->parent->lock);
259 return hr;
262 static HRESULT WINAPI CommonEncoderFrame_SetResolution(IWICBitmapFrameEncode *iface,
263 double dpiX, double dpiY)
265 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
266 HRESULT hr;
268 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
270 EnterCriticalSection(&This->parent->lock);
272 if (!This->initialized || This->frame_created)
274 hr = WINCODEC_ERR_WRONGSTATE;
276 else
278 This->encoder_frame.dpix = dpiX;
279 This->encoder_frame.dpiy = dpiY;
280 hr = S_OK;
283 LeaveCriticalSection(&This->parent->lock);
285 return hr;
288 static HRESULT WINAPI CommonEncoderFrame_SetPixelFormat(IWICBitmapFrameEncode *iface,
289 WICPixelFormatGUID *pPixelFormat)
291 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
292 HRESULT hr;
293 GUID pixel_format;
294 DWORD bpp;
295 BOOL indexed;
297 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
299 EnterCriticalSection(&This->parent->lock);
301 if (!This->initialized || This->frame_created)
303 hr = WINCODEC_ERR_WRONGSTATE;
305 else
307 pixel_format = *pPixelFormat;
308 hr = encoder_get_supported_format(This->parent->encoder, &pixel_format, &bpp, &indexed);
311 if (SUCCEEDED(hr))
313 TRACE("<-- %s bpp=%i indexed=%i\n", wine_dbgstr_guid(&pixel_format), bpp, indexed);
314 *pPixelFormat = pixel_format;
315 This->encoder_frame.pixel_format = pixel_format;
316 This->encoder_frame.bpp = bpp;
317 This->encoder_frame.indexed = indexed;
320 LeaveCriticalSection(&This->parent->lock);
322 return hr;
325 static HRESULT WINAPI CommonEncoderFrame_SetColorContexts(IWICBitmapFrameEncode *iface,
326 UINT cCount, IWICColorContext **ppIColorContext)
328 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
329 return E_NOTIMPL;
332 static HRESULT WINAPI CommonEncoderFrame_SetPalette(IWICBitmapFrameEncode *iface,
333 IWICPalette *palette)
335 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
336 HRESULT hr;
338 TRACE("(%p,%p)\n", iface, palette);
340 if (!palette)
341 return E_INVALIDARG;
343 EnterCriticalSection(&This->parent->lock);
345 if (!This->initialized)
346 hr = WINCODEC_ERR_NOTINITIALIZED;
347 else if (This->frame_created)
348 hr = WINCODEC_ERR_WRONGSTATE;
349 else
350 hr = IWICPalette_GetColors(palette, 256, This->encoder_frame.palette,
351 &This->encoder_frame.num_colors);
353 LeaveCriticalSection(&This->parent->lock);
355 return hr;
358 static HRESULT WINAPI CommonEncoderFrame_SetThumbnail(IWICBitmapFrameEncode *iface,
359 IWICBitmapSource *pIThumbnail)
361 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
362 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
365 static HRESULT WINAPI CommonEncoderFrame_WritePixels(IWICBitmapFrameEncode *iface,
366 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
368 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
369 HRESULT hr=S_OK;
370 DWORD required_stride;
372 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
374 EnterCriticalSection(&This->parent->lock);
376 if (!This->initialized || !This->encoder_frame.height || !This->encoder_frame.width ||
377 !This->encoder_frame.bpp)
379 LeaveCriticalSection(&This->parent->lock);
380 return WINCODEC_ERR_WRONGSTATE;
383 required_stride = (This->encoder_frame.width * This->encoder_frame.bpp + 7)/8;
385 if (lineCount == 0 || This->encoder_frame.height - This->lines_written < lineCount ||
386 cbStride < required_stride || cbBufferSize < cbStride * (lineCount - 1) + required_stride ||
387 !pbPixels)
389 LeaveCriticalSection(&This->parent->lock);
390 return E_INVALIDARG;
393 if (!This->frame_created)
395 hr = encoder_create_frame(This->parent->encoder, &This->encoder_frame);
396 if (SUCCEEDED(hr))
397 This->frame_created = TRUE;
400 if (SUCCEEDED(hr))
402 hr = encoder_write_lines(This->parent->encoder, pbPixels, lineCount, cbStride);
403 if (SUCCEEDED(hr))
404 This->lines_written += lineCount;
407 LeaveCriticalSection(&This->parent->lock);
409 return hr;
412 static HRESULT WINAPI CommonEncoderFrame_WriteSource(IWICBitmapFrameEncode *iface,
413 IWICBitmapSource *pIBitmapSource, WICRect *prc)
415 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
416 HRESULT hr;
417 TRACE("(%p,%p,%s)\n", iface, pIBitmapSource, debug_wic_rect(prc));
419 if (!This->initialized)
420 return WINCODEC_ERR_WRONGSTATE;
422 hr = configure_write_source(iface, pIBitmapSource, prc,
423 This->encoder_frame.bpp ? &This->encoder_frame.pixel_format : NULL,
424 This->encoder_frame.width, This->encoder_frame.height,
425 This->encoder_frame.dpix, This->encoder_frame.dpiy);
427 if (SUCCEEDED(hr))
429 hr = write_source(iface, pIBitmapSource, prc,
430 &This->encoder_frame.pixel_format, This->encoder_frame.bpp,
431 !This->encoder_frame.num_colors && This->encoder_frame.indexed,
432 This->encoder_frame.width, This->encoder_frame.height);
435 return hr;
438 static HRESULT WINAPI CommonEncoderFrame_Commit(IWICBitmapFrameEncode *iface)
440 CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
441 HRESULT hr;
443 TRACE("(%p)\n", iface);
445 EnterCriticalSection(&This->parent->lock);
447 if (!This->frame_created || This->lines_written != This->encoder_frame.height ||
448 This->committed)
450 hr = WINCODEC_ERR_WRONGSTATE;
452 else
454 hr = encoder_commit_frame(This->parent->encoder);
455 if (SUCCEEDED(hr))
457 This->committed = TRUE;
458 This->parent->uncommitted_frame = FALSE;
462 LeaveCriticalSection(&This->parent->lock);
464 return hr;
467 static HRESULT WINAPI CommonEncoderFrame_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
468 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
470 CommonEncoderFrame *encoder = impl_from_IWICBitmapFrameEncode(iface);
472 TRACE("iface, %p, ppIMetadataQueryWriter %p.\n", iface, ppIMetadataQueryWriter);
474 if (!ppIMetadataQueryWriter)
475 return E_INVALIDARG;
477 if (!encoder->initialized)
478 return WINCODEC_ERR_NOTINITIALIZED;
480 if (!(encoder->parent->encoder_info.flags & ENCODER_FLAGS_SUPPORTS_METADATA))
481 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
483 return MetadataQueryWriter_CreateInstance(&encoder->IWICMetadataBlockWriter_iface, NULL, ppIMetadataQueryWriter);
486 static const IWICBitmapFrameEncodeVtbl CommonEncoderFrame_Vtbl = {
487 CommonEncoderFrame_QueryInterface,
488 CommonEncoderFrame_AddRef,
489 CommonEncoderFrame_Release,
490 CommonEncoderFrame_Initialize,
491 CommonEncoderFrame_SetSize,
492 CommonEncoderFrame_SetResolution,
493 CommonEncoderFrame_SetPixelFormat,
494 CommonEncoderFrame_SetColorContexts,
495 CommonEncoderFrame_SetPalette,
496 CommonEncoderFrame_SetThumbnail,
497 CommonEncoderFrame_WritePixels,
498 CommonEncoderFrame_WriteSource,
499 CommonEncoderFrame_Commit,
500 CommonEncoderFrame_GetMetadataQueryWriter
503 static HRESULT WINAPI CommonEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
504 void **ppv)
506 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
507 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
509 if (!ppv) return E_INVALIDARG;
511 if (IsEqualIID(&IID_IUnknown, iid) ||
512 IsEqualIID(&IID_IWICBitmapEncoder, iid))
514 *ppv = &This->IWICBitmapEncoder_iface;
516 else
518 *ppv = NULL;
519 return E_NOINTERFACE;
522 IUnknown_AddRef((IUnknown*)*ppv);
523 return S_OK;
526 static ULONG WINAPI CommonEncoder_AddRef(IWICBitmapEncoder *iface)
528 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
529 ULONG ref = InterlockedIncrement(&This->ref);
531 TRACE("(%p) refcount=%u\n", iface, ref);
533 return ref;
536 static ULONG WINAPI CommonEncoder_Release(IWICBitmapEncoder *iface)
538 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
539 ULONG ref = InterlockedDecrement(&This->ref);
541 TRACE("(%p) refcount=%u\n", iface, ref);
543 if (ref == 0)
545 This->lock.DebugInfo->Spare[0] = 0;
546 DeleteCriticalSection(&This->lock);
547 if (This->stream)
548 IStream_Release(This->stream);
549 encoder_destroy(This->encoder);
550 HeapFree(GetProcessHeap(), 0, This);
553 return ref;
556 static HRESULT WINAPI CommonEncoder_Initialize(IWICBitmapEncoder *iface,
557 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
559 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
560 HRESULT hr;
562 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
564 if (!pIStream)
565 return E_POINTER;
567 EnterCriticalSection(&This->lock);
569 if (This->stream)
571 LeaveCriticalSection(&This->lock);
572 return WINCODEC_ERR_WRONGSTATE;
575 hr = encoder_initialize(This->encoder, pIStream);
577 if (SUCCEEDED(hr))
579 This->stream = pIStream;
580 IStream_AddRef(This->stream);
583 LeaveCriticalSection(&This->lock);
585 return S_OK;
588 static HRESULT WINAPI CommonEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
590 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
591 TRACE("(%p,%p)\n", iface, format);
593 if (!format)
594 return E_INVALIDARG;
596 memcpy(format, &This->encoder_info.container_format, sizeof(*format));
597 return S_OK;
600 static HRESULT WINAPI CommonEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
602 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
603 IWICComponentInfo *comp_info;
604 HRESULT hr;
606 TRACE("%p,%p\n", iface, info);
608 if (!info) return E_INVALIDARG;
610 hr = CreateComponentInfo(&This->encoder_info.clsid, &comp_info);
611 if (hr == S_OK)
613 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
614 IWICComponentInfo_Release(comp_info);
616 return hr;
619 static HRESULT WINAPI CommonEncoder_SetColorContexts(IWICBitmapEncoder *iface,
620 UINT cCount, IWICColorContext **ppIColorContext)
622 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
623 return E_NOTIMPL;
626 static HRESULT WINAPI CommonEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
628 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
629 HRESULT hr;
631 TRACE("(%p,%p)\n", iface, palette);
633 EnterCriticalSection(&This->lock);
635 hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
637 LeaveCriticalSection(&This->lock);
639 return hr;
642 static HRESULT WINAPI CommonEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
644 TRACE("(%p,%p)\n", iface, pIThumbnail);
645 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
648 static HRESULT WINAPI CommonEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
650 TRACE("(%p,%p)\n", iface, pIPreview);
651 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
654 static HRESULT WINAPI CommonEncoderFrame_Block_QueryInterface(IWICMetadataBlockWriter *iface, REFIID iid, void **ppv)
656 CommonEncoderFrame *encoder = impl_from_IWICMetadataBlockWriter(iface);
658 return IWICBitmapFrameEncode_QueryInterface(&encoder->IWICBitmapFrameEncode_iface, iid, ppv);
661 static ULONG WINAPI CommonEncoderFrame_Block_AddRef(IWICMetadataBlockWriter *iface)
663 CommonEncoderFrame *encoder = impl_from_IWICMetadataBlockWriter(iface);
665 return IWICBitmapFrameEncode_AddRef(&encoder->IWICBitmapFrameEncode_iface);
668 static ULONG WINAPI CommonEncoderFrame_Block_Release(IWICMetadataBlockWriter *iface)
670 CommonEncoderFrame *encoder = impl_from_IWICMetadataBlockWriter(iface);
672 return IWICBitmapFrameEncode_Release(&encoder->IWICBitmapFrameEncode_iface);
675 static HRESULT WINAPI CommonEncoderFrame_Block_GetContainerFormat(IWICMetadataBlockWriter *iface, GUID *container_format)
677 FIXME("iface %p, container_format %p stub.\n", iface, container_format);
679 return E_NOTIMPL;
682 static HRESULT WINAPI CommonEncoderFrame_Block_GetCount(IWICMetadataBlockWriter *iface, UINT *count)
684 FIXME("iface %p, count %p stub.\n", iface, count);
686 return E_NOTIMPL;
689 static HRESULT WINAPI CommonEncoderFrame_Block_GetReaderByIndex(IWICMetadataBlockWriter *iface,
690 UINT index, IWICMetadataReader **metadata_reader)
692 FIXME("iface %p, index %d, metadata_reader %p stub.\n", iface, index, metadata_reader);
694 return E_NOTIMPL;
697 static HRESULT WINAPI CommonEncoderFrame_Block_GetEnumerator(IWICMetadataBlockWriter *iface, IEnumUnknown **enum_metadata)
699 FIXME("iface %p, ppIEnumMetadata %p stub.\n", iface, enum_metadata);
701 return E_NOTIMPL;
704 static HRESULT WINAPI CommonEncoderFrame_Block_InitializeFromBlockReader(IWICMetadataBlockWriter *iface,
705 IWICMetadataBlockReader *metadata_block_reader)
707 FIXME("iface %p, metadata_block_reader %p stub.\n", iface, metadata_block_reader);
709 return E_NOTIMPL;
712 static HRESULT WINAPI CommonEncoderFrame_Block_GetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index,
713 IWICMetadataWriter **metadata_writer)
715 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface, index, metadata_writer);
717 return E_NOTIMPL;
720 static HRESULT WINAPI CommonEncoderFrame_Block_AddWriter(IWICMetadataBlockWriter *iface, IWICMetadataWriter *metadata_writer)
722 FIXME("iface %p, metadata_writer %p.\n", iface, metadata_writer);
724 return E_NOTIMPL;
727 static HRESULT WINAPI CommonEncoderFrame_Block_SetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index,
728 IWICMetadataWriter *metadata_writer)
730 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface, index, metadata_writer);
732 return E_NOTIMPL;
735 static HRESULT WINAPI CommonEncoderFrame_Block_RemoveWriterByIndex(IWICMetadataBlockWriter *iface, UINT index)
737 FIXME("iface %p, index %u.\n", iface, index);
739 return E_NOTIMPL;
742 static const IWICMetadataBlockWriterVtbl CommonEncoderFrame_BlockVtbl =
744 CommonEncoderFrame_Block_QueryInterface,
745 CommonEncoderFrame_Block_AddRef,
746 CommonEncoderFrame_Block_Release,
747 CommonEncoderFrame_Block_GetContainerFormat,
748 CommonEncoderFrame_Block_GetCount,
749 CommonEncoderFrame_Block_GetReaderByIndex,
750 CommonEncoderFrame_Block_GetEnumerator,
751 CommonEncoderFrame_Block_InitializeFromBlockReader,
752 CommonEncoderFrame_Block_GetWriterByIndex,
753 CommonEncoderFrame_Block_AddWriter,
754 CommonEncoderFrame_Block_SetWriterByIndex,
755 CommonEncoderFrame_Block_RemoveWriterByIndex,
758 static HRESULT WINAPI CommonEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
759 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
761 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
762 CommonEncoderFrame *result;
763 HRESULT hr;
764 DWORD opts_length;
765 PROPBAG2 opts[6];
767 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
769 EnterCriticalSection(&This->lock);
771 if (This->frame_count != 0 && !(This->encoder_info.flags & ENCODER_FLAGS_MULTI_FRAME))
773 LeaveCriticalSection(&This->lock);
774 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
777 if (!This->stream || This->committed || This->uncommitted_frame)
779 LeaveCriticalSection(&This->lock);
780 return WINCODEC_ERR_NOTINITIALIZED;
783 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*result));
784 if (!result)
786 LeaveCriticalSection(&This->lock);
787 return E_OUTOFMEMORY;
790 result->IWICBitmapFrameEncode_iface.lpVtbl = &CommonEncoderFrame_Vtbl;
791 result->IWICMetadataBlockWriter_iface.lpVtbl = &CommonEncoderFrame_BlockVtbl;
792 result->ref = 1;
793 result->parent = This;
795 if (ppIEncoderOptions)
797 for (opts_length = 0; This->encoder_info.encoder_options[opts_length] < ENCODER_OPTION_END; opts_length++)
799 opts[opts_length] = encoder_option_properties[This->encoder_info.encoder_options[opts_length]];
802 hr = CreatePropertyBag2(opts, opts_length, ppIEncoderOptions);
803 if (FAILED(hr))
805 LeaveCriticalSection(&This->lock);
806 HeapFree(GetProcessHeap(), 0, result);
807 return hr;
811 IWICBitmapEncoder_AddRef(iface);
812 This->frame_count++;
813 This->uncommitted_frame = TRUE;
815 LeaveCriticalSection(&This->lock);
817 *ppIFrameEncode = &result->IWICBitmapFrameEncode_iface;
819 return S_OK;
822 static HRESULT WINAPI CommonEncoder_Commit(IWICBitmapEncoder *iface)
824 CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
825 HRESULT hr;
827 TRACE("(%p)\n", iface);
829 EnterCriticalSection(&This->lock);
831 if (This->committed || This->uncommitted_frame)
832 hr = WINCODEC_ERR_WRONGSTATE;
833 else
835 hr = encoder_commit_file(This->encoder);
836 if (SUCCEEDED(hr))
837 This->committed = TRUE;
840 LeaveCriticalSection(&This->lock);
842 return hr;
845 static HRESULT WINAPI CommonEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
846 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
848 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
849 return E_NOTIMPL;
852 static const IWICBitmapEncoderVtbl CommonEncoder_Vtbl = {
853 CommonEncoder_QueryInterface,
854 CommonEncoder_AddRef,
855 CommonEncoder_Release,
856 CommonEncoder_Initialize,
857 CommonEncoder_GetContainerFormat,
858 CommonEncoder_GetEncoderInfo,
859 CommonEncoder_SetColorContexts,
860 CommonEncoder_SetPalette,
861 CommonEncoder_SetThumbnail,
862 CommonEncoder_SetPreview,
863 CommonEncoder_CreateNewFrame,
864 CommonEncoder_Commit,
865 CommonEncoder_GetMetadataQueryWriter
868 HRESULT CommonEncoder_CreateInstance(struct encoder *encoder,
869 const struct encoder_info *encoder_info, REFIID iid, void** ppv)
871 CommonEncoder *This;
872 HRESULT ret;
874 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
876 *ppv = NULL;
878 This = HeapAlloc(GetProcessHeap(), 0, sizeof(CommonEncoder));
879 if (!This)
881 encoder_destroy(encoder);
882 return E_OUTOFMEMORY;
885 This->IWICBitmapEncoder_iface.lpVtbl = &CommonEncoder_Vtbl;
886 This->ref = 1;
887 This->stream = NULL;
888 This->encoder = encoder;
889 This->encoder_info = *encoder_info;
890 This->frame_count = 0;
891 This->uncommitted_frame = FALSE;
892 This->committed = FALSE;
893 InitializeCriticalSection(&This->lock);
894 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CommonEncoder.lock");
896 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
897 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
899 return ret;