home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / sgi / video / Vrec.py < prev    next >
Text File  |  1996-11-27  |  10KB  |  414 lines

  1. #! /usr/bin/env python
  2. #! /ufs/guido/bin/sgi/python-405
  3.  
  4. # Capture a CMIF movie using the Indigo video library and board
  5.  
  6. # The CMIF video file format is documented in cmif-film.ms.
  7. # Audio data is recorded in AIFF format, using the input sampling
  8. # rate, source and volume set by the audio panel, in mono, 8
  9. # bits/sample.
  10.  
  11.  
  12. # Usage and help functions (keep this up-to-date if you change the program!)
  13.  
  14. def usage():
  15.     print 'Usage: Vrec [options] [moviefile [audiofile]]'
  16.     print
  17.     print 'Options:'
  18.     print '-a            : record audio as well'
  19.     print '-q queuesize  : set the capture queue size (default 2)'
  20.     print '-r rate       : capture 1 out of every "rate" frames', \
  21.                          '(default and min 2)'
  22.     print '-w width      : initial window width', \
  23.                              '(default 256, use 0 for interactive placement)'
  24.     print '-n            : Don\'t write to file, only timing info'
  25.     print '-d            : drop fields if needed'
  26.     print '-g bits       : greyscale (2, 4 or 8 bits)'
  27.     print '-G            : 2-bit greyscale dithered'
  28.     print '-m            : monochrome dithered'
  29.     print '-M value      : monochrome tresholded with value'
  30.     print '-f            : Capture fields (in stead of frames)'
  31.     print '-P frames     : preallocate space for "frames" frames'
  32.     print 'moviefile     : here goes the movie data (default film.video)'
  33.     print 'audiofile     : with -a, here goes the audio data', \
  34.                    '(default film.aiff)'
  35.  
  36. def help():
  37.     print 'Press the left mouse button to start recording, release it to'
  38.     print 'end recording.  You can record as many times as you wish, but'
  39.     print 'each recording overwrites the output file(s) -- only the last'
  40.     print 'recording is kept.'
  41.     print
  42.     print 'Press ESC or use the window manager Quit or Close window option'
  43.     print 'to quit.  If you quit before recording anything, the output'
  44.     print 'file(s) are not touched.'
  45.  
  46.  
  47. # Imported modules
  48.  
  49. import sys
  50. sys.path.append('/ufs/guido/src/video')
  51. import sv, SV
  52. import VFile
  53. import gl, GL, DEVICE
  54. import al, AL
  55. import time
  56. import posix
  57. import getopt
  58. import string
  59. import imageop
  60. import sgi
  61.  
  62.  
  63. # Main program
  64.  
  65. def main():
  66.     format = SV.RGB8_FRAMES
  67.     qsize = 2
  68.     audio = 0
  69.     rate = 2
  70.     width = 0
  71.     norecord = 0
  72.     drop = 0
  73.     mono = 0
  74.     grey = 0
  75.     greybits = 0
  76.     monotreshold = -1
  77.     fields = 0
  78.     preallocspace = 0
  79.  
  80.     # Parse command line
  81.     try:
  82.         opts, args = getopt.getopt(sys.argv[1:], 'aq:r:w:ndg:mM:GfP:')
  83.     except getopt.error, msg:
  84.         sys.stdout = sys.stderr
  85.         print 'Error:', msg, '\n'
  86.         usage()
  87.         sys.exit(2)
  88.  
  89.     # Interpret options
  90.     try:
  91.         for opt, arg in opts:
  92.             if opt == '-a':
  93.                 audio = 1
  94.             elif opt == '-q':
  95.                 qsize = string.atoi(arg)
  96.             elif opt == '-r':
  97.                 rate = string.atoi(arg)
  98.                 if rate < 2:
  99.                     sys.stderr.write( \
  100.                           '-r rate must be >= 2\n')
  101.                     sys.exit(2)
  102.             elif opt == '-w':
  103.                 width = string.atoi(arg)
  104.             elif opt == '-n':
  105.                 norecord = 1
  106.             elif opt == '-d':
  107.                 drop = 1
  108.             elif opt == '-g':
  109.                 grey = 1
  110.                 greybits = string.atoi(arg)
  111.                 if not greybits in (2, 4, 8):
  112.                     sys.stderr.write( \
  113.                 'Only 2, 4 or 8 bit greyscale supported\n')
  114.                     sys.exit(2)
  115.             elif opt == '-G':
  116.                 grey = 1
  117.                 greybits = -2
  118.             elif opt == '-m':
  119.                 mono = 1
  120.             elif opt == '-M':
  121.                 mono = 1
  122.                 monotreshold = string.atoi(arg)
  123.             elif opt == '-f':
  124.                 fields = 1
  125.             elif opt == '-P':
  126.                 preallocspace = string.atoi(arg)
  127.     except string.atoi_error:
  128.         sys.stdout = sys.stderr
  129.         print 'Option', opt, 'requires integer argument'
  130.         sys.exit(2)
  131.  
  132.     # Check excess arguments
  133.     # If norecord is on, refuse filename arguments
  134.     if norecord:
  135.         if args:
  136.             sys.stdout = sys.stderr
  137.             print 'With -n, no filename arguments are used\n'
  138.             usage()
  139.             sys.exit(2)
  140.     elif args[2:]:
  141.         sys.stdout = sys.stderr
  142.         print 'Too many filename arguments\n'
  143.         usage()
  144.         sys.exit(2)
  145.  
  146.     # Process file arguments
  147.     if args:
  148.         filename = args[0]
  149.     else:
  150.         filename = 'film.video'
  151.  
  152.     if args[1:] and not audio:
  153.         sys.stderr.write('-a turned on by appearance of 2nd file\n')
  154.         audio = 1
  155.  
  156.     if audio:
  157.         if args[1:]:
  158.             audiofilename = args[1]
  159.         else:
  160.             audiofilename = 'film.aiff'
  161.     else:
  162.         audiofilename = None
  163.  
  164.     if norecord:
  165.         filename = audiofilename = ''
  166.  
  167.     # Open video
  168.     v = sv.OpenVideo()
  169.     # Determine maximum window size based on signal standard
  170.     param = [SV.BROADCAST, 0]
  171.     v.GetParam(param)
  172.     if param[1] == SV.PAL:
  173.         x = SV.PAL_XMAX
  174.         y = SV.PAL_YMAX
  175.     elif param[1] == SV.NTSC:
  176.         x = SV.NTSC_XMAX
  177.         y = SV.NTSC_YMAX
  178.     else:
  179.         print 'Unknown video standard', param[1]
  180.         sys.exit(1)
  181.  
  182.     gl.foreground()
  183.     gl.maxsize(x, y)
  184.     gl.keepaspect(x, y)
  185.     gl.stepunit(8, 6)
  186.     if width:
  187.         height = width*3/4
  188.         x1 = 150
  189.         x2 = x1 + width-1
  190.         y2 = 768-150
  191.         y1 = y2-height+1
  192.         gl.prefposition(x1, x2, y1, y2)
  193.     win = gl.winopen(filename)
  194.     if width:
  195.         gl.maxsize(x, y)
  196.         gl.keepaspect(x, y)
  197.         gl.stepunit(8, 6)
  198.         gl.winconstraints()
  199.     x, y = gl.getsize()
  200.     print x, 'x', y
  201.  
  202.     v.SetSize(x, y)
  203.  
  204.     if drop:
  205.         param = [SV.FIELDDROP, 1, SV.GENLOCK, SV.GENLOCK_OFF]
  206.     else:
  207.         param = [SV.FIELDDROP, 0, SV.GENLOCK, SV.GENLOCK_ON]
  208.     if mono or grey:
  209.         param = param+[SV.COLOR, SV.MONO, SV.DITHER, 0, \
  210.                    SV.INPUT_BYPASS, 1]
  211.     else:
  212.         param = param+[SV.COLOR, SV.DEFAULT_COLOR, SV.INPUT_BYPASS, 0]
  213.  
  214.     v.BindGLWindow(win, SV.IN_REPLACE)
  215.     v.SetParam(param)
  216.  
  217.     gl.qdevice(DEVICE.LEFTMOUSE)
  218.     gl.qdevice(DEVICE.WINQUIT)
  219.     gl.qdevice(DEVICE.WINSHUT)
  220.     gl.qdevice(DEVICE.ESCKEY)
  221.  
  222.     help()
  223.  
  224.     while 1:
  225.         dev, val = gl.qread()
  226.         if dev == DEVICE.LEFTMOUSE:
  227.             if val == 1:
  228.                 info = format, x, y, qsize, rate
  229.                 record(v, info, filename, audiofilename,\
  230.                       mono, grey, greybits, monotreshold, \
  231.                       fields, preallocspace)
  232.         elif dev == DEVICE.REDRAW:
  233.             # Window resize (or move)
  234.             x, y = gl.getsize()
  235.             print x, 'x', y
  236.             v.SetSize(x, y)
  237.             v.BindGLWindow(win, SV.IN_REPLACE)
  238.         elif dev in (DEVICE.ESCKEY, DEVICE.WINQUIT, DEVICE.WINSHUT):
  239.             # Quit
  240.             v.CloseVideo()
  241.             gl.winclose(win)
  242.             break
  243.  
  244.  
  245. # Record until the mouse is released (or any other GL event)
  246. # XXX audio not yet supported
  247.  
  248. def record(v, info, filename, audiofilename, mono, grey, greybits, \
  249.       monotreshold, fields, preallocspace):
  250.     import thread
  251.     format, x, y, qsize, rate = info
  252.     fps = 59.64 # Fields per second
  253.     # XXX (Strange: need fps of Indigo monitor, not of PAL or NTSC!)
  254.     tpf = 1000.0 / fps # Time per field in msec
  255.     if filename:
  256.         vout = VFile.VoutFile(filename)
  257.         if mono:
  258.             format = 'mono'
  259.         elif grey and greybits == 8:
  260.             format = 'grey'
  261.         elif grey:
  262.             format = 'grey'+`abs(greybits)`
  263.         else:
  264.             format = 'rgb8'
  265.         vout.setformat(format)
  266.         vout.setsize(x, y)
  267.         if fields:
  268.             vout.setpf((1, -2))
  269.         vout.writeheader()
  270.         if preallocspace:
  271.             print 'Preallocating space...'
  272.             vout.prealloc(preallocspace)
  273.             print 'done.'
  274.         MAXSIZE = 20 # XXX should be a user option
  275.         import Queue
  276.         queue = Queue.Queue(MAXSIZE)
  277.         done = thread.allocate_lock()
  278.         done.acquire_lock()
  279.         convertor = None
  280.         if grey:
  281.             if greybits == 2:
  282.                 convertor = imageop.grey2grey2
  283.             elif greybits == 4:
  284.                 convertor = imageop.grey2grey4
  285.             elif greybits == -2:
  286.                 convertor = imageop.dither2grey2
  287.         thread.start_new_thread(saveframes, \
  288.               (vout, queue, done, mono, monotreshold, convertor))
  289.         if audiofilename:
  290.             audiodone = thread.allocate_lock()
  291.             audiodone.acquire_lock()
  292.             audiostop = []
  293.             initaudio(audiofilename, audiostop, audiodone)
  294.     gl.wintitle('(rec) ' + filename)
  295.     lastid = 0
  296.     t0 = time.time()
  297.     count = 0
  298.     ids = []
  299.     v.InitContinuousCapture(info)
  300.     while not gl.qtest():
  301.         try:
  302.             cd, id = v.GetCaptureData()
  303.         except sv.error:
  304.             #time.sleep(0.010) # XXX is this necessary?
  305.             sgi.nap(1)    # XXX Try by Jack
  306.             continue
  307.         ids.append(id)
  308.         
  309.         id = id + 2*rate
  310. ##        if id <> lastid + 2*rate:
  311. ##            print lastid, id
  312.         lastid = id
  313.         count = count+1
  314.         if fields:
  315.             data1, data2 = cd.GetFields()
  316.             cd.UnlockCaptureData()
  317.             if filename:
  318.                 queue.put((data1, int(id*tpf)))
  319.                 queue.put((data2, int((id+1)*tpf)))
  320.         else:
  321.             data = cd.InterleaveFields(1)
  322.             cd.UnlockCaptureData()
  323.             if filename:
  324.                 queue.put((data, int(id*tpf)))
  325.     t1 = time.time()
  326.     gl.wintitle('(busy) ' + filename)
  327.     print lastid, 'fields in', round(t1-t0, 3), 'sec',
  328.     print '--', round(lastid/(t1-t0), 1), 'fields/sec'
  329.     print 'Captured',count*2, 'fields,',
  330.     print round(count*2/(t1-t0), 1), 'f/s',
  331.     if lastid:
  332.         print '(',
  333.         print round(count*200.0/lastid), '%, or',
  334.         print round(count*rate*200.0/lastid), '% of wanted rate )',
  335.     print
  336.     if ids:
  337.         print 'Ids:',
  338.         t0 = ids[0]
  339.         del ids[0]
  340.         for t1 in ids:
  341.             print t1-t0,
  342.             t0 = t1
  343.         print
  344.     if filename and audiofilename:
  345.         audiostop.append(None)
  346.         audiodone.acquire_lock()
  347.     v.EndContinuousCapture()
  348.     if filename:
  349.         queue.put(None) # Sentinel
  350.         done.acquire_lock()
  351.     gl.wintitle('(done) ' + filename)
  352.  
  353.  
  354. # Thread to save the frames to the file
  355.  
  356. def saveframes(vout, queue, done, mono, monotreshold, convertor):
  357.     while 1:
  358.         x = queue.get()
  359.         if not x:
  360.             break
  361.         data, t = x
  362.         if convertor:
  363.             data = convertor(data, len(data), 1)
  364.         elif mono and monotreshold >= 0:
  365.             data = imageop.grey2mono(data, len(data), 1,\
  366.                   monotreshold)
  367.         elif mono:
  368.             data = imageop.dither2mono(data, len(data), 1)
  369.         vout.writeframe(t, data, None)
  370.     sys.stderr.write('Done writing video\n')
  371.     vout.close()
  372.     done.release_lock()
  373.  
  374.  
  375. # Initialize audio recording
  376.  
  377. AQSIZE = 8000 # XXX should be a user option
  378.  
  379. def initaudio(filename, stop, done):
  380.     import thread, aifc
  381.     afile = aifc.open(filename, 'w')
  382.     afile.setnchannels(AL.MONO)
  383.     afile.setsampwidth(AL.SAMPLE_8)
  384.     params = [AL.INPUT_RATE, 0]
  385.     al.getparams(AL.DEFAULT_DEVICE, params)
  386.     print 'audio sampling rate =', params[1]
  387.     afile.setframerate(params[1])
  388.     c = al.newconfig()
  389.     c.setchannels(AL.MONO)
  390.     c.setqueuesize(AQSIZE)
  391.     c.setwidth(AL.SAMPLE_8)
  392.     aport = al.openport(filename, 'r', c)
  393.     thread.start_new_thread(audiorecord, (afile, aport, stop, done))
  394.  
  395.  
  396. # Thread to record audio samples
  397.  
  398. def audiorecord(afile, aport, stop, done):
  399.     while not stop:
  400.         data = aport.readsamps(AQSIZE/2)
  401.         afile.writesampsraw(data)
  402.         del data
  403.     afile.close()
  404.     print 'Done writing audio'
  405.     done.release_lock()
  406.  
  407.  
  408. # Don't forget to call the main program
  409.  
  410. try:
  411.     main()
  412. except KeyboardInterrupt:
  413.     print '[Interrupt]'
  414.