[svn] / trunk / xvidcore / dshow / src / CXvidDecoder.cpp Repository:
ViewVC logotype

Annotation of /trunk/xvidcore/dshow/src/CXvidDecoder.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1899 - (view) (download)

1 : edgomez 1384 /*****************************************************************************
2 :     *
3 :     * XVID MPEG-4 VIDEO CODEC
4 : Isibaar 1896 * - Xvid Decoder part of the DShow Filter -
5 : edgomez 1384 *
6 : Isibaar 1896 * Copyright(C) 2002-2010 Peter Ross <pross@xvid.org>
7 :     * 2003-2010 Michael Militzer <michael@xvid.org>
8 : edgomez 1384 *
9 :     * This program is free software ; you can redistribute it and/or modify
10 :     * it under the terms of the GNU General Public License as published by
11 :     * the Free Software Foundation ; either version 2 of the License, or
12 :     * (at your option) any later version.
13 :     *
14 :     * This program is distributed in the hope that it will be useful,
15 :     * but WITHOUT ANY WARRANTY ; without even the implied warranty of
16 :     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 :     * GNU General Public License for more details.
18 :     *
19 :     * You should have received a copy of the GNU General Public License
20 :     * along with this program ; if not, write to the Free Software
21 :     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 :     *
23 : Isibaar 1899 * $Id: CXvidDecoder.cpp,v 1.21 2010-10-17 18:36:12 Isibaar Exp $
24 : edgomez 1384 *
25 :     ****************************************************************************/
26 :    
27 :     /****************************************************************************
28 :     *
29 :     * 2003/12/11 - added some additional options, mainly to make the deblocking
30 :     * code from xvidcore available. Most of the new code is taken
31 :     * from Nic's dshow filter, (C) Nic, http://nic.dnsalias.com
32 :     *
33 :     ****************************************************************************/
34 :    
35 :     /*
36 :     this requires the directx sdk
37 :     place these paths at the top of the Tools|Options|Directories list
38 :    
39 :     headers:
40 : suxen_drol 1521 C:\DX90SDK\Include
41 :     C:\DX90SDK\Samples\C++\DirectShow\BaseClasses
42 : edgomez 1384
43 : suxen_drol 1521 C:\DX90SDK\Samples\C++\DirectShow\BaseClasses\Release
44 :     C:\DX90SDK\Samples\C++\DirectShow\BaseClasses\Debug
45 : edgomez 1384 */
46 :    
47 : Isibaar 1899 #define XVID_USE_MFT
48 :     #define XVID_USE_TRAYICON
49 : edgomez 1384
50 :     #include <windows.h>
51 :    
52 :     #include <streams.h>
53 :     #include <initguid.h>
54 :     #include <olectl.h>
55 :     #if (1100 > _MSC_VER)
56 :     #include <olectlid.h>
57 :     #endif
58 :     #include <dvdmedia.h> // VIDEOINFOHEADER2
59 :    
60 : Isibaar 1898 #if defined(XVID_USE_MFT)
61 :     #define MFT_UNIQUE_METHOD_NAMES
62 :     #include <mftransform.h>
63 :     #include <mfapi.h>
64 :     #include <mferror.h>
65 :     #include <shlwapi.h>
66 :     #endif
67 :    
68 : Isibaar 1896 #include <shellapi.h>
69 : edgomez 1384
70 : Isibaar 1896 #include <xvid.h> // Xvid API
71 :    
72 :     #include "resource.h"
73 :    
74 : edgomez 1384 #include "IXvidDecoder.h"
75 :     #include "CXvidDecoder.h"
76 :     #include "CAbout.h"
77 :     #include "config.h"
78 :     #include "debug.h"
79 :    
80 :     static bool USE_IYUV;
81 :     static bool USE_YV12;
82 :     static bool USE_YUY2;
83 :     static bool USE_YVYU;
84 :     static bool USE_UYVY;
85 :     static bool USE_RGB32;
86 :     static bool USE_RGB24;
87 :     static bool USE_RG555;
88 :     static bool USE_RG565;
89 :    
90 :     const AMOVIESETUP_MEDIATYPE sudInputPinTypes[] =
91 :     {
92 :     { &MEDIATYPE_Video, &CLSID_XVID },
93 :     { &MEDIATYPE_Video, &CLSID_XVID_UC },
94 :     { &MEDIATYPE_Video, &CLSID_DIVX },
95 :     { &MEDIATYPE_Video, &CLSID_DIVX_UC },
96 :     { &MEDIATYPE_Video, &CLSID_DX50 },
97 :     { &MEDIATYPE_Video, &CLSID_DX50_UC },
98 :     { &MEDIATYPE_Video, &CLSID_MP4V },
99 : suxen_drol 1647 { &MEDIATYPE_Video, &CLSID_MP4V_UC },
100 : edgomez 1384 };
101 :    
102 :     const AMOVIESETUP_MEDIATYPE sudOutputPinTypes[] =
103 :     {
104 :     { &MEDIATYPE_Video, &MEDIASUBTYPE_NULL }
105 :     };
106 :    
107 :    
108 :     const AMOVIESETUP_PIN psudPins[] =
109 :     {
110 :     {
111 :     L"Input", // String pin name
112 :     FALSE, // Is it rendered
113 :     FALSE, // Is it an output
114 :     FALSE, // Allowed none
115 :     FALSE, // Allowed many
116 :     &CLSID_NULL, // Connects to filter
117 :     L"Output", // Connects to pin
118 :     sizeof(sudInputPinTypes) / sizeof(AMOVIESETUP_MEDIATYPE), // Number of types
119 :     &sudInputPinTypes[0] // The pin details
120 :     },
121 :     {
122 :     L"Output", // String pin name
123 :     FALSE, // Is it rendered
124 :     TRUE, // Is it an output
125 :     FALSE, // Allowed none
126 :     FALSE, // Allowed many
127 :     &CLSID_NULL, // Connects to filter
128 :     L"Input", // Connects to pin
129 :     sizeof(sudOutputPinTypes) / sizeof(AMOVIESETUP_MEDIATYPE), // Number of types
130 :     sudOutputPinTypes // The pin details
131 :     }
132 :     };
133 :    
134 :    
135 :     const AMOVIESETUP_FILTER sudXvidDecoder =
136 :     {
137 :     &CLSID_XVID, // Filter CLSID
138 :     XVID_NAME_L, // Filter name
139 :     MERIT_PREFERRED, // Its merit
140 :     sizeof(psudPins) / sizeof(AMOVIESETUP_PIN), // Number of pins
141 :     psudPins // Pin details
142 :     };
143 :    
144 :    
145 :     // List of class IDs and creator functions for the class factory. This
146 :     // provides the link between the OLE entry point in the DLL and an object
147 :     // being created. The class factory will call the static CreateInstance
148 :    
149 :     CFactoryTemplate g_Templates[] =
150 :     {
151 :     {
152 :     XVID_NAME_L,
153 :     &CLSID_XVID,
154 :     CXvidDecoder::CreateInstance,
155 :     NULL,
156 :     &sudXvidDecoder
157 :     },
158 :     {
159 :     XVID_NAME_L L"About",
160 :     &CLSID_CABOUT,
161 :     CAbout::CreateInstance
162 :     }
163 :    
164 :     };
165 :    
166 :     /* note: g_cTemplates must be global; used by strmbase.lib(dllentry.cpp,dllsetup.cpp) */
167 :     int g_cTemplates = sizeof(g_Templates) / sizeof(CFactoryTemplate);
168 :    
169 : Isibaar 1896 #ifdef XVID_USE_TRAYICON
170 :     extern HINSTANCE g_xvid_hInst;
171 : edgomez 1384
172 : Isibaar 1896 static int GUI_Page = 0;
173 :     extern "C" void CALLBACK Configure(HWND hWndParent, HINSTANCE hInstParent, LPSTR lpCmdLine, int nCmdShow );
174 :    
175 :     LRESULT CALLBACK msg_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
176 :     {
177 :     switch ( uMsg )
178 :     {
179 :     case WM_ICONMESSAGE:
180 :     switch(lParam)
181 :     {
182 :     case WM_LBUTTONDBLCLK:
183 :     if (!GUI_Page) {
184 :     GUI_Page = 1;
185 :     Configure(hwnd, g_xvid_hInst, "", 1);
186 :     GUI_Page = 0;
187 :     }
188 :     break;
189 :     default:
190 :     return DefWindowProc(hwnd, uMsg, wParam, lParam);
191 :     };
192 :     break;
193 :    
194 :     default:
195 :     return DefWindowProc(hwnd, uMsg, wParam, lParam);
196 :     }
197 :    
198 :     return TRUE; /* ok */
199 :     }
200 :     #endif
201 :    
202 : edgomez 1384 STDAPI DllRegisterServer()
203 :     {
204 : Isibaar 1898 #if defined(XVID_USE_MFT)
205 :     int inputs_num = sizeof(sudInputPinTypes) / sizeof(AMOVIESETUP_MEDIATYPE);
206 :     int outputs_num = sizeof(sudOutputPinTypes) / sizeof(AMOVIESETUP_MEDIATYPE);
207 :     MFT_REGISTER_TYPE_INFO * mft_bs = new MFT_REGISTER_TYPE_INFO[inputs_num];
208 :     MFT_REGISTER_TYPE_INFO * mft_csp = new MFT_REGISTER_TYPE_INFO[outputs_num];
209 :    
210 :     {
211 :     int i;
212 :     for(i=0;i<inputs_num;i++) {
213 :     mft_bs[i].guidMajorType = *sudInputPinTypes[i].clsMajorType;
214 :     mft_bs[i].guidSubtype = *sudInputPinTypes[i].clsMinorType;
215 :     }
216 :     for(i=0;i<outputs_num;i++) {
217 :     mft_csp[i].guidMajorType = *sudOutputPinTypes[i].clsMajorType;
218 :     mft_csp[i].guidSubtype = *sudOutputPinTypes[i].clsMinorType; // MFT and AM GUIDs really the same?
219 :     }
220 :     }
221 :    
222 :     /* Register the MFT decoder */
223 :     MFTRegister(CLSID_XVID, // CLSID
224 :     MFT_CATEGORY_VIDEO_DECODER, // Category
225 :     const_cast<LPWSTR>(XVID_NAME_L), // Friendly name
226 :     0, // Flags
227 :     inputs_num, // Number of input types
228 :     mft_bs, // Input types
229 :     outputs_num, // Number of output types
230 :     mft_csp, // Output types
231 :     NULL // Attributes (optional)
232 :     );
233 :    
234 :     delete[] mft_bs;
235 :     delete[] mft_csp;
236 :     #endif /* XVID_USE_MFT */
237 :    
238 : edgomez 1384 return AMovieDllRegisterServer2( TRUE );
239 :     }
240 :    
241 :    
242 :     STDAPI DllUnregisterServer()
243 :     {
244 : Isibaar 1898 #if defined(XVID_USE_MFT)
245 :     MFTUnregister(CLSID_XVID);
246 :     #endif
247 : edgomez 1384 return AMovieDllRegisterServer2( FALSE );
248 :     }
249 :    
250 :    
251 :     /* create instance */
252 :    
253 :     CUnknown * WINAPI CXvidDecoder::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
254 :     {
255 :     CXvidDecoder * pNewObject = new CXvidDecoder(punk, phr);
256 :     if (pNewObject == NULL)
257 :     {
258 :     *phr = E_OUTOFMEMORY;
259 :     }
260 :     return pNewObject;
261 :     }
262 :    
263 :    
264 :     /* query interfaces */
265 :    
266 :     STDMETHODIMP CXvidDecoder::NonDelegatingQueryInterface(REFIID riid, void **ppv)
267 :     {
268 :     CheckPointer(ppv, E_POINTER);
269 :    
270 :     if (riid == IID_IXvidDecoder)
271 :     {
272 :     return GetInterface((IXvidDecoder *) this, ppv);
273 :     }
274 :    
275 :     if (riid == IID_ISpecifyPropertyPages)
276 :     {
277 :     return GetInterface((ISpecifyPropertyPages *) this, ppv);
278 :     }
279 :    
280 : Isibaar 1898 #if defined(XVID_USE_MFT)
281 :     if (riid == IID_IMFTransform)
282 :     {
283 :     return GetInterface((IMFTransform *) this, ppv);
284 :     }
285 :     #endif
286 :    
287 : edgomez 1384 return CVideoTransformFilter::NonDelegatingQueryInterface(riid, ppv);
288 :     }
289 :    
290 :    
291 :    
292 :     /* constructor */
293 :    
294 :     #define XVID_DLL_NAME "xvidcore.dll"
295 :    
296 :     CXvidDecoder::CXvidDecoder(LPUNKNOWN punk, HRESULT *phr) :
297 : Isibaar 1605 CVideoTransformFilter(NAME("CXvidDecoder"), punk, CLSID_XVID), m_hdll (NULL)
298 : edgomez 1384 {
299 :     DPRINTF("Constructor");
300 :    
301 : Isibaar 1605 xvid_decore_func = NULL; // Hmm, some strange errors appearing if I try to initialize...
302 :     xvid_global_func = NULL; // ...this in constructor's init-list. So, they assigned here.
303 :    
304 : Isibaar 1896 #ifdef XVID_USE_TRAYICON
305 :     MSG_hwnd = NULL;
306 :     #endif
307 :    
308 : Isibaar 1898 #if defined(XVID_USE_MFT)
309 :     InitializeCriticalSection(&m_mft_lock);
310 :     m_pInputType = NULL;
311 :     m_pOutputType = NULL;
312 :     m_rtFrame = 0;
313 :     m_duration = 0;
314 :     m_discont = 0;
315 :     m_frameRate.Denominator = 1;
316 :     m_frameRate.Numerator = 1;
317 :     #endif
318 :    
319 : Isibaar 1605 LoadRegistryInfo();
320 :    
321 :     *phr = OpenLib();
322 :     }
323 :    
324 :     HRESULT CXvidDecoder::OpenLib()
325 :     {
326 :     DPRINTF("OpenLib");
327 :    
328 :     if (m_hdll != NULL)
329 :     return E_UNEXPECTED; // Seems, that library already opened.
330 :    
331 : edgomez 1384 xvid_gbl_init_t init;
332 :     memset(&init, 0, sizeof(init));
333 :     init.version = XVID_VERSION;
334 :    
335 :     m_hdll = LoadLibrary(XVID_DLL_NAME);
336 :     if (m_hdll == NULL) {
337 :     DPRINTF("dll load failed");
338 : syskin 1498 MessageBox(0, XVID_DLL_NAME " not found","Error", MB_TOPMOST);
339 : Isibaar 1605 return E_FAIL;
340 : edgomez 1384 }
341 :    
342 :     xvid_global_func = (int (__cdecl *)(void *, int, void *, void *))GetProcAddress(m_hdll, "xvid_global");
343 :     if (xvid_global_func == NULL) {
344 : Isibaar 1605 FreeLibrary(m_hdll);
345 :     m_hdll = NULL;
346 : syskin 1498 MessageBox(0, "xvid_global() not found", "Error", MB_TOPMOST);
347 : Isibaar 1605 return E_FAIL;
348 : edgomez 1384 }
349 :    
350 :     xvid_decore_func = (int (__cdecl *)(void *, int, void *, void *))GetProcAddress(m_hdll, "xvid_decore");
351 :     if (xvid_decore_func == NULL) {
352 : Isibaar 1605 xvid_global_func = NULL;
353 :     FreeLibrary(m_hdll);
354 :     m_hdll = NULL;
355 : syskin 1498 MessageBox(0, "xvid_decore() not found", "Error", MB_TOPMOST);
356 : Isibaar 1605 return E_FAIL;
357 : edgomez 1384 }
358 :    
359 :     if (xvid_global_func(0, XVID_GBL_INIT, &init, NULL) < 0)
360 :     {
361 : Isibaar 1605 xvid_global_func = NULL;
362 :     xvid_decore_func = NULL;
363 :     FreeLibrary(m_hdll);
364 :     m_hdll = NULL;
365 : syskin 1498 MessageBox(0, "xvid_global() failed", "Error", MB_TOPMOST);
366 : Isibaar 1605 return E_FAIL;
367 : edgomez 1384 }
368 :    
369 :     memset(&m_create, 0, sizeof(m_create));
370 :     m_create.version = XVID_VERSION;
371 :     m_create.handle = NULL;
372 :    
373 :     memset(&m_frame, 0, sizeof(m_frame));
374 :     m_frame.version = XVID_VERSION;
375 :    
376 :     USE_IYUV = false;
377 :     USE_YV12 = false;
378 :     USE_YUY2 = false;
379 :     USE_YVYU = false;
380 :     USE_UYVY = false;
381 :     USE_RGB32 = false;
382 :     USE_RGB24 = false;
383 :     USE_RG555 = false;
384 :     USE_RG565 = false;
385 :    
386 :     switch ( g_config.nForceColorspace )
387 :     {
388 :     case FORCE_NONE:
389 :     USE_IYUV = true;
390 :     USE_YV12 = true;
391 :     USE_YUY2 = true;
392 :     USE_YVYU = true;
393 :     USE_UYVY = true;
394 :     USE_RGB32 = true;
395 :     USE_RGB24 = true;
396 :     USE_RG555 = true;
397 :     USE_RG565 = true;
398 :     break;
399 :     case FORCE_YV12:
400 :     USE_IYUV = true;
401 :     USE_YV12 = true;
402 :     break;
403 :     case FORCE_YUY2:
404 :     USE_YUY2 = true;
405 :     break;
406 :     case FORCE_RGB24:
407 :     USE_RGB24 = true;
408 :     break;
409 :     case FORCE_RGB32:
410 :     USE_RGB32 = true;
411 :     break;
412 :     }
413 : syskin 1488
414 :     switch (g_config.aspect_ratio)
415 :     {
416 : syskin 1498 case 0:
417 :     case 1:
418 : syskin 1488 break;
419 : syskin 1498 case 2:
420 : syskin 1488 ar_x = 4;
421 :     ar_y = 3;
422 :     break;
423 : syskin 1498 case 3:
424 : syskin 1488 ar_x = 16;
425 :     ar_y = 9;
426 :     break;
427 : syskin 1498 case 4:
428 : syskin 1488 ar_x = 47;
429 :     ar_y = 20;
430 :     break;
431 :     }
432 : Isibaar 1605
433 :     return S_OK;
434 : edgomez 1384 }
435 :    
436 : syskin 1428 void CXvidDecoder::CloseLib()
437 : edgomez 1384 {
438 : Isibaar 1605 DPRINTF("CloseLib");
439 : edgomez 1384
440 : Isibaar 1605 if ((m_create.handle != NULL) && (xvid_decore_func != NULL))
441 :     {
442 : edgomez 1384 xvid_decore_func(m_create.handle, XVID_DEC_DESTROY, 0, 0);
443 :     m_create.handle = NULL;
444 :     }
445 :    
446 : syskin 1428 if (m_hdll != NULL) {
447 : edgomez 1384 FreeLibrary(m_hdll);
448 :     m_hdll = NULL;
449 :     }
450 : Isibaar 1605 xvid_decore_func = NULL;
451 :     xvid_global_func = NULL;
452 : edgomez 1384 }
453 :    
454 : syskin 1428 /* destructor */
455 : edgomez 1384
456 : syskin 1428 CXvidDecoder::~CXvidDecoder()
457 :     {
458 : Isibaar 1605 DPRINTF("Destructor");
459 : syskin 1428 CloseLib();
460 : Isibaar 1896
461 :     #ifdef XVID_USE_TRAYICON
462 :     if (MSG_hwnd != NULL) {
463 :     NOTIFYICONDATA nid;
464 :     nid.cbSize = sizeof(NOTIFYICONDATA);
465 :     nid.hWnd = MSG_hwnd;
466 :     nid.uID = 100;
467 :    
468 :     Shell_NotifyIcon(NIM_DELETE, &nid);
469 :    
470 :     DestroyWindow(MSG_hwnd);
471 :     MSG_hwnd = NULL;
472 :     }
473 :     #endif
474 : Isibaar 1898
475 :     #if defined(XVID_USE_MFT)
476 :     DeleteCriticalSection(&m_mft_lock);
477 :     #endif
478 : syskin 1428 }
479 : edgomez 1384
480 : syskin 1428
481 :    
482 : edgomez 1384 /* check input type */
483 :    
484 :     HRESULT CXvidDecoder::CheckInputType(const CMediaType * mtIn)
485 :     {
486 :     DPRINTF("CheckInputType");
487 :     BITMAPINFOHEADER * hdr;
488 : syskin 1498
489 :     ar_x = ar_y = 0;
490 : edgomez 1384
491 :     if (*mtIn->Type() != MEDIATYPE_Video)
492 :     {
493 :     DPRINTF("Error: Unknown Type");
494 : syskin 1428 CloseLib();
495 : edgomez 1384 return VFW_E_TYPE_NOT_ACCEPTED;
496 :     }
497 :    
498 : Isibaar 1605 if (m_hdll == NULL)
499 :     {
500 :     HRESULT hr = OpenLib();
501 :    
502 :     if (FAILED(hr) || (m_hdll == NULL)) // Paranoid checks.
503 :     return VFW_E_TYPE_NOT_ACCEPTED;
504 :     }
505 :    
506 : edgomez 1384 if (*mtIn->FormatType() == FORMAT_VideoInfo)
507 :     {
508 :     VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) mtIn->Format();
509 :     hdr = &vih->bmiHeader;
510 :     }
511 :     else if (*mtIn->FormatType() == FORMAT_VideoInfo2)
512 :     {
513 :     VIDEOINFOHEADER2 * vih2 = (VIDEOINFOHEADER2 *) mtIn->Format();
514 :     hdr = &vih2->bmiHeader;
515 : syskin 1498 if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1) {
516 : syskin 1488 ar_x = vih2->dwPictAspectRatioX;
517 :     ar_y = vih2->dwPictAspectRatioY;
518 :     }
519 : edgomez 1384 DPRINTF("VIDEOINFOHEADER2 AR: %d:%d", ar_x, ar_y);
520 :     }
521 : suxen_drol 1647 else if (*mtIn->FormatType() == FORMAT_MPEG2Video) {
522 :     MPEG2VIDEOINFO * mpgvi = (MPEG2VIDEOINFO*)mtIn->Format();
523 :     VIDEOINFOHEADER2 * vih2 = &mpgvi->hdr;
524 :     hdr = &vih2->bmiHeader;
525 :     if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1) {
526 :     ar_x = vih2->dwPictAspectRatioX;
527 :     ar_y = vih2->dwPictAspectRatioY;
528 :     }
529 :     DPRINTF("VIDEOINFOHEADER2 AR: %d:%d", ar_x, ar_y);
530 :    
531 :     /* haali media splitter reports VOL information in the format header */
532 :    
533 :     if (mpgvi->cbSequenceHeader>0) {
534 :    
535 :     xvid_dec_stats_t stats;
536 :     memset(&stats, 0, sizeof(stats));
537 :     stats.version = XVID_VERSION;
538 :    
539 :     if (m_create.handle == NULL) {
540 :     if (xvid_decore_func == NULL)
541 :     return E_FAIL;
542 :     if (xvid_decore_func(0, XVID_DEC_CREATE, &m_create, 0) < 0) {
543 :     DPRINTF("*** XVID_DEC_CREATE error");
544 : Isibaar 1868 return E_FAIL;
545 : suxen_drol 1647 }
546 :     }
547 :    
548 :     m_frame.general = 0;
549 :     m_frame.bitstream = (void*)mpgvi->dwSequenceHeader;
550 :     m_frame.length = mpgvi->cbSequenceHeader;
551 :     m_frame.output.csp = XVID_CSP_NULL;
552 :    
553 : Isibaar 1868 int ret = 0;
554 :     if ((ret=xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats)) >= 0) {
555 : suxen_drol 1647 /* honour video dimensions reported in VOL header */
556 :     if (stats.type == XVID_TYPE_VOL) {
557 :     hdr->biWidth = stats.data.vol.width;
558 :     hdr->biHeight = stats.data.vol.height;
559 : Isibaar 1898 }
560 :     }
561 : Isibaar 1868 if (ret == XVID_ERR_MEMORY) return E_FAIL;
562 : Isibaar 1898 }
563 : suxen_drol 1647 }
564 : Isibaar 1898 else
565 :     {
566 : edgomez 1384 DPRINTF("Error: Unknown FormatType");
567 : syskin 1428 CloseLib();
568 : edgomez 1384 return VFW_E_TYPE_NOT_ACCEPTED;
569 : Isibaar 1898 }
570 :     if (hdr->biHeight < 0)
571 :     {
572 :     DPRINTF("colorspace: inverted input format not supported");
573 :     }
574 :    
575 :     m_create.width = hdr->biWidth;
576 :     m_create.height = hdr->biHeight;
577 :    
578 :     switch(hdr->biCompression)
579 :     {
580 : suxen_drol 1647 case FOURCC_mp4v:
581 : edgomez 1384 case FOURCC_MP4V:
582 : syskin 1428 if (!(g_config.supported_4cc & SUPPORT_MP4V)) {
583 :     CloseLib();
584 :     return VFW_E_TYPE_NOT_ACCEPTED;
585 :     }
586 : edgomez 1384 break;
587 :     case FOURCC_DIVX :
588 : syskin 1428 if (!(g_config.supported_4cc & SUPPORT_DIVX)) {
589 :     CloseLib();
590 :     return VFW_E_TYPE_NOT_ACCEPTED;
591 :     }
592 : edgomez 1384 break;
593 :     case FOURCC_DX50 :
594 : syskin 1428 if (!(g_config.supported_4cc & SUPPORT_DX50)) {
595 :     CloseLib();
596 :     return VFW_E_TYPE_NOT_ACCEPTED;
597 :     }
598 : edgomez 1384 case FOURCC_XVID :
599 :     break;
600 :    
601 :    
602 :     default :
603 :     DPRINTF("Unknown fourcc: 0x%08x (%c%c%c%c)",
604 :     hdr->biCompression,
605 :     (hdr->biCompression)&0xff,
606 :     (hdr->biCompression>>8)&0xff,
607 :     (hdr->biCompression>>16)&0xff,
608 :     (hdr->biCompression>>24)&0xff);
609 : syskin 1428 CloseLib();
610 : edgomez 1384 return VFW_E_TYPE_NOT_ACCEPTED;
611 :     }
612 : Isibaar 1890
613 :     m_create.fourcc = hdr->biCompression;
614 :    
615 : edgomez 1384 return S_OK;
616 :     }
617 :    
618 :    
619 :     /* get list of supported output colorspaces */
620 :    
621 :    
622 :     HRESULT CXvidDecoder::GetMediaType(int iPosition, CMediaType *mtOut)
623 :     {
624 :     BITMAPINFOHEADER * bmih;
625 :     DPRINTF("GetMediaType");
626 :    
627 :     if (m_pInput->IsConnected() == FALSE)
628 :     {
629 :     return E_UNEXPECTED;
630 :     }
631 :    
632 :     if (!g_config.videoinfo_compat) {
633 :     VIDEOINFOHEADER2 * vih = (VIDEOINFOHEADER2 *) mtOut->ReallocFormatBuffer(sizeof(VIDEOINFOHEADER2));
634 :     if (vih == NULL) return E_OUTOFMEMORY;
635 :    
636 :     ZeroMemory(vih, sizeof (VIDEOINFOHEADER2));
637 :     bmih = &(vih->bmiHeader);
638 :     mtOut->SetFormatType(&FORMAT_VideoInfo2);
639 :    
640 :     if (ar_x != 0 && ar_y != 0) {
641 :     vih->dwPictAspectRatioX = ar_x;
642 :     vih->dwPictAspectRatioY = ar_y;
643 : syskin 1498 forced_ar = true;
644 : edgomez 1384 } else { // just to be safe
645 :     vih->dwPictAspectRatioX = m_create.width;
646 :     vih->dwPictAspectRatioY = abs(m_create.height);
647 : syskin 1498 forced_ar = false;
648 :     }
649 : edgomez 1384 } else {
650 :    
651 :     VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) mtOut->ReallocFormatBuffer(sizeof(VIDEOINFOHEADER));
652 :     if (vih == NULL) return E_OUTOFMEMORY;
653 :    
654 :     ZeroMemory(vih, sizeof (VIDEOINFOHEADER));
655 :     bmih = &(vih->bmiHeader);
656 :     mtOut->SetFormatType(&FORMAT_VideoInfo);
657 :     }
658 :    
659 :     bmih->biSize = sizeof(BITMAPINFOHEADER);
660 :     bmih->biWidth = m_create.width;
661 :     bmih->biHeight = m_create.height;
662 :     bmih->biPlanes = 1;
663 :    
664 :     if (iPosition < 0) return E_INVALIDARG;
665 :    
666 :     switch(iPosition)
667 :     {
668 :    
669 :     case 0:
670 :     if ( USE_YUY2 )
671 :     {
672 :     bmih->biCompression = MEDIASUBTYPE_YUY2.Data1;
673 :     bmih->biBitCount = 16;
674 :     mtOut->SetSubtype(&MEDIASUBTYPE_YUY2);
675 :     break;
676 :     }
677 :     case 1 :
678 :     if ( USE_YVYU )
679 :     {
680 :     bmih->biCompression = MEDIASUBTYPE_YVYU.Data1;
681 :     bmih->biBitCount = 16;
682 :     mtOut->SetSubtype(&MEDIASUBTYPE_YVYU);
683 :     break;
684 :     }
685 :     case 2 :
686 :     if ( USE_UYVY )
687 :     {
688 :     bmih->biCompression = MEDIASUBTYPE_UYVY.Data1;
689 :     bmih->biBitCount = 16;
690 :     mtOut->SetSubtype(&MEDIASUBTYPE_UYVY);
691 :     break;
692 :     }
693 :     case 3 :
694 :     if ( USE_IYUV )
695 :     {
696 :     bmih->biCompression = CLSID_MEDIASUBTYPE_IYUV.Data1;
697 :     bmih->biBitCount = 12;
698 :     mtOut->SetSubtype(&CLSID_MEDIASUBTYPE_IYUV);
699 :     break;
700 :     }
701 :     case 4 :
702 :     if ( USE_YV12 )
703 :     {
704 :     bmih->biCompression = MEDIASUBTYPE_YV12.Data1;
705 :     bmih->biBitCount = 12;
706 :     mtOut->SetSubtype(&MEDIASUBTYPE_YV12);
707 :     break;
708 :     }
709 :     case 5 :
710 :     if ( USE_RGB32 )
711 :     {
712 :     bmih->biCompression = BI_RGB;
713 :     bmih->biBitCount = 32;
714 :     mtOut->SetSubtype(&MEDIASUBTYPE_RGB32);
715 :     break;
716 :     }
717 :     case 6 :
718 :     if ( USE_RGB24 )
719 :     {
720 :     bmih->biCompression = BI_RGB;
721 :     bmih->biBitCount = 24;
722 :     mtOut->SetSubtype(&MEDIASUBTYPE_RGB24);
723 :     break;
724 :     }
725 :     case 7 :
726 :     if ( USE_RG555 )
727 :     {
728 :     bmih->biCompression = BI_RGB;
729 :     bmih->biBitCount = 16;
730 :     mtOut->SetSubtype(&MEDIASUBTYPE_RGB555);
731 :     break;
732 :     }
733 :     case 8 :
734 :     if ( USE_RG565 )
735 :     {
736 :     bmih->biCompression = BI_RGB;
737 :     bmih->biBitCount = 16;
738 :     mtOut->SetSubtype(&MEDIASUBTYPE_RGB565);
739 :     break;
740 :     }
741 :     default :
742 :     return VFW_S_NO_MORE_ITEMS;
743 :     }
744 :    
745 :     bmih->biSizeImage = GetBitmapSize(bmih);
746 :    
747 :     mtOut->SetType(&MEDIATYPE_Video);
748 :     mtOut->SetTemporalCompression(FALSE);
749 :     mtOut->SetSampleSize(bmih->biSizeImage);
750 :    
751 :     return S_OK;
752 :     }
753 :    
754 :    
755 :     /* (internal function) change colorspace */
756 : suxen_drol 1558 #define CALC_BI_STRIDE(width,bitcount) ((((width * bitcount) + 31) & ~31) >> 3)
757 : edgomez 1384
758 :     HRESULT CXvidDecoder::ChangeColorspace(GUID subtype, GUID formattype, void * format)
759 :     {
760 : suxen_drol 1558 DWORD biWidth;
761 :    
762 : edgomez 1384 if (formattype == FORMAT_VideoInfo)
763 :     {
764 :     VIDEOINFOHEADER * vih = (VIDEOINFOHEADER * )format;
765 : suxen_drol 1558 biWidth = vih->bmiHeader.biWidth;
766 : Isibaar 1898 out_stride = CALC_BI_STRIDE(vih->bmiHeader.biWidth, vih->bmiHeader.biBitCount);
767 : edgomez 1384 rgb_flip = (vih->bmiHeader.biHeight < 0 ? 0 : XVID_CSP_VFLIP);
768 :     }
769 :     else if (formattype == FORMAT_VideoInfo2)
770 :     {
771 :     VIDEOINFOHEADER2 * vih2 = (VIDEOINFOHEADER2 * )format;
772 : suxen_drol 1558 biWidth = vih2->bmiHeader.biWidth;
773 : Isibaar 1898 out_stride = CALC_BI_STRIDE(vih2->bmiHeader.biWidth, vih2->bmiHeader.biBitCount);
774 : edgomez 1384 rgb_flip = (vih2->bmiHeader.biHeight < 0 ? 0 : XVID_CSP_VFLIP);
775 :     }
776 :     else
777 :     {
778 :     return S_FALSE;
779 :     }
780 :    
781 :     if (subtype == CLSID_MEDIASUBTYPE_IYUV)
782 :     {
783 :     DPRINTF("IYUV");
784 :     rgb_flip = 0;
785 :     m_frame.output.csp = XVID_CSP_I420;
786 : Isibaar 1898 out_stride = CALC_BI_STRIDE(biWidth, 8); /* planar format fix */
787 : edgomez 1384 }
788 :     else if (subtype == MEDIASUBTYPE_YV12)
789 :     {
790 :     DPRINTF("YV12");
791 :     rgb_flip = 0;
792 :     m_frame.output.csp = XVID_CSP_YV12;
793 : Isibaar 1898 out_stride = CALC_BI_STRIDE(biWidth, 8); /* planar format fix */
794 : edgomez 1384 }
795 :     else if (subtype == MEDIASUBTYPE_YUY2)
796 :     {
797 :     DPRINTF("YUY2");
798 :     rgb_flip = 0;
799 :     m_frame.output.csp = XVID_CSP_YUY2;
800 :     }
801 :     else if (subtype == MEDIASUBTYPE_YVYU)
802 :     {
803 :     DPRINTF("YVYU");
804 :     rgb_flip = 0;
805 :     m_frame.output.csp = XVID_CSP_YVYU;
806 :     }
807 :     else if (subtype == MEDIASUBTYPE_UYVY)
808 :     {
809 :     DPRINTF("UYVY");
810 :     rgb_flip = 0;
811 :     m_frame.output.csp = XVID_CSP_UYVY;
812 :     }
813 :     else if (subtype == MEDIASUBTYPE_RGB32)
814 :     {
815 :     DPRINTF("RGB32");
816 :     m_frame.output.csp = rgb_flip | XVID_CSP_BGRA;
817 :     }
818 :     else if (subtype == MEDIASUBTYPE_RGB24)
819 :     {
820 :     DPRINTF("RGB24");
821 :     m_frame.output.csp = rgb_flip | XVID_CSP_BGR;
822 :     }
823 :     else if (subtype == MEDIASUBTYPE_RGB555)
824 :     {
825 :     DPRINTF("RGB555");
826 :     m_frame.output.csp = rgb_flip | XVID_CSP_RGB555;
827 :     }
828 :     else if (subtype == MEDIASUBTYPE_RGB565)
829 :     {
830 :     DPRINTF("RGB565");
831 :     m_frame.output.csp = rgb_flip | XVID_CSP_RGB565;
832 :     }
833 :     else if (subtype == GUID_NULL)
834 :     {
835 :     m_frame.output.csp = XVID_CSP_NULL;
836 :     }
837 :     else
838 :     {
839 :     return S_FALSE;
840 :     }
841 :    
842 :     return S_OK;
843 :     }
844 :    
845 :    
846 :     /* set output colorspace */
847 :    
848 :     HRESULT CXvidDecoder::SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt)
849 :     {
850 :     DPRINTF("SetMediaType");
851 :    
852 :     if (direction == PINDIR_OUTPUT)
853 :     {
854 :     return ChangeColorspace(*pmt->Subtype(), *pmt->FormatType(), pmt->Format());
855 :     }
856 :    
857 :     return S_OK;
858 :     }
859 :    
860 :    
861 :     /* check input<->output compatiblity */
862 :    
863 :     HRESULT CXvidDecoder::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
864 :     {
865 :     DPRINTF("CheckTransform");
866 : Isibaar 1896
867 : edgomez 1384 return S_OK;
868 :     }
869 :    
870 : Isibaar 1896 /* input/output pin connection complete */
871 : edgomez 1384
872 : Isibaar 1896 HRESULT CXvidDecoder::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin)
873 :     {
874 :     DPRINTF("CompleteConnect");
875 :    
876 :     #ifdef XVID_USE_TRAYICON
877 :     if ((direction == PINDIR_OUTPUT) && (MSG_hwnd == NULL))
878 :     {
879 :     WNDCLASSEX wc;
880 :    
881 :     wc.cbSize = sizeof(WNDCLASSEX);
882 :     wc.lpfnWndProc = msg_proc;
883 :     wc.style = CS_HREDRAW | CS_VREDRAW;
884 :     wc.cbWndExtra = 0;
885 :     wc.cbClsExtra = 0;
886 :     wc.hInstance = (HINSTANCE) g_xvid_hInst;
887 :     wc.hbrBackground = (HBRUSH) GetStockObject(NULL_BRUSH);
888 :     wc.lpszMenuName = NULL;
889 :     wc.lpszClassName = "XVID_MSG_WINDOW";
890 :     wc.hIcon = NULL;
891 :     wc.hIconSm = NULL;
892 :     wc.hCursor = NULL;
893 :     RegisterClassEx(&wc);
894 :    
895 :     MSG_hwnd = CreateWindowEx(0, "XVID_MSG_WINDOW", NULL, 0, CW_USEDEFAULT,
896 :     CW_USEDEFAULT, 0, 0, HWND_MESSAGE, NULL, (HINSTANCE) g_xvid_hInst, NULL);
897 :    
898 :     /* display the tray icon */
899 :     NOTIFYICONDATA nid;
900 :    
901 :     nid.cbSize = sizeof(NOTIFYICONDATA);
902 :     nid.hWnd = MSG_hwnd;
903 :     nid.uID = 100;
904 :     nid.uVersion = NOTIFYICON_VERSION;
905 :     nid.uCallbackMessage = WM_ICONMESSAGE;
906 :     nid.hIcon = LoadIcon(g_xvid_hInst, MAKEINTRESOURCE(IDI_ICON));
907 :     strcpy_s(nid.szTip, 19, "Xvid Video Decoder");
908 :     nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
909 :    
910 :     Shell_NotifyIcon(NIM_ADD, &nid);
911 :     }
912 :     #endif
913 :    
914 :     return S_OK;
915 :     }
916 :    
917 :     /* input/output pin disconnected */
918 :     HRESULT CXvidDecoder::BreakConnect(PIN_DIRECTION direction)
919 :     {
920 :     DPRINTF("BreakConnect");
921 :    
922 :     #ifdef XVID_USE_TRAYICON
923 :     if ((direction == PINDIR_OUTPUT) && (MSG_hwnd != NULL)) {
924 :     NOTIFYICONDATA nid;
925 :    
926 :     nid.cbSize = sizeof(NOTIFYICONDATA);
927 :     nid.hWnd = MSG_hwnd;
928 :     nid.uID = 100;
929 :     nid.uVersion = NOTIFYICON_VERSION;
930 :    
931 :     if(Shell_NotifyIcon(NIM_DELETE, &nid) == TRUE) {
932 :     DestroyWindow(MSG_hwnd);
933 :     MSG_hwnd = NULL;
934 :     }
935 :     }
936 :     #endif
937 :    
938 :     return S_OK;
939 :     }
940 :    
941 : edgomez 1384 /* alloc output buffer */
942 :    
943 :     HRESULT CXvidDecoder::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
944 :     {
945 :     DPRINTF("DecideBufferSize");
946 :     HRESULT result;
947 :     ALLOCATOR_PROPERTIES ppropActual;
948 :    
949 :     if (m_pInput->IsConnected() == FALSE)
950 :     {
951 :     return E_UNEXPECTED;
952 :     }
953 :    
954 :     ppropInputRequest->cBuffers = 1;
955 :     ppropInputRequest->cbBuffer = m_create.width * m_create.height * 4;
956 :     // cbAlign causes problems with the resize filter */
957 :     // ppropInputRequest->cbAlign = 16;
958 :     ppropInputRequest->cbPrefix = 0;
959 :    
960 :     result = pAlloc->SetProperties(ppropInputRequest, &ppropActual);
961 :     if (result != S_OK)
962 :     {
963 :     return result;
964 :     }
965 :    
966 :     if (ppropActual.cbBuffer < ppropInputRequest->cbBuffer)
967 :     {
968 :     return E_FAIL;
969 :     }
970 :    
971 :     return S_OK;
972 :     }
973 :    
974 :    
975 :     /* decode frame */
976 :    
977 :     HRESULT CXvidDecoder::Transform(IMediaSample *pIn, IMediaSample *pOut)
978 :     {
979 :     DPRINTF("Transform");
980 :     xvid_dec_stats_t stats;
981 :     int length;
982 :    
983 :     memset(&stats, 0, sizeof(stats));
984 :     stats.version = XVID_VERSION;
985 :    
986 :     if (m_create.handle == NULL)
987 :     {
988 : Isibaar 1605 if (xvid_decore_func == NULL)
989 :     return E_FAIL;
990 :    
991 : edgomez 1384 if (xvid_decore_func(0, XVID_DEC_CREATE, &m_create, 0) < 0)
992 :     {
993 :     DPRINTF("*** XVID_DEC_CREATE error");
994 : Isibaar 1868 return E_FAIL;
995 : edgomez 1384 }
996 :     }
997 :    
998 :     AM_MEDIA_TYPE * mtOut;
999 :     pOut->GetMediaType(&mtOut);
1000 :     if (mtOut != NULL)
1001 :     {
1002 :     HRESULT result;
1003 :    
1004 :     result = ChangeColorspace(mtOut->subtype, mtOut->formattype, mtOut->pbFormat);
1005 :     DeleteMediaType(mtOut);
1006 :    
1007 :     if (result != S_OK)
1008 :     {
1009 :     DPRINTF("*** ChangeColorspace error");
1010 :     return result;
1011 :     }
1012 :     }
1013 :    
1014 :     m_frame.length = pIn->GetActualDataLength();
1015 :     if (pIn->GetPointer((BYTE**)&m_frame.bitstream) != S_OK)
1016 :     {
1017 :     return S_FALSE;
1018 :     }
1019 :    
1020 :     if (pOut->GetPointer((BYTE**)&m_frame.output.plane[0]) != S_OK)
1021 :     {
1022 :     return S_FALSE;
1023 :     }
1024 :    
1025 :     m_frame.general = XVID_LOWDELAY;
1026 :    
1027 :     if (pIn->IsDiscontinuity() == S_OK)
1028 : syskin 1427 m_frame.general |= XVID_DISCONTINUITY;
1029 : edgomez 1384
1030 :     if (g_config.nDeblock_Y)
1031 :     m_frame.general |= XVID_DEBLOCKY;
1032 :    
1033 :     if (g_config.nDeblock_UV)
1034 :     m_frame.general |= XVID_DEBLOCKUV;
1035 : syskin 1437
1036 :     if (g_config.nDering_Y)
1037 :     m_frame.general |= XVID_DERINGY;
1038 :    
1039 :     if (g_config.nDering_UV)
1040 :     m_frame.general |= XVID_DERINGUV;
1041 :    
1042 : edgomez 1384 if (g_config.nFilmEffect)
1043 :     m_frame.general |= XVID_FILMEFFECT;
1044 :    
1045 : suxen_drol 1397 m_frame.brightness = g_config.nBrightness;
1046 :    
1047 : edgomez 1384 m_frame.output.csp &= ~XVID_CSP_VFLIP;
1048 :     m_frame.output.csp |= rgb_flip^(g_config.nFlipVideo ? XVID_CSP_VFLIP : 0);
1049 : Isibaar 1898 m_frame.output.stride[0] = out_stride;
1050 : edgomez 1384
1051 : Isibaar 1605 // Paranoid check.
1052 :     if (xvid_decore_func == NULL)
1053 :     return E_FAIL;
1054 : syskin 1498
1055 :    
1056 : edgomez 1384 repeat :
1057 :    
1058 :     if (pIn->IsPreroll() != S_OK)
1059 :     {
1060 :     length = xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats);
1061 : Isibaar 1868
1062 :     if (length == XVID_ERR_MEMORY)
1063 :     return E_FAIL;
1064 :     else if (length < 0)
1065 : edgomez 1384 {
1066 :     DPRINTF("*** XVID_DEC_DECODE");
1067 :     return S_FALSE;
1068 : syskin 1498 } else
1069 :     if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1 && forced_ar == false) {
1070 : suxen_drol 1633
1071 :     if (stats.type != XVID_TYPE_NOTHING) { /* dont attempt to set vmr aspect ratio if no frame was returned by decoder */
1072 : syskin 1498 // inspired by minolta! works for VMR 7 + 9
1073 :     IMediaSample2 *pOut2 = NULL;
1074 :     AM_SAMPLE2_PROPERTIES outProp2;
1075 :     if (SUCCEEDED(pOut->QueryInterface(IID_IMediaSample2, (void **)&pOut2)) &&
1076 :     SUCCEEDED(pOut2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&outProp2)))
1077 :     {
1078 :     CMediaType mtOut2 = m_pOutput->CurrentMediaType();
1079 :     VIDEOINFOHEADER2* vihOut2 = (VIDEOINFOHEADER2*)mtOut2.Format();
1080 : suxen_drol 1502
1081 :     if (*mtOut2.FormatType() == FORMAT_VideoInfo2 &&
1082 :     vihOut2->dwPictAspectRatioX != ar_x && vihOut2->dwPictAspectRatioY != ar_y)
1083 : syskin 1498 {
1084 :     vihOut2->dwPictAspectRatioX = ar_x;
1085 :     vihOut2->dwPictAspectRatioY = ar_y;
1086 :     pOut2->SetMediaType(&mtOut2);
1087 :     m_pOutput->SetMediaType(&mtOut2);
1088 :     }
1089 :     pOut2->Release();
1090 :     }
1091 : suxen_drol 1633 }
1092 : edgomez 1384 }
1093 :     }
1094 :     else
1095 :     { /* Preroll frame - won't be displayed */
1096 :     int tmp = m_frame.output.csp;
1097 :     int tmp_gen = m_frame.general;
1098 :    
1099 :     m_frame.output.csp = XVID_CSP_NULL;
1100 :    
1101 :     /* Disable postprocessing to speed-up seeking */
1102 :     m_frame.general &= ~XVID_DEBLOCKY;
1103 :     m_frame.general &= ~XVID_DEBLOCKUV;
1104 : Isibaar 1605 /*m_frame.general &= ~XVID_DERING;*/
1105 : edgomez 1384 m_frame.general &= ~XVID_FILMEFFECT;
1106 :    
1107 :     length = xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats);
1108 : Isibaar 1868 if (length == XVID_ERR_MEMORY)
1109 :     return E_FAIL;
1110 :     else if (length < 0)
1111 : edgomez 1384 {
1112 :     DPRINTF("*** XVID_DEC_DECODE");
1113 :     return S_FALSE;
1114 :     }
1115 :    
1116 :     m_frame.output.csp = tmp;
1117 :     m_frame.general = tmp_gen;
1118 :     }
1119 :    
1120 :     if (stats.type == XVID_TYPE_NOTHING && length > 0) {
1121 : edgomez 1432 DPRINTF(" B-Frame decoder lag");
1122 : edgomez 1384 return S_FALSE;
1123 :     }
1124 :    
1125 :    
1126 :     if (stats.type == XVID_TYPE_VOL)
1127 :     {
1128 :     if (stats.data.vol.width != m_create.width ||
1129 :     stats.data.vol.height != m_create.height)
1130 :     {
1131 :     DPRINTF("TODO: auto-resize");
1132 :     return S_FALSE;
1133 :     }
1134 : syskin 1498
1135 : edgomez 1384 pOut->SetSyncPoint(TRUE);
1136 :    
1137 : syskin 1498 if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1) { /* auto */
1138 :     int par_x, par_y;
1139 :     if (stats.data.vol.par == XVID_PAR_EXT) {
1140 :     par_x = stats.data.vol.par_width;
1141 :     par_y = stats.data.vol.par_height;
1142 :     } else {
1143 : syskin 1529 par_x = PARS[stats.data.vol.par-1][0];
1144 :     par_y = PARS[stats.data.vol.par-1][1];
1145 : syskin 1498 }
1146 :    
1147 :     ar_x = par_x * stats.data.vol.width;
1148 :     ar_y = par_y * stats.data.vol.height;
1149 :     }
1150 :    
1151 : edgomez 1384 m_frame.bitstream = (BYTE*)m_frame.bitstream + length;
1152 :     m_frame.length -= length;
1153 :     goto repeat;
1154 :     }
1155 :    
1156 :     if (pIn->IsPreroll() == S_OK) {
1157 :     return S_FALSE;
1158 :     }
1159 :    
1160 :     return S_OK;
1161 :     }
1162 :    
1163 :    
1164 :     /* get property page list */
1165 :    
1166 :     STDMETHODIMP CXvidDecoder::GetPages(CAUUID * pPages)
1167 :     {
1168 :     DPRINTF("GetPages");
1169 :    
1170 :     pPages->cElems = 1;
1171 :     pPages->pElems = (GUID *)CoTaskMemAlloc(pPages->cElems * sizeof(GUID));
1172 :     if (pPages->pElems == NULL)
1173 :     {
1174 :     return E_OUTOFMEMORY;
1175 :     }
1176 :     pPages->pElems[0] = CLSID_CABOUT;
1177 :    
1178 :     return S_OK;
1179 :     }
1180 :    
1181 :    
1182 :     /* cleanup pages */
1183 :    
1184 :     STDMETHODIMP CXvidDecoder::FreePages(CAUUID * pPages)
1185 :     {
1186 :     DPRINTF("FreePages");
1187 :     CoTaskMemFree(pPages->pElems);
1188 :     return S_OK;
1189 :     }
1190 : Isibaar 1898
1191 :     /*===============================================================================
1192 :     // MFT Interface
1193 :     //=============================================================================*/
1194 :     #if defined(XVID_USE_MFT)
1195 :     #include <limits.h> // _I64_MAX
1196 :     #define INVALID_TIME _I64_MAX
1197 :    
1198 :     HRESULT CXvidDecoder::MFTGetStreamLimits(DWORD *pdwInputMinimum, DWORD *pdwInputMaximum, DWORD *pdwOutputMinimum, DWORD *pdwOutputMaximum)
1199 :     {
1200 :     DPRINTF("(MFT)GetStreamLimits");
1201 :    
1202 :     if ((pdwInputMinimum == NULL) || (pdwInputMaximum == NULL) || (pdwOutputMinimum == NULL) || (pdwOutputMaximum == NULL))
1203 :     return E_POINTER;
1204 :    
1205 :     /* Just a fixed number of streams allowed */
1206 :     *pdwInputMinimum = *pdwInputMaximum = 1;
1207 :     *pdwOutputMinimum = *pdwOutputMaximum = 1;
1208 :    
1209 :     return S_OK;
1210 :     }
1211 :    
1212 :     HRESULT CXvidDecoder::MFTGetStreamCount(DWORD *pcInputStreams, DWORD *pcOutputStreams)
1213 :     {
1214 :     DPRINTF("(MFT)GetStreamCount");
1215 :    
1216 :     if ((pcInputStreams == NULL) || (pcOutputStreams == NULL))
1217 :     return E_POINTER;
1218 :    
1219 :     /* We have a fixed number of streams */
1220 :     *pcInputStreams = 1;
1221 :     *pcOutputStreams = 1;
1222 :    
1223 :     return S_OK;
1224 :     }
1225 :    
1226 :     HRESULT CXvidDecoder::MFTGetStreamIDs(DWORD dwInputIDArraySize, DWORD *pdwInputIDs, DWORD dwOutputIDArraySize, DWORD *pdwOutputIDs)
1227 :     {
1228 :     DPRINTF("(MFT)GetStreamIDs");
1229 :     return E_NOTIMPL; /* We have fixed number of streams, so stream ID match stream index */
1230 :     }
1231 :    
1232 :     HRESULT CXvidDecoder::MFTGetInputStreamInfo(DWORD dwInputStreamID, MFT_INPUT_STREAM_INFO *pStreamInfo)
1233 :     {
1234 :     DPRINTF("(MFT)GetInputStreamInfo");
1235 :    
1236 :     if (pStreamInfo == NULL)
1237 :     return E_POINTER;
1238 :    
1239 :     if (dwInputStreamID != 0)
1240 :     return MF_E_INVALIDSTREAMNUMBER;
1241 :    
1242 :     EnterCriticalSection(&m_mft_lock);
1243 :    
1244 :     pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER;
1245 :     pStreamInfo->hnsMaxLatency = 0;
1246 :    
1247 :     pStreamInfo->cbSize = 1; /* Need atleast 1 byte input */
1248 :     pStreamInfo->cbMaxLookahead = 0;
1249 :     pStreamInfo->cbAlignment = 1;
1250 :    
1251 :     LeaveCriticalSection(&m_mft_lock);
1252 :     return S_OK;
1253 :     }
1254 :    
1255 :     HRESULT CXvidDecoder::MFTGetOutputStreamInfo(DWORD dwOutputStreamID, MFT_OUTPUT_STREAM_INFO *pStreamInfo)
1256 :     {
1257 :     DPRINTF("(MFT)GetOutputStreamInfo");
1258 :    
1259 :     if (pStreamInfo == NULL)
1260 :     return E_POINTER;
1261 :    
1262 :     if (dwOutputStreamID != 0)
1263 :     return MF_E_INVALIDSTREAMNUMBER;
1264 :    
1265 :     EnterCriticalSection(&m_mft_lock);
1266 :    
1267 :     pStreamInfo->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_DISCARDABLE;
1268 :    
1269 :     if (m_pOutputType == NULL) {
1270 :     pStreamInfo->cbSize = 0;
1271 :     pStreamInfo->cbAlignment = 0;
1272 :     }
1273 :     else {
1274 :     pStreamInfo->cbSize = m_create.width * abs(m_create.height) * 4; // XXX
1275 :     pStreamInfo->cbAlignment = 1;
1276 :     }
1277 :    
1278 :     LeaveCriticalSection(&m_mft_lock);
1279 :     return S_OK;
1280 :     }
1281 :    
1282 :     HRESULT CXvidDecoder::GetAttributes(IMFAttributes** pAttributes)
1283 :     {
1284 :     DPRINTF("(MFT)GetAttributes");
1285 :     return E_NOTIMPL; /* We don't support any attributes */
1286 :     }
1287 :    
1288 :     HRESULT CXvidDecoder::GetInputStreamAttributes(DWORD dwInputStreamID, IMFAttributes **ppAttributes)
1289 :     {
1290 :     DPRINTF("(MFT)GetInputStreamAttributes");
1291 :     return E_NOTIMPL; /* We don't support any attributes */
1292 :     }
1293 :    
1294 :     HRESULT CXvidDecoder::GetOutputStreamAttributes(DWORD dwOutputStreamID, IMFAttributes **ppAttributes)
1295 :     {
1296 :     DPRINTF("(MFT)GetOutputStreamAttributes");
1297 :     return E_NOTIMPL; /* We don't support any attributes */
1298 :     }
1299 :    
1300 :     HRESULT CXvidDecoder::MFTDeleteInputStream(DWORD dwStreamID)
1301 :     {
1302 :     DPRINTF("(MFT)DeleteInputStream");
1303 :     return E_NOTIMPL; /* We have a fixed number of streams */
1304 :     }
1305 :    
1306 :     HRESULT CXvidDecoder::MFTAddInputStreams(DWORD cStreams, DWORD *adwStreamIDs)
1307 :     {
1308 :     DPRINTF("(MFT)AddInputStreams");
1309 :     return E_NOTIMPL; /* We have a fixed number of streams */
1310 :     }
1311 :    
1312 :     HRESULT CXvidDecoder::MFTGetInputAvailableType(DWORD dwInputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType)
1313 :     {
1314 :     DPRINTF("(MFT)GetInputAvailableType");
1315 :    
1316 :     if (dwInputStreamID != 0)
1317 :     return MF_E_INVALIDSTREAMNUMBER;
1318 :    
1319 :     DWORD i = 0;
1320 :     GUID *bs_guid_table[8];
1321 :    
1322 :     bs_guid_table[i++] = (GUID *)&CLSID_XVID;
1323 :     bs_guid_table[i++] = (GUID *)&CLSID_XVID_UC;
1324 :    
1325 :     if (g_config.supported_4cc & SUPPORT_DX50) {
1326 :     bs_guid_table[i++] = (GUID *)&CLSID_DX50;
1327 :     bs_guid_table[i++] = (GUID *)&CLSID_DX50_UC;
1328 :     }
1329 :     if (g_config.supported_4cc & SUPPORT_DIVX) {
1330 :     bs_guid_table[i++] = (GUID *)&CLSID_DIVX;
1331 :     bs_guid_table[i++] = (GUID *)&CLSID_DIVX_UC;
1332 :     }
1333 :     if (g_config.supported_4cc & SUPPORT_MP4V) {
1334 :     bs_guid_table[i++] = (GUID *)&CLSID_MP4V;
1335 :     bs_guid_table[i++] = (GUID *)&CLSID_MP4V_UC;
1336 :     }
1337 :    
1338 :     const GUID *subtype;
1339 :     if (dwTypeIndex < i) {
1340 :     subtype = bs_guid_table[dwTypeIndex];
1341 :     }
1342 :     else {
1343 :     return MF_E_NO_MORE_TYPES;
1344 :     }
1345 :    
1346 :     EnterCriticalSection(&m_mft_lock);
1347 :    
1348 :     HRESULT hr = S_OK;
1349 :    
1350 :     if (ppType) {
1351 :     IMFMediaType *pInputType = NULL;
1352 :     hr = MFCreateMediaType(&pInputType);
1353 :    
1354 :     if (SUCCEEDED(hr))
1355 :     hr = pInputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
1356 :    
1357 :     if (SUCCEEDED(hr))
1358 :     hr = pInputType->SetGUID(MF_MT_SUBTYPE, *subtype);
1359 :    
1360 :     if (SUCCEEDED(hr)) {
1361 :     *ppType = pInputType;
1362 :     (*ppType)->AddRef();
1363 :     }
1364 :     if (pInputType) pInputType->Release();
1365 :     }
1366 :    
1367 :     LeaveCriticalSection(&m_mft_lock);
1368 :    
1369 :     return hr;
1370 :     }
1371 :    
1372 :     HRESULT CXvidDecoder::MFTGetOutputAvailableType(DWORD dwOutputStreamID, DWORD dwTypeIndex, IMFMediaType **ppType)
1373 :     {
1374 :     DPRINTF("(MFT)GetOutputAvailableType");
1375 :    
1376 :     if (ppType == NULL)
1377 :     return E_INVALIDARG;
1378 :    
1379 :     if (dwOutputStreamID != 0)
1380 :     return MF_E_INVALIDSTREAMNUMBER;
1381 :    
1382 :     if (dwTypeIndex < 0) return E_INVALIDARG;
1383 :    
1384 :     GUID csp;
1385 :     int bitdepth = 8;
1386 :     switch(dwTypeIndex)
1387 :     {
1388 :     case 0:
1389 :     if ( USE_YUY2 )
1390 :     {
1391 :     csp = MFVideoFormat_YUY2;
1392 :     bitdepth = 4;
1393 :     break;
1394 :     }
1395 :     case 1 :
1396 :     if ( USE_UYVY )
1397 :     {
1398 :     csp = MFVideoFormat_UYVY;
1399 :     bitdepth = 4;
1400 :     break;
1401 :     }
1402 :     case 2 :
1403 :     if ( USE_IYUV )
1404 :     {
1405 :     csp = MFVideoFormat_IYUV;
1406 :     bitdepth = 3;
1407 :     break;
1408 :     }
1409 :     case 3 :
1410 :     if ( USE_YV12 )
1411 :     {
1412 :     csp = MFVideoFormat_YV12;
1413 :     bitdepth = 3;
1414 :     break;
1415 :     }
1416 :     case 4 :
1417 :     if ( USE_RGB32 )
1418 :     {
1419 :     csp = MFVideoFormat_RGB32;
1420 :     bitdepth = 8;
1421 :     break;
1422 :     }
1423 :     case 5 :
1424 :     if ( USE_RGB24 )
1425 :     {
1426 :     csp = MFVideoFormat_RGB24;
1427 :     bitdepth = 6;
1428 :     break;
1429 :     }
1430 :     case 6 :
1431 :     if ( USE_RG555 )
1432 :     {
1433 :     csp = MFVideoFormat_RGB555;
1434 :     bitdepth = 4;
1435 :     break;
1436 :     }
1437 :     case 7 :
1438 :     if ( USE_RG565 )
1439 :     {
1440 :     csp = MFVideoFormat_RGB565;
1441 :     bitdepth = 4;
1442 :     break;
1443 :     }
1444 :     default :
1445 :     return MF_E_NO_MORE_TYPES;
1446 :     }
1447 :    
1448 :     if (m_pInputType == NULL)
1449 :     return MF_E_TRANSFORM_TYPE_NOT_SET;
1450 :    
1451 :     EnterCriticalSection(&m_mft_lock);
1452 :    
1453 :     HRESULT hr = S_OK;
1454 :    
1455 :     IMFMediaType *pOutputType = NULL;
1456 :     hr = MFCreateMediaType(&pOutputType);
1457 :    
1458 :     if (SUCCEEDED(hr)) {
1459 :     hr = pOutputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
1460 :     }
1461 :    
1462 :     if (SUCCEEDED(hr)) {
1463 :     hr = pOutputType->SetGUID(MF_MT_SUBTYPE, csp);
1464 :     }
1465 :    
1466 :     if (SUCCEEDED(hr)) {
1467 :     hr = pOutputType->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, TRUE);
1468 :     }
1469 :    
1470 :     if (SUCCEEDED(hr)) {
1471 :     hr = pOutputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
1472 :     }
1473 :    
1474 :     if (SUCCEEDED(hr)) {
1475 :     hr = pOutputType->SetUINT32(MF_MT_SAMPLE_SIZE, (m_create.height * m_create.width * bitdepth)>>1);
1476 :     }
1477 :    
1478 :     if (SUCCEEDED(hr)) {
1479 :     hr = MFSetAttributeSize(pOutputType, MF_MT_FRAME_SIZE, m_create.width, m_create.height);
1480 :     }
1481 :    
1482 :     if (SUCCEEDED(hr)) {
1483 :     hr = MFSetAttributeRatio(pOutputType, MF_MT_FRAME_RATE, m_frameRate.Numerator, m_frameRate.Denominator);
1484 :     }
1485 :    
1486 :     if (SUCCEEDED(hr)) {
1487 :     hr = pOutputType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
1488 :     }
1489 :    
1490 :     if (SUCCEEDED(hr)) {
1491 :     hr = MFSetAttributeRatio(pOutputType, MF_MT_PIXEL_ASPECT_RATIO, ar_x, ar_y);
1492 :     }
1493 :    
1494 :     if (SUCCEEDED(hr)) {
1495 :     *ppType = pOutputType;
1496 :     (*ppType)->AddRef();
1497 :     }
1498 :    
1499 :     if (pOutputType) pOutputType->Release();
1500 :    
1501 :     LeaveCriticalSection(&m_mft_lock);
1502 :     return hr;
1503 :     }
1504 :    
1505 :     HRESULT CXvidDecoder::MFTSetInputType(DWORD dwInputStreamID, IMFMediaType *pType, DWORD dwFlags)
1506 :     {
1507 :     DPRINTF("(MFT)SetInputType");
1508 :    
1509 :     if (dwInputStreamID != 0)
1510 :     return MF_E_INVALIDSTREAMNUMBER;
1511 :    
1512 :     if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY)
1513 :     return E_INVALIDARG;
1514 :    
1515 :     EnterCriticalSection(&m_mft_lock);
1516 :    
1517 :     HRESULT hr = S_OK;
1518 :    
1519 :     /* Actually set the type or just test it? */
1520 :     BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
1521 :    
1522 :     /* If we have samples pending the type can't be changed right now */
1523 :     if (HasPendingOutput())
1524 :     hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
1525 :    
1526 :     if (SUCCEEDED(hr)) {
1527 :     if (pType) { // /* Check the type */
1528 :     hr = OnCheckInputType(pType);
1529 :     }
1530 :     }
1531 :    
1532 :     if (SUCCEEDED(hr)) {
1533 :     if (bReallySet) { /* Set the type if needed */
1534 :     hr = OnSetInputType(pType);
1535 :     }
1536 :     }
1537 :    
1538 :     LeaveCriticalSection(&m_mft_lock);
1539 :     return hr;
1540 :     }
1541 :    
1542 :     HRESULT CXvidDecoder::MFTSetOutputType(DWORD dwOutputStreamID, IMFMediaType *pType, DWORD dwFlags)
1543 :     {
1544 :     DPRINTF("(MFT)SetOutputType");
1545 :    
1546 :     if (dwOutputStreamID != 0)
1547 :     return MF_E_INVALIDSTREAMNUMBER;
1548 :    
1549 :     if (dwFlags & ~MFT_SET_TYPE_TEST_ONLY)
1550 :     return E_INVALIDARG;
1551 :    
1552 :     HRESULT hr = S_OK;
1553 :    
1554 :     EnterCriticalSection(&m_mft_lock);
1555 :    
1556 : Isibaar 1899 /* Actually set the type or just test it? */
1557 : Isibaar 1898 BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
1558 :    
1559 :     /* If we have samples pending the type can't be changed right now */
1560 :     if (HasPendingOutput())
1561 :     hr = MF_E_TRANSFORM_CANNOT_CHANGE_MEDIATYPE_WHILE_PROCESSING;
1562 :    
1563 :     if (SUCCEEDED(hr)) {
1564 :     if (pType) { /* Check the type */
1565 :     AM_MEDIA_TYPE *am;
1566 :     hr = MFCreateAMMediaTypeFromMFMediaType(pType, GUID_NULL, &am);
1567 :    
1568 :     if (SUCCEEDED(hr)) {
1569 :     if (FAILED(ChangeColorspace(am->subtype, am->formattype, am->pbFormat))) {
1570 :     DPRINTF("(MFT)InternalCheckOutputType (MF_E_INVALIDTYPE)");
1571 :     return MF_E_INVALIDTYPE;
1572 :     }
1573 :    
1574 :     CoTaskMemFree(am->pbFormat);
1575 :     CoTaskMemFree(am);
1576 :     }
1577 :     }
1578 :     }
1579 :    
1580 :     if (SUCCEEDED(hr)) {
1581 :     if (bReallySet) { /* Set the type if needed */
1582 :     hr = OnSetOutputType(pType);
1583 :     }
1584 :     }
1585 :    
1586 :     #ifdef XVID_USE_TRAYICON
1587 :     if (SUCCEEDED(hr) && MSG_hwnd == NULL) /* Create message passing window */
1588 :     {
1589 :     WNDCLASSEX wc;
1590 :    
1591 :     wc.cbSize = sizeof(WNDCLASSEX);
1592 :     wc.lpfnWndProc = msg_proc;
1593 :     wc.style = CS_HREDRAW | CS_VREDRAW;
1594 :     wc.cbWndExtra = 0;
1595 :     wc.cbClsExtra = 0;
1596 :     wc.hInstance = (HINSTANCE) g_xvid_hInst;
1597 :     wc.hbrBackground = (HBRUSH) GetStockObject(NULL_BRUSH);
1598 :     wc.lpszMenuName = NULL;
1599 :     wc.lpszClassName = "XVID_MSG_WINDOW";
1600 :     wc.hIcon = NULL;
1601 :     wc.hIconSm = NULL;
1602 :     wc.hCursor = NULL;
1603 :     RegisterClassEx(&wc);
1604 :    
1605 :     MSG_hwnd = CreateWindowEx(0, "XVID_MSG_WINDOW", NULL, 0, CW_USEDEFAULT,
1606 :     CW_USEDEFAULT, 0, 0, HWND_MESSAGE, NULL, (HINSTANCE) g_xvid_hInst, NULL);
1607 :    
1608 :     /* display the tray icon */
1609 :     NOTIFYICONDATA nid;
1610 :    
1611 :     nid.cbSize = sizeof(NOTIFYICONDATA);
1612 :     nid.hWnd = MSG_hwnd;
1613 :     nid.uID = 100;
1614 :     nid.uVersion = NOTIFYICON_VERSION;
1615 :     nid.uCallbackMessage = WM_ICONMESSAGE;
1616 :     nid.hIcon = LoadIcon(g_xvid_hInst, MAKEINTRESOURCE(IDI_ICON));
1617 :     strcpy_s(nid.szTip, 19, "Xvid Video Decoder");
1618 :     nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
1619 :    
1620 :     Shell_NotifyIcon(NIM_ADD, &nid);
1621 :     }
1622 :     #endif
1623 :    
1624 :     LeaveCriticalSection(&m_mft_lock);
1625 :     return hr;
1626 :     }
1627 :    
1628 :     HRESULT CXvidDecoder::MFTGetInputCurrentType(DWORD dwInputStreamID, IMFMediaType **ppType)
1629 :     {
1630 :     DPRINTF("(MFT)GetInputCurrentType");
1631 :    
1632 :     if (ppType == NULL)
1633 :     return E_POINTER;
1634 :    
1635 :     if (dwInputStreamID != 0)
1636 :     return MF_E_INVALIDSTREAMNUMBER;
1637 :    
1638 :     EnterCriticalSection(&m_mft_lock);
1639 :    
1640 :     HRESULT hr = S_OK;
1641 :    
1642 :     if (!m_pInputType)
1643 :     hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1644 :    
1645 :     if (SUCCEEDED(hr)) {
1646 :     *ppType = m_pInputType;
1647 :     (*ppType)->AddRef();
1648 :     }
1649 :    
1650 :     LeaveCriticalSection(&m_mft_lock);
1651 :     return hr;
1652 :     }
1653 :    
1654 :     HRESULT CXvidDecoder::MFTGetOutputCurrentType(DWORD dwOutputStreamID, IMFMediaType **ppType)
1655 :     {
1656 :     DPRINTF("(MFT)GetOutputCurrentType");
1657 :    
1658 :     if (ppType == NULL)
1659 :     return E_POINTER;
1660 :    
1661 :     if (dwOutputStreamID != 0)
1662 :     return MF_E_INVALIDSTREAMNUMBER;
1663 :    
1664 :     EnterCriticalSection(&m_mft_lock);
1665 :    
1666 :     HRESULT hr = S_OK;
1667 :    
1668 :     if (!m_pOutputType)
1669 :     hr = MF_E_TRANSFORM_TYPE_NOT_SET;
1670 :    
1671 :     if (SUCCEEDED(hr)) {
1672 :     *ppType = m_pOutputType;
1673 :     (*ppType)->AddRef();
1674 :     }
1675 :    
1676 :     LeaveCriticalSection(&m_mft_lock);
1677 :     return hr;
1678 :     }
1679 :    
1680 :     HRESULT CXvidDecoder::MFTGetInputStatus(DWORD dwInputStreamID, DWORD *pdwFlags)
1681 :     {
1682 :     DPRINTF("(MFT)GetInputStatus");
1683 :    
1684 :     if (pdwFlags == NULL)
1685 :     return E_POINTER;
1686 :    
1687 :     if (dwInputStreamID != 0)
1688 :     return MF_E_INVALIDSTREAMNUMBER;
1689 :    
1690 :     EnterCriticalSection(&m_mft_lock);
1691 :    
1692 :     /* If there's pending output sampels we don't accept new
1693 :     input data until ProcessOutput() or Flush() was called */
1694 :     if (!HasPendingOutput()) {
1695 :     *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;
1696 :     }
1697 :     else {
1698 :     *pdwFlags = 0;
1699 :     }
1700 :    
1701 :     LeaveCriticalSection(&m_mft_lock);
1702 :    
1703 :     return S_OK;
1704 :     }
1705 :    
1706 :     HRESULT CXvidDecoder::MFTGetOutputStatus(DWORD *pdwFlags)
1707 :     {
1708 :     DPRINTF("(MFT)GetOutputStatus");
1709 :    
1710 :     if (pdwFlags == NULL)
1711 :     return E_POINTER;
1712 :    
1713 :     EnterCriticalSection(&m_mft_lock);
1714 :    
1715 :     /* We can render an output sample only after we
1716 :     have decoded one */
1717 :     if (HasPendingOutput()) {
1718 :     *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY;
1719 :     }
1720 :     else {
1721 :     *pdwFlags = 0;
1722 :     }
1723 :    
1724 :     LeaveCriticalSection(&m_mft_lock);
1725 :    
1726 :     return S_OK;
1727 :     }
1728 :    
1729 :     HRESULT CXvidDecoder::MFTSetOutputBounds(LONGLONG hnsLowerBound, LONGLONG hnsUpperBound)
1730 :     {
1731 :     DPRINTF("(MFT)SetOutputBounds");
1732 :     return E_NOTIMPL;
1733 :     }
1734 :    
1735 :     HRESULT CXvidDecoder::MFTProcessEvent(DWORD dwInputStreamID, IMFMediaEvent *pEvent)
1736 :     {
1737 :     DPRINTF("(MFT)ProcessEvent");
1738 :     return E_NOTIMPL; /* We don't handle any stream events */
1739 :     }
1740 :    
1741 :     HRESULT CXvidDecoder::MFTProcessMessage(MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam)
1742 :     {
1743 :     DPRINTF("(MFT)ProcessMessage");
1744 :     HRESULT hr = S_OK;
1745 :    
1746 :     EnterCriticalSection(&m_mft_lock);
1747 :    
1748 :     switch (eMessage)
1749 :     {
1750 :     case MFT_MESSAGE_COMMAND_FLUSH:
1751 :     if (m_create.handle != NULL) {
1752 :     DPRINTF("(MFT)CommandFlush");
1753 :    
1754 :     xvid_dec_stats_t stats;
1755 :     int used_bytes;
1756 :    
1757 :     memset(&stats, 0, sizeof(stats));
1758 :     stats.version = XVID_VERSION;
1759 :    
1760 :     int csp = m_frame.output.csp;
1761 :    
1762 :     m_frame.output.csp = XVID_CSP_INTERNAL;
1763 :     m_frame.bitstream = NULL;
1764 :     m_frame.length = -1;
1765 :     m_frame.general = XVID_LOWDELAY;
1766 :    
1767 :     do {
1768 :     used_bytes = xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats);
1769 :     } while(used_bytes>=0 && stats.type <= 0);
1770 :    
1771 :     m_frame.output.csp = csp;
1772 :     m_frame.output.plane[1] = NULL; /* Don't display flushed samples */
1773 :    
1774 :     //m_timestamp = INVALID_TIME;
1775 :     //m_timelength = INVALID_TIME;
1776 :     //m_rtFrame = 0;
1777 :     }
1778 :     break;
1779 :    
1780 :     case MFT_MESSAGE_COMMAND_DRAIN:
1781 :     m_discont = 1; /* Set discontinuity flag */
1782 :     m_rtFrame = 0;
1783 :     break;
1784 :    
1785 :     case MFT_MESSAGE_SET_D3D_MANAGER:
1786 :     hr = E_NOTIMPL;
1787 :     break;
1788 :    
1789 :     case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
1790 :     case MFT_MESSAGE_NOTIFY_END_STREAMING:
1791 :     break;
1792 :    
1793 :     case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
1794 :     case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
1795 :     break;
1796 :     }
1797 :    
1798 :     LeaveCriticalSection(&m_mft_lock);
1799 :    
1800 :     return hr;
1801 :     }
1802 :    
1803 :     HRESULT CXvidDecoder::MFTProcessInput(DWORD dwInputStreamID, IMFSample *pSample, DWORD dwFlags)
1804 :     {
1805 :     DPRINTF("(MFT)ProcessInput");
1806 :    
1807 :     if (pSample == NULL)
1808 :     return E_POINTER;
1809 :    
1810 :     if (dwInputStreamID != 0)
1811 :     return MF_E_INVALIDSTREAMNUMBER;
1812 :    
1813 :     if (dwFlags != 0)
1814 :     return E_INVALIDARG;
1815 :    
1816 :     if (!m_pInputType || !m_pOutputType) {
1817 :     return MF_E_NOTACCEPTING; /* Must have set input and output types */
1818 :     }
1819 :     else if (HasPendingOutput()) {
1820 :     return MF_E_NOTACCEPTING; /* We still have output samples to render */
1821 :     }
1822 :    
1823 :     xvid_dec_stats_t stats;
1824 :     int length;
1825 :    
1826 :     memset(&stats, 0, sizeof(stats));
1827 :     stats.version = XVID_VERSION;
1828 :    
1829 :     if (m_create.handle == NULL)
1830 :     {
1831 :     if (xvid_decore_func == NULL)
1832 :     return E_FAIL;
1833 :     if (xvid_decore_func(0, XVID_DEC_CREATE, &m_create, 0) < 0)
1834 :     {
1835 :     DPRINTF("*** XVID_DEC_CREATE error");
1836 :     return E_FAIL;
1837 :     }
1838 :     }
1839 :    
1840 :     EnterCriticalSection(&m_mft_lock);
1841 :    
1842 :     HRESULT hr = S_OK;
1843 :     IMFMediaBuffer *pBuffer;
1844 :    
1845 :     if (SUCCEEDED(hr)) {
1846 :     hr = pSample->ConvertToContiguousBuffer(&pBuffer);
1847 :     }
1848 :    
1849 :     if (SUCCEEDED(hr)) {
1850 :     hr = pBuffer->Lock((BYTE**)&m_frame.bitstream, NULL, (DWORD *)&m_frame.length);
1851 :     }
1852 :    
1853 :     m_frame.general = XVID_LOWDELAY;
1854 :    
1855 :     if (m_discont == 1) {
1856 :     m_frame.general |= XVID_DISCONTINUITY;
1857 :     m_discont = 0;
1858 :     }
1859 :    
1860 :     if (g_config.nDeblock_Y)
1861 :     m_frame.general |= XVID_DEBLOCKY;
1862 :    
1863 :     if (g_config.nDeblock_UV)
1864 :     m_frame.general |= XVID_DEBLOCKUV;
1865 :    
1866 :     if (g_config.nDering_Y)
1867 :     m_frame.general |= XVID_DERINGY;
1868 :    
1869 :     if (g_config.nDering_UV)
1870 :     m_frame.general |= XVID_DERINGUV;
1871 :    
1872 :     if (g_config.nFilmEffect)
1873 :     m_frame.general |= XVID_FILMEFFECT;
1874 :    
1875 :     m_frame.brightness = g_config.nBrightness;
1876 :    
1877 :     m_frame.output.csp &= ~XVID_CSP_VFLIP;
1878 :     m_frame.output.csp |= rgb_flip^(g_config.nFlipVideo ? XVID_CSP_VFLIP : 0);
1879 :    
1880 :     int csp = m_frame.output.csp;
1881 :     m_frame.output.csp = XVID_CSP_INTERNAL;
1882 :    
1883 :     // Paranoid check.
1884 :     if (xvid_decore_func == NULL) {
1885 :     hr = E_FAIL;
1886 :     goto END_LOOP;
1887 :     }
1888 :    
1889 :     repeat :
1890 :     length = xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats);
1891 :    
1892 :     if (length == XVID_ERR_MEMORY) {
1893 :     hr = E_FAIL;
1894 :     goto END_LOOP;
1895 :     }
1896 :     else if (length < 0)
1897 :     {
1898 :     DPRINTF("*** XVID_DEC_DECODE");
1899 :     goto END_LOOP;
1900 :     }
1901 :    
1902 :     if (stats.type == XVID_TYPE_NOTHING && length > 0) {
1903 :     DPRINTF(" B-Frame decoder lag");
1904 :     m_frame.output.plane[1] = NULL;
1905 :     goto END_LOOP;
1906 :     }
1907 :    
1908 :     if (stats.type == XVID_TYPE_VOL)
1909 :     {
1910 :     if (stats.data.vol.width != m_create.width ||
1911 :     stats.data.vol.height != m_create.height)
1912 :     {
1913 :     DPRINTF("TODO: auto-resize");
1914 :     m_frame.output.plane[1] = NULL;
1915 :     hr = E_FAIL;
1916 :     }
1917 :    
1918 :     if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1) { /* auto */
1919 :     int par_x, par_y;
1920 :     if (stats.data.vol.par == XVID_PAR_EXT) {
1921 :     par_x = stats.data.vol.par_width;
1922 :     par_y = stats.data.vol.par_height;
1923 :     } else {
1924 :     par_x = PARS[stats.data.vol.par-1][0];
1925 :     par_y = PARS[stats.data.vol.par-1][1];
1926 :     }
1927 :    
1928 :     ar_x = par_x * stats.data.vol.width;
1929 :     ar_y = par_y * stats.data.vol.height;
1930 :     }
1931 :    
1932 :     m_frame.bitstream = (BYTE*)m_frame.bitstream + length;
1933 :     m_frame.length -= length;
1934 :     goto repeat;
1935 :     }
1936 :    
1937 :     END_LOOP:
1938 :     m_frame.output.csp = csp;
1939 :    
1940 :     if (pBuffer) {
1941 :     pBuffer->Unlock();
1942 :     pBuffer->Release();
1943 :     }
1944 :    
1945 :     if (SUCCEEDED(hr)) {
1946 :     /* Try to get a timestamp */
1947 :     if (FAILED(pSample->GetSampleTime(&m_timestamp)))
1948 :     m_timestamp = INVALID_TIME;
1949 :    
1950 :     if (FAILED(pSample->GetSampleDuration(&m_timelength))) {
1951 :     m_timelength = INVALID_TIME;
1952 :     }
1953 :     }
1954 :    
1955 :     LeaveCriticalSection(&m_mft_lock);
1956 :    
1957 :     return hr;
1958 :     }
1959 :    
1960 :     HRESULT CXvidDecoder::MFTProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount, MFT_OUTPUT_DATA_BUFFER *pOutputSamples, DWORD *pdwStatus)
1961 :     {
1962 :     DPRINTF("(MFT)ProcessOutput");
1963 :    
1964 :     /* Preroll in MFT ??
1965 :     Flags ?? -> TODO... */
1966 :     if (dwFlags != 0)
1967 :     return E_INVALIDARG;
1968 :    
1969 :     if (pOutputSamples == NULL || pdwStatus == NULL)
1970 :     return E_POINTER;
1971 :    
1972 :     if (cOutputBufferCount != 1) /* Must be exactly one output buffer */
1973 :     return E_INVALIDARG;
1974 :    
1975 :     if (pOutputSamples[0].pSample == NULL) /* Must have a sample */
1976 :     return E_INVALIDARG;
1977 :    
1978 :     if (!HasPendingOutput()) { /* If there's no sample we need to decode one first */
1979 :     return MF_E_TRANSFORM_NEED_MORE_INPUT;
1980 :     }
1981 :    
1982 :     EnterCriticalSection(&m_mft_lock);
1983 :    
1984 :     HRESULT hr = S_OK;
1985 :    
1986 :     BYTE *Dst = NULL;
1987 :     DWORD buffer_size;
1988 :    
1989 :     IMFMediaBuffer *pOutput = NULL;
1990 :    
1991 :     if (SUCCEEDED(hr)) {
1992 :     hr = pOutputSamples[0].pSample->GetBufferByIndex(0, &pOutput); /* Get output buffer */
1993 :     }
1994 :    
1995 :     if (SUCCEEDED(hr)) {
1996 :     hr = pOutput->GetMaxLength(&buffer_size);
1997 :     }
1998 :    
1999 :     if (SUCCEEDED(hr))
2000 :     hr = pOutput->Lock(&Dst, NULL, NULL);
2001 :    
2002 :     if (SUCCEEDED(hr)) {
2003 :     xvid_gbl_convert_t convert;
2004 :    
2005 :     memset(&convert, 0, sizeof(convert));
2006 :     convert.version = XVID_VERSION;
2007 :    
2008 :     convert.input.csp = XVID_CSP_INTERNAL;
2009 :     convert.input.plane[0] = m_frame.output.plane[0];
2010 :     convert.input.plane[1] = m_frame.output.plane[1];
2011 :     convert.input.plane[2] = m_frame.output.plane[2];
2012 :     convert.input.stride[0] = m_frame.output.stride[0];
2013 :     convert.input.stride[1] = m_frame.output.stride[1];
2014 :     convert.input.stride[2] = m_frame.output.stride[2];
2015 :    
2016 :     convert.output.csp = m_frame.output.csp;
2017 :     convert.output.plane[0] = Dst;
2018 :     convert.output.stride[0] = out_stride;
2019 :    
2020 :     convert.width = m_create.width;
2021 :     convert.height = m_create.height;
2022 :     convert.interlacing = 0;
2023 :    
2024 :     if (m_frame.output.plane[1] != NULL && Dst != NULL && xvid_global_func != NULL)
2025 :     if (xvid_global_func(0, XVID_GBL_CONVERT, &convert, NULL) < 0) /* CSP convert into output buffer */
2026 :     hr = E_FAIL;
2027 :    
2028 :     m_frame.output.plane[1] = NULL;
2029 :     }
2030 :    
2031 :     *pdwStatus = 0;
2032 :    
2033 :     if (SUCCEEDED(hr)) {
2034 :     if (SUCCEEDED(hr))
2035 :     hr = pOutputSamples[0].pSample->SetUINT32(MFSampleExtension_CleanPoint, TRUE); // key frame
2036 :    
2037 :     if (SUCCEEDED(hr)) { /* Set timestamp of output sample */
2038 :     if (m_timestamp != INVALID_TIME)
2039 :     hr = pOutputSamples[0].pSample->SetSampleTime(m_timestamp);
2040 :     else
2041 :     hr = pOutputSamples[0].pSample->SetSampleTime(m_rtFrame);
2042 :    
2043 :     if (m_timelength != INVALID_TIME)
2044 :     hr = pOutputSamples[0].pSample->SetSampleDuration(m_timelength);
2045 :     else
2046 :     hr = pOutputSamples[0].pSample->SetSampleDuration(m_duration);
2047 :    
2048 :     m_rtFrame += m_duration;
2049 :     }
2050 :    
2051 :     if (SUCCEEDED(hr))
2052 :     hr = pOutput->SetCurrentLength(m_create.width * abs(m_create.height) * 4); // XXX
2053 :     }
2054 :    
2055 :     if (pOutput) {
2056 :     pOutput->Unlock();
2057 :     pOutput->Release();
2058 :     }
2059 :    
2060 :     LeaveCriticalSection(&m_mft_lock);
2061 :    
2062 :     return hr;
2063 :     }
2064 :    
2065 :     HRESULT CXvidDecoder::OnCheckInputType(IMFMediaType *pmt)
2066 :     {
2067 :     DPRINTF("(MFT)CheckInputType");
2068 :    
2069 :     HRESULT hr = S_OK;
2070 :    
2071 :     /* Check if input type is already set. Reject any type that is not identical */
2072 :     if (m_pInputType) {
2073 :     DWORD dwFlags = 0;
2074 :     if (S_OK == m_pInputType->IsEqual(pmt, &dwFlags)) {
2075 :     return S_OK;
2076 :     }
2077 :     else {
2078 :     return MF_E_INVALIDTYPE;
2079 :     }
2080 :     }
2081 :    
2082 :     GUID majortype = {0}, subtype = {0};
2083 :     UINT32 width = 0, height = 0;
2084 :    
2085 :     hr = pmt->GetMajorType(&majortype);
2086 :    
2087 :     if (SUCCEEDED(hr)) {
2088 :     if (majortype != MFMediaType_Video) { /* Must be Video */
2089 :     hr = MF_E_INVALIDTYPE;
2090 :     }
2091 :     }
2092 :    
2093 :     if (m_hdll == NULL) {
2094 :     HRESULT hr = OpenLib();
2095 :    
2096 :     if (FAILED(hr) || (m_hdll == NULL)) // Paranoid checks.
2097 :     hr = MF_E_INVALIDTYPE;
2098 :     }
2099 :    
2100 :     if (SUCCEEDED(hr)) {
2101 :     hr = MFGetAttributeSize(pmt, MF_MT_FRAME_SIZE, &width, &height);
2102 :     }
2103 :    
2104 :     /* Check the frame size */
2105 :     if (SUCCEEDED(hr)) {
2106 :     if (width > 4096 || height > 4096) {
2107 :     hr = MF_E_INVALIDTYPE;
2108 :     }
2109 :     }
2110 :     m_create.width = width;
2111 :     m_create.height = height;
2112 :    
2113 :     if (SUCCEEDED(hr)) {
2114 :     if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1) {
2115 :     hr = MFGetAttributeRatio(pmt, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&ar_x, (UINT32*)&ar_y);
2116 :     }
2117 :     }
2118 :    
2119 :     /* TODO1: Make sure there really is a frame rate after all!
2120 :     TODO2: Use the framerate for something! */
2121 :     MFRatio fps = {0};
2122 :     if (SUCCEEDED(hr)) {
2123 :     hr = MFGetAttributeRatio(pmt, MF_MT_FRAME_RATE, (UINT32*)&fps.Numerator, (UINT32*)&fps.Denominator);
2124 :     }
2125 :    
2126 :     if (SUCCEEDED(hr)) {
2127 :     hr = pmt->GetGUID(MF_MT_SUBTYPE, &subtype);
2128 :     }
2129 :    
2130 :     if (subtype == CLSID_MP4V || subtype == CLSID_MP4V_UC) {
2131 :     if (!(g_config.supported_4cc & SUPPORT_MP4V)) {
2132 :     CloseLib();
2133 :     hr = MF_E_INVALIDTYPE;
2134 :     }
2135 :     else m_create.fourcc = FOURCC_MP4V;
2136 :     }
2137 :     else if (subtype == CLSID_DIVX || subtype == CLSID_DIVX_UC) {
2138 :     if (!(g_config.supported_4cc & SUPPORT_DIVX)) {
2139 :     CloseLib();
2140 :     hr = MF_E_INVALIDTYPE;
2141 :     }
2142 :     else m_create.fourcc = FOURCC_DIVX;
2143 :     }
2144 :     else if (subtype == CLSID_DX50 || subtype == CLSID_DX50_UC) {
2145 :     if (!(g_config.supported_4cc & SUPPORT_DX50)) {
2146 :     CloseLib();
2147 :     hr = MF_E_INVALIDTYPE;
2148 :     }
2149 :     else m_create.fourcc = FOURCC_DX50;
2150 :     }
2151 :     else if (subtype == CLSID_XVID || subtype == CLSID_XVID_UC) {
2152 :     m_create.fourcc = FOURCC_XVID;
2153 :     }
2154 :     else {
2155 :     DPRINTF("Unknown subtype!");
2156 :     CloseLib();
2157 :     hr = MF_E_INVALIDTYPE;
2158 :     }
2159 :    
2160 :     /* haali media splitter reports VOL information in the format header */
2161 :     if (SUCCEEDED(hr))
2162 :     {
2163 :     UINT32 cbSeqHeader = 0;
2164 :    
2165 :     (void)pmt->GetBlobSize(MF_MT_MPEG_SEQUENCE_HEADER, &cbSeqHeader);
2166 :    
2167 :     if (cbSeqHeader>0) {
2168 :     xvid_dec_stats_t stats;
2169 :     memset(&stats, 0, sizeof(stats));
2170 :     stats.version = XVID_VERSION;
2171 :    
2172 :     if (m_create.handle == NULL) {
2173 :     if (xvid_decore_func == NULL)
2174 :     hr = E_FAIL;
2175 :     if (xvid_decore_func(0, XVID_DEC_CREATE, &m_create, 0) < 0) {
2176 :     DPRINTF("*** XVID_DEC_CREATE error");
2177 :     hr = E_FAIL;
2178 :     }
2179 :     }
2180 :    
2181 :     if (SUCCEEDED(hr)) {
2182 :     (void)pmt->GetAllocatedBlob(MF_MT_MPEG_SEQUENCE_HEADER, (UINT8 **)&m_frame.bitstream, (UINT32 *)&m_frame.length);
2183 :     m_frame.general = 0;
2184 :     m_frame.output.csp = XVID_CSP_NULL;
2185 :    
2186 :     int ret = 0;
2187 :     if ((ret=xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats)) >= 0) {
2188 :     /* honour video dimensions reported in VOL header */
2189 :     if (stats.type == XVID_TYPE_VOL) {
2190 :     m_create.width = stats.data.vol.width;
2191 :     m_create.height = stats.data.vol.height;
2192 :     }
2193 :     }
2194 :    
2195 :     if (ret == XVID_ERR_MEMORY) hr = E_FAIL;
2196 :     CoTaskMemFree(m_frame.bitstream);
2197 :     }
2198 :     }
2199 :     }
2200 :    
2201 :     return hr;
2202 :     }
2203 :    
2204 :     HRESULT CXvidDecoder::OnSetInputType(IMFMediaType *pmt)
2205 :     {
2206 :     HRESULT hr = S_OK;
2207 :     UINT32 w, h;
2208 :    
2209 :     if (m_pInputType) m_pInputType->Release();
2210 :    
2211 :     hr = MFGetAttributeSize(pmt, MF_MT_FRAME_SIZE, &w, &h);
2212 :     m_create.width = w; m_create.height = h;
2213 :    
2214 :     if (SUCCEEDED(hr))
2215 :     hr = MFGetAttributeRatio(pmt, MF_MT_FRAME_RATE, (UINT32*)&m_frameRate.Numerator, (UINT32*)&m_frameRate.Denominator);
2216 :    
2217 :     if (SUCCEEDED(hr)) { /* Store frame duration, derived from the frame rate */
2218 :     hr = MFFrameRateToAverageTimePerFrame(m_frameRate.Numerator, m_frameRate.Denominator, &m_duration);
2219 :     }
2220 :    
2221 :     if (SUCCEEDED(hr)) {
2222 :     m_pInputType = pmt;
2223 :     m_pInputType->AddRef();
2224 :     }
2225 :    
2226 :     return hr;
2227 :     }
2228 :    
2229 :     HRESULT CXvidDecoder::OnSetOutputType(IMFMediaType *pmt)
2230 :     {
2231 :     if (m_pOutputType) m_pOutputType->Release();
2232 :    
2233 :     m_pOutputType = pmt;
2234 :     m_pOutputType->AddRef();
2235 :    
2236 :     return S_OK;
2237 :     }
2238 :    
2239 :     #endif /* XVID_USE_MFT */

No admin address has been configured
ViewVC Help
Powered by ViewVC 1.0.4