ich möchte mal wieder ein kleines programm vorstellen, das sich als nützlich erwiesen hat. das problem war: ich hätte gerne mms:// streaming support in mpd um einige radiosender die ich sehr mag zu integrieren. das direkt in mpd zu implementieren wurde mir etwas zu komplex (libavcodec > me),
also habe ich einen kleinen http server geschrieben, der auf anfrage beginnt einen stream über gstreamer zu laden und zu convertieren und über den webserver auszugeben. quasi ein streaming-convert-proxy.
derzeit untertützt er nur mms quellen und mp3 ausgaben, aber das kann man mit ein wenig gstreamer kenntnis leicht erweitern wenn nötig.
benutzung eignetlich ganz einfach, einfach PORT und STATIONS nach wunsch anpassen und starten.
dannach kann man unter
http://servername:port/stationname.encodierung
jeweils den stream finden, mit den voreingestellten werte local z.b.
http://localhost:3333/fm4.mp3
wenn eine ungültige station gewählt wird (oder einfach gar nichts) wird eine m3u playlist mit allen möglichen streams zurück gegeben.
das ganze ist absolut nicht multiclient fähig.
Code: Alles auswählen
import socket
import thread
import threading
import gst
import gobject
PORT=3333
STATIONS={'fm4':'mms://stream1.orf.at/fm4_live',
'bayern2':'mms://gffstream-w3a.wm.llnwd.net/gffstream_w3a'}
SOURCES={'mms://': 'mmssrc location={X}'}
ENCODERS={'mp3': { 'gst': 'lame', 'mime': 'audio/mpeg'}}
def close_pipe():
global gst_pipe
if gst_pipe:
gst_pipe.set_state(gst.STATE_NULL)
gst_pipe=None
def create_pipe(request, sock):
global gst_pipe
#request looks like
#/stationame.encoder, currently only encoders with 3 letters are supported
close_pipe()
source=None
encoder=None
# find station souce
if request[1:-4] in STATIONS:
for src_prefix in SOURCES:
if STATIONS[request[1:-4]][0:len(src_prefix)] == src_prefix:
source = SOURCES[src_prefix].replace('{X}',
STATIONS[request[1:-4]])
break
# find encoder
if request[-3:] in ENCODERS:
encoder=ENCODERS[request[-3:]]['gst']
if encoder and source:
gst_pipe = gst.parse_launch(source + " ! decodebin ! " +
encoder + " ! fdsink name=fd_sink")
gst_pipe.get_by_name('fd_sink').set_property('fd',
sock.makefile('wb').fileno())
bus = gst_pipe.get_bus()
bus.add_signal_watch()
bus.connect('message', gstreamer_message)
return ENCODERS[request[-3:]]['mime']
def handle_request(client_sock):
global gst_pipe, transfer_event
req = ""
while True:
data = client_sock.recv(1)
if data == "":
break
req = req + data
if req[-4:] == "\r\n\r\n":
break
req = req.split('\r\n')
mime = create_pipe(req[0].split()[1], client_sock)
if mime:
client_sock.sendall("HTTP/1.1 200 OK\r\n");
client_sock.sendall("Content-Type: "+ mime +"\r\n")
client_sock.sendall("Cache-Control: no-cache, must-revalidate\r\n");
client_sock.sendall("\r\n\r\n")
#start playing till eos or client close
gst_pipe.set_state(gst.STATE_PLAYING)
transfer_event.clear()
transfer_event.wait()
close_pipe()
else:
#create playlist
# Try to find host
host = None
for line in req:
if line[0:4].lower() == 'host':
host = line[6:]
if not host:
host = 'localhost:' + PORT
playlist = ''
for station in STATIONS:
for encoder in ENCODERS:
playlist += 'http://' + host + '/' + station + '.' + encoder + \
'\r\n'
client_sock.sendall("HTTP/1.1 200 OK\r\n");
client_sock.sendall("Content-Type: audio/x-mpegurl\r\n")
client_sock.sendall("Content-Length: " + str(len(playlist)) + "\r\n")
client_sock.sendall("Content-Disposition: attachment; filename=\"play"
+"list.m3u\"\r\n")
client_sock.sendall("Cache-Control: no-cache, must-revalidate\r\n");
client_sock.sendall("\r\n\r\n")
client_sock.sendall(playlist)
def gstreamer_message(bus, message):
global transfer_event
if message.type == gst.MESSAGE_ERROR or message.type == gst.MESSAGE_EOS:
transfer_event.set()
def run_webserver():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', PORT))
sock.listen(1)
try:
while 1:
( clientsock, client ) = sock.accept()
handle_request ( clientsock )
clientsock.close()
finally:
sock.close()
if __name__=='__main__':
gobject.threads_init()
gst_pipe=None
transfer_event=threading.Event()
ws = thread.start_new_thread(run_webserver, ())
try:
gobject.MainLoop().run()
except KeyboardInterrupt:
close_pipe()
print "bye"