Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 1 | #! /ufs/guido/bin/sgi/python-405 |
| 2 | #! /ufs/guido/bin/sgi/python |
| 3 | |
| 4 | # Capture a CMIF movie using the Indigo video library and board |
| 5 | |
| 6 | |
| 7 | # Usage: |
| 8 | # |
Guido van Rossum | 32517f9 | 1992-09-04 13:26:59 +0000 | [diff] [blame] | 9 | # makemovie [-a] [-q queuesize] [-r rate] [-w width] [moviefile [audiofile]] |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 10 | |
| 11 | |
| 12 | # Options: |
| 13 | # |
| 14 | # -a : record audio as well |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 15 | # -q queuesize : set the capture queue size (default 2) |
Guido van Rossum | 32517f9 | 1992-09-04 13:26:59 +0000 | [diff] [blame] | 16 | # -r rate : capture 1 out of every 'rate' frames (default and min 2) |
| 17 | # -w width : initial window width (default interactive placement) |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 18 | # -n : Don't write to file, only timing info |
| 19 | # -d : drop fields if needed |
| 20 | # -g : greyscale |
| 21 | # -m : monochrome dithered |
| 22 | # -M value : monochrome tresholded with value |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 23 | # |
| 24 | # moviefile : here goes the movie data (default film.video); |
| 25 | # the format is documented in cmif-film.ms |
| 26 | # audiofile : with -a, here goes the audio data (default film.aiff); |
| 27 | # audio data is recorded in AIFF format, using the |
| 28 | # input sampling rate, source and volume set by the |
| 29 | # audio panel, in mono, 8 bits/sample |
| 30 | |
| 31 | |
| 32 | # User interface: |
| 33 | # |
| 34 | # Start the application. Resize the window to the desired movie size. |
| 35 | # Press the left mouse button to start recording, release it to end |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 36 | # recording. You can record as many times as you wish, but each time |
| 37 | # you overwrite the output file(s), so only the last recording is |
| 38 | # kept. |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 39 | # |
| 40 | # Press ESC or select the window manager Quit or Close window option |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 41 | # to quit. If you quit before recording anything, the output file(s) |
| 42 | # are not touched. |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 43 | |
| 44 | |
| 45 | import sys |
| 46 | sys.path.append('/ufs/guido/src/video') |
| 47 | import sv, SV |
| 48 | import VFile |
| 49 | import gl, GL, DEVICE |
| 50 | import al, AL |
| 51 | import time |
| 52 | import posix |
| 53 | import getopt |
| 54 | import string |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 55 | import imageop |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 56 | |
| 57 | # Main program |
| 58 | |
| 59 | def main(): |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 60 | format = SV.RGB8_FRAMES |
| 61 | qsize = 2 |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 62 | audio = 0 |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 63 | rate = 2 |
Guido van Rossum | 32517f9 | 1992-09-04 13:26:59 +0000 | [diff] [blame] | 64 | width = 0 |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 65 | norecord = 0 |
| 66 | drop = 0 |
| 67 | mono = 0 |
| 68 | grey = 0 |
| 69 | monotreshold = -1 |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 70 | |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 71 | opts, args = getopt.getopt(sys.argv[1:], 'aq:r:w:ndgmM:') |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 72 | for opt, arg in opts: |
| 73 | if opt == '-a': |
| 74 | audio = 1 |
| 75 | elif opt == '-q': |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 76 | qsize = string.atoi(arg) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 77 | elif opt == '-r': |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 78 | rate = string.atoi(arg) |
| 79 | if rate < 2: |
| 80 | sys.stderr.write('-r rate must be >= 2\n') |
| 81 | sys.exit(2) |
Guido van Rossum | 32517f9 | 1992-09-04 13:26:59 +0000 | [diff] [blame] | 82 | elif opt == '-w': |
| 83 | width = string.atoi(arg) |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 84 | elif opt == '-n': |
| 85 | norecord = 1 |
| 86 | elif opt == '-d': |
| 87 | drop = 1 |
| 88 | elif opt == '-g': |
| 89 | grey = 1 |
| 90 | elif opt == '-m': |
| 91 | mono = 1 |
| 92 | elif opt == '-M': |
| 93 | mono = 1 |
| 94 | monotreshold = string.atoi(arg) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 95 | |
Guido van Rossum | 8a861be | 1992-08-20 14:46:46 +0000 | [diff] [blame] | 96 | if args[2:]: |
| 97 | sys.stderr.write('usage: Vrec [options] [file [audiofile]]\n') |
| 98 | sys.exit(2) |
| 99 | |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 100 | if args: |
| 101 | filename = args[0] |
| 102 | else: |
| 103 | filename = 'film.video' |
| 104 | |
Guido van Rossum | 8a861be | 1992-08-20 14:46:46 +0000 | [diff] [blame] | 105 | if args[1:] and not audio: |
| 106 | sys.stderr.write('-a turned on by appearance of 2nd file\n') |
| 107 | audio = 1 |
| 108 | |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 109 | if audio: |
| 110 | if args[1:]: |
| 111 | audiofilename = args[1] |
| 112 | else: |
| 113 | audiofilename = 'film.aiff' |
| 114 | else: |
| 115 | audiofilename = None |
| 116 | |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 117 | if norecord: |
| 118 | filename = audiofilename = '' |
Guido van Rossum | 32517f9 | 1992-09-04 13:26:59 +0000 | [diff] [blame] | 119 | v = sv.OpenVideo() |
| 120 | # Determine maximum window size based on signal standard |
| 121 | param = [SV.BROADCAST, 0] |
| 122 | v.GetParam(param) |
| 123 | if param[1] == SV.PAL: |
| 124 | x = SV.PAL_XMAX |
| 125 | y = SV.PAL_YMAX |
| 126 | elif param[1] == SV.NTSC: |
| 127 | x = SV.NTSC_XMAX |
| 128 | y = SV.NTSC_YMAX |
| 129 | else: |
| 130 | print 'Unknown video standard', param[1] |
| 131 | sys.exit(1) |
| 132 | |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 133 | gl.foreground() |
Guido van Rossum | 32517f9 | 1992-09-04 13:26:59 +0000 | [diff] [blame] | 134 | gl.maxsize(x, y) |
| 135 | gl.keepaspect(x, y) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 136 | gl.stepunit(8, 6) |
Guido van Rossum | 32517f9 | 1992-09-04 13:26:59 +0000 | [diff] [blame] | 137 | if width: |
| 138 | gl.prefsize(width, width*3/4) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 139 | win = gl.winopen(filename) |
Guido van Rossum | 32517f9 | 1992-09-04 13:26:59 +0000 | [diff] [blame] | 140 | if width: |
| 141 | gl.maxsize(x, y) |
| 142 | gl.keepaspect(x, y) |
| 143 | gl.stepunit(8, 6) |
| 144 | gl.winconstraints() |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 145 | x, y = gl.getsize() |
| 146 | print x, 'x', y |
| 147 | |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 148 | v.SetSize(x, y) |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 149 | |
| 150 | if drop: |
| 151 | param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF] |
| 152 | else: |
| 153 | param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON] |
| 154 | if mono or grey: |
| 155 | param = param+[SV.COLOR, SV.MONO, SV.INPUT_BYPASS, 1] |
| 156 | else: |
| 157 | param = param+[SV.COLOR, SV.DEFAULT_COLOR, SV.INPUT_BYPASS, 0] |
| 158 | v.SetParam(param) |
Guido van Rossum | ff3da05 | 1992-12-09 22:16:35 +0000 | [diff] [blame] | 159 | |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 160 | v.BindGLWindow(win, SV.IN_REPLACE) |
| 161 | |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 162 | gl.qdevice(DEVICE.LEFTMOUSE) |
| 163 | gl.qdevice(DEVICE.WINQUIT) |
| 164 | gl.qdevice(DEVICE.WINSHUT) |
| 165 | gl.qdevice(DEVICE.ESCKEY) |
| 166 | |
| 167 | print 'Press left mouse to start recording, release it to stop' |
| 168 | |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 169 | while 1: |
| 170 | dev, val = gl.qread() |
| 171 | if dev == DEVICE.LEFTMOUSE: |
| 172 | if val == 1: |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 173 | info = format, x, y, qsize, rate |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 174 | record(v, info, filename, audiofilename,\ |
| 175 | mono, grey, monotreshold) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 176 | elif dev == DEVICE.REDRAW: |
| 177 | # Window resize (or move) |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 178 | x, y = gl.getsize() |
| 179 | print x, 'x', y |
| 180 | v.SetSize(x, y) |
| 181 | v.BindGLWindow(win, SV.IN_REPLACE) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 182 | elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT): |
| 183 | # Quit |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 184 | v.CloseVideo() |
| 185 | gl.winclose(win) |
| 186 | break |
| 187 | |
| 188 | |
| 189 | # Record until the mouse is released (or any other GL event) |
| 190 | # XXX audio not yet supported |
| 191 | |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 192 | def record(v, info, filename, audiofilename, mono, grey, monotreshold): |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 193 | import thread |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 194 | format, x, y, qsize, rate = info |
| 195 | fps = 59.64 # Fields per second |
| 196 | # XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!) |
| 197 | tpf = 1000.0 / fps # Time per field in msec |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 198 | if filename: |
| 199 | vout = VFile.VoutFile().init(filename) |
| 200 | if mono: |
| 201 | vout.format = 'mono' |
| 202 | elif grey: |
| 203 | vout.format = 'grey' |
| 204 | else: |
| 205 | vout.format = 'rgb8' |
| 206 | vout.width = x |
| 207 | vout.height = y |
| 208 | vout.writeheader() |
| 209 | MAXSIZE = 20 # XXX should be a user option |
| 210 | import Queue |
| 211 | queue = Queue.Queue().init(MAXSIZE) |
| 212 | done = thread.allocate_lock() |
| 213 | done.acquire_lock() |
| 214 | thread.start_new_thread(saveframes, \ |
| 215 | (vout, queue, done, mono, monotreshold)) |
| 216 | if audiofilename: |
| 217 | audiodone = thread.allocate_lock() |
| 218 | audiodone.acquire_lock() |
| 219 | audiostop = [] |
| 220 | initaudio(audiofilename, audiostop, audiodone) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 221 | gl.wintitle('(rec) ' + filename) |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 222 | lastid = 0 |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 223 | t0 = time.millitimer() |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 224 | count = 0 |
| 225 | timestamps = [] |
| 226 | ids = [] |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 227 | v.InitContinuousCapture(info) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 228 | while not gl.qtest(): |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 229 | try: |
| 230 | cd, id = v.GetCaptureData() |
Guido van Rossum | 42e07af | 1992-09-22 15:01:43 +0000 | [diff] [blame] | 231 | except sv.error: |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 232 | time.millisleep(10) # XXX is this necessary? |
| 233 | continue |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 234 | timestamps.append(time.millitimer()) |
| 235 | ids.append(id) |
| 236 | |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 237 | id = id + 2*rate |
| 238 | ## if id <> lastid + 2*rate: |
| 239 | ## print lastid, id |
| 240 | lastid = id |
| 241 | data = cd.InterleaveFields(1) |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 242 | cd.UnlockCaptureData() |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 243 | count = count+1 |
| 244 | if filename: |
Guido van Rossum | 9533ebe | 1992-12-14 12:29:43 +0000 | [diff] [blame] | 245 | queue.put((data, int(id*tpf))) |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 246 | t1 = time.millitimer() |
| 247 | gl.wintitle('(busy) ' + filename) |
| 248 | print lastid, 'fields in', t1-t0, 'msec', |
| 249 | print '--', 0.1 * int(lastid * 10000.0 / (t1-t0)), 'fields/sec' |
Guido van Rossum | 9533ebe | 1992-12-14 12:29:43 +0000 | [diff] [blame] | 250 | print 'Captured',count*2, 'fields,', |
| 251 | print 0.1*int(count*20000.0/(t1-t0)), 'f/s', |
| 252 | if lastid: |
| 253 | print count*200.0/lastid, '%,', |
| 254 | print count*rate*200.0/lastid, '% of wanted rate', |
| 255 | print |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 256 | t0 = timestamps[0] |
| 257 | del timestamps[0] |
| 258 | print 'Times:', |
| 259 | for t1 in timestamps: |
| 260 | print t1-t0, |
| 261 | t0 = t1 |
| 262 | print |
| 263 | print 'Ids:', |
| 264 | t0 = ids[0] |
| 265 | del ids[0] |
| 266 | for t1 in ids: |
| 267 | print t1-t0, |
| 268 | t0 = t1 |
| 269 | print |
| 270 | if filename and audiofilename: |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 271 | audiostop.append(None) |
| 272 | audiodone.acquire_lock() |
| 273 | v.EndContinuousCapture() |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 274 | if filename: |
| 275 | queue.put(None) # Sentinel |
| 276 | done.acquire_lock() |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 277 | gl.wintitle('(done) ' + filename) |
| 278 | |
| 279 | |
| 280 | # Thread to save the frames to the file |
| 281 | |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 282 | def saveframes(vout, queue, done, mono, monotreshold): |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 283 | while 1: |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 284 | x = queue.get() |
| 285 | if not x: |
| 286 | break |
| 287 | data, t = x |
Jack Jansen | 3b25371 | 1992-12-14 12:25:21 +0000 | [diff] [blame] | 288 | if mono and monotreshold >= 0: |
| 289 | data = imageop.grey2mono(data, len(data), 1,\ |
| 290 | monotreshold) |
| 291 | elif mono: |
| 292 | data = imageop.dither2mono(data, len(data), 1) |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 293 | vout.writeframe(t, data, None) |
| 294 | del data |
| 295 | sys.stderr.write('Done writing video\n') |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 296 | vout.close() |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 297 | done.release_lock() |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 298 | |
| 299 | |
Guido van Rossum | 8a861be | 1992-08-20 14:46:46 +0000 | [diff] [blame] | 300 | # Initialize audio recording |
| 301 | |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 302 | AQSIZE = 8000 # XXX should be a user option |
Guido van Rossum | 8a861be | 1992-08-20 14:46:46 +0000 | [diff] [blame] | 303 | |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 304 | def initaudio(filename, stop, done): |
Guido van Rossum | 8a861be | 1992-08-20 14:46:46 +0000 | [diff] [blame] | 305 | import thread, aiff |
| 306 | afile = aiff.Aiff().init(filename, 'w') |
| 307 | afile.nchannels = AL.MONO |
| 308 | afile.sampwidth = AL.SAMPLE_8 |
| 309 | params = [AL.INPUT_RATE, 0] |
| 310 | al.getparams(AL.DEFAULT_DEVICE, params) |
| 311 | print 'audio sampling rate =', params[1] |
| 312 | afile.samprate = params[1] |
| 313 | c = al.newconfig() |
| 314 | c.setchannels(AL.MONO) |
| 315 | c.setqueuesize(AQSIZE) |
| 316 | c.setwidth(AL.SAMPLE_8) |
| 317 | aport = al.openport(filename, 'r', c) |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 318 | thread.start_new_thread(audiorecord, (afile, aport, stop, done)) |
Guido van Rossum | 8a861be | 1992-08-20 14:46:46 +0000 | [diff] [blame] | 319 | |
| 320 | |
| 321 | # Thread to record audio samples |
| 322 | |
| 323 | # XXX should use writesampsraw for efficiency, but then destroy doesn't |
| 324 | # XXX seem to set the #samples in the header correctly |
| 325 | |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 326 | def audiorecord(afile, aport, stop, done): |
| 327 | while not stop: |
Guido van Rossum | 8a861be | 1992-08-20 14:46:46 +0000 | [diff] [blame] | 328 | data = aport.readsamps(AQSIZE/2) |
| 329 | ## afile.writesampsraw(data) |
| 330 | afile.writesamps(data) |
| 331 | del data |
| 332 | afile.destroy() |
| 333 | print 'Done writing audio' |
Guido van Rossum | 62f6bc8 | 1992-09-03 16:56:04 +0000 | [diff] [blame] | 334 | done.release_lock() |
Guido van Rossum | 8a861be | 1992-08-20 14:46:46 +0000 | [diff] [blame] | 335 | |
| 336 | |
Guido van Rossum | 180924d | 1992-08-20 11:46:28 +0000 | [diff] [blame] | 337 | # Don't forget to call the main program |
| 338 | |
Guido van Rossum | e0be2b3 | 1992-09-01 14:45:57 +0000 | [diff] [blame] | 339 | try: |
| 340 | main() |
| 341 | except KeyboardInterrupt: |
| 342 | print '[Interrupt]' |