Windows Users:
For binary detection on Windows, ensure FFmpeg and FFProbe paths are added to your system path environment variable.
This library leverages FFmpeg to create media packages compatible with online streaming protocols like DASH (Dynamic Adaptive Streaming over HTTP) and HLS (HTTP Live Streaming). It also offers functionalities for DRM (Digital Rights Management) for HLS packaging and managing files stored in cloud storage.
GitHub Repository: https://github.com/quasarstream/python-ffmpeg-video-streaming
This library requires a functioning FFmpeg installation, including both FFMpeg and FFProbe binaries.
For binary detection on Windows, ensure FFmpeg and FFProbe paths are added to your system path environment variable.
Compatibility: This library is only compatible with Python 3.9 or higher.
pip install python-ffmpeg-video-streaming
python-ffmpeg-video-streaming>=0.1
Import the Library:
import ffmpeg_streaming
There are multiple ways to open a media resource:
video = ffmpeg_streaming.input('/var/media/video.mp4')
Refer to the FFmpeg Protocols Documentation for a list of supported resources (http, ftp, etc.).
video = ffmpeg_streaming.input('https://www.quasarstream.com/?"PATH TO A VIDEO FILE" or "PATH TO A LIVE HTTP STREAM"')
You can open a file from a cloud by passing an instance of the Cloud object to the `input` method.
from ffmpeg_streaming import S3
s3 = S3(aws_access_key_id='YOUR_KEY_ID', aws_secret_access_key='YOUR_KEY_SECRET', region_name='YOUR_REGION')
video = ffmpeg_streaming.input(s3, bucket_name="bucket-name", key="video.mp4")
Visit the provided link for examples on accessing files from Amazon S3, Google Cloud Storage, Microsoft Azure Storage, and custom cloud storage solutions.
You can pass the name of a supported, connected capture device(i.e. the name of a webcam, camera, screen and etc) to the input method to stream a live media over the network from your connected device.
video = ffmpeg_streaming.input('CAMERA NAME OR SCREEN NAME', capture=True)
Consult the FFmpeg documentation for capturing webcams and desktops.
Dynamic Adaptive Streaming over HTTP (DASH), also known as MPEG-DASH,allows high-quality streaming over the internet by segmenting content into short HTTP-based file downloads. Clients can choose the segment with the highest bitrate suitable for their network conditions, resulting in a seamless playback experience. Learn more
The library automatically generates Manifest (MPD) and segment files.
from ffmpeg_streaming import Formats
dash = video.dash(Formats.h264())
dash.auto_generate_representations()
dash.output('/var/media/dash.mpd')
To specify the exact kilobit rate and size for each stream, manually create Representation objects and add them to the dash or hls instance:
from ffmpeg_streaming import Formats, Bitrate, Representation, Size
_144p = Representation(Size(256, 144), Bitrate(95 * 1024, 64 * 1024))
_240p = Representation(Size(426, 240), Bitrate(150 * 1024, 94 * 1024))
_360p = Representation(Size(640, 360), Bitrate(276 * 1024, 128 * 1024))
_480p = Representation(Size(854, 480), Bitrate(750 * 1024, 192 * 1024))
_720p = Representation(Size(1280, 720), Bitrate(2048 * 1024, 320 * 1024))
_1080p = Representation(Size(1920, 1080), Bitrate(4096 * 1024, 320 * 1024))
_2k = Representation(Size(2560, 1440), Bitrate(6144 * 1024, 320 * 1024))
_4k = Representation(Size(3840, 2160), Bitrate(17408 * 1024, 320 * 1024))
dash = video.dash(Formats.h264())
dash.representations(_144p, _240p, _360p, _480p, _720p, _1080p, _2k, _4k)
dash.output('/var/media/dash.mpd')
To automatically generate HLS playlists for DASH and HLS, use the auto_generate_representations method:
from ffmpeg_streaming import Formats
dash = video.dash(Formats.h264())
dash.auto_generate_representations([1080, 720, 480])
dash.generate_hls_playlist()
dash.output('/var/media/dash.mpd')
For live streaming from a camera or screen, create Representation objects and add them to the dash instance:
from ffmpeg_streaming import Formats, Bitrate, Representation, Size
_240p = Representation(Size(426, 240), Bitrate(150 * 1024, 94 * 1024))
_360p = Representation(Size(640, 360), Bitrate(276 * 1024, 128 * 1024))
dash = video.dash(Formats.h264())
dash.representations(_240p, _360p)
dash.output('/var/media/dash.mpd')
The auto_generate_representations method cannot be used for camera-based media.
See DASH options and DASH documentation for more information.
HTTP Live Streaming (also known as HLS) is an adaptive bitrate streaming protocol. It uses HTTP-based file downloads and M3U playlists. Learn more
To create HLS files, use the hls instance and specify the output filename:
from ffmpeg_streaming import Formats
hls = video.hls(Formats.h264())
hls.auto_generate_representations()
hls.output('/var/media/hls.m3u8')
To specify the exact kilobit rate and size for each stream, manually create Representation objects and add them to the dash or hls instance:
from ffmpeg_streaming import Formats, Bitrate, Representation, Size
_360p = Representation(Size(640, 360), Bitrate(276 * 1024, 128 * 1024))
_480p = Representation(Size(854, 480), Bitrate(750 * 1024, 192 * 1024))
_720p = Representation(Size(1280, 720), Bitrate(2048 * 1024, 320 * 1024))
hls = video.hls(Formats.h264())
hls.representations(_360p, _480p, _720p)
hls.output('/var/media/hls.m3u8')
For fragmented MP4 format in HLS, use the fragmented_mp4 method:
from ffmpeg_streaming import Formats
hls = video.hls(Formats.h264())
hls.auto_generate_representations([360, 240])
hls.fragmented_mp4()
hls.output('/var/media/hls.m3u8')
For live streaming from a camera or screen, use the hls instance and specify the output filename:
from ffmpeg_streaming import Formats, Bitrate, Representation, Size
_480p = Representation(Size(854, 480), Bitrate(750 * 1024, 192 * 1024))
hls = video.hls(Formats.h264(), hls_list_size=10, hls_time=5)
hls.flags('delete_segments')
hls.representations(_480p)
hls.output('/var/media/hls.m3u8')
The auto_generate_representations method cannot be used for camera-based media. HEVC and VP9 formats are not supported for HLS packaging unless using fragmented MP4.
See HLS options and HLS documentation for more information.
HLS encryption uses the Advanced Encryption Standard (AES) in Cipher Block Chaining (CBC) mode. This means each block is encrypted using the previous block's ciphertext. Learn more
The following code generates a single key for all segments:
from ffmpeg_streaming import Formats
#A path you want to save a random key to your local machine
save_to = '/home/public_html/"PATH TO THE KEY DIRECTORY"/key'
#A URL (or a path) to access the key on your website
url = 'https://www.quasarstream.com/?"PATH TO THE KEY DIRECTORY"/key'
# or url = '/"PATH TO THE KEY DIRECTORY"/key';
hls = video.hls(Formats.h264())
hls.encryption(save_to, url)
hls.auto_generate_representations()
hls.output('/var/media/hls.m3u8')
You can optionally rotate encryption keys periodically by passing a "key rotation period" to the encryption method. This generates a new key after a specified number of segments. For example, with a value of 10, a new key will be created every 10 segments.
from ffmpeg_streaming import Formats
#A path you want to save a random key to your server
save_to = '/home/public_html/"PATH TO THE KEY DIRECTORY"/key'
#A URL (or a path) to access the key on your website
url = 'https://www.quasarstream.com/?"PATH TO THE KEY DIRECTORY"/key'
# or url = '/PATH TO THE KEY DIRECTORY/key';
hls = video.hls(Formats.h264())
hls.encryption(save_to, url, 10)
hls.auto_generate_representations([])
hls.output('/var/media/hls.m3u8')
While FFmpeg supports AES encryption for HLS, it's not a complete Digital Rights Management (DRM) solution. For a full DRM solution, consider FairPlay Streaming, which offers secure key exchange and playback protection across devices. Other options include Microsoft's PlayReady and Google’s Widevine.
It's crucial to secure your encryption keys on your website. Here are some methods:
The following code demonstrates how to monitor the transcoding process:
from ffmpeg_streaming import Formats
import sys
def monitor(ffmpeg, duration, time_, time_left, process):
"""
This function allows you to handle the transcoding process according to your needs.
Examples:
1. Logging or printing ffmpeg log
logging.info(ffmpeg) or print(ffmpeg)
2. Handling Process object based on specific events
if "something happened":
process.terminate()
3. Sending email notifications about completion time
if time_left > 3600 and not already_send:
# Send email if process takes more than an hour
ready_time = time_left + time.time()
Email.send(
email='[email protected]',
subject='Your video will be ready by %s' % datetime.timedelta(seconds=ready_time),
message='Your video takes more than %s hour(s) ...' % round(time_left / 3600)
)
already_send = True
4. Creating a progress bar or displaying other parameters to users
Socket.broadcast(
address=127.0.0.1
port=5050
data={
percentage = per,
time_left = datetime.timedelta(seconds=int(time_left))
}
)
:param ffmpeg: ffmpeg command line
:param duration: video duration
:param time_: current time of transcoded video
:param time_left: seconds left to finish transcoding
:param process: subprocess object
"""
per = round(time_ / duration * 100)
sys.stdout.write(
"\rTranscoding...(%s%%) %s left [%s%s]" %
(per, datetime.timedelta(seconds=int(time_left)), '#' * per, '-' * (100 - per))
)
sys.stdout.flush()
hls = video.hls(Formats.h264())
hls.auto_generate_representations([1080, 720, 480])
hls.output('/var/media/hls.m3u8', monitor=monitor)
You can define the output location by passing a local path to the output method. If the directory doesn't exist, the library will automatically create it for you.
Here's an example using DASH:
from ffmpeg_streaming import Formats
dash = video.dash(Formats.h264())
dash.auto_generate_representations()
dash.output('/var/media/dash.mpd')
If you omit the output parameter, the library will save the files to the same directory as the input file by default.
Here's an example using HLS:
from ffmpeg_streaming import Formats
hls = video.hls(Formats.h264())
hls.auto_generate_representations()
hls.output() # Saves to the input file's directory
When opening a file from cloud storage without specifying a local path, you must provide an output path using output to save it to your local machine.
The library allows you to save packaged files directly to cloud storage providers. This functionality is currently limited to Video On-Demand (VOD) and doesn't support live streaming.
To achieve this, you'll need to create a CloudManager object and configure your cloud storage credentials. Here's an example using Amazon S3:
from ffmpeg_streaming import S3, CloudManager
s3 = S3(aws_access_key_id='YOUR_KEY_ID', aws_secret_access_key='YOUR_KEY_SECRET', region_name='YOUR_REGION')
save_to_s3 = CloudManager().add(s3, bucket_name="bucket-name")
hls.output(clouds=save_to_s3)
For configuration details and examples with other cloud providers like Google Cloud Storage, Microsoft Azure Storage, refer to the provided link.
Additionally, you can save a local copy of the files while uploading to cloud storage:
hls.output('/var/media/hls.m3u8', clouds=save_to_s3)
This method allows you to upload the segmented files and update manifest files directly to an HTTP server or other supported protocols like FTP. This functionality is suitable for live streaming scenarios.
# DASH
dash.output('http://YOUR-WEBSITE.COM/live-stream/out.mpd')
# HLS
hls.save_master_playlist('/var/media/hls.m3u8')
#Before running the following code, ensure you've uploaded the master playlist file (/var/media/hls.m3u8) to your server using FTP or another method.
hls.output('ftp://[user[:password]@]server[:port]/var/media/hls.m3u8')
For HLS, you need to upload the master playlist file to the server manually before using this method.
This section explains how to extract information from a video file using our library.
from ffmpeg_streaming import FFProbe
# Specify the video file path
video_path = '/var/media/video.mp4'
# Create an FFProbe object
ffprobe = FFProbe(video_path)
# Save extracted information as JSON
ffprobe.save_as_json('probe.json')
# Access various data points
# All media information
all_media = ffprobe.all()
# Video format details
video_format = ffprobe.format()
# Stream information (all, video, audio)
streams = ffprobe.streams().all()
videos = ffprobe.streams().videos()
audios = ffprobe.streams().audios()
# Access individual streams
first_stream = ffprobe.streams().first_stream()
first_video = ffprobe.streams().video()
first_audio = ffprobe.streams().audio()
# Print extracted information
print("All Media Information:")
print(all_media)
print("\nVideo Format:")
print(video_format)
print("\nStreams:")
print(streams)
print("\nVideo Streams:")
for video in videos:
print(video)
print("\nAudio Streams:")
for audio in audios:
print(audio)
print("\nFirst Stream:")
print(first_stream)
print("\nFirst Video Stream:")
print(first_video)
print("\nFirst Audio Stream:")
print(first_audio)
# Calculate and print additional details
duration_seconds = float(video_format.get('duration', 0))
duration = datetime.timedelta(seconds=duration_seconds)
print(f"\nDuration: {duration}") # f-string for formatted output
size_kb = int(video_format.get('size', 0)) / 1024
print(f"Size: {round(size_kb)} KB") # f-string with round function
bitrate_kb = int(video_format.get('bit_rate', 0)) / 1024
print(f"Overall Bitrate: {round(bitrate_kb)} KB") # f-string
dimensions = (
first_video.get('width', "Unknown"),
first_video.get('height', "Unknown")
)
print(f"Dimensions: {dimensions[0]}x{dimensions[1]}") # f-string
video_bitrate_kb = int(first_video.get('bit_rate', 0)) / 1024
print(f"Video Bitrate: {round(video_bitrate_kb)} KB") # f-string
audio_bitrate_kb = int(first_audio.get('bit_rate', 0)) / 1024
print(f"Audio Bitrate: {round(audio_bitrate_kb)} KB") # f-string
This section demonstrates how to convert streams using our library. You'll provide a manifest URL to the input method.
from ffmpeg_streaming import Formats, Bitrate, Representation, Size
# Replace with the actual HLS manifest URL
hls_url = 'https://www.quasarstream.com/?PATH/TO/HLS-MANIFEST.M3U8'
# Define a video representation
_480p = Representation(Size(854, 480), Bitrate(750 * 1024, 192 * 1024))
# Create a DASH output
video = ffmpeg_streaming.input(hls_url)
dash = video.dash(Formats.h264())
dash.representations(_480p)
dash.output('/var/media/dash.mpd')
from ffmpeg_streaming import Formats
# Replace with the actual DASH manifest URL
dash_url = 'https://www.quasarstream.com/?PATH/TO/DASH-MANIFEST.MPD'
# Create an HLS output
video = ffmpeg_streaming.input(dash_url)
hls = video.hls(Formats.h264())
hls.auto_generate_representations()
hls.output('/var/media/hls.m3u8')
from ffmpeg_streaming import Formats
# Replace with the actual manifest URL (DASH or HLS)
manifest_url = 'https://www.quasarstream.com/?PATH/TO/MANIFEST.MPD or M3U8'
# Create a file output
video = ffmpeg_streaming.input(manifest_url)
stream = video.stream2file(Formats.h264())
stream.output('/var/media/new-video.mp4')
Here are some recommended open-source players for playing packaged videos:
Need a solution that's perfectly aligned with your unique requirements? Our custom features can handle high volume and complexity. Contact Us to discuss your needs.