Compare commits

..

3 Commits

Author SHA1 Message Date
matthewjheaney
379839bedc simplified segment::load()
Change-Id: I92793d405ee24f2d94a6a6a251a5bada4f0d40a8
2012-03-07 10:47:26 -05:00
matthewjheaney
484c71d875 parse seek head outside of ctor
Change-Id: I44bab1d7d6d7c08e11c3a73f72598426e92e4f89
2012-03-07 09:16:37 -05:00
matthewjheaney
a45b72d731 Parse headers outside of constructor
In several cases, the parser would parse a header
(say, a track header, or the segment info header)
in the constructor for the type.  The parser had
assumed (incorrectly) that the file was well-formed,
but this turned out to be an incorrect assumption.

The parse errors triggered some assertion failures,
but this is not acceptable in a production system.

The parser solved that problem by separating the
construction of the header object from the parsing
of the file.  There is now a separate parse method
to be called after construction of the object,
which returns a status whether the parse was
successful.

This change fixes the bugs from the following
tracker issues:

http://code.google.com/p/webm/issues/detail?id=399
http://code.google.com/p/webm/issues/detail?id=400

Change-Id: Idb09154ae7008429d8613ce3b3e8294f5a12de86
2012-03-06 17:58:45 -05:00
904 changed files with 16033 additions and 51395 deletions

View File

@ -1,97 +0,0 @@
---
Language: Cpp
# BasedOnStyle: Google
# Generated with clang-format 4.0.1
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
IncludeCategories:
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
...

6
.gitattributes vendored
View File

@ -1,6 +0,0 @@
*.sln eol=crlf
*.vcproj eol=crlf
*.vsprops eol=crlf
*.vcxproj eol=crlf
*.mkv -text -diff
*.webm -text -diff

22
.gitignore vendored
View File

@ -2,7 +2,6 @@
*.MKV *.MKV
core core
*.a *.a
*.d
*.so* *.so*
*.o *.o
*~ *~
@ -11,25 +10,6 @@ core
*.user *.user
*.suo *.suo
*.exe *.exe
/*.webm *.webm
Debug Debug
Release Release
*.sdf
*.opensdf
ipch
dumpvtt
mkvmuxer_sample
mkvparser_sample
vttdemux
mkvmuxer_tests
mkvparser_tests
webm_info
webm2pes
webm2pes_tests
webm2ts
vp9_header_parser_tests
vp9_level_stats_tests
Makefile
CMakeFiles
CMakeCache.txt
*.cmake

View File

@ -1,17 +1,13 @@
LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE:= libwebm LOCAL_MODULE:= libmkvparser
LOCAL_CPPFLAGS:=-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS LOCAL_SRC_FILES:= mkvparser.cpp \
LOCAL_CPPFLAGS+=-D__STDC_LIMIT_MACROS -std=c++11 mkvreader.cpp
LOCAL_C_INCLUDES:= $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)
LOCAL_SRC_FILES:= common/file_util.cc \
common/hdr_util.cc \
mkvparser/mkvparser.cc \
mkvparser/mkvreader.cc \
mkvmuxer/mkvmuxer.cc \
mkvmuxer/mkvmuxerutil.cc \
mkvmuxer/mkvwriter.cc
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= mkvparser
LOCAL_SRC_FILES:= sample.cpp
LOCAL_STATIC_LIBRARIES:= libmkvparser
include $(BUILD_EXECUTABLE)

View File

@ -1,436 +0,0 @@
## Copyright (c) 2015 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.
cmake_minimum_required(VERSION 3.2)
project(LIBWEBM CXX)
include("${CMAKE_CURRENT_SOURCE_DIR}/build/cxx_flags.cmake")
if (NOT BUILD_SHARED_LIBS)
include("${CMAKE_CURRENT_SOURCE_DIR}/build/msvc_runtime.cmake")
endif ()
set(LIBWEBM_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
# Build/test configuration flags.
option(ENABLE_WEBMTS "Enables WebM PES/TS support." ON)
option(ENABLE_WEBMINFO "Enables building webm_info." ON)
option(ENABLE_TESTS "Enables tests." OFF)
option(ENABLE_IWYU "Enables include-what-you-use support." OFF)
option(ENABLE_WERROR "Enable warnings as errors." OFF)
option(ENABLE_WEBM_PARSER "Enables new parser API." OFF)
require_cxx_flag_nomsvc("-std=c++11")
add_cxx_preproc_definition("__STDC_CONSTANT_MACROS")
add_cxx_preproc_definition("__STDC_FORMAT_MACROS")
add_cxx_preproc_definition("__STDC_LIMIT_MACROS")
# Set up compiler flags and build properties.
include_directories("${LIBWEBM_SRC_DIR}")
if (MSVC)
add_cxx_flag_if_supported("/W4")
# Disable MSVC warnings that suggest making code non-portable.
add_cxx_flag_if_supported("/wd4996")
if (ENABLE_WERROR)
add_cxx_flag_if_supported("/WX")
endif ()
else ()
add_cxx_flag_if_supported("-Wall")
add_cxx_flag_if_supported("-Wextra")
add_cxx_flag_if_supported("-Wnarrowing")
add_cxx_flag_if_supported("-Wno-deprecated")
add_cxx_flag_if_supported("-Wshorten-64-to-32")
if (ENABLE_WERROR)
add_cxx_flag_if_supported("-Werror")
endif ()
endif ()
# Source list variables.
set(dumpvtt_sources "${LIBWEBM_SRC_DIR}/dumpvtt.cc")
set(libwebm_common_sources
"${LIBWEBM_SRC_DIR}/common/file_util.cc"
"${LIBWEBM_SRC_DIR}/common/file_util.h"
"${LIBWEBM_SRC_DIR}/common/hdr_util.cc"
"${LIBWEBM_SRC_DIR}/common/hdr_util.h"
"${LIBWEBM_SRC_DIR}/common/webmids.h")
set(mkvmuxer_sources
"${LIBWEBM_SRC_DIR}/mkvmuxer/mkvmuxer.cc"
"${LIBWEBM_SRC_DIR}/mkvmuxer/mkvmuxer.h"
"${LIBWEBM_SRC_DIR}/mkvmuxer/mkvmuxertypes.h"
"${LIBWEBM_SRC_DIR}/mkvmuxer/mkvmuxerutil.cc"
"${LIBWEBM_SRC_DIR}/mkvmuxer/mkvmuxerutil.h"
"${LIBWEBM_SRC_DIR}/mkvmuxer/mkvwriter.cc"
"${LIBWEBM_SRC_DIR}/mkvmuxer/mkvwriter.h"
"${LIBWEBM_SRC_DIR}/common/webmids.h")
set(mkvmuxer_sample_sources
"${LIBWEBM_SRC_DIR}/mkvmuxer_sample.cc"
"${LIBWEBM_SRC_DIR}/sample_muxer_metadata.cc"
"${LIBWEBM_SRC_DIR}/sample_muxer_metadata.h")
set(mkvmuxer_tests_sources
"${LIBWEBM_SRC_DIR}/testing/mkvmuxer_tests.cc"
"${LIBWEBM_SRC_DIR}/testing/test_util.cc"
"${LIBWEBM_SRC_DIR}/testing/test_util.h")
set(mkvparser_sources
"${LIBWEBM_SRC_DIR}/mkvparser/mkvparser.cc"
"${LIBWEBM_SRC_DIR}/mkvparser/mkvparser.h"
"${LIBWEBM_SRC_DIR}/mkvparser/mkvreader.cc"
"${LIBWEBM_SRC_DIR}/mkvparser/mkvreader.h"
"${LIBWEBM_SRC_DIR}/common/webmids.h")
set(mkvparser_sample_sources "${LIBWEBM_SRC_DIR}/mkvparser_sample.cc")
set(mkvparser_tests_sources
"${LIBWEBM_SRC_DIR}/testing/mkvparser_tests.cc"
"${LIBWEBM_SRC_DIR}/testing/test_util.cc"
"${LIBWEBM_SRC_DIR}/testing/test_util.h")
set(vp9_header_parser_tests_sources
"${LIBWEBM_SRC_DIR}/common/vp9_header_parser_tests.cc"
"${LIBWEBM_SRC_DIR}/common/vp9_header_parser.cc"
"${LIBWEBM_SRC_DIR}/common/vp9_header_parser.h"
"${LIBWEBM_SRC_DIR}/testing/test_util.cc"
"${LIBWEBM_SRC_DIR}/testing/test_util.h")
set(vp9_level_stats_tests_sources
"${LIBWEBM_SRC_DIR}/common/vp9_header_parser.cc"
"${LIBWEBM_SRC_DIR}/common/vp9_header_parser.h"
"${LIBWEBM_SRC_DIR}/common/vp9_level_stats_tests.cc"
"${LIBWEBM_SRC_DIR}/common/vp9_level_stats.cc"
"${LIBWEBM_SRC_DIR}/common/vp9_level_stats.h"
"${LIBWEBM_SRC_DIR}/testing/test_util.cc"
"${LIBWEBM_SRC_DIR}/testing/test_util.h")
set(vttdemux_sources
"${LIBWEBM_SRC_DIR}/vttdemux.cc"
"${LIBWEBM_SRC_DIR}/webvtt/webvttparser.cc"
"${LIBWEBM_SRC_DIR}/webvtt/webvttparser.h")
set(webm_parser_sources
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/buffer_reader.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/callback.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/dom_types.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/element.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/file_reader.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/id.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/istream_reader.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/reader.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/status.h"
"${LIBWEBM_SRC_DIR}/webm_parser/include/webm/webm_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/ancestory.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/ancestory.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/audio_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/bit_utils.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/bit_utils.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/block_additions_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/block_group_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/block_header_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/block_header_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/block_more_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/block_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/block_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/bool_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/buffer_reader.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/byte_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/callback.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/chapter_atom_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/chapter_display_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/chapters_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/cluster_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/colour_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/content_enc_aes_settings_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/content_encoding_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/content_encodings_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/content_encryption_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/cue_point_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/cue_track_positions_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/cues_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/date_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/date_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/ebml_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/edition_entry_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/element_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/file_reader.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/float_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/float_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/id_element_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/id_element_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/id_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/id_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/info_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/int_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/istream_reader.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/master_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/master_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/master_value_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/mastering_metadata_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/parser_utils.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/parser_utils.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/projection_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/recursive_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/seek_head_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/seek_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/segment_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/segment_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/simple_tag_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/size_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/size_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/skip_callback.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/skip_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/skip_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/slices_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/tag_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/tags_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/targets_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/time_slice_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/track_entry_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/tracks_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/unknown_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/unknown_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/var_int_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/var_int_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/video_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/virtual_block_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/virtual_block_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/void_parser.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/src/void_parser.h"
"${LIBWEBM_SRC_DIR}/webm_parser/src/webm_parser.cc")
set(webm_parser_demo_sources "${LIBWEBM_SRC_DIR}/webm_parser/demo/demo.cc")
set(webm_parser_tests_sources
"${LIBWEBM_SRC_DIR}/webm_parser/tests/audio_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/bit_utils_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/block_additions_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/block_group_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/block_header_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/block_more_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/block_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/bool_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/buffer_reader_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/byte_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/callback_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/chapter_atom_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/chapter_display_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/chapters_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/cluster_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/colour_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/content_enc_aes_settings_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/content_encoding_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/content_encodings_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/content_encryption_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/cue_point_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/cue_track_positions_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/cues_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/date_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/ebml_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/edition_entry_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/element_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/float_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/id_element_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/id_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/info_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/int_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/istream_reader_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/limited_reader_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/master_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/master_value_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/mastering_metadata_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/parser_utils_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/projection_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/recursive_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/seek_head_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/seek_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/segment_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/simple_tag_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/size_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/skip_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/slices_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/tag_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/tags_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/targets_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/time_slice_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/track_entry_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/tracks_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/unknown_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/var_int_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/video_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/virtual_block_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/void_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/webm_parser_test.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/test_utils/element_parser_test.h"
"${LIBWEBM_SRC_DIR}/webm_parser/test_utils/limited_reader.cc"
"${LIBWEBM_SRC_DIR}/webm_parser/test_utils/limited_reader.h"
"${LIBWEBM_SRC_DIR}/webm_parser/test_utils/mock_callback.h"
"${LIBWEBM_SRC_DIR}/webm_parser/test_utils/parser_test.h"
"${LIBWEBM_SRC_DIR}/webm_parser/tests/webm_parser_tests.cc")
set(webm_info_sources
"${LIBWEBM_SRC_DIR}/common/indent.cc"
"${LIBWEBM_SRC_DIR}/common/indent.h"
"${LIBWEBM_SRC_DIR}/common/vp9_header_parser.cc"
"${LIBWEBM_SRC_DIR}/common/vp9_header_parser.h"
"${LIBWEBM_SRC_DIR}/common/vp9_level_stats.cc"
"${LIBWEBM_SRC_DIR}/common/vp9_level_stats.h"
"${LIBWEBM_SRC_DIR}/common/webm_constants.h"
"${LIBWEBM_SRC_DIR}/common/webm_endian.cc"
"${LIBWEBM_SRC_DIR}/common/webm_endian.h"
"${LIBWEBM_SRC_DIR}/webm_info.cc")
set(webmts_sources
"${LIBWEBM_SRC_DIR}/common/libwebm_util.cc"
"${LIBWEBM_SRC_DIR}/common/libwebm_util.h"
"${LIBWEBM_SRC_DIR}/common/video_frame.cc"
"${LIBWEBM_SRC_DIR}/common/video_frame.h"
"${LIBWEBM_SRC_DIR}/m2ts/vpxpes2ts.cc"
"${LIBWEBM_SRC_DIR}/m2ts/vpxpes2ts.h"
"${LIBWEBM_SRC_DIR}/m2ts/vpxpes_parser.cc"
"${LIBWEBM_SRC_DIR}/m2ts/vpxpes_parser.h"
"${LIBWEBM_SRC_DIR}/m2ts/webm2pes.cc"
"${LIBWEBM_SRC_DIR}/m2ts/webm2pes.h")
set(webm2pes_sources "${LIBWEBM_SRC_DIR}/m2ts/webm2pes_main.cc")
set(webm2pes_tests_sources
"${LIBWEBM_SRC_DIR}/testing/test_util.cc"
"${LIBWEBM_SRC_DIR}/testing/test_util.h"
"${LIBWEBM_SRC_DIR}/testing/video_frame_tests.cc"
"${LIBWEBM_SRC_DIR}/m2ts/tests/webm2pes_tests.cc")
set(webm2ts_sources "${LIBWEBM_SRC_DIR}/m2ts/vpxpes2ts_main.cc")
set(webvtt_common_sources
"${LIBWEBM_SRC_DIR}/webvtt/vttreader.cc"
"${LIBWEBM_SRC_DIR}/webvtt/vttreader.h"
"${LIBWEBM_SRC_DIR}/webvtt/webvttparser.cc"
"${LIBWEBM_SRC_DIR}/webvtt/webvttparser.h")
# Targets.
add_library(mkvmuxer OBJECT ${mkvmuxer_sources})
add_library(mkvparser OBJECT ${mkvparser_sources})
add_library(webvtt_common OBJECT ${webvtt_common_sources})
add_library(webm ${libwebm_common_sources}
$<TARGET_OBJECTS:mkvmuxer>
$<TARGET_OBJECTS:mkvparser>)
if (WIN32)
# Use libwebm and libwebm.lib for project and library name on Windows (instead
# webm and webm.lib).
set_target_properties(webm PROPERTIES PROJECT_LABEL libwebm)
set_target_properties(webm PROPERTIES PREFIX lib)
endif ()
add_executable(mkvparser_sample ${mkvparser_sample_sources})
target_link_libraries(mkvparser_sample LINK_PUBLIC webm)
add_executable(mkvmuxer_sample ${mkvmuxer_sample_sources}
$<TARGET_OBJECTS:webvtt_common>)
target_link_libraries(mkvmuxer_sample LINK_PUBLIC webm)
add_executable(dumpvtt ${dumpvtt_sources} $<TARGET_OBJECTS:webvtt_common>)
target_link_libraries(dumpvtt LINK_PUBLIC webm)
add_executable(vttdemux ${vttdemux_sources})
target_link_libraries(vttdemux LINK_PUBLIC webm)
if (ENABLE_WEBMINFO)
add_executable(webm_info ${webm_info_sources})
target_link_libraries(webm_info LINK_PUBLIC webm)
endif ()
if (ENABLE_WEBM_PARSER)
include_directories(webm_parser webm_parser/include)
add_library(webm_parser OBJECT ${webm_parser_sources})
target_sources(webm PUBLIC $<TARGET_OBJECTS:webm_parser>)
add_executable(webm_parser_demo ${webm_parser_demo_sources})
target_link_libraries(webm_parser_demo LINK_PUBLIC webm)
endif ()
if (ENABLE_WEBMTS)
add_library(webmts OBJECT ${webmts_sources})
add_executable(webm2pes ${webm2pes_sources} $<TARGET_OBJECTS:webmts>)
target_link_libraries(webm2pes LINK_PUBLIC webm)
add_executable(webm2ts ${webm2ts_sources} $<TARGET_OBJECTS:webmts>)
target_link_libraries(webm2ts LINK_PUBLIC webm)
endif ()
if (ENABLE_TESTS)
set(GTEST_SRC_DIR "${LIBWEBM_SRC_DIR}/../googletest" CACHE PATH
"Path to Googletest git repository.")
# This directory is where libwebm will build googletest dependencies.
set(GTEST_BUILD_DIR "${CMAKE_BINARY_DIR}/googletest_build")
if (LIBWEBM_DISABLE_GTEST_CMAKE)
add_library(gtest STATIC "${GTEST_SRC_DIR}/googletest/src/gtest-all.cc")
include_directories("${GTEST_SRC_DIR}/googletest")
else ()
add_subdirectory("${GTEST_SRC_DIR}" "${GTEST_BUILD_DIR}")
endif ()
include_directories("${GTEST_SRC_DIR}/googletest/include")
add_executable(mkvmuxer_tests ${mkvmuxer_tests_sources})
target_link_libraries(mkvmuxer_tests LINK_PUBLIC gtest webm)
add_executable(mkvparser_tests ${mkvparser_tests_sources})
target_link_libraries(mkvparser_tests LINK_PUBLIC gtest webm)
add_executable(vp9_header_parser_tests ${vp9_header_parser_tests_sources})
target_link_libraries(vp9_header_parser_tests LINK_PUBLIC gtest webm)
add_executable(vp9_level_stats_tests ${vp9_level_stats_tests_sources})
target_link_libraries(vp9_level_stats_tests LINK_PUBLIC gtest webm)
if (ENABLE_WEBMTS)
add_executable(webm2pes_tests ${webm2pes_tests_sources}
$<TARGET_OBJECTS:webmts>)
target_link_libraries(webm2pes_tests LINK_PUBLIC gtest webm)
endif ()
if (ENABLE_WEBM_PARSER)
include_directories("${GTEST_SRC_DIR}/googlemock/include")
add_executable(webm_parser_tests ${webm_parser_tests_sources})
target_link_libraries(webm_parser_tests LINK_PUBLIC gmock gtest webm)
endif ()
endif ()
# Include-what-you-use.
if (ENABLE_IWYU)
# Make sure all the tools necessary for IWYU are present.
find_program(iwyu_path NAMES include-what-you-use)
find_program(iwyu_tool_path NAMES iwyu_tool.py)
# Some odd behavior on cmake's part: PYTHON_EXECUTABLE and PYTHON_VERSION_*
# are set by cmake when it does its internal python check, but
# PYTHONINTERP_FOUND is empty without explicitly looking for it.
find_package(PythonInterp)
if (iwyu_path AND iwyu_tool_path AND PYTHONINTERP_FOUND)
# Enable compilation command export (needed for iwyu_tool.py)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Add a custom target to run iwyu across all targets.
add_custom_target(iwyu
ALL
COMMAND "${PYTHON_EXECUTABLE}" "${iwyu_tool_path}" -p
"${CMAKE_BINARY_DIR}"
COMMENT "Running include-what-you-use..."
VERBATIM)
else ()
message(STATUS "Ignoring ENABLE_IWYU because reasons:")
message(STATUS " iwyu_path=" ${iwyu_path})
message(STATUS " iwyu_tool_path=" ${iwyu_tool_path})
message(STATUS " PYTHONINTERP_FOUND=" ${PYTHONINTERP_FOUND})
message(STATUS " See README.libwebm for more information.")
endif ()
endif ()

25
Makefile Normal file
View File

@ -0,0 +1,25 @@
CXX := g++
CXXFLAGS := -W -Wall -g
LIBWEBM := libwebm.a
WEBMOBJS := mkvparser.o mkvreader.o mkvmuxer.o mkvmuxerutil.o mkvwriter.o
OBJECTS1 := $(PARSEOBJ) sample.o
OBJECTS2 := $(PARSEOBJ) $(MUXEROBJ) sample_muxer/sample_muxer.o
INCLUDES := -I.
EXES := samplemuxer sample
all: $(EXES)
sample: sample.o $(LIBWEBM)
$(CXX) $^ -o $@
samplemuxer: sample_muxer/sample_muxer.o $(LIBWEBM)
$(CXX) $^ -o $@
libwebm.a: $(WEBMOBJS)
$(AR) rcs $@ $^
%.o: %.cpp
$(CXX) -c $(CXXFLAGS) $(INCLUDES) $< -o $@
clean:
$(RM) -f $(OBJECTS1) $(OBJECTS2) $(WEBMOBJS) $(LIBWEBM) $(EXES) Makefile.bak

View File

@ -1,57 +0,0 @@
CXX := g++
DEFINES := -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
DEFINES += -D__STDC_LIMIT_MACROS
INCLUDES := -I.
CXXFLAGS := -W -Wall -g -std=c++11
ALL_CXXFLAGS := -MMD -MP $(DEFINES) $(INCLUDES) $(CXXFLAGS)
LIBWEBMA := libwebm.a
LIBWEBMSO := libwebm.so
WEBMOBJS := mkvmuxer/mkvmuxer.o mkvmuxer/mkvmuxerutil.o mkvmuxer/mkvwriter.o
WEBMOBJS += mkvparser/mkvparser.o mkvparser/mkvreader.o
WEBMOBJS += common/file_util.o common/hdr_util.o
OBJSA := $(WEBMOBJS:.o=_a.o)
OBJSSO := $(WEBMOBJS:.o=_so.o)
VTTOBJS := webvtt/vttreader.o webvtt/webvttparser.o sample_muxer_metadata.o
EXEOBJS := mkvmuxer_sample.o mkvparser_sample.o dumpvtt.o vttdemux.o
EXES := mkvparser_sample mkvmuxer_sample dumpvtt vttdemux
DEPS := $(WEBMOBJS:.o=.d) $(OBJECTS1:.o=.d) $(OBJECTS2:.o=.d)
DEPS += $(OBJECTS3:.o=.d) $(OBJECTS4:.o=.d) $(OBJSA:.o=.d) $(OBJSSO:.o=.d)
DEPS += $(VTTOBJS:.o=.d) $(EXEOBJS:.o=.d)
CLEAN := $(EXEOBJS) $(VTTOBJS) $(WEBMOBJS) $(OBJSA) $(OBJSSO) $(LIBWEBMA)
CLEAN += $(LIBWEBMSO) $(EXES) $(DEPS) $(INFOOBJS)
all: $(EXES)
mkvparser_sample: mkvparser_sample.o $(LIBWEBMA)
$(CXX) $^ -o $@
mkvmuxer_sample: mkvmuxer_sample.o $(VTTOBJS) $(LIBWEBMA)
$(CXX) $^ -o $@
dumpvtt: dumpvtt.o $(VTTOBJS) $(WEBMOBJS)
$(CXX) $^ -o $@
vttdemux: vttdemux.o $(VTTOBJS) $(LIBWEBMA)
$(CXX) $^ -o $@
shared: $(LIBWEBMSO)
libwebm.a: $(OBJSA)
$(AR) rcs $@ $^
libwebm.so: $(OBJSSO)
$(CXX) $(ALL_CXXFLAGS) -shared $(OBJSSO) -o $(LIBWEBMSO)
%.o: %.cc
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
%_a.o: %.cc
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
%_so.o: %.cc
$(CXX) -c $(ALL_CXXFLAGS) -fPIC $< -o $@
clean:
$(RM) -f $(CLEAN) Makefile.bak
ifneq ($(MAKECMDGOALS), clean)
-include $(DEPS)
endif

View File

@ -1,23 +1,22 @@
Additional IP Rights Grant (Patents) Additional IP Rights Grant (Patents)
------------------------------------
"These implementations" means the copyrightable works that implement the WebM "This implementation" means the copyrightable works distributed by
codecs distributed by Google as part of the WebM Project. Google as part of the WebM Project.
Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge, Google hereby grants to you a perpetual, worldwide, non-exclusive,
royalty-free, irrevocable (except as stated in this section) patent license to no-charge, royalty-free, irrevocable (except as stated in this section)
make, have made, use, offer to sell, sell, import, transfer, and otherwise patent license to make, have made, use, offer to sell, sell, import,
run, modify and propagate the contents of these implementations of WebM, where transfer, and otherwise run, modify and propagate the contents of this
such license applies only to those patent claims, both currently owned by implementation of VP8, where such license applies only to those patent
Google and acquired in the future, licensable by Google that are necessarily claims, both currently owned by Google and acquired in the future,
infringed by these implementations of WebM. This grant does not include claims licensable by Google that are necessarily infringed by this
that would be infringed only as a consequence of further modification of these implementation of VP8. This grant does not include claims that would be
implementations. If you or your agent or exclusive licensee institute or order infringed only as a consequence of further modification of this
or agree to the institution of patent litigation or any other patent implementation. If you or your agent or exclusive licensee institute or
enforcement activity against any entity (including a cross-claim or order or agree to the institution of patent litigation against any
counterclaim in a lawsuit) alleging that any of these implementations of WebM entity (including a cross-claim or counterclaim in a lawsuit) alleging
or any code incorporated within any of these implementations of WebM that this implementation of VP8 or any code incorporated within this
constitute direct or contributory patent infringement, or inducement of implementation of VP8 constitutes direct or contributory patent
patent infringement, then any patent rights granted to you under this License infringement, or inducement of patent infringement, then any patent
for these implementations of WebM shall terminate as of the date such rights granted to you under this License for this implementation of VP8
litigation is filed. shall terminate as of the date such litigation is filed.

View File

@ -1,143 +0,0 @@
Building Libwebm
To build libwebm you must first create project files. To do this run cmake
and pass it the path to your libwebm repo.
Makefile.unix can be used as a fallback on systems that cmake does not
support.
CMake Basics
To generate project/make files for the default toolchain on your system simply
run cmake with the path to the libwebm repo:
$ cmake path/to/libwebm
On Windows the above command will produce Visual Studio project files for the
newest Visual Studio detected on the system. On Mac OS X and Linux systems, the
above command will produce a makefile.
To control what types of projects are generated the -G parameter is added to
the cmake command line. This argument must be followed by the name of a
generator. Running cmake with the --help argument will list the available
generators for your system.
On Mac OS X you would run the following command to generate Xcode projects:
$ cmake path/to/libwebm -G Xcode
On a Windows box you would run the following command to generate Visual Studio
2013 projects:
$ cmake path/to/libwebm -G "Visual Studio 12"
To generate 64-bit Windows Visual Studio 2013 projects:
$ cmake path/to/libwebm "Visual Studio 12 Win64"
CMake Makefiles: Debugging and Optimization
Unlike Visual Studio and Xcode projects, the build configuration for make builds
is controlled when you run cmake. The following examples demonstrate various
build configurations.
Omitting the build type produces makefiles that use build flags containing
neither optimization nor debug flags:
$ cmake path/to/libwebm
A makefile using release (optimized) flags is produced like this:
$ cmake path/to/libwebm -DCMAKE_BUILD_TYPE=release
A release build with debug info can be produced as well:
$ cmake path/to/libwebm -DCMAKE_BUILD_TYPE=relwithdebinfo
And your standard debug build will be produced using:
$ cmake path/to/libwebm -DCMAKE_BUILD_TYPE=debug
Tests
To enable libwebm tests add -DENABLE_TESTS=ON CMake generation command line. For
example:
$ cmake path/to/libwebm -G Xcode -DENABLE_TESTS=ON
Libwebm tests depend on googletest. By default googletest is expected to be a
sibling directory of the Libwebm repository. To change that, update your CMake
command to be similar to the following:
$ cmake path/to/libwebm -G Xcode -DENABLE_TESTS=ON \
-DGTEST_SRC_DIR=/path/to/googletest
The tests rely upon the LIBWEBM_TEST_DATA_PATH environment variable to locate
test input. The following example demonstrates running the muxer tests from the
build directory:
$ LIBWEBM_TEST_DATA_PATH=path/to/libwebm/testing/testdata ./mkvmuxer_tests
Note: Libwebm Googletest integration was built with googletest from
https://github.com/google/googletest.git at git revision
ddb8012eb48bc203aa93dcc2b22c1db516302b29.
CMake Include-what-you-use integration
Include-what-you-use is an analysis tool that helps ensure libwebm includes the
C/C++ header files actually in use. To enable the integration support
ENABLE_IWYU must be turned on at cmake run time:
$ cmake path/to/libwebm -G "Unix Makefiles" -DENABLE_IWYU=ON
This adds the iwyu target to the build. To run include-what-you-use:
$ make iwyu
The following requirements must be met for ENABLE_IWYU to enable the iwyu
target:
1. include-what-you-use and iwyu_tool.py must be in your PATH.
2. A python interpreter must be on the system and available to CMake.
The values of the following variables are used to determine if the requirements
have been met. Values to the right of the equals sign are what a successful run
might look like:
iwyu_path=/path/to/iwyu_tool.py
iwyu_tool_path=/path/to/include-what-you-use
PYTHONINTERP_FOUND=TRUE
An empty PYTHONINTERP_FOUND, or iwyu_path/iwyu_tool_path suffixed with NOTFOUND
are failures.
For Include-what-you-use setup instructions, see:
https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/InstructionsForUsers.md
If, when building the iwyu target, compile errors reporting failures loading
standard include files occur, one solution can be found here:
https://github.com/include-what-you-use/include-what-you-use/issues/100
CMake cross compile
To cross compile libwebm for Windows using mingw-w64 run cmake with the
following arguments:
$ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/libwebm/build/mingw-w64_toolchain.cmake \
path/to/libwebm
Note1: As of this writing googletest will not build via mingw-w64 without
disabling pthreads.
googletest hash: d225acc90bc3a8c420a9bcd1f033033c1ccd7fe0
To build with tests when using mingw-w64 use the following arguments when
running CMake:
$ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/libwebm/build/mingw-w64_toolchain.cmake \
-DENABLE_TESTS=ON -Dgtest_disable_pthreads=ON path/to/libwebm
Note2: i686-w64-mingw32 is the default compiler. This can be controlled using
the MINGW_PREFIX variable:
$ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/libwebm/build/mingw-w64_toolchain.cmake \
-DMINGW_PREFIX=x86_64-w64-mingw32 path/to/libwebm

34
RELEASE.TXT Normal file
View File

@ -0,0 +1,34 @@
1.0.0.5
* Handled case when no duration
* Handled empty clusters
* Handled empty clusters when seeking
* Implemented check lacing bits
1.0.0.4
* Made Cues member variables mutables
* Defined against badly-formatted cue points
* Segment::GetCluster returns CuePoint too
* Separated cue-based searches
1.0.0.3
* Added Block::GetOffset() to get a frame's offset in a block
* Changed cluster count type from size_t to long
* Parsed SeekHead to find cues
* Allowed seeking beyond end of cluster cache
* Added not to attempt to reparse cues element
* Restructured Segment::LoadCluster
* Marked position of cues without parsing cues element
* Allowed cue points to be loaded incrementally
* Implemented to load lazily cue points as they're searched
* Merged Cues::LoadCuePoint into Cues::Find
* Lazy init cues
* Loaded cue point during find
1.0.0.2
* added support for Cues element
* seeking was improved
1.0.0.1
* fixed item 141
* added item 142
* added this file, RELEASE.TXT, to repository

View File

@ -1,73 +0,0 @@
## Copyright (c) 2016 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.
cmake_minimum_required(VERSION 3.2)
include(CheckCXXCompilerFlag)
# String used to cache failed CXX flags.
set(LIBWEBM_FAILED_CXX_FLAGS)
# Checks C++ compiler for support of $cxx_flag. Adds $cxx_flag to
# $CMAKE_CXX_FLAGS when the compile test passes. Caches $c_flag in
# $LIBWEBM_FAILED_CXX_FLAGS when the test fails.
function (add_cxx_flag_if_supported cxx_flag)
unset(CXX_FLAG_FOUND CACHE)
string(FIND "${CMAKE_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FOUND)
unset(CXX_FLAG_FAILED CACHE)
string(FIND "${LIBWEBM_FAILED_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FAILED)
if (${CXX_FLAG_FOUND} EQUAL -1 AND ${CXX_FLAG_FAILED} EQUAL -1)
unset(CXX_FLAG_SUPPORTED CACHE)
message("Checking CXX compiler flag support for: " ${cxx_flag})
check_cxx_compiler_flag("${cxx_flag}" CXX_FLAG_SUPPORTED)
if (CXX_FLAG_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${cxx_flag}" CACHE STRING ""
FORCE)
else ()
set(LIBWEBM_FAILED_CXX_FLAGS "${LIBWEBM_FAILED_CXX_FLAGS} ${cxx_flag}"
CACHE STRING "" FORCE)
endif ()
endif ()
endfunction ()
# Checks CXX compiler for support of $cxx_flag and terminates generation when
# support is not present.
function (require_cxx_flag cxx_flag)
unset(CXX_FLAG_FOUND CACHE)
string(FIND "${CMAKE_CXX_FLAGS}" "${cxx_flag}" CXX_FLAG_FOUND)
if (${CXX_FLAG_FOUND} EQUAL -1)
unset(LIBWEBM_HAVE_CXX_FLAG CACHE)
message("Checking CXX compiler flag support for: " ${cxx_flag})
check_cxx_compiler_flag("${cxx_flag}" LIBWEBM_HAVE_CXX_FLAG)
if (NOT LIBWEBM_HAVE_CXX_FLAG)
message(FATAL_ERROR
"${PROJECT_NAME} requires support for CXX flag: ${cxx_flag}.")
endif ()
set(CMAKE_CXX_FLAGS "${cxx_flag} ${CMAKE_CXX_FLAGS}" CACHE STRING "" FORCE)
endif ()
endfunction ()
# Checks only non-MSVC targets for support of $cxx_flag.
function (require_cxx_flag_nomsvc cxx_flag)
if (NOT MSVC)
require_cxx_flag(${cxx_flag})
endif ()
endfunction ()
# Adds $preproc_def to CXX compiler command line (as -D$preproc_def) if not
# already present.
function (add_cxx_preproc_definition preproc_def)
unset(PREPROC_DEF_FOUND CACHE)
string(FIND "${CMAKE_CXX_FLAGS}" "${preproc_def}" PREPROC_DEF_FOUND)
if (${PREPROC_DEF_FOUND} EQUAL -1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${preproc_def}" CACHE STRING ""
FORCE)
endif ()
endfunction ()

View File

@ -1,23 +0,0 @@
## Copyright (c) 2015 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.
cmake_minimum_required(VERSION 2.8)
if (MSVC)
# CMake defaults to producing code linked to the DLL MSVC runtime. In libwebm
# static is typically desired. Force static code generation unless the user
# running CMake set MSVC_RUNTIME to dll.
if (NOT "${MSVC_RUNTIME}" STREQUAL "dll")
foreach (flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if (${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif (${flag_var} MATCHES "/MD")
endforeach (flag_var)
endif ()
endif ()

View File

@ -1,26 +0,0 @@
## Copyright (c) 2017 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.
if (NOT LIBWEBM_BUILD_X86_MINGW_GCC_CMAKE_)
set(LIBWEBM_BUILD_X86_MINGW_GCC_CMAKE_ 1)
set(CMAKE_SYSTEM_PROCESSOR "x86")
set(CMAKE_SYSTEM_NAME "Windows")
set(CMAKE_C_COMPILER_ARG1 "-m32")
set(CMAKE_CXX_COMPILER_ARG1 "-m32")
if ("${CROSS}" STREQUAL "")
set(CROSS i686-w64-mingw32-)
endif ()
set(CMAKE_C_COMPILER ${CROSS}gcc)
set(CMAKE_CXX_COMPILER ${CROSS}g++)
# Disable googletest CMake usage for mingw cross compiles.
set(LIBWEBM_DISABLE_GTEST_CMAKE 1)
endif () # LIBWEBM_BUILD_X86_MINGW_GCC_CMAKE_

View File

@ -1,24 +0,0 @@
## Copyright (c) 2017 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.
if (NOT LIBWEBM_BUILD_X86_64_MINGW_GCC_CMAKE_)
set(LIBWEBM_BUILD_X86_64_MINGW_GCC_CMAKE_ 1)
set(CMAKE_SYSTEM_PROCESSOR "x86_64")
set(CMAKE_SYSTEM_NAME "Windows")
if ("${CROSS}" STREQUAL "")
set(CROSS x86_64-w64-mingw32-)
endif ()
set(CMAKE_C_COMPILER ${CROSS}gcc)
set(CMAKE_CXX_COMPILER ${CROSS}g++)
# Disable googletest CMake usage for mingw cross compiles.
set(LIBWEBM_DISABLE_GTEST_CMAKE 1)
endif () # LIBWEBM_BUILD_X86_64_MINGW_GCC_CMAKE_

View File

@ -1,62 +0,0 @@
#!/bin/sh
##
## Copyright (c) 2015 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.
##
set -e
devnull='> /dev/null 2>&1'
readonly ORIG_PWD="$(pwd)"
elog() {
echo "${0##*/} failed because: $@" 1>&2
}
vlog() {
if [ "${VERBOSE}" = "yes" ]; then
echo "$@"
fi
}
# Terminates script when name of current directory does not match $1.
check_dir() {
current_dir="$(pwd)"
required_dir="$1"
if [ "${current_dir##*/}" != "${required_dir}" ]; then
elog "This script must be run from the ${required_dir} directory."
exit 1
fi
}
# Terminates the script when $1 is not in $PATH. Any arguments required for
# the tool being tested to return a successful exit code can be passed as
# additional arguments.
check_tool() {
tool="$1"
shift
tool_args="$@"
if ! eval "${tool}" ${tool_args} > /dev/null 2>&1; then
elog "${tool} must be in your path."
exit 1
fi
}
# Echoes git describe output for the directory specified by $1 to stdout.
git_describe() {
git_dir="$1"
check_git
echo $(git -C "${git_dir}" describe)
}
# Echoes current git revision for the directory specifed by $1 to stdout.
git_revision() {
git_dir="$1"
check_git
echo $(git -C "${git_dir}" rev-parse HEAD)
}

View File

