Logo Search packages:      
Sourcecode: helix-player version File versions

vidrend.cpp

/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: vidrend.cpp,v 1.30.2.5 2005/02/01 00:00:15 nhart Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

/****************************************************************************
 *  Debug Settings
 */
// #define ENABLE_TRACE
// #define ENABLE_SYNC_TRACE
// #define ENABLE_SCHED_TRACE
// #define ENABLE_FETCH_TRACE
// #define ENABLE_INPUT_TRACE


/****************************************************************************
 *  Operational Compile-time Settings
 */
// #define SYNC_RESIZE_OK
// #define SYNC_VS_SWITCHING
// #define REBUFFER_ON_VIDEO
#define SET_NONZERO_VIEWFRAME_ONLY
#define RESIZE_AFTER_SITE_ATTACHED
#define DO_ABSOLUTE_TIMING
#ifdef HELIX_FEATURE_VIDREND_SYNCSMOOTHING
#define SYNC_SMOOTHING
#define SYNC_PRE_SMOOTHING
#endif      // HELIX_FEATURE_VIDREND_SYNCSMOOTHING
#define DEFAULT_VS2_TARGETRECT

#define MAX_ULONG32_AS_DOUBLE ((double) ((ULONG32) 0xFFFFFFFF))
#define MAX_LONG32_AS_DOUBLE  ((double) ((LONG32) 0x7FFFFFFF))
#define MIN_LONG32_AS_DOUBLE  ((double) ((LONG32) 0x80000000))

#if defined(_MACINTOSH) || defined(_MAC_UNIX)
#define OSGRANULE_BOOSTING_ENABLED  FALSE
#else // _MACINTOSH
#define OSGRANULE_BOOSTING_ENABLED  TRUE
#endif      // _MACINTOSH

/****************************************************************************
 *  Debug Macros
 */
#ifdef ENABLE_TRACE
#define HX_TRACE_THINGY(x, m, l)                            \
    {                                     \
      FILE* f1;                           \
      f1 = ::fopen(x, "a+");                    \
      (f1)?(::fprintf(f1, "%ld - %s = %ld \n", HX_GET_BETTERTICKCOUNT(), m, l), ::fclose(f1)):(0);\
    }
#else // ENABLE_TRACE
#define HX_TRACE_THINGY(x, m, l)
#endif      // ENABLE_TRACE


/****************************************************************************
 *  Defines
 */
#define BASE_VIDEO_RENDERER_NAME    "Basic Video"
#define NAME_STATS_EXT            ".name"
#define C4CC_STATS_EXT            ".CodecFourCC"

#if defined(HELIX_FEATURE_VIDREND_NO_DEFAULT_WINDOW_SIZE)
#define DEFAULT_WIN_SIZE_X        0
#define DEFAULT_WIN_SIZE_Y        0
#else
#define DEFAULT_WIN_SIZE_X        160
#define DEFAULT_WIN_SIZE_Y        120
#endif

#define SYNC_INTERVAL             20          // in milliseconds
#define EARLY_FRAME_TOL           3     // in milliseconds
#define LATE_FRAME_TOL            30          // in milliseconds
#define NO_FRAMES_POLLING_INTERVAL  20        // in milliseconds
#define MAX_SLEEP_TIME            132         // in milliseconds
#define BLT_PACKET_QUEUE_SIZE     3     // in packets
#define SYNC_GOAL_SMOOTHING_DEPTH   30        // number of samples
#define SPEEDUP_GOAL_SMOOTHING_DEPTH 8        // number of samples
#define MAX_BAD_SAMPLE_INTERVAL         1000    // in milliseconds

#define VIDEO_STAT_INTERVAL       1000    // in milliseconds
#define VIDEO_STAT_INTERVAL_COUNT   2         // number of intervals to average over

#define MAX_OPTIMIZED_VIDEO_LEAD    200 // in milliseconds
#define DEFAULT_HARDWARE_BUFFER_COUNT     4

#define AUDIO_SKEW_POWER          4     // Maximum Audio Speedup Slope as
                                  // 1/(2^AUDIO_SKEW_POWER)
#define MIN_BAD_PERSISTENCE_COUNT   0         // Minimum number of consecutive
                                  // bad sync samples for the
                                  // resync probation period to start
#define MIN_GOOD_PERSISTENCE_COUNT  0         // Minimum number of consecutive
                                  // good sync samples for the
                                  // resync probation period to be
                                  // cancelled

#define MAX_BLT_LOOPS             3
#define BLT_RELIEF_DELAY          1     // in milliseconds

// Absolute timing settings
#define N_STABILIZATION_ITERATIONS  5
#define MAX_ALLOWED_TIMING_ERROR    2
#define SMALLEST_TIMABLE_PERIOD         2

// Default Decoding Priority
#ifdef _WIN32
    #ifdef HELIX_FEATURE_VIDREND_BOOSTDECODE_ON_STARTUP
    // on ce we need to get this started quickly, otherwise the initial packets expire
    // we set the priority so we can check in onpace to reset only once
    #define DFLT_DECODE_PRIORITY        THREAD_PRIORITY_HIGHEST
    #define DFLT_PRESENT_PRIORITY       THREAD_PRIORITY_ABOVE_NORMAL
    #else
    #define DFLT_DECODE_PRIORITY        THREAD_PRIORITY_BELOW_NORMAL
    #define DFLT_PRESENT_PRIORITY       THREAD_PRIORITY_ABOVE_NORMAL
    #endif // HELIX_FEATURE_VIDREND_BOOSTDECODE_ON_STARTUP
#else // _WIN32
#define DFLT_DECODE_PRIORITY      0
#define DFLT_PRESENT_PRIORITY     0
#endif      // _WIN32

// Lowest acceptable version numbers
#define STREAM_MAJOR_VERSION  0
#define STREAM_MINOR_VERSION  0

#define CONTENT_MAJOR_VERSION 0
#define CONTENT_MINOR_VERSION 0

#define DECODER_INTERVAL      5
#define BLTR_INTERVAL         5

#ifdef _WIN32
#define GETBITMAPCOLOR(x) GetBitmapColor( (LPBITMAPINFO)(x) )
#else // _WIN32
#define GETBITMAPCOLOR(x) GetBitmapColor( (HXBitmapInfo*)(x))
#endif      // _WIN32


/****************************************************************************
 *  Includes
 */
#include "hlxclib/stdio.h"
#include "vidrend.ver"
#include "hxtypes.h"
#ifdef _WINDOWS
#include <windows.h>
#endif


#if defined(_UNIX) && !defined(_MAC_UNIX)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef QWS
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#endif /* QWS */

#endif

#include "hxwintyp.h"
#include "hxcom.h"
#include "hxcomm.h"
#include "hxthread.h"

// for sync
#include "hxengin.h"
#include "hxprefs.h"
#include "hxtick.h"
#include "timeval.h"
#include "hxevent.h"
#include "hxvsurf.h"

#include "ihxpckts.h"
#include "hxfiles.h"
#include "hxcore.h"
#include "hxerror.h"
#include "hxrendr.h"
#include "addupcol.h"
// #include "hxhyper.h"
#include "hxplugn.h"
#include "hxwin.h"
// #include "hxasm.h"
#include "hxmon.h"
#include "hxbuffer.h"   // for CHXBuffer

#include "hxassert.h"   // for HX_ASSERT()
#include "hxheap.h"     // for heap checking
#include "hxslist.h"    // CHXSimpleList

#include "chxbufpl.h"

#include "sdpchunk.h"

#include "vidrend.h"
#include "cpacemkr.h"
#include "hxver.h"

#if defined(_WINDOWS) && !defined(WIN32_PLATFORM_PSPC)
#include "ddraw.h"
#endif      /* defined(_WINDOWS) && !defined(WIN32_PLATFORM_PSPC) */

// #include "coloracc.h"
#include "colormap.h"

#include "chxxtype.h"   // For CHXxSize

#if defined(HELIX_FEATURE_PREFERENCES)
#include "hxprefs.h"
#include "hxprefutil.h"
#endif /* HELIX_FEATURE_PREFERENCES */

/****************************************************************************
 *  Debug
 */
#ifdef ENABLE_SYNC_TRACE
#define MAX_SYNC_TRACE_ENTRIES      10000
ULONG32 ulSyncTraceIdx = 0;
ULONG32 syncTraceArray[MAX_SYNC_TRACE_ENTRIES][3];

void DumpSyncEntries(void)
{
    FILE* pFile = NULL;
    ULONG32 ulIdx;

    if (ulSyncTraceIdx > 0)
    {
      pFile = fopen("\\helix\\sync.txt", "wb");
    }

    if (pFile)
    {
      for (ulIdx = 0; ulIdx < ulSyncTraceIdx; ulIdx++)
      {
          fprintf(pFile, "%u\t%u\t%u\n", syncTraceArray[ulIdx][0],
                                 syncTraceArray[ulIdx][1],
                                 syncTraceArray[ulIdx][2]);
      }

      fclose(pFile);
    }

    ulSyncTraceIdx = 0;
}
#endif      // ENABLE_SYNC_TRACE


#ifdef ENABLE_SCHED_TRACE
#define MAX_SCHED_TRACE_ENTRIES     10000
ULONG32 ulSchedTraceIdx = 0;
LONG32 schedTraceArray[MAX_SCHED_TRACE_ENTRIES];

void DumpSchedEntries(void)
{
    FILE* pFile = NULL;
    ULONG32 ulIdx;

    if (ulSchedTraceIdx > 0)
    {
      pFile = fopen("\\helix\\sched.txt", "wb");
    }

    if (pFile)
    {
      for (ulIdx = 0; ulIdx < ulSchedTraceIdx; ulIdx++)
      {
          fprintf(pFile, "%d\n", schedTraceArray[ulIdx]);
      }

      fclose(pFile);
    }

    ulSchedTraceIdx = 0;
}
#endif      // ENABLE_SCHED_TRACE


#ifdef ENABLE_FETCH_TRACE
#define MAX_FETCH_TRACE_ENTRIES     10000
ULONG32 ulFetchTraceIdx = 0;
LONG32 fetchTraceArray[MAX_FETCH_TRACE_ENTRIES];

void DumpFetchEntries(void)
{
    FILE* pFile = NULL;
    ULONG32 ulIdx;

    if (ulFetchTraceIdx > 0)
    {
      pFile = fopen("\\helix\\fetch.txt", "wb");
    }

    if (pFile)
    {
      for (ulIdx = 0; ulIdx < ulFetchTraceIdx; ulIdx++)
      {
          fprintf(pFile, "%d\n", fetchTraceArray[ulIdx]);
      }

      fclose(pFile);
    }

    ulFetchTraceIdx = 0;
}
#endif      // ENABLE_FETCH_TRACE


#ifdef ENABLE_INPUT_TRACE
#define MAX_INPUT_TRACE_ENTRIES     10000
ULONG32 ulInputTraceIdx = 0;
LONG32 inputTraceArray[MAX_INPUT_TRACE_ENTRIES];

void DumpInputEntries(void)
{
    FILE* pFile = NULL;
    ULONG32 ulIdx;

    if (ulInputTraceIdx > 0)
    {
      pFile = fopen("\\helix\\input.txt", "wb");
    }

    if (pFile)
    {
      for (ulIdx = 0; ulIdx < ulInputTraceIdx; ulIdx++)
      {
          fprintf(pFile, "%d\n", inputTraceArray[ulIdx]);
      }

      fclose(pFile);
    }

    ulInputTraceIdx = 0;
}
#endif      // ENABLE_INPUT_TRACE


/****************************************************************************
 *  Constants
 */
const char* const CVideoRenderer::zm_pDescription    = "RealNetworks Video Renderer Plugin";
const char* const CVideoRenderer::zm_pCopyright      = HXVER_COPYRIGHT;
const char* const CVideoRenderer::zm_pMoreInfoURL    = HXVER_MOREINFO;

const char* const CVideoRenderer::zm_pStreamMimeTypes[] =
{
    NULL
};


/************************************************************************
 *  CVideoRenderer
 */
/************************************************************************
 *  Constructor/Destructor
 */
CVideoRenderer::CVideoRenderer(void)
      : m_lRefCount(0)
      , m_pContext(NULL)
      , m_pStream(NULL)
      , m_pHeader(NULL)
      , m_pMutex(NULL)
      , m_pBltMutex(NULL)
      , m_pVSMutex(NULL)
      , m_pDecoderPump(NULL)
      , m_pBltrPump(NULL)
      , m_ulDecoderPacemakerId(0)
      , m_ulBltrPacemakerId(0)
      , m_pDecoderVideoFormat(NULL)
      , m_pBltrVideoFormat(NULL)
      , m_pBackChannel(0)
      , m_pCommonClassFactory(0)
      , m_ulRegistryID(0)
      , m_pVideoStats(NULL)
      , m_pMISUS(NULL)
      , m_pMISUSSite(NULL)
      , m_ulEarlyFrameTol(EARLY_FRAME_TOL)
      , m_ulLateFrameTol(LATE_FRAME_TOL)
      , m_ulNoFramesPollingInterval(NO_FRAMES_POLLING_INTERVAL)
      , m_ulMaxSleepTime(MAX_SLEEP_TIME)
      , m_ulBltPacketQueueSize(BLT_PACKET_QUEUE_SIZE)
      , m_ulSyncGoalSmoothingDepth(SYNC_GOAL_SMOOTHING_DEPTH)
      , m_ulSpeedupGoalSmoothingDepth(SPEEDUP_GOAL_SMOOTHING_DEPTH)
      , m_ulMaxBadSeqSamples(0)
      , m_lTimeLineOffset(0)
      , m_lDecodePriority(DFLT_DECODE_PRIORITY)
      , m_ulStreamBaseTime(0)
      , m_ulBaseTime(0)
      , m_ulTimeNormalizationOffset(0)
      , m_bBitmapSet(FALSE)
      , m_bFrameSizeInitialized(FALSE)
      , m_bWinSizeFixed(FALSE)
      , m_bOSGranuleBoost(OSGRANULE_BOOSTING_ENABLED)
      , m_bOSGranuleBoostVS2(OSGRANULE_BOOSTING_ENABLED)
      , m_bOptimizedBlt(FALSE)
      , m_bUseVideoSurface2(FALSE)
#if defined(_WINDOWS) && defined(HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO)
      , m_bTryVideoSurface2(TRUE)
#else // _WINDOWS
      , m_bTryVideoSurface2(FALSE)
#endif      // _WINDOWS
      , m_bVideoSurface2Transition(FALSE)
      , m_bVideoSurface1Requested(FALSE)
      , m_bVideoSurfaceInitialized(FALSE)
      , m_bVideoSurfaceReinitRequested(FALSE)
      , m_bPresentInProgress(FALSE)
      , m_bVS2BufferUnavailableOnLastBlt(FALSE)
      , m_ulHWBufCount(DEFAULT_HARDWARE_BUFFER_COUNT)
      , m_ulConfigHWBufCount(DEFAULT_HARDWARE_BUFFER_COUNT)
      , m_pClipRect(NULL)
      , m_pPreferences(NULL)
      , m_pRegistry(NULL)
      , m_pScheduler(NULL)
      , m_pOptimizedScheduler(NULL)
      , m_bPendingCallback(FALSE)
      , m_bSchedulerStartRequested(FALSE)
      , m_hPendingHandle(0)
      , m_ulCallbackCounter(0)
      , m_bDecoderRunning(FALSE)
      , m_bSiteAttached(FALSE)
      , m_PlayState(Stopped)
      , m_ulBytesToBuffer(0)
      , m_ulAvgBitRate(0)
      , m_ulPreroll(0)
      , m_ulBufferingStartTime(0)
      , m_ulBufferingStopTime(0)
      , m_ulBufferingTimeOut(0)
      , m_bBufferingOccured(FALSE)
      , m_bBufferingNeeded(FALSE)
      , m_pVideoFormat(NULL)
      , m_pBltPacketQueue(NULL)
      , m_pActiveVideoPacket(NULL)
      , m_ulActiveVideoTime(0)
      , m_bFirstFrame(TRUE)
      , m_bBaseTimeSet(FALSE)
      , m_bFirstSurfaceUpdate(TRUE)
      , m_bPendingRedraw(FALSE)
      , m_bVS1UpdateInProgress(FALSE)
      , m_ulSyncSmoothingDepth(0)
      , m_ulSyncInterval(SYNC_INTERVAL)
      , m_ulBadSeqSampleCount(0)
      , m_ulGoodSeqSampleCount(0)
      , m_fTrendSyncDelta(0.0)
      , m_pResizeCB(NULL)
      , m_pVSurf2InputBIH(NULL)
      , m_bIsScheduledCB(0)
#ifdef HELIX_FEATURE_VIDREND_UNTIMED_DECODE
      , m_bUntimedRendering(FALSE)
#endif /* HELIX_FEATURE_VIDREND_UNTIMED_DECODE */
      , m_bActiveVideoPacketLocalized(FALSE)
{
    m_SetWinSize.cx = 0;
    m_SetWinSize.cy = 0;
    m_LastSetSize.cx = 0;
    m_LastSetSize.cy = 0;

    m_rViewRect.left   = 0;
    m_rViewRect.top    = 0;
    m_rViewRect.right  = 0;
    m_rViewRect.bottom = 0; 

    memset(&m_BitmapInfoHeader, 0, sizeof(HXBitmapInfoHeader));
}

