[prev in list] [next in list] [prev in thread] [next in thread] 

List:       helix-datatype-cvs
Subject:    [Datatype-cvs] wm/video/renderer wmvdecoder.cpp, 1.5.2.2,
From:       gahluwalia () helixcommunity ! org
Date:       2009-09-23 6:05:25
Message-ID: 200909230715.n8N7Fbut011998 () mailer ! progressive-comp ! com
[Download RAW message or body]

Update of /cvsroot/datatype/wm/video/renderer
In directory cvs01.internal.helixcommunity.org:/tmp/cvs-serv19246

Modified Files:
      Tag: hxclient_3_1_0_atlas
	wmvdecoder.cpp wmvformat.cpp wmvrender.cpp wmvrenderdll 
Log Message:
Adding support for vc1 omx hardware decoder

Index: wmvdecoder.cpp
===================================================================
RCS file: /cvsroot/datatype/wm/video/renderer/wmvdecoder.cpp,v
retrieving revision 1.5.2.2
retrieving revision 1.5.2.3
diff -u -d -r1.5.2.2 -r1.5.2.3
--- wmvdecoder.cpp	21 Jul 2008 20:41:47 -0000	1.5.2.2
+++ wmvdecoder.cpp	23 Sep 2009 06:05:21 -0000	1.5.2.3
@@ -32,7 +32,6 @@
  * Contributor(s): 
  *  
  * ***** END LICENSE BLOCK ***** */ 
-
 #include "hlxclib/string.h"
 #include "hxtypes.h"
 #include "hxresult.h"
@@ -50,6 +49,7 @@
 #include "hxprefutil.h"
 #include "pckunpck.h"
 #include "codeclib.h"
+#include "hxalloc.h"
 //#define HELIX_FEATURE_LOGLEVEL_NONE // Uncomment to turn logging off
 #include "hxtlogutil.h"
 #include "wmvdecoder.h"
@@ -66,17 +66,22 @@
 const GUID CWMVideoDecoder::m_guidVideoInfo = {0x05589f80, 0xc356, 0x11ce, {0xbf, \
0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};  const HXWM2HXFOURCC \
CWMVideoDecoder::m_WM2HXFourCC[] =  {
-    {0x31564D57, 0x776D7638}, // WMV1 -> 'wmv8' (WM Video 7/8)
-    {0x32564D57, 0x776D7638}, // WMV2 -> 'wmv8' (WM Video 7/8)
-    {0x33564D57, 0x776D7639}, // WMV3 -> 'wmv9' (WM Video 9)
-    {0x3153534D, 0x776D7639}, // MSS1 -> 'wmv9' (WM Video Screen)
-    {0x3253534D, 0x776D7639}, // MSS2 -> 'wmv9' (WM Video Screen)
-    {0x41564D57, 0x776D7639}, // WMVA -> 'wmv9' (WM Video Advanced Profile)
-    {0x31435657, 0x776D7639}, // WVC1 -> 'wmv9' (WM VC-1)
-    {0x3234504D, 0x776D7638}, // MP42 -> 'wmv8' (Microsoft MPEG-4 Version 2)
-    {0x3334504D, 0x776D7638}, // MP43 -> 'wmv8' (Microsoft MPEG-4 Version 3)
-    {0x5334504D, 0x776D7638}, // MP4S -> 'wmv8' (Microsoft ISO MPEG-4 version 1.1)
-    {0x00000000, 0x00000000}  // Marks the end of the array
+#ifdef HELIX_FEATURE_OMX_VIDEO_DECODER_VC1
+    {0x33564D57, 0x4f4d5856, "(omxv) WMV3 (WM Video 9)"}, // WMV3 -> 'omx' (WM Video \
9) +    {0x31435657,0x4f4d5856, "(omxv) WVC1 (WM VC-1)"}, // WVC1 -> 'omxv' (WM VC-1)
+    {0x41564D57,0x4f4d5856, "(omxv) WMVA (WM Video Advanced Profile)"}, // WMVA -> \
'wmv9' (WM Video Advanced Profile) +#endif
+    {0x31564D57, 0x776D7638, "(wmv8) WM Video 7/8"}, // WMV1 -> 'wmv8' (WM Video \
7/8) +    {0x32564D57, 0x776D7638, "(wmv8) WM Video 7/8"}, // WMV2 -> 'wmv8' (WM \
Video 7/8) +    {0x33564D57, 0x776D7639, "(wmv9) WM Video 9"}, // WMV3 -> 'wmv9' (WM \
Video 9) +    {0x3153534D, 0x776D7639, "(wmv9) WM Video Screen"}, // MSS1 -> 'wmv9' \
(WM Video Screen) +    {0x3253534D, 0x776D7639, "(wmv9) WM Video Screen"}, // MSS2 -> \
'wmv9' (WM Video Screen) +    {0x41564D57, 0x776D7639, "(wmv9) WM Video Advanced \
Profile"}, // WMVA -> 'wmv9' (WM Video Advanced Profile) +    {0x31435657, \
0x776D7639, "(wmv9) WM VC-1"}, // WVC1 -> 'wmv9' (WM VC-1) +    {0x3234504D, \
0x776D7638, "(wmv8) Microsoft MPEG-4 Version 2"}, // MP42 -> 'wmv8' (Microsoft MPEG-4 \
Version 2) +    {0x3334504D, 0x776D7638, "(wmv8) Microsoft MPEG-4 Version 3"}, // \
MP43 -> 'wmv8' (Microsoft MPEG-4 Version 3) +    {0x5334504D, 0x776D7638, "(wmv8) \
Microsoft ISO MPEG-4 Version 1.1"}, // MP4S -> 'wmv8' (Microsoft ISO MPEG-4 version \
1.1) +    {0x00000000, 0x00000000, ""}  // Marks the end of the array   
 };
 
 CWMVideoDecoder::CWMVideoDecoder()