@ -1,93 +0,0 @@
// Copyright (c) 2016 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 "common/file_util.h"
#include <sys/stat.h>
#ifndef _MSC_VER
#include <unistd.h> // close()
#endif
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <ios>
#include <string>
namespace libwebm {
std::string GetTempFileName() {
#if !defined _MSC_VER && !defined __MINGW32__
std::string temp_file_name_template_str =
std::string(std::getenv("TEST_TMPDIR") ? std::getenv("TEST_TMPDIR") :
".") +
"/libwebm_temp.XXXXXX";
char* temp_file_name_template =
new char[temp_file_name_template_str.length() + 1];
memset(temp_file_name_template, 0, temp_file_name_template_str.length() + 1);
temp_file_name_template_str.copy(temp_file_name_template,
temp_file_name_template_str.length(), 0);
int fd = mkstemp(temp_file_name_template);
std::string temp_file_name =
(fd != -1) ? std::string(temp_file_name_template) : std::string();
delete[] temp_file_name_template;
if (fd != -1) {
close(fd);
}
return temp_file_name;
#else
char tmp_file_name[_MAX_PATH];
#if defined _MSC_VER || defined MINGW_HAS_SECURE_API
errno_t err = tmpnam_s(tmp_file_name);
#else
char* fname_pointer = tmpnam(tmp_file_name);
errno_t err = (fname_pointer == &tmp_file_name[0]) ? 0 : -1;
#endif
if (err == 0) {
return std::string(tmp_file_name);
}
return std::string();
#endif
}
uint64_t GetFileSize(const std::string& file_name) {
uint64_t file_size = 0;
#ifndef _MSC_VER
struct stat st;
st.st_size = 0;
if (stat(file_name.c_str(), &st) == 0) {
#else
struct _stat st;
st.st_size = 0;
if (_stat(file_name.c_str(), &st) == 0) {
#endif
file_size = st.st_size;
}
return file_size;
}
bool GetFileContents(const std::string& file_name, std::string* contents) {
std::ifstream file(file_name.c_str());
*contents = std::string(static_cast<size_t>(GetFileSize(file_name)), 0);
if (file.good() && contents->size()) {
file.read(&(*contents)[0], contents->size());
}
return !file.fail();
}
TempFileDeleter::TempFileDeleter() { file_name_ = GetTempFileName(); }
TempFileDeleter::~TempFileDeleter() {
std::ifstream file(file_name_.c_str());
if (file.good()) {
file.close();
std::remove(file_name_.c_str());
}
}
} // namespace libwebm

View File

@ -1,44 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_COMMON_FILE_UTIL_H_
#define LIBWEBM_COMMON_FILE_UTIL_H_
#include <stdint.h>
#include <string>
#include "mkvmuxer/mkvmuxertypes.h" // LIBWEBM_DISALLOW_COPY_AND_ASSIGN()
namespace libwebm {
// Returns a temporary file name.
std::string GetTempFileName();
// Returns size of file specified by |file_name|, or 0 upon failure.
uint64_t GetFileSize(const std::string& file_name);
// Gets the contents file_name as a string. Returns false on error.
bool GetFileContents(const std::string& file_name, std::string* contents);
// Manages life of temporary file specified at time of construction. Deletes
// file upon destruction.
class TempFileDeleter {
public:
TempFileDeleter();
explicit TempFileDeleter(std::string file_name) : file_name_(file_name) {}
~TempFileDeleter();
const std::string& name() const { return file_name_; }
private:
std::string file_name_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TempFileDeleter);
};
} // namespace libwebm
#endif // LIBWEBM_COMMON_FILE_UTIL_H_

View File

@ -1,220 +0,0 @@
// Copyright (c) 2016 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 "hdr_util.h"
#include <climits>
#include <cstddef>
#include <new>
#include "mkvparser/mkvparser.h"
namespace libwebm {
const int Vp9CodecFeatures::kValueNotPresent = INT_MAX;
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
PrimaryChromaticityPtr* muxer_pc) {
muxer_pc->reset(new (std::nothrow)
mkvmuxer::PrimaryChromaticity(parser_pc.x, parser_pc.y));
if (!muxer_pc->get())
return false;
return true;
}
bool MasteringMetadataValuePresent(double value) {
return value != mkvparser::MasteringMetadata::kValueNotPresent;
}
bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm,
mkvmuxer::MasteringMetadata* muxer_mm) {
if (MasteringMetadataValuePresent(parser_mm.luminance_max))
muxer_mm->set_luminance_max(parser_mm.luminance_max);
if (MasteringMetadataValuePresent(parser_mm.luminance_min))
muxer_mm->set_luminance_min(parser_mm.luminance_min);
PrimaryChromaticityPtr r_ptr(nullptr);
PrimaryChromaticityPtr g_ptr(nullptr);
PrimaryChromaticityPtr b_ptr(nullptr);
PrimaryChromaticityPtr wp_ptr(nullptr);
if (parser_mm.r) {
if (!CopyPrimaryChromaticity(*parser_mm.r, &r_ptr))
return false;
}
if (parser_mm.g) {
if (!CopyPrimaryChromaticity(*parser_mm.g, &g_ptr))
return false;
}
if (parser_mm.b) {
if (!CopyPrimaryChromaticity(*parser_mm.b, &b_ptr))
return false;
}
if (parser_mm.white_point) {
if (!CopyPrimaryChromaticity(*parser_mm.white_point, &wp_ptr))
return false;
}
if (!muxer_mm->SetChromaticity(r_ptr.get(), g_ptr.get(), b_ptr.get(),
wp_ptr.get())) {
return false;
}
return true;
}
bool ColourValuePresent(long long value) {
return value != mkvparser::Colour::kValueNotPresent;
}
bool CopyColour(const mkvparser::Colour& parser_colour,
mkvmuxer::Colour* muxer_colour) {
if (!muxer_colour)
return false;
if (ColourValuePresent(parser_colour.matrix_coefficients))
muxer_colour->set_matrix_coefficients(parser_colour.matrix_coefficients);
if (ColourValuePresent(parser_colour.bits_per_channel))
muxer_colour->set_bits_per_channel(parser_colour.bits_per_channel);
if (ColourValuePresent(parser_colour.chroma_subsampling_horz)) {
muxer_colour->set_chroma_subsampling_horz(
parser_colour.chroma_subsampling_horz);
}
if (ColourValuePresent(parser_colour.chroma_subsampling_vert)) {
muxer_colour->set_chroma_subsampling_vert(
parser_colour.chroma_subsampling_vert);
}
if (ColourValuePresent(parser_colour.cb_subsampling_horz))
muxer_colour->set_cb_subsampling_horz(parser_colour.cb_subsampling_horz);
if (ColourValuePresent(parser_colour.cb_subsampling_vert))
muxer_colour->set_cb_subsampling_vert(parser_colour.cb_subsampling_vert);
if (ColourValuePresent(parser_colour.chroma_siting_horz))
muxer_colour->set_chroma_siting_horz(parser_colour.chroma_siting_horz);
if (ColourValuePresent(parser_colour.chroma_siting_vert))
muxer_colour->set_chroma_siting_vert(parser_colour.chroma_siting_vert);
if (ColourValuePresent(parser_colour.range))
muxer_colour->set_range(parser_colour.range);
if (ColourValuePresent(parser_colour.transfer_characteristics)) {
muxer_colour->set_transfer_characteristics(
parser_colour.transfer_characteristics);
}
if (ColourValuePresent(parser_colour.primaries))
muxer_colour->set_primaries(parser_colour.primaries);
if (ColourValuePresent(parser_colour.max_cll))
muxer_colour->set_max_cll(parser_colour.max_cll);
if (ColourValuePresent(parser_colour.max_fall))
muxer_colour->set_max_fall(parser_colour.max_fall);
if (parser_colour.mastering_metadata) {
mkvmuxer::MasteringMetadata muxer_mm;
if (!CopyMasteringMetadata(*parser_colour.mastering_metadata, &muxer_mm))
return false;
if (!muxer_colour->SetMasteringMetadata(muxer_mm))
return false;
}
return true;
}
// Format of VPx private data:
//
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID Byte | Length | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
// | |
// : Bytes 1..Length of Codec Feature :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// ID Byte Format
// ID byte is an unsigned byte.
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |X| ID |
// +-+-+-+-+-+-+-+-+
//
// The X bit is reserved.
//
// See the following link for more information:
// http://www.webmproject.org/vp9/profiles/
bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
Vp9CodecFeatures* features) {
const int kVpxCodecPrivateMinLength = 3;
if (!private_data || !features || length < kVpxCodecPrivateMinLength)
return false;
const uint8_t kVp9ProfileId = 1;
const uint8_t kVp9LevelId = 2;
const uint8_t kVp9BitDepthId = 3;
const uint8_t kVp9ChromaSubsamplingId = 4;
const int kVpxFeatureLength = 1;
int offset = 0;
// Set features to not set.
features->profile = Vp9CodecFeatures::kValueNotPresent;
features->level = Vp9CodecFeatures::kValueNotPresent;
features->bit_depth = Vp9CodecFeatures::kValueNotPresent;
features->chroma_subsampling = Vp9CodecFeatures::kValueNotPresent;
do {
const uint8_t id_byte = private_data[offset++];
const uint8_t length_byte = private_data[offset++];
if (length_byte != kVpxFeatureLength)
return false;
if (id_byte == kVp9ProfileId) {
const int priv_profile = static_cast<int>(private_data[offset++]);
if (priv_profile < 0 || priv_profile > 3)
return false;
if (features->profile != Vp9CodecFeatures::kValueNotPresent &&
features->profile != priv_profile) {
return false;
}
features->profile = priv_profile;
} else if (id_byte == kVp9LevelId) {
const int priv_level = static_cast<int>(private_data[offset++]);
const int kNumLevels = 14;
const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40,
41, 50, 51, 52, 60, 61, 62};
for (int i = 0; i < kNumLevels; ++i) {
if (priv_level == levels[i]) {
if (features->level != Vp9CodecFeatures::kValueNotPresent &&
features->level != priv_level) {
return false;
}
features->level = priv_level;
break;
}
}
if (features->level == Vp9CodecFeatures::kValueNotPresent)
return false;
} else if (id_byte == kVp9BitDepthId) {
const int priv_profile = static_cast<int>(private_data[offset++]);
if (priv_profile != 8 && priv_profile != 10 && priv_profile != 12)
return false;
if (features->bit_depth != Vp9CodecFeatures::kValueNotPresent &&
features->bit_depth != priv_profile) {
return false;
}
features->bit_depth = priv_profile;
} else if (id_byte == kVp9ChromaSubsamplingId) {
const int priv_profile = static_cast<int>(private_data[offset++]);
if (priv_profile != 0 && priv_profile != 2 && priv_profile != 3)
return false;
if (features->chroma_subsampling != Vp9CodecFeatures::kValueNotPresent &&
features->chroma_subsampling != priv_profile) {
return false;
}
features->chroma_subsampling = priv_profile;
} else {
// Invalid ID.
return false;
}
} while (offset + kVpxCodecPrivateMinLength <= length);
return true;
}
} // namespace libwebm

View File

@ -1,71 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_COMMON_HDR_UTIL_H_
#define LIBWEBM_COMMON_HDR_UTIL_H_
#include <stdint.h>
#include <memory>
#include "mkvmuxer/mkvmuxer.h"
namespace mkvparser {
struct Colour;
struct MasteringMetadata;
struct PrimaryChromaticity;
} // namespace mkvparser
namespace libwebm {
// Utility types and functions for working with the Colour element and its
// children. Copiers return true upon success. Presence functions return true
// when the specified element is present.
// TODO(tomfinegan): These should be moved to libwebm_utils once c++11 is
// required by libwebm.
// Features of the VP9 codec that may be set in the CodecPrivate of a VP9 video
// stream. A value of kValueNotPresent represents that the value was not set in
// the CodecPrivate.
struct Vp9CodecFeatures {
static const int kValueNotPresent;
Vp9CodecFeatures()
: profile(kValueNotPresent),
level(kValueNotPresent),
bit_depth(kValueNotPresent),
chroma_subsampling(kValueNotPresent) {}
~Vp9CodecFeatures() {}
int profile;
int level;
int bit_depth;
int chroma_subsampling;
};
typedef std::unique_ptr<mkvmuxer::PrimaryChromaticity> PrimaryChromaticityPtr;
bool CopyPrimaryChromaticity(const mkvparser::PrimaryChromaticity& parser_pc,
PrimaryChromaticityPtr* muxer_pc);
bool MasteringMetadataValuePresent(double value);
bool CopyMasteringMetadata(const mkvparser::MasteringMetadata& parser_mm,
mkvmuxer::MasteringMetadata* muxer_mm);
bool ColourValuePresent(long long value);
bool CopyColour(const mkvparser::Colour& parser_colour,
mkvmuxer::Colour* muxer_colour);
// Returns true if |features| is set to one or more valid values.
bool ParseVpxCodecPrivate(const uint8_t* private_data, int32_t length,
Vp9CodecFeatures* features);
} // namespace libwebm
#endif // LIBWEBM_COMMON_HDR_UTIL_H_

View File