CVideoRenderer::~CVideoRenderer()
{
    // NOTE: You should do your renderer cleanup here, instead of
    // in EndStream(), because your renderer is still left around
    // after the stream is ended in case it is a display renderer
    // and it needs to "paint" it's display area.
    EndOptimizedBlt();

    if (m_pActiveVideoPacket)
    {
      m_pActiveVideoPacket->Clear();
      delete m_pActiveVideoPacket;
      m_pActiveVideoPacket = NULL;
      m_ulActiveVideoTime = 0;
    }

    HX_RELEASE(m_pHeader);
    HX_RELEASE(m_pContext);
    HX_RELEASE(m_pCommonClassFactory);

    if (m_pVideoFormat)
    {
        m_pVideoFormat->Release();
        m_pVideoFormat = NULL;
    }

    HX_DELETE(m_pVSurf2InputBIH);
    HX_DELETE(m_pClipRect);
    HX_DELETE(m_pMutex);
    HX_DELETE(m_pBltMutex);
    HX_DELETE(m_pVSMutex);

    RemoveCallback(m_hPendingHandle);
    m_bPendingCallback = FALSE;

    HX_RELEASE(m_pOptimizedScheduler);
    HX_RELEASE(m_pScheduler);

    HX_RELEASE(m_pPreferences);
    HX_RELEASE(m_pRegistry);

    ClearBltPacketQueue();
    HX_DELETE(m_pBltPacketQueue);

    HX_RELEASE(m_pResizeCB);

#if defined(HELIX_FEATURE_STATS)
    HX_DELETE(m_pVideoStats);
#endif /* HELIX_FEATURE_STATS */
}


/************************************************************************
 *  IHXPlugin Methods
 */
/************************************************************************
 *  Method:
 *    IHXPlugin::InitPlugin
 *  Purpose:
 *    Initializes the plugin for use. This interface must always be
 *    called before any other method is called. This is primarily needed
 *    so that the plugin can have access to the context for creation of
 *    IHXBuffers and IMalloc.
 */
STDMETHODIMP CVideoRenderer::InitPlugin(IUnknown* /*IN*/ pContext)
{
    HX_RESULT retVal = HXR_OK;

    HX_ASSERT(pContext);

    m_pContext = pContext;
    m_pContext->AddRef();

    retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
                              (void**) &m_pCommonClassFactory);

    if (SUCCEEDED(retVal))
    {
      m_pContext->QueryInterface(IID_IHXPreferences,
                                   (void**) &m_pPreferences);
    }

    m_pContext->QueryInterface(IID_IHXRegistry, (void**) &m_pRegistry);

    if (SUCCEEDED(retVal))
    {
      retVal = m_pContext->QueryInterface(IID_IHXScheduler,
                                  (void **) &m_pScheduler);
    }

    if (SUCCEEDED(retVal) && !m_pMutex)
    {
#ifdef THREADS_SUPPORTED
      retVal = HXMutex::MakeMutex(m_pMutex);
#else  // THREADS_SUPPORTED
      retVal = HXMutex::MakeStubMutex(m_pMutex);
#endif  // THREADS_SUPPORTED
    }

    if (SUCCEEDED(retVal) && !m_pBltMutex)
    {
#ifdef THREADS_SUPPORTED
      retVal = HXMutex::MakeMutex(m_pBltMutex);
#else  // THREADS_SUPPORTED
      retVal = HXMutex::MakeStubMutex(m_pBltMutex);
#endif  // THREADS_SUPPORTED
    }

    if (SUCCEEDED(retVal) && !m_pVSMutex)
    {
#ifdef THREADS_SUPPORTED
      retVal = HXMutex::MakeMutex(m_pVSMutex);
#else  // THREADS_SUPPORTED
      retVal = HXMutex::MakeStubMutex(m_pVSMutex);
#endif  // THREADS_SUPPORTED
    }

#if defined(HELIX_FEATURE_STATS)
    if (SUCCEEDED(retVal))
    {
      m_pVideoStats = new CVideoStatistics(m_pContext,
                                   VIDEO_STAT_INTERVAL_COUNT);

      retVal = HXR_OUTOFMEMORY;
      if (m_pVideoStats)
      {
          retVal = HXR_OK;
      }
    }
#endif /* HELIX_FEATURE_STATS */

    if (FAILED(retVal))
    {
      HX_RELEASE(m_pCommonClassFactory);
      HX_RELEASE(m_pPreferences);
      HX_RELEASE(m_pRegistry);
      HX_RELEASE(m_pScheduler);
    }

    return retVal;
}

/************************************************************************
 *  Method:
 *    IHXPlugin::GetPluginInfo
 *  Purpose:
 *    Returns the basic information about this plugin. Including:
 *
 *    bLoadMultiple     whether or not this plugin DLL can be loaded
 *                multiple times. All File Formats must set
 *                this value to TRUE.
 *    pDescription      which is used in about UIs (can be NULL)
 *    pCopyright  which is used in about UIs (can be NULL)
 *    pMoreInfoURL      which is used in about UIs (can be NULL)
 */
STDMETHODIMP CVideoRenderer::GetPluginInfo
(
   REF(BOOL)        /*OUT*/ bLoadMultiple,
   REF(const char*) /*OUT*/ pDescription,
   REF(const char*) /*OUT*/ pCopyright,
   REF(const char*) /*OUT*/ pMoreInfoURL,
   REF(ULONG32)     /*OUT*/ ulVersionNumber
)
{
    bLoadMultiple = TRUE;   // Must be true for file formats.

    pDescription    = zm_pDescription;
    pCopyright        = zm_pCopyright;
    pMoreInfoURL    = zm_pMoreInfoURL;
    ulVersionNumber = TARVER_ULONG32_VERSION;

    return HXR_OK;
}

/************************************************************************
 *  Method:
 *    IHXPlugin::GetRendererInfo
 *  Purpose:
 *    If this object is a file format object this method returns
 *    information vital to the instantiation of file format plugins.
 *    If this object is not a file format object, it should return
 *    HXR_UNEXPECTED.
 */
STDMETHODIMP CVideoRenderer::GetRendererInfo
(
 REF(const char**) /*OUT*/ pStreamMimeTypes,
 REF(UINT32)      /*OUT*/ unInitialGranularity
)
{
    pStreamMimeTypes = (const char**) zm_pStreamMimeTypes;
    unInitialGranularity = SYNC_INTERVAL;
    return HXR_OK;
}




/************************************************************************
 *  IHXRenderer Methods
 */
/////////////////////////////////////////////////////////////////////////
//  Method:
//          IHXRenderer::StartStream
//  Purpose:
//          Called by client engine to inform the renderer of the stream it
//          will be rendering. The stream interface can provide access to
//          its source or player. This method also provides access to the
//          primary client controller interface.
//
STDMETHODIMP CVideoRenderer::StartStream(IHXStream* pStream,
                                 IHXPlayer* pPlayer)
{
    m_pStream  = pStream;

    if (m_pStream)
    {
      m_pStream->AddRef();
    }

#if defined (HELIX_FEATURE_MISU)
    m_pCommonClassFactory->CreateInstance(
      CLSID_IHXMultiInstanceSiteUserSupplier,
      (void**) &m_pMISUS);

    if (m_pMISUS)
    {
      m_pMISUS->SetSingleSiteUser((IUnknown*)(IHXSiteUser*) this);
    }
#endif //HELIX_FEATURE_MISU

    if (m_pStream)
    {
      IHXStreamSource* pSource = 0;
      if (m_pStream->GetSource(pSource) == HXR_OK)
      {
          /* It is OK if the source does not support backchannel. Reasons:
           *
           * 1. This stream may not be coming from h261 fileformat.
           *        It may instead be merged into a container fileformat which
           *        may be does not support BackChannel.
           *
           * 2. The protocol used to serve this stream may not support
           *        BackChannel.
           */
          pSource->QueryInterface(IID_IHXBackChannel, (void**) &m_pBackChannel);

          pSource->Release();
      }
    }

    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//          IHXRenderer::EndStream
//  Purpose:
//          Called by client engine to inform the renderer that the stream
//          is was rendering is closed.
//
STDMETHODIMP CVideoRenderer::EndStream()
{
    // Stop Blts by changing state
    m_pMutex->Lock();
    m_PlayState = Stopped;
    m_pMutex->Unlock();

    // Stop Decoder
    if (m_pDecoderPump)
    {
      m_pDecoderPump->Stop();
      m_pDecoderPump->Signal();
      m_pDecoderPump->WaitForStop();
      m_pDecoderPump->Release();
      m_pDecoderPump = NULL;
    }

    // Wait for Blt if in progress and then flush packet queues
    DisplayMutex_Lock();
    if (m_pVideoFormat)
    {
      m_pVideoFormat->Reset();
    }
    DisplayMutex_Unlock();

    // IHXStream, IHXSourceStream or IHXBackChannel
    // cannot be used after EndStream has been called.
    HX_RELEASE(m_pStream);
    HX_RELEASE(m_pBackChannel);

    // Stop Bltr pump
    if (m_pBltrPump)
    {
      m_pBltrPump->Stop();
      m_pBltrPump->Signal();
    }

    // Flush Optimized Video Surface if used
    if (m_bUseVideoSurface2 && m_pMISUSSite)
    {
      FlushVideoSurface2(m_pMISUSSite);
    }

    if (m_pBltrPump)
    {
      m_pBltrPump->WaitForStop();
      m_pBltrPump->Release();
      m_pBltrPump = NULL;
    }

    DisplayMutex_Lock();
    if (m_pVideoFormat)
    {
        m_pVideoFormat->Release();
        m_pVideoFormat = NULL;
    }
    DisplayMutex_Unlock();

#ifdef ENABLE_SYNC_TRACE
    DumpSyncEntries();
#endif      // ENABLE_SYNC_TRACE

#ifdef ENABLE_SCHED_TRACE
    DumpSchedEntries();
#endif      // ENABLE_SCHED_TRACE

#ifdef ENABLE_FETCH_TRACE
    DumpFetchEntries();
#endif      // ENABLE_FETCH_TRACE

#ifdef ENABLE_INPUT_TRACE
    DumpInputEntries();
#endif      // ENABLE_INPUT_TRACE

    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//          IHXRenderer::OnHeader
//  Purpose:
//          Called by client engine when a header for this renderer is
//          available. The header will arrive before any packets.
//
STDMETHODIMP CVideoRenderer::OnHeader(IHXValues* pHeader)
{
    HX_RESULT retVal = HXR_OK;

    HX_DELETE(m_pClipRect);

    // Keep this for later use...
    HX_RELEASE(m_pHeader);
    m_pHeader = pHeader;
    m_pHeader->AddRef();

    m_ulStreamBaseTime = 0;
    m_ulBaseTime = 0;
    m_ulTimeNormalizationOffset = 0;

    // check the stream versions
    m_pHeader->AddRef();
    retVal = CheckStreamVersions(m_pHeader);
    m_pHeader->Release();

#ifdef HELIX_FEATURE_QUICKTIME
    IHXBuffer* pSDPData = NULL;

    if (SUCCEEDED(retVal) &&
      SUCCEEDED(pHeader->GetPropertyCString("SDPData", pSDPData)))
    {
      char *pData = (char*) pSDPData->GetBuffer();
      IHXValues *pValues = NULL;

      if (pData &&
          SUCCEEDED(SDPParseChunk(pData,
                            strlen(pData),
                            pValues,
                            m_pCommonClassFactory,
                            SDPCTX_Renderer)))
      {
          ULONG32 ulLeft;
          ULONG32 ulRight;
          ULONG32 ulTop;
          ULONG32 ulBottom;

          if (SUCCEEDED(pValues->GetPropertyULONG32(
                "ClipFrameLeft", ulLeft)) &&
            SUCCEEDED(pValues->GetPropertyULONG32(
                "ClipFrameRight", ulRight)) &&
            SUCCEEDED(pValues->GetPropertyULONG32(
                "ClipFrameTop", ulTop)) &&
            SUCCEEDED(pValues->GetPropertyULONG32(
                "ClipFrameBottom", ulBottom)))
          {
            retVal = HXR_OUTOFMEMORY;

            m_pClipRect = (HXxRect*) new HXxRect;
            if (m_pClipRect)
            {
                m_pClipRect->left = (INT32) ulLeft;
                m_pClipRect->right = (INT32) ulRight;
                m_pClipRect->top = (INT32) ulTop;
                m_pClipRect->bottom = (INT32) ulBottom;
                retVal = HXR_OK;
            }
          }
      }

      HX_RELEASE(pValues);
    }

    HX_RELEASE(pSDPData);
#endif      // HELIX_FEATURE_QUICKTIME

    if (SUCCEEDED(retVal))
    {
      m_pVideoFormat = CreateFormatObject(m_pHeader);

      retVal = HXR_OUTOFMEMORY;
      if (m_pVideoFormat)
      {
          m_pVideoFormat->AddRef();
          retVal = HXR_OK;
      }
    }

    if (SUCCEEDED(retVal))
    {
      retVal = m_pVideoFormat->Init(pHeader);
    }

    if (SUCCEEDED(retVal))
    {
      m_ulEarlyFrameTol = GetEarlyFrameTolerance();
      m_ulLateFrameTol = GetLateFrameTolerance();
      m_ulMaxOptimizedVideoLead = GetMaxOptimizedVideoLead();

      m_ulMaxSleepTime = GetMaxSleepTime();
      m_ulNoFramesPollingInterval = GetNoFramesPollingInterval();
      m_ulBltPacketQueueSize = GetBltPacketQueueSize();
      m_ulSyncGoalSmoothingDepth = GetSyncGoalSmoothingDepth();
      m_ulSpeedupGoalSmoothingDepth = GetSpeedupGoalSmoothingDepth();
      m_ulMaxBadSeqSamples = GetMaxBadSeqSamples();
    }

    // Setup preroll
    if (SUCCEEDED(retVal))
    {
      BOOL bSetNewPreroll = FALSE;
        m_ulPreroll = 0;
      ULONG32 ulMinPreroll = m_pVideoFormat->GetMinimumPreroll(pHeader);
      ULONG32 ulMaxPreroll = m_pVideoFormat->GetMaximumPreroll(pHeader);

        // Check that the stream header has a preroll value. If not...
      pHeader->GetPropertyULONG32("Preroll", m_ulPreroll);
      if (m_ulPreroll == 0)
      {
            // ... let's use default value.
          m_ulPreroll = m_pVideoFormat->GetDefaultPreroll(pHeader);
          bSetNewPreroll = TRUE;
      }
        else if( m_ulPreroll > ulMaxPreroll )
        {
            m_ulPreroll = ulMaxPreroll;
          bSetNewPreroll = TRUE;
        }
      else if (m_ulPreroll < ulMinPreroll)
      {
          m_ulPreroll = ulMinPreroll;
          bSetNewPreroll = TRUE;
      }

      if (bSetNewPreroll)
      {
          pHeader->SetPropertyULONG32("Preroll", m_ulPreroll);
      }
    }

    // Determine Average Bitrate
    if (SUCCEEDED(retVal))
    {
      if (FAILED(pHeader->GetPropertyULONG32("AvgBitRate", m_ulAvgBitRate)))
      {
          m_ulAvgBitRate = 0;
      }
    }

    // Create Blt Queue
    if (SUCCEEDED(retVal))
    {
      m_pBltPacketQueue = new CRingBuffer(m_ulBltPacketQueueSize);

      retVal = HXR_OUTOFMEMORY;
      if (m_pBltPacketQueue)
      {
          retVal = HXR_OK;
      }
    }

    return retVal;
}


/////////////////////////////////////////////////////////////////////////////
//  Method:
//    CVideoRenderer::CheckStreamVersions
//  copied from CRealAudioRenderer
HX_RESULT CVideoRenderer::CheckStreamVersions(IHXValues* pHeader)
{
    // check stream and content versions so an upgrade can
    // be called if necessary...
    HX_RESULT pnr = HXR_OK;

    BOOL bVersionOK = TRUE;

    UINT32 ulStreamVersion = 0;
    UINT32 ulContentVersion = 0;

    if(HXR_OK == pHeader->GetPropertyULONG32("StreamVersion",
      ulStreamVersion))
    {
      UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulStreamVersion);
      UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulStreamVersion);
      ULONG32 ulThisMajorVersion = 0;
      ULONG32 ulThisMinorVersion = 0;

      GetStreamVersion(ulThisMajorVersion, ulThisMinorVersion);

      if((ulMajorVersion > ulThisMajorVersion) ||
         ((ulMinorVersion > ulThisMinorVersion) &&
          (ulMajorVersion == ulThisMajorVersion)))
      {
          bVersionOK = FALSE;
      }
    }

    if(bVersionOK &&
       (HXR_OK == pHeader->GetPropertyULONG32("ContentVersion",
                                    ulContentVersion)))
    {
      UINT32 ulMajorVersion = HX_GET_MAJOR_VERSION(ulContentVersion);
      UINT32 ulMinorVersion = HX_GET_MINOR_VERSION(ulContentVersion);
      ULONG32 ulThisMajorVersion = 0;
      ULONG32 ulThisMinorVersion = 0;

      GetContentVersion(ulThisMajorVersion, ulThisMinorVersion);

      if((ulMajorVersion > ulThisMajorVersion) ||
         ((ulMinorVersion > ulThisMinorVersion) &&
          (ulMajorVersion == ulMajorVersion)))
      {
          bVersionOK = FALSE;
      }
    }

    if(!bVersionOK)
    {
        AddToAutoUpgradeCollection(GetUpgradeMimeType(), m_pContext);

      pnr = HXR_FAIL;
    }

    return pnr;
}


