Create GetStream
Created GetStream, a function used to get the stream descriptor for a single stream. This allows for finer control over the stream compared to the batch GetStreams. Added "trick_play_factor" to GetStream so that the trick play factor did not have to be added the stream descriptor value and "injected" into the stream. Change-Id: Ifbde64b961a673aafa5f6d21f33a68d02fb46610
This commit is contained in:
parent
9547000eb6
commit
b81b832522
|
@ -42,6 +42,23 @@ class StreamDescriptor(object):
|
||||||
return self.buffer
|
return self.buffer
|
||||||
|
|
||||||
|
|
||||||
|
def GetExtension(stream_descriptor, output_format):
|
||||||
|
# TODO(rkuroiwa): Support ttml.
|
||||||
|
if stream_descriptor == 'text':
|
||||||
|
return 'vtt'
|
||||||
|
if output_format:
|
||||||
|
return output_format
|
||||||
|
# Default to mp4.
|
||||||
|
return 'mp4'
|
||||||
|
|
||||||
|
|
||||||
|
def GetSegmentedExtension(base_extension):
|
||||||
|
if base_extension == 'mp4':
|
||||||
|
return 'm4s'
|
||||||
|
|
||||||
|
return base_extension
|
||||||
|
|
||||||
|
|
||||||
class PackagerAppTest(unittest.TestCase):
|
class PackagerAppTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -54,7 +71,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
self.output_prefix = os.path.join(self.tmp_dir, 'output')
|
self.output_prefix = os.path.join(self.tmp_dir, 'output')
|
||||||
self.mpd_output = self.output_prefix + '.mpd'
|
self.mpd_output = self.output_prefix + '.mpd'
|
||||||
self.hls_master_playlist_output = self.output_prefix + '.m3u8'
|
self.hls_master_playlist_output = self.output_prefix + '.m3u8'
|
||||||
self.output = None
|
self.output = []
|
||||||
|
|
||||||
# Test variables.
|
# Test variables.
|
||||||
self.encryption_key_id = '31323334353637383930313233343536'
|
self.encryption_key_id = '31323334353637383930313233343536'
|
||||||
|
@ -76,79 +93,124 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
if test_env.options.remove_temp_files_after_test:
|
if test_env.options.remove_temp_files_after_test:
|
||||||
shutil.rmtree(self.tmp_dir)
|
shutil.rmtree(self.tmp_dir)
|
||||||
|
|
||||||
def _GetStreams(self,
|
def _GetStream(self,
|
||||||
stream_descriptors,
|
descriptor,
|
||||||
language_override=None,
|
language=None,
|
||||||
output_format=None,
|
output_format=None,
|
||||||
segmented=False,
|
segmented=False,
|
||||||
hls=False,
|
hls=False,
|
||||||
test_files=None):
|
trick_play_factor=None,
|
||||||
if test_files is None:
|
drm_label=None,
|
||||||
test_files = ['bear-640x360.mp4']
|
skip_encryption=None,
|
||||||
streams = []
|
test_file=None,
|
||||||
if not self.output:
|
test_file_index=None):
|
||||||
self.output = []
|
"""Get a stream descriptor as a string.
|
||||||
|
|
||||||
for test_file_index, test_file_name in enumerate(test_files):
|
|
||||||
test_file = os.path.join(self.test_data_dir, test_file_name)
|
|
||||||
for stream_descriptor in stream_descriptors:
|
|
||||||
if len(test_files) == 1:
|
|
||||||
output_prefix = '%s_%s' % (self.output_prefix, stream_descriptor)
|
|
||||||
else:
|
|
||||||
output_prefix = '%s_%d_%s' % (self.output_prefix, test_file_index,
|
|
||||||
stream_descriptor)
|
|
||||||
# Replace ',', '=' with '_' to make it more like a filename, also
|
|
||||||
# avoid potential illegal charactors for a filename.
|
|
||||||
for ch in [',', '=']:
|
|
||||||
output_prefix = output_prefix.replace(ch, '_')
|
|
||||||
|
|
||||||
stream = StreamDescriptor(test_file)
|
Create the stream descriptor as a string for the given parameters so that
|
||||||
stream.Append('stream', stream_descriptor)
|
it can be passed as an input parameter to the packager.
|
||||||
|
|
||||||
base_ext = self._GetExtension(stream_descriptor, output_format)
|
|
||||||
segment_ext = self._GetSegmentedExtension(base_ext)
|
|
||||||
|
|
||||||
requires_init_segment = segmented and base_ext not in ['ts', 'vtt']
|
Args:
|
||||||
|
descriptor: The name of the stream in the container that should be used as
|
||||||
|
input for the output.
|
||||||
|
language: The language override for the input stream.
|
||||||
|
output_format: Specify the format for the output.
|
||||||
|
segmented: Should the output use a segmented formatted. This will affect
|
||||||
|
the output extensions and manifests.
|
||||||
|
hls: Should the output be for an HLS manifest.
|
||||||
|
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
|
||||||
|
same as not specifying a trick play factor.
|
||||||
|
drm_label: Sets the drm label for the stream.
|
||||||
|
skip_encryption: If set to true, the stream will not be encrypted.
|
||||||
|
test_file: Specify the input file to use. If the input file is not
|
||||||
|
specify, a default file will be used.
|
||||||
|
test_file_index: Specify the index of the input out of a group of input
|
||||||
|
files.
|
||||||
|
|
||||||
if requires_init_segment:
|
|
||||||
init_seg = '%s-init.%s' % (output_prefix, base_ext)
|
|
||||||
stream.Append('init_segment', init_seg)
|
|
||||||
|
|
||||||
if segmented:
|
Returns:
|
||||||
seg_template = '%s-$Number$.%s' % (output_prefix, segment_ext)
|
A string that makes up a single stream descriptor for input to the
|
||||||
stream.Append('segment_template', seg_template)
|
packager.
|
||||||
|
"""
|
||||||
|
|
||||||
self.output.append(output_prefix)
|
test_file = test_file or 'bear-640x360.mp4'
|
||||||
else:
|
test_file = os.path.join(self.test_data_dir, test_file)
|
||||||
output = '%s.%s' % (output_prefix, base_ext)
|
|
||||||
stream.Append('output', output)
|
|
||||||
self.output.append(output)
|
|
||||||
|
|
||||||
if output_format:
|
if test_file_index is None:
|
||||||
stream.Append('format', output_format)
|
output_file = '%s_%s' % (self.output_prefix, descriptor)
|
||||||
if language_override:
|
else:
|
||||||
stream.Append('lang', language_override)
|
str_params = (self.output_prefix, test_file_index, descriptor)
|
||||||
if hls:
|
output_file = '%s_%d_%s' % str_params
|
||||||
stream.Append('playlist_name', stream_descriptor + '.m3u8')
|
|
||||||
|
|
||||||
streams.append(str(stream))
|
if trick_play_factor:
|
||||||
|
output_file += '_trick_play_factor_%d' % trick_play_factor
|
||||||
|
|
||||||
return streams
|
if skip_encryption:
|
||||||
|
output_file += '_skip_encryption'
|
||||||
|
|
||||||
|
stream = StreamDescriptor(test_file)
|
||||||
|
stream.Append('stream', descriptor)
|
||||||
|
|
||||||
|
base_ext = GetExtension(descriptor, output_format)
|
||||||
|
|
||||||
|
requires_init_segment = segmented and base_ext not in ['ts', 'vtt']
|
||||||
|
|
||||||
|
if requires_init_segment:
|
||||||
|
init_seg = '%s-init.%s' % (output_file, base_ext)
|
||||||
|
stream.Append('init_segment', init_seg)
|
||||||
|
|
||||||
|
if segmented:
|
||||||
|
segment_ext = GetSegmentedExtension(base_ext)
|
||||||
|
seg_template = '%s-$Number$.%s' % (output_file, segment_ext)
|
||||||
|
stream.Append('segment_template', seg_template)
|
||||||
|
else:
|
||||||
|
output_file = '%s.%s' % (output_file, base_ext)
|
||||||
|
stream.Append('output', output_file)
|
||||||
|
|
||||||
|
self.output.append(output_file)
|
||||||
|
|
||||||
def _GetExtension(self, stream_descriptor, output_format):
|
|
||||||
# TODO(vaage): Support ttml.
|
|
||||||
if stream_descriptor == 'text':
|
|
||||||
return 'vtt'
|
|
||||||
if output_format:
|
if output_format:
|
||||||
return output_format
|
stream.Append('format', output_format)
|
||||||
# Default to mp4.
|
|
||||||
return 'mp4'
|
|
||||||
|
|
||||||
def _GetSegmentedExtension(self, base_extension):
|
if language:
|
||||||
if base_extension == 'mp4':
|
stream.Append('lang', language)
|
||||||
return 'm4s'
|
|
||||||
|
|
||||||
return base_extension
|
if hls:
|
||||||
|
stream.Append('playlist_name', descriptor + '.m3u8')
|
||||||
|
|
||||||
|
if trick_play_factor:
|
||||||
|
stream.Append('trick_play_factor', trick_play_factor)
|
||||||
|
|
||||||
|
if drm_label:
|
||||||
|
stream.Append('drm_label', drm_label)
|
||||||
|
|
||||||
|
if skip_encryption:
|
||||||
|
stream.Append('skip_encryption', 1)
|
||||||
|
|
||||||
|
return str(stream)
|
||||||
|
|
||||||
|
def _GetStreams(self, streams, test_files=None, **kwargs):
|
||||||
|
# Make sure there is a valid list that we can get the length from.
|
||||||
|
test_files = test_files or []
|
||||||
|
test_files_count = len(test_files)
|
||||||
|
|
||||||
|
out = []
|
||||||
|
|
||||||
|
if test_files_count == 0:
|
||||||
|
for stream in streams:
|
||||||
|
out.append(self._GetStream(stream, **kwargs))
|
||||||
|
elif test_files_count == 1:
|
||||||
|
for stream in streams:
|
||||||
|
out.append(self._GetStream(stream, test_file=test_files[0], **kwargs))
|
||||||
|
else:
|
||||||
|
for index, filename in enumerate(test_files):
|
||||||
|
for stream in streams:
|
||||||
|
out.append(self._GetStream(
|
||||||
|
stream, test_file_index=index, test_file=filename, **kwargs))
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
def _GetFlags(self,
|
def _GetFlags(self,
|
||||||
strip_parameter_set_nalus=True,
|
strip_parameter_set_nalus=True,
|
||||||
|
@ -483,19 +545,27 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
self._DiffGold(self.mpd_output, 'bear-640x360-av-golden.mpd')
|
self._DiffGold(self.mpd_output, 'bear-640x360-av-golden.mpd')
|
||||||
|
|
||||||
def testPackageAudioVideoWithTrickPlay(self):
|
def testPackageAudioVideoWithTrickPlay(self):
|
||||||
self.assertPackageSuccess(
|
streams = [
|
||||||
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1']),
|
self._GetStream('audio'),
|
||||||
self._GetFlags())
|
self._GetStream('video'),
|
||||||
|
self._GetStream('video', trick_play_factor=1),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertPackageSuccess(streams, self._GetFlags())
|
||||||
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-golden.mp4')
|
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-golden.mp4')
|
||||||
self._DiffGold(self.mpd_output, 'bear-640x360-av-trick-1-golden.mpd')
|
self._DiffGold(self.mpd_output, 'bear-640x360-av-trick-1-golden.mpd')
|
||||||
|
|
||||||
def testPackageAudioVideoWithTwoTrickPlay(self):
|
def testPackageAudioVideoWithTwoTrickPlay(self):
|
||||||
self.assertPackageSuccess(
|
streams = [
|
||||||
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1',
|
self._GetStream('audio'),
|
||||||
'video,trick_play_factor=2']),
|
self._GetStream('video'),
|
||||||
self._GetFlags())
|
self._GetStream('video', trick_play_factor=1),
|
||||||
|
self._GetStream('video', trick_play_factor=2),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertPackageSuccess(streams, self._GetFlags())
|
||||||
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-golden.mp4')
|
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-golden.mp4')
|
||||||
|
@ -504,10 +574,14 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
'bear-640x360-av-trick-1-trick-2-golden.mpd')
|
'bear-640x360-av-trick-1-trick-2-golden.mpd')
|
||||||
|
|
||||||
def testPackageAudioVideoWithTwoTrickPlayDecreasingRate(self):
|
def testPackageAudioVideoWithTwoTrickPlayDecreasingRate(self):
|
||||||
self.assertPackageSuccess(
|
streams = [
|
||||||
self._GetStreams(['audio', 'video', 'video,trick_play_factor=2',
|
self._GetStream('audio'),
|
||||||
'video,trick_play_factor=1']),
|
self._GetStream('video'),
|
||||||
self._GetFlags())
|
self._GetStream('video', trick_play_factor=2),
|
||||||
|
self._GetStream('video', trick_play_factor=1),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertPackageSuccess(streams, self._GetFlags())
|
||||||
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
self._DiffGold(self.output[2], 'bear-640x360-v-trick-2-golden.mp4')
|
self._DiffGold(self.output[2], 'bear-640x360-v-trick-2-golden.mp4')
|
||||||
|
@ -519,7 +593,7 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
|
|
||||||
def testPackageAudioVideoWithLanguageOverride(self):
|
def testPackageAudioVideoWithLanguageOverride(self):
|
||||||
self.assertPackageSuccess(
|
self.assertPackageSuccess(
|
||||||
self._GetStreams(['audio', 'video'], language_override='por-BR'),
|
self._GetStreams(['audio', 'video'], language='por-BR'),
|
||||||
self._GetFlags())
|
self._GetFlags())
|
||||||
self._DiffGold(self.output[0], 'bear-640x360-a-por-golden.mp4')
|
self._DiffGold(self.output[0], 'bear-640x360-a-por-golden.mp4')
|
||||||
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
@ -527,7 +601,7 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
|
|
||||||
def testPackageAudioVideoWithLanguageOverrideWithSubtag(self):
|
def testPackageAudioVideoWithLanguageOverrideWithSubtag(self):
|
||||||
self.assertPackageSuccess(
|
self.assertPackageSuccess(
|
||||||
self._GetStreams(['audio', 'video'], language_override='por-BR'),
|
self._GetStreams(['audio', 'video'], language='por-BR'),
|
||||||
self._GetFlags())
|
self._GetFlags())
|
||||||
self._DiffGold(self.output[0], 'bear-640x360-a-por-BR-golden.mp4')
|
self._DiffGold(self.output[0], 'bear-640x360-a-por-BR-golden.mp4')
|
||||||
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._DiffGold(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
@ -798,9 +872,12 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
]
|
]
|
||||||
# DRM label 'MyVideo' is not defined, will fall back to the key for the
|
# DRM label 'MyVideo' is not defined, will fall back to the key for the
|
||||||
# empty default label.
|
# empty default label.
|
||||||
self.assertPackageSuccess(
|
streams = [
|
||||||
self._GetStreams(['audio,drm_label=MyAudio',
|
self._GetStream('audio', drm_label='MyAudio'),
|
||||||
'video,drm_label=MyVideo']), flags)
|
self._GetStream('video', drm_label='MyVideo')
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertPackageSuccess(streams, flags)
|
||||||
|
|
||||||
self.encryption_key_id = audio_key_id
|
self.encryption_key_id = audio_key_id
|
||||||
self.encryption_key = audio_key
|
self.encryption_key = audio_key
|
||||||
|
@ -810,18 +887,27 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
|
||||||
def testPackageWithEncryptionOfOnlyVideoStream(self):
|
def testPackageWithEncryptionOfOnlyVideoStream(self):
|
||||||
self.assertPackageSuccess(
|
streams = [
|
||||||
self._GetStreams(['audio,skip_encryption=1', 'video']),
|
self._GetStream('audio', skip_encryption=True),
|
||||||
self._GetFlags(encryption=True))
|
self._GetStream('video')
|
||||||
|
]
|
||||||
|
flags = self._GetFlags(encryption=True)
|
||||||
|
|
||||||
|
self.assertPackageSuccess(streams, flags)
|
||||||
|
|
||||||
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
|
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
|
||||||
self._DiffGold(self.mpd_output, 'bear-640x360-a-clear-v-cenc-golden.mpd')
|
self._DiffGold(self.mpd_output, 'bear-640x360-a-clear-v-cenc-golden.mpd')
|
||||||
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
|
||||||
def testPackageWithEncryptionAndTrickPlay(self):
|
def testPackageWithEncryptionAndTrickPlay(self):
|
||||||
self.assertPackageSuccess(
|
streams = [
|
||||||
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1']),
|
self._GetStream('audio'),
|
||||||
self._GetFlags(encryption=True))
|
self._GetStream('video'),
|
||||||
|
self._GetStream('video', trick_play_factor=1),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertPackageSuccess(streams, self._GetFlags(encryption=True))
|
||||||
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
|
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
|
||||||
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
|
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
|
||||||
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-cenc-golden.mp4')
|
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-cenc-golden.mp4')
|
||||||
|
@ -833,10 +919,14 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
# TODO(hmchen): Add a test case that SD and HD AdapatationSet share one trick
|
# TODO(hmchen): Add a test case that SD and HD AdapatationSet share one trick
|
||||||
# play stream.
|
# play stream.
|
||||||
def testPackageWithEncryptionAndTwoTrickPlays(self):
|
def testPackageWithEncryptionAndTwoTrickPlays(self):
|
||||||
self.assertPackageSuccess(
|
streams = [
|
||||||
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1',
|
self._GetStream('audio'),
|
||||||
'video,trick_play_factor=2']),
|
self._GetStream('video'),
|
||||||
self._GetFlags(encryption=True))
|
self._GetStream('video', trick_play_factor=1),
|
||||||
|
self._GetStream('video', trick_play_factor=2),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertPackageSuccess(streams, self._GetFlags(encryption=True))
|
||||||
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
|
self._DiffGold(self.output[0], 'bear-640x360-a-cenc-golden.mp4')
|
||||||
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
|
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
|
||||||
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-cenc-golden.mp4')
|
self._DiffGold(self.output[2], 'bear-640x360-v-trick-1-cenc-golden.mp4')
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||||
<Representation id="1" bandwidth="126510" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="126510" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
<BaseURL>output_audio_skip_encryption_1.mp4</BaseURL>
|
<BaseURL>output_audio_skip_encryption.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="757-824" timescale="44100">
|
<SegmentBase indexRange="757-824" timescale="44100">
|
||||||
<Initialization range="0-756"/>
|
<Initialization range="0-756"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
|
|
Loading…
Reference in New Issue