Skip to content

Commit 3870b07

Browse files
Fix interlacing detection.
AutoDeint() was using m_scan_locked to lock in the current detected interlaced vs progressive detection which totally broke it's intended functionality, on top of that the MythDVDPlayer had disabled this broken-ness but only for DVD's. Also the comments said that progressive video would be detected on the first progressive frame, but that wasn't the case. The m_scan_locked hack was further broken by some threading changes so it didn't even work as a hack anymore. Anyway this was a mess so I've just rewritten the AutoDeint code. Now AutoDeint() tracks the last 30 frames and if any of them are interlaced we decide that the video is interlaced and conversely if all are progressive we decide the video is progressive. Thirty frames is very arbritary, generally three would be enough as it would account for 3-2 pulldown and all variations there of. But Video that is progressive and accidentally deinterlaced looks a lot better than video that is interlaced and not deinterlaced for progressive display. I've also added a small hack for NTSC and PAL video, if the number of lines in the video is 480 or 576 we assume the video is interlaced. After watching a poorly mastered DVD one too many times I decided this hack was necessary. The DVD override for still frames will still ensure that those are not deinterlaced, this is just for the autodetection in the video.
1 parent ea364b3 commit 3870b07

File tree

5 files changed

+53
-63
lines changed

5 files changed

+53
-63
lines changed

mythtv/libs/libmythtv/mythbdplayer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void MythBDPlayer::DisplayPauseFrame(void)
4444
if (player_ctx->buffer->IsBD() &&
4545
player_ctx->buffer->BD()->IsInStillFrame())
4646
{
47-
SetScanType(kScan_Progressive);
47+
SetScanType(kScan_Progressive, false);
4848
}
4949
DisplayMenu();
5050
MythPlayer::DisplayPauseFrame();

mythtv/libs/libmythtv/mythdvdplayer.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ MythDVDPlayer::MythDVDPlayer(bool muted)
1616
{
1717
}
1818

19-
void MythDVDPlayer::AutoDeint(VideoFrame *frame, bool allow_lock)
20-
{
21-
MythPlayer::AutoDeint(frame, false);
22-
}
23-
2419
void MythDVDPlayer::ReleaseNextVideoFrame(VideoFrame *buffer,
2520
int64_t timecode, bool wrap)
2621
{
@@ -48,7 +43,7 @@ void MythDVDPlayer::DisplayPauseFrame(void)
4843
if (player_ctx->buffer->IsDVD() &&
4944
player_ctx->buffer->DVD()->IsInStillFrame())
5045
{
51-
SetScanType(kScan_Progressive);
46+
SetScanType(kScan_Progressive, false);
5247
}
5348
DisplayDVDButton();
5449
MythPlayer::DisplayPauseFrame();

mythtv/libs/libmythtv/mythdvdplayer.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ class MythDVDPlayer : public MythPlayer
6969
virtual void SeekForScreenGrab(uint64_t &number, uint64_t frameNum,
7070
bool absolute);
7171

72-
// Private initialization stuff
73-
virtual void AutoDeint(VideoFrame* frame, bool allow_lock = true);
74-
7572
// Complicated gets
7673
virtual long long CalcMaxFFTime(long long ff, bool setjump = true) const;
7774
virtual void calcSliderPos(osdInfo &info, bool paddedFields = false);

mythtv/libs/libmythtv/mythplayer.cpp

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,10 @@ MythPlayer::MythPlayer(bool muted)
154154
video_disp_dim(0,0), video_dim(0,0),
155155
video_frame_rate(29.97f), video_aspect(4.0f / 3.0f),
156156
forced_video_aspect(-1),
157-
resetScan(kScan_Ignore), m_scan(kScan_Interlaced),
158-
m_scan_locked(false), m_scan_tracker(0), m_scan_initialized(false),
157+
resetScanType(kScan_Ignore), resetScanAllowLock(false),
158+
m_scan(kScan_Interlaced),
159+
m_scan_locked(false), m_scan_tracker_index(0),
160+
m_scan_initialized(false),
159161
keyframedist(30),
160162
// Prebuffering
161163
buffering(false),
@@ -669,6 +671,12 @@ FrameScanType MythPlayer::detectInterlace(FrameScanType newScan,
669671
scan = newScan;
670672
};
671673

674+
// Almost all NTSC/PAL sized frames we'll ever see will be interlaced
675+
// even if the frames are marked as progressive, so detect those as
676+
// being interlaced.
677+
if ((480 == video_height || 576 == video_height) && fps <= 30)
678+
scan = kScan_Interlaced;
679+
672680
LOG(VB_PLAYBACK, LOG_INFO, LOC + dbg+toQString(scan));
673681

674682
return scan;
@@ -691,76 +699,66 @@ void MythPlayer::FallbackDeint(void)
691699
videoOutput->FallbackDeint();
692700
}
693701