@@ -204,46 +209,65 @@
 HX_RESULT CWMVideoDecoder::Open()
 {
     HX_RESULT retVal = HXR_FAIL;
-
-    if (m_bInitialized)
+    HXBOOL bTryAgain=FALSE;
+	
+    if (!m_bInitialized)
+    {
+        return HXR_FAIL;
+    }
+    do
     {
+        bTryAgain = FALSE;
         // Load the codec dll
-		retVal = OpenCodec(m_ulCodec4CC);		
+        retVal = OpenCodec(m_ulCodec4CC);		
         if (SUCCEEDED(retVal))
         {
-            // Create a single stream
-		    retVal = OpenStream();
-		    if (retVal == HXR_UNSUPPORTED_VIDEO)
+            //Create a single stream
+	        retVal = OpenStream();
+    	    if (SUCCEEDED(retVal))
+	        {
+	           break;
+	        }
+        }
+        retVal = GetCodec4CC(m_VideoInfoHeader.m_bmiHeader.biCompression, \
&m_ulCodec4CC); +        if (SUCCEEDED(retVal))
+    	{
+    	    // We found another 4cc mapping, so try again
+    	    bTryAgain = TRUE;
+    	    // Create the codec string from the codec 4cc
+    	    HX_RELEASE(m_pCodecNameStr);
+    	    retVal = CreateCodecNameString(m_pContext, m_ulCodec4CC, &m_pCodecNameStr);
+    	}        
+     } while (bTryAgain);
+	
+    if (retVal == HXR_UNSUPPORTED_VIDEO)
+    { 
+        // This is a version of WMV which is not supported.
+        // Determine which version it is.
+        const char* pszCodecName = NULL;
+        switch (m_VideoInfoHeader.m_bmiHeader.biCompression)
+        {
+            case 0x31564D57: pszCodecName = "Windows Media Video 7";        break;
+			case 0x32564D57: pszCodecName = "Windows Media Video 8";        break;
+            case 0x3153534D: pszCodecName = "Windows Media Video 7 Screen"; break;
+            case 0x3253534D: pszCodecName = "Windows Media Video 9 Screen"; break;
+        }
+        if (m_pContext && pszCodecName)
+        {
+            // Create the error string
+            CHXString strErr("This clip contains ");
+            strErr += pszCodecName;
+            strErr += ", which is currently unsupported.";
+            // QI for IHXErrorMessages
+            IHXErrorMessages* pErrMsg = NULL;
+            m_pContext->QueryInterface(IID_IHXErrorMessages, (void**) &pErrMsg);
+            if (pErrMsg)
             {
-                // This is a version of WMV which is not supported.
-                // Determine which version it is.
-                const char* pszCodecName = NULL;
-                switch (m_VideoInfoHeader.m_bmiHeader.biCompression)
-                {
-                    case 0x31564D57: pszCodecName = "Windows Media Video 7";        \
                break;
-					case 0x32564D57: pszCodecName = "Windows Media Video 8";        break;
-                    case 0x3153534D: pszCodecName = "Windows Media Video 7 Screen"; \
                break;
-                    case 0x3253534D: pszCodecName = "Windows Media Video 9 Screen"; \
                break;
-                }
-                if (m_pContext && pszCodecName)
-                {
-                    // Create the error string
-                    CHXString strErr("This clip contains ");
-                    strErr += pszCodecName;
-                    strErr += ", which is currently unsupported.";
-                    // QI for IHXErrorMessages
-                    IHXErrorMessages* pErrMsg = NULL;
-                    m_pContext->QueryInterface(IID_IHXErrorMessages, (void**) \
                &pErrMsg);
-                    if (pErrMsg)
-                    {
-                        pErrMsg->Report(HXLOG_ERR, retVal, 0, (const char*) strErr, \
                NULL);
-                    }
-                    HX_RELEASE(pErrMsg);
-                }
+                pErrMsg->Report(HXLOG_ERR, retVal, 0, (const char*) strErr, NULL);
             }
-        }
+            HX_RELEASE(pErrMsg);
+        }           
     }
