473 lines
16 KiB
C
473 lines
16 KiB
C
#ifndef NABTSAPI_H
|
|
#define NABTSAPI_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif /*__cplusplus*/
|
|
|
|
/* Useful constants */
|
|
|
|
#define NABTS_BYTES_PER_LINE 36
|
|
//#define NABTS_SAMPLES_PER_LINE (pState->SamplesPerLine) /* no longer constant */
|
|
#define MAX_SAMPLE_RATE 6.0
|
|
#define MAX_NABTS_SAMPLES_PER_LINE ((int)(1536.0*MAX_SAMPLE_RATE/5.0))
|
|
/* +++++++ make sure that sampling
|
|
rates >6 give errors, or increase
|
|
this number */
|
|
|
|
/* "Double" is the internally used floating-point representation
|
|
(currently typedef'd to "float" below).
|
|
All floating point numbers exposed to the outside through the API
|
|
are actual "double" values (rather than the internal "Double") */
|
|
|
|
typedef float Double;
|
|
|
|
|
|
#define NDSP_SIGS_TO_ACQUIRE 1
|
|
|
|
enum {
|
|
NDSP_ERROR_ILLEGAL_NDSP_STATE= 1,
|
|
NDSP_ERROR_ILLEGAL_STATS= 2,
|
|
NDSP_ERROR_ILLEGAL_FILTER= 3,
|
|
NDSP_ERROR_NO_GCR= 4,
|
|
NDSP_ERROR_UNSUPPORTED_SAMPLING_RATE= 5,
|
|
NDSP_ERROR_ILLEGAL_VBIINFOHEADER= 6
|
|
};
|
|
|
|
enum {
|
|
NDSP_NO_FEC= 1,
|
|
NDSP_BUNDLE_FEC_1= 2,
|
|
NDSP_BUNDLE_FEC_2= 3
|
|
};
|
|
|
|
|
|
// FP helper routines
|
|
extern long __cdecl float2long(float);
|
|
extern unsigned short __cdecl floatSetup();
|
|
extern void __cdecl floatRestore(unsigned short);
|
|
|
|
|
|
/* Globals */
|
|
extern int g_nNabtsRetrainDuration; /* in frames */
|
|
extern int g_nNabtsRetrainDelay; /* in frames */
|
|
extern BOOL g_bUseGCR; /* enable use of the GCR signal */
|
|
|
|
extern Double g_pdSync[];
|
|
extern int g_nNabtsSyncSize;
|
|
extern Double g_pdGCRSignal1[];
|
|
extern Double g_pdGCRSignal2[];
|
|
extern int g_nNabtsGcrSize;
|
|
|
|
/* extern Double g_pdSync5[], g_pdGCRSignal1_5[], g_pdSignal2_5[]; */
|
|
|
|
/* Forward declarations of types. */
|
|
typedef struct ndsp_decoder_str NDSPState;
|
|
typedef struct nfec_state_str NFECState;
|
|
typedef struct ndsp_line_stats_str NDSPLineStats;
|
|
typedef struct ndsp_gcr_stats_str NDSPGCRStats;
|
|
typedef struct nfec_line_stats_str NFECLineStats;
|
|
typedef struct nfec_bundle_str NFECBundle;
|
|
typedef void (NFECCallback)(void *pContext, NFECBundle *pBundle, int groupAddr,
|
|
int nGoodLines);
|
|
typedef struct ndsp_gcr_str NDSPSigMatch;
|
|
|
|
/* Create a new "DSP state".
|
|
|
|
A separate DSP state should be maintained for each separate
|
|
simultaneous source to the DSP.
|
|
|
|
NDSPStartRetrain() is implicitly called upon creation of a new state.
|
|
|
|
The argument must be NULL or a pointer to sizeof(NDSPState) bytes
|
|
of memory. In the latter case, NDSPStateDestroy will not free this
|
|
memory.
|
|
*/
|
|
|
|
NDSPState *NDSPStateNew(void *mem);
|
|
|
|
/* Destroys the DSP state.
|
|
Automatically disconnects from any FEC state.
|
|
|
|
Returns 0 on success.
|
|
Returns NDSP_ERROR_ILLEGAL_NDSP_STATE if illegal state.
|
|
*/
|
|
|
|
int NDSPStateDestroy(NDSPState *pState);
|
|
|
|
/*
|
|
|
|
Connect the given NFECState and NDSPState
|
|
|
|
For cases where the NDSP and NFEC modules are connected,
|
|
giving pointers to the connected state may result in increased
|
|
robustness and efficiency.
|
|
|
|
Note that only one of
|
|
NDSPStateConnectToFEC or
|
|
NFECStateConnectToDSP
|
|
need be called to connect the two states. (Calling both is OK).
|
|
|
|
Returns 0 on success.
|
|
Returns NDSP_ERROR_ILLEGAL_NDSP_STATE if illegal DSP state.
|
|
|
|
*/
|
|
|
|
int NDSPStateConnectToFEC(NDSPState *pDSPState, NFECState *pFECState);
|
|
|
|
int NFECStateConnectToDSP(NFECState *pFECState, NDSPState *pDSPState);
|
|
|
|
/*
|
|
|
|
Tells the DSP to initiate a "fast retrain". This is useful if you
|
|
suspect that conditions have changed sufficiently to be worth spending
|
|
significant CPU to quickly train on a signal.
|
|
|
|
This should be called when the source of video changes.
|
|
|
|
Returns 0 on success.
|
|
Returns NDSP_ERROR_ILLEGAL_NDSP_STATE if illegal DSP state.
|
|
|
|
*/
|
|
|
|
int NDSPStartRetrain(NDSPState *pState);
|
|
|
|
/*
|
|
* Inputs:
|
|
* pbSamples: pointer to 8-bit raw NABTS samples
|
|
* pState: NDSPState to use for decoding
|
|
* nFECType: Can be set to:
|
|
* NDSP_NO_FEC (don't use FEC information)
|
|
* NDSP_BUNDLE_FEC_1 (use Norpak-style bundle FEC info)
|
|
* NDSP_BUNDLE_FEC_2 (use Wavephore-style bundle FEC info)
|
|
* nFieldNumber:
|
|
* A number that increments by one for each successive field.
|
|
* "Odd" fields (as defined by NTSC) must be odd numbers
|
|
* "Even" fields must be even numbers.
|
|
* nLineNumber:
|
|
* The NTSC line (starting from the top of the field)
|
|
* from which this sample was taken.
|
|
*
|
|
* Outputs:
|
|
* pbDest: decoded data ("NABTS_BYTES_PER_LINE" (36) bytes long)
|
|
* pLineStats: stats on decoded data
|
|
*
|
|
* Errors:
|
|
*
|
|
* Returns 0 if no error
|
|
* Returns NDSP_ERROR_ILLEGAL_NDSP_STATE if state is illegal or uses
|
|
* unsupported settings
|
|
* Returns NDSP_ERROR_ILLEGAL_STATS if stats is passed incorrectly
|
|
*
|
|
* Notes:
|
|
* pbDest must point to a buffer at least 36 bytes long
|
|
* pLineStats->nSize must be set to sizeof(*pLineStats) prior to call
|
|
* (to maintain backwards compatibility should we add fields in the future)
|
|
* pLineStats->nSize will be set to the size actually filled in by
|
|
* the call (the number will stay the same or get smaller)
|
|
* Currently the routine only supports a pState with an FIR filter
|
|
* that has 5 taps
|
|
* nFECType is currently unused, but would potentially be used to give
|
|
* FEC feedback to the DSP decode, for possible tuning and/or retry
|
|
*/
|
|
|
|
int NDSPDecodeLine(unsigned char *pbDest, NDSPLineStats *pLineStats,
|
|
unsigned char *pbSamples, NDSPState *pState,
|
|
int nFECType,
|
|
int nFieldNumber, int nLineNumber,
|
|
KS_VBIINFOHEADER *pVBIINFO);
|
|
|
|
/* typedef'd as NDSPLineStats above */
|
|
struct ndsp_line_stats_str {
|
|
int nSize; /* Should be set to the size of this structure.
|
|
Used to maintain backwards compatibility as we add fields */
|
|
|
|
int nConfidence; /* Set to 0-100 as a measure of expected reliability.
|
|
Low numbers are caused either by a noisy signal, or
|
|
if the line is in fact not NABTS */
|
|
|
|
int nFirstBit; /* The position of the center of
|
|
the first sync bit sample */
|
|
|
|
double dDC; /* the calculated DC offset used to threshold samples.
|
|
This is dependent on the current way we decode NABTS
|
|
and may not be used in the future */
|
|
|
|
};
|
|
|
|
/* typedef'd as NDSPGCRStats above */
|
|
struct ndsp_gcr_stats_str {
|
|
int nSize; /* Should be set to the size of this structure.
|
|
Used to maintain backwards compatibility as we add fields */
|
|
|
|
BOOL bUsed; /* Was this line used by calculations?
|
|
If FALSE, none of the values below are valid. */
|
|
|
|
int nConfidence; /* Set to 0-100 as a measure of expected reliability.
|
|
Low numbers are typically caused by a noisy signal.
|
|
A confidence less than 50 means the algorithm
|
|
decided that this line was far enough from being a
|
|
GCR line that it wasn't used as such */
|
|
};
|
|
|
|
/* Like NDSPDecodeLine, but only decode only from nStart to nEnd bytes.
|
|
By decoding the first 3 bytes (sync), a confidence measure can be made.
|
|
By decoding the next 3 bytes, the group ID can be had.
|
|
*/
|
|
|
|
int NDSPPartialDecodeLine(unsigned char *pbDest, NDSPLineStats *pLineStats,
|
|
unsigned char *pbSamples, NDSPState *pState,
|
|
int nFECType,
|
|
int nFieldNumber, int nLineNumber,
|
|
int nStart, int nEnd,
|
|
KS_VBIINFOHEADER *pVBIINFO);
|
|
|
|
/* Hamming-decode a single byte.
|
|
Useful for decoding group addresses in NABTS data
|
|
|
|
Hamming decoding can fix a one-bit error and detect (but not
|
|
correct) a two-bit error.
|
|
|
|
*nBitErrors is set to the number of detected bit errors in the byte.
|
|
if *nBitErrors is 0 or 1, the hamming-decoded value (from 0 to 15)
|
|
is returned.
|
|
|
|
if *nBitErrors is 2, -1 is returned.
|
|
|
|
*/
|
|
|
|
int NFECHammingDecode(unsigned char bByte, int *nBitErrors);
|
|
|
|
/* Get NABTS group address from NABTS decoded line.
|
|
|
|
*nBitErrors is set to the total number of errors detected in the three
|
|
group address bytes.
|
|
|
|
If address is correctable, *bCorrectable is set to TRUE, and an address
|
|
between 0 and 4095 is returned.
|
|
|
|
If address is not correctable, -1 is returned.
|
|
|
|
This only works for standard, fully NABTS-compliant packets
|
|
*/
|
|
|
|
int NFECGetGroupAddress(NFECState *nState, unsigned char *bData, int *nBitErrors);
|
|
|
|
|
|
/*
|
|
* Conditionally process raw samples from a GCR line and modify
|
|
* the NDSP state accordingly.
|
|
*
|
|
* This routine should be called with the GCR line from each incoming field.
|
|
* (NTSC line 19)
|
|
*
|
|
* Even if the GCR line is known to not be present in the signal, you
|
|
* should call this function once per frame anyway. If no GCR is found,
|
|
* this function will cause an equalization based on the NABTS sync bytes.
|
|
*
|
|
* This routine will not process all lines passed to it. The frequency
|
|
* with which is processes lines depends on the current NDSP state,
|
|
* including whether a fast retrain is currently being performed.
|
|
*
|
|
* Inputs:
|
|
* pbSamples: pointer to 8-bit raw samples
|
|
* pState: NDSPState to use for decoding
|
|
* nFieldNumber:
|
|
* A number that increments by one for each successive field.
|
|
* "Odd" fields (as defined by NTSC) must be odd numbers
|
|
* "Even" fields must be even numbers.
|
|
* nLineNumber:
|
|
* The NTSC line (starting from the top of the field)
|
|
* from which this sample was taken.
|
|
*
|
|
* Outputs:
|
|
* pbDest:
|
|
* pLineStats: stats on decoded data
|
|
* Errors:
|
|
*
|
|
* Returns 0 if no error
|
|
* Returns NDSP_ERROR_ILLEGAL_NDSP_STATE if state is illegal or uses
|
|
* unsupported settings
|
|
* Returns NDSP_ERROR_ILLEGAL_STATS if stats is passed incorrectly
|
|
*
|
|
* Notes:
|
|
* pbDest must point to a buffer at least 36 bytes long
|
|
* pLineStats->nSize must be set to sizeof(*pLineStats) prior to call
|
|
* (to maintain backwards compatibility should we add fields in the future)
|
|
* pLineStats->nSize will be set to the size actually filled in by
|
|
* the call (the number will stay the same or get smaller)
|
|
*/
|
|
|
|
int NDSPProcessGCRLine(NDSPGCRStats *pLineStats,
|
|
unsigned char *pbSamples, NDSPState *pState,
|
|
int nFieldNumber, int nLineNumber,
|
|
KS_VBIINFOHEADER *pVBIINFO);
|
|
|
|
#define NDSP_MAX_FIR_COEFFS 50
|
|
#define NDSP_MAX_FIR_TAIL MAX_NABTS_SAMPLES_PER_LINE
|
|
|
|
struct variable_tap_str {
|
|
int nTapLoc;
|
|
Double dTap;
|
|
};
|
|
|
|
typedef struct fir_filter_str {
|
|
BOOL bVariableTaps;
|
|
int nTaps; /* must be of form 2n+1 if bVariableTaps is zero */
|
|
Double dTapSpacing; /* Only for bVariableTaps = FALSE */
|
|
int nMinTap; /* Only for bVariableTaps = TRUE */
|
|
int nMaxTap; /* Only for bVariableTaps = TRUE */
|
|
Double pdTaps[NDSP_MAX_FIR_COEFFS];
|
|
int pnTapLocs[NDSP_MAX_FIR_COEFFS];
|
|
} FIRFilter;
|
|
|
|
/* typedef'd as NDSPSigMatch above */
|
|
struct ndsp_gcr_str {
|
|
Double dMaxval;
|
|
int nOffset;
|
|
unsigned char pbSamples[MAX_NABTS_SAMPLES_PER_LINE];
|
|
};
|
|
|
|
/* typedef'd as NDSPState above */
|
|
struct ndsp_decoder_str {
|
|
unsigned int uMagic; /* must be set to NDSP_STATE_MAGIC */
|
|
int nRetrainState;
|
|
int nUsingGCR; /* 0 for no GCR, > 0 means using GCR */
|
|
FIRFilter filter;
|
|
/*
|
|
unsigned char pbBestGCRLine[MAX_NABTS_SAMPLES_PER_LINE];
|
|
Double dBestGCRLineVal;
|
|
*/
|
|
|
|
NDSPSigMatch psmPosGCRs[NDSP_SIGS_TO_ACQUIRE];
|
|
NDSPSigMatch psmNegGCRs[NDSP_SIGS_TO_ACQUIRE];
|
|
NDSPSigMatch psmSyncs[NDSP_SIGS_TO_ACQUIRE];
|
|
|
|
BOOL bFreeStateMem;
|
|
|
|
BOOL bUsingScratch1;
|
|
Double pdScratch1[MAX_NABTS_SAMPLES_PER_LINE+NDSP_MAX_FIR_TAIL*2];
|
|
BOOL bUsingScratch2;
|
|
Double pdScratch2[MAX_NABTS_SAMPLES_PER_LINE+NDSP_MAX_FIR_TAIL*2];
|
|
FIRFilter filterScratch3;
|
|
FIRFilter filterGCREqualizeTemplate;
|
|
FIRFilter filterNabsyncEqualizeTemplate;
|
|
BOOL bUsingScratch3;
|
|
Double pdScratch3[NDSP_MAX_FIR_COEFFS*NDSP_MAX_FIR_COEFFS];
|
|
BOOL bUsingScratch4;
|
|
Double pdScratch4[NDSP_MAX_FIR_COEFFS];
|
|
BOOL bUsingScratch5;
|
|
Double pdScratch5[MAX_NABTS_SAMPLES_PER_LINE+NDSP_MAX_FIR_TAIL*2];
|
|
BOOL bUsingScratch6;
|
|
Double pdScratch6[MAX_NABTS_SAMPLES_PER_LINE+NDSP_MAX_FIR_TAIL*2];
|
|
BOOL bUsingScratch7;
|
|
Double pdScratch7[MAX_NABTS_SAMPLES_PER_LINE+NDSP_MAX_FIR_TAIL*2];
|
|
BOOL bUsingScratch8;
|
|
Double pdScratch8[MAX_NABTS_SAMPLES_PER_LINE+NDSP_MAX_FIR_TAIL*2];
|
|
|
|
Double dSampleRate;
|
|
Double dSampleFreq;
|
|
|
|
long SamplesPerLine;
|
|
};
|
|
|
|
/* Create a new "FEC state".
|
|
|
|
A separate FEC state should be maintained for each separate
|
|
simultaneous source to the FEC.
|
|
|
|
Returns NULL on failure (i.e., out of memory).
|
|
*/
|
|
|
|
NFECState *NFECStateNew();
|
|
|
|
|
|
/* Set the sampling rate of a state to a new value */
|
|
int NDSPStateSetSampleRate(NDSPState* pState, unsigned long samp_rate);
|
|
|
|
|
|
/* Destroys the FEC state.
|
|
Automatically disconnects from any DSP state. */
|
|
|
|
void NFECStateDestroy(NFECState *nState);
|
|
|
|
/* Set a list of group addresses to listen to. If pGroupAddrs is NULL,
|
|
then listen to all group addresses. Returns nonzero on success, zero
|
|
on failure. (On failure, the state is not changed.)
|
|
*/
|
|
|
|
int NFECStateSetGroupAddrs(NFECState *pState, int *pGroupAddrs,
|
|
int nGroupAddrs);
|
|
|
|
/* You pass in a line (36 bytes, as received from the DSP), a pointer
|
|
to a NFECLineStats structure, and a callback function (to say what to
|
|
do with the data). The prototype for the callback function is given
|
|
above. The callback is responsible for freeing its pBundle argument. */
|
|
|
|
void NFECDecodeLine(unsigned char *line,
|
|
int confidence,
|
|
NFECState *pState,
|
|
NFECLineStats *pLineStats,
|
|
NFECCallback *cb,
|
|
void *pContext);
|
|
|
|
typedef enum {NFEC_OK, NFEC_GUESS, NFEC_BAD} NFECPacketStatus;
|
|
|
|
typedef enum {NFEC_LINE_OK, NFEC_LINE_CHECKSUM_ERR, NFEC_LINE_CORRUPT} NFECLineStatus;
|
|
|
|
struct nfec_line_stats_str {
|
|
int nSize; /* Should be set to the size of this structure.
|
|
Used to maintain backwards compatibility as we add fields */
|
|
|
|
NFECLineStatus status; /* This will be filled in with the status of
|
|
the passed-in line. The possible values are:
|
|
NFEC_LINE_OK: The line passed all tests; it is
|
|
almost certainly a valid, FEC'd NABTS line.
|
|
NFEC_LINE_CHECKSUM_ERR: We were able to
|
|
munge the line until it looked valid; we're going
|
|
to attempt to make use of this line.
|
|
NFEC_LINE_CORRUPT: We were unable to guess
|
|
how to change this line to make it valid; it
|
|
will be discarded.
|
|
(The statistics here are subject to change.) */
|
|
};
|
|
|
|
typedef struct nfec_packet_str {
|
|
unsigned char data[28]; /* The actual data in this packet. */
|
|
int len; /* The amount of useful data in this packet
|
|
(excluding FEC and filler). Will usually
|
|
be either 0 or 26, but may vary in
|
|
the presence of filler. */
|
|
NFECPacketStatus status; /* The status of this packet; some indication
|
|
of whether the packet is valid. (This
|
|
is subject to change.) */
|
|
#ifdef DEBUG_FEC
|
|
unsigned char line;
|
|
unsigned long frame;
|
|
#endif //DEBUG_FEC
|
|
} NFECPacket;
|
|
|
|
/* typedef'd as NFECBundle above */
|
|
struct nfec_bundle_str {
|
|
NFECPacket packets[16];
|
|
int nBitErrors; /* The number of bits changed by the FEC
|
|
in this bundle (not counting bits
|
|
corrected in missing lines). */
|
|
int lineConfAvg; /* Average of all line confidences presented */
|
|
};
|
|
|
|
/* Flushes any remaining data from the FEC state (i.e. unfinished
|
|
bundles). Calls "cb" with any data returned */
|
|
|
|
void NFECStateFlush(NFECState *pState, NFECCallback *cb, void *pContext);
|
|
|
|
/* Garbage collect streams. If you want to time out bundles,
|
|
* call NFECGarbageCollect() every field.
|
|
*/
|
|
void NFECGarbageCollect(NFECState *pState, NFECCallback *cb, void *pContext);
|
|
|
|
#ifdef __cplusplus
|
|
} // end - extern "C"
|
|
#endif /*__cplusplus*/
|
|
|
|
#endif /*NABTSAPI_H*/
|