"headless" VideoProducerService

Christopher Cope cope at mcs.anl.gov
Tue Aug 5 17:18:15 CDT 2003


Hey everybody!!!

Finally, after working on this WAY TOO LONG, I have a headless video 
producer script that works and interfaces with ag2 the way it should.
Tell me if you see any problems.

headlessVideo.mash creates a video stream defined by the arguments pssed 
to it. if run with smash, this does not require any sort of display. so it 
can replace vic as the executable called in VideoProducerService.

VideoProducerService.py is Tom's script for running and passing AG 
settings to vic, modified for the headlessVideo.mash script. 

VideoProducerService.py runs the command "smash headlessVideo.mash <args>"

smash is essentially the mash executable, except without any sort of gui-X 
stuff. therefore mash needs to be installed for it to work.

my directions for doing this are as follows::
set your CVSROOT to 
:pserver:anonymous at cvs.openmash.org:/usr/mash/src/repository

cvs login

cvs checkout mash-code

now you will need to copy the desCore library into the mash-code 
directory.

build it: ./configure --enable-des --enable-rijndael && make && ./build

...

so this is what you should need to do. but somewhere along the lines a 
makefile broke or something. im not quite sure and am looking into it. all 
i know is that it used to build fine, and that smash ran my script 
properly last night. :-)

what i do know, is that headlessVideo.mash is fine, and instead of banging 
my head against the wall over this, i'm going to, as Ivan suggested, 
work on getting autoplace working for mash-vic right now, and come back to 
the "why wont mash do what it used to do?" problem in a day. 

heres the headless video script, and my releasecandidate ;) version of 
VideoProducerService.py

i could see a need for better error checking when parsing arguments sent 
to the script. i tried to have it imitate vic as much as possible. but 
aside from that, headlessVideo.mash is final.

VideoProducerService.py might need a change or two once i get mash working 
properly again. there was not an obvious one-for-one translation between 
the arguments orginally passed to vic, and the arguments that can be 
passed to my script. can anyone point me to doc specifying all the user 
defineable settings, and any y'all desire???

VideoProducerService.py and VideoProducerService.svc, as you know, are 
combined into a .zip and then opened by the AG.

So yeah, heres my stuff, got beef?
Chris


-------------- next part --------------
# headlessVideo.mash
#
# usage:
# smash headlessVideo.mash 224.2.3.4/9822 device 1 channel S-Video defaultTTL 16 key DES/somethingsecret

Import enable
import Application AddressBlock VideoAgent VideoPipeline


Class SimpleVideoApp -superclass Application

SimpleVideoApp instproc init {HOST TTL KEY} {
        $self next sv;
        $self add_default defaultTTL $TTL;
        $self instvar agent_ vpipe_;
        set agent_ [new VideoAgent $self $HOST];
        set vpipe_ [new VideoPipeline $agent_];
	if {$KEY != "none"} {
		$agent_ install-key $KEY;
	}
}

SimpleVideoApp instproc run {DEVICE CODEC} {
        $self instvar agent_ vpipe_;
	set device_list [$vpipe_ input_devices];
	# change the following number to the desired device
	set device [lindex $device_list $DEVICE];
	$vpipe_ select $device $CODEC;
	$vpipe_ start;
}

SimpleVideoApp instproc enhance {CHANNEL FORMAT BPS FPS QUALITY BW_LOCAL BW_SESSION} {
	$self instvar agent_ vpipe_;

	# FIXME: this requires more information on how to know which arguments 
	#	are valid for each method

	$vpipe_ set_port $CHANNEL;
	$vpipe_ set_norm $FORMAT;
	$vpipe_ set_quality $QUALITY;
	$vpipe_ set_fps $FPS;
	$vpipe_ set_bps $BPS;
	#$agent_ sessionbw $BW_SESSION;
	#$agent_ local_bandwidth $BW_LOCAL;
}

if ($argc==0) {
	error "Usage smash headless-videostream.mash <host/port> <options>";
	exit;
}

# set hostPort 224.2.3.4/9288
set hostPort [lindex $argv 0]

# DEFAULT PARAMETERS
# These can be changed by passing arguments
set deviceNum 1;
set channelNum S-Video;
set ttl 16;
set codec h261;
set format ntsc;
set fps 20;
set bw_session 100;
set key none;
# set rtpName none;
set bps 3000000;
set quality 10;
set bw_local 1000;

set curarg 1;
set stoopid 2;
while ($curarg<$argc) {
	set param [lindex $argv $curarg];
	set conf [lindex $argv $curarg];
	if { $param == "-D" || $param=="device" } {
		set deviceNum conf;
	}
	if { $param == "-I" || $param == "channel" } {
		set channelNum conf;
	}
	if { $param == "-t" || $param == "ttl" || $param == "defaultTTL" } {
		set ttl conf;
	}
	if { $param == "-F" || $param == "framerate" } {
		set fps conf;
	}
	if { $param == "-B" || $param == "maxbw" } {
		set bps conf;
	}
	if { $param == "-sbw" || $param == "bandwidth" } {
		set bw_session conf;
	}
	if { $param == "-q" || $param == "quality" } {
		set deviceNum conf;
	}
	if { $param == "-f" || $param == "defaultFormat" } {
		set codec conf;
	}
	if { $param == "-omft" || $param == "inputType" } {
		set format conf;
	}
	if { $param == "-K" || $param == "key" } {
		set key conf;
	}
	set $curarg [expr $curarg + $stoopid];
}  

set app [new SimpleVideoApp $hostPort $ttl $key]
set vp [$app set vpipe_]

$app run $deviceNum $codec
$app enhance $channelNum $format $bps $fps $quality $bw_local $bw_session