-
     return retVal;
 }
 
@@ -583,6 +607,13 @@
             codecInit.pOutMof   = (HX_MOF*) &mofOut;
             codecInit.memoryRef = (HXMEMORY) m_pInputAllocator;
             codecInit.pContext  = m_pContext;
+#if defined HELIX_FEATURE_OMX_VIDEO_DECODER_VC1
+            //  Set MofTag to "WVC1"  so that omx video decoder wrapper can identify \
which decoder to load +            if(pMofIn->submoftag == HX_OMXV_ID) // "OMXV"
+            {
+                pMofIn->submoftag = HX_WVC1VIDEO_ID; // "WVC1"
+            }
+#endif	
             // Open the stream
             retVal = m_pCodecLib->PNCodec_StreamOpen(m_pCodec, &m_pStream, \
&codecInit);  if (SUCCEEDED(retVal))
@@ -663,19 +694,35 @@
 HX_RESULT CWMVideoDecoder::GetCodec4CC(UINT32 ulWMFourCC, UINT32* pulCodec4CC)
 {
     HX_RESULT retVal = HXR_FAIL;
-
     if (pulCodec4CC)
     {
         // See if the GUID matches a supported GUID in our table
         HXBOOL         bFound = FALSE;
+        HXBOOL         bFoundStart = TRUE;		
         HXWM2HXFOURCC* pEntry = (HXWM2HXFOURCC*) &m_WM2HXFourCC[0];
+    	if (*pulCodec4CC != 0)
+    	{
+    	    // Start search from previous location
+    	    bFoundStart = FALSE;
+    	}		
         while (pEntry && pEntry->m_ulHX4CC)
         {
-            if (ulWMFourCC == pEntry->m_ulWM4CC)
+            if (!bFoundStart && *pulCodec4CC == pEntry->m_ulWM4CC)
+            {  
+                if( ulWMFourCC == pEntry->m_ulWM4CC)
+                {
+                    *pulCodec4CC = pEntry->m_ulHX4CC;
+                    bFound       = TRUE;
+                    break;
+            	}
+                bFoundStart       = TRUE;
+                break;
+            }
+            else if (ulWMFourCC == pEntry->m_ulWM4CC && bFoundStart)
             {
                 *pulCodec4CC = pEntry->m_ulHX4CC;
-                bFound       = TRUE;
-                break;
+		         bFound       = TRUE;
+		         break;
             }
             pEntry++;
         }
@@ -685,7 +732,6 @@
             retVal = HXR_OK;
         }
     }
-
     return retVal;
 }
 
@@ -716,3 +762,27 @@
 
     return retVal;
 }
