shaka-packager/README.md

361 lines
13 KiB
Markdown

# ![Shaka Packager](docs/shaka-packager.png)
[![Build Status](https://travis-ci.org/google/shaka-packager.svg?branch=master)](https://travis-ci.org/google/shaka-packager)
[![Build status](https://ci.appveyor.com/api/projects/status/3t8iu603rp25sa74?svg=true)](https://ci.appveyor.com/project/shaka/shaka-packager)
Media packaging SDK intended for C++ programmers writing DASH/HLS packager
applications with common encryption support, Widevine DRM support, Live, and
Video-On-Demand.
This document provides the information needed to create a DASH/HLS packager
that is able to remux and encrypt a video into fragmented ISO BMFF format with
common encryption (CENC) support. The DASH/HLS packaging API is also designed
in such a way for easy extension to more source and destination formats.
Current supported codecs:
| Codecs | ISO-BMFF | WebM | MPEG2-TS | WVM |
|:-----------------:|:------------:|:------------:|:------------:|:-----------:|
| H264 (AVC) | I / O | - | I / O | I |
| H265 (HEVC) | I / O | - | I | - |
| VP8 | *I / O* | I / O | - | - |
| VP9 | *I / O* | I / O | - | - |
| AAC | I / O | - | I / O | I |
| Dolby AC3/EAC3 | I / O | - | - | - |
| DTS | I / O | - | - | - |
| Opus | *I / O* | I / O | - | - |
| Vorbis | - | I / O | - | - |
** I for input and O for output.
** VP8/VP9/Opus support in ISO-BMFF is experimental.
This project is supported on Linux, Windows and MacOSX platforms.
# Useful Links #
- [API Documentation](https://google.github.io/shaka-packager/docs)
- [Mailing List](https://groups.google.com/forum/#!forum/shaka-packager-users)
(join for release announcements or problem discussions)
- [Docker Builds](https://hub.docker.com/r/google/shaka-packager/tags/)
- Several open source players:
- [Web: Shaka Player](https://github.com/google/shaka-player)
- [Web: dash.js](https://github.com/Dash-Industry-Forum/dash.js)
- [Android: ExoPlayer](https://github.com/google/ExoPlayer)
# Setting Up For Development #
1. Packager source is managed by Git at
https://www.github.com/google/shaka-packager. We use gclient tool from Chromium
to manage third party libraries. You will need Git (v1.7.5 or above) installed
on your machine to access the source code.
2. Install Chromium depot tools which contains gclient and ninja
See http://www.chromium.org/developers/how-tos/install-depot-tools for
details.
3. Get the source
```Shell
mkdir shaka_packager
cd shaka_packager
gclient config https://www.github.com/google/shaka-packager.git --name=src
gclient sync
```
To sync to a particular commit or version, use 'gclient sync -r \<revision\>', e.g.
```Shell
# Sync to commit 4cb5326355e1559d60b46167740e04624d0d2f51
gclient sync -r 4cb5326355e1559d60b46167740e04624d0d2f51
# Sync to version 1.2.0
gclient sync -r v1.2.0
```
4. Build
We use ninja, which is much faster than make, to build our code:
```Shell
cd src
ninja -C out/{Debug,Release} [Module]
```
Module is optional. If not specified, build all, e.g.
```Shell
ninja -C out/Debug # build all modules in Debug mode
ninja -C out/Release # build all modules in Release mode
ninja -C out/Release mp4 # build mp4 module in Release mode
```
Refer to ninja manual for details.
We also provide a mechanism to change build configurations, for example,
developers can change build system to “make” by overriding *GYP_GENERATORS*.
```Shell
GYP_GENERATORS='make' gclient runhooks
```
Another example, developers can also enable clang by overriding *GYP_DEFINE*.
```Shell
GYP_DEFINES='clang=1' gclient runhooks
```
5. Updating the code
Update your current branch with *git pull* followed by *gclient sync*. Note
that if you are not on a branch, *git pull* will not work, and you will need
to use *git fetch* instead.
6. Contributing
See https://github.com/google/shaka-packager/blob/master/CONTRIBUTING.md for
details.
# Using Docker For Testing / Development #
[Docker](https://www.docker.com/whatisdocker) is a tool that can package an
application and its dependencies in a virtual container to run on different
host operating systems.
1. Install [Docker](https://docs.docker.com/installation/).
2. Pull prebuilt image from Dockerhub or build an image locally
2.a. Pull prebuilt image from Dockerhub
```Shell
docker pull google/shaka-packager
```
2.b. Build an image locally
```Shell
docker build -t google/shaka-packager github.com/google/shaka-packager.git
```
3. Run the container (`your_media_path` should be your media folder)
```Shell
docker run -v /your_media_path/:/media -it --rm google/shaka-packager
```
4. Testing
```Shell
# Make sure you run step 3 and you're inside the container.
cd /media
# VOD: mp4 --> dash
packager input=/media/example.mp4,stream=audio,output=audio.mp4 \
input=/media/example.mp4,stream=video,output=video.mp4 \
--profile on-demand --mpd_output example.mpd
# Leave the container.
exit
```
Outputs are available in your media folder `your_media_path`.
# Design Overview #
Major modules are described below:
Demuxer is responsible for extracting elementary stream samples from a
multimedia file, e.g. an ISO BMFF file. The demuxed streams can be fed into a
muxer to generate multimedia files. An optional KeySource can be provided to
Demuxer to decrypt CENC and WVM source content.
Demuxer reads from source through the File interface. A concrete LocalFile
class is already implemented. The users may also implement their own File class
if they want to read/write using a different kinds of protocol, e.g. network
storage, http etc.
Muxer is responsible for taking elementary stream samples and producing media
segments. An optional KeySource can be provided to Muxer to generate encrypted
outputs. Muxer writes to output using the same File interface as Demuxer.
Demuxer and Muxer are connected using MediaStream. MediaStream wraps the
elementary streams and is responsible for the interaction between Demuxer and
Muxer. A demuxer can transmits multiple MediaStreams; similarly, A muxer is
able to accept and mux multiple MediaStreams, not necessarily from the same
Demuxer.
MpdBuilder is responsible for the creation of Media Presentation Description as
specified in ISO/IEC 23009-1 DASH MPD spec.
Refer to [Design](docs/design.md),
[API](https://google.github.io/shaka-packager/docs) for details.
# DASH-IF IOP Compliance #
We try out best to be compliant to [Guidelines for Implementation: DASH-IF
Interoperability Points](http://dashif.org/wp-content/uploads/2015/04/DASH-IF-IOP-v3.0.pdf).
We are already compliant to most of the requirements specified by the document,
with two exceptions:
- ContentProtection elements are still put under Representation element instead
of AdaptationSet element;
- Representations encrypted with different keys are still put under the same
AdaptationSet.
We created a flag '--generate_dash_if_iop_compliant_mpd', if enabled,
- ContentProtection elements will be moved under AdaptationSet;
- Representations encrypted with different keys will be put under different
AdaptationSets, grouped by `@group` attribute.
Users can enable the flag '--generate_dash_if_iop_compliant_mpd' to have these
features. This flag will be enabled by default in a future release.
Please feel free to file a bug or feature request if there are any
incompatibilities with DASH-IF IOP or other standards / specifications.
# Driver Program Sample Usage #
Sample driver programs **packager** and **mpd_generator** are written using the
SDK.
Some sample usages:
Run the program without arguments will display the help page with the list of
command line arguments:
```Shell
packager
```
Dump stream info:
```Shell
packager input=sintel.mp4 --dump_stream_info
```
Demux audio from the input and generate a fragmented mp4:
```Shell
packager input=sintel.mp4,stream=audio,output=fragmented_sintel.mp4
```
Demux streams from the input and generates a mpd with on-demand profile along
with fragmented mp4:
```Shell
packager \
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
--profile on-demand \
--mpd_output sintel_vod.mpd
```
Includes a subtitle input from webvtt:
```Shell
packager \
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
input=sintel_english_input.vtt,stream=text,output=sintel_english.vtt \
--profile on-demand \
--mpd_output sintel_vod.mpd
```
You may also generate mpd with live profile. Here is an example with IPTV input
streams:
```Shell
packager \
'input=udp://224.1.1.5:5003,stream=audio,init_segment=live-audio.mp4,segment_template=live-audio-$Number$.mp4,bandwidth=130000' \
'input=udp://224.1.1.5:5003,stream=video,init_segment=live-video-sd.mp4,segment_template=live-video-sd-$Number$.mp4,bandwidth=2000000' \
'input=udp://224.1.1.5:5002,stream=video,init_segment=live-video-hd.mp4,segment_template=live-video-hd-$Number$.mp4,bandwidth=5000000' \
--profile live \
--mpd_output live.mpd
```
A UDP url is of the form udp://ip:port[?options]. Here is an example:
udp://224.1.1.5:5003?reuse=1&interface=10.11.12.13&timeout=1234567.
Three options are supported right now:
- reuse=1|0
Allow or disallow reusing UDP sockets. Default to 0.
- interface=interface_ip_address
Address of the interface over which to receive UDP multicast streams.
- timeout=microseconds
Timeout in microseconds. Default to unlimited.
Demux video from the input and generate an encrypted fragmented mp4 using
Widevine encryption with RSA signing key file *widevine_test_private.der*:
```Shell
packager input=sintel.mp4,stream=video,output=encrypted_sintel.mp4 \
--enable_widevine_encryption \
--key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \
--content_id "3031323334353637" \
--signer "widevine_test" \
--rsa_signing_key_path "widevine_test_private.der"
```
The program also supports AES signing. Here is an example with encryption key
rotates every 1800 seconds:
```Shell
packager \
'input=udp://224.1.1.5:5003,stream=audio,init_segment=live-audio.mp4,segment_template=live-audio-$Number$.mp4,bandwidth=130000' \
'input=udp://224.1.1.5:5003,stream=video,init_segment=live-video-sd.mp4,segment_template=live-video-sd-$Number$.mp4,bandwidth=2000000' \
'input=udp://224.1.1.5:5002,stream=video,init_segment=live-video-hd.mp4,segment_template=live-video-hd-$Number$.mp4,bandwidth=5000000' \
--profile live \
--mpd_output live.mpd \
--enable_widevine_encryption \
--key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \
--content_id "3031323334353637" \
--signer "widevine_test" \
--aes_signing_key "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9" \
--aes_signing_iv "d58ce954203b7c9a9a9d467f59839249" \
--crypto_period_duration 1800
```
Note that key rotation is only supported for live profile.
Demux and decrypt video from a WVM container, and generate encrypted fragmented
mp4 using Widevine encryption with RSA signing key file
*widevine_test_private.der*:
```Shell
packager input=sintel.wvm,stream=video,output=encrypted_sintel.mp4 \
--enable_widevine_decryption \
--enable_widevine_encryption \
--key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \
--content_id "3031323334353637" \
--signer "widevine_test" \
--rsa_signing_key_path "widevine_test_private.der"
```
The program can be told to generate MediaInfo files, which can be fed to
**mpd_generate** to generate the mpd file.
```Shell
packager \
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
--output_media_info
mpd_generator \
--input "sintel_video.mp4.media_info,sintel_audio.mp4.media_info" \
--output "sintel.mpd"
```
Output MPEG2-TS video.
```Shell
packager \
'input=bear-1280x720.mp4,stream=video,segment_template=bear$Number$.ts'
```
Output HLS playlists with MPEG2-TS video. The following outputs a Master
Playlist as `master.m3u8`. And the Media Playlist for the video as
`playlist.m3u8`. The optional `--hls_base_url` specifies the prefix for the
generated TS segments.
```Shell
packager \
'input=bear-1280x720.mp4,stream=video,segment_template=bear$Number$.ts,playlist_name=playlist.m3u8' \
--single_segment=false \
--hls_master_playlist_output="master.m3u8" \
--hls_base_url="http://localhost:10000/"
```
For audio Media Playlists, the name and group for EXT-X-MEDIA tag must be
specified.
```Shell
packager \
'input=input.mp4,stream=video,segment_template=output$Number$.ts,playlist_name=video_playlist.m3u8' \
'input=input.mp4,stream=audio,segment_template=output_audio$Number$.ts,playlist_name=audio_playlist.m3u8,hls_group_id=audio,hls_name=ENGLISH' \
--single_segment=false \
--hls_master_playlist_output="master_playlist.m3u8" \
--hls_base_url="http://localhost:10000/"
```