/////////////////////////////////////////////////////////////////////////
//  Method:
//          IHXRenderer::OnPacket
//  Purpose:
//          Called by client engine when a packet for this renderer is
//          due.
//
STDMETHODIMP CVideoRenderer::OnPacket(IHXPacket* pPacket, LONG32 lTimeOffset)
{
    m_lTimeLineOffset = lTimeOffset;

#ifdef ENABLE_INPUT_TRACE
    if (ulInputTraceIdx < MAX_INPUT_TRACE_ENTRIES)
    {
      inputTraceArray[ulInputTraceIdx++] =
          ComputeTimeAhead(pPacket->GetTime(), 0);
    }
#endif      // ENABLE_INPUT_TRACE

    if (m_bSchedulerStartRequested)
    {
      StartSchedulers();
    }

    BOOL bQueueRet = m_pVideoFormat->Enqueue(pPacket);
    if(bQueueRet == FALSE && m_pVideoFormat->GetLastError() == HXR_OUTOFMEMORY)
    {
        return HXR_OUTOFMEMORY;
    }

    // try to decode a frame
    if (m_PlayState == Playing)
    {
      if (!IsDecoderRunning() || NULL == m_pDecoderPump)
      {
          BOOL bDecRet = m_pVideoFormat->DecodeFrame();
            if( bDecRet == FALSE && m_pVideoFormat->GetLastError() == HXR_OUTOFMEMORY )
            {
                return HXR_OUTOFMEMORY;
            }
      }
      else
      {
          m_pDecoderPump->Signal();
      }
    }
    else
    {
      if (!m_bBaseTimeSet)
      {
          m_pMutex->Lock();
          if (m_PlayState != Playing)
          {
            m_ulBaseTime = pPacket->GetTime();
          }
          m_pMutex->Unlock();
          m_bBaseTimeSet = TRUE;
      }

      // If we are seeking, this is a pre-seek packet and there is
      // no need to decode it
      if (m_PlayState != Seeking)
      {
          if (!IsDecoderRunning() || NULL == m_pDecoderPump)
          {
            m_pVideoFormat->DecodeFrame();
          }
          else
          {
            m_pDecoderPump->Signal();
          }

          if (m_PlayState == Buffering)
          {
            if (IsBufferingComplete(pPacket))
            {
                RequestBufferingEnd();
            }
          }
      }
    }

    return HXR_OK;
}


/////////////////////////////////////////////////////////////////////////
//  Method:
//          IHXRenderer::OnTimeSync
//  Purpose:
//          Called by client engine to inform the renderer of the current
//          time relative to the streams synchronized time-line. The
//          renderer should use this time value to update its display or
//          render it's stream data accordingly.
//
STDMETHODIMP CVideoRenderer::OnTimeSync(ULONG32 ulTime)
{
    ULONG32 ulStreamBaseTime = HX_GET_BETTERTICKCOUNT();
    ULONG32 ulBaseTime = ulTime;
    BOOL bGoodSample = TRUE;

    if (m_bSchedulerStartRequested)
    {
      StartSchedulers();
    }

#ifdef HELIX_FEATURE_STATS
    if (((ULONG32) (ulStreamBaseTime - m_pVideoStats->GetLastSyncTime())) >=
      VIDEO_STAT_INTERVAL)
    {
      m_pVideoStats->SyncStats(ulStreamBaseTime);
    }
#endif /* HELIX_FEATURE_STATS */

#ifdef ENABLE_SYNC_TRACE
    ULONG32 ulOrigStreamBaseTime = ulStreamBaseTime;
#endif // ENABLE_SYNC_TRACE

#ifdef SYNC_SMOOTHING_OLD_SCHEME
    LONG32 lNewSyncDelta = (LONG32) (ulStreamBaseTime - m_lTrendSyncDelta - ulTime);
    m_lTrendSyncDelta += lNewSyncDelta / ((LONG32) (m_ulSyncSmoothingDepth + 1));

    ulStreamBaseTime = ulTime + m_lTrendSyncDelta;

    if (m_ulSyncSmoothingDepth < m_ulSyncGoalSmoothingDepth)
    {
      m_ulSyncSmoothingDepth++;
    }
#endif      // SYNC_SMOOTHING_OLD_SCHEME

#ifdef SYNC_PRE_SMOOTHING
    if (m_ulSyncSmoothingDepth > 0)
    {
      LONG32 lStreamBaseDelta = ((LONG32) (ulStreamBaseTime - m_ulStreamBaseTime));
      ULONG32 ulBaseDelta = ulBaseTime - m_ulBaseTime;
      BOOL bSkipSmoothing = FALSE;

      bGoodSample = ((lStreamBaseDelta <= 0) ||
                   (((ULONG32) lStreamBaseDelta) <=
                    (ulBaseDelta + (ulBaseDelta >> AUDIO_SKEW_POWER))) ||
                   (bSkipSmoothing = ((m_ulBadSeqSampleCount++) > m_ulMaxBadSeqSamples)));

      if (bSkipSmoothing)
      {
          m_ulSyncSmoothingDepth = 0;
          m_fTrendSyncDelta = 0.0;
      }
    }
#endif      // SYNC_PRE_SMOOTHING

    if (bGoodSample)
    {
#ifdef SYNC_SMOOTHING
      double fNewSyncDelta = (((double) ((ULONG32) (ulStreamBaseTime - ulTime))) -
                         m_fTrendSyncDelta);

      // If we have a m_fTrendSyncDelta, make sure we consider
      // m_fTrendSyncDelta wrap-around in relation to fNewSyncDelta
      if (m_ulSyncSmoothingDepth > 0)
      {
          if (fNewSyncDelta > MAX_LONG32_AS_DOUBLE)
          {
            fNewSyncDelta = MAX_ULONG32_AS_DOUBLE - fNewSyncDelta;
          }
          else if (fNewSyncDelta < MIN_LONG32_AS_DOUBLE)
          {
            fNewSyncDelta += MAX_ULONG32_AS_DOUBLE;
          }
      }

      if (fNewSyncDelta < 0.0)
      {
          // We are trying to speed up: use speed up smoothing criteria
          m_fTrendSyncDelta += (fNewSyncDelta /
                          ((m_ulSyncSmoothingDepth >= m_ulSpeedupGoalSmoothingDepth) ?
                           m_ulSpeedupGoalSmoothingDepth + 1 : m_ulSyncSmoothingDepth + 1));
      }
      else
      {
          m_fTrendSyncDelta += fNewSyncDelta / (m_ulSyncSmoothingDepth + 1);
      }

      if (m_fTrendSyncDelta > MAX_ULONG32_AS_DOUBLE)
      {
          m_fTrendSyncDelta -= MAX_ULONG32_AS_DOUBLE;
      }
      else if (m_fTrendSyncDelta < 0)
      {
           m_fTrendSyncDelta += MAX_ULONG32_AS_DOUBLE;
      }

      ulStreamBaseTime = ulTime + ((ULONG32) (m_fTrendSyncDelta));

      if (m_ulSyncSmoothingDepth < m_ulSyncGoalSmoothingDepth)
      {
          m_ulSyncSmoothingDepth++;
      }
#endif      // SYNC_SMOOTHING

      m_ulGoodSeqSampleCount++;

      m_ulStreamBaseTime = ulStreamBaseTime;
      m_ulBaseTime = ulBaseTime;
      m_ulTimeNormalizationOffset = m_ulStreamBaseTime -
                              m_ulBaseTime -
                              m_lTimeLineOffset;

      if (m_ulGoodSeqSampleCount >= MIN_GOOD_PERSISTENCE_COUNT)
      {
          m_ulBadSeqSampleCount = 0;
      }
    }
    else
    {
      // This is a bad sample
      if (m_ulBadSeqSampleCount >= MIN_BAD_PERSISTENCE_COUNT)
      {
          m_ulGoodSeqSampleCount = 0;
      }
    }

#ifdef ENABLE_SYNC_TRACE
    if (ulSyncTraceIdx < MAX_SYNC_TRACE_ENTRIES)
    {
      syncTraceArray[ulSyncTraceIdx][0] = m_ulBaseTime;
      syncTraceArray[ulSyncTraceIdx][1] = m_ulStreamBaseTime;
      syncTraceArray[ulSyncTraceIdx++][2] = ulOrigStreamBaseTime;
    }
#endif      // ENABLE_SYNC_TRACE

    if (m_PlayState == Playing)
    {
      if (!IsDecoderRunning())
      {
          m_pVideoFormat->DecodeFrame();
      }

      if (m_bBufferingNeeded)
      {
          m_pMutex->Lock();

          if (m_PlayState == Playing)
          {
            BeginBuffering();
          }

          m_pMutex->Unlock();
      }
    }
    else if ((m_PlayState == PlayStarting) ||
           (m_PlayState == Buffering))
    {
      m_pMutex->Lock();

      m_bBaseTimeSet = TRUE;

      // Reset the offset to avoid race condition
      // with m_ulTimeNormalizationOffset setting in OnPacket()
      if (bGoodSample)
      {
          m_ulTimeNormalizationOffset = m_ulStreamBaseTime -
                                m_ulBaseTime -
                                m_lTimeLineOffset;
      }

      if (m_PlayState == Buffering)
      {
          EndBuffering();
          m_PlayState = PlayStarting;
      }

      if (m_PlayState == PlayStarting)
      {
          m_PlayState = Playing;

          BltIfNeeded();

          StartSchedulers();

          if (m_pBltrPump)
          {
            m_pBltrPump->Signal();
          }
      }

      m_pMutex->Unlock();
    }

    return HXR_OK;
}


HX_RESULT CVideoRenderer::StartSchedulers(void)
{
    HX_RESULT retVal = HXR_OK;


#ifdef HELIX_FEATURE_VIDREND_UNTIMED_DECODE

    // When running the decoder as fast as possible, we dont want to start the scheduler, so short

    // circuit this code. Additionally, calls such as BltIfNeeded() and ScheduleCallback() (which

    // may still be called) make assumptions based on the state of our interactions with the

    // scheduler, so we satisfy them by setting a pending handle representing a nonexistant callback.

    if( m_bUntimedRendering )

    {

      m_hPendingHandle = 1;

      return HXR_OK;

    }

#endif /* HELIX_FEATURE_VIDREND_UNTIMED_DECODE */


    m_bSchedulerStartRequested = FALSE;

    DisplayMutex_Lock();

    if (ShouldKickStartScheduler())
    {
      m_bBufferingNeeded = FALSE;
      ScheduleCallback(0);
    }

    if (SUCCEEDED(retVal) && (m_pDecoderPump == NULL))
    {
      CVideoPaceMaker* pVideoPaceMaker;
      retVal = HXR_OUTOFMEMORY;

      pVideoPaceMaker = new CVideoPaceMaker;

      if (pVideoPaceMaker)
      {
          retVal = pVideoPaceMaker->QueryInterface(
            IID_IHXPaceMaker,
            (void**) &m_pDecoderPump);

          if (SUCCEEDED(retVal))
          {
            pVideoPaceMaker = NULL;
            m_pDecoderPump->Start(this,
                GetDecodePriority(),
                DECODER_INTERVAL,
                m_ulDecoderPacemakerId);
          }
      }

      HX_DELETE(pVideoPaceMaker);
    }

    if (SUCCEEDED(retVal) && (m_pBltrPump == NULL) && m_bTryVideoSurface2)
    {
      CVideoPaceMaker* pVideoPaceMaker;
      retVal = HXR_OUTOFMEMORY;

      pVideoPaceMaker = new CVideoPaceMaker;

      if (pVideoPaceMaker)
      {
          retVal = pVideoPaceMaker->QueryInterface(
            IID_IHXPaceMaker,
            (void**) &m_pBltrPump);

          if (SUCCEEDED(retVal))
          {
            pVideoPaceMaker = NULL;
            m_pBltrPump->Start(this,
                DFLT_PRESENT_PRIORITY,
                BLTR_INTERVAL,
                m_ulBltrPacemakerId);
          }
      }

      HX_DELETE(pVideoPaceMaker);
    }

    DisplayMutex_Unlock();

    return retVal;
}


