From 96f413a435c8920415a082d022938d0e93d41072 Mon Sep 17 00:00:00 2001 From: Scott Theisen Date: Sun, 6 Oct 2024 20:39:10 -0400 Subject: [PATCH 1/5] MythAVRational: create C++ wrapper for FFmpeg libavutil AVRational --- mythtv/libs/libmythtv/CMakeLists.txt | 1 + mythtv/libs/libmythtv/libmythtv.pro | 1 + mythtv/libs/libmythtv/mythavrational.h | 100 +++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 mythtv/libs/libmythtv/mythavrational.h diff --git a/mythtv/libs/libmythtv/CMakeLists.txt b/mythtv/libs/libmythtv/CMakeLists.txt index 984e180f2ee..cb497029765 100644 --- a/mythtv/libs/libmythtv/CMakeLists.txt +++ b/mythtv/libs/libmythtv/CMakeLists.txt @@ -60,6 +60,7 @@ add_library( livetvchain.h metadataimagehelper.cpp metadataimagehelper.h + mythavrational.h mythavutil.cpp mythavutil.h mythframe.cpp diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro index 63256e15b32..63250d440ab 100644 --- a/mythtv/libs/libmythtv/libmythtv.pro +++ b/mythtv/libs/libmythtv/libmythtv.pro @@ -143,6 +143,7 @@ HEADERS += io/mythstreamingbuffer.h HEADERS += io/mythinteractivebuffer.h HEADERS += io/mythopticalbuffer.h HEADERS += metadataimagehelper.h +HEADERS += mythavrational.h HEADERS += mythavutil.h HEADERS += recordingfile.h HEADERS += driveroption.h diff --git a/mythtv/libs/libmythtv/mythavrational.h b/mythtv/libs/libmythtv/mythavrational.h new file mode 100644 index 00000000000..23929b5f6d6 --- /dev/null +++ b/mythtv/libs/libmythtv/mythavrational.h @@ -0,0 +1,100 @@ +#ifndef MYTH_AV_RATIONAL_H +#define MYTH_AV_RATIONAL_H + +extern "C" +{ +#include "libavutil/rational.h" +} + +#include + +/** +C++ wrapper for FFmpeg libavutil AVRational. +*/ +class MythAVRational +{ + public: + explicit MythAVRational(int n = 0, int d = 1) : m_q({n, d}) {} + explicit MythAVRational(AVRational q) : m_q(q) {} + /** + @brief Convert a double to a MythAVRational. + + @note This is not an overload of the constructor since that would create + calls to ambiguous overloads. + */ + static MythAVRational fromDouble(double d, int64_t max) + { + return MythAVRational(av_d2q(d, max)); + } + + AVRational get_q() const { return m_q; } + /// @brief Convert the rational number to fixed point. + long long toFixed(long long base) const + { + return (base * m_q.num) / m_q.den; + } + double toDouble() const { return av_q2d(m_q); } + QString toString() const + { + return QStringLiteral("%1/%2").arg(QString::number(m_q.num), QString::number(m_q.den)); + } + + bool isNonzero() const { return m_q.num != 0; } + /// @return True, if the denominator is not zero; 0/0 is indeterminate and x/0 is undefined. + bool isValid() const { return m_q.den != 0; } + + [[nodiscard]] MythAVRational reduce(int64_t max) const + { + bool ignore; + return reduce(max, ignore); + } + [[nodiscard]] MythAVRational reduce(int64_t max, bool& exact) const + { + MythAVRational q; + exact = av_reduce(&q.m_q.num, &q.m_q.den, m_q.num, m_q.den, max); + return q; + } + [[nodiscard]] MythAVRational invert() const { return MythAVRational(av_inv_q(m_q)); } + + static int cmp(const MythAVRational& a, const MythAVRational& b) { return av_cmp_q(a.m_q, b.m_q); } + + MythAVRational& operator+=(const MythAVRational& rhs); + MythAVRational& operator-=(const MythAVRational& rhs); + MythAVRational& operator*=(const MythAVRational& rhs); + MythAVRational& operator/=(const MythAVRational& rhs); + private: + AVRational m_q {.num = 0, .den = 1}; +}; + +inline bool operator==(const MythAVRational& lhs, const MythAVRational& rhs) { return MythAVRational::cmp(lhs, rhs) == 0; } +inline bool operator!=(const MythAVRational& lhs, const MythAVRational& rhs) { return MythAVRational::cmp(lhs, rhs) != 0; } +inline bool operator< (const MythAVRational& lhs, const MythAVRational& rhs) { return MythAVRational::cmp(lhs, rhs) < 0; } +inline bool operator> (const MythAVRational& lhs, const MythAVRational& rhs) { return MythAVRational::cmp(lhs, rhs) > 0; } +inline bool operator<=(const MythAVRational& lhs, const MythAVRational& rhs) { return MythAVRational::cmp(lhs, rhs) <= 0; } +inline bool operator>=(const MythAVRational& lhs, const MythAVRational& rhs) { return MythAVRational::cmp(lhs, rhs) >= 0; } + +inline MythAVRational operator+(const MythAVRational& lhs, const MythAVRational& rhs) +{ + return MythAVRational(av_add_q(lhs.get_q(), rhs.get_q())); +} + +inline MythAVRational operator-(const MythAVRational& lhs, const MythAVRational& rhs) +{ + return MythAVRational(av_sub_q(lhs.get_q(), rhs.get_q())); +} + +inline MythAVRational operator*(const MythAVRational& lhs, const MythAVRational& rhs) +{ + return MythAVRational(av_mul_q(lhs.get_q(), rhs.get_q())); +} + +inline MythAVRational operator/(const MythAVRational& lhs, const MythAVRational& rhs) +{ + return MythAVRational(av_div_q(lhs.get_q(), rhs.get_q())); +} + +inline MythAVRational& MythAVRational::operator+=(const MythAVRational& rhs) { return *this = operator+(*this, rhs); } +inline MythAVRational& MythAVRational::operator-=(const MythAVRational& rhs) { return *this = operator-(*this, rhs); } +inline MythAVRational& MythAVRational::operator*=(const MythAVRational& rhs) { return *this = operator*(*this, rhs); } +inline MythAVRational& MythAVRational::operator/=(const MythAVRational& rhs) { return *this = operator/(*this, rhs); } +#endif // MYTH_AV_RATIONAL_H From ab8af5cb50bee8fcd1076c4e3332456b92367cbf Mon Sep 17 00:00:00 2001 From: Scott Theisen Date: Tue, 19 Jul 2022 23:43:20 -0400 Subject: [PATCH 2/5] MythAVRational: replace class FrameRate N.B.: many instances still use or convert to floating point. --- mythtv/libs/libmythtv/mpeg/AVCParser.cpp | 8 +++--- mythtv/libs/libmythtv/mpeg/AVCParser.h | 2 +- mythtv/libs/libmythtv/mpeg/H2645Parser.h | 4 +-- mythtv/libs/libmythtv/mpeg/HEVCParser.cpp | 6 ++--- mythtv/libs/libmythtv/mpeg/HEVCParser.h | 2 +- .../recorders/NuppelVideoRecorder.cpp | 2 +- .../libs/libmythtv/recorders/dtvrecorder.cpp | 26 +++++++++---------- mythtv/libs/libmythtv/recorders/dtvrecorder.h | 2 +- .../libs/libmythtv/recorders/recorderbase.cpp | 2 +- .../libs/libmythtv/recorders/recorderbase.h | 23 +++------------- 10 files changed, 30 insertions(+), 47 deletions(-) diff --git a/mythtv/libs/libmythtv/mpeg/AVCParser.cpp b/mythtv/libs/libmythtv/mpeg/AVCParser.cpp index 947d6a75aeb..0d8aeec489e 100644 --- a/mythtv/libs/libmythtv/mpeg/AVCParser.cpp +++ b/mythtv/libs/libmythtv/mpeg/AVCParser.cpp @@ -1074,12 +1074,12 @@ double AVCParser::frameRate(void) const return fps; } -void AVCParser::getFrameRate(FrameRate &result) const +MythAVRational AVCParser::getFrameRate() const { if (m_unitsInTick == 0) - result = FrameRate(0); + return MythAVRational(0); else if (m_timeScale & 0x1) - result = FrameRate(m_timeScale, m_unitsInTick * 2); + return MythAVRational(m_timeScale, m_unitsInTick * 2); else - result = FrameRate(m_timeScale / 2, m_unitsInTick); + return MythAVRational(m_timeScale / 2, m_unitsInTick); } diff --git a/mythtv/libs/libmythtv/mpeg/AVCParser.h b/mythtv/libs/libmythtv/mpeg/AVCParser.h index 5bad079a595..edf66bb75b0 100644 --- a/mythtv/libs/libmythtv/mpeg/AVCParser.h +++ b/mythtv/libs/libmythtv/mpeg/AVCParser.h @@ -115,7 +115,7 @@ class AVCParser : public H2645Parser uint pictureHeightCropped(void) const override; double frameRate(void) const; - void getFrameRate(FrameRate &result) const override; + MythAVRational getFrameRate() const override; void set_AU_pending(void) { diff --git a/mythtv/libs/libmythtv/mpeg/H2645Parser.h b/mythtv/libs/libmythtv/mpeg/H2645Parser.h index 82e25de500a..b37a4ec73ce 100644 --- a/mythtv/libs/libmythtv/mpeg/H2645Parser.h +++ b/mythtv/libs/libmythtv/mpeg/H2645Parser.h @@ -31,10 +31,10 @@ #include "libmythbase/mythconfig.h" #include "libmythbase/mythlogging.h" +#include "libmythtv/mythavrational.h" #include "libmythtv/scantype.h" class BitReader; -class FrameRate; class H2645Parser { public: @@ -70,7 +70,7 @@ class H2645Parser { /** \brief Computes aspect ratio from picture size and sample aspect ratio */ uint aspectRatio(void) const; - virtual void getFrameRate(FrameRate &result) const = 0; + virtual MythAVRational getFrameRate() const = 0; virtual field_type getFieldType(void) const = 0; uint64_t frameAUstreamOffset(void) const {return m_frameStartOffset;} diff --git a/mythtv/libs/libmythtv/mpeg/HEVCParser.cpp b/mythtv/libs/libmythtv/mpeg/HEVCParser.cpp index 55fb2606bb9..5f3012474c8 100644 --- a/mythtv/libs/libmythtv/mpeg/HEVCParser.cpp +++ b/mythtv/libs/libmythtv/mpeg/HEVCParser.cpp @@ -2067,8 +2067,8 @@ uint HEVCParser::pictureHeightCropped(void) const m_frameCropBottomOffset) * crop_unit_y); } -void HEVCParser::getFrameRate(FrameRate &result) const +MythAVRational HEVCParser::getFrameRate() const { - result = (m_unitsInTick == 0) ? FrameRate(0) : - FrameRate(m_timeScale, m_unitsInTick); + return (m_unitsInTick == 0) ? MythAVRational(0) : + MythAVRational(m_timeScale, m_unitsInTick); } diff --git a/mythtv/libs/libmythtv/mpeg/HEVCParser.h b/mythtv/libs/libmythtv/mpeg/HEVCParser.h index 1f06d8dcee0..3c87b159def 100644 --- a/mythtv/libs/libmythtv/mpeg/HEVCParser.h +++ b/mythtv/libs/libmythtv/mpeg/HEVCParser.h @@ -252,7 +252,7 @@ class HEVCParser : public H2645Parser uint pictureHeightCropped(void) const override; field_type getFieldType(void) const override { return FRAME; } - void getFrameRate(FrameRate &result) const override; + MythAVRational getFrameRate() const override; protected: bool newAU(void); diff --git a/mythtv/libs/libmythtv/recorders/NuppelVideoRecorder.cpp b/mythtv/libs/libmythtv/recorders/NuppelVideoRecorder.cpp index cf485b0ec9b..e51a56255ae 100644 --- a/mythtv/libs/libmythtv/recorders/NuppelVideoRecorder.cpp +++ b/mythtv/libs/libmythtv/recorders/NuppelVideoRecorder.cpp @@ -591,7 +591,7 @@ void NuppelVideoRecorder::UpdateResolutions(void) break; } - FrameRate frameRate(den, num); + auto frameRate = MythAVRational(den, num); if (frameRate.isNonzero() && frameRate != m_frameRate) { m_frameRate = frameRate; diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp index 59d26837374..8bbd9c07dfc 100644 --- a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp +++ b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp @@ -196,7 +196,7 @@ void DTVRecorder::ClearStatistics(void) m_totalDuration = 0; m_tdBase = 0; m_tdTickCount = 0; - m_tdTickFramerate = FrameRate(0); + m_tdTickFramerate = MythAVRational(0); } @@ -367,13 +367,13 @@ static QDateTime ts_to_qdatetime( return dt.addMSecs((pts - pts_first)/90); } -static const std::array frameRateMap = { - FrameRate(0), FrameRate(24000, 1001), FrameRate(24), - FrameRate(25), FrameRate(30000, 1001), FrameRate(30), - FrameRate(50), FrameRate(60000, 1001), FrameRate(60), - FrameRate(0), FrameRate(0), FrameRate(0), - FrameRate(0), FrameRate(0), FrameRate(0), - FrameRate(0) +static const std::array frameRateMap = { + MythAVRational(0), MythAVRational(24000, 1001), MythAVRational(24), + MythAVRational(25), MythAVRational(30000, 1001), MythAVRational(30), + MythAVRational(50), MythAVRational(60000, 1001), MythAVRational(60), + MythAVRational(0), MythAVRational(0), MythAVRational(0), + MythAVRational(0), MythAVRational(0), MythAVRational(0), + MythAVRational(0) }; /** \fn DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) @@ -424,7 +424,7 @@ bool DTVRecorder::FindMPEG2Keyframes(const TSPacket* tspacket) uint aspectRatio = 0; uint height = 0; uint width = 0; - FrameRate frameRate(0); + MythAVRational frameRate {0}; // Scan for PES header codes; specifically picture_start // sequence_start (SEQ) and group_start (GOP). @@ -745,7 +745,7 @@ void DTVRecorder::UpdateFramesWritten(void) if (m_tdTickFramerate.isNonzero()) { m_totalDuration = m_tdBase + (int64_t) 500 * m_tdTickCount * - m_tdTickFramerate.getDen() / (double) m_tdTickFramerate.getNum(); + m_tdTickFramerate.invert().toDouble(); } if (m_framesWrittenCount < 2000 || m_framesWrittenCount % 1000 == 0) @@ -896,7 +896,7 @@ bool DTVRecorder::FindH2645Keyframes(const TSPacket *tspacket) uint aspectRatio = 0; uint height = 0; uint width = 0; - FrameRate frameRate(0); + MythAVRational frameRate {0}; SCAN_t scantype(SCAN_t::UNKNOWN_SCAN); bool hasFrame = false; @@ -995,7 +995,7 @@ bool DTVRecorder::FindH2645Keyframes(const TSPacket *tspacket) height = m_h2645Parser->pictureHeight(); aspectRatio = m_h2645Parser->aspectRatio(); scantype = m_h2645Parser->GetScanType(); - m_h2645Parser->getFrameRate(frameRate); + frameRate = m_h2645Parser->getFrameRate(); } } } // for (; i < TSPacket::kSize; ++i) @@ -1129,7 +1129,7 @@ void DTVRecorder::FindPSKeyFrames(const uint8_t *buffer, uint len) uint aspectRatio = 0; uint height = 0; uint width = 0; - FrameRate frameRate(0); + MythAVRational frameRate {0}; uint skip = std::max(m_audioBytesRemaining, m_otherBytesRemaining); while (bufptr + skip < bufend) diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.h b/mythtv/libs/libmythtv/recorders/dtvrecorder.h index 6eb28fde1ed..96238d70b22 100644 --- a/mythtv/libs/libmythtv/recorders/dtvrecorder.h +++ b/mythtv/libs/libmythtv/recorders/dtvrecorder.h @@ -199,7 +199,7 @@ class DTVRecorder : // m_td_base + (m_td_tick_count * m_td_tick_framerate / 2) double m_tdBase {0.0}; uint64_t m_tdTickCount {0}; - FrameRate m_tdTickFramerate {0}; + MythAVRational m_tdTickFramerate {0}; SCAN_t m_scanType {SCAN_t::UNKNOWN_SCAN}; // Music Choice diff --git a/mythtv/libs/libmythtv/recorders/recorderbase.cpp b/mythtv/libs/libmythtv/recorders/recorderbase.cpp index 6dae752fbca..df5c0d4abd7 100644 --- a/mythtv/libs/libmythtv/recorders/recorderbase.cpp +++ b/mythtv/libs/libmythtv/recorders/recorderbase.cpp @@ -371,7 +371,7 @@ bool RecorderBase::CheckForRingBufferSwitch(void) ResetForNewFile(); m_videoAspect = m_videoWidth = m_videoHeight = 0; - m_frameRate = FrameRate(0); + m_frameRate = MythAVRational(0); SetRingBuffer(m_nextRingBuffer); SetRecording(m_nextRecording); diff --git a/mythtv/libs/libmythtv/recorders/recorderbase.h b/mythtv/libs/libmythtv/recorders/recorderbase.h index 16467334aa1..68cde2b1041 100644 --- a/mythtv/libs/libmythtv/recorders/recorderbase.h +++ b/mythtv/libs/libmythtv/recorders/recorderbase.h @@ -16,6 +16,7 @@ #include "libmythbase/programtypes.h" // for MarkTypes, frm_pos_map_t #include "libmythtv/mythtvexp.h" +#include "libmythtv/mythavrational.h" #include "libmythtv/recordingfile.h" #include "libmythtv/recordingquality.h" #include "libmythtv/scantype.h" @@ -35,24 +36,6 @@ class ChannelBase; class MythMediaBuffer; class TVRec; -class FrameRate -{ -public: - explicit FrameRate(uint n, uint d=1) : m_num(n), m_den(d) {} - double toDouble(void) const { return m_num / (double)m_den; } - bool isNonzero(void) const { return m_num != 0U; } - uint getNum(void) const { return m_num; } - uint getDen(void) const { return m_den; } - QString toString(void) const { return QString("%1/%2").arg(m_num).arg(m_den); } - bool operator==(const FrameRate other) const { - return m_num == other.m_num && m_den == other.m_den; - } - bool operator!=(const FrameRate other) const { return !(*this == other); } -private: - uint m_num; - uint m_den; -}; - /** \class RecorderBase * \brief This is the abstract base class for supporting * recorder hardware. @@ -78,7 +61,7 @@ class MTV_PUBLIC RecorderBase : public QRunnable { m_videoFrameRate = rate; m_ntscFrameRate = (29.96 <= rate && 29.98 >= rate); - m_frameRate = FrameRate(lround(rate * 100), 100); + m_frameRate = MythAVRational(lround(rate * 100), 100); } /** \brief Changes the Recording from the one set initially with @@ -324,7 +307,7 @@ class MTV_PUBLIC RecorderBase : public QRunnable uint m_videoHeight {0}; uint m_videoWidth {0}; - FrameRate m_frameRate {0}; + MythAVRational m_frameRate {0}; RecordingInfo *m_curRecording {nullptr}; From ff203322128a18730e8104a221125068cb5f9563 Mon Sep 17 00:00:00 2001 From: Scott Theisen Date: Wed, 20 Jul 2022 00:16:11 -0400 Subject: [PATCH 3/5] DTVRecorder::UpdateFramesWritten: update comments to reflect code --- mythtv/libs/libmythtv/recorders/dtvrecorder.cpp | 1 + mythtv/libs/libmythtv/recorders/dtvrecorder.h | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp index 8bbd9c07dfc..944ee2a0df3 100644 --- a/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp +++ b/mythtv/libs/libmythtv/recorders/dtvrecorder.cpp @@ -744,6 +744,7 @@ void DTVRecorder::UpdateFramesWritten(void) m_tdTickCount += (2 + m_repeatPict); if (m_tdTickFramerate.isNonzero()) { + // not 1000 since m_tdTickCount needs to be divided by 2 to get an equivalent frame count m_totalDuration = m_tdBase + (int64_t) 500 * m_tdTickCount * m_tdTickFramerate.invert().toDouble(); } diff --git a/mythtv/libs/libmythtv/recorders/dtvrecorder.h b/mythtv/libs/libmythtv/recorders/dtvrecorder.h index 96238d70b22..0bfa78fdf9a 100644 --- a/mythtv/libs/libmythtv/recorders/dtvrecorder.h +++ b/mythtv/libs/libmythtv/recorders/dtvrecorder.h @@ -194,10 +194,16 @@ class DTVRecorder : mutable QAtomicInt m_continuityErrorCount {0}; unsigned long long m_framesSeenCount {0}; unsigned long long m_framesWrittenCount {0}; - double m_totalDuration {0.0}; // usec - // Calculate m_total_duration as - // m_td_base + (m_td_tick_count * m_td_tick_framerate / 2) + /// @brief Total milliseconds that have passed since the start of the recording. + double m_totalDuration {0.0}; + /// @brief Milliseconds from the start to m_tdTickCount = 0. double m_tdBase {0.0}; + /** @brief Count of the number of equivalent interlaced fields that have passed + since m_tdBase. + + @note This needs to be divied by 2 to get the number of @e frames corresponding to + m_tdTickFramerate. + */ uint64_t m_tdTickCount {0}; MythAVRational m_tdTickFramerate {0}; SCAN_t m_scanType {SCAN_t::UNKNOWN_SCAN}; From cc41061374e1fbeda1f8dd9dcb0ac7f0367e1dc3 Mon Sep 17 00:00:00 2001 From: Scott Theisen Date: Wed, 20 Jul 2022 00:49:46 -0400 Subject: [PATCH 4/5] DecoderBase::m_totalDuration: wrap with MythAVRational --- .../libs/libmythtv/decoders/avformatdecoder.cpp | 16 ++++++++-------- mythtv/libs/libmythtv/decoders/decoderbase.cpp | 9 ++++----- mythtv/libs/libmythtv/decoders/decoderbase.h | 12 +++--------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/mythtv/libs/libmythtv/decoders/avformatdecoder.cpp b/mythtv/libs/libmythtv/decoders/avformatdecoder.cpp index f42abba7b70..5f813241772 100644 --- a/mythtv/libs/libmythtv/decoders/avformatdecoder.cpp +++ b/mythtv/libs/libmythtv/decoders/avformatdecoder.cpp @@ -3028,9 +3028,9 @@ void AvFormatDecoder::HandleGopStart( m_positionMap.push_back(entry); if (m_trackTotalDuration) { - m_frameToDurMap[m_framesRead] = - llround(m_totalDuration.num * 1000.0 / m_totalDuration.den); - m_durToFrameMap[m_frameToDurMap[m_framesRead]] = m_framesRead; + long long duration = m_totalDuration.toFixed(1000LL); + m_frameToDurMap[m_framesRead] = duration; + m_durToFrameMap[duration] = m_framesRead; } } @@ -3307,11 +3307,11 @@ bool AvFormatDecoder::PreProcessVideoPacket(AVStream *curstream, AVPacket *pkt) // The ffmpeg libraries represent a frame interval of a // 59.94fps video as 1501/90000 seconds, when it should // actually be 1501.5/90000 seconds. - AVRational pkt_dur = AVRationalInit(pkt->duration); - pkt_dur = av_mul_q(pkt_dur, curstream->time_base); - if (pkt_dur.num == 1501 && pkt_dur.den == 90000) - pkt_dur = AVRationalInit(1001, 60000); // 1501.5/90000 - m_totalDuration = av_add_q(m_totalDuration, pkt_dur); + MythAVRational pkt_dur {static_cast(pkt->duration)}; + pkt_dur *= MythAVRational(curstream->time_base); + if (pkt_dur == MythAVRational(1501, 90000)) + pkt_dur = MythAVRational(1001, 60000); // 1501.5/90000 + m_totalDuration += pkt_dur; } m_justAfterChange = false; diff --git a/mythtv/libs/libmythtv/decoders/decoderbase.cpp b/mythtv/libs/libmythtv/decoders/decoderbase.cpp index b635647afa6..741f64fafbb 100644 --- a/mythtv/libs/libmythtv/decoders/decoderbase.cpp +++ b/mythtv/libs/libmythtv/decoders/decoderbase.cpp @@ -17,7 +17,6 @@ DecoderBase::DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo) : m_parent(parent), m_playbackInfo(new ProgramInfo(pginfo)), m_audio(m_parent->GetAudio()), - m_totalDuration(AVRationalInit(0)), // language preference m_languagePreference(iso639_get_language_key_list()) @@ -61,7 +60,7 @@ void DecoderBase::Reset(bool reset_video_data, bool seek_reset, bool reset_file) m_frameCounter += 100; m_fpsSkip = 0; m_framesRead = 0; - m_totalDuration = AVRationalInit(0); + m_totalDuration = MythAVRational(0); m_dontSyncPositionMap = false; } @@ -883,7 +882,7 @@ void DecoderBase::FileChanged(void) ResetPosMap(); m_framesPlayed = 0; m_framesRead = 0; - m_totalDuration = AVRationalInit(0); + m_totalDuration = MythAVRational(0); m_waitingForChange = false; m_justAfterChange = true; @@ -1293,10 +1292,10 @@ QString toString(AudioTrackType type) void DecoderBase::SaveTotalDuration(void) { - if (!m_playbackInfo || av_q2d(m_totalDuration) == 0) + if (!m_playbackInfo || !m_totalDuration.isNonzero() || !m_totalDuration.isValid()) return; - m_playbackInfo->SaveTotalDuration(millisecondsFromFloat(1000 * av_q2d(m_totalDuration))); + m_playbackInfo->SaveTotalDuration(std::chrono::milliseconds{m_totalDuration.toFixed(1000)}); } void DecoderBase::SaveTotalFrames(void) diff --git a/mythtv/libs/libmythtv/decoders/decoderbase.h b/mythtv/libs/libmythtv/decoders/decoderbase.h index 3c11a5d1470..28e9c785186 100644 --- a/mythtv/libs/libmythtv/decoders/decoderbase.h +++ b/mythtv/libs/libmythtv/decoders/decoderbase.h @@ -9,6 +9,7 @@ #include "libmythbase/mythdbcon.h" #include "libmythbase/programinfo.h" #include "libmythtv/io/mythmediabuffer.h" +#include "libmythtv/mythavrational.h" #include "libmythtv/mythavutil.h" #include "libmythtv/mythcodecid.h" #include "libmythtv/mythvideoprofile.h" @@ -110,13 +111,6 @@ class StreamInfo }; using sinfo_vec_t = std::vector; -inline AVRational AVRationalInit(int num, int den = 1) { - AVRational result; - result.num = num; - result.den = den; - return result; -} - class DecoderBase { public: @@ -256,7 +250,7 @@ class DecoderBase virtual bool SetVideoByComponentTag(int /*tag*/) { return false; } void SaveTotalDuration(void); - void ResetTotalDuration(void) { m_totalDuration = AVRationalInit(0); } + void ResetTotalDuration(void) { m_totalDuration = MythAVRational(0); } void SaveTotalFrames(void); void TrackTotalDuration(bool track) { m_trackTotalDuration = track; } int GetfpsMultiplier(void) const { return m_fpsMultiplier; } @@ -300,7 +294,7 @@ class DecoderBase long long m_framesPlayed {0}; long long m_framesRead {0}; uint64_t m_frameCounter {0}; - AVRational m_totalDuration; + MythAVRational m_totalDuration {0}; int m_keyframeDist {-1}; long long m_lastKey {0}; long long m_indexOffset {0}; From cfcee2f106aa05a8cb7b75f755e9fe7e6495754a Mon Sep 17 00:00:00 2001 From: Scott Theisen Date: Wed, 20 Jul 2022 01:12:50 -0400 Subject: [PATCH 5/5] H2645Parser::aspectRatio(): convert to MythAVRational 1E-5 feels exact to me and the values should all fit comfortably in the `int`s of an AVRational. --- mythtv/libs/libmythtv/mpeg/H2645Parser.cpp | 51 ++++++++++------------ 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/mythtv/libs/libmythtv/mpeg/H2645Parser.cpp b/mythtv/libs/libmythtv/mpeg/H2645Parser.cpp index 89b75238529..2a0ebbb9e6a 100644 --- a/mythtv/libs/libmythtv/mpeg/H2645Parser.cpp +++ b/mythtv/libs/libmythtv/mpeg/H2645Parser.cpp @@ -6,7 +6,6 @@ #include "recorders/dtvrecorder.h" // for FrameRate and ScanType #include "bitreader.h" -#include #include /* @@ -388,10 +387,10 @@ void H2645Parser::vui_parameters(BitReader& br, bool hevc) uint H2645Parser::aspectRatio(void) const { - double aspect = 0.0; + MythAVRational aspect {0}; if (m_picHeight) - aspect = pictureWidthCropped() / (double)pictureHeightCropped(); + aspect = MythAVRational(pictureWidthCropped(), pictureHeightCropped()); switch (m_aspectRatioIdc) { @@ -400,82 +399,80 @@ uint H2645Parser::aspectRatio(void) const break; case 2: // 12:11 - aspect *= 1.0909090909090908; + aspect *= MythAVRational(12, 11); break; case 3: // 10:11 - aspect *= 0.90909090909090906; + aspect *= MythAVRational(10, 11); break; case 4: // 16:11 - aspect *= 1.4545454545454546; + aspect *= MythAVRational(16, 11); break; case 5: // 40:33 - aspect *= 1.2121212121212122; + aspect *= MythAVRational(40, 33); break; case 6: // 24:11 - aspect *= 2.1818181818181817; + aspect *= MythAVRational(24, 11); break; case 7: // 20:11 - aspect *= 1.8181818181818181; + aspect *= MythAVRational(20, 11); break; case 8: // 32:11 - aspect *= 2.9090909090909092; + aspect *= MythAVRational(32, 11); break; case 9: // 80:33 - aspect *= 2.4242424242424243; + aspect *= MythAVRational(80, 33); break; case 10: // 18:11 - aspect *= 1.6363636363636365; + aspect *= MythAVRational(18, 11); break; case 11: // 15:11 - aspect *= 1.3636363636363635; + aspect *= MythAVRational(15, 11); break; case 12: // 64:33 - aspect *= 1.9393939393939394; + aspect *= MythAVRational(64, 33); break; case 13: // 160:99 - aspect *= 1.6161616161616161; + aspect *= MythAVRational(160, 99); break; case 14: // 4:3 - aspect *= 1.3333333333333333; + aspect *= MythAVRational(4, 3); break; case 15: // 3:2 - aspect *= 1.5; + aspect *= MythAVRational(3, 2); break; case 16: // 2:1 - aspect *= 2.0; + aspect *= MythAVRational(2, 1); break; case kExtendedSar: if (m_sarHeight) - aspect *= m_sarWidth / (double)m_sarHeight; + aspect *= MythAVRational(m_sarWidth, m_sarHeight); else - aspect = 0.0; + aspect = MythAVRational(0); break; } - // TODO use an integer-based Rational number instead of floating point - static constexpr double eps = 1E-5; - if (aspect == 0.0) + if (aspect == MythAVRational(0)) return 0; - if (fabs(aspect - 1.3333333333333333) < eps) + if (aspect == MythAVRational(4, 3)) // 1.3333333333333333 return 2; - if (fabs(aspect - 1.7777777777777777) < eps) + if (aspect == MythAVRational(16, 9)) // 1.7777777777777777 return 3; - if (fabs(aspect - 2.21) < eps) + if (aspect == MythAVRational(221, 100)) // 2.21 return 4; - return aspect * 1000000; + return aspect.toFixed(1000000); }