+++ /dev/null
-all:
- python setup.py build
-
-install:
- python setup.py install
-
-clean:
- rm -Rf build
+++ /dev/null
-from distutils.core import setup, Extension
-
-FFMPEG_DIR = '../ffmpeg'
-
-vlc = Extension('vlc',
- sources = ['vlcmodule.c'],
- include_dirs = ['../include'],
- libraries = ['vlc', 'rt', 'dl' , 'pthread', 'ffmpeg', 'm',
- 'memcpymmx','stream_out_transcode',
- 'i420_rgb_mmx','i420_yuy2_mmx','i420_ymga_mmx',
- 'i422_yuy2_mmx','memcpymmxext','memcpy3dn',
- 'avcodec'],
- library_dirs = [ '../lib',
- '../modules/stream_out', '../modules/encoder/ffmpeg',
- '../modules/misc/memcpy','../modules/video_chroma',
- '../modules/codec/ffmpeg', FFMPEG_DIR + '/libavcodec'])
-
-
-setup (name = 'PackageName',
- version = '1.0',
- description = 'This is a demonstration package',
- ext_modules = [vlc])
-
+++ /dev/null
-#include <Python.h>
-#include <vlc/vlc.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-
-static PyObject *vlc_create(PyObject *self, PyObject *args)
-{
- int iRc;
-
- iRc = VLC_Create();
- return Py_BuildValue("i", iRc);
-}
-
-
-static PyObject *vlc_init(PyObject *self, PyObject *args)
-{
- int iVlc;
- char *pArgv[] = { "vlc", "--sout", NULL };
- int iRc;
-
- if (!PyArg_ParseTuple(args, "is", &iVlc, &pArgv[2]))
- return NULL;
- iRc = VLC_Init(iVlc, 3, pArgv);
- return Py_BuildValue("i", iRc);
-}
-
-
-static PyObject *vlc_addTarget(PyObject *self, PyObject *args)
-{
- int iVlc;
- char *file;
- int iRc;
-
- if (!PyArg_ParseTuple(args, "is", &iVlc, &file))
- return NULL;
- iRc = VLC_AddTarget(iVlc, file, 0, 0, PLAYLIST_APPEND, PLAYLIST_END);
- return Py_BuildValue("i", iRc);
-}
-
-
-static PyObject *vlc_play(PyObject *self, PyObject *args)
-{
- int iVlc;
- int iRc;
-
- if (!PyArg_ParseTuple(args, "i", &iVlc))
- return NULL;
- iRc = VLC_Play(iVlc);
- return Py_BuildValue("i", iRc);
-}
-
-
-static PyObject *vlc_stop(PyObject *self, PyObject *args)
-{
- int iVlc;
- int iRc;
-
- if (!PyArg_ParseTuple(args, "i", &iVlc))
- return NULL;
- iRc = VLC_CleanUp(iVlc);
- return Py_BuildValue("i", iRc);
-}
-
-
-static PyObject *vlc_pause(PyObject *self, PyObject *args)
-{
- int iVlc;
- int iRc;
-
- if (!PyArg_ParseTuple(args, "i", &iVlc))
- return NULL;
- iRc = VLC_Pause(iVlc);
- return Py_BuildValue("i", iRc);
-}
-
-
-static PyMethodDef VlcMethods[] = {
- {"create", vlc_create, METH_VARARGS, _("Create a vlc thread.")},
- {"init", vlc_init, METH_VARARGS, _("Initialize a vlc thread.")},
- {"addTarget", vlc_addTarget, METH_VARARGS, _("Add a target in the playlist.")},
- {"play", vlc_play, METH_VARARGS, _("Play")},
- {"stop", vlc_stop, METH_VARARGS, _("Stop")},
- {"pause", vlc_pause, METH_VARARGS, _("Pause")},
- {NULL, NULL, 0, NULL} /* Sentinel */
-};
-
-
-void initvlc(void)
-{
- Py_InitModule("vlc", VlcMethods);
-}
-
+++ /dev/null
-#!/usr/bin/python -O
-#
-# VideoLAN RTSP Server
-#
-# Author: Cyril Deguet <asmax@via.ecp.fr>
-
-import cfg
-
-from sap import SapServer
-from session import Session
-
-
-class AnnounceList:
- "List of streams to be announced"
-
- def __init__(self):
- # Create the SAP server
- self.multicastList = {}
- self.sapServer = SapServer()
- self.sapServer.start()
-
- def readPlaylist(self):
- pass
-
- def addMulticastSession(self, session):
- "Add a multicast session in the announce list"
- self.multicastList[session.id] = session
-
- def delMulticastSession(self, session):
- "Delete a multicast session from the announce list"
- del self.multicastList[session.id]
+++ /dev/null
-# Nice kludge to share global variables ;-)
-
-pass
+++ /dev/null
-#!/usr/bin/python -O
-#
-# VideoLAN RTSP Server
-#
-# Author: Cyril Deguet <asmax@via.ecp.fr>
-
-
-import cfg, string, threading
-
-
-class PlayList:
- "Contains the media playlist"
-
- def __init__(self):
- self.lock = threading.Lock()
-
- def readConfig(self, filename):
- "Read the playlist file"
- f = open(filename)
- newList = {}
- while 1:
- line = string.strip(f.readline())
- if line == "":
- break
- items = string.split(line, '\t')
- newList[items[0]] = {'file':items[1], 'name':items[2], 'addr':items[3]}
- self.lock.acquire()
- self.list = newList
- self.lock.release()
-
- def getMedia(self, uri):
- "Return the description of an item in the playlist"
- self.lock.acquire()
- if self.list.has_key(uri):
- media = self.list[uri]
- else:
- media = None
- self.lock.release()
- return media
-
+++ /dev/null
-#!/usr/bin/python
-#
-# VideoLAN RTSP Server
-#
-# Author: Cyril Deguet <asmax@via.ecp.fr>
-#
-# See: RFC 2326 Real Time Streaming Protocol
-# RFC 2327 Session Description Protocol
-
-
-import cfg, mimetools, re, socket, time, SocketServer, string, sys
-
-from sap import SdpMessage
-
-
-class RtspServerHandler(SocketServer.StreamRequestHandler):
- "Request handler of the server socket"
-
- version = "RTSP/1.0"
- ok = "200 OK"
- badRequest = "400 Bad request"
- uriNotFound = "404 Not found"
- sessionNotFound = "454 Session not found"
- invalidHeader = "456 Header field not valid for resource"
- internalError = "500 Internal server error"
- notImplemented = "501 Not implemented"
-
- def error(self, message, cseq):
- self.wfile.write(self.version + " " + message + "\r\n" + \
- "Cseq: " + cseq + "\r\n" + \
- "\r\n")
-
- def parseHeader(self, header):
- "Split a RTCP header into a mapping of parameters"
- list = map(string.strip, re.split('[; \n]*', header, re.S))
- result = {}
- for item in list:
- m = re.match('([^=]*)(?:=(.*))?', item)
- if m is None:
- return None
- result[m.group(1)] = m.group(2)
- return result
-
- def optionsMethod(self):
- "Handle an OPTION request"
- response = "Public: OPTIONS, DESCRIBE, SETUP, PLAY, PAUSE, PING, TEARDOWN\r\n" + \
- "\r\n"
- return response
-
- def pingMethod(self, msg):
- "Handle a PING request"
- cseq = msg.getheader('cseq')
- id = msg.getheader('Session')
- if id is None:
- self.error(self.badRequest, cseq)
- return
- response = "Session: " + id + "\r\n" + \
- "\r\n"
- return response
-
- def describeMethod(self, msg, uri):
- "Handle a DESCRIBE request"
- cseq = msg.getheader('cseq')
-
- # Find the URI in the playlist
- media = cfg.playlist.getMedia(uri)
- if media is None:
- self.error(self.uriNotFound, cseq)
- return None
-
- message = SdpMessage(media['name'], media['addr'], uri)
- description = message.getMessage()
- size = `len(description)`
- response = "Content-Type: application/sdp\r\n" + \
- "Content-Length: " + size + "\r\n" + \
- "\r\n" + description
- return response
-
- def setupMethod(self, msg, uri):
- "Handle a SETUP request"
- cseq = msg.getheader('cseq')
-
- # Find the URI in the playlist
- media = cfg.playlist.getMedia(uri)
- if media is None:
- self.error(self.uriNotFound, cseq)
- return None
-
- transportHeader = msg.getheader('transport')
- if transportHeader is None:
- self.error(self.badRequest, cseq)
- return None
- transport = self.parseHeader(transportHeader)
-
- # Check the multicast/unicast fields in the headers
- if transport.has_key('multicast'):
- type = "multicast"
- elif transport.has_key('unicast'):
- type = "unicast"
- else:
- self.error(self.invalidHeader, cseq)
- return None
-
- # Check the destination field in the headers
- dest= None
- if transport.has_key('destination'):
- dest = transport['destination']
- if dest is None:
- dest = media['addr'] # default destination address
-
- id = cfg.sessionList.newSession(uri, dest)
- if id is None:
- self.error(self.internalError, cseq)
- return None
- response = "Session: " + id + "\r\n" + \
- "Transport: RTP/MP2T/UDP;" + type + ";destination=" + dest + "\r\n" + \
- "\r\n"
- return response
-
- def playMethod(self, msg, uri):
- "Handle a PLAY request"
- cseq = msg.getheader('cseq')
-
- # Find the URI in the playlist
- media = cfg.playlist.getMedia(uri)
- if media is None:
- self.error(self.uriNotFound, cseq)
- return None
-
- id = msg.getheader('Session')
- session = cfg.sessionList.getSession(id)
- if session is None:
- self.error(self.sessionNotFound, cseq)
- return None
- if session.play() < 0:
- self.error(self.internalError, cseq)
- return None
- response = "Session: " + id + "\r\n" + \
- "\r\n"
- return response
-
- def pauseMethod(self, msg, uri):
- "Handle a PAUSE request"
- cseq = msg.getheader('cseq')
-
- # Find the URI in the playlist
- media = cfg.playlist.getMedia(uri)
- if media is None:
- self.error(self.uriNotFound, cseq)
- return None
-
- id = msg.getheader('Session')
- session = cfg.sessionList.getSession(id)
- if session is None:
- self.error(self.sessionNotFound, cseq)
- return None
- if session.pause() < 0:
- self.error(self.internalError, cseq)
- return None
- response = "Session: " + id + "\r\n" + \
- "\r\n"
- return response
-
- def teardownMethod(self, msg, uri):
- "Handle a TEARDOWN request"
- cseq = msg.getheader('cseq')
-
- # Find the URI in the playlist
- media = cfg.playlist.getMedia(uri)
- if media is None:
- self.error(self.uriNotFound, cseq)
- return None
-
- id = msg.getheader('Session')
- session = cfg.sessionList.getSession(id)
- if session is None:
- self.error(self.sessionNotFound, cseq)
- return None
- if session.stop() < 0:
- self.error(self.internalError, cseq)
- return None
- if cfg.sessionList.delSession(id) < 0:
- self.error(self.internalError, cseq)
- return None
- response = "\r\n"
- return response
-
- def parseRequest(self):
- "Parse a RSTP request"
- requestLine = self.rfile.readline()
- m = re.match("(?P<method>[A-Z]+) (?P<uri>(\*|(?:(?P<protocol>rtsp|rtspu)://" + \
- "(?P<host>[^:/]*)(:(?P<port>\d*))?(?P<path>.*)))) " + \
- "RTSP/(?P<major>\d)\.(?P<minor>\d)", requestLine)
- if m is None:
- self.error(self.badRequest, "0")
- return
- uri = m.group('uri')
-
- # Get the message headers
- msg = mimetools.Message(self.rfile, "0")
- cseq = msg.getheader('CSeq')
- if cseq is None:
- self.error(self.badRequest, "0")
- return
-
- method = m.group('method')
- if method == 'OPTIONS':
- response = self.optionsMethod()
- elif method == 'DESCRIBE':
- response = self.describeMethod(msg, uri)
- elif method == 'SETUP':
- response = self.setupMethod(msg, uri)
- elif method == 'PLAY':
- response = self.playMethod(msg, uri)
- elif method == 'PAUSE':
- response = self.pauseMethod(msg, uri)
- elif method == 'PING':
- response = self.pingMethod(msg)
- elif method == 'TEARDOWN':
- response = self.teardownMethod(msg, uri)
- else:
- self.error(self.notImplemented, cseq)
- return
-
- # Send the response
- if response is None:
- return
- else:
- self.wfile.write(self.version + " " + self.ok + "\r\n" + \
- "CSeq: " + cseq + "\r\n" + \
- response)
-
- def handle(self):
- "Handle an incoming request"
- while 1:
- try:
- self.parseRequest()
- except IOError:
- return
-
-
+++ /dev/null
-rtsp://hostname.domain.org:1554/film1 /opt/media/film1.mpg A sample stream file 239.255.12.42
-rtsp://hostname.domain.org:1554/film2 /opt/media/film2.mpg Another stream 239.255.42.12
+++ /dev/null
-#!/usr/bin/python -O
-#
-# VideoLAN RTSP Server
-#
-# Author: Cyril Deguet <asmax@via.ecp.fr>
-
-
-import cfg,socket,struct,time,threading
-
-
-def ntpTime():
- "Return the current time in NTP decimal format"
- return "%d" % (int(time.time()) + 2208988800L)
-
-
-
-class SdpMessage:
- "Build a SDP message"
-
- uri = "http://www.videolan.org/"
-
- def __init__(self, sessionName, address, uri):
- "Build the message"
- self.sessionName = sessionName
- self.address = address
- self.uri = uri
-
- def getMessage(self):
- "Return the SDP message"
- msg = "v=0\r\n" + \
- "o=asmax " + ntpTime() + " " + ntpTime() + \
- " IN IP4 sphinx.via.ecp.fr\r\n" + \
- "s=" + self.sessionName + "\r\n" + \
- "u=" + self.uri + "\r\n" + \
- "t=0 0\r\n" + \
- "c=IN IP4 " + self.address + "/1\r\n" + \
- "m=video 1234 RTP/MP2T 33\r\n" + \
- "a=control:" + self.uri + "\r\n"
- return msg
-
-
-
-class SapServer(threading.Thread):
- "SAP server class"
-
- PORT = 9875
- GROUP = "224.2.127.254"
- TTL = 1
-
- def __init__(self):
- # Open the socket
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, self.TTL)
- self.sock.connect((self.GROUP, self.PORT))
-
- def sendMessage(self, message):
- "Message must be a SdpMessage"
- # FIXME
- header = " " + struct.pack("!BH", 12, 4212) + socket.inet_aton('138.195.156.214')
- data = header + message.getMessage()
- self.sock.send(data)
-
- def announce(self):
- for id, session in cfg.announceList.multicastList.items():
- message = SdpMessage(session.name, session.dest, session.uri)
- self.sendMessage(message)
-
- def run(self):
- while 1:
- self.announce()
- time.sleep(1)
+++ /dev/null
-#!/usr/bin/python -O
-#
-# VideoLAN RTSP Server
-#
-# Author: Cyril Deguet <asmax@via.ecp.fr>
-
-
-import cfg, random, time
-
-from streamer import VlcError, VlcStreamer
-
-
-class Session:
- "RTSP Session"
-
- def __init__(self, id, uri, dest):
- self.id = id
- self.uri = uri
- self.dest = dest
- self.state = 'ready'
- media = cfg.playlist.getMedia(self.uri)
- self.fileName = media['file']
- self.name = media['name']
- address = "rtp/ts://" + dest
- self.streamer = VlcStreamer(self.fileName, address)
-
- def play(self):
- "Play this session"
- if self.state == 'playing':
- print "Session " + self.id + " (" + self.fileName + "): already playing"
- return 0
- self.state = 'playing'
- print "Session " + self.id + " (" + self.fileName + "): play"
- try:
- self.streamer.play()
- except VlcError:
- print "Streamer: play failed"
- return -1
- cfg.announceList.addMulticastSession(self)
- return 0
-
- def pause(self):
- "Pause this session"
- print "Session " + self.id + " (" + self.fileName + "): pause"
- self.state = 'ready'
- try:
- self.streamer.pause()
- except VlcError:
- print "Streamer: pause failed"
- return -1
- return 0
-
- def stop(self):
- "Stop this session"
- print "Session " + self.id + " (" + self.fileName + "): stop"
- try:
- self.streamer.stop()
- except VlcError:
- print "Streamer: stop failed"
- return -1
- return 0
-
-
-
-class SessionList:
- "Manages RTSP sessions"
-
- list = {}
- chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
-
- def __init__(self):
- self.rand = random.Random(time.time())
-
- def newSessionId(self):
- "Build a random session id"
- id = ""
- for x in range(12):
- id += self.chars[self.rand.randrange(0, len(self.chars), 1)]
- return id
-
- def newSession(self, uri, dest):
- "Create a new RTSP session"
- id = self.newSessionId()
- while self.list.has_key(id):
- id = self.newSessionId()
- try:
- session = Session(id, uri, dest)
- except VlcError:
- print "Streamer: creation failed"
- return None
- self.list[id] = session
- print "New session: " + id
- return id
-
- def getSession(self, id):
- "Get a session from its session id"
- if self.list.has_key(id):
- return self.list[id]
- else:
- return None
-
- def delSession(self, id):
- "Delete a session"
- if self.list.has_key(id):
- del self.list[id]
- return 0
- else:
- return -1
-
-
+++ /dev/null
-#!/usr/bin/python -O
-#
-# VideoLAN RTSP Server
-#
-# Author: Cyril Deguet <asmax@via.ecp.fr>
-
-import cfg, vlc
-
-
-class VlcError(Exception):
- "Exception class for libvlc calls"
- pass
-
-
-
-class VlcStreamer:
- "Manage a streamer with libvlc"
-
- def __init__(self, file, address):
- "Create the streamer"
- self.file = file
- self.address = address
- self.id = vlc.create()
- if self.id < 0:
- raise VlcError
- if vlc.init(self.id, self.address) < 0:
- raise VlcError
- if vlc.addTarget(self.id, self.file) < 0:
- raise VlcError
-
- def play(self):
- "Play the stream"
- if vlc.play(self.id) < 0:
- raise VlcError
-
- def stop(self):
- "Stop the stream"
- if vlc.stop(self.id) < 0:
- raise VlcError
-
- def pause(self):
- "Pause the stream"
- if vlc.pause(self.id) < 0:
- raise VlcError
-
-
+++ /dev/null
-#!/usr/bin/python -O
-#
-# VideoLAN RTSP Server
-#
-# Author: Cyril Deguet <asmax@via.ecp.fr>
-
-
-import cfg, sap, SocketServer, string, sys, time
-
-from announce import AnnounceList
-from playlist import PlayList
-from rtsp import RtspServerHandler
-from session import SessionList
-
-
-PORT = 1554
-
-if len(sys.argv) == 1:
- print "Usage: vlrs <playlist>\n"
- sys.exit()
-
-cfg.playlist = PlayList()
-cfg.playlist.readConfig(sys.argv[1])
-cfg.sessionList = SessionList()
-cfg.announceList = AnnounceList()
-
-rtspServer = SocketServer.TCPServer(('', PORT), RtspServerHandler)
-try:
- rtspServer.serve_forever()
-except KeyboardInterrupt:
- rtspServer.server_close()
-