I am trying to create a simple web server with twisted in python. I am having trouble serving an m4a audio file though.
In the current program, when I load http://localhost:8880/mp3.html, it works fine. It shows the audio player and the mp3 plays. In addition, the program prints both "/mp3.html" and "/test.mp3".
However, when I load http://localhost:8880/m4a.html, it doesn't work. It shows the audio player, but the m4a doesn't play. In addition, the program prints only "/m4a.html" and not "/test.m4a".
My current code is below.
import urlparse
import os
from twisted.internet import reactor
from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.web.static import File
import time
import subprocess
import mimetypes
class playM4A(Resource):
isLeaf = True
def render_GET(self, request):
this=urlparse.urlparse(request.path)#scheme,netloc,path,query
root,ext=os.path.splitext(this.path)
filename=os.path.basename(request.path)
fileFolder=request.path.replace(filename,"")
self.serverRoot=os.getcwd()
print request.path
if ext==".m4a":
thisFile=File(self.serverRoot+request.path)
return File.render_GET(thisFile,request)
elif ext==".mp3":
thisFile=File(self.serverRoot+request.path)
return File.render_GET(thisFile,request)
elif filename=="m4a.html":
return """
<html>
<audio controls>
<source src="http://localhost:8880/test.m4a" type="audio/mp4a-latm">
Your browser does not support the audio element.
</audio>
not m4a </html>"""
elif filename=="mp3.html":
return """
<html>
<audio controls>
<source src="http://localhost:8880/test.mp3" type="audio/mp3">
Your browser does not support the audio element.
</audio>
not m4a </html>"""
resource = playM4A()
factory = Site(resource)
reactor.listenTCP(8880, factory)
reactor.run()
The code works if you change audio/mp4a-latm to audio/mp4
Related
I am trying to share the desktop video of a windows virtual machine to show onto a linux Django web server. When I run the Python scripts, the screen sharing would show as a separate application window.
How do I get the Python separate window to show onto the Django web server instead?
receiver.py (running on linux machine)
from vidstream import StreamingServer
import threading
receiver = StreamingServer('ipaddr', 8080)
t = threading.Thread(target=receiver.start_server)
t.start()
while input("") != 'STOP':
continue
receiver.stop_server()
sender.py (running on windows virtual machine)
from vidstream import ScreenShareClient
import threading
sender = ScreenShareClient('ipaddr', 8080)
t = threading.Thread(target=sender.start_stream)
t.start()
while input("") != 'STOP':
continue
sender.stop_stream()
urls.py
from django.urls import path
from . import views
# URL configuration
urlpatterns = [
path('index/', views.getIndex),
path('', views.button),
path('receiver/', views.receiver),
]
views.py
from django.shortcuts import render
import requests
import sys
from subprocess import run,PIPE
from django.http import HttpResponse, StreamingHttpResponse
def button(request):
return render(request, 'receiver.html')
def receiver(request):
inp=request.POST.get()
out=run([sys.executable, "//home//cts//ctdjango//receiver.py"],shell=False,stdout=PIPE)
print(out)
return render(request, 'receiver.html', {'data':out.stdout})
receiver.html
<html>
<head>
<title>Cybertest Receiver</title>
</head>
<body>
<form action="/djangosite/templates/receiver.html" method="POST">
{% csrf_token %}
{% if data %}
<p>Output data: {{ data }}</p>
{% else %}
<p>No data output</p>
{% endif %}
<br><br>
<button type=“submit“>Run script</button>
</form>
</body>
</html>
I think the approach is not correct: to be able to play a video inside a browser you need to provide a proper streaming format supported by the browser.
I suggest m3u8 format, with this format you will also be able to see it using
software like VLC Media Player.
Proposed approach:
Your webserver will simply need serve two kind of files:
an index file (.m3u8)
pieces of video (called segment files) recorded from the screen capture
An example using python and gstreamer can be found here: Stream live video to browser using GStreamer
It is a starting point, what you want to achieve is reachable but you have to properly
connect together some pieces and is not trivial.
I'm currently trying to code something that will let websites view my webcam. I'm roughly following the tutorial linked on this website, except using Python and pygame instead of Processing.
At the moment, my code is grabbing a pygame image (which was originally a SimpleCV image), attempting to convert it into jpg format, and send it over websockets to the client where it will display it inside an img tag. However, I can't seem to figure out how to convert a pygame image into jpg and get it to display properly on the web browser.
This is my code for the server, which uses Flask and gevent:
#!/usr/bin/env python
import base64
import cStringIO
import time
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from flask import Flask, request, render_template
import pygame
pygame.init()
import SimpleCV as scv
app = Flask(__name__)
cam = scv.Camera(0)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/camera')
def camera():
if request.environ.get('wsgi.websocket'):
ws = request.environ['wsgi.websocket']
while True:
image = cam.getImage().flipHorizontal().getPGSurface()
data = cStringIO.StringIO()
pygame.image.save(image, data)
ws.send(base64.b64encode(data.getvalue()))
time.sleep(0.5)
if __name__ == '__main__':
http_server = WSGIServer(('',5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
This is my HTML file:
<!DOCTYPE HTML>
<html>
<head>
<title>Flask/Gevent WebSocket Test</title>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
if ("WebSocket" in window) {
cam = new WebSocket("ws://" + document.domain + ":5000/camera");
cam.onmessage = function (msg) {
$("#cam").attr('src', 'data:image/jpg;base64,' + msg.data);
};
cam.onerror = function(e) {
console.log(e);
}
} else {
alert("WebSocket not supported");
}
});
</script>
</head>
<body>
<img id="cam" src="" width="640" height="480" />
</body>
</html>
These are the specific lines that I think I'm having trouble with:
while True:
image = cam.getImage().flipHorizontal().getPGSurface()
data = cStringIO.StringIO()
pygame.image.save(image, data)
ws.send(base64.b64encode(data.getvalue()))
time.sleep(0.5)
Currently, if I try and run my code, going to localhost:5000 will display an invalid jpg image. It also becomes really laggy if I try running it on Firefox, but that may be an unrelated issue that I can debug later.
I've checked and made sure that the pygame image is a valid one, since I'm converting it from another library, and also checked that I was using websockets correctly by sending text data back and forth.
I've also tried calling pygame.image.to_string to try and convert the pygame surface into RGB format, but that also doesn't work.
What am I doing wrong?
Using the underlying PIL image, we can write to a file-like object, read back and base-64 encode it:
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from flask import Flask, request
from time import sleep
from cStringIO import StringIO
import pygame
pygame.init()
import SimpleCV as scv
app = Flask(__name__)
cam = scv.Camera(0)
#app.route('/camera')
def camera():
if request.environ.get('wsgi.websocket'):
ws = request.environ['wsgi.websocket']
while True:
fp = StringIO()
image = cam.getImage().flipHorizontal().getPIL()
image.save(fp, 'JPEG')
ws.send(fp.getvalue().encode("base64"))
#fp.close() << benchmark and memory tests needed
sleep(0.5)
if __name__ == '__main__':
http_server = WSGIServer(('',5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
I'm fighting with the same issue and the problem is a double codification. In the Python file, you have to remove the line "ws.send(base64.b64encode(data.getvalue()))" and send the image without encoded. Then in the js file, your script will make the codification and that all.
Really simple, I want to create a temporary html page that I display with the usual webbrowser.
Why does the following code produce an empty page?
import tempfile
import webbrowser
import time
with tempfile.NamedTemporaryFile('r+', suffix = '.html') as f:
f.write('<html><body><h1>Test</h1></body></html>')
webbrowser.open('file://' + f.name)
time.sleep(1) # to prevent the file from dying before displayed
Because your file doesn't exist on the disk and sits entirely in memory. That's why the browser starts but opens nothing since no code has been provided.
Try this:
#!/usr/bin/python
import tempfile
import webbrowser
tmp=tempfile.NamedTemporaryFile(delete=False)
path=tmp.name+'.html'
f=open(path, 'w')
f.write("<html><body><h1>Test</h1></body></html>")
f.close()
webbrowser.open('file://' + path)
Tested on Python 3.4.
import subprocess
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
PORT = 7000
HOST = '127.0.0.1'
SERVER_ADDRESS = '{host}:{port}'.format(host=HOST, port=PORT)
FULL_SERVER_ADDRESS = 'http://' + SERVER_ADDRESS
def TemproraryHttpServer(page_content_type, raw_data):
"""
A simpe, temprorary http web server on the pure Python 3.
It has features for processing pages with a XML or HTML content.
"""
class HTTPServerRequestHandler(BaseHTTPRequestHandler):
"""
An handler of request for the server, hosting XML-pages.
"""
def do_GET(self):
"""Handle GET requests"""
# response from page
self.send_response(200)
# set up headers for pages
content_type = 'text/{0}'.format(page_content_type)
self.send_header('Content-type', content_type)
self.end_headers()
# writing data on a page
self.wfile.write(bytes(raw_data, encoding='utf'))
return
if page_content_type not in ['html', 'xml']:
raise ValueError('This server can serve only HTML or XML pages.')
page_content_type = page_content_type
# kill a process, hosted on a localhost:PORT
subprocess.call(['fuser', '-k', '{0}/tcp'.format(PORT)])
# Started creating a temprorary http server.
httpd = HTTPServer((HOST, PORT), HTTPServerRequestHandler)
# run a temprorary http server
httpd.serve_forever()
if __name__ == '__main__':
def run_xml_server():
xml_data = """
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
"""
# open in a browser URL and see a result
webbrowser.open(FULL_SERVER_ADDRESS)
# run server
TemproraryHttpServer('xml', xml_data)
def run_html_server():
html_data = """
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
"""
# open in a browser URL and see a result
webbrowser.open(FULL_SERVER_ADDRESS)
# run server
TemproraryHttpServer('html', html_data)
# choice needed server:
# run_xml_server()
# run_html_server()
Just change the file's current position.
import tempfile
import webbrowser
import time
with tempfile.NamedTemporaryFile('r+', suffix = '.html') as f:
f.write('<html><body><h1>Test</h1></body></html>')
webbrowser.open('file://' + f.name)
f.seek(0)
time.sleep(1) # to prevent the file from dying before displayed
This piece of code is an edition to the previews one and continuation of the discussion with the OP. It shows time.sleep() after webbrowser.open(). I don't think it's actually needed because the /tmp directory is emptied automatically on a regular bases by the OS but the OP commented that if he deletes the temp file via Python it is deleted before it gets fully loaded by the browser. Most likely it happens because the "browser" process is detached from this scrip which is its parent and Python doesn't wait for the process completion before executing the next statement. I though it would be clear for everyone without explanation but obviously you, guys, don't read comments.
import os, time
# ...
webbrowser.open('file://' + path)
time.sleep(1)
if os.path.exists(path):
os.remove(path)
I'm trying just for learning how to serve a video with the blobstore without it takes all the screen the video, for example
here I imported Video as video_model
class ViewVideo(webapp.Reque...,blobstore_handlers.BlobstoreDownloadHandler):
def get(self):
video_id = self.request.get('video_id')
video_instance = None
if video_id:
video_instance = video_model().get_video_content(video_id)
self.response.headers['Content-Type'] = 'video/mp4'
self.send_blob(video_instance.content.key())
class Video(db.Model):
content = blobstore.BlobReferenceProperty()
title = db.StringProperty()
def get_video(self,video_id):
return Video.get_by_id(video_id)
def get_video_content(self,content):
query_str = "SELECT * FROM Video WHERE content =:content"
return db.GqlQuery(query_str,content=content).get()
Where the video_id came from a url given, but as you see I put it directly in send_blob() function and this one when I tested it takes all the screen just to see the video, I was wondering how can I serve the video from my application without happening this, I was thinking embedded HTML but I can't figure it out how the source will be
Any help will be grateful
If it lacks of content to answer the question I will edit it
Without HTML5, it's a tricky mess. With HTML5, it becomes easy & elegant. Serve to the user's browser, as part of whatever page you're serving, the following HTML (5) snippet:
<video width="320" height="240" controls>
<source src="/getmp4?video_id=whatever" type="video/mp4">
Your browser does not support the video tag: please upgrade it!
</video>
and use that ViewVideo handler to serve only the /getmp4 URL, not the URL that your user directly gets via their browser.
The 320, 240, and the choice to show controls, are all optional, of course -- as even more is the use of whatever for the video id!-)
I'm currently trying to code something that will let websites view my webcam. I'm roughly following the tutorial linked on this website, except using Python and pygame instead of Processing.
At the moment, my code is grabbing a pygame image (which was originally a SimpleCV image), attempting to convert it into jpg format, and send it over websockets to the client where it will display it inside an img tag. However, I can't seem to figure out how to convert a pygame image into jpg and get it to display properly on the web browser.
This is my code for the server, which uses Flask and gevent:
#!/usr/bin/env python
import base64
import cStringIO
import time
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from flask import Flask, request, render_template
import pygame
pygame.init()
import SimpleCV as scv
app = Flask(__name__)
cam = scv.Camera(0)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/camera')
def camera():
if request.environ.get('wsgi.websocket'):
ws = request.environ['wsgi.websocket']
while True:
image = cam.getImage().flipHorizontal().getPGSurface()
data = cStringIO.StringIO()
pygame.image.save(image, data)
ws.send(base64.b64encode(data.getvalue()))
time.sleep(0.5)
if __name__ == '__main__':
http_server = WSGIServer(('',5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
This is my HTML file:
<!DOCTYPE HTML>
<html>
<head>
<title>Flask/Gevent WebSocket Test</title>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
if ("WebSocket" in window) {
cam = new WebSocket("ws://" + document.domain + ":5000/camera");
cam.onmessage = function (msg) {
$("#cam").attr('src', 'data:image/jpg;base64,' + msg.data);
};
cam.onerror = function(e) {
console.log(e);
}
} else {
alert("WebSocket not supported");
}
});
</script>
</head>
<body>
<img id="cam" src="" width="640" height="480" />
</body>
</html>
These are the specific lines that I think I'm having trouble with:
while True:
image = cam.getImage().flipHorizontal().getPGSurface()
data = cStringIO.StringIO()
pygame.image.save(image, data)
ws.send(base64.b64encode(data.getvalue()))
time.sleep(0.5)
Currently, if I try and run my code, going to localhost:5000 will display an invalid jpg image. It also becomes really laggy if I try running it on Firefox, but that may be an unrelated issue that I can debug later.
I've checked and made sure that the pygame image is a valid one, since I'm converting it from another library, and also checked that I was using websockets correctly by sending text data back and forth.
I've also tried calling pygame.image.to_string to try and convert the pygame surface into RGB format, but that also doesn't work.
What am I doing wrong?
Using the underlying PIL image, we can write to a file-like object, read back and base-64 encode it:
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from flask import Flask, request
from time import sleep
from cStringIO import StringIO
import pygame
pygame.init()
import SimpleCV as scv
app = Flask(__name__)
cam = scv.Camera(0)
#app.route('/camera')
def camera():
if request.environ.get('wsgi.websocket'):
ws = request.environ['wsgi.websocket']
while True:
fp = StringIO()
image = cam.getImage().flipHorizontal().getPIL()
image.save(fp, 'JPEG')
ws.send(fp.getvalue().encode("base64"))
#fp.close() << benchmark and memory tests needed
sleep(0.5)
if __name__ == '__main__':
http_server = WSGIServer(('',5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
I'm fighting with the same issue and the problem is a double codification. In the Python file, you have to remove the line "ws.send(base64.b64encode(data.getvalue()))" and send the image without encoded. Then in the js file, your script will make the codification and that all.