@ -1,29 +0,0 @@
/*
* 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 "common/indent.h"
#include <string>
namespace libwebm {
Indent::Indent(int indent) : indent_(indent), indent_str_() { Update(); }
void Indent::Adjust(int indent) {
indent_ += indent;
if (indent_ < 0)
indent_ = 0;
Update();
}
void Indent::Update() { indent_str_ = std::string(indent_, ' '); }
} // namespace libwebm

View File

@ -1,48 +0,0 @@
/*
* 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 LIBWEBM_COMMON_INDENT_H_
#define LIBWEBM_COMMON_INDENT_H_
#include <string>
#include "mkvmuxer/mkvmuxertypes.h"
namespace libwebm {
const int kIncreaseIndent = 2;
const int kDecreaseIndent = -2;
// Used for formatting output so objects only have to keep track of spacing
// within their scope.
class Indent {
public:
explicit Indent(int indent);
// Changes the number of spaces output. The value adjusted is relative to
// |indent_|.
void Adjust(int indent);
std::string indent_str() const { return indent_str_; }
private:
// Called after |indent_| is changed. This will set |indent_str_| to the
// proper number of spaces.
void Update();
int indent_;
std::string indent_str_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(Indent);
};
} // namespace libwebm
#endif // LIBWEBM_COMMON_INDENT_H_

View File

@ -1,110 +0,0 @@
// Copyright (c) 2015 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 "common/libwebm_util.h"
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <limits>
namespace libwebm {
std::int64_t NanosecondsTo90KhzTicks(std::int64_t nanoseconds) {
const double pts_seconds = nanoseconds / kNanosecondsPerSecond;
return static_cast<std::int64_t>(pts_seconds * 90000);
}
std::int64_t Khz90TicksToNanoseconds(std::int64_t ticks) {
const double seconds = ticks / 90000.0;
return static_cast<std::int64_t>(seconds * kNanosecondsPerSecond);
}
bool ParseVP9SuperFrameIndex(const std::uint8_t* frame,
std::size_t frame_length, Ranges* frame_ranges,
bool* error) {
if (frame == nullptr || frame_length == 0 || frame_ranges == nullptr ||
error == nullptr) {
return false;
}
bool parse_ok = false;
const std::uint8_t marker = frame[frame_length - 1];
const std::uint32_t kHasSuperFrameIndexMask = 0xe0;
const std::uint32_t kSuperFrameMarker = 0xc0;
const std::uint32_t kLengthFieldSizeMask = 0x3;
if ((marker & kHasSuperFrameIndexMask) == kSuperFrameMarker) {
const std::uint32_t kFrameCountMask = 0x7;
const int num_frames = (marker & kFrameCountMask) + 1;
const int length_field_size = ((marker >> 3) & kLengthFieldSizeMask) + 1;
const std::size_t index_length = 2 + length_field_size * num_frames;
if (frame_length < index_length) {
std::fprintf(stderr,
"VP9ParseSuperFrameIndex: Invalid superframe index size.\n");
*error = true;
return false;
}
// Consume the super frame index. Note: it's at the end of the super frame.
const std::size_t length = frame_length - index_length;
if (length >= index_length &&
frame[frame_length - index_length] == marker) {
// Found a valid superframe index.
const std::uint8_t* byte = frame + length + 1;
std::size_t frame_offset = 0;
for (int i = 0; i < num_frames; ++i) {
std::uint32_t child_frame_length = 0;
for (int j = 0; j < length_field_size; ++j) {
child_frame_length |= (*byte++) << (j * 8);
}
if (length - frame_offset < child_frame_length) {
std::fprintf(stderr,
"ParseVP9SuperFrameIndex: Invalid superframe, sub frame "
"larger than entire frame.\n");
*error = true;
return false;
}
frame_ranges->push_back(Range(frame_offset, child_frame_length));
frame_offset += child_frame_length;
}
if (static_cast<int>(frame_ranges->size()) != num_frames) {
std::fprintf(stderr, "VP9Parse: superframe index parse failed.\n");
*error = true;
return false;
}
parse_ok = true;
} else {
std::fprintf(stderr, "VP9Parse: Invalid superframe index.\n");
*error = true;
}
}
return parse_ok;
}
bool WriteUint8(std::uint8_t val, std::FILE* fileptr) {
if (fileptr == nullptr)
return false;
return (std::fputc(val, fileptr) == val);
}
std::uint16_t ReadUint16(const std::uint8_t* buf) {
if (buf == nullptr)
return 0;
return ((buf[0] << 8) | buf[1]);
}
} // namespace libwebm

View File

@ -1,65 +0,0 @@
// Copyright (c) 2015 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 LIBWEBM_COMMON_LIBWEBM_UTIL_H_
#define LIBWEBM_COMMON_LIBWEBM_UTIL_H_
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <memory>
#include <vector>
namespace libwebm {
const double kNanosecondsPerSecond = 1000000000.0;
// fclose functor for wrapping FILE in std::unique_ptr.
// TODO(tomfinegan): Move this to file_util once c++11 restrictions are
// relaxed.
struct FILEDeleter {
int operator()(std::FILE* f) {
if (f != nullptr)
return fclose(f);
return 0;
}
};
typedef std::unique_ptr<std::FILE, FILEDeleter> FilePtr;
struct Range {
Range(std::size_t off, std::size_t len) : offset(off), length(len) {}
Range() = delete;
Range(const Range&) = default;
Range(Range&&) = default;
~Range() = default;
const std::size_t offset;
const std::size_t length;
};
typedef std::vector<Range> Ranges;
// Converts |nanoseconds| to 90000 Hz clock ticks and vice versa. Each return
// the converted value.
std::int64_t NanosecondsTo90KhzTicks(std::int64_t nanoseconds);
std::int64_t Khz90TicksToNanoseconds(std::int64_t khz90_ticks);
// Returns true and stores frame offsets and lengths in |frame_ranges| when
// |frame| has a valid VP9 super frame index. Sets |error| to true when parsing
// fails for any reason.
bool ParseVP9SuperFrameIndex(const std::uint8_t* frame,
std::size_t frame_length, Ranges* frame_ranges,
bool* error);
// Writes |val| to |fileptr| and returns true upon success.
bool WriteUint8(std::uint8_t val, std::FILE* fileptr);
// Reads 2 bytes from |buf| and returns them as a uint16_t. Returns 0 when |buf|
// is a nullptr.
std::uint16_t ReadUint16(const std::uint8_t* buf);
} // namespace libwebm
#endif // LIBWEBM_COMMON_LIBWEBM_UTIL_H_

View File

@ -1,43 +0,0 @@
// Copyright (c) 2016 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 "common/video_frame.h"
namespace libwebm {
bool VideoFrame::Buffer::Init(std::size_t new_length) {
capacity = 0;
length = 0;
data.reset(new std::uint8_t[new_length]);
if (data.get() == nullptr) {
fprintf(stderr, "VideoFrame: Out of memory.");
return false;
}
capacity = new_length;
length = 0;
return true;
}
bool VideoFrame::Init(std::size_t length) { return buffer_.Init(length); }
bool VideoFrame::Init(std::size_t length, std::int64_t nano_pts, Codec codec) {
nanosecond_pts_ = nano_pts;
codec_ = codec;
return Init(length);
}
bool VideoFrame::SetBufferLength(std::size_t length) {
if (length > buffer_.capacity || buffer_.data.get() == nullptr)
return false;
buffer_.length = length;
return true;
}
} // namespace libwebm

View File

@ -1,68 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_COMMON_VIDEO_FRAME_H_
#define LIBWEBM_COMMON_VIDEO_FRAME_H_
#include <cstdint>
#include <memory>
namespace libwebm {
// VideoFrame is a storage class for compressed video frames.
class VideoFrame {
public:
enum Codec { kVP8, kVP9 };
struct Buffer {
Buffer() = default;
~Buffer() = default;
// Resets |data| to be of size |new_length| bytes, sets |capacity| to
// |new_length|, sets |length| to 0 (aka empty). Returns true for success.
bool Init(std::size_t new_length);
std::unique_ptr<std::uint8_t[]> data;
std::size_t length = 0;
std::size_t capacity = 0;
};
VideoFrame() = default;
~VideoFrame() = default;
VideoFrame(std::int64_t pts_in_nanoseconds, Codec vpx_codec)
: nanosecond_pts_(pts_in_nanoseconds), codec_(vpx_codec) {}
VideoFrame(bool keyframe, std::int64_t pts_in_nanoseconds, Codec vpx_codec)
: keyframe_(keyframe),
nanosecond_pts_(pts_in_nanoseconds),
codec_(vpx_codec) {}
bool Init(std::size_t length);
bool Init(std::size_t length, std::int64_t nano_pts, Codec codec);
// Updates actual length of data stored in |buffer_.data| when it's been
// written via the raw pointer returned from buffer_.data.get().
// Returns false when buffer_.data.get() return nullptr and/or when
// |length| > |buffer_.length|. Returns true otherwise.
bool SetBufferLength(std::size_t length);
// Accessors.
const Buffer& buffer() const { return buffer_; }
bool keyframe() const { return keyframe_; }
std::int64_t nanosecond_pts() const { return nanosecond_pts_; }
Codec codec() const { return codec_; }
// Mutators.
void set_nanosecond_pts(std::int64_t nano_pts) { nanosecond_pts_ = nano_pts; }
private:
Buffer buffer_;
bool keyframe_ = false;
std::int64_t nanosecond_pts_ = 0;
Codec codec_ = kVP9;
};
} // namespace libwebm
#endif // LIBWEBM_COMMON_VIDEO_FRAME_H_

View File

@ -1,266 +0,0 @@
// Copyright (c) 2016 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 "common/vp9_header_parser.h"
#include <stdio.h>
namespace vp9_parser {
bool Vp9HeaderParser::SetFrame(const uint8_t* frame, size_t length) {
if (!frame || length == 0)
return false;
frame_ = frame;
frame_size_ = length;
bit_offset_ = 0;
profile_ = -1;
show_existing_frame_ = 0;
key_ = 0;
altref_ = 0;
error_resilient_mode_ = 0;
intra_only_ = 0;
reset_frame_context_ = 0;
color_space_ = 0;
color_range_ = 0;
subsampling_x_ = 0;
subsampling_y_ = 0;
refresh_frame_flags_ = 0;
return true;
}
bool Vp9HeaderParser::ParseUncompressedHeader(const uint8_t* frame,
size_t length) {
if (!SetFrame(frame, length))
return false;
const int frame_marker = VpxReadLiteral(2);
if (frame_marker != kVp9FrameMarker) {
fprintf(stderr, "Invalid VP9 frame_marker:%d\n", frame_marker);
return false;
}
profile_ = ReadBit();
profile_ |= ReadBit() << 1;
if (profile_ > 2)
profile_ += ReadBit();
// TODO(fgalligan): Decide how to handle show existing frames.
show_existing_frame_ = ReadBit();
if (show_existing_frame_)
return true;
key_ = !ReadBit();
altref_ = !ReadBit();
error_resilient_mode_ = ReadBit();
if (key_) {
if (!ValidateVp9SyncCode()) {
fprintf(stderr, "Invalid Sync code!\n");
return false;
}
ParseColorSpace();
ParseFrameResolution();
ParseFrameParallelMode();
ParseTileInfo();
} else {
intra_only_ = altref_ ? ReadBit() : 0;
reset_frame_context_ = error_resilient_mode_ ? 0 : VpxReadLiteral(2);
if (intra_only_) {
if (!ValidateVp9SyncCode()) {
fprintf(stderr, "Invalid Sync code!\n");
return false;
}
if (profile_ > 0) {
ParseColorSpace();
} else {
// NOTE: The intra-only frame header does not include the specification
// of either the color format or color sub-sampling in profile 0. VP9
// specifies that the default color format should be YUV 4:2:0 in this
// case (normative).
color_space_ = kVpxCsBt601;
color_range_ = kVpxCrStudioRange;
subsampling_y_ = subsampling_x_ = 1;
bit_depth_ = 8;
}
refresh_frame_flags_ = VpxReadLiteral(kRefFrames);
ParseFrameResolution();
} else {
refresh_frame_flags_ = VpxReadLiteral(kRefFrames);
for (int i = 0; i < kRefsPerFrame; ++i) {
VpxReadLiteral(kRefFrames_LOG2); // Consume ref.
ReadBit(); // Consume ref sign bias.
}
bool found = false;
for (int i = 0; i < kRefsPerFrame; ++i) {
if (ReadBit()) {
// Found previous reference, width and height did not change since
// last frame.
found = true;
break;
}
}
if (!found)
ParseFrameResolution();
}
}
return true;
}
int Vp9HeaderParser::ReadBit() {
const size_t off = bit_offset_;
const size_t byte_offset = off >> 3;
const int bit_shift = 7 - static_cast<int>(off & 0x7);
if (byte_offset < frame_size_) {
const int bit = (frame_[byte_offset] >> bit_shift) & 1;
bit_offset_++;
return bit;
} else {
return 0;
}
}
int Vp9HeaderParser::VpxReadLiteral(int bits) {
int value = 0;
for (int bit = bits - 1; bit >= 0; --bit)
value |= ReadBit() << bit;
return value;
}
bool Vp9HeaderParser::ValidateVp9SyncCode() {
const int sync_code_0 = VpxReadLiteral(8);
const int sync_code_1 = VpxReadLiteral(8);
const int sync_code_2 = VpxReadLiteral(8);
return (sync_code_0 == 0x49 && sync_code_1 == 0x83 && sync_code_2 == 0x42);
}
void Vp9HeaderParser::ParseColorSpace() {
bit_depth_ = 0;
if (profile_ >= 2)
bit_depth_ = ReadBit() ? 12 : 10;
else
bit_depth_ = 8;
color_space_ = VpxReadLiteral(3);
if (color_space_ != kVpxCsSrgb) {
color_range_ = ReadBit();
if (profile_ == 1 || profile_ == 3) {
subsampling_x_ = ReadBit();
subsampling_y_ = ReadBit();
ReadBit();
} else {
subsampling_y_ = subsampling_x_ = 1;
}
} else {
color_range_ = kVpxCrFullRange;
if (profile_ == 1 || profile_ == 3) {
subsampling_y_ = subsampling_x_ = 0;
ReadBit();
}
}
}
void Vp9HeaderParser::ParseFrameResolution() {
width_ = VpxReadLiteral(16) + 1;
height_ = VpxReadLiteral(16) + 1;
}
void Vp9HeaderParser::ParseFrameParallelMode() {
if (ReadBit()) {
VpxReadLiteral(16); // display width
VpxReadLiteral(16); // display height
}
if (!error_resilient_mode_) {
ReadBit(); // Consume refresh frame context
frame_parallel_mode_ = ReadBit();
} else {
frame_parallel_mode_ = 1;
}
}
void Vp9HeaderParser::ParseTileInfo() {
VpxReadLiteral(2); // Consume frame context index
// loopfilter
VpxReadLiteral(6); // Consume filter level
VpxReadLiteral(3); // Consume sharpness level
const bool mode_ref_delta_enabled = ReadBit();
if (mode_ref_delta_enabled) {
const bool mode_ref_delta_update = ReadBit();
if (mode_ref_delta_update) {
const int kMaxRefLFDeltas = 4;
for (int i = 0; i < kMaxRefLFDeltas; ++i) {
if (ReadBit())
VpxReadLiteral(7); // Consume ref_deltas + sign
}
const int kMaxModeDeltas = 2;
for (int i = 0; i < kMaxModeDeltas; ++i) {
if (ReadBit())
VpxReadLiteral(7); // Consume mode_delta + sign
}
}
}
// quantization
VpxReadLiteral(8); // Consume base_q
SkipDeltaQ(); // y dc
SkipDeltaQ(); // uv ac
SkipDeltaQ(); // uv dc
// segmentation
const bool segmentation_enabled = ReadBit();
if (!segmentation_enabled) {
const int aligned_width = AlignPowerOfTwo(width_, kMiSizeLog2);
const int mi_cols = aligned_width >> kMiSizeLog2;
const int aligned_mi_cols = AlignPowerOfTwo(mi_cols, kMiSizeLog2);
const int sb_cols = aligned_mi_cols >> 3; // to_sbs(mi_cols);
int min_log2_n_tiles, max_log2_n_tiles;
for (max_log2_n_tiles = 0;
(sb_cols >> max_log2_n_tiles) >= kMinTileWidthB64;
max_log2_n_tiles++) {
}
max_log2_n_tiles--;
if (max_log2_n_tiles < 0)
max_log2_n_tiles = 0;
for (min_log2_n_tiles = 0; (kMaxTileWidthB64 << min_log2_n_tiles) < sb_cols;
min_log2_n_tiles++) {
}
// columns
const int max_log2_tile_cols = max_log2_n_tiles;
const int min_log2_tile_cols = min_log2_n_tiles;
int max_ones = max_log2_tile_cols - min_log2_tile_cols;
int log2_tile_cols = min_log2_tile_cols;
while (max_ones-- && ReadBit())
log2_tile_cols++;
// rows
int log2_tile_rows = ReadBit();
if (log2_tile_rows)
log2_tile_rows += ReadBit();
row_tiles_ = 1 << log2_tile_rows;
column_tiles_ = 1 << log2_tile_cols;
}
}
void Vp9HeaderParser::SkipDeltaQ() {
if (ReadBit())
VpxReadLiteral(4);
}
int Vp9HeaderParser::AlignPowerOfTwo(int value, int n) {
return (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1));
}
} // namespace vp9_parser

View File

@ -1,125 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_COMMON_VP9_HEADER_PARSER_H_
#define LIBWEBM_COMMON_VP9_HEADER_PARSER_H_
#include <stddef.h>
#include <stdint.h>
namespace vp9_parser {
const int kVp9FrameMarker = 2;
const int kMinTileWidthB64 = 4;
const int kMaxTileWidthB64 = 64;
const int kRefFrames = 8;
const int kRefsPerFrame = 3;
const int kRefFrames_LOG2 = 3;
const int kVpxCsBt601 = 1;
const int kVpxCsSrgb = 7;
const int kVpxCrStudioRange = 0;
const int kVpxCrFullRange = 1;
const int kMiSizeLog2 = 3;
// Class to parse the header of a VP9 frame.
class Vp9HeaderParser {
public:
Vp9HeaderParser()
: frame_(NULL),
frame_size_(0),
bit_offset_(0),
profile_(-1),
show_existing_frame_(0),
key_(0),
altref_(0),
error_resilient_mode_(0),
intra_only_(0),
reset_frame_context_(0),
bit_depth_(0),
color_space_(0),
color_range_(0),
subsampling_x_(0),
subsampling_y_(0),
refresh_frame_flags_(0),
width_(0),
height_(0),
row_tiles_(0),
column_tiles_(0),
frame_parallel_mode_(0) {}
// Parse the VP9 uncompressed header. The return values of the remaining
// functions are only valid on success.
bool ParseUncompressedHeader(const uint8_t* frame, size_t length);
size_t frame_size() const { return frame_size_; }
int profile() const { return profile_; }
int key() const { return key_; }
int altref() const { return altref_; }
int error_resilient_mode() const { return error_resilient_mode_; }
int bit_depth() const { return bit_depth_; }
int color_space() const { return color_space_; }
int width() const { return width_; }
int height() const { return height_; }
int refresh_frame_flags() const { return refresh_frame_flags_; }
int row_tiles() const { return row_tiles_; }
int column_tiles() const { return column_tiles_; }
int frame_parallel_mode() const { return frame_parallel_mode_; }
private:
// Set the compressed VP9 frame.
bool SetFrame(const uint8_t* frame, size_t length);
// Returns the next bit of the frame.
int ReadBit();
// Returns the next |bits| of the frame.
int VpxReadLiteral(int bits);
// Returns true if the vp9 sync code is valid.
bool ValidateVp9SyncCode();
// Parses bit_depth_, color_space_, subsampling_x_, subsampling_y_, and
// color_range_.
void ParseColorSpace();
// Parses width and height of the frame.
void ParseFrameResolution();
// Parses frame_parallel_mode_. This function skips over some features.
void ParseFrameParallelMode();
// Parses row and column tiles. This function skips over some features.
void ParseTileInfo();
void SkipDeltaQ();
int AlignPowerOfTwo(int value, int n);
const uint8_t* frame_;
size_t frame_size_;
size_t bit_offset_;
int profile_;
int show_existing_frame_;
int key_;
int altref_;
int error_resilient_mode_;
int intra_only_;
int reset_frame_context_;
int bit_depth_;
int color_space_;
int color_range_;
int subsampling_x_;
int subsampling_y_;
int refresh_frame_flags_;
int width_;
int height_;
int row_tiles_;
int column_tiles_;
int frame_parallel_mode_;
};
} // namespace vp9_parser
#endif // LIBWEBM_COMMON_VP9_HEADER_PARSER_H_

View File

@ -1,181 +0,0 @@
// Copyright (c) 2016 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 "common/vp9_header_parser.h"
#include <string>
#include "gtest/gtest.h"
#include "common/hdr_util.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
#include "testing/test_util.h"
namespace {
class Vp9HeaderParserTests : public ::testing::Test {
public:
Vp9HeaderParserTests() : is_reader_open_(false), segment_(NULL) {}
~Vp9HeaderParserTests() override {
CloseReader();
if (segment_ != NULL) {
delete segment_;
segment_ = NULL;
}
}
void CloseReader() {
if (is_reader_open_) {
reader_.Close();
}
is_reader_open_ = false;
}
void CreateAndLoadSegment(const std::string& filename,
int expected_doc_type_ver) {
filename_ = test::GetTestFilePath(filename);
ASSERT_EQ(0, reader_.Open(filename_.c_str()));
is_reader_open_ = true;
pos_ = 0;
mkvparser::EBMLHeader ebml_header;
ebml_header.Parse(&reader_, pos_);
ASSERT_EQ(1, ebml_header.m_version);
ASSERT_EQ(1, ebml_header.m_readVersion);
ASSERT_STREQ("webm", ebml_header.m_docType);
ASSERT_EQ(expected_doc_type_ver, ebml_header.m_docTypeVersion);
ASSERT_EQ(2, ebml_header.m_docTypeReadVersion);
ASSERT_EQ(0, mkvparser::Segment::CreateInstance(&reader_, pos_, segment_));
ASSERT_FALSE(HasFailure());
ASSERT_GE(0, segment_->Load());
}
void CreateAndLoadSegment(const std::string& filename) {
CreateAndLoadSegment(filename, 4);
}
// Load a corrupted segment with no expectation of correctness.
void CreateAndLoadInvalidSegment(const std::string& filename) {
filename_ = test::GetTestFilePath(filename);
ASSERT_EQ(0, reader_.Open(filename_.c_str()));
is_reader_open_ = true;
pos_ = 0;
mkvparser::EBMLHeader ebml_header;
ebml_header.Parse(&reader_, pos_);
ASSERT_EQ(0, mkvparser::Segment::CreateInstance(&reader_, pos_, segment_));
ASSERT_GE(0, segment_->Load());
}
void ProcessTheFrames(bool invalid_bitstream) {
unsigned char* data = NULL;
size_t data_len = 0;
const mkvparser::Tracks* const parser_tracks = segment_->GetTracks();
ASSERT_TRUE(parser_tracks != NULL);
const mkvparser::Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
while ((cluster != NULL) && !cluster->EOS()) {
const mkvparser::BlockEntry* block_entry;
long status = cluster->GetFirst(block_entry); // NOLINT
ASSERT_EQ(0, status);
while ((block_entry != NULL) && !block_entry->EOS()) {
const mkvparser::Block* const block = block_entry->GetBlock();
ASSERT_TRUE(block != NULL);
const long long trackNum = block->GetTrackNumber(); // NOLINT
const mkvparser::Track* const parser_track =
parser_tracks->GetTrackByNumber(
static_cast<unsigned long>(trackNum)); // NOLINT
ASSERT_TRUE(parser_track != NULL);
const long long track_type = parser_track->GetType(); // NOLINT
if (track_type == mkvparser::Track::kVideo) {
const int frame_count = block->GetFrameCount();
for (int i = 0; i < frame_count; ++i) {
const mkvparser::Block::Frame& frame = block->GetFrame(i);
if (static_cast<size_t>(frame.len) > data_len) {
delete[] data;
data = new unsigned char[frame.len];
ASSERT_TRUE(data != NULL);
data_len = static_cast<size_t>(frame.len);
}
ASSERT_FALSE(frame.Read(&reader_, data));
ASSERT_EQ(parser_.ParseUncompressedHeader(data, data_len),
!invalid_bitstream);
}
}
status = cluster->GetNext(block_entry, block_entry);
ASSERT_EQ(0, status);
}
cluster = segment_->GetNext(cluster);
}
delete[] data;
}
protected:
mkvparser::MkvReader reader_;
bool is_reader_open_;
mkvparser::Segment* segment_;
std::string filename_;
long long pos_; // NOLINT
vp9_parser::Vp9HeaderParser parser_;
};
TEST_F(Vp9HeaderParserTests, VideoOnlyFile) {
ASSERT_NO_FATAL_FAILURE(CreateAndLoadSegment("test_stereo_left_right.webm"));
ProcessTheFrames(false);
EXPECT_EQ(256, parser_.width());
EXPECT_EQ(144, parser_.height());
EXPECT_EQ(1, parser_.column_tiles());
EXPECT_EQ(0, parser_.frame_parallel_mode());
}
TEST_F(Vp9HeaderParserTests, Muxed) {
ASSERT_NO_FATAL_FAILURE(
CreateAndLoadSegment("bbb_480p_vp9_opus_1second.webm", 4));
ProcessTheFrames(false);
EXPECT_EQ(854, parser_.width());
EXPECT_EQ(480, parser_.height());
EXPECT_EQ(2, parser_.column_tiles());
EXPECT_EQ(1, parser_.frame_parallel_mode());
}
TEST_F(Vp9HeaderParserTests, Invalid) {
const char* files[] = {
"invalid/invalid_vp9_bitstream-bug_1416.webm",
"invalid/invalid_vp9_bitstream-bug_1417.webm",
};
for (int i = 0; i < static_cast<int>(sizeof(files) / sizeof(files[0])); ++i) {
SCOPED_TRACE(files[i]);
ASSERT_NO_FATAL_FAILURE(CreateAndLoadInvalidSegment(files[i]));
ProcessTheFrames(true);
CloseReader();
delete segment_;
segment_ = NULL;
}
}
TEST_F(Vp9HeaderParserTests, API) {
vp9_parser::Vp9HeaderParser parser;
uint8_t data;
EXPECT_FALSE(parser.ParseUncompressedHeader(NULL, 0));
EXPECT_FALSE(parser.ParseUncompressedHeader(NULL, 10));
EXPECT_FALSE(parser.ParseUncompressedHeader(&data, 0));
}
} // namespace
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,269 +0,0 @@
// Copyright (c) 2016 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 "common/vp9_level_stats.h"
#include <inttypes.h>
#include <limits>
#include <utility>
#include "common/webm_constants.h"
namespace vp9_parser {
const Vp9LevelRow Vp9LevelStats::Vp9LevelTable[kNumVp9Levels] = {
{LEVEL_1, 829440, 36864, 200, 400, 2, 1, 4, 8, 512},
{LEVEL_1_1, 2764800, 73728, 800, 1000, 2, 1, 4, 8, 768},
{LEVEL_2, 4608000, 122880, 1800, 1500, 2, 1, 4, 8, 960},
{LEVEL_2_1, 9216000, 245760, 3600, 2800, 2, 2, 4, 8, 1344},
{LEVEL_3, 20736000, 552960, 7200, 6000, 2, 4, 4, 8, 2048},
{LEVEL_3_1, 36864000, 983040, 12000, 10000, 2, 4, 4, 8, 2752},
{LEVEL_4, 83558400, 2228224, 18000, 16000, 4, 4, 4, 8, 4160},
{LEVEL_4_1, 160432128, 2228224, 30000, 18000, 4, 4, 5, 6, 4160},
{LEVEL_5, 311951360, 8912896, 60000, 36000, 6, 8, 6, 4, 8384},
{LEVEL_5_1, 588251136, 8912896, 120000, 46000, 8, 8, 10, 4, 8384},
// CPB Size = 0 for levels 5_2 to 6_2
{LEVEL_5_2, 1176502272, 8912896, 180000, 0, 8, 8, 10, 4, 8384},
{LEVEL_6, 1176502272, 35651584, 180000, 0, 8, 16, 10, 4, 16832},
{LEVEL_6_1, 2353004544, 35651584, 240000, 0, 8, 16, 10, 4, 16832},
{LEVEL_6_2, 4706009088, 35651584, 480000, 0, 8, 16, 10, 4, 16832}};
void Vp9LevelStats::AddFrame(const Vp9HeaderParser& parser, int64_t time_ns) {
++frames;
if (start_ns_ == -1)
start_ns_ = time_ns;
end_ns_ = time_ns;
const int width = parser.width();
const int height = parser.height();
const int64_t luma_picture_size = width * height;
const int64_t luma_picture_breadth = (width > height) ? width : height;
if (luma_picture_size > max_luma_picture_size_)
max_luma_picture_size_ = luma_picture_size;
if (luma_picture_breadth > max_luma_picture_breadth_)
max_luma_picture_breadth_ = luma_picture_breadth;
total_compressed_size_ += parser.frame_size();
while (!luma_window_.empty() &&
luma_window_.front().first <
(time_ns - (libwebm::kNanosecondsPerSecondi - 1))) {
current_luma_size_ -= luma_window_.front().second;
luma_window_.pop();
}
current_luma_size_ += luma_picture_size;
luma_window_.push(std::make_pair(time_ns, luma_picture_size));
if (current_luma_size_ > max_luma_size_) {
max_luma_size_ = current_luma_size_;
max_luma_end_ns_ = luma_window_.back().first;
}
// Record CPB stats.
// Remove all frames that are less than window size.
while (cpb_window_.size() > 3) {
current_cpb_size_ -= cpb_window_.front().second;
cpb_window_.pop();
}
cpb_window_.push(std::make_pair(time_ns, parser.frame_size()));
current_cpb_size_ += parser.frame_size();
if (current_cpb_size_ > max_cpb_size_) {
max_cpb_size_ = current_cpb_size_;
max_cpb_start_ns_ = cpb_window_.front().first;
max_cpb_end_ns_ = cpb_window_.back().first;
}
if (max_cpb_window_size_ < static_cast<int64_t>(cpb_window_.size())) {
max_cpb_window_size_ = cpb_window_.size();
max_cpb_window_end_ns_ = time_ns;
}
// Record altref stats.
if (parser.altref()) {
const int delta_altref = frames_since_last_altref;
if (first_altref) {
first_altref = false;
} else if (delta_altref < minimum_altref_distance) {
minimum_altref_distance = delta_altref;
min_altref_end_ns = time_ns;
}
frames_since_last_altref = 0;
} else {
++frames_since_last_altref;
++displayed_frames;
// TODO(fgalligan): Add support for other color formats. Currently assuming
// 420.
total_uncompressed_bits_ +=
(luma_picture_size * parser.bit_depth() * 3) / 2;
}
// Count max reference frames.
if (parser.key() == 1) {
frames_refreshed_ = 0;
} else {
frames_refreshed_ |= parser.refresh_frame_flags();
int ref_frame_count = frames_refreshed_ & 1;
for (int i = 1; i < kMaxVp9RefFrames; ++i) {
ref_frame_count += (frames_refreshed_ >> i) & 1;
}
if (ref_frame_count > max_frames_refreshed_)
max_frames_refreshed_ = ref_frame_count;
}
// Count max tiles.
const int tiles = parser.column_tiles();
if (tiles > max_column_tiles_)
max_column_tiles_ = tiles;
}
Vp9Level Vp9LevelStats::GetLevel() const {
const int64_t max_luma_sample_rate = GetMaxLumaSampleRate();
const int64_t max_luma_picture_size = GetMaxLumaPictureSize();
const int64_t max_luma_picture_breadth = GetMaxLumaPictureBreadth();
const double average_bitrate = GetAverageBitRate();
const double max_cpb_size = GetMaxCpbSize();
const double compresion_ratio = GetCompressionRatio();
const int max_column_tiles = GetMaxColumnTiles();
const int min_altref_distance = GetMinimumAltrefDistance();
const int max_ref_frames = GetMaxReferenceFrames();
int level_index = 0;
Vp9Level max_level = LEVEL_UNKNOWN;
const double grace_multiplier =
max_luma_sample_rate_grace_percent_ / 100.0 + 1.0;
for (int i = 0; i < kNumVp9Levels; ++i) {
if (max_luma_sample_rate <=
Vp9LevelTable[i].max_luma_sample_rate * grace_multiplier) {
if (max_level < Vp9LevelTable[i].level) {
max_level = Vp9LevelTable[i].level;
level_index = i;
}
break;
}
}
for (int i = 0; i < kNumVp9Levels; ++i) {
if (max_luma_picture_size <= Vp9LevelTable[i].max_luma_picture_size) {
if (max_level < Vp9LevelTable[i].level) {
max_level = Vp9LevelTable[i].level;
level_index = i;
}
break;
}
}
for (int i = 0; i < kNumVp9Levels; ++i) {
if (max_luma_picture_breadth <= Vp9LevelTable[i].max_luma_picture_breadth) {
if (max_level < Vp9LevelTable[i].level) {
max_level = Vp9LevelTable[i].level;
level_index = i;
}
break;
}
}
for (int i = 0; i < kNumVp9Levels; ++i) {
if (average_bitrate <= Vp9LevelTable[i].average_bitrate) {
if (max_level < Vp9LevelTable[i].level) {
max_level = Vp9LevelTable[i].level;
level_index = i;
}
break;
}
}
for (int i = 0; i < kNumVp9Levels; ++i) {
// Only check CPB size for levels that are defined.
if (Vp9LevelTable[i].max_cpb_size > 0 &&
max_cpb_size <= Vp9LevelTable[i].max_cpb_size) {
if (max_level < Vp9LevelTable[i].level) {
max_level = Vp9LevelTable[i].level;
level_index = i;
}
break;
}
}
for (int i = 0; i < kNumVp9Levels; ++i) {
if (max_column_tiles <= Vp9LevelTable[i].max_tiles) {
if (max_level < Vp9LevelTable[i].level) {
max_level = Vp9LevelTable[i].level;
level_index = i;
}
break;
}
}
for (int i = 0; i < kNumVp9Levels; ++i) {
if (max_ref_frames <= Vp9LevelTable[i].max_ref_frames) {
if (max_level < Vp9LevelTable[i].level) {
max_level = Vp9LevelTable[i].level;
level_index = i;
}
break;
}
}
// Check if the current level meets the minimum altref distance requirement.
// If not, set to unknown level as we can't move up a level as the minimum
// altref distance get farther apart and we can't move down a level as we are
// already at the minimum level for all the other requirements.
if (min_altref_distance < Vp9LevelTable[level_index].min_altref_distance)
max_level = LEVEL_UNKNOWN;
// The minimum compression ratio has the same behavior as minimum altref
// distance.
if (compresion_ratio < Vp9LevelTable[level_index].compresion_ratio)
max_level = LEVEL_UNKNOWN;
return max_level;
}
int64_t Vp9LevelStats::GetMaxLumaSampleRate() const { return max_luma_size_; }
int64_t Vp9LevelStats::GetMaxLumaPictureSize() const {
return max_luma_picture_size_;
}
int64_t Vp9LevelStats::GetMaxLumaPictureBreadth() const {
return max_luma_picture_breadth_;
}
double Vp9LevelStats::GetAverageBitRate() const {
const int64_t frame_duration_ns = end_ns_ - start_ns_;
double duration_seconds =
((duration_ns_ == -1) ? frame_duration_ns : duration_ns_) /
libwebm::kNanosecondsPerSecond;
if (estimate_last_frame_duration_ &&
(duration_ns_ == -1 || duration_ns_ <= frame_duration_ns)) {
const double sec_per_frame = frame_duration_ns /
libwebm::kNanosecondsPerSecond /
(displayed_frames - 1);
duration_seconds += sec_per_frame;
}
return total_compressed_size_ / duration_seconds / 125.0;
}
double Vp9LevelStats::GetMaxCpbSize() const { return max_cpb_size_ / 125.0; }
double Vp9LevelStats::GetCompressionRatio() const {
return total_uncompressed_bits_ /
static_cast<double>(total_compressed_size_ * 8);
}
int Vp9LevelStats::GetMaxColumnTiles() const { return max_column_tiles_; }
int Vp9LevelStats::GetMinimumAltrefDistance() const {
if (minimum_altref_distance != std::numeric_limits<int>::max())
return minimum_altref_distance;
else
return -1;
}
int Vp9LevelStats::GetMaxReferenceFrames() const {
return max_frames_refreshed_;
}
} // namespace vp9_parser

View File

@ -1,215 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_COMMON_VP9_LEVEL_STATS_H_
#define LIBWEBM_COMMON_VP9_LEVEL_STATS_H_
#include <limits>
#include <queue>
#include <utility>
#include "common/vp9_header_parser.h"
namespace vp9_parser {
const int kMaxVp9RefFrames = 8;
// Defined VP9 levels. See http://www.webmproject.org/vp9/profiles/ for
// detailed information on VP9 levels.
const int kNumVp9Levels = 14;
enum Vp9Level {
LEVEL_UNKNOWN = 0,
LEVEL_1 = 10,
LEVEL_1_1 = 11,
LEVEL_2 = 20,
LEVEL_2_1 = 21,
LEVEL_3 = 30,
LEVEL_3_1 = 31,
LEVEL_4 = 40,
LEVEL_4_1 = 41,
LEVEL_5 = 50,
LEVEL_5_1 = 51,
LEVEL_5_2 = 52,
LEVEL_6 = 60,
LEVEL_6_1 = 61,
LEVEL_6_2 = 62
};
struct Vp9LevelRow {
Vp9LevelRow() = default;
~Vp9LevelRow() = default;
Vp9LevelRow(Vp9LevelRow&& other) = default;
Vp9LevelRow(const Vp9LevelRow& other) = default;
Vp9LevelRow& operator=(Vp9LevelRow&& other) = delete;
Vp9LevelRow& operator=(const Vp9LevelRow& other) = delete;
Vp9Level level;
int64_t max_luma_sample_rate;
int64_t max_luma_picture_size;
int64_t max_luma_picture_breadth;
double average_bitrate;
double max_cpb_size;
double compresion_ratio;
int max_tiles;
int min_altref_distance;
int max_ref_frames;
};
// Class to determine the VP9 level of a VP9 bitstream.
class Vp9LevelStats {
public:
static const Vp9LevelRow Vp9LevelTable[kNumVp9Levels];
Vp9LevelStats()
: frames(0),
displayed_frames(0),
start_ns_(-1),
end_ns_(-1),
duration_ns_(-1),
max_luma_picture_size_(0),
max_luma_picture_breadth_(0),
current_luma_size_(0),
max_luma_size_(0),
max_luma_end_ns_(0),
max_luma_sample_rate_grace_percent_(1.5),
first_altref(true),
frames_since_last_altref(0),
minimum_altref_distance(std::numeric_limits<int>::max()),
min_altref_end_ns(0),
max_cpb_window_size_(0),
max_cpb_window_end_ns_(0),
current_cpb_size_(0),
max_cpb_size_(0),
max_cpb_start_ns_(0),
max_cpb_end_ns_(0),
total_compressed_size_(0),
total_uncompressed_bits_(0),
frames_refreshed_(0),
max_frames_refreshed_(0),
max_column_tiles_(0),
estimate_last_frame_duration_(true) {}
~Vp9LevelStats() = default;
Vp9LevelStats(Vp9LevelStats&& other) = delete;
Vp9LevelStats(const Vp9LevelStats& other) = delete;
Vp9LevelStats& operator=(Vp9LevelStats&& other) = delete;
Vp9LevelStats& operator=(const Vp9LevelStats& other) = delete;
// Collects stats on a VP9 frame. The frame must already be parsed by
// |parser|. |time_ns| is the start time of the frame in nanoseconds.
void AddFrame(const Vp9HeaderParser& parser, int64_t time_ns);
// Returns the current VP9 level. All of the video frames should have been
// processed with AddFrame before calling this function.
Vp9Level GetLevel() const;
// Returns the maximum luma samples (pixels) per second. The Alt-Ref frames
// are taken into account, therefore this number may be larger than the
// display luma samples per second
int64_t GetMaxLumaSampleRate() const;
// The maximum frame size (width * height) in samples.
int64_t GetMaxLumaPictureSize() const;
// The maximum frame breadth (max of width and height) in samples.
int64_t GetMaxLumaPictureBreadth() const;
// The average bitrate of the video in kbps.
double GetAverageBitRate() const;
// The largest data size for any 4 consecutive frames in kilobits.
double GetMaxCpbSize() const;
// The ratio of total bytes decompressed over total bytes compressed.
double GetCompressionRatio() const;
// The maximum number of VP9 column tiles.
int GetMaxColumnTiles() const;
// The minimum distance in frames between two consecutive alternate reference
// frames.
int GetMinimumAltrefDistance() const;
// The maximum number of reference frames that had to be stored.
int GetMaxReferenceFrames() const;
// Sets the duration of the video stream in nanoseconds. If the duration is
// not explictly set by this function then this class will use end - start
// as the duration.
void set_duration(int64_t time_ns) { duration_ns_ = time_ns; }
double max_luma_sample_rate_grace_percent() const {
return max_luma_sample_rate_grace_percent_;
}
void set_max_luma_sample_rate_grace_percent(double percent) {
max_luma_sample_rate_grace_percent_ = percent;
}
bool estimate_last_frame_duration() const {
return estimate_last_frame_duration_;
}
// If true try to estimate the last frame's duration if the stream's duration
// is not set or the stream's duration equals the last frame's timestamp.
void set_estimate_last_frame_duration(bool flag) {
estimate_last_frame_duration_ = flag;
}
private:
int frames;
int displayed_frames;
int64_t start_ns_;
int64_t end_ns_;
int64_t duration_ns_;
int64_t max_luma_picture_size_;
int64_t max_luma_picture_breadth_;
// This is used to calculate the maximum number of luma samples per second.
// The first value is the luma picture size and the second value is the time
// in nanoseconds of one frame.
std::queue<std::pair<int64_t, int64_t>> luma_window_;
int64_t current_luma_size_;
int64_t max_luma_size_;
int64_t max_luma_end_ns_;
// MaxLumaSampleRate = (ExampleFrameRate + ExampleFrameRate /
// MinimumAltrefDistance) * MaxLumaPictureSize. For levels 1-4
// ExampleFrameRate / MinimumAltrefDistance is non-integer, so using a sliding
// window of one frame to calculate MaxLumaSampleRate may have frames >
// (ExampleFrameRate + ExampleFrameRate / MinimumAltrefDistance) in the
// window. In order to address this issue, a grace percent of 1.5 was added.
double max_luma_sample_rate_grace_percent_;
bool first_altref;
int frames_since_last_altref;
int minimum_altref_distance;
int64_t min_altref_end_ns;
// This is used to calculate the maximum number of compressed bytes for four
// consecutive frames. The first value is the compressed frame size and the
// second value is the time in nanoseconds of one frame.
std::queue<std::pair<int64_t, int64_t>> cpb_window_;
int64_t max_cpb_window_size_;
int64_t max_cpb_window_end_ns_;
int64_t current_cpb_size_;
int64_t max_cpb_size_;
int64_t max_cpb_start_ns_;
int64_t max_cpb_end_ns_;
int64_t total_compressed_size_;
int64_t total_uncompressed_bits_;
int frames_refreshed_;
int max_frames_refreshed_;
int max_column_tiles_;
bool estimate_last_frame_duration_;
};
} // namespace vp9_parser
#endif // LIBWEBM_COMMON_VP9_LEVEL_STATS_H_

View File

@ -1,191 +0,0 @@
// Copyright (c) 2016 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 "common/vp9_level_stats.h"
#include <memory>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "common/hdr_util.h"
#include "common/vp9_header_parser.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
#include "testing/test_util.h"
namespace {
// TODO(fgalligan): Refactor this test with other test files in this directory.
class Vp9LevelStatsTests : public ::testing::Test {
public:
Vp9LevelStatsTests() : is_reader_open_(false) {}
~Vp9LevelStatsTests() override { CloseReader(); }
void CloseReader() {
if (is_reader_open_) {
reader_.Close();
}
is_reader_open_ = false;
}
void CreateAndLoadSegment(const std::string& filename,
int expected_doc_type_ver) {
ASSERT_NE(0u, filename.length());
filename_ = test::GetTestFilePath(filename);
ASSERT_EQ(0, reader_.Open(filename_.c_str()));
is_reader_open_ = true;
pos_ = 0;
mkvparser::EBMLHeader ebml_header;
ebml_header.Parse(&reader_, pos_);
ASSERT_EQ(1, ebml_header.m_version);
ASSERT_EQ(1, ebml_header.m_readVersion);
ASSERT_STREQ("webm", ebml_header.m_docType);
ASSERT_EQ(expected_doc_type_ver, ebml_header.m_docTypeVersion);
ASSERT_EQ(2, ebml_header.m_docTypeReadVersion);
mkvparser::Segment* temp;
ASSERT_EQ(0, mkvparser::Segment::CreateInstance(&reader_, pos_, temp));
segment_.reset(temp);
ASSERT_FALSE(HasFailure());
ASSERT_GE(0, segment_->Load());
}
void CreateAndLoadSegment(const std::string& filename) {
CreateAndLoadSegment(filename, 4);
}
void ProcessTheFrames() {
std::vector<uint8_t> data;
size_t data_len = 0;
const mkvparser::Tracks* const parser_tracks = segment_->GetTracks();
ASSERT_TRUE(parser_tracks != NULL);
const mkvparser::Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster);
while ((cluster != NULL) && !cluster->EOS()) {
const mkvparser::BlockEntry* block_entry;
long status = cluster->GetFirst(block_entry); // NOLINT
ASSERT_EQ(0, status);
while ((block_entry != NULL) && !block_entry->EOS()) {
const mkvparser::Block* const block = block_entry->GetBlock();
ASSERT_TRUE(block != NULL);
const long long trackNum = block->GetTrackNumber(); // NOLINT
const mkvparser::Track* const parser_track =
parser_tracks->GetTrackByNumber(
static_cast<unsigned long>(trackNum)); // NOLINT
ASSERT_TRUE(parser_track != NULL);
const long long track_type = parser_track->GetType(); // NOLINT
if (track_type == mkvparser::Track::kVideo) {
const int frame_count = block->GetFrameCount();
const long long time_ns = block->GetTime(cluster); // NOLINT
for (int i = 0; i < frame_count; ++i) {
const mkvparser::Block::Frame& frame = block->GetFrame(i);
if (static_cast<size_t>(frame.len) > data.size()) {
data.resize(frame.len);
data_len = static_cast<size_t>(frame.len);
}
ASSERT_FALSE(frame.Read(&reader_, &data[0]));
parser_.ParseUncompressedHeader(&data[0], data_len);
stats_.AddFrame(parser_, time_ns);
}
}
status = cluster->GetNext(block_entry, block_entry);
ASSERT_EQ(0, status);
}
cluster = segment_->GetNext(cluster);
}
}
protected:
mkvparser::MkvReader reader_;
bool is_reader_open_;
std::unique_ptr<mkvparser::Segment> segment_;
std::string filename_;
long long pos_; // NOLINT
vp9_parser::Vp9HeaderParser parser_;
vp9_parser::Vp9LevelStats stats_;
};
TEST_F(Vp9LevelStatsTests, VideoOnlyFile) {
CreateAndLoadSegment("test_stereo_left_right.webm");
ProcessTheFrames();
EXPECT_EQ(256, parser_.width());
EXPECT_EQ(144, parser_.height());
EXPECT_EQ(1, parser_.column_tiles());
EXPECT_EQ(0, parser_.frame_parallel_mode());
EXPECT_EQ(11, stats_.GetLevel());
EXPECT_EQ(479232, stats_.GetMaxLumaSampleRate());
EXPECT_EQ(36864, stats_.GetMaxLumaPictureSize());
EXPECT_DOUBLE_EQ(264.03233333333333, stats_.GetAverageBitRate());
EXPECT_DOUBLE_EQ(147.136, stats_.GetMaxCpbSize());
EXPECT_DOUBLE_EQ(19.267458404715583, stats_.GetCompressionRatio());
EXPECT_EQ(1, stats_.GetMaxColumnTiles());
EXPECT_EQ(11, stats_.GetMinimumAltrefDistance());
EXPECT_EQ(3, stats_.GetMaxReferenceFrames());
EXPECT_TRUE(stats_.estimate_last_frame_duration());
stats_.set_estimate_last_frame_duration(false);
EXPECT_DOUBLE_EQ(275.512, stats_.GetAverageBitRate());
}
TEST_F(Vp9LevelStatsTests, Muxed) {
CreateAndLoadSegment("bbb_480p_vp9_opus_1second.webm", 4);
ProcessTheFrames();
EXPECT_EQ(854, parser_.width());
EXPECT_EQ(480, parser_.height());
EXPECT_EQ(2, parser_.column_tiles());
EXPECT_EQ(1, parser_.frame_parallel_mode());
EXPECT_EQ(30, stats_.GetLevel());
EXPECT_EQ(9838080, stats_.GetMaxLumaSampleRate());
EXPECT_EQ(409920, stats_.GetMaxLumaPictureSize());
EXPECT_DOUBLE_EQ(447.09394572025053, stats_.GetAverageBitRate());
EXPECT_DOUBLE_EQ(118.464, stats_.GetMaxCpbSize());
EXPECT_DOUBLE_EQ(241.17670131398313, stats_.GetCompressionRatio());
EXPECT_EQ(2, stats_.GetMaxColumnTiles());
EXPECT_EQ(9, stats_.GetMinimumAltrefDistance());
EXPECT_EQ(3, stats_.GetMaxReferenceFrames());
stats_.set_estimate_last_frame_duration(false);
EXPECT_DOUBLE_EQ(468.38413361169108, stats_.GetAverageBitRate());
}
TEST_F(Vp9LevelStatsTests, SetDuration) {
CreateAndLoadSegment("test_stereo_left_right.webm");
ProcessTheFrames();
const int64_t kDurationNano = 2080000000; // 2.08 seconds
stats_.set_duration(kDurationNano);
EXPECT_EQ(256, parser_.width());
EXPECT_EQ(144, parser_.height());
EXPECT_EQ(1, parser_.column_tiles());
EXPECT_EQ(0, parser_.frame_parallel_mode());
EXPECT_EQ(11, stats_.GetLevel());
EXPECT_EQ(479232, stats_.GetMaxLumaSampleRate());
EXPECT_EQ(36864, stats_.GetMaxLumaPictureSize());
EXPECT_DOUBLE_EQ(264.9153846153846, stats_.GetAverageBitRate());
EXPECT_DOUBLE_EQ(147.136, stats_.GetMaxCpbSize());
EXPECT_DOUBLE_EQ(19.267458404715583, stats_.GetCompressionRatio());
EXPECT_EQ(1, stats_.GetMaxColumnTiles());
EXPECT_EQ(11, stats_.GetMinimumAltrefDistance());
EXPECT_EQ(3, stats_.GetMaxReferenceFrames());
}
} // namespace
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,20 +0,0 @@
// 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 LIBWEBM_COMMON_WEBM_CONSTANTS_H_
#define LIBWEBM_COMMON_WEBM_CONSTANTS_H_
namespace libwebm {
const double kNanosecondsPerSecond = 1000000000.0;
const int kNanosecondsPerSecondi = 1000000000;
const int kNanosecondsPerMillisecond = 1000000;
} // namespace libwebm
#endif // LIBWEBM_COMMON_WEBM_CONSTANTS_H_

View File

@ -1,85 +0,0 @@
// 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 "common/webm_endian.h"
#include <stdint.h>
namespace {
// Swaps unsigned 32 bit values to big endian if needed. Returns |value|
// unmodified if architecture is big endian. Returns swapped bytes of |value|
// if architecture is little endian. Returns 0 otherwise.
uint32_t swap32_check_little_endian(uint32_t value) {
// Check endianness.
union {
uint32_t val32;
uint8_t c[4];
} check;
check.val32 = 0x01234567U;
// Check for big endian.
if (check.c[3] == 0x67)
return value;
// Check for not little endian.
if (check.c[0] != 0x67)
return 0;
return value << 24 | ((value << 8) & 0x0000FF00U) |
((value >> 8) & 0x00FF0000U) | value >> 24;
}
// Swaps unsigned 64 bit values to big endian if needed. Returns |value|
// unmodified if architecture is big endian. Returns swapped bytes of |value|
// if architecture is little endian. Returns 0 otherwise.
uint64_t swap64_check_little_endian(uint64_t value) {
// Check endianness.
union {
uint64_t val64;
uint8_t c[8];
} check;
check.val64 = 0x0123456789ABCDEFULL;
// Check for big endian.
if (check.c[7] == 0xEF)
return value;
// Check for not little endian.
if (check.c[0] != 0xEF)
return 0;
return value << 56 | ((value << 40) & 0x00FF000000000000ULL) |
((value << 24) & 0x0000FF0000000000ULL) |
((value << 8) & 0x000000FF00000000ULL) |
((value >> 8) & 0x00000000FF000000ULL) |
((value >> 24) & 0x0000000000FF0000ULL) |
((value >> 40) & 0x000000000000FF00ULL) | value >> 56;
}
} // namespace
namespace libwebm {
uint32_t host_to_bigendian(uint32_t value) {
return swap32_check_little_endian(value);
}
uint32_t bigendian_to_host(uint32_t value) {
return swap32_check_little_endian(value);
}
uint64_t host_to_bigendian(uint64_t value) {
return swap64_check_little_endian(value);
}
uint64_t bigendian_to_host(uint64_t value) {
return swap64_check_little_endian(value);
}
} // namespace libwebm

View File

@ -1,38 +0,0 @@
// 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 LIBWEBM_COMMON_WEBM_ENDIAN_H_
#define LIBWEBM_COMMON_WEBM_ENDIAN_H_
#include <stdint.h>
namespace libwebm {
// Swaps unsigned 32 bit values to big endian if needed. Returns |value| if
// architecture is big endian. Returns big endian value if architecture is
// little endian. Returns 0 otherwise.
uint32_t host_to_bigendian(uint32_t value);
// Swaps unsigned 32 bit values to little endian if needed. Returns |value| if
// architecture is big endian. Returns little endian value if architecture is
// little endian. Returns 0 otherwise.
uint32_t bigendian_to_host(uint32_t value);
// Swaps unsigned 64 bit values to big endian if needed. Returns |value| if
// architecture is big endian. Returns big endian value if architecture is
// little endian. Returns 0 otherwise.
uint64_t host_to_bigendian(uint64_t value);
// Swaps unsigned 64 bit values to little endian if needed. Returns |value| if
// architecture is big endian. Returns little endian value if architecture is
// little endian. Returns 0 otherwise.
uint64_t bigendian_to_host(uint64_t value);
} // namespace libwebm
#endif // LIBWEBM_COMMON_WEBM_ENDIAN_H_

View File

@ -1,192 +0,0 @@
// 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 COMMON_WEBMIDS_H_
#define COMMON_WEBMIDS_H_
namespace libwebm {
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,
kMkvTitle = 0x7BA9,
kMkvMuxingApp = 0x4D80,
kMkvWritingApp = 0x5741,
// Cluster
kMkvCluster = 0x1F43B675,
kMkvTimecode = 0xE7,
kMkvPrevSize = 0xAB,
kMkvBlockGroup = 0xA0,
kMkvBlock = 0xA1,
kMkvBlockDuration = 0x9B,
kMkvReferenceBlock = 0xFB,
kMkvLaceNumber = 0xCC,
kMkvSimpleBlock = 0xA3,
kMkvBlockAdditions = 0x75A1,
kMkvBlockMore = 0xA6,
kMkvBlockAddID = 0xEE,
kMkvBlockAdditional = 0xA5,
kMkvDiscardPadding = 0x75A2,
// Track
kMkvTracks = 0x1654AE6B,
kMkvTrackEntry = 0xAE,
kMkvTrackNumber = 0xD7,
kMkvTrackUID = 0x73C5,
kMkvTrackType = 0x83,
kMkvFlagEnabled = 0xB9,
kMkvFlagDefault = 0x88,
kMkvFlagForced = 0x55AA,
kMkvFlagLacing = 0x9C,
kMkvDefaultDuration = 0x23E383,
kMkvMaxBlockAdditionID = 0x55EE,
kMkvName = 0x536E,
kMkvLanguage = 0x22B59C,
kMkvCodecID = 0x86,
kMkvCodecPrivate = 0x63A2,
kMkvCodecName = 0x258688,
kMkvCodecDelay = 0x56AA,
kMkvSeekPreRoll = 0x56BB,
// video
kMkvVideo = 0xE0,
kMkvFlagInterlaced = 0x9A,
kMkvStereoMode = 0x53B8,
kMkvAlphaMode = 0x53C0,
kMkvPixelWidth = 0xB0,
kMkvPixelHeight = 0xBA,
kMkvPixelCropBottom = 0x54AA,
kMkvPixelCropTop = 0x54BB,
kMkvPixelCropLeft = 0x54CC,
kMkvPixelCropRight = 0x54DD,
kMkvDisplayWidth = 0x54B0,
kMkvDisplayHeight = 0x54BA,
kMkvDisplayUnit = 0x54B2,
kMkvAspectRatioType = 0x54B3,
kMkvFrameRate = 0x2383E3,
// end video
// colour
kMkvColour = 0x55B0,
kMkvMatrixCoefficients = 0x55B1,
kMkvBitsPerChannel = 0x55B2,
kMkvChromaSubsamplingHorz = 0x55B3,
kMkvChromaSubsamplingVert = 0x55B4,
kMkvCbSubsamplingHorz = 0x55B5,
kMkvCbSubsamplingVert = 0x55B6,
kMkvChromaSitingHorz = 0x55B7,
kMkvChromaSitingVert = 0x55B8,
kMkvRange = 0x55B9,
kMkvTransferCharacteristics = 0x55BA,
kMkvPrimaries = 0x55BB,
kMkvMaxCLL = 0x55BC,
kMkvMaxFALL = 0x55BD,
// mastering metadata
kMkvMasteringMetadata = 0x55D0,
kMkvPrimaryRChromaticityX = 0x55D1,
kMkvPrimaryRChromaticityY = 0x55D2,
kMkvPrimaryGChromaticityX = 0x55D3,
kMkvPrimaryGChromaticityY = 0x55D4,
kMkvPrimaryBChromaticityX = 0x55D5,
kMkvPrimaryBChromaticityY = 0x55D6,
kMkvWhitePointChromaticityX = 0x55D7,
kMkvWhitePointChromaticityY = 0x55D8,
kMkvLuminanceMax = 0x55D9,
kMkvLuminanceMin = 0x55DA,
// end mastering metadata
// end colour
// projection
kMkvProjection = 0x7670,
kMkvProjectionType = 0x7671,
kMkvProjectionPrivate = 0x7672,
kMkvProjectionPoseYaw = 0x7673,
kMkvProjectionPosePitch = 0x7674,
kMkvProjectionPoseRoll = 0x7675,
// end projection
// audio
kMkvAudio = 0xE1,
kMkvSamplingFrequency = 0xB5,
kMkvOutputSamplingFrequency = 0x78B5,
kMkvChannels = 0x9F,
kMkvBitDepth = 0x6264,
// end audio
// ContentEncodings
kMkvContentEncodings = 0x6D80,
kMkvContentEncoding = 0x6240,
kMkvContentEncodingOrder = 0x5031,
kMkvContentEncodingScope = 0x5032,
kMkvContentEncodingType = 0x5033,
kMkvContentCompression = 0x5034,
kMkvContentCompAlgo = 0x4254,
kMkvContentCompSettings = 0x4255,
kMkvContentEncryption = 0x5035,
kMkvContentEncAlgo = 0x47E1,
kMkvContentEncKeyID = 0x47E2,
kMkvContentSignature = 0x47E3,
kMkvContentSigKeyID = 0x47E4,
kMkvContentSigAlgo = 0x47E5,
kMkvContentSigHashAlgo = 0x47E6,
kMkvContentEncAESSettings = 0x47E7,
kMkvAESSettingsCipherMode = 0x47E8,
kMkvAESSettingsCipherInitData = 0x47E9,
// end ContentEncodings
// Cueing Data
kMkvCues = 0x1C53BB6B,
kMkvCuePoint = 0xBB,
kMkvCueTime = 0xB3,
kMkvCueTrackPositions = 0xB7,
kMkvCueTrack = 0xF7,
kMkvCueClusterPosition = 0xF1,
kMkvCueBlockNumber = 0x5378,
// Chapters
kMkvChapters = 0x1043A770,
kMkvEditionEntry = 0x45B9,
kMkvChapterAtom = 0xB6,
kMkvChapterUID = 0x73C4,
kMkvChapterStringUID = 0x5654,
kMkvChapterTimeStart = 0x91,
kMkvChapterTimeEnd = 0x92,
kMkvChapterDisplay = 0x80,
kMkvChapString = 0x85,
kMkvChapLanguage = 0x437C,
kMkvChapCountry = 0x437E,
// Tags
kMkvTags = 0x1254C367,
kMkvTag = 0x7373,
kMkvSimpleTag = 0x67C8,
kMkvTagName = 0x45A3,
kMkvTagString = 0x4487
};
} // namespace libwebm
#endif // COMMON_WEBMIDS_H_

View File

@ -1,91 +0,0 @@
// 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 "webvtt/vttreader.h"
#include "webvtt/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);
}
}

View File

@ -1,15 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_HDR_UTIL_HPP_
#define LIBWEBM_HDR_UTIL_HPP_
// This file is a wrapper for the file included immediately after this comment.
// New projects should not include this file: include the file included below.
#include "common/hdr_util.h"
#endif // LIBWEBM_HDR_UTIL_HPP_

View File

@ -1,207 +0,0 @@
#!/bin/sh
##
## Copyright (c) 2015 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.
##
## This script generates 'WebM.framework'. An iOS app can mux/demux WebM
## container files by including 'WebM.framework'.
##
## Run ./iosbuild.sh to generate 'WebM.framework'. By default the framework
## bundle will be created in a directory called framework. Use --out-dir to
## change the output directory.
##
## This script is based on iosbuild.sh from the libwebp project.
. $(dirname $0)/common/common.sh
# Trap function. Cleans up build output.
cleanup() {
local readonly res=$?
cd "${ORIG_PWD}"
for dir in ${LIBDIRS}; do
if [ -d "${dir}" ]; then
rm -rf "${dir}"
fi
done
if [ $res -ne 0 ]; then
elog "build exited with error ($res)"
fi
}
trap cleanup EXIT
check_dir libwebm
iosbuild_usage() {
cat << EOF
Usage: ${0##*/} [arguments]
--help: Display this message and exit.
--out-dir: Override output directory (default is ${OUTDIR}).
--show-build-output: Show output from each library build.
--verbose: Output information about the environment and each stage of the
build.
EOF
}
# Extract the latest SDK version from the final field of the form: iphoneosX.Y
readonly SDK=$(xcodebuild -showsdks \
| grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}'
)
# Extract Xcode version.
readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2)
if [ -z "${XCODE}" ]; then
echo "Xcode not available"
exit 1
fi
# Add iPhoneOS-V6 to the list of platforms below if you need armv6 support.
# Note that iPhoneOS-V6 support is not available with the iOS6 SDK.
readonly INCLUDES="common/file_util.h
common/hdr_util.h
common/webmids.h
mkvmuxer/mkvmuxer.h
mkvmuxer/mkvmuxertypes.h
mkvmuxer/mkvmuxerutil.h
mkvmuxer/mkvwriter.h
mkvparser/mkvparser.h
mkvparser/mkvreader.h"
readonly PLATFORMS="iPhoneSimulator
iPhoneSimulator64
iPhoneOS-V7
iPhoneOS-V7s
iPhoneOS-V7-arm64"
readonly TARGETDIR="WebM.framework"
readonly DEVELOPER="$(xcode-select --print-path)"
readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
readonly LIPO="$(xcrun -sdk iphoneos${SDK} -find lipo)"
LIBLIST=""
OPT_FLAGS="-DNDEBUG -O3"
readonly SDK_MAJOR_VERSION="$(echo ${SDK} | awk -F '.' '{ print $1 }')"
if [ -z "${SDK_MAJOR_VERSION}" ]; then
elog "iOS SDK not available"
exit 1
elif [ "${SDK_MAJOR_VERSION}" -lt "6" ]; then
elog "You need iOS SDK version 6 or above"
exit 1
else
vlog "iOS SDK Version ${SDK}"
fi
# Parse the command line.
while [ -n "$1" ]; do
case "$1" in
--help)
iosbuild_usage
exit
;;
--out-dir)
OUTDIR="$2"
shift
;;
--enable-debug)
OPT_FLAGS="-g"
;;
--show-build-output)
devnull=
;;
--verbose)
VERBOSE=yes
;;
*)
iosbuild_usage
exit 1
;;
esac
shift
done
readonly OPT_FLAGS="${OPT_FLAGS}"
readonly OUTDIR="${OUTDIR:-framework}"
if [ "${VERBOSE}" = "yes" ]; then
cat << EOF
OUTDIR=${OUTDIR}
INCLUDES=${INCLUDES}
PLATFORMS=${PLATFORMS}
TARGETDIR=${TARGETDIR}
DEVELOPER=${DEVELOPER}
LIPO=${LIPO}
OPT_FLAGS=${OPT_FLAGS}
ORIG_PWD=${ORIG_PWD}
EOF
fi
rm -rf "${OUTDIR}/${TARGETDIR}"
mkdir -p "${OUTDIR}/${TARGETDIR}/Headers/"
for PLATFORM in ${PLATFORMS}; do
ARCH2=""
if [ "${PLATFORM}" = "iPhoneOS-V7-arm64" ]; then
PLATFORM="iPhoneOS"
ARCH="aarch64"
ARCH2="arm64"
elif [ "${PLATFORM}" = "iPhoneOS-V7s" ]; then
PLATFORM="iPhoneOS"
ARCH="armv7s"
elif [ "${PLATFORM}" = "iPhoneOS-V7" ]; then
PLATFORM="iPhoneOS"
ARCH="armv7"
elif [ "${PLATFORM}" = "iPhoneOS-V6" ]; then
PLATFORM="iPhoneOS"
ARCH="armv6"
elif [ "${PLATFORM}" = "iPhoneSimulator64" ]; then
PLATFORM="iPhoneSimulator"
ARCH="x86_64"
else
ARCH="i386"
fi
LIBDIR="${OUTDIR}/${PLATFORM}-${SDK}-${ARCH}"
LIBDIRS="${LIBDIRS} ${LIBDIR}"
LIBFILE="${LIBDIR}/libwebm.a"
eval mkdir -p "${LIBDIR}" ${devnull}
DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain"
SDKROOT="${PLATFORMSROOT}/"
SDKROOT="${SDKROOT}${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDK}.sdk/"
CXXFLAGS="-arch ${ARCH2:-${ARCH}} -isysroot ${SDKROOT} ${OPT_FLAGS}
-miphoneos-version-min=6.0"
# enable bitcode if available
if [ "${SDK_MAJOR_VERSION}" -gt 8 ]; then
CXXFLAGS="${CXXFLAGS} -fembed-bitcode"
fi
# Build using the legacy makefile (instead of generating via cmake).
eval make -f Makefile.unix libwebm.a CXXFLAGS=\"${CXXFLAGS}\" ${devnull}
# copy lib and add it to LIBLIST.
eval cp libwebm.a "${LIBFILE}" ${devnull}
LIBLIST="${LIBLIST} ${LIBFILE}"
# clean build so we can go again.
eval make -f Makefile.unix clean ${devnull}
done
# create include sub dirs in framework dir.
readonly framework_header_dir="${OUTDIR}/${TARGETDIR}/Headers"
readonly framework_header_sub_dirs="common mkvmuxer mkvparser"
for dir in ${framework_header_sub_dirs}; do
mkdir "${framework_header_dir}/${dir}"
done
for header_file in ${INCLUDES}; do
eval cp -p ${header_file} "${framework_header_dir}/${header_file}" ${devnull}
done
eval ${LIPO} -create ${LIBLIST} -output "${OUTDIR}/${TARGETDIR}/WebM" ${devnull}
echo "Succesfully built ${TARGETDIR} in ${OUTDIR}."

