mfplat: Add MFCreateAMMediaTypeFromMFMediaType stub.
[wine.git] / dlls / ir50_32 / ir50.c
blob65c93f7fe5e74e3dcee727cc08f50ba89310863e
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;
148 unsigned int stride;
150 TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out);
152 if ( !decoder )
153 return ICERR_BADPARAM;
155 if ( out->bmiHeader.biBitCount == 32 )
156 output_subtype = &MFVideoFormat_RGB32;
157 else if ( out->bmiHeader.biBitCount == 24 )
158 output_subtype = &MFVideoFormat_RGB24;
159 else if ( out->bmiHeader.biBitCount == 16 )
160 output_subtype = &MFVideoFormat_RGB555;
161 else
162 return ICERR_BADFORMAT;
164 stride = (out->bmiHeader.biWidth + 3) & ~3;
165 if (out->bmiHeader.biHeight >= 0)
166 stride = -stride;
168 if ( FAILED(MFCreateMediaType( &input_type )) )
169 return ICERR_INTERNAL;
171 if ( FAILED(MFCreateMediaType( &output_type )) )
173 IMFMediaType_Release( input_type );
174 return ICERR_INTERNAL;
177 if ( FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) ||
178 FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_SUBTYPE, &MFVideoFormat_IV50 )) )
179 goto done;
180 if ( FAILED(IMFMediaType_SetUINT64(
181 input_type, &MF_MT_FRAME_SIZE,
182 make_uint64( in->bmiHeader.biWidth, in->bmiHeader.biHeight ) )) )
183 goto done;
185 if ( FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) ||
186 FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_SUBTYPE, output_subtype )) )
187 goto done;
188 if ( FAILED(IMFMediaType_SetUINT64(
189 output_type, &MF_MT_FRAME_SIZE,
190 make_uint64( out->bmiHeader.biWidth, abs(out->bmiHeader.biHeight) ) )) )
191 goto done;
192 if ( FAILED(IMFMediaType_SetUINT32( output_type, &MF_MT_DEFAULT_STRIDE, stride)) )
193 goto done;
195 if ( FAILED(IMFTransform_SetInputType( decoder, 0, input_type, 0 )) ||
196 FAILED(IMFTransform_SetOutputType( decoder, 0, output_type, 0 )) )
197 goto done;
199 r = ICERR_OK;
201 done:
202 IMFMediaType_Release( input_type );
203 IMFMediaType_Release( output_type );
204 return r;
207 static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size )
209 IMFSample *in_sample = NULL, *out_sample = NULL;
210 IMFMediaBuffer *in_buf = NULL, *out_buf = NULL;
211 MFT_OUTPUT_DATA_BUFFER mft_buf;
212 DWORD mft_status;
213 BYTE *data;
214 HRESULT hr;
215 LRESULT r = ICERR_INTERNAL;
217 TRACE("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size);
219 if ( FAILED(MFCreateSample( &in_sample )) )
220 return ICERR_INTERNAL;
222 if ( FAILED(MFCreateMemoryBuffer( icd->lpbiInput->biSizeImage, &in_buf )) )
223 goto done;
225 if ( FAILED(IMFSample_AddBuffer( in_sample, in_buf )) )
226 goto done;
228 if ( FAILED(MFCreateSample( &out_sample )) )
229 goto done;
231 if ( FAILED(MFCreateMemoryBuffer( icd->lpbiOutput->biSizeImage, &out_buf )) )
232 goto done;
234 if ( FAILED(IMFSample_AddBuffer( out_sample, out_buf )) )
235 goto done;
237 if ( FAILED(IMFMediaBuffer_Lock( in_buf, &data, NULL, NULL )))
238 goto done;
240 memcpy( data, icd->lpInput, icd->lpbiInput->biSizeImage );
242 if ( FAILED(IMFMediaBuffer_Unlock( in_buf )) )
243 goto done;
245 if ( FAILED(IMFMediaBuffer_SetCurrentLength( in_buf, icd->lpbiInput->biSizeImage )) )
246 goto done;
248 if ( FAILED(IMFTransform_ProcessInput( decoder, 0, in_sample, 0 )) )
249 goto done;
251 memset( &mft_buf, 0, sizeof(mft_buf) );
252 mft_buf.pSample = out_sample;
254 hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status );
255 if ( SUCCEEDED(hr) && (mft_status & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE) )
256 hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status );
258 if ( SUCCEEDED(hr) )
260 LONG width = icd->lpbiOutput->biWidth * (icd->lpbiOutput->biBitCount / 8);
261 LONG height = abs( icd->lpbiOutput->biHeight );
262 LONG stride = (width + 3) & ~3;
263 BYTE *output = (BYTE *)icd->lpOutput;
265 if ( FAILED(IMFMediaBuffer_Lock( out_buf, &data, NULL, NULL )))
266 goto done;
268 MFCopyImage( output, stride, data, stride, width, height );
270 IMFMediaBuffer_Unlock( out_buf );
271 r = ICERR_OK;
273 else if ( hr == MF_E_TRANSFORM_NEED_MORE_INPUT )
275 TRACE("no output received.\n");
276 r = ICERR_OK;
279 done:
280 if ( in_buf )
281 IMFMediaBuffer_Release( in_buf );
282 if ( in_sample )
283 IMFSample_Release( in_sample );
284 if ( out_buf )
285 IMFMediaBuffer_Release( out_buf );
286 if ( out_sample )
287 IMFSample_Release( out_sample );
289 return r;
292 static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize )
294 TRACE("ICM_GETINFO %p %lu\n", icinfo, dwSize);
296 if ( !icinfo ) return sizeof(ICINFO);
297 if ( dwSize < sizeof(ICINFO) ) return 0;
299 icinfo->dwSize = sizeof(ICINFO);
300 icinfo->fccType = ICTYPE_VIDEO;
301 icinfo->fccHandler = IV50_MAGIC;
302 icinfo->dwFlags = 0;
303 icinfo->dwVersion = ICVERSION;
304 icinfo->dwVersionICM = ICVERSION;
306 LoadStringW( IR50_32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName) );
307 LoadStringW( IR50_32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription) );
308 /* msvfw32 will fill icinfo->szDriver for us */
310 return sizeof(ICINFO);
313 /***********************************************************************
314 * DriverProc (IR50_32.@)
316 LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg,
317 LPARAM lParam1, LPARAM lParam2 )
319 IMFTransform *decoder = (IMFTransform *) dwDriverId;
320 LRESULT r = ICERR_UNSUPPORTED;
322 TRACE("%Id %p %04x %08Ix %08Ix\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
324 switch( msg )
326 case DRV_LOAD:
327 TRACE("DRV_LOAD\n");
328 r = 1;
329 break;
331 case DRV_OPEN:
332 r = IV50_Open((ICINFO *)lParam2);
333 break;
335 case DRV_CLOSE:
336 TRACE("DRV_CLOSE\n");
337 if ( decoder )
338 IMFTransform_Release( decoder );
339 r = 1;
340 break;
342 case DRV_ENABLE:
343 case DRV_DISABLE:
344 case DRV_FREE:
345 break;
347 case ICM_GETINFO:
348 r = IV50_GetInfo( (ICINFO *) lParam1, (DWORD) lParam2 );
349 break;
351 case ICM_DECOMPRESS_QUERY:
352 r = IV50_DecompressQuery( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 );
353 break;
355 case ICM_DECOMPRESS_GET_FORMAT:
356 r = IV50_DecompressGetFormat( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 );
357 break;
359 case ICM_DECOMPRESS_GET_PALETTE:
360 FIXME("ICM_DECOMPRESS_GET_PALETTE\n");
361 break;
363 case ICM_DECOMPRESS:
364 r = IV50_Decompress( decoder, (ICDECOMPRESS *) lParam1, (DWORD) lParam2 );
365 break;
367 case ICM_DECOMPRESS_BEGIN:
368 r = IV50_DecompressBegin( decoder, (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 );
369 break;
371 case ICM_DECOMPRESS_END:
372 r = ICERR_UNSUPPORTED;
373 break;
375 case ICM_DECOMPRESSEX_QUERY:
376 FIXME("ICM_DECOMPRESSEX_QUERY\n");
377 break;
379 case ICM_DECOMPRESSEX:
380 FIXME("ICM_DECOMPRESSEX\n");
381 break;
383 case ICM_COMPRESS_QUERY:
384 r = ICERR_BADFORMAT;
385 /* fall through */
386 case ICM_COMPRESS_GET_FORMAT:
387 case ICM_COMPRESS_END:
388 case ICM_COMPRESS:
389 FIXME("compression not implemented\n");
390 break;
392 case ICM_CONFIGURE:
393 break;
395 default:
396 FIXME("Unknown message: %04x %Id %Id\n", msg, lParam1, lParam2);
399 return r;
402 /***********************************************************************
403 * DllMain
405 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
407 TRACE("(%p,%lu,%p)\n", hModule, dwReason, lpReserved);
409 switch (dwReason)
411 case DLL_PROCESS_ATTACH:
412 DisableThreadLibraryCalls(hModule);
413 IR50_32_hModule = hModule;
414 break;
416 return TRUE;