#!/usr/bin/env python

# video mobilization
# mobi, based on http://giss.tv/wiki/images/1/19/Webcamstream-v4l2.pys

import sys, os
import pango
import pygtk, gtk, gobject
import pygst
pygst.require("0.10")
import gst

class GTK_Main:

	def __init__(self):

		# read in and store all settings for this session
		self.configure()

		# draw the window and buttons
		self.build_gui()

		# build a simple view-only gstreamer pipeline
		# and launch the viewr
		self.build_view_pipelist()
		pipeline = " ! ".join(self.pipelist)
		self.message(pipeline)
		self.player = gst.parse_launch (pipeline)
		self.launch_player()

	def configure(self):
		# get important env variables
		home = os.environ.get("HOME")
		user = os.environ.get("USER")

		# set default values
		self.settings = {} 
		self.settings['out_file'] = 1
		self.settings['out_file_template'] = home + "/mobi"
		self.settings['out_file_path'] = "" 
		self.settings['out_icecast'] = 1
		self.settings['out_icecast_ip'] = "a.stream.mayfirst.org"
		self.settings['out_icecast_port'] = "8000"
		self.settings['out_icecast_mount'] = user + ".ogg"
		self.settings['out_icecast_password'] = "source"
		self.settings['capture_video'] = 1
		self.settings['video_source'] = "ximagesrc"
		self.settings['video_width'] = "320"
		self.settings['video_height'] = "240"
		self.settings['video_framerate'] = "25/2"
		self.settings['theora_encoding_quality'] = "16" 
		self.settings['capture_audio'] = 1
		self.settings['audio_source'] = "alsasrc"
		self.settings['vorbis_encoding_quality'] = "0.2"
		self.settings['debug'] = 1

		# override with environmental variables
		for k,v in self.settings.iteritems():
			test_var = 'MOBI_' + k.upper()
			if (os.environ.get(test_var) != None):
				self.settings[k] = os.environ.get(test_var)
		
		# sanity checking and set calculated default values
		if self.settings['out_file'] == 1:
			if len(self.settings['out_file_path']) == 0:	
				if len(self.settings['out_file_template']) == 0:
					print "Neither out_file or out_file_template is set\n";
					exit
				# calculate out_file based on out_file_template
				import random
				random_string = ''
				for i in range(5):
					random_string += random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
				self.settings['out_file_path'] = self.settings['out_file_template'] + random_string + ".ogg"

		if self.settings['out_icecast'] == 1:	
			if self.settings['out_icecast_ip'] == '': 
				print "out_icecast_ip not set\n"
				sys.exit()
			if self.settings['out_icecast_port'] == '':
				print "out_icecast_port not set\n"
				sys.exit()
			if self.settings['out_icecast_mount'] == '':
				print "out_icecast_mount not set\n"
				sys.exit()
			if self.settings['out_icecast_password'] == '':
				print "out_icecast_password not set\n"
				sys.exit()

		if self.settings['capture_video'] != 1:
			if self.settings['capture_audio'] != 1:
				print "Neither audio or video capture chosen"
				sys.exit()

	def build_gui(self):

		# build the window
		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
		self.window.set_title("Webcam-Viewer")
		self.window.set_default_size(500, 400)
		self.window.connect("destroy", gtk.main_quit, "WM destroy")

		# create a parent vertical box, add the video player
		# to it
		vbox = gtk.VBox()
		self.window.add(vbox)
		self.movie_window = gtk.DrawingArea()
		vbox.add(self.movie_window)

		# create a box below it for choosing what you want to capture
		# (video + audio, audio only, video only)
		hbox_capture = gtk.HBox()
		vbox.pack_start(hbox_capture, False)
		hbox_capture.set_border_width(10)
		hbox_capture.pack_start(gtk.Label())

		radio_button = gtk.RadioButton(None, "Audio + Video")
		radio_button.connect("toggled", self.set_capture_audio_video)
		radio_button.set_active(True)
		hbox_capture.pack_start(radio_button, True, True, 0)
		radio_button.show()

		radio_button = gtk.RadioButton(radio_button, "Audio Only")
		radio_button.connect("toggled", self.set_capture_audio)
		hbox_capture.pack_start(radio_button, True, True, 0)
		radio_button.show()

		radio_button = gtk.RadioButton(radio_button, "Video Only")
		radio_button.connect("toggled", self.set_capture_video)
		hbox_capture.pack_start(radio_button, True, True, 0)
		radio_button.show()

		# build a third box below with action buttons
		# for starting/stopping/quitting and to show the
		# status
		hbox_status = gtk.HBox()
		vbox.pack_start(hbox_status, False)
		hbox_status.set_border_width(10)
		hbox_status.pack_start(gtk.Label())
		
		self.button_start_stop = gtk.Button("Start")
		self.button_start_stop.connect("clicked", self.start_stop)
		hbox_status.pack_start(self.button_start_stop, False)
		self.button_quit = gtk.Button("Quit")
		self.button_quit.connect("clicked", self.exit)
		hbox_status.pack_start(self.button_quit, False)
		hbox_status.add(gtk.Label())

		self.status_label = gtk.Label("Status: Not Streaming")
		hbox_status.pack_start(self.status_label, False)

		self.window.show_all()

	def launch_player(self):
		bus = self.player.get_bus()
		bus.add_signal_watch()
		bus.enable_sync_message_emission()
		bus.connect("message", self.on_message)
		bus.connect("sync-message::element", self.on_sync_message)
		self.player.set_state(gst.STATE_PLAYING)

	def build_view_pipelist(self):
		self.pipelist= []
		self.pipelist.append(self.settings['video_source'])
		self.pipelist.append('autovideosink')

	def build_mobi_pipelist(self):
		self.pipelist= []
		if self.settings['capture_video'] == 1:
			self.pipelist.append(self.settings['video_source'])
			self.pipelist.append("queue")
			self.pipelist.append("videoscale")
                        self.pipelist.append("video/x-raw-rgb,width=640,height=480,framerate=10/1")
			# self.pipelist.append("video/x-raw-rgb,width=" + self.settings['video_width'] +",height="+self.settings['video_height']) 
			self.pipelist.append("ffmpegcolorspace")
				
			# display video
			self.pipelist.append("tee name=tscreen")
			self.pipelist.append("queue")
			self.pipelist.append("autovideosink tscreen.")
			# self.pipelist.append("queue")
			# self.pipelist.append("videorate")
			# self.pipelist.append("video/x-raw-rgb,framerate="+self.settings['video_framerate'])
			self.pipelist.append("queue")
			self.pipelist.append("theoraenc quality="+self.settings['theora_encoding_quality'])
			self.pipelist.append("queue")

		#audio input
		if self.settings['capture_audio'] == 1:
                        self.pipelist.append("mux. "+self.settings['audio_source'])
			# self.pipelist.append("oggmux name=mux "+self.settings['audio_source'])
			self.pipelist.append("queue")
			self.pipelist.append("audioconvert")
			self.pipelist.append("vorbisenc quality="+self.settings['vorbis_encoding_quality'])
                        self.pipelist.append("mux. oggmux name=mux")
			# self.pipelist.append("queue")
			# self.pipelist.append("audio/x-raw-int,rate=22050,channels=1")
			# self.pipelist.append("queue")
			# self.pipelist.append("mux. mux.")
		else:
			self.pipelist.append("oggmux")

		self.pipelist.append("queue")

		#recording part
		if self.settings['out_file'] == 1:
			self.pipelist.append("tee name=tfile")
			self.pipelist.append("queue")
			self.pipelist.append("filesink location="+self.settings['out_file_path']+" tfile.")
			self.pipelist.append("queue")

		# streaming part
		if self.settings['out_icecast'] == 1:
			self.pipelist.append("shout2send ip="+self.settings['out_icecast_ip']+" port="+self.settings['out_icecast_port']+" mount="+self.settings['out_icecast_mount']+" password="+self.settings['out_icecast_password'])


	def set_status(self):
			status = "Status: "
			if self.settings['capture_video'] == 1:
				if self.settings['capture_audio'] == 1:
					status = status + "Streaming audio + video"
				else:
					status = status + "Streaming video only"
			else:
				if self.settings['capture_audio'] == 1:
					status = status + "Streaming audio only"

			self.status_label.set_label(status)

	def start_stop(self, w):
		if self.button_start_stop.get_label() == "Start":
			self.button_start_stop.set_label("Stop")
			self.set_status()
			# Set up the gstreamer pipeline
			self.build_mobi_pipelist()
			pipeline = " ! ".join(self.pipelist)
			self.message(pipeline)
			self.player.set_state(gst.STATE_NULL)
			self.player = gst.parse_launch (pipeline)
			self.launch_player()
		else:
			self.button_start_stop.set_label("Start")
			self.status_label.set_label("Status: Not Streaming")
			# rebuil pipelist for just viewing
			self.build_view_pipelist()
			pipeline = " ! ".join(self.pipelist)
			#print "gstreamer command : ", pipeline
			self.player.set_state(gst.STATE_NULL)
			self.player = gst.parse_launch (pipeline)
			self.launch_player()

	def exit(self, widget, data=None):
		gtk.main_quit()

	def on_message(self, bus, message):
		t = message.type
		if t == gst.MESSAGE_EOS:
			self.player.set_state(gst.STATE_NULL)
			self.button_start_stop.set_label("Start")
		elif t == gst.MESSAGE_ERROR:
			err, debug = message.parse_error()
			self.message(err)
			self.message(debug)
			self.player.set_state(gst.STATE_NULL)
			self.button_start_stop.set_label("Start")

	def on_sync_message(self, bus, message):
		if message.structure is None:
			return
		message_name = message.structure.get_name()
		if message_name == "prepare-xwindow-id":
			# Assign the viewport
			imagesink = message.src
			gtk.gdk.threads_enter()
			gtk.gdk.display_get_default().sync()
			imagesink.set_property("force-aspect-ratio", True)
			imagesink.set_xwindow_id(self.movie_window.window.xid)
			gtk.gdk.threads_leave()

	def set_capture_audio_video(self,w):
		self.settings['capture_video'] = 1
		self.settings['capture_audio'] = 1
		self.settings['out_icecast_mount'] = self.settings['out_icecast_mount'].replace('audio','video')

	def set_capture_audio(self,w):
		self.settings['capture_video'] = 0
		self.settings['capture_audio'] = 1
		self.settings['out_icecast_mount'] = self.settings['out_icecast_mount'].replace('video','audio')

	def set_capture_video(self,w):
		self.settings['capture_video'] = 1
		self.settings['capture_audio'] = 0
		self.settings['out_icecast_mount'] = self.settings['out_icecast_mount'].replace('audio','video')

	def message(self,message):
		if self.settings['debug'] == 1:
			print message

GTK_Main()
gtk.gdk.threads_init()
gtk.main()