/////////////////////////////////////////////////////////////////////////
//  Method:
//    IHXRenderer::OnPreSeek
//  Purpose:
//    Called by client engine to inform the renderer that a seek is
//    about to occur. The render is informed the last time for the
//    stream's time line before the seek, as well as the first new
//    time for the stream's time line after the seek will be completed.
//
STDMETHODIMP CVideoRenderer::OnPreSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
{
    // Change state to stop Blts
    m_pMutex->Lock();
    m_PlayState = Seeking;
    m_pMutex->Unlock();

    // Suspend the Decoder pump
    if (m_pDecoderPump)
    {
      m_pDecoderPump->Suspend(TRUE);
      m_pDecoderPump->Signal();
      m_pDecoderPump->WaitForSuspend();
    }

    // Wait for Blt in progress to complete and reset
    // packet queues
    DisplayMutex_Lock();

    m_pVideoFormat->SetStartTime(ulNewTime);
    m_pVideoFormat->Reset();
#if defined(HELIX_FEATURE_STATS)
    m_pVideoStats->ResetSequence();
#endif /* HELIX_FEATURE_STATS */

    m_bFirstSurfaceUpdate = TRUE;
    m_bFirstFrame = TRUE;
    m_bBaseTimeSet = FALSE;

    DisplayMutex_Unlock();

    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//    IHXRenderer::OnPostSeek
//  Purpose:
//    Called by client engine to inform the renderer that a seek has
//    just occured. The render is informed the last time for the
//    stream's time line before the seek, as well as the first new
//    time for the stream's time line after the seek.
//
STDMETHODIMP CVideoRenderer::OnPostSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
{
    DisplayMutex_Lock();

    // clean up the packet lists
    m_pVideoFormat->SetStartTime(ulNewTime);
    m_pVideoFormat->Reset();

#if defined(HELIX_FEATURE_STATS)
    m_pVideoStats->ResetSequence();
#endif /* HELIX_FEATURE_STATS */

    m_bFirstSurfaceUpdate = TRUE;
    m_bFirstFrame = TRUE;
    m_ulBaseTime = ulNewTime;
    m_bBaseTimeSet = TRUE;
    m_bVS2BufferUnavailableOnLastBlt = FALSE;

    if (m_pDecoderPump)
    {
      m_pDecoderPump->Suspend(FALSE);
      m_pDecoderPump->Signal();
    }

    if (m_bUseVideoSurface2 && m_pMISUSSite)
    {
      FlushVideoSurface2(m_pMISUSSite);
    }

    DisplayMutex_Unlock();

    // PostSeek signals the proper packets are to start arriving
    m_pMutex->Lock();
    m_PlayState = PlayStarting;
    m_pMutex->Unlock();

    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//    IHXRenderer::OnPause
//  Purpose:
//    Called by client engine to inform the renderer that a pause has
//    just occured. The render is informed the last time for the
//    stream's time line before the pause.
//
STDMETHODIMP CVideoRenderer::OnPause(ULONG32 ulTime)
{
    m_pMutex->Lock();

    m_PlayState = Paused;

    m_pMutex->Unlock();

    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//    IHXRenderer::OnBegin
//  Purpose:
//    Called by client engine to inform the renderer that a begin or
//    resume has just occured. The render is informed the first time
//    for the stream's time line after the resume.
//
STDMETHODIMP CVideoRenderer::OnBegin(ULONG32 ulTime)
{
    HX_RESULT retVal = HXR_OK;

    m_pMutex->Lock();

    m_bBufferingOccured = FALSE;
    // If we are seeking, PostSeek will notify us when the play
    // will be starting
    if (m_PlayState != Seeking)
    {
      m_PlayState = PlayStarting;
    }

    // No need to clear the Blt Packet queue here since
    // The Refresh event will always clear it and clearing
    // it here would create a race condition on Blt Packet
    // Queue (ring buffer) read.
    // ClearBltPacketQueue();
    m_ulSyncSmoothingDepth = 0;
    m_ulBadSeqSampleCount = 0;
    m_ulGoodSeqSampleCount = 0;
    m_bIsScheduledCB = 0;
    m_bVS2BufferUnavailableOnLastBlt = FALSE;

    retVal = StartSchedulers();

    m_pMutex->Unlock();

#ifdef HELIX_FEATURE_VIDREND_BOOSTDECODE_ON_STARTUP
    if (m_pDecoderPump)
    {
       //m_pDecoderPump->Suspend(TRUE);
       //m_pDecoderPump->WaitForSuspend();  // Wait for decoder thread to start and suspends itself
       //m_pDecoderPump->Suspend(FALSE);
       m_pDecoderPump->Signal();   // Kick-out decoder pump from suspension
    }
#endif  // HELIX_FEATURE_VIDREND_BOOSTDECODE_ON_STARTUP

    return retVal;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//    IHXRenderer::OnBuffering
//  Purpose:
//    Called by client engine to inform the renderer that buffering
//    of data is occuring. The render is informed of the reason for
//    the buffering (start-up of stream, seek has occured, network
//    congestion, etc.), as well as percentage complete of the
//    buffering process.
//
STDMETHODIMP CVideoRenderer::OnBuffering(ULONG32 ulFlags, UINT16 unPercentComplete)
{
    HX_RESULT retVal = HXR_OK;

    m_pMutex->Lock();

    if (m_PlayState == Buffering)
    {
      if (IsBufferingComplete())
      {
          EndBuffering();
      }
    }
    else if (m_PlayState == Playing)
    {
      m_PlayState = PlayStarting;
    }

    m_pMutex->Unlock();

    return retVal;
}

/////////////////////////////////////////////////////////////////////////
//  Method:
//    IHXRenderer::GetDisplayType
//  Purpose:
//    Called by client engine to ask the renderer for it's preferred
//    display type. When layout information is not present, the
//    renderer will be asked for it's prefered display type. Depending
//    on the display type a buffer of additional information may be
//    needed. This buffer could contain information about preferred
//    window size.
//
STDMETHODIMP CVideoRenderer::GetDisplayType(REF(HX_DISPLAY_TYPE) ulFlags,
                                 REF(IHXBuffer*) pBuffer)
{
    ulFlags = HX_DISPLAY_WINDOW |
            HX_DISPLAY_SUPPORTS_RESIZE |
            HX_DISPLAY_SUPPORTS_FULLSCREEN |
            HX_DISPLAY_SUPPORTS_VIDCONTROLS;

    return HXR_OK;
}

/************************************************************************
*     Method:
*         IHXRenderer::OnEndofPackets
*     Purpose:
*         Called by client engine to inform the renderer that all the
*         packets have been delivered. However, if the user seeks before
*         EndStream() is called, renderer may start getting packets again
*         and the client engine will eventually call this function again.
*/
STDMETHODIMP CVideoRenderer::OnEndofPackets(void)
{
    if (m_pVideoFormat)
    {
      m_pVideoFormat->OnRawPacketsEnded();
    }

    return HXR_OK;
}


/************************************************************************
 *  IHXStatistics Methods
 */
/************************************************************************
 *  InitializeStatistics
 */
#define MAX_STAT_ENTRY_PAIRS  32
STDMETHODIMP CVideoRenderer::InitializeStatistics(UINT32 ulRegistryID)
{
    BOOL bCodecNameKnown = FALSE;
    char* pValue = NULL;
    HX_RESULT retVal = HXR_UNEXPECTED;

    m_ulRegistryID = ulRegistryID;

#if defined(HELIX_FEATURE_STATS)
    if (m_pVideoStats)
    {
      retVal = HXR_OK;
    }

    if (SUCCEEDED(retVal))
    {
      pValue = (char*) GetCodecName();
      if (pValue != NULL)
      {
          ReportStat(VS_CODEC_NAME, pValue);
          bCodecNameKnown = TRUE;
      }
    }

    if (SUCCEEDED(retVal))
    {
      pValue = (char*) GetRendererName();
      if (pValue != NULL)
      {
          ReportStat(VS_REND_NAME, pValue);
          // If Codec name is unknown, use a more generic renderer name
          if (!bCodecNameKnown)
          {
            ReportStat(VS_CODEC_NAME, pValue);
          }
      }
    }

    if (SUCCEEDED(retVal))
    {
      pValue = (char*) GetCodecFourCC();
      if (pValue != NULL)
      {
          ReportStat(VS_CODEC_4CC, pValue);
      }
    }

    if (SUCCEEDED(retVal))
    {
      ReportStat(VS_CURRENT_FRAMERATE, "0.0");
      ReportStat(VS_FRAMES_DISPLAYED, "100.0");
      ReportStat(VS_FRAMES_DROPPED, (INT32) 0);
      ReportStat(VS_FRAMES_LOST, (INT32) 0);
      ReportStat(VS_SURESTREAM, "FALSE");
      ReportStat(VS_IMAGE_WIDTH, (INT32) 0);
      ReportStat(VS_IMAGE_HEIGHT, (INT32) 0);
    }

    if (SUCCEEDED(retVal))
    {
      InitExtraStats();
    }

    if (SUCCEEDED(retVal))
    {
      retVal = m_pVideoStats->DisplayStats(m_ulRegistryID);
    }

    return retVal;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_STATS */
}

/************************************************************************
 *  UpdateStatistics
 */
STDMETHODIMP CVideoRenderer::UpdateStatistics()
{
#if defined(HELIX_FEATURE_STATS)
    HX_RESULT retVal = HXR_UNEXPECTED;

    if (m_pVideoStats)
    {
      retVal = HXR_OK;
    }

    if (SUCCEEDED(retVal))
    {
      retVal = m_pVideoStats->DisplayStats(m_ulRegistryID);
    }

    return retVal;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_STATS */
}


/************************************************************************
 *  IHXUntimedDecoder Methods
 */
#ifdef HELIX_FEATURE_VIDREND_UNTIMED_DECODE
STDMETHODIMP_(BOOL) CVideoRenderer::IsUntimedRendering()
{
    return m_bUntimedRendering;
}
STDMETHODIMP_(HX_RESULT) CVideoRenderer::SetUntimedRendering(BOOL bUntimedRendering)
{

    if( m_PlayState != Stopped && m_PlayState != PlayStarting )

    {

      return HXR_UNEXPECTED;

    }


    m_bUntimedRendering = bUntimedRendering;


    return HXR_OK;
}
#endif /* HELIX_FEATURE_VIDREND_UNTIMED_DECODE */

/************************************************************************
 *  IHXUpdateProperties Methods
 */
/************************************************************************
 *  UpdatePacketTimeOffset
 *    Call this method to update the timestamp offset of cached packets
 */
STDMETHODIMP CVideoRenderer::UpdatePacketTimeOffset(INT32 lTimeOffset)
{
    m_lTimeLineOffset -= lTimeOffset;

    return HXR_OK;
}


/************************************************************************
 *    Method:
 *        IHXUpdateProperties::UpdatePlayTimes
 *    Purpose:
 *        Call this method to update the playtime attributes
 */
STDMETHODIMP
CVideoRenderer::UpdatePlayTimes(IHXValues* pProps)
{
    return HXR_OK;
}


/************************************************************************
 *  IHXRenderTimeLine Methods
 */
/************************************************************************
 *  GetTimeLineValue
 */
STDMETHODIMP CVideoRenderer::GetTimeLineValue(REF(UINT32) ulTime)
{
    ulTime = ((ULONG32) -ComputeTimeAhead(0, 0));

    if (m_PlayState != Playing)
    {
        return HXR_TIMELINE_SUSPENDED;
    }

    return HXR_OK;
}


/************************************************************************
 *  IHXSiteUser Methods
 */
/************************************************************************
 *  AttachSite
 */
STDMETHODIMP CVideoRenderer::AttachSite(IHXSite* /*IN*/ pSite)
{
    if (m_pMISUSSite)
    {
      return HXR_UNEXPECTED;
    }

    m_bSiteAttached = TRUE;

    m_pMISUSSite = pSite;
    m_pMISUSSite->AddRef();

    // for sync
    IHXInterruptSafe* pIHXInterruptSafe = NULL;

    if (HXR_OK == m_pMISUSSite->QueryInterface(IID_IHXInterruptSafe,
                                     (void**)&pIHXInterruptSafe))
    {
      // Get the pref to use the optimized scheduler or not
      BOOL bUseOptimized = TRUE;
      IHXBuffer* pPrefBuffer;

      if( m_pPreferences &&
            m_pPreferences->ReadPref("UseOptimizedScheduler",
            pPrefBuffer) == HXR_OK)
      {
          bUseOptimized = *(pPrefBuffer->GetBuffer()) == '1';
          HX_RELEASE(pPrefBuffer);
      }

      if (pIHXInterruptSafe->IsInterruptSafe() && bUseOptimized)
      {
          HX_RELEASE(m_pOptimizedScheduler);
          if (HXR_OK !=
                m_pContext->QueryInterface(IID_IHXOptimizedScheduler,
                (void **) &m_pOptimizedScheduler))
          {
            // just for good luck
            m_pOptimizedScheduler = NULL;
          }
      }
    }
    HX_RELEASE(pIHXInterruptSafe);

#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    // Get Run Configuration
    // Use of VideoSurface2
    if (m_pPreferences)
    {
      ReadPrefBOOL(m_pPreferences, "VideoBoost\\NoFlip", m_bTryVideoSurface2);
    }

    // Use of OS Granule Boosting
    if (m_pPreferences)
    {
      ReadPrefBOOL(m_pPreferences, "VideoBoost\\NoOSGranuleBoost", m_bOSGranuleBoost);
      m_bOSGranuleBoostVS2 = m_bOSGranuleBoost;
    }

    // Hardware buffer count to request from VideoSurface2
    if (m_bTryVideoSurface2 && m_pPreferences)
    {
      ReadPrefINT32(m_pPreferences, "VideoBoost\\InitialHSCount", m_ulConfigHWBufCount);
    }

#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    /*
     * This is the best time to set the size of the site, we
     * know for example the the header has already been received
     * at this point.
     *
     * In most display renderers, you will store size information
     * in your stream header. In this example, we assume a specific
     * size, but we will initialize that size here as if it had
     * come from our header.
     *
     */
    SetupBitmapDefaults(m_pHeader, m_BitmapInfoHeader);
    FormatAndSetViewFrame(m_pClipRect,
                    m_BitmapInfoHeader,
                    m_rViewRect);

    m_bBitmapSet = ((m_BitmapInfoHeader.biWidth > 0) &&
                (m_BitmapInfoHeader.biHeight > 0));

    return HXR_OK;
}


STDMETHODIMP
CVideoRenderer::DetachSite()
{
    m_bSiteAttached = FALSE;

    HX_RELEASE(m_pMISUSSite);

    // We're done with these...
    if (m_pMISUS)
    {
      m_pMISUS->ReleaseSingleSiteUser();
    }

    HX_RELEASE(m_pMISUS);

    return HXR_OK;
}

STDMETHODIMP_(BOOL)
CVideoRenderer::NeedsWindowedSites()
{
    return FALSE;
};

STDMETHODIMP
CVideoRenderer::HandleEvent(HXxEvent* /*IN*/ pEvent)
{
    HX_RESULT retVal = HXR_OK;

    pEvent->handled = FALSE;
    pEvent->result  = 0;

    switch (pEvent->event)
    {
    case HX_SURFACE_UPDATE:
      m_pVSMutex->Lock();
      retVal = UpdateDisplay(pEvent, TRUE);
      m_pVSMutex->Unlock();
      break;

#if defined(HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO)
    case HX_SURFACE_MODE_CHANGE:
      switch ((int) pEvent->param2)
      {
      case HX_VIDEOSURFACE1_RECOMMENDED:
          pEvent->result = SwitchToVideoSurface1();

          if (SUCCEEDED(pEvent->result))
          {
            pEvent->handled = TRUE;
          }
          break;

      case HX_VIDEOSURFACE1_NOT_RECOMMENDED:
          pEvent->result = SwitchToVideoSurface2();

          if (SUCCEEDED(pEvent->result))
          {
            pEvent->handled = TRUE;
          }
          break;

      default:
          HX_ASSERT(FALSE);
          break;
      }
      break;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    default:
      // nothing to do
      break;
    }

    return retVal;
}

// *** IUnknown methods ***

/****************************************************************************
*  IUnknown::AddRef                                            ref:  hxcom.h
*
*  This routine increases the object reference count in a thread safe
*  manner. The reference count is used to manage the lifetime of an object.
*  This method must be explicitly called by the user whenever a new
*  reference to an object is used.
*/
STDMETHODIMP_(ULONG32) CVideoRenderer::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

/****************************************************************************
*  IUnknown::Release                                           ref:  hxcom.h
*
*  This routine decreases the object reference count in a thread safe
*  manner, and deletes the object if no more references to it exist. It must
*  be called explicitly by the user whenever an object is no longer needed.
*/
STDMETHODIMP_(ULONG32) CVideoRenderer::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;
    return 0;
}

/****************************************************************************
*  IUnknown::QueryInterface                                    ref:  hxcom.h
*
*  This routine indicates which interfaces this object supports. If a given
*  interface is supported, the object's reference count is incremented, and
*  a reference to that interface is returned. Otherwise a NULL object and
*  error code are returned. This method is called by other objects to
*  discover the functionality of this object.
*/
STDMETHODIMP CVideoRenderer::QueryInterface(REFIID riid, void** ppvObj)
{
    QInterfaceList  qiList[] =
    {
      { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*)this},
      { GET_IIDHANDLE(IID_IHXInterruptSafe), (IHXInterruptSafe*)this},
      { GET_IIDHANDLE(IID_IHXUpdateProperties), (IHXUpdateProperties*)this},
      { GET_IIDHANDLE(IID_IHXRenderTimeLine), (IHXRenderTimeLine*)this},

#ifdef HELIX_FEATURE_VIDREND_UNTIMED_DECODE

      { GET_IIDHANDLE(IID_IHXUntimedRenderer), (IHXUntimedRenderer*)this},

#endif

      { GET_IIDHANDLE(IID_IHXPaceMakerResponse), (IHXPaceMakerResponse*)this},
      { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXPlugin*) this},
      { GET_IIDHANDLE(IID_IHXPlugin), (IHXPlugin*)this},
      { GET_IIDHANDLE(IID_IHXRenderer), (IHXRenderer*)this},
      { GET_IIDHANDLE(IID_IHXSiteUser), (IHXSiteUser*)this},
      { GET_IIDHANDLE(IID_IHXStatistics), (IHXStatistics*)this},
    };

    if (QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj) == HXR_OK)
    {
      return HXR_OK ;
    }
    else if (m_pMISUS && IsEqualIID(riid, IID_IHXSiteUserSupplier))
    {
      return m_pMISUS->QueryInterface(IID_IHXSiteUserSupplier,ppvObj);
    }
    else
    {
      *ppvObj = NULL;
      return HXR_NOINTERFACE;
    }
}


/****************************************************************************
 *  Renderer's customizable fuctions - can be called any time
 */
/****************************************************************************
 *  GetStreamVersion
 */
void CVideoRenderer::GetStreamVersion(ULONG32 &ulThisMajorVersion,
                                    ULONG32 &ulThisMinorVersion)
{
    ulThisMajorVersion = STREAM_MAJOR_VERSION;
    ulThisMinorVersion = STREAM_MINOR_VERSION;
}

/****************************************************************************
 *  GetContentVersion
 */
void CVideoRenderer::GetContentVersion(ULONG32 &ulThisMajorVersion,
                                     ULONG32 &ulThisMinorVersion)
{
    ulThisMajorVersion = CONTENT_MAJOR_VERSION;
    ulThisMinorVersion = CONTENT_MINOR_VERSION;
}

/****************************************************************************
 *  GetUpgradeMimeType
 */
const char* CVideoRenderer::GetUpgradeMimeType(void)
{
    const char** pStreamMimeTypes = NULL;
    UINT32 ulInitialGranularity;

    GetRendererInfo(pStreamMimeTypes, ulInitialGranularity);

    if (pStreamMimeTypes)
    {
      return pStreamMimeTypes[0];
    }

    return NULL;
}

/****************************************************************************
 *  GetRendererName
 */
const char* CVideoRenderer::GetRendererName(void)
{
    return BASE_VIDEO_RENDERER_NAME;
}

/****************************************************************************
 *  GetCodecName
 */
const char* CVideoRenderer::GetCodecName(void)
{
    return NULL;
}

/****************************************************************************
 *  GetCodecFourCC
 */
const char* CVideoRenderer::GetCodecFourCC(void)
{
    return NULL;
}

/****************************************************************************
 *  GetLateFrameTolerance
 */
ULONG32 CVideoRenderer::GetLateFrameTolerance(void)
{
    return LATE_FRAME_TOL;
}

/****************************************************************************
 *  GetEarlyFrameTolerance
 */
ULONG32 CVideoRenderer::GetEarlyFrameTolerance(void)
{
    return EARLY_FRAME_TOL;
}

/****************************************************************************
 *  GetMaxOptimizedVideoLead
 */
ULONG32 CVideoRenderer::GetMaxOptimizedVideoLead(void)
{
    return MAX_OPTIMIZED_VIDEO_LEAD;
}

/****************************************************************************
 *  GetBltPacketQueueSize
 */
ULONG32 CVideoRenderer::GetBltPacketQueueSize(void)
{
    ULONG32 ulSize = BLT_PACKET_QUEUE_SIZE;

    if (m_pVideoFormat)
    {
      m_pVideoFormat->GetMaxDecodedFrames();
    }

    return ulSize;
}

/****************************************************************************
 *  GetSyncGoalSmoothingDepth
 */