694-
void MythPlayer::AutoDeint(VideoFrame *frame, bool allow_lock)
702+
void MythPlayer::AutoDeint(VideoFrame *frame)
695703
{
696704
if (!frame || m_scan_locked)
697705
return;
698706

699-
if (frame->interlaced_frame)
707+
// Almost all NTSC/PAL sized frames we'll ever see will be interlaced
708+
// even if the frames are marked as progressive, so detect those as
709+
// being interlaced.
710+
if (frame->height == 480 || frame->height == 576)
711+
frame->interlaced_frame = 1;
712+
713+
const static int kScanTrackerSize = 30;
714+
bool iframe = bool(frame->interlaced_frame);
715+
if (m_scan_tracker.size() < kScanTrackerSize)
700716
{
701-
if (m_scan_tracker < 0)
702-
{
703-
LOG(VB_PLAYBACK, LOG_INFO, LOC +
704-
QString("interlaced frame seen after %1 progressive frames")
705-
.arg(abs(m_scan_tracker)));
706-
m_scan_tracker = 2;
707-
if (allow_lock)
708-
{
709-
LOG(VB_PLAYBACK, LOG_INFO, LOC + "Locking scan to Interlaced.");
710-
SetScanType(kScan_Interlaced);
711-
return;
712-
}
713-
}
714-
m_scan_tracker++;
717+
m_scan_tracker.push_back(iframe);
715718
}
716719
else
717720
{
718-
if (m_scan_tracker > 0)
719-
{
720-
LOG(VB_PLAYBACK, LOG_INFO, LOC +
721-
QString("progressive frame seen after %1 interlaced frames")
722-
.arg(m_scan_tracker));
723-
m_scan_tracker = 0;
724-
}
725-
m_scan_tracker--;
721+
m_scan_tracker_index %= kScanTrackerSize;
722+
m_scan_tracker[m_scan_tracker_index] = iframe;
723+
m_scan_tracker_index++;
726724
}
727725

728-
if ((m_scan_tracker % 400) == 0)
726+
FrameScanType scan = (iframe) ? kScan_Interlaced : kScan_Progressive;
727+
if (m_scan != scan)
729728
{
730-
QString type = (m_scan_tracker < 0) ? "progressive" : "interlaced";
731-
LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("%1 %2 frames seen.")
732-
.arg(abs(m_scan_tracker)).arg(type));
729+
for (int i = 0; scan == kScan_Progressive &&
730+
i < m_scan_tracker.size(); i++)
731+
scan = (m_scan_tracker[i]) ? kScan_Interlaced : kScan_Progressive;
732+
SetScanType(scan, false);
733733
}
734-
735-
int min_count = !allow_lock ? 0 : 2;
736-
if (abs(m_scan_tracker) <= min_count)
737-
return;
738-
739-
SetScanType((m_scan_tracker > min_count) ? kScan_Interlaced : kScan_Progressive);
740-
m_scan_locked = false;
741734
}
742735

743-
void MythPlayer::SetScanType(FrameScanType scan)
736+
void MythPlayer::SetScanType(FrameScanType scan, bool allow_lock)
744737
{
745738
QMutexLocker locker(&videofiltersLock);
746739

747740
if (!is_current_thread(playerThread))
748741
{
749-
resetScan = scan;
742+
resetScanType = scan;
743+
resetScanAllowLock = allow_lock;
750744
return;
751745
}
752746

753747
if (!videoOutput || !videosync)
754748
return; // hopefully this will be called again later...
755749

756-
resetScan = kScan_Ignore;
750+
resetScanType = kScan_Ignore;
757751

758752
if (m_scan_initialized &&
759753
m_scan == scan &&
760754
m_frame_interval == frame_interval)
761755
return;
762756

763-
m_scan_locked = (scan != kScan_Detect);
757+
LOG(VB_PLAYBACK, LOG_INFO,
758+
QString("SetScanType(%1, allow_lock %2)")
759+
.arg(scan).arg(allow_lock));
760+
761+
m_scan_locked = allow_lock && (scan != kScan_Detect);
764762

765763
m_scan_initialized = true;
766764
m_frame_interval = frame_interval;
@@ -833,10 +831,9 @@ void MythPlayer::SetVideoParams(int width, int height, double fps,
833831
if (IsErrored())
834832
return;
835833

834+
m_scan_tracker.clear();
836835
SetScanType(detectInterlace(scan, m_scan, video_frame_rate,
837-
video_disp_dim.height()));
838-
m_scan_locked = false;
839-
m_scan_tracker = (m_scan == kScan_Interlaced) ? 2 : 0;
836+
video_disp_dim.height()), false);
840837
}
841838