+
+void 
+CWMVideoDecoder::ReleaseBuffer(UINT8* pBuff)
+{
+    HXCODEC_DATA sData;
+    sData.data = pBuff;
+    m_pCodecLib->PNStream_ReleaseFrame(m_pStream,&sData);
+}
+
+HX_RESULT 
+CWMVideoDecoder::GetProperty(UINT32 id, void* pPropVal)
+{
+    
+    return m_pCodecLib->PNStream_GetProperty(m_pStream, 
+				      id,
+				      pPropVal);
+}
+
+
+HX_RESULT 
+CWMVideoDecoder::SetSeek(UINT32 uval)
+{
+    return m_pCodecLib->PNStream_SetProperty(m_pStream, SP_SEEK, &uval);
+}

Index: wmvformat.cpp
===================================================================
RCS file: /cvsroot/datatype/wm/video/renderer/wmvformat.cpp,v
retrieving revision 1.5.12.2
retrieving revision 1.5.12.3
diff -u -d -r1.5.12.2 -r1.5.12.3
--- wmvformat.cpp	15 Apr 2009 11:50:53 -0000	1.5.12.2
+++ wmvformat.cpp	23 Sep 2009 06:05:21 -0000	1.5.12.3
@@ -52,6 +52,9 @@
 #include "wmvdecoder.h"
 #include "wmvrender.h"
 #include "wmvformat.h"
+#include "hxvsurf.h"
+#include "hxmtypes.h"
+
 
 #if defined(HELIX_FEATURE_MIN_HEAP)
 #define HX_WMV_MAX_BUFFERED_DECODED_FRAMES           4
@@ -106,6 +109,8 @@
 	m_ulDecodeCount 				= 0;
 	m_ulFrameCount 					= 0;
     m_pContext                     = NULL;
+    m_bDecoderMemMgt               = FALSE;
+    m_pOutputAllocator             = NULL;
     // Sanity check
     HX_ASSERT(m_pCommonClassFactory);
     HX_ASSERT(m_pWMVideoRenderer);
@@ -152,6 +157,13 @@
                                        pOpaqueData, &cInfo);
             if (SUCCEEDED(retVal))
             {
+#ifdef HELIX_FEATURE_USE_OMX_DECODED_BUFFERS            
+                if( cInfo.m_ulNumSubStreams > 1)
+                {
+                    ClearWMOpaqueDataInfo(&cInfo);
+                    return HXR_UNSUPPORTED_VIDEO;
+                }
+#endif				
                 // Assign the number of substreams
                 m_ulNumSubStreams = cInfo.m_ulNumSubStreams;
                 // Initialize the active substream to the number
@@ -195,8 +207,7 @@
                             // NULL out the array
                             memset(m_ppWMVideoDecoder, 0, sizeof(CWMVideoDecoder*) * \
m_ulNumSubStreams);  // Get the output allocator from the renderer
-                            CHXMemoryAllocator* pOutputAlloc = NULL;
-                            retVal = \
m_pWMVideoRenderer->GetOutputAllocator(&pOutputAlloc); +                            \
retVal = m_pWMVideoRenderer->GetOutputAllocator(&m_pOutputAllocator);  if \
(SUCCEEDED(retVal))  {
                                 // Now loop through each decoder, creating and \
initializing it @@ -212,7 +223,7 @@
                                                                              this,
                                                                              \
                cInfo.m_ppSubStreamHdr[i],
                                                                              \
                m_pInputAllocator,
-                                                                             \
pOutputAlloc, +                                                                       \
                m_pOutputAllocator,
                                                                              \
                bWillDropPostDecode,
                                                                              \
ulPostDecodeDropThreshold);  if (SUCCEEDED(retVal))
@@ -221,6 +232,7 @@
                                             // XXXMEH - later for optimization, we \
                may want to
                                             // delay the opening of the codec until \
                we actually need it.
                                             retVal = m_ppWMVideoDecoder[i]->Open();
+                                            \
m_ppWMVideoDecoder[i]->GetProperty(SP_HWMEM_MGT, &m_bDecoderMemMgt);											  }
                                     }
                                     else
@@ -272,7 +284,6 @@
                                     }
                                 }
                             }
-                            HX_RELEASE(pOutputAlloc);
                         }
                     }
                 }
@@ -309,11 +320,13 @@
 
     FlushDecodedRingBuffer();
     HX_DELETE(m_pDecodedRingBuffer);
+   _Reset();
     ClearDecoderArray();
 
