windows-nt/Source/XPSP1/NT/multimedia/dshow/timecode/vtcdcode.cpp
2020-09-26 16:20:57 +08:00

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;
}