37
libwebm_2005.sln Normal file
View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwebm", "libwebm_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", "sample_2005.vcproj", "{0CB5681F-6065-490C-98C8-05531732ED7E}"
ProjectSection(ProjectDependencies) = postProject
{F9128EC6-C008-41AD-B38F-0E70D549D9F4} = {F9128EC6-C008-41AD-B38F-0E70D549D9F4}
EndProjectSection
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

204
libwebm_2005.vcproj Normal file
View File

@ -0,0 +1,204 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="libwebm"
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="false"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
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"
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="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
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=".\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>

38
libwebm_2008.sln Normal file
View 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\sample_muxer.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

209
libwebm_2008.vcproj Normal file
View File

@ -0,0 +1,209 @@
<?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="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(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"
/>
<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"
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>

View File

@ -1,158 +0,0 @@
// Copyright (c) 2016 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 "m2ts/webm2pes.h"
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "common/file_util.h"
#include "common/libwebm_util.h"
#include "m2ts/vpxpes_parser.h"
#include "testing/test_util.h"
namespace {
class Webm2PesTests : public ::testing::Test {
public:
// Constants for validating known values from input data.
const std::uint8_t kMinVideoStreamId = 0xE0;
const std::uint8_t kMaxVideoStreamId = 0xEF;
const int kPesHeaderSize = 6;
const int kPesOptionalHeaderStartOffset = kPesHeaderSize;
const int kPesOptionalHeaderSize = 9;
const int kPesOptionalHeaderMarkerValue = 0x2;
const int kWebm2PesOptHeaderRemainingSize = 6;
const int kBcmvHeaderSize = 10;
Webm2PesTests() = default;
~Webm2PesTests() = default;
void CreateAndLoadTestInput() {
libwebm::Webm2Pes converter(input_file_name_, temp_file_name_.name());
ASSERT_TRUE(converter.ConvertToFile());
ASSERT_TRUE(parser_.Open(pes_file_name()));
}
bool VerifyPacketStartCode(const libwebm::VpxPesParser::PesHeader& header) {
// PES packets all start with the byte sequence 0x0 0x0 0x1.
if (header.start_code[0] != 0 || header.start_code[1] != 0 ||
header.start_code[2] != 1) {
return false;
}
return true;
}
const std::string& pes_file_name() const { return temp_file_name_.name(); }
libwebm::VpxPesParser* parser() { return &parser_; }
private:
const libwebm::TempFileDeleter temp_file_name_;
const std::string input_file_name_ =
test::GetTestFilePath("bbb_480p_vp9_opus_1second.webm");
libwebm::VpxPesParser parser_;
};
TEST_F(Webm2PesTests, CreatePesFile) { CreateAndLoadTestInput(); }
TEST_F(Webm2PesTests, CanParseFirstPacket) {
CreateAndLoadTestInput();
libwebm::VpxPesParser::PesHeader header;
libwebm::VideoFrame frame;
ASSERT_TRUE(parser()->ParseNextPacket(&header, &frame));
EXPECT_TRUE(VerifyPacketStartCode(header));
// 9 bytes: PES optional header
// 10 bytes: BCMV Header
// 83 bytes: frame
// 102 bytes total in packet length field:
const std::size_t kPesPayloadLength = 102;
EXPECT_EQ(kPesPayloadLength, header.packet_length);
EXPECT_GE(header.stream_id, kMinVideoStreamId);
EXPECT_LE(header.stream_id, kMaxVideoStreamId);
// Test PesOptionalHeader values.
EXPECT_EQ(kPesOptionalHeaderMarkerValue, header.opt_header.marker);
EXPECT_EQ(kWebm2PesOptHeaderRemainingSize, header.opt_header.remaining_size);
EXPECT_EQ(0, header.opt_header.scrambling);
EXPECT_EQ(0, header.opt_header.priority);
EXPECT_EQ(0, header.opt_header.data_alignment);
EXPECT_EQ(0, header.opt_header.copyright);
EXPECT_EQ(0, header.opt_header.original);
EXPECT_EQ(1, header.opt_header.has_pts);
EXPECT_EQ(0, header.opt_header.has_dts);
EXPECT_EQ(0, header.opt_header.unused_fields);
// Test the BCMV header.
// Note: The length field of the BCMV header includes its own length.
const std::size_t kBcmvBaseLength = 10;
const std::size_t kFirstFrameLength = 83;
const libwebm::VpxPesParser::BcmvHeader kFirstBcmvHeader(kFirstFrameLength +
kBcmvBaseLength);
EXPECT_TRUE(header.bcmv_header.Valid());
EXPECT_EQ(kFirstBcmvHeader, header.bcmv_header);
// Parse the next packet to confirm correct parse and consumption of payload.
EXPECT_TRUE(parser()->ParseNextPacket(&header, &frame));
}
TEST_F(Webm2PesTests, CanMuxLargeBuffers) {
const std::size_t kBufferSize = 100 * 1024;
const std::int64_t kFakeTimestamp = libwebm::kNanosecondsPerSecond;
libwebm::VideoFrame fake_frame(kFakeTimestamp, libwebm::VideoFrame::kVP9);
ASSERT_TRUE(fake_frame.Init(kBufferSize));
std::memset(fake_frame.buffer().data.get(), 0x80, kBufferSize);
ASSERT_TRUE(fake_frame.SetBufferLength(kBufferSize));
libwebm::PacketDataBuffer pes_packet_buffer;
ASSERT_TRUE(
libwebm::Webm2Pes::WritePesPacket(fake_frame, &pes_packet_buffer));
// TODO(tomfinegan): Change VpxPesParser so it can read from a buffer, and get
// rid of this extra step.
libwebm::FilePtr pes_file(std::fopen(pes_file_name().c_str(), "wb"),
libwebm::FILEDeleter());
ASSERT_EQ(pes_packet_buffer.size(),
fwrite(&pes_packet_buffer[0], 1, pes_packet_buffer.size(),
pes_file.get()));
fclose(pes_file.get());
pes_file.release();
libwebm::VpxPesParser parser;
ASSERT_TRUE(parser.Open(pes_file_name()));
libwebm::VpxPesParser::PesHeader header;
libwebm::VideoFrame parsed_frame;
ASSERT_TRUE(parser.ParseNextPacket(&header, &parsed_frame));
EXPECT_EQ(fake_frame.nanosecond_pts(), parsed_frame.nanosecond_pts());
EXPECT_EQ(fake_frame.buffer().length, parsed_frame.buffer().length);
EXPECT_EQ(0, std::memcmp(fake_frame.buffer().data.get(),
parsed_frame.buffer().data.get(), kBufferSize));
}
TEST_F(Webm2PesTests, ParserConsumesAllInput) {
CreateAndLoadTestInput();
libwebm::VpxPesParser::PesHeader header;
libwebm::VideoFrame frame;
while (parser()->ParseNextPacket(&header, &frame) == true) {
EXPECT_TRUE(VerifyPacketStartCode(header));
}
EXPECT_EQ(0, parser()->BytesAvailable());
}
} // namespace
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,217 +0,0 @@
// Copyright (c) 2016 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 "m2ts/vpxpes2ts.h"
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <vector>
namespace libwebm {
// TODO(tomfinegan): Dedupe this and PesHeaderField.
// Stores a value and its size in bits for writing into a MPEG2 TS Header.
// Maximum size is 64 bits. Users may call the Check() method to perform minimal
// validation (size > 0 and <= 64).
struct TsHeaderField {
TsHeaderField(std::uint64_t value, std::uint32_t size_in_bits,
std::uint8_t byte_index, std::uint8_t bits_to_shift)
: bits(value),
num_bits(size_in_bits),
index(byte_index),
shift(bits_to_shift) {}
TsHeaderField() = delete;
TsHeaderField(const TsHeaderField&) = default;
TsHeaderField(TsHeaderField&&) = default;
~TsHeaderField() = default;
bool Check() const {
return num_bits > 0 && num_bits <= 64 && shift >= 0 && shift < 64;
}
// Value to be stored in the field.
std::uint64_t bits;
// Number of bits in the value.
const int num_bits;
// Index into the header for the byte in which |bits| will be written.
const std::uint8_t index;
// Number of bits to left shift value before or'ing. Ignored for whole bytes.
const int shift;
};
// Data storage for MPEG2 Transport Stream headers.
// https://en.wikipedia.org/wiki/MPEG_transport_stream#Packet
struct TsHeader {
TsHeader(bool payload_start, bool adaptation_flag, std::uint8_t counter)
: is_payload_start(payload_start),
has_adaptation(adaptation_flag),
counter_value(counter) {}
TsHeader() = delete;
TsHeader(const TsHeader&) = default;
TsHeader(TsHeader&&) = default;
~TsHeader() = default;
void Write(PacketDataBuffer* buffer) const;
// Indicates the packet is the beginning of a new fragmented payload.
const bool is_payload_start;
// Indicates the packet contains an adaptation field.
const bool has_adaptation;
// The sync byte is the bit pattern of 0x47 (ASCII char 'G').
const std::uint8_t kTsHeaderSyncByte = 0x47;
const std::uint8_t sync_byte = kTsHeaderSyncByte;
// Value for |continuity_counter|. Used to detect gaps when demuxing.
const std::uint8_t counter_value;
// Set when FEC is impossible. Always 0.
const TsHeaderField transport_error_indicator = TsHeaderField(0, 1, 1, 7);
// This MPEG2 TS header is the start of a new payload (aka PES packet).
const TsHeaderField payload_unit_start_indicator =
TsHeaderField(is_payload_start ? 1 : 0, 1, 1, 6);
// Set when the current packet has a higher priority than other packets with
// the same PID. Always 0 for VPX.
const TsHeaderField transport_priority = TsHeaderField(0, 1, 1, 5);
// https://en.wikipedia.org/wiki/MPEG_transport_stream#Packet_Identifier_.28PID.29
// 0x0020-0x1FFA May be assigned as needed to Program Map Tables, elementary
// streams and other data tables.
// Note: Though we hard code to 0x20, this value is actually 13 bits-- the
// buffer for the header is always set to 0, so it doesn't matter in practice.
const TsHeaderField pid = TsHeaderField(0x20, 8, 2, 0);
// Indicates scrambling key. Unused; always 0.
const TsHeaderField scrambling_control = TsHeaderField(0, 2, 3, 6);
// Adaptation field flag. Unused; always 0.
// TODO(tomfinegan): Not sure this is OK. Might need to add support for
// writing the Adaptation Field.
const TsHeaderField adaptation_field_flag =
TsHeaderField(has_adaptation ? 1 : 0, 1, 3, 5);
// Payload flag. All output packets created here have payloads. Always 1.
const TsHeaderField payload_flag = TsHeaderField(1, 1, 3, 4);
// Continuity counter. Two bit field that is incremented for every packet.
const TsHeaderField continuity_counter =
TsHeaderField(counter_value, 4, 3, 3);
};
void TsHeader::Write(PacketDataBuffer* buffer) const {
std::uint8_t* byte = &(*buffer)[0];
*byte = sync_byte;
*++byte = 0;
*byte |= transport_error_indicator.bits << transport_error_indicator.shift;
*byte |= payload_unit_start_indicator.bits
<< payload_unit_start_indicator.shift;
*byte |= transport_priority.bits << transport_priority.shift;
*++byte = pid.bits & 0xff;
*++byte = 0;
*byte |= scrambling_control.bits << scrambling_control.shift;
*byte |= adaptation_field_flag.bits << adaptation_field_flag.shift;
*byte |= payload_flag.bits << payload_flag.shift;
*byte |= continuity_counter.bits; // last 4 bits.
}
bool VpxPes2Ts::ConvertToFile() {
output_file_ = FilePtr(fopen(output_file_name_.c_str(), "wb"), FILEDeleter());
if (output_file_ == nullptr) {
std::fprintf(stderr, "VpxPes2Ts: Cannot open %s for output.\n",
output_file_name_.c_str());
return false;
}
pes_converter_.reset(new Webm2Pes(input_file_name_, this));
if (pes_converter_ == nullptr) {
std::fprintf(stderr, "VpxPes2Ts: Out of memory.\n");
return false;
}
return pes_converter_->ConvertToPacketReceiver();
}
bool VpxPes2Ts::ReceivePacket(const PacketDataBuffer& packet_data) {
const int kTsHeaderSize = 4;
const int kTsPayloadSize = 184;
const int kTsPacketSize = kTsHeaderSize + kTsPayloadSize;
int bytes_to_packetize = static_cast<int>(packet_data.size());
std::uint8_t continuity_counter = 0;
std::size_t read_pos = 0;
ts_buffer_.reserve(kTsPacketSize);
while (bytes_to_packetize > 0) {
if (continuity_counter > 0xf)
continuity_counter = 0;
// Calculate payload size (need to know if we'll have to pad with an empty
// adaptation field).
int payload_size = std::min(bytes_to_packetize, kTsPayloadSize);
// Write the TS header.
const TsHeader header(
bytes_to_packetize == static_cast<int>(packet_data.size()),
payload_size != kTsPayloadSize, continuity_counter);
header.Write(&ts_buffer_);
int write_pos = kTsHeaderSize;
// (pre)Pad payload with an empty adaptation field. All packets must be
// |kTsPacketSize| (188).
if (payload_size < kTsPayloadSize) {
// We need at least 2 bytes to write an empty adaptation field.
if (payload_size == (kTsPayloadSize - 1)) {
payload_size--;
}
// Padding adaptation field:
// 8 bits: number of adaptation field bytes following this byte.
// 8 bits: unused (in this program) flags.
// This is followed by a run of 0xff to reach |kTsPayloadSize| (184)
// bytes.
const int pad_size = kTsPayloadSize - payload_size - 1 - 1;
ts_buffer_[write_pos++] = pad_size + 1;
ts_buffer_[write_pos++] = 0;
const std::uint8_t kStuffingByte = 0xff;
for (int i = 0; i < pad_size; ++i) {
ts_buffer_[write_pos++] = kStuffingByte;
}
}
for (int i = 0; i < payload_size; ++i) {
ts_buffer_[write_pos++] = packet_data[read_pos++];
}
bytes_to_packetize -= payload_size;
continuity_counter++;
if (write_pos != kTsPacketSize) {
fprintf(stderr, "VpxPes2Ts: Invalid packet length.\n");
return false;
}
// Write contents of |ts_buffer_| to |output_file_|.
// TODO(tomfinegan): Writing 188 bytes at a time isn't exactly efficient...
// Fix me.
if (static_cast<int>(std::fwrite(&ts_buffer_[0], 1, kTsPacketSize,
output_file_.get())) != kTsPacketSize) {
std::fprintf(stderr, "VpxPes2Ts: TS packet write failed.\n");
return false;
}
}
return true;
}
} // namespace libwebm

View File

@ -1,45 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_M2TS_VPXPES2TS_H_
#define LIBWEBM_M2TS_VPXPES2TS_H_
#include <memory>
#include <string>
#include "common/libwebm_util.h"
#include "m2ts/webm2pes.h"
namespace libwebm {
class VpxPes2Ts : public PacketReceiverInterface {
public:
VpxPes2Ts(const std::string& input_file_name,
const std::string& output_file_name)
: input_file_name_(input_file_name),
output_file_name_(output_file_name) {}
virtual ~VpxPes2Ts() = default;
VpxPes2Ts() = delete;
VpxPes2Ts(const VpxPes2Ts&) = delete;
VpxPes2Ts(VpxPes2Ts&&) = delete;
bool ConvertToFile();
private:
bool ReceivePacket(const PacketDataBuffer& packet_data) override;
const std::string input_file_name_;
const std::string output_file_name_;
FilePtr output_file_;
std::unique_ptr<Webm2Pes> pes_converter_;
PacketDataBuffer ts_buffer_;
};
} // namespace libwebm
#endif // LIBWEBM_M2TS_VPXPES2TS_H_

View File

@ -1,33 +0,0 @@
// Copyright (c) 2016 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 "m2ts/vpxpes2ts.h"
#include <cstdio>
#include <cstdlib>
#include <string>
namespace {
void Usage(const char* argv[]) {
printf("Usage: %s <WebM file> <output file>", argv[0]);
}
} // namespace
int main(int argc, const char* argv[]) {
if (argc < 3) {
Usage(argv);
return EXIT_FAILURE;
}
const std::string input_path = argv[1];
const std::string output_path = argv[2];
libwebm::VpxPes2Ts converter(input_path, output_path);
return converter.ConvertToFile() == true ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@ -1,410 +0,0 @@
// Copyright (c) 2016 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 "vpxpes_parser.h"
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <limits>
#include <vector>
#include "common/file_util.h"
namespace libwebm {
VpxPesParser::BcmvHeader::BcmvHeader(std::uint32_t len) : length(len) {
id[0] = 'B';
id[1] = 'C';
id[2] = 'M';
id[3] = 'V';
}
bool VpxPesParser::BcmvHeader::operator==(const BcmvHeader& other) const {
return (other.length == length && other.id[0] == id[0] &&
other.id[1] == id[1] && other.id[2] == id[2] && other.id[3] == id[3]);
}
bool VpxPesParser::BcmvHeader::Valid() const {
return (length > 0 && id[0] == 'B' && id[1] == 'C' && id[2] == 'M' &&
id[3] == 'V');
}
// TODO(tomfinegan): Break Open() into separate functions. One that opens the
// file, and one that reads one packet at a time. As things are files larger
// than the maximum availble memory for the current process cannot be loaded.
bool VpxPesParser::Open(const std::string& pes_file) {
pes_file_size_ = static_cast<size_t>(libwebm::GetFileSize(pes_file));
if (pes_file_size_ <= 0)
return false;
pes_file_data_.reserve(static_cast<size_t>(pes_file_size_));
libwebm::FilePtr file = libwebm::FilePtr(std::fopen(pes_file.c_str(), "rb"),
libwebm::FILEDeleter());
int byte;
while ((byte = fgetc(file.get())) != EOF) {
pes_file_data_.push_back(static_cast<std::uint8_t>(byte));
}
if (!feof(file.get()) || ferror(file.get()) ||
pes_file_size_ != pes_file_data_.size()) {
return false;
}
read_pos_ = 0;
parse_state_ = kFindStartCode;
return true;
}
bool VpxPesParser::VerifyPacketStartCode() const {
if (read_pos_ + 2 > pes_file_data_.size())
return false;
// PES packets all start with the byte sequence 0x0 0x0 0x1.
if (pes_file_data_[read_pos_] != 0 || pes_file_data_[read_pos_ + 1] != 0 ||
pes_file_data_[read_pos_ + 2] != 1) {
return false;
}
return true;
}
bool VpxPesParser::ReadStreamId(std::uint8_t* stream_id) const {
if (!stream_id || BytesAvailable() < 4)
return false;
*stream_id = pes_file_data_[read_pos_ + 3];
return true;
}
bool VpxPesParser::ReadPacketLength(std::uint16_t* packet_length) const {
if (!packet_length || BytesAvailable() < 6)
return false;
// Read and byte swap 16 bit big endian length.
*packet_length =
(pes_file_data_[read_pos_ + 4] << 8) | pes_file_data_[read_pos_ + 5];
return true;
}
bool VpxPesParser::ParsePesHeader(PesHeader* header) {
if (!header || parse_state_ != kParsePesHeader)
return false;
if (!VerifyPacketStartCode())
return false;
std::size_t pos = read_pos_;
for (auto& a : header->start_code) {
a = pes_file_data_[pos++];
}
// PES Video stream IDs start at E0.
if (!ReadStreamId(&header->stream_id))
return false;
if (header->stream_id < kMinVideoStreamId ||
header->stream_id > kMaxVideoStreamId)
return false;
if (!ReadPacketLength(&header->packet_length))
return false;
read_pos_ += kPesHeaderSize;
parse_state_ = kParsePesOptionalHeader;
return true;
}
// TODO(tomfinegan): Make these masks constants.
bool VpxPesParser::ParsePesOptionalHeader(PesOptionalHeader* header) {
if (!header || parse_state_ != kParsePesOptionalHeader ||
read_pos_ >= pes_file_size_) {
return false;
}
std::size_t consumed = 0;
PacketData poh_buffer;
if (!RemoveStartCodeEmulationPreventionBytes(&pes_file_data_[read_pos_],
kPesOptionalHeaderSize,
&poh_buffer, &consumed)) {
return false;
}
std::size_t offset = 0;
header->marker = (poh_buffer[offset] & 0x80) >> 6;
header->scrambling = (poh_buffer[offset] & 0x30) >> 4;
header->priority = (poh_buffer[offset] & 0x8) >> 3;
header->data_alignment = (poh_buffer[offset] & 0xc) >> 2;
header->copyright = (poh_buffer[offset] & 0x2) >> 1;
header->original = poh_buffer[offset] & 0x1;
offset++;
header->has_pts = (poh_buffer[offset] & 0x80) >> 7;
header->has_dts = (poh_buffer[offset] & 0x40) >> 6;
header->unused_fields = poh_buffer[offset] & 0x3f;
offset++;
header->remaining_size = poh_buffer[offset];
if (header->remaining_size !=
static_cast<int>(kWebm2PesOptHeaderRemainingSize))
return false;
size_t bytes_left = header->remaining_size;
offset++;
if (header->has_pts) {
// Read PTS markers. Format:
// PTS: 5 bytes
// 4 bits (flag: PTS present, but no DTS): 0x2 ('0010')
// 36 bits (90khz PTS):
// top 3 bits
// marker ('1')
// middle 15 bits
// marker ('1')
// bottom 15 bits
// marker ('1')
// TODO(tomfinegan): read/store the timestamp.
header->pts_dts_flag = (poh_buffer[offset] & 0x20) >> 4;
// Check the marker bits.
if ((poh_buffer[offset + 0] & 1) != 1 ||
(poh_buffer[offset + 2] & 1) != 1 ||
(poh_buffer[offset + 4] & 1) != 1) {
return false;
}
header->pts = (poh_buffer[offset] & 0xe) << 29 |
((ReadUint16(&poh_buffer[offset + 1]) & ~1) << 14) |
(ReadUint16(&poh_buffer[offset + 3]) >> 1);
offset += 5;
bytes_left -= 5;
}
// Validate stuffing byte(s).
for (size_t i = 0; i < bytes_left; ++i) {
if (poh_buffer[offset + i] != 0xff)
return false;
}
read_pos_ += consumed;
parse_state_ = kParseBcmvHeader;
return true;
}
// Parses and validates a BCMV header.
bool VpxPesParser::ParseBcmvHeader(BcmvHeader* header) {
if (!header || parse_state_ != kParseBcmvHeader)
return false;
PacketData bcmv_buffer;
std::size_t consumed = 0;
if (!RemoveStartCodeEmulationPreventionBytes(&pes_file_data_[read_pos_],
kBcmvHeaderSize, &bcmv_buffer,
&consumed)) {
return false;
}
std::size_t offset = 0;
header->id[0] = bcmv_buffer[offset++];
header->id[1] = bcmv_buffer[offset++];
header->id[2] = bcmv_buffer[offset++];
header->id[3] = bcmv_buffer[offset++];
header->length = 0;
header->length |= bcmv_buffer[offset++] << 24;
header->length |= bcmv_buffer[offset++] << 16;
header->length |= bcmv_buffer[offset++] << 8;
header->length |= bcmv_buffer[offset++];
// Length stored in the BCMV header is followed by 2 bytes of 0 padding.
if (bcmv_buffer[offset++] != 0 || bcmv_buffer[offset++] != 0)
return false;
if (!header->Valid())
return false;
parse_state_ = kFindStartCode;
read_pos_ += consumed;
return true;
}
bool VpxPesParser::FindStartCode(std::size_t origin,
std::size_t* offset) const {
if (read_pos_ + 2 >= pes_file_size_)
return false;
const std::size_t length = pes_file_size_ - origin;
if (length < 3)
return false;
const uint8_t* const data = &pes_file_data_[origin];
for (std::size_t i = 0; i < length - 3; ++i) {
if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1) {
*offset = origin + i;
return true;
}
}
return false;
}
bool VpxPesParser::IsPayloadFragmented(const PesHeader& header) const {
return (header.packet_length != 0 &&
(header.packet_length - kPesOptionalHeaderSize) !=
header.bcmv_header.length);
}
bool VpxPesParser::AccumulateFragmentedPayload(std::size_t pes_packet_length,
std::size_t payload_length) {
PesHeader fragment_header;
const std::size_t first_fragment_length =
pes_packet_length - kPesOptionalHeaderSize - kBcmvHeaderSize;
for (std::size_t i = 0; i < first_fragment_length; ++i) {
payload_.push_back(pes_file_data_[read_pos_ + i]);
}
read_pos_ += first_fragment_length;
parse_state_ = kFindStartCode;
while (payload_.size() < payload_length) {
PesHeader header;
std::size_t packet_start_pos = read_pos_;
if (!FindStartCode(read_pos_, &packet_start_pos)) {
return false;
}
parse_state_ = kParsePesHeader;
read_pos_ = packet_start_pos;
if (!ParsePesHeader(&header)) {
return false;
}
if (!ParsePesOptionalHeader(&header.opt_header)) {
return false;
}
const std::size_t fragment_length =
header.packet_length - kPesOptionalHeaderSize;
std::size_t consumed = 0;
if (!RemoveStartCodeEmulationPreventionBytes(&pes_file_data_[read_pos_],
fragment_length, &payload_,
&consumed)) {
return false;
}
read_pos_ += consumed;
}
return true;
}
bool VpxPesParser::RemoveStartCodeEmulationPreventionBytes(
const std::uint8_t* raw_data, std::size_t bytes_required,
PacketData* processed_data, std::size_t* bytes_consumed) const {
if (bytes_required == 0 || !processed_data)
return false;
std::size_t num_zeros = 0;
std::size_t bytes_copied = 0;
const std::uint8_t* const end_of_input =
&pes_file_data_[0] + pes_file_data_.size();
std::size_t i;
for (i = 0; bytes_copied < bytes_required; ++i) {
if (raw_data + i > end_of_input)
return false;
bool skip = false;
const std::uint8_t byte = raw_data[i];
if (byte == 0) {
++num_zeros;
} else if (byte == 0x3 && num_zeros == 2) {
skip = true;
num_zeros = 0;
} else {
num_zeros = 0;
}
if (skip == false) {
processed_data->push_back(byte);
++bytes_copied;
}
}
*bytes_consumed = i;
return true;
}
int VpxPesParser::BytesAvailable() const {
return static_cast<int>(pes_file_data_.size() - read_pos_);
}
bool VpxPesParser::ParseNextPacket(PesHeader* header, VideoFrame* frame) {
if (!header || !frame || parse_state_ != kFindStartCode ||
BytesAvailable() == 0) {
return false;
}
std::size_t packet_start_pos = read_pos_;
if (!FindStartCode(read_pos_, &packet_start_pos)) {
return false;
}
parse_state_ = kParsePesHeader;
read_pos_ = packet_start_pos;
if (!ParsePesHeader(header)) {
return false;
}
if (!ParsePesOptionalHeader(&header->opt_header)) {
return false;
}
if (!ParseBcmvHeader(&header->bcmv_header)) {
return false;
}
// BCMV header length includes the length of the BCMVHeader itself. Adjust:
const std::size_t payload_length =
header->bcmv_header.length - BcmvHeader::size();
// Make sure there's enough input data to read the entire frame.
if (read_pos_ + payload_length > pes_file_data_.size()) {
// Need more data.
printf("VpxPesParser: Not enough data. Required: %u Available: %u\n",
static_cast<unsigned int>(payload_length),
static_cast<unsigned int>(pes_file_data_.size() - read_pos_));
parse_state_ = kFindStartCode;
read_pos_ = packet_start_pos;
return false;
}
if (IsPayloadFragmented(*header)) {
if (!AccumulateFragmentedPayload(header->packet_length, payload_length)) {
fprintf(stderr, "VpxPesParser: Failed parsing fragmented payload!\n");
return false;
}
} else {
std::size_t consumed = 0;
if (!RemoveStartCodeEmulationPreventionBytes(
&pes_file_data_[read_pos_], payload_length, &payload_, &consumed)) {
return false;
}
read_pos_ += consumed;
}
if (frame->buffer().capacity < payload_.size()) {
if (frame->Init(payload_.size()) == false) {
fprintf(stderr, "VpxPesParser: Out of memory.\n");
return false;
}
}
frame->set_nanosecond_pts(Khz90TicksToNanoseconds(header->opt_header.pts));
std::memcpy(frame->buffer().data.get(), &payload_[0], payload_.size());
frame->SetBufferLength(payload_.size());
payload_.clear();
parse_state_ = kFindStartCode;
return true;
}
} // namespace libwebm

View File

@ -1,177 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_M2TS_VPXPES_PARSER_H_
#define LIBWEBM_M2TS_VPXPES_PARSER_H_
#include <cstdint>
#include <string>
#include <vector>
#include "common/libwebm_util.h"
#include "common/video_frame.h"
namespace libwebm {
// Parser for VPx PES. Requires that the _entire_ PES stream can be stored in
// a std::vector<std::uint8_t> and read into memory when Open() is called.
// TODO(tomfinegan): Support incremental parse.
class VpxPesParser {
public:
typedef std::vector<std::uint8_t> PesFileData;
typedef std::vector<std::uint8_t> PacketData;
enum ParseState {
kFindStartCode,
kParsePesHeader,
kParsePesOptionalHeader,
kParseBcmvHeader,
};
struct PesOptionalHeader {
int marker = 0;
int scrambling = 0;
int priority = 0;
int data_alignment = 0;
int copyright = 0;
int original = 0;
int has_pts = 0;
int has_dts = 0;
int unused_fields = 0;
int remaining_size = 0;
int pts_dts_flag = 0;
std::uint64_t pts = 0;
int stuffing_byte = 0;
};
struct BcmvHeader {
BcmvHeader() = default;
~BcmvHeader() = default;
BcmvHeader(const BcmvHeader&) = delete;
BcmvHeader(BcmvHeader&&) = delete;
// Convenience ctor for quick validation of expected values via operator==
// after parsing input.
explicit BcmvHeader(std::uint32_t len);
bool operator==(const BcmvHeader& other) const;
void Reset();
bool Valid() const;
static std::size_t size() { return 10; }
char id[4] = {0};
std::uint32_t length = 0;
};
struct PesHeader {
std::uint8_t start_code[4] = {0};
std::uint16_t packet_length = 0;
std::uint8_t stream_id = 0;
PesOptionalHeader opt_header;
BcmvHeader bcmv_header;
};
// Constants for validating known values from input data.
const std::uint8_t kMinVideoStreamId = 0xE0;
const std::uint8_t kMaxVideoStreamId = 0xEF;
const std::size_t kPesHeaderSize = 6;
const std::size_t kPesOptionalHeaderStartOffset = kPesHeaderSize;
const std::size_t kPesOptionalHeaderSize = 9;
const std::size_t kPesOptionalHeaderMarkerValue = 0x2;
const std::size_t kWebm2PesOptHeaderRemainingSize = 6;
const std::size_t kBcmvHeaderSize = 10;
VpxPesParser() = default;
~VpxPesParser() = default;
// Opens file specified by |pes_file_path| and reads its contents. Returns
// true after successful read of input file.
bool Open(const std::string& pes_file_path);
// Parses the next packet in the PES. PES header information is stored in
// |header|, and the frame payload is stored in |frame|. Returns true when
// a full frame has been consumed from the PES.
bool ParseNextPacket(PesHeader* header, VideoFrame* frame);
// PES Header parsing utility functions.
// PES Header structure:
// Start code Stream ID Packet length (16 bits)
// / / ____/
// | | /
// Byte0 Byte1 Byte2 Byte3 Byte4 Byte5
// 0 0 1 X Y
bool VerifyPacketStartCode() const;
bool ReadStreamId(std::uint8_t* stream_id) const;
bool ReadPacketLength(std::uint16_t* packet_length) const;
std::uint64_t pes_file_size() const { return pes_file_size_; }
const PesFileData& pes_file_data() const { return pes_file_data_; }
// Returns number of unparsed bytes remaining.
int BytesAvailable() const;
private:
// Parses and verifies the static 6 byte portion that begins every PES packet.
bool ParsePesHeader(PesHeader* header);
// Parses a PES optional header, the optional header following the static
// header that begins the VPX PES packet.
// https://en.wikipedia.org/wiki/Packetized_elementary_stream
bool ParsePesOptionalHeader(PesOptionalHeader* header);
// Parses and validates the BCMV header. This immediately follows the optional
// header.
bool ParseBcmvHeader(BcmvHeader* header);
// Returns true when a start code is found and sets |offset| to the position
// of the start code relative to |pes_file_data_[read_pos_]|.
// Does not set |offset| value if the end of |pes_file_data_| is reached
// without locating a start code.
// Note: A start code is the byte sequence 0x00 0x00 0x01.
bool FindStartCode(std::size_t origin, std::size_t* offset) const;
// Returns true when a PES packet containing a BCMV header contains only a
// portion of the frame payload length reported by the BCMV header.
bool IsPayloadFragmented(const PesHeader& header) const;
// Parses PES and PES Optional header while accumulating payload data in
// |payload_|.
// Returns true once all payload fragments have been stored in |payload_|.
// Returns false if unable to accumulate full payload.
bool AccumulateFragmentedPayload(std::size_t pes_packet_length,
std::size_t payload_length);
// The byte sequence 0x0 0x0 0x1 is a start code in PES. When PES muxers
// encounter 0x0 0x0 0x1 or 0x0 0x0 0x3, an additional 0x3 is inserted into
// the PES. The following change occurs:
// 0x0 0x0 0x1 => 0x0 0x0 0x3 0x1
// 0x0 0x0 0x3 => 0x0 0x0 0x3 0x3
// PES demuxers must reverse the change:
// 0x0 0x0 0x3 0x1 => 0x0 0x0 0x1
// 0x0 0x0 0x3 0x3 => 0x0 0x0 0x3
// PES optional header, BCMV header, and payload data must be preprocessed to
// avoid potentially invalid data due to the presence of inserted bytes.
//
// Removes start code emulation prevention bytes while copying data from
// |raw_data| to |processed_data|. Returns true when |bytes_required| bytes
// have been written to |processed_data|. Reports bytes consumed during the
// operation via |bytes_consumed|.
bool RemoveStartCodeEmulationPreventionBytes(
const std::uint8_t* raw_data, std::size_t bytes_required,
PacketData* processed_data, std::size_t* bytes_consumed) const;
std::size_t pes_file_size_ = 0;
PacketData payload_;
PesFileData pes_file_data_;
std::size_t read_pos_ = 0;
ParseState parse_state_ = kFindStartCode;
};
} // namespace libwebm
#endif // LIBWEBM_M2TS_VPXPES_PARSER_H_

View File

