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

Diff of /xvidcore/dshow/src/CXvidDecoder.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1, Sat Feb 22 08:22:03 2003 UTC revision 1.1.2.2, Mon Jun 9 13:49:00 2003 UTC
# Line 0  Line 1 
1    /*****************************************************************************
2     *
3     *  XVID MPEG-4 VIDEO CODEC
4     *  - XviD Decoder part of the DShow Filter  -
5     *
6     *  Copyright(C) 2002-2003 Peter Ross <pross@xvid.org>
7     *
8     *  This program is free software ; you can redistribute it and/or modify
9     *  it under the terms of the GNU General Public License as published by
10     *  the Free Software Foundation ; either version 2 of the License, or
11     *  (at your option) any later version.
12     *
13     *  This program is distributed in the hope that it will be useful,
14     *  but WITHOUT ANY WARRANTY ; without even the implied warranty of
15     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     *  GNU General Public License for more details.
17     *
18     *  You should have received a copy of the GNU General Public License
19     *  along with this program ; if not, write to the Free Software
20     *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21     *
22     * $Id$
23     *
24     ****************************************************************************/
25    
26     /*
27            this requires the directx sdk
28            place these paths at the top of the Tools|Options|Directories list
29    
30            headers:
31            C:\DXVCSDK\include
32            C:\DXVCSDK\samples\Multimedia\DirectShow\BaseClasses
33    
34            libraries (optional):
35            C:\DXVCSDK\samples\Multimedia\DirectShow\BaseClasses\Release
36    */
37    
38    
39    
40    #include <windows.h>
41    
42    #include <streams.h>
43    #include <initguid.h>
44    #include <olectl.h>
45    #if (1100 > _MSC_VER)
46    #include <olectlid.h>
47    #endif
48    #include <dvdmedia.h>   // VIDEOINFOHEADER2
49    
50    #include <xvid.h>               // XviD API
51    
52    #include "IXvidDecoder.h"
53    #include "CXvidDecoder.h"
54    #include "CAbout.h"
55    
56    
57    const AMOVIESETUP_MEDIATYPE sudInputPinTypes[] =
58    {
59        { &MEDIATYPE_Video, &CLSID_XVID },
60            { &MEDIATYPE_Video, &CLSID_XVID_UC },
61            { &MEDIATYPE_Video, &CLSID_DIVX },
62            { &MEDIATYPE_Video, &CLSID_DIVX_UC },
63            { &MEDIATYPE_Video, &CLSID_DX50 },
64            { &MEDIATYPE_Video, &CLSID_DX50_UC },
65    };
66    
67    const AMOVIESETUP_MEDIATYPE sudOutputPinTypes[] =
68    {
69        { &MEDIATYPE_Video, &MEDIASUBTYPE_NULL }
70    };
71    
72    
73    const AMOVIESETUP_PIN psudPins[] =
74    {
75            {
76                    L"Input",           // String pin name
77                    FALSE,              // Is it rendered
78                    FALSE,              // Is it an output
79                    FALSE,              // Allowed none
80                    FALSE,              // Allowed many
81                    &CLSID_NULL,        // Connects to filter
82                    L"Output",          // Connects to pin
83                    sizeof(sudInputPinTypes) / sizeof(AMOVIESETUP_MEDIATYPE), // Number of types
84                    &sudInputPinTypes[0]    // The pin details
85            },
86            {
87                    L"Output",          // String pin name
88                    FALSE,              // Is it rendered
89                    TRUE,               // Is it an output
90                    FALSE,              // Allowed none
91                    FALSE,              // Allowed many
92                    &CLSID_NULL,        // Connects to filter
93                    L"Input",           // Connects to pin
94                    sizeof(sudOutputPinTypes) / sizeof(AMOVIESETUP_MEDIATYPE),      // Number of types
95                    sudOutputPinTypes       // The pin details
96            }
97    };
98    
99    
100    const AMOVIESETUP_FILTER sudXvidDecoder =
101    {
102            &CLSID_XVID,                    // Filter CLSID
103            XVID_NAME_L,                    // Filter name
104            MERIT_PREFERRED,                // Its merit
105            sizeof(psudPins) / sizeof(AMOVIESETUP_PIN),     // Number of pins
106            psudPins                                // Pin details
107    };
108    
109    
110    // List of class IDs and creator functions for the class factory. This
111    // provides the link between the OLE entry point in the DLL and an object
112    // being created. The class factory will call the static CreateInstance
113    
114    CFactoryTemplate g_Templates[] =
115    {
116            {
117                    XVID_NAME_L,
118                    &CLSID_XVID,
119                    CXvidDecoder::CreateInstance,
120                    NULL,
121                    &sudXvidDecoder
122            },
123            {
124                    XVID_NAME_L L"About",
125                    &CLSID_CABOUT,
126                    CAbout::CreateInstance
127            }
128    
129    };
130    
131    int g_cTemplates = sizeof(g_Templates) / sizeof(CFactoryTemplate);
132    
133    
134    
135    
136    STDAPI DllRegisterServer()
137    {
138        return AMovieDllRegisterServer2( TRUE );
139    }
140    
141    
142    STDAPI DllUnregisterServer()
143    {
144        return AMovieDllRegisterServer2( FALSE );
145    }
146    
147    
148    /* create instance */
149    
150    CUnknown * WINAPI CXvidDecoder::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
151    {
152        CXvidDecoder * pNewObject = new CXvidDecoder(punk, phr);
153        if (pNewObject == NULL)
154            {
155            *phr = E_OUTOFMEMORY;
156        }
157        return pNewObject;
158    }
159    
160    
161    /* query interfaces */
162    
163    STDMETHODIMP CXvidDecoder::NonDelegatingQueryInterface(REFIID riid, void **ppv)
164    {
165            CheckPointer(ppv, E_POINTER);
166    
167            if (riid == IID_IXvidDecoder)
168            {
169                    return GetInterface((IXvidDecoder *) this, ppv);
170            }
171    
172            if (riid == IID_ISpecifyPropertyPages)
173            {
174            return GetInterface((ISpecifyPropertyPages *) this, ppv);
175            }
176    
177            return CVideoTransformFilter::NonDelegatingQueryInterface(riid, ppv);
178    }
179    
180    
181    
182    /* dummy decore() */
183    
184    static int dummy_xvid_decore(void * handle, int opt, void * param1, void * param2)
185    {
186            return XVID_ERR_FAIL;
187    }
188    
189    
190    
191    /* constructor */
192    
193    #define XVID_DLL_NAME           "xvid.dll"
194    #define XVID_GLOBAL_NAME        "xvid_global"
195    #define XVID_DECORE_NAME        "xvid_decore"
196    
197    CXvidDecoder::CXvidDecoder(LPUNKNOWN punk, HRESULT *phr) :
198        CVideoTransformFilter(NAME("CXvidDecoder"), punk, CLSID_XVID)
199    {
200            DPRINTF("Constructor");
201    
202            m_xvid_decore = dummy_xvid_decore;
203    
204            m_hdll = LoadLibrary(XVID_DLL_NAME);
205            if (m_hdll == NULL) {
206                    DPRINTF("dll load failed");
207                    MessageBox(0, XVID_DLL_NAME " not found","Error", 0);
208                    return;
209            }
210    
211            m_xvid_global = (int (__cdecl *)(void *, int, void *, void *))GetProcAddress(m_hdll, XVID_GLOBAL_NAME);
212            if (m_xvid_global == NULL) {
213                    MessageBox(0, XVID_GLOBAL_NAME "() not found", "Error", 0);
214                    return;
215            }
216    
217            m_xvid_decore = (int (__cdecl *)(void *, int, void *, void *))GetProcAddress(m_hdll, XVID_DECORE_NAME);
218            if (m_xvid_decore == NULL) {
219                    MessageBox(0, XVID_DECORE_NAME "() not found", "Error", 0);
220                    return;
221            }
222    
223            xvid_gbl_init_t init;
224            memset(&init, 0, sizeof(init));
225            init.version = XVID_VERSION;
226            if (m_xvid_global(0, XVID_GBL_INIT, &init, NULL) < 0)
227            {
228                    MessageBox(0, XVID_GLOBAL_NAME "() failed", "Error", 0);
229                    return;
230            }
231    
232            memset(&m_create, 0, sizeof(m_create));
233            m_create.version = XVID_VERSION;
234            m_create.handle = NULL;
235    
236            memset(&m_frame, 0, sizeof(m_frame));
237            m_frame.version = XVID_VERSION;
238    }
239    
240    
241    
242    /* destructor */
243    
244    CXvidDecoder::~CXvidDecoder()
245    {
246            DPRINTF("Destructor");
247    
248            if (m_create.handle != NULL)
249            {
250                    m_xvid_decore(m_create.handle, XVID_DEC_DESTROY, 0, 0);
251                    m_create.handle = NULL;
252            }
253    
254            if (m_hdll != NULL)
255            {
256                    FreeLibrary(m_hdll);
257                    m_hdll = NULL;
258            }
259    }
260    
261    
262    
263    /* check input type */
264    
265    HRESULT CXvidDecoder::CheckInputType(const CMediaType * mtIn)
266    {
267            DPRINTF("CheckInputType");
268            BITMAPINFOHEADER * hdr;
269    
270            if (*mtIn->Type() != MEDIATYPE_Video)
271            {
272                    DPRINTF("Error: Unknown Type");
273                    return VFW_E_TYPE_NOT_ACCEPTED;
274            }
275    
276            if (*mtIn->FormatType() == FORMAT_VideoInfo)
277            {
278                    VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) mtIn->Format();
279                    hdr = &vih->bmiHeader;
280            }
281            else if (*mtIn->FormatType() == FORMAT_VideoInfo2)
282            {
283                    VIDEOINFOHEADER2 * vih2 = (VIDEOINFOHEADER2 *) mtIn->Format();
284                    hdr = &vih2->bmiHeader;
285            }
286            else
287            {
288                    DPRINTF("Error: Unknown FormatType");
289                    return VFW_E_TYPE_NOT_ACCEPTED;
290            }
291    
292            if (hdr->biHeight < 0)
293            {
294                    DPRINTF("colorspace: inverted input format not supported");
295            }
296    
297            m_create.width = hdr->biWidth;
298            m_create.height = hdr->biHeight;
299    
300            switch(hdr->biCompression)
301            {
302            case FOURCC_XVID :
303    //      case FOURCC_DIVX :
304    //      case FOURCC_DX50 :
305                    break;
306    
307            default :
308                    DPRINTF("Unknown fourcc: 0x%08x (%c%c%c%c)",
309                            hdr->biCompression,
310                            (hdr->biCompression)&0xff,
311                            (hdr->biCompression>>8)&0xff,
312                            (hdr->biCompression>>16)&0xff,
313                            (hdr->biCompression>>24)&0xff);
314                    return VFW_E_TYPE_NOT_ACCEPTED;
315            }
316    
317            return S_OK;
318    }
319    
320    
321    #define USE_IYUV
322    #define USE_YV12
323    #define USE_YUY2
324    #define USE_YVYU
325    #define USE_UYVY
326    #define USE_RGB32
327    #define USE_RGB24
328    #define USE_RG555
329    #define USE_RG565
330    
331    /* get list of supported output colorspaces */
332    
333    HRESULT CXvidDecoder::GetMediaType(int iPosition, CMediaType *mtOut)
334    {
335            DPRINTF("GetMediaType");
336    
337            if (m_pInput->IsConnected() == FALSE)
338            {
339                    return E_UNEXPECTED;
340            }
341    
342            VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) mtOut->ReallocFormatBuffer(sizeof(VIDEOINFOHEADER));
343            if (vih == NULL)
344            {
345                    return E_OUTOFMEMORY;
346            }
347    
348            ZeroMemory(vih, sizeof (VIDEOINFOHEADER));
349            vih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
350            vih->bmiHeader.biWidth  = m_create.width;
351            vih->bmiHeader.biHeight = m_create.height;
352            vih->bmiHeader.biPlanes = 1;
353    
354            if (iPosition < 0)
355            {
356                    return E_INVALIDARG;
357            }
358    
359            switch(iPosition)
360            {
361            case 0  :
362    #ifdef USE_IYUV
363                    vih->bmiHeader.biCompression = MEDIASUBTYPE_IYUV.Data1;
364                    vih->bmiHeader.biBitCount = 12;
365                    mtOut->SetSubtype(&MEDIASUBTYPE_IYUV);
366                    break;
367    #endif
368            case 1  :
369    #ifdef USE_YV12
370                    vih->bmiHeader.biCompression = MEDIASUBTYPE_YV12.Data1;
371                    vih->bmiHeader.biBitCount = 12;
372                    mtOut->SetSubtype(&MEDIASUBTYPE_YV12);
373                    break;
374    #endif
375            case 2:
376    #ifdef USE_YUY2
377                    vih->bmiHeader.biCompression = MEDIASUBTYPE_YUY2.Data1;
378                    vih->bmiHeader.biBitCount = 16;
379                    mtOut->SetSubtype(&MEDIASUBTYPE_YUY2);
380                    break;
381    #endif
382            case 3 :
383    #ifdef USE_YVYU
384                    vih->bmiHeader.biCompression = MEDIASUBTYPE_YVYU.Data1;
385                    vih->bmiHeader.biBitCount = 16;
386                    mtOut->SetSubtype(&MEDIASUBTYPE_YVYU);
387                    break;
388    #endif
389            case 4 :
390    #ifdef USE_UYVY
391                    vih->bmiHeader.biCompression = MEDIASUBTYPE_UYVY.Data1;
392                    vih->bmiHeader.biBitCount = 16;
393                    mtOut->SetSubtype(&MEDIASUBTYPE_UYVY);
394                    break;
395    #endif
396            case 5 :
397    #ifdef USE_RGB32
398                    vih->bmiHeader.biCompression = BI_RGB;
399                    vih->bmiHeader.biBitCount = 32;
400                    mtOut->SetSubtype(&MEDIASUBTYPE_RGB32);
401                    break;
402    #endif
403            case 6 :
404    #ifdef USE_RGB24
405                    vih->bmiHeader.biCompression = BI_RGB;
406                    vih->bmiHeader.biBitCount = 24;
407                    mtOut->SetSubtype(&MEDIASUBTYPE_RGB24);
408                    break;
409    #endif
410            case 7 :
411    #ifdef USE_RG555
412                    vih->bmiHeader.biCompression = BI_RGB;
413                    vih->bmiHeader.biBitCount = 16;
414                    mtOut->SetSubtype(&MEDIASUBTYPE_RGB555);
415                    break;
416    #endif
417            case 8 :
418    #ifdef USE_RG565
419                    vih->bmiHeader.biCompression = BI_RGB;
420                    vih->bmiHeader.biBitCount = 16;
421                    mtOut->SetSubtype(&MEDIASUBTYPE_RGB565);
422                    break;
423    #endif
424            default :
425                    return VFW_S_NO_MORE_ITEMS;
426            }
427    
428            vih->bmiHeader.biSizeImage = GetBitmapSize(&vih->bmiHeader);
429    
430            mtOut->SetType(&MEDIATYPE_Video);
431            mtOut->SetFormatType(&FORMAT_VideoInfo);
432            mtOut->SetTemporalCompression(FALSE);
433            mtOut->SetSampleSize(vih->bmiHeader.biSizeImage);
434    
435            return S_OK;
436    }
437    
438    
439    /* (internal function) change colorspace */
440    
441    HRESULT CXvidDecoder::ChangeColorspace(GUID subtype, GUID formattype, void * format)
442    {
443            int rgb_flip;
444    
445            if (formattype == FORMAT_VideoInfo)
446            {
447                    VIDEOINFOHEADER * vih = (VIDEOINFOHEADER * )format;
448                    m_frame.output.stride[0] = (((vih->bmiHeader.biWidth * vih->bmiHeader.biBitCount) + 31) & ~31) >> 3;
449                    rgb_flip = (vih->bmiHeader.biHeight < 0 ? 0 : XVID_CSP_VFLIP);
450            }
451            else if (formattype == FORMAT_VideoInfo2)
452            {
453                    VIDEOINFOHEADER2 * vih2 = (VIDEOINFOHEADER2 * )format;
454                    m_frame.output.stride[0] = (((vih2->bmiHeader.biWidth * vih2->bmiHeader.biBitCount) + 31) & ~31) >> 3;
455                    rgb_flip = (vih2->bmiHeader.biHeight < 0 ? 0 : XVID_CSP_VFLIP);
456            }
457            else
458            {
459                    return S_FALSE;
460            }
461    
462            if (subtype == MEDIASUBTYPE_IYUV)
463            {
464                    DPRINTF("IYUV");
465                    m_frame.output.csp = XVID_CSP_I420;
466                    m_frame.output.stride[0] = (m_frame.output.stride[0] * 2) / 3;  /* planar format fix */
467            }
468            else if (subtype == MEDIASUBTYPE_YV12)
469            {
470                    DPRINTF("YV12");
471                    m_frame.output.csp = XVID_CSP_YV12;
472                    m_frame.output.stride[0] = (m_frame.output.stride[0] * 2) / 3;  /* planar format fix */
473            }
474            else if (subtype == MEDIASUBTYPE_YUY2)
475            {
476                    DPRINTF("YUY2");
477                    m_frame.output.csp = XVID_CSP_YUY2;
478            }
479            else if (subtype == MEDIASUBTYPE_YVYU)
480            {
481                    DPRINTF("YVYU");
482                    m_frame.output.csp = XVID_CSP_YVYU;
483            }
484            else if (subtype == MEDIASUBTYPE_UYVY)
485            {
486                    DPRINTF("UYVY");
487                    m_frame.output.csp = XVID_CSP_UYVY;
488            }
489            else if (subtype == MEDIASUBTYPE_RGB32)
490            {
491                    DPRINTF("RGB32");
492                    m_frame.output.csp = rgb_flip | XVID_CSP_BGRA;
493            }
494            else if (subtype == MEDIASUBTYPE_RGB24)
495            {
496                    DPRINTF("RGB24");
497                    m_frame.output.csp = rgb_flip | XVID_CSP_BGR;
498            }
499            else if (subtype == MEDIASUBTYPE_RGB555)
500            {
501                    DPRINTF("RGB555");
502                    m_frame.output.csp = rgb_flip | XVID_CSP_RGB555;
503            }
504            else if (subtype == MEDIASUBTYPE_RGB565)
505            {
506                    DPRINTF("RGB565");
507                    m_frame.output.csp = rgb_flip | XVID_CSP_RGB565;
508            }
509            else if (subtype == GUID_NULL)
510            {
511                    m_frame.output.csp = XVID_CSP_NULL;
512            }
513            else
514            {
515                    return S_FALSE;
516            }
517    
518            return S_OK;
519    }
520    
521    
522    /* set output colorspace */
523    
524    HRESULT CXvidDecoder::SetMediaType(PIN_DIRECTION direction, const CMediaType *pmt)
525    {
526            DPRINTF("SetMediaType");
527    
528            if (direction == PINDIR_OUTPUT)
529            {
530                    return ChangeColorspace(*pmt->Subtype(), *pmt->FormatType(), pmt->Format());
531            }
532    
533            return S_OK;
534    }
535    
536    
537    /* check input<->output compatiblity */
538    
539    HRESULT CXvidDecoder::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
540    {
541            DPRINTF("CheckTransform");
542            return S_OK;
543    }
544    
545    
546    /* alloc output buffer */
547    
548    HRESULT CXvidDecoder::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
549    {
550            DPRINTF("DecideBufferSize");
551            HRESULT result;
552            ALLOCATOR_PROPERTIES ppropActual;
553    
554            if (m_pInput->IsConnected() == FALSE)
555            {
556                    return E_UNEXPECTED;
557            }
558    
559            ppropInputRequest->cBuffers = 1;
560            ppropInputRequest->cbBuffer = m_create.width * m_create.height * 4;
561            // cbAlign causes problems with the resize filter */
562            // ppropInputRequest->cbAlign = 16;
563            ppropInputRequest->cbPrefix = 0;
564    
565            result = pAlloc->SetProperties(ppropInputRequest, &ppropActual);
566            if (result != S_OK)
567            {
568                    return result;
569            }
570    
571            if (ppropActual.cbBuffer < ppropInputRequest->cbBuffer)
572            {
573                    return E_FAIL;
574            }
575    
576            return S_OK;
577    }
578    
579    
580    /* decode frame */
581    
582    HRESULT CXvidDecoder::Transform(IMediaSample *pIn, IMediaSample *pOut)
583    {
584            DPRINTF("Transform");
585            xvid_dec_stats_t stats;
586        int length;
587    
588            memset(&stats, 0, sizeof(stats));
589            stats.version = XVID_VERSION;
590    
591            if (m_create.handle == NULL)
592            {
593                    if (m_xvid_decore(0, XVID_DEC_CREATE, &m_create, 0) < 0)
594                    {
595                DPRINTF("*** XVID_DEC_CREATE error");
596                            return S_FALSE;
597                    }
598            }
599    
600            AM_MEDIA_TYPE * mtOut;
601            pOut->GetMediaType(&mtOut);
602            if (mtOut != NULL)
603            {
604                    HRESULT result;
605    
606                    result = ChangeColorspace(mtOut->subtype, mtOut->formattype, mtOut->pbFormat);
607                    DeleteMediaType(mtOut);
608    
609                    if (result != S_OK)
610                    {
611                DPRINTF("*** ChangeColorspace error");
612                            return result;
613                    }
614            }
615    
616            m_frame.length = pIn->GetActualDataLength();
617            if (pIn->GetPointer((BYTE**)&m_frame.bitstream) != S_OK)
618            {
619                    return S_FALSE;
620            }
621    
622            if (pOut->GetPointer((BYTE**)&m_frame.output.plane[0]) != S_OK)
623            {
624                    return S_FALSE;
625            }
626    
627            m_frame.general = XVID_LOWDELAY;
628            if (pIn->IsDiscontinuity() == S_OK)
629                    m_frame.general = XVID_DISCONTINUITY;
630    
631    repeat :
632    
633            if (pIn->IsPreroll() != S_OK)
634            {
635                    length = m_xvid_decore(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats);
636                    if (length < 0)
637                    {
638                DPRINTF("*** XVID_DEC_DECODE");
639                            return S_FALSE;
640                    }
641            }
642            else
643            {
644                    int tmp = m_frame.output.csp;
645                    m_frame.output.csp = XVID_CSP_NULL;
646    
647                    length = m_xvid_decore(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats);
648                    if (length < 0)
649                    {
650                DPRINTF("*** XVID_DEC_DECODE");
651                            return S_FALSE;
652                    }
653    
654                    m_frame.output.csp = tmp;
655            }
656    
657            if (stats.type == XVID_TYPE_VOL)
658            {
659                    if (stats.data.vol.width != m_create.width ||
660                            stats.data.vol.height != m_create.height)
661                    {
662                            DPRINTF("TODO: auto-resize");
663                            return S_FALSE;
664                    }
665    
666                    m_frame.bitstream = (BYTE*)m_frame.bitstream + length;
667                    m_frame.length -= length;
668                    goto repeat;
669            }
670    
671            return S_OK;
672    }
673    
674    
675    /* get property page list */
676    
677    STDMETHODIMP CXvidDecoder::GetPages(CAUUID * pPages)
678    {
679            DPRINTF("GetPages");
680    
681            pPages->cElems = 1;
682            pPages->pElems = (GUID *)CoTaskMemAlloc(pPages->cElems * sizeof(GUID));
683            if (pPages->pElems == NULL)
684            {
685                    return E_OUTOFMEMORY;
686            }
687            pPages->pElems[0] = CLSID_CABOUT;
688    
689            return S_OK;
690    }
691    
692    
693    /* cleanup pages */
694    
695    STDMETHODIMP CXvidDecoder::FreePages(CAUUID * pPages)
696    {
697            DPRINTF("FreePages");
698            CoTaskMemFree(pPages->pElems);
699            return S_OK;
700    }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.1.2.2

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