Search code examples
pythonherokuffmpegbuildpack

How to use the Heroku buildpack ffmpeg for Python?


I want to use the ffmpeg buildpack in my Python app on Heroku.
I am using the ffmpeg buildpack from https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.

How can I use buildpack? subprocess? os? How to call the ffmpeg? Anybody can teach me?

This is my code and I want to convert mp4 file to mp3 file. Actually,I don`t know about the detect/compile/release file.

   subprocess.call(['ffmpeg', '-i', 'xxx.mp4','-vn','-f mp3', 'xxx.mp3'])
   subprocess.call(['ffmpeg', '-i', 'xxx.mp4','-vn','-f mp3', 'xxx.mp3'])

Solution

  • First of, I assume you already know how to deploy a Python app to Heroku and you already have a working app accessible from Heroku, as this answer is specific to how to use the ffmpeg buildpack. (If you don't yet, check Getting Started on Heroku with Python first).

    Step 1: Adding the ffmpeg buildpack

    Buildpacks basically tell Heroku how to setup the environment for your app (which dependencies to install, which scripts to run, etc.). For Python apps, you need to have the official heroku/python buildpack, and you can check this by:

    $ heroku buildpacks
    === ginomempin-ffmpeg-app Buildpack URL
    heroku/python
    

    To add other dependencies (ffmpeg), you need to install the buildpack for it on your Heroku app (ex. https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest). From the Heroku docs on Adding a buildpack, this is done by heroku buildpacks:add <buildpack>:

    $ heroku buildpacks:add --index 2 https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git
    Buildpack added. Next release on ginomempin-ffmpeg-app will use:
      1. heroku/python
      2. https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git
    Run git push heroku master to create a new release using these buildpacks.
    
    $ heroku buildpacks
    === ginomempin-ffmpeg-app Buildpack URLs
    1. heroku/python
    2. https://github.com/jonathanong/heroku-buildpack-ffmpeg-latest.git
    

    Note the --index 2 there in my example. This is just to order the buildpacks, Python first since it's the main buildpack, then ffmpeg second. It depends on your app.

    Now, test it by making changes to your code then deploy (i.e. git push heroku master). The Heroku logs should display that the buildpack is now added:

    remote: -----> Python app detected
    remote: -----> Installing requirements with pip
    remote:
    remote: -----> ffmpeg app detected
    remote: -----> Install ffmpeg
    remote:        DOWNLOAD_URL =  https://johnvansickle.com/ffmpeg/builds/ffmpeg-git-amd64-static.tar.xz
    remote:        exporting PATH
    

    Step 2: Checking the ffmpeg buildpack

    Use the heroku run command to check how to use the installed ffmpeg. For this sample app, I pushed a assets/sample.mp4 test file on the root directory of my app.

    ├── app.py
    ├── assets
    │   └── sample.mp4
    ├── ...
    └── runtime.txt
    
    $ heroku run "which ffmpeg"
    Running which ffmpeg on ⬢ ginomempin-ffmpeg-app... up, run.7460 (Free)
    /app/vendor/ffmpeg/ffmpeg
    
    $ heroku run "ffmpeg -i assets/sample.mp4 -vn -f mp3 assets/sample.mp3"
    ...
    Output #0, mp3, to 'assets/sample.mp3':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        ...
    

    Once you now know how to run your ffmpeg commands (and that it works), all you have to do is call the same set of commands from your app. Note that, you don't need to change directories (as you did with your initial code) or specify the path to ffmpeg.

    Step 3: Calling ffmpeg from Python app

    Using Python's subprocess to call the same commands:

    cmd = ['ffmpeg', '-i', './assets/sample.mp4', '-vn', '-f', 'mp3', './assets/sample.mp3']
    out = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print(out.stdout)
    print(out.stderr)
    for f in os.listdir("./assets"):
        print(f)
    

    Make sure that you separate all the space-separated parts of the command into a separate element in the list. You can then check the output using heroku logs --tail (for some reason, the ffmpeg output is stored in stderr instead of stdout):

    2019-09-29T11:54:57.050692+00:00 app[web.1]: b''
    2019-09-29T11:54:57.050736+00:00 app[web.1]: b"ffmpeg version N-50091-gfc20ba9e04-static https://johnvansickle.com/ffmpeg/  
    ...  
    Output #0, mp3, to './assets/sample.mp3':\n  
      Metadata:\n    
        major_brand     : isom\n  
        minor_version   : 512\n  
        compatible_brands: isomiso2avc1mp41\n    
        TSSE            : Lavf58.33.100\n   
    ...
    2019-09-29T11:54:57.050809+00:00 app[web.1]: sample.mp4
    2019-09-29T11:54:57.050815+00:00 app[web.1]: sample.mp3
    

    You should be getting the same subprocess.run output as the output you get when you use heroku run.