Update cmd flags to support static mpd with live profile
- Deprecated command line flags --profile and --single_segment. 'segment_template' in stream descriptors implies live profile and non-single segment. - Added flag --generate_static_mpd_for_live_profile to generate static mpd for live profile; if not set, dynamic mpd will be generated. Close #142 Change-Id: I78879297ed118f0f246c4753a16ad125bd6b5e4f
This commit is contained in:
parent
5aaae303e8
commit
80c54a533a
25
README.md
25
README.md
|
@ -145,7 +145,7 @@ host operating systems.
|
||||||
# VOD: mp4 --> dash
|
# VOD: mp4 --> dash
|
||||||
packager input=/media/example.mp4,stream=audio,output=audio.mp4 \
|
packager input=/media/example.mp4,stream=audio,output=audio.mp4 \
|
||||||
input=/media/example.mp4,stream=video,output=video.mp4 \
|
input=/media/example.mp4,stream=video,output=video.mp4 \
|
||||||
--profile on-demand --mpd_output example.mpd
|
--mpd_output example.mpd
|
||||||
|
|
||||||
# Leave the container.
|
# Leave the container.
|
||||||
exit
|
exit
|
||||||
|
@ -231,13 +231,11 @@ Demux audio from the input and generate a fragmented mp4:
|
||||||
packager input=sintel.mp4,stream=audio,output=fragmented_sintel.mp4
|
packager input=sintel.mp4,stream=audio,output=fragmented_sintel.mp4
|
||||||
```
|
```
|
||||||
|
|
||||||
Demux streams from the input and generates a mpd with on-demand profile along
|
Demux streams from the input and generates a mpd with fragmented mp4:
|
||||||
with fragmented mp4:
|
|
||||||
```Shell
|
```Shell
|
||||||
packager \
|
packager \
|
||||||
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
|
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
|
||||||
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
|
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
|
||||||
--profile on-demand \
|
|
||||||
--mpd_output sintel_vod.mpd
|
--mpd_output sintel_vod.mpd
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -247,19 +245,17 @@ packager \
|
||||||
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
|
input=sintel.mp4,stream=audio,output=sintel_audio.mp4 \
|
||||||
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
|
input=sintel.mp4,stream=video,output=sintel_video.mp4 \
|
||||||
input=sintel_english_input.vtt,stream=text,output=sintel_english.vtt \
|
input=sintel_english_input.vtt,stream=text,output=sintel_english.vtt \
|
||||||
--profile on-demand \
|
|
||||||
--mpd_output sintel_vod.mpd
|
--mpd_output sintel_vod.mpd
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
You may also generate mpd with live profile. Here is an example with IPTV input
|
You may also generate mpd with live profile by specifying segment_template in
|
||||||
streams:
|
stream descriptors. Here is an example with IPTV input streams:
|
||||||
```Shell
|
```Shell
|
||||||
packager \
|
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=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: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' \
|
'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
|
--mpd_output live.mpd
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -274,6 +270,16 @@ Three options are supported right now:
|
||||||
- timeout=microseconds
|
- timeout=microseconds
|
||||||
Timeout in microseconds. Default to unlimited.
|
Timeout in microseconds. Default to unlimited.
|
||||||
|
|
||||||
|
To generate static mpd with live profile. An additional flag needs to be
|
||||||
|
specified:
|
||||||
|
```Shell
|
||||||
|
packager \
|
||||||
|
'input=sintel.mp4,stream=audio,init_segment=audio.mp4,segment_template=audio-$Number$.mp4' \
|
||||||
|
'input=sintel.mp4,stream=video,init_segment=video.mp4,segment_template=video-$Number$.mp4' \
|
||||||
|
--mpd_output live_static.mpd \
|
||||||
|
--generate_static_mpd
|
||||||
|
```
|
||||||
|
|
||||||
Demux video from the input and generate an encrypted fragmented mp4 using
|
Demux video from the input and generate an encrypted fragmented mp4 using
|
||||||
Widevine encryption with RSA signing key file *widevine_test_private.der*:
|
Widevine encryption with RSA signing key file *widevine_test_private.der*:
|
||||||
```Shell
|
```Shell
|
||||||
|
@ -292,7 +298,6 @@ 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=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: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' \
|
'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 \
|
--mpd_output live.mpd \
|
||||||
--enable_widevine_encryption \
|
--enable_widevine_encryption \
|
||||||
--key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \
|
--key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \
|
||||||
|
@ -343,7 +348,6 @@ generated TS segments.
|
||||||
```Shell
|
```Shell
|
||||||
packager \
|
packager \
|
||||||
'input=bear-1280x720.mp4,stream=video,segment_template=bear$Number$.ts,playlist_name=playlist.m3u8' \
|
'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_master_playlist_output="master.m3u8" \
|
||||||
--hls_base_url="http://localhost:10000/"
|
--hls_base_url="http://localhost:10000/"
|
||||||
```
|
```
|
||||||
|
@ -354,7 +358,6 @@ specified.
|
||||||
packager \
|
packager \
|
||||||
'input=input.mp4,stream=video,segment_template=output$Number$.ts,playlist_name=video_playlist.m3u8' \
|
'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' \
|
'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_master_playlist_output="master_playlist.m3u8" \
|
||||||
--hls_base_url="http://localhost:10000/"
|
--hls_base_url="http://localhost:10000/"
|
||||||
```
|
```
|
||||||
|
|
|
@ -8,6 +8,14 @@
|
||||||
|
|
||||||
#include "packager/app/mpd_flags.h"
|
#include "packager/app/mpd_flags.h"
|
||||||
|
|
||||||
|
DEFINE_bool(generate_static_mpd,
|
||||||
|
false,
|
||||||
|
"Set to true to generate static mpd. If segment_template is "
|
||||||
|
"specified in stream descriptors, shaka-packager generates dynamic "
|
||||||
|
"mpd by default; if this flag is enabled, shaka-packager generates "
|
||||||
|
"static mpd instead. Note that if segment_template is not "
|
||||||
|
"specified, shaka-packager always generates static mpd regardless "
|
||||||
|
"of the value of this flag.");
|
||||||
// TODO(rkuroiwa, kqyang): Remove the 'Exclusive' statements once
|
// TODO(rkuroiwa, kqyang): Remove the 'Exclusive' statements once
|
||||||
// --output_media_info can work together with --mpd_output.
|
// --output_media_info can work together with --mpd_output.
|
||||||
DEFINE_bool(output_media_info,
|
DEFINE_bool(output_media_info,
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
|
DECLARE_bool(generate_static_mpd);
|
||||||
DECLARE_bool(output_media_info);
|
DECLARE_bool(output_media_info);
|
||||||
DECLARE_string(mpd_output);
|
DECLARE_string(mpd_output);
|
||||||
DECLARE_string(base_urls);
|
DECLARE_string(base_urls);
|
||||||
|
|
|
@ -8,18 +8,9 @@
|
||||||
|
|
||||||
#include "packager/app/muxer_flags.h"
|
#include "packager/app/muxer_flags.h"
|
||||||
|
|
||||||
DEFINE_string(profile,
|
|
||||||
"",
|
|
||||||
"Specify the target DASH profile: on-demand or live. This will "
|
|
||||||
"set proper option values to ensure conformance to the desired "
|
|
||||||
"profile.");
|
|
||||||
DEFINE_double(clear_lead,
|
DEFINE_double(clear_lead,
|
||||||
10.0f,
|
10.0f,
|
||||||
"Clear lead in seconds if encryption is enabled.");
|
"Clear lead in seconds if encryption is enabled.");
|
||||||
DEFINE_bool(single_segment,
|
|
||||||
true,
|
|
||||||
"Generate a single segment for the media presentation. This option "
|
|
||||||
"should be set for on demand profile.");
|
|
||||||
DEFINE_double(segment_duration,
|
DEFINE_double(segment_duration,
|
||||||
10.0f,
|
10.0f,
|
||||||
"Segment duration in seconds. If single_segment is specified, "
|
"Segment duration in seconds. If single_segment is specified, "
|
||||||
|
|
|
@ -11,9 +11,7 @@
|
||||||
|
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
DECLARE_string(profile);
|
|
||||||
DECLARE_double(clear_lead);
|
DECLARE_double(clear_lead);
|
||||||
DECLARE_bool(single_segment);
|
|
||||||
DECLARE_double(segment_duration);
|
DECLARE_double(segment_duration);
|
||||||
DECLARE_bool(segment_sap_aligned);
|
DECLARE_bool(segment_sap_aligned);
|
||||||
DECLARE_double(fragment_duration);
|
DECLARE_double(fragment_duration);
|
||||||
|
|
|
@ -265,11 +265,6 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
stream_muxer_options.segment_template = stream_iter->segment_template;
|
stream_muxer_options.segment_template = stream_iter->segment_template;
|
||||||
if (stream_muxer_options.single_segment) {
|
|
||||||
LOG(WARNING) << "Segment template and single segment are incompatible, "
|
|
||||||
"setting single segment to false.";
|
|
||||||
stream_muxer_options.single_segment = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stream_muxer_options.bandwidth = stream_iter->bandwidth;
|
stream_muxer_options.bandwidth = stream_iter->bandwidth;
|
||||||
|
|
||||||
|
@ -419,20 +414,11 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
||||||
if (protection_scheme == FOURCC_NULL)
|
if (protection_scheme == FOURCC_NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!AssignFlagsFromProfile())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (FLAGS_output_media_info && !FLAGS_mpd_output.empty()) {
|
if (FLAGS_output_media_info && !FLAGS_mpd_output.empty()) {
|
||||||
NOTIMPLEMENTED() << "ERROR: --output_media_info and --mpd_output do not "
|
NOTIMPLEMENTED() << "ERROR: --output_media_info and --mpd_output do not "
|
||||||
"work together.";
|
"work together.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (FLAGS_output_media_info && !FLAGS_single_segment) {
|
|
||||||
// TODO(rkuroiwa, kqyang): Support partial media info dump for live.
|
|
||||||
NOTIMPLEMENTED() << "ERROR: --output_media_info is only supported if "
|
|
||||||
"--single_segment is true.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since there isn't a muxer listener that can output both MPD and HLS,
|
// Since there isn't a muxer listener that can output both MPD and HLS,
|
||||||
// disallow specifying both MPD and HLS flags.
|
// disallow specifying both MPD and HLS flags.
|
||||||
|
@ -446,8 +432,28 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
||||||
if (!GetMuxerOptions(&muxer_options))
|
if (!GetMuxerOptions(&muxer_options))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
DCHECK(!stream_descriptors.empty());
|
||||||
|
// On demand profile generates single file segment while live profile
|
||||||
|
// generates multiple segments specified using segment template.
|
||||||
|
const bool on_demand_dash_profile =
|
||||||
|
stream_descriptors.begin()->segment_template.empty();
|
||||||
|
for (const auto& stream_descriptor : stream_descriptors) {
|
||||||
|
if (on_demand_dash_profile != stream_descriptor.segment_template.empty()) {
|
||||||
|
LOG(ERROR) << "Inconsistent stream descriptor specification: "
|
||||||
|
"segment_template should be specified for none or all "
|
||||||
|
"stream descriptors.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FLAGS_output_media_info && !on_demand_dash_profile) {
|
||||||
|
// TODO(rkuroiwa, kqyang): Support partial media info dump for live.
|
||||||
|
NOTIMPLEMENTED() << "ERROR: --output_media_info is only supported for "
|
||||||
|
"on-demand profile (not using segment_template).";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MpdOptions mpd_options;
|
MpdOptions mpd_options;
|
||||||
if (!GetMpdOptions(&mpd_options))
|
if (!GetMpdOptions(on_demand_dash_profile, &mpd_options))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create encryption key source if needed.
|
// Create encryption key source if needed.
|
||||||
|
|
|
@ -125,30 +125,9 @@ std::unique_ptr<KeySource> CreateDecryptionKeySource() {
|
||||||
return decryption_key_source;
|
return decryption_key_source;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssignFlagsFromProfile() {
|
|
||||||
bool single_segment = FLAGS_single_segment;
|
|
||||||
if (FLAGS_profile == "on-demand") {
|
|
||||||
single_segment = true;
|
|
||||||
} else if (FLAGS_profile == "live") {
|
|
||||||
single_segment = false;
|
|
||||||
} else if (FLAGS_profile != "") {
|
|
||||||
fprintf(stderr, "ERROR: --profile '%s' is not supported.\n",
|
|
||||||
FLAGS_profile.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FLAGS_single_segment != single_segment) {
|
|
||||||
FLAGS_single_segment = single_segment;
|
|
||||||
fprintf(stdout, "Profile %s: set --single_segment to %s.\n",
|
|
||||||
FLAGS_profile.c_str(), single_segment ? "true" : "false");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetMuxerOptions(MuxerOptions* muxer_options) {
|
bool GetMuxerOptions(MuxerOptions* muxer_options) {
|
||||||
DCHECK(muxer_options);
|
DCHECK(muxer_options);
|
||||||
|
|
||||||
muxer_options->single_segment = FLAGS_single_segment;
|
|
||||||
muxer_options->segment_duration = FLAGS_segment_duration;
|
muxer_options->segment_duration = FLAGS_segment_duration;
|
||||||
muxer_options->fragment_duration = FLAGS_fragment_duration;
|
muxer_options->fragment_duration = FLAGS_fragment_duration;
|
||||||
muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned;
|
muxer_options->segment_sap_aligned = FLAGS_segment_sap_aligned;
|
||||||
|
@ -168,15 +147,15 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetMpdOptions(MpdOptions* mpd_options) {
|
bool GetMpdOptions(bool on_demand_profile, MpdOptions* mpd_options) {
|
||||||
DCHECK(mpd_options);
|
DCHECK(mpd_options);
|
||||||
|
|
||||||
mpd_options->dash_profile =
|
mpd_options->dash_profile =
|
||||||
FLAGS_single_segment ? DashProfile::kOnDemand : DashProfile::kLive;
|
on_demand_profile ? DashProfile::kOnDemand : DashProfile::kLive;
|
||||||
// Single segment does not always mean static mpd.
|
|
||||||
// TODO(kqyang): Add a new flag for mpd type and update the code.
|
|
||||||
mpd_options->mpd_type =
|
mpd_options->mpd_type =
|
||||||
FLAGS_single_segment ? MpdType::kStatic : MpdType::kDynamic;
|
(on_demand_profile || FLAGS_generate_static_mpd)
|
||||||
|
? MpdType::kStatic
|
||||||
|
: MpdType::kDynamic;
|
||||||
mpd_options->availability_time_offset = FLAGS_availability_time_offset;
|
mpd_options->availability_time_offset = FLAGS_availability_time_offset;
|
||||||
mpd_options->minimum_update_period = FLAGS_minimum_update_period;
|
mpd_options->minimum_update_period = FLAGS_minimum_update_period;
|
||||||
mpd_options->min_buffer_time = FLAGS_min_buffer_time;
|
mpd_options->min_buffer_time = FLAGS_min_buffer_time;
|
||||||
|
|
|
@ -42,14 +42,11 @@ std::unique_ptr<KeySource> CreateEncryptionKeySource();
|
||||||
/// decryption is not required.
|
/// decryption is not required.
|
||||||
std::unique_ptr<KeySource> CreateDecryptionKeySource();
|
std::unique_ptr<KeySource> CreateDecryptionKeySource();
|
||||||
|
|
||||||
/// Set flags according to profile.
|
|
||||||
bool AssignFlagsFromProfile();
|
|
||||||
|
|
||||||
/// Fill MuxerOptions members using provided command line options.
|
/// Fill MuxerOptions members using provided command line options.
|
||||||
bool GetMuxerOptions(MuxerOptions* muxer_options);
|
bool GetMuxerOptions(MuxerOptions* muxer_options);
|
||||||
|
|
||||||
/// Fill MpdOptions members using provided command line options.
|
/// Fill MpdOptions members using provided command line options.
|
||||||
bool GetMpdOptions(MpdOptions* mpd_options);
|
bool GetMpdOptions(bool on_demand_profile, MpdOptions* mpd_options);
|
||||||
|
|
||||||
/// Select and add a stream from a provided set to a muxer.
|
/// Select and add a stream from a provided set to a muxer.
|
||||||
/// @param streams contains the set of MediaStreams from which to select.
|
/// @param streams contains the set of MediaStreams from which to select.
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
//
|
||||||
|
// Defines retired / deprecated flags. These flags will be removed in later
|
||||||
|
// versions.
|
||||||
|
|
||||||
|
#include "packager/app/retired_flags.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
DEFINE_string(profile, "", "This flag is deprecated. Do not use.");
|
||||||
|
DEFINE_bool(single_segment, true, "This flag is deprecated. Do not use.");
|
||||||
|
|
||||||
|
// The current gflags library does not provide a way to check whether a flag is
|
||||||
|
// set in command line. If a flag has a different value to its default value,
|
||||||
|
// the flag must have been set. It is possible that the flag is set to the same
|
||||||
|
// value as its default value though.
|
||||||
|
bool InformRetiredStringFlag(const char* flagname, const std::string& value) {
|
||||||
|
if (!value.empty())
|
||||||
|
fprintf(stderr, "WARNING: %s is deprecated and ignored.\n", flagname);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InformRetiredDefaultTrueFlag(const char* flagname, bool value) {
|
||||||
|
if (!value)
|
||||||
|
fprintf(stderr, "WARNING: %s is deprecated and ignored.\n", flagname);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_validator(profile, &InformRetiredStringFlag);
|
||||||
|
DEFINE_validator(single_segment, &InformRetiredDefaultTrueFlag);
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
|
DECLARE_string(profile);
|
||||||
|
DECLARE_bool(single_segment);
|
|
@ -110,7 +110,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
output_format='ts',
|
output_format='ts',
|
||||||
live=True,
|
live=True,
|
||||||
test_files=['bear-640x360.ts']),
|
test_files=['bear-640x360.ts']),
|
||||||
self._GetFlags(live=True, output_hls=True))
|
self._GetFlags(output_hls=True))
|
||||||
self._DiffLiveGold(self.output[0],
|
self._DiffLiveGold(self.output[0],
|
||||||
'bear-640x360-a-golden',
|
'bear-640x360-a-golden',
|
||||||
output_format='ts')
|
output_format='ts')
|
||||||
|
@ -220,8 +220,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
output_format='ts',
|
output_format='ts',
|
||||||
live=True,
|
live=True,
|
||||||
test_files=['bear-640x360.ts']),
|
test_files=['bear-640x360.ts']),
|
||||||
self._GetFlags(encryption=True,
|
self._GetFlags(encryption=True, output_hls=True))
|
||||||
live=True, output_hls=True))
|
|
||||||
self._DiffLiveGold(self.output[0],
|
self._DiffLiveGold(self.output[0],
|
||||||
'bear-640x360-a-enc-golden',
|
'bear-640x360-a-enc-golden',
|
||||||
output_format='ts')
|
output_format='ts')
|
||||||
|
@ -329,8 +328,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
|
|
||||||
def testPackageWithLiveProfile(self):
|
def testPackageWithLiveProfile(self):
|
||||||
self.packager.Package(
|
self.packager.Package(
|
||||||
self._GetStreams(['audio', 'video'], live=True),
|
self._GetStreams(['audio', 'video'], live=True), self._GetFlags())
|
||||||
self._GetFlags(live=True))
|
|
||||||
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-golden')
|
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-golden')
|
||||||
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden')
|
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-golden')
|
||||||
self._DiffLiveMpdGold(self.mpd_output, 'bear-640x360-av-live-golden.mpd')
|
self._DiffLiveMpdGold(self.mpd_output, 'bear-640x360-av-live-golden.mpd')
|
||||||
|
@ -338,7 +336,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
def testPackageWithLiveProfileAndEncryption(self):
|
def testPackageWithLiveProfileAndEncryption(self):
|
||||||
self.packager.Package(
|
self.packager.Package(
|
||||||
self._GetStreams(['audio', 'video'], live=True),
|
self._GetStreams(['audio', 'video'], live=True),
|
||||||
self._GetFlags(encryption=True, live=True))
|
self._GetFlags(encryption=True))
|
||||||
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-cenc-golden')
|
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-cenc-golden')
|
||||||
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-cenc-golden')
|
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-cenc-golden')
|
||||||
self._DiffLiveMpdGold(self.mpd_output,
|
self._DiffLiveMpdGold(self.mpd_output,
|
||||||
|
@ -347,8 +345,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
def testPackageWithLiveProfileAndEncryptionAndDashIfIop(self):
|
def testPackageWithLiveProfileAndEncryptionAndDashIfIop(self):
|
||||||
self.packager.Package(
|
self.packager.Package(
|
||||||
self._GetStreams(['audio', 'video'], live=True),
|
self._GetStreams(['audio', 'video'], live=True),
|
||||||
self._GetFlags(encryption=True,
|
self._GetFlags(encryption=True, dash_if_iop=True))
|
||||||
live=True, dash_if_iop=True))
|
|
||||||
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-cenc-golden')
|
self._DiffLiveGold(self.output[0], 'bear-640x360-a-live-cenc-golden')
|
||||||
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-cenc-golden')
|
self._DiffLiveGold(self.output[1], 'bear-640x360-v-live-cenc-golden')
|
||||||
self._DiffLiveMpdGold(self.mpd_output,
|
self._DiffLiveMpdGold(self.mpd_output,
|
||||||
|
@ -360,8 +357,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
live=True,
|
live=True,
|
||||||
test_files=['bear-1280x720.mp4', 'bear-640x360.mp4',
|
test_files=['bear-1280x720.mp4', 'bear-640x360.mp4',
|
||||||
'bear-320x180.mp4']),
|
'bear-320x180.mp4']),
|
||||||
self._GetFlags(encryption=True,
|
self._GetFlags(encryption=True, dash_if_iop=True))
|
||||||
live=True, dash_if_iop=True))
|
|
||||||
self._DiffLiveGold(self.output[2], 'bear-640x360-a-live-cenc-golden')
|
self._DiffLiveGold(self.output[2], 'bear-640x360-a-live-cenc-golden')
|
||||||
self._DiffLiveGold(self.output[3], 'bear-640x360-v-live-cenc-golden')
|
self._DiffLiveGold(self.output[3], 'bear-640x360-v-live-cenc-golden')
|
||||||
# Mpd cannot be validated right now since we don't generate determinstic
|
# Mpd cannot be validated right now since we don't generate determinstic
|
||||||
|
@ -371,9 +367,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
def testPackageWithLiveProfileAndKeyRotation(self):
|
def testPackageWithLiveProfileAndKeyRotation(self):
|
||||||
self.packager.Package(
|
self.packager.Package(
|
||||||
self._GetStreams(['audio', 'video'], live=True),
|
self._GetStreams(['audio', 'video'], live=True),
|
||||||
self._GetFlags(encryption=True,
|
self._GetFlags(encryption=True, key_rotation=True))
|
||||||
key_rotation=True,
|
|
||||||
live=True))
|
|
||||||
self._DiffLiveGold(self.output[0],
|
self._DiffLiveGold(self.output[0],
|
||||||
'bear-640x360-a-live-cenc-rotation-golden')
|
'bear-640x360-a-live-cenc-rotation-golden')
|
||||||
self._DiffLiveGold(self.output[1],
|
self._DiffLiveGold(self.output[1],
|
||||||
|
@ -386,7 +380,6 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
self._GetStreams(['audio', 'video'], live=True),
|
self._GetStreams(['audio', 'video'], live=True),
|
||||||
self._GetFlags(encryption=True,
|
self._GetFlags(encryption=True,
|
||||||
key_rotation=True,
|
key_rotation=True,
|
||||||
live=True,
|
|
||||||
dash_if_iop=True))
|
dash_if_iop=True))
|
||||||
self._DiffLiveGold(self.output[0],
|
self._DiffLiveGold(self.output[0],
|
||||||
'bear-640x360-a-live-cenc-rotation-golden')
|
'bear-640x360-a-live-cenc-rotation-golden')
|
||||||
|
@ -496,7 +489,6 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
random_iv=False,
|
random_iv=False,
|
||||||
widevine_encryption=False,
|
widevine_encryption=False,
|
||||||
key_rotation=False,
|
key_rotation=False,
|
||||||
live=False,
|
|
||||||
dash_if_iop=False,
|
dash_if_iop=False,
|
||||||
output_media_info=False,
|
output_media_info=False,
|
||||||
output_hls=False,
|
output_hls=False,
|
||||||
|
@ -526,8 +518,6 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
if key_rotation:
|
if key_rotation:
|
||||||
flags.append('--crypto_period_duration=1')
|
flags.append('--crypto_period_duration=1')
|
||||||
|
|
||||||
if live:
|
|
||||||
flags.append('--profile=live')
|
|
||||||
if dash_if_iop:
|
if dash_if_iop:
|
||||||
flags.append('--generate_dash_if_iop_compliant_mpd')
|
flags.append('--generate_dash_if_iop_compliant_mpd')
|
||||||
if output_media_info:
|
if output_media_info:
|
||||||
|
|
|
@ -9,17 +9,8 @@
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
MuxerOptions::MuxerOptions()
|
MuxerOptions::MuxerOptions() = default;
|
||||||
: single_segment(false),
|
MuxerOptions::~MuxerOptions() = default;
|
||||||
segment_duration(0),
|
|
||||||
fragment_duration(0),
|
|
||||||
segment_sap_aligned(false),
|
|
||||||
fragment_sap_aligned(false),
|
|
||||||
num_subsegments_per_sidx(0),
|
|
||||||
mp4_use_decoding_timestamp_in_timeline(false),
|
|
||||||
bandwidth(0),
|
|
||||||
webm_subsample_encryption(true) {}
|
|
||||||
MuxerOptions::~MuxerOptions() {}
|
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
|
@ -19,42 +19,38 @@ struct MuxerOptions {
|
||||||
MuxerOptions();
|
MuxerOptions();
|
||||||
~MuxerOptions();
|
~MuxerOptions();
|
||||||
|
|
||||||
/// Generate a single segment for each media presentation. This option
|
|
||||||
/// should be set for on demand profile.
|
|
||||||
bool single_segment;
|
|
||||||
|
|
||||||
/// Segment duration in seconds. If single_segment is specified, this
|
/// Segment duration in seconds. If single_segment is specified, this
|
||||||
/// parameter sets the duration of a subsegment; otherwise, this parameter
|
/// parameter sets the duration of a subsegment; otherwise, this parameter
|
||||||
/// sets the duration of a segment. A segment can contain one or many
|
/// sets the duration of a segment. A segment can contain one or many
|
||||||
/// fragments.
|
/// fragments.
|
||||||
double segment_duration;
|
double segment_duration = 0;
|
||||||
|
|
||||||
/// Fragment duration in seconds. Should not be larger than the segment
|
/// Fragment duration in seconds. Should not be larger than the segment
|
||||||
/// duration.
|
/// duration.
|
||||||
double fragment_duration;
|
double fragment_duration = 0;
|
||||||
|
|
||||||
/// Force segments to begin with stream access points. Segment duration may
|
/// Force segments to begin with stream access points. Segment duration may
|
||||||
/// not be exactly what specified by segment_duration.
|
/// not be exactly what specified by segment_duration.
|
||||||
bool segment_sap_aligned;
|
bool segment_sap_aligned = false;
|
||||||
|
|
||||||
/// Force fragments to begin with stream access points. Fragment duration
|
/// Force fragments to begin with stream access points. Fragment duration
|
||||||
/// may not be exactly what specified by segment_duration. Setting to true
|
/// may not be exactly what specified by segment_duration. Setting to true
|
||||||
/// implies that segment_sap_aligned is true as well.
|
/// implies that segment_sap_aligned is true as well.
|
||||||
bool fragment_sap_aligned;
|
bool fragment_sap_aligned = false;
|
||||||
|
|
||||||
/// For ISO BMFF only.
|
/// For ISO BMFF only.
|
||||||
/// Set the number of subsegments in each SIDX box. If 0, a single SIDX box
|
/// 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
|
/// 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
|
/// will pack N subsegments in the root SIDX of the segment, with
|
||||||
/// segment_duration/N/fragment_duration fragments per subsegment.
|
/// segment_duration/N/fragment_duration fragments per subsegment.
|
||||||
int num_subsegments_per_sidx;
|
int num_subsegments_per_sidx = 0;
|
||||||
|
|
||||||
/// For ISO BMFF only.
|
/// For ISO BMFF only.
|
||||||
/// Set the flag use_decoding_timestamp_in_timeline, which if set to true, use
|
/// Set the flag use_decoding_timestamp_in_timeline, which if set to true, use
|
||||||
/// decoding timestamp instead of presentation timestamp in media timeline,
|
/// decoding timestamp instead of presentation timestamp in media timeline,
|
||||||
/// which is needed to workaround a Chromium bug that decoding timestamp is
|
/// which is needed to workaround a Chromium bug that decoding timestamp is
|
||||||
/// used in buffered range, https://crbug.com/398130.
|
/// used in buffered range, https://crbug.com/398130.
|
||||||
bool mp4_use_decoding_timestamp_in_timeline;
|
bool mp4_use_decoding_timestamp_in_timeline = false;
|
||||||
|
|
||||||
/// Output file name. If segment_template is not specified, the Muxer
|
/// Output file name. If segment_template is not specified, the Muxer
|
||||||
/// generates this single output file with all segments concatenated;
|
/// generates this single output file with all segments concatenated;
|
||||||
|
@ -72,10 +68,10 @@ struct MuxerOptions {
|
||||||
|
|
||||||
/// User-specified bit rate for the media stream. If zero, the muxer will
|
/// User-specified bit rate for the media stream. If zero, the muxer will
|
||||||
/// attempt to estimate.
|
/// attempt to estimate.
|
||||||
uint32_t bandwidth;
|
uint32_t bandwidth = 0;
|
||||||
|
|
||||||
// Enable/disable subsample encryption for WebM containers.
|
// Enable/disable subsample encryption for WebM containers.
|
||||||
bool webm_subsample_encryption;
|
bool webm_subsample_encryption = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -44,7 +44,6 @@ MediaInfo ConvertToMediaInfo(const std::string& media_info_string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDefaultLiveMuxerOptionsValues(media::MuxerOptions* muxer_options) {
|
void SetDefaultLiveMuxerOptionsValues(media::MuxerOptions* muxer_options) {
|
||||||
muxer_options->single_segment = false;
|
|
||||||
muxer_options->segment_duration = 10.0;
|
muxer_options->segment_duration = 10.0;
|
||||||
muxer_options->fragment_duration = 10.0;
|
muxer_options->fragment_duration = 10.0;
|
||||||
muxer_options->segment_sap_aligned = true;
|
muxer_options->segment_sap_aligned = true;
|
||||||
|
|
|
@ -149,9 +149,8 @@ void SetMediaInfoStreamInfo(const StreamInfo& stream_info,
|
||||||
void SetMediaInfoMuxerOptions(const MuxerOptions& muxer_options,
|
void SetMediaInfoMuxerOptions(const MuxerOptions& muxer_options,
|
||||||
MediaInfo* media_info) {
|
MediaInfo* media_info) {
|
||||||
DCHECK(media_info);
|
DCHECK(media_info);
|
||||||
if (muxer_options.single_segment) {
|
if (muxer_options.segment_template.empty()) {
|
||||||
media_info->set_media_file_name(muxer_options.output_file_name);
|
media_info->set_media_file_name(muxer_options.output_file_name);
|
||||||
DCHECK(muxer_options.segment_template.empty());
|
|
||||||
} else {
|
} else {
|
||||||
media_info->set_init_segment_name(muxer_options.output_file_name);
|
media_info->set_init_segment_name(muxer_options.output_file_name);
|
||||||
media_info->set_segment_template(muxer_options.segment_template);
|
media_info->set_segment_template(muxer_options.segment_template);
|
||||||
|
|
|
@ -73,7 +73,6 @@ OnMediaEndParameters GetDefaultOnMediaEndParams() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) {
|
void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) {
|
||||||
muxer_options->single_segment = true;
|
|
||||||
muxer_options->segment_duration = 10.0;
|
muxer_options->segment_duration = 10.0;
|
||||||
muxer_options->fragment_duration = 10.0;
|
muxer_options->fragment_duration = 10.0;
|
||||||
muxer_options->segment_sap_aligned = true;
|
muxer_options->segment_sap_aligned = true;
|
||||||
|
|
|
@ -45,7 +45,7 @@ void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type) {
|
ContainerType container_type) {
|
||||||
DCHECK(muxer_options.single_segment);
|
DCHECK(muxer_options.segment_template.empty());
|
||||||
media_info_.reset(new MediaInfo());
|
media_info_.reset(new MediaInfo());
|
||||||
if (!internal::GenerateMediaInfo(muxer_options,
|
if (!internal::GenerateMediaInfo(muxer_options,
|
||||||
stream_info,
|
stream_info,
|
||||||
|
|
|
@ -134,7 +134,7 @@ Status MP4Muxer::Initialize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options().single_segment) {
|
if (options().segment_template.empty()) {
|
||||||
segmenter_.reset(new SingleSegmentSegmenter(options(), std::move(ftyp),
|
segmenter_.reset(new SingleSegmentSegmenter(options(), std::move(ftyp),
|
||||||
std::move(moov)));
|
std::move(moov)));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "packager/media/base/muxer_util.h"
|
||||||
#include "packager/media/formats/webm/segmenter_test_base.h"
|
#include "packager/media/formats/webm/segmenter_test_base.h"
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
@ -27,12 +28,10 @@ const uint8_t kBasicSupportDataInit[] = {
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
// ID: Info, Payload Size: 88
|
// ID: Info, Payload Size: 81
|
||||||
0x15, 0x49, 0xa9, 0x66, 0xd8,
|
0x15, 0x49, 0xa9, 0x66, 0xd1,
|
||||||
// TimecodeScale: 1000000
|
// TimecodeScale: 1000000
|
||||||
0x2a, 0xd7, 0xb1, 0x83, 0x0f, 0x42, 0x40,
|
0x2a, 0xd7, 0xb1, 0x83, 0x0f, 0x42, 0x40,
|
||||||
// Duration: float(0)
|
|
||||||
0x44, 0x89, 0x84, 0x3f, 0x80, 0x00, 0x00,
|
|
||||||
// MuxingApp: 'libwebm-0.2.1.0'
|
// MuxingApp: 'libwebm-0.2.1.0'
|
||||||
0x4d, 0x80, 0x8f, 0x6c, 0x69, 0x62, 0x77, 0x65, 0x62, 0x6d, 0x2d, 0x30,
|
0x4d, 0x80, 0x8f, 0x6c, 0x69, 0x62, 0x77, 0x65, 0x62, 0x6d, 0x2d, 0x30,
|
||||||
0x2e, 0x32, 0x2e, 0x31, 0x2e, 0x30,
|
0x2e, 0x32, 0x2e, 0x31, 0x2e, 0x30,
|
||||||
|
@ -93,7 +92,10 @@ const uint8_t kBasicSupportDataSegment[] = {
|
||||||
|
|
||||||
class MultiSegmentSegmenterTest : public SegmentTestBase {
|
class MultiSegmentSegmenterTest : public SegmentTestBase {
|
||||||
public:
|
public:
|
||||||
MultiSegmentSegmenterTest() : info_(CreateVideoStreamInfo()) {}
|
MultiSegmentSegmenterTest()
|
||||||
|
: info_(CreateVideoStreamInfo()),
|
||||||
|
segment_template_(std::string(kMemoryFilePrefix) +
|
||||||
|
"output-template-$Number$.webm") {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InitializeSegmenter(const MuxerOptions& options) {
|
void InitializeSegmenter(const MuxerOptions& options) {
|
||||||
|
@ -102,12 +104,18 @@ class MultiSegmentSegmenterTest : public SegmentTestBase {
|
||||||
options, info_.get(), NULL, &segmenter_));
|
options, info_.get(), NULL, &segmenter_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TemplateFileName(int number) const {
|
||||||
|
return GetSegmentName(segment_template_, 0, number, 0);
|
||||||
|
}
|
||||||
|
|
||||||
scoped_refptr<StreamInfo> info_;
|
scoped_refptr<StreamInfo> info_;
|
||||||
|
std::string segment_template_;
|
||||||
std::unique_ptr<webm::Segmenter> segmenter_;
|
std::unique_ptr<webm::Segmenter> segmenter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(MultiSegmentSegmenterTest, BasicSupport) {
|
TEST_F(MultiSegmentSegmenterTest, BasicSupport) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
|
options.segment_template = segment_template_;
|
||||||
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
||||||
|
|
||||||
// Write the samples to the Segmenter.
|
// Write the samples to the Segmenter.
|
||||||
|
@ -128,6 +136,7 @@ TEST_F(MultiSegmentSegmenterTest, BasicSupport) {
|
||||||
|
|
||||||
TEST_F(MultiSegmentSegmenterTest, SplitsFilesOnSegmentDuration) {
|
TEST_F(MultiSegmentSegmenterTest, SplitsFilesOnSegmentDuration) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
|
options.segment_template = segment_template_;
|
||||||
options.segment_duration = 5; // seconds
|
options.segment_duration = 5; // seconds
|
||||||
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
||||||
|
|
||||||
|
@ -154,6 +163,7 @@ TEST_F(MultiSegmentSegmenterTest, SplitsFilesOnSegmentDuration) {
|
||||||
|
|
||||||
TEST_F(MultiSegmentSegmenterTest, RespectsSegmentSAPAlign) {
|
TEST_F(MultiSegmentSegmenterTest, RespectsSegmentSAPAlign) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
|
options.segment_template = segment_template_;
|
||||||
options.segment_duration = 3; // seconds
|
options.segment_duration = 3; // seconds
|
||||||
options.segment_sap_aligned = true;
|
options.segment_sap_aligned = true;
|
||||||
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
||||||
|
@ -182,6 +192,7 @@ TEST_F(MultiSegmentSegmenterTest, RespectsSegmentSAPAlign) {
|
||||||
|
|
||||||
TEST_F(MultiSegmentSegmenterTest, SplitsClustersOnFragmentDuration) {
|
TEST_F(MultiSegmentSegmenterTest, SplitsClustersOnFragmentDuration) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
|
options.segment_template = segment_template_;
|
||||||
options.fragment_duration = 5; // seconds
|
options.fragment_duration = 5; // seconds
|
||||||
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
||||||
|
|
||||||
|
@ -205,6 +216,7 @@ TEST_F(MultiSegmentSegmenterTest, SplitsClustersOnFragmentDuration) {
|
||||||
|
|
||||||
TEST_F(MultiSegmentSegmenterTest, RespectsFragmentSAPAlign) {
|
TEST_F(MultiSegmentSegmenterTest, RespectsFragmentSAPAlign) {
|
||||||
MuxerOptions options = CreateMuxerOptions();
|
MuxerOptions options = CreateMuxerOptions();
|
||||||
|
options.segment_template = segment_template_;
|
||||||
options.fragment_duration = 3; // seconds
|
options.fragment_duration = 3; // seconds
|
||||||
options.fragment_sap_aligned = true;
|
options.fragment_sap_aligned = true;
|
||||||
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
|
||||||
|
@ -230,4 +242,3 @@ TEST_F(MultiSegmentSegmenterTest, RespectsFragmentSAPAlign) {
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ Status Segmenter::Initialize(std::unique_ptr<MkvWriter> writer,
|
||||||
(GetPackagerProjectUrl() + " version " + version).c_str());
|
(GetPackagerProjectUrl() + " version " + version).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options().single_segment) {
|
if (options().segment_template.empty()) {
|
||||||
// Set an initial duration so the duration element is written; will be
|
// Set an initial duration so the duration element is written; will be
|
||||||
// overwritten at the end. This works because this is a float and floats
|
// overwritten at the end. This works because this is a float and floats
|
||||||
// are always the same size.
|
// are always the same size.
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include "packager/media/formats/webm/segmenter_test_base.h"
|
#include "packager/media/formats/webm/segmenter_test_base.h"
|
||||||
|
|
||||||
#include "packager/media/base/muxer_util.h"
|
|
||||||
#include "packager/media/file/memory_file.h"
|
#include "packager/media/file/memory_file.h"
|
||||||
#include "packager/media/formats/webm/webm_constants.h"
|
#include "packager/media/formats/webm/webm_constants.h"
|
||||||
#include "packager/version/version.h"
|
#include "packager/version/version.h"
|
||||||
|
@ -43,10 +42,7 @@ void SegmentTestBase::SetUp() {
|
||||||
SetPackagerVersionForTesting("test");
|
SetPackagerVersionForTesting("test");
|
||||||
|
|
||||||
output_file_name_ = std::string(kMemoryFilePrefix) + "output-file.webm";
|
output_file_name_ = std::string(kMemoryFilePrefix) + "output-file.webm";
|
||||||
segment_template_ =
|
|
||||||
std::string(kMemoryFilePrefix) + "output-template-$Number$.webm";
|
|
||||||
cur_time_timescale_ = 0;
|
cur_time_timescale_ = 0;
|
||||||
single_segment_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SegmentTestBase::TearDown() {
|
void SegmentTestBase::TearDown() {
|
||||||
|
@ -78,9 +74,7 @@ scoped_refptr<MediaSample> SegmentTestBase::CreateSample(
|
||||||
|
|
||||||
MuxerOptions SegmentTestBase::CreateMuxerOptions() const {
|
MuxerOptions SegmentTestBase::CreateMuxerOptions() const {
|
||||||
MuxerOptions ret;
|
MuxerOptions ret;
|
||||||
ret.single_segment = single_segment_;
|
|
||||||
ret.output_file_name = output_file_name_;
|
ret.output_file_name = output_file_name_;
|
||||||
ret.segment_template = segment_template_;
|
|
||||||
ret.segment_duration = 30; // seconds
|
ret.segment_duration = 30; // seconds
|
||||||
ret.fragment_duration = 30; // seconds
|
ret.fragment_duration = 30; // seconds
|
||||||
ret.segment_sap_aligned = false;
|
ret.segment_sap_aligned = false;
|
||||||
|
@ -102,10 +96,6 @@ std::string SegmentTestBase::OutputFileName() const {
|
||||||
return output_file_name_;
|
return output_file_name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SegmentTestBase::TemplateFileName(int number) const {
|
|
||||||
return GetSegmentName(segment_template_, 0, number, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SegmentTestBase::ClusterParser::ClusterParser() : in_cluster_(false) {}
|
SegmentTestBase::ClusterParser::ClusterParser() : in_cluster_(false) {}
|
||||||
|
|
||||||
SegmentTestBase::ClusterParser::~ClusterParser() {}
|
SegmentTestBase::ClusterParser::~ClusterParser() {}
|
||||||
|
|
|
@ -43,7 +43,7 @@ Status WebMMuxer::Initialize() {
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
if (!options().single_segment) {
|
if (!options().segment_template.empty()) {
|
||||||
segmenter_.reset(new MultiSegmentSegmenter(options()));
|
segmenter_.reset(new MultiSegmentSegmenter(options()));
|
||||||
} else {
|
} else {
|
||||||
segmenter_.reset(new TwoPassSingleSegmentSegmenter(options()));
|
segmenter_.reset(new TwoPassSingleSegmentSegmenter(options()));
|
||||||
|
|
|
@ -140,8 +140,6 @@ bool PackagerTestBasic::ContentsEqual(const std::string& file1,
|
||||||
MuxerOptions PackagerTestBasic::SetupOptions(const std::string& output,
|
MuxerOptions PackagerTestBasic::SetupOptions(const std::string& output,
|
||||||
bool single_segment) {
|
bool single_segment) {
|
||||||
MuxerOptions options;
|
MuxerOptions options;
|
||||||
options.single_segment = single_segment;
|
|
||||||
|
|
||||||
options.segment_duration = kSegmentDurationInSeconds;
|
options.segment_duration = kSegmentDurationInSeconds;
|
||||||
options.fragment_duration = kFragmentDurationInSecodns;
|
options.fragment_duration = kFragmentDurationInSecodns;
|
||||||
options.segment_sap_aligned = kSegmentSapAligned;
|
options.segment_sap_aligned = kSegmentSapAligned;
|
||||||
|
@ -149,6 +147,7 @@ MuxerOptions PackagerTestBasic::SetupOptions(const std::string& output,
|
||||||
options.num_subsegments_per_sidx = kNumSubsegmentsPerSidx;
|
options.num_subsegments_per_sidx = kNumSubsegmentsPerSidx;
|
||||||
|
|
||||||
options.output_file_name = GetFullPath(output);
|
options.output_file_name = GetFullPath(output);
|
||||||
|
if (!single_segment)
|
||||||
options.segment_template = GetFullPath(kSegmentTemplate);
|
options.segment_template = GetFullPath(kSegmentTemplate);
|
||||||
options.temp_dir = test_directory_.AsUTF8Unsafe();
|
options.temp_dir = test_directory_.AsUTF8Unsafe();
|
||||||
return options;
|
return options;
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
'app/packager_main.cc',
|
'app/packager_main.cc',
|
||||||
'app/packager_util.cc',
|
'app/packager_util.cc',
|
||||||
'app/packager_util.h',
|
'app/packager_util.h',
|
||||||
|
'app/retired_flags.cc',
|
||||||
|
'app/retired_flags.h',
|
||||||
'app/stream_descriptor.cc',
|
'app/stream_descriptor.cc',
|
||||||
'app/stream_descriptor.h',
|
'app/stream_descriptor.h',
|
||||||
'app/validate_flag.cc',
|
'app/validate_flag.cc',
|
||||||
|
|
Loading…
Reference in New Issue