186 lines
5.2 KiB
C++
186 lines
5.2 KiB
C++
/**********************************************************************
|
|
Copyright (c) 1994 - 1997 Microsoft Corporation. All Rights Reserved.
|
|
|
|
VITCDecode, Ken Greenebaum / David Maymudes, November 1996
|
|
|
|
A generic vertical interval timecode decoder. Pass it 8 bit video lines
|
|
samples and it will decode the VITC timecode encoded therein.
|
|
|
|
This code based on the VITC description in John Ratcliff's Timecode; A user's
|
|
guide (second edition)
|
|
**********************************************************************/
|
|
#include <stdio.h>
|
|
#include <wtypes.h>
|
|
#include "vtcdcode.h"
|
|
|
|
|
|
/**********************************************************************
|
|
helper function to decode raw VITC bits found in the bit buffer
|
|
**********************************************************************/
|
|
int
|
|
compute(int bitNumber, int numBits, int bits[])
|
|
{
|
|
int value = 0;
|
|
int count;
|
|
int index;
|
|
|
|
index = bitNumber;
|
|
for(count = 0; count < numBits; count++) {
|
|
value+= bits[index] << count;
|
|
index = (index+1);
|
|
}
|
|
|
|
return(value);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
initialize internal state
|
|
**********************************************************************/
|
|
VITCdecoder::VITCdecoder()
|
|
{
|
|
// values to reset
|
|
_validTimeCode = 0; // no, we don't have a valid timecode, yet
|
|
|
|
// should scan buffer for these
|
|
// !!! completely arbitrary!
|
|
_low = 80;
|
|
_high = 120;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
Decode and return the user bits from the raw VITC decoded bits in the
|
|
ring buffer.
|
|
|
|
Returns True if there is a valid timecode in the ring buffer
|
|
|
|
In general this is only true immediately after the decode method returns
|
|
a non-zero timecode sample sync
|
|
**********************************************************************/
|
|
int
|
|
VITCdecoder::getUserBits(VITCuserBits *bits)
|
|
{
|
|
if(_validTimeCode) { // verify that valid timecode is in buffer
|
|
bits->user1 = compute( 6, 4, _bits);
|
|
bits->user2 = compute(16, 4, _bits);
|
|
bits->user3 = compute(26, 4, _bits);
|
|
bits->user4 = compute(36, 4, _bits);
|
|
bits->user5 = compute(46, 4, _bits);
|
|
bits->user6 = compute(56, 4, _bits);
|
|
bits->user7 = compute(66, 4, _bits);
|
|
bits->user8 = compute(76, 4, _bits);
|
|
}
|
|
return(_validTimeCode);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
Decode and return the TimeCode from the raw VITC decoded bits.
|
|
|
|
Returns True if there is a valid timecode,,
|
|
|
|
In general this is only true immediately after the decode method returns
|
|
a non-zero timecode sample sync
|
|
|
|
**********************************************************************/
|
|
int
|
|
VITCdecoder::getTimeCode(TimeCode *tc)
|
|
{
|
|
if(_validTimeCode) { // verify that valid timecode is in buffer
|
|
int hour, minute, second, frame;
|
|
|
|
frame = compute( 2, 4, _bits); // frame units 0-3 1,2,4,8
|
|
frame += 10*compute(12, 2, _bits); // frame tens 0-1 1,2
|
|
|
|
second = compute(22, 4, _bits);
|
|
second+= 10*compute(32, 3, _bits);
|
|
|
|
minute = compute(42, 4, _bits);
|
|
minute+= 10*compute(52, 3, _bits);
|
|
|
|
hour = compute(62, 4, _bits);
|
|
hour += 10*compute(72, 2, _bits);
|
|
|
|
tc->SetTime(hour, minute, second, frame); // XXX for now
|
|
}
|
|
return(_validTimeCode);
|
|
}
|
|
|
|
|
|
// !!! really this should be adaptive, by looking for the first bit transition.
|
|
|
|
// this formula found by looking at VITC data from one tape on a BT-848, I found that
|
|
// bits took 1/96th of a line, starting at 3.5/96ths in.
|
|
int bitStart(int bit, int lineWidth)
|
|
{
|
|
return (lineWidth * (bit + 3) + lineWidth / 2) / 96;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
Accept a new line of video, decode the bits present in it, and return
|
|
whether a timeCode was completed being decoded.
|
|
**********************************************************************/
|
|
int
|
|
VITCdecoder::decodeBuffer(BYTE *buf, int bufferSize)
|
|
{
|
|
int bit;
|
|
int badbits = 0;
|
|
|
|
int startPos = bitStart(0, bufferSize);
|
|
|
|
for (bit = 0; bit < 90; bit++) {
|
|
int endPos = bitStart(bit+1, bufferSize);
|
|
|
|
// !!! arbitrarily don't look at first/last two pixels so as to avoid
|
|
// edges of bits
|
|
int len = endPos - startPos - 4;
|
|
DWORD total = 0;
|
|
for (int pos = startPos+2; pos < endPos-2; pos++) {
|
|
total += (DWORD) buf[pos];
|
|
}
|
|
|
|
// printf("bit %d: %d (%d-%d)\n", bit, total / len, startPos, endPos);
|
|
if (total < _low * len) {
|
|
// record 0
|
|
_bits[bit] = 0;
|
|
} else if (total > _high * len) {
|
|
// record 1
|
|
_bits[bit] = 1;
|
|
} else {
|
|
// record error
|
|
_bits[bit] = -1;
|
|
badbits++;
|
|
}
|
|
startPos = endPos;
|
|
|
|
|
|
|
|
// !!! should terminate loop immediately if there's a problem to save time
|
|
}
|
|
|
|
// printf("%d bad bits\n", badbits);
|
|
|
|
_validTimeCode = (badbits == 0);
|
|
|
|
// check sync bits
|
|
if (badbits == 0) {
|
|
for (bit = 0; bit < 90; bit += 10) {
|
|
if (_bits[bit] != 1) {
|
|
// printf("bit %d should be 1\n", bit);
|
|
_validTimeCode = 0;
|
|
}
|
|
|
|
if (_bits[bit+1] != 0) {
|
|
// printf("bit %d should be 0\n", bit+1);
|
|
_validTimeCode = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// !!! should also check CRC in last few bits
|
|
|
|
return _validTimeCode;
|
|
}
|