ULONG32 CVideoRenderer::GetSyncGoalSmoothingDepth(void)
{
    return SYNC_GOAL_SMOOTHING_DEPTH;
}

/****************************************************************************
 *  GetSpeedupGoalSmoothingDepth
 */
ULONG32 CVideoRenderer::GetSpeedupGoalSmoothingDepth(void)
{
    return SPEEDUP_GOAL_SMOOTHING_DEPTH;
}

/****************************************************************************
 *  GetNoFramesPollingInterval
 */
ULONG32 CVideoRenderer::GetNoFramesPollingInterval(void)
{
    return NO_FRAMES_POLLING_INTERVAL;
}

/****************************************************************************
 *  GetMaxSleepTime
 */
ULONG32 CVideoRenderer::GetMaxSleepTime(void)
{
    return m_ulMaxSleepTime;
}


/****************************************************************************
 *  GetMaxSleepTime
 */
ULONG32 CVideoRenderer::GetMaxBadSeqSamples(void)
{
    return MAX_BAD_SAMPLE_INTERVAL / m_ulSyncInterval;
}


/****************************************************************************
 *  GetDecodePriority
 */
LONG32 CVideoRenderer::GetDecodePriority(void)
{
    return m_lDecodePriority;
}


HX_RESULT CVideoRenderer::SetDecodePriority(LONG32 lPriority)
{
    HX_RESULT retVal = HXR_OK;

    if (m_pDecoderPump)
    {
      retVal = m_pDecoderPump->SetPriority(lPriority);
    }

    if (SUCCEEDED(retVal))
    {
      m_lDecodePriority = lPriority;
    }

    return retVal;
}


/****************************************************************************
 *  CreateFormatObject
 */
CVideoFormat* CVideoRenderer::CreateFormatObject(IHXValues* pHeader)
{
    return new CVideoFormat(m_pCommonClassFactory,
                      this);
}

/****************************************************************************
 *  SetupBitmapDefaults
 */
void CVideoRenderer::SetupBitmapDefaults(IHXValues* pHeader,
                                 HXBitmapInfoHeader &bitmapInfoHeader)
{
    // size calculation is taken from crvvideo
    bitmapInfoHeader.biSize = sizeof (HXBitmapInfoHeader);
    bitmapInfoHeader.biWidth = 0; // 352; // unknown
    bitmapInfoHeader.biHeight = 0; // 288;      // unknown
    bitmapInfoHeader.biPlanes = 1;
    bitmapInfoHeader.biBitCount = 24;
    bitmapInfoHeader.biCompression = HX_I420;
    bitmapInfoHeader.biSizeImage = bitmapInfoHeader.biWidth *
                             bitmapInfoHeader.biHeight *
                             bitmapInfoHeader.biBitCount /
                             8;
    bitmapInfoHeader.biXPelsPerMeter = 0;
    bitmapInfoHeader.biYPelsPerMeter = 0;
    bitmapInfoHeader.biClrUsed = 0;
    bitmapInfoHeader.biClrImportant = 0;
    bitmapInfoHeader.rcolor   = 0;
    bitmapInfoHeader.gcolor   = 0;
    bitmapInfoHeader.bcolor   = 0;
}

/****************************************************************************
 *  FormatAndSetViewFrame
 */
void CVideoRenderer::FormatAndSetViewFrame(HXxRect* pClipRect,
                                 HXBitmapInfoHeader &bitmapInfoHeader,
                                 HXxRect &rViewRect,
                                 BOOL bMutex)
{
    BOOL bAsDefault = TRUE;
    HXxSize szViewFrame;

    if (bMutex)
    {
      DisplayMutex_Lock();
    }

    if (pClipRect)
    {
      rViewRect = *pClipRect;

      // Insure the ViewRect is inside the bitmap Rect
      // Clip x
      rViewRect.left = (rViewRect.left > 0) ?
          rViewRect.left : 0;
      rViewRect.right = (rViewRect.right > 0) ?
          rViewRect.right : 0;
      rViewRect.left = (rViewRect.left < bitmapInfoHeader.biWidth) ?
          rViewRect.left : bitmapInfoHeader.biWidth;
      rViewRect.right = (rViewRect.right < bitmapInfoHeader.biWidth) ?
          rViewRect.right : bitmapInfoHeader.biWidth;

      // Clip y
      rViewRect.top = (rViewRect.top > 0) ?
          rViewRect.top : 0;
      rViewRect.bottom = (rViewRect.bottom > 0) ?
          rViewRect.bottom : 0;
      rViewRect.top = (rViewRect.top < bitmapInfoHeader.biHeight) ?
          rViewRect.top : bitmapInfoHeader.biHeight;
      rViewRect.bottom = (rViewRect.bottom < bitmapInfoHeader.biHeight) ?
          rViewRect.bottom : bitmapInfoHeader.biHeight;
    }
    else
    {
      rViewRect.left = 0;
      rViewRect.top = 0;
      rViewRect.right = bitmapInfoHeader.biWidth;
      rViewRect.bottom = bitmapInfoHeader.biHeight;
    }

    // Compute Size
    szViewFrame.cx = rViewRect.right - rViewRect.left;
    szViewFrame.cy = rViewRect.bottom - rViewRect.top;

    if ((szViewFrame.cx <= 0) || (szViewFrame.cy <= 0))
    {
      if (m_pClipRect)
      {
          szViewFrame.cx = m_pClipRect->right - m_pClipRect->left;
          szViewFrame.cy = m_pClipRect->bottom - m_pClipRect->top;
      }

      if ((szViewFrame.cx <= 0) || (szViewFrame.cy <= 0))
      {
          szViewFrame.cx = DEFAULT_WIN_SIZE_X;
          szViewFrame.cy = DEFAULT_WIN_SIZE_Y;
      }
    }

    if (m_pClipRect)
    {
      bAsDefault = FALSE;
    }

    _ResizeViewFrame(szViewFrame, FALSE, TRUE, bAsDefault);

    if (bMutex)
    {
      DisplayMutex_Unlock();
    }
}


/****************************************************************************
 *  ResizeViewFrame
 */
BOOL CVideoRenderer::ResizeViewFrame(HXxSize szViewFrame,
                             BOOL bMutex)
{
    HX_RESULT retVal;

    retVal = _ResizeViewFrame(szViewFrame,
                        bMutex,
                        FALSE,
                        FALSE);

    return retVal;
}

BOOL CVideoRenderer::_ResizeViewFrame(HXxSize szViewFrame,
                              BOOL bMutex,
                              BOOL bForceSyncResize,
                              BOOL bAsDefault)
{
    BOOL bRetVal = FALSE;

    if (m_bFrameSizeInitialized)
    {
      return bRetVal;
    }

    if (bMutex)
    {
      DisplayMutex_Lock();
    }

    if (!m_bFrameSizeInitialized)
    {
      // If window size is already set, ignore further attempts to
      // resize
      if (m_bWinSizeFixed)
      {
          szViewFrame.cx = m_SetWinSize.cx;
          szViewFrame.cy = m_SetWinSize.cy;
      }

      // If resulting size invalid, default to cliprect or bitmap size
      if ((szViewFrame.cx <= 0) || (szViewFrame.cy <= 0))
      {
          if (((szViewFrame.cx <= 0) || (szViewFrame.cy <= 0)) &&
            m_pClipRect)
          {
            szViewFrame.cx = m_pClipRect->right - m_pClipRect->left;
            szViewFrame.cy = m_pClipRect->bottom - m_pClipRect->top;
          }

          if ((szViewFrame.cx <= 0) || (szViewFrame.cy <= 0))
          {
            szViewFrame.cx = m_BitmapInfoHeader.biWidth;
            szViewFrame.cy = m_BitmapInfoHeader.biHeight;
          }
      }

      m_SetWinSize.cx = szViewFrame.cx;
      m_SetWinSize.cy = szViewFrame.cy;

#if !defined(HELIX_FEATURE_VIDREND_DYNAMIC_RESIZE)
      m_bWinSizeFixed = (m_bWinSizeFixed || (!bAsDefault));
#else
        HX_ASSERT(!m_bWinSizeFixed);
#endif

#ifdef RESIZE_AFTER_SITE_ATTACHED
      if (m_bSiteAttached)
#endif      // RESIZE_AFTER_SITE_ATTACHED
      {
#ifdef SET_NONZERO_VIEWFRAME_ONLY
          if ((szViewFrame.cx > 0) && (szViewFrame.cy > 0))
#endif      // SET_NONZERO_VIEWFRAME_ONLY
          {
#ifdef SYNC_RESIZE_OK
            bForceSyncResize = TRUE;
#endif      // SYNC_RESIZE_OK

            if ((m_LastSetSize.cx != szViewFrame.cx) ||
                (m_LastSetSize.cy != szViewFrame.cy))
            {
                m_LastSetSize = szViewFrame;

                if (bForceSyncResize)
                {
                  m_pMISUSSite->SetSize(szViewFrame);
                }
                else
                {
                  if (m_pResizeCB == NULL)
                  {
                      m_pResizeCB = new CSetSizeCB(m_pMISUSSite);

                      HX_ASSERT(m_pResizeCB);

                      if (m_pResizeCB)
                      {
                        m_pResizeCB->AddRef();
                      }
                  }

                  if (m_pResizeCB)
                  {
                      m_pResizeCB->SetSize(szViewFrame);

                      HX_ASSERT(m_pScheduler);

                      if (m_pScheduler)
                      {
                        m_pScheduler->RelativeEnter(m_pResizeCB, 0);
                      }
                  }
                }
            }
          }

          // Once the the frame size is initialized, it is no longer
          // changable by the renderer.
          // The frame size can become initialzied only of the window
          // size is fixed. It can become fixed only if explicitly set
          // by non-default mode call to ResizeViewFrame.  ResizeViewFrame
          // can be called in non-default mode by either the video format
          // or the call can be made internally based on meta-header
          // specified information (e.g. clip rect.)
          if (m_bWinSizeFixed)
          {
            m_bFrameSizeInitialized = TRUE;
            bRetVal = TRUE;
          }
      }
    }

    if (bMutex)
    {
      DisplayMutex_Unlock();
    }

    return bRetVal;
}


/****************************************************************************
 *  SetSyncInterval
 */
void CVideoRenderer::SetSyncInterval(ULONG32 ulSyncInterval)
{
    if (ulSyncInterval != 0)
    {
      m_ulSyncInterval = ulSyncInterval;
    }
}


/****************************************************************************
 *  InitExtraStats
 */
HX_RESULT CVideoRenderer::InitExtraStats(void)
{
    return HXR_OK;
}


/****************************************************************************
 *  Method:
 *    CVideoFormat::AdjustVideoMapping
 *
 */
void CVideoRenderer::AdjustVideoMapping(HXxRect &destRect,
                              HXxRect &sorcRect,
                              CMediaPacket*pActiveVideoPacket)
{
    return;
}

/****************************************************************************
 *  Renderer's private fuctions
 */
BOOL CVideoRenderer::ForceRefresh(void)
{
    BOOL bIsVisible;

    // Ask what the size was really set to!
    HXxSize finalSize;
    m_pMISUSSite->GetSize(finalSize);

    /* We now damage the entire rect all the time             */
    HXxRect damageRect = {0, 0, finalSize.cx, finalSize.cy};

    // Mark associated screen area as damaged as well...
    m_pMISUSSite->DamageRect(damageRect);

    HX_ASSERT(!m_bPendingRedraw);
    HX_ASSERT(!m_bVS1UpdateInProgress);

    m_bPendingRedraw = TRUE;
    m_bVS1UpdateInProgress = TRUE;

    m_pVSMutex->Unlock();
    m_pMISUSSite->ForceRedraw();
    m_pVSMutex->Lock();
    m_bVS1UpdateInProgress = FALSE;

    // If the redraw is still pending, it did not occur so assume the
    // surface is invisible
    bIsVisible = !m_bPendingRedraw;
    m_bPendingRedraw = FALSE;

    return bIsVisible;
}

HX_RESULT CVideoRenderer::UpdateDisplay(HXxEvent* pEvent,
                              BOOL bSystemEvent,
                              BOOL bIsVisible)
{
    IHXVideoSurface* pVideoSurface;
    CMediaPacket* pTmpPacket;
    CMediaPacket* pVideoPacket = NULL;
    BOOL bBitmapFormatChanged = FALSE;
    BOOL bNewFrameBlt = FALSE;
    HXxSize windowSize = {0, 0};
    LONG32 lFramesInBuffer;
    HX_RESULT retVal = HXR_OK;

    if (m_bVS1UpdateInProgress && m_bUseVideoSurface2)
    {
      // Ignore update for incorrect surface
      return HXR_OK;
    }

    lFramesInBuffer = m_pBltPacketQueue->Count();

    m_bPendingRedraw = FALSE;

    HX_TRACE_THINGY("C:/trace.txt", "Handle", m_hPendingHandle);

    if (!m_bUseVideoSurface2 || !bSystemEvent)
    {
      do
      {
          pVideoPacket = (CMediaPacket*) m_pBltPacketQueue->Get();
          lFramesInBuffer--;


          if ((lFramesInBuffer <= 0) ||
            (!m_pVideoFormat->IsFrameSkippable(pVideoPacket)))
          {
            bNewFrameBlt = TRUE;
            break;
          }

#if defined(HELIX_FEATURE_STATS)
          m_pVideoStats->ReportDroppedFrame();
#endif /* HELIX_FEATURE_STATS */

          ReleasePacket(pVideoPacket);
      } while (TRUE);
    }

    pVideoSurface = (IHXVideoSurface*) (pEvent->param1);

    if (pVideoPacket)
    {
      if (m_bVS2BufferUnavailableOnLastBlt &&
          m_pActiveVideoPacket)
      {
          m_bVS2BufferUnavailableOnLastBlt = FALSE;
#if defined(HELIX_FEATURE_STATS)
          m_pVideoStats->ReportDroppedFrame();
#endif /* HELIX_FEATURE_STATS */
      }

      pTmpPacket = pVideoPacket;
      pVideoPacket = m_pActiveVideoPacket;
      m_pActiveVideoPacket = pTmpPacket;
      m_ulActiveVideoTime = pTmpPacket->m_ulTime;

      bBitmapFormatChanged = (m_pActiveVideoPacket->m_pSampleDesc &&
                        m_pVideoFormat->IsBitmapFormatChanged(
                              m_BitmapInfoHeader,
                              m_pActiveVideoPacket));
    }

    if (((!m_bVideoSurfaceInitialized) && m_pActiveVideoPacket) ||
      m_bVideoSurfaceReinitRequested ||
      bBitmapFormatChanged)
    {
      BOOL bUsedVideoSurface2 = m_bUseVideoSurface2;

      if (bBitmapFormatChanged)
      {
          m_pVideoFormat->InitBitmapInfoHeader(m_BitmapInfoHeader,
                                     m_pActiveVideoPacket);
          m_bBitmapSet = TRUE;
          m_bVideoSurfaceInitialized = FALSE;   // Force full reinit
      }

      FormatAndSetViewFrame(m_pClipRect,
                        m_BitmapInfoHeader,
                        m_rViewRect,
                        FALSE);

      HX_ASSERT(m_bBitmapSet);
      
      // If we do not have information on the bitmap configuration or if
      // we do not have surface to cofigure - do not intialize
      if (m_bBitmapSet && pVideoSurface)
      {
          // Try VideoSurface2 first unless not desired
          if (m_bTryVideoSurface2 && (!m_bVideoSurface1Requested))
          {
            InitVideoSurface2(m_SetWinSize.cx, m_SetWinSize.cy);
          }

          // Try VideoSurface1 if prefered or if VideoSurface2 would
          // not initialize
          if ((!m_bUseVideoSurface2) || m_bVideoSurface1Requested)
          {
            // Video Surface1 must be used
            InitVideoSurface1(bUsedVideoSurface2, pVideoSurface);
          }

          m_bVideoSurfaceInitialized = TRUE;
          m_bVideoSurfaceReinitRequested = FALSE;

          m_bSchedulerStartRequested = TRUE;


          // Force the cycle in the decoder pump to expedite the completion
          // of the scheduler start request.
          if (IsDecoderRunning())
          {
            if (m_pDecoderPump)
            {
                m_pDecoderPump->Signal();
            }
          }

#if defined(HELIX_FEATURE_STATS)
          ReportStat(VS_IMAGE_WIDTH, (INT32) (m_rViewRect.right - m_rViewRect.left));
          ReportStat(VS_IMAGE_HEIGHT, (INT32) (m_rViewRect.bottom - m_rViewRect.top));
#endif /* #if defined(HELIX_FEATURE_STATS) */
      }

        // Now that we have the video dimensions, check to see that this clip
        // is not going to be too taxing on the poor CPU.
        UINT32 ulMaxVidWidth = 0;
        UINT32 ulMaxVidHeight = 0;
        if( m_pPreferences && 
            ( HXR_OK == ReadPrefINT32( m_pPreferences, "MaxVideoWidth", ulMaxVidWidth ) ) &&
            ( HXR_OK == ReadPrefINT32( m_pPreferences, "MaxVideoHeight", ulMaxVidHeight ) ) )
        {
            ULONG32 ulMaxVidArea = ulMaxVidWidth * ulMaxVidHeight;
            INT32 nWidth = (INT32) (m_rViewRect.right - m_rViewRect.left);
            INT32 nHeight = (INT32) (m_rViewRect.bottom - m_rViewRect.top);
            if( (ULONG32)(nWidth*nHeight) > ulMaxVidArea )
            {
                IHXErrorMessages * pErrMsg = NULL;
                m_pContext->QueryInterface(IID_IHXErrorMessages, (void**)&pErrMsg);
                if( pErrMsg )
                {
                    pErrMsg->Report(HXLOG_ERR, HXR_SLOW_MACHINE, 0, NULL, NULL);
                    HX_RELEASE(pErrMsg);
                }
            }
        }
    }
    
    if (m_pActiveVideoPacket && bIsVisible && pVideoSurface)
    {
      HX_ASSERT(m_bVideoSurfaceInitialized);

      if (m_bVideoSurfaceInitialized && m_pActiveVideoPacket->m_pData)
      {
#ifdef DEFAULT_VS2_TARGETRECT
          if (!m_bUseVideoSurface2)
#endif      // DEFAULT_VS2_TARGETRECT
          {
            m_pMISUSSite->GetSize(windowSize);
          }

          HXxRect rDestRect = { 0, 0, windowSize.cx, windowSize.cy };
          HXxRect rSrcRect = m_rViewRect;

          AdjustVideoMapping(rDestRect, rSrcRect, m_pActiveVideoPacket);

          if (m_bUseVideoSurface2)
          {
            pEvent->result = UpdateVideoSurface2(pVideoSurface,
                                         rDestRect,
                                         rSrcRect,
                                         !bNewFrameBlt,
                                         bSystemEvent);

            if (pEvent->result == HXR_ABORT)
            {
                pEvent->result = HXR_OK;
                retVal = HXR_ABORT;
            }
          }
          else if (bSystemEvent)
          {
            pEvent->result = UpdateVideoSurface(pVideoSurface,
                                        m_pActiveVideoPacket,
                                        rDestRect,
                                        rSrcRect,
                                        m_bOptimizedBlt);

            if (FAILED(pEvent->result))
            {
                if (m_bVideoSurfaceReinitRequested)
                {
                  HX_ASSERT(!m_bVideoSurface1Requested);

                  InitVideoSurface2(m_SetWinSize.cx, m_SetWinSize.cy);

                  if (m_bUseVideoSurface2)
                  {
                      m_bVideoSurfaceInitialized = TRUE;
                      m_bVideoSurfaceReinitRequested = FALSE;

                      pEvent->result = UpdateVideoSurface2(pVideoSurface,
                                                 rDestRect,
                                                 rSrcRect,
                                                 FALSE,
                                                 bSystemEvent);

                      if (pEvent->result == HXR_ABORT)
                      {
                        pEvent->result = HXR_OK;
                      }
                  }
                }
                else
                {
                  InitVideoSurface1(FALSE, pVideoSurface);

                  pEvent->result = UpdateVideoSurface(pVideoSurface,
                                              m_pActiveVideoPacket,
                                              rDestRect,
                                              rSrcRect,
                                              m_bOptimizedBlt);
                }
            }
          }
          else
          {
            // This is not a system event and this call is not under
            // the protection of the top level site (TLS) mutex and
            // it needs to be.
            // Bring it under the TLS mutex protection by envoking
            // forced refresh
            bIsVisible = ForceRefresh();

            pEvent->result = HXR_OK;
            retVal = HXR_ABORT;
          }

          if (bNewFrameBlt && bIsVisible)
          {
#if defined(HELIX_FEATURE_STATS)
            if (pEvent->result == HXR_OK)
            {
                m_pVideoStats->ReportBlt(m_pActiveVideoPacket->m_ulTime);
            }
            else if (!m_bVS2BufferUnavailableOnLastBlt)
            {
                // If buffer wasn't available, we'll try again
                m_pVideoStats->ReportDroppedFrame();
            }
#endif /* HELIX_FEATURE_STATS */
          }
      }
    }

    if (pVideoPacket)
    {
      ReleasePacket(pVideoPacket, m_bActiveVideoPacketLocalized);
      m_bActiveVideoPacketLocalized = FALSE;
    }

    pEvent->handled = TRUE;

    return retVal;
}