@ -1,542 +0,0 @@
// Copyright (c) 2015 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 "m2ts/webm2pes.h"
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <new>
#include <vector>
#include "common/libwebm_util.h"
namespace libwebm {
const std::size_t Webm2Pes::kMaxPayloadSize = 32768;
//
// PesOptionalHeader methods.
//
void PesOptionalHeader::SetPtsBits(std::int64_t pts_90khz) {
std::uint64_t* pts_bits = &pts.bits;
*pts_bits = 0;
// PTS is broken up and stored in 40 bits as shown:
//
// PES PTS Only flag
// / Marker Marker Marker
// | / / /
// | | | |
// 7654 321 0 765432107654321 0 765432107654321 0
// 0010 PTS 32-30 1 PTS 29-15 1 PTS 14-0 1
const std::uint32_t pts1 = (pts_90khz >> 30) & 0x7;
const std::uint32_t pts2 = (pts_90khz >> 15) & 0x7FFF;
const std::uint32_t pts3 = pts_90khz & 0x7FFF;
std::uint8_t buffer[5] = {0};
// PTS only flag.
buffer[0] |= 1 << 5;
// Top 3 bits of PTS and 1 bit marker.
buffer[0] |= pts1 << 1;
// Marker.
buffer[0] |= 1;
// Next 15 bits of pts and 1 bit marker.
// Top 8 bits of second PTS chunk.
buffer[1] |= (pts2 >> 7) & 0xff;
// bottom 7 bits of second PTS chunk.
buffer[2] |= (pts2 << 1);
// Marker.
buffer[2] |= 1;
// Last 15 bits of pts and 1 bit marker.
// Top 8 bits of second PTS chunk.
buffer[3] |= (pts3 >> 7) & 0xff;
// bottom 7 bits of second PTS chunk.
buffer[4] |= (pts3 << 1);
// Marker.
buffer[4] |= 1;
// Write bits into PesHeaderField.
std::memcpy(reinterpret_cast<std::uint8_t*>(pts_bits), buffer, 5);
}
// Writes fields to |buffer| and returns true. Returns false when write or
// field value validation fails.
bool PesOptionalHeader::Write(bool write_pts, PacketDataBuffer* buffer) const {
if (buffer == nullptr) {
std::fprintf(stderr, "Webm2Pes: nullptr in opt header writer.\n");
return false;
}
const int kHeaderSize = 9;
std::uint8_t header[kHeaderSize] = {0};
std::uint8_t* byte = header;
if (marker.Check() != true || scrambling.Check() != true ||
priority.Check() != true || data_alignment.Check() != true ||
copyright.Check() != true || original.Check() != true ||
has_pts.Check() != true || has_dts.Check() != true ||
pts.Check() != true || stuffing_byte.Check() != true) {
std::fprintf(stderr, "Webm2Pes: Invalid PES Optional Header field.\n");
return false;
}
// TODO(tomfinegan): As noted in above, the PesHeaderFields should be an
// array (or some data structure) that can be iterated over.
// First byte of header, fields: marker, scrambling, priority, alignment,
// copyright, original.
*byte = 0;
*byte |= marker.bits << marker.shift;
*byte |= scrambling.bits << scrambling.shift;
*byte |= priority.bits << priority.shift;
*byte |= data_alignment.bits << data_alignment.shift;
*byte |= copyright.bits << copyright.shift;
*byte |= original.bits << original.shift;
// Second byte of header, fields: has_pts, has_dts, unused fields.
*++byte = 0;
if (write_pts == true)
*byte |= has_pts.bits << has_pts.shift;
*byte |= has_dts.bits << has_dts.shift;
// Third byte of header, fields: remaining size of header.
*++byte = remaining_size.bits & 0xff; // Field is 8 bits wide.
int num_stuffing_bytes =
(pts.num_bits + 7) / 8 + 1 /* always 1 stuffing byte */;
if (write_pts == true) {
// Write the PTS value as big endian and adjust stuffing byte count
// accordingly.
*++byte = pts.bits & 0xff;
*++byte = (pts.bits >> 8) & 0xff;
*++byte = (pts.bits >> 16) & 0xff;
*++byte = (pts.bits >> 24) & 0xff;
*++byte = (pts.bits >> 32) & 0xff;
num_stuffing_bytes = 1;
}
// Add the stuffing byte(s).
for (int i = 0; i < num_stuffing_bytes; ++i)
*++byte = stuffing_byte.bits & 0xff;
return CopyAndEscapeStartCodes(&header[0], kHeaderSize, buffer);
}
//
// BCMVHeader methods.
//
bool BCMVHeader::Write(PacketDataBuffer* buffer) const {
if (buffer == nullptr) {
std::fprintf(stderr, "Webm2Pes: nullptr for buffer in BCMV Write.\n");
return false;
}
const int kBcmvSize = 4;
for (int i = 0; i < kBcmvSize; ++i)
buffer->push_back(bcmv[i]);
// Note: The 4 byte length field must include the size of the BCMV header.
const int kRemainingBytes = 6;
const uint32_t bcmv_total_length = length + static_cast<uint32_t>(size());
const uint8_t bcmv_buffer[kRemainingBytes] = {
static_cast<std::uint8_t>((bcmv_total_length >> 24) & 0xff),
static_cast<std::uint8_t>((bcmv_total_length >> 16) & 0xff),
static_cast<std::uint8_t>((bcmv_total_length >> 8) & 0xff),
static_cast<std::uint8_t>(bcmv_total_length & 0xff),
0,
0 /* 2 bytes 0 padding */};
return CopyAndEscapeStartCodes(bcmv_buffer, kRemainingBytes, buffer);
}
//
// PesHeader methods.
//
// Writes out the header to |buffer|. Calls PesOptionalHeader::Write() to write
// |optional_header| contents. Returns true when successful, false otherwise.
bool PesHeader::Write(bool write_pts, PacketDataBuffer* buffer) const {
if (buffer == nullptr) {
std::fprintf(stderr, "Webm2Pes: nullptr in header writer.\n");
return false;
}
// Write |start_code|.
const int kStartCodeLength = 4;
for (int i = 0; i < kStartCodeLength; ++i)
buffer->push_back(start_code[i]);
// The length field here reports number of bytes following the field. The
// length of the optional header must be added to the payload length set by
// the user.
const std::size_t header_length =
packet_length + optional_header.size_in_bytes();
if (header_length > UINT16_MAX)
return false;
// Write |header_length| as big endian.
std::uint8_t byte = (header_length >> 8) & 0xff;
buffer->push_back(byte);
byte = header_length & 0xff;
buffer->push_back(byte);
// Write the (not really) optional header.
if (optional_header.Write(write_pts, buffer) != true) {
std::fprintf(stderr, "Webm2Pes: PES optional header write failed.");
return false;
}
return true;
}
//
// Webm2Pes methods.
//
bool Webm2Pes::ConvertToFile() {
if (input_file_name_.empty() || output_file_name_.empty()) {
std::fprintf(stderr, "Webm2Pes: input and/or output file name(s) empty.\n");
return false;
}
output_file_ = FilePtr(fopen(output_file_name_.c_str(), "wb"), FILEDeleter());
if (output_file_ == nullptr) {
std::fprintf(stderr, "Webm2Pes: Cannot open %s for output.\n",
output_file_name_.c_str());
return false;
}
if (InitWebmParser() != true) {
std::fprintf(stderr, "Webm2Pes: Cannot initialize WebM parser.\n");
return false;
}
// Walk clusters in segment.
const mkvparser::Cluster* cluster = webm_parser_->GetFirst();
while (cluster != nullptr && cluster->EOS() == false) {
const mkvparser::BlockEntry* block_entry = nullptr;
std::int64_t block_status = cluster->GetFirst(block_entry);
if (block_status < 0) {
std::fprintf(stderr, "Webm2Pes: Cannot parse first block in %s.\n",
input_file_name_.c_str());
return false;
}
// Walk blocks in cluster.
while (block_entry != nullptr && block_entry->EOS() == false) {
const mkvparser::Block* block = block_entry->GetBlock();
if (block->GetTrackNumber() == video_track_num_) {
const int frame_count = block->GetFrameCount();
// Walk frames in block.
for (int frame_num = 0; frame_num < frame_count; ++frame_num) {
const mkvparser::Block::Frame& mkvparser_frame =
block->GetFrame(frame_num);
// Read the frame.
VideoFrame vpx_frame(block->GetTime(cluster), codec_);
if (ReadVideoFrame(mkvparser_frame, &vpx_frame) == false) {
fprintf(stderr, "Webm2Pes: frame read failed.\n");
return false;
}
// Write frame out as PES packet(s).
if (WritePesPacket(vpx_frame, &packet_data_) == false) {
std::fprintf(stderr, "Webm2Pes: WritePesPacket failed.\n");
return false;
}
// Write contents of |packet_data_| to |output_file_|.
if (std::fwrite(&packet_data_[0], 1, packet_data_.size(),
output_file_.get()) != packet_data_.size()) {
std::fprintf(stderr, "Webm2Pes: packet payload write failed.\n");
return false;
}
bytes_written_ += packet_data_.size();
}
}
block_status = cluster->GetNext(block_entry, block_entry);
if (block_status < 0) {
std::fprintf(stderr, "Webm2Pes: Cannot parse block in %s.\n",
input_file_name_.c_str());
return false;
}
}
cluster = webm_parser_->GetNext(cluster);
}
std::fflush(output_file_.get());
return true;
}
bool Webm2Pes::ConvertToPacketReceiver() {
if (input_file_name_.empty() || packet_sink_ == nullptr) {
std::fprintf(stderr, "Webm2Pes: input file name empty or null sink.\n");
return false;
}
if (InitWebmParser() != true) {
std::fprintf(stderr, "Webm2Pes: Cannot initialize WebM parser.\n");
return false;
}
// Walk clusters in segment.
const mkvparser::Cluster* cluster = webm_parser_->GetFirst();
while (cluster != nullptr && cluster->EOS() == false) {
const mkvparser::BlockEntry* block_entry = nullptr;
std::int64_t block_status = cluster->GetFirst(block_entry);
if (block_status < 0) {
std::fprintf(stderr, "Webm2Pes: Cannot parse first block in %s.\n",
input_file_name_.c_str());
return false;
}
// Walk blocks in cluster.
while (block_entry != nullptr && block_entry->EOS() == false) {
const mkvparser::Block* block = block_entry->GetBlock();
if (block->GetTrackNumber() == video_track_num_) {
const int frame_count = block->GetFrameCount();
// Walk frames in block.
for (int frame_num = 0; frame_num < frame_count; ++frame_num) {
const mkvparser::Block::Frame& mkvparser_frame =
block->GetFrame(frame_num);
// Read the frame.
VideoFrame frame(block->GetTime(cluster), codec_);
if (ReadVideoFrame(mkvparser_frame, &frame) == false) {
fprintf(stderr, "Webm2Pes: frame read failed.\n");
return false;
}
// Write frame out as PES packet(s).
if (WritePesPacket(frame, &packet_data_) == false) {
std::fprintf(stderr, "Webm2Pes: WritePesPacket failed.\n");
return false;
}
if (packet_sink_->ReceivePacket(packet_data_) != true) {
std::fprintf(stderr, "Webm2Pes: ReceivePacket failed.\n");
return false;
}
bytes_written_ += packet_data_.size();
}
}
block_status = cluster->GetNext(block_entry, block_entry);
if (block_status < 0) {
std::fprintf(stderr, "Webm2Pes: Cannot parse block in %s.\n",
input_file_name_.c_str());
return false;
}
}
cluster = webm_parser_->GetNext(cluster);
}
return true;
}
bool Webm2Pes::InitWebmParser() {
if (webm_reader_.Open(input_file_name_.c_str()) != 0) {
std::fprintf(stderr, "Webm2Pes: Cannot open %s as input.\n",
input_file_name_.c_str());
return false;
}
using mkvparser::Segment;
Segment* webm_parser = nullptr;
if (Segment::CreateInstance(&webm_reader_, 0 /* pos */,
webm_parser /* Segment*& */) != 0) {
std::fprintf(stderr, "Webm2Pes: Cannot create WebM parser.\n");
return false;
}
webm_parser_.reset(webm_parser);
if (webm_parser_->Load() != 0) {
std::fprintf(stderr, "Webm2Pes: Cannot parse %s.\n",
input_file_name_.c_str());
return false;
}
// Make sure there's a video track.
const mkvparser::Tracks* tracks = webm_parser_->GetTracks();
if (tracks == nullptr) {
std::fprintf(stderr, "Webm2Pes: %s has no tracks.\n",
input_file_name_.c_str());
return false;
}
timecode_scale_ = webm_parser_->GetInfo()->GetTimeCodeScale();
for (int track_index = 0;
track_index < static_cast<int>(tracks->GetTracksCount());
++track_index) {
const mkvparser::Track* track = tracks->GetTrackByIndex(track_index);
if (track && track->GetType() == mkvparser::Track::kVideo) {
if (std::string(track->GetCodecId()) == std::string("V_VP8")) {
codec_ = VideoFrame::kVP8;
} else if (std::string(track->GetCodecId()) == std::string("V_VP9")) {
codec_ = VideoFrame::kVP9;
} else {
fprintf(stderr, "Webm2Pes: Codec must be VP8 or VP9.\n");
return false;
}
video_track_num_ = track_index + 1;
break;
}
}
if (video_track_num_ < 1) {
std::fprintf(stderr, "Webm2Pes: No video track found in %s.\n",
input_file_name_.c_str());
return false;
}
return true;
}
bool Webm2Pes::ReadVideoFrame(const mkvparser::Block::Frame& mkvparser_frame,
VideoFrame* frame) {
if (mkvparser_frame.len < 1 || frame == nullptr)
return false;
const std::size_t mkv_len = static_cast<std::size_t>(mkvparser_frame.len);
if (mkv_len > frame->buffer().capacity) {
const std::size_t new_size = 2 * mkv_len;
if (frame->Init(new_size) == false) {
std::fprintf(stderr, "Webm2Pes: Out of memory.\n");
return false;
}
}
if (mkvparser_frame.Read(&webm_reader_, frame->buffer().data.get()) != 0) {
std::fprintf(stderr, "Webm2Pes: Error reading VPx frame!\n");
return false;
}
return frame->SetBufferLength(mkv_len);
}
bool Webm2Pes::WritePesPacket(const VideoFrame& frame,
PacketDataBuffer* packet_data) {
if (frame.buffer().data.get() == nullptr || frame.buffer().length < 1)
return false;
Ranges frame_ranges;
if (frame.codec() == VideoFrame::kVP9) {
bool error = false;
const bool has_superframe_index =
ParseVP9SuperFrameIndex(frame.buffer().data.get(),
frame.buffer().length, &frame_ranges, &error);
if (error) {
std::fprintf(stderr, "Webm2Pes: Superframe index parse failed.\n");
return false;
}
if (has_superframe_index == false) {
frame_ranges.push_back(Range(0, frame.buffer().length));
}
} else {
frame_ranges.push_back(Range(0, frame.buffer().length));
}
const std::int64_t khz90_pts =
NanosecondsTo90KhzTicks(frame.nanosecond_pts());
PesHeader header;
header.optional_header.SetPtsBits(khz90_pts);
packet_data->clear();
for (const Range& packet_payload_range : frame_ranges) {
std::size_t extra_bytes = 0;
if (packet_payload_range.length > kMaxPayloadSize) {
extra_bytes = packet_payload_range.length - kMaxPayloadSize;
}
if (packet_payload_range.length + packet_payload_range.offset >
frame.buffer().length) {
std::fprintf(stderr, "Webm2Pes: Invalid frame length.\n");
return false;
}
// First packet of new frame. Always include PTS and BCMV header.
header.packet_length =
packet_payload_range.length - extra_bytes + BCMVHeader::size();
if (header.Write(true, packet_data) != true) {
std::fprintf(stderr, "Webm2Pes: packet header write failed.\n");
return false;
}
BCMVHeader bcmv_header(static_cast<uint32_t>(packet_payload_range.length));
if (bcmv_header.Write(packet_data) != true) {
std::fprintf(stderr, "Webm2Pes: BCMV write failed.\n");
return false;
}
// Insert the payload at the end of |packet_data|.
const std::uint8_t* const payload_start =
frame.buffer().data.get() + packet_payload_range.offset;
const std::size_t bytes_to_copy = packet_payload_range.length - extra_bytes;
if (CopyAndEscapeStartCodes(payload_start, bytes_to_copy, packet_data) ==
false) {
fprintf(stderr, "Webm2Pes: Payload write failed.\n");
return false;
}
std::size_t bytes_copied = bytes_to_copy;
while (extra_bytes) {
// Write PES packets for the remaining data, but omit the PTS and BCMV
// header.
const std::size_t extra_bytes_to_copy =
std::min(kMaxPayloadSize, extra_bytes);
extra_bytes -= extra_bytes_to_copy;
header.packet_length = extra_bytes_to_copy;
if (header.Write(false, packet_data) != true) {
fprintf(stderr, "Webm2pes: fragment write failed.\n");
return false;
}
const std::uint8_t* fragment_start = payload_start + bytes_copied;
if (CopyAndEscapeStartCodes(fragment_start, extra_bytes_to_copy,
packet_data) == false) {
fprintf(stderr, "Webm2Pes: Payload write failed.\n");
return false;
}
bytes_copied += extra_bytes_to_copy;
}
}
return true;
}
bool CopyAndEscapeStartCodes(const std::uint8_t* raw_input,
std::size_t raw_input_length,
PacketDataBuffer* packet_buffer) {
if (raw_input == nullptr || raw_input_length < 1 || packet_buffer == nullptr)
return false;
int num_zeros = 0;
for (std::size_t i = 0; i < raw_input_length; ++i) {
const uint8_t byte = raw_input[i];
if (byte == 0) {
++num_zeros;
} else if (num_zeros >= 2 && (byte == 0x1 || byte == 0x3)) {
packet_buffer->push_back(0x3);
num_zeros = 0;
} else {
num_zeros = 0;
}
packet_buffer->push_back(byte);
}
return true;
}
} // namespace libwebm

View File

@ -1,274 +0,0 @@
// Copyright (c) 2015 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 LIBWEBM_M2TS_WEBM2PES_H_
#define LIBWEBM_M2TS_WEBM2PES_H_
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "common/libwebm_util.h"
#include "common/video_frame.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
// Webm2pes
//
// Webm2pes consumes a WebM file containing a VP8 or VP9 video stream and
// outputs a PES stream suitable for inclusion in a MPEG2 Transport Stream.
//
// In the simplest case the PES stream output by Webm2pes consists of a sequence
// of PES packets with the following structure:
// | PES Header w/PTS | BCMV Header | Payload (VPx frame) |
//
// More typically the output will look like the following due to the PES
// payload size limitations caused by the format of the PES header.
// The PES header contains only 2 bytes of storage for expressing payload size.
// VPx PES streams containing fragmented packets look like this:
//
// | PH PTS | BCMV | Payload fragment 1 | PH | Payload fragment 2 | ...
//
// PH = PES Header
// PH PTS = PES Header with PTS
// BCMV = BCMV Header
//
// Note that start codes are properly escaped by Webm2pes, and start code
// emulation prevention bytes must be stripped from the output stream before
// it can be parsed.
namespace libwebm {
// Stores a value and its size in bits for writing into a PES Optional Header.
// Maximum size is 64 bits. Users may call the Check() method to perform minimal
// validation (size > 0 and <= 64).
struct PesHeaderField {
PesHeaderField(std::uint64_t value, std::uint32_t size_in_bits,
std::uint8_t byte_index, std::uint8_t bits_to_shift)
: bits(value),
num_bits(size_in_bits),
index(byte_index),
shift(bits_to_shift) {}
PesHeaderField() = delete;
PesHeaderField(const PesHeaderField&) = default;
PesHeaderField(PesHeaderField&&) = default;
~PesHeaderField() = default;
bool Check() const {
return num_bits > 0 && num_bits <= 64 && shift >= 0 && shift < 64;
}
// Value to be stored in the field.
std::uint64_t bits;
// Number of bits in the value.
const int num_bits;
// Index into the header for the byte in which |bits| will be written.
const std::uint8_t index;
// Number of bits to shift value before or'ing.
const int shift;
};
// Data is stored in buffers before being written to output files.
typedef std::vector<std::uint8_t> PacketDataBuffer;
// Storage for PES Optional Header values. Fields written in order using sizes
// specified.
struct PesOptionalHeader {
// TODO(tomfinegan): The fields could be in an array, which would allow the
// code writing the optional header to iterate over the fields instead of
// having code for dealing with each one.
// 2 bits (marker): 2 ('10')
const PesHeaderField marker = PesHeaderField(2, 2, 0, 6);
// 2 bits (no scrambling): 0x0 ('00')
const PesHeaderField scrambling = PesHeaderField(0, 2, 0, 4);
// 1 bit (priority): 0x0 ('0')
const PesHeaderField priority = PesHeaderField(0, 1, 0, 3);
// TODO(tomfinegan): The BCMV header could be considered a sync word, and this
// field should be 1 when a sync word follows the packet. Clarify.
// 1 bit (data alignment): 0x0 ('0')
const PesHeaderField data_alignment = PesHeaderField(0, 1, 0, 2);
// 1 bit (copyright): 0x0 ('0')
const PesHeaderField copyright = PesHeaderField(0, 1, 0, 1);
// 1 bit (original/copy): 0x0 ('0')
const PesHeaderField original = PesHeaderField(0, 1, 0, 0);
// 1 bit (has_pts): 0x1 ('1')
const PesHeaderField has_pts = PesHeaderField(1, 1, 1, 7);
// 1 bit (has_dts): 0x0 ('0')
const PesHeaderField has_dts = PesHeaderField(0, 1, 1, 6);
// 6 bits (unused fields): 0x0 ('000000')
const PesHeaderField unused = PesHeaderField(0, 6, 1, 0);
// 8 bits (size of remaining data in the Header).
const PesHeaderField remaining_size = PesHeaderField(6, 8, 2, 0);
// PTS: 5 bytes
// 4 bits (flag: PTS present, but no DTS): 0x2 ('0010')
// 36 bits (90khz PTS):
// top 3 bits
// marker ('1')
// middle 15 bits
// marker ('1')
// bottom 15 bits
// marker ('1')
PesHeaderField pts = PesHeaderField(0, 40, 3, 0);
PesHeaderField stuffing_byte = PesHeaderField(0xFF, 8, 8, 0);
// PTS omitted in fragments. Size remains unchanged: More stuffing bytes.
bool fragment = false;
static std::size_t size_in_bytes() { return 9; }
// Writes |pts_90khz| to |pts| per format described at its declaration above.
void SetPtsBits(std::int64_t pts_90khz);
// Writes fields to |buffer| and returns true. Returns false when write or
// field value validation fails.
bool Write(bool write_pts, PacketDataBuffer* buffer) const;
};
// Describes custom 10 byte header that immediately follows the PES Optional
// Header in each PES packet output by Webm2Pes:
// 4 byte 'B' 'C' 'M' 'V'
// 4 byte big-endian length of frame
// 2 bytes 0 padding
struct BCMVHeader {
explicit BCMVHeader(std::uint32_t frame_length) : length(frame_length) {}
BCMVHeader() = delete;
BCMVHeader(const BCMVHeader&) = delete;
BCMVHeader(BCMVHeader&&) = delete;
~BCMVHeader() = default;
const std::uint8_t bcmv[4] = {'B', 'C', 'M', 'V'};
const std::uint32_t length;
static std::size_t size() { return 10; }
// Write the BCMV Header into |buffer|. Caller responsible for ensuring
// destination buffer is of size >= BCMVHeader::size().
bool Write(PacketDataBuffer* buffer) const;
bool Write(uint8_t* buffer);
};
struct PesHeader {
const std::uint8_t start_code[4] = {
0x00, 0x00,
0x01, // 0x000001 is the PES packet start code prefix.
0xE0}; // 0xE0 is the minimum video stream ID.
std::uint16_t packet_length = 0; // Number of bytes _after_ this field.
PesOptionalHeader optional_header;
std::size_t size() const {
return optional_header.size_in_bytes() +
6 /* start_code + packet_length */ + packet_length;
}
// Writes out the header to |buffer|. Calls PesOptionalHeader::Write() to
// write |optional_header| contents. Returns true when successful, false
// otherwise.
bool Write(bool write_pts, PacketDataBuffer* buffer) const;
};
class PacketReceiverInterface {
public:
virtual ~PacketReceiverInterface() {}
virtual bool ReceivePacket(const PacketDataBuffer& packet) = 0;
};
// Converts the VP9 track of a WebM file to a Packetized Elementary Stream
// suitable for use in a MPEG2TS.
// https://en.wikipedia.org/wiki/Packetized_elementary_stream
// https://en.wikipedia.org/wiki/MPEG_transport_stream
class Webm2Pes {
public:
static const std::size_t kMaxPayloadSize;
Webm2Pes(const std::string& input_file, const std::string& output_file)
: input_file_name_(input_file), output_file_name_(output_file) {}
Webm2Pes(const std::string& input_file, PacketReceiverInterface* packet_sink)
: input_file_name_(input_file), packet_sink_(packet_sink) {}
Webm2Pes() = delete;
Webm2Pes(const Webm2Pes&) = delete;
Webm2Pes(Webm2Pes&&) = delete;
~Webm2Pes() = default;
// Converts the VPx video stream to a PES file and returns true. Returns false
// to report failure.
bool ConvertToFile();
// Converts the VPx video stream to a sequence of PES packets, and calls the
// PacketReceiverInterface::ReceivePacket() once for each VPx frame. The
// packet sent to the receiver may contain multiple PES packets. Returns only
// after full conversion or error. Returns true for success, and false when
// an error occurs.
bool ConvertToPacketReceiver();
// Writes |vpx_frame| out as PES packet[s] and stores output in |packet_data|.
// Returns true for success, false for failure.
static bool WritePesPacket(const VideoFrame& frame,
PacketDataBuffer* packet_data);
uint64_t bytes_written() const { return bytes_written_; }
private:
bool InitWebmParser();
bool ReadVideoFrame(const mkvparser::Block::Frame& mkvparser_frame,
VideoFrame* frame);
const std::string input_file_name_;
const std::string output_file_name_;
std::unique_ptr<mkvparser::Segment> webm_parser_;
mkvparser::MkvReader webm_reader_;
FilePtr output_file_;
// Video track num in the WebM file.
int video_track_num_ = 0;
// Video codec reported by CodecName from Video TrackEntry.
VideoFrame::Codec codec_;
// Input timecode scale.
std::int64_t timecode_scale_ = 1000000;
// Packet sink; when constructed with a PacketReceiverInterface*, packet and
// type of packet are sent to |packet_sink_| instead of written to an output
// file.
PacketReceiverInterface* packet_sink_ = nullptr;
PacketDataBuffer packet_data_;
std::uint64_t bytes_written_ = 0;
};
// Copies |raw_input_length| bytes from |raw_input| to |packet_buffer| while
// escaping start codes. Returns true when bytes are successfully copied.
// A start code is the 3 byte sequence 0x00 0x00 0x01. When
// the sequence is encountered, the value 0x03 is inserted. To avoid
// any ambiguity at reassembly time, the same is done for the sequence
// 0x00 0x00 0x03. So, the following transformation occurs for when either
// of the noted sequences is encountered:
//
// 0x00 0x00 0x01 => 0x00 0x00 0x03 0x01
// 0x00 0x00 0x03 => 0x00 0x00 0x03 0x03
bool CopyAndEscapeStartCodes(const std::uint8_t* raw_input,
std::size_t raw_input_length,
PacketDataBuffer* packet_buffer);
} // namespace libwebm
#endif // LIBWEBM_M2TS_WEBM2PES_H_

View File

@ -1,33 +0,0 @@
// Copyright (c) 2015 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 "m2ts/webm2pes.h"
#include <cstdio>
#include <cstdlib>
#include <string>
namespace {
void Usage(const char* argv[]) {
printf("Usage: %s <WebM file> <output file>", argv[0]);
}
} // namespace
int main(int argc, const char* argv[]) {
if (argc < 3) {
Usage(argv);
return EXIT_FAILURE;
}
const std::string input_path = argv[1];
const std::string output_path = argv[2];
libwebm::Webm2Pes converter(input_path, output_path);
return converter.ConvertToFile() == true ? EXIT_SUCCESS : EXIT_FAILURE;
}

2081
mkvmuxer.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,841 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved. // Copyright (c) 2011 The WebM project authors. All Rights Reserved.
// //
// Use of this source code is governed by a BSD-style license // 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 // that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found // tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may // in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree. // be found in the AUTHORS file in the root of the source tree.
#ifndef LIBWEBM_MKVMUXER_HPP_
#define LIBWEBM_MKVMUXER_HPP_
// This file is a wrapper for the file included immediately after this comment. #ifndef MKVMUXER_HPP
// New projects should not include this file: include the file included below. #define MKVMUXER_HPP
#include "mkvmuxer/mkvmuxer.h"
#endif // LIBWEBM_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);
};
///////////////////////////////////////////////////////////////
// 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 only be encrypted once 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();
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_; }
// 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;
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_;
// 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.
// timestamp: Timecode of the frame relative to the cluster timecode.
// is_key: Flag telling whether or not this frame is a key frame.
bool AddFrame(const uint8* frame,
uint64 length,
uint64 track_number,
short timecode,
bool is_key);
// 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:
// 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_; }
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 an audio track to the segment. Returns the number of the track on
// success, 0 on error.
uint64 AddAudioTrack(int32 sample_rate, int32 channels);
// 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 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,
bool is_key);
// Adds a video track to the segment. Returns the number of the track on
// success, 0 on error.
uint64 AddVideoTrack(int32 width, int32 height);
// 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:
// Adds a cue point to the Cues element. |timestamp| is the time in
// nanoseconds of the cue's time. Returns true on success.
bool AddCuePoint(uint64 timestamp);
// 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 true on success and if there
// are no frames queued.
bool 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();
// 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 cluster should be started with the next
// frame.
bool new_cluster_;
// 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +0,0 @@
// 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_MKVMUXERTYPES_H_
#define MKVMUXER_MKVMUXERTYPES_H_
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;
} // namespace mkvmuxer
// 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&)
#endif // MKVMUXER_MKVMUXERTYPES_HPP_

View File

