From 8dab9f7ce21b1597c3fa00742a7d532887a94ea3 Mon Sep 17 00:00:00 2001 From: Adam Sampson Date: Sun, 5 Jan 2020 00:04:02 +0000 Subject: [PATCH 1/3] Exit with an error if seeking by frame number fails. This can happen on early-CLV discs, or if the starting position isn't good enough -- it's more useful to exit than to continue decoding from the wrong position. --- ld-cut | 8 +++++++- ld-decode | 4 +++- lddecode/core.py | 20 +++++++++----------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ld-cut b/ld-cut index 5c742fe71..fd1ab3b36 100755 --- a/ld-cut +++ b/ld-cut @@ -69,13 +69,19 @@ if args.MTF_offset is not None: if args.seek != -1: startloc = ldd.seek(args.start, args.seek) - if startloc > 1: + if startloc is None: + print("ERROR: Seeking failed") + exit(1) + elif startloc > 1: startloc -= 1 else: startloc = args.start * 2 if args.end != -1: endloc = ldd.seek(startloc, args.end) + if endloc is None: + print("ERROR: Seeking failed") + exit(1) elif args.length != -1: endloc = startloc + (args.length * 2) else: diff --git a/ld-decode b/ld-decode index 7d7813695..cd9c5607e 100755 --- a/ld-decode +++ b/ld-decode @@ -89,7 +89,9 @@ if system == 'NTSC' and not args.ntscj: #print(ldd.blackIRE) if args.seek != -1: - ldd.seek(firstframe, args.seek) + if ldd.seek(firstframe, args.seek) is None: + print("ERROR: Seeking failed") + exit(1) if args.MTF is not None: ldd.rf.mtf_mult = args.MTF diff --git a/lddecode/core.py b/lddecode/core.py index 1a1d6b328..563821e51 100644 --- a/lddecode/core.py +++ b/lddecode/core.py @@ -2968,21 +2968,19 @@ def seek(self, start, target): for retries in range(3): fnr = self.seek_getframenr(cur) - cur = int((self.fieldloc / self.bytes_per_field)) if fnr is None: return None - else: - if fnr == target: - logging.info("Finished seek") - print("Finished seeking, starting at frame", fnr, file=sys.stderr) - self.roughseek(cur) - return cur - else: - cur += ((target - fnr) * 2) - 1 - print("Finished seeking, starting at frame", fnr, file=sys.stderr) + cur = int((self.fieldloc / self.bytes_per_field)) + if fnr == target: + logging.info("Finished seek") + print("Finished seeking, starting at frame", fnr, file=sys.stderr) + self.roughseek(cur) + return cur + + cur += ((target - fnr) * 2) - 1 - return cur - 0 + return None def build_json(self, f): ''' build up the JSON structure for file output. ''' From e12e620f4b543385ab7164847b75f8fa7d0acd32 Mon Sep 17 00:00:00 2001 From: Adam Sampson Date: Sun, 5 Jan 2020 00:05:23 +0000 Subject: [PATCH 2/3] Recognise the VBI code for the lead-in. --- lddecode/core.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lddecode/core.py b/lddecode/core.py index 563821e51..ae43d38b2 100644 --- a/lddecode/core.py +++ b/lddecode/core.py @@ -2489,6 +2489,7 @@ def __init__(self, fname_in, fname_out, freader, analog_audio = 0, digital_audio self.fieldinfo = [] + self.leadIn = False self.leadOut = False self.isCLV = False self.frameNumber = None @@ -2667,6 +2668,8 @@ def decodeFrameNumber(self, f1, f2): if l == 0x80eeee: # lead-out reached leadoutCount += 1 + elif l == 0x88ffff: # lead-in + self.leadIn = True elif (l & 0xf0dd00) == 0xf0dd00: # CLV minutes/hours self.clvMinutes = (l & 0xf) + (((l >> 4) & 0xf) * 10) + (((l >> 16) & 0xf) * 60) self.isCLV = True @@ -2913,6 +2916,8 @@ def buildmetadata(self, f): print("file frame %d CLV timecode %d:%.2d.%.2d frame %d" % (rawloc, self.clvMinutes, self.clvSeconds, self.clvFrameNum, self.frameNumber), file=sys.stderr) elif self.frameNumber: print("file frame %d CAV frame %d" % (rawloc, self.frameNumber), file=sys.stderr) + elif self.leadIn: + print("file frame %d lead in" % (rawloc), file=sys.stderr) elif self.leadOut: print("file frame %d lead out" % (rawloc), file=sys.stderr) else: From 480843a3fbbed35bf1a2b248de96ff853db0577c Mon Sep 17 00:00:00 2001 From: Adam Sampson Date: Sun, 5 Jan 2020 00:28:57 +0000 Subject: [PATCH 3/3] Reject invalid BCD in VBI codes. --- lddecode/core.py | 61 +++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/lddecode/core.py b/lddecode/core.py index ae43d38b2..67df32b2e 100644 --- a/lddecode/core.py +++ b/lddecode/core.py @@ -2660,46 +2660,53 @@ def decodeFrameNumber(self, f1, f2): self.clvSeconds = None self.clvFrameNum = None + def decodeBCD(bcd): + """Read a BCD-encoded number. + Raise ValueError if any of the digits aren't valid BCD.""" + + if bcd == 0: + return 0 + else: + digit = bcd & 0xF + if digit > 9: + raise ValueError("Non-decimal BCD digit") + return (10 * decodeBCD(bcd >> 4)) + digit + leadoutCount = 0 for l in f1.linecode + f2.linecode: if l is None: continue - + if l == 0x80eeee: # lead-out reached leadoutCount += 1 elif l == 0x88ffff: # lead-in self.leadIn = True elif (l & 0xf0dd00) == 0xf0dd00: # CLV minutes/hours - self.clvMinutes = (l & 0xf) + (((l >> 4) & 0xf) * 10) + (((l >> 16) & 0xf) * 60) - self.isCLV = True - #logging.info('CLV', mins) + try: + self.clvMinutes = decodeBCD(l & 0xff) + (decodeBCD((l >> 16) & 0xf) * 60) + self.isCLV = True + #logging.info('CLV', mins) + except ValueError: + pass elif (l & 0xf00000) == 0xf00000: # CAV frame # Ignore the top bit of the first digit, used for PSC - l &= 0x7ffff - - fnum = 0 - for y in range(16, -1, -4): - fnum *= 10 - toadd = l >> y & 0x0f - if toadd > 9: - fnum = -1 - break - fnum += toadd - - fnum = fnum if fnum < 80000 else fnum - 80000 - - if fnum >= 0: - return fnum - + try: + return decodeBCD(l & 0x7ffff) + except ValueError: + pass elif (l & 0x80f000) == 0x80e000: # CLV picture # - self.clvSeconds = (((l >> 16) & 0xf) - 10) * 10 - self.clvSeconds += ((l >> 8) & 0xf) - - self.clvFrameNum = ((l >> 4) & 0xf) * 10 - self.clvFrameNum += (l & 0xf) - - self.isCLV = True + try: + sec1s = decodeBCD((l >> 8) & 0xf) + sec10s = ((l >> 16) & 0xf) - 0xa + if sec10s < 0: + raise ValueError("Digit 2 not in range A-F") + + self.clvFrameNum = decodeBCD(l & 0xff) + self.clvSeconds = sec1s + (10 * sec10s) + self.isCLV = True + except ValueError: + pass if self.clvMinutes is not None: if self.clvSeconds is not None: # newer CLV