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