support for iframe index with mp4-dash in HLS mode

This commit is contained in:
Gilles Boccon-Gibod
2017-10-14 12:47:41 -07:00
parent 69bd8e2d73
commit c2bbef701d
16 changed files with 743 additions and 39 deletions

View File

@@ -156,7 +156,7 @@ LibraryModule(name = 'Bento4',
build_source_files = env['AP4_SYSTEM_SOURCES'],
included_modules = 'Config')
for name in ['Mp4Dump', 'Mp4Info', 'Mp4Edit', 'Mp4Encrypt', 'Mp4Decrypt', 'Mp4Tag', 'Mp4Extract', 'Mp4RtpHintInfo', 'Mp42Aac', 'Mp42Avc', 'Mp42Hevc', 'Mp42Ts', 'Mp42Hls', 'Mp4DcfPackager', 'Mp4Fragment', 'Mp4Compact', 'Mp4Split', 'Mp4AudioClip', 'Mp4Mux', 'AvcInfo', 'HevcInfo']:
for name in ['Mp4Dump', 'Mp4Info', 'Mp4Edit', 'Mp4Encrypt', 'Mp4Decrypt', 'Mp4Tag', 'Mp4Extract', 'Mp4RtpHintInfo', 'Mp42Aac', 'Mp42Avc', 'Mp42Hevc', 'Mp42Ts', 'Mp42Hls', 'Mp4DcfPackager', 'Mp4Fragment', 'Mp4Compact', 'Mp4Split', 'Mp4AudioClip', 'Mp4Mux', 'Mp4Diff', 'Mp4IframeIndex', 'AvcInfo', 'HevcInfo']:
Executable(name, source_dir='C++/Apps/'+name)
Executable('Aac2Mp4', source_dir='C++/Apps/Aac2Mp4')

View File

@@ -0,0 +1,35 @@
##########################################################################
#
# Mp4Info Program
#
# (c) 2002-2008 Axiomatic Systems, LLC
#
##########################################################################
all: mp4iframeindex
##########################################################################
# includes
##########################################################################
include $(BUILD_ROOT)/Makefiles/Lib.exp
##########################################################################
# targets
##########################################################################
TARGET_SOURCES = Mp4IframeIndex.cpp
##########################################################################
# make path
##########################################################################
VPATH += $(SOURCE_ROOT)/Apps/Mp4IframeIndex
##########################################################################
# includes
##########################################################################
include $(BUILD_ROOT)/Makefiles/Rules.mak
##########################################################################
# rules
##########################################################################
mp4iframeindex: $(TARGET_OBJECTS) $(TARGET_LIBRARY_FILES)
$(LINK) $(TARGET_OBJECTS) -o $@ $(LINK_LIBRARIES)

View File

@@ -153,6 +153,10 @@ mp42hls: lib
$(TITLE)
@$(INVOKE_SUBMAKE) -f $(BUILD_ROOT)/Makefiles/Mp42Hls.mak
mp4iframeindex: lib
$(TITLE)
@$(INVOKE_SUBMAKE) -f $(BUILD_ROOT)/Makefiles/Mp4IframeIndex.mak
##################################################################
# includes
##################################################################

View File

