Compare commits
97 Commits
libwebm-1.
...
sandbox/ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dca6be3a32 | ||
|
|
4a5141344e | ||
|
|
2fc496a0d6 | ||
|
|
cb8899a920 | ||
|
|
49078292b4 | ||
|
|
4f494f6dd4 | ||
|
|
7ef225de9f | ||
|
|
8f0c3333d1 | ||
|
|
bf664baf05 | ||
|
|
232bae0d50 | ||
|
|
69c9348f07 | ||
|
|
711af0c505 | ||
|
|
38173f9d49 | ||
|
|
21a2bd14c7 | ||
|
|
9ec562f72d | ||
|
|
e6e2b6b387 | ||
|
|
a2ca300513 | ||
|
|
6cf00207c0 | ||
|
|
4df02ce68b | ||
|
|
4ffb162798 | ||
|
|
76d9cf9cf4 | ||
|
|
20f64ff979 | ||
|
|
537da82f37 | ||
|
|
db20aaa2b1 | ||
|
|
c9e284b9e7 | ||
|
|
07ac1947f0 | ||
|
|
0edf087bbb | ||
|
|
c425e965aa | ||
|
|
ed6282b2d6 | ||
|
|
282a67599c | ||
|
|
adebb53754 | ||
|
|
a320f5be63 | ||
|
|
c4d2b27b7a | ||
|
|
13a90600ea | ||
|
|
478b524df3 | ||
|
|
010a457bc9 | ||
|
|
47a09523b2 | ||
|
|
84bf4a41dc | ||
|
|
177df33d25 | ||
|
|
4fff53441d | ||
|
|
ca13a5bae0 | ||
|
|
cb69e608b4 | ||
|
|
f6b0408aba | ||
|
|
9a561ab4dd | ||
|
|
0568dd63a6 | ||
|
|
56488f73ef | ||
|
|
f270ddaeb8 | ||
|
|
041a5c5811 | ||
|
|
6fa7c7611c | ||
|
|
71d296e44c | ||
|
|
72052ed8b1 | ||
|
|
a88d62b682 | ||
|
|
28d54555a7 | ||
|
|
359b3654ad | ||
|
|
000944c4e4 | ||
|
|
8da8206fa0 | ||
|
|
7a9a72f984 | ||
|
|
d2327e2b65 | ||
|
|
1e37a264f1 | ||
|
|
01d5924817 | ||
|
|
a20f4255c7 | ||
|
|
69df730519 | ||
|
|
f7aa8ab33d | ||
|
|
73ad7bd83c | ||
|
|
4c682199b0 | ||
|
|
9303667611 | ||
|
|
4affedd0a7 | ||
|
|
23808a7ba4 | ||
|
|
32227e70c1 | ||
|
|
2d3461b4b3 | ||
|
|
a09f15f00e | ||
|
|
6d99850e7c | ||
|
|
1ae4335c1c | ||
|
|
52f0a92192 | ||
|
|
6ebe4a39df | ||
|
|
a3dd40877d | ||
|
|
1623fb983b | ||
|
|
18ac83d501 | ||
|
|
5942099a85 | ||
|
|
9ecedef185 | ||
|
|
6f68021678 | ||
|
|
3395c36a8e | ||
|
|
ffe5a8e548 | ||
|
|
a9c65fbbc0 | ||
|
|
31a9d5470e | ||
|
|
2b84a12da8 | ||
|
|
bd833a82e4 | ||
|
|
7b07758854 | ||
|
|
00ed87aad6 | ||
|
|
06f08663be | ||
|
|
35ded77a23 | ||
|
|
1f33611caa | ||
|
|
70f9644a8d | ||
|
|
f2bd78ef6b | ||
|
|
2083c72300 | ||
|
|
f5ec272e54 | ||
|
|
b324e52139 |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.sln eol=crlf
|
||||
*.vcproj eol=crlf
|
||||
*.vsprops eol=crlf
|
||||
*.vcxproj eol=crlf
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -12,4 +12,7 @@ core
|
||||
*.exe
|
||||
*.webm
|
||||
Debug
|
||||
Release
|
||||
Release
|
||||
*.sdf
|
||||
*.opensdf
|
||||
ipch
|
||||
55
Makefile
55
Makefile
@@ -1,20 +1,47 @@
|
||||
LIB = libmkvparser.a
|
||||
OBJECTS = mkvparser.o mkvreader.o sample.o
|
||||
EXE = sample
|
||||
CFLAGS = -W -Wall -g
|
||||
CXX := g++
|
||||
CXXFLAGS := -W -Wall -g
|
||||
LIBWEBMA := libwebm.a
|
||||
LIBWEBMSO := libwebm.so
|
||||
WEBMOBJS := mkvparser.o mkvreader.o mkvmuxer.o mkvmuxerutil.o mkvwriter.o
|
||||
OBJSA := $(WEBMOBJS:.o=_a.o)
|
||||
OBJSSO := $(WEBMOBJS:.o=_so.o)
|
||||
OBJECTS1 := sample.o
|
||||
OBJECTS2 := sample_muxer.o vttreader.o webvttparser.o sample_muxer_metadata.o
|
||||
OBJECTS3 := dumpvtt.o vttreader.o webvttparser.o
|
||||
OBJECTS4 := vttdemux.o webvttparser.o
|
||||
INCLUDES := -I.
|
||||
EXES := samplemuxer sample dumpvtt vttdemux
|
||||
|
||||
$(EXE): $(OBJECTS)
|
||||
$(AR) rcs $(LIB) mkvparser.o
|
||||
$(CXX) $(OBJECTS) -L./ -lmkvparser -o $(EXE)
|
||||
all: $(EXES)
|
||||
|
||||
mkvparser.o: mkvparser.cpp
|
||||
$(CXX) -c $(CFLAGS) mkvparser.cpp -o mkvparser.o
|
||||
sample: sample.o $(LIBWEBMA)
|
||||
$(CXX) $^ -o $@
|
||||
|
||||
mkvreader.o: mkvreader.cpp
|
||||
$(CXX) -c $(CFLAGS) mkvreader.cpp -o mkvreader.o
|
||||
samplemuxer: $(OBJECTS2) $(LIBWEBMA)
|
||||
$(CXX) $^ -o $@
|
||||
|
||||
sample.o: sample.cpp
|
||||
$(CXX) -c $(CFLAGS) sample.cpp -o sample.o
|
||||
dumpvtt: $(OBJECTS3)
|
||||
$(CXX) $^ -o $@
|
||||
|
||||
shared: $(LIBWEBMSO)
|
||||
|
||||
vttdemux: $(OBJECTS4) $(LIBWEBMA)
|
||||
$(CXX) $^ -o $@
|
||||
|
||||
libwebm.a: $(OBJSA)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
libwebm.so: $(OBJSSO)
|
||||
$(CXX) $(CXXFLAGS) -shared $(OBJSSO) -o $(LIBWEBMSO)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(CXXFLAGS) $(INCLUDES) $< -o $@
|
||||
|
||||
%_a.o: %.cpp
|
||||
$(CXX) -c $(CXXFLAGS) $(INCLUDES) $< -o $@
|
||||
|
||||
%_so.o: %.cpp
|
||||
$(CXX) -c $(CXXFLAGS) -fPIC $(INCLUDES) $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJECTS) $(LIB) $(EXE) Makefile.bak
|
||||
$(RM) -f $(OBJECTS1) $(OBJECTS2) $(OBJECTS3) $(OBJECTS4) $(OBJSA) $(OBJSSO) $(LIBWEBMA) $(LIBWEBMSO) $(EXES) Makefile.bak
|
||||
|
||||
98
dumpvtt.cc
Normal file
98
dumpvtt.cc
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include "./vttreader.h"
|
||||
#include "./webvttparser.h"
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stdout, "usage: dumpvtt <vtt file>\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
libwebvtt::VttReader reader;
|
||||
const char* const filename = argv[1];
|
||||
|
||||
if (int e = reader.Open(filename)) {
|
||||
(void)e;
|
||||
fprintf(stderr, "open failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
libwebvtt::Parser parser(&reader);
|
||||
|
||||
if (int e = parser.Init()) {
|
||||
(void)e;
|
||||
fprintf(stderr, "parser init failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (libwebvtt::Cue cue;;) {
|
||||
const int e = parser.Parse(&cue);
|
||||
|
||||
if (e < 0) { // error
|
||||
fprintf(stderr, "error parsing cue\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (e > 0) // EOF
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
fprintf(stdout, "cue identifier: \"%s\"\n", cue.identifier.c_str());
|
||||
|
||||
const libwebvtt::Time& st = cue.start_time;
|
||||
fprintf(stdout, "cue start time: \"HH=%i MM=%i SS=%i SSS=%i\"\n",
|
||||
st.hours,
|
||||
st.minutes,
|
||||
st.seconds,
|
||||
st.milliseconds);
|
||||
|
||||
const libwebvtt::Time& sp = cue.stop_time;
|
||||
fprintf(stdout, "cue stop time: \"HH=%i MM=%i SS=%i SSS=%i\"\n",
|
||||
sp.hours,
|
||||
sp.minutes,
|
||||
sp.seconds,
|
||||
sp.milliseconds);
|
||||
|
||||
{
|
||||
typedef libwebvtt::Cue::settings_t::const_iterator iter_t;
|
||||
iter_t i = cue.settings.begin();
|
||||
const iter_t j = cue.settings.end();
|
||||
|
||||
if (i == j) {
|
||||
fprintf(stdout, "cue setting: <no settings present>\n");
|
||||
} else {
|
||||
while (i != j) {
|
||||
const libwebvtt::Setting& setting = *i++;
|
||||
fprintf(stdout, "cue setting: name=%s value=%s\n",
|
||||
setting.name.c_str(),
|
||||
setting.value.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
typedef libwebvtt::Cue::payload_t::const_iterator iter_t;
|
||||
iter_t i = cue.payload.begin();
|
||||
const iter_t j = cue.payload.end();
|
||||
|
||||
int idx = 1;
|
||||
while (i != j) {
|
||||
const std::string& payload = *i++;
|
||||
const char* const payload_str = payload.c_str();
|
||||
fprintf(stdout, "cue payload[%i]: \"%s\"\n", idx, payload_str);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
38
libwebm_2008.sln
Normal file
38
libwebm_2008.sln
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample", "sample_2008.vcproj", "{0CB5681F-6065-490C-98C8-05531732ED7E}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA} = {7B1F12CA-0724-430B-B61A-1D357C912CBA}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwebm", "libwebm_2008.vcproj", "{7B1F12CA-0724-430B-B61A-1D357C912CBA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_muxer", "sample_muxer_2008.vcproj", "{B407561F-1F5E-4798-B9C2-81AB09CFBC16}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA} = {7B1F12CA-0724-430B-B61A-1D357C912CBA}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.Build.0 = Release|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Release|Win32.Build.0 = Release|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,178 +1,210 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="mkvparser"
|
||||
ProjectGUID="{F9128EC6-C008-41AD-B38F-0E70D549D9F4}"
|
||||
RootNamespace="mkvparser"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
UseOfMFC="0"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="false"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
UseOfMFC="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mkvparser.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvreader.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mkvparser.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvreader.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="libwebm"
|
||||
ProjectGUID="{7B1F12CA-0724-430B-B61A-1D357C912CBA}"
|
||||
RootNamespace="libwebm"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(ProjectDir)..\lib\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ProjectDir)..\obj\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="false"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="1"
|
||||
DisableSpecificWarnings="4996"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(ProjectDir)..\lib\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ProjectDir)..\obj\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="0"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mkvmuxer.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvmuxerutil.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvparser.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvreader.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvwriter.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mkvmuxer.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvmuxertypes.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvmuxerutil.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvparser.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvreader.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvwriter.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\webmids.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
46
libwebm_2010.sln
Normal file
46
libwebm_2010.sln
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample", "sample_2010.vcxproj", "{0CB5681F-6065-490C-98C8-05531732ED7E}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwebm", "libwebm_2010.vcxproj", "{7B1F12CA-0724-430B-B61A-1D357C912CBA}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_muxer", "sample_muxer_2010.vcxproj", "{B407561F-1F5E-4798-B9C2-81AB09CFBC16}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug DLL|Win32 = Debug DLL|Win32
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release DLL|Win32 = Release DLL|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug DLL|Win32.Build.0 = Debug DLL|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release DLL|Win32.ActiveCfg = Release DLL|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release DLL|Win32.Build.0 = Release DLL|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.Build.0 = Release|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Debug DLL|Win32.Build.0 = Debug DLL|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Release DLL|Win32.ActiveCfg = Release DLL|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Release DLL|Win32.Build.0 = Release DLL|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{7B1F12CA-0724-430B-B61A-1D357C912CBA}.Release|Win32.Build.0 = Release|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug DLL|Win32.Build.0 = Debug DLL|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release DLL|Win32.ActiveCfg = Release DLL|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release DLL|Win32.Build.0 = Release DLL|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
150
libwebm_2010.vcxproj
Normal file
150
libwebm_2010.vcxproj
Normal file
@@ -0,0 +1,150 @@
|
||||
<?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 DLL|Win32">
|
||||
<Configuration>Debug DLL</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release DLL|Win32">
|
||||
<Configuration>Release DLL</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>libwebm</ProjectName>
|
||||
<ProjectGuid>{7B1F12CA-0724-430B-B61A-1D357C912CBA}</ProjectGuid>
|
||||
<RootNamespace>libwebm</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\lib\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">$(ProjectDir)..\lib\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\lib\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">$(ProjectDir)..\lib\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mkvmuxer.cpp" />
|
||||
<ClCompile Include="mkvmuxerutil.cpp" />
|
||||
<ClCompile Include="mkvparser.cpp" />
|
||||
<ClCompile Include="mkvreader.cpp" />
|
||||
<ClCompile Include="mkvwriter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="mkvmuxer.hpp" />
|
||||
<ClInclude Include="mkvmuxertypes.hpp" />
|
||||
<ClInclude Include="mkvmuxerutil.hpp" />
|
||||
<ClInclude Include="mkvparser.hpp" />
|
||||
<ClInclude Include="mkvreader.hpp" />
|
||||
<ClInclude Include="mkvwriter.hpp" />
|
||||
<ClInclude Include="webmids.hpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
53
libwebm_2010.vcxproj.filters
Normal file
53
libwebm_2010.vcxproj.filters
Normal file
@@ -0,0 +1,53 @@
|
||||
<?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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mkvmuxer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mkvmuxerutil.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mkvparser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mkvreader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mkvwriter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="mkvmuxer.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mkvmuxertypes.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mkvmuxerutil.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mkvparser.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mkvreader.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="mkvwriter.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webmids.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
2330
mkvmuxer.cpp
Normal file
2330
mkvmuxer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
950
mkvmuxer.hpp
Normal file
950
mkvmuxer.hpp
Normal file
@@ -0,0 +1,950 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef MKVMUXER_HPP
|
||||
#define MKVMUXER_HPP
|
||||
|
||||
#include "mkvmuxertypes.hpp"
|
||||
|
||||
// For a description of the WebM elements see
|
||||
// http://www.webmproject.org/code/specs/container/.
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
class MkvWriter;
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Interface used by the mkvmuxer to write out the Mkv data.
|
||||
class IMkvWriter {
|
||||
public:
|
||||
// Writes out |len| bytes of |buf|. Returns 0 on success.
|
||||
virtual int32 Write(const void* buf, uint32 len) = 0;
|
||||
|
||||
// Returns the offset of the output position from the beginning of the
|
||||
// output.
|
||||
virtual int64 Position() const = 0;
|
||||
|
||||
// Set the current File position. Returns 0 on success.
|
||||
virtual int32 Position(int64 position) = 0;
|
||||
|
||||
// Returns true if the writer is seekable.
|
||||
virtual bool Seekable() const = 0;
|
||||
|
||||
// Element start notification. Called whenever an element identifier is about
|
||||
// to be written to the stream. |element_id| is the element identifier, and
|
||||
// |position| is the location in the WebM stream where the first octet of the
|
||||
// element identifier will be written.
|
||||
// Note: the |MkvId| enumeration in webmids.hpp defines element values.
|
||||
virtual void ElementStartNotify(uint64 element_id, int64 position) = 0;
|
||||
|
||||
protected:
|
||||
IMkvWriter();
|
||||
virtual ~IMkvWriter();
|
||||
|
||||
private:
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(IMkvWriter);
|
||||
};
|
||||
|
||||
// Writes out the EBML header for a WebM file. This function must be called
|
||||
// before any other libwebm writing functions are called.
|
||||
bool WriteEbmlHeader(IMkvWriter* writer);
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Class to hold data the will be written to a block.
|
||||
class Frame {
|
||||
public:
|
||||
Frame();
|
||||
~Frame();
|
||||
|
||||
// Copies |frame| data into |frame_|. Returns true on success.
|
||||
bool Init(const uint8* frame, uint64 length);
|
||||
|
||||
const uint8* frame() const { return frame_; }
|
||||
uint64 length() const { return length_; }
|
||||
void set_track_number(uint64 track_number) { track_number_ = track_number; }
|
||||
uint64 track_number() const { return track_number_; }
|
||||
void set_timestamp(uint64 timestamp) { timestamp_ = timestamp; }
|
||||
uint64 timestamp() const { return timestamp_; }
|
||||
void set_is_key(bool key) { is_key_ = key; }
|
||||
bool is_key() const { return is_key_; }
|
||||
|
||||
private:
|
||||
// Pointer to the data. Owned by this class.
|
||||
uint8* frame_;
|
||||
|
||||
// Length of the data.
|
||||
uint64 length_;
|
||||
|
||||
// Mkv track number the data is associated with.
|
||||
uint64 track_number_;
|
||||
|
||||
// Timestamp of the data in nanoseconds.
|
||||
uint64 timestamp_;
|
||||
|
||||
// Flag telling if the data should set the key flag of a block.
|
||||
bool is_key_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Class to hold one cue point in a Cues element.
|
||||
class CuePoint {
|
||||
public:
|
||||
CuePoint();
|
||||
~CuePoint();
|
||||
|
||||
// Returns the size in bytes for the entire CuePoint element.
|
||||
uint64 Size() const;
|
||||
|
||||
// Output the CuePoint element to the writer. Returns true on success.
|
||||
bool Write(IMkvWriter* writer) const;
|
||||
|
||||
void set_time(uint64 time) { time_ = time; }
|
||||
uint64 time() const { return time_; }
|
||||
void set_track(uint64 track) { track_ = track; }
|
||||
uint64 track() const { return track_; }
|
||||
void set_cluster_pos(uint64 cluster_pos) { cluster_pos_ = cluster_pos; }
|
||||
uint64 cluster_pos() const { return cluster_pos_; }
|
||||
void set_block_number(uint64 block_number) { block_number_ = block_number; }
|
||||
uint64 block_number() const { return block_number_; }
|
||||
void set_output_block_number(bool output_block_number) {
|
||||
output_block_number_ = output_block_number;
|
||||
}
|
||||
bool output_block_number() const { return output_block_number_; }
|
||||
|
||||
private:
|
||||
// Returns the size in bytes for the payload of the CuePoint element.
|
||||
uint64 PayloadSize() const;
|
||||
|
||||
// Absolute timecode according to the segment time base.
|
||||
uint64 time_;
|
||||
|
||||
// The Track element associated with the CuePoint.
|
||||
uint64 track_;
|
||||
|
||||
// The position of the Cluster containing the Block.
|
||||
uint64 cluster_pos_;
|
||||
|
||||
// Number of the Block within the Cluster, starting from 1.
|
||||
uint64 block_number_;
|
||||
|
||||
// If true the muxer will write out the block number for the cue if the
|
||||
// block number is different than the default of 1. Default is set to true.
|
||||
bool output_block_number_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(CuePoint);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Cues element.
|
||||
class Cues {
|
||||
public:
|
||||
Cues();
|
||||
~Cues();
|
||||
|
||||
// Adds a cue point to the Cues element. Returns true on success.
|
||||
bool AddCue(CuePoint* cue);
|
||||
|
||||
// Returns the cue point by index. Returns NULL if there is no cue point
|
||||
// match.
|
||||
const CuePoint* GetCueByIndex(int32 index) const;
|
||||
|
||||
// Output the Cues element to the writer. Returns true on success.
|
||||
bool Write(IMkvWriter* writer) const;
|
||||
|
||||
int32 cue_entries_size() const { return cue_entries_size_; }
|
||||
void set_output_block_number(bool output_block_number) {
|
||||
output_block_number_ = output_block_number;
|
||||
}
|
||||
bool output_block_number() const { return output_block_number_; }
|
||||
|
||||
private:
|
||||
// Number of allocated elements in |cue_entries_|.
|
||||
int32 cue_entries_capacity_;
|
||||
|
||||
// Number of CuePoints in |cue_entries_|.
|
||||
int32 cue_entries_size_;
|
||||
|
||||
// CuePoint list.
|
||||
CuePoint** cue_entries_;
|
||||
|
||||
// If true the muxer will write out the block number for the cue if the
|
||||
// block number is different than the default of 1. Default is set to true.
|
||||
bool output_block_number_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cues);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// ContentEncAESSettings element
|
||||
class ContentEncAESSettings {
|
||||
public:
|
||||
enum {
|
||||
kCTR = 1
|
||||
};
|
||||
|
||||
ContentEncAESSettings();
|
||||
~ContentEncAESSettings() {}
|
||||
|
||||
// Returns the size in bytes for the ContentEncAESSettings element.
|
||||
uint64 Size() const;
|
||||
|
||||
// Writes out the ContentEncAESSettings element to |writer|. Returns true on
|
||||
// success.
|
||||
bool Write(IMkvWriter* writer) const;
|
||||
|
||||
uint64 cipher_mode() const { return cipher_mode_; }
|
||||
|
||||
private:
|
||||
// Returns the size in bytes for the payload of the ContentEncAESSettings
|
||||
// element.
|
||||
uint64 PayloadSize() const;
|
||||
|
||||
// Sub elements
|
||||
uint64 cipher_mode_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncAESSettings);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// ContentEncoding element
|
||||
// Elements used to describe if the track data has been encrypted or
|
||||
// compressed with zlib or header stripping.
|
||||
// Currently only whole frames can be encrypted with AES. This dictates that
|
||||
// ContentEncodingOrder will be 0, ContentEncodingScope will be 1,
|
||||
// ContentEncodingType will be 1, and ContentEncAlgo will be 5.
|
||||
class ContentEncoding {
|
||||
public:
|
||||
ContentEncoding();
|
||||
~ContentEncoding();
|
||||
|
||||
// Sets the content encryption id. Copies |length| bytes from |id| to
|
||||
// |enc_key_id_|. Returns true on success.
|
||||
bool SetEncryptionID(const uint8* id, uint64 length);
|
||||
|
||||
// Returns the size in bytes for the ContentEncoding element.
|
||||
uint64 Size() const;
|
||||
|
||||
// Writes out the ContentEncoding element to |writer|. Returns true on
|
||||
// success.
|
||||
bool Write(IMkvWriter* writer) const;
|
||||
|
||||
uint64 enc_algo() const { return enc_algo_; }
|
||||
uint64 encoding_order() const { return encoding_order_; }
|
||||
uint64 encoding_scope() const { return encoding_scope_; }
|
||||
uint64 encoding_type() const { return encoding_type_; }
|
||||
ContentEncAESSettings* enc_aes_settings() { return &enc_aes_settings_; }
|
||||
|
||||
private:
|
||||
// Returns the size in bytes for the encoding elements.
|
||||
uint64 EncodingSize(uint64 compresion_size, uint64 encryption_size) const;
|
||||
|
||||
// Returns the size in bytes for the encryption elements.
|
||||
uint64 EncryptionSize() const;
|
||||
|
||||
// Track element names
|
||||
uint64 enc_algo_;
|
||||
uint8* enc_key_id_;
|
||||
uint64 encoding_order_;
|
||||
uint64 encoding_scope_;
|
||||
uint64 encoding_type_;
|
||||
|
||||
// ContentEncAESSettings element.
|
||||
ContentEncAESSettings enc_aes_settings_;
|
||||
|
||||
// Size of the ContentEncKeyID data in bytes.
|
||||
uint64 enc_key_id_length_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Track element.
|
||||
class Track {
|
||||
public:
|
||||
Track();
|
||||
virtual ~Track();
|
||||
|
||||
// Adds a ContentEncoding element to the Track. Returns true on success.
|
||||
virtual bool AddContentEncoding();
|
||||
|
||||
// Returns the ContentEncoding by index. Returns NULL if there is no
|
||||
// ContentEncoding match.
|
||||
ContentEncoding* GetContentEncodingByIndex(uint32 index) const;
|
||||
|
||||
// Returns the size in bytes for the payload of the Track element.
|
||||
virtual uint64 PayloadSize() const;
|
||||
|
||||
// Returns the size in bytes of the Track element.
|
||||
virtual uint64 Size() const;
|
||||
|
||||
// Output the Track element to the writer. Returns true on success.
|
||||
virtual bool Write(IMkvWriter* writer) const;
|
||||
|
||||
// Sets the CodecPrivate element of the Track element. Copies |length|
|
||||
// bytes from |codec_private| to |codec_private_|. Returns true on success.
|
||||
bool SetCodecPrivate(const uint8* codec_private, uint64 length);
|
||||
|
||||
void set_codec_id(const char* codec_id);
|
||||
const char* codec_id() const { return codec_id_; }
|
||||
const uint8* codec_private() const { return codec_private_; }
|
||||
void set_language(const char* language);
|
||||
const char* language() const { return language_; }
|
||||
void set_name(const char* name);
|
||||
const char* name() const { return name_; }
|
||||
void set_number(uint64 number) { number_ = number; }
|
||||
uint64 number() const { return number_; }
|
||||
void set_type(uint64 type) { type_ = type; }
|
||||
uint64 type() const { return type_; }
|
||||
uint64 uid() const { return uid_; }
|
||||
|
||||
uint64 codec_private_length() const { return codec_private_length_; }
|
||||
uint32 content_encoding_entries_size() const {
|
||||
return content_encoding_entries_size_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Returns a random number to be used for the Track UID.
|
||||
static uint64 MakeUID();
|
||||
|
||||
// Track element names
|
||||
char* codec_id_;
|
||||
uint8* codec_private_;
|
||||
char* language_;
|
||||
char* name_;
|
||||
uint64 number_;
|
||||
uint64 type_;
|
||||
const uint64 uid_;
|
||||
|
||||
// Size of the CodecPrivate data in bytes.
|
||||
uint64 codec_private_length_;
|
||||
|
||||
// ContentEncoding element list.
|
||||
ContentEncoding** content_encoding_entries_;
|
||||
|
||||
// Number of ContentEncoding elements added.
|
||||
uint32 content_encoding_entries_size_;
|
||||
|
||||
// Flag telling if the rand call was seeded.
|
||||
static bool is_seeded_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Track);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Track that has video specific elements.
|
||||
class VideoTrack : public Track {
|
||||
public:
|
||||
// Supported modes for stereo 3D.
|
||||
enum StereoMode {
|
||||
kMono = 0,
|
||||
kSideBySideLeftIsFirst = 1,
|
||||
kTopBottomRightIsFirst = 2,
|
||||
kTopBottomLeftIsFirst = 3,
|
||||
kSideBySideRightIsFirst = 11
|
||||
};
|
||||
|
||||
VideoTrack();
|
||||
virtual ~VideoTrack();
|
||||
|
||||
// Returns the size in bytes for the payload of the Track element plus the
|
||||
// video specific elements.
|
||||
virtual uint64 PayloadSize() const;
|
||||
|
||||
// Output the VideoTrack element to the writer. Returns true on success.
|
||||
virtual bool Write(IMkvWriter* writer) const;
|
||||
|
||||
// Sets the video's stereo mode. Returns true on success.
|
||||
bool SetStereoMode(uint64 stereo_mode);
|
||||
|
||||
void set_display_height(uint64 height) { display_height_ = height; }
|
||||
uint64 display_height() const { return display_height_; }
|
||||
void set_display_width(uint64 width) { display_width_ = width; }
|
||||
uint64 display_width() const { return display_width_; }
|
||||
void set_frame_rate(double frame_rate) { frame_rate_ = frame_rate; }
|
||||
double frame_rate() const { return frame_rate_; }
|
||||
void set_height(uint64 height) { height_ = height; }
|
||||
uint64 height() const { return height_; }
|
||||
uint64 stereo_mode() { return stereo_mode_; }
|
||||
void set_width(uint64 width) { width_ = width; }
|
||||
uint64 width() const { return width_; }
|
||||
|
||||
private:
|
||||
// Returns the size in bytes of the Video element.
|
||||
uint64 VideoPayloadSize() const;
|
||||
|
||||
// Video track element names.
|
||||
uint64 display_height_;
|
||||
uint64 display_width_;
|
||||
double frame_rate_;
|
||||
uint64 height_;
|
||||
uint64 stereo_mode_;
|
||||
uint64 width_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(VideoTrack);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Track that has audio specific elements.
|
||||
class AudioTrack : public Track {
|
||||
public:
|
||||
AudioTrack();
|
||||
virtual ~AudioTrack();
|
||||
|
||||
// Returns the size in bytes for the payload of the Track element plus the
|
||||
// audio specific elements.
|
||||
virtual uint64 PayloadSize() const;
|
||||
|
||||
// Output the AudioTrack element to the writer. Returns true on success.
|
||||
virtual bool Write(IMkvWriter* writer) const;
|
||||
|
||||
void set_bit_depth(uint64 bit_depth) { bit_depth_ = bit_depth; }
|
||||
uint64 bit_depth() const { return bit_depth_; }
|
||||
void set_channels(uint64 channels) { channels_ = channels; }
|
||||
uint64 channels() const { return channels_; }
|
||||
void set_sample_rate(double sample_rate) { sample_rate_ = sample_rate; }
|
||||
double sample_rate() const { return sample_rate_; }
|
||||
|
||||
private:
|
||||
// Audio track element names.
|
||||
uint64 bit_depth_;
|
||||
uint64 channels_;
|
||||
double sample_rate_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(AudioTrack);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Tracks element
|
||||
class Tracks {
|
||||
public:
|
||||
// Audio and video type defined by the Matroska specs.
|
||||
enum {
|
||||
kVideo = 0x1,
|
||||
kAudio = 0x2
|
||||
};
|
||||
// Vorbis and VP8 coded id defined by the Matroska specs.
|
||||
static const char* const kVorbisCodecId;
|
||||
static const char* const kVp8CodecId;
|
||||
|
||||
Tracks();
|
||||
~Tracks();
|
||||
|
||||
// Adds a Track element to the Tracks object. |track| will be owned and
|
||||
// deleted by the Tracks object. Returns true on success. |number| is the
|
||||
// number to use for the track. |number| must be >= 0. If |number| == 0
|
||||
// then the muxer will decide on the track number.
|
||||
bool AddTrack(Track* track, int32 number);
|
||||
|
||||
// Returns the track by index. Returns NULL if there is no track match.
|
||||
const Track* GetTrackByIndex(uint32 idx) const;
|
||||
|
||||
// Search the Tracks and return the track that matches |tn|. Returns NULL
|
||||
// if there is no track match.
|
||||
Track* GetTrackByNumber(uint64 track_number) const;
|
||||
|
||||
// Returns true if the track number is an audio track.
|
||||
bool TrackIsAudio(uint64 track_number) const;
|
||||
|
||||
// Returns true if the track number is a video track.
|
||||
bool TrackIsVideo(uint64 track_number) const;
|
||||
|
||||
// Output the Tracks element to the writer. Returns true on success.
|
||||
bool Write(IMkvWriter* writer) const;
|
||||
|
||||
uint32 track_entries_size() const { return track_entries_size_; }
|
||||
|
||||
private:
|
||||
// Track element list.
|
||||
Track** track_entries_;
|
||||
|
||||
// Number of Track elements added.
|
||||
uint32 track_entries_size_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Tracks);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Cluster element
|
||||
//
|
||||
// Notes:
|
||||
// |Init| must be called before any other method in this class.
|
||||
class Cluster {
|
||||
public:
|
||||
Cluster(uint64 timecode, int64 cues_pos);
|
||||
~Cluster();
|
||||
|
||||
// |timecode| is the absolute timecode of the cluster. |cues_pos| is the
|
||||
// position for the cluster within the segment that should be written in
|
||||
// the cues element.
|
||||
bool Init(IMkvWriter* ptr_writer);
|
||||
|
||||
// Adds a frame to be output in the file. The frame is written out through
|
||||
// |writer_| if successful. Returns true on success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions. The range of allowed values is [1, 126].
|
||||
// timecode: Absolute (not relative to cluster) timestamp of the
|
||||
// frame, expressed in timecode units.
|
||||
// is_key: Flag telling whether or not this frame is a key frame.
|
||||
bool AddFrame(const uint8* frame,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
uint64 timecode, // timecode units (absolute)
|
||||
bool is_key);
|
||||
|
||||
// Writes a frame of metadata to the output medium; returns true on
|
||||
// success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions. The range of allowed values is [1, 126].
|
||||
// timecode: Absolute (not relative to cluster) timestamp of the
|
||||
// metadata frame, expressed in timecode units.
|
||||
// duration: Duration of metadata frame, in timecode units.
|
||||
//
|
||||
// The metadata frame is written as a block group, with a duration
|
||||
// sub-element but no reference time sub-elements (indicating that
|
||||
// it is considered a keyframe, per Matroska semantics).
|
||||
bool AddMetadata(const uint8* frame,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
uint64 timecode, // timecode units (absolute)
|
||||
uint64 duration); // timecode units
|
||||
|
||||
// Increments the size of the cluster's data in bytes.
|
||||
void AddPayloadSize(uint64 size);
|
||||
|
||||
// Closes the cluster so no more data can be written to it. Will update the
|
||||
// cluster's size if |writer_| is seekable. Returns true on success.
|
||||
bool Finalize();
|
||||
|
||||
// Returns the size in bytes for the entire Cluster element.
|
||||
uint64 Size() const;
|
||||
|
||||
int32 blocks_added() const { return blocks_added_; }
|
||||
uint64 payload_size() const { return payload_size_; }
|
||||
int64 position_for_cues() const { return position_for_cues_; }
|
||||
uint64 timecode() const { return timecode_; }
|
||||
|
||||
private:
|
||||
// Signature that matches either of WriteSimpleBlock or WriteMetadataBlock
|
||||
// in the muxer utilities package.
|
||||
typedef uint64 (*WriteBlock)(IMkvWriter* writer,
|
||||
const uint8* data,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
int64 timecode,
|
||||
uint64 generic_arg);
|
||||
|
||||
// Used to implement AddFrame and AddMetadata.
|
||||
bool DoWriteBlock(const uint8* frame,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
uint64 absolute_timecode,
|
||||
uint64 generic_arg,
|
||||
WriteBlock write_block);
|
||||
|
||||
// Outputs the Cluster header to |writer_|. Returns true on success.
|
||||
bool WriteClusterHeader();
|
||||
|
||||
// Number of blocks added to the cluster.
|
||||
int32 blocks_added_;
|
||||
|
||||
// Flag telling if the cluster has been closed.
|
||||
bool finalized_;
|
||||
|
||||
// Flag telling if the cluster's header has been written.
|
||||
bool header_written_;
|
||||
|
||||
// The size of the cluster elements in bytes.
|
||||
uint64 payload_size_;
|
||||
|
||||
// The file position used for cue points.
|
||||
const int64 position_for_cues_;
|
||||
|
||||
// The file position of the cluster's size element.
|
||||
int64 size_position_;
|
||||
|
||||
// The absolute timecode of the cluster.
|
||||
const uint64 timecode_;
|
||||
|
||||
// Pointer to the writer object. Not owned by this class.
|
||||
IMkvWriter* writer_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Cluster);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// SeekHead element
|
||||
class SeekHead {
|
||||
public:
|
||||
SeekHead();
|
||||
~SeekHead();
|
||||
|
||||
// TODO(fgalligan): Change this to reserve a certain size. Then check how
|
||||
// big the seek entry to be added is as not every seek entry will be the
|
||||
// maximum size it could be.
|
||||
// Adds a seek entry to be written out when the element is finalized. |id|
|
||||
// must be the coded mkv element id. |pos| is the file position of the
|
||||
// element. Returns true on success.
|
||||
bool AddSeekEntry(uint32 id, uint64 pos);
|
||||
|
||||
// Writes out SeekHead and SeekEntry elements. Returns true on success.
|
||||
bool Finalize(IMkvWriter* writer) const;
|
||||
|
||||
// Reserves space by writing out a Void element which will be updated with
|
||||
// a SeekHead element later. Returns true on success.
|
||||
bool Write(IMkvWriter* writer);
|
||||
|
||||
private:
|
||||
// We are going to put a cap on the number of Seek Entries.
|
||||
const static int32 kSeekEntryCount = 4;
|
||||
|
||||
// Returns the maximum size in bytes of one seek entry.
|
||||
uint64 MaxEntrySize() const;
|
||||
|
||||
// Seek entry id element list.
|
||||
uint32 seek_entry_id_[kSeekEntryCount];
|
||||
|
||||
// Seek entry pos element list.
|
||||
uint64 seek_entry_pos_[kSeekEntryCount];
|
||||
|
||||
// The file position of SeekHead element.
|
||||
int64 start_pos_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SeekHead);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Segment Information element
|
||||
class SegmentInfo {
|
||||
public:
|
||||
SegmentInfo();
|
||||
~SegmentInfo();
|
||||
|
||||
// Will update the duration if |duration_| is > 0.0. Returns true on success.
|
||||
bool Finalize(IMkvWriter* writer) const;
|
||||
|
||||
// Sets |muxing_app_| and |writing_app_|.
|
||||
bool Init();
|
||||
|
||||
// Output the Segment Information element to the writer. Returns true on
|
||||
// success.
|
||||
bool Write(IMkvWriter* writer);
|
||||
|
||||
void set_duration(double duration) { duration_ = duration; }
|
||||
double duration() const { return duration_; }
|
||||
void set_muxing_app(const char* app);
|
||||
const char* muxing_app() const { return muxing_app_; }
|
||||
void set_timecode_scale(uint64 scale) { timecode_scale_ = scale; }
|
||||
uint64 timecode_scale() const { return timecode_scale_; }
|
||||
void set_writing_app(const char* app);
|
||||
const char* writing_app() const { return writing_app_; }
|
||||
|
||||
private:
|
||||
// Segment Information element names.
|
||||
// Initially set to -1 to signify that a duration has not been set and should
|
||||
// not be written out.
|
||||
double duration_;
|
||||
// Set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
|
||||
char* muxing_app_;
|
||||
uint64 timecode_scale_;
|
||||
// Initially set to libwebm-%d.%d.%d.%d, major, minor, build, revision.
|
||||
char* writing_app_;
|
||||
|
||||
// The file position of the duration element.
|
||||
int64 duration_pos_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(SegmentInfo);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// This class represents the main segment in a WebM file. Currently only
|
||||
// supports one Segment element.
|
||||
//
|
||||
// Notes:
|
||||
// |Init| must be called before any other method in this class.
|
||||
class Segment {
|
||||
public:
|
||||
enum Mode {
|
||||
kLive = 0x1,
|
||||
kFile = 0x2
|
||||
};
|
||||
|
||||
const static uint64 kDefaultMaxClusterDuration = 30000000000ULL;
|
||||
|
||||
Segment();
|
||||
~Segment();
|
||||
|
||||
// Initializes |SegmentInfo| and returns result. Always returns false when
|
||||
// |ptr_writer| is NULL.
|
||||
bool Init(IMkvWriter* ptr_writer);
|
||||
|
||||
// Adds a generic track to the segment. Returns the newly-allocated
|
||||
// track object (which is owned by the segment) on success, NULL on
|
||||
// error. |number| is the number to use for the track. |number|
|
||||
// must be >= 0. If |number| == 0 then the muxer will decide on the
|
||||
// track number.
|
||||
Track* AddTrack(int32 number);
|
||||
|
||||
// Adds an audio track to the segment. Returns the number of the track on
|
||||
// success, 0 on error. |number| is the number to use for the audio track.
|
||||
// |number| must be >= 0. If |number| == 0 then the muxer will decide on
|
||||
// the track number.
|
||||
uint64 AddAudioTrack(int32 sample_rate, int32 channels, int32 number);
|
||||
|
||||
// Adds a cue point to the Cues element. |timestamp| is the time in
|
||||
// nanoseconds of the cue's time. |track| is the Track of the Cue. Returns
|
||||
// true on success.
|
||||
bool AddCuePoint(uint64 timestamp, uint64 track);
|
||||
|
||||
// Adds a frame to be output in the file. Returns true on success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions.
|
||||
// timestamp: Timestamp of the frame in nanoseconds from 0.
|
||||
// is_key: Flag telling whether or not this frame is a key frame.
|
||||
bool AddFrame(const uint8* frame,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
uint64 timestamp_ns,
|
||||
bool is_key);
|
||||
|
||||
// Writes a frame of metadata to the output medium; returns true on
|
||||
// success.
|
||||
// Inputs:
|
||||
// frame: Pointer to the data
|
||||
// length: Length of the data
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions.
|
||||
// timecode: Absolute timestamp of the metadata frame, expressed
|
||||
// in nanosecond units.
|
||||
// duration: Duration of metadata frame, in nanosecond units.
|
||||
//
|
||||
// The metadata frame is written as a block group, with a duration
|
||||
// sub-element but no reference time sub-elements (indicating that
|
||||
// it is considered a keyframe, per Matroska semantics).
|
||||
bool AddMetadata(const uint8* frame,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
uint64 timestamp_ns,
|
||||
uint64 duration_ns);
|
||||
|
||||
// Adds a video track to the segment. Returns the number of the track on
|
||||
// success, 0 on error. |number| is the number to use for the video track.
|
||||
// |number| must be >= 0. If |number| == 0 then the muxer will decide on
|
||||
// the track number.
|
||||
uint64 AddVideoTrack(int32 width, int32 height, int32 number);
|
||||
|
||||
// Sets which track to use for the Cues element. Must have added the track
|
||||
// before calling this function. Returns true on success. |track_number| is
|
||||
// returned by the Add track functions.
|
||||
bool CuesTrack(uint64 track_number);
|
||||
|
||||
// Writes out any frames that have not been written out. Finalizes the last
|
||||
// cluster. May update the size and duration of the segment. May output the
|
||||
// Cues element. May finalize the SeekHead element. Returns true on success.
|
||||
bool Finalize();
|
||||
|
||||
// Returns the Cues object.
|
||||
Cues* GetCues() { return &cues_; }
|
||||
|
||||
// Returns the Segment Information object.
|
||||
SegmentInfo* GetSegmentInfo() { return &segment_info_; }
|
||||
|
||||
// Search the Tracks and return the track that matches |track_number|.
|
||||
// Returns NULL if there is no track match.
|
||||
Track* GetTrackByNumber(uint64 track_number) const;
|
||||
|
||||
// Toggles whether to output a cues element.
|
||||
void OutputCues(bool output_cues);
|
||||
|
||||
// Sets if the muxer will output files in chunks or not. |chunking| is a
|
||||
// flag telling whether or not to turn on chunking. |filename| is the base
|
||||
// filename for the chunk files. The header chunk file will be named
|
||||
// |filename|.hdr and the data chunks will be named
|
||||
// |filename|_XXXXXX.chk. Chunking implies that the muxer will be writing
|
||||
// to files so the muxer will use the default MkvWriter class to control
|
||||
// what data is written to what files. Returns true on success.
|
||||
// TODO: Should we change the IMkvWriter Interface to add Open and Close?
|
||||
// That will force the interface to be dependent on files.
|
||||
bool SetChunking(bool chunking, const char* filename);
|
||||
|
||||
bool chunking() const { return chunking_; }
|
||||
uint64 cues_track() const { return cues_track_; }
|
||||
void set_max_cluster_duration(uint64 max_cluster_duration) {
|
||||
max_cluster_duration_ = max_cluster_duration;
|
||||
}
|
||||
uint64 max_cluster_duration() const { return max_cluster_duration_; }
|
||||
void set_max_cluster_size(uint64 max_cluster_size) {
|
||||
max_cluster_size_ = max_cluster_size;
|
||||
}
|
||||
uint64 max_cluster_size() const { return max_cluster_size_; }
|
||||
void set_mode(Mode mode) { mode_ = mode; }
|
||||
Mode mode() const { return mode_; }
|
||||
bool output_cues() const { return output_cues_; }
|
||||
const SegmentInfo* segment_info() const { return &segment_info_; }
|
||||
|
||||
private:
|
||||
// Checks if header information has been output and initialized. If not it
|
||||
// will output the Segment element and initialize the SeekHead elment and
|
||||
// Cues elements.
|
||||
bool CheckHeaderInfo();
|
||||
|
||||
// Sets |name| according to how many chunks have been written. |ext| is the
|
||||
// file extension. |name| must be deleted by the calling app. Returns true
|
||||
// on success.
|
||||
bool UpdateChunkName(const char* ext, char** name) const;
|
||||
|
||||
// Returns the maximum offset within the segment's payload. When chunking
|
||||
// this function is needed to determine offsets of elements within the
|
||||
// chunked files. Returns -1 on error.
|
||||
int64 MaxOffset();
|
||||
|
||||
// Adds the frame to our frame array.
|
||||
bool QueueFrame(Frame* frame);
|
||||
|
||||
// Output all frames that are queued. Returns -1 on error, otherwise
|
||||
// it returns the number of frames written.
|
||||
int WriteFramesAll();
|
||||
|
||||
// Output all frames that are queued that have an end time that is less
|
||||
// then |timestamp|. Returns true on success and if there are no frames
|
||||
// queued.
|
||||
bool WriteFramesLessThan(uint64 timestamp);
|
||||
|
||||
// Outputs the segment header, Segment Information element, SeekHead element,
|
||||
// and Tracks element to |writer_|.
|
||||
bool WriteSegmentHeader();
|
||||
|
||||
// Given a frame with the specified timestamp (nanosecond units) and
|
||||
// keyframe status, determine whether a new cluster should be
|
||||
// created, before writing enqueued frames and the frame itself. The
|
||||
// function returns one of the following values:
|
||||
// -1 = error: an out-of-order frame was detected
|
||||
// 0 = do not create a new cluster, and write frame to the existing cluster
|
||||
// 1 = create a new cluster, and write frame to that new cluster
|
||||
// 2 = create a new cluster, and re-run test
|
||||
int TestFrame(uint64 track_num, uint64 timestamp_ns, bool key) const;
|
||||
|
||||
// Create a new cluster, using the earlier of the first enqueued
|
||||
// frame, or the indicated time. Returns true on success.
|
||||
bool MakeNewCluster(uint64 timestamp_ns);
|
||||
|
||||
// Checks whether a new cluster needs to be created, and if so
|
||||
// creates a new cluster. Returns false if creation of a new cluster
|
||||
// was necessary but creation was not successful.
|
||||
bool DoNewClusterProcessing(uint64 track_num, uint64 timestamp_ns, bool key);
|
||||
|
||||
// WebM elements
|
||||
Cues cues_;
|
||||
SeekHead seek_head_;
|
||||
SegmentInfo segment_info_;
|
||||
Tracks tracks_;
|
||||
|
||||
// Number of chunks written.
|
||||
int chunk_count_;
|
||||
|
||||
// Current chunk filename.
|
||||
char* chunk_name_;
|
||||
|
||||
// Default MkvWriter object created by this class used for writing clusters
|
||||
// out in separate files.
|
||||
MkvWriter* chunk_writer_cluster_;
|
||||
|
||||
// Default MkvWriter object created by this class used for writing Cues
|
||||
// element out to a file.
|
||||
MkvWriter* chunk_writer_cues_;
|
||||
|
||||
// Default MkvWriter object created by this class used for writing the
|
||||
// Matroska header out to a file.
|
||||
MkvWriter* chunk_writer_header_;
|
||||
|
||||
// Flag telling whether or not the muxer is chunking output to multiple
|
||||
// files.
|
||||
bool chunking_;
|
||||
|
||||
// Base filename for the chunked files.
|
||||
char* chunking_base_name_;
|
||||
|
||||
// List of clusters.
|
||||
Cluster** cluster_list_;
|
||||
|
||||
// Number of cluster pointers allocated in the cluster list.
|
||||
int32 cluster_list_capacity_;
|
||||
|
||||
// Number of clusters in the cluster list.
|
||||
int32 cluster_list_size_;
|
||||
|
||||
// Track number that is associated with the cues element for this segment.
|
||||
uint64 cues_track_;
|
||||
|
||||
// List of stored audio frames. These variables are used to store frames so
|
||||
// the muxer can follow the guideline "Audio blocks that contain the video
|
||||
// key frame's timecode should be in the same cluster as the video key frame
|
||||
// block."
|
||||
Frame** frames_;
|
||||
|
||||
// Number of frame pointers allocated in the frame list.
|
||||
int32 frames_capacity_;
|
||||
|
||||
// Number of frames in the frame list.
|
||||
int32 frames_size_;
|
||||
|
||||
// Flag telling if a video track has been added to the segment.
|
||||
bool has_video_;
|
||||
|
||||
// Flag telling if the segment's header has been written.
|
||||
bool header_written_;
|
||||
|
||||
// Last timestamp in nanoseconds added to a cluster.
|
||||
uint64 last_timestamp_;
|
||||
|
||||
// Maximum time in nanoseconds for a cluster duration. This variable is a
|
||||
// guideline and some clusters may have a longer duration. Default is 30
|
||||
// seconds.
|
||||
uint64 max_cluster_duration_;
|
||||
|
||||
// Maximum size in bytes for a cluster. This variable is a guideline and
|
||||
// some clusters may have a larger size. Default is 0 which signifies that
|
||||
// the muxer will decide the size.
|
||||
uint64 max_cluster_size_;
|
||||
|
||||
// The mode that segment is in. If set to |kLive| the writer must not
|
||||
// seek backwards.
|
||||
Mode mode_;
|
||||
|
||||
// Flag telling the muxer that a new cue point should be added.
|
||||
bool new_cuepoint_;
|
||||
|
||||
// TODO(fgalligan): Should we add support for more than one Cues element?
|
||||
// Flag whether or not the muxer should output a Cues element.
|
||||
bool output_cues_;
|
||||
|
||||
// The file position of the segment's payload.
|
||||
int64 payload_pos_;
|
||||
|
||||
// The file position of the element's size.
|
||||
int64 size_position_;
|
||||
|
||||
// Pointer to the writer objects. Not owned by this class.
|
||||
IMkvWriter* writer_cluster_;
|
||||
IMkvWriter* writer_cues_;
|
||||
IMkvWriter* writer_header_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Segment);
|
||||
};
|
||||
|
||||
} //end namespace mkvmuxer
|
||||
|
||||
#endif //MKVMUXER_HPP
|
||||
30
mkvmuxertypes.hpp
Normal file
30
mkvmuxertypes.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef MKVMUXERTYPES_HPP
|
||||
#define MKVMUXERTYPES_HPP
|
||||
|
||||
// Copied from Chromium basictypes.h
|
||||
// A macro to disallow the copy constructor and operator= functions
|
||||
// This should be used in the private: declarations for a class
|
||||
#define LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef short int16;
|
||||
typedef int int32;
|
||||
typedef unsigned int uint32;
|
||||
typedef long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
|
||||
} //end namespace mkvmuxer
|
||||
|
||||
#endif // MKVMUXERTYPES_HPP
|
||||
504
mkvmuxerutil.cpp
Normal file
504
mkvmuxerutil.cpp
Normal file
@@ -0,0 +1,504 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include "mkvmuxerutil.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include <limits>
|
||||
#include <new>
|
||||
|
||||
#include "mkvwriter.hpp"
|
||||
#include "webmids.hpp"
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
int32 GetCodedUIntSize(uint64 value) {
|
||||
if (value < 0x000000000000007FULL)
|
||||
return 1;
|
||||
else if (value < 0x0000000000003FFFULL)
|
||||
return 2;
|
||||
else if (value < 0x00000000001FFFFFULL)
|
||||
return 3;
|
||||
else if (value < 0x000000000FFFFFFFULL)
|
||||
return 4;
|
||||
else if (value < 0x00000007FFFFFFFFULL)
|
||||
return 5;
|
||||
else if (value < 0x000003FFFFFFFFFFULL)
|
||||
return 6;
|
||||
else if (value < 0x0001FFFFFFFFFFFFULL)
|
||||
return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
int32 GetUIntSize(uint64 value) {
|
||||
if (value < 0x0000000000000100ULL)
|
||||
return 1;
|
||||
else if (value < 0x0000000000010000ULL)
|
||||
return 2;
|
||||
else if (value < 0x0000000001000000ULL)
|
||||
return 3;
|
||||
else if (value < 0x0000000100000000ULL)
|
||||
return 4;
|
||||
else if (value < 0x0000010000000000ULL)
|
||||
return 5;
|
||||
else if (value < 0x0001000000000000ULL)
|
||||
return 6;
|
||||
else if (value < 0x0100000000000000ULL)
|
||||
return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
uint64 EbmlMasterElementSize(uint64 type, uint64 value) {
|
||||
// Size of EBML ID
|
||||
int32 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += GetCodedUIntSize(value);
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, uint64 value) {
|
||||
// Size of EBML ID
|
||||
int32 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += GetUIntSize(value);
|
||||
|
||||
// Size of Datasize
|
||||
ebml_size++;
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, float value) {
|
||||
// Size of EBML ID
|
||||
uint64 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += sizeof(value);
|
||||
|
||||
// Size of Datasize
|
||||
ebml_size++;
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, const char* value) {
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
// Size of EBML ID
|
||||
uint64 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += strlen(value);
|
||||
|
||||
// Size of Datasize
|
||||
ebml_size++;
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size) {
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
// Size of EBML ID
|
||||
uint64 ebml_size = GetUIntSize(type);
|
||||
|
||||
// Datasize
|
||||
ebml_size += size;
|
||||
|
||||
// Size of Datasize
|
||||
ebml_size += GetCodedUIntSize(size);
|
||||
|
||||
return ebml_size;
|
||||
}
|
||||
|
||||
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size) {
|
||||
if (!writer || size < 1 || size > 8)
|
||||
return -1;
|
||||
|
||||
for (int32 i = 1; i <= size; ++i) {
|
||||
const int32 byte_count = size - i;
|
||||
const int32 bit_count = byte_count * 8;
|
||||
|
||||
const int64 bb = value >> bit_count;
|
||||
const uint8 b = static_cast<uint8>(bb);
|
||||
|
||||
const int32 status = writer->Write(&b, 1);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 SerializeFloat(IMkvWriter* writer, float f) {
|
||||
if (!writer)
|
||||
return -1;
|
||||
|
||||
const uint32& val = reinterpret_cast<const uint32&>(f);
|
||||
|
||||
for (int32 i = 1; i <= 4; ++i) {
|
||||
const int32 byte_count = 4 - i;
|
||||
const int32 bit_count = byte_count * 8;
|
||||
|
||||
const uint32 bb = val >> bit_count;
|
||||
const uint8 b = static_cast<uint8>(bb);
|
||||
|
||||
const int32 status = writer->Write(&b, 1);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 WriteUInt(IMkvWriter* writer, uint64 value) {
|
||||
if (!writer)
|
||||
return -1;
|
||||
|
||||
int32 size = GetCodedUIntSize(value);
|
||||
|
||||
return WriteUIntSize(writer, value, size);
|
||||
}
|
||||
|
||||
int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size) {
|
||||
if (!writer || size < 0 || size > 8)
|
||||
return -1;
|
||||
|
||||
if (size > 0) {
|
||||
const uint64 bit = 1LL << (size * 7);
|
||||
|
||||
if (value > (bit - 2))
|
||||
return -1;
|
||||
|
||||
value |= bit;
|
||||
} else {
|
||||
size = 1;
|
||||
int64 bit;
|
||||
|
||||
for (;;) {
|
||||
bit = 1LL << (size * 7);
|
||||
const uint64 max = bit - 2;
|
||||
|
||||
if (value <= max)
|
||||
break;
|
||||
|
||||
++size;
|
||||
}
|
||||
|
||||
if (size > 8)
|
||||
return false;
|
||||
|
||||
value |= bit;
|
||||
}
|
||||
|
||||
return SerializeInt(writer, value, size);
|
||||
}
|
||||
|
||||
int32 WriteID(IMkvWriter* writer, uint64 type) {
|
||||
if (!writer)
|
||||
return -1;
|
||||
|
||||
writer->ElementStartNotify(type, writer->Position());
|
||||
|
||||
const int32 size = GetUIntSize(type);
|
||||
|
||||
return SerializeInt(writer, type, size);
|
||||
}
|
||||
|
||||
bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 type, uint64 size) {
|
||||
if (!writer)
|
||||
return false;
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
if (WriteUInt(writer, size))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value) {
|
||||
if (!writer)
|
||||
return false;
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
const uint64 size = GetUIntSize(value);
|
||||
if (WriteUInt(writer, size))
|
||||
return false;
|
||||
|
||||
if (SerializeInt(writer, value, static_cast<int32>(size)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value) {
|
||||
if (!writer)
|
||||
return false;
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
if (WriteUInt(writer, 4))
|
||||
return false;
|
||||
|
||||
if (SerializeFloat(writer, value))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value) {
|
||||
if (!writer || !value)
|
||||
return false;
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
const int32 length = strlen(value);
|
||||
if (WriteUInt(writer, length))
|
||||
return false;
|
||||
|
||||
if (writer->Write(value, length))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEbmlElement(IMkvWriter* writer,
|
||||
uint64 type,
|
||||
const uint8* value,
|
||||
uint64 size) {
|
||||
if (!writer || !value || size < 1)
|
||||
return false;
|
||||
|
||||
if (WriteID(writer, type))
|
||||
return false;
|
||||
|
||||
if (WriteUInt(writer, size))
|
||||
return false;
|
||||
|
||||
if (writer->Write(value, static_cast<uint32>(size)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64 WriteSimpleBlock(IMkvWriter* writer,
|
||||
const uint8* data,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
int64 timecode,
|
||||
uint64 is_key) {
|
||||
if (!writer)
|
||||
return false;
|
||||
|
||||
if (!data || length < 1)
|
||||
return false;
|
||||
|
||||
// Here we only permit track number values to be no greater than
|
||||
// 126, which the largest value we can store having a Matroska
|
||||
// integer representation of only 1 byte.
|
||||
|
||||
if (track_number < 1 || track_number > 126)
|
||||
return false;
|
||||
|
||||
// Technically the timestamp for a block can be less than the
|
||||
// timestamp for the cluster itself (remember that block timestamp
|
||||
// is a signed, 16-bit integer). However, as a simplification we
|
||||
// only permit non-negative cluster-relative timestamps for blocks.
|
||||
|
||||
if (timecode < 0 || timecode > std::numeric_limits<int16>::max())
|
||||
return false;
|
||||
|
||||
if (WriteID(writer, kMkvSimpleBlock))
|
||||
return 0;
|
||||
|
||||
const int32 size = static_cast<int32>(length) + 4;
|
||||
if (WriteUInt(writer, size))
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, static_cast<uint64>(track_number)))
|
||||
return 0;
|
||||
|
||||
if (SerializeInt(writer, timecode, 2))
|
||||
return 0;
|
||||
|
||||
uint64 flags = 0;
|
||||
if (is_key)
|
||||
flags |= 0x80;
|
||||
|
||||
if (SerializeInt(writer, flags, 1))
|
||||
return 0;
|
||||
|
||||
if (writer->Write(data, static_cast<uint32>(length)))
|
||||
return 0;
|
||||
|
||||
const uint64 element_size =
|
||||
GetUIntSize(kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 + length;
|
||||
|
||||
return element_size;
|
||||
}
|
||||
|
||||
// We must write the metadata (key)frame as a BlockGroup element,
|
||||
// because we need to specify a duration for the frame. The
|
||||
// BlockGroup element comprises the frame itself and its duration,
|
||||
// and is laid out as follows:
|
||||
//
|
||||
// BlockGroup tag
|
||||
// BlockGroup size
|
||||
// Block tag
|
||||
// Block size
|
||||
// (the frame is the block payload)
|
||||
// Duration tag
|
||||
// Duration size
|
||||
// (duration payload)
|
||||
//
|
||||
uint64 WriteMetadataBlock(IMkvWriter* writer,
|
||||
const uint8* data,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
int64 timecode,
|
||||
uint64 duration) {
|
||||
// We don't backtrack when writing to the stream, so we must
|
||||
// pre-compute the BlockGroup size, by summing the sizes of each
|
||||
// sub-element (the block and the duration).
|
||||
|
||||
// We use a single byte for the track number of the block, which
|
||||
// means the block header is exactly 4 bytes.
|
||||
|
||||
// TODO(matthewjheaney): use EbmlMasterElementSize and WriteEbmlMasterElement
|
||||
|
||||
const uint64 block_payload_size = 4 + length;
|
||||
const int32 block_size = GetCodedUIntSize(block_payload_size);
|
||||
const uint64 block_elem_size = 1 + block_size + block_payload_size;
|
||||
|
||||
const int32 duration_payload_size = GetUIntSize(duration);
|
||||
const int32 duration_size = GetCodedUIntSize(duration_payload_size);
|
||||
const uint64 duration_elem_size = 1 + duration_size + duration_payload_size;
|
||||
|
||||
const uint64 blockg_payload_size = block_elem_size + duration_elem_size;
|
||||
const int32 blockg_size = GetCodedUIntSize(blockg_payload_size);
|
||||
const uint64 blockg_elem_size = 1 + blockg_size + blockg_payload_size;
|
||||
|
||||
if (WriteID(writer, kMkvBlockGroup)) // 1-byte ID size
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, blockg_payload_size))
|
||||
return 0;
|
||||
|
||||
// Write Block element
|
||||
|
||||
if (WriteID(writer, kMkvBlock)) // 1-byte ID size
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, block_payload_size))
|
||||
return 0;
|
||||
|
||||
// Byte 1 of 4
|
||||
|
||||
if (WriteUInt(writer, track_number))
|
||||
return 0;
|
||||
|
||||
// Bytes 2 & 3 of 4
|
||||
|
||||
if (SerializeInt(writer, timecode, 2))
|
||||
return 0;
|
||||
|
||||
// Byte 4 of 4
|
||||
|
||||
const uint64 flags = 0;
|
||||
|
||||
if (SerializeInt(writer, flags, 1))
|
||||
return 0;
|
||||
|
||||
// Now write the actual frame (of metadata)
|
||||
|
||||
if (writer->Write(data, static_cast<uint32>(length)))
|
||||
return 0;
|
||||
|
||||
// Write Duration element
|
||||
|
||||
if (WriteID(writer, kMkvBlockDuration)) // 1-byte ID size
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, duration_payload_size))
|
||||
return 0;
|
||||
|
||||
if (SerializeInt(writer, duration, duration_payload_size))
|
||||
return 0;
|
||||
|
||||
// Note that we don't write a reference time as part of the block
|
||||
// group; no reference time(s) indicates that this block is a
|
||||
// keyframe. (Unlike the case for a SimpleBlock element, the header
|
||||
// bits of the Block sub-element of a BlockGroup element do not
|
||||
// indicate keyframe status. The keyframe status is inferred from
|
||||
// the absence of reference time sub-elements.)
|
||||
|
||||
return blockg_elem_size;
|
||||
}
|
||||
|
||||
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size) {
|
||||
if (!writer)
|
||||
return false;
|
||||
|
||||
// Subtract one for the void ID and the coded size.
|
||||
uint64 void_entry_size = size - 1 - GetCodedUIntSize(size-1);
|
||||
uint64 void_size = EbmlMasterElementSize(kMkvVoid, void_entry_size) +
|
||||
void_entry_size;
|
||||
|
||||
if (void_size != size)
|
||||
return 0;
|
||||
|
||||
const int64 payload_position = writer->Position();
|
||||
if (payload_position < 0)
|
||||
return 0;
|
||||
|
||||
if (WriteID(writer, kMkvVoid))
|
||||
return 0;
|
||||
|
||||
if (WriteUInt(writer, void_entry_size))
|
||||
return 0;
|
||||
|
||||
const uint8 value = 0;
|
||||
for (int32 i = 0; i < static_cast<int32>(void_entry_size); ++i) {
|
||||
if (writer->Write(&value, 1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int64 stop_position = writer->Position();
|
||||
if (stop_position < 0 ||
|
||||
stop_position - payload_position != static_cast<int64>(void_size))
|
||||
return 0;
|
||||
|
||||
return void_size;
|
||||
}
|
||||
|
||||
void GetVersion(int32* major, int32* minor, int32* build, int32* revision) {
|
||||
*major = 0;
|
||||
*minor = 2;
|
||||
*build = 0;
|
||||
*revision = 0;
|
||||
}
|
||||
|
||||
} // namespace mkvmuxer
|
||||
101
mkvmuxerutil.hpp
Normal file
101
mkvmuxerutil.hpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef MKVMUXERUTIL_HPP
|
||||
#define MKVMUXERUTIL_HPP
|
||||
|
||||
#include "mkvmuxertypes.hpp"
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
class IMkvWriter;
|
||||
|
||||
const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
|
||||
|
||||
// Writes out |value| in Big Endian order. Returns 0 on success.
|
||||
int32 SerializeInt(IMkvWriter* writer, int64 value, int32 size);
|
||||
|
||||
// Returns the size in bytes of the element.
|
||||
uint64 EbmlMasterElementSize(uint64 type, uint64 value);
|
||||
uint64 EbmlElementSize(uint64 type, uint64 value);
|
||||
uint64 EbmlElementSize(uint64 type, float value);
|
||||
uint64 EbmlElementSize(uint64 type, const char* value);
|
||||
uint64 EbmlElementSize(uint64 type, const uint8* value, uint64 size);
|
||||
|
||||
// Creates an EBML coded number from |value| and writes it out. The size of
|
||||
// the coded number is determined by the value of |value|. |value| must not
|
||||
// be in a coded form. Returns 0 on success.
|
||||
int32 WriteUInt(IMkvWriter* writer, uint64 value);
|
||||
|
||||
// Creates an EBML coded number from |value| and writes it out. The size of
|
||||
// the coded number is determined by the value of |size|. |value| must not
|
||||
// be in a coded form. Returns 0 on success.
|
||||
int32 WriteUIntSize(IMkvWriter* writer, uint64 value, int32 size);
|
||||
|
||||
// Output an Mkv master element. Returns true if the element was written.
|
||||
bool WriteEbmlMasterElement(IMkvWriter* writer, uint64 value, uint64 size);
|
||||
|
||||
// Outputs an Mkv ID, calls |IMkvWriter::ElementStartNotify|, and passes the
|
||||
// ID to |SerializeInt|. Returns 0 on success.
|
||||
int32 WriteID(IMkvWriter* writer, uint64 type);
|
||||
|
||||
// Output an Mkv non-master element. Returns true if the element was written.
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, float value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, const char* value);
|
||||
bool WriteEbmlElement(IMkvWriter* writer,
|
||||
uint64 type,
|
||||
const uint8* value,
|
||||
uint64 size);
|
||||
|
||||
// Output an Mkv Simple Block.
|
||||
// Inputs:
|
||||
// data: Pointer to the data.
|
||||
// length: Length of the data.
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions. Only values in the range [1, 126] are
|
||||
// permitted.
|
||||
// timecode: Relative timecode of the Block. Only values in the
|
||||
// range [0, 2^15) are permitted.
|
||||
// is_key: Non-zero value specifies that frame is a key frame.
|
||||
uint64 WriteSimpleBlock(IMkvWriter* writer,
|
||||
const uint8* data,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
int64 timecode,
|
||||
uint64 is_key);
|
||||
|
||||
// Output a metadata keyframe, using a Block Group element.
|
||||
// Inputs:
|
||||
// data: Pointer to the (meta)data.
|
||||
// length: Length of the (meta)data.
|
||||
// track_number: Track to add the data to. Value returned by Add track
|
||||
// functions. Only values in the range [1, 126] are
|
||||
// permitted.
|
||||
// timecode Timecode of frame, relative to cluster timecode. Only
|
||||
// values in the range [0, 2^15) are permitted.
|
||||
// duration_timecode Duration of frame, using timecode units.
|
||||
uint64 WriteMetadataBlock(IMkvWriter* writer,
|
||||
const uint8* data,
|
||||
uint64 length,
|
||||
uint64 track_number,
|
||||
int64 timecode,
|
||||
uint64 duration_timecode);
|
||||
|
||||
// Output a void element. |size| must be the entire size in bytes that will be
|
||||
// void. The function will calculate the size of the void header and subtract
|
||||
// it from |size|.
|
||||
uint64 WriteVoidElement(IMkvWriter* writer, uint64 size);
|
||||
|
||||
// Returns the version number of the muxer in |major|, |minor|, |build|,
|
||||
// and |revision|.
|
||||
void GetVersion(int32* major, int32* minor, int32* build, int32* revision);
|
||||
|
||||
} //end namespace mkvmuxer
|
||||
|
||||
#endif // MKVMUXERUTIL_HPP
|
||||
4427
mkvparser.cpp
4427
mkvparser.cpp
File diff suppressed because it is too large
Load Diff
386
mkvparser.hpp
386
mkvparser.hpp
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstddef>
|
||||
|
||||
namespace mkvparser
|
||||
{
|
||||
@@ -29,17 +30,26 @@ protected:
|
||||
|
||||
long long GetUIntLength(IMkvReader*, long long, long&);
|
||||
long long ReadUInt(IMkvReader*, long long, long&);
|
||||
long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&);
|
||||
long long UnserializeUInt(IMkvReader*, long long pos, long long size);
|
||||
float Unserialize4Float(IMkvReader*, long long);
|
||||
double Unserialize8Double(IMkvReader*, long long);
|
||||
short Unserialize2SInt(IMkvReader*, long long);
|
||||
signed char Unserialize1SInt(IMkvReader*, long long);
|
||||
|
||||
long UnserializeFloat(IMkvReader*, long long pos, long long size, double&);
|
||||
long UnserializeInt(IMkvReader*, long long pos, long len, long long& result);
|
||||
|
||||
long UnserializeString(
|
||||
IMkvReader*,
|
||||
long long pos,
|
||||
long long size,
|
||||
char*& str);
|
||||
|
||||
long ParseElementHeader(
|
||||
IMkvReader* pReader,
|
||||
long long& pos, //consume id and size fields
|
||||
long long stop, //if you know size of element's parent
|
||||
long long& id,
|
||||
long long& size);
|
||||
|
||||
bool Match(IMkvReader*, long long&, unsigned long, long long&);
|
||||
bool Match(IMkvReader*, long long&, unsigned long, char*&);
|
||||
bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&);
|
||||
bool Match(IMkvReader*, long long&, unsigned long, double&);
|
||||
bool Match(IMkvReader*, long long&, unsigned long, short&);
|
||||
|
||||
void GetVersion(int& major, int& minor, int& build, int& revision);
|
||||
|
||||
@@ -73,9 +83,11 @@ public:
|
||||
const long long m_start;
|
||||
const long long m_size;
|
||||
|
||||
Block(long long start, long long size, IMkvReader*);
|
||||
Block(long long start, long long size);
|
||||
~Block();
|
||||
|
||||
long Parse(const Cluster*);
|
||||
|
||||
long long GetTrackNumber() const;
|
||||
long long GetTimeCode(const Cluster*) const; //absolute, but not scaled
|
||||
long long GetTime(const Cluster*) const; //absolute, and scaled (ns)
|
||||
@@ -83,6 +95,9 @@ public:
|
||||
void SetKey(bool);
|
||||
bool IsInvisible() const;
|
||||
|
||||
enum Lacing { kLacingNone, kLacingXiph, kLacingFixed, kLacingEbml };
|
||||
Lacing GetLacing() const;
|
||||
|
||||
int GetFrameCount() const; //to index frames: [0, count)
|
||||
|
||||
struct Frame
|
||||
@@ -111,16 +126,23 @@ class BlockEntry
|
||||
BlockEntry(const BlockEntry&);
|
||||
BlockEntry& operator=(const BlockEntry&);
|
||||
|
||||
protected:
|
||||
BlockEntry(Cluster*, long index);
|
||||
|
||||
public:
|
||||
virtual ~BlockEntry();
|
||||
virtual bool EOS() const = 0;
|
||||
virtual const Cluster* GetCluster() const = 0;
|
||||
virtual size_t GetIndex() const = 0;
|
||||
|
||||
bool EOS() const;
|
||||
const Cluster* GetCluster() const;
|
||||
long GetIndex() const;
|
||||
virtual const Block* GetBlock() const = 0;
|
||||
//virtual bool IsBFrame() const = 0;
|
||||
|
||||
enum Kind { kBlockEOS, kBlockSimple, kBlockGroup };
|
||||
virtual Kind GetKind() const = 0;
|
||||
|
||||
protected:
|
||||
BlockEntry();
|
||||
Cluster* const m_pCluster;
|
||||
const long m_index;
|
||||
|
||||
};
|
||||
|
||||
@@ -131,17 +153,13 @@ class SimpleBlock : public BlockEntry
|
||||
SimpleBlock& operator=(const SimpleBlock&);
|
||||
|
||||
public:
|
||||
SimpleBlock(Cluster*, size_t, long long start, long long size);
|
||||
SimpleBlock(Cluster*, long index, long long start, long long size);
|
||||
long Parse();
|
||||
|
||||
bool EOS() const;
|
||||
const Cluster* GetCluster() const;
|
||||
size_t GetIndex() const;
|
||||
Kind GetKind() const;
|
||||
const Block* GetBlock() const;
|
||||
//bool IsBFrame() const;
|
||||
|
||||
protected:
|
||||
Cluster* const m_pCluster;
|
||||
const size_t m_index;
|
||||
Block m_block;
|
||||
|
||||
};
|
||||
@@ -153,41 +171,143 @@ class BlockGroup : public BlockEntry
|
||||
BlockGroup& operator=(const BlockGroup&);
|
||||
|
||||
public:
|
||||
BlockGroup(Cluster*, size_t, long long, long long);
|
||||
~BlockGroup();
|
||||
BlockGroup(
|
||||
Cluster*,
|
||||
long index,
|
||||
long long block_start, //absolute pos of block's payload
|
||||
long long block_size, //size of block's payload
|
||||
long long prev,
|
||||
long long next,
|
||||
long long duration);
|
||||
|
||||
bool EOS() const;
|
||||
const Cluster* GetCluster() const;
|
||||
size_t GetIndex() const;
|
||||
long Parse();
|
||||
|
||||
Kind GetKind() const;
|
||||
const Block* GetBlock() const;
|
||||
//bool IsBFrame() const;
|
||||
|
||||
short GetPrevTimeCode() const; //relative to block's time
|
||||
short GetNextTimeCode() const; //as above
|
||||
|
||||
protected:
|
||||
Cluster* const m_pCluster;
|
||||
const size_t m_index;
|
||||
long long GetPrevTimeCode() const; //relative to block's time
|
||||
long long GetNextTimeCode() const; //as above
|
||||
long long GetDurationTimeCode() const;
|
||||
|
||||
private:
|
||||
BlockGroup(Cluster*, size_t, unsigned long);
|
||||
void ParseBlock(long long start, long long size);
|
||||
|
||||
short m_prevTimeCode;
|
||||
short m_nextTimeCode;
|
||||
|
||||
//TODO: the Matroska spec says you can have multiple blocks within the
|
||||
//same block group, with blocks ranked by priority (the flag bits).
|
||||
//For now we just cache a single block.
|
||||
#if 0
|
||||
typedef std::deque<Block*> blocks_t;
|
||||
blocks_t m_blocks; //In practice should contain only a single element.
|
||||
#else
|
||||
Block* m_pBlock;
|
||||
#endif
|
||||
Block m_block;
|
||||
const long long m_prev;
|
||||
const long long m_next;
|
||||
const long long m_duration;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// ContentEncoding element
|
||||
// Elements used to describe if the track data has been encrypted or
|
||||
// compressed with zlib or header stripping.
|
||||
class ContentEncoding {
|
||||
public:
|
||||
enum {
|
||||
kCTR = 1
|
||||
};
|
||||
|
||||
ContentEncoding();
|
||||
~ContentEncoding();
|
||||
|
||||
// ContentCompression element names
|
||||
struct ContentCompression {
|
||||
ContentCompression();
|
||||
~ContentCompression();
|
||||
|
||||
unsigned long long algo;
|
||||
unsigned char* settings;
|
||||
};
|
||||
|
||||
// ContentEncAESSettings element names
|
||||
struct ContentEncAESSettings {
|
||||
ContentEncAESSettings() : cipher_mode(kCTR) {}
|
||||
~ContentEncAESSettings() {}
|
||||
|
||||
unsigned long long cipher_mode;
|
||||
};
|
||||
|
||||
// ContentEncryption element names
|
||||
struct ContentEncryption {
|
||||
ContentEncryption();
|
||||
~ContentEncryption();
|
||||
|
||||
unsigned long long algo;
|
||||
unsigned char* key_id;
|
||||
long long key_id_len;
|
||||
unsigned char* signature;
|
||||
long long signature_len;
|
||||
unsigned char* sig_key_id;
|
||||
long long sig_key_id_len;
|
||||
unsigned long long sig_algo;
|
||||
unsigned long long sig_hash_algo;
|
||||
|
||||
ContentEncAESSettings aes_settings;
|
||||
};
|
||||
|
||||
// Returns ContentCompression represented by |idx|. Returns NULL if |idx|
|
||||
// is out of bounds.
|
||||
const ContentCompression* GetCompressionByIndex(unsigned long idx) const;
|
||||
|
||||
// Returns number of ContentCompression elements in this ContentEncoding
|
||||
// element.
|
||||
unsigned long GetCompressionCount() const;
|
||||
|
||||
// Returns ContentEncryption represented by |idx|. Returns NULL if |idx|
|
||||
// is out of bounds.
|
||||
const ContentEncryption* GetEncryptionByIndex(unsigned long idx) const;
|
||||
|
||||
// Returns number of ContentEncryption elements in this ContentEncoding
|
||||
// element.
|
||||
unsigned long GetEncryptionCount() const;
|
||||
|
||||
// Parses the ContentEncAESSettings element from |pReader|. |start| is the
|
||||
// starting offset of the ContentEncAESSettings payload. |size| is the
|
||||
// size in bytes of the ContentEncAESSettings payload. |encryption| is
|
||||
// where the parsed values will be stored.
|
||||
long ParseContentEncAESSettingsEntry(long long start,
|
||||
long long size,
|
||||
IMkvReader* pReader,
|
||||
ContentEncAESSettings* aes);
|
||||
|
||||
// Parses the ContentEncoding element from |pReader|. |start| is the
|
||||
// starting offset of the ContentEncoding payload. |size| is the size in
|
||||
// bytes of the ContentEncoding payload. Returns true on success.
|
||||
long ParseContentEncodingEntry(long long start,
|
||||
long long size,
|
||||
IMkvReader* pReader);
|
||||
|
||||
// Parses the ContentEncryption element from |pReader|. |start| is the
|
||||
// starting offset of the ContentEncryption payload. |size| is the size in
|
||||
// bytes of the ContentEncryption payload. |encryption| is where the parsed
|
||||
// values will be stored.
|
||||
long ParseEncryptionEntry(long long start,
|
||||
long long size,
|
||||
IMkvReader* pReader,
|
||||
ContentEncryption* encryption);
|
||||
|
||||
unsigned long long encoding_order() const { return encoding_order_; }
|
||||
unsigned long long encoding_scope() const { return encoding_scope_; }
|
||||
unsigned long long encoding_type() const { return encoding_type_; }
|
||||
|
||||
private:
|
||||
// Member variables for list of ContentCompression elements.
|
||||
ContentCompression** compression_entries_;
|
||||
ContentCompression** compression_entries_end_;
|
||||
|
||||
// Member variables for list of ContentEncryption elements.
|
||||
ContentEncryption** encryption_entries_;
|
||||
ContentEncryption** encryption_entries_end_;
|
||||
|
||||
// ContentEncoding element names
|
||||
unsigned long long encoding_order_;
|
||||
unsigned long long encoding_scope_;
|
||||
unsigned long long encoding_type_;
|
||||
|
||||
// LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding);
|
||||
ContentEncoding(const ContentEncoding&);
|
||||
ContentEncoding& operator=(const ContentEncoding&);
|
||||
};
|
||||
|
||||
class Track
|
||||
{
|
||||
@@ -195,13 +315,23 @@ class Track
|
||||
Track& operator=(const Track&);
|
||||
|
||||
public:
|
||||
class Info;
|
||||
static long Create(
|
||||
Segment*,
|
||||
const Info&,
|
||||
long long element_start,
|
||||
long long element_size,
|
||||
Track*&);
|
||||
|
||||
enum Type { kVideo = 1, kAudio = 2 };
|
||||
|
||||
Segment* const m_pSegment;
|
||||
const long long m_element_start;
|
||||
const long long m_element_size;
|
||||
virtual ~Track();
|
||||
|
||||
long long GetType() const;
|
||||
long long GetNumber() const;
|
||||
long GetType() const;
|
||||
long GetNumber() const;
|
||||
unsigned long long GetUid() const;
|
||||
const char* GetNameAsUTF8() const;
|
||||
const char* GetCodecNameAsUTF8() const;
|
||||
@@ -217,50 +347,63 @@ public:
|
||||
long long size;
|
||||
};
|
||||
|
||||
struct Info
|
||||
class Info
|
||||
{
|
||||
long long type;
|
||||
long long number;
|
||||
public:
|
||||
Info();
|
||||
~Info();
|
||||
int Copy(Info&) const;
|
||||
void Clear();
|
||||
private:
|
||||
Info(const Info&);
|
||||
Info& operator=(const Info&);
|
||||
public:
|
||||
long type;
|
||||
long number;
|
||||
unsigned long long uid;
|
||||
char* nameAsUTF8;
|
||||
char* codecId;
|
||||
char* codecNameAsUTF8;
|
||||
unsigned char* codecPrivate;
|
||||
size_t codecPrivateSize;
|
||||
char* codecNameAsUTF8;
|
||||
bool lacing;
|
||||
Settings settings;
|
||||
|
||||
Info();
|
||||
void Clear();
|
||||
private:
|
||||
int CopyStr(char* Info::*str, Info&) const;
|
||||
};
|
||||
|
||||
long GetFirst(const BlockEntry*&) const;
|
||||
long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
|
||||
virtual bool VetEntry(const BlockEntry*) const = 0;
|
||||
virtual long Seek(long long time_ns, const BlockEntry*&) const = 0;
|
||||
virtual bool VetEntry(const BlockEntry*) const;
|
||||
virtual long Seek(long long time_ns, const BlockEntry*&) const;
|
||||
|
||||
const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const;
|
||||
unsigned long GetContentEncodingCount() const;
|
||||
|
||||
long ParseContentEncodingsEntry(long long start, long long size);
|
||||
|
||||
protected:
|
||||
Track(
|
||||
Segment*,
|
||||
const Info&,
|
||||
long long element_start,
|
||||
long long element_size);
|
||||
const Info m_info;
|
||||
|
||||
Info m_info;
|
||||
|
||||
class EOSBlock : public BlockEntry
|
||||
{
|
||||
public:
|
||||
EOSBlock();
|
||||
|
||||
bool EOS() const;
|
||||
const Cluster* GetCluster() const;
|
||||
size_t GetIndex() const;
|
||||
Kind GetKind() const;
|
||||
const Block* GetBlock() const;
|
||||
bool IsBFrame() const;
|
||||
};
|
||||
|
||||
EOSBlock m_eos;
|
||||
|
||||
private:
|
||||
ContentEncoding** content_encoding_entries_;
|
||||
ContentEncoding** content_encoding_entries_end_;
|
||||
};
|
||||
|
||||
|
||||
@@ -269,12 +412,19 @@ class VideoTrack : public Track
|
||||
VideoTrack(const VideoTrack&);
|
||||
VideoTrack& operator=(const VideoTrack&);
|
||||
|
||||
public:
|
||||
VideoTrack(
|
||||
Segment*,
|
||||
long long element_start,
|
||||
long long element_size);
|
||||
|
||||
public:
|
||||
static long Parse(
|
||||
Segment*,
|
||||
const Info&,
|
||||
long long element_start,
|
||||
long long element_size);
|
||||
long long element_size,
|
||||
VideoTrack*&);
|
||||
|
||||
long long GetWidth() const;
|
||||
long long GetHeight() const;
|
||||
double GetFrameRate() const;
|
||||
@@ -295,16 +445,21 @@ class AudioTrack : public Track
|
||||
AudioTrack(const AudioTrack&);
|
||||
AudioTrack& operator=(const AudioTrack&);
|
||||
|
||||
public:
|
||||
AudioTrack(
|
||||
Segment*,
|
||||
long long element_start,
|
||||
long long element_size);
|
||||
public:
|
||||
static long Parse(
|
||||
Segment*,
|
||||
const Info&,
|
||||
long long element_start,
|
||||
long long element_size);
|
||||
long long element_size,
|
||||
AudioTrack*&);
|
||||
|
||||
double GetSamplingRate() const;
|
||||
long long GetChannels() const;
|
||||
long long GetBitDepth() const;
|
||||
bool VetEntry(const BlockEntry*) const;
|
||||
long Seek(long long time_ns, const BlockEntry*&) const;
|
||||
|
||||
private:
|
||||
@@ -332,24 +487,27 @@ public:
|
||||
long long size,
|
||||
long long element_start,
|
||||
long long element_size);
|
||||
virtual ~Tracks();
|
||||
|
||||
const Track* GetTrackByNumber(unsigned long tn) const;
|
||||
~Tracks();
|
||||
|
||||
long Parse();
|
||||
|
||||
unsigned long GetTracksCount() const;
|
||||
|
||||
const Track* GetTrackByNumber(long tn) const;
|
||||
const Track* GetTrackByIndex(unsigned long idx) const;
|
||||
|
||||
private:
|
||||
Track** m_trackEntries;
|
||||
Track** m_trackEntriesEnd;
|
||||
|
||||
void ParseTrackEntry(
|
||||
long long,
|
||||
long long,
|
||||
Track*&,
|
||||
long ParseTrackEntry(
|
||||
long long payload_start,
|
||||
long long payload_size,
|
||||
long long element_start,
|
||||
long long element_size);
|
||||
long long element_size,
|
||||
Track*&) const;
|
||||
|
||||
public:
|
||||
unsigned long GetTracksCount() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -374,6 +532,8 @@ public:
|
||||
|
||||
~SegmentInfo();
|
||||
|
||||
long Parse();
|
||||
|
||||
long long GetTimeCodeScale() const;
|
||||
long long GetDuration() const; //scaled
|
||||
const char* GetMuxingAppAsUTF8() const;
|
||||
@@ -410,24 +570,48 @@ public:
|
||||
|
||||
~SeekHead();
|
||||
|
||||
long Parse();
|
||||
|
||||
struct Entry
|
||||
{
|
||||
//the SeekHead entry payload
|
||||
long long id;
|
||||
long long pos;
|
||||
|
||||
//absolute pos of SeekEntry ID
|
||||
long long element_start;
|
||||
|
||||
//SeekEntry ID size + size size + payload
|
||||
long long element_size;
|
||||
};
|
||||
|
||||
int GetCount() const;
|
||||
const Entry* GetEntry(int idx) const;
|
||||
|
||||
struct VoidElement
|
||||
{
|
||||
//absolute pos of Void ID
|
||||
long long element_start;
|
||||
|
||||
//ID size + size size + payload size
|
||||
long long element_size;
|
||||
};
|
||||
|
||||
int GetVoidElementCount() const;
|
||||
const VoidElement* GetVoidElement(int idx) const;
|
||||
|
||||
private:
|
||||
Entry* m_entries;
|
||||
int m_count;
|
||||
int m_entry_count;
|
||||
|
||||
static void ParseEntry(
|
||||
VoidElement* m_void_elements;
|
||||
int m_void_element_count;
|
||||
|
||||
static bool ParseEntry(
|
||||
IMkvReader*,
|
||||
long long pos,
|
||||
long long pos, //payload
|
||||
long long size,
|
||||
Entry*&);
|
||||
Entry*);
|
||||
|
||||
};
|
||||
|
||||
@@ -562,14 +746,15 @@ public:
|
||||
long long GetFirstTime() const; //time (ns) of first (earliest) block
|
||||
long long GetLastTime() const; //time (ns) of last (latest) block
|
||||
|
||||
const BlockEntry* GetFirst() const;
|
||||
const BlockEntry* GetLast() const;
|
||||
const BlockEntry* GetNext(const BlockEntry*) const;
|
||||
long GetFirst(const BlockEntry*&) const;
|
||||
long GetLast(const BlockEntry*&) const;
|
||||
long GetNext(const BlockEntry* curr, const BlockEntry*& next) const;
|
||||
|
||||
const BlockEntry* GetEntry(const Track*, long long ns = -1) const;
|
||||
const BlockEntry* GetEntry(
|
||||
const CuePoint&,
|
||||
const CuePoint::TrackPosition&) const;
|
||||
const BlockEntry* GetMaxKey(const VideoTrack*) const;
|
||||
//const BlockEntry* GetMaxKey(const VideoTrack*) const;
|
||||
|
||||
// static bool HasBlockEntries(const Segment*, long long);
|
||||
|
||||
@@ -581,11 +766,8 @@ public:
|
||||
|
||||
long GetEntryCount() const;
|
||||
|
||||
void Load() const;
|
||||
long Load(long long& pos, long& size) const;
|
||||
|
||||
void LoadBlockEntries() const;
|
||||
|
||||
long Parse(long long& pos, long& size) const;
|
||||
long GetEntry(long index, const mkvparser::BlockEntry*&) const;
|
||||
|
||||
@@ -616,12 +798,12 @@ private:
|
||||
mutable long m_entries_size;
|
||||
mutable long m_entries_count;
|
||||
|
||||
long ParseSimpleBlock(long long, long long&, long&) const;
|
||||
long ParseBlockGroup(long long, long long&, long&) const;
|
||||
long ParseSimpleBlock(long long, long long&, long&);
|
||||
long ParseBlockGroup(long long, long long&, long&);
|
||||
|
||||
void CreateBlock(long long id, long long pos, long long size) const;
|
||||
void CreateBlockGroup(long long, long long, BlockEntry**&) const;
|
||||
void CreateSimpleBlock(long long, long long, BlockEntry**&) const;
|
||||
long CreateBlock(long long id, long long pos, long long size);
|
||||
long CreateBlockGroup(long long, long long);
|
||||
long CreateSimpleBlock(long long, long long);
|
||||
|
||||
};
|
||||
|
||||
@@ -636,10 +818,17 @@ class Segment
|
||||
Segment& operator=(const Segment&);
|
||||
|
||||
private:
|
||||
Segment(IMkvReader*, long long pos, long long size);
|
||||
Segment(
|
||||
IMkvReader*,
|
||||
long long elem_start,
|
||||
//long long elem_size,
|
||||
long long pos,
|
||||
long long size);
|
||||
|
||||
public:
|
||||
IMkvReader* const m_pReader;
|
||||
const long long m_element_start;
|
||||
//const long long m_element_size;
|
||||
const long long m_start; //posn of segment payload
|
||||
const long long m_size; //size of segment payload
|
||||
Cluster m_eos; //TODO: make private?
|
||||
@@ -650,7 +839,8 @@ public:
|
||||
long Load(); //loads headers and all clusters
|
||||
|
||||
//for incremental loading
|
||||
long long Unparsed() const;
|
||||
//long long Unparsed() const;
|
||||
bool DoneParsing() const;
|
||||
long long ParseHeaders(); //stops when first cluster is found
|
||||
//long FindNextCluster(long long& pos, long& size) const;
|
||||
long LoadCluster(long long& pos, long& size); //load one cluster
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mkvparser_2005", "mkvparser_2005.vcproj", "{F9128EC6-C008-41AD-B38F-0E70D549D9F4}"
|
||||
ProjectSection(WebsiteProperties) = preProject
|
||||
Debug.AspNetCompiler.Debug = "True"
|
||||
Release.AspNetCompiler.Debug = "False"
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_2005", "sample_2005.vcproj", "{0CB5681F-6065-490C-98C8-05531732ED7E}"
|
||||
ProjectSection(WebsiteProperties) = preProject
|
||||
Debug.AspNetCompiler.Debug = "True"
|
||||
Release.AspNetCompiler.Debug = "False"
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4}.Release|Win32.Build.0 = Release|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,176 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="mkvparser"
|
||||
ProjectGUID="{F9128EC6-C008-41AD-B38F-0E70D549D9F4}"
|
||||
RootNamespace="mkvparser"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
UseOfMFC="0"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mkvparser.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvreader.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mkvparser.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\mkvreader.hpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,29 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mkvparser", "mkvparser_2008.vcproj", "{F9128EC6-C008-41AD-B38F-0E70D549D9F4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample", "sample_2008.vcproj", "{0CB5681F-6065-490C-98C8-05531732ED7E}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4} = {F9128EC6-C008-41AD-B38F-0E70D549D9F4}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F9128EC6-C008-41AD-B38F-0E70D549D9F4}.Release|Win32.Build.0 = Release|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0CB5681F-6065-490C-98C8-05531732ED7E}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -10,6 +10,9 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace mkvparser
|
||||
{
|
||||
|
||||
MkvReader::MkvReader() :
|
||||
m_file(NULL)
|
||||
{
|
||||
@@ -121,3 +124,5 @@ int MkvReader::Read(long long offset, long len, unsigned char* buffer)
|
||||
|
||||
return 0; //success
|
||||
}
|
||||
|
||||
} //end namespace mkvparser
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
#include "mkvparser.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
class MkvReader : public mkvparser::IMkvReader
|
||||
namespace mkvparser
|
||||
{
|
||||
|
||||
class MkvReader : public IMkvReader
|
||||
{
|
||||
MkvReader(const MkvReader&);
|
||||
MkvReader& operator=(const MkvReader&);
|
||||
@@ -31,4 +34,6 @@ private:
|
||||
FILE* m_file;
|
||||
};
|
||||
|
||||
} //end namespace mkvparser
|
||||
|
||||
#endif //MKVREADER_HPP
|
||||
|
||||
259
mkvstream.cc
Normal file
259
mkvstream.cc
Normal file
@@ -0,0 +1,259 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include "./mkvstream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
MkvStream::MkvStream() : file_(NULL) {
|
||||
}
|
||||
|
||||
MkvStream::~MkvStream() {
|
||||
Close();
|
||||
}
|
||||
|
||||
int MkvStream::Open(const char* filename) {
|
||||
if (filename == NULL || file_ != NULL)
|
||||
return -1;
|
||||
|
||||
file_ = fopen(filename, "rb");
|
||||
if (file_ == NULL)
|
||||
return -1;
|
||||
|
||||
total_ = -1; // means "end-of-file not reached yet"
|
||||
avail_ = 0;
|
||||
|
||||
// Establish invariant
|
||||
|
||||
cache_.push_back(Page());
|
||||
Page& page = cache_.back();
|
||||
page.off_ = 0;
|
||||
|
||||
const int e = page.Read(this);
|
||||
|
||||
if (e < 0) {
|
||||
Close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MkvStream::Close() {
|
||||
if (file_) {
|
||||
fclose(file_);
|
||||
file_ = NULL;
|
||||
|
||||
cache_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
int MkvStream::Read(long long pos, long len, unsigned char* buf) {
|
||||
if (file_ == NULL)
|
||||
return -1;
|
||||
|
||||
assert(!cache_.empty()); // invariant
|
||||
assert(avail_ >= cache_.back().off_);
|
||||
|
||||
// For now, we only support sequential reading of streams, with no
|
||||
// jumps backwards in the stream. Were this a real network cache,
|
||||
// we would have to purge the cache then reissue another fetch over
|
||||
// the wire. (To be precise, this operation would report a cache
|
||||
// miss to the parser, which would be reported back to the caller as
|
||||
// an underflow. The caller would then call PopulateCache directly,
|
||||
// then re-try the parse.)
|
||||
|
||||
if (pos < 0)
|
||||
return -1; // bad arg
|
||||
|
||||
if (pos < cache_.front().off_)
|
||||
return -1; // attempt to read non-sequentially
|
||||
|
||||
if (total_ >= 0 && pos > total_)
|
||||
return -1; // attempt to read beyond end-of-stream
|
||||
|
||||
if (len < 0)
|
||||
return -1; // bad arg
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
const long long end = pos + len;
|
||||
|
||||
if (total_ >= 0 && end > total_)
|
||||
return -1; // attempt to read beyond end of stream
|
||||
|
||||
// Over a wire, network reads are slow, or block completely, which
|
||||
// is not acceptable (e.g. it would leave you unable to pump windows
|
||||
// messages). Hence the need for a cache. If we won't have enough
|
||||
// data in the cache to service this read call, we report underflow
|
||||
// to the parser, which in turn reports it back to the caller. The
|
||||
// caller is then expected to populate the cache, using whatever
|
||||
// mechanism is appropriate for the application (e.g. post an async
|
||||
// read and wait for completion), and then re-try the parse. This
|
||||
// is a simulator, so all the caller needs to do here is call
|
||||
// PopulateCache, but in a real application with real network I/O,
|
||||
// populating the cache can get very complex (especially when
|
||||
// seeking is supported).
|
||||
|
||||
if (end > avail_) // not enough data in the cache
|
||||
return mkvparser::E_BUFFER_NOT_FULL;
|
||||
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
typedef cache_t::const_iterator iter_t;
|
||||
|
||||
const iter_t i = cache_.begin();
|
||||
const iter_t j = cache_.end();
|
||||
|
||||
const iter_t kk = std::upper_bound(i, j, pos, Page::Less());
|
||||
iter_t k = --iter_t(kk);
|
||||
|
||||
while (len > 0) {
|
||||
assert(pos + len == end);
|
||||
|
||||
const long long page_off = k->off_;
|
||||
assert(page_off <= pos);
|
||||
|
||||
long long page_end = page_off + Page::kSize;
|
||||
if (page_end > end)
|
||||
page_end = end;
|
||||
|
||||
const unsigned char* const src = k->buf_ + (pos - page_off);
|
||||
|
||||
const long long count_ = page_end - pos;
|
||||
assert(count_ <= len);
|
||||
|
||||
const size_t count = static_cast<size_t>(count_);
|
||||
memcpy(buf, src, count);
|
||||
|
||||
pos += count;
|
||||
len -= count;
|
||||
buf += count;
|
||||
}
|
||||
|
||||
assert(pos == end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MkvStream::Length(long long* total, long long* avail) {
|
||||
if (file_ == NULL || total == NULL || avail == NULL)
|
||||
return -1;
|
||||
|
||||
*total = total_;
|
||||
*avail = avail_;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MkvStream::PopulateCache(long long pos, long requested_len) {
|
||||
if (file_ == NULL)
|
||||
return -1;
|
||||
|
||||
assert(!cache_.empty());
|
||||
assert(avail_ >= 0);
|
||||
assert(total_ < 0 || total_ == avail_);
|
||||
|
||||
if (pos < 0)
|
||||
return -1;
|
||||
|
||||
if (pos < cache_.front().off_)
|
||||
return -1; // attempt to read non-sequentially
|
||||
|
||||
if (requested_len < 0)
|
||||
return -1;
|
||||
|
||||
if (requested_len == 0)
|
||||
return 0; //TODO(matthewjheaney): ensure pos in cache?
|
||||
|
||||
// Simulate a network read, which might not return all
|
||||
// requested bytes immediately:
|
||||
|
||||
const long actual_len = 1 + rand() % requested_len;
|
||||
const long long end = pos + actual_len;
|
||||
|
||||
long long off = cache_.back().off_;
|
||||
assert(off % Page::kSize == 0);
|
||||
assert(off <= avail_);
|
||||
|
||||
while (total_ < 0 && avail_ < end) {
|
||||
cache_.push_back(Page());
|
||||
Page& page = cache_.back();
|
||||
|
||||
off += Page::kSize;
|
||||
page.off_ = off;
|
||||
|
||||
const int e = page.Read(this);
|
||||
|
||||
if (e < 0) // error
|
||||
return -1;
|
||||
|
||||
assert(e == 0 || total_ >= 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MkvStream::PurgeCache(long long pos) {
|
||||
if (file_ == NULL)
|
||||
return -1;
|
||||
|
||||
if (pos < 0)
|
||||
return -1;
|
||||
|
||||
assert(!cache_.empty());
|
||||
|
||||
if (pos < cache_.front().off_)
|
||||
return 0;
|
||||
|
||||
typedef cache_t::iterator iter_t;
|
||||
|
||||
iter_t i = cache_.begin();
|
||||
const iter_t j = cache_.end();
|
||||
const iter_t kk = std::upper_bound(i, j, pos, Page::Less());
|
||||
const iter_t k = --iter_t(kk);
|
||||
|
||||
while (i != k)
|
||||
cache_.erase(i++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MkvStream::Page::Read(MkvStream* stream) {
|
||||
assert(stream);
|
||||
assert(stream->total_ < 0);
|
||||
assert(stream->avail_ >= 0);
|
||||
assert(off_ % kSize == 0);
|
||||
assert(off_ == stream->avail_);
|
||||
|
||||
FILE* const f = stream->file_;
|
||||
assert(f);
|
||||
|
||||
unsigned char* dst = buf_;
|
||||
|
||||
for (int i = 0; i < kSize; ++i) {
|
||||
const int c = fgetc(f);
|
||||
|
||||
if (c == EOF) {
|
||||
if (!feof(f))
|
||||
return -1;
|
||||
|
||||
stream->total_ = stream->avail_;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*dst++ = static_cast<unsigned char>(c);
|
||||
++stream->avail_;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
90
mkvstream.h
Normal file
90
mkvstream.h
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef MKVSTREAM_H_
|
||||
#define MKVSTREAM_H_
|
||||
|
||||
#include <cstdio>
|
||||
#include <deque>
|
||||
#include "./mkvparser.hpp"
|
||||
|
||||
class MkvStream : public mkvparser::IMkvReader {
|
||||
public:
|
||||
MkvStream();
|
||||
virtual ~MkvStream();
|
||||
|
||||
// Open the file identified by |filename| in read-only mode, as a
|
||||
// binary stream of bytes. Returns 0 on success, negative if error.
|
||||
int Open(const char* filename);
|
||||
|
||||
// Closes the file stream. Note that the stream is automatically
|
||||
// closed when the MkvStream object is destroyed.
|
||||
void Close();
|
||||
|
||||
// Fetches |len| bytes of data from the cache, started at absolute
|
||||
// stream position |pos|, reading into buffer |buf|. Returns
|
||||
// negative value if error (including mkvparser::E_BUFFER_NOT_FULL,
|
||||
// to indicate that not all of the requested bytes were in the
|
||||
// cache), 0 on success (all requested bytes were returned).
|
||||
virtual int Read(long long pos, long len, unsigned char* buf);
|
||||
|
||||
// The |total| argument indicates how many total bytes are in the
|
||||
// stream. This network simulator sets |total| to -1 until we reach
|
||||
// end-of-stream, at which point |total| is set to the file size.
|
||||
// The |available| argument indicates how much of the stream has been
|
||||
// consumed. Returns negative on error, 0 on success.
|
||||
virtual int Length(long long* total, long long* available);
|
||||
|
||||
// Read |len| bytes from the file stream into the cache, starting
|
||||
// at absolute file position |pos|. This is a network simulator
|
||||
// so the actual number of bytes read into the cache might be less
|
||||
// than requested. Returns negative if error, 0 on success.
|
||||
int PopulateCache(long long pos, long len);
|
||||
|
||||
// Notify this reader that the stream up to (but not including)
|
||||
// offset |pos| has been parsed and is no longer of interest,
|
||||
// hence that portion of the stream can be removed from the cache.
|
||||
// Returns negative if error, 0 on success.
|
||||
int PurgeCache(long long pos);
|
||||
|
||||
private:
|
||||
MkvStream(const MkvStream&);
|
||||
MkvStream& operator=(const MkvStream&);
|
||||
|
||||
struct Page {
|
||||
int Read(MkvStream*);
|
||||
|
||||
enum { kSize = 1024 };
|
||||
unsigned char buf_[kSize];
|
||||
long long off_;
|
||||
|
||||
struct Less {
|
||||
bool operator()(const Page& page, long long pos) const {
|
||||
return (page.off_ < pos);
|
||||
}
|
||||
|
||||
bool operator()(long long pos, const Page& page) const {
|
||||
return (pos < page.off_);
|
||||
}
|
||||
|
||||
bool operator()(const Page& lhs, const Page& rhs) const {
|
||||
return (lhs.off_ < rhs.off_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
FILE* file_;
|
||||
|
||||
typedef std::deque<Page> cache_t;
|
||||
cache_t cache_;
|
||||
|
||||
long long total_;
|
||||
long long avail_;
|
||||
};
|
||||
|
||||
#endif
|
||||
94
mkvwriter.cpp
Normal file
94
mkvwriter.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include "mkvwriter.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <share.h> // for _SH_DENYWR
|
||||
#endif
|
||||
|
||||
#include <new>
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
MkvWriter::MkvWriter() : file_(NULL) {
|
||||
}
|
||||
|
||||
MkvWriter::~MkvWriter() {
|
||||
Close();
|
||||
}
|
||||
|
||||
int32 MkvWriter::Write(const void* buffer, uint32 length) {
|
||||
if (!file_)
|
||||
return -1;
|
||||
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
if (buffer == NULL)
|
||||
return -1;
|
||||
|
||||
const size_t bytes_written = fwrite(buffer, 1, length, file_);
|
||||
|
||||
return (bytes_written == length) ? 0 : -1;
|
||||
}
|
||||
|
||||
bool MkvWriter::Open(const char* filename) {
|
||||
if (filename == NULL)
|
||||
return false;
|
||||
|
||||
if (file_)
|
||||
return false;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
file_ = _fsopen(filename, "wb", _SH_DENYWR);
|
||||
#else
|
||||
file_ = fopen(filename, "wb");
|
||||
#endif
|
||||
if (file_ == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MkvWriter::Close() {
|
||||
if (file_) {
|
||||
fclose(file_);
|
||||
file_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int64 MkvWriter::Position() const {
|
||||
if (!file_)
|
||||
return 0;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
return _ftelli64(file_);
|
||||
#else
|
||||
return ftell(file_);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 MkvWriter::Position(int64 position) {
|
||||
if (!file_)
|
||||
return -1;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
return _fseeki64(file_, position, SEEK_SET);
|
||||
#else
|
||||
return fseek(file_, position, SEEK_SET);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MkvWriter::Seekable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void MkvWriter::ElementStartNotify(uint64, int64) {
|
||||
}
|
||||
|
||||
} // namespace mkvmuxer
|
||||
49
mkvwriter.hpp
Normal file
49
mkvwriter.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef MKVWRITER_HPP
|
||||
#define MKVWRITER_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mkvmuxer.hpp"
|
||||
#include "mkvmuxertypes.hpp"
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
// Default implementation of the IMkvWriter interface on Windows.
|
||||
class MkvWriter : public IMkvWriter {
|
||||
public:
|
||||
MkvWriter();
|
||||
virtual ~MkvWriter();
|
||||
|
||||
// IMkvWriter interface
|
||||
virtual int64 Position() const;
|
||||
virtual int32 Position(int64 position);
|
||||
virtual bool Seekable() const;
|
||||
virtual int32 Write(const void* buffer, uint32 length);
|
||||
virtual void ElementStartNotify(uint64 element_id, int64 position);
|
||||
|
||||
// Creates and opens a file for writing. |filename| is the name of the file
|
||||
// to open. This function will overwrite the contents of |filename|. Returns
|
||||
// true on success.
|
||||
bool Open(const char* filename);
|
||||
|
||||
// Closes an opened file.
|
||||
void Close();
|
||||
|
||||
private:
|
||||
// File handle to output file.
|
||||
FILE* file_;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
|
||||
};
|
||||
|
||||
} //end namespace mkvmuxer
|
||||
|
||||
#endif // MKVWRITER_HPP
|
||||
42
netparse.cc
Normal file
42
netparse.cc
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
//#include <cstdio>
|
||||
//#include <cstdlib>
|
||||
#include "./mkvparser.hpp"
|
||||
#include "./mkvstream.h"
|
||||
|
||||
namespace {
|
||||
int ParserEbmlHeader(long long* pos);
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stdout, "usage: netparse <mkvfile>\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
MkvStream reader;
|
||||
const char* const filename = argv[1];
|
||||
|
||||
int e = reader.Open(filename);
|
||||
if (e) {
|
||||
fprintf(stdout, "open failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int ParserEbmlHeader(long long* pos) {
|
||||
}
|
||||
|
||||
}
|
||||
88
sample.cpp
88
sample.cpp
@@ -11,6 +11,17 @@
|
||||
|
||||
#include "mkvreader.hpp"
|
||||
#include "mkvparser.hpp"
|
||||
#include <memory>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Silences these warnings:
|
||||
// warning C4996: 'mbstowcs': This function or variable may be unsafe. Consider
|
||||
// using mbstowcs_s instead. To disable deprecation, use
|
||||
// _CRT_SECURE_NO_WARNINGS. See online help for details.
|
||||
// Fixing this warning requires use of a function available only on Windows,
|
||||
// and this sample code must support non-windows platforms.
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
|
||||
static const wchar_t* utf8towcs(const char* str)
|
||||
{
|
||||
@@ -73,15 +84,18 @@ int main(int argc, char* argv[])
|
||||
printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
|
||||
printf("\t\tPos\t\t\t: %lld\n", pos);
|
||||
|
||||
mkvparser::Segment* pSegment;
|
||||
typedef mkvparser::Segment seg_t;
|
||||
seg_t* pSegment_;
|
||||
|
||||
long long ret = mkvparser::Segment::CreateInstance(&reader, pos, pSegment);
|
||||
long long ret = seg_t::CreateInstance(&reader, pos, pSegment_);
|
||||
if (ret)
|
||||
{
|
||||
printf("\n Segment::CreateInstance() failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const std::auto_ptr<seg_t> pSegment(pSegment_);
|
||||
|
||||
ret = pSegment->Load();
|
||||
if (ret < 0)
|
||||
{
|
||||
@@ -147,8 +161,6 @@ int main(int argc, char* argv[])
|
||||
unsigned long i = 0;
|
||||
const unsigned long j = pTracks->GetTracksCount();
|
||||
|
||||
enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
|
||||
|
||||
printf("\n\t\t\t Track Info\n");
|
||||
|
||||
while (i != j)
|
||||
@@ -158,13 +170,13 @@ int main(int argc, char* argv[])
|
||||
if (pTrack == NULL)
|
||||
continue;
|
||||
|
||||
const long long trackType = pTrack->GetType();
|
||||
const long long trackNumber = pTrack->GetNumber();
|
||||
const long trackType = pTrack->GetType();
|
||||
const long trackNumber = pTrack->GetNumber();
|
||||
const unsigned long long trackUid = pTrack->GetUid();
|
||||
const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());
|
||||
|
||||
printf("\t\tTrack Type\t\t: %lld\n", trackType);
|
||||
printf("\t\tTrack Number\t\t: %lld\n", trackNumber);
|
||||
printf("\t\tTrack Type\t\t: %ld\n", trackType);
|
||||
printf("\t\tTrack Number\t\t: %ld\n", trackNumber);
|
||||
printf("\t\tTrack Uid\t\t: %lld\n", trackUid);
|
||||
|
||||
if (pTrackName == NULL)
|
||||
@@ -193,7 +205,7 @@ int main(int argc, char* argv[])
|
||||
delete [] pCodecName;
|
||||
}
|
||||
|
||||
if (trackType == VIDEO_TRACK)
|
||||
if (trackType == mkvparser::Track::kVideo)
|
||||
{
|
||||
const VideoTrack* const pVideoTrack =
|
||||
static_cast<const VideoTrack*>(pTrack);
|
||||
@@ -208,7 +220,7 @@ int main(int argc, char* argv[])
|
||||
printf("\t\tVideo Rate\t\t: %f\n",rate);
|
||||
}
|
||||
|
||||
if (trackType == AUDIO_TRACK)
|
||||
if (trackType == mkvparser::Track::kAudio)
|
||||
{
|
||||
const AudioTrack* const pAudioTrack =
|
||||
static_cast<const AudioTrack*>(pTrack);
|
||||
@@ -232,7 +244,6 @@ int main(int argc, char* argv[])
|
||||
if (clusterCount == 0)
|
||||
{
|
||||
printf("\t\tSegment has no clusters.\n");
|
||||
delete pSegment;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -246,7 +257,16 @@ int main(int argc, char* argv[])
|
||||
const long long time_ns = pCluster->GetTime();
|
||||
printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);
|
||||
|
||||
const BlockEntry* pBlockEntry = pCluster->GetFirst();
|
||||
const BlockEntry* pBlockEntry;
|
||||
|
||||
long status = pCluster->GetFirst(pBlockEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
{
|
||||
printf("\t\tError parsing first block of cluster\n");
|
||||
fflush(stdout);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
|
||||
{
|
||||
@@ -254,30 +274,42 @@ int main(int argc, char* argv[])
|
||||
const long long trackNum = pBlock->GetTrackNumber();
|
||||
const unsigned long tn = static_cast<unsigned long>(trackNum);
|
||||
const Track* const pTrack = pTracks->GetTrackByNumber(tn);
|
||||
const long long trackType = pTrack->GetType();
|
||||
const int frameCount = pBlock->GetFrameCount();
|
||||
const long long time_ns = pBlock->GetTime(pCluster);
|
||||
|
||||
printf("\t\t\tBlock\t\t:%s,%s,%15lld\n",
|
||||
(trackType == VIDEO_TRACK) ? "V" : "A",
|
||||
pBlock->IsKey() ? "I" : "P",
|
||||
time_ns);
|
||||
|
||||
for (int i = 0; i < frameCount; ++i)
|
||||
if (pTrack == NULL)
|
||||
printf("\t\t\tBlock\t\t:UNKNOWN TRACK TYPE\n");
|
||||
else
|
||||
{
|
||||
const Block::Frame& theFrame = pBlock->GetFrame(i);
|
||||
const long size = theFrame.len;
|
||||
const long long offset = theFrame.pos;
|
||||
printf("\t\t\t %15ld,%15llx\n", size, offset);
|
||||
const long long trackType = pTrack->GetType();
|
||||
const int frameCount = pBlock->GetFrameCount();
|
||||
const long long time_ns = pBlock->GetTime(pCluster);
|
||||
|
||||
printf("\t\t\tBlock\t\t:%s,%s,%15lld\n",
|
||||
(trackType == mkvparser::Track::kVideo) ? "V" : "A",
|
||||
pBlock->IsKey() ? "I" : "P",
|
||||
time_ns);
|
||||
|
||||
for (int i = 0; i < frameCount; ++i)
|
||||
{
|
||||
const Block::Frame& theFrame = pBlock->GetFrame(i);
|
||||
const long size = theFrame.len;
|
||||
const long long offset = theFrame.pos;
|
||||
printf("\t\t\t %15ld,%15llx\n", size, offset);
|
||||
}
|
||||
}
|
||||
|
||||
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
||||
status = pCluster->GetNext(pBlockEntry, pBlockEntry);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("\t\t\tError parsing next block of cluster\n");
|
||||
fflush(stdout);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pCluster = pSegment->GetNext(pCluster);
|
||||
}
|
||||
|
||||
delete pSegment;
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,193 +1,181 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="sample"
|
||||
ProjectGUID="{0CB5681F-6065-490C-98C8-05531732ED7E}"
|
||||
RootNamespace="sample"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="false"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies=".\Debug\mkvparser.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies=".\Release\mkvparser.lib"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\sample.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="sample"
|
||||
ProjectGUID="{0CB5681F-6065-490C-98C8-05531732ED7E}"
|
||||
RootNamespace="sample"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(ProjectDir)..\exe\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ProjectDir)..\obj\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="false"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="$(ProjectDir)..\lib\libwebm_2008\libwebm\$(PlatformName)\$(ConfigurationName)\libwebm.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(ProjectDir)..\exe\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ProjectDir)..\obj\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="$(ProjectDir)..\lib\libwebm_2008\libwebm\$(PlatformName)\$(ConfigurationName)\libwebm.lib"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\sample.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
|
||||
181
sample_2010.vcxproj
Normal file
181
sample_2010.vcxproj
Normal file
@@ -0,0 +1,181 @@
|
||||
<?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 DLL|Win32">
|
||||
<Configuration>Debug DLL</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release DLL|Win32">
|
||||
<Configuration>Release DLL</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>sample</ProjectName>
|
||||
<ProjectGuid>{0CB5681F-6065-490C-98C8-05531732ED7E}</ProjectGuid>
|
||||
<RootNamespace>sample</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\exe\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">$(ProjectDir)..\exe\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">true</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\exe\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">$(ProjectDir)..\exe\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)..\lib\libwebm_2010\libwebm\$(Platform)\$(Configuration)\libwebm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)..\lib\libwebm_2010\libwebm\$(Platform)\$(Configuration)\libwebm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)..\lib\libwebm_2010\libwebm\$(Platform)\$(Configuration)\libwebm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)..\lib\libwebm_2010\libwebm\$(Platform)\$(Configuration)\libwebm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sample.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="libwebm_2010.vcxproj">
|
||||
<Project>{7b1f12ca-0724-430b-b61a-1d357c912cba}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
6
sample_2010.vcxproj.filters
Normal file
6
sample_2010.vcxproj.filters
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sample.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
510
sample_muxer.cpp
Normal file
510
sample_muxer.cpp
Normal file
@@ -0,0 +1,510 @@
|
||||
// Copyright (c) 2011 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
// libwebm parser includes
|
||||
#include "mkvreader.hpp"
|
||||
#include "mkvparser.hpp"
|
||||
|
||||
// libwebm muxer includes
|
||||
#include "mkvmuxer.hpp"
|
||||
#include "mkvwriter.hpp"
|
||||
#include "mkvmuxerutil.hpp"
|
||||
|
||||
#include "sample_muxer_metadata.h"
|
||||
|
||||
using mkvmuxer::uint64;
|
||||
|
||||
namespace {
|
||||
|
||||
void Usage() {
|
||||
printf("Usage: sample_muxer -i input -o output [options]\n");
|
||||
printf("\n");
|
||||
printf("Main options:\n");
|
||||
printf(" -h | -? show help\n");
|
||||
printf(" -video <int> >0 outputs video\n");
|
||||
printf(" -audio <int> >0 outputs audio\n");
|
||||
printf(" -live <int> >0 puts the muxer into live mode\n");
|
||||
printf(" 0 puts the muxer into file mode\n");
|
||||
printf(" -output_cues <int> >0 outputs cues element\n");
|
||||
printf(" -cues_on_video_track <int> >0 outputs cues on video track\n");
|
||||
printf(" -cues_on_audio_track <int> >0 outputs cues on audio track\n");
|
||||
printf(" -max_cluster_duration <double> in seconds\n");
|
||||
printf(" -max_cluster_size <int> in bytes\n");
|
||||
printf(" -switch_tracks <int> >0 switches tracks in output\n");
|
||||
printf(" -audio_track_number <int> >0 Changes the audio track number\n");
|
||||
printf(" -video_track_number <int> >0 Changes the video track number\n");
|
||||
printf(" -chunking <string> Chunk output\n");
|
||||
printf("\n");
|
||||
printf("Video options:\n");
|
||||
printf(" -display_width <int> Display width in pixels\n");
|
||||
printf(" -display_height <int> Display height in pixels\n");
|
||||
printf(" -stereo_mode <int> 3D video mode\n");
|
||||
printf("\n");
|
||||
printf("Cues options:\n");
|
||||
printf(" -output_cues_block_number <int> >0 outputs cue block number\n");
|
||||
printf("\n");
|
||||
printf("Metadata options:\n");
|
||||
printf(" -webvtt-subtitles <vttfile> "
|
||||
"add WebVTT subtitles as metadata track\n");
|
||||
printf(" -webvtt-captions <vttfile> "
|
||||
"add WebVTT captions as metadata track\n");
|
||||
printf(" -webvtt-descriptions <vttfile> "
|
||||
"add WebVTT descriptions as metadata track\n");
|
||||
printf(" -webvtt-metadata <vttfile> "
|
||||
"add WebVTT subtitles as metadata track\n");
|
||||
}
|
||||
|
||||
struct MetadataFile {
|
||||
const char* name;
|
||||
SampleMuxerMetadata::Kind kind;
|
||||
};
|
||||
|
||||
typedef std::list<MetadataFile> metadata_files_t;
|
||||
|
||||
// Cache the WebVTT filenames specified as command-line args.
|
||||
bool LoadMetadataFiles(
|
||||
const metadata_files_t& files,
|
||||
SampleMuxerMetadata* metadata) {
|
||||
typedef metadata_files_t::const_iterator iter_t;
|
||||
|
||||
iter_t i = files.begin();
|
||||
const iter_t j = files.end();
|
||||
|
||||
while (i != j) {
|
||||
const metadata_files_t::value_type& v = *i++;
|
||||
|
||||
if (!metadata->Load(v.name, v.kind))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ParseArgWebVTT(
|
||||
char* argv[],
|
||||
int* argv_index,
|
||||
int argc_check,
|
||||
metadata_files_t* metadata_files) {
|
||||
int& i = *argv_index;
|
||||
|
||||
enum { kCount = 4 };
|
||||
struct Arg { const char* name; SampleMuxerMetadata::Kind kind; };
|
||||
const Arg args[kCount] = {
|
||||
{ "-webvtt-subtitles", SampleMuxerMetadata::kSubtitles },
|
||||
{ "-webvtt-captions", SampleMuxerMetadata::kCaptions },
|
||||
{ "-webvtt-descriptions", SampleMuxerMetadata::kDescriptions },
|
||||
{ "-webvtt-metadata", SampleMuxerMetadata::kMetadata }
|
||||
};
|
||||
|
||||
for (int idx = 0; idx < kCount; ++idx) {
|
||||
const Arg& arg = args[idx];
|
||||
|
||||
if (strcmp(arg.name, argv[i]) != 0) // no match
|
||||
continue;
|
||||
|
||||
++i; // consume arg name here
|
||||
|
||||
if (i > argc_check) {
|
||||
printf("missing value for %s\n", arg.name);
|
||||
return -1; // error
|
||||
}
|
||||
|
||||
MetadataFile f;
|
||||
f.name = argv[i]; // arg value is consumed via caller's loop idx
|
||||
f.kind = arg.kind;
|
||||
|
||||
metadata_files->push_back(f);
|
||||
return 1; // successfully parsed WebVTT arg
|
||||
}
|
||||
|
||||
return 0; // not a WebVTT arg
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
char* input = NULL;
|
||||
char* output = NULL;
|
||||
|
||||
// Segment variables
|
||||
bool output_video = true;
|
||||
bool output_audio = true;
|
||||
bool live_mode = false;
|
||||
bool output_cues = true;
|
||||
bool cues_on_video_track = true;
|
||||
bool cues_on_audio_track = false;
|
||||
uint64 max_cluster_duration = 0;
|
||||
uint64 max_cluster_size = 0;
|
||||
bool switch_tracks = false;
|
||||
int audio_track_number = 0; // 0 tells muxer to decide.
|
||||
int video_track_number = 0; // 0 tells muxer to decide.
|
||||
bool chunking = false;
|
||||
const char* chunk_name = NULL;
|
||||
|
||||
bool output_cues_block_number = true;
|
||||
|
||||
uint64 display_width = 0;
|
||||
uint64 display_height = 0;
|
||||
uint64 stereo_mode = 0;
|
||||
|
||||
metadata_files_t metadata_files;
|
||||
|
||||
const int argc_check = argc - 1;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
char* end;
|
||||
|
||||
if (!strcmp("-h", argv[i]) || !strcmp("-?", argv[i])) {
|
||||
Usage();
|
||||
return EXIT_SUCCESS;
|
||||
} else if (!strcmp("-i", argv[i]) && i < argc_check) {
|
||||
input = argv[++i];
|
||||
} else if (!strcmp("-o", argv[i]) && i < argc_check) {
|
||||
output = argv[++i];
|
||||
} else if (!strcmp("-video", argv[i]) && i < argc_check) {
|
||||
output_video = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-audio", argv[i]) && i < argc_check) {
|
||||
output_audio = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-live", argv[i]) && i < argc_check) {
|
||||
live_mode = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-output_cues", argv[i]) && i < argc_check) {
|
||||
output_cues = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-cues_on_video_track", argv[i]) && i < argc_check) {
|
||||
cues_on_video_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
if (cues_on_video_track)
|
||||
cues_on_audio_track = false;
|
||||
} else if (!strcmp("-cues_on_audio_track", argv[i]) && i < argc_check) {
|
||||
cues_on_audio_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
if (cues_on_audio_track)
|
||||
cues_on_video_track = false;
|
||||
} else if (!strcmp("-max_cluster_duration", argv[i]) && i < argc_check) {
|
||||
const double seconds = strtod(argv[++i], &end);
|
||||
max_cluster_duration =
|
||||
static_cast<uint64>(seconds * 1000000000.0);
|
||||
} else if (!strcmp("-max_cluster_size", argv[i]) && i < argc_check) {
|
||||
max_cluster_size = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-switch_tracks", argv[i]) && i < argc_check) {
|
||||
switch_tracks = strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (!strcmp("-audio_track_number", argv[i]) && i < argc_check) {
|
||||
audio_track_number = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-video_track_number", argv[i]) && i < argc_check) {
|
||||
video_track_number = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-chunking", argv[i]) && i < argc_check) {
|
||||
chunking = true;
|
||||
chunk_name = argv[++i];
|
||||
} else if (!strcmp("-display_width", argv[i]) && i < argc_check) {
|
||||
display_width = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-display_height", argv[i]) && i < argc_check) {
|
||||
display_height = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-stereo_mode", argv[i]) && i < argc_check) {
|
||||
stereo_mode = strtol(argv[++i], &end, 10);
|
||||
} else if (!strcmp("-output_cues_block_number", argv[i]) &&
|
||||
i < argc_check) {
|
||||
output_cues_block_number =
|
||||
strtol(argv[++i], &end, 10) == 0 ? false : true;
|
||||
} else if (int e = ParseArgWebVTT(argv, &i, argc_check, &metadata_files)) {
|
||||
if (e < 0)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (input == NULL || output == NULL) {
|
||||
Usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Get parser header info
|
||||
mkvparser::MkvReader reader;
|
||||
|
||||
if (reader.Open(input)) {
|
||||
printf("\n Filename is invalid or error while opening.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
long long pos = 0;
|
||||
mkvparser::EBMLHeader ebml_header;
|
||||
ebml_header.Parse(&reader, pos);
|
||||
|
||||
mkvparser::Segment* parser_segment;
|
||||
long long ret = mkvparser::Segment::CreateInstance(&reader,
|
||||
pos,
|
||||
parser_segment);
|
||||
if (ret) {
|
||||
printf("\n Segment::CreateInstance() failed.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ret = parser_segment->Load();
|
||||
if (ret < 0) {
|
||||
printf("\n Segment::Load() failed.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const mkvparser::SegmentInfo* const segment_info = parser_segment->GetInfo();
|
||||
const long long timeCodeScale = segment_info->GetTimeCodeScale();
|
||||
|
||||
// Set muxer header info
|
||||
mkvmuxer::MkvWriter writer;
|
||||
|
||||
if (!writer.Open(output)) {
|
||||
printf("\n Filename is invalid or error while opening.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Set Segment element attributes
|
||||
mkvmuxer::Segment muxer_segment;
|
||||
|
||||
if (!muxer_segment.Init(&writer)) {
|
||||
printf("\n Could not initialize muxer segment!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (live_mode)
|
||||
muxer_segment.set_mode(mkvmuxer::Segment::kLive);
|
||||
else
|
||||
muxer_segment.set_mode(mkvmuxer::Segment::kFile);
|
||||
|
||||
if (chunking)
|
||||
muxer_segment.SetChunking(true, chunk_name);
|
||||
|
||||
if (max_cluster_duration > 0)
|
||||
muxer_segment.set_max_cluster_duration(max_cluster_duration);
|
||||
if (max_cluster_size > 0)
|
||||
muxer_segment.set_max_cluster_size(max_cluster_size);
|
||||
muxer_segment.OutputCues(output_cues);
|
||||
|
||||
// Set SegmentInfo element attributes
|
||||
mkvmuxer::SegmentInfo* const info = muxer_segment.GetSegmentInfo();
|
||||
info->set_timecode_scale(timeCodeScale);
|
||||
info->set_writing_app("sample_muxer");
|
||||
|
||||
// Set Tracks element attributes
|
||||
const mkvparser::Tracks* const parser_tracks = parser_segment->GetTracks();
|
||||
unsigned long i = 0;
|
||||
uint64 vid_track = 0; // no track added
|
||||
uint64 aud_track = 0; // no track added
|
||||
|
||||
using mkvparser::Track;
|
||||
|
||||
while (i != parser_tracks->GetTracksCount()) {
|
||||
int track_num = i++;
|
||||
if (switch_tracks)
|
||||
track_num = i % parser_tracks->GetTracksCount();
|
||||
|
||||
const mkvparser::Track* const parser_track =
|
||||
parser_tracks->GetTrackByIndex(track_num);
|
||||
|
||||
if (parser_track == NULL)
|
||||
continue;
|
||||
|
||||
// TODO(fgalligan): Add support for language to parser.
|
||||
const char* const track_name = parser_track->GetNameAsUTF8();
|
||||
|
||||
const long long track_type = parser_track->GetType();
|
||||
|
||||
if (track_type == Track::kVideo && output_video) {
|
||||
// Get the video track from the parser
|
||||
const mkvparser::VideoTrack* const pVideoTrack =
|
||||
static_cast<const mkvparser::VideoTrack*>(parser_track);
|
||||
const long long width = pVideoTrack->GetWidth();
|
||||
const long long height = pVideoTrack->GetHeight();
|
||||
|
||||
// Add the video track to the muxer
|
||||
vid_track = muxer_segment.AddVideoTrack(static_cast<int>(width),
|
||||
static_cast<int>(height),
|
||||
video_track_number);
|
||||
if (!vid_track) {
|
||||
printf("\n Could not add video track.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
mkvmuxer::VideoTrack* const video =
|
||||
static_cast<mkvmuxer::VideoTrack*>(
|
||||
muxer_segment.GetTrackByNumber(vid_track));
|
||||
if (!video) {
|
||||
printf("\n Could not get video track.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (track_name)
|
||||
video->set_name(track_name);
|
||||
|
||||
if (display_width > 0)
|
||||
video->set_display_width(display_width);
|
||||
if (display_height > 0)
|
||||
video->set_display_height(display_height);
|
||||
if (stereo_mode > 0)
|
||||
video->SetStereoMode(stereo_mode);
|
||||
|
||||
const double rate = pVideoTrack->GetFrameRate();
|
||||
if (rate > 0.0) {
|
||||
video->set_frame_rate(rate);
|
||||
}
|
||||
} else if (track_type == Track::kAudio && output_audio) {
|
||||
// Get the audio track from the parser
|
||||
const mkvparser::AudioTrack* const pAudioTrack =
|
||||
static_cast<const mkvparser::AudioTrack*>(parser_track);
|
||||
const long long channels = pAudioTrack->GetChannels();
|
||||
const double sample_rate = pAudioTrack->GetSamplingRate();
|
||||
|
||||
// Add the audio track to the muxer
|
||||
aud_track = muxer_segment.AddAudioTrack(static_cast<int>(sample_rate),
|
||||
static_cast<int>(channels),
|
||||
audio_track_number);
|
||||
if (!aud_track) {
|
||||
printf("\n Could not add audio track.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
mkvmuxer::AudioTrack* const audio =
|
||||
static_cast<mkvmuxer::AudioTrack*>(
|
||||
muxer_segment.GetTrackByNumber(aud_track));
|
||||
if (!audio) {
|
||||
printf("\n Could not get audio track.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (track_name)
|
||||
audio->set_name(track_name);
|
||||
|
||||
size_t private_size;
|
||||
const unsigned char* const private_data =
|
||||
pAudioTrack->GetCodecPrivate(private_size);
|
||||
if (private_size > 0) {
|
||||
if (!audio->SetCodecPrivate(private_data, private_size)) {
|
||||
printf("\n Could not add audio private data.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
const long long bit_depth = pAudioTrack->GetBitDepth();
|
||||
if (bit_depth > 0)
|
||||
audio->set_bit_depth(bit_depth);
|
||||
}
|
||||
}
|
||||
|
||||
// We have created all the video and audio tracks. If any WebVTT
|
||||
// files were specified as command-line args, then parse them and
|
||||
// add a track to the output file corresponding to each metadata
|
||||
// input file.
|
||||
|
||||
SampleMuxerMetadata metadata;
|
||||
|
||||
if (!metadata.Init(&muxer_segment)) {
|
||||
printf("\n Could not initialize metadata cache.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!LoadMetadataFiles(metadata_files, &metadata))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// Set Cues element attributes
|
||||
mkvmuxer::Cues* const cues = muxer_segment.GetCues();
|
||||
cues->set_output_block_number(output_cues_block_number);
|
||||
if (cues_on_video_track && vid_track)
|
||||
muxer_segment.CuesTrack(vid_track);
|
||||
if (cues_on_audio_track && aud_track)
|
||||
muxer_segment.CuesTrack(aud_track);
|
||||
|
||||
// Write clusters
|
||||
unsigned char* data = NULL;
|
||||
int data_len = 0;
|
||||
|
||||
const mkvparser::Cluster* cluster = parser_segment->GetFirst();
|
||||
|
||||
while ((cluster != NULL) && !cluster->EOS()) {
|
||||
const mkvparser::BlockEntry* block_entry;
|
||||
|
||||
long status = cluster->GetFirst(block_entry);
|
||||
|
||||
if (status)
|
||||
{
|
||||
printf("\n Could not get first block of cluster.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while ((block_entry != NULL) && !block_entry->EOS()) {
|
||||
const mkvparser::Block* const block = block_entry->GetBlock();
|
||||
const long long trackNum = block->GetTrackNumber();
|
||||
const mkvparser::Track* const parser_track =
|
||||
parser_tracks->GetTrackByNumber(
|
||||
static_cast<unsigned long>(trackNum));
|
||||
const long long track_type = parser_track->GetType();
|
||||
const long long time_ns = block->GetTime(cluster);
|
||||
|
||||
// Flush any metadata frames to the output file, before we write
|
||||
// the current block.
|
||||
if (!metadata.Write(time_ns))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if ((track_type == Track::kAudio && output_audio) ||
|
||||
(track_type == Track::kVideo && output_video)) {
|
||||
const int frame_count = block->GetFrameCount();
|
||||
const bool is_key = block->IsKey();
|
||||
|
||||
for (int i = 0; i < frame_count; ++i) {
|
||||
const mkvparser::Block::Frame& frame = block->GetFrame(i);
|
||||
|
||||
if (frame.len > data_len) {
|
||||
delete [] data;
|
||||
data = new unsigned char[frame.len];
|
||||
if (!data)
|
||||
return EXIT_FAILURE;
|
||||
data_len = frame.len;
|
||||
}
|
||||
|
||||
if (frame.Read(&reader, data))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
uint64 track_num = vid_track;
|
||||
if (track_type == Track::kAudio)
|
||||
track_num = aud_track;
|
||||
|
||||
if (!muxer_segment.AddFrame(data,
|
||||
frame.len,
|
||||
track_num,
|
||||
time_ns,
|
||||
is_key)) {
|
||||
printf("\n Could not add frame.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = cluster->GetNext(block_entry, block_entry);
|
||||
|
||||
if (status)
|
||||
{
|
||||
printf("\n Could not get next block of cluster.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
cluster = parser_segment->GetNext(cluster);
|
||||
}
|
||||
|
||||
// We have exhausted all video and audio frames in the input file.
|
||||
// Flush any remaining metadata frames to the output file.
|
||||
if (!metadata.Write(-1))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
muxer_segment.Finalize();
|
||||
|
||||
delete [] data;
|
||||
delete parser_segment;
|
||||
|
||||
writer.Close();
|
||||
reader.Close();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,193 +1,179 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="sample"
|
||||
ProjectGUID="{0CB5681F-6065-490C-98C8-05531732ED7E}"
|
||||
RootNamespace="sample"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies=".\Debug\mkvparser.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\sample.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="sample_muxer"
|
||||
ProjectGUID="{B407561F-1F5E-4798-B9C2-81AB09CFBC16}"
|
||||
RootNamespace="sample_muxer"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(ProjectDir)..\exe\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ProjectDir)..\obj\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="$(ProjectDir)..\lib\libwebm_2008\libwebm\$(PlatformName)\$(ConfigurationName)\libwebm.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(ProjectDir)..\exe\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ProjectDir)..\obj\libwebm_2008\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="../"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="0"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="$(ProjectDir)..\lib\libwebm_2008\libwebm\$(PlatformName)\$(ConfigurationName)\libwebm.lib"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\sample_muxer.cpp"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
177
sample_muxer_2010.vcxproj
Normal file
177
sample_muxer_2010.vcxproj
Normal file
@@ -0,0 +1,177 @@
|
||||
<?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 DLL|Win32">
|
||||
<Configuration>Debug DLL</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release DLL|Win32">
|
||||
<Configuration>Release DLL</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>sample_muxer</ProjectName>
|
||||
<ProjectGuid>{B407561F-1F5E-4798-B9C2-81AB09CFBC16}</ProjectGuid>
|
||||
<RootNamespace>sample_muxer</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>Windows7.1SDK</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\exe\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">$(ProjectDir)..\exe\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">true</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\exe\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">$(ProjectDir)..\exe\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">$(ProjectDir)..\obj\libwebm_2010\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)..\lib\libwebm_2010\libwebm\$(Platform)\$(Configuration)\libwebm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug DLL|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)..\lib\libwebm_2010\libwebm\$(Platform)\$(Configuration)\libwebm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)..\lib\libwebm_2010\libwebm\$(Platform)\$(Configuration)\libwebm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release DLL|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(ProjectDir)..\lib\libwebm_2010\libwebm\$(Platform)\$(Configuration)\libwebm.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sample_muxer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="libwebm_2010.vcxproj">
|
||||
<Project>{7b1f12ca-0724-430b-b61a-1d357c912cba}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
6
sample_muxer_2010.vcxproj.filters
Normal file
6
sample_muxer_2010.vcxproj.filters
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="sample_muxer.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
240
sample_muxer_metadata.cc
Normal file
240
sample_muxer_metadata.cc
Normal file
@@ -0,0 +1,240 @@
|
||||
#include "sample_muxer_metadata.h"
|
||||
#include <string>
|
||||
#include "vttreader.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
SampleMuxerMetadata::SampleMuxerMetadata() : segment_(NULL) {
|
||||
}
|
||||
|
||||
bool SampleMuxerMetadata::Init(mkvmuxer::Segment* segment) {
|
||||
if (segment == NULL || segment_ != NULL)
|
||||
return false;
|
||||
|
||||
segment_ = segment;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SampleMuxerMetadata::Load(const char* file, Kind kind) {
|
||||
mkvmuxer::uint64 track_num;
|
||||
|
||||
if (!AddTrack(kind, &track_num)) {
|
||||
printf("Unable to add track for WebVTT file \"%s\"\n", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Parse(file, kind, track_num);
|
||||
}
|
||||
|
||||
bool SampleMuxerMetadata::Write(mkvmuxer::int64 time_ns) {
|
||||
typedef cues_set_t::iterator iter_t;
|
||||
|
||||
iter_t i = cues_set_.begin();
|
||||
const iter_t j = cues_set_.end();
|
||||
|
||||
while (i != j) {
|
||||
const cues_set_t::value_type& v = *i;
|
||||
|
||||
if (time_ns >= 0 && v > time_ns)
|
||||
return true; // nothing else to do just yet
|
||||
|
||||
if (!v.Write(segment_)) {
|
||||
printf("\nCould not add metadata.\n");
|
||||
return false; // error
|
||||
}
|
||||
|
||||
cues_set_.erase(i++);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SampleMuxerMetadata::AddTrack(
|
||||
Kind kind,
|
||||
mkvmuxer::uint64* track_num) {
|
||||
*track_num = 0;
|
||||
|
||||
// Track number value 0 means "let muxer choose track number"
|
||||
mkvmuxer::Track* const track = segment_->AddTrack(0);
|
||||
|
||||
if (track == NULL) // error
|
||||
return false;
|
||||
|
||||
// Return the track number value chosen by the muxer
|
||||
*track_num = track->number();
|
||||
|
||||
int type;
|
||||
const char* codec_id;
|
||||
|
||||
switch (kind) {
|
||||
case kSubtitles:
|
||||
type = 0x11;
|
||||
codec_id = "D_WEBVTT/SUBTITLES";
|
||||
break;
|
||||
|
||||
case kCaptions:
|
||||
type = 0x11;
|
||||
codec_id = "D_WEBVTT/CAPTIONS";
|
||||
break;
|
||||
|
||||
case kDescriptions:
|
||||
type = 0x21;
|
||||
codec_id = "D_WEBVTT/DESCRIPTIONS";
|
||||
break;
|
||||
|
||||
case kMetadata:
|
||||
type = 0x21;
|
||||
codec_id = "D_WEBVTT/METADATA";
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
track->set_type(type);
|
||||
track->set_codec_id(codec_id);
|
||||
|
||||
// TODO(matthewjheaney): set name and language
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SampleMuxerMetadata::Parse(
|
||||
const char* file,
|
||||
Kind /* kind */,
|
||||
mkvmuxer::uint64 track_num) {
|
||||
libwebvtt::VttReader r;
|
||||
int e = r.Open(file);
|
||||
|
||||
if (e) {
|
||||
printf("Unable to open WebVTT file: \"%s\"\n", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
libwebvtt::Parser p(&r);
|
||||
|
||||
e = p.Init();
|
||||
|
||||
if (e < 0) { // error
|
||||
printf("Error parsing WebVTT file: \"%s\"\n", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
SortableCue cue;
|
||||
cue.track_num = track_num;
|
||||
|
||||
libwebvtt::Time t;
|
||||
t.hours = -1;
|
||||
|
||||
for (;;) {
|
||||
cue_t& c = cue.cue;
|
||||
e = p.Parse(&c);
|
||||
|
||||
if (e < 0) { // error
|
||||
printf("Error parsing WebVTT file: \"%s\"\n", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e > 0) // EOF
|
||||
return true;
|
||||
|
||||
if (c.start_time >= t) {
|
||||
t = c.start_time;
|
||||
} else {
|
||||
printf("bad WebVTT cue timestamp (out-of-order)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c.stop_time < c.start_time) {
|
||||
printf("bad WebVTT cue timestamp (stop < start)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
cues_set_.insert(cue);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleMuxerMetadata::MakeFrame(const cue_t& c, string* pf) {
|
||||
pf->clear();
|
||||
WriteCueIdentifier(c.identifier, pf);
|
||||
WriteCueSettings(c.settings, pf);
|
||||
WriteCuePayload(c.payload, pf);
|
||||
}
|
||||
|
||||
void SampleMuxerMetadata::WriteCueIdentifier(
|
||||
const string& identifier,
|
||||
string* pf) {
|
||||
pf->append(identifier);
|
||||
pf->push_back('\x0A'); // LF
|
||||
}
|
||||
|
||||
void SampleMuxerMetadata::WriteCueSettings(
|
||||
const cue_t::settings_t& settings,
|
||||
string* pf) {
|
||||
if (settings.empty()) {
|
||||
pf->push_back('\x0A'); // LF
|
||||
return;
|
||||
}
|
||||
|
||||
typedef cue_t::settings_t::const_iterator iter_t;
|
||||
|
||||
iter_t i = settings.begin();
|
||||
const iter_t j = settings.end();
|
||||
|
||||
for (;;) {
|
||||
const libwebvtt::Setting& setting = *i++;
|
||||
|
||||
pf->append(setting.name);
|
||||
pf->push_back(':');
|
||||
pf->append(setting.value);
|
||||
|
||||
if (i == j)
|
||||
break;
|
||||
|
||||
pf->push_back(' '); // separate settings with whitespace
|
||||
}
|
||||
|
||||
pf->push_back('\x0A'); // LF
|
||||
}
|
||||
|
||||
void SampleMuxerMetadata::WriteCuePayload(
|
||||
const cue_t::payload_t& payload,
|
||||
string* pf) {
|
||||
typedef cue_t::payload_t::const_iterator iter_t;
|
||||
|
||||
iter_t i = payload.begin();
|
||||
const iter_t j = payload.end();
|
||||
|
||||
while (i != j) {
|
||||
const string& line = *i++;
|
||||
pf->append(line);
|
||||
pf->push_back('\x0A'); // LF
|
||||
}
|
||||
}
|
||||
|
||||
bool SampleMuxerMetadata::SortableCue::Write(
|
||||
mkvmuxer::Segment* segment) const {
|
||||
// Cue start time expressed in milliseconds
|
||||
const mkvmuxer::int64 start_ms = cue.start_time.presentation();
|
||||
|
||||
// Cue start time expressed in nanoseconds (MKV time)
|
||||
const mkvmuxer::int64 start_ns = start_ms * 1000000;
|
||||
|
||||
// Cue stop time expressed in milliseconds
|
||||
const mkvmuxer::int64 stop_ms = cue.stop_time.presentation();
|
||||
|
||||
// Cue stop time expressed in nanonseconds
|
||||
const mkvmuxer::int64 stop_ns = stop_ms * 1000000;
|
||||
|
||||
// Metadata blocks always specify the block duration.
|
||||
const mkvmuxer::int64 duration_ns = stop_ns - start_ns;
|
||||
|
||||
string frame;
|
||||
MakeFrame(cue, &frame);
|
||||
|
||||
typedef const mkvmuxer::uint8* data_t;
|
||||
const data_t buf = reinterpret_cast<data_t>(frame.data());
|
||||
const mkvmuxer::uint64 len = frame.length();
|
||||
|
||||
return segment->AddMetadata(buf, len, track_num, start_ns, duration_ns);
|
||||
}
|
||||
113
sample_muxer_metadata.h
Normal file
113
sample_muxer_metadata.h
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef SAMPLE_MUXER_METADATA_H_ // NOLINT
|
||||
#define SAMPLE_MUXER_METADATA_H_
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
#include "mkvmuxer.hpp"
|
||||
#include "webvttparser.h"
|
||||
|
||||
class SampleMuxerMetadata {
|
||||
public:
|
||||
enum Kind {
|
||||
kSubtitles,
|
||||
kCaptions,
|
||||
kDescriptions,
|
||||
kMetadata
|
||||
};
|
||||
|
||||
SampleMuxerMetadata();
|
||||
|
||||
// Bind this metadata object to the muxer instance. Returns false
|
||||
// if segment equals NULL, or Init has already been called.
|
||||
bool Init(mkvmuxer::Segment* segment);
|
||||
|
||||
// Parse the WebVTT file |filename| having the indicated |kind|, and
|
||||
// create a corresponding track in the segment. Returns false on
|
||||
// error.
|
||||
bool Load(const char* filename, Kind kind);
|
||||
|
||||
// Write any WebVTT cues whose time is less or equal to |time_ns| as
|
||||
// a metadata block in its corresponding track. If |time_ns| is
|
||||
// negative, write all remaining cues. Returns false on error.
|
||||
bool Write(mkvmuxer::int64 time_ns);
|
||||
|
||||
private:
|
||||
typedef libwebvtt::Cue cue_t;
|
||||
|
||||
// Used to sort cues as they are loaded.
|
||||
struct SortableCue {
|
||||
bool operator>(mkvmuxer::int64 time_ns) const {
|
||||
// Cue start time expressed in milliseconds
|
||||
const mkvmuxer::int64 start_ms = cue.start_time.presentation();
|
||||
|
||||
// Cue start time expressed in nanoseconds (MKV time)
|
||||
const mkvmuxer::int64 start_ns = start_ms * 1000000;
|
||||
|
||||
return (start_ns > time_ns);
|
||||
}
|
||||
|
||||
bool operator<(const SortableCue& rhs) const {
|
||||
if (cue.start_time < rhs.cue.start_time)
|
||||
return true;
|
||||
|
||||
if (cue.start_time > rhs.cue.start_time)
|
||||
return false;
|
||||
|
||||
return (track_num < rhs.track_num);
|
||||
}
|
||||
|
||||
// Write this cue as a metablock to |segment|. Returns false on
|
||||
// error.
|
||||
bool Write(mkvmuxer::Segment* segment) const;
|
||||
|
||||
mkvmuxer::uint64 track_num;
|
||||
cue_t cue;
|
||||
};
|
||||
|
||||
typedef std::multiset<SortableCue> cues_set_t;
|
||||
|
||||
// Add a metadata track to the segment having the indicated |kind|,
|
||||
// returning the |track_num| that has been chosen for this track.
|
||||
// Returns false on error.
|
||||
bool AddTrack(Kind kind, mkvmuxer::uint64* track_num);
|
||||
|
||||
// Parse the WebVTT |file| having the indicated |kind| and
|
||||
// |track_num|, adding each parsed cue to cues set. Returns false
|
||||
// on error.
|
||||
bool Parse(const char* file, Kind kind, mkvmuxer::uint64 track_num);
|
||||
|
||||
// Converts a WebVTT cue to a Matroska metadata block.
|
||||
static void MakeFrame(const cue_t& cue, std::string* frame);
|
||||
|
||||
// Populate the cue identifier part of the metadata block.
|
||||
static void WriteCueIdentifier(const std::string& identifier,
|
||||
std::string* frame);
|
||||
|
||||
// Populate the cue settings part of the metadata block.
|
||||
static void WriteCueSettings(const cue_t::settings_t& settings,
|
||||
std::string* frame);
|
||||
|
||||
// Populate the payload part of the metadata block.
|
||||
static void WriteCuePayload(const cue_t::payload_t& payload,
|
||||
std::string* frame);
|
||||
|
||||
mkvmuxer::Segment* segment_;
|
||||
|
||||
// Set of cues ordered by time and then by track number.
|
||||
cues_set_t cues_set_;
|
||||
|
||||
// Disable copy ctor and copy assign.
|
||||
SampleMuxerMetadata(const SampleMuxerMetadata&);
|
||||
SampleMuxerMetadata& operator=(const SampleMuxerMetadata&);
|
||||
};
|
||||
|
||||
#endif // SAMPLE_MUXER_METADATA_H_ // NOLINT
|
||||
736
vttdemux.cc
Normal file
736
vttdemux.cc
Normal file
@@ -0,0 +1,736 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "./mkvparser.hpp"
|
||||
#include "./mkvreader.hpp"
|
||||
#include "./webvttparser.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace vttdemux {
|
||||
|
||||
typedef long long mkvtime_t; // NOLINT
|
||||
typedef long long mkvpos_t; // NOLINT
|
||||
typedef std::auto_ptr<mkvparser::Segment> segment_ptr_t;
|
||||
|
||||
// WebVTT metadata tracks have a type (encoded in the CodecID for the track).
|
||||
// We use |type| to synthesize a filename for the out-of-band WebVTT |file|.
|
||||
struct MetadataInfo {
|
||||
enum Type { kSubtitles, kCaptions, kDescriptions, kMetadata } type;
|
||||
FILE* file;
|
||||
};
|
||||
|
||||
// We use a map, indexed by track number, to collect information about
|
||||
// each track in the input file.
|
||||
typedef std::map<long, MetadataInfo> metadata_map_t; // NOLINT
|
||||
|
||||
// The data from the original WebVTT Cue is stored as a WebM block.
|
||||
// The FrameParser is used to parse the lines of text out from the
|
||||
// block, in order to reconstruct the original WebVTT Cue.
|
||||
class FrameParser : public libwebvtt::LineReader {
|
||||
public:
|
||||
// Bind the FrameParser instance to a WebM block.
|
||||
explicit FrameParser(const mkvparser::BlockGroup* block_group);
|
||||
virtual ~FrameParser();
|
||||
|
||||
// The Webm block (group) to which this instance is bound. We
|
||||
// treat the payload of the block as a stream of characters.
|
||||
const mkvparser::BlockGroup* const block_group_;
|
||||
|
||||
protected:
|
||||
// Read the next character from the character stream (the payload
|
||||
// of the WebM block). We increment the stream pointer |pos_| as
|
||||
// each character from the stream is consumed.
|
||||
virtual int GetChar(char* c);
|
||||
|
||||
// End-of-line handling requires that we put a character back into
|
||||
// the stream. Here we need only decrement the stream pointer |pos_|
|
||||
// to unconsume the character.
|
||||
virtual void UngetChar(char c);
|
||||
|
||||
// The current position in the character stream (the payload of the block).
|
||||
mkvpos_t pos_;
|
||||
|
||||
// The position of the end of the character stream. When the current
|
||||
// position |pos_| equals the end position |pos_end_|, the entire
|
||||
// stream (block payload) has been consumed and end-of-stream is indicated.
|
||||
mkvpos_t pos_end_;
|
||||
|
||||
private:
|
||||
// Disable copy ctor and copy assign
|
||||
FrameParser(const FrameParser&);
|
||||
FrameParser& operator=(const FrameParser&);
|
||||
};
|
||||
|
||||
// Parse the EBML header of the WebM input file, to determine whether we
|
||||
// actually have a WebM file. Returns false if this is not a WebM file.
|
||||
bool ParseHeader(mkvparser::IMkvReader* reader, mkvpos_t* pos);
|
||||
|
||||
// Parse the Segment of the input file and load all of its clusters.
|
||||
// Returns false if there was an error parsing the file.
|
||||
bool ParseSegment(
|
||||
mkvparser::IMkvReader* reader,
|
||||
mkvpos_t pos,
|
||||
segment_ptr_t* segment);
|
||||
|
||||
// Iterate over the tracks of the input file and cache information about
|
||||
// each metadata track.
|
||||
void BuildMap(const mkvparser::Segment* segment, metadata_map_t* metadata_map);
|
||||
|
||||
// For each track listed in the cache, synthesize its output filename
|
||||
// and open a file handle that designates the out-of-band file.
|
||||
// Returns false if we were unable to open an output file for a track.
|
||||
bool OpenFiles(metadata_map_t* metadata_map, const char* filename);
|
||||
|
||||
// Close the file handle for each track in the cache.
|
||||
void CloseFiles(metadata_map_t* metadata_map);
|
||||
|
||||
// Iterate over the clusters of the input file, and write a WebVTT cue
|
||||
// for each metadata block. Returns false if processing of a cluster
|
||||
// failed.
|
||||
bool WriteFiles(const metadata_map_t& m, mkvparser::Segment* s);
|
||||
|
||||
// Write the WebVTT header for each track in the cache. We do this
|
||||
// immediately before writing the actual WebVTT cues. Returns false
|
||||
// if the write failed.
|
||||
bool InitializeFiles(const metadata_map_t& metadata_map);
|
||||
|
||||
// Iterate over the blocks of the |cluster|, writing a WebVTT cue to
|
||||
// its associated output file for each block of metadata. Returns
|
||||
// false if processing a block failed, or there was a parse error.
|
||||
bool ProcessCluster(
|
||||
const metadata_map_t& metadata_map,
|
||||
const mkvparser::Cluster* cluster);
|
||||
|
||||
// Look up this track number in the cache, and if found (meaning this
|
||||
// is a metadata track), write a WebVTT cue to the associated output
|
||||
// file. Returns false if writing the WebVTT cue failed.
|
||||
bool ProcessBlockEntry(
|
||||
const metadata_map_t& metadata_map,
|
||||
const mkvparser::BlockEntry* block_entry);
|
||||
|
||||
// Parse the lines of text from the |block_group| to reconstruct the
|
||||
// original WebVTT cue, and write it to the associated output |file|.
|
||||
// Returns false if there was an error writing to the output file.
|
||||
bool WriteCue(FILE* file, const mkvparser::BlockGroup* block_group);
|
||||
|
||||
// Consume a line of text from the character stream, and if the line
|
||||
// is not empty write the cue identifier to the associated output
|
||||
// file. Returns false if there was an error writing to the file.
|
||||
bool WriteCueIdentifier(FILE* f, FrameParser* parser);
|
||||
|
||||
// Consume a line of text from the character stream (which holds any
|
||||
// cue settings) and write the cue timings line for this cue to the
|
||||
// associated output file. Returns false if there was an error
|
||||
// writing to the file.
|
||||
bool WriteCueTimings(
|
||||
FILE* f,
|
||||
FrameParser* parser);
|
||||
|
||||
// Write the timestamp (representating either the start time or stop
|
||||
// time of the cue) to the output file. Returns false if there was an
|
||||
// error writing to the file.
|
||||
bool WriteCueTime(
|
||||
FILE* f,
|
||||
mkvtime_t time_ns);
|
||||
|
||||
// Consume the remaining lines of text from the character stream
|
||||
// (these lines are the actual payload of the WebVTT cue), and write
|
||||
// them to the associated output file. Returns false if there was an
|
||||
// error writing to the file.
|
||||
bool WriteCuePayload(
|
||||
FILE* f,
|
||||
FrameParser* parser);
|
||||
} // namespace vttdemux
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc != 2) {
|
||||
printf("usage: vttdemux <webmfile>\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
const char* const filename = argv[1];
|
||||
mkvparser::MkvReader reader;
|
||||
|
||||
int e = reader.Open(filename);
|
||||
|
||||
if (e) { // error
|
||||
printf("unable to open file\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
vttdemux::mkvpos_t pos;
|
||||
|
||||
if (!vttdemux::ParseHeader(&reader, &pos))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
vttdemux::segment_ptr_t segment_ptr;
|
||||
|
||||
if (!vttdemux::ParseSegment(&reader, pos, &segment_ptr))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
vttdemux::metadata_map_t metadata_map;
|
||||
|
||||
BuildMap(segment_ptr.get(), &metadata_map);
|
||||
|
||||
if (metadata_map.empty()) {
|
||||
printf("no metadata tracks found\n");
|
||||
return EXIT_FAILURE; // TODO(matthewjheaney): correct result?
|
||||
}
|
||||
|
||||
if (!OpenFiles(&metadata_map, filename)) {
|
||||
CloseFiles(&metadata_map); // nothing to flush, so not strictly necessary
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!WriteFiles(metadata_map, segment_ptr.get())) {
|
||||
CloseFiles(&metadata_map); // might as well flush what we do have
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CloseFiles(&metadata_map);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
namespace vttdemux {
|
||||
|
||||
FrameParser::FrameParser(const mkvparser::BlockGroup* block_group)
|
||||
: block_group_(block_group) {
|
||||
const mkvparser::Block* const block = block_group->GetBlock();
|
||||
const mkvparser::Block::Frame& f = block->GetFrame(0);
|
||||
|
||||
// The beginning and end of the character stream corresponds to the
|
||||
// position of this block's frame within the WebM input file.
|
||||
|
||||
pos_ = f.pos;
|
||||
pos_end_ = f.pos + f.len;
|
||||
}
|
||||
|
||||
FrameParser::~FrameParser() {
|
||||
}
|
||||
|
||||
int FrameParser::GetChar(char* c) {
|
||||
if (pos_ >= pos_end_) // end-of-stream
|
||||
return 1; // per the semantics of libwebvtt::Reader::GetChar
|
||||
|
||||
const mkvparser::Cluster* const cluster = block_group_->GetCluster();
|
||||
const mkvparser::Segment* const segment = cluster->m_pSegment;
|
||||
mkvparser::IMkvReader* const reader = segment->m_pReader;
|
||||
|
||||
unsigned char* const buf = reinterpret_cast<unsigned char*>(c);
|
||||
const int result = reader->Read(pos_, 1, buf);
|
||||
|
||||
if (result < 0) // error
|
||||
return -1;
|
||||
|
||||
++pos_; // consume this character in the stream
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FrameParser::UngetChar(char /* c */ ) {
|
||||
// All we need to do here is decrement the position in the stream.
|
||||
// The next time GetChar is called the same character will be
|
||||
// re-read from the input file.
|
||||
--pos_;
|
||||
}
|
||||
|
||||
} // namespace vttdemux
|
||||
|
||||
bool vttdemux::ParseHeader(
|
||||
mkvparser::IMkvReader* reader,
|
||||
mkvpos_t* pos) {
|
||||
mkvparser::EBMLHeader h;
|
||||
const mkvpos_t status = h.Parse(reader, *pos);
|
||||
|
||||
if (status) {
|
||||
printf("error parsing EBML header\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(h.m_docType, "webm") != 0) {
|
||||
printf("bad doctype\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; // success
|
||||
}
|
||||
|
||||
bool vttdemux::ParseSegment(
|
||||
mkvparser::IMkvReader* reader,
|
||||
mkvpos_t pos,
|
||||
segment_ptr_t* segment_ptr) {
|
||||
// We first create the segment object.
|
||||
|
||||
mkvparser::Segment* p;
|
||||
const mkvpos_t create = mkvparser::Segment::CreateInstance(reader, pos, p);
|
||||
|
||||
if (create) {
|
||||
printf("error parsing segment element\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
segment_ptr->reset(p);
|
||||
|
||||
// Now parse all of the segment's sub-elements, in toto.
|
||||
|
||||
const long status = p->Load(); // NOLINT
|
||||
|
||||
if (status < 0) {
|
||||
printf("error loading segment\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vttdemux::BuildMap(
|
||||
const mkvparser::Segment* segment,
|
||||
metadata_map_t* map_ptr) {
|
||||
const mkvparser::Tracks* const tt = segment->GetTracks();
|
||||
if (tt == NULL)
|
||||
return;
|
||||
|
||||
const long tc = tt->GetTracksCount(); // NOLINT
|
||||
if (tc <= 0)
|
||||
return;
|
||||
|
||||
metadata_map_t& m = *map_ptr;
|
||||
|
||||
// Iterate over the tracks in the intput file. We determine whether
|
||||
// a track holds metadata by inspecting its CodecID.
|
||||
|
||||
for (long idx = 0; idx < tc; ++idx) { // NOLINT
|
||||
const mkvparser::Track* const t = tt->GetTrackByIndex(idx);
|
||||
|
||||
if (t == NULL) // weird
|
||||
continue;
|
||||
|
||||
const char* const codec_id = t->GetCodecId();
|
||||
|
||||
if (codec_id == NULL) // weird
|
||||
continue;
|
||||
|
||||
MetadataInfo info;
|
||||
info.file = NULL;
|
||||
|
||||
if (strcmp(codec_id, "D_WEBVTT/SUBTITLES") == 0) {
|
||||
info.type = MetadataInfo::kSubtitles;
|
||||
} else if (strcmp(codec_id, "D_WEBVTT/CAPTIONS") == 0) {
|
||||
info.type = MetadataInfo::kCaptions;
|
||||
} else if (strcmp(codec_id, "D_WEBVTT/DESCRIPTIONS") == 0) {
|
||||
info.type = MetadataInfo::kDescriptions;
|
||||
} else if (strcmp(codec_id, "D_WEBVTT/METADATA") == 0) {
|
||||
info.type = MetadataInfo::kMetadata;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
const long tn = t->GetNumber(); // NOLINT
|
||||
m[tn] = info; // create an entry in the cache for this track
|
||||
}
|
||||
}
|
||||
|
||||
bool vttdemux::OpenFiles(metadata_map_t* metadata_map, const char* filename) {
|
||||
if (metadata_map == NULL || metadata_map->empty())
|
||||
return false;
|
||||
|
||||
if (filename == NULL)
|
||||
return false;
|
||||
|
||||
// Find the position of the filename extension. We synthesize the
|
||||
// output filename from the directory path and basename of the input
|
||||
// filename.
|
||||
|
||||
const char* const ext = strrchr(filename, '.');
|
||||
|
||||
if (ext == NULL) // TODO(matthewjheaney): liberalize?
|
||||
return false;
|
||||
|
||||
// Remember whether a track of this type has already been seen (the
|
||||
// map key) by keeping a count (the map item). We quality the
|
||||
// output filename with the track number if there is more than one
|
||||
// track having a given type.
|
||||
|
||||
std::map<MetadataInfo::Type, int> exists;
|
||||
|
||||
typedef metadata_map_t::iterator iter_t;
|
||||
|
||||
metadata_map_t& m = *metadata_map;
|
||||
const iter_t ii = m.begin();
|
||||
const iter_t j = m.end();
|
||||
|
||||
// Make a first pass over the cache to determine whether there is
|
||||
// more than one track corresponding to a given metadata type.
|
||||
|
||||
iter_t i = ii;
|
||||
while (i != j) {
|
||||
const metadata_map_t::value_type& v = *i++;
|
||||
const MetadataInfo& info = v.second;
|
||||
const MetadataInfo::Type type = info.type;
|
||||
++exists[type];
|
||||
}
|
||||
|
||||
// Make a second pass over the cache, synthesizing the filename of
|
||||
// each output file (from the input file basename, the input track
|
||||
// metadata type, and its track number if necessary), and then
|
||||
// opening a WebVTT output file having that filename.
|
||||
|
||||
i = ii;
|
||||
while (i != j) {
|
||||
metadata_map_t::value_type& v = *i++;
|
||||
MetadataInfo& info = v.second;
|
||||
const MetadataInfo::Type type = info.type;
|
||||
|
||||
// Start with the basename of the input file.
|
||||
|
||||
string name(filename, ext);
|
||||
|
||||
// Next append the metadata kind.
|
||||
|
||||
switch (type) {
|
||||
case MetadataInfo::kSubtitles:
|
||||
name += "_SUBTITLES";
|
||||
break;
|
||||
|
||||
case MetadataInfo::kCaptions:
|
||||
name += "_CAPTIONS";
|
||||
break;
|
||||
|
||||
case MetadataInfo::kDescriptions:
|
||||
name += "_DESCRIPTIONS";
|
||||
break;
|
||||
|
||||
case MetadataInfo::kMetadata:
|
||||
name += "_METADATA";
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there is more than one metadata track having a given type
|
||||
// (the WebVTT-in-WebM spec doesn't preclude this), then qualify
|
||||
// the output filename with the input track number.
|
||||
|
||||
if (exists[type] > 1) {
|
||||
enum { kLen = 33 };
|
||||
char str[kLen]; // max 126 tracks, so only 4 chars really needed
|
||||
snprintf(str, kLen, "%ld", v.first); // track number
|
||||
name += str;
|
||||
}
|
||||
|
||||
// Finally append the output filename extension.
|
||||
|
||||
name += ".vtt";
|
||||
|
||||
// We have synthesized the full output filename, so attempt to
|
||||
// open the WebVTT output file.
|
||||
|
||||
info.file = fopen(name.c_str(), "wb");
|
||||
|
||||
if (info.file == NULL) {
|
||||
printf("unable to open output file %s\n", name.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vttdemux::CloseFiles(metadata_map_t* metadata_map) {
|
||||
if (metadata_map == NULL)
|
||||
return;
|
||||
|
||||
metadata_map_t& m = *metadata_map;
|
||||
|
||||
typedef metadata_map_t::iterator iter_t;
|
||||
|
||||
iter_t i = m.begin();
|
||||
const iter_t j = m.end();
|
||||
|
||||
// Gracefully close each output file, to ensure all output gets
|
||||
// propertly flushed.
|
||||
|
||||
while (i != j) {
|
||||
metadata_map_t::value_type& v = *i++;
|
||||
MetadataInfo& info = v.second;
|
||||
|
||||
fclose(info.file);
|
||||
info.file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool vttdemux::WriteFiles(const metadata_map_t& m, mkvparser::Segment* s) {
|
||||
// First write the WebVTT header.
|
||||
|
||||
InitializeFiles(m);
|
||||
|
||||
// Now iterate over the clusters, writing the WebVTT cue as we parse
|
||||
// each metadata block.
|
||||
|
||||
const mkvparser::Cluster* cluster = s->GetFirst();
|
||||
|
||||
while (cluster != NULL && !cluster->EOS()) {
|
||||
if (!ProcessCluster(m, cluster))
|
||||
return false;
|
||||
|
||||
cluster = s->GetNext(cluster);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vttdemux::InitializeFiles(const metadata_map_t& m) {
|
||||
// Write the WebVTT header for each output file in the cache.
|
||||
|
||||
typedef metadata_map_t::const_iterator iter_t;
|
||||
iter_t i = m.begin();
|
||||
const iter_t j = m.end();
|
||||
|
||||
while (i != j) {
|
||||
const metadata_map_t::value_type& v = *i++;
|
||||
const MetadataInfo& info = v.second;
|
||||
FILE* const f = info.file;
|
||||
|
||||
if (fputs("WEBVTT\n", f) < 0) {
|
||||
printf("unable to initialize output file\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vttdemux::ProcessCluster(
|
||||
const metadata_map_t& m,
|
||||
const mkvparser::Cluster* c) {
|
||||
// Visit the blocks in this cluster, writing a WebVTT cue for each
|
||||
// metadata block.
|
||||
|
||||
const mkvparser::BlockEntry* block_entry;
|
||||
|
||||
long result = c->GetFirst(block_entry); // NOLINT
|
||||
if (result < 0) { // error
|
||||
printf("bad cluster (unable to get first block)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
while (block_entry != NULL && !block_entry->EOS()) {
|
||||
if (!ProcessBlockEntry(m, block_entry))
|
||||
return false;
|
||||
|
||||
result = c->GetNext(block_entry, block_entry);
|
||||
if (result < 0) { // error
|
||||
printf("bad cluster (unable to get next block)\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vttdemux::ProcessBlockEntry(
|
||||
const metadata_map_t& m,
|
||||
const mkvparser::BlockEntry* block_entry) {
|
||||
// If the track number for this block is in the cache, then we have
|
||||
// a metadata block, so write the WebVTT cue to the output file.
|
||||
|
||||
const mkvparser::Block* const block = block_entry->GetBlock();
|
||||
const long long tn = block->GetTrackNumber(); // NOLINT
|
||||
|
||||
typedef metadata_map_t::const_iterator iter_t;
|
||||
const iter_t i = m.find(tn);
|
||||
|
||||
if (i == m.end()) // not a metadata track
|
||||
return true; // nothing else to do
|
||||
|
||||
if (block_entry->GetKind() != mkvparser::BlockEntry::kBlockGroup)
|
||||
return false; // weird
|
||||
|
||||
typedef mkvparser::BlockGroup BG;
|
||||
const BG* const block_group = static_cast<const BG*>(block_entry);
|
||||
|
||||
const MetadataInfo& info = i->second;
|
||||
FILE* const f = info.file;
|
||||
|
||||
return WriteCue(f, block_group);
|
||||
}
|
||||
|
||||
bool vttdemux::WriteCue(
|
||||
FILE* f,
|
||||
const mkvparser::BlockGroup* block_group) {
|
||||
// Bind a FrameParser object to the block, which allows us to
|
||||
// extract each line of text from the payload of the block.
|
||||
FrameParser parser(block_group);
|
||||
|
||||
// We start a new cue by writing a cue separator (an empty line)
|
||||
// into the stream.
|
||||
|
||||
if (fputc('\n', f) < 0)
|
||||
return false;
|
||||
|
||||
// A WebVTT Cue comprises 3 things: a cue identifier, followed by
|
||||
// the cue timings, followed by the payload of the cue. We write
|
||||
// each part of the cue in sequence.
|
||||
|
||||
if (!WriteCueIdentifier(f, &parser))
|
||||
return false;
|
||||
|
||||
if (!WriteCueTimings(f, &parser))
|
||||
return false;
|
||||
|
||||
if (!WriteCuePayload(f, &parser))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vttdemux::WriteCueIdentifier(
|
||||
FILE* f,
|
||||
FrameParser* parser) {
|
||||
string line;
|
||||
int e = parser->GetLine(&line);
|
||||
|
||||
if (e) // error or EOS
|
||||
return false;
|
||||
|
||||
// If the cue identifier line is empty, this means that the original
|
||||
// WebVTT cue did not have a cue identifier, so we don't bother
|
||||
// writing an extra line terminator to the output file (though doing
|
||||
// so would be harmless).
|
||||
|
||||
if (!line.empty()) {
|
||||
if (fputs(line.c_str(), f) < 0)
|
||||
return false;
|
||||
|
||||
if (fputc('\n', f) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vttdemux::WriteCueTimings(
|
||||
FILE* f,
|
||||
FrameParser* parser) {
|
||||
const mkvparser::BlockGroup* const block_group = parser->block_group_;
|
||||
const mkvparser::Cluster* const cluster = block_group->GetCluster();
|
||||
const mkvparser::Block* const block = block_group->GetBlock();
|
||||
|
||||
// A WebVTT Cue "timings" line comprises two parts: the start and
|
||||
// stop time for this cue, followed by the (optional) cue settings,
|
||||
// such as orientation of the rendered text or its size. Only the
|
||||
// settings part of the cue timings line is stored in the WebM
|
||||
// block. We reconstruct the start and stop times of the WebVTT cue
|
||||
// from the timestamp and duration of the WebM block.
|
||||
|
||||
const mkvtime_t start_ns = block->GetTime(cluster);
|
||||
|
||||
if (!WriteCueTime(f, start_ns))
|
||||
return false;
|
||||
|
||||
if (fputs(" --> ", f) < 0)
|
||||
return false;
|
||||
|
||||
const mkvtime_t duration_timecode = block_group->GetDurationTimeCode();
|
||||
|
||||
if (duration_timecode < 0)
|
||||
return false;
|
||||
|
||||
const mkvparser::Segment* const segment = cluster->m_pSegment;
|
||||
const mkvparser::SegmentInfo* const info = segment->GetInfo();
|
||||
|
||||
if (info == NULL)
|
||||
return false;
|
||||
|
||||
const mkvtime_t timecode_scale = info->GetTimeCodeScale();
|
||||
|
||||
if (timecode_scale <= 0)
|
||||
return false;
|
||||
|
||||
const mkvtime_t duration_ns = duration_timecode * timecode_scale;
|
||||
const mkvtime_t stop_ns = start_ns + duration_ns;
|
||||
|
||||
if (!WriteCueTime(f, stop_ns))
|
||||
return false;
|
||||
|
||||
string line;
|
||||
int e = parser->GetLine(&line);
|
||||
|
||||
if (e) // error or EOS
|
||||
return false;
|
||||
|
||||
if (!line.empty()) {
|
||||
if (fputc(' ', f) < 0)
|
||||
return false;
|
||||
|
||||
if (fputs(line.c_str(), f) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fputc('\n', f) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vttdemux::WriteCueTime(
|
||||
FILE* f,
|
||||
mkvtime_t time_ns) {
|
||||
mkvtime_t ms = time_ns / 1000000; // WebVTT time has millisecond resolution
|
||||
|
||||
mkvtime_t sec = ms / 1000;
|
||||
ms -= sec * 1000;
|
||||
|
||||
mkvtime_t min = sec / 60;
|
||||
sec -= 60 * min;
|
||||
|
||||
mkvtime_t hr = min / 60;
|
||||
min -= 60 * hr;
|
||||
|
||||
if (hr > 0) {
|
||||
if (fprintf(f, "%02lld:", hr) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fprintf(f, "%02lld:%02lld.%03lld", min, sec, ms) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vttdemux::WriteCuePayload(
|
||||
FILE* f,
|
||||
FrameParser* parser) {
|
||||
int count = 0; // count of lines of payload text written to output file
|
||||
for (string line;;) {
|
||||
const int e = parser->GetLine(&line);
|
||||
|
||||
if (e < 0) // error (only -- we allow EOS here)
|
||||
return false;
|
||||
|
||||
if (line.empty()) // TODO(matthewjheaney): retain this check?
|
||||
break;
|
||||
|
||||
if (fprintf(f, "%s\n", line.c_str()) < 0)
|
||||
return false;
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
if (count <= 0) // WebVTT cue requires non-empty payload
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
57
vttreader.cc
Normal file
57
vttreader.cc
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include "./vttreader.h" // NOLINT
|
||||
|
||||
namespace libwebvtt {
|
||||
|
||||
VttReader::VttReader() : file_(NULL) {
|
||||
}
|
||||
|
||||
VttReader::~VttReader() {
|
||||
Close();
|
||||
}
|
||||
|
||||
int VttReader::Open(const char* filename) {
|
||||
if (filename == NULL || file_ != NULL)
|
||||
return -1;
|
||||
|
||||
file_ = fopen(filename, "rb");
|
||||
if (file_ == NULL)
|
||||
return -1;
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
void VttReader::Close() {
|
||||
if (file_) {
|
||||
fclose(file_);
|
||||
file_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int VttReader::GetChar(char* c) {
|
||||
if (c == NULL || file_ == NULL)
|
||||
return -1;
|
||||
|
||||
const int result = fgetc(file_);
|
||||
if (result != EOF) {
|
||||
*c = static_cast<char>(result);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
if (ferror(file_))
|
||||
return -1; // error
|
||||
|
||||
if (feof(file_))
|
||||
return 1; // EOF
|
||||
|
||||
return -1; // weird
|
||||
}
|
||||
|
||||
} // namespace libwebvtt
|
||||
44
vttreader.h
Normal file
44
vttreader.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef VTTREADER_H_ // NOLINT
|
||||
#define VTTREADER_H_
|
||||
|
||||
#include <cstdio>
|
||||
#include "./webvttparser.h"
|
||||
|
||||
namespace libwebvtt {
|
||||
|
||||
class VttReader : public libwebvtt::Reader {
|
||||
public:
|
||||
VttReader();
|
||||
virtual ~VttReader();
|
||||
|
||||
// Open the file identified by |filename| in read-only mode, as a
|
||||
// binary stream of bytes. Returns 0 on success, negative if error.
|
||||
int Open(const char* filename);
|
||||
|
||||
// Closes the file stream. Note that the stream is automatically
|
||||
// closed when the VttReader object is destroyed.
|
||||
void Close();
|
||||
|
||||
// Reads the next character in the file stream, as per the semantics
|
||||
// of Reader::GetChar. Returns negative if error, 0 on success, and
|
||||
// positive if end-of-stream has been reached.
|
||||
virtual int GetChar(char* c);
|
||||
|
||||
private:
|
||||
FILE* file_;
|
||||
|
||||
VttReader(const VttReader&);
|
||||
VttReader& operator=(const VttReader&);
|
||||
};
|
||||
|
||||
} // namespace libwebvtt
|
||||
|
||||
#endif // VTTREADER_H_ // NOLINT
|
||||
120
webmids.hpp
Normal file
120
webmids.hpp
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef WEBMIDS_HPP
|
||||
#define WEBMIDS_HPP
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
enum MkvId {
|
||||
kMkvEBML = 0x1A45DFA3,
|
||||
kMkvEBMLVersion = 0x4286,
|
||||
kMkvEBMLReadVersion = 0x42F7,
|
||||
kMkvEBMLMaxIDLength = 0x42F2,
|
||||
kMkvEBMLMaxSizeLength = 0x42F3,
|
||||
kMkvDocType = 0x4282,
|
||||
kMkvDocTypeVersion = 0x4287,
|
||||
kMkvDocTypeReadVersion = 0x4285,
|
||||
kMkvVoid = 0xEC,
|
||||
kMkvSignatureSlot = 0x1B538667,
|
||||
kMkvSignatureAlgo = 0x7E8A,
|
||||
kMkvSignatureHash = 0x7E9A,
|
||||
kMkvSignaturePublicKey = 0x7EA5,
|
||||
kMkvSignature = 0x7EB5,
|
||||
kMkvSignatureElements = 0x7E5B,
|
||||
kMkvSignatureElementList = 0x7E7B,
|
||||
kMkvSignedElement = 0x6532,
|
||||
//segment
|
||||
kMkvSegment = 0x18538067,
|
||||
//Meta Seek Information
|
||||
kMkvSeekHead = 0x114D9B74,
|
||||
kMkvSeek = 0x4DBB,
|
||||
kMkvSeekID = 0x53AB,
|
||||
kMkvSeekPosition = 0x53AC,
|
||||
//Segment Information
|
||||
kMkvInfo = 0x1549A966,
|
||||
kMkvTimecodeScale = 0x2AD7B1,
|
||||
kMkvDuration = 0x4489,
|
||||
kMkvDateUTC = 0x4461,
|
||||
kMkvMuxingApp = 0x4D80,
|
||||
kMkvWritingApp = 0x5741,
|
||||
//Cluster
|
||||
kMkvCluster = 0x1F43B675,
|
||||
kMkvTimecode = 0xE7,
|
||||
kMkvPrevSize = 0xAB,
|
||||
kMkvBlockGroup = 0xA0,
|
||||
kMkvBlock = 0xA1,
|
||||
kMkvBlockDuration = 0x9B,
|
||||
kMkvReferenceBlock = 0xFB,
|
||||
kMkvLaceNumber = 0xCC,
|
||||
kMkvSimpleBlock = 0xA3,
|
||||
//Track
|
||||
kMkvTracks = 0x1654AE6B,
|
||||
kMkvTrackEntry = 0xAE,
|
||||
kMkvTrackNumber = 0xD7,
|
||||
kMkvTrackUID = 0x73C5,
|
||||
kMkvTrackType = 0x83,
|
||||
kMkvFlagEnabled = 0xB9,
|
||||
kMkvFlagDefault = 0x88,
|
||||
kMkvFlagForced = 0x55AA,
|
||||
kMkvFlagLacing = 0x9C,
|
||||
kMkvDefaultDuration = 0x23E383,
|
||||
kMkvName = 0x536E,
|
||||
kMkvLanguage = 0x22B59C,
|
||||
kMkvCodecID = 0x86,
|
||||
kMkvCodecPrivate = 0x63A2,
|
||||
kMkvCodecName = 0x258688,
|
||||
//video
|
||||
kMkvVideo = 0xE0,
|
||||
kMkvFlagInterlaced = 0x9A,
|
||||
kMkvStereoMode = 0x53B8,
|
||||
kMkvPixelWidth = 0xB0,
|
||||
kMkvPixelHeight = 0xBA,
|
||||
kMkvPixelCropBottom = 0x54AA,
|
||||
kMkvPixelCropTop = 0x54BB,
|
||||
kMkvPixelCropLeft = 0x54CC,
|
||||
kMkvPixelCropRight = 0x54DD,
|
||||
kMkvDisplayWidth = 0x54B0,
|
||||
kMkvDisplayHeight = 0x54BA,
|
||||
kMkvDisplayUnit = 0x54B2,
|
||||
kMkvAspectRatioType = 0x54B3,
|
||||
kMkvFrameRate = 0x2383E3,
|
||||
//end video
|
||||
//audio
|
||||
kMkvAudio = 0xE1,
|
||||
kMkvSamplingFrequency = 0xB5,
|
||||
kMkvOutputSamplingFrequency = 0x78B5,
|
||||
kMkvChannels = 0x9F,
|
||||
kMkvBitDepth = 0x6264,
|
||||
//end audio
|
||||
//ContentEncodings
|
||||
kMkvContentEncodings = 0x6D80,
|
||||
kMkvContentEncoding = 0x6240,
|
||||
kMkvContentEncodingOrder = 0x5031,
|
||||
kMkvContentEncodingScope = 0x5032,
|
||||
kMkvContentEncodingType = 0x5033,
|
||||
kMkvContentEncryption = 0x5035,
|
||||
kMkvContentEncAlgo = 0x47E1,
|
||||
kMkvContentEncKeyID = 0x47E2,
|
||||
kMkvContentEncAESSettings = 0x47E7,
|
||||
kMkvAESSettingsCipherMode = 0x47E8,
|
||||
kMkvAESSettingsCipherInitData = 0x47E9,
|
||||
//end ContentEncodings
|
||||
//Cueing Data
|
||||
kMkvCues = 0x1C53BB6B,
|
||||
kMkvCuePoint = 0xBB,
|
||||
kMkvCueTime = 0xB3,
|
||||
kMkvCueTrackPositions = 0xB7,
|
||||
kMkvCueTrack = 0xF7,
|
||||
kMkvCueClusterPosition = 0xF1,
|
||||
kMkvCueBlockNumber = 0x5378,
|
||||
};
|
||||
|
||||
} // end namespace mkvmuxer
|
||||
|
||||
#endif // WEBMIDS_HPP
|
||||
706
webvttparser.cc
Normal file
706
webvttparser.cc
Normal file
@@ -0,0 +1,706 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include "./webvttparser.h" // NOLINT
|
||||
#include <climits>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace libwebvtt {
|
||||
|
||||
enum {
|
||||
kNUL = '\x00',
|
||||
kSPACE = ' ',
|
||||
kTAB = '\x09',
|
||||
kLF = '\x0A',
|
||||
kCR = '\x0D'
|
||||
};
|
||||
|
||||
Reader::~Reader() {
|
||||
}
|
||||
|
||||
LineReader::~LineReader() {
|
||||
}
|
||||
|
||||
int LineReader::GetLine(string* line_ptr) {
|
||||
if (line_ptr == NULL)
|
||||
return -1;
|
||||
|
||||
string& ln = *line_ptr;
|
||||
ln.clear();
|
||||
|
||||
// Consume characters from the stream, until we
|
||||
// reach end-of-line (or end-of-stream).
|
||||
|
||||
// The WebVTT spec states that lines may be
|
||||
// terminated in any of these three ways:
|
||||
// LF
|
||||
// CR
|
||||
// CR LF
|
||||
|
||||
// We interrogate each character as we read it from the stream.
|
||||
// If we detect an end-of-line character, we consume the full
|
||||
// end-of-line indication, and we're done; otherwise, accumulate
|
||||
// the character and repeat.
|
||||
|
||||
for (;;) {
|
||||
char c;
|
||||
const int e = GetChar(&c);
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (e > 0) // EOF
|
||||
return (ln.empty()) ? 1 : 0;
|
||||
|
||||
// We have a character, so we must first determine
|
||||
// whether we have reached end-of-line.
|
||||
|
||||
if (c == kLF)
|
||||
return 0; // handle the easy end-of-line case immediately
|
||||
|
||||
if (c == kCR)
|
||||
break; // handle the hard end-of-line case outside of loop
|
||||
|
||||
// To defend against pathological or malicious streams, we
|
||||
// cap the line length at some arbitrarily-large value:
|
||||
enum { kMaxLineLength = 10000 }; // arbitrary
|
||||
|
||||
if (ln.length() >= kMaxLineLength)
|
||||
return -1;
|
||||
|
||||
// We don't have an end-of-line character, so accumulate
|
||||
// the character in our line buffer.
|
||||
ln.push_back(c);
|
||||
}
|
||||
|
||||
// We detected a CR. We must interrogate the next character
|
||||
// in the stream, to determine whether we have a LF (which
|
||||
// would make it part of this same line).
|
||||
|
||||
char c;
|
||||
const int e = GetChar(&c);
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (e > 0) // EOF
|
||||
return 0;
|
||||
|
||||
// If next character in the stream is not a LF, return it
|
||||
// to the stream (because it's part of the next line).
|
||||
if (c != kLF)
|
||||
UngetChar(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Parser::Parser(Reader* r) : reader_(r), unget_(-1) {
|
||||
}
|
||||
|
||||
Parser::~Parser() {
|
||||
}
|
||||
|
||||
int Parser::Init() {
|
||||
int e = ParseBOM();
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (e > 0) // EOF
|
||||
return -1;
|
||||
|
||||
// Parse "WEBVTT". We read from the stream one character at-a-time, in
|
||||
// order to defend against non-WebVTT streams (e.g. binary files) that don't
|
||||
// happen to comprise lines of text demarcated with line terminators.
|
||||
|
||||
const char kId[] = "WEBVTT";
|
||||
|
||||
for (const char* p = kId; *p; ++p) {
|
||||
char c;
|
||||
e = GetChar(&c);
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (e > 0) // EOF
|
||||
return -1;
|
||||
|
||||
if (c != *p)
|
||||
return -1;
|
||||
}
|
||||
|
||||
string line;
|
||||
|
||||
e = GetLine(&line);
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (e > 0) // EOF
|
||||
return 0; // weird but valid
|
||||
|
||||
if (!line.empty()) {
|
||||
// Parse optional characters that follow "WEBVTT"
|
||||
|
||||
const char c = line[0];
|
||||
|
||||
if (c != kSPACE && c != kTAB)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The WebVTT spec requires that the "WEBVTT" line
|
||||
// be followed by an empty line (to separate it from
|
||||
// first cue).
|
||||
|
||||
e = GetLine(&line);
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (e > 0) // EOF
|
||||
return 0; // weird but we allow it
|
||||
|
||||
if (!line.empty())
|
||||
return -1;
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
int Parser::Parse(Cue* cue) {
|
||||
if (cue == NULL)
|
||||
return -1;
|
||||
|
||||
// Parse first non-blank line
|
||||
|
||||
string line;
|
||||
int e;
|
||||
|
||||
for (;;) {
|
||||
e = GetLine(&line);
|
||||
|
||||
if (e) // EOF is OK here
|
||||
return e;
|
||||
|
||||
if (!line.empty())
|
||||
break;
|
||||
}
|
||||
|
||||
// A WebVTT cue comprises an optional cue identifier line followed
|
||||
// by a (non-optional) timings line. You determine whether you have
|
||||
// a timings line by scanning for the arrow token, the lexeme of which
|
||||
// may not appear in the cue identifier line.
|
||||
|
||||
const char kArrow[] = "-->";
|
||||
string::size_type arrow_pos = line.find(kArrow);
|
||||
|
||||
if (arrow_pos != string::npos) {
|
||||
// We found a timings line, which implies that we don't have a cue
|
||||
// identifier.
|
||||
|
||||
cue->identifier.clear();
|
||||
} else {
|
||||
// We did not find a timings line, so we assume that we have a cue
|
||||
// identifier line, and then try again to find the cue timings on
|
||||
// the next line.
|
||||
|
||||
cue->identifier.swap(line);
|
||||
|
||||
e = GetLine(&line);
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (e > 0) // EOF
|
||||
return -1;
|
||||
|
||||
arrow_pos = line.find(kArrow);
|
||||
|
||||
if (arrow_pos == string::npos) // not a timings line
|
||||
return -1;
|
||||
}
|
||||
|
||||
e = ParseTimingsLine(&line,
|
||||
arrow_pos,
|
||||
&cue->start_time,
|
||||
&cue->stop_time,
|
||||
&cue->settings);
|
||||
|
||||
if (e) // error
|
||||
return e;
|
||||
|
||||
// The cue payload comprises all the non-empty
|
||||
// lines that follow the timings line.
|
||||
|
||||
Cue::payload_t& p = cue->payload;
|
||||
p.clear();
|
||||
|
||||
for (;;) {
|
||||
e = GetLine(&line);
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (line.empty())
|
||||
break;
|
||||
|
||||
p.push_back(line);
|
||||
}
|
||||
|
||||
if (p.empty())
|
||||
return -1;
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
int Parser::GetChar(char* c) {
|
||||
if (unget_ >= 0) {
|
||||
*c = static_cast<char>(unget_);
|
||||
unget_ = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return reader_->GetChar(c);
|
||||
}
|
||||
|
||||
void Parser::UngetChar(char c) {
|
||||
unget_ = static_cast<unsigned char>(c);
|
||||
}
|
||||
|
||||
int Parser::ParseBOM() {
|
||||
// Explanation of UTF-8 BOM:
|
||||
// http://en.wikipedia.org/wiki/Byte_order_mark
|
||||
|
||||
static const char BOM[] = "\xEF\xBB\xBF"; // UTF-8 BOM
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
char c;
|
||||
int e = GetChar(&c);
|
||||
|
||||
if (e < 0) // error
|
||||
return e;
|
||||
|
||||
if (e > 0) // EOF
|
||||
return 1;
|
||||
|
||||
if (c != BOM[i]) {
|
||||
if (i == 0) { // we don't have a BOM
|
||||
UngetChar(c);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// We started a BOM, so we must finish the BOM.
|
||||
return -1; // error
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
int Parser::ParseTimingsLine(
|
||||
string* line_ptr,
|
||||
string::size_type arrow_pos,
|
||||
Time* start_time,
|
||||
Time* stop_time,
|
||||
Cue::settings_t* settings) {
|
||||
if (line_ptr == NULL)
|
||||
return -1;
|
||||
|
||||
string& line = *line_ptr;
|
||||
|
||||
if (arrow_pos == string::npos || arrow_pos >= line.length())
|
||||
return -1;
|
||||
|
||||
// Place a NUL character at the start of the arrow token, in
|
||||
// order to demarcate the start time from remainder of line.
|
||||
line[arrow_pos] = kNUL;
|
||||
string::size_type idx = 0;
|
||||
|
||||
int e = ParseTime(line, &idx, start_time);
|
||||
if (e) // error
|
||||
return e;
|
||||
|
||||
// Detect any junk that follows the start time,
|
||||
// but precedes the arrow symbol.
|
||||
|
||||
while (char c = line[idx]) {
|
||||
if (c != kSPACE && c != kTAB)
|
||||
return -1;
|
||||
++idx;
|
||||
}
|
||||
|
||||
// Place a NUL character at the end of the line,
|
||||
// so the scanner has a place to stop, and begin
|
||||
// the scan just beyond the arrow token.
|
||||
|
||||
line.push_back(kNUL);
|
||||
idx = arrow_pos + 3;
|
||||
|
||||
e = ParseTime(line, &idx, stop_time);
|
||||
if (e) // error
|
||||
return e;
|
||||
|
||||
e = ParseSettings(line, idx, settings);
|
||||
if (e) // error
|
||||
return e;
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
int Parser::ParseTime(
|
||||
const string& line,
|
||||
string::size_type* idx_ptr,
|
||||
Time* time) {
|
||||
if (idx_ptr == NULL)
|
||||
return -1;
|
||||
|
||||
string::size_type& idx = *idx_ptr;
|
||||
|
||||
if (idx == string::npos || idx >= line.length())
|
||||
return -1;
|
||||
|
||||
if (time == NULL)
|
||||
return -1;
|
||||
|
||||
// Consume any whitespace that precedes the timestamp.
|
||||
|
||||
while (char c = line[idx]) {
|
||||
if (c != kSPACE && c != kTAB)
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
|
||||
// WebVTT timestamp syntax comes in three flavors:
|
||||
// SS[.sss]
|
||||
// MM:SS[.sss]
|
||||
// HH:MM:SS[.sss]
|
||||
|
||||
// Parse a generic number value. We don't know which component
|
||||
// of the time we have yet, until we do more parsing.
|
||||
|
||||
int val = ParseNumber(line, &idx);
|
||||
|
||||
if (val < 0) // error
|
||||
return val;
|
||||
|
||||
Time& t = *time;
|
||||
|
||||
// The presence of a colon character indicates that we have
|
||||
// an [HH:]MM:SS style syntax.
|
||||
|
||||
if (line[idx] == ':') {
|
||||
// We have either HH:MM:SS or MM:SS
|
||||
|
||||
// The value we just parsed is either the hours or minutes.
|
||||
// It must be followed by another number value (that is
|
||||
// either minutes or seconds).
|
||||
|
||||
const int first_val = val;
|
||||
|
||||
++idx; // consume colon
|
||||
|
||||
// Parse second value
|
||||
|
||||
val = ParseNumber(line, &idx);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val >= 60) // either MM or SS
|
||||
return -1;
|
||||
|
||||
if (line[idx] == ':') {
|
||||
// We have HH:MM:SS
|
||||
|
||||
t.hours = first_val;
|
||||
t.minutes = val; // vetted above
|
||||
|
||||
++idx; // consume MM:SS colon
|
||||
|
||||
// We have parsed the hours and minutes.
|
||||
// We must now parse the seconds.
|
||||
|
||||
val = ParseNumber(line, &idx);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val >= 60) // SS part of HH:MM:SS
|
||||
return -1;
|
||||
|
||||
t.seconds = val;
|
||||
} else {
|
||||
// We have MM:SS
|
||||
|
||||
// The implication here is that the hour value was omitted
|
||||
// from the timestamp (because it was 0).
|
||||
|
||||
if (first_val >= 60) // minutes
|
||||
return -1;
|
||||
|
||||
t.hours = 0;
|
||||
t.minutes = first_val;
|
||||
t.seconds = val; // vetted above
|
||||
}
|
||||
} else {
|
||||
// We have SS (only)
|
||||
|
||||
// The time is expressed as total number of seconds,
|
||||
// so the seconds value has no upper bound.
|
||||
|
||||
t.seconds = val;
|
||||
|
||||
// Convert SS to HH:MM:SS
|
||||
|
||||
t.minutes = t.seconds / 60;
|
||||
t.seconds -= t.minutes * 60;
|
||||
|
||||
t.hours = t.minutes / 60;
|
||||
t.minutes -= t.hours * 60;
|
||||
}
|
||||
|
||||
// We have parsed the hours, minutes, and seconds.
|
||||
// We must now parse the milliseconds.
|
||||
|
||||
if (line[idx] != '.') { // no milliseconds
|
||||
t.milliseconds = 0;
|
||||
} else {
|
||||
++idx; // consume FULL STOP
|
||||
|
||||
val = ParseNumber(line, &idx);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val >= 1000)
|
||||
return -1;
|
||||
|
||||
if (val < 10)
|
||||
t.milliseconds = val * 100;
|
||||
else if (val < 100)
|
||||
t.milliseconds = val * 10;
|
||||
else
|
||||
t.milliseconds = val;
|
||||
}
|
||||
|
||||
// We have parsed the time proper. We must check for any
|
||||
// junk that immediately follows the time specifier.
|
||||
|
||||
const char c = line[idx];
|
||||
|
||||
if (c != kNUL && c != kSPACE && c != kTAB)
|
||||
return -1;
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
int Parser::ParseSettings(
|
||||
const string& line,
|
||||
string::size_type idx,
|
||||
Cue::settings_t* settings) {
|
||||
settings->clear();
|
||||
|
||||
if (idx == string::npos || idx >= line.length())
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
// We must parse a line comprising a sequence of 0 or more
|
||||
// NAME:VALUE pairs, separated by whitespace. The line iself is
|
||||
// terminated with a NUL char (indicating end-of-line).
|
||||
|
||||
for (;;) {
|
||||
const char c = line[idx];
|
||||
|
||||
if (c == kNUL) // end-of-line
|
||||
return 0; // success
|
||||
|
||||
if (c != kSPACE && c != kTAB)
|
||||
break;
|
||||
|
||||
++idx; // consume whitespace
|
||||
}
|
||||
|
||||
// We have consumed the whitespace, and have not yet reached
|
||||
// end-of-line, so there is something on the line for us to parse.
|
||||
|
||||
settings->push_back(Setting());
|
||||
Setting& s = settings->back();
|
||||
|
||||
// Parse the NAME part of the settings pair.
|
||||
|
||||
for (;;) {
|
||||
const char c = line[idx];
|
||||
|
||||
if (c == ':') // we have reached end of NAME part
|
||||
break;
|
||||
|
||||
if (c == kNUL || c == kSPACE || c == kTAB)
|
||||
return -1;
|
||||
|
||||
s.name.push_back(c);
|
||||
|
||||
++idx;
|
||||
}
|
||||
|
||||
if (s.name.empty())
|
||||
return -1;
|
||||
|
||||
++idx; // consume colon
|
||||
|
||||
// Parse the VALUE part of the settings pair.
|
||||
|
||||
for (;;) {
|
||||
const char c = line[idx];
|
||||
|
||||
if (c == kNUL || c == kSPACE || c == kTAB)
|
||||
break;
|
||||
|
||||
if (c == ':') // suspicious when part of VALUE
|
||||
return -1; // TODO(matthewjheaney): verify this behavior
|
||||
|
||||
s.value.push_back(c);
|
||||
|
||||
++idx;
|
||||
}
|
||||
|
||||
if (s.value.empty())
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int Parser::ParseNumber(
|
||||
const string& line,
|
||||
string::size_type* idx_ptr) {
|
||||
if (idx_ptr == NULL)
|
||||
return -1;
|
||||
|
||||
string::size_type& idx = *idx_ptr;
|
||||
|
||||
if (idx == string::npos || idx >= line.length())
|
||||
return -1;
|
||||
|
||||
if (!isdigit(line[idx]))
|
||||
return -1;
|
||||
|
||||
long long val = 0; // NOLINT
|
||||
|
||||
while (isdigit(line[idx])) {
|
||||
val *= 10;
|
||||
val += static_cast<int>(line[idx] - '0');
|
||||
|
||||
if (val > INT_MAX)
|
||||
return -1;
|
||||
|
||||
++idx;
|
||||
}
|
||||
|
||||
return static_cast<int>(val);
|
||||
}
|
||||
|
||||
bool Time::operator==(const Time& rhs) const {
|
||||
if (hours != rhs.hours)
|
||||
return false;
|
||||
|
||||
if (minutes != rhs.minutes)
|
||||
return false;
|
||||
|
||||
if (seconds != rhs.seconds)
|
||||
return false;
|
||||
|
||||
return (milliseconds == rhs.milliseconds);
|
||||
}
|
||||
|
||||
bool Time::operator<(const Time& rhs) const {
|
||||
if (hours < rhs.hours)
|
||||
return true;
|
||||
|
||||
if (hours > rhs.hours)
|
||||
return false;
|
||||
|
||||
if (minutes < rhs.minutes)
|
||||
return true;
|
||||
|
||||
if (minutes > rhs.minutes)
|
||||
return false;
|
||||
|
||||
if (seconds < rhs.seconds)
|
||||
return true;
|
||||
|
||||
if (seconds > rhs.seconds)
|
||||
return false;
|
||||
|
||||
return (milliseconds < rhs.milliseconds);
|
||||
}
|
||||
|
||||
bool Time::operator>(const Time& rhs) const {
|
||||
return rhs.operator<(*this);
|
||||
}
|
||||
|
||||
bool Time::operator<=(const Time& rhs) const {
|
||||
return !this->operator>(rhs);
|
||||
}
|
||||
|
||||
bool Time::operator>=(const Time& rhs) const {
|
||||
return !this->operator<(rhs);
|
||||
}
|
||||
|
||||
presentation_t Time::presentation() const {
|
||||
const presentation_t h = 1000LL * 3600LL * presentation_t(hours);
|
||||
const presentation_t m = 1000LL * 60LL * presentation_t(minutes);
|
||||
const presentation_t s = 1000LL * presentation_t(seconds);
|
||||
const presentation_t result = h + m + s + milliseconds;
|
||||
return result;
|
||||
}
|
||||
|
||||
Time& Time::presentation(presentation_t d) {
|
||||
if (d < 0) { // error
|
||||
hours = 0;
|
||||
minutes = 0;
|
||||
seconds = 0;
|
||||
milliseconds = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
seconds = d / 1000;
|
||||
milliseconds = d - 1000 * seconds;
|
||||
|
||||
minutes = seconds / 60;
|
||||
seconds -= 60 * minutes;
|
||||
|
||||
hours = minutes / 60;
|
||||
minutes -= 60 * hours;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Time& Time::operator+=(presentation_t rhs) {
|
||||
const presentation_t d = this->presentation();
|
||||
const presentation_t dd = d + rhs;
|
||||
this->presentation(dd);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Time Time::operator+(presentation_t d) const {
|
||||
Time t(*this);
|
||||
t += d;
|
||||
return t;
|
||||
}
|
||||
|
||||
Time& Time::operator-=(presentation_t d) {
|
||||
return this->operator+=(-d);
|
||||
}
|
||||
|
||||
presentation_t Time::operator-(const Time& t) const {
|
||||
const presentation_t rhs = t.presentation();
|
||||
const presentation_t lhs = this->presentation();
|
||||
const presentation_t result = lhs - rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace libwebvtt
|
||||
162
webvttparser.h
Normal file
162
webvttparser.h
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#ifndef WEBVTTPARSER_H_ // NOLINT
|
||||
#define WEBVTTPARSER_H_
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace libwebvtt {
|
||||
|
||||
class Reader {
|
||||
public:
|
||||
// Fetch a character from the stream. Return
|
||||
// negative if error, positive if end-of-stream,
|
||||
// and 0 if a character is available.
|
||||
virtual int GetChar(char* c) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~Reader();
|
||||
};
|
||||
|
||||
class LineReader : protected Reader {
|
||||
public:
|
||||
// Consume a line of text from the stream, stripping off
|
||||
// the line terminator characters. Returns negative if error,
|
||||
// 0 on success, and positive at end-of-stream.
|
||||
int GetLine(std::string* line);
|
||||
|
||||
protected:
|
||||
virtual ~LineReader();
|
||||
|
||||
// Puts a character back into the stream.
|
||||
virtual void UngetChar(char c) = 0;
|
||||
};
|
||||
|
||||
// As measured in thousandths of a second,
|
||||
// e.g. a duration of 1 equals 0.001 seconds,
|
||||
// and a duration of 1000 equals 1 second.
|
||||
typedef long long presentation_t; // NOLINT
|
||||
|
||||
struct Time {
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
int milliseconds;
|
||||
|
||||
bool operator==(const Time& rhs) const;
|
||||
bool operator<(const Time& rhs) const;
|
||||
bool operator>(const Time& rhs) const;
|
||||
bool operator<=(const Time& rhs) const;
|
||||
bool operator>=(const Time& rhs) const;
|
||||
|
||||
presentation_t presentation() const;
|
||||
Time& presentation(presentation_t);
|
||||
|
||||
Time& operator+=(presentation_t);
|
||||
Time operator+(presentation_t) const;
|
||||
|
||||
Time& operator-=(presentation_t);
|
||||
presentation_t operator-(const Time&) const;
|
||||
};
|
||||
|
||||
struct Setting {
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct Cue {
|
||||
std::string identifier;
|
||||
|
||||
Time start_time;
|
||||
Time stop_time;
|
||||
|
||||
typedef std::list<Setting> settings_t;
|
||||
settings_t settings;
|
||||
|
||||
typedef std::list<std::string> payload_t;
|
||||
payload_t payload;
|
||||
};
|
||||
|
||||
class Parser : private LineReader {
|
||||
public:
|
||||
explicit Parser(Reader* r);
|
||||
virtual ~Parser();
|
||||
|
||||
// Pre-parse enough of the stream to determine whether
|
||||
// this is really a WEBVTT file. Returns 0 on success,
|
||||
// negative if error.
|
||||
int Init();
|
||||
|
||||
// Parse the next WebVTT cue from the stream. Returns 0 if
|
||||
// an entire cue was parsed, negative if error, and positive
|
||||
// at end-of-stream.
|
||||
int Parse(Cue* cue);
|
||||
|
||||
private:
|
||||
// Returns the next character in the stream, using the look-back character
|
||||
// if present (as per Reader::GetChar).
|
||||
virtual int GetChar(char* c);
|
||||
|
||||
// Puts a character back into the stream (as per LineReader::UngetChar).
|
||||
virtual void UngetChar(char c);
|
||||
|
||||
// Check for presence of a UTF-8 BOM in the stream. Returns
|
||||
// negative if error, 0 on success, and positive at end-of-stream.
|
||||
int ParseBOM();
|
||||
|
||||
// Parse the distinguished "cue timings" line, which includes the start
|
||||
// and stop times and settings. Argument |line| contains the complete
|
||||
// line of text (as returned by ParseLine()), which the function is free
|
||||
// to modify as it sees fit, to facilitate scanning. Argument |arrow_pos|
|
||||
// is the offset of the arrow token ("-->"), which indicates that this is
|
||||
// the timings line. Returns negative if error, 0 on success.
|
||||
//
|
||||
static int ParseTimingsLine(std::string* line,
|
||||
std::string::size_type arrow_pos,
|
||||
Time* start_time,
|
||||
Time* stop_time,
|
||||
Cue::settings_t* settings);
|
||||
|
||||
// Parse a single time specifier (from the timings line), starting
|
||||
// at the given offset; lexical scanning stops when a NUL character
|
||||
// is detected. The function modifies offset |off| by the number of
|
||||
// characters consumed. Returns negative if error, 0 on success.
|
||||
//
|
||||
static int ParseTime(const std::string& line,
|
||||
std::string::size_type* off,
|
||||
Time* time);
|
||||
|
||||
// Parse the cue settings from the timings line, starting at the
|
||||
// given offset. Returns negative if error, 0 on success.
|
||||
//
|
||||
static int ParseSettings(const std::string& line,
|
||||
std::string::size_type off,
|
||||
Cue::settings_t* settings);
|
||||
|
||||
// Parse a non-negative integer from the characters in |line| beginning
|
||||
// at offset |off|. The function increments |off| by the number
|
||||
// of characters consumed. Returns the value, or negative if error.
|
||||
//
|
||||
static int ParseNumber(const std::string& line,
|
||||
std::string::size_type* off);
|
||||
|
||||
Reader* const reader_;
|
||||
|
||||
// Provides one character's worth of look-back, to facilitate scanning.
|
||||
int unget_;
|
||||
|
||||
// Disable copy ctor and copy assign for Parser.
|
||||
Parser(const Parser&);
|
||||
Parser& operator=(const Parser&);
|
||||
};
|
||||
|
||||
} // namespace libwebvtt
|
||||
|
||||
#endif // WEBVTTPARSER_H_ // NOLINT
|
||||
Reference in New Issue
Block a user