MythTV master
mythvideoscantracker.cpp
Go to the documentation of this file.
1// MythTV
3#include "mythframe.h"
4#include "mythavutil.h"
5#include "mythplayerui.h"
6#include "mythvideoout.h"
8
9#define LOC QString("ScanTracker: ")
10
12 : m_parentPlayer(Parent)
13{
14}
15
17{
18 // Default to interlaced playback but set the tracker to progressive
19 // Enable autodetection of interlaced/progressive from video stream
20 // Previously we set to interlaced and the scan tracker to 2 but this
21 // mis-'detected' a number of streams as interlaced when they are progressive.
22 // This significantly reduces the number of errors and also ensures we do not
23 // needlessly setup deinterlacers - which may consume significant resources.
24 // We set to interlaced for those streams whose frame rate is initially detected
25 // as e.g. 59.9 when it is actually 29.97 interlaced.
27 m_scanLocked = false;
28 m_scanTracker = -2;
29 if (VideoOutput)
30 VideoOutput->SetDeinterlacing(true, m_parentPlayer->CanSupportDoubleRate());
31}
32
34{
35 m_scanInitialized = false;
36 m_scanLocked = false;
37}
38
40{
41 m_scanLocked = false;
43}
44
46{
47 int next = m_scanOverride + 1;
48 if (next > kScan_Progressive)
49 next = kScan_Detect;
50 return static_cast<FrameScanType>(next);
51}
52
54{
55 if (m_scanOverride == Scan)
56 return;
57
58 m_scanOverride = Scan;
60 {
61 m_scanLocked = false;
62 m_scanInitialized = false;
63 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Reverting to auto detection of scan");
64 }
65}
66
68{
69 if (!Frame)
70 return kScan_Progressive;
71
72 // Update details for debug OSD
73 m_lastDeinterlacer = Frame->m_deinterlaceInuse;
74 m_lastDeinterlacer2x = Frame->m_deinterlaceInuse2x;
75 // We use the underlying pix_fmt as it retains the distinction between hardware
76 // and software frames for decode only decoders.
77 m_lastFrameCodec = MythAVUtil::PixelFormatToFrameType(static_cast<AVPixelFormat>(Frame->m_pixFmt));
78
79 // Decide on type and rate
80 FrameScanType result = m_scan;
81 if ((kScan_Detect == m_scan) || (kScan_Ignore == m_scan) || Frame->m_alreadyDeinterlaced)
82 {
83 result = kScan_Progressive;
84 }
85 else if (is_interlaced(m_scan))
86 {
87 result = kScan_Interlaced;
88 Frame->m_interlacedReverse = (m_scan == kScan_Intr2ndField);
89 }
90
91 // Only display the second field if needed.
92 // This is somewhat circular - we check for double rate support when enabling
93 // deinterlacing, request that in the video buffers and the differing implementations
94 // then set m_lastDeinterlacer2x when they are actually using double rate
95 SecondField = is_interlaced(result) && m_lastDeinterlacer2x;
96 return result;
97}
98
100{
101 return m_scan;
102}
103
105{
107 return m_scanOverride;
108 return m_scan;
109}
110
111void MythVideoScanTracker::CheckScanUpdate(MythVideoOutput* VideoOutput, std::chrono::microseconds FrameInterval)
112{
114 SetScanType(m_resetScan, VideoOutput, FrameInterval);
115}
116
118{
120}
121
123 std::chrono::microseconds FrameInterval)
124{
126 {
127 m_resetScan = Scan;
128 return;
129 }
130
131 if (!VideoOutput)
132 return;
133
135
136 if (m_scanInitialized && (m_scan == Scan) && (m_lastFrameInterval == FrameInterval))
137 return;
138
139 m_scanLocked = (Scan != kScan_Detect);
140 m_scanInitialized = true;
141 m_lastFrameInterval = FrameInterval;
142
143 if (is_interlaced(Scan))
144 {
145 float currentspeed = m_parentPlayer->GetPlaySpeed();
146 bool normal = (currentspeed > 0.99F) && (currentspeed < 1.01F) && m_parentPlayer->AtNormalSpeed();
147 VideoOutput->SetDeinterlacing(true, m_parentPlayer->CanSupportDoubleRate() && normal);
148 }
149 else if (kScan_Progressive == Scan)
150 {
151 VideoOutput->SetDeinterlacing(false, false);
152 }
153
154 m_scan = Scan;
155}
156
178 std::chrono::microseconds FrameInterval, bool AllowLock)
179{
180 if (!Frame)
181 return;
182
184 {
185 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Locking scan override to '%1'")
187 SetScanType(m_scanOverride, VideoOutput, FrameInterval);
188 }
189
190 // This is currently only signalled for H264 content
191 if (Frame->m_newGOP)
192 {
194 ((Frame->m_interlaced && !is_interlaced(m_scan)) ||
195 (!Frame->m_interlaced && is_interlaced(m_scan))))
196 {
197 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Unlocking frame scan");
198 m_scanLocked = false;
199 }
200 }
201
202 if (m_scanLocked)
203 return;
204
205 if (Frame->m_interlaced)
206 {
207 if (m_scanTracker < 0)
208 {
209 LOG(VB_PLAYBACK, LOG_INFO, LOC +
210 QString("Interlaced frame seen after %1 progressive frames")
211 .arg(abs(m_scanTracker)));
212 m_scanTracker = 2;
213 if (AllowLock)
214 {
215 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Locking scan to Interlaced.");
217 return;
218 }
219 }
221 }
222 else
223 {
224 if (m_scanTracker > 0)
225 {
226 LOG(VB_PLAYBACK, LOG_INFO, LOC +
227 QString("Progressive frame seen after %1 interlaced frames")
228 .arg(m_scanTracker));
229 m_scanTracker = 0;
230 }
232 }
233
234 int min_count = !AllowLock ? 0 : 2;
235 if (abs(m_scanTracker) <= min_count)
236 return;
237
239 VideoOutput, FrameInterval);
240 m_scanLocked = false;
241}
242
244{
246 QString dbg = QString("DetectInterlace(") + ScanTypeToString(NewScan) +
247 QString(", ") + ScanTypeToString(scan) + QString(", ") +
248 QString("%1").arg(static_cast<double>(Rate)) + QString(", ") +
249 QString("%1").arg(VideoHeight) + QString(") ->");
250
251 if (kScan_Ignore != NewScan || kScan_Detect == scan)
252 {
253 // The scanning mode should be decoded from the stream - otherwise guess
254 // default to interlaced
256 // 720P, outside interlaced frame rates or too large for interlaced
257 if ((720 == VideoHeight) || (Rate < 25) || (Rate > 30) || (VideoHeight > 1080))
259 if (kScan_Detect != NewScan)
260 scan = NewScan;
261 }
262
263 LOG(VB_PLAYBACK, LOG_INFO, LOC + dbg + ScanTypeToString(scan));
264 return scan;
265}
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:72
bool CanSupportDoubleRate()
bool AtNormalSpeed(void) const
Definition: mythplayer.h:157
float GetPlaySpeed(void) const
Definition: mythplayer.h:138
static QString DeinterlacerName(MythDeintType Deint, bool DoubleRate, VideoFrameType Format=FMT_NONE)
Definition: mythframe.cpp:462
MythDeintType m_lastDeinterlacer
FrameScanType GetScanForDisplay(MythVideoFrame *Frame, bool &SecondField)
FrameScanType DetectInterlace(FrameScanType NewScan, float Rate, int VideoHeight)
void SetScanType(FrameScanType Scan, MythVideoOutput *VideoOutput, std::chrono::microseconds FrameInterval)
std::chrono::microseconds m_lastFrameInterval
void SetScanOverride(FrameScanType Scan)
VideoFrameType m_lastFrameCodec
MythPlayerUI * m_parentPlayer
void CheckScanUpdate(MythVideoOutput *VideoOutput, std::chrono::microseconds FrameInterval)
FrameScanType GetScanType() const
void InitialiseScan(MythVideoOutput *VideoOutput)
MythVideoScanTracker(MythPlayerUI *Parent)
FrameScanType NextScanOverride()
FrameScanType GetScanTypeWithOverride() const
virtual void AutoDeint(MythVideoFrame *Frame, MythVideoOutput *VideoOutput, std::chrono::microseconds FrameInterval, bool AllowLock=true)
Check whether deinterlacing should be enabled.
This class serves as the base class for all video output methods.
bool is_current_thread(MThread *thread)
Use this to determine if you are in the named thread.
Definition: mthread.cpp:40
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define LOC
def scan(profile, smoonURL, gate)
Definition: scan.py:54
FrameScanType
Definition: videoouttypes.h:95
@ kScan_Intr2ndField
Definition: videoouttypes.h:99
@ kScan_Ignore
Definition: videoouttypes.h:96
@ kScan_Interlaced
Definition: videoouttypes.h:98
@ kScan_Detect
Definition: videoouttypes.h:97
@ kScan_Progressive
QString ScanTypeToUserString(FrameScanType Scan, bool Forced=false)
QString ScanTypeToString(FrameScanType Scan)
bool is_interlaced(FrameScanType Scan)