@@ -13,6 +13,8 @@
buildPhases = (
);
dependencies = (
CACAF6931F91C49400B75DC3 /* PBXTargetDependency */,
CACAF6911F91C48F00B75DC3 /* PBXTargetDependency */,
CA640EA11B09AAEF00C93DCF /* PBXTargetDependency */,
CA00A65E1A1C383E0064B4D3 /* PBXTargetDependency */,
CA418B141948F0A300D202E0 /* PBXTargetDependency */,
@@ -144,6 +146,8 @@
CA86EEE519A95E30008A3B00 /* FragmentCreatorTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CA86EEE419A95E30008A3B00 /* FragmentCreatorTest.cpp */; };
CA87B94A1F81B0C4005F42D6 /* libBento4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAA7E6C914ACD763008AA54E /* libBento4.a */; };
CA87B94D1F81B130005F42D6 /* Mp4Diff.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CA87B94C1F81B122005F42D6 /* Mp4Diff.cpp */; };
CA87B95B1F895AD9005F42D6 /* libBento4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAA7E6C914ACD763008AA54E /* libBento4.a */; };
CA87B95E1F895F90005F42D6 /* Mp4IframeIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CA87B95D1F895B14005F42D6 /* Mp4IframeIndex.cpp */; };
CA8A94D91929A68700836179 /* libBento4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAA7E6C914ACD763008AA54E /* libBento4.a */; };
CA8A94DC1929A6C100836179 /* Mp4Mux.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CA8A94DB1929A6C100836179 /* Mp4Mux.cpp */; };
CA8A94DD1929DD9100836179 /* Ap4AvcParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CA3EDA960D7E14D3007AE943 /* Ap4AvcParser.cpp */; };
@@ -732,6 +736,13 @@
remoteGlobalIDString = CA86EED619A95DD3008A3B00;
remoteInfo = FragmentCreatorTest;
};
CA87B9591F895ACE005F42D6 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D2AAC045055464E500DB518D;
remoteInfo = Bento4;
};
CA8A94D71929A67500836179 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
@@ -816,6 +827,20 @@
remoteGlobalIDString = D2AAC045055464E500DB518D;
remoteInfo = Bento4;
};
CACAF6901F91C48F00B75DC3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = CA87B9511F895A84005F42D6;
remoteInfo = Mp4IframeIndex;
};
CACAF6921F91C49400B75DC3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = CA87B9411F81B08B005F42D6;
remoteInfo = Mp4Diff;
};
CAE1FBEE1AF8493E00607B3C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
@@ -981,6 +1006,15 @@
);
runOnlyForDeploymentPostprocessing = 1;
};
CA87B9501F895A84005F42D6 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
CAFE9C671D1B487700F9FF67 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -1079,8 +1113,9 @@
CA86EED719A95DD3008A3B00 /* FragmentCreatorTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = FragmentCreatorTest; sourceTree = BUILT_PRODUCTS_DIR; };
CA86EEE419A95E30008A3B00 /* FragmentCreatorTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FragmentCreatorTest.cpp; sourceTree = "<group>"; };
CA87B9421F81B08B005F42D6 /* mp4diff */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mp4diff; sourceTree = BUILT_PRODUCTS_DIR; };
CA87B9441F81B08B005F42D6 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
CA87B94C1F81B122005F42D6 /* Mp4Diff.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mp4Diff.cpp; sourceTree = "<group>"; };
CA87B9521F895A84005F42D6 /* Mp4IframeIndex */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; name = Mp4IframeIndex; path = mp4iframeindex; sourceTree = BUILT_PRODUCTS_DIR; };
CA87B95D1F895B14005F42D6 /* Mp4IframeIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mp4IframeIndex.cpp; sourceTree = "<group>"; };
CA8A94CE1929A65E00836179 /* mp4mux */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mp4mux; sourceTree = BUILT_PRODUCTS_DIR; };
CA8A94DB1929A6C100836179 /* Mp4Mux.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mp4Mux.cpp; sourceTree = "<group>"; };
CA8B6A600F66D20900720A07 /* Ap4MfhdAtom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Ap4MfhdAtom.cpp; sourceTree = "<group>"; };
@@ -1514,6 +1549,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
CA87B94F1F895A84005F42D6 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
CA87B95B1F895AD9005F42D6 /* libBento4.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
CA8A94CB1929A65E00836179 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -1665,7 +1708,6 @@
CA646A860CE97B2D009699D7 /* Apps */,
CA646A9B0CE97B51009699D7 /* Test */,
C6A0FF2B0290797F04C91782 /* Documentation */,
CA87B9431F81B08B005F42D6 /* Mp4Diff */,
1AB674ADFE9D54B511CA2CBB /* Products */,
CA87B9491F81B0C4005F42D6 /* Frameworks */,
);
@@ -1730,6 +1772,7 @@
CAE1FBF61AF8493E00607B3C /* mp42hls */,
CAFE9C691D1B487700F9FF67 /* LargeFilesTest */,
CA87B9421F81B08B005F42D6 /* mp4diff */,
CA87B9521F895A84005F42D6 /* Mp4IframeIndex */,
);
name = Products;
sourceTree = "<group>";
@@ -1821,6 +1864,7 @@
CA646A910CE97B2D009699D7 /* Mp4Encrypt */,
CA646A930CE97B2D009699D7 /* Mp4Extract */,
CA6103E2128599C20039C7E6 /* Mp4Fragment */,
CA87B95C1F895B14005F42D6 /* Mp4IframeIndex */,
CA646A950CE97B2D009699D7 /* Mp4Info */,
CA8A94DA1929A6C100836179 /* Mp4Mux */,
CA00A65A1A1C38210064B4D3 /* Mp4Pssh */,
@@ -1961,14 +2005,6 @@
path = FragmentCreator;
sourceTree = "<group>";
};
CA87B9431F81B08B005F42D6 /* Mp4Diff */ = {
isa = PBXGroup;
children = (
CA87B9441F81B08B005F42D6 /* main.cpp */,
);
path = Mp4Diff;
sourceTree = "<group>";
};
CA87B9491F81B0C4005F42D6 /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -1984,6 +2020,14 @@
path = Mp4Diff;
sourceTree = "<group>";
};
CA87B95C1F895B14005F42D6 /* Mp4IframeIndex */ = {
isa = PBXGroup;
children = (
CA87B95D1F895B14005F42D6 /* Mp4IframeIndex.cpp */,
);
path = Mp4IframeIndex;
sourceTree = "<group>";
};
CA8A94DA1929A6C100836179 /* Mp4Mux */ = {
isa = PBXGroup;
children = (
@@ -2969,6 +3013,24 @@
productReference = CA87B9421F81B08B005F42D6 /* mp4diff */;
productType = "com.apple.product-type.tool";
};
CA87B9511F895A84005F42D6 /* Mp4IframeIndex */ = {
isa = PBXNativeTarget;
buildConfigurationList = CA87B9581F895A84005F42D6 /* Build configuration list for PBXNativeTarget "Mp4IframeIndex" */;
buildPhases = (
CA87B94E1F895A84005F42D6 /* Sources */,
CA87B94F1F895A84005F42D6 /* Frameworks */,
CA87B9501F895A84005F42D6 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
CA87B95A1F895ACE005F42D6 /* PBXTargetDependency */,
);
name = Mp4IframeIndex;
productName = Mp4IframeIndex;
productReference = CA87B9521F895A84005F42D6 /* Mp4IframeIndex */;
productType = "com.apple.product-type.tool";
};
CA8A94CD1929A65E00836179 /* Mp4Mux */ = {
isa = PBXNativeTarget;
buildConfigurationList = CA8A94D61929A65E00836179 /* Build configuration list for PBXNativeTarget "Mp4Mux" */;
@@ -3293,6 +3355,10 @@
CreatedOnToolsVersion = 9.0;
ProvisioningStyle = Manual;
};
CA87B9511F895A84005F42D6 = {
CreatedOnToolsVersion = 9.0;
ProvisioningStyle = Automatic;
};
CAFE9C681D1B487700F9FF67 = {
CreatedOnToolsVersion = 7.3;
};
@@ -3355,6 +3421,7 @@
CAFC31B80FEB3DDD00EF80A0 /* FragmentParserTest */,
CA86EED619A95DD3008A3B00 /* FragmentCreatorTest */,
CAFE9C681D1B487700F9FF67 /* LargeFilesTest */,
CA87B9511F895A84005F42D6 /* Mp4IframeIndex */,
);
};
/* End PBXProject section */
@@ -3536,6 +3603,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
CA87B94E1F895A84005F42D6 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CA87B95E1F895F90005F42D6 /* Mp4IframeIndex.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
CA8A94CA1929A65E00836179 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4033,6 +4108,11 @@
target = CA86EED619A95DD3008A3B00 /* FragmentCreatorTest */;
targetProxy = CA86EEEC19BD6865008A3B00 /* PBXContainerItemProxy */;
};
CA87B95A1F895ACE005F42D6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D2AAC045055464E500DB518D /* Bento4 */;
targetProxy = CA87B9591F895ACE005F42D6 /* PBXContainerItemProxy */;
};
CA8A94D81929A67500836179 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D2AAC045055464E500DB518D /* Bento4 */;
@@ -4093,6 +4173,16 @@
target = D2AAC045055464E500DB518D /* Bento4 */;
targetProxy = CAC8F17A16BE447A00C49741 /* PBXContainerItemProxy */;
};
CACAF6911F91C48F00B75DC3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = CA87B9511F895A84005F42D6 /* Mp4IframeIndex */;
targetProxy = CACAF6901F91C48F00B75DC3 /* PBXContainerItemProxy */;
};
CACAF6931F91C49400B75DC3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = CA87B9411F81B08B005F42D6 /* Mp4Diff */;
targetProxy = CACAF6921F91C49400B75DC3 /* PBXContainerItemProxy */;
};
CAE1FBED1AF8493E00607B3C /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D2AAC045055464E500DB518D /* Bento4 */;
@@ -4846,6 +4936,69 @@
};
name = Release;
};
CA87B9561F895A84005F42D6 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = mp4iframeindex;
SDKROOT = macosx;
};
name = Debug;
};
CA87B9571F895A84005F42D6 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_NAME = mp4iframeindex;
SDKROOT = macosx;
};
name = Release;
};
CA8A94D41929A65E00836179 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -5621,6 +5774,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CA87B9581F895A84005F42D6 /* Build configuration list for PBXNativeTarget "Mp4IframeIndex" */ = {
isa = XCConfigurationList;
buildConfigurations = (
CA87B9561F895A84005F42D6 /* Debug */,
CA87B9571F895A84005F42D6 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
CA8A94D61929A65E00836179 /* Build configuration list for PBXNativeTarget "Mp4Mux" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@@ -103,6 +103,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mp42Avc", "Mp42Avc\Mp42Avc.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mp42Hevc", "Mp42Hevc\Mp42Hevc.vcxproj", "{2ED2DF44-488D-470A-9C52-88D9D10518F7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mp4IframeIndex", "Mp4IframeIndex\Mp4IframeIndex.vcxproj", "{FD311CE7-C059-457C-BEEC-86CEB1E7014D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -213,6 +215,10 @@ Global
{2ED2DF44-488D-470A-9C52-88D9D10518F7}.Debug|Win32.Build.0 = Debug|Win32
{2ED2DF44-488D-470A-9C52-88D9D10518F7}.Release|Win32.ActiveCfg = Release|Win32
{2ED2DF44-488D-470A-9C52-88D9D10518F7}.Release|Win32.Build.0 = Release|Win32
{FD311CE7-C059-457C-BEEC-86CEB1E7014D}.Debug|Win32.ActiveCfg = Debug|Win32
{FD311CE7-C059-457C-BEEC-86CEB1E7014D}.Debug|Win32.Build.0 = Debug|Win32
{FD311CE7-C059-457C-BEEC-86CEB1E7014D}.Release|Win32.ActiveCfg = Release|Win32
{FD311CE7-C059-457C-BEEC-86CEB1E7014D}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -237,6 +243,7 @@ Global
{EA2B1E39-B9F4-4424-A01B-65628E87BEB5} = {92E4C2EB-ED44-4B47-805D-CC272C8838EB}
{28D14679-1C21-4B6E-B891-62769EDCEFFF} = {92E4C2EB-ED44-4B47-805D-CC272C8838EB}
{2ED2DF44-488D-470A-9C52-88D9D10518F7} = {92E4C2EB-ED44-4B47-805D-CC272C8838EB}
{FD311CE7-C059-457C-BEEC-86CEB1E7014D} = {92E4C2EB-ED44-4B47-805D-CC272C8838EB}
{FA13F082-633C-4DAD-B282-6B0E1BDD3412} = {FAE70B4A-0D9D-4748-9DED-991D4101AE93}
{B031A581-FDE5-4CDC-A124-573F6EECB54A} = {FAE70B4A-0D9D-4748-9DED-991D4101AE93}
{23C9BE84-E4D3-4F06-9188-533991022D48} = {FAE70B4A-0D9D-4748-9DED-991D4101AE93}

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{FD311CE7-C059-457C-BEEC-86CEB1E7014D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Mp4IframeIndex</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\..\Source\C++\Core;..\..\..\..\Source\C++\MetaData;..\..\..\..\Source\C++\Codecs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\..\Source\C++\Core;..\..\..\..\Source\C++\MetaData;..\..\..\..\Source\C++\Codecs;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="..\Bento4\Bento4.vcxproj">
<Project>{a714aa1c-45a9-403d-a6e1-020e520119a2}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\Source\C++\Apps\Mp4IframeIndex\Mp4IframeIndex.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\Source\C++\Apps\Mp4IframeIndex\Mp4IframeIndex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -44,7 +44,7 @@ include_directories(
)
# Apps
set(BENTO4_APPS "Aac2Mp4;Mp42Aac;Mp42Ts;Mp42Hls;Mp4Compact;Mp4DcfPackager;Mp4Decrypt;Mp4Dump;Mp4Edit;Mp4Encrypt;Mp4Extract;Mp4Fragment;Mp4Info;Mp4Mux;Mp4Split;Mp4Tag")
set(BENTO4_APPS "Aac2Mp4;Mp42Aac;Mp42Ts;Mp42Hls;Mp4Compact;Mp4DcfPackager;Mp4Decrypt;Mp4Dump;Mp4Edit;Mp4Encrypt;Mp4Extract;Mp4Fragment;Mp4Info;Mp4Mux;Mp4Split;Mp4Tag;Mp4Diff;Mp4IframeIndex")
foreach(app ${BENTO4_APPS})
string(TOLOWER ${app} binary_name)
add_executable(${binary_name} ${SOURCE_ROOT}/Apps/${app}/${app}.cpp)

View File

@@ -237,6 +237,7 @@ bin_files = [
(bin_in,'aac2mp4','bin'),
(bin_in,'mp42ts','bin'),
(bin_in,'mp42hls','bin'),
(bin_in,'mp4iframeindex','bin'),
(bin_in,'*.a','lib'),
(bin_in,'*.dll','bin'),
(bin_in,'*.dylib','bin'),

View File

@@ -1,8 +1,8 @@
/*****************************************************************
|
| AP4 - MP4 File Info
| AP4 - MP4 File Comparator
|
| Copyright 2002-2015 Axiomatic Systems, LLC
| Copyright 2002-2017 Axiomatic Systems, LLC
|
|
| This file is part of Bento4/AP4 (MP4 Atom Processing Library).

View File

@@ -0,0 +1,263 @@
/*****************************************************************
|
| AP4 - MP4 I-Frame Indexer
|
| Copyright 2002-2017 Axiomatic Systems, LLC
|
|
| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
|
| Unless you have obtained Bento4 under a difference license,
| this version of Bento4 is Bento4|GPL.
| Bento4|GPL is free software; you can redistribute it and/or modify
| it under the terms of the GNU General Public License as published by
| the Free Software Foundation; either version 2, or (at your option)
| any later version.
|
| Bento4|GPL is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU General Public License
| along with Bento4|GPL; see the file COPYING. If not, write to the
| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
| 02111-1307, USA.
|
****************************************************************/
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "Ap4.h"
/*----------------------------------------------------------------------
| constants
+---------------------------------------------------------------------*/
#define BANNER "MP4 Iframe Index - Version 1.0.0\n"\
"(Bento4 Version " AP4_VERSION_STRING ")\n"\
"(c) 2002-2017 Axiomatic Systems, LLC"
/*----------------------------------------------------------------------
| PrintUsageAndExit
+---------------------------------------------------------------------*/
static void
PrintUsageAndExit()
{
fprintf(stderr,
BANNER
"\n\nusage: mp4iframeindex [options] <input> [<output>]\n"
" options:\n"
" --track <id>: ID of the video track\n"
);
exit(1);
}
/*----------------------------------------------------------------------
| IndexTrack
+---------------------------------------------------------------------*/
static AP4_Result
IndexTrack(AP4_Track& track, const char** separator, AP4_ByteStream* output)
{
AP4_Sample sample;
for (unsigned int i=0; i<track.GetSampleCount(); i++) {
// get the sample
AP4_Result result = track.GetSample(i, sample);
if (AP4_FAILED(result)) return result;
if (sample.IsSync()) {
AP4_Offset offset = sample.GetOffset();
char workspace[256];
AP4_FormatString(workspace, sizeof(workspace),
"%s{ \"size\": %u, \"offset\": %llu, \"fragmentStart\": 0 }",
*separator,
(unsigned int)sample.GetSize(),
(unsigned long long)offset);
*separator = ",\n";
output->WriteString(workspace);
}
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| IndexFragments
+---------------------------------------------------------------------*/
static AP4_Result
IndexFragments(AP4_Movie& movie, unsigned int track_id, AP4_ByteStream* stream, const char** separator, AP4_ByteStream* output)
{
stream->Seek(0);
AP4_LinearReader reader(movie, stream);
reader.EnableTrack(track_id);
AP4_Sample sample;
AP4_Position last_fragment_position = (AP4_Position)(-1);
for (unsigned int i=0; ; i++) {
AP4_UI32 found_track_id = 0;
AP4_Result result = reader.GetNextSample(sample, found_track_id);
if (AP4_FAILED(result)) break;
// only output the first sync sample of each fragment
if (reader.GetCurrentFragmentPosition() == last_fragment_position) {
continue;
}
if (found_track_id == track_id && sample.IsSync()) {
AP4_Offset offset = sample.GetOffset();
char workspace[256];
AP4_FormatString(workspace, sizeof(workspace),
"%s{ \"size\": %u, \"offset\": %llu, \"fragmentStart\": %llu }",
*separator,
(unsigned int)sample.GetSize(),
(unsigned long long)offset,
(unsigned long long)reader.GetCurrentFragmentPosition());
*separator = ",\n";
output->WriteString(workspace);
}
last_fragment_position = reader.GetCurrentFragmentPosition();
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| main
+---------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
if (argc < 2) {
PrintUsageAndExit();
}
const char* input_filename = NULL;
const char* output_filename = NULL;
const char* moov_filename = NULL;
unsigned int track_id = 0;
++argv;
while (char* arg = *argv++) {
if (!strcmp(arg, "--track")) {
arg = *argv++;
if (arg == NULL) {
fprintf(stderr, "ERROR: missing argument after --track option\n");
return 1;
}
track_id = (unsigned int)strtoul(arg, NULL, 10);
} else if (!strcmp(arg, "--fragments-info")) {
moov_filename = *argv++;
if (moov_filename == NULL) {
fprintf(stderr, "ERROR: missing argument after --fragments-info option\n");
}
} else if (input_filename == NULL) {
input_filename = arg;
} else if (output_filename == NULL) {
output_filename = arg;
} else {
fprintf(stderr, "ERROR: unexpected argument '%s'\n", arg);
return 1;
}
}
if (input_filename == NULL) {
fprintf(stderr, "ERROR: input filename missing\n");
return 1;
}
if (output_filename == NULL) {
output_filename = "-stdout";
}
AP4_ByteStream* output = NULL;
AP4_Result result = AP4_FileByteStream::Create(output_filename,
AP4_FileByteStream::STREAM_MODE_WRITE,
output);
if (AP4_FAILED(result)) {
fprintf(stderr, "ERROR: cannot open output file %s (%d)\n", input_filename, result);
return 1;
}
AP4_ByteStream* input = NULL;
result = AP4_FileByteStream::Create(input_filename,
AP4_FileByteStream::STREAM_MODE_READ,
input);
if (AP4_FAILED(result)) {
fprintf(stderr, "ERROR: cannot open input file %s (%d)\n", input_filename, result);
return 1;
}
AP4_ByteStream* moov = NULL;
if (moov_filename) {
result = AP4_FileByteStream::Create(moov_filename,
AP4_FileByteStream::STREAM_MODE_READ,
moov);
if (AP4_FAILED(result)) {
fprintf(stderr, "ERROR: cannot open fragments info file %s (%d)\n", moov_filename, result);
return 1;
}
}
AP4_File* input_file = new AP4_File(*input, true);
AP4_Movie* input_movie = input_file->GetMovie();
AP4_File* moov_file = moov ? new AP4_File(*moov, true) : NULL;
AP4_Track* track = NULL;
const char* separator = "";
if (input_movie == NULL) {
// we need a movie to get to the fragments
if (moov_file == NULL) {
fprintf(stderr, "ERROR: input file does not contain a movie (use --fragments-info option)\n");
goto end;
}
input_movie = moov_file->GetMovie();
}
// select the track
if (track_id == 0) {
track = input_movie->GetTrack(AP4_Track::TYPE_VIDEO);
if (track) {
track_id = track->GetId();
}
} else {
track = input_movie->GetTrack(track_id);
}
// check that we found the track
if (!track) {
fprintf(stderr, "ERROR: video track not found\n");
goto end;
}
// check the track type
if (track->GetType() != AP4_Track::TYPE_VIDEO) {
fprintf(stderr, "ERROR: track ID %d is not a video track\n", track->GetId());
goto end;
}
// start
output->WriteString("[\n");
// index the track
result = IndexTrack(*track, &separator, output);
if (AP4_FAILED(result)) {
fprintf(stderr, "ERROR: failed to index track (%d)\n", result);
}
// index the fragments
result = IndexFragments(*input_movie, track_id, input, &separator, output);
if (AP4_FAILED(result)) {
fprintf(stderr, "ERROR: failed to index fragments (%d)\n", result);
}
// end
output->WriteString("\n]\n");
end:
delete input_file;
delete moov_file;
if (moov) moov->Release();
input->Release();
output->Release();
return result == AP4_SUCCESS ? 0 : 1;
}

View File

@@ -1189,6 +1189,7 @@ AP4_HevcFrameParser::Feed(const AP4_UI08* nal_unit,
unsigned int nal_unit_type = (nal_unit[0] >> 1) & 0x3F;
unsigned int nuh_layer_id = (((nal_unit[0] & 1) << 5) | (nal_unit[1] >> 3));
unsigned int nuh_temporal_id = nal_unit[1] & 0x7;
(void)nuh_layer_id;
if (nuh_temporal_id-- == 0) {
// illegal value, ignore this NAL unit

View File

@@ -46,6 +46,7 @@ AP4_LinearReader::AP4_LinearReader(AP4_Movie& movie,
m_Movie(movie),
m_Fragment(NULL),
m_FragmentStream(fragment_stream),
m_CurrentFragmentPosition(0),
m_NextFragmentPosition(0),
m_BufferFullness(0),
m_BufferFullnessPeak(0),
@@ -55,7 +56,8 @@ AP4_LinearReader::AP4_LinearReader(AP4_Movie& movie,
m_HasFragments = movie.HasFragments();
if (fragment_stream) {
fragment_stream->AddReference();
fragment_stream->Tell(m_NextFragmentPosition);
fragment_stream->Tell(m_CurrentFragmentPosition);
m_NextFragmentPosition = m_CurrentFragmentPosition;
}
}
@@ -339,6 +341,7 @@ AP4_LinearReader::AdvanceFragment()
// go the the start of the next fragment
result = m_FragmentStream->Seek(m_NextFragmentPosition);
if (AP4_FAILED(result)) return result;
m_CurrentFragmentPosition = m_NextFragmentPosition;
// read atoms until we find a moof
assert(m_HasFragments);
@@ -346,11 +349,16 @@ AP4_LinearReader::AdvanceFragment()
AP4_DefaultAtomFactory atom_factory;
do {
AP4_Atom* atom = NULL;
AP4_Position last_position = 0;
m_FragmentStream->Tell(last_position);
result = atom_factory.CreateAtomFromStream(*m_FragmentStream, atom);
if (AP4_SUCCEEDED(result)) {
if (atom->GetType() == AP4_ATOM_TYPE_MOOF) {
AP4_ContainerAtom* moof = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
if (moof) {
// remember where the moof started
m_CurrentFragmentPosition = last_position;
// remember where we are in the stream
AP4_Position position = 0;
m_FragmentStream->Tell(position);

View File

@@ -90,6 +90,7 @@ public:
// accessors
AP4_Size GetBufferFullness() { return m_BufferFullness; }
AP4_Position GetCurrentFragmentPosition() { return m_CurrentFragmentPosition; }
// classes
class SampleReader {
@@ -178,6 +179,7 @@ protected:
bool m_HasFragments;
AP4_MovieFragment* m_Fragment;
AP4_ByteStream* m_FragmentStream;
AP4_Position m_CurrentFragmentPosition;
AP4_Position m_NextFragmentPosition;
AP4_Array<Tracker*> m_Trackers;
AP4_Size m_BufferFullness;

View File

@@ -571,27 +571,70 @@ def OutputDash(options, set_attributes, audio_sets, video_sets, subtitles_sets,
#############################################
def OutputHlsTrack(options, track, media_subdir, media_playlist_name, media_file_name):
def ComputeHlsWidevineKeyLine(options, track):
try:
pairs = options.widevine_header.split('#')
fields = {}
for pair in pairs:
name, value = pair.split(':', 1)
fields[name] = value
except:
raise Exception('invalid syntax for --widevine-header option')
if 'content_id' not in fields:
fields['content_id'] = '*'
if 'kid' not in fields:
fields['kid'] = track.key_info['kid']
json_param = '{ "provider": "%(provider)s", "content_id": "%(content_id)s", "key_ids": ["%(kid)s"] }' % fields
key_line = 'URI="data:text/plain;base64,'+json_param.encode('base64').replace('\n','')+'",KEYFORMAT="com.widevine",KEYFORMATVERSIONS="1",IV=0x'+track.key_info['iv']
return key_line
#############################################
def ComputeHlsFairplayKeyLine(options):
return 'URI="'+options.fairplay_key_uri+'",KEYFORMAT="com.apple.streamingkeydelivery",KEYFORMATVERSIONS="1"'
#############################################
def OutputHlsCommon(options, track, media_subdir, playlist_name, media_file_name):
hls_target_duration = math.ceil(max(track.segment_durations))
media_playlist_file = open(path.join(options.output_dir, media_subdir, media_playlist_name), 'w+')
media_playlist_file.write('#EXTM3U\r\n')
media_playlist_file.write('# Created with Bento4 mp4-dash.py, VERSION=' + VERSION + '-' + SDK_REVISION+'\r\n')
media_playlist_file.write('#\r\n')
media_playlist_file.write('#EXT-X-VERSION:6\r\n')
media_playlist_file.write('#EXT-X-PLAYLIST-TYPE:VOD\r\n')
media_playlist_file.write('#EXT-X-INDEPENDENT-SEGMENTS\r\n')
media_playlist_file.write('#EXT-X-TARGETDURATION:%d\r\n' % (hls_target_duration))
media_playlist_file.write('#EXT-X-MEDIA-SEQUENCE:0\r\n')
if options.on_demand or not options.split:
init_segment_size = track.parent.init_segment.position + track.parent.init_segment.size
media_playlist_file.write('#EXT-X-MAP:URI="%s",BYTERANGE="%d@0"\r\n' % (media_file_name, init_segment_size))
playlist_file = open(path.join(options.output_dir, media_subdir, playlist_name), 'w+')
playlist_file.write('#EXTM3U\r\n')
playlist_file.write('# Created with Bento4 mp4-dash.py, VERSION=' + VERSION + '-' + SDK_REVISION+'\r\n')
playlist_file.write('#\r\n')
playlist_file.write('#EXT-X-VERSION:6\r\n')
playlist_file.write('#EXT-X-PLAYLIST-TYPE:VOD\r\n')
playlist_file.write('#EXT-X-INDEPENDENT-SEGMENTS\r\n')
playlist_file.write('#EXT-X-TARGETDURATION:%d\r\n' % (hls_target_duration))
playlist_file.write('#EXT-X-MEDIA-SEQUENCE:0\r\n')
if options.split:
playlist_file.write('#EXT-X-MAP:URI="%s"\r\n' % (SPLIT_INIT_SEGMENT_NAME))
else:
media_playlist_file.write('#EXT-X-MAP:URI="%s"\r\n' % (SPLIT_INIT_SEGMENT_NAME))
segment_pattern = SEGMENT_PATTERN.replace('ll','')
init_segment_size = track.parent.init_segment.position + track.parent.init_segment.size
playlist_file.write('#EXT-X-MAP:URI="%s",BYTERANGE="%d@0"\r\n' % (media_file_name, init_segment_size))
if options.encryption_key:
media_playlist_file.write('#EXT-X-KEY:METHOD=SAMPLE-AES,URI="'+options.hls_key_url+'",IV=0x'+track.key_info['iv']+'\r\n')
key_lines = []
if options.fairplay_key_uri:
key_lines.append(ComputeHlsFairplayKeyLine(options))
if options.widevine_header:
key_lines.append(ComputeHlsWidevineKeyLine(options, track))
if len(key_lines) == 0:
key_lines.append('URI="'+options.hls_key_url+'",IV=0x'+track.key_info['iv'])
for key_line in key_lines:
playlist_file.write('#EXT-X-KEY:METHOD=SAMPLE-AES,'+key_line+'\r\n')
return playlist_file
#############################################
def OutputHlsTrack(options, track, media_subdir, media_playlist_name, media_file_name):
media_playlist_file = OutputHlsCommon(options, track, media_subdir, media_playlist_name, media_file_name)
if options.split:
segment_pattern = SEGMENT_PATTERN.replace('ll','')
for i in range(len(track.segment_durations)):
media_playlist_file.write('#EXTINF:%f,\r\n' % (track.segment_durations[i]))
@@ -607,6 +650,47 @@ def OutputHlsTrack(options, track, media_subdir, media_playlist_name, media_file
media_playlist_file.write('#EXT-X-ENDLIST\r\n')
#############################################
def OutputHlsIframeIndex(options, track, media_subdir, iframes_playlist_name, media_file_name):
index_playlist_file = OutputHlsCommon(options, track, media_subdir, iframes_playlist_name, media_file_name)
index_playlist_file.write('#EXT-X-I-FRAMES-ONLY\r\n')
if not options.split:
# get the I-frame index for a single file
json_index = Mp4IframIndex(options, path.join(options.output_dir, media_file_name))
index = json.loads(json_index)
for i in range(len(track.segment_durations)):
if i < len(index):
index_entry = index[i]
index_playlist_file.write('#EXTINF:%f,\r\n' % (track.segment_durations[i]))
fragment_start = int(index_entry['fragmentStart'])
iframe_offset = int(index_entry['offset'])
iframe_size = int(index_entry['size'])
iframe_range_size = iframe_size + (iframe_offset-fragment_start)
index_playlist_file.write('#EXT-X-BYTERANGE:%d@%d\r\n' % (iframe_range_size, fragment_start))
index_playlist_file.write(media_file_name+'\r\n')
else:
segment_pattern = SEGMENT_PATTERN.replace('ll','')
for i in range(len(track.segment_durations)):
fragment_basename = segment_pattern % (i+1)
fragment_file = path.join(options.output_dir, media_subdir, fragment_basename)
init_file = path.join(options.output_dir, media_subdir, options.init_segment)
if not path.exists(fragment_file):
break
json_index = Mp4IframIndex(options, fragment_file, fragments_info=init_file)
index = json.loads(json_index)
if len(index) < 1:
break
iframe_size = int(index[0]['size'])
iframe_offset = int(index[0]['offset'])
iframe_range_size = iframe_size + iframe_offset
index_playlist_file.write('#EXTINF:%f,\r\n' % (track.segment_durations[i]))
index_playlist_file.write('#EXT-X-BYTERANGE:%d@0\r\n' % (iframe_range_size))
index_playlist_file.write(fragment_basename+'\r\n')
index_playlist_file.write('#EXT-X-ENDLIST\r\n')
#############################################
def OutputHls(options, set_attributes, audio_sets, video_sets, subtitles_sets, subtitles_files):
all_audio_tracks = sum(audio_sets.values(), [])
@@ -670,15 +754,17 @@ def OutputHls(options, set_attributes, audio_sets, video_sets, subtitles_sets, s
master_playlist_file.write('# Video\r\n')
for video_track in all_video_tracks:
if options.on_demand or not options.split:
media_subdir = ''
media_file_name = video_track.parent.media_name
media_playlist_name = video_track.representation_id+".m3u8"
media_playlist_path = media_playlist_name
media_subdir = ''
media_file_name = video_track.parent.media_name
media_playlist_name = video_track.representation_id+".m3u8"
media_playlist_path = media_playlist_name
iframes_playlist_name = video_track.representation_id+"_iframes.m3u8"
else:
media_subdir = video_track.representation_id
media_file_name = ''
media_playlist_name = options.hls_media_playlist_name
media_playlist_path = media_subdir+'/'+media_playlist_name
media_subdir = video_track.representation_id
media_file_name = ''
media_playlist_name = options.hls_media_playlist_name
media_playlist_path = media_subdir+'/'+media_playlist_name
iframes_playlist_name = options.hls_iframes_playlist_name
if len(audio_groups):
# one entry per audio group
@@ -703,6 +789,17 @@ def OutputHls(options, set_attributes, audio_sets, video_sets, subtitles_sets, s
master_playlist_file.write(media_playlist_path+'\r\n')
OutputHlsTrack(options, video_track, media_subdir, media_playlist_name, media_file_name)
OutputHlsIframeIndex(options, video_track, media_subdir, iframes_playlist_name, media_file_name)
master_playlist_file.write('\r\n# I-Frame Playlists\r\n')
for video_track in all_video_tracks:
master_playlist_file.write('#EXT-X-I-FRAME-STREAM-INF:AVERAGE-BANDWIDTH=%d,BANDWIDTH=%d,CODECS="%s",RESOLUTION=%dx%d,URI="%s"\r\n' % (
video_track.average_segment_bitrate,
video_track.max_segment_bitrate,
video_track.codec,
video_track.width,
video_track.height,
media_playlist_path))
if len(subtitles_files):
master_playlist_file.write('# Subtitles\r\n')
@@ -1244,6 +1341,8 @@ def main():
"The <primetime-data> argument can be either: " +
"(1) the character '@' followed by the name of a file containing the Primetime Metadata to use, or "
"(2) the character '#' followed by the Primetime Metadata encoded in Base64")
parser.add_option('', "--fairplay-key-uri", dest="fairplay_key_uri",
help="Specify the key URI to use for FairPlay Streaming key delivery (only valid with --hls option)")
parser.add_option('', "--exec-dir", metavar="<exec_dir>", dest="exec_dir", default=default_exec_dir,
help="Directory where the Bento4 executables are located")
(options, args) = parser.parse_args()
@@ -1337,10 +1436,16 @@ def main():
if options.widevine_header:
options.widevine = True
if options.hls and options.widevine_header.startswith('#'):
raise Exception('with --hls, only the <name>:<value> pair syntax is supported for the --widevine-header option')
if options.primetime_metadata:
options.primetime = True
if options.fairplay_key_uri:
if not options.hls:
sys.stderr.write('WARNING: --fairplay-key-uri is only valid with --hls, ignoring\n')
if options.hls:
if options.encryption_key and options.encryption_cenc_scheme != 'cbcs':
raise Exception('--hls requires --encryption-cenc-scheme=cbcs')

View File

@@ -302,6 +302,9 @@ def Mp4Encrypt(options, input_filename, output_filename, *args, **kwargs):
def Mp42Hls(options, input_filename, *args, **kwargs):
return Bento4Command(options, 'mp42hls', input_filename, *args, **kwargs)
def Mp4IframIndex(options, input_filename, *args, **kwargs):
return Bento4Command(options, 'mp4iframeindex', input_filename, *args, **kwargs)
class Mp4Atom:
def __init__(self, type, size, position):
self.type = type