xref: /reactos/dll/win32/windowscodecs/encoder.c (revision 197ed01e)
1 /*
2  * Copyright 2020 Esme Povirk
3  *
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.
8  *
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.
13  *
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
17  */
18 
19 #include <stdarg.h>
20 
21 #define COBJMACROS
22 
23 #include "windef.h"
24 #include "winbase.h"
25 #include "objbase.h"
26 
27 #include "wincodecs_private.h"
28 
29 #include "wine/debug.h"
30 
31 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
32 
33 static const PROPBAG2 encoder_option_properties[ENCODER_OPTION_END] = {
34     { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)L"InterlaceOption" },
35     { PROPBAG2_TYPE_DATA, VT_UI1,  0, 0, (LPOLESTR)L"FilterOption" },
36     { PROPBAG2_TYPE_DATA, VT_UI1,  0, 0, (LPOLESTR)L"TiffCompressionMethod" },
37     { PROPBAG2_TYPE_DATA, VT_R4,   0, 0, (LPOLESTR)L"CompressionQuality" },
38     { PROPBAG2_TYPE_DATA, VT_R4,            0, 0, (LPOLESTR)L"ImageQuality" },
39     { PROPBAG2_TYPE_DATA, VT_UI1,           0, 0, (LPOLESTR)L"BitmapTransform" },
40     { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)L"Luminance" },
41     { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)L"Chrominance" },
42     { PROPBAG2_TYPE_DATA, VT_UI1,           0, 0, (LPOLESTR)L"JpegYCrCbSubsampling" },
43     { PROPBAG2_TYPE_DATA, VT_BOOL,          0, 0, (LPOLESTR)L"SuppressApp0" }
44 };
45 
46 typedef struct CommonEncoder {
47     IWICBitmapEncoder IWICBitmapEncoder_iface;
48     LONG ref;
49     CRITICAL_SECTION lock; /* must be held when stream or encoder is accessed */
50     IStream *stream;
51     struct encoder *encoder;
52     struct encoder_info encoder_info;
53     UINT frame_count;
54     BOOL uncommitted_frame;
55     BOOL committed;
56 } CommonEncoder;
57 
58 typedef struct CommonEncoderFrame {
59     IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
60     IWICMetadataBlockWriter IWICMetadataBlockWriter_iface;
61     LONG ref;
62     CommonEncoder *parent;
63     struct encoder_frame encoder_frame;
64     BOOL initialized;
65     BOOL frame_created;
66     UINT lines_written;
67     BOOL committed;
68 } CommonEncoderFrame;
69 
impl_from_IWICBitmapEncoder(IWICBitmapEncoder * iface)70 static inline CommonEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
71 {
72     return CONTAINING_RECORD(iface, CommonEncoder, IWICBitmapEncoder_iface);
73 }
74 
impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode * iface)75 static inline CommonEncoderFrame *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
76 {
77     return CONTAINING_RECORD(iface, CommonEncoderFrame, IWICBitmapFrameEncode_iface);
78 }
79 
impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter * iface)80 static inline CommonEncoderFrame *impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter *iface)
81 {
82     return CONTAINING_RECORD(iface, CommonEncoderFrame, IWICMetadataBlockWriter_iface);
83 }
84 
CommonEncoderFrame_QueryInterface(IWICBitmapFrameEncode * iface,REFIID iid,void ** ppv)85 static HRESULT WINAPI CommonEncoderFrame_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
86     void **ppv)
87 {
88     CommonEncoderFrame *object = impl_from_IWICBitmapFrameEncode(iface);
89     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
90 
91     if (!ppv) return E_INVALIDARG;
92 
93     if (IsEqualIID(&IID_IUnknown, iid) ||
94         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
95     {
96         *ppv = &object->IWICBitmapFrameEncode_iface;
97     }
98     else if (object->parent->encoder_info.flags & ENCODER_FLAGS_SUPPORTS_METADATA
99             && IsEqualIID(&IID_IWICMetadataBlockWriter, iid))
100     {
101         *ppv = &object->IWICMetadataBlockWriter_iface;
102     }
103     else
104     {
105         *ppv = NULL;
106         return E_NOINTERFACE;
107     }
108 
109     IUnknown_AddRef((IUnknown*)*ppv);
110     return S_OK;
111 }
112 
CommonEncoderFrame_AddRef(IWICBitmapFrameEncode * iface)113 static ULONG WINAPI CommonEncoderFrame_AddRef(IWICBitmapFrameEncode *iface)
114 {
115     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
116     ULONG ref = InterlockedIncrement(&This->ref);
117 
118     TRACE("(%p) refcount=%lu\n", iface, ref);
119 
120     return ref;
121 }
122 
CommonEncoderFrame_Release(IWICBitmapFrameEncode * iface)123 static ULONG WINAPI CommonEncoderFrame_Release(IWICBitmapFrameEncode *iface)
124 {
125     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
126     ULONG ref = InterlockedDecrement(&This->ref);
127 
128     TRACE("(%p) refcount=%lu\n", iface, ref);
129 
130     if (ref == 0)
131     {
132         IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface);
133         free(This);
134     }
135 
136     return ref;
137 }
138 
CommonEncoderFrame_Initialize(IWICBitmapFrameEncode * iface,IPropertyBag2 * pIEncoderOptions)139 static HRESULT WINAPI CommonEncoderFrame_Initialize(IWICBitmapFrameEncode *iface,
140     IPropertyBag2 *pIEncoderOptions)
141 {
142     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
143     HRESULT hr=S_OK;
144     struct encoder_frame options = {{0}};
145     PROPBAG2 opts[7]= {{0}};
146     VARIANT opt_values[7];
147     HRESULT opt_hres[7];
148     DWORD num_opts, i;
149 
150     TRACE("(%p,%p)\n", iface, pIEncoderOptions);
151 
152     if (pIEncoderOptions)
153     {
154         for (i=0; This->parent->encoder_info.encoder_options[i] != ENCODER_OPTION_END; i++)
155             opts[i] = encoder_option_properties[This->parent->encoder_info.encoder_options[i]];
156         num_opts = i;
157 
158         hr = IPropertyBag2_Read(pIEncoderOptions, num_opts, opts, NULL, opt_values, opt_hres);
159 
160         if (FAILED(hr))
161             return hr;
162 
163         for (i=0; This->parent->encoder_info.encoder_options[i] != ENCODER_OPTION_END; i++)
164         {
165             VARIANT *val = &opt_values[i];
166 
167             switch (This->parent->encoder_info.encoder_options[i])
168             {
169             case ENCODER_OPTION_INTERLACE:
170                 if (V_VT(val) == VT_EMPTY)
171                     options.interlace = FALSE;
172                 else
173                     options.interlace = (V_BOOL(val) != 0);
174                 break;
175             case ENCODER_OPTION_FILTER:
176                 options.filter = V_UI1(val);
177                 if (options.filter > WICPngFilterAdaptive)
178                 {
179                     WARN("Unrecognized filter option value %lu.\n", options.filter);
180                     options.filter = WICPngFilterUnspecified;
181                 }
182                 break;
183             default:
184                 break;
185             }
186         }
187     }
188     else
189     {
190         options.interlace = FALSE;
191         options.filter = WICPngFilterUnspecified;
192     }
193 
194     EnterCriticalSection(&This->parent->lock);
195 
196     if (This->initialized)
197         hr = WINCODEC_ERR_WRONGSTATE;
198     else
199     {
200         This->encoder_frame = options;
201         This->initialized = TRUE;
202     }
203 
204     LeaveCriticalSection(&This->parent->lock);
205 
206     return hr;
207 }
208 
CommonEncoderFrame_SetSize(IWICBitmapFrameEncode * iface,UINT uiWidth,UINT uiHeight)209 static HRESULT WINAPI CommonEncoderFrame_SetSize(IWICBitmapFrameEncode *iface,
210     UINT uiWidth, UINT uiHeight)
211 {
212     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
213     HRESULT hr;
214 
215     TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
216 
217     EnterCriticalSection(&This->parent->lock);
218 
219     if (This->parent->encoder_info.flags & ENCODER_FLAGS_ICNS_SIZE)
220     {
221         if (uiWidth != uiHeight)
222         {
223             WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight);
224             hr = E_INVALIDARG;
225             goto end;
226         }
227 
228         switch (uiWidth)
229         {
230             case 16:
231             case 32:
232             case 48:
233             case 128:
234             case 256:
235             case 512:
236                 break;
237             default:
238                 WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight);
239                 hr = E_INVALIDARG;
240                 goto end;
241         }
242     }
243 
244     if (!This->initialized || This->frame_created)
245     {
246         hr = WINCODEC_ERR_WRONGSTATE;
247     }
248     else
249     {
250         This->encoder_frame.width = uiWidth;
251         This->encoder_frame.height = uiHeight;
252         hr = S_OK;
253     }
254 
255 end:
256     LeaveCriticalSection(&This->parent->lock);
257 
258     return hr;
259 }
260 
CommonEncoderFrame_SetResolution(IWICBitmapFrameEncode * iface,double dpiX,double dpiY)261 static HRESULT WINAPI CommonEncoderFrame_SetResolution(IWICBitmapFrameEncode *iface,
262     double dpiX, double dpiY)
263 {
264     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
265     HRESULT hr;
266 
267     TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
268 
269     EnterCriticalSection(&This->parent->lock);
270 
271     if (!This->initialized || This->frame_created)
272     {
273         hr = WINCODEC_ERR_WRONGSTATE;
274     }
275     else
276     {
277         This->encoder_frame.dpix = dpiX;
278         This->encoder_frame.dpiy = dpiY;
279         hr = S_OK;
280     }
281 
282     LeaveCriticalSection(&This->parent->lock);
283 
284     return hr;
285 }
286 
CommonEncoderFrame_SetPixelFormat(IWICBitmapFrameEncode * iface,WICPixelFormatGUID * pPixelFormat)287 static HRESULT WINAPI CommonEncoderFrame_SetPixelFormat(IWICBitmapFrameEncode *iface,
288     WICPixelFormatGUID *pPixelFormat)
289 {
290     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
291     HRESULT hr;
292     GUID pixel_format;
293     DWORD bpp;
294     BOOL indexed;
295 
296     TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
297 
298     EnterCriticalSection(&This->parent->lock);
299 
300     if (!This->initialized || This->frame_created)
301     {
302         hr = WINCODEC_ERR_WRONGSTATE;
303     }
304     else
305     {
306         pixel_format = *pPixelFormat;
307         hr = encoder_get_supported_format(This->parent->encoder, &pixel_format, &bpp, &indexed);
308     }
309 
310     if (SUCCEEDED(hr))
311     {
312         TRACE("<-- %s bpp=%li indexed=%i\n", wine_dbgstr_guid(&pixel_format), bpp, indexed);
313         *pPixelFormat = pixel_format;
314         This->encoder_frame.pixel_format = pixel_format;
315         This->encoder_frame.bpp = bpp;
316         This->encoder_frame.indexed = indexed;
317     }
318 
319     LeaveCriticalSection(&This->parent->lock);
320 
321     return hr;
322 }
323 
CommonEncoderFrame_SetColorContexts(IWICBitmapFrameEncode * iface,UINT cCount,IWICColorContext ** ppIColorContext)324 static HRESULT WINAPI CommonEncoderFrame_SetColorContexts(IWICBitmapFrameEncode *iface,
325     UINT cCount, IWICColorContext **ppIColorContext)
326 {
327     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
328     return E_NOTIMPL;
329 }
330 
CommonEncoderFrame_SetPalette(IWICBitmapFrameEncode * iface,IWICPalette * palette)331 static HRESULT WINAPI CommonEncoderFrame_SetPalette(IWICBitmapFrameEncode *iface,
332     IWICPalette *palette)
333 {
334     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
335     HRESULT hr;
336 
337     TRACE("(%p,%p)\n", iface, palette);
338 
339     if (!palette)
340         return E_INVALIDARG;
341 
342     EnterCriticalSection(&This->parent->lock);
343 
344     if (!This->initialized)
345         hr = WINCODEC_ERR_NOTINITIALIZED;
346     else if (This->frame_created)
347         hr = WINCODEC_ERR_WRONGSTATE;
348     else
349         hr = IWICPalette_GetColors(palette, 256, This->encoder_frame.palette,
350             &This->encoder_frame.num_colors);
351 
352     LeaveCriticalSection(&This->parent->lock);
353 
354     return hr;
355 }
356 
CommonEncoderFrame_SetThumbnail(IWICBitmapFrameEncode * iface,IWICBitmapSource * pIThumbnail)357 static HRESULT WINAPI CommonEncoderFrame_SetThumbnail(IWICBitmapFrameEncode *iface,
358     IWICBitmapSource *pIThumbnail)
359 {
360     FIXME("(%p,%p): stub\n", iface, pIThumbnail);
361     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
362 }
363 
CommonEncoderFrame_WritePixels(IWICBitmapFrameEncode * iface,UINT lineCount,UINT cbStride,UINT cbBufferSize,BYTE * pbPixels)364 static HRESULT WINAPI CommonEncoderFrame_WritePixels(IWICBitmapFrameEncode *iface,
365     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
366 {
367     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
368     HRESULT hr=S_OK;
369     DWORD required_stride;
370 
371     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
372 
373     EnterCriticalSection(&This->parent->lock);
374 
375     if (!This->initialized || !This->encoder_frame.height || !This->encoder_frame.width ||
376         !This->encoder_frame.bpp)
377     {
378         LeaveCriticalSection(&This->parent->lock);
379         return WINCODEC_ERR_WRONGSTATE;
380     }
381 
382     required_stride = (This->encoder_frame.width * This->encoder_frame.bpp + 7)/8;
383 
384     if (lineCount == 0 || This->encoder_frame.height - This->lines_written < lineCount ||
385         cbStride < required_stride || cbBufferSize < cbStride * (lineCount - 1) + required_stride ||
386         !pbPixels)
387     {
388         LeaveCriticalSection(&This->parent->lock);
389         return E_INVALIDARG;
390     }
391 
392     if (!This->frame_created)
393     {
394         hr = encoder_create_frame(This->parent->encoder, &This->encoder_frame);
395         if (SUCCEEDED(hr))
396             This->frame_created = TRUE;
397     }
398 
399     if (SUCCEEDED(hr))
400     {
401         hr = encoder_write_lines(This->parent->encoder, pbPixels, lineCount, cbStride);
402         if (SUCCEEDED(hr))
403             This->lines_written += lineCount;
404     }
405 
406     LeaveCriticalSection(&This->parent->lock);
407 
408     return hr;
409 }
410 
CommonEncoderFrame_WriteSource(IWICBitmapFrameEncode * iface,IWICBitmapSource * pIBitmapSource,WICRect * prc)411 static HRESULT WINAPI CommonEncoderFrame_WriteSource(IWICBitmapFrameEncode *iface,
412     IWICBitmapSource *pIBitmapSource, WICRect *prc)
413 {
414     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
415     HRESULT hr;
416     TRACE("(%p,%p,%s)\n", iface, pIBitmapSource, debug_wic_rect(prc));
417 
418     if (!This->initialized)
419         return WINCODEC_ERR_WRONGSTATE;
420 
421     hr = configure_write_source(iface, pIBitmapSource, prc,
422         This->encoder_frame.bpp ? &This->encoder_frame.pixel_format : NULL,
423         This->encoder_frame.width, This->encoder_frame.height,
424         This->encoder_frame.dpix, This->encoder_frame.dpiy);
425 
426     if (SUCCEEDED(hr))
427     {
428         hr = write_source(iface, pIBitmapSource, prc,
429             &This->encoder_frame.pixel_format, This->encoder_frame.bpp,
430             !This->encoder_frame.num_colors && This->encoder_frame.indexed,
431             This->encoder_frame.width, This->encoder_frame.height);
432     }
433 
434     return hr;
435 }
436 
CommonEncoderFrame_Commit(IWICBitmapFrameEncode * iface)437 static HRESULT WINAPI CommonEncoderFrame_Commit(IWICBitmapFrameEncode *iface)
438 {
439     CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface);
440     HRESULT hr;
441 
442     TRACE("(%p)\n", iface);
443 
444     EnterCriticalSection(&This->parent->lock);
445 
446     if (!This->frame_created || This->lines_written != This->encoder_frame.height ||
447         This->committed)
448     {
449         hr = WINCODEC_ERR_WRONGSTATE;
450     }
451     else
452     {
453         hr = encoder_commit_frame(This->parent->encoder);
454         if (SUCCEEDED(hr))
455         {
456             This->committed = TRUE;
457             This->parent->uncommitted_frame = FALSE;
458         }
459     }
460 
461     LeaveCriticalSection(&This->parent->lock);
462 
463     return hr;
464 }
465 
CommonEncoderFrame_GetMetadataQueryWriter(IWICBitmapFrameEncode * iface,IWICMetadataQueryWriter ** ppIMetadataQueryWriter)466 static HRESULT WINAPI CommonEncoderFrame_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
467     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
468 {
469     CommonEncoderFrame *encoder = impl_from_IWICBitmapFrameEncode(iface);
470 
471     TRACE("iface, %p, ppIMetadataQueryWriter %p.\n", iface, ppIMetadataQueryWriter);
472 
473     if (!ppIMetadataQueryWriter)
474         return E_INVALIDARG;
475 
476     if (!encoder->initialized)
477         return WINCODEC_ERR_NOTINITIALIZED;
478 
479     if (!(encoder->parent->encoder_info.flags & ENCODER_FLAGS_SUPPORTS_METADATA))
480         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
481 
482     return MetadataQueryWriter_CreateInstance(&encoder->IWICMetadataBlockWriter_iface, NULL, ppIMetadataQueryWriter);
483 }
484 
485 static const IWICBitmapFrameEncodeVtbl CommonEncoderFrame_Vtbl = {
486     CommonEncoderFrame_QueryInterface,
487     CommonEncoderFrame_AddRef,
488     CommonEncoderFrame_Release,
489     CommonEncoderFrame_Initialize,
490     CommonEncoderFrame_SetSize,
491     CommonEncoderFrame_SetResolution,
492     CommonEncoderFrame_SetPixelFormat,
493     CommonEncoderFrame_SetColorContexts,
494     CommonEncoderFrame_SetPalette,
495     CommonEncoderFrame_SetThumbnail,
496     CommonEncoderFrame_WritePixels,
497     CommonEncoderFrame_WriteSource,
498     CommonEncoderFrame_Commit,
499     CommonEncoderFrame_GetMetadataQueryWriter
500 };
501 
CommonEncoder_QueryInterface(IWICBitmapEncoder * iface,REFIID iid,void ** ppv)502 static HRESULT WINAPI CommonEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
503     void **ppv)
504 {
505     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
506     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
507 
508     if (!ppv) return E_INVALIDARG;
509 
510     if (IsEqualIID(&IID_IUnknown, iid) ||
511         IsEqualIID(&IID_IWICBitmapEncoder, iid))
512     {
513         *ppv = &This->IWICBitmapEncoder_iface;
514     }
515     else
516     {
517         *ppv = NULL;
518         return E_NOINTERFACE;
519     }
520 
521     IUnknown_AddRef((IUnknown*)*ppv);
522     return S_OK;
523 }
524 
CommonEncoder_AddRef(IWICBitmapEncoder * iface)525 static ULONG WINAPI CommonEncoder_AddRef(IWICBitmapEncoder *iface)
526 {
527     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
528     ULONG ref = InterlockedIncrement(&This->ref);
529 
530     TRACE("(%p) refcount=%lu\n", iface, ref);
531 
532     return ref;
533 }
534 
CommonEncoder_Release(IWICBitmapEncoder * iface)535 static ULONG WINAPI CommonEncoder_Release(IWICBitmapEncoder *iface)
536 {
537     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
538     ULONG ref = InterlockedDecrement(&This->ref);
539 
540     TRACE("(%p) refcount=%lu\n", iface, ref);
541 
542     if (ref == 0)
543     {
544         This->lock.DebugInfo->Spare[0] = 0;
545         DeleteCriticalSection(&This->lock);
546         if (This->stream)
547             IStream_Release(This->stream);
548         encoder_destroy(This->encoder);
549         free(This);
550     }
551 
552     return ref;
553 }
554 
CommonEncoder_Initialize(IWICBitmapEncoder * iface,IStream * pIStream,WICBitmapEncoderCacheOption cacheOption)555 static HRESULT WINAPI CommonEncoder_Initialize(IWICBitmapEncoder *iface,
556     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
557 {
558     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
559     HRESULT hr;
560 
561     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
562 
563     if (!pIStream)
564         return E_POINTER;
565 
566     EnterCriticalSection(&This->lock);
567 
568     if (This->stream)
569     {
570         LeaveCriticalSection(&This->lock);
571         return WINCODEC_ERR_WRONGSTATE;
572     }
573 
574     hr = encoder_initialize(This->encoder, pIStream);
575 
576     if (SUCCEEDED(hr))
577     {
578         This->stream = pIStream;
579         IStream_AddRef(This->stream);
580     }
581 
582     LeaveCriticalSection(&This->lock);
583 
584     return S_OK;
585 }
586 
CommonEncoder_GetContainerFormat(IWICBitmapEncoder * iface,GUID * format)587 static HRESULT WINAPI CommonEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
588 {
589     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
590     TRACE("(%p,%p)\n", iface, format);
591 
592     if (!format)
593         return E_INVALIDARG;
594 
595     memcpy(format, &This->encoder_info.container_format, sizeof(*format));
596     return S_OK;
597 }
598 
CommonEncoder_GetEncoderInfo(IWICBitmapEncoder * iface,IWICBitmapEncoderInfo ** info)599 static HRESULT WINAPI CommonEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
600 {
601     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
602     IWICComponentInfo *comp_info;
603     HRESULT hr;
604 
605     TRACE("%p,%p\n", iface, info);
606 
607     if (!info) return E_INVALIDARG;
608 
609     hr = CreateComponentInfo(&This->encoder_info.clsid, &comp_info);
610     if (hr == S_OK)
611     {
612         hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
613         IWICComponentInfo_Release(comp_info);
614     }
615     return hr;
616 }
617 
CommonEncoder_SetColorContexts(IWICBitmapEncoder * iface,UINT cCount,IWICColorContext ** ppIColorContext)618 static HRESULT WINAPI CommonEncoder_SetColorContexts(IWICBitmapEncoder *iface,
619     UINT cCount, IWICColorContext **ppIColorContext)
620 {
621     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
622     return E_NOTIMPL;
623 }
624 
CommonEncoder_SetPalette(IWICBitmapEncoder * iface,IWICPalette * palette)625 static HRESULT WINAPI CommonEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
626 {
627     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
628     HRESULT hr;
629 
630     TRACE("(%p,%p)\n", iface, palette);
631 
632     EnterCriticalSection(&This->lock);
633 
634     hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
635 
636     LeaveCriticalSection(&This->lock);
637 
638     return hr;
639 }
640 
CommonEncoder_SetThumbnail(IWICBitmapEncoder * iface,IWICBitmapSource * pIThumbnail)641 static HRESULT WINAPI CommonEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
642 {
643     TRACE("(%p,%p)\n", iface, pIThumbnail);
644     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
645 }
646 
CommonEncoder_SetPreview(IWICBitmapEncoder * iface,IWICBitmapSource * pIPreview)647 static HRESULT WINAPI CommonEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
648 {
649     TRACE("(%p,%p)\n", iface, pIPreview);
650     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
651 }
652 
CommonEncoderFrame_Block_QueryInterface(IWICMetadataBlockWriter * iface,REFIID iid,void ** ppv)653 static HRESULT WINAPI CommonEncoderFrame_Block_QueryInterface(IWICMetadataBlockWriter *iface, REFIID iid, void **ppv)
654 {
655     CommonEncoderFrame *encoder = impl_from_IWICMetadataBlockWriter(iface);
656 
657     return IWICBitmapFrameEncode_QueryInterface(&encoder->IWICBitmapFrameEncode_iface, iid, ppv);
658 }
659 
CommonEncoderFrame_Block_AddRef(IWICMetadataBlockWriter * iface)660 static ULONG WINAPI CommonEncoderFrame_Block_AddRef(IWICMetadataBlockWriter *iface)
661 {
662     CommonEncoderFrame *encoder = impl_from_IWICMetadataBlockWriter(iface);
663 
664     return IWICBitmapFrameEncode_AddRef(&encoder->IWICBitmapFrameEncode_iface);
665 }
666 
CommonEncoderFrame_Block_Release(IWICMetadataBlockWriter * iface)667 static ULONG WINAPI CommonEncoderFrame_Block_Release(IWICMetadataBlockWriter *iface)
668 {
669     CommonEncoderFrame *encoder = impl_from_IWICMetadataBlockWriter(iface);
670 
671     return IWICBitmapFrameEncode_Release(&encoder->IWICBitmapFrameEncode_iface);
672 }
673 
CommonEncoderFrame_Block_GetContainerFormat(IWICMetadataBlockWriter * iface,GUID * container_format)674 static HRESULT WINAPI CommonEncoderFrame_Block_GetContainerFormat(IWICMetadataBlockWriter *iface, GUID *container_format)
675 {
676     FIXME("iface %p, container_format %p stub.\n", iface, container_format);
677 
678     return E_NOTIMPL;
679 }
680 
CommonEncoderFrame_Block_GetCount(IWICMetadataBlockWriter * iface,UINT * count)681 static HRESULT WINAPI CommonEncoderFrame_Block_GetCount(IWICMetadataBlockWriter *iface, UINT *count)
682 {
683     FIXME("iface %p, count %p stub.\n", iface, count);
684 
685     return E_NOTIMPL;
686 }
687 
CommonEncoderFrame_Block_GetReaderByIndex(IWICMetadataBlockWriter * iface,UINT index,IWICMetadataReader ** metadata_reader)688 static HRESULT WINAPI CommonEncoderFrame_Block_GetReaderByIndex(IWICMetadataBlockWriter *iface,
689         UINT index, IWICMetadataReader **metadata_reader)
690 {
691     FIXME("iface %p, index %d, metadata_reader %p stub.\n", iface, index, metadata_reader);
692 
693     return E_NOTIMPL;
694 }
695 
CommonEncoderFrame_Block_GetEnumerator(IWICMetadataBlockWriter * iface,IEnumUnknown ** enum_metadata)696 static HRESULT WINAPI CommonEncoderFrame_Block_GetEnumerator(IWICMetadataBlockWriter *iface, IEnumUnknown **enum_metadata)
697 {
698     FIXME("iface %p, ppIEnumMetadata %p stub.\n", iface, enum_metadata);
699 
700     return E_NOTIMPL;
701 }
702 
CommonEncoderFrame_Block_InitializeFromBlockReader(IWICMetadataBlockWriter * iface,IWICMetadataBlockReader * metadata_block_reader)703 static HRESULT WINAPI CommonEncoderFrame_Block_InitializeFromBlockReader(IWICMetadataBlockWriter *iface,
704         IWICMetadataBlockReader *metadata_block_reader)
705 {
706     FIXME("iface %p, metadata_block_reader %p stub.\n", iface, metadata_block_reader);
707 
708     return E_NOTIMPL;
709 }
710 
CommonEncoderFrame_Block_GetWriterByIndex(IWICMetadataBlockWriter * iface,UINT index,IWICMetadataWriter ** metadata_writer)711 static HRESULT WINAPI CommonEncoderFrame_Block_GetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index,
712         IWICMetadataWriter **metadata_writer)
713 {
714     FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface, index, metadata_writer);
715 
716     return E_NOTIMPL;
717 }
718 
CommonEncoderFrame_Block_AddWriter(IWICMetadataBlockWriter * iface,IWICMetadataWriter * metadata_writer)719 static HRESULT WINAPI CommonEncoderFrame_Block_AddWriter(IWICMetadataBlockWriter *iface, IWICMetadataWriter *metadata_writer)
720 {
721     FIXME("iface %p, metadata_writer %p.\n", iface, metadata_writer);
722 
723     return E_NOTIMPL;
724 }
725 
CommonEncoderFrame_Block_SetWriterByIndex(IWICMetadataBlockWriter * iface,UINT index,IWICMetadataWriter * metadata_writer)726 static HRESULT WINAPI CommonEncoderFrame_Block_SetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index,
727         IWICMetadataWriter *metadata_writer)
728 {
729     FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface, index, metadata_writer);
730 
731     return E_NOTIMPL;
732 }
733 
CommonEncoderFrame_Block_RemoveWriterByIndex(IWICMetadataBlockWriter * iface,UINT index)734 static HRESULT WINAPI CommonEncoderFrame_Block_RemoveWriterByIndex(IWICMetadataBlockWriter *iface, UINT index)
735 {
736     FIXME("iface %p, index %u.\n", iface, index);
737 
738     return E_NOTIMPL;
739 }
740 
741 static const IWICMetadataBlockWriterVtbl CommonEncoderFrame_BlockVtbl =
742 {
743     CommonEncoderFrame_Block_QueryInterface,
744     CommonEncoderFrame_Block_AddRef,
745     CommonEncoderFrame_Block_Release,
746     CommonEncoderFrame_Block_GetContainerFormat,
747     CommonEncoderFrame_Block_GetCount,
748     CommonEncoderFrame_Block_GetReaderByIndex,
749     CommonEncoderFrame_Block_GetEnumerator,
750     CommonEncoderFrame_Block_InitializeFromBlockReader,
751     CommonEncoderFrame_Block_GetWriterByIndex,
752     CommonEncoderFrame_Block_AddWriter,
753     CommonEncoderFrame_Block_SetWriterByIndex,
754     CommonEncoderFrame_Block_RemoveWriterByIndex,
755 };
756 
CommonEncoder_CreateNewFrame(IWICBitmapEncoder * iface,IWICBitmapFrameEncode ** ppIFrameEncode,IPropertyBag2 ** ppIEncoderOptions)757 static HRESULT WINAPI CommonEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
758     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
759 {
760     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
761     CommonEncoderFrame *result;
762     HRESULT hr;
763     DWORD opts_length;
764     PROPBAG2 opts[6];
765 
766     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
767 
768     EnterCriticalSection(&This->lock);
769 
770     if (This->frame_count != 0 && !(This->encoder_info.flags & ENCODER_FLAGS_MULTI_FRAME))
771     {
772         LeaveCriticalSection(&This->lock);
773         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
774     }
775 
776     if (!This->stream || This->committed || This->uncommitted_frame)
777     {
778         LeaveCriticalSection(&This->lock);
779         return WINCODEC_ERR_NOTINITIALIZED;
780     }
781 
782     result = calloc(1, sizeof(*result));
783     if (!result)
784     {
785         LeaveCriticalSection(&This->lock);
786         return E_OUTOFMEMORY;
787     }
788 
789     result->IWICBitmapFrameEncode_iface.lpVtbl = &CommonEncoderFrame_Vtbl;
790     result->IWICMetadataBlockWriter_iface.lpVtbl = &CommonEncoderFrame_BlockVtbl;
791     result->ref = 1;
792     result->parent = This;
793 
794     if (ppIEncoderOptions)
795     {
796         for (opts_length = 0; This->encoder_info.encoder_options[opts_length] < ENCODER_OPTION_END; opts_length++)
797         {
798             opts[opts_length] = encoder_option_properties[This->encoder_info.encoder_options[opts_length]];
799         }
800 
801         hr = CreatePropertyBag2(opts, opts_length, ppIEncoderOptions);
802         if (FAILED(hr))
803         {
804             LeaveCriticalSection(&This->lock);
805             free(result);
806             return hr;
807         }
808     }
809 
810     IWICBitmapEncoder_AddRef(iface);
811     This->frame_count++;
812     This->uncommitted_frame = TRUE;
813 
814     LeaveCriticalSection(&This->lock);
815 
816     *ppIFrameEncode = &result->IWICBitmapFrameEncode_iface;
817 
818     return S_OK;
819 }
820 
CommonEncoder_Commit(IWICBitmapEncoder * iface)821 static HRESULT WINAPI CommonEncoder_Commit(IWICBitmapEncoder *iface)
822 {
823     CommonEncoder *This = impl_from_IWICBitmapEncoder(iface);
824     HRESULT hr;
825 
826     TRACE("(%p)\n", iface);
827 
828     EnterCriticalSection(&This->lock);
829 
830     if (This->committed || This->uncommitted_frame)
831         hr = WINCODEC_ERR_WRONGSTATE;
832     else
833     {
834         hr = encoder_commit_file(This->encoder);
835         if (SUCCEEDED(hr))
836             This->committed = TRUE;
837     }
838 
839     LeaveCriticalSection(&This->lock);
840 
841     return hr;
842 }
843 
CommonEncoder_GetMetadataQueryWriter(IWICBitmapEncoder * iface,IWICMetadataQueryWriter ** ppIMetadataQueryWriter)844 static HRESULT WINAPI CommonEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
845     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
846 {
847     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
848     return E_NOTIMPL;
849 }
850 
851 static const IWICBitmapEncoderVtbl CommonEncoder_Vtbl = {
852     CommonEncoder_QueryInterface,
853     CommonEncoder_AddRef,
854     CommonEncoder_Release,
855     CommonEncoder_Initialize,
856     CommonEncoder_GetContainerFormat,
857     CommonEncoder_GetEncoderInfo,
858     CommonEncoder_SetColorContexts,
859     CommonEncoder_SetPalette,
860     CommonEncoder_SetThumbnail,
861     CommonEncoder_SetPreview,
862     CommonEncoder_CreateNewFrame,
863     CommonEncoder_Commit,
864     CommonEncoder_GetMetadataQueryWriter
865 };
866 
CommonEncoder_CreateInstance(struct encoder * encoder,const struct encoder_info * encoder_info,REFIID iid,void ** ppv)867 HRESULT CommonEncoder_CreateInstance(struct encoder *encoder,
868     const struct encoder_info *encoder_info, REFIID iid, void** ppv)
869 {
870     CommonEncoder *This;
871     HRESULT ret;
872 
873     TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
874 
875     *ppv = NULL;
876 
877     This = malloc(sizeof(CommonEncoder));
878     if (!This)
879     {
880         encoder_destroy(encoder);
881         return E_OUTOFMEMORY;
882     }
883 
884     This->IWICBitmapEncoder_iface.lpVtbl = &CommonEncoder_Vtbl;
885     This->ref = 1;
886     This->stream = NULL;
887     This->encoder = encoder;
888     This->encoder_info = *encoder_info;
889     This->frame_count = 0;
890     This->uncommitted_frame = FALSE;
891     This->committed = FALSE;
892 #ifdef __REACTOS__
893     InitializeCriticalSection(&This->lock);
894 #else
895     InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
896 #endif
897     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CommonEncoder.lock");
898 
899     ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
900     IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
901 
902     return ret;
903 }
904