-    _Reset();
+ 
 
     HX_DELETE(m_pInputAllocator);
+    HX_RELEASE(m_pOutputAllocator);
     HX_DELETE(m_pCodecOutputBitmapInfoHeader);
     HX_DELETE(m_pRuleToSubStreamMap);
     HX_DELETE(m_pRuleToFlagMap);
@@ -468,13 +481,7 @@
         {
             if (pData->data)
             {
-                CHXMemoryAllocator* pAlloc = NULL;
-                HX_RESULT rv = m_pWMVideoRenderer->GetOutputAllocator(&pAlloc);
-                if (pAlloc)
-                {
-                    pAlloc->ReleasePacketPtr(pData->data);
-                }
-                HX_RELEASE(pAlloc);
+            	_KillWMVOutputBuffer(pData->data);
                 m_pWMVideoRenderer->ReportDroppedFrame();
             }
         }
@@ -739,8 +746,8 @@
     }
 
     // Check for decoded frames already available
-    pDecodedPacket = (HXCODEC_DATA*) m_pDecodedRingBuffer->Get();
 
+    pDecodedPacket = (HXCODEC_DATA*) m_pDecodedRingBuffer->Get();
     // Loop processing frames in the following order:
     // 1. Return (queue) currently outstanding decoded frames (mormally is 0)
     // 2. Decode input frame (must do unless frame dropped pre-decode)
@@ -890,7 +897,7 @@
                 pVideoPacket->SetBufferKiller(KillWMVOutputBuffer);
                 pVideoPacket->SetSampleDescKiller(KillWMVSampleDesc);
                 // Set the user data
-                pVideoPacket->m_pUserData = m_pWMVideoRenderer;
+                pVideoPacket->m_pUserData = this;
                 // NULL out the decoded packet pointer
                 pDecodedPacket = NULL;
                 // Assign the decoded frame pointer
@@ -913,8 +920,9 @@
         }
         
         // See if more decoded frames are avaialable
-        if (CanReturnDecodedPacket())
+        if (CanReturnDecodedPacket() && SUCCEEDED(status))
         {
+
             pDecodedPacket = (HXCODEC_DATA*) m_pDecodedRingBuffer->Get();
         }
     }
@@ -945,7 +953,7 @@
 HX_RESULT CWMVideoFormat::SetupOutputFormat(HX_MOF* pMOF)
 {
     HX_RESULT retVal = HXR_FAIL;
-
+    UINT32 ulColorType;
     if (pMOF)
     {
         if (!m_pCodecOutputBitmapInfoHeader)
@@ -962,11 +970,18 @@
             retVal = HXR_OK;
             // Get the media size
             HX_FORMAT_IMAGE* pFormatImage = (HX_FORMAT_IMAGE*) pMOF;
+	        switch (pFormatImage->submoftag)
+	        {
+	            case HX_RGB3_ID:    ulColorType = HX_RGB; break;
+	            case HX_YUY2_ID:    ulColorType = HX_YUY2; break;
+	            case HX_OMXV_ID:    ulColorType = HX_OMXV; break;
+	            default:            ulColorType = HX_I420; break;
+	        }			
             m_MediaSize.cy = pFormatImage->uiHeight;
             m_MediaSize.cx = pFormatImage->uiWidth;
             // Set the HXBitmapInfoHeader struct
             m_pCodecOutputBitmapInfoHeader->biBitCount    = \
                pFormatImage->uiBitCount;
-            m_pCodecOutputBitmapInfoHeader->biCompression = pFormatImage->submoftag;
+            m_pCodecOutputBitmapInfoHeader->biCompression = ulColorType;
             m_pCodecOutputBitmapInfoHeader->biWidth       = pFormatImage->uiWidth;
             m_pCodecOutputBitmapInfoHeader->biHeight      = pFormatImage->uiHeight;
             m_pCodecOutputBitmapInfoHeader->biPlanes      = 1;
@@ -1047,6 +1062,11 @@
     m_ulHeightContainedInSegment = 0;
     m_MediaSize.cx               = 0;
     m_MediaSize.cy               = 0;
+    if(m_ppWMVideoDecoder && m_ppWMVideoDecoder[m_ulActiveSubStreamIndex])
+    {
+        UINT32 uTime = GetStartTime();
+        m_ppWMVideoDecoder[m_ulActiveSubStreamIndex]->SetSeek(uTime);
+    }	
 }
 
 void CWMVideoFormat::ReleaseDecodedPacket(HXCODEC_DATA*& rpDecodedPacket)
@@ -1054,7 +1074,7 @@
     HX_ASSERT(rpDecodedPacket);
     if (rpDecodedPacket)
     {
-        KillWMVSampleDesc(rpDecodedPacket, m_pWMVideoRenderer);
+        KillWMVSampleDesc(rpDecodedPacket, this);
         rpDecodedPacket = NULL;
     }
 }
