Support dash_only and hls_only parameters (#721)

This allows conditional stream descriptors which apply to DASH or HLS only.

Closes #651.
This commit is contained in:
sr90 2020-03-06 10:19:47 -08:00 committed by GitHub
parent 055c67888b
commit a1dd82d478
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 127 additions and 2 deletions

View File

@ -23,5 +23,6 @@ More Screens Ltd. <*@morescreens.net>
Philo Inc. <*@philo.com> Philo Inc. <*@philo.com>
Piotr Srebrny <srebrny.piotr@gmail.com> Piotr Srebrny <srebrny.piotr@gmail.com>
Richard Eklycke <richard@eklycke.se> Richard Eklycke <richard@eklycke.se>
Sanil Raut <sr1990003@gmail.com>
Sergio Ammirata <sergio@ammirata.net> Sergio Ammirata <sergio@ammirata.net>
The Chromium Authors <*@chromium.org> The Chromium Authors <*@chromium.org>

View File

@ -37,5 +37,6 @@ Leo Law <leoltlaw.gh@gmail.com>
Piotr Srebrny <srebrny.piotr@gmail.com> Piotr Srebrny <srebrny.piotr@gmail.com>
Richard Eklycke <richard@eklycke.se> Richard Eklycke <richard@eklycke.se>
Rintaro Kuroiwa <rkuroiwa@google.com> Rintaro Kuroiwa <rkuroiwa@google.com>
Sanil Raut <sr1990003@gmail.com>
Sergio Ammirata <sergio@ammirata.net> Sergio Ammirata <sergio@ammirata.net>
Thomas Inskip <tinskip@google.com> Thomas Inskip <tinskip@google.com>

View File

@ -85,3 +85,8 @@ DASH options
Ignored if $Time$ is used in segment template, since $Time$ requires Ignored if $Time$ is used in segment template, since $Time$ requires
accurate Segment Timeline. accurate Segment Timeline.
--dash_only=0|1
Optional. Defaults to 0 if not specified. If it is set to 1, indicates the
stream is DASH only.

View File

@ -75,3 +75,8 @@ HLS options
The EXT-X-MEDIA-SEQUENCE documentation can be read here: The EXT-X-MEDIA-SEQUENCE documentation can be read here:
https://tools.ietf.org/html/rfc8216#section-4.3.3.2. https://tools.ietf.org/html/rfc8216#section-4.3.3.2.
--hls_only=0|1
Optional. Defaults to 0 if not specified. If it is set to 1, indicates the
stream is HLS only.

View File

@ -11,3 +11,21 @@
The above packaging command creates five single file MP4 streams, and HLS The above packaging command creates five single file MP4 streams, and HLS
playlists as well as DASH manifests. playlists as well as DASH manifests.
* Output DASH + HLS with dash_only and hls_only options
$ packager \
'in=h264_baseline_360p_600.mp4,stream=audio,init_segment=audio/init.mp4,segment_template=audio/$Number$.m4s' \
'in=input_text.vtt,stream=text,init_segment=text/init.mp4,segment_template=text/$Number$.m4s,dash_only=true' \
'in=input_text.vtt,stream=text,segment_template=text/$Number$.vtt,hls_only=true' \
'in=h264_baseline_360p_600.mp4,stream=video,init_segment=h264_360p/init.mp4,segment_template=h264_360p/$Number$.m4s' \
'in=h264_main_480p_1000.mp4,stream=video,init_segment=h264_480p/init.mp4,segment_template=h264_480p/$Number$.m4s' \
'in=h264_main_720p_3000.mp4,stream=video,init_segment=h264_720p/init.mp4,segment_template=h264_720p/$Number$.m4s' \
'in=h264_high_1080p_6000.mp4,stream=video,init_segment=h264_1080p/init.mp4,segment_template=h264_1080p/$Number$.m4s' \
--generate_static_live_mpd --mpd_output h264.mpd \
--hls_master_playlist_output h264_master.m3u8
The above packaging command creates HLS playlists and DASH manifest while using
dash_only for creating segmented WebVTT in mp4 format and hls_only option for
creating WebVTT in text format.

View File

@ -33,6 +33,8 @@ enum FieldType {
kHlsCharacteristicsField, kHlsCharacteristicsField,
kDashAccessiblitiesField, kDashAccessiblitiesField,
kDashRolesField, kDashRolesField,
kDashOnlyField,
kHlsOnlyField,
}; };
struct FieldNameToTypeMapping { struct FieldNameToTypeMapping {
@ -77,6 +79,8 @@ const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
{"dash_role", kDashRolesField}, {"dash_role", kDashRolesField},
{"roles", kDashRolesField}, {"roles", kDashRolesField},
{"role", kDashRolesField}, {"role", kDashRolesField},
{"dash_only", kDashOnlyField},
{"hls_only", kHlsOnlyField},
}; };
FieldType GetFieldType(const std::string& field_name) { FieldType GetFieldType(const std::string& field_name) {
@ -206,6 +210,32 @@ base::Optional<StreamDescriptor> ParseStreamDescriptor(
base::SplitString(iter->second, ";", base::TRIM_WHITESPACE, base::SplitString(iter->second, ";", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY); base::SPLIT_WANT_NONEMPTY);
break; break;
case kDashOnlyField:
unsigned dash_only_value;
if (!base::StringToUint(iter->second, &dash_only_value)) {
LOG(ERROR) << "Non-numeric option for dash_only field "
"specified (" << iter->second << ").";
return base::nullopt;
}
if (dash_only_value > 1) {
LOG(ERROR) << "dash_only should be either 0 or 1.";
return base::nullopt;
}
descriptor.dash_only = dash_only_value > 0;
break;
case kHlsOnlyField:
unsigned hls_only_value;
if (!base::StringToUint(iter->second, &hls_only_value)) {
LOG(ERROR) << "Non-numeric option for hls_only field "
"specified (" << iter->second << ").";
return base::nullopt;
}
if (hls_only_value > 1) {
LOG(ERROR) << "hls_only should be either 0 or 1.";
return base::nullopt;
}
descriptor.hls_only = hls_only_value > 0;
break;
default: default:
LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first
<< "\")."; << "\").";

View File

@ -275,8 +275,10 @@ class PackagerAppTest(unittest.TestCase):
using_time_specifier=False, using_time_specifier=False,
hls=False, hls=False,
hls_characteristics=None, hls_characteristics=None,
hls_only=None,
dash_accessibilities=None, dash_accessibilities=None,
dash_roles=None, dash_roles=None,
dash_only=None,
trick_play_factor=None, trick_play_factor=None,
drm_label=None, drm_label=None,
skip_encryption=None, skip_encryption=None,
@ -303,8 +305,10 @@ class PackagerAppTest(unittest.TestCase):
$Number$. This flag is only relevant if segmented is True. $Number$. This flag is only relevant if segmented is True.
hls: Should the output be for an HLS manifest. hls: Should the output be for an HLS manifest.
hls_characteristics: CHARACTERISTICS attribute for the HLS stream. hls_characteristics: CHARACTERISTICS attribute for the HLS stream.
hls_only: If set to true, will indicate that the stream is for HLS only.
dash_accessibilities: Accessibility element for the DASH stream. dash_accessibilities: Accessibility element for the DASH stream.
dash_roles: Role element for the DASH stream. dash_roles: Role element for the DASH stream.
dash_only: If set to true, will indicate that the stream is for DASH only.
trick_play_factor: Signals the stream is to be used for a trick play trick_play_factor: Signals the stream is to be used for a trick play
stream and which key frames to use. A trick play factor of 0 is the stream and which key frames to use. A trick play factor of 0 is the
same as not specifying a trick play factor. same as not specifying a trick play factor.
@ -360,11 +364,17 @@ class PackagerAppTest(unittest.TestCase):
if hls_characteristics: if hls_characteristics:
stream.Append('hls_characteristics', hls_characteristics) stream.Append('hls_characteristics', hls_characteristics)
if hls_only:
stream.Append('hls_only', 1)
if dash_accessibilities: if dash_accessibilities:
stream.Append('dash_accessibilities', dash_accessibilities) stream.Append('dash_accessibilities', dash_accessibilities)
if dash_roles: if dash_roles:
stream.Append('dash_roles', dash_roles) stream.Append('dash_roles', dash_roles)
if dash_only:
stream.Append('dash_only', 1)
requires_init_segment = segmented and base_ext not in [ requires_init_segment = segmented and base_ext not in [
'aac', 'ac3', 'ec3', 'ts', 'vtt' 'aac', 'ac3', 'ec3', 'ts', 'vtt'
] ]
@ -700,6 +710,14 @@ class PackagerFunctionalTest(PackagerAppTest):
# order of trick play factors gets the same mpd. # order of trick play factors gets the same mpd.
self._CheckTestResults('audio-video-with-two-trick-play') self._CheckTestResults('audio-video-with-two-trick-play')
def testDashOnlyAndHlsOnly(self):
streams = [
self._GetStream('video', hls_only=True),
self._GetStream('audio', dash_only=True),
]
self.assertPackageSuccess(streams, self._GetFlags(output_dash=True,output_hls=True))
self._CheckTestResults('hls-only-dash-only')
def testAudioVideoWithLanguageOverride(self): def testAudioVideoWithLanguageOverride(self):
self.assertPackageSuccess( self.assertPackageSuccess(
self._GetStreams(['audio', 'video'], language='por', hls=True), self._GetStreams(['audio', 'video'], language='por', hls=True),

View File

@ -0,0 +1,5 @@
#EXTM3U
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-STREAM-INF:BANDWIDTH=973483,AVERAGE-BANDWIDTH=879459,CODECS="avc1.64001e",RESOLUTION=640x360,FRAME-RATE=29.970
stream_1.m3u8

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.739954710006714S">
<Period id="0">
<AdaptationSet id="0" contentType="audio" subsegmentAlignment="true">
<Representation id="0" bandwidth="133334" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<BaseURL>bear-640x360-audio.mp4</BaseURL>
<SegmentBase indexRange="793-860" timescale="44100">
<Initialization range="0-792"/>
</SegmentBase>
</Representation>
</AdaptationSet>
</Period>
</MPD>

View File

@ -0,0 +1,16 @@
#EXTM3U
#EXT-X-VERSION:6
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
#EXT-X-TARGETDURATION:2
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="bear-640x360-video.mp4",BYTERANGE="859@0"
#EXTINF:1.001,
#EXT-X-BYTERANGE:99313@927
bear-640x360-video.mp4
#EXTINF:1.001,
#EXT-X-BYTERANGE:121807
bear-640x360-video.mp4
#EXTINF:0.734,
#EXT-X-BYTERANGE:79662
bear-640x360-video.mp4
#EXT-X-ENDLIST

View File

@ -105,11 +105,13 @@ std::unique_ptr<MuxerListener> MuxerListenerFactory::CreateListener(
combined_listener->AddListener( combined_listener->AddListener(
CreateMediaInfoDumpListenerInternal(stream.media_info_output)); CreateMediaInfoDumpListenerInternal(stream.media_info_output));
} }
if (mpd_notifier_) {
if (mpd_notifier_ && !stream.hls_only) {
combined_listener->AddListener( combined_listener->AddListener(
CreateMpdListenerInternal(stream, mpd_notifier_)); CreateMpdListenerInternal(stream, mpd_notifier_));
} }
if (hls_notifier_) {
if (hls_notifier_ && !stream.dash_only) {
for (auto& listener : for (auto& listener :
CreateHlsListenersInternal(stream, stream_index, hls_notifier_)) { CreateHlsListenersInternal(stream, stream_index, hls_notifier_)) {
combined_listener->AddListener(std::move(listener)); combined_listener->AddListener(std::move(listener));

View File

@ -46,11 +46,13 @@ class MuxerListenerFactory {
std::string hls_playlist_name; std::string hls_playlist_name;
std::string hls_iframe_playlist_name; std::string hls_iframe_playlist_name;
std::vector<std::string> hls_characteristics; std::vector<std::string> hls_characteristics;
bool hls_only = false;
// DASH specific values needed to write DASH mpd. Will only be used if an // DASH specific values needed to write DASH mpd. Will only be used if an
// MpdNotifier is given to the factory. // MpdNotifier is given to the factory.
std::vector<std::string> dash_accessiblities; std::vector<std::string> dash_accessiblities;
std::vector<std::string> dash_roles; std::vector<std::string> dash_roles;
bool dash_only = false;
}; };
/// Create a new muxer listener. /// Create a new muxer listener.

View File

@ -93,9 +93,11 @@ MuxerListenerFactory::StreamData ToMuxerListenerData(
data.hls_playlist_name = stream.hls_playlist_name; data.hls_playlist_name = stream.hls_playlist_name;
data.hls_iframe_playlist_name = stream.hls_iframe_playlist_name; data.hls_iframe_playlist_name = stream.hls_iframe_playlist_name;
data.hls_characteristics = stream.hls_characteristics; data.hls_characteristics = stream.hls_characteristics;
data.hls_only = stream.hls_only;
data.dash_accessiblities = stream.dash_accessiblities; data.dash_accessiblities = stream.dash_accessiblities;
data.dash_roles = stream.dash_roles; data.dash_roles = stream.dash_roles;
data.dash_only = stream.dash_only;
return data; return data;
}; };

View File

@ -128,6 +128,11 @@ struct StreamDescriptor {
std::vector<std::string> dash_accessiblities; std::vector<std::string> dash_accessiblities;
/// Optional for DASH output. It defines Role elements of the stream. /// Optional for DASH output. It defines Role elements of the stream.
std::vector<std::string> dash_roles; std::vector<std::string> dash_roles;
/// Set to true to indicate that the stream is for dash only.
bool dash_only = false;
/// Set to true to indicate that the stream is for hls only.
bool hls_only = false;
}; };
class SHAKA_EXPORT Packager { class SHAKA_EXPORT Packager {