HX_RESULT CVideoRenderer::UpdateVideoSurface(IHXVideoSurface* pVideoSurface,
                                   CMediaPacket* pVideoPacket,
                                   HXxRect &destRect,
                                   HXxRect &sorcRect,
                                   BOOL bOptimizedBlt)
{
    HX_RESULT retVal;

    if (bOptimizedBlt)
    {
      retVal = pVideoSurface->OptimizedBlt(
          pVideoPacket->m_pData,
          destRect,
          sorcRect);
    }
    else
    {
      retVal = pVideoSurface->Blt(
          pVideoPacket->m_pData,
          &m_BitmapInfoHeader,
          destRect,
          sorcRect);
    }

    return retVal;
}


HX_RESULT CVideoRenderer::InitVideoSurface1(BOOL bUsedVideoSurface2,
                                  IHXVideoSurface* pVideoSurface)
{
    HX_RESULT retVal = HXR_OK;

    if (bUsedVideoSurface2)
    {
      OffOptimizedVideo();
    }

    /***
    if (pVideoSurface)
    {
      retVal = pVideoSurface->EndOptimizedBlt();
    }
    else
    {
      EndOptimizedBlt();
    }
    ***/

    // Video Surface1 is needed - try optimized Blt setup
    if (!m_bVideoSurfaceInitialized)
    {
      if (pVideoSurface)
      {
          retVal = pVideoSurface->BeginOptimizedBlt(&m_BitmapInfoHeader);
      }
      else
      {
          retVal = BeginOptimizedBlt(&m_BitmapInfoHeader);
      }

      if (SUCCEEDED(retVal))
      {
          m_bOptimizedBlt = TRUE;
      }
      else
      {
          m_bOptimizedBlt = FALSE;
      }

      retVal = HXR_OK;
    }

    if (SUCCEEDED(retVal))
    {
      m_ulEarlyFrameTol = GetEarlyFrameTolerance();
      HX_DELETE(m_pVSurf2InputBIH);
      m_bUseVideoSurface2 = FALSE;
      if (m_bVS2BufferUnavailableOnLastBlt)
      {
#if defined(HELIX_FEATURE_STATS)
          m_pVideoStats->ReportDroppedFrame();
#endif /* HELIX_FEATURE_STATS */
          m_bVS2BufferUnavailableOnLastBlt = FALSE;
      }
    }

    return retVal;
}


inline BOOL CVideoRenderer::ShouldKickStartScheduler()
{
    BOOL bShouldStart;

    bShouldStart = (!m_bPendingCallback && !m_bUseVideoSurface2);

    return bShouldStart;
}


HX_RESULT CVideoRenderer::ScheduleCallback(UINT32 ulRelativeTime,
                                 BOOL bIsScheduled,
                                 UINT32 ulBaseTime)
{
    IHXCallback* pCallback = (IHXCallback*) this;
    CallbackHandle hPendingHandle;
    ULONG32 ulThisCallbackCount;

    if (m_hPendingHandle == (CallbackHandle)NULL)
    {
      m_bPendingCallback = TRUE;
      m_ulCallbackCounter++;
      if (m_ulCallbackCounter == 0)
      {
          m_ulCallbackCounter++;
      }
      ulThisCallbackCount = m_ulCallbackCounter;
      m_hPendingHandle = ulThisCallbackCount;
      m_bIsScheduledCB = bIsScheduled;

      if (ulRelativeTime > m_ulMaxSleepTime)
      {
          ulRelativeTime = m_ulMaxSleepTime;
          m_bIsScheduledCB = FALSE;
      }

      HX_TRACE_THINGY("C:/trace.txt", "SchedCBTime", ulRelativeTime);

#ifdef DO_ABSOLUTE_TIMING
      LONG32 lTimeOffset;
      HXTimeval hxTime;
      ULONG32 ulNTries = N_STABILIZATION_ITERATIONS;
      ULONG32 ulCurrentTime1;
      ULONG32 ulCurrentTime2;

      if (bIsScheduled)
      {
          // Obtain atomic time reading (avoid context switch)
          do
          {
            ulCurrentTime1 = HX_GET_BETTERTICKCOUNT();

            // Always use the optimized scheduler if we have one
            if (m_pOptimizedScheduler != NULL)
            {
                hxTime = m_pOptimizedScheduler->GetCurrentSchedulerTime();
            }
            else
            {
                hxTime = m_pScheduler->GetCurrentSchedulerTime();
            }

            ulCurrentTime2 = HX_GET_BETTERTICKCOUNT();

            lTimeOffset = (LONG32) (ulCurrentTime2 - ulBaseTime + ulRelativeTime);

            ulNTries--;
          } while (((ulCurrentTime2 - ulCurrentTime1) > MAX_ALLOWED_TIMING_ERROR) &&
            (ulNTries != 0) &&
            (lTimeOffset > 0));

          if (lTimeOffset >= SMALLEST_TIMABLE_PERIOD)
          {
            hxTime.tv_usec += (lTimeOffset * MILLISECOND);
            if (hxTime.tv_usec >= SECOND)
            {
                hxTime.tv_sec += (hxTime.tv_usec / SECOND);
                hxTime.tv_usec %= SECOND;
            }
          }

          hPendingHandle = ScheduleAbsoluteCallback(hxTime, pCallback);
      }
      else
#endif  // DO_ABSOLUTE_TIMING
      {

          hPendingHandle = ScheduleRelativeCallback(ulRelativeTime, pCallback);

      }

      HX_ASSERT(hPendingHandle);

      // Remember the handle if callback did not already fire synchronously
      if (m_hPendingHandle == ulThisCallbackCount)
      {
          HX_TRACE_THINGY("C:/trace.txt", "SchedCBHandle", hPendingHandle);

          m_hPendingHandle = hPendingHandle;
          m_bPendingCallback = (m_hPendingHandle != ((CallbackHandle) NULL));
      }
    }

    return HXR_OK;
}


inline CallbackHandle CVideoRenderer::ScheduleRelativeCallback
(
    UINT32 ulRelativeTime,
    IHXCallback* pCallback
)
{
    CallbackHandle hCallback;

    // Always use the optimized scheduler if we have one
    if (m_pOptimizedScheduler != NULL)
    {
      hCallback = m_pOptimizedScheduler->RelativeEnter(
          pCallback, ulRelativeTime);
    }
    else
    {
      hCallback = m_pScheduler->RelativeEnter(
          pCallback, ulRelativeTime);
    }

    return hCallback;
}


inline CallbackHandle CVideoRenderer::ScheduleAbsoluteCallback
(
    HXTimeval &hxTime,
    IHXCallback* pCallback
)
{
    CallbackHandle hCallback;

    // Always use the optimized scheduler if we have one
    if (m_pOptimizedScheduler != NULL)
    {
      hCallback = m_pOptimizedScheduler->AbsoluteEnter(
          pCallback, hxTime);
    }
    else
    {
      hCallback = m_pScheduler->AbsoluteEnter(
          pCallback, hxTime);
    }

    return hCallback;
}


void CVideoRenderer::RemoveCallback(CallbackHandle &hCallback)
{
    if (hCallback != (CallbackHandle)NULL)
    {
      if (m_pOptimizedScheduler != NULL)
      {
          m_pOptimizedScheduler->Remove(hCallback);
      }
      else if (m_pScheduler)
      {
          m_pScheduler->Remove(hCallback);
      }

      hCallback = NULL;
    }
}


/*
 *   Draw any frame that's due, and schedule a new callback for the next
 *   frame
 */
void CVideoRenderer::SchedulerCallback(BOOL bIsScheduled,
                               BOOL bResched,
                               BOOL bIsVS2Call,
                               BOOL bProcessUndisplayableFramesOnly)
{
    CMediaPacket* pPkt;
    LONG32 lTimeDelta;
    ULONG32 ulNextFrameTime;
    BOOL bFrameIsSkippable;
    ULONG32 ulBaseTime;
    BOOL bHaveNextFrame;
    BOOL bDisplayFrame;
    ULONG32 ulLoopCounter = 0;

    DisplayMutex_Lock();

    while ((m_PlayState == Playing) ||
         ((m_PlayState == PlayStarting) && m_bFirstFrame))
    {
      if (m_bUseVideoSurface2)
      {
          if (bIsVS2Call)
          {
            m_bVideoSurface2Transition = FALSE;
          }
          else
          {
            m_bPendingCallback = FALSE;
            DisplayMutex_Unlock();
            return;
          }
      }
      else
      {
          if (bIsVS2Call)
          {
            DisplayMutex_Unlock();
            return;
          }

          m_bVS2BufferUnavailableOnLastBlt = FALSE;
      }

#ifdef ENABLE_FETCH_TRACE
      ULONG32 ulFetchTraceStart = HX_GET_BETTERTICKCOUNT();
#endif      // ENABLE_FETCH_TRACE

      bDisplayFrame = TRUE;

#ifdef HELIX_FEATURE_VIDREND_UNTIMED_DECODE
      if( !m_bUntimedRendering )
      {
#endif /* HELIX_FEATURE_VIDREND_UNTIMED_DECODE */
      while ((bHaveNextFrame = m_pVideoFormat->GetNextFrameTime(ulNextFrameTime)) != 0)
      {

#ifdef ENABLE_FETCH_TRACE
          if (ulFetchTraceIdx < MAX_FETCH_TRACE_ENTRIES)
          {
            fetchTraceArray[ulFetchTraceIdx++] =
                HX_GET_BETTERTICKCOUNT() - ulFetchTraceStart;
          }
#endif      // ENABLE_FETCH_TRACE

          lTimeDelta = ComputeTimeAhead(ulNextFrameTime,
                                0,
                                &ulBaseTime);

          if (((lTimeDelta + ((LONG32) m_ulLateFrameTol)) >= 0) ||
            bIsScheduled ||
            m_bVS2BufferUnavailableOnLastBlt)
          {
            break;
          }
          else
          {
#ifdef ENABLE_SCHED_TRACE
            if (ulSchedTraceIdx < MAX_SCHED_TRACE_ENTRIES)
            {
                schedTraceArray[ulSchedTraceIdx++] = lTimeDelta;
            }
#endif      // ENABLE_SCHED_TRACE

            bFrameIsSkippable = TRUE;

            m_pVideoFormat->IsNextFrameSkippable(bFrameIsSkippable);

            if (!bFrameIsSkippable)
            {
                if (m_bFirstFrame)
                {
                  bDisplayFrame = FALSE;
                }
                break;
            }
          }

#ifdef ENABLE_FETCH_TRACE
          ulFetchTraceStart = HX_GET_BETTERTICKCOUNT();
#endif      // ENABLE_FETCH_TRACE

          pPkt = m_pVideoFormat->Dequeue();

#ifdef ENABLE_FETCH_TRACE
          if (ulFetchTraceIdx < MAX_FETCH_TRACE_ENTRIES)
          {
            fetchTraceArray[ulFetchTraceIdx++] =
                HX_GET_BETTERTICKCOUNT() - ulFetchTraceStart;
          }
#endif      // ENABLE_FETCH_TRACE

          if (!m_bFirstFrame)
          {
#if defined(HELIX_FEATURE_STATS)
            m_pVideoStats->ReportDroppedFrame();
#endif /* HELIX_FEATURE_STATS */
          }

          ReleasePacket(pPkt);
      }
#ifdef HELIX_FEATURE_VIDREND_UNTIMED_DECODE
      } else {
          bHaveNextFrame = m_pVideoFormat->GetNextFrameTime(ulNextFrameTime);
          lTimeDelta = 0;

          ComputeTimeAhead( 0, 0, &ulBaseTime );

      }
#endif /* HELIX_FEATURE_VIDREND_UNTIMED_DECODE */

      if (bProcessUndisplayableFramesOnly && bDisplayFrame)
      {
          DisplayMutex_Unlock();
          return;
      }

      if (!m_bVS2BufferUnavailableOnLastBlt)
      {
          if (bHaveNextFrame)
          {
            if ((lTimeDelta > ((LONG32) m_ulEarlyFrameTol)) &&
                (!m_bFirstFrame))
            {
                if (bResched)
                {
                  ScheduleCallback(lTimeDelta, TRUE, ulBaseTime);
                }

                DisplayMutex_Unlock();

                return;
            }
          }
          else
          {
            if (bResched)
            {
                // m_pVideoFormat->DecodeFrame();  MBO: Give user Input priority
                ScheduleCallback(m_ulNoFramesPollingInterval);
            }

            DisplayMutex_Unlock();

            return;
          }

          // Render
          pPkt = m_pVideoFormat->Dequeue();
      }
      else
      {
          // We need to reblt - but if there is a frame that's up to date
          // use it instead of old failed frame.
          pPkt = NULL;
          if (bHaveNextFrame && (lTimeDelta <= 0))
          {
            pPkt = m_pVideoFormat->Dequeue();
          }
      }

      if (pPkt != NULL)
      {
#ifdef ENABLE_SCHED_TRACE
          if (ulSchedTraceIdx < MAX_SCHED_TRACE_ENTRIES)
          {
            schedTraceArray[ulSchedTraceIdx++] = lTimeDelta;
          }
#endif      // ENABLE_SCHED_TRACE

          if (m_pMISUSSite &&
            m_pBltPacketQueue->Put(pPkt))
          {
            if (pPkt->m_pData && bDisplayFrame)
            {
                m_bFirstFrame = FALSE;
            }

            if (m_bUseVideoSurface2)
            {
                ForceDisplayUpdate(FALSE, bDisplayFrame);

                if (m_bVS2BufferUnavailableOnLastBlt)
                {
                  // We couldn't blt frame because video buffer
                  // wasn't available, try again a bit later
                  DisplayMutex_Unlock();
                  return;
                }
            }
            else
            {
                if ((!bDisplayFrame) || (!ForceRefresh()))
                {
                  // Site redraw did not occur - treat this as if the surface
                  // is invisible
                  ForceDisplayUpdate(FALSE, FALSE);
                  HX_ASSERT(!m_bPendingRedraw);
                }
            }
          }
          else
          {
#if defined(HELIX_FEATURE_STATS)
            m_pVideoStats->ReportDroppedFrame();
#endif /* HELIX_FEATURE_STATS */
            ReleasePacket(pPkt);
          }
      }
      else
      {
          // This is a reblt servicing
          if (m_bUseVideoSurface2)
          {
            HX_ASSERT(bDisplayFrame);

            ForceDisplayUpdate(FALSE, bDisplayFrame);

            if (m_bVS2BufferUnavailableOnLastBlt)
            {
                // We couldn't blt frame because video buffer
                // wasn't available, try again a bit later
                DisplayMutex_Unlock();
                return;
            }
          }
      }

      if (bResched)
      {
          ulLoopCounter++;

          if (ulLoopCounter > MAX_BLT_LOOPS)
          {
            ScheduleCallback(BLT_RELIEF_DELAY);

            DisplayMutex_Unlock();

            return;
          }
      }
      else
      {
          if (!bIsVS2Call)
          {
            DisplayMutex_Unlock();

            return;
          }
      }

      bIsScheduled = FALSE;
    }

    if ((m_PlayState != Stopped) &&
      bResched)
    {
      ScheduleCallback(NO_FRAMES_POLLING_INTERVAL);

      DisplayMutex_Unlock();

      return;
    }

    m_bPendingCallback = FALSE;

    DisplayMutex_Unlock();
}

