422 lines
10 KiB
C++
422 lines
10 KiB
C++
// $Header: G:/SwDev/WDM/Video/bt848/rcs/Field.h 1.12 1998/05/08 18:18:51 tomz Exp $
|
|
|
|
#ifndef __FIELD_H
|
|
#define __FIELD_H
|
|
|
|
/* Type: VideoStream
|
|
* Purpose: Identifies a video stream channel
|
|
* Note: Not all of these are used today. It should be a fairly minor job to
|
|
* start using them, though
|
|
*/
|
|
typedef enum
|
|
{
|
|
VS_Below = -1,
|
|
VS_Field1, VS_Field2, VS_VBI1, VS_VBI2, VS_Analog, VS_CC, VS_EDS,
|
|
VS_Raw,
|
|
VS_Above
|
|
} VideoStream;
|
|
|
|
#define STREAM_IDX_CAPTURE 0
|
|
#define STREAM_IDX_PREVIEW 1
|
|
#define STREAM_IDX_VBI 2
|
|
#define STREAM_IDX_ANALOG 3
|
|
|
|
|
|
#include "mytypes.h"
|
|
#include "scaler.h"
|
|
#include "pscolspc.h"
|
|
#include "viddefs.h"
|
|
#include "queue.h"
|
|
#include "preg.h"
|
|
#include "chanifac.h"
|
|
|
|
const MaxProgsForField = 2;
|
|
|
|
typedef Queue<DataBuf> VidBufQueue;
|
|
|
|
/* Class: Field
|
|
* Purpose: Encapsulates the operation of a single video field provided by BtPisces
|
|
* Attributes:
|
|
* Operations:
|
|
*/
|
|
|
|
extern "C" VOID STREAMAPI AdapterCancelPacket(IN PHW_STREAM_REQUEST_BLOCK Srb);
|
|
|
|
class Field
|
|
{
|
|
private:
|
|
PsColorSpace LocalColSpace_;
|
|
VidBufQueue *BufQue_;
|
|
DWORD dwPitch_;
|
|
bool Started_;
|
|
int SkipCount_;
|
|
long TimePerFrame_;
|
|
LONGLONG LapsedTime_;
|
|
LONG FrameTiming_;
|
|
VideoStream VidStrm_;
|
|
|
|
// used to notify video channel
|
|
ChanIface *callback_;
|
|
|
|
bool Paired_;
|
|
bool ready_;
|
|
|
|
// this is used by the video channel to report timestamps
|
|
LONGLONG InterruptCounter_;
|
|
LONGLONG FrameCounter_;
|
|
|
|
RegField &CaptureEnable_;
|
|
|
|
public:
|
|
|
|
bool Interrupt_;
|
|
|
|
Field( RegField &CapEn, RegBase *ColReg, RegBase *WordSwap,
|
|
RegBase *ByteSwap );
|
|
virtual ~Field() {}
|
|
|
|
inline void CancelSrbList( )
|
|
{
|
|
while( !BufQue_->IsEmpty( ) )
|
|
{
|
|
DataBuf buf = BufQue_->Get();
|
|
AdapterCancelPacket( buf.pSrb_ );
|
|
}
|
|
|
|
BufQue_->Flush();
|
|
}
|
|
|
|
void Notify( PVOID pTag, bool skipped )
|
|
{ if ( callback_ ) callback_->Notify( pTag, skipped ); }
|
|
|
|
void SetStreamID( VideoStream );
|
|
VideoStream GetStreamID();
|
|
|
|
void ResetCounters();
|
|
|
|
virtual ErrorCode SetAnalogWindow( MRect &r ) = 0;
|
|
virtual void GetAnalogWindow( MRect &r ) = 0;
|
|
|
|
virtual ErrorCode SetDigitalWindow( MRect &r ) = 0;
|
|
virtual void GetDigitalWindow( MRect &r ) = 0;
|
|
|
|
void SetBufPitch( DWORD dwP ) {
|
|
dwPitch_ = dwP;
|
|
DebugOut((1, "SetBufPitch(%d)\n", dwPitch_));
|
|
}
|
|
DWORD GetBufPitch() { return dwPitch_; }
|
|
|
|
virtual void SetColorFormat( ColFmt aColor )
|
|
{ LocalColSpace_.SetColorFormat( aColor ); }
|
|
|
|
virtual ColFmt GetColorFormat()
|
|
{ return LocalColSpace_.GetColorFormat(); }
|
|
|
|
DataBuf GetNextBuffer();
|
|
|
|
void SetFrameRate( long time );
|
|
void SetPaired( bool p );
|
|
bool GetPaired();
|
|
|
|
void SetReady( bool flag );
|
|
bool GetReady();
|
|
|
|
void SetBufQuePtr( VidBufQueue *pQ ) { BufQue_ = pQ; }
|
|
VidBufQueue &GetCurrentQue() { return *BufQue_; }
|
|
|
|
void SetCallback( ChanIface *iface ) { callback_ = iface;}
|
|
|
|
State Start();
|
|
void Stop();
|
|
bool IsStarted() { return Started_; }
|
|
|
|
State Skip();
|
|
|
|
// called by the BtPiscess::ProcessRISCIntr()
|
|
void GotInterrupt() { InterruptCounter_++; }
|
|
|
|
void GetCounters( LONGLONG &FrameNo, LONGLONG &drop );
|
|
|
|
void SetStandardTiming( LONG t );
|
|
LONG GetStandardTiming();
|
|
|
|
};
|
|
|
|
/* Class: FieldWithScaler
|
|
* Purpose: Adds scaling capability to a field
|
|
* Attributes:
|
|
* Operations:
|
|
*/
|
|
class FieldWithScaler : public Field
|
|
{
|
|
private:
|
|
Scaler LocalScaler_;
|
|
|
|
public:
|
|
FieldWithScaler( RegField &CapEn, VidField field, RegBase *ColReg,
|
|
RegBase *WordSwap, RegBase *ByteSwap ) : LocalScaler_( field ),
|
|
Field( CapEn, ColReg, WordSwap, ByteSwap ) {}
|
|
|
|
virtual ErrorCode SetAnalogWindow( MRect &r ) { return LocalScaler_.SetAnalogWin( r ); }
|
|
virtual void GetAnalogWindow( MRect &r ) { LocalScaler_.GetAnalogWin( r ); }
|
|
|
|
virtual ErrorCode SetDigitalWindow( MRect &r ) { return LocalScaler_.SetDigitalWin( r ); }
|
|
virtual void GetDigitalWindow( MRect &r ) { LocalScaler_.GetDigitalWin( r ); }
|
|
|
|
void VideoFormatChanged( VideoFormat format );
|
|
void TurnVFilter( State s );
|
|
};
|
|
|
|
/* Class: VBIField
|
|
* Purpose: Encapsulates the operation of a VBI data 'field'
|
|
* Attributes:
|
|
* Operations:
|
|
*/
|
|
class VBIField : public Field
|
|
{
|
|
private:
|
|
DECLARE_VBIPACKETSIZE;
|
|
DECLARE_VBIDELAY;
|
|
|
|
MRect AnalogWin_;
|
|
MRect DigitalWin_;
|
|
|
|
public:
|
|
VBIField( RegField &CapEn ) : Field( CapEn, NULL, NULL, NULL ),
|
|
CONSTRUCT_VBIPACKETSIZE, CONSTRUCT_VBIDELAY
|
|
{}
|
|
|
|
virtual void SetColorFormat( ColFmt ) {}
|
|
virtual ColFmt GetColorFormat() { return CF_VBI; };
|
|
|
|
virtual ErrorCode SetAnalogWindow( MRect &r ) { AnalogWin_ = r; return Success; }
|
|
virtual void GetAnalogWindow( MRect &r ) { r = AnalogWin_; }
|
|
|
|
virtual ErrorCode SetDigitalWindow( MRect &r )
|
|
{
|
|
DigitalWin_ = r;
|
|
DWORD dwNoOfDWORDs = r.Width() / 4;
|
|
// SetBufPitch( r.Width() * ColorSpace( CF_VBI ).GetBitCount() / 8 );
|
|
VBI_PKT_LO = (BYTE)dwNoOfDWORDs;
|
|
VBI_PKT_HI = dwNoOfDWORDs > 0xff; // set the 9th bit
|
|
VBI_HDELAY = r.left;
|
|
return Success;
|
|
}
|
|
virtual void GetDigitalWindow( MRect &r ) { r = DigitalWin_; }
|
|
|
|
~VBIField() {}
|
|
};
|
|
|
|
inline Field::Field( RegField &CapEn, RegBase *ColReg, RegBase *WordSwap,
|
|
RegBase *ByteSwap ) : SkipCount_( 0 ), CaptureEnable_( CapEn ),
|
|
LocalColSpace_( CF_RGB32, *ColReg, *WordSwap, *ByteSwap ),
|
|
Started_( false ), callback_( NULL ), BufQue_( NULL ), dwPitch_( 0 ),
|
|
TimePerFrame_( 333667 ), LapsedTime_( 0 ),InterruptCounter_( 0 ),
|
|
FrameCounter_( 0 ), Interrupt_( true ), FrameTiming_( 333667 )
|
|
{
|
|
|
|
}
|
|
|
|
/* Method: Field::SetFrameRate
|
|
* Purpose: Sets frame rate
|
|
* Input: time: long, time in 100s nanoseconds per frame
|
|
*/
|
|
inline void Field::SetFrameRate( long time )
|
|
{
|
|
TimePerFrame_ = time;
|
|
|
|
// this is needed to make sure very first get returns a buffer
|
|
LapsedTime_ = time;
|
|
}
|
|
|
|
inline void Field::SetStreamID( VideoStream st )
|
|
{
|
|
VidStrm_ = st;
|
|
}
|
|
|
|
inline VideoStream Field::GetStreamID()
|
|
{
|
|
return VidStrm_;
|
|
}
|
|
|
|
inline void Field::SetPaired( bool p )
|
|
{
|
|
Paired_ = p;
|
|
}
|
|
|
|
inline bool Field::GetPaired()
|
|
{
|
|
return Paired_;
|
|
}
|
|
|
|
inline void Field::GetCounters( LONGLONG &FrameNo, LONGLONG &drop )
|
|
{
|
|
// Frame number is what frame index we should be on.
|
|
// Use interrupt count, not just frames returned.
|
|
FrameNo = InterruptCounter_;
|
|
|
|
// Drop count = number of interrupts - number of completed buffers
|
|
drop = InterruptCounter_ - FrameCounter_;
|
|
|
|
if ( drop > 0 )
|
|
{
|
|
drop--;
|
|
|
|
// We've reported the drops, so show frame count as caught
|
|
// up to interrupt count
|
|
FrameCounter_ += drop;
|
|
DebugOut((1, "%d,", drop));
|
|
}
|
|
else if ( drop < 0 )
|
|
{
|
|
DebugOut((1, "*** %d ***,", drop));
|
|
}
|
|
else
|
|
{
|
|
DebugOut((1, "0,"));
|
|
}
|
|
}
|
|
|
|
inline void Field::ResetCounters()
|
|
{
|
|
FrameCounter_ = InterruptCounter_ = 0;
|
|
}
|
|
|
|
inline void Field::SetReady( bool flag )
|
|
{
|
|
ready_ = flag;
|
|
}
|
|
|
|
inline bool Field::GetReady()
|
|
{
|
|
return ready_;
|
|
}
|
|
|
|
inline void Field::SetStandardTiming( LONG t )
|
|
{
|
|
FrameTiming_ = t;
|
|
}
|
|
|
|
inline LONG Field::GetStandardTiming()
|
|
{
|
|
return FrameTiming_;
|
|
}
|
|
|
|
/* Method: Field::GetNextBuffer
|
|
* Purpose: Returns next buffer from the queue, if time is correct for it.
|
|
* Input: None
|
|
*/
|
|
inline DataBuf Field::GetNextBuffer()
|
|
{
|
|
// that's how long it takes to capture a frame of video
|
|
LapsedTime_ += GetStandardTiming();
|
|
DataBuf buf;
|
|
|
|
// [TMZ] [!!!] - hack, disable wait 'cause it doesn't work
|
|
|
|
//if ( LapsedTime_ >= TimePerFrame_ ) {
|
|
if ( 1 ) {
|
|
|
|
// have to increment the frame number if we want that frame only
|
|
if ( IsStarted() ) {
|
|
GotInterrupt();
|
|
}
|
|
|
|
//#define FORCE_BUFFER_SKIP_TESTING
|
|
#ifdef FORCE_BUFFER_SKIP_TESTING
|
|
static int iTestSkip = 0;
|
|
BOOL bEmpty = BufQue_->IsEmpty();
|
|
DebugOut((0, "Queue(%x) bEmpty = %d\n", BufQue_, bEmpty));
|
|
if ( iTestSkip++ & 1 ) {
|
|
// Every other query should look like the buffer is empty.
|
|
bEmpty = TRUE;
|
|
DebugOut((1, " [override] set bEmpty = %d\n", bEmpty));
|
|
}
|
|
if ( !bEmpty ) {
|
|
buf = BufQue_->Get();
|
|
DebugOut((1, " GotBuf addr %X\n", buf.pData_ ) );
|
|
LapsedTime_ = 0;
|
|
FrameCounter_++;
|
|
} else {
|
|
DebugOut((1, " No buffer in que at %d\n",LapsedTime_));
|
|
if ( !IsStarted() ) {
|
|
InterruptCounter_--;
|
|
FrameCounter_--;
|
|
}
|
|
}
|
|
#else
|
|
if ( !BufQue_->IsEmpty() ) {
|
|
buf = BufQue_->Get();
|
|
DebugOut((1, "GotBuf addr %X\n", buf.pData_ ) );
|
|
LapsedTime_ = 0;
|
|
FrameCounter_++;
|
|
} else {
|
|
DebugOut((1, "No buffer in que at %d\n",LapsedTime_));
|
|
if ( !IsStarted() ) {
|
|
InterruptCounter_--;
|
|
FrameCounter_--;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
DebugOut((1, "returning buf {pSrb=%x, pData=%x}\n", buf.pSrb_, buf.pData_ ) );
|
|
return buf;
|
|
}
|
|
|
|
/* Method: Field::Start
|
|
* Purpose: Initiates the data flow out of decoder into the FIFO
|
|
* Input: None
|
|
* Output: State: Off if channel was off; On if channel was on
|
|
*/
|
|
inline State Field::Start()
|
|
{
|
|
Trace t("Field::Start()");
|
|
|
|
Started_ = true;
|
|
State RetVal = SkipCount_ >= MaxProgsForField ? Off : On;
|
|
SkipCount_--;
|
|
if ( SkipCount_ < 0 )
|
|
SkipCount_ = 0;
|
|
CaptureEnable_ = On;
|
|
return RetVal;
|
|
}
|
|
|
|
inline void Field::Stop()
|
|
{
|
|
Trace t("Field::Stop()");
|
|
|
|
Started_ = false;
|
|
CaptureEnable_ = Off;
|
|
LapsedTime_ = TimePerFrame_;
|
|
}
|
|
|
|
/* Method: Field::Skip
|
|
* Purpose: Increments the skip count and stops the data flow if it exceeds the max
|
|
* Input: None
|
|
* Output: State: Off if channel is stopped; On if channel remains running
|
|
*/
|
|
inline State Field::Skip()
|
|
{
|
|
Trace t("Field::Skip()");
|
|
|
|
SkipCount_++;
|
|
if ( SkipCount_ >= MaxProgsForField ) {
|
|
Stop();
|
|
return Off;
|
|
}
|
|
return On;
|
|
}
|
|
|
|
inline void FieldWithScaler::VideoFormatChanged( VideoFormat format )
|
|
{
|
|
LocalScaler_.VideoFormatChanged( format );
|
|
}
|
|
|
|
inline void FieldWithScaler::TurnVFilter( State s )
|
|
{
|
|
LocalScaler_.TurnVFilter( s );
|
|
}
|
|
|
|
|
|
#endif
|