text: // $Header: G:/SwDev/WDM/Video/bt848/rcs/Vidch.h 1.14 1998/05/11 23:59:58 tomz Exp $
  
  #ifndef __VXDVIDCH_H
  #define __VXDVIDCH_H
  
  extern "C" {
     #include "strmini.h"
     #include "ksmedia.h"
  }
  
  #include "mytypes.h"
  #include "pisces.h"
  #include "vidchifc.h"
  
  typedef enum  { Closed, Open, Created, Started, Paused } StreamState;
  typedef enum { Single, Paired } StreamType;
  void GetRequestedSize2( const KS_VIDEOINFOHEADER2 &vidHdr, MSize &size );
  void GetRequestedSize( const KS_VIDEOINFOHEADER &vidHdr, MSize &size );
  
  extern PHW_STREAM_REQUEST_BLOCK StreamIdxToSrb[];
  
  /* Class: VideoChannel
   * Purpose: The base class to be used in the BtPisces capture VxD. Used for
   *   processing user requests ( comes from the device class, goes to capture
   *   chip class )
   * Attributes:
   * Methods
   */
  class VideoChannel
  {
     protected:
  
        BtPisces  *Digitizer_;
  
        SRBQueue  Requests_;
  
        KS_VIDEOINFOHEADER        VidHeader_;
        KS_VIDEOINFOHEADER2        VidHeader2_;
        // this seems to be the most convenient place for the original copy
        // other option is to make SetVidHdr() virtual and move this member into
        // the PairedChannels
        KS_VIDEOINFOHEADER        OrigVidHeader_;
        KS_VIDEOINFOHEADER2        OrigVidHeader2_;
  
  		BOOL					m_bIsVideoInfo2;
  
        DWORD               FieldType_;
        VidBufQueue         BufQue_;
  
        VideoChanIface      Caller_;
  
        DWORD               dwBufferOffset_;
  
        HANDLE              hMasterClock;
  
        KSSTATE             KSState_;
  
        LONG                TimePerFrame_;
  
        VideoStream         Stream_;
        Field              *OurField_;
  
        StreamState         State_;
        bool                NeedNotification_;
  
        virtual  void Interrupt( PVOID pTag, bool skipped );
                 void CheckNotificationNeed();
  
        static void STREAMAPI TimeStamp( PHW_STREAM_REQUEST_BLOCK pSrb );
        static void STREAMAPI TimeStampVBI( PHW_STREAM_REQUEST_BLOCK pSrb );
  
        PVOID pStrmEx_; 
  
     public:
  
        PHW_STREAM_REQUEST_BLOCK  pSRB_;
  
  #ifdef ENABLE_DDRAW_STUFF
  	// Kernel DDraw interface
  	BOOL                        bKernelDirectDrawRegistered;
  	HANDLE                      hUserDirectDrawHandle;       // DD itself
  	HANDLE                      hKernelDirectDrawHandle;
  	BOOL                        bPreEventOccurred;
  	BOOL                        bPostEventOccurred;
  #endif
  
  
  		BOOL	IsVideoInfo2() { return m_bIsVideoInfo2; }
        PVOID GetStrmEx() 
        {
           DEBUG_ASSERT(pStrmEx_ != 0);
           return pStrmEx_;
        }
        VOID SetStrmEx(PVOID pv) 
        {
           DEBUG_ASSERT(pv != 0);
           pStrmEx_ = pv;
        }
        
        BOOL bIsVBI();
        BOOL bIsVideo();
  
        VOID ResetCounters();
  
        virtual ErrorCode OpenChannel();
        virtual ErrorCode CloseChannel();
        virtual ErrorCode SetFormat( ColFmt );
                ColFmt    GetFormat();
        virtual ErrorCode SetDigitalWindow( MRect &r );
        virtual ErrorCode SetAnalogWindow( MRect &r );
        virtual ErrorCode Create();
        virtual void      Start();
        virtual ErrorCode Stop();
        virtual ErrorCode Pause();
  
                StreamState GetState();
                KSSTATE     GetKSState();
                void        SetKSState( KSSTATE st );
                      
                VideoStream GetStreamID();
  
                void        SetClockMaster( HANDLE h );
                
                //LONGLONG    GetFramesNo();
                
                LONG      GetTimePerFrame();
                void      SetTimePerFrame( LONG time );
  
                void      SetInterrupt( bool state );
                void      SetCallback( ChanIface *cb );
  
        virtual StreamType GetStreamType();
  
        virtual  void AddSRB( PHW_STREAM_REQUEST_BLOCK pSrb );
        virtual  bool RemoveSRB( PHW_STREAM_REQUEST_BLOCK pSrb );
        virtual  void ChangeNotification( PHW_STREAM_REQUEST_BLOCK pSrb );
  
        virtual void AddBuffer( PVOID );
  
                void SetSRB( PHW_STREAM_REQUEST_BLOCK srb );
                PHW_STREAM_REQUEST_BLOCK GetSRB();
  
                void SetVidHdr( const KS_VIDEOINFOHEADER &rVidHdr );
                void SetVidHdr2( const KS_VIDEOINFOHEADER2 &rVidHdr );
                PKS_VIDEOINFOHEADER GetVidHdr();
                KS_VIDEOINFOHEADER2* GetVidHdr2();
  
                void SetBufPitch( DWORD dwP );
  
                void  SetDefaultQue()
                { Digitizer_->SetBufQuePtr( *OurField_, &BufQue_ ); }
  
                void SetPaired( bool p = false );
  
                void IntNotify( PVOID pTag, bool skipped );
  
                bool IsOpen();
                void SetOpen();
                void SetClose();
  
        void Init( BtPisces *const pCapChip );
  
        VideoChannel( VideoStream aStrm );
        virtual ~VideoChannel();
  
        friend class VideoChanIface;
  
        // placement new
        void *operator new( size_t, void *buf ) { return buf; }
        void operator delete( void *, size_t ) {}
  };
  
  /* Class: PairedVideoChannels
   * Purpose: Implements basic functionality of paired video channels
   */
  template <class ParentChan>
  class PairedVideoChannels : public ParentChan
  {
     typedef ParentChan Parent;
     public:
        VideoChannel &slave;
  
        PairedVideoChannels( VideoStream st, VideoChannel &chan );
  
        virtual ErrorCode Create();
        virtual void      Start();
        virtual ErrorCode Stop();
        virtual ErrorCode Pause();
  
        virtual StreamType GetStreamType();
  };
  
  template <class ParentChan>
  inline PairedVideoChannels<ParentChan>::PairedVideoChannels( VideoStream st, VideoChannel &chan )
     : ParentChan( st ), slave( chan )
  {}
  
  /* Class: InterVideoChannel
   * Purpose: The base class to be used in the BtPisces capture VxD. Used for
   *   processing user requests ( comes from the device class, goes to capture
   *   chip class )
   * Attributes:
   * Methods
   */
  class InterVideoChannel : public PairedVideoChannels<VideoChannel>
  {
     typedef PairedVideoChannels<VideoChannel> Parent;
  
     public:
        virtual ErrorCode Create();
        virtual void      AddSRB( PHW_STREAM_REQUEST_BLOCK pSrb );
        InterVideoChannel( VideoStream aStrm, VideoChannel &chan );
        virtual  void Interrupt( PVOID pTag, bool skipped );
  };
  
  inline InterVideoChannel::InterVideoChannel( VideoStream aStrm, VideoChannel &chan )
     : Parent( aStrm, chan )
  {}
  
  /* Class: AlterVideoChannel
   * Purpose: The base class to be used in the BtPisces capture VxD. Used for
   *   processing user requests ( comes from the device class, goes to capture
   *   chip class )
   * Attributes:
   * Methods
   */
  template <class ParentChan>
  class AlterVideoChannel : public PairedVideoChannels<ParentChan>
  {
     typedef PairedVideoChannels<ParentChan> Parent;
  
     int toggle_;
  
     public:
        virtual ErrorCode Create();
        virtual void      AddSRB( PHW_STREAM_REQUEST_BLOCK pSrb );
        virtual  bool     RemoveSRB( PHW_STREAM_REQUEST_BLOCK pSrb );
        AlterVideoChannel( VideoStream aStrm, VideoChannel &chan );
  };
  
  /* Class: VBIChannel
   * Purpose: Implements functionality for the VBI field
   */
  class VBIChannel : public VideoChannel
  {
     typedef VideoChannel Parent;
  
     // Channel Change information
  
     public:
        bool  Dirty_;
        KS_TVTUNER_CHANGE_INFO   TVTunerChangeInfo_;
        KS_VBIINFOHEADER         VBIInfoHeader_;
  
        virtual  void Interrupt( PVOID pTag, bool skipped );
        virtual  void ChangeNotification( PHW_STREAM_REQUEST_BLOCK pSrb );
        VBIChannel( VideoStream aStrm );
        void SetVBIInfHdr( const KS_VBIINFOHEADER &vbiHdr );
  };
  
  /* Class: VBIAlterChannel
   * Purpose: Implements alternating VBI fields
   */
  
  class VBIAlterChannel : public AlterVideoChannel<VBIChannel>
  {
     typedef AlterVideoChannel<VBIChannel> Parent;
  
     public:
        void SetVidHdr( const KS_DATAFORMAT_VBIINFOHEADER &df );
        void SetVidHdr2( const KS_DATAFORMAT_VBIINFOHEADER &df );
        VBIAlterChannel( VideoStream aStrm, VBIChannel &chan );
  };
  
  inline VBIChannel::VBIChannel( VideoStream aStrm ) : VideoChannel( aStrm ),
     Dirty_( false )
  {}
  
  inline void DumpVbiInfoHeader( const KS_VBIINFOHEADER &vbiHdr )
  {
     // typedef struct tagKS_VBIINFOHEADER {
     //     ULONG       StartLine;              // inclusive
     //     ULONG       EndLine;                // inclusive
     //     ULONG       SamplingFrequency;      // Hz.
     //     ULONG       MinLineStartTime;       // microSec * 100 from HSync LE
     //     ULONG       MaxLineStartTime;       // microSec * 100 from HSync LE
     //     ULONG       ActualLineStartTime;    // microSec * 100 from HSync LE
     //     ULONG       ActualLineEndTime;      // microSec * 100 from HSync LE
     //     ULONG       VideoStandard;          // KS_AnalogVideoStandard*
     //     ULONG       SamplesPerLine;
     //     ULONG       StrideInBytes;          // May be > SamplesPerLine
     //     ULONG       BufferSize;             // Bytes
     // } KS_VBIINFOHEADER, *PKS_VBIINFOHEADER;
  
     DebugOut((0, "KS_VBIINFOHEADER at address %x\n", &vbiHdr));
     DUMP(vbiHdr.StartLine);
     DUMP(vbiHdr.EndLine);
     DUMP(vbiHdr.SamplingFrequency);
     DUMP(vbiHdr.MinLineStartTime);
     DUMP(vbiHdr.MaxLineStartTime);
     DUMP(vbiHdr.ActualLineStartTime);
     DUMP(vbiHdr.ActualLineEndTime);
     DUMP(vbiHdr.VideoStandard);
     DUMP(vbiHdr.SamplesPerLine);
     DUMP(vbiHdr.StrideInBytes);
     DUMP(vbiHdr.BufferSize);
  }
  inline void VBIChannel::SetVBIInfHdr( const KS_VBIINFOHEADER &vbiHdr )
  {
     VBIInfoHeader_ = vbiHdr;
  }
  
  inline VBIAlterChannel::VBIAlterChannel( VideoStream aStrm, VBIChannel &chan )
     : AlterVideoChannel<VBIChannel>( aStrm, chan )
  {}
  
  template <class ParentChan>
  inline AlterVideoChannel<ParentChan>::AlterVideoChannel( VideoStream aStrm, VideoChannel &chan )
     : Parent( aStrm, chan ), toggle_( 0 )
  {}
  
  inline void VideoChannel::SetSRB( PHW_STREAM_REQUEST_BLOCK srb )
  {
     pSRB_ = srb;
  }
  
  
  /* Method: AlterVideoChannel::AddSRB
   * Purpose: This method dispatches the SRB to the next appropriate channel
   * Input: pSrb:
   */
  template <class ParentChan>
  void AlterVideoChannel<ParentChan>::AddSRB( PHW_STREAM_REQUEST_BLOCK pSrb )
  {
     if ( !toggle_ ) {
        // first buffer goes to the slave channel as it comes out of the
        // decoder first
        DebugOut((1, "slave.AddSRB(%x)\n", pSrb));
        slave.AddSRB( pSrb );
     } else {
        DebugOut((1, "parent.AddSRB(%x)\n", pSrb));
        Parent::AddSRB( pSrb );
     }
     toggle_++;
     toggle_ %= 2;
  }
  
  /* Method: AlterVideoChannel::RemoveSRB
   * Purpose: Just calls into each channel in hope one of them will find the SRB
   * Input: pSRB
   * Output: None
   */
  template <class ParentChan>
  bool AlterVideoChannel<ParentChan>::RemoveSRB( PHW_STREAM_REQUEST_BLOCK pSrb )
  {
     // one or the other will pick it up
     
     bool b1 = slave.RemoveSRB( pSrb );
     bool b2 = Parent::RemoveSRB( pSrb );
  
     if( !b1 && !b2 )
     {
        DebugOut((1, "AlterVideoChannel<ParentChan>::RemoveSRB - RemoveSRB failed\n"));
     }
     return ( b1 || b2 );
  }
  
  /* Method: AlterVideoChannel::Create
   * Purpose: Sets the slave video params and calls into parent to do the work
   * Input: pSRB
   * Output: None
   */
  template <class ParentChan>
  ErrorCode AlterVideoChannel<ParentChan>::Create()
  {
     slave.SetVidHdr( VidHeader_ );
     return Parent::Create();
  }
  
  inline PHW_STREAM_REQUEST_BLOCK VideoChannel::GetSRB()
  {
     return pSRB_;
  }
  
  inline void DumpVideoInfoHeader(const KS_VIDEOINFOHEADER &rVidHdr)
  {
     DebugOut((0, "-----------------------------------------\n"));
     DebugOut((0, "setting KS_VIDEOINFOHEADER\n"));
     DebugOut((0, "-----------------------------------------\n"));
     DebugOut((0, "rcSource (%d,%d,%d,%d)\n",
        rVidHdr.rcSource.left, 
        rVidHdr.rcSource.top,
        rVidHdr.rcSource.right, 
        rVidHdr.rcSource.bottom));
  
     DebugOut((0, "rcTarget (%d,%d,%d,%d)\n",
        rVidHdr.rcTarget.left, 
        rVidHdr.rcTarget.top,
        rVidHdr.rcTarget.right, 
        rVidHdr.rcTarget.bottom));
  
     DebugOut((0, "dwBitRate (%u)\n", rVidHdr.dwBitRate));
     DebugOut((0, "dwBitErrorRate (%u)\n", rVidHdr.dwBitErrorRate));
     DebugOut((0, "bmiHeader\n"));
     DebugOut((0, "   biSize (%d)\n", rVidHdr.bmiHeader.biSize));
     DebugOut((0, "   biWidth (%d)\n", rVidHdr.bmiHeader.biWidth));
     DebugOut((0, "   biHeight (%d)\n", rVidHdr.bmiHeader.biHeight));
     DebugOut((0, "   biPlanes (%d)\n", rVidHdr.bmiHeader.biPlanes));
     DebugOut((0, "   biBitCount (%d)\n", rVidHdr.bmiHeader.biBitCount));
     DebugOut((0, "   biCompression (%d)\n", rVidHdr.bmiHeader.biCompression));
     DebugOut((0, "   biSizeImage (%d)\n", rVidHdr.bmiHeader.biSizeImage));
     DebugOut((0, "   biXPelsPerMeter (%d)\n", rVidHdr.bmiHeader.biXPelsPerMeter));
     DebugOut((0, "   biYPelsPerMeter (%d)\n", rVidHdr.bmiHeader.biYPelsPerMeter));
     DebugOut((0, "   biClrUsed (%d)\n", rVidHdr.bmiHeader.biClrUsed));
     DebugOut((0, "   biClrImportant (%d)\n", rVidHdr.bmiHeader.biClrImportant));
  }
  
  inline void VideoChannel::SetVidHdr( const KS_VIDEOINFOHEADER &rVidHdr )
  {
     // DumpVideoInfoHeader(rVidHdr);
  
  	m_bIsVideoInfo2 = FALSE;
     VidHeader_ = rVidHdr;
     // save this for paired channels
     OrigVidHeader_ = rVidHdr;
  }
                                     
  inline void VideoChannel::SetVidHdr2( const KS_VIDEOINFOHEADER2 &rVidHdr )
  {
     // DumpVideoInfoHeader(rVidHdr);
  
  	m_bIsVideoInfo2 = TRUE;
     VidHeader2_ = rVidHdr;
     // save this for paired channels
     OrigVidHeader2_ = rVidHdr;
  }
                                     
  inline PKS_VIDEOINFOHEADER VideoChannel::GetVidHdr()
  {
     return &VidHeader_;
  }
  
  inline KS_VIDEOINFOHEADER2* VideoChannel::GetVidHdr2()
  {
     return &VidHeader2_;
  }
  
  inline void VideoChannel::SetBufPitch( DWORD dwP )
  {
     Digitizer_->SetBufPitch( dwP, *OurField_ );
  }
  
  inline bool VideoChannel::IsOpen()
  {
     return State_ >= Open;
  }
  
  inline void VideoChannel::SetOpen()
  {
     State_ = Open;
  }
  
  inline void VideoChannel::SetClose()
  {
     State_ = Closed;
  }
  
  inline void VideoChannel::Init( BtPisces *const pCapChip )
  {
     Digitizer_ = pCapChip;
  }
  
  inline StreamState VideoChannel::GetState()
  {
      return State_;
  }
  
  inline VideoStream VideoChannel::GetStreamID()
  {
     return OurField_->GetStreamID();
  }
  
  inline void VideoChannel::SetPaired( bool p )
  {
     OurField_->SetPaired( p );
  }
  
  inline void VideoChannel::SetClockMaster( HANDLE h )
  {
     DebugOut((1, "SetClockMaster(%x)\n", h ));
     hMasterClock = h;
  }
  
  inline KSSTATE VideoChannel::GetKSState()
  {
     return KSState_;
  }
  
  inline void    VideoChannel::SetKSState( KSSTATE st )
  {
     KSState_ = st;
  }
  
  #if 0
  inline LONGLONG VideoChannel::GetFramesNo()
  {
     LONGLONG PicNumber, DropCnt;
     OurField_->GetCounters( PicNumber, DropCnt );
     return PicNumber;
  }
  #endif
  
  inline LONG VideoChannel::GetTimePerFrame()
  {
     return OurField_->GetStandardTiming();
  }
  
  inline void VideoChannel::SetTimePerFrame( LONG time )
  {
     TimePerFrame_ = time;
     OurField_->SetStandardTiming( time );
  }
  
  inline void VideoChannel::IntNotify( PVOID pTag, bool skipped )
  {
     Caller_.Notify( pTag, skipped );
  }
  
  inline void VideoChannel::SetInterrupt( bool state )
  {
     OurField_->Interrupt_ = state;
  }
  
  inline void VideoChannel::SetCallback( ChanIface *cb )
  {
     OurField_->SetCallback( cb );
  }
  
  #ifdef _MSC_VER
  #pragma warning(disable:4355)
  #endif
  inline VideoChannel::VideoChannel( VideoStream aStrm ) :
     NeedNotification_( false ), BufQue_(), Caller_( this ), Stream_( aStrm ),
     OurField_( NULL ), State_( Closed ), pSRB_( NULL ), VidHeader_(), Requests_(),
     dwBufferOffset_( 0 ), hMasterClock( NULL ), TimePerFrame_( 333667 )
  {
  	m_bIsVideoInfo2 = FALSE;
  
  #ifdef ENABLE_DDRAW_STUFF
  	bKernelDirectDrawRegistered = FALSE;
  	hUserDirectDrawHandle = NULL;    
  	hKernelDirectDrawHandle = NULL;
  	bPreEventOccurred = FALSE;
  	bPostEventOccurred = FALSE;
  #endif
  
     // VS_Field1 is defined as 0
     FieldType_ = aStrm & 0x01 ? KS_VIDEO_FLAG_FIELD2 : KS_VIDEO_FLAG_FIELD1;
  }
  
  template <class ParentChan>
  StreamType PairedVideoChannels<ParentChan>::GetStreamType()
  {
     return Paired;
  }
  
  /* Method: PairedVideoChannel::Create
   * Purpose: Creates both streams
   * Input: None
   * Output: None
   */
  template <class ParentChan>
  ErrorCode PairedVideoChannels<ParentChan>::Create()
  {
     if ( slave.Create() == Success ) {
        Digitizer_->SetPlanarAdjust( 0 );
        return Parent::Create();
     }
     return Fail;
  }
  
  /* Method: PairedVideoChannels::Start
   * Purpose: Starts both channels
   * Input: None
   * Output: None
   */
  template <class ParentChan>
  void PairedVideoChannels<ParentChan>::Start()
  {
     slave.Start();
     Parent::Start();
  }
  
  /* Method: PairedVideoChannels::Stop
   * Purpose: Stops both channels
   * Input: None
   * Output: None
   */
  template <class ParentChan>
  ErrorCode PairedVideoChannels<ParentChan>::Stop()
  {
     slave.Stop();
     Parent::Stop();
     return Success;
  }
  
  /* Method: PairedVideoChannels::Pause
   * Purpose: Pauses both channels
   * Input: None
   * Output: None
   */
  template <class ParentChan>
  ErrorCode PairedVideoChannels<ParentChan>::Pause()
  {
     if ( bIsVBI() )
     {
        Digitizer_->PairedPause( (VBIEStartLocation + DistBetweenProgs) );
     }
     else
     {
        Digitizer_->PairedPause( (EvenStartLocation + DistBetweenProgs) );
     }
     State_ = Paused;
     return Success;
  }
  
  #endif __VXDVIDCH_H
  