void CVideoRenderer::ForceDisplayUpdate(BOOL bInternalSurfaceUpdateOnly,
                              BOOL bHasVisibleSurface)
{
    // Create fake events for HandleSurfaceUpdate:
    HX_ASSERT(m_pMISUSSite);

#if defined (HELIX_FEATURE_MISU)
    IHXSiteEnumerator* pSiteEnumerator;
    if (SUCCEEDED(m_pMISUSSite->QueryInterface(IID_IHXSiteEnumerator,
                                     (void**) &pSiteEnumerator)))
    {
      IHXSite* pSite;
      IHXSiteEnumerator::SitePosition nextPosition;

      if (FAILED(pSiteEnumerator->GetFirstSite(pSite, nextPosition)))
      {
          HX_ASSERT(FALSE);
      }
      else
      {
          BOOL bKeepUpdating = TRUE;

          do
          {
            bKeepUpdating = (ForceDisplayUpdateOnSite(pSite, 
                                            bInternalSurfaceUpdateOnly, 
                                            bHasVisibleSurface) != HXR_ABORT);
            pSite->Release();
          }
          while (bKeepUpdating &&
               SUCCEEDED(pSiteEnumerator->GetNextSite(pSite, nextPosition)));
      }

      pSiteEnumerator->Release();
    }
    else
    {
      ForceDisplayUpdateOnSite(m_pMISUSSite,
                         bInternalSurfaceUpdateOnly,
                         bHasVisibleSurface);
    }
#else //HELIX_FEATURE_MISU

    ForceDisplayUpdateOnSite(m_pMISUSSite,
                       bInternalSurfaceUpdateOnly,
                       bHasVisibleSurface);

#endif      //HELIX_FEATURE_MISU

}

HX_RESULT CVideoRenderer::ForceDisplayUpdateOnSite(IHXSite* pSite, 
                                       BOOL bInternalSurfaceUpdateOnly,
                                       BOOL bHasVisibleSurface)
{
    HX_RESULT retVal = HXR_OK;

    IHXVideoSurface2* pVideoSurface2;
    IHXSite2* pSite2 = NULL;
    IHXVideoSurface* pVideoSurface = NULL;
    
    if (SUCCEEDED(pSite->QueryInterface(IID_IHXSite2, (void**) &pSite2)))
    {
      pSite2->GetVideoSurface(pVideoSurface);
    }

    if (bInternalSurfaceUpdateOnly)
    {
      if (pVideoSurface)
      {
          if (SUCCEEDED(pVideoSurface->QueryInterface(IID_IHXVideoSurface2, 
                                          (void**) &pVideoSurface2)))
          {
            pVideoSurface2->PresentIfReady();
            pVideoSurface2->Release();
          }
      }
    }
    else
    {
      HXxEvent fakeEvent;

      fakeEvent.param1 = (void*) pVideoSurface;
      retVal = UpdateDisplay(&fakeEvent, FALSE, bHasVisibleSurface);
    }
    
    HX_RELEASE(pVideoSurface);
    HX_RELEASE(pSite2);

    return retVal;
}


STDMETHODIMP CVideoRenderer::Func(void)
{
    HX_TRACE_THINGY("C:/trace.txt", "Func", 0);

    m_hPendingHandle = NULL;

    SchedulerCallback(m_bIsScheduledCB);

    return HXR_OK;
}


HX_RESULT CVideoRenderer::BeginOptimizedBlt(HXBitmapInfoHeader* pBitmapInfo)
{
    HX_RESULT retVal = HXR_UNEXPECTED;
    IHXSite2* pMISUSSite2   = NULL;
    IHXVideoSurface* pVideoSurface = NULL;

    if (m_pMISUSSite)
    {
        m_pMISUSSite->QueryInterface(IID_IHXSite2, (void**)&pMISUSSite2);
        if (pBitmapInfo && pMISUSSite2)
        {
            if (SUCCEEDED(pMISUSSite2->GetVideoSurface(pVideoSurface)))
            {
                retVal = pVideoSurface->BeginOptimizedBlt(pBitmapInfo);
                if (retVal == HXR_OK)
                {
                    m_bOptimizedBlt = TRUE;
                }
                HX_RELEASE(pVideoSurface);
            }
        }
      HX_RELEASE(pMISUSSite2);
    }

    return retVal;
}


void CVideoRenderer::EndOptimizedBlt(void)
{
    IHXSite2* pMISUSSite2 = NULL;
    IHXVideoSurface* pVideoSurface = NULL;

    if (m_bOptimizedBlt && m_pMISUSSite)
    {
      m_pMISUSSite->QueryInterface(IID_IHXSite2, (void**)&pMISUSSite2);

      if (pMISUSSite2)
      {
          pMISUSSite2->GetVideoSurface(pVideoSurface);
          if (pVideoSurface)
          {
            pVideoSurface->EndOptimizedBlt();
            m_bOptimizedBlt = FALSE;
            HX_RELEASE(pVideoSurface);
          }
      }
    }

    HX_RELEASE(pMISUSSite2);
}


inline void CVideoRenderer::RequestBuffering(void)
{
    m_bBufferingNeeded = TRUE;
}


inline void CVideoRenderer::RequestBufferingEnd(void)
{
    m_bBufferingNeeded = FALSE;
}


HX_RESULT CVideoRenderer::BeginBuffering(void)
{
    HX_RESULT retVal = HXR_FAIL;
#ifdef REBUFFER_ON_VIDEO

    m_ulBufferingStartTime = HX_GET_BETTERTICKCOUNT();

    // If this is a reccuring rebuffer, start buffering only if
    // the preroll period passed since the last buffering completion.
    // This is done to prevent buffering all the time.
    if (!m_bBufferingOccured ||
      ((m_ulBufferingStartTime - m_ulBufferingStopTime) > m_ulPreroll))
    {
      // Bytes to Buffer could be used for Predata
      // - Predata was not found beneficial yet
      m_ulBytesToBuffer = (ULONG32) (((double) m_ulPreroll) *
                               ((double) m_ulAvgBitRate) /
                               8000.0);

      m_ulBufferingTimeOut = m_ulPreroll * 2;

      if (m_ulBufferingTimeOut > 0)
      {
          m_PlayState = Buffering;

          retVal = m_pStream->ReportRebufferStatus(1, 0);
      }
    }
#endif      // REBUFFER_ON_VIDEO

    return retVal;
}


HX_RESULT CVideoRenderer::EndBuffering(void)
{
    HX_RESULT retVal = HXR_UNEXPECTED;

#ifdef REBUFFER_ON_VIDEO

    if (m_PlayState == Buffering)
    {
      m_PlayState = PlayStarting;
      m_bBufferingOccured = TRUE;
      m_ulBufferingStopTime = HX_GET_BETTERTICKCOUNT();

      HX_ASSERT(m_pStream);
      retVal = m_pStream->ReportRebufferStatus(1,1);
    }
#endif      // REBUFFER_ON_VIDEO

    return retVal;
}


inline BOOL CVideoRenderer::IsBufferingComplete(IHXPacket *pPacket)
{
#ifdef REBUFFER_ON_VIDEO
    ULONG32 ulTimeNow = HX_GET_BETTERTICKCOUNT();

    if ((m_PlayState == Buffering) && (m_bBufferingNeeded))
    {
      if (pPacket &&
          ((pPacket->GetTime() - m_ulBaseTime) > m_ulPreroll))
      {
          return TRUE;
      }

      return ((ulTimeNow - m_ulBufferingStartTime) > m_ulBufferingTimeOut);
    }
#endif      // REBUFFER_ON_VIDEO

    return TRUE;
}


HX_RESULT CVideoRenderer::LocalizeActiveVideoPacket(void)
{
    HX_RESULT retVal = HXR_IGNORE;

    DisplayMutex_Lock();

    if (m_pActiveVideoPacket && (!m_bActiveVideoPacketLocalized))
    {
      CMediaPacket* pLocalPacket = NULL;
      ULONG32 ulDataSize = m_pActiveVideoPacket->m_ulDataSize;
      UINT8* pData = new UINT8 [ulDataSize];

      retVal = HXR_OUTOFMEMORY;
      if (pData)
      {
          retVal = HXR_OK;
      }

      if (retVal == HXR_OK)
      {
          pLocalPacket = new CMediaPacket(pData,
                                  pData,
                                  ulDataSize,
                                  ulDataSize,
                                  m_pActiveVideoPacket->m_ulTime,
                                  m_pActiveVideoPacket->m_ulFlags,
                                  NULL);

          retVal = HXR_OUTOFMEMORY;
          if (pLocalPacket)
          {
            retVal = HXR_OK;
          }
      }

      if (retVal == HXR_OK)
      {
          memcpy(pData, m_pActiveVideoPacket->m_pData, ulDataSize); /* Flawfinder: ignore */
          ReleasePacket(m_pActiveVideoPacket);
          m_pActiveVideoPacket = pLocalPacket;
          m_bActiveVideoPacketLocalized = TRUE;
      }
      else
      {
          HX_VECTOR_DELETE(pData);
          HX_DELETE(pLocalPacket);
      }
    }

    DisplayMutex_Unlock();

    return retVal;
}


void CVideoRenderer::ReleaseFramePacket(CMediaPacket* pPacket)
{
    ReleasePacket(pPacket);
}


void CVideoRenderer::ReleasePacket(CMediaPacket* pPacket,
                                BOOL bForceKill)
{
    CHXBufferPool* pFramePool = NULL;

    if (m_pVideoFormat)
    {
      m_pVideoFormat->OnDecodedPacketRelease(pPacket);
      pFramePool = m_pVideoFormat->GetFramePool();
    }

    if (pPacket)
    {
      if (pFramePool && (!bForceKill))
      {
          pFramePool->Put(pPacket);
      }
      else
      {
          pPacket->Clear();
          delete pPacket;
      }
    }

    if (IsDecoderRunning())
    {
      if (m_pDecoderPump)
      {
          m_pDecoderPump->Signal();
      }
    }
    else
    {
      if (m_pVideoFormat)
      {
          m_pVideoFormat->DecodeFrame();
      }
    }
}


void CVideoRenderer::ClearBltPacketQueue(void)
{
    CMediaPacket* pVideoPacket;

    if (m_pBltPacketQueue)
    {
      while ((pVideoPacket = (CMediaPacket*) m_pBltPacketQueue->Get()) != 0)
      {
          ReleasePacket(pVideoPacket);
      }
    }
}


/****************************************************************************
 *  CVideoRenderer::CSetSizeCB
 *  This routine increases the object reference count in a thread safe
 *  manner. The reference count is used to manage the lifetime of an object.
 *  This method must be explicitly called by the user whenever a new
 *  reference to an object is used.
 */
/****************************************************************************
 *  CVideoRenderer::CSetSizeCB::QueryInterface
 */
STDMETHODIMP CVideoRenderer::CSetSizeCB::QueryInterface(REFIID riid,
                                            void** ppvObj)
{
    QInterfaceList  qiList[] =
    {
      { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXPlugin*) this},
      { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*)this},
    };

    return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
}

/****************************************************************************
 *  CVideoRenderer::CSetSizeCB::AddRef                             \
 */
STDMETHODIMP_(ULONG32) CVideoRenderer::CSetSizeCB::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

/****************************************************************************
 *  CVideoRenderer::CSetSizeCB::Release
 */
STDMETHODIMP_(ULONG32) CVideoRenderer::CSetSizeCB::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;
    return 0;
}

/****************************************************************************
 *  CVideoRenderer::CSetSizeCB::Func
 */
STDMETHODIMP CVideoRenderer::CSetSizeCB::Func()
{
    return m_pSite->SetSize(m_szViewFrame);
}


/****************************************************************************
 *  CVideoRenderer::Pacemaker Responses
 */
STDMETHODIMP CVideoRenderer::OnPaceStart(ULONG32 ulId)
{
    if (ulId == m_ulDecoderPacemakerId)
    {
      if (m_pVideoFormat)
      {
          m_pDecoderVideoFormat = m_pVideoFormat;
          m_pDecoderVideoFormat->AddRef();
      }
      m_bDecoderRunning = TRUE;
    }
    else if (ulId == m_ulBltrPacemakerId)
    {
      if (m_pVideoFormat)
      {
          m_pBltrVideoFormat = m_pVideoFormat;
          m_pBltrVideoFormat->AddRef();
      }
    }

    return HXR_OK;
}

STDMETHODIMP CVideoRenderer::OnPaceEnd(ULONG32 ulId)
{
    if (ulId == m_ulDecoderPacemakerId)
    {
      m_bDecoderRunning = FALSE;
        if (m_pDecoderVideoFormat)
        {
            m_pDecoderVideoFormat->Release();
            m_pDecoderVideoFormat = NULL;
        }
    }
    else if (ulId == m_ulBltrPacemakerId)
    {
        if (m_pBltrVideoFormat)
        {
            m_pBltrVideoFormat->Release();
            m_pBltrVideoFormat = NULL;
        }
    }

    return HXR_OK;
}

STDMETHODIMP CVideoRenderer::OnPace(ULONG32 ulId)
{
    if (ulId == m_ulBltrPacemakerId)
    {
      PresentFrame();
    }
    else if (ulId == m_ulDecoderPacemakerId)
    {
      if (m_bSchedulerStartRequested)
      {
          StartSchedulers();
      }

      while ((m_pDecoderVideoFormat->DecodeFrame()) != 0) ;

#ifdef HELIX_FEATURE_VIDREND_BOOSTDECODE_ON_STARTUP
      // on ce we need to get this started quickly, otherwise the initial packets expire
      if (THREAD_PRIORITY_BELOW_NORMAL != GetDecodePriority())
      {
          SetDecodePriority(THREAD_PRIORITY_BELOW_NORMAL);
          return HXR_OK;
      }
#endif
    }

    return HXR_OK;
}


/****************************************************************************
 *  Video Surface 2 Support
 */