@@ -1202,19 +1222,37 @@
 {
     if (pBuffer)
     {
-        CWMVideoRenderer* pRenderer = (CWMVideoRenderer*) pUserData;
-        HX_ASSERT(pRenderer);
-        if (pRenderer)
+        CWMVideoFormat* pVidFmt = (CWMVideoFormat*)pUserData;
+        HX_ASSERT(pVidFmt);
+        if (pVidFmt)
         {
-            // Get the allocator
-            CHXMemoryAllocator* pAlloc = NULL;
-            pRenderer->GetOutputAllocator(&pAlloc);
-            if (pAlloc)
-            {
-                pAlloc->ReleasePacketPtr((BYTE*) pBuffer);
-            }
-            HX_RELEASE(pAlloc);
+            pVidFmt->_KillWMVOutputBuffer(pBuffer);
         }
     }
 }
 
+void CWMVideoFormat::_KillWMVOutputBuffer(void* pBuffer)
+{
+    if(m_bDecoderMemMgt)
+    {
+        DecoderReleaseBuffer((UINT8*)pBuffer);
+    }
+    else
+    {
+         if (m_pOutputAllocator)
+         {
+            m_pOutputAllocator->ReleasePacketPtr((UINT8*) pBuffer);
+         }
+    }
+}
+
+void 
+CWMVideoFormat::DecoderReleaseBuffer(UINT8* pBuff)
+{
+    if(m_ppWMVideoDecoder && m_ppWMVideoDecoder[m_ulActiveSubStreamIndex])
+    {
+   	    m_ppWMVideoDecoder[m_ulActiveSubStreamIndex]->ReleaseBuffer(pBuff);
+   	}
+}
+
+

Index: wmvrender.cpp
===================================================================
RCS file: /cvsroot/datatype/wm/video/renderer/wmvrender.cpp,v
retrieving revision 1.2.2.4
retrieving revision 1.2.2.5
diff -u -d -r1.2.2.4 -r1.2.2.5
--- wmvrender.cpp	13 Aug 2008 06:11:02 -0000	1.2.2.4
+++ wmvrender.cpp	23 Sep 2009 06:05:21 -0000	1.2.2.5
@@ -276,3 +276,16 @@
 {
 	return m_dDecodeTimeRatio;
 }
+STDMETHODIMP CWMVideoRenderer::EndStream()
+{
+    if (m_pActiveVideoPacket)
+    {
+        m_pActiveVideoPacket->Clear();
+        delete m_pActiveVideoPacket;
+        m_pActiveVideoPacket = NULL;
+    }
+
+    CVideoRenderer::EndStream();
+
+    return HXR_OK;
+}

Index: wmvrenderdll
===================================================================
RCS file: /cvsroot/datatype/wm/video/renderer/wmvrenderdll,v
retrieving revision 1.3
retrieving revision 1.3.12.1
diff -u -d -r1.3 -r1.3.12.1
--- wmvrenderdll	15 Jun 2006 14:34:46 -0000	1.3
+++ wmvrenderdll	23 Sep 2009 06:05:21 -0000	1.3.12.1
@@ -37,6 +37,9 @@
 
 UmakefileVersion(2,2)
 
+if project.IsDefined("HELIX_FEATURE_USE_OMX_DECODED_BUFFERS"):
+    project.AddDefines('HW_VIDEO_MEMORY_FRONTEND', 'HELIX_FEATURE_MIN_HEAP')
+
 project.AddModuleIncludes("common/include",
                           "client/include",
                           "client/videosvc/include",


_______________________________________________
Datatype-cvs mailing list
Datatype-cvs@helixcommunity.org
http://lists.helixcommunity.org/mailman/listinfo/datatype-cvs


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic