Added architecture diagram
Also remove outdated design.md. Change-Id: I237b374a2fffe348b1daf5f8d1c37c57b4898fde
This commit is contained in:
parent
068e220ac7
commit
75e1fc3175
239
docs/design.md
239
docs/design.md
|
@ -1,239 +0,0 @@
|
||||||
#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.
|
|
||||||
|
|
||||||
API document is available at https://google.github.io/shaka-packager/docs.
|
|
||||||
|
|
||||||
##Creating Demuxer##
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// Create a demuxer from |input_media_file|.
|
|
||||||
// |input_media_file| could be any supported files, e.g. if the users have
|
|
||||||
// implemented a network file interface with prefix “network”,
|
|
||||||
// |input_media_file| with value “network://xxxx” would open a network
|
|
||||||
// file automatically.
|
|
||||||
Demuxer demuxer(input_media_file);
|
|
||||||
```
|
|
||||||
|
|
||||||
##Creating KeySource for source content decryption##
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// A KeySource is required if the source content is encrypted, since the media
|
|
||||||
// must be decrytped prior to further processing.
|
|
||||||
```
|
|
||||||
|
|
||||||
###WidevineKeySource###
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// Users may use WidevineKeySource to fetch keys from Widevine
|
|
||||||
// common encryption server.
|
|
||||||
|
|
||||||
scoped_ptr<WidevineKeySource> widevine_decryption_key_source(
|
|
||||||
new WidevineKeySource(key_server_url));
|
|
||||||
|
|
||||||
// A request signer might be required to sign the common encryption request.
|
|
||||||
scoped_ptr<RequestSigner> signer(
|
|
||||||
RsaRequestSigner::CreateSigner(signer_name, pkcs1_rsa_private_key));
|
|
||||||
if (!signer) { … }
|
|
||||||
widevine_decryption_key_source->set_signer(signer.Pass());
|
|
||||||
|
|
||||||
// Set encryption key source to demuxer.
|
|
||||||
muxer->SetKeySource(widevine_decryption_key_source.Pass());
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
##Creating MpdBuilder##
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// |mpd_type| indicates whether the mpd should be for VOD or live profile.
|
|
||||||
// |mpd_options| contains a set of configurable options. See below for details.
|
|
||||||
MpdBuilder mpd_builder(mpd_type, mpd_options);
|
|
||||||
```
|
|
||||||
|
|
||||||
Mpd Options
|
|
||||||
```C++
|
|
||||||
// Specifies, in seconds, a common duration used in the definition of the MPD
|
|
||||||
// Representation data rate.
|
|
||||||
mpd_options.min_buffer_time = 5.0;
|
|
||||||
|
|
||||||
// The below options are for live profile only.
|
|
||||||
|
|
||||||
// Indicates to the player how often to refresh the media presentations, in
|
|
||||||
// seconds.
|
|
||||||
mpd_options.minimum_update_period = 5.0;
|
|
||||||
|
|
||||||
// Guranteed duration of the time shifting buffer, in seconds.
|
|
||||||
mpd_options.time_shift_buffer_depth = 1800.0;
|
|
||||||
|
|
||||||
// Specifies a delay, in seconds, to be added to the media presentation time.
|
|
||||||
mpd_options.suggested_presentation_delay = 10.0;
|
|
||||||
```
|
|
||||||
|
|
||||||
Using MpdBuilder Instance
|
|
||||||
```C++
|
|
||||||
mpd_builder.AddBaseUrl("http://foo.com/bar"); // Add a <BaseURL> element.
|
|
||||||
AdaptationSet* video_adaptation_set = mpd_builder.AddAdaptationSet();
|
|
||||||
|
|
||||||
// Create MediaInfo object.
|
|
||||||
Representation* representation =
|
|
||||||
video_adaptation_set->AddRepresentation(media_info_object);
|
|
||||||
assert(representation); // Make sure it succeeded.
|
|
||||||
// |representation| is owned by |video_adatptation_set|, no additional
|
|
||||||
// operations are required to generate a valid MPD.
|
|
||||||
|
|
||||||
std::cout << mpd_builder.ToString() << std::endl; // Print the MPD to stdout.
|
|
||||||
```
|
|
||||||
|
|
||||||
MpdWriter: MpdBuilder Wrapper class
|
|
||||||
```C++
|
|
||||||
// Get file names with MediaInfo protobuf, i.e. media_info_files (array).
|
|
||||||
MpdWrite mpd_writer;
|
|
||||||
for (size_t i = 0; i < n; ++i)
|
|
||||||
mpd_writer.AddFile(media_info_files[i]);
|
|
||||||
|
|
||||||
mpd_writer.WriteMpdToFile("output_file_name.mpd");
|
|
||||||
```
|
|
||||||
|
|
||||||
##Creating Muxer##
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// See below for muxer options.
|
|
||||||
MuxerOptions muxer_options;
|
|
||||||
|
|
||||||
// Create a MP4Muxer with options specified by |options|.
|
|
||||||
mp4::MP4Muxer muxer(muxer_options);
|
|
||||||
```
|
|
||||||
|
|
||||||
Muxer Options
|
|
||||||
```C++
|
|
||||||
// Generate a single segment for each media presentation. This option
|
|
||||||
// should be set for on demand profile.
|
|
||||||
muxer_options.single_segment = true;
|
|
||||||
|
|
||||||
// Segment duration in seconds. If single_segment is specified, this parameter
|
|
||||||
// sets the duration of a subsegment; otherwise, this parameter sets the
|
|
||||||
// duration of a segment. A segment can contain one to many fragments.
|
|
||||||
muxer_options.segment_duration = 10.0;
|
|
||||||
|
|
||||||
// Fragment duration in seconds. Should not be larger than the segment
|
|
||||||
// duration.
|
|
||||||
muxer_options.fragment_duration = 2.0;
|
|
||||||
|
|
||||||
// Force segments to begin with stream access points. Segment duration may
|
|
||||||
// not be exactly what asked by segment_duration.
|
|
||||||
muxer_options.segment_sap_aligned = true;
|
|
||||||
|
|
||||||
// Force fragments to begin with stream access points. Fragment duration
|
|
||||||
// may not be exactly what asked by segment_duration. Imply
|
|
||||||
// segment_sap_aligned.
|
|
||||||
muxer_options.fragment_sap_aligned = true;
|
|
||||||
|
|
||||||
// For ISO BMFF only.
|
|
||||||
// Set the number of subsegments in each SIDX box. If 0, a single SIDX box
|
|
||||||
// is used per segment. If -1, no SIDX box is used. Otherwise, the Muxer
|
|
||||||
// will pack N subsegments in the root SIDX of the segment, with
|
|
||||||
// segment_duration/N/fragment_duration fragments per subsegment.
|
|
||||||
muxer_options.num_subsegments_per_sidx = 1;
|
|
||||||
|
|
||||||
// Output file name. If segment_template is not specified, the Muxer
|
|
||||||
// generates this single output file with all segments concatenated;
|
|
||||||
// Otherwise, it specifies the init segment name.
|
|
||||||
muxer_options.output_file_name = …;
|
|
||||||
|
|
||||||
// Specify output segment name pattern for generated segments. It can
|
|
||||||
// furthermore be configured by using a subset of the SegmentTemplate
|
|
||||||
// identifiers: $RepresentationID$, $Number$, $Bandwidth$ and $Time$.
|
|
||||||
// Optional.
|
|
||||||
muxer_options.segment_template = …;
|
|
||||||
|
|
||||||
// Specify the temporary directory for intermediate files.
|
|
||||||
muxer_options.temp_dir = …;
|
|
||||||
|
|
||||||
// User specified bit rate for the media stream. If zero, the muxer will
|
|
||||||
// attempt to estimate.
|
|
||||||
muxer_options.bandwidth = 0;
|
|
||||||
```
|
|
||||||
|
|
||||||
##Creating KeySource for content encryption##
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// A KeySource is optional. The stream won’t be encrypted if an
|
|
||||||
// KeySource is not provided.
|
|
||||||
```
|
|
||||||
|
|
||||||
###WidevineKeySource###
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// Users may use WidevineKeySource to fetch keys from Widevine
|
|
||||||
// common encryption server.
|
|
||||||
|
|
||||||
scoped_ptr<WidevineKeySource> widevine_encryption_key_source(
|
|
||||||
new WidevineKeySource(key_server_url, signer.Pass()));
|
|
||||||
|
|
||||||
// A request signer might be required to sign the common encryption request.
|
|
||||||
scoped_ptr<RequestSigner> signer(
|
|
||||||
RsaRequestSigner::CreateSigner(signer_name, pkcs1_rsa_private_key));
|
|
||||||
if (!signer) { … }
|
|
||||||
widevine_encryption_key_source->set_signer(signer.Pass());
|
|
||||||
|
|
||||||
// Grab keys for the content.
|
|
||||||
status = widevine_encryption_key_source->FetchKeys(content_id, policy));
|
|
||||||
if (!status.ok()) { … }
|
|
||||||
|
|
||||||
// Set encryption key source to muxer.
|
|
||||||
// |max_sd_pixels| defines the threshold to determine whether a video track
|
|
||||||
// should be considered as SD or HD and accordingly, whether SD key or HD key
|
|
||||||
// should be used to encrypt the stream.
|
|
||||||
// |clear_lead| specifies clear lead duration in seconds.
|
|
||||||
// |crypto_period_duration| if not zero, enable key rotation with specified
|
|
||||||
// crypto period.
|
|
||||||
muxer->SetKeySource(
|
|
||||||
widevine_encryption_key_source.get(), max_sd_pixels,
|
|
||||||
clear_lead, crypto_period_duration);
|
|
||||||
```
|
|
||||||
|
|
||||||
##Connecting Demuxer and Muxer##
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// Initialize the demuxer.
|
|
||||||
status = demuxer.Initialize();
|
|
||||||
if (!status.ok()) { … }
|
|
||||||
|
|
||||||
// After intializing the demuxer, we can query demuxer streams
|
|
||||||
// using demuxer.streams().
|
|
||||||
// The function below adds the first stream into muxer, which sets up
|
|
||||||
// the connection between Demuxer and Muxer.
|
|
||||||
status = muxer.AddStream(demuxer.streams()[0]);
|
|
||||||
if (!status.ok()) { … }
|
|
||||||
```
|
|
||||||
|
|
||||||
##Starting Remuxing##
|
|
||||||
|
|
||||||
```C++
|
|
||||||
// Starts remuxing process. It runs until completion or abort due to error.
|
|
||||||
status = demuxer.Run();
|
|
||||||
if (!status.ok()) { … }
|
|
||||||
```
|
|
|
@ -35,6 +35,7 @@ extensions = ['sphinx.ext.autodoc',
|
||||||
'sphinx.ext.mathjax',
|
'sphinx.ext.mathjax',
|
||||||
'sphinx.ext.viewcode',
|
'sphinx.ext.viewcode',
|
||||||
'sphinx.ext.githubpages',
|
'sphinx.ext.githubpages',
|
||||||
|
'sphinxcontrib.plantuml',
|
||||||
'cloud_sptheme.ext.table_styling',
|
'cloud_sptheme.ext.table_styling',
|
||||||
'breathe']
|
'breathe']
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
Design
|
||||||
|
======
|
||||||
|
|
||||||
|
Architecture diagram
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. graphviz::
|
||||||
|
|
||||||
|
digraph shaka_packager {
|
||||||
|
label=<<u>Shaka Packager Architecture</u>>
|
||||||
|
labelloc=t
|
||||||
|
|
||||||
|
subgraph cluster_media {
|
||||||
|
label=<<u>Media Processing Pipeline</u>>
|
||||||
|
|
||||||
|
Demuxer, ChunkingHandler, EncryptionHandler, Replicator,
|
||||||
|
TrickplayHandler, Muxer [shape=rectangle]
|
||||||
|
|
||||||
|
Demuxer -> ChunkingHandler [style=bold headlabel="many" taillabel="1"]
|
||||||
|
ChunkingHandler -> EncryptionHandler -> Replicator -> TrickplayHandler
|
||||||
|
-> Muxer [style=bold]
|
||||||
|
ChunkingHandler -> Replicator -> Muxer [style=bold]
|
||||||
|
}
|
||||||
|
|
||||||
|
MuxerListener, MpdNotifyMuxerListener, HlsNotifyMuxerListener,
|
||||||
|
MpdNotifier, HlsNotifier [shape=rectangle style=rounded]
|
||||||
|
|
||||||
|
Muxer -> MuxerListener
|
||||||
|
MuxerListener -> MpdNotifyMuxerListener, HlsNotifyMuxerListener
|
||||||
|
[dir=back arrowtail=onormal]
|
||||||
|
|
||||||
|
subgraph cluster_manifest {
|
||||||
|
label=<<u>Manifest Generation</u>>
|
||||||
|
|
||||||
|
HlsNotifyMuxerListener -> HlsNotifier [headlabel="1" taillabel="many"]
|
||||||
|
MpdNotifyMuxerListener -> MpdNotifier [headlabel="1" taillabel="many"]
|
||||||
|
|
||||||
|
MasterPlaylist, MediaPlaylist, MpdBuilder, AdaptationSet,
|
||||||
|
Representation [shape=trapezium]
|
||||||
|
|
||||||
|
HlsNotifier -> MasterPlaylist
|
||||||
|
MasterPlaylist -> MediaPlaylist
|
||||||
|
[dir=back arrowtail=diamond headlabel="many" taillabel="1"]
|
||||||
|
MpdNotifier -> MpdBuilder
|
||||||
|
MpdBuilder -> AdaptationSet -> Representation
|
||||||
|
[dir=back arrowtail=diamond headlabel="many" taillabel="1"]
|
||||||
|
|
||||||
|
{rank=same; MasterPlaylist, MpdBuilder}
|
||||||
|
{rank=same; MediaPlaylist, Representation}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.. graphviz::
|
||||||
|
|
||||||
|
digraph shaka_packager {
|
||||||
|
subgraph cluster_demuxer {
|
||||||
|
style=rounded
|
||||||
|
label=<<u> </u>>
|
||||||
|
|
||||||
|
Demuxer2 [label="Demuxer" shape=rectangle]
|
||||||
|
Demuxer2 -> MediaParser
|
||||||
|
[dir=back arrowtail=diamond headlabel="1" taillabel="1"]
|
||||||
|
MediaParser -> Mp4MediaParser, WebMMediaParser, Mp2tMediaParser,
|
||||||
|
WvmMediaParser [dir=back arrowtail=onormal]
|
||||||
|
}
|
||||||
|
|
||||||
|
subgraph cluster_muxer {
|
||||||
|
style=rounded
|
||||||
|
label=<<u> </u>>
|
||||||
|
|
||||||
|
Muxer2 [label="Muxer" shape=rectangle]
|
||||||
|
Muxer2 -> Mp4Muxer, WebMMuxer, Mp2tMuxer [dir=back arrowtail=onormal]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.. graphviz::
|
||||||
|
|
||||||
|
digraph shaka_packager {
|
||||||
|
subgraph cluster_legend {
|
||||||
|
style=rounded
|
||||||
|
label=<<u>Legend</u>>
|
||||||
|
|
||||||
|
node [shape=plaintext]
|
||||||
|
|
||||||
|
blank1 [label="" height=0]
|
||||||
|
blank2 [label="" height=0]
|
||||||
|
blank3 [label="" height=0]
|
||||||
|
|
||||||
|
"Composition" -> blank1 [dir=back arrowtail=diamond]
|
||||||
|
"Inheritance" -> blank2 [dir=back arrowtail=onormal]
|
||||||
|
"MediaHandler data flow" -> blank3 [style=bold]
|
||||||
|
|
||||||
|
"Bridge Class" [shape=rectangle style=rounded]
|
||||||
|
"Manifest Class" [shape=trapezium]
|
||||||
|
MediaHandler [shape=rectangle]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Media handler data flow
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
.. graphviz::
|
||||||
|
|
||||||
|
digraph g {
|
||||||
|
rankdir=LR
|
||||||
|
|
||||||
|
StreamData [
|
||||||
|
label="{... | SegmentInfo | MediaSample ... | SegmentInfo | MediaSample ... | StreamInfo}"
|
||||||
|
shape=record
|
||||||
|
style=rounded
|
||||||
|
];
|
||||||
|
|
||||||
|
MediaHandler [shape=rectangle]
|
||||||
|
MediaHandler2 [shape=rectangle, label=MediaHandler]
|
||||||
|
MediaHandler -> StreamData -> MediaHandler2
|
||||||
|
}
|
||||||
|
|
||||||
|
.. uml::
|
||||||
|
|
||||||
|
MediaHandler -> MediaHandler2 : StreamInfo
|
||||||
|
MediaHandler -> MediaHandler2 : MediaSample
|
||||||
|
MediaHandler -> MediaHandler2 : MediaSample
|
||||||
|
MediaHandler -> MediaHandler2 : ...
|
||||||
|
MediaHandler -> MediaHandler2 : MediaSample
|
||||||
|
MediaHandler -> MediaHandler2 : SegmentInfo
|
||||||
|
MediaHandler -> MediaHandler2 : MediaSample
|
||||||
|
MediaHandler -> MediaHandler2 : MediaSample
|
||||||
|
MediaHandler -> MediaHandler2 : ...
|
||||||
|
MediaHandler -> MediaHandler2 : MediaSample
|
||||||
|
MediaHandler -> MediaHandler2 : SegmentInfo
|
||||||
|
MediaHandler -> MediaHandler2 : ...
|
|
@ -13,6 +13,7 @@ source code repository: https://github.com/google/shaka-packager
|
||||||
|
|
||||||
documentation.rst
|
documentation.rst
|
||||||
tutorials/tutorials.rst
|
tutorials/tutorials.rst
|
||||||
|
design.rst
|
||||||
library.rst
|
library.rst
|
||||||
|
|
||||||
.. include a hidden TOC to avoid sphinx complaint.
|
.. include a hidden TOC to avoid sphinx complaint.
|
||||||
|
@ -20,7 +21,6 @@ source code repository: https://github.com/google/shaka-packager
|
||||||
:hidden:
|
:hidden:
|
||||||
|
|
||||||
build_instructions.md
|
build_instructions.md
|
||||||
design.rst
|
|
||||||
docker_instructions.md
|
docker_instructions.md
|
||||||
library_details.rst
|
library_details.rst
|
||||||
tutorials/encoding.rst
|
tutorials/encoding.rst
|
||||||
|
|
Loading…
Reference in New Issue