python-airplay icon indicating copy to clipboard operation
python-airplay copied to clipboard

Add support for using ffmpeg to transcode on the fly

Open cnelson opened this issue 9 years ago • 2 comments

If ffmpeg is installed on the host we are on, use it to do file serving and stream conversion

cnelson avatar Feb 23 '16 18:02 cnelson

Sketch:

Use ffprobe to probe the file and see if it is already playable. Code looks something like:

# parse our input file
try:
    obj = json.loads(
        subprocess.check_output([
            'ffprobe'

            "-v", #no output other than json
            "quiet",

            "-print_format", #output in json
            "json",

            "-show_format", #tell us about the container
            "-show_streams", #and whats inside

            path_or_url
        ])
    )
except subprocess.CalledProcessError:
    obj = None

For now, already playable for means:

  • Container is 'mov,mp4,m4a,3gp,3g2,mj2'
  • Video must be track 0 and be 'h264'
  • At least one 'aac' audio track (it's ok to send other tracks, AC3, etc)

In the future, we could use server_info() to inspect the device features and identify what formats it supports.

If the file meets those criteria then we don't need to do anything, play like we do today

If it needs a transcode, create a temporary directory (optionally allow the user to specify the base path, as on many systems, the default path returned by tempfile can be quite small) and launch ffmpeg in a subprocess with options like:

ffmpeg -i path_or_url -hls_list_size 0 -hls_flags single_file /some/generated/tempdir/foo.m3u8

We'll use RangeHTTPServer to deliver the HLS files to the AirPlay device. This will require a small change to RangeHTTPServer so it takes a list of allowed files (currently it only allows one) so it will allow access to both the m3u8 file and the .ts file ffmpeg will create.

Code would look something like:

if ap.can_play(path_or_url):
    url = path_or_url
else:
    # will use atexit to cleanup tempdir, so we don't leave huge video files lying around
    hls_files = ap.transcode(path_or_url, tmpdir=None)

    url = ap.serve(hls_files)

ap.play(url)

cnelson avatar Feb 26 '16 20:02 cnelson

a83f20601d561b94a6f7bb2e79d05d2f0c4addc6 fixes RangeHTTPServer to handle serving multiple files.

cnelson avatar Feb 29 '16 07:02 cnelson