Go to the documentation of this file.
37 #define LOC ((m_tvrec) ? \
38 QString("DTVRec[%1]: ").arg(m_tvrec->GetInputId()) : \
39 QString("DTVRec(0x%1): ").arg(intptr_t(this),0,16))
93 if (name ==
"recordingtype")
104 if (name ==
"wait_for_seqstart")
106 else if (name ==
"recordmpts")
113 const QString &videodev,
114 const QString& ,
const QString& )
142 LOG(VB_RECORD, LOG_INFO,
LOC +
"ResetForNewFile(void)");
206 LOG(VB_RECORD, LOG_INFO,
LOC +
"Reset(void)");
245 if (atsc && atsc->DesiredMinorChannel())
248 atsc->DesiredMinorChannel());
282 int interval = thresh;
286 .fetchAndStoreRelaxed(thresh * 4 / 5);
291 .fetchAndStoreRelaxed(thresh * 9 / 8);
297 LOG(VB_RECORD, LOG_DEBUG,
LOC +
298 QString(
"Updating timeOfLatestData elapsed(%1) interval(%2)")
299 .arg(elapsed.count()).arg(interval));
324 LOG(VB_GENERAL, LOG_INFO,
LOC +
325 QString(
"BufferedWrite: Writes are failing, "
326 "setting status to %1")
334 const uint8_t *bufptr,
int bytes_left,
int pts_or_dts)
339 bool has_pts = (bufptr[3] & 0x80) != 0;
341 if (((
kExtractPTS == pts_or_dts) && !has_pts) || (offset + 5 > bytes_left))
344 bool has_dts = (bufptr[3] & 0x40) != 0;
349 offset += has_pts ? 5 : 0;
350 if (offset + 5 > bytes_left)
354 return ((uint64_t(bufptr[offset+0] & 0x0e) << 29) |
355 (uint64_t(bufptr[offset+1] ) << 22) |
356 (uint64_t(bufptr[offset+2] & 0xfe) << 14) |
357 (uint64_t(bufptr[offset+3] ) << 7) |
358 (uint64_t(bufptr[offset+4] & 0xfe) >> 1));
362 uint64_t
pts, uint64_t pts_first,
const QDateTime &pts_first_dt)
365 pts += 0x1FFFFFFFFLL;
366 const QDateTime& dt = pts_first_dt;
367 return dt.addMSecs((
pts - pts_first)/90);
421 bool hasFrame =
false;
422 bool hasKeyFrame =
false;
424 uint aspectRatio = 0;
436 const uint8_t *bufptr = tspacket->
data() + tspacket->
AFCOffset();
440 while (bufptr < bufend)
443 int bytes_left = bufend - bufptr;
468 aspectRatio = (bufptr[3] >> 4);
471 height = ((bufptr[1] & 0xf) << 8) | bufptr[2];
472 width = (bufptr[0] <<4) | (bufptr[1]>>4);
480 int ext_type = (bufptr[0] >> 4);
492 int picture_structure = bufptr[2] & 3;
493 int top_field_first = bufptr[3] & (1 << 7);
494 int repeat_first_field = bufptr[3] & (1 << 1);
495 int progressive_frame = bufptr[4] & (1 << 7);
497 LOG(VB_RECORD, LOG_DEBUG,
LOC +
498 QString(
"picture_coding_extension(): (m_progressiveSequence: %1) picture_structure: %2 top_field_first: %3 repeat_first_field: %4 progressive_frame: %5")
500 QString::number(picture_structure , 2),
501 QString::number(top_field_first , 2),
502 QString::number(repeat_first_field , 2),
503 QString::number(progressive_frame , 2)
509 if (picture_structure == 0b00)
513 else if (picture_structure == 0b11)
518 else if (picture_structure < 0b11)
523 if (top_field_first != 0)
525 hasFrame = (picture_structure == 0b01);
529 hasFrame = (picture_structure == 0b10);
536 if (repeat_first_field)
545 else if (progressive_frame)
574 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Music Choice program detected");
580 if (hasFrame && !hasKeyFrame)
594 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString
595 (
"Keyframe @ %1 + %2 = %3")
606 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString
607 (
"Frame @ %1 + %2 = %3")
640 LOG(VB_RECORD, LOG_INFO,
LOC +
641 QString(
"FindMPEG2Keyframes: frame rate = %1")
661 LOG(VB_RECORD, LOG_DEBUG,
662 "Switching from dts tracking to pts tracking." +
663 QString(
"TS count is %1").arg(
m_tsCount[stream_id]));
667 int64_t gap_threshold = 90000;
671 gap_threshold = 2*90000LL;
675 gap_threshold = 8*90000LL;
679 int64_t diff = ts -
m_tsLast[stream_id];
682 if (diff < (10 * -90000LL))
684 diff += 0x1ffffffffLL;
701 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"Inserted gap %1 dur %2")
709 LOG(VB_GENERAL, LOG_INFO,
LOC +
710 QString(
"HandleTimestamps: too much damage, "
711 "setting status to %1")
753 LOG(VB_RECORD, LOG_DEBUG,
754 QString(
"count=%1 m_frameRate=%2 tick_frameRate=%3 "
755 "tick_cnt=%4 tick_base=%5 _total_dur=%6")
767 bool hasKeyFrame =
false;
771 static constexpr uint64_t kMsecPerDay { 24ULL * 60 * 60 * 1000 };
773 uint64_t elapsed = 0;
776 auto expected_frame = (uint64_t) ((
double)elapsed / frame_interval);
779 expected_frame += (uint64_t) ((
double)kMsecPerDay / frame_interval);
813 LOG(VB_RECORD, LOG_INFO,
LOC +
"DSMCC - FindOtherKeyframes() - "
814 "generating initial key-frame");
878 LOG(VB_GENERAL, LOG_ERR,
LOC +
"FindH2645Keyframes: No ringbuffer");
884 LOG(VB_GENERAL, LOG_ERR,
LOC +
"FindH2645Keyframes: m_h2645Parser not present");
896 uint aspectRatio = 0;
902 bool hasFrame =
false;
903 bool hasKeyFrame =
false;
915 LOG(VB_GENERAL, LOG_ERR,
LOC +
916 "PES packet start code may overflow to next TS packet, "
917 "aborting keyframe search");
922 if (tspacket->
data()[i ] != 0x00 ||
923 tspacket->
data()[i+1] != 0x00 ||
924 tspacket->
data()[i+2] != 0x01)
929 LOG(VB_GENERAL, LOG_ERR,
LOC +
930 "PES start code not found in TS packet with PUSI set");
941 LOG(VB_GENERAL, LOG_ERR,
LOC +
942 "PES packet headers overflow to next TS packet, "
943 "aborting keyframe search");
953 const unsigned char pes_header_length = tspacket->
data()[i + 5];
958 LOG(VB_GENERAL, LOG_ERR,
LOC +
959 "PES packet headers overflow to next TS packet, "
960 "aborting keyframe search");
967 i += 5 + pes_header_length;
971 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"PES synced");
983 i += (bytes_used - 1);
1005 if (hasFrame && !hasKeyFrame &&
1009 LOG(VB_RECORD, LOG_WARNING,
LOC +
1010 QString(
"FindH2645Keyframes: %1 frames without a keyframe.")
1017 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString
1018 (
"Keyframe @ %1 + %2 = %3 AU %4")
1030 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString
1031 (
"Frame @ %1 + %2 = %3 AU %4")
1064 LOG(VB_RECORD, LOG_INFO,
LOC +
1065 QString(
"FindH2645Keyframes: timescale: %1, tick: %2, framerate: %3")
1068 .arg( frameRate.
toDouble() * 1000 ) );
1075 LOG(VB_RECORD, LOG_INFO,
LOC +
1076 QString(
"FindH2645Keyframes: scan type: %1")
1078 "Interlaced" :
"Progressive"));
1095 uint64_t startpos = 0;
1125 const uint8_t *bufstart = buffer;
1126 const uint8_t *bufptr = buffer;
1127 const uint8_t *bufend = buffer + len;
1129 uint aspectRatio = 0;
1135 while (bufptr + skip < bufend)
1137 bool hasFrame =
false;
1138 bool hasKeyFrame =
false;
1140 const uint8_t *
tmp = bufptr;
1152 int pes_packet_length = -1;
1153 if ((bufend - bufptr) >= 2)
1154 pes_packet_length = ((bufptr[0]<<8) | bufptr[1]) + 2 + 6;
1161 pes_packet_length = -1;
1162 if (bufend-bufptr >= 4)
1164 uint frmtypei = (bufptr[1]>>3) & 0x7;
1165 if ((1 <= frmtypei) && (frmtypei <= 5))
1175 pes_packet_length = -1;
1181 pes_packet_length = -1;
1186 aspectRatio = (bufptr[3] >> 4);
1189 height = ((bufptr[1] & 0xf) << 8) | bufptr[2];
1190 width = (bufptr[0] <<4) | (bufptr[1]>>4);
1216 if (hasFrame && !hasKeyFrame)
1246 if (height && width &&
1257 LOG(VB_RECORD, LOG_INFO,
LOC +
1258 QString(
"FindPSKeyFrames: frame rate = %1")
1259 .arg(frameRate.
toDouble() * 1000));
1263 if (hasKeyFrame || hasFrame)
1286 int bytes_skipped = bufend - bufptr;
1287 if (bytes_skipped > 0)
1298 uint64_t rem = (bufend - bufstart);
1302 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
1303 QString(
"idx: %1, rem: %2").arg(idx).arg(rem));
1311 LOG(VB_RECORD, LOG_ERR,
LOC +
"SetPAT(NULL)");
1326 int oldProgNum = progNum;
1328 LOG(VB_GENERAL, LOG_INFO,
LOC +
1329 QString(
"Update desired program found in SPTS PAT from %1 to %2")
1330 .arg(oldProgNum).arg(progNum));
1332 pmtpid = _pat->
FindPID(progNum);
1337 LOG(VB_RECORD, LOG_ERR,
LOC +
1338 QString(
"SetPAT(): Ignoring PAT not containing our desired "
1339 "program (%1)...").arg(progNum));
1343 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"SetPAT(%1 on pid 0x%2)")
1344 .arg(progNum).arg(pmtpid,0,16));
1363 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"SetPMT(%1, %2)").arg(progNum)
1364 .arg(_pmt ==
nullptr ?
"NULL" :
"valid"));
1369 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"SetPMT(%1)").arg(progNum));
1375 bool has_no_av =
true;
1393 LOG(VB_RECORD, LOG_ERR,
LOC +
"HandleSingleProgramPAT(NULL)");
1412 LOG(VB_RECORD, LOG_ERR,
LOC +
"HandleSingleProgramPMT(NULL)");
1419 uint bestAudioCodec = 0;
1449 if (avcParser !=
nullptr)
1458 LOG(VB_GENERAL, LOG_INFO,
LOC +
"HEVC detected");
1548 const uint pid = tspacket.
PID();
1558 double erate = v * 100.0 /
m_packetCount.fetchAndAddRelaxed(0);
1559 LOG(VB_RECORD, LOG_WARNING,
LOC +
1560 QString(
"PID 0x%1 discontinuity detected ((%2+1)%16!=%3) %4%")
1561 .arg(pid,0,16).arg(old_cnt,2)
1633 else if (streamType != 0)
1636 LOG(VB_RECORD, LOG_ERR,
LOC +
1637 "ProcessVideoTSPacket: unknown stream type!");
1676 const uint pid = tspacket.
PID();
1686 double erate = v * 100.0 /
m_packetCount.fetchAndAddRelaxed(0);
1687 LOG(VB_RECORD, LOG_WARNING,
LOC +
1688 QString(
"A/V PID 0x%1 discontinuity detected ((%2+1)%16!=%3) %4%")
1690 .arg(erate,5,
'f',2));
1696 LOG(VB_RECORD, LOG_INFO,
LOC +
1697 QString(
"PID 0x%1 Found Payload Start").arg(pid,0,16));
void FindPSKeyFrames(const uint8_t *buffer, uint len) override
void HandleSingleProgramPMT(ProgramMapTable *pmt, bool insert) override
std::array< uint8_t, 0x1fff+1 > m_pidStatus
MythTimer m_timeOfLatestDataTimer
uint ProgramPID(uint i) const
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void SetPositionMapType(MarkTypes type)
Set seektable type.
@ MPEG2ExtensionStartCode
Followed by an extension byte, not documented here.
@ MPEGVideoStreamEnd
Last MPEG-1/2 video stream (w/ext hdr)
@ OpenCableVideo
Always MPEG-2??
QDateTime m_timeOfLatestData
ProgramMapTable * m_inputPmt
PMT on input side.
void VideoCodecChange(AVCodecID vCodec)
Note a change in video codec.
double toDouble(void) const
@ MPEGAudioStreamBegin
First MPEG-1/2 audio stream (w/ext hdr)
bool CheckCC(uint pid, uint new_cnt)
uint StreamCount(void) const
void SetDesiredProgram(int p)
unsigned long long m_framesWrittenCount
std::vector< unsigned char > m_payloadBuffer
void AddMPEGSPListener(MPEGSingleProgramStreamListener *val)
virtual void getFrameRate(FrameRate &result) const =0
static const uint kMaxKeyFrameDistance
If the number of regular frames detected since the last detected keyframe exceeds this value,...
void ResetForNewFile(void) override
QElapsedTimer m_audioTimer
Holds information on a TV Program one might wish to record.
ProgramAssociationTable * m_inputPat
PAT on input side.
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
bool ProcessVideoTSPacket(const TSPacket &tspacket) override
@ MPEG2AudioAmd1
ISO 13818-3/AMD-1 Audio using LATM syntax.
const TSHeader * tsheader() const
bool FindOtherKeyframes(const TSPacket *tspacket)
Non-Audio/Video data.
unsigned int m_videoBytesRemaining
int FindPID(uint pid) const
Locates stream index of pid.
void SetOptionsFromProfile(RecordingProfile *profile, const QString &videodev, const QString &audiodev, const QString &vbidev) override
Sets basic recorder options.
void Reset(void) override
Reset the recorder to the startup state.
uint PCRPID(void) const
stream that contains program clock reference.
void HandlePAT(const ProgramAssociationTable *_pat) override
unsigned long long m_lastGopSeen
void stop(void)
Stops timer, next call to isRunning() will return false and any calls to elapsed() or restart() will ...
unsigned int AFCOffset(void) const
uint pictureWidth(void) const
bool isRunning(void) const
Returns true if start() or restart() has been called at least once since construction and since any c...
virtual void SetStreamData(MPEGStreamData *data)
void BufferedWrite(const TSPacket &tspacket, bool insert=false)
bool IsVideo(uint i, const QString &sistandard) const
Returns true iff the stream at index i is a video stream.
std::array< uint64_t, 256 > m_tsCount
uint32_t GetUnitsInTick(void) const
void start(void)
starts measuring elapsed time.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
unsigned long long m_framesSeenCount
bool IsDamaged(void) const
uint ProgramCount(void) const
virtual QString GetSIStandard(void) const
void FinishRecording(void) override
Flushes the ringbuffer, and if this is not a live LiveTV recording saves the position map and filesiz...
virtual void SetCAMPMT(const ProgramMapTable *)
std::array< int64_t, 256 > m_tsFirst
QAtomicInt m_timeOfLatestDataPacketInterval
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
static bool IsVideo(uint type)
Returns true iff video is an MPEG1/2/3, H264 or open cable video stream.
std::array< uint8_t, 0x1fff+1 > m_continuityCounter
bool isNonzero(void) const
static QString toString(RecStatus::Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
static const unsigned char kPayloadStartSeen
virtual bool IsListeningPID(uint pid) const
RecordingInfo * m_curRecording
FrameRate m_tdTickFramerate
@ MPEG2AACAudio
ISO 13818-7 Audio w/ADTS syntax.
frm_pos_map_t m_durationMapDelta
@ PrivSec
ISO 13818-1 private tables & ITU H.222.0.
void SetStrOption(RecordingProfile *profile, const QString &name)
Convenience function used to set QString options from a profile.
void HandleSingleProgramPAT(ProgramAssociationTable *pat, bool insert) override
void SetDesiredChannel(int major, int minor)
@ SequenceStartCode
Sequence (SEQ) start code contains frame size, aspect ratio and fps.
RecStatus::Type GetRecordingStatus(void) const
bool ProcessAVTSPacket(const TSPacket &tspacket)
Common code for processing either audio or video packets.
uint ProgramNumber(uint i) const
@ VC1Video
SMPTE 421M video codec (aka VC1) in Blu-Ray.
unsigned long long m_lastKeyframeSeen
void AspectChange(uint aspect, long long frame)
Note a change in aspect ratio in the recordedmark table.
int m_progressiveSequence
uint64_t keyframeAUstreamOffset(void) const
void HandleKeyframe(int64_t extra)
This save the current frame to the position maps and handles ringbuffer switching.
SCAN_t GetScanType(void) const
static bool IsAudio(uint type)
Returns true iff audio is MPEG1/2, AAC, AC3 or DTS audio stream.
RecordingGaps m_recordingGaps
virtual void ClearStatistics(void)
Used to access the data of a Transport Stream packet.
Encapsulates data about ATSC stream and emits events for most tables.
uint StreamType(uint i) const
#define LOC
DTVRecorder – base class for Digital Televison recorders Copyright 2003-2004 by Brandon Beattie,...
virtual RecordingQuality * GetRecordingQuality(const RecordingInfo *ri) const
Returns a report about the current recordings quality.
Encapsulates data about MPEG stream and emits events for each table.
std::chrono::milliseconds restart(void)
Returns milliseconds elapsed since last start() or restart() and resets the count.
bool onFrameStart(void) const
void ResolutionChange(uint width, uint height, long long frame)
Note a change in video size in the recordedmark table.
bool FindAudioKeyframes(const TSPacket *tspacket)
void AudioCodecChange(AVCodecID aCodec)
Note a change in audio codec.
H2645Parser * m_h2645Parser
void HandleH2645Keyframe(void)
This save the current frame to the position maps and handles ringbuffer switching.
static const std::array< const FrameRate, 16 > frameRateMap
MPEGStreamData * GetStreamData(void) const
frm_pos_map_t m_durationMap
@ H264Video
ISO 14492-10 & ITU H.264 (aka MPEG-4-AVC)
std::array< uint8_t, 0x1fff+1 > m_streamId
void SetTotalFrames(uint64_t total_frames)
Note the total frames in the recordedmark table.
@ H265Video
ISO 23008-2 & ITU H.265 (aka HEVC, Ultra HD)
void AddTSStatistics(int continuity_error_count, int packet_count)
void ClearStatistics(void) override
bool ProcessTSPacket(const TSPacket &tspacket) override
@ GOPStartCode
Group of Pictures (GOP) start code.
void SetOption(const QString &name, const QString &value) override
Set an specific option.
MythTimer m_recordMptsTimer
@ MPEGVideoStreamBegin
First MPEG-1/2 video stream (w/ext hdr)
frm_pos_map_t m_positionMap
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
AVContainer m_containerFormat
void SetDuration(std::chrono::milliseconds duration)
Note the total duration in the recordedmark table.
The Program Association Table lists all the programs in a stream, and is always found on PID 0.
@ MPEG4Video
ISO 14492-2 (aka MPEG-4)
void FrameRateChange(uint framerate, uint64_t frame)
Note a change in video frame rate in the recordedmark table.
unsigned long long m_lastSeqSeen
int GetNumSetting(const QString &key, int defaultval=0)
bool IsAudio(uint i, const QString &sistandard) const
Returns true iff the stream at index i is an audio stream.
virtual uint32_t addBytes(const uint8_t *bytes, uint32_t byte_count, uint64_t stream_offset)=0
virtual void FinishRecording(void)
frm_pos_map_t m_positionMapDelta
bool start_code_is_valid(uint32_t start_code)
Test whether a start code found by find_start_code() is valid.
unsigned int m_audioBytesRemaining
virtual void StopRecording(void)
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
bool m_hasWrittenOtherKeyframe
void AddMPEGListener(MPEGStreamListener *val)
unsigned int m_otherBytesRemaining
MythMediaBuffer * m_ringBuffer
bool ProcessAudioTSPacket(const TSPacket &tspacket) override
void AddDVBMainListener(DVBMainStreamListener *val)
bool FindMPEG2Keyframes(const TSPacket *tspacket)
Locates the keyframes and saves them to the position map.
void UpdateFramesWritten(void)
bool m_waitForKeyframeOption
Wait for the a GOP/SEQ-start before sending data.
virtual void SetRecordingStatus(RecStatus::Type status, const QString &file, int line)
MPEGStreamData * m_streamData
QDateTime m_timeOfFirstData
static int64_t extract_timestamp(const uint8_t *bufptr, int bytes_left, int pts_or_dts)
int DesiredProgram(void) const
QString m_error
non-empty iff irrecoverable recording error detected
void ClearPositionMap(MarkTypes type) const
@ AC3Audio
A/53 Part 3:2009 6.7.1.
virtual field_type getFieldType(void) const =0
QAtomicInt m_timeOfFirstDataIsSet
void addMSecs(std::chrono::milliseconds ms)
Adds an offset to the last call to start() or restart().
This is the abstract base class for supporting recorder hardware.
void HandlePMT(uint progNum, const ProgramMapTable *_pmt) override
This is the coordinating class of the Recorder Subsystem.
QAtomicInt m_continuityErrorCount
bool onKeyFrameStart(void) const
AVCodecID m_primaryAudioCodec
uint aspectRatio(void) const
Computes aspect ratio from picture size and sample aspect ratio.
static QDateTime ts_to_qdatetime(uint64_t pts, uint64_t pts_first, const QDateTime &pts_first_dt)
virtual void SetOption(const QString &name, const QString &value)
Set an specific option.
std::chrono::duration< CHRONO_TYPE, std::ratio< 1, 90000 > > pts
AVCodecID m_primaryVideoCodec
std::vector< TSPacket > m_scratch
QString toString(void) const
@ MPEG2Video
ISO 13818-2 & ITU H.262 (aka MPEG-2)
void GetAsTSPackets(std::vector< TSPacket > &output, uint cc) const
Returns payload only PESPacket as series of TSPackets.
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
uint FindPID(uint progNum) const
uint32_t GetTimeScale(void) const
int m_minimumRecordingQuality
static constexpr std::chrono::milliseconds kTimeOfLatestDataIntervalTarget
timeOfLatest update interval target in milliseconds.
QRecursiveMutex m_pidLock
bool FindH2645Keyframes(const TSPacket *tspacket)
uint pictureHeight(void) const
void HandleTimestamps(int stream_id, int64_t pts, int64_t dts)
@ MPEG1Video
ISO 11172-2 (aka MPEG-1)
virtual bool CheckForRingBufferSwitch(void)
If requested, switch to new RingBuffer/ProgramInfo objects.
uint StreamPID(uint i) const
@ MPEGAudioStreamEnd
Last MPEG-1/2 audio stream (w/ext hdr)
RecordingQuality * GetRecordingQuality(const RecordingInfo *r) const override
Returns a report about the current recordings quality.
QAtomicInt m_timeOfLatestDataCount
const MTV_PUBLIC uint8_t * find_start_code_truncated(const uint8_t *p, const uint8_t *end, uint32_t *start_code)
By preserving the start_code value between subsequent calls, the caller can detect start codes across...
@ EAC3Audio
A/53 Part 3:2009 6.7.3.
virtual void InitStreamData(void)
void VideoScanChange(SCAN_t scan, uint64_t frame)
Note a change in video scan type in the recordedmark table.
std::array< int64_t, 256 > m_tsLast
std::array< QDateTime, 256 > m_tsFirstDt
QString GetSetting(const QString &key, const QString &defaultval="")
static constexpr unsigned int kSize
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::milliseconds > millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
bool stateChanged(void) const
void SetIntOption(RecordingProfile *profile, const QString &name)
Convenience function used to set integer options from a profile.