HX_RESULT CVideoRenderer::InitVideoSurface2(ULONG32 ulWidth, ULONG32 ulHeight)
{
#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    HX_RESULT retVal = HXR_FAIL;

    BOOL bTryVideoSurface2 = m_bTryVideoSurface2;

    if (bTryVideoSurface2)
    {
        HX_ASSERT(m_pMISUSSite);
        IHXVideoSurface* pVideoSurface = NULL;
      IHXVideoSurface2* pVideoSurface2 = NULL;
        IHXSite2* pSite2 = NULL;

      if (m_bUseVideoSurface2 &&
          m_pVSurf2InputBIH &&
          (m_pVSurf2InputBIH->biWidth == ((LONG32) ulWidth)) &&
          (m_pVSurf2InputBIH->biHeight == ((LONG32) ulHeight)))
      {
          return HXR_OK;
      }

      // EndOptimizedBlt();

      bTryVideoSurface2 = FALSE;

        m_pMISUSSite->QueryInterface(IID_IHXSite2, (void**) &pSite2);
        if (pSite2)
        {
            pSite2->GetVideoSurface(pVideoSurface);
        }
      HX_RELEASE(pSite2);

        HX_ASSERT(pVideoSurface);
        if (pVideoSurface)
        {
            pVideoSurface->QueryInterface(IID_IHXVideoSurface2,
                                          (void**) &pVideoSurface2);
        }
        HX_RELEASE(pVideoSurface);

        if (pVideoSurface2)
        {
          HXBitmapInfoHeader userBIH;
          ULONG32 ulUserBufCount;
            IHXBuffer* pInitialCountBuffer = NULL;
          HX_RESULT status;

          m_ulHWBufCount = m_ulConfigHWBufCount;

          HX_RELEASE(pInitialCountBuffer);

          if (m_pVSurf2InputBIH == NULL)
          {
            m_pVSurf2InputBIH = new HXBitmapInfoHeader;
          }

          retVal = HXR_OUTOFMEMORY;
          if (m_pVSurf2InputBIH)
          {
            *m_pVSurf2InputBIH = m_BitmapInfoHeader;
            m_pVSurf2InputBIH->biWidth = ulWidth;
            m_pVSurf2InputBIH->biHeight = ulHeight;
            retVal = HXR_OK;
          }

            if (SUCCEEDED(retVal))
          {
            do
            {
                // SetProperties should modify m_pVSurf2InputBIH
                status = pVideoSurface2->SetProperties(m_pVSurf2InputBIH,
                                             m_ulHWBufCount,
                                             (IHXRenderTimeLine*) this);

                /*** This code creates a leak - the renderer is not released
                 *** Needs investigation.
                if (SUCCEEDED(status) && (m_ulHWBufCount > 0))
                {
                  UINT8* pVideoMem;
                  INT32 iPitch;

                  status = pVideoSurface2->GetVideoMem(pVideoMem,
                                               iPitch,
                                               HX_WAIT_FOREVER,
                                               m_pVSurf2InputBIH);

                  if (SUCCEEDED(status))
                  {
                      pVideoSurface2->ReleaseVideoMem(pVideoMem);
                  }
                }
                 ***/

                userBIH = *m_pVSurf2InputBIH;
                ulUserBufCount = m_ulHWBufCount;

                retVal = OnOptimizedVideo(status,
                                    m_BitmapInfoHeader,
                                    userBIH,
                                    ulUserBufCount);

                if (retVal == HXR_RETRY)
                {
                  *m_pVSurf2InputBIH = userBIH;
                  m_ulHWBufCount = ulUserBufCount;
                }
            } while (retVal == HXR_RETRY);
          }

          if (SUCCEEDED(retVal) &&
            SUCCEEDED(status) &&
            (m_ulHWBufCount != 0))
          {
            bTryVideoSurface2 = TRUE;
          }
      }

      if (bTryVideoSurface2)
      {
          // Turning on video surface 2
          m_ulEarlyFrameTol = m_ulMaxOptimizedVideoLead;
          if (!m_bUseVideoSurface2)
          {
            m_bVideoSurface2Transition = TRUE;
            m_bUseVideoSurface2 = TRUE;
            if (m_pBltrPump)
            {
                // Wake up Bltr thread
                m_pBltrPump->Suspend(FALSE);
                m_pBltrPump->Signal();
            }
          }
      }

      HX_RELEASE(pVideoSurface2);
    }

    if (FAILED(retVal))
    {
      HX_DELETE(m_pVSurf2InputBIH);
    }

    m_bUseVideoSurface2 = bTryVideoSurface2;

    return retVal;
#else // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    return HXR_NOTIMPL;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
}


HX_RESULT CVideoRenderer::UpdateVideoSurface2(IHXVideoSurface* pVideoSurface,
                                    HXxRect &destRect,
                                    HXxRect &sorcRect,
                                    BOOL bRefresh,
                                    BOOL bSystemEvent)
{
#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    VideoMemStruct videoMemoryInfo;
    IHXVideoSurface2* pVideoSurface2 = NULL;
    HX_RESULT retVal;

    HX_ASSERT(pVideoSurface);

    videoMemoryInfo.pVidMem = NULL;

    retVal = pVideoSurface->QueryInterface(IID_IHXVideoSurface2,
                                 (void**) &pVideoSurface2);

    if (!bRefresh)
    {
      m_bPresentInProgress = TRUE;

      // If we are in transition to video surface 2, we are not in
      // natural Bltr thread, thus do not unlock the mutex to prevent
      // other Blt entry points for interfering until the transition
      // to natural queue thread is complete.
      if (!m_bVideoSurface2Transition)
      {
          DisplayMutex_Unlock();
      }

      if (SUCCEEDED(retVal))
      {
          HX_ASSERT(m_bVideoSurface2Transition ? bSystemEvent : TRUE);

          retVal = pVideoSurface2->GetVideoMem(&videoMemoryInfo,
                                                 m_bVideoSurface2Transition ?
                                        HX_WAIT_NEVER : HX_WAIT_FOREVER);

          m_bVS2BufferUnavailableOnLastBlt = FAILED(retVal);
      }

      if (!m_bVideoSurface2Transition)
      {
          DisplayMutex_Lock();

          // If the switch to VS1 occured after we successfully obtained video
          // memory, fail this VS2 Blt
          if ((!m_bUseVideoSurface2) && SUCCEEDED(retVal))
          {
            retVal = HXR_FAIL;
          }
      }

      if (SUCCEEDED(retVal))
      {
          retVal = TransferOptimizedVideo(pVideoSurface2,
                                            &videoMemoryInfo,
                                  m_pActiveVideoPacket,
                                  m_BitmapInfoHeader,
                                  sorcRect,
                                  sorcRect);
      }

      if (SUCCEEDED(retVal))
      {
          if (m_bFirstSurfaceUpdate)
          {
            m_bFirstSurfaceUpdate = FALSE;

            if (bSystemEvent)
            {
                retVal = pVideoSurface2->Present(&videoMemoryInfo,
                                         m_pActiveVideoPacket->m_ulTime,
                                         HX_MODE_IMMEDIATE,
                                         &destRect,
                                         &sorcRect);

                // We'll fail if the site is hidden by SMIL:
                if (FAILED(retVal))
                {
                  retVal = pVideoSurface2->Present(&videoMemoryInfo,
                                           m_pActiveVideoPacket->m_ulTime,
                                           HX_MODE_TIMED,
                                           &destRect,
                                           &sorcRect);
                }
            }
            else
            {
                // Unless this is a system event we are not under the protection of the
                // top level site mutex and present immediate will acquire TLS mutex.
                // We must avoid deadlock with HandleEvent by relinquishing
                // VS mutex and forcing refresh.
                m_bPresentInProgress = FALSE;
                BOOL bIsVisible = ForceRefresh();

                // We'll fail if the site is not visible
                if (bIsVisible)
                {
                  // Abort any further updates for multiple site users since
                  // ForceRefresh will take care of all of them
                  retVal = HXR_ABORT;
                }
                else
                {
                  retVal = pVideoSurface2->Present(&videoMemoryInfo,
                                           m_pActiveVideoPacket->m_ulTime,
                                           HX_MODE_TIMED,
                                           &destRect,
                                           &sorcRect);
                }
            }
          }
          else
          {
            retVal = pVideoSurface2->Present(&videoMemoryInfo,
                                     m_pActiveVideoPacket->m_ulTime,
                                     HX_MODE_TIMED,
                                     &destRect,
                                     &sorcRect);
          }

          if (SUCCEEDED(retVal))
          {
            videoMemoryInfo.pVidMem = NULL;
          }
      }

      m_bPresentInProgress = FALSE;
    }
    else if (!m_bPresentInProgress)
    {
      HX_ASSERT(bSystemEvent);

      retVal = pVideoSurface2->Present(NULL,
                               0,
                               HX_MODE_REFRESH,
                               &destRect,
                               &sorcRect);

      // If no frames in video surface - make one and present it
      if (FAILED(retVal) && bSystemEvent)
      {
          retVal = pVideoSurface2->GetVideoMem(&videoMemoryInfo,
                                                 HX_WAIT_NEVER);

          if (SUCCEEDED(retVal))
          {
            retVal = TransferOptimizedVideo(pVideoSurface2,
                                      &videoMemoryInfo,
                                    m_pActiveVideoPacket,
                                    m_BitmapInfoHeader,
                                    sorcRect,
                                    sorcRect);

            if (SUCCEEDED(retVal))
            {
                retVal = pVideoSurface2->Present(&videoMemoryInfo,
                                         m_pActiveVideoPacket->m_ulTime,
                                         HX_MODE_IMMEDIATE,
                                         &destRect,
                                         &sorcRect);

                if (FAILED(retVal))
                {
                  pVideoSurface2->ReleaseVideoMem(&videoMemoryInfo);
                  retVal = pVideoSurface2->Present(NULL,
                                           0,
                                           HX_MODE_REFRESH,
                                           &destRect,
                                           &sorcRect);
                }

                videoMemoryInfo.pVidMem = NULL;
            }
          }
          else
          {
            retVal = pVideoSurface2->Present(NULL,
                                     0,
                                     HX_MODE_REFRESH,
                                     &destRect,
                                     &sorcRect);
          }
      }
    }

    if (videoMemoryInfo.pVidMem != NULL)
    {
      pVideoSurface2->ReleaseVideoMem(&videoMemoryInfo);
    }

    HX_RELEASE(pVideoSurface2);

    return retVal;
#else // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    return HXR_NOTIMPL;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
}


HX_RESULT CVideoRenderer::FlushVideoSurface2(IHXSite* pSite)
{
#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    HX_RESULT retVal = HXR_FAIL;

    IHXVideoSurface* pVideoSurface;
    IHXVideoSurface2* pVideoSurface2;
    IHXSite2* pSite2;

    HX_ASSERT(pSite);

    if (SUCCEEDED(pSite->QueryInterface(IID_IHXSite2, (void**) &pSite2)))
    {
      if (SUCCEEDED(pSite2->GetVideoSurface(pVideoSurface)))
      {
          if (SUCCEEDED(pVideoSurface->QueryInterface(IID_IHXVideoSurface2,
                                          (void**) &pVideoSurface2)))
          {
            pVideoSurface2->Flush();
            pVideoSurface2->Release();
            retVal = HXR_OK;
          }

          pVideoSurface->Release();
      }

      pSite2->Release();
    }

    HX_ASSERT(SUCCEEDED(retVal));

    return retVal;
#else // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    return HXR_NOTIMPL;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
}


inline HX_RESULT CVideoRenderer::SwitchToVideoSurface1(void)
{
#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    HX_RESULT retVal = HXR_OK;

    m_pVSMutex->Lock();

    m_bVideoSurface1Requested = TRUE;
    if (m_bUseVideoSurface2)
    {
      HX_TRACE_THINGY("C:/trace.txt", "-->Switch to VS1", 0);

#ifdef SYNC_VS_SWITCHING
      InitVideoSurface1(TRUE);
      StartSchedulers();
#else // SYNC_VS_SWITCHING
      // Force Video Surface reinitialization
      m_bVideoSurfaceReinitRequested = TRUE;
#endif      // SYNC_VS_SWITCHING
    }

    m_pVSMutex->Unlock();

    return retVal;
#else // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    return HXR_NOTIMPL;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
}


inline HX_RESULT CVideoRenderer::SwitchToVideoSurface2(void)
{
#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    HX_RESULT retVal = HXR_OK;

    m_pVSMutex->Lock();

    m_bVideoSurface1Requested = FALSE;
    if (!m_bUseVideoSurface2)
    {
      if (m_bTryVideoSurface2)
      {
          HX_TRACE_THINGY("C:/trace.txt", "-->Switch to VS2", 0);

#ifdef SYNC_VS_SWITCHING
          InitVideoSurface2(m_SetWinSize.cx, m_SetWinSize.cy);
          StartSchedulers();
#else // SYNC_VS_SWITCHING
          // Force Video Surface reinitialization
          m_bVideoSurfaceReinitRequested = TRUE;
#endif      // SYNC_VS_SWITCHING
      }
      else
      {
          // VideoSurface2 is not allowed
          HX_TRACE_THINGY("C:/trace.txt", "-->Switch to VS2 Denied!", 0);

          retVal = HXR_FAIL;
      }
    }

    m_pVSMutex->Unlock();

    return retVal;
#else // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    return HXR_NOTIMPL;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
}


/****************************************************************************
 *  Method:
 *    CVideoFormat::OnOptimizedVideo
 *
 */
HX_RESULT CVideoRenderer::OnOptimizedVideo(HX_RESULT status,
                                 const HXBitmapInfoHeader& sourceBIH,
                                 HXBitmapInfoHeader &targetBIH,
                                 ULONG32 &ulTargetBufCount)
{
#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    HX_RESULT retVal = HXR_FAIL;

    if (SUCCEEDED(status) &&
      (ulTargetBufCount > 0) &&
      (GETBITMAPCOLOR(&sourceBIH) == CID_I420))
    {
        retVal = HXR_OK;
    }

    return retVal;
#else // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    return HXR_NOTIMPL;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
}


/****************************************************************************
 *  Method:
 *    CVideoFormat::OffOptimizedVideo
 *
 */
void CVideoRenderer::OffOptimizedVideo(void)
{
    return;
}


/****************************************************************************
 *  Method:
 *    CVideoFormat::TransferOptimizedVideo
 *
 */
HX_RESULT CVideoRenderer::TransferOptimizedVideo(IHXVideoSurface2* pVideoSurface2,
                                                 VideoMemStruct* pVideoMemoryInfo,
                                                 CMediaPacket* pVideoPacket,
                                                 const HXBitmapInfoHeader& sorcBIH,
                                                 HXxRect &destRect,
                                                 HXxRect &sorcRect)
{
#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    SourceInputStruct input;
    UINT8* aSrcInput[3];
    INT32 aSrcPitch[3];
    HX_RESULT retVal = HXR_FAIL;

    input.aSrcInput = aSrcInput;
    input.aSrcPitch = aSrcPitch;
    input.nNumInputs = 3;

    if (GETBITMAPCOLOR(&sorcBIH) == CID_I420)
    {
      aSrcInput[0] = pVideoPacket->m_pData;
      aSrcInput[1] = aSrcInput[0] + (sorcBIH.biWidth * sorcBIH.biHeight);
      aSrcInput[2] = aSrcInput[1] +
                   ((sorcBIH.biWidth / 2) * (sorcBIH.biHeight / 2));

      aSrcPitch[0] = sorcBIH.biWidth;
      aSrcPitch[1] = sorcBIH.biWidth / 2;
      aSrcPitch[2] = sorcBIH.biWidth / 2;

        CHXxSize sorcSize(sorcBIH.biWidth, sorcBIH.biHeight);
        CHXxSize destSize(pVideoMemoryInfo->bmi.biWidth, pVideoMemoryInfo->bmi.biHeight);

        retVal = pVideoSurface2->ColorConvert(HX_I420,
                                              &sorcSize,
                                              &sorcRect,
                                              &input,
                                              pVideoMemoryInfo->bmi.biCompression,
                                              pVideoMemoryInfo->pVidMem,
                                              &destSize,
                                              &destRect,
                                              pVideoMemoryInfo->lPitch);

        // Alpha blend subrects:
        for (UINT32 i = 0; i < pVideoMemoryInfo->ulCount; ++i)
        {
                       destSize.SetSize(pVideoMemoryInfo->pAlphaList[i].ulImageWidth, pVideoMemoryInfo->pAlphaList[i].ulImageHeight);
            HX_RESULT localResult = pVideoSurface2->ColorConvert(
                             HX_I420,
                             &sorcSize,
                             &pVideoMemoryInfo->pAlphaList[i].rcImageRect,
                             &input,
                             pVideoMemoryInfo->pAlphaList[i].ulFourCC,
                             pVideoMemoryInfo->pAlphaList[i].pBuffer,
                                                        &destSize,
                             &pVideoMemoryInfo->pAlphaList[i].rcImageRect,
                             pVideoMemoryInfo->pAlphaList[i].lPitch);
            if (SUCCEEDED(retVal))
            {
                retVal = localResult;
            }
        }
    }

    return retVal;
#else // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    return HXR_NOTIMPL;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
}


void CVideoRenderer::PresentFrame(void)
{
#ifdef HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
    if (m_bUseVideoSurface2)
    {
      SchedulerCallback(FALSE,    // not scheduled
                    FALSE,    // do not resched
                    TRUE);    // is VS2 call
    }
    else
    {
      // Video Surface2 has been turned off
      IHXPaceMaker* pBltr = m_pBltrPump;

      if (pBltr)
      {
          if (m_bTryVideoSurface2)
          {
            // We might try VideoSurface2 again later - suspend the
            // Bltr thread for now
            pBltr->Suspend(TRUE);
          }
          else
          {
            // We are not to try VideoSurface2 any more - stop the
            // Bltr thread
            pBltr->Stop();
            pBltr->Signal();
          }
      }
    }
#else // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO

    ;
#endif      // HELIX_FEATURE_VIDREND_OPTIMIZEDVIDEO
}



Generated by  Doxygen 1.6.0   Back to index