842839
void MythPlayer::SetFileLength(int total, int frames)
@@ -2153,12 +2150,10 @@ void MythPlayer::VideoStart(void)
21532150

21542151
// Default to Interlaced playback to allocate the deinterlacer structures
21552152
// Enable autodetection of interlaced/progressive from video stream
2156-
// And initialoze m_scan_tracker to 2 which will immediately switch to
2157-
// progressive if the first frame is progressive in AutoDeint().
21582153
m_scan = kScan_Interlaced;
21592154
m_scan_locked = false;
21602155
m_double_framerate = false;
2161-
m_scan_tracker = 2;
2156+
m_scan_tracker.clear();
21622157

21632158
if (player_ctx->IsPIP() && using_null_videoout)
21642159
{
@@ -2571,8 +2566,8 @@ void MythPlayer::EventLoop(void)
25712566
SetCaptionsEnabled(false, false);
25722567

25732568
// reset the scan (and hence deinterlacers) if triggered by the decoder
2574-
if (resetScan != kScan_Ignore)
2575-
SetScanType(resetScan);
2569+
if (resetScanType != kScan_Ignore)
2570+
SetScanType(resetScanType, resetScanAllowLock);
25762571

25772572
// refresh the position map for an in-progress recording while editing
25782573
if (hasFullPositionMap && watchingrecording && player_ctx->recorder &&

mythtv/libs/libmythtv/mythplayer.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ class MTV_PUBLIC MythPlayer
314314
void DisableHardwareDecoders(void) { no_hardware_decoders = true; }
315315
void NextScanType(void)
316316
{ SetScanType((FrameScanType)(((int)m_scan + 1) & 0x3)); }
317-
void SetScanType(FrameScanType);
317+
void SetScanType(FrameScanType, bool allow_lock = true);
318318
FrameScanType GetScanType(void) const { return m_scan; }
319319
bool IsScanTypeLocked(void) const { return m_scan_locked; }
320320
void Zoom(ZoomDirection direction);
@@ -461,7 +461,7 @@ class MTV_PUBLIC MythPlayer
461461
void InitFilters(void);
462462
FrameScanType detectInterlace(FrameScanType newScan, FrameScanType scan,
463463
float fps, int video_height);
464-
virtual void AutoDeint(VideoFrame* frame, bool allow_lock = true);
464+
void AutoDeint(VideoFrame*);
465465

466466
// Private Sets
467467
void SetPlayingInfo(const ProgramInfo &pginfo);
@@ -614,13 +614,16 @@ class MTV_PUBLIC MythPlayer
614614
float video_aspect; ///< Video (input) Apect Ratio
615615
float forced_video_aspect;
616616
/// Tell the player thread to set the scan type (and hence deinterlacers)
617-
FrameScanType resetScan;
617+
FrameScanType resetScanType;
618+
bool resetScanAllowLock;
618619
/// Video (input) Scan Type (interlaced, progressive, detect, ignore...)
619620
FrameScanType m_scan;
620621
/// Set when the user selects a scan type, overriding the detected one
621622
bool m_scan_locked;
623+
/// Index into m_scan_tracker
624+
int m_scan_tracker_index;
622625
/// Used for tracking of scan type for auto-detection of interlacing
623-
int m_scan_tracker;
626+
QList<bool> m_scan_tracker;
624627
/// Set when SetScanType runs the first time
625628
bool m_scan_initialized;
626629
/// Video (input) Number of frames between key frames (often inaccurate)

0 commit comments

Comments
 (0)