@ -1,744 +0,0 @@
// 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 "mkvmuxer/mkvmuxerutil.h"
#ifdef __ANDROID__
#include <fcntl.h>
#include <unistd.h>
#endif
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <new>
#include "common/webmids.h"
#include "mkvmuxer/mkvmuxer.h"
#include "mkvmuxer/mkvwriter.h"
namespace mkvmuxer {
namespace {
// Date elements are always 8 octets in size.
const int kDateElementSize = 8;
uint64 WriteBlock(IMkvWriter* writer, const Frame* const frame, int64 timecode,
uint64 timecode_scale) {
uint64 block_additional_elem_size = 0;
uint64 block_addid_elem_size = 0;
uint64 block_more_payload_size = 0;
uint64 block_more_elem_size = 0;
uint64 block_additions_payload_size = 0;
uint64 block_additions_elem_size = 0;
if (frame->additional()) {
block_additional_elem_size =
EbmlElementSize(libwebm::kMkvBlockAdditional, frame->additional(),
frame->additional_length());
block_addid_elem_size = EbmlElementSize(
libwebm::kMkvBlockAddID, static_cast<uint64>(frame->add_id()));
block_more_payload_size =
block_addid_elem_size + block_additional_elem_size;
block_more_elem_size =
EbmlMasterElementSize(libwebm::kMkvBlockMore, block_more_payload_size) +
block_more_payload_size;
block_additions_payload_size = block_more_elem_size;
block_additions_elem_size =
EbmlMasterElementSize(libwebm::kMkvBlockAdditions,
block_additions_payload_size) +
block_additions_payload_size;
}
uint64 discard_padding_elem_size = 0;
if (frame->discard_padding() != 0) {
discard_padding_elem_size =
EbmlElementSize(libwebm::kMkvDiscardPadding,
static_cast<int64>(frame->discard_padding()));
}
const uint64 reference_block_timestamp =
frame->reference_block_timestamp() / timecode_scale;
uint64 reference_block_elem_size = 0;
if (!frame->is_key()) {
reference_block_elem_size =
EbmlElementSize(libwebm::kMkvReferenceBlock, reference_block_timestamp);
}
const uint64 duration = frame->duration() / timecode_scale;
uint64 block_duration_elem_size = 0;
if (duration > 0)
block_duration_elem_size =
EbmlElementSize(libwebm::kMkvBlockDuration, duration);
const uint64 block_payload_size = 4 + frame->length();
const uint64 block_elem_size =
EbmlMasterElementSize(libwebm::kMkvBlock, block_payload_size) +
block_payload_size;
const uint64 block_group_payload_size =
block_elem_size + block_additions_elem_size + block_duration_elem_size +
discard_padding_elem_size + reference_block_elem_size;
if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockGroup,
block_group_payload_size)) {
return 0;
}
if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlock, block_payload_size))
return 0;
if (WriteUInt(writer, frame->track_number()))
return 0;
if (SerializeInt(writer, timecode, 2))
return 0;
// For a Block, flags is always 0.
if (SerializeInt(writer, 0, 1))
return 0;
if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
return 0;
if (frame->additional()) {
if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockAdditions,
block_additions_payload_size)) {
return 0;
}
if (!WriteEbmlMasterElement(writer, libwebm::kMkvBlockMore,
block_more_payload_size))
return 0;
if (!WriteEbmlElement(writer, libwebm::kMkvBlockAddID,
static_cast<uint64>(frame->add_id())))
return 0;
if (!WriteEbmlElement(writer, libwebm::kMkvBlockAdditional,
frame->additional(), frame->additional_length())) {
return 0;
}
}
if (frame->discard_padding() != 0 &&
!WriteEbmlElement(writer, libwebm::kMkvDiscardPadding,
static_cast<int64>(frame->discard_padding()))) {
return false;
}
if (!frame->is_key() &&
!WriteEbmlElement(writer, libwebm::kMkvReferenceBlock,
reference_block_timestamp)) {
return false;
}
if (duration > 0 &&
!WriteEbmlElement(writer, libwebm::kMkvBlockDuration, duration)) {
return false;
}
return EbmlMasterElementSize(libwebm::kMkvBlockGroup,
block_group_payload_size) +
block_group_payload_size;
}
uint64 WriteSimpleBlock(IMkvWriter* writer, const Frame* const frame,
int64 timecode) {
if (WriteID(writer, libwebm::kMkvSimpleBlock))
return 0;
const int32 size = static_cast<int32>(frame->length()) + 4;
if (WriteUInt(writer, size))
return 0;
if (WriteUInt(writer, static_cast<uint64>(frame->track_number())))
return 0;
if (SerializeInt(writer, timecode, 2))
return 0;
uint64 flags = 0;
if (frame->is_key())
flags |= 0x80;
if (SerializeInt(writer, flags, 1))
return 0;
if (writer->Write(frame->frame(), static_cast<uint32>(frame->length())))
return 0;
return GetUIntSize(libwebm::kMkvSimpleBlock) + GetCodedUIntSize(size) + 4 +
frame->length();
}
} // namespace
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;
}
int32 GetIntSize(int64 value) {
// Doubling the requested value ensures positive values with their high bit
// set are written with 0-padding to avoid flipping the signedness.
const uint64 v = (value < 0) ? value ^ -1LL : value;
return GetUIntSize(2 * v);
}
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, int64 value) {
// Size of EBML ID
int32 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += GetIntSize(value);
// Size of Datasize
ebml_size++;
return ebml_size;
}
uint64 EbmlElementSize(uint64 type, uint64 value) {
return EbmlElementSize(type, value, 0);
}
uint64 EbmlElementSize(uint64 type, uint64 value, uint64 fixed_size) {
// Size of EBML ID
uint64 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += (fixed_size > 0) ? fixed_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(float);
// 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 += GetCodedUIntSize(strlen(value));
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;
}
uint64 EbmlDateElementSize(uint64 type) {
// Size of EBML ID
uint64 ebml_size = GetUIntSize(type);
// Datasize
ebml_size += kDateElementSize;
// Size of Datasize
ebml_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;
assert(sizeof(uint32) == sizeof(float));
// This union is merely used to avoid a reinterpret_cast from float& to
// uint32& which will result in violation of strict aliasing.
union U32 {
uint32 u32;
float f;
} value;
value.f = f;
for (int32 i = 1; i <= 4; ++i) {
const int32 byte_count = 4 - i;
const int32 bit_count = byte_count * 8;
const uint8 byte = static_cast<uint8>(value.u32 >> bit_count);
const int32 status = writer->Write(&byte, 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) {
return WriteEbmlElement(writer, type, value, 0);
}
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value,
uint64 fixed_size) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
uint64 size = GetUIntSize(value);
if (fixed_size > 0) {
if (size > fixed_size)
return false;
size = fixed_size;
}
if (WriteUInt(writer, size))
return false;
if (SerializeInt(writer, value, static_cast<int32>(size)))
return false;
return true;
}
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, int64 value) {
if (!writer)
return false;
if (WriteID(writer, type))
return 0;
const uint64 size = GetIntSize(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 uint64 length = strlen(value);
if (WriteUInt(writer, length))
return false;
if (writer->Write(value, static_cast<const uint32>(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;
}
bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value) {
if (!writer)
return false;
if (WriteID(writer, type))
return false;
if (WriteUInt(writer, kDateElementSize))
return false;
if (SerializeInt(writer, value, kDateElementSize))
return false;
return true;
}
uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
Cluster* cluster) {
if (!writer || !frame || !frame->IsValid() || !cluster ||
!cluster->timecode_scale())
return 0;
// Technically the timecode for a block can be less than the
// timecode for the cluster itself (remember that block timecode
// is a signed, 16-bit integer). However, as a simplification we
// only permit non-negative cluster-relative timecodes for blocks.
const int64 relative_timecode = cluster->GetRelativeTimecode(
frame->timestamp() / cluster->timecode_scale());
if (relative_timecode < 0 || relative_timecode > kMaxBlockTimecode)
return 0;
return frame->CanBeSimpleBlock() ?
WriteSimpleBlock(writer, frame, relative_timecode) :
WriteBlock(writer, frame, relative_timecode,
cluster->timecode_scale());
}
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(libwebm::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, libwebm::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 = 1;
*revision = 0;
}
uint64 MakeUID(unsigned int* seed) {
uint64 uid = 0;
#ifdef __MINGW32__
srand(*seed);
#endif
for (int i = 0; i < 7; ++i) { // avoid problems with 8-byte values
uid <<= 8;
// TODO(fgalligan): Move random number generation to platform specific code.
#ifdef _MSC_VER
(void)seed;
const int32 nn = rand();
#elif __ANDROID__
(void)seed;
int32 temp_num = 1;
int fd = open("/dev/urandom", O_RDONLY);
if (fd != -1) {
read(fd, &temp_num, sizeof(temp_num));
close(fd);
}
const int32 nn = temp_num;
#elif defined __MINGW32__
const int32 nn = rand();
#else
const int32 nn = rand_r(seed);
#endif
const int32 n = 0xFF & (nn >> 4); // throw away low-order bits
uid |= n;
}
return uid;
}
bool IsMatrixCoefficientsValueValid(uint64_t value) {
switch (value) {
case mkvmuxer::Colour::kGbr:
case mkvmuxer::Colour::kBt709:
case mkvmuxer::Colour::kUnspecifiedMc:
case mkvmuxer::Colour::kReserved:
case mkvmuxer::Colour::kFcc:
case mkvmuxer::Colour::kBt470bg:
case mkvmuxer::Colour::kSmpte170MMc:
case mkvmuxer::Colour::kSmpte240MMc:
case mkvmuxer::Colour::kYcocg:
case mkvmuxer::Colour::kBt2020NonConstantLuminance:
case mkvmuxer::Colour::kBt2020ConstantLuminance:
return true;
}
return false;
}
bool IsChromaSitingHorzValueValid(uint64_t value) {
switch (value) {
case mkvmuxer::Colour::kUnspecifiedCsh:
case mkvmuxer::Colour::kLeftCollocated:
case mkvmuxer::Colour::kHalfCsh:
return true;
}
return false;
}
bool IsChromaSitingVertValueValid(uint64_t value) {
switch (value) {
case mkvmuxer::Colour::kUnspecifiedCsv:
case mkvmuxer::Colour::kTopCollocated:
case mkvmuxer::Colour::kHalfCsv:
return true;
}
return false;
}
bool IsColourRangeValueValid(uint64_t value) {
switch (value) {
case mkvmuxer::Colour::kUnspecifiedCr:
case mkvmuxer::Colour::kBroadcastRange:
case mkvmuxer::Colour::kFullRange:
case mkvmuxer::Colour::kMcTcDefined:
return true;
}
return false;
}
bool IsTransferCharacteristicsValueValid(uint64_t value) {
switch (value) {
case mkvmuxer::Colour::kIturBt709Tc:
case mkvmuxer::Colour::kUnspecifiedTc:
case mkvmuxer::Colour::kReservedTc:
case mkvmuxer::Colour::kGamma22Curve:
case mkvmuxer::Colour::kGamma28Curve:
case mkvmuxer::Colour::kSmpte170MTc:
case mkvmuxer::Colour::kSmpte240MTc:
case mkvmuxer::Colour::kLinear:
case mkvmuxer::Colour::kLog:
case mkvmuxer::Colour::kLogSqrt:
case mkvmuxer::Colour::kIec6196624:
case mkvmuxer::Colour::kIturBt1361ExtendedColourGamut:
case mkvmuxer::Colour::kIec6196621:
case mkvmuxer::Colour::kIturBt202010bit:
case mkvmuxer::Colour::kIturBt202012bit:
case mkvmuxer::Colour::kSmpteSt2084:
case mkvmuxer::Colour::kSmpteSt4281Tc:
case mkvmuxer::Colour::kAribStdB67Hlg:
return true;
}
return false;
}
bool IsPrimariesValueValid(uint64_t value) {
switch (value) {
case mkvmuxer::Colour::kReservedP0:
case mkvmuxer::Colour::kIturBt709P:
case mkvmuxer::Colour::kUnspecifiedP:
case mkvmuxer::Colour::kReservedP3:
case mkvmuxer::Colour::kIturBt470M:
case mkvmuxer::Colour::kIturBt470Bg:
case mkvmuxer::Colour::kSmpte170MP:
case mkvmuxer::Colour::kSmpte240MP:
case mkvmuxer::Colour::kFilm:
case mkvmuxer::Colour::kIturBt2020:
case mkvmuxer::Colour::kSmpteSt4281P:
case mkvmuxer::Colour::kJedecP22Phosphors:
return true;
}
return false;
}
} // namespace mkvmuxer

View File

@ -1,112 +0,0 @@
// 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_MKVMUXERUTIL_H_
#define MKVMUXER_MKVMUXERUTIL_H_
#include "mkvmuxertypes.h"
#include "stdint.h"
namespace mkvmuxer {
class Cluster;
class Frame;
class IMkvWriter;
// TODO(tomfinegan): mkvmuxer:: integer types continue to be used here because
// changing them causes pain for downstream projects. It would be nice if a
// solution that allows removal of the mkvmuxer:: integer types while avoiding
// pain for downstream users of libwebm. Considering that mkvmuxerutil.{cc,h}
// are really, for the great majority of cases, EBML size calculation and writer
// functions, perhaps a more EBML focused utility would be the way to go as a
// first step.
const uint64 kEbmlUnknownValue = 0x01FFFFFFFFFFFFFFULL;
const int64 kMaxBlockTimecode = 0x07FFFLL;
// 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.
int32 GetUIntSize(uint64 value);
int32 GetIntSize(int64 value);
int32 GetCodedUIntSize(uint64 value);
uint64 EbmlMasterElementSize(uint64 type, uint64 value);
uint64 EbmlElementSize(uint64 type, int64 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);
uint64 EbmlDateElementSize(uint64 type);
// Returns the size in bytes of the element assuming that the element was
// written using |fixed_size| bytes. If |fixed_size| is set to zero, then it
// computes the necessary number of bytes based on |value|.
uint64 EbmlElementSize(uint64 type, uint64 value, uint64 fixed_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, int64 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);
bool WriteEbmlDateElement(IMkvWriter* writer, uint64 type, int64 value);
// Output an Mkv non-master element using fixed size. The element will be
// written out using exactly |fixed_size| bytes. If |fixed_size| is set to zero
// then it computes the necessary number of bytes based on |value|. Returns true
// if the element was written.
bool WriteEbmlElement(IMkvWriter* writer, uint64 type, uint64 value,
uint64 fixed_size);
// Output a Mkv Frame. It decides the correct element to write (Block vs
// SimpleBlock) based on the parameters of the Frame.
uint64 WriteFrame(IMkvWriter* writer, const Frame* const frame,
Cluster* cluster);
// 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);
// Returns a random number to be used for UID, using |seed| to seed
// the random-number generator (see POSIX rand_r() for semantics).
uint64 MakeUID(unsigned int* seed);
// Colour field validation helpers. All return true when |value| is valid.
bool IsMatrixCoefficientsValueValid(uint64_t value);
bool IsChromaSitingHorzValueValid(uint64_t value);
bool IsChromaSitingVertValueValid(uint64_t value);
bool IsColourRangeValueValid(uint64_t value);
bool IsTransferCharacteristicsValueValid(uint64_t value);
bool IsPrimariesValueValid(uint64_t value);
} // namespace mkvmuxer
#endif // MKVMUXER_MKVMUXERUTIL_H_

View File

@ -1,51 +0,0 @@
// 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_MKVWRITER_H_
#define MKVMUXER_MKVWRITER_H_
#include <stdio.h>
#include "mkvmuxer/mkvmuxer.h"
#include "mkvmuxer/mkvmuxertypes.h"
namespace mkvmuxer {
// Default implementation of the IMkvWriter interface on Windows.
class MkvWriter : public IMkvWriter {
public:
MkvWriter();
explicit MkvWriter(FILE* fp);
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_;
bool writer_owns_file_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
};
} // namespace mkvmuxer
#endif // MKVMUXER_MKVWRITER_H_

View File

@ -1,785 +0,0 @@
// 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 <stdint.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <list>
#include <memory>
#include <string>
// libwebm common includes.
#include "common/file_util.h"
#include "common/hdr_util.h"
// libwebm mkvparser includes
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
// libwebm mkvmuxer includes
#include "mkvmuxer/mkvmuxer.h"
#include "mkvmuxer/mkvmuxertypes.h"
#include "mkvmuxer/mkvwriter.h"
#include "sample_muxer_metadata.h"
namespace {
void Usage() {
printf("Usage: mkvmuxer_sample -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(" -copy_tags <int> >0 Copies the tags\n");
printf(" -accurate_cluster_duration <int> ");
printf(">0 Writes the last frame in each cluster with Duration\n");
printf(" -fixed_size_cluster_timecode <int> ");
printf(">0 Writes the cluster timecode using exactly 8 bytes\n");
printf(" -copy_input_duration >0 Copies the input duration\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(" -pixel_width <int> Override pixel width\n");
printf(" -pixel_height <int> Override pixel height\n");
printf(" -projection_type <int> Set/override projection type:\n");
printf(" 0: Rectangular\n");
printf(" 1: Equirectangular\n");
printf(" 2: Cube map\n");
printf(" 3: Mesh\n");
printf(" -projection_file <string> Override projection private data");
printf(" with contents of this file\n");
printf(" -projection_pose_yaw <float> Projection pose yaw\n");
printf(" -projection_pose_pitch <float> Projection pose pitch\n");
printf(" -projection_pose_roll <float> Projection pose roll\n");
printf(" -stereo_mode <int> 3D video mode\n");
printf("\n");
printf("VP9 options:\n");
printf(" -profile <int> VP9 profile\n");
printf(" -level <int> VP9 level\n");
printf("\n");
printf("Cues options:\n");
printf(" -output_cues_block_number <int> >0 outputs cue block number\n");
printf(" -cues_before_clusters <int> >0 puts Cues before Clusters\n");
printf("\n");
printf("Metadata options:\n");
printf(" -webvtt-subtitles <vttfile> ");
printf("add WebVTT subtitles as metadata track\n");
printf(" -webvtt-captions <vttfile> ");
printf("add WebVTT captions as metadata track\n");
printf(" -webvtt-descriptions <vttfile> ");
printf("add WebVTT descriptions as metadata track\n");
printf(" -webvtt-metadata <vttfile> ");
printf("add WebVTT subtitles as metadata track\n");
printf(" -webvtt-chapters <vttfile> ");
printf("add WebVTT chapters as MKV chapters element\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 = 5 };
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},
{"-webvtt-chapters", SampleMuxerMetadata::kChapters}};
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
}
bool CopyVideoProjection(const mkvparser::Projection& parser_projection,
mkvmuxer::Projection* muxer_projection) {
typedef mkvmuxer::Projection::ProjectionType MuxerProjType;
const int kTypeNotPresent = mkvparser::Projection::kTypeNotPresent;
if (parser_projection.type != kTypeNotPresent) {
muxer_projection->set_type(
static_cast<MuxerProjType>(parser_projection.type));
}
if (parser_projection.private_data &&
parser_projection.private_data_length > 0) {
if (!muxer_projection->SetProjectionPrivate(
parser_projection.private_data,
parser_projection.private_data_length)) {
return false;
}
}
const float kValueNotPresent = mkvparser::Projection::kValueNotPresent;
if (parser_projection.pose_yaw != kValueNotPresent)
muxer_projection->set_pose_yaw(parser_projection.pose_yaw);
if (parser_projection.pose_pitch != kValueNotPresent)
muxer_projection->set_pose_pitch(parser_projection.pose_pitch);
if (parser_projection.pose_roll != kValueNotPresent)
muxer_projection->set_pose_roll(parser_projection.pose_roll);
return true;
}
} // 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_before_clusters = false;
bool cues_on_video_track = true;
bool cues_on_audio_track = false;
uint64_t max_cluster_duration = 0;
uint64_t 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;
bool copy_tags = false;
const char* chunk_name = NULL;
bool accurate_cluster_duration = false;
bool fixed_size_cluster_timecode = false;
bool copy_input_duration = false;
bool output_cues_block_number = true;
uint64_t display_width = 0;
uint64_t display_height = 0;
uint64_t pixel_width = 0;
uint64_t pixel_height = 0;
uint64_t stereo_mode = 0;
const char* projection_file = 0;
int64_t projection_type = mkvparser::Projection::kTypeNotPresent;
float projection_pose_roll = mkvparser::Projection::kValueNotPresent;
float projection_pose_pitch = mkvparser::Projection::kValueNotPresent;
float projection_pose_yaw = mkvparser::Projection::kValueNotPresent;
int vp9_profile = -1; // No profile set.
int vp9_level = -1; // No level set.
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_before_clusters", argv[i]) && i < argc_check) {
cues_before_clusters = 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_t>(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 = static_cast<int>(strtol(argv[++i], &end, 10));
} else if (!strcmp("-video_track_number", argv[i]) && i < argc_check) {
video_track_number = static_cast<int>(strtol(argv[++i], &end, 10));
} else if (!strcmp("-chunking", argv[i]) && i < argc_check) {
chunking = true;
chunk_name = argv[++i];
} else if (!strcmp("-copy_tags", argv[i]) && i < argc_check) {
copy_tags = strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-accurate_cluster_duration", argv[i]) &&
i < argc_check) {
accurate_cluster_duration =
strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-fixed_size_cluster_timecode", argv[i]) &&
i < argc_check) {
fixed_size_cluster_timecode =
strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-copy_input_duration", argv[i]) && i < argc_check) {
copy_input_duration = strtol(argv[++i], &end, 10) == 0 ? false : true;
} 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("-pixel_width", argv[i]) && i < argc_check) {
pixel_width = strtol(argv[++i], &end, 10);
} else if (!strcmp("-pixel_height", argv[i]) && i < argc_check) {
pixel_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("-projection_type", argv[i]) && i < argc_check) {
projection_type = strtol(argv[++i], &end, 10);
} else if (!strcmp("-projection_file", argv[i]) && i < argc_check) {
projection_file = argv[++i];
} else if (!strcmp("-projection_pose_roll", argv[i]) && i < argc_check) {
projection_pose_roll = strtof(argv[++i], &end);
} else if (!strcmp("-projection_pose_pitch", argv[i]) && i < argc_check) {
projection_pose_pitch = strtof(argv[++i], &end);
} else if (!strcmp("-projection_pose_yaw", argv[i]) && i < argc_check) {
projection_pose_yaw = strtof(argv[++i], &end);
} else if (!strcmp("-profile", argv[i]) && i < argc_check) {
vp9_profile = static_cast<int>(strtol(argv[++i], &end, 10));
} else if (!strcmp("-level", argv[i]) && i < argc_check) {
vp9_level = static_cast<int>(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;
long long ret = ebml_header.Parse(&reader, pos);
if (ret) {
printf("\n EBMLHeader::Parse() failed.");
return EXIT_FAILURE;
}
mkvparser::Segment* parser_segment_;
ret = mkvparser::Segment::CreateInstance(&reader, pos, parser_segment_);
if (ret) {
printf("\n Segment::CreateInstance() failed.");
return EXIT_FAILURE;
}
const std::unique_ptr<mkvparser::Segment> parser_segment(parser_segment_);
ret = parser_segment->Load();
if (ret < 0) {
printf("\n Segment::Load() failed.");
return EXIT_FAILURE;
}
const mkvparser::SegmentInfo* const segment_info = parser_segment->GetInfo();
if (segment_info == NULL) {
printf("\n Segment::GetInfo() failed.");
return EXIT_FAILURE;
}
const long long timeCodeScale = segment_info->GetTimeCodeScale();
// Set muxer header info
mkvmuxer::MkvWriter writer;
const std::string temp_file =
cues_before_clusters ? libwebm::GetTempFileName() : output;
if (!writer.Open(temp_file.c_str())) {
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;
}
muxer_segment.AccurateClusterDuration(accurate_cluster_duration);
muxer_segment.UseFixedSizeClusterTimecode(fixed_size_cluster_timecode);
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("mkvmuxer_sample");
const mkvparser::Tags* const tags = parser_segment->GetTags();
if (copy_tags && tags) {
for (int i = 0; i < tags->GetTagCount(); i++) {
const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
mkvmuxer::Tag* muxer_tag = muxer_segment.AddTag();
for (int j = 0; j < tag->GetSimpleTagCount(); j++) {
const mkvparser::Tags::SimpleTag* const simple_tag =
tag->GetSimpleTag(j);
muxer_tag->add_simple_tag(simple_tag->GetTagName(),
simple_tag->GetTagString());
}
}
}
// Set Tracks element attributes
const mkvparser::Tracks* const parser_tracks = parser_segment->GetTracks();
unsigned long i = 0;
uint64_t vid_track = 0; // no track added
uint64_t aud_track = 0; // no track added
using mkvparser::Track;
while (i != parser_tracks->GetTracksCount()) {
unsigned long track_num = i++;
if (switch_tracks)
track_num = i % parser_tracks->GetTracksCount();
const 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 (pVideoTrack->GetColour()) {
mkvmuxer::Colour muxer_colour;
if (!libwebm::CopyColour(*pVideoTrack->GetColour(), &muxer_colour))
return EXIT_FAILURE;
if (!video->SetColour(muxer_colour))
return EXIT_FAILURE;
}
if (pVideoTrack->GetProjection() ||
projection_type != mkvparser::Projection::kTypeNotPresent) {
mkvmuxer::Projection muxer_projection;
const mkvparser::Projection* const parser_projection =
pVideoTrack->GetProjection();
typedef mkvmuxer::Projection::ProjectionType MuxerProjType;
if (parser_projection &&
!CopyVideoProjection(*parser_projection, &muxer_projection)) {
printf("\n Unable to copy video projection.\n");
return EXIT_FAILURE;
}
// Override the values that came from parser if set on command line.
if (projection_type != mkvparser::Projection::kTypeNotPresent) {
muxer_projection.set_type(
static_cast<MuxerProjType>(projection_type));
if (projection_type == mkvparser::Projection::kRectangular &&
projection_file != NULL) {
printf("\n Rectangular projection must not have private data.\n");
return EXIT_FAILURE;
} else if ((projection_type == mkvparser::Projection::kCubeMap ||
projection_type == mkvparser::Projection::kMesh) &&
projection_file == NULL) {
printf("\n Mesh or CubeMap projection must have private data.\n");
return EXIT_FAILURE;
}
if (projection_file != NULL) {
std::string contents;
if (!libwebm::GetFileContents(projection_file, &contents) ||
contents.size() == 0) {
printf("\n Failed to read file \"%s\" or file is empty\n",
projection_file);
return EXIT_FAILURE;
}
if (!muxer_projection.SetProjectionPrivate(
reinterpret_cast<uint8_t*>(&contents[0]),
contents.size())) {
printf("\n Failed to SetProjectionPrivate of length %zu.\n",
contents.size());
return EXIT_FAILURE;
}
}
}
const float kValueNotPresent = mkvparser::Projection::kValueNotPresent;
if (projection_pose_yaw != kValueNotPresent)
muxer_projection.set_pose_yaw(projection_pose_yaw);
if (projection_pose_pitch != kValueNotPresent)
muxer_projection.set_pose_pitch(projection_pose_pitch);
if (projection_pose_roll != kValueNotPresent)
muxer_projection.set_pose_roll(projection_pose_roll);
if (!video->SetProjection(muxer_projection))
return EXIT_FAILURE;
}
if (track_name)
video->set_name(track_name);
video->set_codec_id(pVideoTrack->GetCodecId());
if (display_width > 0)
video->set_display_width(display_width);
if (display_height > 0)
video->set_display_height(display_height);
if (pixel_width > 0)
video->set_pixel_width(pixel_width);
if (pixel_height > 0)
video->set_pixel_height(pixel_height);
if (stereo_mode > 0)
video->SetStereoMode(stereo_mode);
const double rate = pVideoTrack->GetFrameRate();
if (rate > 0.0) {
video->set_frame_rate(rate);
}
if (vp9_profile >= 0 || vp9_level >= 0) {
const int kMaxVp9PrivateSize = 6;
unsigned char private_data[kMaxVp9PrivateSize];
int private_size = 0;
if (vp9_profile >= 0) {
if (vp9_profile < 0 || vp9_profile > 3) {
printf("\n VP9 profile(%d) is not valid.\n", vp9_profile);
return EXIT_FAILURE;
}
const uint8_t kVp9ProfileId = 1;
const uint8_t kVp9ProfileIdLength = 1;
private_data[private_size++] = kVp9ProfileId;
private_data[private_size++] = kVp9ProfileIdLength;
private_data[private_size++] = vp9_profile;
}
if (vp9_level >= 0) {
const int kNumLevels = 14;
const int levels[kNumLevels] = {10, 11, 20, 21, 30, 31, 40,
41, 50, 51, 52, 60, 61, 62};
bool level_is_valid = false;
for (int i = 0; i < kNumLevels; ++i) {
if (vp9_level == levels[i]) {
level_is_valid = true;
break;
}
}
if (!level_is_valid) {
printf("\n VP9 level(%d) is not valid.\n", vp9_level);
return EXIT_FAILURE;
}
const uint8_t kVp9LevelId = 2;
const uint8_t kVp9LevelIdLength = 1;
private_data[private_size++] = kVp9LevelId;
private_data[private_size++] = kVp9LevelIdLength;
private_data[private_size++] = vp9_level;
}
if (!video->SetCodecPrivate(private_data, private_size)) {
printf("\n Could not add video private data.\n");
return EXIT_FAILURE;
}
}
} 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);
audio->set_codec_id(pAudioTrack->GetCodecId());
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);
if (pAudioTrack->GetCodecDelay())
audio->set_codec_delay(pAudioTrack->GetCodecDelay());
if (pAudioTrack->GetSeekPreRoll())
audio->set_seek_pre_roll(pAudioTrack->GetSeekPreRoll());
}
}
// 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;
if (!metadata.AddChapters())
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;
long 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));
// When |parser_track| is NULL, it means that the track number in the
// Block is invalid (i.e.) the was no TrackEntry corresponding to the
// track number. So we reject the file.
if (!parser_track) {
return EXIT_FAILURE;
}
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();
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;
mkvmuxer::Frame muxer_frame;
if (!muxer_frame.Init(data, frame.len))
return EXIT_FAILURE;
muxer_frame.set_track_number(track_type == Track::kAudio ? aud_track :
vid_track);
if (block->GetDiscardPadding())
muxer_frame.set_discard_padding(block->GetDiscardPadding());
muxer_frame.set_timestamp(time_ns);
muxer_frame.set_is_key(block->IsKey());
if (!muxer_segment.AddGenericFrame(&muxer_frame)) {
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;
if (copy_input_duration) {
const double input_duration =
static_cast<double>(segment_info->GetDuration()) / timeCodeScale;
muxer_segment.set_duration(input_duration);
}
if (!muxer_segment.Finalize()) {
printf("Finalization of segment failed.\n");
return EXIT_FAILURE;
}
reader.Close();
writer.Close();
if (cues_before_clusters) {
if (reader.Open(temp_file.c_str())) {
printf("\n Filename is invalid or error while opening.\n");
return EXIT_FAILURE;
}
if (!writer.Open(output)) {
printf("\n Filename is invalid or error while opening.\n");
return EXIT_FAILURE;
}
if (!muxer_segment.CopyAndMoveCuesBeforeClusters(&reader, &writer)) {
printf("\n Unable to copy and move cues before clusters.\n");
return EXIT_FAILURE;
}
reader.Close();
writer.Close();
remove(temp_file.c_str());
}
delete[] data;
return EXIT_SUCCESS;
}

View File

@ -1,15 +1,29 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved. // Copyright (c) 2011 The WebM project authors. All Rights Reserved.
// //
// Use of this source code is governed by a BSD-style license // 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 // that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found // tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may // in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree. // be found in the AUTHORS file in the root of the source tree.
#ifndef LIBWEBM_MKVMUXERTYPES_HPP_
#define LIBWEBM_MKVMUXERTYPES_HPP_
// This file is a wrapper for the file included immediately after this comment. #ifndef MKVMUXERTYPES_HPP
// New projects should not include this file: include the file included below. #define MKVMUXERTYPES_HPP
#include "mkvmuxer/mkvmuxertypes.h"
#endif // LIBWEBM_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 int int32;
typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
} //end namespace mkvmuxer
#endif // MKVMUXERTYPES_HPP

390
mkvmuxerutil.cpp Normal file
View File

@ -0,0 +1,390 @@
// 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 "mkvmuxerutil.hpp"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#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,
char track_number,
short timecode,
bool is_key) {
if (!writer || !data || length < 1 || track_number < 1 || timecode < 0)
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, static_cast<uint64>(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;
}
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 = 0;
build = 0;
revision = 1;
}
} // namespace mkvmuxer

View File

@ -1,18 +1,82 @@
// Copyright (c) 2016 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 // 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 // that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found // tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may // in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree. // be found in the AUTHORS file in the root of the source tree.
#ifndef LIBWEBM_MKVMUXERUTIL_HPP_
#define LIBWEBM_MKVMUXERUTIL_HPP_
// This file is a wrapper for the file included immediately after this comment. #ifndef MKVMUXERUTIL_HPP
// New projects should not include this file: include the file included below. #define MKVMUXERUTIL_HPP
#include "mkvmuxer/mkvmuxerutil.h"
using mkvmuxer::EbmlElementSize; #include "mkvmuxertypes.hpp"
using mkvmuxer::EbmlMasterElementSize;
#endif // LIBWEBM_MKVMUXERUTIL_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.
// timecode: Relative timecode of the Block.
// is_key: Flag telling whether or not this frame is a key frame.
uint64 WriteSimpleBlock(IMkvWriter* writer,
const uint8* data,
uint64 length,
char track_number,
short timecode,
bool is_key);
// 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

