Add version information in generated outputs
For mp4 outputs, a metadata box with version information is added to moov box. For mpd outputs, a text comment with version information is added in the beginning of mpd file. Issue #60 Change-Id: I783ba370781c0a8f77c910ff1172bad2e7edff75
This commit is contained in:
parent
9466582d9a
commit
e0040a4910
|
@ -1,35 +1,34 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/python
|
||||||
#
|
#
|
||||||
# Copyright 2014 Google Inc. All rights reserved.
|
# Copyright 2014 Google Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# Use of this source code is governed by a BSD-style
|
# Use of this source code is governed by a BSD-style
|
||||||
# license that can be found in the LICENSE file or at
|
# license that can be found in the LICENSE file or at
|
||||||
# https://developers.google.com/open-source/licenses/bsd
|
# https://developers.google.com/open-source/licenses/bsd
|
||||||
#
|
"""This script wraps gyp and sets up build environments.
|
||||||
# This script is a wrapper for Packager that adds some support for how GYP
|
|
||||||
# is invoked by Packager.
|
Build instructions:
|
||||||
#
|
|
||||||
# Build instructions:
|
1. Setup gyp: ./gyp_packager.py or use gclient runhooks
|
||||||
#
|
|
||||||
# 1. Setup gyp: ./gyp_packager.py
|
clang is enabled by default, which can be disabled by overriding
|
||||||
#
|
GYP_DEFINE environment variable, i.e.
|
||||||
# clang is not enabled by default, which can be enabled by overriding
|
"GYP_DEFINES='clang=0' gclient runhooks".
|
||||||
# GYP_DEFINE environment variable, i.e.
|
|
||||||
# "GYP_DEFINES='clang=1' ./gyp_packager.py".
|
Ninja is the default build system. User can also change to make by
|
||||||
#
|
overriding GYP_GENERATORS to make, i.e.
|
||||||
# Ninja is the default build system. User can also change to make by
|
"GYP_GENERATORS='make' gclient runhooks".
|
||||||
# overriding GYP_GENERATORS to make, i.e.
|
|
||||||
# "GYP_GENERATORS='make' ./gyp_packager.py".
|
2. The first step generates the make files but does not start the
|
||||||
#
|
build process. Ninja is the default build system. Refer to Ninja
|
||||||
# 2. The first step generates the make files but does not start the
|
manual on how to do the build.
|
||||||
# build process. Ninja is the default build system. Refer to Ninja
|
|
||||||
# manual on how to do the build.
|
Common syntaxes: ninja -C out/{Debug/Release} [Module]
|
||||||
#
|
Module is optional. If not specified, build everything.
|
||||||
# Common syntaxes: ninja -C out/{Debug/Release} [Module]
|
|
||||||
# Module is optional. If not specified, build everything.
|
Step 1 is only required if there is any gyp file change. Otherwise, you
|
||||||
#
|
may just run ninja.
|
||||||
# Step 1 is only required if there is any gyp file change. Otherwise, you
|
"""
|
||||||
# may just run ninja.
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -37,11 +36,14 @@ import sys
|
||||||
checkout_dir = os.path.dirname(os.path.realpath(__file__))
|
checkout_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
src_dir = os.path.join(checkout_dir, 'packager')
|
src_dir = os.path.join(checkout_dir, 'packager')
|
||||||
|
|
||||||
|
# Workaround the dynamic path.
|
||||||
|
# pylint: disable=g-import-not-at-top,g-bad-import-order
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(src_dir, 'build'))
|
sys.path.insert(0, os.path.join(src_dir, 'build'))
|
||||||
import gyp_helper # Workaround the dynamic path. pylint: disable-msg=F0401
|
import gyp_helper
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(src_dir, 'tools', 'gyp', 'pylib'))
|
sys.path.insert(0, os.path.join(src_dir, 'tools', 'gyp', 'pylib'))
|
||||||
import gyp # Workaround the dynamic path. pylint: disable-msg=F0401
|
import gyp
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
|
@ -58,12 +60,15 @@ if __name__ == '__main__':
|
||||||
args.extend(['-I' + os.path.join(src_dir, 'build', 'common.gypi')])
|
args.extend(['-I' + os.path.join(src_dir, 'build', 'common.gypi')])
|
||||||
|
|
||||||
# Set these default GYP_DEFINES if user does not set the value explicitly.
|
# Set these default GYP_DEFINES if user does not set the value explicitly.
|
||||||
_DEFAULT_DEFINES = {'test_isolation_mode': 'noop', 'use_glib': 0,
|
_DEFAULT_DEFINES = {'test_isolation_mode': 'noop',
|
||||||
'use_openssl': 1, 'use_x11': 0,
|
'use_glib': 0,
|
||||||
'linux_use_gold_binary': 0, 'linux_use_gold_flags': 0}
|
'use_openssl': 1,
|
||||||
|
'use_x11': 0,
|
||||||
|
'linux_use_gold_binary': 0,
|
||||||
|
'linux_use_gold_flags': 0}
|
||||||
|
|
||||||
gyp_defines = (os.environ['GYP_DEFINES'] if os.environ.get('GYP_DEFINES')
|
gyp_defines = (os.environ['GYP_DEFINES'] if os.environ.get('GYP_DEFINES') else
|
||||||
else '')
|
'')
|
||||||
for key in _DEFAULT_DEFINES:
|
for key in _DEFAULT_DEFINES:
|
||||||
if key not in gyp_defines:
|
if key not in gyp_defines:
|
||||||
gyp_defines += ' {0}={1}'.format(key, _DEFAULT_DEFINES[key])
|
gyp_defines += ' {0}={1}'.format(key, _DEFAULT_DEFINES[key])
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "packager/base/strings/string_split.h"
|
#include "packager/base/strings/string_split.h"
|
||||||
#include "packager/base/strings/stringprintf.h"
|
#include "packager/base/strings/stringprintf.h"
|
||||||
#include "packager/mpd/util/mpd_writer.h"
|
#include "packager/mpd/util/mpd_writer.h"
|
||||||
|
#include "packager/version/version.h"
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -88,7 +89,9 @@ int MpdMain(int argc, char** argv) {
|
||||||
|
|
||||||
ExitStatus status = CheckRequiredFlags();
|
ExitStatus status = CheckRequiredFlags();
|
||||||
if (status != kSuccess) {
|
if (status != kSuccess) {
|
||||||
google::ShowUsageWithFlags(argv[0]);
|
std::string version_string =
|
||||||
|
base::StringPrintf("mpd_generator version %s", kPackagerVersion);
|
||||||
|
google::ShowUsageWithFlags(version_string.c_str());
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "packager/mpd/base/media_info.pb.h"
|
#include "packager/mpd/base/media_info.pb.h"
|
||||||
#include "packager/mpd/base/mpd_builder.h"
|
#include "packager/mpd/base/mpd_builder.h"
|
||||||
#include "packager/mpd/base/simple_mpd_notifier.h"
|
#include "packager/mpd/base/simple_mpd_notifier.h"
|
||||||
|
#include "packager/version/version.h"
|
||||||
|
|
||||||
DEFINE_bool(use_fake_clock_for_muxer,
|
DEFINE_bool(use_fake_clock_for_muxer,
|
||||||
false,
|
false,
|
||||||
|
@ -45,37 +46,36 @@ DEFINE_bool(use_fake_clock_for_muxer,
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char kUsage[] =
|
const char kUsage[] =
|
||||||
"Packager driver program. Sample Usage:\n"
|
"Packager driver program. Usage:\n\n"
|
||||||
"%s [flags] <stream_descriptor> ...\n"
|
"%s [flags] <stream_descriptor> ...\n"
|
||||||
"stream_descriptor consists of comma separated field_name/value pairs:\n"
|
"stream_descriptor consists of comma separated field_name/value pairs:\n"
|
||||||
"field_name=value,[field_name=value,]...\n"
|
"field_name=value,[field_name=value,]...\n"
|
||||||
"Supported field names are as follows:\n"
|
"Supported field names are as follows:\n"
|
||||||
" - input (in): Required input/source media file path or network stream "
|
" - input (in): Required input/source media file path or network stream\n"
|
||||||
" URL.\n"
|
" URL.\n"
|
||||||
" - stream_selector (stream): Required field with value 'audio', 'video', "
|
" - stream_selector (stream): Required field with value 'audio',\n"
|
||||||
"or stream number (zero based).\n"
|
" 'video', or stream number (zero based).\n"
|
||||||
" - output (out): Required output file (single file) or initialization "
|
" - output (out): Required output file (single file) or initialization\n"
|
||||||
" file path (multiple file).\n"
|
" file path (multiple file).\n"
|
||||||
" - segment_template (segment): Optional value which specifies the "
|
" - segment_template (segment): Optional value which specifies the\n"
|
||||||
"naming pattern for the segment files, and that the stream should be "
|
" naming pattern for the segment files, and that the stream should be\n"
|
||||||
"split into multiple files. Its presence should be consistent across "
|
" split into multiple files. Its presence should be consistent across\n"
|
||||||
" streams.\n"
|
" streams.\n"
|
||||||
" - bandwidth (bw): Optional value which contains a user-specified "
|
" - bandwidth (bw): Optional value which contains a user-specified\n"
|
||||||
"content bit rate for the stream, in bits/sec. If specified, this value is "
|
" content bit rate for the stream, in bits/sec. If specified, this\n"
|
||||||
"propagated to the $Bandwidth$ template parameter for segment names. "
|
" value is propagated to the $Bandwidth$ template parameter for\n"
|
||||||
"If not specified, its value may be estimated.\n"
|
" segment names. If not specified, its value may be estimated.\n"
|
||||||
" - language (lang): Optional value which contains a user-specified "
|
" - language (lang): Optional value which contains a user-specified\n"
|
||||||
"language tag. If specified, this value overrides any language metadata "
|
" language tag. If specified, this value overrides any language\n"
|
||||||
"in the input track.\n"
|
" metadata in the input track.\n"
|
||||||
" - output_format (format): Optional value which specifies the format "
|
" - output_format (format): Optional value which specifies the format\n"
|
||||||
"of the output files (MP4 or WebM). If not specified, it will be "
|
" of the output files (MP4 or WebM). If not specified, it will be\n"
|
||||||
" derived from the file extension of the output file.\n";
|
" derived from the file extension of the output file.\n";
|
||||||
|
|
||||||
const char kMediaInfoSuffix[] = ".media_info";
|
const char kMediaInfoSuffix[] = ".media_info";
|
||||||
|
|
||||||
enum ExitStatus {
|
enum ExitStatus {
|
||||||
kSuccess = 0,
|
kSuccess = 0,
|
||||||
kNoArgument,
|
|
||||||
kArgumentValidationFailed,
|
kArgumentValidationFailed,
|
||||||
kPackagingFailed,
|
kPackagingFailed,
|
||||||
kInternalError,
|
kInternalError,
|
||||||
|
@ -441,8 +441,10 @@ int PackagerMain(int argc, char** argv) {
|
||||||
google::SetUsageMessage(base::StringPrintf(kUsage, argv[0]));
|
google::SetUsageMessage(base::StringPrintf(kUsage, argv[0]));
|
||||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
google::ShowUsageWithFlags(argv[0]);
|
std::string version_string =
|
||||||
return kNoArgument;
|
base::StringPrintf("edash-packager version %s", kPackagerVersion);
|
||||||
|
google::ShowUsageWithFlags(version_string.c_str());
|
||||||
|
return kSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateWidevineCryptoFlags() || !ValidateFixedCryptoFlags())
|
if (!ValidateWidevineCryptoFlags() || !ValidateFixedCryptoFlags())
|
||||||
|
|
|
@ -25,6 +25,16 @@
|
||||||
#include "packager/mpd/base/mpd_builder.h"
|
#include "packager/mpd/base/mpd_builder.h"
|
||||||
|
|
||||||
DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
|
DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
|
||||||
|
DEFINE_bool(override_version_string,
|
||||||
|
false,
|
||||||
|
"Override packager version string in the generated outputs with "
|
||||||
|
"--test_version_string if it is set to true. Should be used for "
|
||||||
|
"testing only.");
|
||||||
|
DEFINE_string(test_version_string,
|
||||||
|
"",
|
||||||
|
"Packager version string for testing. Ignored if "
|
||||||
|
"--override_version_string is false. Should be used for testing "
|
||||||
|
"only.");
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
@ -146,6 +156,8 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) {
|
||||||
muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned;
|
muxer_options->fragment_sap_aligned = FLAGS_fragment_sap_aligned;
|
||||||
muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
|
muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
|
||||||
muxer_options->temp_dir = FLAGS_temp_dir;
|
muxer_options->temp_dir = FLAGS_temp_dir;
|
||||||
|
if (FLAGS_override_version_string)
|
||||||
|
muxer_options->packager_version_string = FLAGS_test_version_string;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +170,8 @@ bool GetMpdOptions(MpdOptions* mpd_options) {
|
||||||
mpd_options->time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
|
mpd_options->time_shift_buffer_depth = FLAGS_time_shift_buffer_depth;
|
||||||
mpd_options->suggested_presentation_delay =
|
mpd_options->suggested_presentation_delay =
|
||||||
FLAGS_suggested_presentation_delay;
|
FLAGS_suggested_presentation_delay;
|
||||||
|
if (FLAGS_override_version_string)
|
||||||
|
mpd_options->packager_version_string = FLAGS_test_version_string;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,13 @@ class PackagerApp(object):
|
||||||
cmd = [self.binary, input_str, '--dump_stream_info']
|
cmd = [self.binary, input_str, '--dump_stream_info']
|
||||||
return subprocess.check_output(cmd)
|
return subprocess.check_output(cmd)
|
||||||
|
|
||||||
|
def Version(self):
|
||||||
|
output = subprocess.check_output([self.binary])
|
||||||
|
# The output should of the form:
|
||||||
|
# edash-packager version xxx: Description...
|
||||||
|
# We consider everything before ':' part of version.
|
||||||
|
return output.split(':')[0]
|
||||||
|
|
||||||
def Package(self, streams, flags=None):
|
def Package(self, streams, flags=None):
|
||||||
if flags is None:
|
if flags is None:
|
||||||
flags = []
|
flags = []
|
||||||
|
|
|
@ -38,6 +38,11 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
def testBuildingCode(self):
|
def testBuildingCode(self):
|
||||||
self.assertEqual(0, self.packager.BuildSrc())
|
self.assertEqual(0, self.packager.BuildSrc())
|
||||||
|
|
||||||
|
def testVersion(self):
|
||||||
|
self.assertRegexpMatches(
|
||||||
|
self.packager.Version(), '^edash-packager version '
|
||||||
|
'((?P<tag>[\w\.]+)-)?(?P<hash>[a-f\d]+)-(debug|release)$')
|
||||||
|
|
||||||
def testDumpStreamInfo(self):
|
def testDumpStreamInfo(self):
|
||||||
test_file = os.path.join(self.test_data_dir, 'bear-640x360.mp4')
|
test_file = os.path.join(self.test_data_dir, 'bear-640x360.mp4')
|
||||||
stream_info = self.packager.DumpStreamInfo(test_file)
|
stream_info = self.packager.DumpStreamInfo(test_file)
|
||||||
|
@ -346,6 +351,10 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
# Use fake clock, so output can be compared.
|
# Use fake clock, so output can be compared.
|
||||||
if use_fake_clock:
|
if use_fake_clock:
|
||||||
flags.append('--use_fake_clock_for_muxer')
|
flags.append('--use_fake_clock_for_muxer')
|
||||||
|
|
||||||
|
# Override packager version string for testing.
|
||||||
|
flags += ['--override_version_string', '--test_version_string',
|
||||||
|
'<tag>-<hash>-<test>']
|
||||||
return flags
|
return flags
|
||||||
|
|
||||||
def _CompareWithGold(self, test_output, golden_file_name):
|
def _CompareWithGold(self, test_output, golden_file_name):
|
||||||
|
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
bandwidth: 128728
|
bandwidth: 129127
|
||||||
audio_info {
|
audio_info {
|
||||||
codec: "mp4a.40.2"
|
codec: "mp4a.40.2"
|
||||||
sampling_frequency: 44100
|
sampling_frequency: 44100
|
||||||
|
@ -8,11 +8,11 @@ audio_info {
|
||||||
}
|
}
|
||||||
init_range {
|
init_range {
|
||||||
begin: 0
|
begin: 0
|
||||||
end: 816
|
end: 954
|
||||||
}
|
}
|
||||||
index_range {
|
index_range {
|
||||||
begin: 817
|
begin: 955
|
||||||
end: 884
|
end: 1022
|
||||||
}
|
}
|
||||||
media_file_name: "place_holder"
|
media_file_name: "place_holder"
|
||||||
media_duration_seconds: 2.7631745
|
media_duration_seconds: 2.7631745
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,28 +1,29 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
<Representation id="0" bandwidth="885151" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="885555" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<BaseURL>output_video.mp4</BaseURL>
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="941-1008" timescale="30000">
|
<SegmentBase indexRange="1079-1146" timescale="30000">
|
||||||
<Initialization range="0-940"/>
|
<Initialization range="0-1078"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||||
<Representation id="1" bandwidth="128728" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="129127" 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"/>
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<BaseURL>output_audio.mp4</BaseURL>
|
<BaseURL>output_audio.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="817-884" timescale="44100">
|
<SegmentBase indexRange="955-1022" timescale="44100">
|
||||||
<Initialization range="0-816"/>
|
<Initialization range="0-954"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
|
@ -6,10 +7,10 @@
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<Representation id="0" bandwidth="885151" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="885555" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<BaseURL>output_video.mp4</BaseURL>
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="941-1008" timescale="30000">
|
<SegmentBase indexRange="1079-1146" timescale="30000">
|
||||||
<Initialization range="0-940"/>
|
<Initialization range="0-1078"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
|
@ -18,11 +19,11 @@
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<Representation id="1" bandwidth="128728" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="129127" 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.mp4</BaseURL>
|
<BaseURL>output_audio.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="817-884" timescale="44100">
|
<SegmentBase indexRange="955-1022" timescale="44100">
|
||||||
<Initialization range="0-816"/>
|
<Initialization range="0-954"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
<Representation id="0" bandwidth="881637" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<BaseURL>output_video.mp4</BaseURL>
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="677-744" timescale="30000">
|
<SegmentBase indexRange="815-882" timescale="30000">
|
||||||
<Initialization range="0-676"/>
|
<Initialization range="0-814"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||||
<Representation id="1" bandwidth="126087" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="1" bandwidth="126487" 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.mp4</BaseURL>
|
<BaseURL>output_audio.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="611-678" timescale="44100">
|
<SegmentBase indexRange="749-816" timescale="44100">
|
||||||
<Initialization range="0-610"/>
|
<Initialization range="0-748"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||||
<Period start="PT0S">
|
<Period start="PT0S">
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||||
<Period start="PT0S">
|
<Period start="PT0S">
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||||
<Period start="PT0S">
|
<Period start="PT0S">
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||||
<Period start="PT0S">
|
<Period start="PT0S">
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="dynamic" profiles="urn:mpeg:dash:profile:isoff-live:2011" availabilityStartTime="place_holder" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
|
||||||
<Period start="PT0S">
|
<Period start="PT0S">
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.763174533843994S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" contentType="text">
|
<AdaptationSet id="0" contentType="text">
|
||||||
|
@ -7,19 +8,19 @@
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="1" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
<AdaptationSet id="1" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
<Representation id="1" bandwidth="881637" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="1" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<BaseURL>output_video.mp4</BaseURL>
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="677-744" timescale="30000">
|
<SegmentBase indexRange="815-882" timescale="30000">
|
||||||
<Initialization range="0-676"/>
|
<Initialization range="0-814"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
<AdaptationSet id="2" contentType="audio" subsegmentAlignment="true">
|
<AdaptationSet id="2" contentType="audio" subsegmentAlignment="true">
|
||||||
<Representation id="2" bandwidth="126087" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
<Representation id="2" bandwidth="126487" 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.mp4</BaseURL>
|
<BaseURL>output_audio.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="611-678" timescale="44100">
|
<SegmentBase indexRange="749-816" timescale="44100">
|
||||||
<Initialization range="0-610"/>
|
<Initialization range="0-748"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
|
|
Binary file not shown.
|
@ -1,15 +1,16 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.7694332599639893S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.7694332599639893S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
<Representation id="0" bandwidth="264624" codecs="hev1.1.6.L63.80" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="265022" codecs="hev1.1.6.L63.80" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
<cenc:pssh>AAAAMHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABAxMjM0NTY3ODkwMTIzNDU2</cenc:pssh>
|
||||||
</ContentProtection>
|
</ContentProtection>
|
||||||
<BaseURL>output_video.mp4</BaseURL>
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="2721-2764" timescale="30000">
|
<SegmentBase indexRange="2859-2902" timescale="30000">
|
||||||
<Initialization range="0-2720"/>
|
<Initialization range="0-2858"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
|
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
bandwidth: 885151
|
bandwidth: 885555
|
||||||
video_info {
|
video_info {
|
||||||
codec: "avc1.64001e"
|
codec: "avc1.64001e"
|
||||||
width: 640
|
width: 640
|
||||||
|
@ -11,11 +11,11 @@ video_info {
|
||||||
}
|
}
|
||||||
init_range {
|
init_range {
|
||||||
begin: 0
|
begin: 0
|
||||||
end: 940
|
end: 1078
|
||||||
}
|
}
|
||||||
index_range {
|
index_range {
|
||||||
begin: 941
|
begin: 1079
|
||||||
end: 1008
|
end: 1146
|
||||||
}
|
}
|
||||||
media_file_name: "place_holder"
|
media_file_name: "place_holder"
|
||||||
media_duration_seconds: 2.7360666
|
media_duration_seconds: 2.7360666
|
||||||
|
|
Binary file not shown.
|
@ -1,11 +1,12 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.7360665798187256S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT2.7360665798187256S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
<Representation id="0" bandwidth="881637" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
<Representation id="0" bandwidth="882040" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1" width="640" height="360" frameRate="30000/1001">
|
||||||
<BaseURL>output_0.mp4</BaseURL>
|
<BaseURL>output_0.mp4</BaseURL>
|
||||||
<SegmentBase indexRange="677-744" timescale="30000">
|
<SegmentBase indexRange="815-882" timescale="30000">
|
||||||
<Initialization range="0-676"/>
|
<Initialization range="0-814"/>
|
||||||
</SegmentBase>
|
</SegmentBase>
|
||||||
</Representation>
|
</Representation>
|
||||||
</AdaptationSet>
|
</AdaptationSet>
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/edash-packager version <tag>-<hash>-<test>-->
|
||||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" minBufferTime="PT2S" type="static" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" mediaPresentationDuration="PT0S">
|
||||||
<Period>
|
<Period>
|
||||||
<AdaptationSet id="0" contentType="text">
|
<AdaptationSet id="0" contentType="text">
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
'../../third_party/boringssl/boringssl.gyp:boringssl',
|
'../../third_party/boringssl/boringssl.gyp:boringssl',
|
||||||
'../../third_party/curl/curl.gyp:libcurl',
|
'../../third_party/curl/curl.gyp:libcurl',
|
||||||
'../../third_party/libxml/libxml.gyp:libxml',
|
'../../third_party/libxml/libxml.gyp:libxml',
|
||||||
|
'../../version/version.gyp:version',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
#include "packager/media/base/muxer_options.h"
|
#include "packager/media/base/muxer_options.h"
|
||||||
|
#include "packager/version/version.h"
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
@ -16,7 +17,8 @@ MuxerOptions::MuxerOptions()
|
||||||
segment_sap_aligned(false),
|
segment_sap_aligned(false),
|
||||||
fragment_sap_aligned(false),
|
fragment_sap_aligned(false),
|
||||||
num_subsegments_per_sidx(0),
|
num_subsegments_per_sidx(0),
|
||||||
bandwidth(0) {}
|
bandwidth(0),
|
||||||
|
packager_version_string(kPackagerVersion) {}
|
||||||
MuxerOptions::~MuxerOptions() {}
|
MuxerOptions::~MuxerOptions() {}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -66,6 +66,9 @@ 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;
|
||||||
|
|
||||||
|
/// Specify the version string to be embedded in the output files.
|
||||||
|
std::string packager_version_string;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -63,6 +63,11 @@ bool IsIvSizeValid(size_t iv_size) {
|
||||||
// bit(5) Reserved // 0
|
// bit(5) Reserved // 0
|
||||||
const uint8_t kDdtsExtraData[] = {0xe4, 0x7c, 0, 4, 0, 0x0f, 0};
|
const uint8_t kDdtsExtraData[] = {0xe4, 0x7c, 0, 4, 0, 0x0f, 0};
|
||||||
|
|
||||||
|
// ID3v2 header: http://id3.org/id3v2.4.0-structure
|
||||||
|
const uint32_t kID3v2HeaderSize = 10;
|
||||||
|
const char kID3v2Identifier[] = "ID3";
|
||||||
|
const uint16_t kID3v2Version = 0x0400; // id3v2.4.0
|
||||||
|
|
||||||
// Utility functions to check if the 64bit integers can fit in 32bit integer.
|
// Utility functions to check if the 64bit integers can fit in 32bit integer.
|
||||||
bool IsFitIn32Bits(uint64_t a) {
|
bool IsFitIn32Bits(uint64_t a) {
|
||||||
return a <= std::numeric_limits<uint32_t>::max();
|
return a <= std::numeric_limits<uint32_t>::max();
|
||||||
|
@ -89,6 +94,36 @@ namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace mp4 {
|
namespace mp4 {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TrackType FourCCToTrackType(FourCC fourcc) {
|
||||||
|
switch (fourcc) {
|
||||||
|
case FOURCC_VIDE:
|
||||||
|
return kVideo;
|
||||||
|
case FOURCC_SOUN:
|
||||||
|
return kAudio;
|
||||||
|
case FOURCC_TEXT:
|
||||||
|
return kText;
|
||||||
|
default:
|
||||||
|
return kInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FourCC TrackTypeToFourCC(TrackType track_type) {
|
||||||
|
switch (track_type) {
|
||||||
|
case kVideo:
|
||||||
|
return FOURCC_VIDE;
|
||||||
|
case kAudio:
|
||||||
|
return FOURCC_SOUN;
|
||||||
|
case kText:
|
||||||
|
return FOURCC_TEXT;
|
||||||
|
default:
|
||||||
|
return FOURCC_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
FileType::FileType() : major_brand(FOURCC_NULL), minor_version(0) {}
|
FileType::FileType() : major_brand(FOURCC_NULL), minor_version(0) {}
|
||||||
FileType::~FileType() {}
|
FileType::~FileType() {}
|
||||||
FourCC FileType::BoxType() const { return FOURCC_FTYP; }
|
FourCC FileType::BoxType() const { return FOURCC_FTYP; }
|
||||||
|
@ -967,44 +1002,37 @@ uint32_t Edit::ComputeSizeInternal() {
|
||||||
return HeaderSize() + list.ComputeSize();
|
return HeaderSize() + list.ComputeSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
HandlerReference::HandlerReference() : type(kInvalid) {}
|
HandlerReference::HandlerReference() : handler_type(FOURCC_NULL) {}
|
||||||
HandlerReference::~HandlerReference() {}
|
HandlerReference::~HandlerReference() {}
|
||||||
FourCC HandlerReference::BoxType() const { return FOURCC_HDLR; }
|
FourCC HandlerReference::BoxType() const { return FOURCC_HDLR; }
|
||||||
|
|
||||||
bool HandlerReference::ReadWriteInternal(BoxBuffer* buffer) {
|
bool HandlerReference::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
FourCC hdlr_type = FOURCC_NULL;
|
|
||||||
std::vector<uint8_t> handler_name;
|
std::vector<uint8_t> handler_name;
|
||||||
if (!buffer->Reading()) {
|
if (!buffer->Reading()) {
|
||||||
if (type == kVideo) {
|
switch (handler_type) {
|
||||||
hdlr_type = FOURCC_VIDE;
|
case FOURCC_VIDE:
|
||||||
handler_name.assign(kVideoHandlerName,
|
handler_name.assign(kVideoHandlerName,
|
||||||
kVideoHandlerName + arraysize(kVideoHandlerName));
|
kVideoHandlerName + arraysize(kVideoHandlerName));
|
||||||
} else if (type == kAudio) {
|
break;
|
||||||
hdlr_type = FOURCC_SOUN;
|
case FOURCC_SOUN:
|
||||||
handler_name.assign(kAudioHandlerName,
|
handler_name.assign(kAudioHandlerName,
|
||||||
kAudioHandlerName + arraysize(kAudioHandlerName));
|
kAudioHandlerName + arraysize(kAudioHandlerName));
|
||||||
} else if (type == kText) {
|
break;
|
||||||
hdlr_type = FOURCC_TEXT;
|
case FOURCC_TEXT:
|
||||||
handler_name.assign(kTextHandlerName,
|
handler_name.assign(kTextHandlerName,
|
||||||
kTextHandlerName + arraysize(kTextHandlerName));
|
kTextHandlerName + arraysize(kTextHandlerName));
|
||||||
} else {
|
break;
|
||||||
|
case FOURCC_ID32:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
NOTIMPLEMENTED();
|
NOTIMPLEMENTED();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
||||||
buffer->IgnoreBytes(4) && // predefined.
|
buffer->IgnoreBytes(4) && // predefined.
|
||||||
buffer->ReadWriteFourCC(&hdlr_type));
|
buffer->ReadWriteFourCC(&handler_type));
|
||||||
if (buffer->Reading()) {
|
if (!buffer->Reading()) {
|
||||||
// Note: for reading, remaining fields in box ignored.
|
|
||||||
if (hdlr_type == FOURCC_VIDE) {
|
|
||||||
type = kVideo;
|
|
||||||
} else if (hdlr_type == FOURCC_SOUN) {
|
|
||||||
type = kAudio;
|
|
||||||
} else {
|
|
||||||
type = kInvalid;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RCHECK(buffer->IgnoreBytes(12) && // reserved.
|
RCHECK(buffer->IgnoreBytes(12) && // reserved.
|
||||||
buffer->ReadWriteVector(&handler_name, handler_name.size()));
|
buffer->ReadWriteVector(&handler_name, handler_name.size()));
|
||||||
}
|
}
|
||||||
|
@ -1013,16 +1041,161 @@ bool HandlerReference::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
|
|
||||||
uint32_t HandlerReference::ComputeSizeInternal() {
|
uint32_t HandlerReference::ComputeSizeInternal() {
|
||||||
uint32_t box_size = HeaderSize() + kFourCCSize + 16; // 16 bytes Reserved
|
uint32_t box_size = HeaderSize() + kFourCCSize + 16; // 16 bytes Reserved
|
||||||
if (type == kVideo) {
|
switch (handler_type) {
|
||||||
|
case FOURCC_VIDE:
|
||||||
box_size += sizeof(kVideoHandlerName);
|
box_size += sizeof(kVideoHandlerName);
|
||||||
} else if (type == kAudio) {
|
break;
|
||||||
|
case FOURCC_SOUN:
|
||||||
box_size += sizeof(kAudioHandlerName);
|
box_size += sizeof(kAudioHandlerName);
|
||||||
} else {
|
break;
|
||||||
|
case FOURCC_TEXT:
|
||||||
box_size += sizeof(kTextHandlerName);
|
box_size += sizeof(kTextHandlerName);
|
||||||
|
break;
|
||||||
|
case FOURCC_ID32:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NOTIMPLEMENTED();
|
||||||
}
|
}
|
||||||
return box_size;
|
return box_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Language::ReadWrite(BoxBuffer* buffer) {
|
||||||
|
if (buffer->Reading()) {
|
||||||
|
// Read language codes into temp first then use BitReader to read the
|
||||||
|
// values. ISO-639-2/T language code: unsigned int(5)[3] language (2 bytes).
|
||||||
|
std::vector<uint8_t> temp;
|
||||||
|
RCHECK(buffer->ReadWriteVector(&temp, 2));
|
||||||
|
|
||||||
|
BitReader bit_reader(&temp[0], 2);
|
||||||
|
bit_reader.SkipBits(1);
|
||||||
|
char language[3];
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
CHECK(bit_reader.ReadBits(5, &language[i]));
|
||||||
|
language[i] += 0x60;
|
||||||
|
}
|
||||||
|
code.assign(language, 3);
|
||||||
|
} else {
|
||||||
|
// Set up default language if it is not set.
|
||||||
|
const char kUndefinedLanguage[] = "und";
|
||||||
|
if (code.empty())
|
||||||
|
code = kUndefinedLanguage;
|
||||||
|
DCHECK_EQ(code.size(), 3u);
|
||||||
|
|
||||||
|
// Lang format: bit(1) pad, unsigned int(5)[3] language.
|
||||||
|
uint16_t lang = 0;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
lang |= (code[i] - 0x60) << ((2 - i) * 5);
|
||||||
|
RCHECK(buffer->ReadWriteUInt16(&lang));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Language::ComputeSize() const {
|
||||||
|
// ISO-639-2/T language code: unsigned int(5)[3] language (2 bytes).
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PrivFrame::ReadWrite(BoxBuffer* buffer) {
|
||||||
|
FourCC fourcc = FOURCC_PRIV;
|
||||||
|
RCHECK(buffer->ReadWriteFourCC(&fourcc));
|
||||||
|
if (fourcc != FOURCC_PRIV) {
|
||||||
|
VLOG(1) << "Skip unrecognized id3 frame during read: "
|
||||||
|
<< FourCCToString(fourcc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t frame_size = owner.size() + 1 + value.size();
|
||||||
|
// size should be encoded as synchsafe integer, which is not support here.
|
||||||
|
// We don't expect frame_size to be larger than 0x7F. Synchsafe integers less
|
||||||
|
// than 0x7F is encoded in the same way as normal integer.
|
||||||
|
DCHECK_LT(frame_size, 0x7Fu);
|
||||||
|
uint16_t flags = 0;
|
||||||
|
RCHECK(buffer->ReadWriteUInt32(&frame_size) &&
|
||||||
|
buffer->ReadWriteUInt16(&flags));
|
||||||
|
|
||||||
|
if (buffer->Reading()) {
|
||||||
|
std::string str;
|
||||||
|
RCHECK(buffer->ReadWriteString(&str, frame_size));
|
||||||
|
// |owner| is null terminated.
|
||||||
|
size_t pos = str.find('\0');
|
||||||
|
RCHECK(pos < str.size());
|
||||||
|
owner = str.substr(0, pos);
|
||||||
|
value = str.substr(pos + 1);
|
||||||
|
} else {
|
||||||
|
uint8_t byte = 0; // Null terminating byte between owner and value.
|
||||||
|
RCHECK(buffer->ReadWriteString(&owner, owner.size()) &&
|
||||||
|
buffer->ReadWriteUInt8(&byte) &&
|
||||||
|
buffer->ReadWriteString(&value, value.size()));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PrivFrame::ComputeSize() const {
|
||||||
|
if (owner.empty() && value.empty())
|
||||||
|
return 0;
|
||||||
|
const uint32_t kFourCCSize = 4;
|
||||||
|
return kFourCCSize + sizeof(uint32_t) + sizeof(uint16_t) + owner.size() + 1 +
|
||||||
|
value.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
ID3v2::ID3v2() {}
|
||||||
|
ID3v2::~ID3v2() {}
|
||||||
|
|
||||||
|
FourCC ID3v2::BoxType() const { return FOURCC_ID32; }
|
||||||
|
|
||||||
|
bool ID3v2::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
|
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
||||||
|
language.ReadWrite(buffer));
|
||||||
|
|
||||||
|
// Read/Write ID3v2 header
|
||||||
|
std::string id3v2_identifier = kID3v2Identifier;
|
||||||
|
uint16_t version = kID3v2Version;
|
||||||
|
// We only support PrivateFrame in ID3.
|
||||||
|
uint32_t data_size = private_frame.ComputeSize();
|
||||||
|
// size should be encoded as synchsafe integer, which is not support here.
|
||||||
|
// We don't expect data_size to be larger than 0x7F. Synchsafe integers less
|
||||||
|
// than 0x7F is encoded in the same way as normal integer.
|
||||||
|
DCHECK_LT(data_size, 0x7Fu);
|
||||||
|
uint8_t flags = 0;
|
||||||
|
RCHECK(buffer->ReadWriteString(&id3v2_identifier, id3v2_identifier.size()) &&
|
||||||
|
buffer->ReadWriteUInt16(&version) &&
|
||||||
|
buffer->ReadWriteUInt8(&flags) &&
|
||||||
|
buffer->ReadWriteUInt32(&data_size));
|
||||||
|
|
||||||
|
RCHECK(private_frame.ReadWrite(buffer));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ID3v2::ComputeSizeInternal() {
|
||||||
|
uint32_t private_frame_size = private_frame.ComputeSize();
|
||||||
|
// Skip ID3v2 box generation if there is no private frame.
|
||||||
|
return private_frame_size == 0 ? 0 : HeaderSize() + language.ComputeSize() +
|
||||||
|
kID3v2HeaderSize +
|
||||||
|
private_frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Metadata::Metadata() {}
|
||||||
|
Metadata::~Metadata() {}
|
||||||
|
|
||||||
|
FourCC Metadata::BoxType() const {
|
||||||
|
return FOURCC_META;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
|
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
||||||
|
buffer->PrepareChildren() &&
|
||||||
|
buffer->ReadWriteChild(&handler) &&
|
||||||
|
buffer->TryReadWriteChild(&id3v2));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Metadata::ComputeSizeInternal() {
|
||||||
|
uint32_t id3v2_size = id3v2.ComputeSize();
|
||||||
|
// Skip metadata box generation if there is no metadata box.
|
||||||
|
return id3v2_size == 0 ? 0
|
||||||
|
: HeaderSize() + handler.ComputeSize() + id3v2_size;
|
||||||
|
}
|
||||||
|
|
||||||
CodecConfigurationRecord::CodecConfigurationRecord() : box_type(FOURCC_NULL) {}
|
CodecConfigurationRecord::CodecConfigurationRecord() : box_type(FOURCC_NULL) {}
|
||||||
CodecConfigurationRecord::~CodecConfigurationRecord() {}
|
CodecConfigurationRecord::~CodecConfigurationRecord() {}
|
||||||
FourCC CodecConfigurationRecord::BoxType() const {
|
FourCC CodecConfigurationRecord::BoxType() const {
|
||||||
|
@ -1369,9 +1542,7 @@ uint32_t WVTTSampleEntry::ComputeSizeInternal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaHeader::MediaHeader()
|
MediaHeader::MediaHeader()
|
||||||
: creation_time(0), modification_time(0), timescale(0), duration(0) {
|
: creation_time(0), modification_time(0), timescale(0), duration(0) {}
|
||||||
language[0] = 0;
|
|
||||||
}
|
|
||||||
MediaHeader::~MediaHeader() {}
|
MediaHeader::~MediaHeader() {}
|
||||||
FourCC MediaHeader::BoxType() const { return FOURCC_MDHD; }
|
FourCC MediaHeader::BoxType() const { return FOURCC_MDHD; }
|
||||||
|
|
||||||
|
@ -1382,42 +1553,16 @@ bool MediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
RCHECK(buffer->ReadWriteUInt64NBytes(&creation_time, num_bytes) &&
|
RCHECK(buffer->ReadWriteUInt64NBytes(&creation_time, num_bytes) &&
|
||||||
buffer->ReadWriteUInt64NBytes(&modification_time, num_bytes) &&
|
buffer->ReadWriteUInt64NBytes(&modification_time, num_bytes) &&
|
||||||
buffer->ReadWriteUInt32(×cale) &&
|
buffer->ReadWriteUInt32(×cale) &&
|
||||||
buffer->ReadWriteUInt64NBytes(&duration, num_bytes));
|
buffer->ReadWriteUInt64NBytes(&duration, num_bytes) &&
|
||||||
|
language.ReadWrite(buffer) &&
|
||||||
if (buffer->Reading()) {
|
buffer->IgnoreBytes(2)); // predefined.
|
||||||
// Read language codes into temp first then use BitReader to read the
|
|
||||||
// values. ISO-639-2/T language code: unsigned int(5)[3] language (2 bytes).
|
|
||||||
std::vector<uint8_t> temp;
|
|
||||||
RCHECK(buffer->ReadWriteVector(&temp, 2));
|
|
||||||
|
|
||||||
BitReader bit_reader(&temp[0], 2);
|
|
||||||
bit_reader.SkipBits(1);
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
|
||||||
CHECK(bit_reader.ReadBits(5, &language[i]));
|
|
||||||
language[i] += 0x60;
|
|
||||||
}
|
|
||||||
language[3] = '\0';
|
|
||||||
} else {
|
|
||||||
// Set up default language if it is not set.
|
|
||||||
const char kUndefinedLanguage[] = "und";
|
|
||||||
if (language[0] == 0)
|
|
||||||
strcpy(language, kUndefinedLanguage);
|
|
||||||
|
|
||||||
// Lang format: bit(1) pad, unsigned int(5)[3] language.
|
|
||||||
uint16_t lang = 0;
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
lang |= (language[i] - 0x60) << ((2 - i) * 5);
|
|
||||||
RCHECK(buffer->ReadWriteUInt16(&lang));
|
|
||||||
}
|
|
||||||
|
|
||||||
RCHECK(buffer->IgnoreBytes(2)); // predefined.
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MediaHeader::ComputeSizeInternal() {
|
uint32_t MediaHeader::ComputeSizeInternal() {
|
||||||
version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
|
version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
|
||||||
return HeaderSize() + sizeof(timescale) +
|
return HeaderSize() + sizeof(timescale) +
|
||||||
sizeof(uint32_t) * (1 + version) * 3 + 2 + // 2 bytes language.
|
sizeof(uint32_t) * (1 + version) * 3 + language.ComputeSize() +
|
||||||
2; // 2 bytes predefined.
|
2; // 2 bytes predefined.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1580,24 +1725,30 @@ FourCC Media::BoxType() const { return FOURCC_MDIA; }
|
||||||
bool Media::ReadWriteInternal(BoxBuffer* buffer) {
|
bool Media::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
||||||
buffer->PrepareChildren() &&
|
buffer->PrepareChildren() &&
|
||||||
buffer->ReadWriteChild(&header) &&
|
buffer->ReadWriteChild(&header));
|
||||||
buffer->ReadWriteChild(&handler));
|
|
||||||
if (buffer->Reading()) {
|
if (buffer->Reading()) {
|
||||||
|
RCHECK(buffer->ReadWriteChild(&handler));
|
||||||
// Maddeningly, the HandlerReference box specifies how to parse the
|
// Maddeningly, the HandlerReference box specifies how to parse the
|
||||||
// SampleDescription box, making the latter the only box (of those that we
|
// SampleDescription box, making the latter the only box (of those that we
|
||||||
// support) which cannot be parsed correctly on its own (or even with
|
// support) which cannot be parsed correctly on its own (or even with
|
||||||
// information from its strict ancestor tree). We thus copy the handler type
|
// information from its strict ancestor tree). We thus copy the handler type
|
||||||
// to the sample description box *before* parsing it to provide this
|
// to the sample description box *before* parsing it to provide this
|
||||||
// information while parsing.
|
// information while parsing.
|
||||||
information.sample_table.description.type = handler.type;
|
information.sample_table.description.type =
|
||||||
|
FourCCToTrackType(handler.handler_type);
|
||||||
} else {
|
} else {
|
||||||
DCHECK_EQ(information.sample_table.description.type, handler.type);
|
handler.handler_type =
|
||||||
|
TrackTypeToFourCC(information.sample_table.description.type);
|
||||||
|
RCHECK(handler.handler_type != FOURCC_NULL);
|
||||||
|
RCHECK(buffer->ReadWriteChild(&handler));
|
||||||
}
|
}
|
||||||
RCHECK(buffer->ReadWriteChild(&information));
|
RCHECK(buffer->ReadWriteChild(&information));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Media::ComputeSizeInternal() {
|
uint32_t Media::ComputeSizeInternal() {
|
||||||
|
handler.handler_type =
|
||||||
|
TrackTypeToFourCC(information.sample_table.description.type);
|
||||||
return HeaderSize() + header.ComputeSize() + handler.ComputeSize() +
|
return HeaderSize() + header.ComputeSize() + handler.ComputeSize() +
|
||||||
information.ComputeSize();
|
information.ComputeSize();
|
||||||
}
|
}
|
||||||
|
@ -1702,6 +1853,7 @@ bool Movie::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
||||||
buffer->PrepareChildren() &&
|
buffer->PrepareChildren() &&
|
||||||
buffer->ReadWriteChild(&header) &&
|
buffer->ReadWriteChild(&header) &&
|
||||||
|
buffer->TryReadWriteChild(&metadata) &&
|
||||||
buffer->TryReadWriteChild(&extends));
|
buffer->TryReadWriteChild(&extends));
|
||||||
if (buffer->Reading()) {
|
if (buffer->Reading()) {
|
||||||
BoxReader* reader = buffer->reader();
|
BoxReader* reader = buffer->reader();
|
||||||
|
@ -1718,8 +1870,8 @@ bool Movie::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Movie::ComputeSizeInternal() {
|
uint32_t Movie::ComputeSizeInternal() {
|
||||||
uint32_t box_size =
|
uint32_t box_size = HeaderSize() + header.ComputeSize() +
|
||||||
HeaderSize() + header.ComputeSize() + extends.ComputeSize();
|
metadata.ComputeSize() + extends.ComputeSize();
|
||||||
for (uint32_t i = 0; i < tracks.size(); ++i)
|
for (uint32_t i = 0; i < tracks.size(); ++i)
|
||||||
box_size += tracks[i].ComputeSize();
|
box_size += tracks[i].ComputeSize();
|
||||||
for (uint32_t i = 0; i < pssh.size(); ++i)
|
for (uint32_t i = 0; i < pssh.size(); ++i)
|
||||||
|
|
|
@ -222,7 +222,41 @@ struct Edit : Box {
|
||||||
struct HandlerReference : FullBox {
|
struct HandlerReference : FullBox {
|
||||||
DECLARE_BOX_METHODS(HandlerReference);
|
DECLARE_BOX_METHODS(HandlerReference);
|
||||||
|
|
||||||
TrackType type;
|
FourCC handler_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Language {
|
||||||
|
bool ReadWrite(BoxBuffer* buffer);
|
||||||
|
uint32_t ComputeSize() const;
|
||||||
|
|
||||||
|
std::string code;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Implemented per http://id3.org/id3v2.4.0-frames.
|
||||||
|
struct PrivFrame {
|
||||||
|
bool ReadWrite(BoxBuffer* buffer);
|
||||||
|
uint32_t ComputeSize() const;
|
||||||
|
|
||||||
|
std::string owner;
|
||||||
|
std::string value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Implemented per http://mp4ra.org/specs.html#id3v2 and
|
||||||
|
/// http://id3.org/id3v2.4.0-structure.
|
||||||
|
struct ID3v2 : FullBox {
|
||||||
|
DECLARE_BOX_METHODS(ID3v2);
|
||||||
|
|
||||||
|
Language language;
|
||||||
|
|
||||||
|
/// We only support PrivateFrame in ID3. Other frames are ignored.
|
||||||
|
PrivFrame private_frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Metadata : FullBox {
|
||||||
|
DECLARE_BOX_METHODS(Metadata);
|
||||||
|
|
||||||
|
HandlerReference handler;
|
||||||
|
ID3v2 id3v2;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CodecConfigurationRecord : Box {
|
struct CodecConfigurationRecord : Box {
|
||||||
|
@ -422,8 +456,7 @@ struct MediaHeader : FullBox {
|
||||||
uint64_t modification_time;
|
uint64_t modification_time;
|
||||||
uint32_t timescale;
|
uint32_t timescale;
|
||||||
uint64_t duration;
|
uint64_t duration;
|
||||||
// 3-char language code + 1 null terminating char.
|
Language language;
|
||||||
char language[4];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VideoMediaHeader : FullBox {
|
struct VideoMediaHeader : FullBox {
|
||||||
|
@ -519,6 +552,7 @@ struct Movie : Box {
|
||||||
DECLARE_BOX_METHODS(Movie);
|
DECLARE_BOX_METHODS(Movie);
|
||||||
|
|
||||||
MovieHeader header;
|
MovieHeader header;
|
||||||
|
Metadata metadata; // Used to hold version information.
|
||||||
MovieExtends extends;
|
MovieExtends extends;
|
||||||
std::vector<Track> tracks;
|
std::vector<Track> tracks;
|
||||||
std::vector<ProtectionSystemSpecificHeader> pssh;
|
std::vector<ProtectionSystemSpecificHeader> pssh;
|
||||||
|
|
|
@ -180,7 +180,24 @@ inline bool operator==(const Edit& lhs, const Edit& rhs) {
|
||||||
|
|
||||||
inline bool operator==(const HandlerReference& lhs,
|
inline bool operator==(const HandlerReference& lhs,
|
||||||
const HandlerReference& rhs) {
|
const HandlerReference& rhs) {
|
||||||
return lhs.type == rhs.type;
|
return lhs.handler_type == rhs.handler_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const Language& lhs,
|
||||||
|
const Language& rhs) {
|
||||||
|
return lhs.code == rhs.code;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const PrivFrame& lhs, const PrivFrame& rhs) {
|
||||||
|
return lhs.owner == rhs.owner && lhs.value == rhs.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const ID3v2& lhs, const ID3v2& rhs) {
|
||||||
|
return lhs.language == rhs.language && lhs.private_frame == rhs.private_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const Metadata& lhs, const Metadata& rhs) {
|
||||||
|
return lhs.handler == rhs.handler && lhs.id3v2 == rhs.id3v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const CodecConfigurationRecord& lhs,
|
inline bool operator==(const CodecConfigurationRecord& lhs,
|
||||||
|
@ -252,7 +269,7 @@ inline bool operator==(const MediaHeader& lhs, const MediaHeader& rhs) {
|
||||||
return lhs.creation_time == rhs.creation_time &&
|
return lhs.creation_time == rhs.creation_time &&
|
||||||
lhs.modification_time == rhs.modification_time &&
|
lhs.modification_time == rhs.modification_time &&
|
||||||
lhs.timescale == rhs.timescale && lhs.duration == rhs.duration &&
|
lhs.timescale == rhs.timescale && lhs.duration == rhs.duration &&
|
||||||
strcmp(lhs.language, rhs.language) == 0;
|
lhs.language == rhs.language;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const VideoMediaHeader& lhs,
|
inline bool operator==(const VideoMediaHeader& lhs,
|
||||||
|
|
|
@ -286,11 +286,29 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
|
|
||||||
void Modify(Edit* edts) { Modify(&edts->list); }
|
void Modify(Edit* edts) { Modify(&edts->list); }
|
||||||
|
|
||||||
void Fill(HandlerReference* hdlr) {
|
void Fill(HandlerReference* hdlr) { hdlr->handler_type = FOURCC_VIDE; }
|
||||||
hdlr->type = kSampleDescriptionTrackType;
|
|
||||||
|
void Modify(HandlerReference* hdlr) { hdlr->handler_type = FOURCC_SOUN; }
|
||||||
|
|
||||||
|
void Fill(ID3v2* id3v2) {
|
||||||
|
id3v2->language.code = "eng";
|
||||||
|
id3v2->private_frame.owner = "edash-packager";
|
||||||
|
id3v2->private_frame.value = "version 1.2.0-debug";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Modify(HandlerReference* hdlr) { hdlr->type = kAudio; }
|
void Modify(ID3v2* id3v2) {
|
||||||
|
id3v2->language.code = "fre";
|
||||||
|
id3v2->private_frame.value = "version 1.3.1-release";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fill(Metadata* metadata) {
|
||||||
|
metadata->handler.handler_type = FOURCC_ID32;
|
||||||
|
Fill(&metadata->id3v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Modify(Metadata* metadata) {
|
||||||
|
Modify(&metadata->id3v2);
|
||||||
|
}
|
||||||
|
|
||||||
void Fill(PixelAspectRatio* pasp) {
|
void Fill(PixelAspectRatio* pasp) {
|
||||||
pasp->h_spacing = 5;
|
pasp->h_spacing = 5;
|
||||||
|
@ -517,14 +535,14 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1;
|
static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1;
|
||||||
mdhd->timescale = 50000;
|
mdhd->timescale = 50000;
|
||||||
mdhd->duration = 250000;
|
mdhd->duration = 250000;
|
||||||
strcpy(mdhd->language, "abc");
|
mdhd->language.code = "abc";
|
||||||
mdhd->version = 1;
|
mdhd->version = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Modify(MediaHeader* mdhd) {
|
void Modify(MediaHeader* mdhd) {
|
||||||
mdhd->creation_time = 2;
|
mdhd->creation_time = 2;
|
||||||
mdhd->modification_time = std::numeric_limits<uint32_t>::max();
|
mdhd->modification_time = std::numeric_limits<uint32_t>::max();
|
||||||
strcpy(mdhd->language, "und");
|
mdhd->language.code = "und";
|
||||||
mdhd->version = 0;
|
mdhd->version = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,6 +651,7 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
|
|
||||||
void Fill(Movie* moov) {
|
void Fill(Movie* moov) {
|
||||||
Fill(&moov->header);
|
Fill(&moov->header);
|
||||||
|
Fill(&moov->metadata);
|
||||||
Fill(&moov->extends);
|
Fill(&moov->extends);
|
||||||
moov->tracks.resize(2);
|
moov->tracks.resize(2);
|
||||||
Fill(&moov->tracks[0]);
|
Fill(&moov->tracks[0]);
|
||||||
|
@ -854,6 +873,8 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
Modify(&vttc->cue_payload);
|
Modify(&vttc->cue_payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsOptional(const ID3v2* box) { return true; }
|
||||||
|
bool IsOptional(const Metadata* box) { return true; }
|
||||||
bool IsOptional(const SampleAuxiliaryInformationOffset* box) { return true; }
|
bool IsOptional(const SampleAuxiliaryInformationOffset* box) { return true; }
|
||||||
bool IsOptional(const SampleAuxiliaryInformationSize* box) { return true; }
|
bool IsOptional(const SampleAuxiliaryInformationSize* box) { return true; }
|
||||||
bool IsOptional(const SampleEncryption* box) { return true; }
|
bool IsOptional(const SampleEncryption* box) { return true; }
|
||||||
|
@ -881,8 +902,9 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
scoped_ptr<BufferWriter> buffer_;
|
scoped_ptr<BufferWriter> buffer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef testing::Types<
|
// GTEST support a maximum of 50 types in the template list, so we have to
|
||||||
FileType,
|
// break it into two groups.
|
||||||
|
typedef testing::Types<FileType,
|
||||||
SegmentType,
|
SegmentType,
|
||||||
ProtectionSystemSpecificHeader,
|
ProtectionSystemSpecificHeader,
|
||||||
SampleAuxiliaryInformationOffset,
|
SampleAuxiliaryInformationOffset,
|
||||||
|
@ -897,10 +919,13 @@ typedef testing::Types<
|
||||||
EditList,
|
EditList,
|
||||||
Edit,
|
Edit,
|
||||||
HandlerReference,
|
HandlerReference,
|
||||||
|
ID3v2,
|
||||||
|
Metadata,
|
||||||
CodecConfigurationRecord,
|
CodecConfigurationRecord,
|
||||||
PixelAspectRatio,
|
PixelAspectRatio,
|
||||||
VideoSampleEntry,
|
VideoSampleEntry,
|
||||||
ElementaryStreamDescriptor,
|
ElementaryStreamDescriptor,
|
||||||
|
DTSSpecific,
|
||||||
AudioSampleEntry,
|
AudioSampleEntry,
|
||||||
WebVTTConfigurationBox,
|
WebVTTConfigurationBox,
|
||||||
WebVTTSourceLabelBox,
|
WebVTTSourceLabelBox,
|
||||||
|
@ -914,8 +939,9 @@ typedef testing::Types<
|
||||||
ChunkLargeOffset,
|
ChunkLargeOffset,
|
||||||
ChunkOffset,
|
ChunkOffset,
|
||||||
SyncSample,
|
SyncSample,
|
||||||
SampleTable,
|
SampleTable>
|
||||||
MediaHeader,
|
Boxes;
|
||||||
|
typedef testing::Types<MediaHeader,
|
||||||
VideoMediaHeader,
|
VideoMediaHeader,
|
||||||
SoundMediaHeader,
|
SoundMediaHeader,
|
||||||
SubtitleMediaHeader,
|
SubtitleMediaHeader,
|
||||||
|
@ -931,11 +957,7 @@ typedef testing::Types<
|
||||||
Movie,
|
Movie,
|
||||||
TrackFragmentDecodeTime,
|
TrackFragmentDecodeTime,
|
||||||
MovieFragmentHeader,
|
MovieFragmentHeader,
|
||||||
TrackFragmentHeader> Boxes;
|
TrackFragmentHeader,
|
||||||
|
|
||||||
// GTEST support a maximum of 50 types in the template list, so we have to
|
|
||||||
// break it into two groups.
|
|
||||||
typedef testing::Types<
|
|
||||||
TrackFragmentRun,
|
TrackFragmentRun,
|
||||||
TrackFragment,
|
TrackFragment,
|
||||||
MovieFragment,
|
MovieFragment,
|
||||||
|
@ -949,8 +971,8 @@ typedef testing::Types<
|
||||||
CuePayloadBox,
|
CuePayloadBox,
|
||||||
VTTEmptyCueBox,
|
VTTEmptyCueBox,
|
||||||
VTTAdditionalTextBox,
|
VTTAdditionalTextBox,
|
||||||
VTTCueBox,
|
VTTCueBox>
|
||||||
DTSSpecific> Boxes2;
|
Boxes2;
|
||||||
|
|
||||||
TYPED_TEST_CASE_P(BoxDefinitionsTestGeneral);
|
TYPED_TEST_CASE_P(BoxDefinitionsTestGeneral);
|
||||||
|
|
||||||
|
@ -1021,6 +1043,20 @@ INSTANTIATE_TYPED_TEST_CASE_P(BoxDefinitionTypedTests2,
|
||||||
// Test other cases of box input.
|
// Test other cases of box input.
|
||||||
class BoxDefinitionsTest : public BoxDefinitionsTestGeneral<Box> {};
|
class BoxDefinitionsTest : public BoxDefinitionsTestGeneral<Box> {};
|
||||||
|
|
||||||
|
TEST_F(BoxDefinitionsTest, MediaHandlerType) {
|
||||||
|
Media media;
|
||||||
|
Fill(&media);
|
||||||
|
// Clear handler type. When this box is written, it will derive handler type
|
||||||
|
// from sample table description.
|
||||||
|
media.handler.handler_type = FOURCC_NULL;
|
||||||
|
media.information.sample_table.description.type = kVideo;
|
||||||
|
media.Write(this->buffer_.get());
|
||||||
|
|
||||||
|
Media media_readback;
|
||||||
|
ASSERT_TRUE(ReadBack(&media_readback));
|
||||||
|
ASSERT_EQ(FOURCC_VIDE, media_readback.handler.handler_type);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(BoxDefinitionsTest, DTSSampleEntry) {
|
TEST_F(BoxDefinitionsTest, DTSSampleEntry) {
|
||||||
AudioSampleEntry entry;
|
AudioSampleEntry entry;
|
||||||
entry.format = FOURCC_DTSE;
|
entry.format = FOURCC_DTSE;
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace mp4 {
|
||||||
// TODO(rkuroiwa): Make these case sensitive. e.g. FOURCC_avc1.
|
// TODO(rkuroiwa): Make these case sensitive. e.g. FOURCC_avc1.
|
||||||
enum FourCC {
|
enum FourCC {
|
||||||
FOURCC_NULL = 0,
|
FOURCC_NULL = 0,
|
||||||
|
FOURCC_ID32 = 0x49443332,
|
||||||
|
FOURCC_PRIV = 0x50524956,
|
||||||
FOURCC_AVC1 = 0x61766331,
|
FOURCC_AVC1 = 0x61766331,
|
||||||
FOURCC_AVCC = 0x61766343,
|
FOURCC_AVCC = 0x61766343,
|
||||||
FOURCC_BLOC = 0x626C6F63,
|
FOURCC_BLOC = 0x626C6F63,
|
||||||
|
|
|
@ -327,7 +327,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
||||||
RCHECK(desc_idx > 0);
|
RCHECK(desc_idx > 0);
|
||||||
desc_idx -= 1; // BMFF descriptor index is one-based
|
desc_idx -= 1; // BMFF descriptor index is one-based
|
||||||
|
|
||||||
if (track->media.handler.type == kAudio) {
|
if (samp_descr.type == kAudio) {
|
||||||
RCHECK(!samp_descr.audio_entries.empty());
|
RCHECK(!samp_descr.audio_entries.empty());
|
||||||
|
|
||||||
// It is not uncommon to find otherwise-valid files with incorrect sample
|
// It is not uncommon to find otherwise-valid files with incorrect sample
|
||||||
|
@ -428,7 +428,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
||||||
duration,
|
duration,
|
||||||
codec,
|
codec,
|
||||||
AudioStreamInfo::GetCodecString(codec, audio_object_type),
|
AudioStreamInfo::GetCodecString(codec, audio_object_type),
|
||||||
track->media.header.language,
|
track->media.header.language.code,
|
||||||
entry.samplesize,
|
entry.samplesize,
|
||||||
num_channels,
|
num_channels,
|
||||||
sampling_frequency,
|
sampling_frequency,
|
||||||
|
@ -439,7 +439,7 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
||||||
is_encrypted));
|
is_encrypted));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (track->media.handler.type == kVideo) {
|
if (samp_descr.type == kVideo) {
|
||||||
RCHECK(!samp_descr.video_entries.empty());
|
RCHECK(!samp_descr.video_entries.empty());
|
||||||
if (desc_idx >= samp_descr.video_entries.size())
|
if (desc_idx >= samp_descr.video_entries.size())
|
||||||
desc_idx = 0;
|
desc_idx = 0;
|
||||||
|
@ -527,8 +527,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
||||||
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
|
DVLOG(1) << "is_video_track_encrypted_: " << is_encrypted;
|
||||||
streams.push_back(new VideoStreamInfo(
|
streams.push_back(new VideoStreamInfo(
|
||||||
track->header.track_id, timescale, duration, video_codec,
|
track->header.track_id, timescale, duration, video_codec,
|
||||||
codec_string, track->media.header.language, coded_width, coded_height,
|
codec_string, track->media.header.language.code, coded_width,
|
||||||
pixel_width, pixel_height,
|
coded_height, pixel_width, pixel_height,
|
||||||
0, // trick_play_rate
|
0, // trick_play_rate
|
||||||
nalu_length_size, vector_as_array(&entry.codec_config_record.data),
|
nalu_length_size, vector_as_array(&entry.codec_config_record.data),
|
||||||
entry.codec_config_record.data.size(), is_encrypted));
|
entry.codec_config_record.data.size(), is_encrypted));
|
||||||
|
|
|
@ -187,13 +187,12 @@ void MP4Muxer::InitializeTrak(const StreamInfo* info, Track* trak) {
|
||||||
trak->media.header.timescale = info->time_scale();
|
trak->media.header.timescale = info->time_scale();
|
||||||
trak->media.header.duration = 0;
|
trak->media.header.duration = 0;
|
||||||
if (!info->language().empty()) {
|
if (!info->language().empty()) {
|
||||||
const size_t language_size = arraysize(trak->media.header.language) - 1;
|
// ISO-639-2/T language code should be 3 characters..
|
||||||
if (info->language().size() != language_size) {
|
if (info->language().size() != 3) {
|
||||||
LOG(WARNING) << "'" << info->language() << "' is not a valid ISO-639-2 "
|
LOG(WARNING) << "'" << info->language() << "' is not a valid ISO-639-2 "
|
||||||
<< "language code, ignoring.";
|
<< "language code, ignoring.";
|
||||||
} else {
|
} else {
|
||||||
memcpy(trak->media.header.language, info->language().c_str(),
|
trak->media.header.language.code = info->language();
|
||||||
language_size + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,8 +216,6 @@ void MP4Muxer::GenerateVideoTrak(const VideoStreamInfo* video_info,
|
||||||
trak->header.width = video_info->width() * sample_aspect_ratio * 0x10000;
|
trak->header.width = video_info->width() * sample_aspect_ratio * 0x10000;
|
||||||
trak->header.height = video_info->height() * 0x10000;
|
trak->header.height = video_info->height() * 0x10000;
|
||||||
|
|
||||||
trak->media.handler.type = kVideo;
|
|
||||||
|
|
||||||
VideoSampleEntry video;
|
VideoSampleEntry video;
|
||||||
video.format = VideoCodecToFourCC(video_info->codec());
|
video.format = VideoCodecToFourCC(video_info->codec());
|
||||||
video.width = video_info->width();
|
video.width = video_info->width();
|
||||||
|
@ -241,7 +238,6 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info,
|
||||||
InitializeTrak(audio_info, trak);
|
InitializeTrak(audio_info, trak);
|
||||||
|
|
||||||
trak->header.volume = 0x100;
|
trak->header.volume = 0x100;
|
||||||
trak->media.handler.type = kAudio;
|
|
||||||
|
|
||||||
AudioSampleEntry audio;
|
AudioSampleEntry audio;
|
||||||
audio.format = AudioCodecToFourCC(audio_info->codec());
|
audio.format = AudioCodecToFourCC(audio_info->codec());
|
||||||
|
|
|
@ -238,6 +238,13 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
||||||
// Use the reference stream's time scale as movie time scale.
|
// Use the reference stream's time scale as movie time scale.
|
||||||
moov_->header.timescale = sidx_->timescale;
|
moov_->header.timescale = sidx_->timescale;
|
||||||
moof_->header.sequence_number = 1;
|
moof_->header.sequence_number = 1;
|
||||||
|
|
||||||
|
// Fill in version information.
|
||||||
|
moov_->metadata.handler.handler_type = FOURCC_ID32;
|
||||||
|
moov_->metadata.id3v2.language.code = "eng";
|
||||||
|
moov_->metadata.id3v2.private_frame.owner =
|
||||||
|
"https://github.com/google/edash-packager";
|
||||||
|
moov_->metadata.id3v2.private_frame.value = options_.packager_version_string;
|
||||||
return DoInitialize();
|
return DoInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "packager/base/memory/ref_counted.h"
|
#include "packager/base/memory/ref_counted.h"
|
||||||
#include "packager/base/memory/scoped_ptr.h"
|
#include "packager/base/memory/scoped_ptr.h"
|
||||||
#include "packager/media/base/status.h"
|
#include "packager/media/base/status.h"
|
||||||
|
#include "packager/media/formats/mp4/box_definitions.h"
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
@ -30,11 +31,6 @@ namespace mp4 {
|
||||||
|
|
||||||
class Fragmenter;
|
class Fragmenter;
|
||||||
|
|
||||||
struct FileType;
|
|
||||||
struct Movie;
|
|
||||||
struct MovieFragment;
|
|
||||||
struct SegmentIndex;
|
|
||||||
|
|
||||||
/// This class defines the Segmenter which is responsible for organizing
|
/// This class defines the Segmenter which is responsible for organizing
|
||||||
/// fragments into segments/subsegments and package them into a MP4 file.
|
/// fragments into segments/subsegments and package them into a MP4 file.
|
||||||
/// Inherited by MultiSegmentSegmenter and SingleSegmentSegmenter.
|
/// Inherited by MultiSegmentSegmenter and SingleSegmentSegmenter.
|
||||||
|
|
|
@ -494,7 +494,13 @@ xmlDocPtr MpdBuilder::GenerateMpd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
DCHECK(doc);
|
DCHECK(doc);
|
||||||
xmlDocSetRootElement(doc.get(), mpd.Release());
|
std::string version_string =
|
||||||
|
"Generated with https://github.com/google/edash-packager version " +
|
||||||
|
mpd_options_.packager_version_string;
|
||||||
|
xml::scoped_xml_ptr<xmlNode> comment(
|
||||||
|
xmlNewDocComment(doc.get(), BAD_CAST version_string.c_str()));
|
||||||
|
xmlDocSetRootElement(doc.get(), comment.get());
|
||||||
|
xmlAddSibling(comment.release(), mpd.Release());
|
||||||
return doc.release();
|
return doc.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,8 @@ class DynamicMpdBuilderTest : public MpdBuilderTest<MpdBuilder::kDynamic> {
|
||||||
// current time.
|
// current time.
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
mpd_.availability_start_time_ = "2011-12-25T12:30:00";
|
mpd_.availability_start_time_ = "2011-12-25T12:30:00";
|
||||||
|
// Override packager version string for testing.
|
||||||
|
mpd_.mpd_options_.packager_version_string = "<tag>-<hash>-<test>";
|
||||||
}
|
}
|
||||||
|
|
||||||
MpdOptions* mutable_mpd_options() { return &mpd_.mpd_options_; }
|
MpdOptions* mutable_mpd_options() { return &mpd_.mpd_options_; }
|
||||||
|
@ -1776,6 +1778,8 @@ TEST_F(StaticMpdBuilderTest, Text) {
|
||||||
TEST_F(DynamicMpdBuilderTest, CheckMpdAttributes) {
|
TEST_F(DynamicMpdBuilderTest, CheckMpdAttributes) {
|
||||||
static const char kExpectedOutput[] =
|
static const char kExpectedOutput[] =
|
||||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<!--Generated with https://github.com/google/edash-packager "
|
||||||
|
"version <tag>-<hash>-<test>-->\n"
|
||||||
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" "
|
"<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" "
|
||||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
|
||||||
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
|
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
#ifndef MPD_BASE_MPD_OPTIONS_H_
|
#ifndef MPD_BASE_MPD_OPTIONS_H_
|
||||||
#define MPD_BASE_MPD_OPTIONS_H_
|
#define MPD_BASE_MPD_OPTIONS_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "packager/version/version.h"
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
|
||||||
/// Defines Mpd Options.
|
/// Defines Mpd Options.
|
||||||
|
@ -17,7 +21,8 @@ struct MpdOptions {
|
||||||
// TODO(tinskip): Set min_buffer_time in unit tests rather than here.
|
// TODO(tinskip): Set min_buffer_time in unit tests rather than here.
|
||||||
min_buffer_time(2.0),
|
min_buffer_time(2.0),
|
||||||
time_shift_buffer_depth(0),
|
time_shift_buffer_depth(0),
|
||||||
suggested_presentation_delay(0) {}
|
suggested_presentation_delay(0),
|
||||||
|
packager_version_string(kPackagerVersion) {}
|
||||||
|
|
||||||
~MpdOptions() {};
|
~MpdOptions() {};
|
||||||
|
|
||||||
|
@ -26,6 +31,7 @@ struct MpdOptions {
|
||||||
double min_buffer_time;
|
double min_buffer_time;
|
||||||
double time_shift_buffer_depth;
|
double time_shift_buffer_depth;
|
||||||
double suggested_presentation_delay;
|
double suggested_presentation_delay;
|
||||||
|
std::string packager_version_string;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
'../base/base.gyp:base',
|
'../base/base.gyp:base',
|
||||||
'../media/file/file.gyp:file',
|
'../media/file/file.gyp:file',
|
||||||
'../third_party/libxml/libxml.gyp:libxml',
|
'../third_party/libxml/libxml.gyp:libxml',
|
||||||
|
'../version/version.gyp:version',
|
||||||
'media_info_proto',
|
'media_info_proto',
|
||||||
],
|
],
|
||||||
'export_dependent_settings': [
|
'export_dependent_settings': [
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright 2015 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
|
||||||
|
"""This script is used to generate version string for packager."""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# To support python version before 2.7, which does not have
|
||||||
|
# subprocess.check_output.
|
||||||
|
if 'check_output' not in dir(subprocess):
|
||||||
|
|
||||||
|
def check_output_implementation(*popenargs, **kwargs):
|
||||||
|
"""Implement check_output if it is not available."""
|
||||||
|
if 'stdout' in kwargs:
|
||||||
|
raise ValueError('stdout argument not allowed, it will be overridden.')
|
||||||
|
process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
|
||||||
|
output, unused_err = process.communicate()
|
||||||
|
retcode = process.poll()
|
||||||
|
if retcode:
|
||||||
|
cmd = kwargs.get('args')
|
||||||
|
if cmd is None:
|
||||||
|
cmd = popenargs[0]
|
||||||
|
raise subprocess.CalledProcessError(retcode, cmd)
|
||||||
|
return output
|
||||||
|
|
||||||
|
subprocess.check_output = check_output_implementation
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
version_tag = subprocess.check_output(['git', 'tag', '--points-at', 'HEAD'
|
||||||
|
]).rstrip()
|
||||||
|
version_hash = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'
|
||||||
|
]).rstrip()
|
||||||
|
if version_tag:
|
||||||
|
print '{0}-{1}'.format(version_tag, version_hash)
|
||||||
|
else:
|
||||||
|
print version_hash
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2015 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 "packager/version/version.h"
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
|
||||||
|
#if defined(PACKAGER_VERSION)
|
||||||
|
// PACKAGER_VERSION is generated in gyp file using script
|
||||||
|
// generate_version_string.py.
|
||||||
|
#if defined(NDEBUG)
|
||||||
|
const char kPackagerVersion[] = PACKAGER_VERSION "-release";
|
||||||
|
#else
|
||||||
|
const char kPackagerVersion[] = PACKAGER_VERSION "-debug";
|
||||||
|
#endif // #if defined(NDEBUG)
|
||||||
|
#else
|
||||||
|
const char kPackagerVersion[] = "";
|
||||||
|
#endif // #if defined(PACKAGER_VERSION)
|
||||||
|
|
||||||
|
} // namespace edash_packager
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright 2015 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
|
||||||
|
|
||||||
|
{
|
||||||
|
'includes': [
|
||||||
|
'../common.gypi',
|
||||||
|
],
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'version',
|
||||||
|
'type': '<(component)',
|
||||||
|
'defines': [
|
||||||
|
'PACKAGER_VERSION="<!(python generate_version_string.py)"',
|
||||||
|
],
|
||||||
|
'sources': [
|
||||||
|
'version.cc',
|
||||||
|
'version.h',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright 2015 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
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
|
||||||
|
extern const char kPackagerVersion[];
|
||||||
|
|
||||||
|
} // namespace edash_packager
|
Loading…
Reference in New Issue