# FIXME 
# you never know when someone might want to have a VPS stream video for a certain length of time, and then die
# this can be set below
# set timeLimit 10000
# after $timeLimit [[$app set vpipe_] stop]

vwait forever
-------------- next part --------------
#-----------------------------------------------------------------------------
# Name:        VideoProducerService.py
# Purpose:     
#
# Author:      Thomas D. Uram
#
# Created:     2003/06/02
# RCS-ID:      $Id: VideoProducerService.py,v 1.10 2003/05/28 18:51:32 turam Exp $
# Copyright:   (c) 2002
# Licence:     See COPYING.TXT
#-----------------------------------------------------------------------------
import sys
import os
from AccessGrid.hosting.pyGlobus.Server import Server
from AccessGrid.Types import Capability
from AccessGrid.AGService import AGService
from AccessGrid import Platform
from AccessGrid.AGParameter import ValueParameter, OptionSetParameter, RangeParameter, TextParameter
from AccessGrid.NetworkLocation import MulticastNetworkLocation


class VideoProducerService( AGService ):
   encodings = [ "h261" ]
   def __init__( self, server ):
      AGService.__init__( self, server )
      self.capabilities = [ Capability( Capability.PRODUCER, Capability.VIDEO ) ]
      self.executable = "smash headlessVideo.mash"

      #
      # Set configuration parameters
      #
      # note: the datatype of the port parameter changes when a resource is set!
      self.configuration["streamname"] = TextParameter( "streamname", "Video" )
      self.configuration["port"] = TextParameter( "port", "" ) 
      self.configuration["encoding"] = OptionSetParameter( "encoding", "h261", VideoProducerService.encodings )
      self.configuration["bandwidth"] = RangeParameter( "bandwidth", 800, 0, 3072 ) 
      self.configuration["framerate"] = RangeParameter( "framerate", 25, 1, 30 ) 

   def Start( self ):
      """Start service"""
      try:
         
         # 
         # Start the service; in this case, store command line args in a list and let
         # the superclass _Start the service
         options = []
         options.append( '%s/%d' % ( self.streamDescription.location.host, 
                                     self.streamDescription.location.port) )

         option.append( "device %d" % (device) )
	 option.append( "channel %d" % (channel) ) # channel can be given by a number or a string ("S-Video", "Television"...) the strings are lookedup and specify a number
         options.append( 'defaultTTL %d' % (self.streamDescription.location.ttl) )
         option.append( "bandwidth %d" % (self.configuration["bandwidth"].value) )
         option.append( "framerate %d" % (self.configuration["framerate"].value) )
         option.append( "defaultFormat %s" % (self.configuration["encoding"].value) )
         option.append( "inputType NTSC" )

         if self.streamDescription.encryptionFlag != 0:
            options.append( "-K" )
            options.append( self.streamDescription.encryptionKey )
         if self.streamDescription.location.__dict__.has_key("type"):
            # use TTL from multicast locations only
            if self.streamDescription.location.type == MulticastNetworkLocation.TYPE:
               options.append( "-t" )
               options.append( '%d' % (self.streamDescription.location.ttl) )
         
         self.log.info("Starting VideoProducerService")
         self.log.info(" executable = %s" % self.executable)
         self.log.info(" options = %s" % options)
         self._Start( options )
         #os.remove(startupfile)
      except:
         self.log.exception("Exception in VideoProducerService.Start")
         raise Exception("Failed to start service")
   Start.soap_export_as = "Start"

   def Stop( self ):
       """Stop the service"""
       AGService.ForceStop(self)         
   Stop.soap_export_as = "Stop"

   def ConfigureStream( self, streamDescription ):
      """Configure the Service according to the StreamDescription"""
      ret = AGService.ConfigureStream( self, streamDescription )
      if ret and self.started:
         # service is already running with this config; ignore
         return
      # if started, stop
      if self.started:
         self.Stop()
      # if enabled, start
      if self.enabled:
         self.Start()
   ConfigureStream.soap_export_as = "ConfigureStream"

   def SetResource( self, resource ):
      """Set the resource used by this service"""
      self.log.info("VideoProducerService.SetResource : %s" % resource.resource )
      self.resource = resource
      if "portTypes" in self.resource.__dict__.keys():
          self.configuration["port"] = OptionSetParameter( "port", self.resource.portTypes[0], 
                                                           self.resource.portTypes )
   SetResource.soap_export_as = "SetResource"

   def SetIdentity(self, profile):
      """
      Set the identity of the user driving the node
      """
      Platform.SetRtpDefaults( profile )
   SetIdentity.soap_export_as = "SetIdentity"

def AuthCallback(server, g_handle, remote_user, context):
    return 1

# Signal handler to shut down cleanly
def SignalHandler(signum, frame):
    """
    SignalHandler catches signals and shuts down the service.
    Then it stops the hostingEnvironment.
    """
    global agService
    agService.Shutdown()
if __name__ == '__main__':
   from AccessGrid.hosting.pyGlobus import Client
   import thread
   import signal
   import time
   server = Server( int(sys.argv[1]), auth_callback=AuthCallback )
   
   agService = VideoProducerService(server)
   service = server.create_service_object("Service")
   agService._bind_to_service( service )
   # Register the signal handler so we can shut down cleanly
   signal.signal(signal.SIGINT, SignalHandler)
   print "Starting server at", agService.get_handle()
   server.RunInThread()
   # Keep the main thread busy so we can catch signals
   while server.IsRunning():
      time.sleep(1)
-------------- next part --------------
[ServiceDescription]

name = VideoProducerService

description = Vic-based video service to send video to multicast address

capabilities = Capability1

executable = VideoProducerService.py

platform = neutral



[Capability1]

role = producer

type = video


More information about the ag-dev mailing list