9429
mkvparser.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,896 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved. // Copyright (c) 2010 The WebM project authors. All Rights Reserved.
// //
// Use of this source code is governed by a BSD-style license // 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 // that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found // tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may // in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree. // be found in the AUTHORS file in the root of the source tree.
#ifndef LIBWEBM_MKVPARSER_HPP_
#define LIBWEBM_MKVPARSER_HPP_
// This file is a wrapper for the file included immediately after this comment. #ifndef MKVPARSER_HPP
// New projects should not include this file: include the file included below. #define MKVPARSER_HPP
#include "mkvparser/mkvparser.h"
#endif // LIBWEBM_MKVPARSER_HPP_ #include <cstdlib>
#include <cstdio>
#include <cstddef>
namespace mkvparser
{
const int E_FILE_FORMAT_INVALID = -2;
const int E_BUFFER_NOT_FULL = -3;
class IMkvReader
{
public:
virtual int Read(long long pos, long len, unsigned char* buf) = 0;
virtual int Length(long long* total, long long* available) = 0;
protected:
virtual ~IMkvReader();
};
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);
#if 0
short Unserialize2SInt(IMkvReader*, long long);
signed char Unserialize1SInt(IMkvReader*, long long);
#else
long UnserializeInt(IMkvReader*, long long pos, long len, long long& result);
#endif
long UnserializeString(IMkvReader*, long long pos, long long size, char*&);
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);
struct EBMLHeader
{
EBMLHeader();
~EBMLHeader();
long long m_version;
long long m_readVersion;
long long m_maxIdLength;
long long m_maxSizeLength;
char* m_docType;
long long m_docTypeVersion;
long long m_docTypeReadVersion;
long long Parse(IMkvReader*, long long&);
void Init();
};
class Segment;
class Track;
class Cluster;
class Block
{
Block(const Block&);
Block& operator=(const Block&);
public:
const long long m_start;
const long long m_size;
Block(long long start, long long size);
~Block();
long Parse(IMkvReader*);
long long GetTrackNumber() const;
long long GetTimeCode(const Cluster*) const; //absolute, but not scaled
long long GetTime(const Cluster*) const; //absolute, and scaled (ns)
bool IsKey() const;
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
{
long long pos; //absolute offset
long len;
long Read(IMkvReader*, unsigned char*) const;
};
const Frame& GetFrame(int frame_index) const;
private:
long long m_track; //Track::Number()
short m_timecode; //relative to cluster
unsigned char m_flags;
Frame* m_frames;
int m_frame_count;
};
class BlockEntry
{
BlockEntry(const BlockEntry&);
BlockEntry& operator=(const BlockEntry&);
protected:
BlockEntry(Cluster*, long index);
public:
virtual ~BlockEntry();
bool EOS() const;
const Cluster* GetCluster() const;
long GetIndex() const;
virtual const Block* GetBlock() const = 0;
enum Kind { kBlockEOS, kBlockSimple, kBlockGroup };
virtual Kind GetKind() const = 0;
protected:
Cluster* const m_pCluster;
const long m_index;
};
class SimpleBlock : public BlockEntry
{
SimpleBlock(const SimpleBlock&);
SimpleBlock& operator=(const SimpleBlock&);
public:
SimpleBlock(Cluster*, long index, long long start, long long size);
long Parse();
Kind GetKind() const;
const Block* GetBlock() const;
protected:
Block m_block;
};
class BlockGroup : public BlockEntry
{
BlockGroup(const BlockGroup&);
BlockGroup& operator=(const BlockGroup&);
public:
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);
long Parse();
Kind GetKind() const;
const Block* GetBlock() const;
long long GetPrevTimeCode() const; //relative to block's time
long long GetNextTimeCode() const; //as above
long long GetDuration() const;
private:
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:
ContentEncoding();
~ContentEncoding();
// ContentCompression element names
struct ContentCompression {
ContentCompression();
~ContentCompression();
unsigned long long algo;
unsigned char* settings;
};
// 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;
};
// 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 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.
bool ParseContentEncodingEntry(long long start,
long long size,
IMkvReader* const 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.
void ParseEncryptionEntry(long long start,
long long size,
IMkvReader* const pReader,
ContentEncryption* const 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
{
Track(const Track&);
Track& operator=(const Track&);
public:
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;
unsigned long long GetUid() const;
const char* GetNameAsUTF8() const;
const char* GetCodecNameAsUTF8() const;
const char* GetCodecId() const;
const unsigned char* GetCodecPrivate(size_t&) const;
bool GetLacing() const;
const BlockEntry* GetEOS() const;
struct Settings
{
long long start;
long long size;
};
struct Info
{
long long type;
long long number;
unsigned long long uid;
char* nameAsUTF8;
char* codecId;
unsigned char* codecPrivate;
size_t codecPrivateSize;
char* codecNameAsUTF8;
bool lacing;
Settings settings;
Info();
void Clear();
};
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;
const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const;
unsigned long GetContentEncodingCount() const;
void ParseContentEncodingsEntry(long long start, long long size);
protected:
Track(
Segment*,
const Info&,
long long element_start,
long long element_size);
const Info m_info;
class EOSBlock : public BlockEntry
{
public:
EOSBlock();
Kind GetKind() const;
const Block* GetBlock() const;
};
EOSBlock m_eos;
private:
ContentEncoding** content_encoding_entries_;
ContentEncoding** content_encoding_entries_end_;
};
class VideoTrack : public Track
{
VideoTrack(const VideoTrack&);
VideoTrack& operator=(const VideoTrack&);
VideoTrack(
Segment*,
const Info&,
long long element_start,
long long element_size);
public:
static long Parse(
Segment*,
const Info&,
long long element_start,
long long element_size,
VideoTrack*&);
long long GetWidth() const;
long long GetHeight() const;
double GetFrameRate() const;
bool VetEntry(const BlockEntry*) const;
long Seek(long long time_ns, const BlockEntry*&) const;
private:
long long m_width;
long long m_height;
double m_rate;
};
class AudioTrack : public Track
{
AudioTrack(const AudioTrack&);
AudioTrack& operator=(const AudioTrack&);
AudioTrack(
Segment*,
const Info&,
long long element_start,
long long element_size);
public:
static long Parse(
Segment*,
const Info&,
long long element_start,
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:
double m_rate;
long long m_channels;
long long m_bitDepth;
};
class Tracks
{
Tracks(const Tracks&);
Tracks& operator=(const Tracks&);
public:
Segment* const m_pSegment;
const long long m_start;
const long long m_size;
const long long m_element_start;
const long long m_element_size;
Tracks(
Segment*,
long long start,
long long size,
long long element_start,
long long element_size);
~Tracks();
long Parse();
unsigned long GetTracksCount() const;
const Track* GetTrackByNumber(unsigned long tn) const;
const Track* GetTrackByIndex(unsigned long idx) const;
private:
Track** m_trackEntries;
Track** m_trackEntriesEnd;
long ParseTrackEntry(
long long payload_start,
long long payload_size,
long long element_start,
long long element_size,
Track*&) const;
};
class SegmentInfo
{
SegmentInfo(const SegmentInfo&);
SegmentInfo& operator=(const SegmentInfo&);
public:
Segment* const m_pSegment;
const long long m_start;
const long long m_size;
const long long m_element_start;
const long long m_element_size;
SegmentInfo(
Segment*,
long long start,
long long size,
long long element_start,
long long element_size);
~SegmentInfo();
long Parse();
long long GetTimeCodeScale() const;
long long GetDuration() const; //scaled
const char* GetMuxingAppAsUTF8() const;
const char* GetWritingAppAsUTF8() const;
const char* GetTitleAsUTF8() const;
private:
long long m_timecodeScale;
double m_duration;
char* m_pMuxingAppAsUTF8;
char* m_pWritingAppAsUTF8;
char* m_pTitleAsUTF8;
};
class SeekHead
{
SeekHead(const SeekHead&);
SeekHead& operator=(const SeekHead&);
public:
Segment* const m_pSegment;
const long long m_start;
const long long m_size;
const long long m_element_start;
const long long m_element_size;
SeekHead(
Segment*,
long long start,
long long size,
long long element_start,
long long element_size);
~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_entry_count;
VoidElement* m_void_elements;
int m_void_element_count;
static bool ParseEntry(
IMkvReader*,
long long pos, //payload
long long size,
Entry*);
};
class Cues;
class CuePoint
{
friend class Cues;
CuePoint(long, long long);
~CuePoint();
CuePoint(const CuePoint&);
CuePoint& operator=(const CuePoint&);
public:
long long m_element_start;
long long m_element_size;
void Load(IMkvReader*);
long long GetTimeCode() const; //absolute but unscaled
long long GetTime(const Segment*) const; //absolute and scaled (ns units)
struct TrackPosition
{
long long m_track;
long long m_pos; //of cluster
long long m_block;
//codec_state //defaults to 0
//reference = clusters containing req'd referenced blocks
// reftime = timecode of the referenced block
void Parse(IMkvReader*, long long, long long);
};
const TrackPosition* Find(const Track*) const;
private:
const long m_index;
long long m_timecode;
TrackPosition* m_track_positions;
size_t m_track_positions_count;
};
class Cues
{
friend class Segment;
Cues(
Segment*,
long long start,
long long size,
long long element_start,
long long element_size);
~Cues();
Cues(const Cues&);
Cues& operator=(const Cues&);
public:
Segment* const m_pSegment;
const long long m_start;
const long long m_size;
const long long m_element_start;
const long long m_element_size;
bool Find( //lower bound of time_ns
long long time_ns,
const Track*,
const CuePoint*&,
const CuePoint::TrackPosition*&) const;
#if 0
bool FindNext( //upper_bound of time_ns
long long time_ns,
const Track*,
const CuePoint*&,
const CuePoint::TrackPosition*&) const;
#endif
const CuePoint* GetFirst() const;
const CuePoint* GetLast() const;
const CuePoint* GetNext(const CuePoint*) const;
const BlockEntry* GetBlock(
const CuePoint*,
const CuePoint::TrackPosition*) const;
bool LoadCuePoint() const;
long GetCount() const; //loaded only
//long GetTotal() const; //loaded + preloaded
bool DoneParsing() const;
private:
void Init() const;
void PreloadCuePoint(long&, long long) const;
mutable CuePoint** m_cue_points;
mutable long m_count;
mutable long m_preload_count;
mutable long long m_pos;
};
class Cluster
{
friend class Segment;
Cluster(const Cluster&);
Cluster& operator=(const Cluster&);
public:
Segment* const m_pSegment;
public:
static Cluster* Create(
Segment*,
long index, //index in segment
long long off); //offset relative to segment
//long long element_size);
Cluster(); //EndOfStream
~Cluster();
bool EOS() const;
long long GetTimeCode() const; //absolute, but not scaled
long long GetTime() const; //absolute, and scaled (nanosecond units)
long long GetFirstTime() const; //time (ns) of first (earliest) block
long long GetLastTime() const; //time (ns) of last (latest) block
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;
// static bool HasBlockEntries(const Segment*, long long);
static long HasBlockEntries(
const Segment*,
long long idoff,
long long& pos,
long& size);
long GetEntryCount() const;
long Load(long long& pos, long& size) const;
long Parse(long long& pos, long& size) const;
long GetEntry(long index, const mkvparser::BlockEntry*&) const;
protected:
Cluster(
Segment*,
long index,
long long element_start);
//long long element_size);
public:
const long long m_element_start;
long long GetPosition() const; //offset relative to segment
long GetIndex() const;
long long GetElementSize() const;
//long long GetPayloadSize() const;
//long long Unparsed() const;
private:
long m_index;
mutable long long m_pos;
//mutable long long m_size;
mutable long long m_element_size;
mutable long long m_timecode;
mutable BlockEntry** m_entries;
mutable long m_entries_size;
mutable long m_entries_count;
long ParseSimpleBlock(long long, long long&, long&);
long ParseBlockGroup(long long, long long&, long&);
long CreateBlock(long long id, long long pos, long long size);
long CreateBlockGroup(long long, long long);
long CreateSimpleBlock(long long, long long);
};
class Segment
{
friend class Cues;
friend class VideoTrack;
friend class AudioTrack;
Segment(const Segment&);
Segment& operator=(const Segment&);
private:
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?
static long long CreateInstance(IMkvReader*, long long, Segment*&);
~Segment();
long Load(); //loads headers and all clusters
//for incremental loading
//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
long LoadCluster();
long ParseNext(
const Cluster* pCurr,
const Cluster*& pNext,
long long& pos,
long& size);
#if 0
//This pair parses one cluster, but only changes the state of the
//segment object when the cluster is actually added to the index.
long ParseCluster(long long& cluster_pos, long long& new_pos) const;
bool AddCluster(long long cluster_pos, long long new_pos);
#endif
const SeekHead* GetSeekHead() const;
const Tracks* GetTracks() const;
const SegmentInfo* GetInfo() const;
const Cues* GetCues() const;
long long GetDuration() const;
unsigned long GetCount() const;
const Cluster* GetFirst() const;
const Cluster* GetLast() const;
const Cluster* GetNext(const Cluster*);
const Cluster* FindCluster(long long time_nanoseconds) const;
//const BlockEntry* Seek(long long time_nanoseconds, const Track*) const;
const Cluster* FindOrPreloadCluster(long long pos);
long ParseCues(
long long cues_off, //offset relative to start of segment
long long& parse_pos,
long& parse_len);
private:
long long m_pos; //absolute file posn; what has been consumed so far
Cluster* m_pUnknownSize;
SeekHead* m_pSeekHead;
SegmentInfo* m_pInfo;
Tracks* m_pTracks;
Cues* m_pCues;
Cluster** m_clusters;
long m_clusterCount; //number of entries for which m_index >= 0
long m_clusterPreloadCount; //number of entries for which m_index < 0
long m_clusterSize; //array size
long DoLoadCluster(long long&, long&);
long DoLoadClusterUnknownSize(long long&, long&);
long DoParseNext(const Cluster*&, long long&, long&);
void AppendCluster(Cluster*);
void PreloadCluster(Cluster*, ptrdiff_t);
//void ParseSeekHead(long long pos, long long size);
//void ParseSeekEntry(long long pos, long long size);
//void ParseCues(long long);
const BlockEntry* GetBlock(
const CuePoint&,
const CuePoint::TrackPosition&);
};
} //end namespace mkvparser
inline long mkvparser::Segment::LoadCluster()
{
long long pos;
long size;
return LoadCluster(pos, size);
}
#endif //MKVPARSER_HPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,133 +0,0 @@
// Copyright (c) 2010 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 "mkvparser/mkvreader.h"
#include <sys/types.h>
#include <cassert>
namespace mkvparser {
MkvReader::MkvReader() : m_file(NULL), reader_owns_file_(true) {}
MkvReader::MkvReader(FILE* fp) : m_file(fp), reader_owns_file_(false) {
GetFileSize();
}
MkvReader::~MkvReader() {
if (reader_owns_file_)
Close();
m_file = NULL;
}
int MkvReader::Open(const char* fileName) {
if (fileName == NULL)
return -1;
if (m_file)
return -1;
#ifdef _MSC_VER
const errno_t e = fopen_s(&m_file, fileName, "rb");
if (e)
return -1; // error
#else
m_file = fopen(fileName, "rb");
if (m_file == NULL)
return -1;
#endif
return !GetFileSize();
}
bool MkvReader::GetFileSize() {
if (m_file == NULL)
return false;
#ifdef _MSC_VER
int status = _fseeki64(m_file, 0L, SEEK_END);
if (status)
return false; // error
m_length = _ftelli64(m_file);
#else
fseek(m_file, 0L, SEEK_END);
m_length = ftell(m_file);
#endif
assert(m_length >= 0);
if (m_length < 0)
return false;
#ifdef _MSC_VER
status = _fseeki64(m_file, 0L, SEEK_SET);
if (status)
return false; // error
#else
fseek(m_file, 0L, SEEK_SET);
#endif
return true;
}
void MkvReader::Close() {
if (m_file != NULL) {
fclose(m_file);
m_file = NULL;
}
}
int MkvReader::Length(long long* total, long long* available) {
if (m_file == NULL)
return -1;
if (total)
*total = m_length;
if (available)
*available = m_length;
return 0;
}
int MkvReader::Read(long long offset, long len, unsigned char* buffer) {
if (m_file == NULL)
return -1;
if (offset < 0)
return -1;
if (len < 0)
return -1;
if (len == 0)
return 0;
if (offset >= m_length)
return -1;
#ifdef _MSC_VER
const int status = _fseeki64(m_file, offset, SEEK_SET);
if (status)
return -1; // error
#else
fseeko(m_file, static_cast<off_t>(offset), SEEK_SET);
#endif
const size_t size = fread(buffer, 1, len, m_file);
if (size < size_t(len))
return -1; // error
return 0; // success
}
} // namespace mkvparser

View File

@ -1,45 +0,0 @@
// Copyright (c) 2010 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 MKVPARSER_MKVREADER_H_
#define MKVPARSER_MKVREADER_H_
#include <cstdio>
#include "mkvparser/mkvparser.h"
namespace mkvparser {
class MkvReader : public IMkvReader {
public:
MkvReader();
explicit MkvReader(FILE* fp);
virtual ~MkvReader();
int Open(const char*);
void Close();
virtual int Read(long long position, long length, unsigned char* buffer);
virtual int Length(long long* total, long long* available);
private:
MkvReader(const MkvReader&);
MkvReader& operator=(const MkvReader&);
// Determines the size of the file. This is called either by the constructor
// or by the Open function depending on file ownership. Returns true on
// success.
bool GetFileSize();
long long m_length;
FILE* m_file;
bool reader_owns_file_;
};
} // namespace mkvparser
#endif // MKVPARSER_MKVREADER_H_

View File

@ -1,459 +0,0 @@
// Copyright (c) 2010 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.
//
// This sample application demonstrates how to use the Matroska parser
// library, which allows clients to handle a Matroska format file.
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <new>
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
namespace {
const wchar_t* utf8towcs(const char* str) {
if (str == NULL)
return NULL;
// TODO: this probably requires that the locale be
// configured somehow:
const size_t size = mbstowcs(NULL, str, 0);
if (size == 0 || size == static_cast<size_t>(-1))
return NULL;
wchar_t* const val = new (std::nothrow) wchar_t[size + 1];
if (val == NULL)
return NULL;
mbstowcs(val, str, size);
val[size] = L'\0';
return val;
}
bool InputHasCues(const mkvparser::Segment* const segment) {
const mkvparser::Cues* const cues = segment->GetCues();
if (cues == NULL)
return false;
while (!cues->DoneParsing())
cues->LoadCuePoint();
const mkvparser::CuePoint* const cue_point = cues->GetFirst();
if (cue_point == NULL)
return false;
return true;
}
bool MasteringMetadataValuePresent(double value) {
return value != mkvparser::MasteringMetadata::kValueNotPresent;
}
bool ColourValuePresent(long long value) {
return value != mkvparser::Colour::kValueNotPresent;
}
} // namespace
int main(int argc, char* argv[]) {
if (argc == 1) {
printf("Mkv Parser Sample Application\n");
printf(" Usage: %s <input file> \n", argv[0]);
return EXIT_FAILURE;
}
mkvparser::MkvReader reader;
if (reader.Open(argv[1])) {
printf("\n Filename is invalid or error while opening.\n");
return EXIT_FAILURE;
}
int maj, min, build, rev;
mkvparser::GetVersion(maj, min, build, rev);
printf("\t\t libwebm version: %d.%d.%d.%d\n", maj, min, build, rev);
long long pos = 0;
mkvparser::EBMLHeader ebmlHeader;
long long ret = ebmlHeader.Parse(&reader, pos);
if (ret < 0) {
printf("\n EBMLHeader::Parse() failed.");
return EXIT_FAILURE;
}
printf("\t\t\t EBML Header\n");
printf("\t\tEBML Version\t\t: %lld\n", ebmlHeader.m_version);
printf("\t\tEBML MaxIDLength\t: %lld\n", ebmlHeader.m_maxIdLength);
printf("\t\tEBML MaxSizeLength\t: %lld\n", ebmlHeader.m_maxSizeLength);
printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
printf("\t\tPos\t\t\t: %lld\n", pos);
typedef mkvparser::Segment seg_t;
seg_t* pSegment_;
ret = seg_t::CreateInstance(&reader, pos, pSegment_);
if (ret) {
printf("\n Segment::CreateInstance() failed.");
return EXIT_FAILURE;
}
const std::unique_ptr<seg_t> pSegment(pSegment_);
ret = pSegment->Load();
if (ret < 0) {
printf("\n Segment::Load() failed.");
return EXIT_FAILURE;
}
const mkvparser::SegmentInfo* const pSegmentInfo = pSegment->GetInfo();
if (pSegmentInfo == NULL) {
printf("\n Segment::GetInfo() failed.");
return EXIT_FAILURE;
}
const long long timeCodeScale = pSegmentInfo->GetTimeCodeScale();
const long long duration_ns = pSegmentInfo->GetDuration();
const char* const pTitle_ = pSegmentInfo->GetTitleAsUTF8();
const wchar_t* const pTitle = utf8towcs(pTitle_);
const char* const pMuxingApp_ = pSegmentInfo->GetMuxingAppAsUTF8();
const wchar_t* const pMuxingApp = utf8towcs(pMuxingApp_);
const char* const pWritingApp_ = pSegmentInfo->GetWritingAppAsUTF8();
const wchar_t* const pWritingApp = utf8towcs(pWritingApp_);
printf("\n");
printf("\t\t\t Segment Info\n");
printf("\t\tTimeCodeScale\t\t: %lld \n", timeCodeScale);
printf("\t\tDuration\t\t: %lld\n", duration_ns);
const double duration_sec = double(duration_ns) / 1000000000;
printf("\t\tDuration(secs)\t\t: %7.3lf\n", duration_sec);
if (pTitle == NULL)
printf("\t\tTrack Name\t\t: NULL\n");
else {
printf("\t\tTrack Name\t\t: %ls\n", pTitle);
delete[] pTitle;
}
if (pMuxingApp == NULL)
printf("\t\tMuxing App\t\t: NULL\n");
else {
printf("\t\tMuxing App\t\t: %ls\n", pMuxingApp);
delete[] pMuxingApp;
}
if (pWritingApp == NULL)
printf("\t\tWriting App\t\t: NULL\n");
else {
printf("\t\tWriting App\t\t: %ls\n", pWritingApp);
delete[] pWritingApp;
}
// pos of segment payload
printf("\t\tPosition(Segment)\t: %lld\n", pSegment->m_start);
// size of segment payload
printf("\t\tSize(Segment)\t\t: %lld\n", pSegment->m_size);
const mkvparser::Tracks* pTracks = pSegment->GetTracks();
unsigned long track_num = 0;
const unsigned long num_tracks = pTracks->GetTracksCount();
printf("\n\t\t\t Track Info\n");
while (track_num != num_tracks) {
const mkvparser::Track* const pTrack =
pTracks->GetTrackByIndex(track_num++);
if (pTrack == NULL)
continue;
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: %ld\n", trackType);
printf("\t\tTrack Number\t\t: %ld\n", trackNumber);
printf("\t\tTrack Uid\t\t: %lld\n", trackUid);
if (pTrackName == NULL)
printf("\t\tTrack Name\t\t: NULL\n");
else {
printf("\t\tTrack Name\t\t: %ls \n", pTrackName);
delete[] pTrackName;
}
const char* const pCodecId = pTrack->GetCodecId();
if (pCodecId == NULL)
printf("\t\tCodec Id\t\t: NULL\n");
else
printf("\t\tCodec Id\t\t: %s\n", pCodecId);
size_t codec_private_size = 0;
if (pTrack->GetCodecPrivate(codec_private_size)) {
printf("\t\tCodec private length: %u bytes\n",
static_cast<unsigned int>(codec_private_size));
}
const char* const pCodecName_ = pTrack->GetCodecNameAsUTF8();
const wchar_t* const pCodecName = utf8towcs(pCodecName_);
if (pCodecName == NULL)
printf("\t\tCodec Name\t\t: NULL\n");
else {
printf("\t\tCodec Name\t\t: %ls\n", pCodecName);
delete[] pCodecName;
}
if (trackType == mkvparser::Track::kVideo) {
const mkvparser::VideoTrack* const pVideoTrack =
static_cast<const mkvparser::VideoTrack*>(pTrack);
const long long width = pVideoTrack->GetWidth();
printf("\t\tVideo Width\t\t: %lld\n", width);
const long long height = pVideoTrack->GetHeight();
printf("\t\tVideo Height\t\t: %lld\n", height);
const double rate = pVideoTrack->GetFrameRate();
printf("\t\tVideo Rate\t\t: %f\n", rate);
const mkvparser::Colour* const colour = pVideoTrack->GetColour();
if (colour) {
printf("\t\tVideo Colour:\n");
if (ColourValuePresent(colour->matrix_coefficients))
printf("\t\t\tMatrixCoefficients: %lld\n",
colour->matrix_coefficients);
if (ColourValuePresent(colour->bits_per_channel))
printf("\t\t\tBitsPerChannel: %lld\n", colour->bits_per_channel);
if (ColourValuePresent(colour->chroma_subsampling_horz))
printf("\t\t\tChromaSubsamplingHorz: %lld\n",
colour->chroma_subsampling_horz);
if (ColourValuePresent(colour->chroma_subsampling_vert))
printf("\t\t\tChromaSubsamplingVert: %lld\n",
colour->chroma_subsampling_vert);
if (ColourValuePresent(colour->cb_subsampling_horz))
printf("\t\t\tCbSubsamplingHorz: %lld\n",
colour->cb_subsampling_horz);
if (ColourValuePresent(colour->cb_subsampling_vert))
printf("\t\t\tCbSubsamplingVert: %lld\n",
colour->cb_subsampling_vert);
if (ColourValuePresent(colour->chroma_siting_horz))
printf("\t\t\tChromaSitingHorz: %lld\n", colour->chroma_siting_horz);
if (ColourValuePresent(colour->chroma_siting_vert))
printf("\t\t\tChromaSitingVert: %lld\n", colour->chroma_siting_vert);
if (ColourValuePresent(colour->range))
printf("\t\t\tRange: %lld\n", colour->range);
if (ColourValuePresent(colour->transfer_characteristics))
printf("\t\t\tTransferCharacteristics: %lld\n",
colour->transfer_characteristics);
if (ColourValuePresent(colour->primaries))
printf("\t\t\tPrimaries: %lld\n", colour->primaries);
if (ColourValuePresent(colour->max_cll))
printf("\t\t\tMaxCLL: %lld\n", colour->max_cll);
if (ColourValuePresent(colour->max_fall))
printf("\t\t\tMaxFALL: %lld\n", colour->max_fall);
if (colour->mastering_metadata) {
const mkvparser::MasteringMetadata* const mm =
colour->mastering_metadata;
printf("\t\t\tMastering Metadata:\n");
if (MasteringMetadataValuePresent(mm->luminance_max))
printf("\t\t\t\tLuminanceMax: %f\n", mm->luminance_max);
if (MasteringMetadataValuePresent(mm->luminance_min))
printf("\t\t\t\tLuminanceMin: %f\n", mm->luminance_min);
if (mm->r) {
printf("\t\t\t\t\tPrimaryRChromaticityX: %f\n", mm->r->x);
printf("\t\t\t\t\tPrimaryRChromaticityY: %f\n", mm->r->y);
}
if (mm->g) {
printf("\t\t\t\t\tPrimaryGChromaticityX: %f\n", mm->g->x);
printf("\t\t\t\t\tPrimaryGChromaticityY: %f\n", mm->g->y);
}
if (mm->b) {
printf("\t\t\t\t\tPrimaryBChromaticityX: %f\n", mm->b->x);
printf("\t\t\t\t\tPrimaryBChromaticityY: %f\n", mm->b->y);
}
if (mm->white_point) {
printf("\t\t\t\t\tWhitePointChromaticityX: %f\n",
mm->white_point->x);
printf("\t\t\t\t\tWhitePointChromaticityY: %f\n",
mm->white_point->y);
}
}
}
const mkvparser::Projection* const projection =
pVideoTrack->GetProjection();
if (projection) {
printf("\t\tVideo Projection:\n");
if (projection->type != mkvparser::Projection::kTypeNotPresent)
printf("\t\t\tProjectionType: %d\n",
static_cast<int>(projection->type));
if (projection->private_data) {
printf("\t\t\tProjectionPrivate: %u bytes\n",
static_cast<unsigned int>(projection->private_data_length));
}
if (projection->pose_yaw != mkvparser::Projection::kValueNotPresent)
printf("\t\t\tProjectionPoseYaw: %f\n", projection->pose_yaw);
if (projection->pose_pitch != mkvparser::Projection::kValueNotPresent)
printf("\t\t\tProjectionPosePitch: %f\n", projection->pose_pitch);
if (projection->pose_roll != mkvparser::Projection::kValueNotPresent)
printf("\t\t\tProjectionPosePitch: %f\n", projection->pose_roll);
}
}
if (trackType == mkvparser::Track::kAudio) {
const mkvparser::AudioTrack* const pAudioTrack =
static_cast<const mkvparser::AudioTrack*>(pTrack);
const long long channels = pAudioTrack->GetChannels();
printf("\t\tAudio Channels\t\t: %lld\n", channels);
const long long bitDepth = pAudioTrack->GetBitDepth();
printf("\t\tAudio BitDepth\t\t: %lld\n", bitDepth);
const double sampleRate = pAudioTrack->GetSamplingRate();
printf("\t\tAddio Sample Rate\t: %.3f\n", sampleRate);
const long long codecDelay = pAudioTrack->GetCodecDelay();
printf("\t\tAudio Codec Delay\t\t: %lld\n", codecDelay);
const long long seekPreRoll = pAudioTrack->GetSeekPreRoll();
printf("\t\tAudio Seek Pre Roll\t\t: %lld\n", seekPreRoll);
}
}
printf("\n\n\t\t\t Cluster Info\n");
const unsigned long clusterCount = pSegment->GetCount();
printf("\t\tCluster Count\t: %ld\n\n", clusterCount);
if (clusterCount == 0) {
printf("\t\tSegment has no clusters.\n");
return EXIT_FAILURE;
}
const mkvparser::Cluster* pCluster = pSegment->GetFirst();
while (pCluster != NULL && !pCluster->EOS()) {
const long long timeCode = pCluster->GetTimeCode();
printf("\t\tCluster Time Code\t: %lld\n", timeCode);
const long long time_ns = pCluster->GetTime();
printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);
const mkvparser::BlockEntry* pBlockEntry;
long status = pCluster->GetFirst(pBlockEntry);
if (status < 0) // error
{
printf("\t\tError parsing first block of cluster\n");
fflush(stdout);
return EXIT_FAILURE;
}
while (pBlockEntry != NULL && !pBlockEntry->EOS()) {
const mkvparser::Block* const pBlock = pBlockEntry->GetBlock();
const long long trackNum = pBlock->GetTrackNumber();
const unsigned long tn = static_cast<unsigned long>(trackNum);
const mkvparser::Track* const pTrack = pTracks->GetTrackByNumber(tn);
if (pTrack == NULL)
printf("\t\t\tBlock\t\t:UNKNOWN TRACK TYPE\n");
else {
const long long trackType = pTrack->GetType();
const int frameCount = pBlock->GetFrameCount();
const long long time_ns = pBlock->GetTime(pCluster);
const long long discard_padding = pBlock->GetDiscardPadding();
printf("\t\t\tBlock\t\t:%s,%s,%15lld,%lld\n",
(trackType == mkvparser::Track::kVideo) ? "V" : "A",
pBlock->IsKey() ? "I" : "P", time_ns, discard_padding);
for (int i = 0; i < frameCount; ++i) {
const mkvparser::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);
}
}
status = pCluster->GetNext(pBlockEntry, pBlockEntry);
if (status < 0) {
printf("\t\t\tError parsing next block of cluster\n");
fflush(stdout);
return EXIT_FAILURE;
}
}
pCluster = pSegment->GetNext(pCluster);
}
if (InputHasCues(pSegment.get())) {
// Walk them.
const mkvparser::Cues* const cues = pSegment->GetCues();
const mkvparser::CuePoint* cue = cues->GetFirst();
int cue_point_num = 1;
printf("\t\tCues\n");
do {
for (track_num = 0; track_num < num_tracks; ++track_num) {
const mkvparser::Track* const track =
pTracks->GetTrackByIndex(track_num);
const mkvparser::CuePoint::TrackPosition* const track_pos =
cue->Find(track);
if (track_pos != NULL) {
const char track_type =
(track->GetType() == mkvparser::Track::kVideo) ? 'V' : 'A';
printf(
"\t\t\tCue Point %4d Track %3lu(%c) Time %14lld "
"Block %4lld Pos %8llx\n",
cue_point_num, track->GetNumber(), track_type,
cue->GetTime(pSegment.get()), track_pos->m_block,
track_pos->m_pos);
}
}
cue = cues->GetNext(cue);
++cue_point_num;
} while (cue != NULL);
}
const mkvparser::Tags* const tags = pSegment->GetTags();
if (tags && tags->GetTagCount() > 0) {
printf("\t\tTags\n");
for (int i = 0; i < tags->GetTagCount(); ++i) {
const mkvparser::Tags::Tag* const tag = tags->GetTag(i);
printf("\t\t\tTag\n");
for (int j = 0; j < tag->GetSimpleTagCount(); j++) {
const mkvparser::Tags::SimpleTag* const simple_tag =
tag->GetSimpleTag(j);
printf("\t\t\t\tSimple Tag \"%s\" Value \"%s\"\n",
simple_tag->GetTagName(), simple_tag->GetTagString());
}
}
}
fflush(stdout);
return EXIT_SUCCESS;
}

128
mkvreader.cpp Normal file
View File

@ -0,0 +1,128 @@
// Copyright (c) 2010 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 "mkvreader.hpp"
#include <cassert>
namespace mkvparser
{
MkvReader::MkvReader() :
m_file(NULL)
{
}
MkvReader::~MkvReader()
{
Close();
}
int MkvReader::Open(const char* fileName)
{
if (fileName == NULL)
return -1;
if (m_file)
return -1;
#ifdef WIN32
const errno_t e = fopen_s(&m_file, fileName, "rb");
if (e)
return -1; //error
#else
m_file = fopen(fileName, "rb");
if (m_file == NULL)
return -1;
#endif
#ifdef WIN32
int status = _fseeki64(m_file, 0L, SEEK_END);
if (status)
return -1; //error
m_length = _ftelli64(m_file);
#else
fseek(m_file, 0L, SEEK_END);
m_length = ftell(m_file);
#endif
assert(m_length >= 0);
#ifdef WIN32
status = _fseeki64(m_file, 0L, SEEK_SET);
if (status)
return -1; //error
#else
fseek(m_file, 0L, SEEK_SET);
#endif
return 0;
}
void MkvReader::Close()
{
if (m_file != NULL)
{
fclose(m_file);
m_file = NULL;
}
}
int MkvReader::Length(long long* total, long long* available)
{
if (m_file == NULL)
return -1;
if (total)
*total = m_length;
if (available)
*available = m_length;
return 0;
}
int MkvReader::Read(long long offset, long len, unsigned char* buffer)
{
if (m_file == NULL)
return -1;
if (offset < 0)
return -1;
if (len < 0)
return -1;
if (len == 0)
return 0;
if (offset >= m_length)
return -1;
#ifdef WIN32
const int status = _fseeki64(m_file, offset, SEEK_SET);
if (status)
return -1; //error
#else
fseek(m_file, offset, SEEK_SET);
#endif
const size_t size = fread(buffer, 1, len, m_file);
if (size < size_t(len))
return -1; //error
return 0; //success
}
} //end namespace mkvparser

View File

@ -1,15 +1,39 @@
// Copyright (c) 2016 The WebM project authors. All Rights Reserved. // Copyright (c) 2010 The WebM project authors. All Rights Reserved.
// //
// Use of this source code is governed by a BSD-style license // 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 // that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found // tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may // in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree. // be found in the AUTHORS file in the root of the source tree.
#ifndef LIBWEBM_MKVREADER_HPP_
#define LIBWEBM_MKVREADER_HPP_
// This file is a wrapper for the file included immediately after this comment. #ifndef MKVREADER_HPP
// New projects should not include this file: include the file included below. #define MKVREADER_HPP
#include "mkvparser/mkvreader.h"
#endif // LIBWEBM_MKVREADER_HPP_ #include "mkvparser.hpp"
#include <cstdio>
namespace mkvparser
{
class MkvReader : public IMkvReader
{
MkvReader(const MkvReader&);
MkvReader& operator=(const MkvReader&);
public:
MkvReader();
virtual ~MkvReader();
int Open(const char*);
void Close();
bool IsOpen() const;
virtual int Read(long long position, long length, unsigned char* buffer);
virtual int Length(long long* total, long long* available);
private:
long long m_length;
FILE* m_file;
};
} //end namespace mkvparser
#endif //MKVREADER_HPP

View File

@ -1,4 +1,4 @@
// Copyright (c) 2012 The WebM project authors. All Rights Reserved. // Copyright (c) 2011 The WebM project authors. All Rights Reserved.
// //
// Use of this source code is governed by a BSD-style license // 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 // that can be found in the LICENSE file in the root of the source
@ -6,21 +6,22 @@
// in the file PATENTS. All contributing project authors may // in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree. // be found in the AUTHORS file in the root of the source tree.
#include "mkvmuxer/mkvwriter.h" #include "mkvwriter.hpp"
#include <sys/types.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#include <share.h> // for _SH_DENYWR #include <share.h> // for _SH_DENYWR
#endif #endif
#include <new>
namespace mkvmuxer { namespace mkvmuxer {
MkvWriter::MkvWriter() : file_(NULL), writer_owns_file_(true) {} MkvWriter::MkvWriter() : file_(NULL) {
}
MkvWriter::MkvWriter(FILE* fp) : file_(fp), writer_owns_file_(false) {} MkvWriter::~MkvWriter() {
Close();
MkvWriter::~MkvWriter() { Close(); } }
int32 MkvWriter::Write(const void* buffer, uint32 length) { int32 MkvWriter::Write(const void* buffer, uint32 length) {
if (!file_) if (!file_)
@ -55,11 +56,11 @@ bool MkvWriter::Open(const char* filename) {
} }
void MkvWriter::Close() { void MkvWriter::Close() {
if (file_ && writer_owns_file_) { if (file_) {
fclose(file_); fclose(file_);
}
file_ = NULL; file_ = NULL;
} }
}
int64 MkvWriter::Position() const { int64 MkvWriter::Position() const {
if (!file_) if (!file_)
@ -79,12 +80,15 @@ int32 MkvWriter::Position(int64 position) {
#ifdef _MSC_VER #ifdef _MSC_VER
return _fseeki64(file_, position, SEEK_SET); return _fseeki64(file_, position, SEEK_SET);
#else #else
return fseeko(file_, static_cast<off_t>(position), SEEK_SET); return fseek(file_, position, SEEK_SET);
#endif #endif
} }
bool MkvWriter::Seekable() const { return true; } bool MkvWriter::Seekable() const {
return true;
}
void MkvWriter::ElementStartNotify(uint64, int64) {} void MkvWriter::ElementStartNotify(uint64, int64) {
}
} // namespace mkvmuxer } // namespace mkvmuxer

View File

@ -1,15 +1,49 @@
// Copyright (c) 2016 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 // 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 // that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found // tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may // in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree. // be found in the AUTHORS file in the root of the source tree.
#ifndef LIBWEBM_MKVWRITER_HPP_
#define LIBWEBM_MKVWRITER_HPP_
// This file is a wrapper for the file included immediately after this comment. #ifndef MKVWRITER_HPP
// New projects should not include this file: include the file included below. #define MKVWRITER_HPP
#include "mkvmuxer/mkvwriter.h"
#endif // LIBWEBM_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

317
sample.cpp Normal file
View File

@ -0,0 +1,317 @@
// Copyright (c) 2010 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.
//
// This sample application demonstrates how to use the matroska parser
// library, which allows clients to handle a matroska format file.
#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)
{
if (str == NULL)
return NULL;
//TODO: this probably requires that the locale be
//configured somehow:
const size_t size = mbstowcs(NULL, str, 0);
if (size == 0)
return NULL;
wchar_t* const val = new wchar_t[size+1];
mbstowcs(val, str, size);
val[size] = L'\0';
return val;
}
int main(int argc, char* argv[])
{
if (argc == 1)
{
printf("\t\t\tMkv Parser Sample Application\n");
printf("\t\t\tUsage: \n");
printf("\t\t\t ./sample [input file] \n");
printf("\t\t\t ./sample sample.mkv \n");
return -1;
}
using namespace mkvparser;
MkvReader reader;
if (reader.Open(argv[1]))
{
printf("\n Filename is invalid or error while opening.\n");
return -1;
}
int maj, min, build, rev;
GetVersion(maj, min, build, rev);
printf("\t\t libmkv verison: %d.%d.%d.%d\n", maj, min, build, rev);
long long pos = 0;
EBMLHeader ebmlHeader;
ebmlHeader.Parse(&reader, pos);
printf("\t\t\t EBML Header\n");
printf("\t\tEBML Version\t\t: %lld\n", ebmlHeader.m_version);
printf("\t\tEBML MaxIDLength\t: %lld\n", ebmlHeader.m_maxIdLength);
printf("\t\tEBML MaxSizeLength\t: %lld\n", ebmlHeader.m_maxSizeLength);
printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
printf("\t\tPos\t\t\t: %lld\n", pos);
typedef mkvparser::Segment seg_t;
seg_t* 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)
{
printf("\n Segment::Load() failed.");
return -1;
}
const SegmentInfo* const pSegmentInfo = pSegment->GetInfo();
const long long timeCodeScale = pSegmentInfo->GetTimeCodeScale();
const long long duration_ns = pSegmentInfo->GetDuration();
const char* const pTitle_ = pSegmentInfo->GetTitleAsUTF8();
const wchar_t* const pTitle = utf8towcs(pTitle_);
const char* const pMuxingApp_ = pSegmentInfo->GetMuxingAppAsUTF8();
const wchar_t* const pMuxingApp = utf8towcs(pMuxingApp_);
const char* const pWritingApp_ = pSegmentInfo->GetWritingAppAsUTF8();
const wchar_t* const pWritingApp = utf8towcs(pWritingApp_);
printf("\n");
printf("\t\t\t Segment Info\n");
printf("\t\tTimeCodeScale\t\t: %lld \n", timeCodeScale);
printf("\t\tDuration\t\t: %lld\n", duration_ns);
const double duration_sec = double(duration_ns) / 1000000000;
printf("\t\tDuration(secs)\t\t: %7.3lf\n", duration_sec);
if (pTitle == NULL)
printf("\t\tTrack Name\t\t: NULL\n");
else
{
printf("\t\tTrack Name\t\t: %ls\n", pTitle);
delete [] pTitle;
}
if (pMuxingApp == NULL)
printf("\t\tMuxing App\t\t: NULL\n");
else
{
printf("\t\tMuxing App\t\t: %ls\n", pMuxingApp);
delete [] pMuxingApp;
}
if (pWritingApp == NULL)
printf("\t\tWriting App\t\t: NULL\n");
else
{
printf("\t\tWriting App\t\t: %ls\n", pWritingApp);
delete [] pWritingApp;
}
// pos of segment payload
printf("\t\tPosition(Segment)\t: %lld\n", pSegment->m_start);
// size of segment payload
printf("\t\tSize(Segment)\t\t: %lld\n", pSegment->m_size);
const mkvparser::Tracks* pTracks = pSegment->GetTracks();
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)
{
const Track* const pTrack = pTracks->GetTrackByIndex(i++);
if (pTrack == NULL)
continue;
const long long trackType = pTrack->GetType();
const long 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 Uid\t\t: %lld\n", trackUid);
if (pTrackName == NULL)
printf("\t\tTrack Name\t\t: NULL\n");
else
{
printf("\t\tTrack Name\t\t: %ls \n", pTrackName);
delete [] pTrackName;
}
const char* const pCodecId = pTrack->GetCodecId();
if (pCodecId == NULL)
printf("\t\tCodec Id\t\t: NULL\n");
else
printf("\t\tCodec Id\t\t: %s\n", pCodecId);
const char* const pCodecName_ = pTrack->GetCodecNameAsUTF8();
const wchar_t* const pCodecName = utf8towcs(pCodecName_);
if (pCodecName == NULL)
printf("\t\tCodec Name\t\t: NULL\n");
else
{
printf("\t\tCodec Name\t\t: %ls\n", pCodecName);
delete [] pCodecName;
}
if (trackType == VIDEO_TRACK)
{
const VideoTrack* const pVideoTrack =
static_cast<const VideoTrack*>(pTrack);
const long long width = pVideoTrack->GetWidth();
printf("\t\tVideo Width\t\t: %lld\n", width);
const long long height = pVideoTrack->GetHeight();
printf("\t\tVideo Height\t\t: %lld\n", height);
const double rate = pVideoTrack->GetFrameRate();
printf("\t\tVideo Rate\t\t: %f\n",rate);
}
if (trackType == AUDIO_TRACK)
{
const AudioTrack* const pAudioTrack =
static_cast<const AudioTrack*>(pTrack);
const long long channels = pAudioTrack->GetChannels();
printf("\t\tAudio Channels\t\t: %lld\n", channels);
const long long bitDepth = pAudioTrack->GetBitDepth();
printf("\t\tAudio BitDepth\t\t: %lld\n", bitDepth);
const double sampleRate = pAudioTrack->GetSamplingRate();
printf("\t\tAddio Sample Rate\t: %.3f\n", sampleRate);
}
}
printf("\n\n\t\t\t Cluster Info\n");
const unsigned long clusterCount = pSegment->GetCount();
printf("\t\tCluster Count\t: %ld\n\n", clusterCount);
if (clusterCount == 0)
{
printf("\t\tSegment has no clusters.\n");
return -1;
}
const mkvparser::Cluster* pCluster = pSegment->GetFirst();
while ((pCluster != NULL) && !pCluster->EOS())
{
const long long timeCode = pCluster->GetTimeCode();
printf("\t\tCluster Time Code\t: %lld\n", timeCode);
const long long time_ns = pCluster->GetTime();
printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);
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())
{
const Block* const pBlock = pBlockEntry->GetBlock();
const long long trackNum = pBlock->GetTrackNumber();
const unsigned long tn = static_cast<unsigned long>(trackNum);
const Track* const pTrack = pTracks->GetTrackByNumber(tn);
if (pTrack == NULL)
printf("\t\t\tBlock\t\t:UNKNOWN TRACK TYPE\n");
else
{
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)
{
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);
}
}
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);
}
fflush(stdout);
return 0;
}

194
sample_2005.vcproj Normal file
View File

@ -0,0 +1,194 @@
<?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="false"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies=".\Debug\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="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="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies=".\Release\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="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>

193
sample_2008.vcproj Normal file
View File

@ -0,0 +1,193 @@
<?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\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="$(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="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies=".\Release\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>
<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>

View File

@ -0,0 +1,397 @@
// 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>
// libwebm parser includes
#include "mkvreader.hpp"
#include "mkvparser.hpp"
// libwebm muxer includes
#include "mkvmuxer.hpp"
#include "mkvwriter.hpp"
#include "mkvmuxerutil.hpp"
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(" 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");
}
} //end namespace
int main(int argc, char* argv[]) {
using mkvmuxer::uint64;
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 = true;
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;
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])) {
input = argv[++i];
} else if (!strcmp("-o", argv[i])) {
output = argv[++i];
} else if (!strcmp("-video", argv[i])) {
output_video = strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-audio", argv[i])) {
output_audio = strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-live", argv[i])) {
live_mode = strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-output_cues", argv[i])) {
output_cues = strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-cues_on_video_track", argv[i])) {
cues_on_video_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-cues_on_audio_track", argv[i])) {
cues_on_audio_track = strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-max_cluster_duration", argv[i])) {
const double seconds = strtod(argv[++i], &end);
max_cluster_duration =
static_cast<uint64>(seconds * 1000000000.0);
} else if (!strcmp("-max_cluster_size", argv[i])) {
max_cluster_size = strtol(argv[++i], &end, 10);
} else if (!strcmp("-switch_tracks", argv[i])) {
switch_tracks = strtol(argv[++i], &end, 10) == 0 ? false : true;
} else if (!strcmp("-audio_track_number", argv[i])) {
audio_track_number = strtol(argv[++i], &end, 10);
} else if (!strcmp("-video_track_number", argv[i])) {
video_track_number = strtol(argv[++i], &end, 10);
} else if (!strcmp("-chunking", argv[i])) {
chunking = true;
chunk_name = argv[++i];
} else if (!strcmp("-display_width", argv[i])) {
display_width = strtol(argv[++i], &end, 10);
} else if (!strcmp("-display_height", argv[i])) {
display_height = strtol(argv[++i], &end, 10);
} else if (!strcmp("-stereo_mode", argv[i])) {
stereo_mode = strtol(argv[++i], &end, 10);
} else if (!strcmp("-output_cues_block_number", argv[i])) {
output_cues_block_number =
strtol(argv[++i], &end, 10) == 0 ? false : true;
}
}
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
enum { kVideoTrack = 1, kAudioTrack = 2 };
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
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 == kVideoTrack && 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 == kAudioTrack && 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);
}
}
// 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();
if ((track_type == kAudioTrack && output_audio) ||
(track_type == kVideoTrack && output_video)) {
const int frame_count = block->GetFrameCount();
const long long time_ns = block->GetTime(cluster);
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 == kAudioTrack)
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);
}
muxer_segment.Finalize();
delete [] data;
delete parser_segment;
writer.Close();
reader.Close();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,197 @@
<?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="$(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="1"
UsePrecompiledHeader="0"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="..\Debug\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="$(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"
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="..\Release\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>
<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_muxer.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -1,391 +0,0 @@
// 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.
//
// This sample application demonstrates how to use the matroska parser
// library, which allows clients to handle a matroska format file.
#include "sample_muxer_metadata.h"
#include <cstdio>
#include <string>
#include "mkvmuxer/mkvmuxer.h"
#include "webvtt/vttreader.h"
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) {
if (kind == kChapters)
return LoadChapters(file);
uint64_t 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::AddChapters() {
typedef cue_list_t::const_iterator iter_t;
iter_t i = chapter_cues_.begin();
const iter_t j = chapter_cues_.end();
while (i != j) {
const cue_t& chapter = *i++;
if (!AddChapter(chapter))
return false;
}
return true;
}
bool SampleMuxerMetadata::Write(int64_t 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::LoadChapters(const char* file) {
if (!chapter_cues_.empty()) {
printf("Support for more than one chapters file is not yet implemented\n");
return false;
}
cue_list_t cues;
if (!ParseChapters(file, &cues))
return false;
// TODO(matthewjheaney): support more than one chapters file
chapter_cues_.swap(cues);
return true;
}
bool SampleMuxerMetadata::ParseChapters(const char* file,
cue_list_t* cues_ptr) {
cue_list_t& cues = *cues_ptr;
cues.clear();
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;
}
libwebvtt::Time t;
t.hours = -1;
for (;;) {
cue_t c;
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) {
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;
}
t = c.start_time;
cues.push_back(c);
}
}
bool SampleMuxerMetadata::AddChapter(const cue_t& cue) {
// TODO(matthewjheaney): support language and country
mkvmuxer::Chapter* const chapter = segment_->AddChapter();
if (chapter == NULL) {
printf("Unable to add chapter\n");
return false;
}
if (cue.identifier.empty()) {
chapter->set_id(NULL);
} else {
const char* const id = cue.identifier.c_str();
if (!chapter->set_id(id)) {
printf("Unable to set chapter id\n");
return false;
}
}
typedef libwebvtt::presentation_t time_ms_t;
const time_ms_t start_time_ms = cue.start_time.presentation();
const time_ms_t stop_time_ms = cue.stop_time.presentation();
enum { kNsPerMs = 1000000 };
const uint64_t start_time_ns = start_time_ms * kNsPerMs;
const uint64_t stop_time_ns = stop_time_ms * kNsPerMs;
chapter->set_time(*segment_, start_time_ns, stop_time_ns);
typedef libwebvtt::Cue::payload_t::const_iterator iter_t;
iter_t i = cue.payload.begin();
const iter_t j = cue.payload.end();
std::string title;
for (;;) {
title += *i++;
if (i == j)
break;
enum { kLF = '\x0A' };
title += kLF;
}
if (!chapter->add_string(title.c_str(), NULL, NULL)) {
printf("Unable to set chapter title\n");
return false;
}
return true;
}
bool SampleMuxerMetadata::AddTrack(Kind kind, uint64_t* 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 */,
uint64_t 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, std::string* pf) {
pf->clear();
WriteCueIdentifier(c.identifier, pf);
WriteCueSettings(c.settings, pf);
WriteCuePayload(c.payload, pf);
}
void SampleMuxerMetadata::WriteCueIdentifier(const std::string& identifier,
std::string* pf) {
pf->append(identifier);
pf->push_back('\x0A'); // LF
}
void SampleMuxerMetadata::WriteCueSettings(const cue_t::settings_t& settings,
std::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,
std::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 std::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 int64_t start_ms = cue.start_time.presentation();
// Cue start time expressed in nanoseconds (MKV time)
const int64_t start_ns = start_ms * 1000000;
// Cue stop time expressed in milliseconds
const int64_t stop_ms = cue.stop_time.presentation();
// Cue stop time expressed in nanonseconds
const int64_t stop_ns = stop_ms * 1000000;
// Metadata blocks always specify the block duration.
const int64_t duration_ns = stop_ns - start_ns;
std::string frame;
MakeFrame(cue, &frame);
typedef const uint8_t* data_t;
const data_t buf = reinterpret_cast<data_t>(frame.data());
const uint64_t len = frame.length();
mkvmuxer::Frame muxer_frame;
if (!muxer_frame.Init(buf, len))
return 0;
muxer_frame.set_track_number(track_num);
muxer_frame.set_timestamp(start_ns);
muxer_frame.set_duration(duration_ns);
muxer_frame.set_is_key(true); // All metadata frames are keyframes.
return segment->AddGenericFrame(&muxer_frame);
}

View File

