|
|
//==========================================================================;
//
// Decoder - Main decoder implementation
//
// $Date: 21 Aug 1998 21:46:26 $
// $Revision: 1.1 $
// $Author: Tashjian $
//
// $Copyright: (c) 1997 - 1998 ATI Technologies Inc. All Rights Reserved. $
//
//==========================================================================;
#include "mytypes.h"
#include "Scaler.h"
#include "decoder.h"
#include "dcdrvals.h"
#include "capmain.h"
#define CON_vs_BRI // HW does contrast incorrectly, try to adjust in SW
//===========================================================================
// Bt848 Decoder Class Implementation
//===========================================================================
#define REGALIGNMENT 1
/////////////////////////////////////////////////////////////////////////////
// Constructor
/////////////////////////////////////////////////////////////////////////////
Decoder::Decoder(PDEVICE_PARMS pDeviceParms) : // init register min, max, default
m_regHue(HueMin, HueMax, HueDef), m_regSaturationNTSC(SatMinNTSC, SatMaxNTSC, SatDefNTSC), m_regSaturationSECAM(SatMinSECAM, SatMaxSECAM, SatDefSECAM), m_regContrast(ConMin, ConMax, ConDef), m_regBrightness(BrtMin, BrtMax, BrtDef), m_param(ParamMin, ParamMax, ParamDef),
decRegSTATUS (((0x00 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldHLOC(decRegSTATUS, 6, 1, RW) , decFieldNUML(decRegSTATUS, 4, 1, RW) , decFieldCSEL(decRegSTATUS, 3, 1, RW) , decFieldSTATUS_RES(decRegSTATUS, 2, 1, RW) , decFieldLOF(decRegSTATUS, 1, 1, RW) , decFieldCOF(decRegSTATUS, 0, 1, RW) , decRegIFORM (((0x01 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldHACTIVE(decRegIFORM, 7, 1, RW) , decFieldMUXSEL(decRegIFORM, 5, 2, RW) , decFieldXTSEL(decRegIFORM, 3, 2, RW) , decFieldFORMAT(decRegIFORM, 0, 3, RW) , decRegTDEC (((0x02 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldDEC_FIELD(decRegTDEC, 7, 1, RW) , decFieldDEC_FIELDALIGN(decRegTDEC, 6, 1, RW) , decFieldDEC_RAT(decRegTDEC, 0, 6, RW) , decRegBRIGHT (((0x0A + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegMISCCONTROL (((0x0B + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldLNOTCH(decRegMISCCONTROL, 7, 1, RW) , decFieldCOMP(decRegMISCCONTROL, 6, 1, RW) , decFieldLDEC(decRegMISCCONTROL, 5, 1, RW) , decFieldMISCCONTROL_RES(decRegMISCCONTROL, 3, 1, RW) , decFieldCON_MSB(decRegMISCCONTROL, 2, 1, RW) , decFieldSAT_U_MSB(decRegMISCCONTROL, 1, 1, RW) , decFieldSAT_V_MSB(decRegMISCCONTROL, 0, 1, RW) , decRegCONTRAST_LO (((0x0C + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegSAT_U_LO (((0x0D + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegSAT_V_LO (((0x0E + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegHUE (((0x0F + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegSCLOOP (((0x10 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldCAGC(decRegSCLOOP, 6, 1, RW) , decFieldCKILL(decRegSCLOOP, 5, 1, RW) , decRegWC_UP(((0x11 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegOFORM (((0x12 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldVBI_FRAME(decRegOFORM, 4, 1, RW) , decFieldCODE(decRegOFORM, 3, 1, RW) , decFieldLEN(decRegOFORM, 2, 1, RW) , decRegVSCALE_HI (((0x13 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldYCOMB(decRegVSCALE_HI, 7, 1, RW) , decFieldCOMB(decRegVSCALE_HI, 6, 1, RW) , decFieldINT(decRegVSCALE_HI, 5, 1, RW) , decRegTEST (((0x15 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegVPOLE (((0x16 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldOUT_EN (decRegVPOLE, 7, 1, RW), decFieldDVALID (decRegVPOLE, 6, 1, RW), decFieldVACTIVE (decRegVPOLE, 5, 1, RW), decFieldCBFLAG (decRegVPOLE, 4, 1, RW), decFieldFIELD (decRegVPOLE, 3, 1, RW), decFieldACTIVE (decRegVPOLE, 2, 1, RW), decFieldHRESET (decRegVPOLE, 1, 1, RW), decFieldVRESET (decRegVPOLE, 0, 1, RW), decRegADELAY (((0x18 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegBDELAY (((0x19 + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegADC (((0x1A + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldCLK_SLEEP(decRegADC, 3, 1, RW) , decFieldC_SLEEP(decRegADC, 1, 1, RW) , decFieldCRUSH(decRegADC, 0, 1, RW), decRegVTC (((0x1B + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decFieldHSFMT(decRegVTC, 7, 1, RW) , decRegWC_DN(((0x1E + 0) * REGALIGNMENT) + 0, RW, pDeviceParms) , decRegSRESET (((0x1F + 0) * REGALIGNMENT) + 0, RW, pDeviceParms), decRegODD_MISCCONTROL (((0x0B + -0x03) * REGALIGNMENT) + 0x8C, RW, pDeviceParms) , decFieldODD_LNOTCH(decRegODD_MISCCONTROL, 7, 1, RW) , decFieldODD_COMP(decRegODD_MISCCONTROL, 6, 1, RW) , decFieldODD_LDEC(decRegODD_MISCCONTROL, 5, 1, RW) , decFieldODD_CBSENSE(decRegODD_MISCCONTROL, 4, 1, RW) , decFieldODD_MISCCONTROL_RES(decRegODD_MISCCONTROL, 3, 1, RW) , decFieldODD_CON_MSB(decRegODD_MISCCONTROL, 2, 1, RW) , decFieldODD_SAT_U_MSB(decRegODD_MISCCONTROL, 1, 1, RW) , decFieldODD_SAT_V_MSB(decRegODD_MISCCONTROL, 0, 1, RW) , decRegODD_SCLOOP (((0x10 + -0x03) * REGALIGNMENT) + 0x8C, RW, pDeviceParms) , decFieldODD_CAGC(decRegODD_SCLOOP, 6, 1, RW) , decFieldODD_CKILL(decRegODD_SCLOOP, 5, 1, RW) , decFieldODD_HFILT(decRegODD_SCLOOP, 3, 2, RW) , decRegODD_VSCALE_HI (((0x13 + -0x03) * REGALIGNMENT) + 0x8C, RW, pDeviceParms) , decFieldODD_YCOMB(decRegODD_VSCALE_HI, 7, 1, RW) , decFieldODD_COMB(decRegODD_VSCALE_HI, 6, 1, RW) , decFieldODD_INT(decRegODD_VSCALE_HI, 5, 1, RW) , decRegODD_VTC (((0x1B + -0x03) * REGALIGNMENT) + 0x8C, RW, pDeviceParms) , decFieldODD_HSFMT(decRegODD_VTC, 7, 1, RW) { if(!(pDeviceParms->chipRev < 4)) { // need to set this to 0x4F
decRegWC_UP = 0x4F; // and this one to 0x7F to make sure CRUSH bit works for not plain vanila BT829
decRegWC_DN = 0x7F; }
// HACTIVE should always be 0
decFieldHACTIVE = 0;
decFieldHSFMT = 0;
// The following lines were commented out in an attempt to
// have a picture which closely matches what an ordinary TV would
// show. However, it should be noted that Brooktree recommended to
// comment out only the 'SetLowColorAutoRemoval' line. Probably the
// best solution of all would be to somehow expose these options
// to the application.
// Instead of using default values, set some registers fields to optimum values
/*
SetLumaDecimation(TRUE); SetChromaAGC(TRUE); SetLowColorAutoRemoval(FALSE); SetAdaptiveAGC(FALSE); */
// for contrast adjustment purpose
regBright = 0x00; // brightness register value before adjustment
regContrast = 0xD8; // contrast register value before adjustment
m_supportedVideoStandards = KS_AnalogVideo_NTSC_M | KS_AnalogVideo_NTSC_M_J | KS_AnalogVideo_PAL_B | KS_AnalogVideo_PAL_D | KS_AnalogVideo_PAL_G | KS_AnalogVideo_PAL_H | KS_AnalogVideo_PAL_I | KS_AnalogVideo_PAL_M | KS_AnalogVideo_PAL_N; //Paul: what BT 829 can support (from L829A_A functional Description)
if(!(pDeviceParms->chipRev < 4)) m_supportedVideoStandards |= KS_AnalogVideo_SECAM_B | KS_AnalogVideo_SECAM_D | KS_AnalogVideo_SECAM_G | KS_AnalogVideo_SECAM_H | KS_AnalogVideo_SECAM_K | KS_AnalogVideo_SECAM_K1 | KS_AnalogVideo_SECAM_L | KS_AnalogVideo_SECAM_L1; m_supportedVideoStandards &= pDeviceParms->ulVideoInStandardsSupportedByCrystal; //Paul: AND with whatever supported by the onboard crystal
// jaybo
// loop until we find a supported TV standard, and use that to init
UINT k; for (k = 1; k; k += k) { if (k & m_supportedVideoStandards) { SetVideoDecoderStandard(k); break; } } // end jaybo
}
/////////////////////////////////////////////////////////////////////////////
// Destructor
/////////////////////////////////////////////////////////////////////////////
Decoder::~Decoder() { }
void Decoder::GetVideoDecoderCaps(PKSPROPERTY_VIDEODECODER_CAPS_S pS) { pS->StandardsSupported = m_supportedVideoStandards;
pS->Capabilities = KS_VIDEODECODER_FLAGS_CAN_DISABLE_OUTPUT | KS_VIDEODECODER_FLAGS_CAN_INDICATE_LOCKED ;
// How long (ms) til locked indicator is valid.
// 31 line periods * 63.5uS per line.
pS->SettlingTime = 2;
// Not sure about this
// HSync per VSync
pS->HSyncPerVSync = 6; }
void Decoder::GetVideoDecoderStatus(PKSPROPERTY_VIDEODECODER_STATUS_S pS) { pS->NumberOfLines = Is525LinesVideo() ? 525 : 625; pS->SignalLocked = decFieldHLOC == 1; }
DWORD Decoder::GetVideoDecoderStandard() { return m_videoStandard; //Paul
}
BOOL Decoder::SetVideoDecoderStandard(DWORD standard) { if (m_supportedVideoStandards & standard) //Paul: standard must be a supported standard
{ m_videoStandard = standard;
switch ( m_videoStandard ) { case KS_AnalogVideo_NTSC_M: Decoder::SetVideoFormat(VFormat_NTSC); break; case KS_AnalogVideo_NTSC_M_J: Decoder::SetVideoFormat(VFormat_NTSC_J); break; case KS_AnalogVideo_PAL_B: case KS_AnalogVideo_PAL_D: case KS_AnalogVideo_PAL_G: case KS_AnalogVideo_PAL_H: case KS_AnalogVideo_PAL_I: Decoder::SetVideoFormat(VFormat_PAL_BDGHI); // PAL_BDGHI covers most areas
break; case KS_AnalogVideo_PAL_M: Decoder::SetVideoFormat(VFormat_PAL_M); break; case KS_AnalogVideo_PAL_N: Decoder::SetVideoFormat(VFormat_PAL_N_COMB); break; default: //Paul: SECAM
Decoder::SetVideoFormat(VFormat_SECAM);
} return TRUE; } else return FALSE;
}
//===== Device Status register ==============================================
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::Is525LinesVideo()
// Purpose: Check to see if we are dealing with 525 lines video signal
// Input: None
// Output: None
// Return: TRUE if 525 lines detected; else FALSE (assume 625 lines)
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::Is525LinesVideo() { return (BOOL) (decFieldNUML == 0); //525
}
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsCrystal0Selected()
// Purpose: Reflect whether XTAL0 or XTAL1 is selected
// Input: None
// Output: None
// Return: TRUE if XTAL0 selected; else FALSE (XTAL1 selected)
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsCrystal0Selected() { return (BOOL) (decFieldCSEL == 0); }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsLumaOverflow()
// Purpose: Indicates if luma ADC overflow
// Input: None
// Output: None
// Return: TRUE if luma ADC overflow; else FALSE
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsLumaOverflow() { return (BOOL) (decFieldLOF == 1); }
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::ResetLumaOverflow()
// Purpose: Reset luma ADC overflow bit
// Input: None
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::ResetLumaOverflow() { decFieldLOF = 0; // write to it will reset the bit
}
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsChromaOverflow()
// Purpose: Indicates if chroma ADC overflow
// Input: None
// Output: None
// Return: TRUE if chroma ADC overflow; else FALSE
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsChromaOverflow() { return (BOOL) (decFieldCOF == 1); }
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::ResetChromaOverflow()
// Purpose: Reset chroma ADC overflow bit
// Input: None
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::ResetChromaOverflow() { decFieldCOF = 0; // write to it will reset the bit
}
//===== Input Format register ===============================================
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::SetVideoInput(Connector source)
// Purpose: Select which connector as input
// Input: Connector source - SVideo, Tuner, Composite
// Output: None
// Return: Fail if error in parameter, else Success
/////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::SetVideoInput(Connector source) { if ((source != ConSVideo) && (source != ConTuner) && (source != ConComposite)) return Fail;
decFieldMUXSEL = (ULONG)source + 1;
// set to composite or Y/C component video depends on video source
SetCompositeVideo((source == ConSVideo) ? FALSE : TRUE); return Success; }
/////////////////////////////////////////////////////////////////////////////
// Method: Connector Decoder::GetVideoInput()
// Purpose: Get which connector is input
// Input: None
// Output: None
// Return: Video source - SVideo, Tuner, Composite
/////////////////////////////////////////////////////////////////////////////
Connector Decoder::GetVideoInput() { return ((Connector)(decFieldMUXSEL-1)); }
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::SetCrystal(Crystal crystalNo)
// Purpose: Select which crystal as input
// Input: Crystal crystalNo:
// XT0 - Crystal_XT0
// XT1 - Crystal_XT1
// Auto select - Crystal_AutoSelect
// Output: None
// Return: Fail if error in parameter, else Success
/////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::SetCrystal(Crystal crystalNo) { if ((crystalNo < Crystal_XT0) || (crystalNo > Crystal_AutoSelect)) return Fail;
decFieldXTSEL = crystalNo; return Success; }
/////////////////////////////////////////////////////////////////////////////
// Method: int Decoder::GetCrystal()
// Purpose: Get which crystal is input
// Input: None
// Output: None
// Return: Crystal Number:
// XT0 - Crystal_XT0
// XT1 - Crystal_XT1
// Auto select - Crystal_AutoSelect
/////////////////////////////////////////////////////////////////////////////
int Decoder::GetCrystal() { return ((int)decFieldXTSEL); }
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::SetVideoFormat(VideoFormat format)
// Purpose: Set video format
// Input: Video format -
// Auto format: VFormat_AutoDetect
// NTSC (M): VFormat_NTSC
// NTSC Japan: VFormat_NTSC_J
// PAL (B, D, G, H, I): VFormat_PAL_BDGHI
// PAL (M): VFormat_PAL_M
// PAL(N): VFormat_PAL_N
// SECAM: VFormat_SECAM
// PAN(N Combo) VFormat_PAL_N_COMB
// Output: None
// Return: Fail if error in parameter, else Success
// Notes: Available video formats are: NTSC, PAL(B, D, G, H, I), PAL(M),
// PAL(N), SECAM
// This function also sets the AGCDelay (ADELAY) and BrustDelay
// (BDELAY) registers
/////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::SetVideoFormat(VideoFormat format) { if ((format < VFormat_AutoDetect) || (format > VFormat_PAL_N_COMB)) return Fail;
switch (format) { case VFormat_PAL_M: case VFormat_NTSC: case VFormat_NTSC_J: decFieldFORMAT = format; decRegADELAY = 0x68; decRegBDELAY = 0x5D; SetChromaComb(TRUE); // enable chroma comb
SelectCrystal('N'); // select NTSC crystal
break;
case VFormat_PAL_BDGHI: case VFormat_PAL_N: decFieldFORMAT = format; decRegADELAY = 0x7F; decRegBDELAY = 0x72; SetChromaComb(TRUE); // enable chroma comb
SelectCrystal('P'); // select PAL crystal
break;
case VFormat_PAL_N_COMB: decFieldFORMAT = format; decRegADELAY = 0x7F; decRegBDELAY = 0x72; SetChromaComb(TRUE); // enable chroma comb
SelectCrystal('N'); // select NTSC crystal
break;
case VFormat_SECAM: decFieldFORMAT = format; decRegADELAY = 0x7F; decRegBDELAY = 0xA0; SetChromaComb(FALSE); // disable chroma comb
SelectCrystal('P'); // select PAL crystal
break; default: // VFormat_AutoDetect
// auto format detect by examining the number of lines
if (Decoder::Is525LinesVideo()) // lines == 525 -> NTSC
Decoder::SetVideoFormat(VFormat_NTSC); else // lines == 625 -> PAL/SECAM
Decoder::SetVideoFormat(VFormat_PAL_BDGHI); // PAL_BDGHI covers most areas
}
SetSaturation(m_satParam); return Success; }
/////////////////////////////////////////////////////////////////////////////
// Method: int Decoder::GetVideoFormat()
// Purpose: Obtain video format
// Input: None
// Output: None
// Return: Video format
// Auto format: VFormat_AutoDetect
// NTSC (M): VFormat_NTSC
// PAL (B, D, G, H, I): VFormat_PAL_BDGHI
// PAL (M): VFormat_PAL_M
// PAL(N): VFormat_PAL_N
// SECAM: VFormat_SECAM
// PAN(N Combo) VFormat_PAL_N_COMB
/////////////////////////////////////////////////////////////////////////////
int Decoder::GetVideoFormat() { BYTE bFormat = (BYTE)decFieldFORMAT; if (!bFormat) // autodetection enabled
return Is525LinesVideo() ? VFormat_NTSC : VFormat_SECAM; else return bFormat; }
//===== Temporal Decimation register ========================================
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::SetRate(BOOL fields, VidField even, int rate)
// Purpose: Set frames or fields rate
// Input: BOOL fields - TRUE for fields, FALSE for frames
// VidField even - TRUE to start decimation with even field, FALSE odd
// int rate - decimation rate: frames (1-50/60); fields(1-25/30)
// Output: None
// Return: Fail if error in parameter, else Success
/////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::SetRate(BOOL fields, VidField vf, int rate) { int nMax; if (Is525LinesVideo() == TRUE) nMax = 30; // NTSC
else nMax = 25; // PAL/SECAM
// if setting frame rate, double the max value
if (fields == FALSE) nMax *= 2;
if (rate < 0 || rate > nMax) return Fail;
decFieldDEC_FIELD = (fields == FALSE) ? Off : On; decFieldDEC_FIELDALIGN = (vf == VF_Even) ? On : Off; int nDrop = (BYTE) nMax - rate; decFieldDEC_RAT = (BYTE) (fields == FALSE) ? nDrop : nDrop * 2;
return Success; }
//===== Brightness Control register =========================================
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::SetBrightness(int param)
// Purpose: Set video brightness
// Input: int param - parameter value (0-255; default 128)
// Output: None
// Return: Fail if error in parameter, else Success
// Note: See IsAdjustContrast() for detailed description of the contrast
// adjustment calculation
/////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::SetBrightness(int param) { if(m_param.OutOfRange(param)) return Fail;
// perform mapping to our range
int mapped; if (Mapping(param, m_param, &mapped, m_regBrightness) == Fail) return Fail;
m_briParam = (WORD)param;
// calculate brightness value
int value = (128 * mapped) / m_regBrightness.Max() ;
// need to limit the value to 0x7F (+50%) because 0x80 is -50%!
if ((mapped > 0) && (value == 0x80)) value = 0x7F;
// perform adjustment of brightness register if adjustment is needed
if (IsAdjustContrast()) { regBright = value; // brightness value before adjustment
long A = (long)regBright * (long)0xD8; long B = 64 * ((long)0xD8 - (long)regContrast); long temp = 0x00; if (regContrast != 0) // already limit contrast > zero; just in case here
temp = ((A + B) / (long)regContrast); temp = (temp < -128) ? -128 : ((temp > 127) ? 127 : temp); value = (BYTE)temp;
}
decRegBRIGHT = (BYTE)value;
return Success; }
/////////////////////////////////////////////////////////////////////////////
// Method: int Decoder::GetBrightness()
// Purpose: Obtain brightness value
// Input: None
// Output: None
// Return: Brightness parameter (0-255)
/////////////////////////////////////////////////////////////////////////////
int Decoder::GetBrightness() { return m_briParam; }
//===== Miscellaneous Control register (E_CONTROL, O_CONTROL) ===============
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetLumaNotchFilter(BOOL mode)
// Purpose: Enable/Disable luma notch filter
// Input: BOOL mode - TRUE = Enable; FALSE = Disable
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetLumaNotchFilter(BOOL mode) { decFieldLNOTCH = (mode == FALSE) ? On : Off; // reverse
}
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsLumaNotchFilter()
// Purpose: Check if luma notch filter is enable or disable
// Input: None
// Output: None
// Return: TRUE = Enable; FALSE = Disable
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsLumaNotchFilter() { return (decFieldLNOTCH == Off) ? TRUE : FALSE; // reverse
}
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetCompositeVideo(BOOL mode)
// Purpose: Select composite or Y/C component video
// Input: BOOL mode - TRUE = Composite; FALSE = Y/C Component
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetCompositeVideo(BOOL mode) { if (mode == TRUE) { // composite video
decFieldCOMP = Off; Decoder::SetChromaADC(FALSE); // disable chroma ADC
Decoder::SetLumaNotchFilter(TRUE); // enable luma notch filter
} else { // Y/C Component video
decFieldCOMP = On; Decoder::SetChromaADC(TRUE); // enable chroma ADC
Decoder::SetLumaNotchFilter(FALSE); // disable luma notch filter
} }
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetLumaDecimation(BOOL mode)
// Purpose: Enable/Disable luma decimation filter
// Input: BOOL mode - TRUE = Enable; FALSE = Disable
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetLumaDecimation(BOOL mode) { // value of 0 turns the decimation on
decFieldLDEC = (mode == TRUE) ? 0 : 1; }
//===== Luma Gain register (CON_MSB, CONTRAST_LO) ===========================
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::SetContrast(int param)
// Purpose: Set video contrast
// Input: int param - parameter value (0-255; default 128)
// Output: None
// Return: Fail if error in parameter, else Success
// Note: See IsAdjustContrast() for detailed description of the contrast
// adjustment calculation
/////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::SetContrast(int param) { if(m_param.OutOfRange(param)) return Fail;
BOOL adjustContrast = IsAdjustContrast(); // is contrast need to be adjusted
// if adjust contrast is needed, make sure contrast reg value != 0
if (adjustContrast) m_regContrast = CRegInfo(1, ConMax, ConDef);
// perform mapping to our range
int mapped; if (Mapping(param, m_param, &mapped, m_regContrast) == Fail) return Fail;
m_conParam = (WORD)param;
// calculate contrast
DWORD value = (DWORD)0x1FF * (DWORD)mapped; value /= (DWORD)m_regContrast.Max(); if (value > 0x1FF) value = 0x1FF;
// contrast is set by a 9 bit value; set LSB first
decRegCONTRAST_LO = value;
// now set the Miscellaneous Control Register CON_V_MSB to the 9th bit value
decFieldCON_MSB = ((value & 0x0100) ? On : Off);
// perform adjustment of brightness register if adjustment is needed
if (adjustContrast) { regContrast = (WORD)value; // contrast value
long A = (long)regBright * (long)0xD8; long B = 64 * ((long)0xD8 - (long)regContrast); long temp = 0x00; if (regContrast != 0) // already limit contrast > zero; just in case here
temp = ((A + B) / (long)regContrast); temp = (temp < -128) ? -128 : ((temp > 127) ? 127 : temp); decRegBRIGHT = (BYTE)temp;
}
return Success; }
/////////////////////////////////////////////////////////////////////////////
// Method: int Decoder::GetContrast()
// Purpose: Obtain contrast value
// Input: None
// Output: None
// Return: Contrast parameter (0-255)
/////////////////////////////////////////////////////////////////////////////
int Decoder::GetContrast() { return m_conParam; }
//===== Chroma Gain register (SAT_U_MSB, SAT_V_MSB, SAT_U_LO, SAT_V_LO) =====
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::SetSaturation(int param)
// Purpose: Set color saturation by modifying U and V values
// Input: int param - parameter value (0-255; default 128)
// Output: None
// Return: Fail if error in parameter, else Success
/////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::SetSaturation(int param) { if(m_param.OutOfRange(param)) return Fail;
// color saturation is controlled by two nine bit values:
// ChromaU & ChromaV
// To maintain normal color balance, the ratio between the 2 register
// values should be kept at the power-up default ratio
// Note that U & V values for NTSC and PAL are the same, SECAM is different
WORD nominalNTSC_U = 0xFE; // nominal value (i.e. 100%) for NTSC/PAL
WORD nominalNTSC_V = 0xB4; WORD nominalSECAM_U = 0x87; // nominal value (i.e. 100%) for SECAM
WORD nominalSECAM_V = 0x85;
CRegInfo regSat; // selected saturation register; NTSC/PAL or SECAM
WORD nominal_U, nominal_V; // selected nominal U and V value; NTSC/PAL or SECAM
// select U & V values of either NTSC/PAL or SECAM to be used for calculation
if (GetVideoFormat() == VFormat_SECAM) { nominal_U = nominalSECAM_U; nominal_V = nominalSECAM_V; regSat = m_regSaturationSECAM; } else { nominal_U = nominalNTSC_U; nominal_V = nominalNTSC_V; regSat = m_regSaturationNTSC; }
// perform mapping to our range
int mapped; if (Mapping(param, m_param, &mapped, regSat) == Fail) return Fail;
m_satParam = (WORD)param;
WORD max_nominal = max(nominal_U, nominal_V);
// calculate U and V values
WORD Uvalue = (WORD) ((DWORD)mapped * (DWORD)nominal_U / (DWORD)max_nominal); WORD Vvalue = (WORD) ((DWORD)mapped * (DWORD)nominal_V / (DWORD)max_nominal);
// set U
decRegSAT_U_LO = Uvalue;
// now set the Miscellaneous Control Register SAT_U_MSB to the 9th bit value
decFieldSAT_U_MSB = ((Uvalue & 0x0100) ? On : Off);
// set V
decRegSAT_V_LO = Vvalue;
// now set the Miscellaneous Control Register SAT_V_MSB to the 9th bit value
decFieldSAT_V_MSB = ((Vvalue & 0x0100) ? On : Off);
return Success; }
/////////////////////////////////////////////////////////////////////////////
// Method: int Decoder::GetSaturation()
// Purpose: Obtain saturation value
// Input: None
// Output: None
// Return: Saturation parameter (0-255)
/////////////////////////////////////////////////////////////////////////////
int Decoder::GetSaturation() { return m_satParam; }
//===== Hue Control register (HUE) ==========================================
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::SetHue(int param)
// Purpose: Set video hue
// Input: int param - parameter value (0-255; default 128)
// Output: None
// Return: Fail if error in parameter, else Success
/////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::SetHue(int param) { if(m_param.OutOfRange(param)) return Fail;
// perform mapping to our range
int mapped; if (Mapping(param, m_param, &mapped, m_regHue) == Fail) return Fail;
m_hueParam = (WORD)param;
int value = (-128 * mapped) / m_regHue.Max();
if (value > 127) value = 127; else if (value < -128) value = -128;
decRegHUE = value;
return Success; }
/////////////////////////////////////////////////////////////////////////////
// Method: int Decoder::GetHue()
// Purpose: Obtain hue value
// Input: None
// Output: None
// Return: Hue parameter (0-255)
/////////////////////////////////////////////////////////////////////////////
int Decoder::GetHue() { return m_hueParam; }
//===== SC Loop Control register (E_SCLOOP, O_SCLOOP) =======================
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetChromaAGC(BOOL mode)
// Purpose: Enable/Disable Chroma AGC compensation
// Input: BOOL mode - TRUE = Enable, FALSE = Disable
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetChromaAGC(BOOL mode) { decFieldCAGC = (mode == FALSE) ? Off : On; }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsChromaAGC()
// Purpose: Check if Chroma AGC compensation is enable or disable
// Input: None
// Output: None
// Return: TRUE = Enable, FALSE = Disable
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsChromaAGC() { return (decFieldCAGC == On) ? TRUE : FALSE; }
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetLowColorAutoRemoval(BOOL mode)
// Purpose: Enable/Disable low color detection and removal
// Input: BOOL mode - TRUE = Enable, FALSE = Disable
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetLowColorAutoRemoval(BOOL mode) { decFieldCKILL = (mode == FALSE) ? Off : On; }
//===== Output Format register (OFORM) ======================================
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetVBIFrameMode(BOOL mode)
// Purpose: Enable/Disable VBI frame output mode
// Input: BOOL mode - TRUE = Enable, FALSE = Disable
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetVBIFrameMode(BOOL mode) { decFieldVBI_FRAME = (mode == FALSE) ? Off : On; }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsVBIFrameMode()
// Purpose: Check if VBI frame output mode is enabled
// Input: None
// Output: None
// Return: TRUE = Enable, FALSE = Disable
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsVBIFrameMode() { return (decFieldVBI_FRAME == On) ? TRUE : FALSE; }
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetCodeInsertionEnabled(BOOL mode)
// Purpose:
// Input: BOOL mode - TRUE = Disabled, FALSE = Enabled
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetCodeInsertionEnabled(BOOL mode) { decFieldCODE = (mode == TRUE) ? On : Off; }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsCodeInsertionEnabled()
// Purpose: Check if code insertion in data stream is enabled
// Input: None
// Output: None
// Return: TRUE = enabled, FALSE = disabled
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsCodeInsertionEnabled() { return (decFieldCODE == On) ? TRUE : FALSE; }
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::Set16BitDataStream(BOOL mode)
// Purpose: 8 or 16 bit data stream
// Input: BOOL mode - TRUE = 16, FALSE = 8
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::Set16BitDataStream(BOOL mode) { decFieldLEN = (mode == TRUE) ? On : Off; }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::Is16BitDatastream()
// Purpose: Check if 16 bit data stream
// Input: None
// Output: None
// Return: TRUE = 16, FALSE = 8
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::Is16BitDataStream() { return (decFieldLEN == On) ? TRUE : FALSE; }
//===== Vertical Scaling register (E_VSCALE_HI, O_VSCALE_HI) ================
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetChromaComb(BOOL mode)
// Purpose: Enable/Disable chroma comb
// Input: BOOL mode - TRUE = Enable, FALSE = Disable
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetChromaComb(BOOL mode) { decFieldCOMB = (mode == FALSE) ? Off : On; }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsChromaComb()
// Purpose: Check if chroma comb is enable or disable
// Input: None
// Output: None
// Return: TRUE = Enable, FALSE = Disable
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsChromaComb() { return (decFieldCOMB == On) ? TRUE : FALSE; } /////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetInterlaced(BOOL mode)
// Purpose: Enable/Disable Interlace
// Input: BOOL mode - TRUE = Interlaced
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetInterlaced(BOOL mode) { decFieldINT = (mode == FALSE) ? Off : On; }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsInterlaced()
// Purpose: Check if interlaced or non-interlaced
// Input: None
// Output: None
// Return: TRUE = Interlaced
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsInterlaced() { return (decFieldINT == On) ? TRUE : FALSE; } //===== VPOLE register ==================================================
BOOL Decoder::IsOutputEnabled () { return (decFieldOUT_EN == m_outputEnablePolarity); }
void Decoder::SetOutputEnabled (BOOL mode) { decFieldOUT_EN = (mode == TRUE) ? m_outputEnablePolarity : !m_outputEnablePolarity; }
BOOL Decoder::IsHighOdd () { return (decFieldFIELD == 0); // 0 enabled; 1 even
}
void Decoder::SetHighOdd (BOOL mode) { decFieldFIELD = (mode == TRUE) ? 0 : 1; // 0 enabled; 1 even
}
//===== ADC Interface register (ADC) =========================================
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::PowerDown(BOOL mode)
// Purpose: Select normal or shut down clock operation
// Input: BOOL mode - TRUE = shut down, FALSE = normal operation
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::PowerDown(BOOL mode) { decFieldCLK_SLEEP = (mode == FALSE) ? Off : On; }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsPowerDown()
// Purpose: Check if clock operation has been shut down
// Input: None
// Output: None
// Return: TRUE = shut down, FALSE = normal operation
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsPowerDown() { return (decFieldCLK_SLEEP == On) ? TRUE : FALSE; }
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetChromaADC(BOOL mode)
// Purpose: Select normal or sleep C ADC operation
// Input: BOOL mode - TRUE = normal, FALSE = sleep
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SetChromaADC(BOOL mode) { decFieldC_SLEEP = (mode == FALSE) ? On : Off; // reverse
}
/*^^////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SetAdaptiveAGC(BOOL mode)
// Purpose: Set adaptive or non-adaptive AGC operation
// Input: BOOL mode - TRUE = Adaptive, FALSE = Non-adaptive
// Output: None
// Return: None
*////////////////////////////////////////////////////////////////////////////
void Decoder::SetAdaptiveAGC(BOOL mode) { decFieldCRUSH = (mode == FALSE) ? Off : On; }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsAdaptiveAGC()
// Purpose: Check if adaptive or non-adaptive AGC operation is selected
// Input: None
// Output: None
// Return: TRUE = Adaptive, FALSE = Non-adaptive
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsAdaptiveAGC() { return (decFieldCRUSH == On) ? TRUE : FALSE; }
//===== Software Reset register (SRESET) ====================================
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SoftwareReset()
// Purpose: Perform software reset; all registers set to default values
// Input: None
// Output: None
// Return: None
/////////////////////////////////////////////////////////////////////////////
void Decoder::SoftwareReset() { decRegSRESET = 0x00; // write any value will do
}
//===== Test Control register (TEST) ========================================
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::AdjustInertialDampener(BOOL mode)
// Purpose: for factory diagnostics only
// Input: TRUE or FALSE
// Output: None
// Return: None
// NOTE: For factory diagnostics only!!!!!!!
// John Welch's dirty little secret
/////////////////////////////////////////////////////////////////////////////
void Decoder::AdjustInertialDampener(BOOL mode) { #pragma message ("FOR TEST DIAGNOSTICS ONLY! ")
decRegTEST = (mode == FALSE) ? 0x00 : 0x01; }
/////////////////////////////////////////////////////////////////////////////
// Method: void Decoder::SelectCrystal(char useCrystal)
// Purpose: Select correct crystal for NTSC or PAL
// Input: char useCrystal - 'N' for NTSC; 'P' for PAL
// Output: None
// Return: None
// NOTE: Assume at most 2 crystals installed in hardware. i.e. 1 for NTSC
// and the other for PAL/SECAM.
// If there is only 1 crystal exists (which must be crystal XT0),
// do nothing since it is already selected.
/////////////////////////////////////////////////////////////////////////////
void Decoder::SelectCrystal(char useCrystal) { #pragma message("do something about registry")
/*
// locate crystal information in the registry
// the keys to look for in registry are:
// 1. Bt848\NumXTAL - number of crystal installed
// possible values are "1" or "2"
// 2. Bt848\XT0 - what crystal type is for crystal 0
// possible values are "NTSC", "PAL"
// There is another key exist which may be useful in the future:
// Bt848\XT1 - what crystal type is for crystal 1
// possible values are "NTSC", "PAL", and "NONE"
VRegistryKey vkey(PRK_CLASSES_ROOT, "Bt848");
// make sure the key exists
if (vkey.lastError() == ERROR_SUCCESS) { char * numCrystalKey = "NumXTAL"; char nCrystal[5]; DWORD nCrystalLen = 2; // need only first char; '1' or '2'
// get number of crystal exists
if (vkey.getSubkeyValue(numCrystalKey, nCrystal, (DWORD *)&nCrystalLen)) { // if there is only 1 crystal, no other crystal to change to
if (nCrystal[0] == '2') { char * crystalTypeKey = "XT0"; // crystal 0 type
char crystalType[10]; DWORD crystalTypeLen = 6; // need only first char: 'N' or 'P'
// get the crystal 0 information
if (vkey.getSubkeyValue(crystalTypeKey, crystalType, (DWORD *)&crystalTypeLen)) // compare with what we want to use
if ((IsCrystal0Selected() && (crystalType[0] != useCrystal)) || (!IsCrystal0Selected() && (crystalType[0] == useCrystal))) // need to change crystal
SetCrystal(IsCrystal0Selected() ? Crystal_XT1 : Crystal_XT0); } } } */ }
/////////////////////////////////////////////////////////////////////////////
// Method: ErrorCode Decoder::Mapping(int fromValue, CRegInfo fromRange,
// int * toValue, CRegInfo toRange)
// Purpose: Map a value in certain range to a value in another range
// Input: int fromValue - value to be mapped from
// CRegInfo fromRange - range of value mapping from
// CRegInfo toRange - range of value mapping to
// Output: int * toValue - mapped value
// Return: Fail if error in parameter, else Success
// Comment: No range checking is performed here. Assume parameters are in
// valid ranges.
// The mapping function does not assume default is always the mid
// point of the whole range. It only assumes default values of the
// two ranges correspond to each other.
//
// The mapping formula is:
//
// For fromRange.Min() <= fromValue <= fromRange.Default():
//
// fromValue (fromRange.Default() - fromRange.Min())
// ------------------------------------------------ + fromRange.Min()
// toRange.Default() - toRange.Min()
//
// For fromRange.Default() < fromValue <= fromRange.Max():
//
// (fromValue - fromRange.Default()) (toRange.Max() - toRange.Default())
// --------------------------------------------------------------------- + toRange.Default()
// toRange.Max() - toRange.Default()
//
////////////////////////////////////////////////////////////////////////////
ErrorCode Decoder::Mapping(int fromValue, CRegInfo fromRange, int * toValue, CRegInfo toRange) { // calculate intermediate values
DWORD a = toRange.Default() - toRange.Min(); DWORD b = fromRange.Default() - fromRange.Min(); DWORD c = toRange.Max() - toRange.Default(); DWORD d = fromRange.Max() - fromRange.Default();
// prevent divide by zero
if ((b == 0) || (d == 0)) return (Fail);
// perform mapping
if (fromValue <= fromRange.Default()) *toValue = (int) (DWORD)fromValue * a / b + (DWORD)toRange.Min(); else *toValue = (int) ((DWORD)fromValue - (DWORD)fromRange.Default()) * c / d + (DWORD)toRange.Default();
return (Success); }
/////////////////////////////////////////////////////////////////////////////
// Method: BOOL Decoder::IsAdjustContrast()
// Purpose: Check registry key whether adjust contrast is needed
// Input: None
// Output: None
// Return: TRUE = adjust contrast, FALSE = don't adjust contrast
// Note: If adjust contrast is turn on, brightness register value will be
// adjusted such that it remains a constant after the calculation
// performed by the hardware.
//
// The formula is:
// To keep brightness constant (i.e. not affect by changing contrast)
// set brightness to B/(C/C0)
// where B is value of brightness before adjustment
// C is contrast value
// C0 is nominal contrast value (0xD8)
//
// To adjust the contrast level such that it is at the middle of
// black and white: set brightness to (B * C0 + 64 * (C0 - C))/C
// (this is what Intel wants)
//
// Currently there is still limitation of how much adjustment
// can be performed. For example, if brightness is already high,
// (i.e. brightness reg value close to 0x7F), lowering contrast
// until a certain level will have no adjustment effect on brightness.
// In fact, it would even bring down brightness to darkness.
//
// Example 1: if brightness is at nominal value (0x00), contrast can
// only go down to 0x47 (brightness adjustment is already
// at max of 0x7F) before it starts affecting brightness
// which takes it darkness.
// Example 2: if brightness is at nominal value (0x00), contrast can
// go all the way up with brightness adjusted correctly.
// However, the max adjustment used is only 0xDC and
// the max adjustment we can use is 0x&F.
// Example 3: if brightness is at max (0x7F), lowering contrast
// cannot be compensated by adjusting brightness anymore.
// The result is gradually taking brightness to darkness.
// Example 4: if brightness is at min (0x80), lowering contrast has
// no visual effect. Bringing contrast to max is using
// 0xA5 in brightness for compensation.
//
// One last note, the center is defined as the middle of the
// gamma adjusted luminance level. Changing it to use the middle of
// the linear (RGB) luminance level is possible.
/////////////////////////////////////////////////////////////////////////////
BOOL Decoder::IsAdjustContrast() { return FALSE; /*
// locate adjust contrast information in the registry
// the key to look for in registry is:
// Bt848\AdjustContrast - 0 = don't adjust contrast
// 1 = adjust contrast
VRegistryKey vkey(PRK_CLASSES_ROOT, "Bt848");
// make sure the key exists
if (vkey.lastError() == ERROR_SUCCESS) { char * adjustContrastKey = "AdjustContrast"; char key[3]; DWORD keyLen = 2; // need only first char; '0' or '1'
// get the registry value and check it, if exist
if ((vkey.getSubkeyValue(adjustContrastKey, key, (DWORD *)&keyLen)) && (key[0] == '1')) return (TRUE); } return (FALSE); */ }
|