forked from happycube/ld-decode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathld-decode
executable file
·156 lines (123 loc) · 6.96 KB
/
ld-decode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
from base64 import b64encode
import copy
from datetime import datetime
import getopt
import io
from io import BytesIO
import os
import signal
import sys
import argparse
import json
import traceback
from lddecode.core import *
from lddecode.utils import *
options_epilog = """FREQ can be a bare number in MHz, or a number with one of the case-insensitive suffixes Hz, kHz, MHz, GHz, fSC (meaning NTSC) or fSCPAL."""
parser = argparse.ArgumentParser(description='Extracts audio and video from raw RF laserdisc captures', epilog=options_epilog)
parser.add_argument('infile', metavar='infile', type=str, help='source file')
parser.add_argument('outfile', metavar='outfile', type=str, help='base name for destination files')
parser.add_argument('-s', '--start', metavar='start', type=float, default=0, help='rough jump to frame n of capture (default is 0)')
parser.add_argument('--start_fileloc', metavar='start_fileloc', type=float, default=-1, help='jump to precise sample # in the file')
parser.add_argument('-S', '--seek', metavar='seek', type=int, default=-1, help='seek to frame n of capture')
#parser.add_argument('-E', '--end', metavar='end', type=int, default=-1, help='cutting: last frame')
parser.add_argument('-l', '--length', metavar='length', type=int, default = 110000, help='limit length to n frames')
parser.add_argument('-p', '--pal', '--PAL', dest='pal', action='store_true', help='source is in PAL format')
parser.add_argument('-n', '--ntsc', dest='ntsc', action='store_true', help='source is in NTSC format')
#parser.add_argument('-c', '--cut', dest='cut', action='store_true', help='cut (to r16) instead of decode')
parser.add_argument('-m', '--MTF', metavar='mtf', type=float, default=None, help='mtf compensation multiplier')
parser.add_argument('--MTF_offset', metavar='mtf_offset', type=float, default=None, help='mtf compensation offset')
parser.add_argument('-j', '--NTSCJ', dest='ntscj', action='store_true', help='source is in NTSC-J (IRE 0 black) format')
parser.add_argument('--noAGC', dest='noAGC', action='store_true', default=False, help='Disable AGC')
parser.add_argument('--noDOD', dest='nodod', action='store_true', default=False, help='disable dropout detector')
parser.add_argument('--noEFM', dest='noefm', action='store_true', default=False, help='Disable EFM front end')
parser.add_argument('--daa', dest='daa', action='store_true', default=False, help='Disable analog audio decoding')
parser.add_argument('--ignoreleadout', dest='ignoreleadout', action='store_true', default=False, help='continue decoding after lead-out seen')
parser.add_argument('--verboseVITS', dest='verboseVITS', action='store_true', default=False, help='Enable additional JSON fields')
parser.add_argument('--lowband', dest='lowband', action='store_true', default=False, help='Use more restricted RF settings for noisier disks')
parser.add_argument('--NTSC_color_notch_filter', dest='NTSC_color_notch_filter', action='store_true', default=False, help='Mitigate interference from analog audio in reds in NTSC captures')
parser.add_argument('--V4300D_notch_filter', dest='V4300D_notch_filter', action='store_true', default=False, help='LD-V4300D PAL/digital audio captures: remove spurious ~8.5mhz signal')
parser.add_argument('-d', '--deemp_adjust', metavar='deemp_adjust', type=float, default=1.0, help='mtf compensation multiplier')
parser.add_argument('-t', '--threads', metavar='threads', type=int, default=5, help='number of CPU threads to use')
parser.add_argument('-f', '--frequency', dest='inputfreq', metavar='FREQ', type=parse_frequency, default=None, help='RF sampling frequency in source file (default is 40MHz)')
parser.add_argument('--video_bpf_high', dest='vbpf_high', metavar='FREQ', type=parse_frequency, default=None, help='Video BPF high end frequency')
parser.add_argument('--video_lpf', dest='vlpf', metavar='FREQ', type=parse_frequency, default=None, help='Video low-pass filter frequency')
args = parser.parse_args()
#print(args)
filename = args.infile
outname = args.outfile
firstframe = args.start
req_frames = args.length
vid_standard = 'PAL' if args.pal else 'NTSC'
if args.pal and args.ntsc:
print("ERROR: Can only be PAL or NTSC")
exit(1)
extra_options = {'useAGC': not args.noAGC, 'deemp_level': (args.deemp_adjust, args.deemp_adjust)}
if vid_standard == 'NTSC' and args.NTSC_color_notch_filter:
extra_options['NTSC_ColorNotchFilter'] = True
if vid_standard == 'PAL' and args.V4300D_notch_filter:
extra_options['PAL_V4300D_NotchFilter'] = True
if args.lowband:
extra_options['lowband'] = True
try:
loader = make_loader(filename, args.inputfreq)
except ValueError as e:
print(e)
exit(1)
system = 'PAL' if args.pal else 'NTSC'
# Wrap the LDdecode creation so that the signal handler is not taken by sub-threads,
# allowing SIGINT/control-C's to be handled cleanly
original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
ldd = LDdecode(filename, outname, loader, analog_audio = 0 if args.daa else 44.100, digital_audio = not args.noefm, system=system, doDOD = not args.nodod, threads=args.threads, extra_options=extra_options)
signal.signal(signal.SIGINT, original_sigint_handler)
if args.start_fileloc != -1:
ldd.roughseek(args.start_fileloc, False)
else:
ldd.roughseek(firstframe * 2)
if system == 'NTSC' and not args.ntscj:
ldd.blackIRE = 7.5
#print(ldd.blackIRE)
if args.seek != -1:
if ldd.seek(args.seek if firstframe == 0 else firstframe, args.seek) is None:
print("ERROR: Seeking failed", file=sys.stderr)
exit(1)
if args.MTF is not None:
ldd.rf.mtf_mult = args.MTF
if args.MTF_offset is not None:
ldd.rf.mtf_offset = args.MTF_offset
DecoderParamsOverride = {}
if args.vbpf_high is not None:
DecoderParamsOverride['video_bpf_high'] = args.vbpf_high * 1000000
if args.vlpf is not None:
DecoderParamsOverride['video_lpf_freq'] = args.vlpf * 1000000
if len(DecoderParamsOverride.keys()):
ldd.demodcache.setparams(DecoderParamsOverride)
if args.verboseVITS:
ldd.verboseVITS = True
done = False
while not done and ldd.fields_written < (req_frames * 2):
try:
f = ldd.readfield()
except KeyboardInterrupt as kbd:
print("Terminated, saving JSON and exiting", file=sys.stderr)
write_json(ldd, outname)
ldd.close()
exit(1)
except Exception as err:
print("ERROR - please paste the following into a bug report:", file=sys.stderr)
print("current sample:", ldd.fdoffset, file=sys.stderr)
print("arguments:", args, file=sys.stderr)
print("Exception:", err, " Traceback:", file=sys.stderr)
traceback.print_tb(err.__traceback__)
write_json(ldd, outname)
ldd.close()
exit(1)
if f is None or (args.ignoreleadout == False and ldd.leadOut == True):
done = True
# print(ldd.fields_written)
if ldd.fields_written < 100 or ((ldd.fields_written % 500) == 0):
#print('write json')
write_json(ldd, outname)
print("saving JSON and exiting", file=sys.stderr)
write_json(ldd, outname)
ldd.close()