@ -1,137 +0,0 @@
// 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 <stdint.h>
#include <list>
#include <set>
#include <string>
#include "webvtt/webvttparser.h"
namespace mkvmuxer {
class Chapter;
class Frame;
class Segment;
class Track;
} // namespace mkvmuxer
class SampleMuxerMetadata {
public:
enum Kind { kSubtitles, kCaptions, kDescriptions, kMetadata, kChapters };
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 (or chapters element) in the
// segment. Returns false on error.
bool Load(const char* filename, Kind kind);
bool AddChapters();
// 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(int64_t time_ns);
private:
typedef libwebvtt::Cue cue_t;
// Used to sort cues as they are loaded.
struct SortableCue {
bool operator>(int64_t time_ns) const {
// Cue start time expressed in milliseconds
const int64_t start_ms = cue.start_time.presentation();
// Cue start time expressed in nanoseconds (MKV time)
const int64_t 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;
uint64_t track_num;
cue_t cue;
};
typedef std::multiset<SortableCue> cues_set_t;
typedef std::list<cue_t> cue_list_t;
// Parse the WebVTT cues in the named |file|, returning false on
// error. We handle chapters as a special case, because they are
// stored in their own, dedicated level-1 element.
bool LoadChapters(const char* file);
// Parse the WebVTT chapters in |file| to populate |cues|. Returns
// false on error.
static bool ParseChapters(const char* file, cue_list_t* cues);
// Adds WebVTT cue |chapter| to the chapters element of the output
// file's segment element. Returns false on error.
bool AddChapter(const cue_t& chapter);
// 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, uint64_t* 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, uint64_t 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_;
// The cues that will be used to populate the Chapters level-1
// element of the output file.
cue_list_t chapter_cues_;
// Disable copy ctor and copy assign.
SampleMuxerMetadata(const SampleMuxerMetadata&);
SampleMuxerMetadata& operator=(const SampleMuxerMetadata&);
};
#endif // SAMPLE_MUXER_METADATA_H_ // NOLINT

File diff suppressed because it is too large Load Diff

View File

@ -1,823 +0,0 @@
// Copyright (c) 2016 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 "gtest/gtest.h"
#include <array>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <string>
#include "common/hdr_util.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
#include "testing/test_util.h"
using mkvparser::AudioTrack;
using mkvparser::Block;
using mkvparser::BlockEntry;
using mkvparser::BlockGroup;
using mkvparser::Cluster;
using mkvparser::CuePoint;
using mkvparser::Cues;
using mkvparser::MkvReader;
using mkvparser::Segment;
using mkvparser::SegmentInfo;
using mkvparser::Track;
using mkvparser::Tracks;
using mkvparser::VideoTrack;
namespace test {
// Base class containing boiler plate stuff.
class ParserTest : public testing::Test {
public:
ParserTest() : is_reader_open_(false), segment_(NULL) {
memset(dummy_data_, -1, kFrameLength);
memset(gold_frame_, 0, kFrameLength);
}
virtual ~ParserTest() {
CloseReader();
if (segment_ != NULL) {
delete segment_;
segment_ = NULL;
}
}
void CloseReader() {
if (is_reader_open_) {
reader_.Close();
}
is_reader_open_ = false;
}
bool CreateAndLoadSegment(const std::string& filename,
int expected_doc_type_ver) {
filename_ = GetTestFilePath(filename);
if (reader_.Open(filename_.c_str())) {
return false;
}
is_reader_open_ = true;
pos_ = 0;
mkvparser::EBMLHeader ebml_header;
ebml_header.Parse(&reader_, pos_);
EXPECT_EQ(1, ebml_header.m_version);
EXPECT_EQ(1, ebml_header.m_readVersion);
EXPECT_STREQ("webm", ebml_header.m_docType);
EXPECT_EQ(expected_doc_type_ver, ebml_header.m_docTypeVersion);
EXPECT_EQ(2, ebml_header.m_docTypeReadVersion);
if (mkvparser::Segment::CreateInstance(&reader_, pos_, segment_)) {
return false;
}
return !HasFailure() && segment_->Load() >= 0;
}
bool CreateAndLoadSegment(const std::string& filename) {
return CreateAndLoadSegment(filename, 4);
}
void CreateSegmentNoHeaderChecks(const std::string& filename) {
filename_ = GetTestFilePath(filename);
ASSERT_NE(0u, filename_.length());
ASSERT_EQ(0, reader_.Open(filename_.c_str()));
mkvparser::EBMLHeader ebml_header;
ASSERT_EQ(0, ebml_header.Parse(&reader_, pos_));
ASSERT_EQ(0, mkvparser::Segment::CreateInstance(&reader_, pos_, segment_));
}
void CompareBlockContents(const Cluster* const cluster,
const Block* const block, std::uint64_t timestamp,
int track_number, bool is_key, int frame_count) {
ASSERT_TRUE(block != NULL);
EXPECT_EQ(track_number, block->GetTrackNumber());
EXPECT_EQ(static_cast<long long>(timestamp), block->GetTime(cluster));
EXPECT_EQ(is_key, block->IsKey());
EXPECT_EQ(frame_count, block->GetFrameCount());
const Block::Frame& frame = block->GetFrame(0);
EXPECT_EQ(kFrameLength, frame.len);
std::memset(dummy_data_, -1, kFrameLength);
frame.Read(&reader_, dummy_data_);
EXPECT_EQ(0, std::memcmp(gold_frame_, dummy_data_, kFrameLength));
}
void CompareCuePointContents(const Track* const track,
const CuePoint* const cue_point,
std::uint64_t timestamp, int track_number,
std::uint64_t pos) {
ASSERT_TRUE(cue_point != NULL);
EXPECT_EQ(static_cast<long long>(timestamp), cue_point->GetTime(segment_));
const CuePoint::TrackPosition* const track_position =
cue_point->Find(track);
EXPECT_EQ(track_number, track_position->m_track);
EXPECT_EQ(static_cast<long long>(pos), track_position->m_pos);
}
protected:
MkvReader reader_;
bool is_reader_open_;
Segment* segment_;
std::string filename_;
long long pos_;
std::uint8_t dummy_data_[kFrameLength];
std::uint8_t gold_frame_[kFrameLength];
};
TEST_F(ParserTest, SegmentInfo) {
ASSERT_TRUE(CreateAndLoadSegment("segment_info.webm"));
const SegmentInfo* const info = segment_->GetInfo();
EXPECT_EQ(kTimeCodeScale, info->GetTimeCodeScale());
EXPECT_STREQ(kAppString, info->GetMuxingAppAsUTF8());
EXPECT_STREQ(kAppString, info->GetWritingAppAsUTF8());
}
TEST_F(ParserTest, TrackEntries) {
ASSERT_TRUE(CreateAndLoadSegment("tracks.webm"));
const Tracks* const tracks = segment_->GetTracks();
const unsigned int kTracksCount = 2;
EXPECT_EQ(kTracksCount, tracks->GetTracksCount());
for (int i = 0; i < 2; ++i) {
const Track* const track = tracks->GetTrackByIndex(i);
ASSERT_TRUE(track != NULL);
EXPECT_STREQ(kTrackName, track->GetNameAsUTF8());
if (track->GetType() == Track::kVideo) {
const VideoTrack* const video_track =
dynamic_cast<const VideoTrack*>(track);
EXPECT_EQ(kWidth, static_cast<int>(video_track->GetWidth()));
EXPECT_EQ(kHeight, static_cast<int>(video_track->GetHeight()));
EXPECT_STREQ(kVP8CodecId, video_track->GetCodecId());
EXPECT_DOUBLE_EQ(kVideoFrameRate, video_track->GetFrameRate());
const unsigned int kTrackUid = 1;
EXPECT_EQ(kTrackUid, video_track->GetUid());
} else if (track->GetType() == Track::kAudio) {
const AudioTrack* const audio_track =
dynamic_cast<const AudioTrack*>(track);
EXPECT_EQ(kSampleRate, audio_track->GetSamplingRate());
EXPECT_EQ(kChannels, audio_track->GetChannels());
EXPECT_EQ(kBitDepth, audio_track->GetBitDepth());
EXPECT_STREQ(kVorbisCodecId, audio_track->GetCodecId());
const unsigned int kTrackUid = 2;
EXPECT_EQ(kTrackUid, audio_track->GetUid());
}
}
}
TEST_F(ParserTest, SimpleBlock) {
ASSERT_TRUE(CreateAndLoadSegment("simple_block.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// Get the cluster
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 0, kVideoTrackNumber,
false, 1);
// Get the second block
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 2000000,
kVideoTrackNumber, false, 1);
// End of Stream
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
ASSERT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, MultipleClusters) {
ASSERT_TRUE(CreateAndLoadSegment("force_new_cluster.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// Get the first cluster
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 0, kVideoTrackNumber,
false, 1);
// Get the second cluster
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
EXPECT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the second block
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 2000000,
kVideoTrackNumber, false, 1);
// Get the third block
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 4000000,
kVideoTrackNumber, false, 1);
// Get the third cluster
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
EXPECT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the fourth block
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
CompareBlockContents(cluster, block_entry->GetBlock(), 6000000,
kVideoTrackNumber, false, 1);
// End of Stream
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
EXPECT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, BlockGroup) {
ASSERT_TRUE(CreateAndLoadSegment("metadata_block.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// Get the cluster
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
EXPECT_EQ(BlockEntry::Kind::kBlockGroup, block_entry->GetKind());
const BlockGroup* block_group = static_cast<const BlockGroup*>(block_entry);
EXPECT_EQ(2, block_group->GetDurationTimeCode());
CompareBlockContents(cluster, block_group->GetBlock(), 0,
kMetadataTrackNumber, true, 1);
// Get the second block
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
EXPECT_EQ(BlockEntry::Kind::kBlockGroup, block_entry->GetKind());
block_group = static_cast<const BlockGroup*>(block_entry);
EXPECT_EQ(6, block_group->GetDurationTimeCode());
CompareBlockContents(cluster, block_group->GetBlock(), 2000000,
kMetadataTrackNumber, true, 1);
// End of Stream
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
EXPECT_EQ(NULL, block_entry);
cluster = segment_->GetNext(cluster);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, Cues) {
ASSERT_TRUE(CreateAndLoadSegment("output_cues.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const Track* const track = segment_->GetTracks()->GetTrackByIndex(0);
const Cues* const cues = segment_->GetCues();
ASSERT_TRUE(cues != NULL);
while (!cues->DoneParsing()) {
cues->LoadCuePoint();
}
EXPECT_EQ(3, cues->GetCount());
// Get first Cue Point
const CuePoint* cue_point = cues->GetFirst();
CompareCuePointContents(track, cue_point, 0, kVideoTrackNumber, 206);
// Get second Cue Point
cue_point = cues->GetNext(cue_point);
CompareCuePointContents(track, cue_point, 6000000, kVideoTrackNumber, 269);
// Get third (also last) Cue Point
cue_point = cues->GetNext(cue_point);
const CuePoint* last_cue_point = cues->GetLast();
EXPECT_TRUE(cue_point == last_cue_point);
CompareCuePointContents(track, cue_point, 4000000, kVideoTrackNumber, 269);
EXPECT_TRUE(ValidateCues(segment_, &reader_));
}
TEST_F(ParserTest, CuesBeforeClusters) {
ASSERT_TRUE(CreateAndLoadSegment("cues_before_clusters.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const Track* const track = segment_->GetTracks()->GetTrackByIndex(0);
const Cues* const cues = segment_->GetCues();
ASSERT_TRUE(cues != NULL);
while (!cues->DoneParsing()) {
cues->LoadCuePoint();
}
EXPECT_EQ(2, cues->GetCount());
// Get first Cue Point
const CuePoint* cue_point = cues->GetFirst();
CompareCuePointContents(track, cue_point, 0, kVideoTrackNumber, 238);
// Get second (also last) Cue Point
cue_point = cues->GetNext(cue_point);
const CuePoint* last_cue_point = cues->GetLast();
EXPECT_TRUE(cue_point == last_cue_point);
CompareCuePointContents(track, cue_point, 6000000, kVideoTrackNumber, 301);
EXPECT_TRUE(ValidateCues(segment_, &reader_));
}
TEST_F(ParserTest, CuesTrackNumber) {
ASSERT_TRUE(CreateAndLoadSegment("set_cues_track_number.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const Track* const track = segment_->GetTracks()->GetTrackByIndex(0);
const Cues* const cues = segment_->GetCues();
ASSERT_TRUE(cues != NULL);
while (!cues->DoneParsing()) {
cues->LoadCuePoint();
}
EXPECT_EQ(2, cues->GetCount());
// Get first Cue Point
const CuePoint* cue_point = cues->GetFirst();
CompareCuePointContents(track, cue_point, 0, 10, 206);
// Get second (also last) Cue Point
cue_point = cues->GetNext(cue_point);
const CuePoint* last_cue_point = cues->GetLast();
EXPECT_TRUE(cue_point == last_cue_point);
CompareCuePointContents(track, cue_point, 6000000, 10, 269);
EXPECT_TRUE(ValidateCues(segment_, &reader_));
}
TEST_F(ParserTest, Opus) {
ASSERT_TRUE(CreateAndLoadSegment("bbb_480p_vp9_opus_1second.webm", 4));
const unsigned int kTracksCount = 2;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// --------------------------------------------------------------------------
// Track Header validation.
const Tracks* const tracks = segment_->GetTracks();
EXPECT_EQ(kTracksCount, tracks->GetTracksCount());
for (int i = 0; i < 2; ++i) {
const Track* const track = tracks->GetTrackByIndex(i);
ASSERT_TRUE(track != NULL);
EXPECT_EQ(NULL, track->GetNameAsUTF8());
EXPECT_STREQ("und", track->GetLanguage());
EXPECT_EQ(i + 1, track->GetNumber());
EXPECT_FALSE(track->GetLacing());
if (track->GetType() == Track::kVideo) {
const VideoTrack* const video_track =
dynamic_cast<const VideoTrack*>(track);
EXPECT_EQ(854, static_cast<int>(video_track->GetWidth()));
EXPECT_EQ(480, static_cast<int>(video_track->GetHeight()));
EXPECT_STREQ(kVP9CodecId, video_track->GetCodecId());
EXPECT_DOUBLE_EQ(0., video_track->GetFrameRate());
EXPECT_EQ(41666666,
static_cast<int>(video_track->GetDefaultDuration())); // 24.000
const unsigned int kVideoUid = kVideoTrackNumber;
EXPECT_EQ(kVideoUid, video_track->GetUid());
const unsigned int kCodecDelay = 0;
EXPECT_EQ(kCodecDelay, video_track->GetCodecDelay());
const unsigned int kSeekPreRoll = 0;
EXPECT_EQ(kSeekPreRoll, video_track->GetSeekPreRoll());
size_t video_codec_private_size;
EXPECT_EQ(NULL, video_track->GetCodecPrivate(video_codec_private_size));
const unsigned int kPrivateSize = 0;
EXPECT_EQ(kPrivateSize, video_codec_private_size);
} else if (track->GetType() == Track::kAudio) {
const AudioTrack* const audio_track =
dynamic_cast<const AudioTrack*>(track);
EXPECT_EQ(48000, audio_track->GetSamplingRate());
EXPECT_EQ(6, audio_track->GetChannels());
EXPECT_EQ(32, audio_track->GetBitDepth());
EXPECT_STREQ(kOpusCodecId, audio_track->GetCodecId());
EXPECT_EQ(kAudioTrackNumber, static_cast<int>(audio_track->GetUid()));
const unsigned int kDefaultDuration = 0;
EXPECT_EQ(kDefaultDuration, audio_track->GetDefaultDuration());
EXPECT_EQ(kOpusCodecDelay, audio_track->GetCodecDelay());
EXPECT_EQ(kOpusSeekPreroll, audio_track->GetSeekPreRoll());
size_t audio_codec_private_size;
EXPECT_TRUE(audio_track->GetCodecPrivate(audio_codec_private_size) !=
NULL);
EXPECT_GE(audio_codec_private_size, kOpusPrivateDataSizeMinimum);
}
}
// --------------------------------------------------------------------------
// Parse the file to do block-level validation.
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
for (; cluster != NULL && !cluster->EOS();
cluster = segment_->GetNext(cluster)) {
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
while (block_entry != NULL && !block_entry->EOS()) {
const Block* const block = block_entry->GetBlock();
ASSERT_TRUE(block != NULL);
EXPECT_FALSE(block->IsInvisible());
EXPECT_EQ(Block::kLacingNone, block->GetLacing());
const std::uint32_t track_number =
static_cast<std::uint32_t>(block->GetTrackNumber());
const Track* const track = tracks->GetTrackByNumber(track_number);
ASSERT_TRUE(track != NULL);
EXPECT_EQ(track->GetNumber(), block->GetTrackNumber());
const unsigned int kContentEncodingCount = 0;
EXPECT_EQ(kContentEncodingCount,
track->GetContentEncodingCount()); // no encryption
const std::int64_t track_type = track->GetType();
EXPECT_TRUE(track_type == Track::kVideo || track_type == Track::kAudio);
if (track_type == Track::kVideo) {
EXPECT_EQ(BlockEntry::kBlockSimple, block_entry->GetKind());
EXPECT_EQ(0, block->GetDiscardPadding());
} else {
EXPECT_TRUE(block->IsKey());
const std::int64_t kLastAudioTimecode = 1001;
const std::int64_t timecode = block->GetTimeCode(cluster);
// Only the final Opus block should have discard padding.
if (timecode == kLastAudioTimecode) {
EXPECT_EQ(BlockEntry::kBlockGroup, block_entry->GetKind());
EXPECT_EQ(13500000, block->GetDiscardPadding());
} else {
EXPECT_EQ(BlockEntry::kBlockSimple, block_entry->GetKind());
EXPECT_EQ(0, block->GetDiscardPadding());
}
}
const int frame_count = block->GetFrameCount();
const Block::Frame& frame = block->GetFrame(0);
EXPECT_EQ(1, frame_count);
EXPECT_GT(frame.len, 0);
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
}
}
ASSERT_TRUE(cluster != NULL);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, DiscardPadding) {
// Test an artificial file with some extreme DiscardPadding values.
const std::string file = "discard_padding.webm";
ASSERT_TRUE(CreateAndLoadSegment(file, 4));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
// --------------------------------------------------------------------------
// Track Header validation.
const Tracks* const tracks = segment_->GetTracks();
EXPECT_EQ(kTracksCount, tracks->GetTracksCount());
const Track* const track = tracks->GetTrackByIndex(0);
ASSERT_TRUE(track != NULL);
EXPECT_STREQ(NULL, track->GetNameAsUTF8());
EXPECT_EQ(NULL, track->GetLanguage());
EXPECT_EQ(kAudioTrackNumber, track->GetNumber());
EXPECT_TRUE(track->GetLacing());
EXPECT_EQ(Track::kAudio, track->GetType());
const AudioTrack* const audio_track = dynamic_cast<const AudioTrack*>(track);
EXPECT_EQ(30, audio_track->GetSamplingRate());
EXPECT_EQ(2, audio_track->GetChannels());
EXPECT_STREQ(kOpusCodecId, audio_track->GetCodecId());
EXPECT_EQ(kAudioTrackNumber, static_cast<int>(audio_track->GetUid()));
const unsigned int kDefaultDuration = 0;
EXPECT_EQ(kDefaultDuration, audio_track->GetDefaultDuration());
const unsigned int kCodecDelay = 0;
EXPECT_EQ(kCodecDelay, audio_track->GetCodecDelay());
const unsigned int kSeekPreRoll = 0;
EXPECT_EQ(kSeekPreRoll, audio_track->GetSeekPreRoll());
size_t audio_codec_private_size;
EXPECT_EQ(NULL, audio_track->GetCodecPrivate(audio_codec_private_size));
const unsigned int kPrivateSize = 0;
EXPECT_EQ(kPrivateSize, audio_codec_private_size);
// --------------------------------------------------------------------------
// Parse the file to do block-level validation.
const Cluster* cluster = segment_->GetFirst();
ASSERT_TRUE(cluster != NULL);
EXPECT_FALSE(cluster->EOS());
const unsigned int kSegmentCount = 1;
EXPECT_EQ(kSegmentCount, segment_->GetCount());
// Get the first block
const BlockEntry* block_entry;
EXPECT_EQ(0, cluster->GetFirst(block_entry));
ASSERT_TRUE(block_entry != NULL);
EXPECT_FALSE(block_entry->EOS());
const std::array<int, 3> discard_padding = {{12810000, 127, -128}};
int index = 0;
while (block_entry != NULL && !block_entry->EOS()) {
const Block* const block = block_entry->GetBlock();
ASSERT_TRUE(block != NULL);
EXPECT_FALSE(block->IsInvisible());
EXPECT_EQ(Block::kLacingNone, block->GetLacing());
const std::uint32_t track_number =
static_cast<std::uint32_t>(block->GetTrackNumber());
const Track* const track = tracks->GetTrackByNumber(track_number);
ASSERT_TRUE(track != NULL);
EXPECT_EQ(track->GetNumber(), block->GetTrackNumber());
const unsigned int kContentEncodingCount = 0;
EXPECT_EQ(kContentEncodingCount,
track->GetContentEncodingCount()); // no encryption
const std::int64_t track_type = track->GetType();
EXPECT_EQ(Track::kAudio, track_type);
EXPECT_TRUE(block->IsKey());
// All blocks have DiscardPadding.
EXPECT_EQ(BlockEntry::kBlockGroup, block_entry->GetKind());
ASSERT_LT(index, static_cast<int>(discard_padding.size()));
EXPECT_EQ(discard_padding[index], block->GetDiscardPadding());
++index;
const int frame_count = block->GetFrameCount();
const Block::Frame& frame = block->GetFrame(0);
EXPECT_EQ(1, frame_count);
EXPECT_GT(frame.len, 0);
EXPECT_EQ(0, cluster->GetNext(block_entry, block_entry));
}
cluster = segment_->GetNext(cluster);
ASSERT_TRUE(cluster != NULL);
EXPECT_TRUE(cluster->EOS());
}
TEST_F(ParserTest, StereoModeParsedCorrectly) {
ASSERT_TRUE(CreateAndLoadSegment("test_stereo_left_right.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const VideoTrack* const video_track = dynamic_cast<const VideoTrack*>(
segment_->GetTracks()->GetTrackByIndex(0));
EXPECT_EQ(1, video_track->GetStereoMode());
EXPECT_EQ(256, video_track->GetWidth());
EXPECT_EQ(144, video_track->GetHeight());
EXPECT_EQ(128, video_track->GetDisplayWidth());
EXPECT_EQ(144, video_track->GetDisplayHeight());
}
TEST_F(ParserTest, CanParseColour) {
ASSERT_TRUE(CreateAndLoadSegment("colour.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const VideoTrack* const video_track = dynamic_cast<const VideoTrack*>(
segment_->GetTracks()->GetTrackByIndex(0));
const mkvparser::Colour* const colour = video_track->GetColour();
ASSERT_TRUE(colour != nullptr);
EXPECT_EQ(0u, colour->matrix_coefficients);
EXPECT_EQ(1u, colour->bits_per_channel);
EXPECT_EQ(2u, colour->chroma_subsampling_horz);
EXPECT_EQ(3u, colour->chroma_subsampling_vert);
EXPECT_EQ(4u, colour->cb_subsampling_horz);
EXPECT_EQ(5u, colour->cb_subsampling_vert);
EXPECT_EQ(1u, colour->chroma_siting_horz);
EXPECT_EQ(1u, colour->chroma_siting_vert);
EXPECT_EQ(2u, colour->range);
EXPECT_EQ(9u, colour->transfer_characteristics);
EXPECT_EQ(10u, colour->primaries);
EXPECT_EQ(11u, colour->max_cll);
EXPECT_EQ(12u, colour->max_fall);
const mkvparser::MasteringMetadata* const mm =
video_track->GetColour()->mastering_metadata;
ASSERT_TRUE(mm != nullptr);
ASSERT_TRUE(mm->r != nullptr);
ASSERT_TRUE(mm->g != nullptr);
ASSERT_TRUE(mm->b != nullptr);
ASSERT_TRUE(mm->white_point != nullptr);
EXPECT_FLOAT_EQ(.1, mm->r->x);
EXPECT_FLOAT_EQ(.2, mm->r->y);
EXPECT_FLOAT_EQ(.1, mm->g->x);
EXPECT_FLOAT_EQ(.2, mm->g->y);
EXPECT_FLOAT_EQ(.1, mm->b->x);
EXPECT_FLOAT_EQ(.2, mm->b->y);
EXPECT_FLOAT_EQ(.1, mm->white_point->x);
EXPECT_FLOAT_EQ(.2, mm->white_point->y);
EXPECT_FLOAT_EQ(30.0, mm->luminance_min);
EXPECT_FLOAT_EQ(40.0, mm->luminance_max);
}
TEST_F(ParserTest, CanParseProjection) {
ASSERT_TRUE(CreateAndLoadSegment("projection.webm"));
const unsigned int kTracksCount = 1;
EXPECT_EQ(kTracksCount, segment_->GetTracks()->GetTracksCount());
const VideoTrack* const video_track =
static_cast<const VideoTrack*>(segment_->GetTracks()->GetTrackByIndex(0));
const mkvparser::Projection* const projection = video_track->GetProjection();
ASSERT_TRUE(projection != nullptr);
EXPECT_EQ(mkvparser::Projection::kRectangular, projection->type);
EXPECT_FLOAT_EQ(1, projection->pose_yaw);
EXPECT_FLOAT_EQ(2, projection->pose_pitch);
EXPECT_FLOAT_EQ(3, projection->pose_roll);
EXPECT_EQ(1u, projection->private_data_length);
ASSERT_TRUE(projection->private_data != nullptr);
EXPECT_EQ(4u, projection->private_data[0]);
}
TEST_F(ParserTest, Vp9CodecLevelTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(11, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecProfileTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {1, 1, 1};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecBitDepthTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {3, 1, 8};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(8, features.bit_depth);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent,
features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecChromaSubsamplingTest) {
const int kCodecPrivateLength = 3;
const uint8_t good_codec_private_profile[kCodecPrivateLength] = {4, 1, 0};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&good_codec_private_profile[0],
kCodecPrivateLength, &features));
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.profile);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.level);
EXPECT_EQ(libwebm::Vp9CodecFeatures::kValueNotPresent, features.bit_depth);
EXPECT_EQ(0, features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecProfileLevelTest) {
const int kCodecPrivateLength = 6;
const uint8_t codec_private[kCodecPrivateLength] = {1, 1, 1, 2, 1, 11};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&codec_private[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(11, features.level);
}
TEST_F(ParserTest, Vp9CodecAllTest) {
const int kCodecPrivateLength = 12;
const uint8_t codec_private[kCodecPrivateLength] = {1, 1, 1, 2, 1, 11,
3, 1, 8, 4, 1, 0};
libwebm::Vp9CodecFeatures features;
EXPECT_TRUE(libwebm::ParseVpxCodecPrivate(&codec_private[0],
kCodecPrivateLength, &features));
EXPECT_EQ(1, features.profile);
EXPECT_EQ(11, features.level);
EXPECT_EQ(8, features.bit_depth);
EXPECT_EQ(0, features.chroma_subsampling);
}
TEST_F(ParserTest, Vp9CodecPrivateBadTest) {
const int kCodecPrivateLength = 3;
libwebm::Vp9CodecFeatures features;
// Test invalid codec private data; all of these should return false.
const uint8_t bad_codec_private[kCodecPrivateLength] = {0, 0, 0};
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(NULL, kCodecPrivateLength, &features));
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0, &features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&bad_codec_private[0],
kCodecPrivateLength, &features));
const uint8_t good_codec_private_level[kCodecPrivateLength] = {2, 1, 11};
// Test parse of codec private chunks, but lie about length.
EXPECT_FALSE(
libwebm::ParseVpxCodecPrivate(&bad_codec_private[0], 0, &features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0], 0,
&features));
EXPECT_FALSE(libwebm::ParseVpxCodecPrivate(&good_codec_private_level[0],
kCodecPrivateLength, NULL));
}
TEST_F(ParserTest, InvalidTruncatedChapterString) {
ASSERT_NO_FATAL_FAILURE(CreateSegmentNoHeaderChecks(
"invalid/chapters_truncated_chapter_string.mkv"));
EXPECT_EQ(mkvparser::E_PARSE_FAILED, segment_->Load());
}
TEST_F(ParserTest, InvalidTruncatedChapterString2) {
ASSERT_NO_FATAL_FAILURE(CreateSegmentNoHeaderChecks(
"invalid/chapters_truncated_chapter_string_2.mkv"));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID, segment_->Load());
}
TEST_F(ParserTest, InvalidFixedLacingSize) {
ASSERT_NO_FATAL_FAILURE(
CreateSegmentNoHeaderChecks("invalid/fixed_lacing_bad_lace_size.mkv"));
ASSERT_EQ(0, segment_->Load());
const mkvparser::BlockEntry* block_entry = NULL;
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID,
segment_->GetFirst()->GetFirst(block_entry));
}
TEST_F(ParserTest, InvalidBlockEndsBeyondCluster) {
ASSERT_NO_FATAL_FAILURE(
CreateSegmentNoHeaderChecks("invalid/block_ends_beyond_cluster.mkv"));
ASSERT_EQ(0, segment_->Load());
const mkvparser::BlockEntry* block_entry = NULL;
EXPECT_EQ(0, segment_->GetFirst()->GetFirst(block_entry));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID,
segment_->GetFirst()->GetNext(block_entry, block_entry));
}
TEST_F(ParserTest, InvalidBlockGroupBlockEndsBlockGroup) {
ASSERT_NO_FATAL_FAILURE(CreateSegmentNoHeaderChecks(
"invalid/blockgroup_block_ends_beyond_blockgroup.mkv"));
ASSERT_EQ(0, segment_->Load());
const mkvparser::BlockEntry* block_entry = NULL;
EXPECT_EQ(0, segment_->GetFirst()->GetFirst(block_entry));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID,
segment_->GetFirst()->GetNext(block_entry, block_entry));
}
TEST_F(ParserTest, InvalidProjectionFloatOverflow) {
ASSERT_NO_FATAL_FAILURE(
CreateSegmentNoHeaderChecks("invalid/projection_float_overflow.webm"));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID, segment_->Load());
}
TEST_F(ParserTest, InvalidPrimaryChromaticityParseFail) {
ASSERT_NO_FATAL_FAILURE(CreateSegmentNoHeaderChecks(
"invalid/primarychromaticity_fieldtoolarge.webm"));
EXPECT_EQ(mkvparser::E_FILE_FORMAT_INVALID, segment_->Load());
}
} // namespace test
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,215 +0,0 @@
// Copyright (c) 2016 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 "testing/test_util.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ios>
#include <string>
#include "common/libwebm_util.h"
#include "common/webmids.h"
#include "mkvparser/mkvparser.h"
#include "mkvparser/mkvreader.h"
namespace test {
std::string GetTestDataDir() {
const char* test_data_path = std::getenv("LIBWEBM_TEST_DATA_PATH");
return test_data_path ? std::string(test_data_path) : std::string();
}
std::string GetTestFilePath(const std::string& name) {
const std::string libwebm_testdata_dir = GetTestDataDir();
return libwebm_testdata_dir + "/" + name;
}
bool CompareFiles(const std::string& file1, const std::string& file2) {
const std::size_t kBlockSize = 4096;
std::uint8_t buf1[kBlockSize] = {0};
std::uint8_t buf2[kBlockSize] = {0};
libwebm::FilePtr f1 =
libwebm::FilePtr(std::fopen(file1.c_str(), "rb"), libwebm::FILEDeleter());
libwebm::FilePtr f2 =
libwebm::FilePtr(std::fopen(file2.c_str(), "rb"), libwebm::FILEDeleter());
if (!f1.get() || !f2.get()) {
// Files cannot match if one or both couldn't be opened.
return false;
}
do {
const std::size_t r1 = std::fread(buf1, 1, kBlockSize, f1.get());
const std::size_t r2 = std::fread(buf2, 1, kBlockSize, f2.get());
// TODO(fgalligan): Add output of which byte differs.
if (r1 != r2 || std::memcmp(buf1, buf2, r1)) {
return 0; // Files are not equal
}
} while (!std::feof(f1.get()) && !std::feof(f2.get()));
return std::feof(f1.get()) && std::feof(f2.get());
}
bool HasCuePoints(const mkvparser::Segment* segment,
std::int64_t* cues_offset) {
if (!segment || !cues_offset) {
return false;
}
using mkvparser::SeekHead;
const SeekHead* const seek_head = segment->GetSeekHead();
if (!seek_head) {
return false;
}
std::int64_t offset = 0;
for (int i = 0; i < seek_head->GetCount(); ++i) {
const SeekHead::Entry* const entry = seek_head->GetEntry(i);
if (entry->id == libwebm::kMkvCues) {
offset = entry->pos;
}
}
if (offset <= 0) {
// No Cues found.
return false;
}
*cues_offset = offset;
return true;
}
bool ValidateCues(mkvparser::Segment* segment, mkvparser::IMkvReader* reader) {
if (!segment) {
return false;
}
std::int64_t cues_offset = 0;
if (!HasCuePoints(segment, &cues_offset)) {
// No cues to validate, everything is OK.
return true;
}
// Parse Cues.
long long cues_pos = 0; // NOLINT
long cues_len = 0; // NOLINT
if (segment->ParseCues(cues_offset, cues_pos, cues_len)) {
return false;
}
// Get a pointer to the video track if it exists. Otherwise, we assume
// that Cues are based on the first track (which is true for all our test
// files).
const mkvparser::Tracks* const tracks = segment->GetTracks();
const mkvparser::Track* cues_track = tracks->GetTrackByIndex(0);
for (int i = 1; i < static_cast<int>(tracks->GetTracksCount()); ++i) {
const mkvparser::Track* const track = tracks->GetTrackByIndex(i);
if (track->GetType() == mkvparser::Track::kVideo) {
cues_track = track;
break;
}
}
// Iterate through Cues and verify if they are pointing to the correct
// Cluster position.
const mkvparser::Cues* const cues = segment->GetCues();
const mkvparser::CuePoint* cue_point = NULL;
while (cues->LoadCuePoint()) {
if (!cue_point) {
cue_point = cues->GetFirst();
} else {
cue_point = cues->GetNext(cue_point);
}
const mkvparser::CuePoint::TrackPosition* const track_position =
cue_point->Find(cues_track);
const long long cluster_pos = track_position->m_pos + // NOLINT
segment->m_start;
// If a cluster does not begin at |cluster_pos|, then the file is
// incorrect.
long length; // NOLINT
const std::int64_t id = mkvparser::ReadID(reader, cluster_pos, length);
if (id != libwebm::kMkvCluster) {
return false;
}
}
return true;
}
MkvParser::~MkvParser() {
delete segment;
delete reader;
}
bool ParseMkvFileReleaseParser(const std::string& webm_file,
MkvParser* parser_out) {
parser_out->reader = new (std::nothrow) mkvparser::MkvReader;
mkvparser::MkvReader& reader = *parser_out->reader;
if (!parser_out->reader || reader.Open(webm_file.c_str()) < 0) {
return false;
}
long long pos = 0; // NOLINT
mkvparser::EBMLHeader ebml_header;
if (ebml_header.Parse(&reader, pos)) {
return false;
}
using mkvparser::Segment;
Segment* segment_ptr = nullptr;
if (Segment::CreateInstance(&reader, pos, segment_ptr)) {
return false;
}
std::unique_ptr<Segment> segment(segment_ptr);
long result;
if ((result = segment->Load()) < 0) {
return false;
}
const mkvparser::Cluster* cluster = segment->GetFirst();
if (!cluster || cluster->EOS()) {
return false;
}
while (cluster && cluster->EOS() == false) {
if (cluster->GetTimeCode() < 0) {
return false;
}
const mkvparser::BlockEntry* block = nullptr;
if (cluster->GetFirst(block) < 0) {
return false;
}
while (block != NULL && block->EOS() == false) {
if (cluster->GetNext(block, block) < 0) {
return false;
}
}
cluster = segment->GetNext(cluster);
}
parser_out->segment = segment.release();
return true;
}
bool ParseMkvFile(const std::string& webm_file) {
MkvParser parser;
const bool result = ParseMkvFileReleaseParser(webm_file, &parser);
delete parser.segment;
delete parser.reader;
return result;
}
} // namespace test

View File

@ -1,88 +0,0 @@
// Copyright (c) 2016 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 LIBWEBM_TESTING_TEST_UTIL_H_
#define LIBWEBM_TESTING_TEST_UTIL_H_
#include <stdint.h>
#include <cstddef>
#include <string>
namespace mkvparser {
class IMkvReader;
class MkvReader;
class Segment;
}
namespace test {
// constants for muxer and parser tests
const char kAppString[] = "mkvmuxer_unit_tests";
const char kOpusCodecId[] = "A_OPUS";
const char kVorbisCodecId[] = "A_VORBIS";
const int kAudioTrackNumber = 2;
const int kBitDepth = 2;
const int kChannels = 2;
const double kDuration = 2.345;
const int kFrameLength = 10;
const int kHeight = 180;
const int kInvalidTrackNumber = 100;
const std::uint64_t kOpusCodecDelay = 6500000;
const std::size_t kOpusPrivateDataSizeMinimum = 19;
const std::uint64_t kOpusSeekPreroll = 80000000;
const char kMetadataCodecId[] = "D_WEBVTT/METADATA";
const int kMetadataTrackNumber = 3;
const int kMetadataTrackType = 0x21;
const int kSampleRate = 30;
const int kTimeCodeScale = 1000;
const char kTrackName[] = "unit_test";
const char kVP8CodecId[] = "V_VP8";
const char kVP9CodecId[] = "V_VP9";
const double kVideoFrameRate = 0.5;
const int kVideoTrackNumber = 1;
const int kWidth = 320;
// Returns the path to the test data directory by reading and returning the
// contents the LIBWEBM_TESTDATA_DIR environment variable.
std::string GetTestDataDir();
// Returns the absolute path to the file of |name| in LIBWEBM_TESTDATA_DIR.
std::string GetTestFilePath(const std::string& name);
// Byte-wise comparison of two files |file1| and |file2|. Returns true if the
// files match exactly, false otherwise.
bool CompareFiles(const std::string& file1, const std::string& file2);
// Returns true and sets |cues_offset| to the cues location within the MKV file
// parsed by |segment| when the MKV file has cue points.
bool HasCuePoints(const mkvparser::Segment* segment, std::int64_t* cues_offset);
// Validates cue points. Assumes caller has already called Load() on |segment|.
// Returns true when:
// All cue points point at clusters, OR
// Data parsed by |segment| has no cue points.
bool ValidateCues(mkvparser::Segment* segment, mkvparser::IMkvReader* reader);
// Parses |webm_file| using mkvparser and returns true when file parses
// successfully (all clusters and blocks can be successfully walked). Second
// variant allows further interaction with the parsed file via transferring
// ownership of the mkvparser Segment and MkvReader to the caller via
// |parser_out|.
struct MkvParser {
MkvParser() = default;
~MkvParser();
mkvparser::Segment* segment = nullptr;
mkvparser::MkvReader* reader = nullptr;
};
bool ParseMkvFile(const std::string& webm_file);
bool ParseMkvFileReleaseParser(const std::string& webm_file,
MkvParser* parser_out);
} // namespace test
#endif // LIBWEBM_TESTING_TEST_UTIL_H_

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,24 +0,0 @@
Why the files in this directory are considered invalid:
block_ends_beyond_cluster.mkv -
File containing a single cluster with two simple blocks. One valid, and the
second reporting a size that would cause the block to end far beyond the end
of its parent cluster.
blockgroup_block_ends_beyond_blockgroup.mkv -
File containing a single cluster and two blockgroups. The first blockgroup is
valid. The second blockgroup contains a block reporting a size that spans well
past the block and the end of the file.
chapters_truncated_chapter_string.mkv -
File with a Chapters element that ends with a ChapterAtom whose ChapterDisplay
element contains a truncated ChapterString.
chapters_truncated_chapter_string_2.mkv -
Nearly identical to chapters_truncated_chapter_string.mkv, but with a void
element and a partial cluster. Causes mkvparser to fail in a slightly
different manner.
fixed_lacing_bad_lace_size.mkv -
File containing a BlockGroup with fixed lacing, but reports a total laced size
that is not evenly divisible by the number of laced frames.

Some files were not shown because too many files have changed in this diff Show More