wineps: Handle EMR_INVERTRGN record in spool files.
[wine.git] / dlls / ir50_32 / ir50.c
blobccd7f2457728b56bca4d66bd788bca4a58f9d88f
1 /*
2 * Intel Indeo 5 Video Decoder
3 * Copyright 2023 Shaun Ren for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "commdlg.h"
28 #include "vfw.h"
29 #include "initguid.h"
30 #include "ir50_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(ir50_32);
36 static HINSTANCE IR50_32_hModule;
38 #define IV50_MAGIC mmioFOURCC('I','V','5','0')
39 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
41 DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0'));
43 static inline UINT64
44 make_uint64( UINT32 high, UINT32 low )
46 return ((UINT64)high << 32) | low;
50 static LRESULT
51 IV50_Open( const ICINFO *icinfo )
53 IMFTransform *decoder = NULL;
55 TRACE("DRV_OPEN %p\n", icinfo);
57 if ( icinfo && compare_fourcc( icinfo->fccType, ICTYPE_VIDEO ) )
58 return 0;
60 if ( FAILED(winegstreamer_create_video_decoder( &decoder )) )
61 return 0;
63 return (LRESULT)decoder;
66 static LRESULT
67 IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out )
69 TRACE("ICM_DECOMPRESS_QUERY %p %p\n", in, out);
71 TRACE("in->planes = %d\n", in->bmiHeader.biPlanes);
72 TRACE("in->bpp = %d\n", in->bmiHeader.biBitCount);
73 TRACE("in->height = %ld\n", in->bmiHeader.biHeight);
74 TRACE("in->width = %ld\n", in->bmiHeader.biWidth);
75 TRACE("in->compr = %#lx\n", in->bmiHeader.biCompression);
77 if ( in->bmiHeader.biCompression != IV50_MAGIC )
79 TRACE("can't do %#lx compression\n", in->bmiHeader.biCompression);
80 return ICERR_BADFORMAT;
83 /* output must be same dimensions as input */
84 if ( out )
86 TRACE("out->planes = %d\n", out->bmiHeader.biPlanes);
87 TRACE("out->bpp = %d\n", out->bmiHeader.biBitCount);
88 TRACE("out->height = %ld\n", out->bmiHeader.biHeight);
89 TRACE("out->width = %ld\n", out->bmiHeader.biWidth);
90 TRACE("out->compr = %#lx\n", out->bmiHeader.biCompression);
92 if ( out->bmiHeader.biCompression != BI_RGB )
94 TRACE("incompatible compression requested\n");
95 return ICERR_BADFORMAT;
98 if ( out->bmiHeader.biBitCount != 32 && out->bmiHeader.biBitCount != 24 && out->bmiHeader.biBitCount != 16 )
100 TRACE("incompatible depth requested\n");
101 return ICERR_BADFORMAT;
104 if ( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes ||
105 in->bmiHeader.biHeight != abs(out->bmiHeader.biHeight) ||
106 in->bmiHeader.biWidth != out->bmiHeader.biWidth )
108 TRACE("incompatible output dimensions requested\n");
109 return ICERR_BADFORMAT;
113 return ICERR_OK;
116 static LRESULT
117 IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out )
119 DWORD size;
121 TRACE("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out);
123 if ( !in )
124 return ICERR_BADPARAM;
126 if ( in->bmiHeader.biCompression != IV50_MAGIC )
127 return ICERR_BADFORMAT;
129 size = in->bmiHeader.biSize;
130 if ( out )
132 memcpy( out, in, size );
133 out->bmiHeader.biHeight = abs(in->bmiHeader.biHeight);
134 out->bmiHeader.biCompression = BI_RGB;
135 out->bmiHeader.biBitCount = 32;
136 out->bmiHeader.biSizeImage = out->bmiHeader.biWidth * out->bmiHeader.biHeight * 4;
137 return ICERR_OK;
140 return size;
143 static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out )
145 IMFMediaType *input_type, *output_type;
146 const GUID *output_subtype;
147 LRESULT r = ICERR_INTERNAL;
149 TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out);
151 if ( !decoder )
152 return ICERR_BADPARAM;
154 if ( out->bmiHeader.biBitCount == 32 )
155 output_subtype = &MFVideoFormat_RGB32;
156 else if ( out->bmiHeader.biBitCount == 24 )
157 output_subtype = &MFVideoFormat_RGB24;
158 else if ( out->bmiHeader.biBitCount == 16 )
159 output_subtype = &MFVideoFormat_RGB555;
160 else
161 return ICERR_BADFORMAT;
163 if ( FAILED(MFCreateMediaType( &input_type )) )
164 return ICERR_INTERNAL;
166 if ( FAILED(MFCreateMediaType( &output_type )) )
168 IMFMediaType_Release( input_type );
169 return ICERR_INTERNAL;
172 if ( FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) ||
173 FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_SUBTYPE, &MFVideoFormat_IV50 )) )
174 goto done;
175 if ( FAILED(IMFMediaType_SetUINT64(
176 input_type, &MF_MT_FRAME_SIZE,
177 make_uint64( in->bmiHeader.biWidth, in->bmiHeader.biHeight ) )) )
178 goto done;
180 if ( FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) ||
181 FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_SUBTYPE, output_subtype )) )
182 goto done;
183 if ( FAILED(IMFMediaType_SetUINT64(
184 output_type, &MF_MT_FRAME_SIZE,
185 make_uint64( out->bmiHeader.biWidth, abs(out->bmiHeader.biHeight) ) )) )
186 goto done;
188 if ( FAILED(IMFTransform_SetInputType( decoder, 0, input_type, 0 )) ||
189 FAILED(IMFTransform_SetOutputType( decoder, 0, output_type, 0 )) )
190 goto done;
192 r = ICERR_OK;
194 done:
195 IMFMediaType_Release( input_type );
196 IMFMediaType_Release( output_type );
197 return r;
200 static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size )
202 IMFSample *in_sample = NULL, *out_sample = NULL;
203 IMFMediaBuffer *in_buf = NULL, *out_buf = NULL;
204 MFT_OUTPUT_DATA_BUFFER mft_buf;
205 DWORD mft_status;
206 BYTE *data;
207 HRESULT hr;
208 LRESULT r = ICERR_INTERNAL;
210 TRACE("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size);
212 if ( FAILED(MFCreateSample( &in_sample )) )
213 return ICERR_INTERNAL;
215 if ( FAILED(MFCreateMemoryBuffer( icd->lpbiInput->biSizeImage, &in_buf )) )
216 goto done;
218 if ( FAILED(IMFSample_AddBuffer( in_sample, in_buf )) )
219 goto done;
221 if ( FAILED(MFCreateSample( &out_sample )) )
222 goto done;
224 if ( FAILED(MFCreateMemoryBuffer( icd->lpbiOutput->biSizeImage, &out_buf )) )
225 goto done;
227 if ( FAILED(IMFSample_AddBuffer( out_sample, out_buf )) )
228 goto done;
230 if ( FAILED(IMFMediaBuffer_Lock( in_buf, &data, NULL, NULL )))
231 goto done;
233 memcpy( data, icd->lpInput, icd->lpbiInput->biSizeImage );
235 if ( FAILED(IMFMediaBuffer_Unlock( in_buf )) )
236 goto done;
238 if ( FAILED(IMFMediaBuffer_SetCurrentLength( in_buf, icd->lpbiInput->biSizeImage )) )
239 goto done;
241 if ( FAILED(IMFTransform_ProcessInput( decoder, 0, in_sample, 0 )) )
242 goto done;
244 memset( &mft_buf, 0, sizeof(mft_buf) );
245 mft_buf.pSample = out_sample;
247 hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status );
248 if ( SUCCEEDED(hr) && (mft_status & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE) )
249 hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status );
251 if ( SUCCEEDED(hr) )
253 LONG width = icd->lpbiOutput->biWidth * (icd->lpbiOutput->biBitCount / 8);
254 LONG height = abs( icd->lpbiOutput->biHeight );
255 LONG data_stride = (width + 3) & ~3;
256 LONG out_stride = icd->lpbiOutput->biHeight >= 0 ? -data_stride : data_stride;
257 BYTE *output_start = (BYTE *)icd->lpOutput;
259 if (out_stride < 0)
260 output_start += (height - 1) * abs(out_stride);
262 if ( FAILED(IMFMediaBuffer_Lock( out_buf, &data, NULL, NULL )))
263 goto done;
265 MFCopyImage( output_start, out_stride, data, data_stride, width, height );
267 IMFMediaBuffer_Unlock( out_buf );
268 r = ICERR_OK;
270 else if ( hr == MF_E_TRANSFORM_NEED_MORE_INPUT )
272 TRACE("no output received.\n");
273 r = ICERR_OK;
276 done:
277 if ( in_buf )
278 IMFMediaBuffer_Release( in_buf );
279 if ( in_sample )
280 IMFSample_Release( in_sample );
281 if ( out_buf )
282 IMFMediaBuffer_Release( out_buf );
283 if ( out_sample )
284 IMFSample_Release( out_sample );
286 return r;
289 static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize )
291 TRACE("ICM_GETINFO %p %lu\n", icinfo, dwSize);
293 if ( !icinfo ) return sizeof(ICINFO);
294 if ( dwSize < sizeof(ICINFO) ) return 0;
296 icinfo->dwSize = sizeof(ICINFO);
297 icinfo->fccType = ICTYPE_VIDEO;
298 icinfo->fccHandler = IV50_MAGIC;
299 icinfo->dwFlags = 0;
300 icinfo->dwVersion = ICVERSION;
301 icinfo->dwVersionICM = ICVERSION;
303 LoadStringW( IR50_32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName) );
304 LoadStringW( IR50_32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription) );
305 /* msvfw32 will fill icinfo->szDriver for us */
307 return sizeof(ICINFO);
310 /***********************************************************************
311 * DriverProc (IR50_32.@)
313 LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg,
314 LPARAM lParam1, LPARAM lParam2 )
316 IMFTransform *decoder = (IMFTransform *) dwDriverId;
317 LRESULT r = ICERR_UNSUPPORTED;
319 TRACE("%Id %p %04x %08Ix %08Ix\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
321 switch( msg )
323 case DRV_LOAD:
324 TRACE("DRV_LOAD\n");
325 r = 1;
326 break;
328 case DRV_OPEN:
329 r = IV50_Open((ICINFO *)lParam2);
330 break;
332 case DRV_CLOSE:
333 TRACE("DRV_CLOSE\n");
334 if ( decoder )
335 IMFTransform_Release( decoder );
336 r = 1;
337 break;
339 case DRV_ENABLE:
340 case DRV_DISABLE:
341 case DRV_FREE:
342 break;
344 case ICM_GETINFO:
345 r = IV50_GetInfo( (ICINFO *) lParam1, (DWORD) lParam2 );
346 break;
348 case ICM_DECOMPRESS_QUERY:
349 r = IV50_DecompressQuery( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 );
350 break;
352 case ICM_DECOMPRESS_GET_FORMAT:
353 r = IV50_DecompressGetFormat( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 );
354 break;
356 case ICM_DECOMPRESS_GET_PALETTE:
357 FIXME("ICM_DECOMPRESS_GET_PALETTE\n");
358 break;
360 case ICM_DECOMPRESS:
361 r = IV50_Decompress( decoder, (ICDECOMPRESS *) lParam1, (DWORD) lParam2 );
362 break;
364 case ICM_DECOMPRESS_BEGIN:
365 r = IV50_DecompressBegin( decoder, (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 );
366 break;
368 case ICM_DECOMPRESS_END:
369 r = ICERR_UNSUPPORTED;
370 break;
372 case ICM_DECOMPRESSEX_QUERY:
373 FIXME("ICM_DECOMPRESSEX_QUERY\n");
374 break;
376 case ICM_DECOMPRESSEX:
377 FIXME("ICM_DECOMPRESSEX\n");
378 break;
380 case ICM_COMPRESS_QUERY:
381 r = ICERR_BADFORMAT;
382 /* fall through */
383 case ICM_COMPRESS_GET_FORMAT:
384 case ICM_COMPRESS_END:
385 case ICM_COMPRESS:
386 FIXME("compression not implemented\n");
387 break;
389 case ICM_CONFIGURE:
390 break;
392 default:
393 FIXME("Unknown message: %04x %Id %Id\n", msg, lParam1, lParam2);
396 return r;
399 /***********************************************************************
400 * DllMain
402 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
404 TRACE("(%p,%lu,%p)\n", hModule, dwReason, lpReserved);
406 switch (dwReason)
408 case DLL_PROCESS_ATTACH:
409 DisableThreadLibraryCalls(hModule);
410 IR50_32_hModule = hModule;
411 break;
413 return TRUE;