Created
May 28, 2018 11:46
-
-
Save anthonyeden/f3b3bdf6f62badd8f87bb574283f488a to your computer and use it in GitHub Desktop.
Sending FFmpeg output to HTTP, via Python's Flash
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Streaming FFmpeg to HTTP, via Python's Flask. | |
This is an incredibly simple example, which will yield issues due to inconsistant input and output rates. | |
If you're going to use this, VLC works okay as a client. | |
You really need to move FFmpeg into a separate thread, which should help stream audio more consistantly to the HTTP client. | |
Example by Anthony Eden (https://mediarealm.com.au) | |
""" | |
from flask import Flask | |
from flask import stream_with_context, request, Response | |
import subprocess | |
import time | |
app = Flask(__name__) | |
@app.route("/") | |
def hello(): | |
def generate(): | |
startTime = time.time() | |
buffer = [] | |
sentBurst = False | |
ffmpeg_command = ["ffmpeg", "-f", "avfoundation", "-i", ":2", "-acodec", "libmp3lame", "-ab", "32k", "-ac", "1", "-f", "mpeg", "pipe:stdout"] | |
process = subprocess.Popen(ffmpeg_command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, bufsize = -1) | |
while True: | |
# Get some data from ffmpeg | |
line = process.stdout.read(1024) | |
# We buffer everything before outputting it | |
buffer.append(line) | |
# Minimum buffer time, 3 seconds | |
if sentBurst is False and time.time() > startTime + 3 and len(buffer) > 0: | |
sentBurst = True | |
for i in range(0, len(buffer) - 2): | |
print "Send initial burst #", i | |
yield buffer.pop(0) | |
elif time.time() > startTime + 3 and len(buffer) > 0: | |
yield buffer.pop(0) | |
process.poll() | |
if isinstance(process.returncode, int): | |
if process.returncode > 0: | |
print 'FFmpeg Error', p.returncode | |
break | |
return Response(stream_with_context(generate()), mimetype = "audio/mpeg") | |
if __name__ == "__main__": | |
app.run() |
I never understood how it worked, but do now from this blog
https://cjwebb.com/posts/python-docker-ffmpeg-h264-mp4/
The link above is broken... but there is another one
https://cjwebb.com/python-docker-ffmpeg-h264-mp4/
any idea how to close the connection and make it work better??
You can catch GeneratorExit exception inside the generate function. Here's the link: pallets/flask#2702 (comment)
I tested and it worked flawlessly.
Another option to kill the process is to use the call_on_close
decorator:
response = Response(stream_with_context(generate()), mimetype = "audio/mpeg")
@response.call_on_close
def on_close():
process.kill()
return response
But you need to start the ffmpeg process outside of the generate
closure e.g.
ffmpeg_command = ["ffmpeg", "-f", "avfoundation", "-i", ":2", "-acodec", "libmp3lame", "-ab", "32k", "-ac", "1", "-f", "mpeg", "pipe:stdout"]
process = subprocess.Popen(ffmpeg_command, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, bufsize = -1)
def generate():
startTime = time.time()
buffer = []
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
any idea how to close the connection and make it work better??