Introduction
Hello! 😎
In this tutorial, I will show you how to use Flask to create an endpoint that receives a video file, converts it to mp4, and then returns the mp4 to the user.
Requirements
- GStreamer Installed
- GObject Installed
The installation may vary depending on the operating system you are using.
Creating The Virtual Environment
First, we need to create the Python virtual environment, this can be done via the following command:
python3 -m venv env
Then it can be activated via the following:
source env/bin/activate
Done. Next, we need to install the dependencies.
Installing The Dependencies
Next, create a file called "requirements.txt" and add the following to it:
flask
pygobject
tempdir
To install the dependencies, run the following command:
pip install -r requirements.txt
All done! 😄 Now we can actually get coding.
Creating The Endpoint
Next, open up "main.py" First, we import the modules needed. Add the following imports:
from flask import Flask, request, send_file
import os
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject
import tempfile
import shutil
We also ensure GStreamer is above version 1.0.
Next, we need to initialize the Flask application and GStreamer; this can be done via the following line:
app = Flask(__name__)
Gst.init(None)
Next we will create the endpoint that will take a file, use GStreamer to convert the video into an mp4 and then return the file to the user.
@app.route('/convert', methods=['POST'])
def convert():
if 'file' not in request.files:
return 'No file part in the request', 400
file = request.files['file']
if file.filename == '':
return 'No selected file', 400
tmp_file = tempfile.NamedTemporaryFile(delete = False)
tmp_file.write(file.read())
tmp_file.close()
pipeline_str = f'filesrc location={tmp_file.name} ! decodebin ! x264enc ! mp4mux ! filesink location={tmp_file.name}.mp4'
pipeline = Gst.parse_launch(pipeline_str)
pipeline.set_state(Gst.State.PLAYING)
bus = pipeline.get_bus()
msg = bus.timed_pop_filtered(Gst.CLOCK_TIME_NONE,
Gst.MessageType.ERROR | Gst.MessageType.EOS)
pipeline.set_state(Gst.State.NULL)
if msg.type == Gst.MessageType.ERROR:
os.remove(tmp_file.name)
return f'Error converting file: {msg.parse_error()}'
return send_file(tmp_file.name + ".mp4", mimetype='video/mp4', as_attachment=True, download_name=tmp_file.name)
os.remove(tmp_file.name)
The code does quite a bit, but I try to explain it in order.
First of all, we check that the user has actually sent something and has a name; if not, we return the error to the user.
We then create a temp file to save the file that the user sent via the request in order to convert it using GStreamer.
We then create the GStreamer pipeline and then convert the file, we listen for any errors during conversion and, if an error occurs, inform the user.
If the conversion was a success, the file is sent back to the user, and the temporary file is removed.
Phew! Hopefully that explained it well enough for you to understand. 🥴
Finally, we need to write the main method:
if __name__ == "__main__":
app.run(debug=True)
Done! 😄
Trying It Out
Now we can actually run the code and try to convert a file. 👀
Start up the server with the following command:
python main.py
Once the server is started, you can try converting a file with the following curl command:
curl -X POST -F file=@big-buck-bunny_trailer.webm http://localhost:5000/convert -o output.mp4
You will need a file to test it with, so make sure to change the file option. Once done, you should see an output.mp4 file in the directory. You should also be able to play it.😺
Conclusion
Here I have shown how to create a simple video converter using Flask, Python, and GStreamer.
Hopefully this has been of some use to you, and as always, happy coding! 😎
You can find the source code for this tutorial via:
https://github.com/ethand91/flask-video-converter
Like me work? I post about a variety of topics, if you would like to see more, please like and follow me.
Also, I love coffee.
If you are looking to learn Algorithm Patterns to ace the coding interview, I recommend the following course
Top comments (1)
Good stuff. Anyone productising this will want to have some background process doing the transcoding, otherwise it will tie up a web server connection.
If I had my complicators gloves on it would be interesting to have the encoding process run by another service, e.g. celery, but also have some way for it to communicate back to the user.
The file could be piped to that service as it uploads, where possible encoding can happen at the same time and get status back to the user about the encoding process.