318 lines
15 KiB
C
318 lines
15 KiB
C
|
/* SPDX-License-Identifier: MIT */
|
||
|
/**
|
||
|
@file ancillarydata_timecode.h
|
||
|
@brief Declares the AJAAncillaryData_Timecode class.
|
||
|
@copyright (C) 2010-2021 AJA Video Systems, Inc.
|
||
|
**/
|
||
|
|
||
|
#ifndef AJA_ANCILLARYDATA_TIMECODE_H
|
||
|
#define AJA_ANCILLARYDATA_TIMECODE_H
|
||
|
|
||
|
#include "ajabase/common/timecode.h"
|
||
|
#include "ajabase/common/timebase.h"
|
||
|
#include "ancillarydatafactory.h"
|
||
|
#include "ancillarydata.h"
|
||
|
|
||
|
|
||
|
enum AJAAncillaryData_Timecode_Format
|
||
|
{
|
||
|
AJAAncillaryData_Timecode_Format_Unknown, // not set (usually defaults to 30 fps)
|
||
|
|
||
|
AJAAncillaryData_Timecode_Format_60fps, // 60/59.94 fps format ("NTSC")
|
||
|
AJAAncillaryData_Timecode_Format_50fps, // 50 fps format ("PAL")
|
||
|
AJAAncillaryData_Timecode_Format_48fps, // 48/47.95 fps format
|
||
|
AJAAncillaryData_Timecode_Format_30fps, // 30/29.97 fps format ("NTSC")
|
||
|
AJAAncillaryData_Timecode_Format_25fps, // 25 fps format ("PAL")
|
||
|
AJAAncillaryData_Timecode_Format_24fps // 24/23.98 fps format
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief This is the base class for the AJAAncillaryData_Timecode_ATC and AJAAncillaryData_Timecode_VITC
|
||
|
classes, because they share the same "payload" data (i.e. timecode) and only differ in the transport
|
||
|
(ancillary packets vs. "analog" coding).
|
||
|
@note Do not instantiate a "pure" AJAAncillaryData_Timecode object. Always use the subclasses.
|
||
|
**/
|
||
|
class AJAExport AJAAncillaryData_Timecode : public AJAAncillaryData
|
||
|
{
|
||
|
public:
|
||
|
AJAAncillaryData_Timecode ();
|
||
|
AJAAncillaryData_Timecode (const AJAAncillaryData_Timecode & inClone);
|
||
|
AJAAncillaryData_Timecode (const AJAAncillaryData_Timecode * pClone);
|
||
|
AJAAncillaryData_Timecode (const AJAAncillaryData *pData);
|
||
|
|
||
|
virtual inline ~AJAAncillaryData_Timecode () {}
|
||
|
|
||
|
virtual void Clear (void); ///< @brief Frees my allocated memory, if any, and resets my members to their default values.
|
||
|
|
||
|
/**
|
||
|
@brief Assignment operator -- replaces my contents with the right-hand-side value.
|
||
|
@param[in] inRHS The value to be assigned to me.
|
||
|
@return A reference to myself.
|
||
|
**/
|
||
|
virtual AJAAncillaryData_Timecode & operator = (const AJAAncillaryData_Timecode & inRHS);
|
||
|
|
||
|
virtual inline AJAAncillaryData_Timecode * Clone (void) const {return new AJAAncillaryData_Timecode (this);} ///< @return A clone of myself.
|
||
|
|
||
|
/**
|
||
|
@brief Parses out (interprets) the "local" ancillary data from my payload data.
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus ParsePayloadData (void);
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief Generate the payload data from the "local" ancillary data.
|
||
|
@note This method is overridden for the specific Anc data type.
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus GeneratePayloadData (void) {return AJA_STATUS_SUCCESS;}
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief Sets my raw "time" hex values.
|
||
|
@param[in] inDigitNum Specifies the index (0-7) of time digits in "transmission" order:
|
||
|
0 = 1st (frame units) digit, 1 = 2nd digit, ... 7 = last (hour tens) digit.
|
||
|
@param[in] inHexValue Specifies the hex value (least significant 4 bits) to be set.
|
||
|
@param[in] inMask Optionally specifies which bits to set: (1 = set bit to new value, 0 = retain current bit value).
|
||
|
Defaults to 0x0F.
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetTimeHexValue (const uint8_t inDigitNum, const uint8_t inHexValue, const uint8_t inMask = 0x0f);
|
||
|
|
||
|
/**
|
||
|
@brief Answers with my current raw "time" hex values.
|
||
|
@param[in] inDigitNum Specifies the index (0-7) of the time digit of interest, in "transmission" order:
|
||
|
0 = 1st (frame units) digit, 1 = 2nd digit, ... 7 = last (hour tens) digit.
|
||
|
@param[out] outHexValue Receives the hex value (least significant 4 bits) to be set.
|
||
|
@param[in] inMask Optionally specifies which bits to receive: (1 = set bit to new value, 0 = retain current bit value).
|
||
|
Defaults to 0x0F.
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus GetTimeHexValue (uint8_t inDigitNum, uint8_t & outHexValue, uint8_t inMask = 0x0f) const;
|
||
|
|
||
|
/**
|
||
|
@brief Sets my timecode "time" using discrete BCD digits.
|
||
|
@param[in] inHourTens Specifies the hours "tens" digit value.
|
||
|
@param[in] inHourOnes Specifies the hours "ones" digit value.
|
||
|
@param[in] inMinTens Specifies the minutes "tens" digit value.
|
||
|
@param[in] inMinOnes Specifies the minutes "ones" digit value.
|
||
|
@param[in] inSecsTens Specifies the seconds "tens" digit value.
|
||
|
@param[in] inSecsOnes Specifies the seconds "ones" digit value.
|
||
|
@param[in] inFrameTens Specifies the frame "tens" digit value.
|
||
|
@param[in] inFrameOnes Specifies the frame "ones" digit value.
|
||
|
@note Each digit is masked to the number of bits allotted in the payload. Note that the digit order is reversed!
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetTimeDigits ( const uint8_t inHourTens, const uint8_t inHourOnes,
|
||
|
const uint8_t inMinTens, const uint8_t inMinOnes,
|
||
|
const uint8_t inSecsTens, const uint8_t inSecsOnes,
|
||
|
const uint8_t inFrameTens, const uint8_t inFrameOnes);
|
||
|
|
||
|
/**
|
||
|
@brief Answers with my current timecode "time" as discrete BCD digits.
|
||
|
@param[out] outHourTens Specifies the hours "tens" digit value.
|
||
|
@param[out] outHourOnes Specifies the hours "ones" digit value.
|
||
|
@param[out] outMinTens Specifies the minutes "tens" digit value.
|
||
|
@param[out] outMinOnes Specifies the minutes "ones" digit value.
|
||
|
@param[out] outSecsTens Specifies the seconds "tens" digit value.
|
||
|
@param[out] outSecsOnes Specifies the seconds "ones" digit value.
|
||
|
@param[out] outFrameTens Specifies the frame "tens" digit value.
|
||
|
@param[out] outFrameOnes Specifies the frame "ones" digit value.
|
||
|
@note Each digit is masked to the number of bits allotted in the payload. Note that the digit order is reversed!
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus GetTimeDigits ( uint8_t & outHourTens, uint8_t & outHourOnes,
|
||
|
uint8_t & outMinTens, uint8_t & outMinOnes,
|
||
|
uint8_t & outSecsTens, uint8_t & outSecsOnes,
|
||
|
uint8_t & outFrameTens, uint8_t & outFrameOnes) const;
|
||
|
|
||
|
/**
|
||
|
@brief Sets my timecode "time" with hours, minutes, seconds, frames (in decimal, not BCD digits).
|
||
|
@param[in] inFormat Specifies a valid AJAAncillaryData_Timecode_Format.
|
||
|
@param[in] inHours Specifies the hours value, which must be less than 24.
|
||
|
@param[in] inMinutes Specifies the minutes value, which must be less than 60.
|
||
|
@param[in] inSeconds Specifies the seconds value, which must be less than 60.
|
||
|
@param[in] inFrames Specifies the frame value, which must be less than the frame rate.
|
||
|
@note This method takes into account the "FieldID" bit for HFR timecode formats (e.g. p50, p59.94, p60, etc.).
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetTime (const AJAAncillaryData_Timecode_Format inFormat, const uint32_t inHours,
|
||
|
const uint32_t inMinutes, const uint32_t inSeconds, const uint32_t inFrames);
|
||
|
|
||
|
/**
|
||
|
@brief Answers with my current timecode "time" as individual hour, minute, second, and frame components (in decimal, not BCD digits).
|
||
|
@param[in] inFormat Specifies a valid AJAAncillaryData_Timecode_Format.
|
||
|
@param[out] outHours Receives the hours value.
|
||
|
@param[out] outMinutes Receives the minutes value.
|
||
|
@param[out] outSeconds Receives the seconds value.
|
||
|
@param[out] outFrames Receives the frame value.
|
||
|
@note This method takes into account the "FieldID" bit for HFR timecode formats (e.g. p50, p59.94, p60, etc.).
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus GetTime (const AJAAncillaryData_Timecode_Format inFormat, uint32_t & outHours,
|
||
|
uint32_t & outMinutes, uint32_t & outSeconds, uint32_t & outFrames) const;
|
||
|
|
||
|
/**
|
||
|
@brief Sets my timecode "time" from an AJATimeCode.
|
||
|
@param[in] inTimecode Specifies the timecode.
|
||
|
@param[in] inTimeBase Specifies the time base (frame rate) associated with the specified timecode.
|
||
|
@param[in] inIsDropFrame Specify 'true' for dropframe; otherwise false.
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetTimecode (const AJATimeCode & inTimecode, const AJATimeBase & inTimeBase, const bool inIsDropFrame);
|
||
|
|
||
|
/**
|
||
|
@brief Answers with my timecode "time" as an AJATimeCode.
|
||
|
@param[out] outTimecode Receives the timecode.
|
||
|
@param[out] outTimeBase Receives the time base (frame rate).
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus GetTimecode (AJATimeCode & outTimecode, AJATimeBase & outTimeBase) const;
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief Sets my raw "Binary Group" hex values.
|
||
|
@param[in] digitNum the index (0 - 7) of the Binary Group value in "transmission" order, i.e. 0 = 1st (BG1) digit, 1 = 2nd digit, ..., 7 = last (BG7) digit
|
||
|
@param[in] hexValue the hex value (ls 4 bits) to be set/get
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetBinaryGroupHexValue (uint8_t digitNum, uint8_t hexValue, uint8_t mask = 0x0f);
|
||
|
virtual AJAStatus GetBinaryGroupHexValue (uint8_t digitNum, uint8_t& hexValue, uint8_t mask = 0x0f) const;
|
||
|
|
||
|
/**
|
||
|
@brief Sets my binary group values.
|
||
|
@param[in] bg8 binary group values (only the ls 4 bits of each value are retained) - note that the BG order is reversed!)
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetBinaryGroups (uint8_t bg8, uint8_t bg7, uint8_t bg6, uint8_t bg5, uint8_t bg4, uint8_t bg3, uint8_t bg2, uint8_t bg1);
|
||
|
virtual AJAStatus GetBinaryGroups (uint8_t& bg8, uint8_t& bg7, uint8_t& bg6, uint8_t& bg5, uint8_t& bg4, uint8_t& bg3, uint8_t& bg2, uint8_t& bg1) const;
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief Sets my FieldID flag.
|
||
|
@param[in] bFlag false = field 1 (0), true = field 2 (1)
|
||
|
@param[in] tcFmt AJAAncillaryData_Timecode_Format associated with timecode (default is handled as 30-frame timecode).
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetFieldIdFlag (bool bFlag, AJAAncillaryData_Timecode_Format tcFmt = AJAAncillaryData_Timecode_Format_Unknown);
|
||
|
virtual AJAStatus GetFieldIdFlag (bool& bFlag, AJAAncillaryData_Timecode_Format tcFmt = AJAAncillaryData_Timecode_Format_Unknown) const;
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief Sets my drop frame flag.
|
||
|
@param[in] bFlag false = non-dropframe format, true = drop frame
|
||
|
@param[in] tcFmt AJAAncillaryData_Timecode_Format associated with timecode (default is handled as 30-frame timecode).
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetDropFrameFlag (bool bFlag, AJAAncillaryData_Timecode_Format tcFmt = AJAAncillaryData_Timecode_Format_Unknown);
|
||
|
virtual AJAStatus GetDropFrameFlag (bool& bFlag, AJAAncillaryData_Timecode_Format tcFmt = AJAAncillaryData_Timecode_Format_Unknown) const;
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief Sets my color frame flag.
|
||
|
@param[in] bFlag false = no relation between color frames and timecode values, true = timecode values are aligned with color frames (see SMPTE-12M).
|
||
|
@param[in] tcFmt AJAAncillaryData_Timecode_Format associated with timecode (default is handled as 30-frame timecode).
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetColorFrameFlag (bool bFlag, AJAAncillaryData_Timecode_Format tcFmt = AJAAncillaryData_Timecode_Format_Unknown);
|
||
|
virtual AJAStatus GetColorFrameFlag (bool& bFlag, AJAAncillaryData_Timecode_Format tcFmt = AJAAncillaryData_Timecode_Format_Unknown) const;
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief Sets my binary group flag (3 bits).
|
||
|
@param[in] inBGFlag Specifies the BG Flag value (only the least significant 3 bits are retained).
|
||
|
@param[in] inFormat Specifies the timecode format associated with timecode (default is handled as 30-frame timecode).
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus SetBinaryGroupFlag (const uint8_t inBGFlag, const AJAAncillaryData_Timecode_Format inFormat = AJAAncillaryData_Timecode_Format_Unknown);
|
||
|
|
||
|
/**
|
||
|
@brief Answers with my current binary group flag (3 bits).
|
||
|
@param[out] outBGFlag Specifies the BG Flag value (only the least significant 3 bits are retained).
|
||
|
@param[in] inFormat Specifies the timecode format associated with timecode (default is handled as 30-frame timecode).
|
||
|
@return AJA_STATUS_SUCCESS if successful.
|
||
|
**/
|
||
|
virtual AJAStatus GetBinaryGroupFlag (uint8_t & outBGFlag, const AJAAncillaryData_Timecode_Format inFormat = AJAAncillaryData_Timecode_Format_Unknown) const;
|
||
|
|
||
|
/**
|
||
|
@param[in] pInAncData A valid pointer to an AJAAncillaryData instance.
|
||
|
@return The AJAAncillaryDataType if I recognize this ancillary data (or unknown if unrecognized).
|
||
|
**/
|
||
|
static AJAAncillaryDataType RecognizeThisAncillaryData (const AJAAncillaryData * pInAncData);
|
||
|
|
||
|
/**
|
||
|
@brief Streams a human-readable representation of me to the given output stream.
|
||
|
@param inOutStream Specifies the output stream.
|
||
|
@param[in] inDetailed Specify 'true' for a detailed representation; otherwise use 'false' for a brief one.
|
||
|
@return The given output stream.
|
||
|
**/
|
||
|
virtual std::ostream & Print (std::ostream & inOutStream, const bool inDetailed = false) const;
|
||
|
|
||
|
/**
|
||
|
@return A string containing my human-readable timecode.
|
||
|
**/
|
||
|
virtual std::string TimecodeString (void) const;
|
||
|
|
||
|
/**
|
||
|
@brief Get the timecode format that matches the input timebase.
|
||
|
@param[in] inTimeBase Specifies the time base (frame rate) associated with the specified timecode.
|
||
|
@return The AJAAncillaryData_Timecode_Format that corresponds to the input timebase, returns AJAAncillaryData_Timecode_Format_Unknown when no match found.
|
||
|
**/
|
||
|
static AJAAncillaryData_Timecode_Format GetTimecodeFormatFromTimeBase (const AJATimeBase & inTimeBase);
|
||
|
|
||
|
protected:
|
||
|
void Init (void); // NOT virtual - called by constructors
|
||
|
|
||
|
// Which timecode digits go in which elements of timeDigits[]
|
||
|
// Note that this is the same order as received/transmitted, i.e. ls digits FIRST!
|
||
|
enum
|
||
|
{
|
||
|
kTcFrameUnits = 0,
|
||
|
kTcFrameTens = 1,
|
||
|
kTcSecondUnits = 2,
|
||
|
kTcSecondTens = 3,
|
||
|
kTcMinuteUnits = 4,
|
||
|
kTcMinuteTens = 5,
|
||
|
kTcHourUnits = 6,
|
||
|
kTcHourTens = 7,
|
||
|
kNumTimeDigits = 8
|
||
|
};
|
||
|
|
||
|
// Which binary groups go in which elements of binaryGroup[]?
|
||
|
// Note that this is the same order as received/transmitted, i.e. ls digits FIRST!
|
||
|
enum
|
||
|
{
|
||
|
kBg1 = 0,
|
||
|
kBg2 = 1,
|
||
|
kBg3 = 2,
|
||
|
kBg4 = 3,
|
||
|
kBg5 = 4,
|
||
|
kBg6 = 5,
|
||
|
kBg7 = 6,
|
||
|
kBg8 = 7,
|
||
|
kNumBinaryGroups = 8
|
||
|
};
|
||
|
|
||
|
// Note: if you make a change to the local member data, be sure to ALSO make the appropriate
|
||
|
// changes in the Init() and operator= methods!
|
||
|
|
||
|
// The timecode data is stored as "raw" hex nibbles of data, split up between "time" values and "binary group" values.
|
||
|
// This means that sundry "flags" which take advantage of unused time bits (e.g. bits 2 and 3 of the hour tens digit)
|
||
|
// are kept with the hex digit data, and only parsed in or out by the appropriate Set()/Get() methods.
|
||
|
uint8_t m_timeDigits[kNumTimeDigits]; // the 8 hex values of the time data, in order of received/transmitted (i.e. ls digits first)
|
||
|
uint8_t m_binaryGroup[kNumBinaryGroups]; // the 8 hex values of the "Binary Groups", in order from BG1 - BG8
|
||
|
|
||
|
}; // AJAAncillaryData_Timecode
|
||
|
|
||
|
|
||
|
/**
|
||
|
@brief Writes a human-readable rendition of the given AJAAncillaryData_Timecode into the given output stream.
|
||
|
@param inOutStream Specifies the output stream to be written.
|
||
|
@param[in] inAncData Specifies the AJAAncillaryData_Timecode to be rendered into the output stream.
|
||
|
@return A non-constant reference to the specified output stream.
|
||
|
**/
|
||
|
inline std::ostream & operator << (std::ostream & inOutStream, const AJAAncillaryData_Timecode & inAncData) {return inAncData.Print (inOutStream);}
|
||
|
|
||
|
#endif // AJA_ANCILLARYDATA_TIMECODE_H
|